summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--LICENCE1
-rw-r--r--configure.ac3
-rw-r--r--defines.h6
-rw-r--r--openbsd-compat/realpath.c266
5 files changed, 140 insertions, 141 deletions
diff --git a/ChangeLog b/ChangeLog
index 37539b728..f62f121df 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,9 @@
120050810 120050810
2 - (dtucker) [configure.ac] Test libedit library and headers for compatibility. 2 - (dtucker) [configure.ac] Test libedit library and headers for compatibility.
3 Report from skeleten AT shillest.net, ok djm@ 3 Report from skeleten AT shillest.net, ok djm@
4 - (dtucker) [LICENCE configure.ac defines.h openbsd-compat/realpath.c]
5 Sync current (thread-safe) version of realpath.c from OpenBSD (which is
6 in turn based on FreeBSD's). ok djm@
4 7
520050809 820050809
6 - (tim) [configure.ac] Allow --with-audit=no. OK dtucker@ 9 - (tim) [configure.ac] Allow --with-audit=no. OK dtucker@
@@ -2904,4 +2907,4 @@
2904 - (djm) Trim deprecated options from INSTALL. Mention UsePAM 2907 - (djm) Trim deprecated options from INSTALL. Mention UsePAM
2905 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu 2908 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
2906 2909
2907$Id: ChangeLog,v 1.3864 2005/08/10 10:34:15 dtucker Exp $ 2910$Id: ChangeLog,v 1.3865 2005/08/10 11:52:36 dtucker Exp $
diff --git a/LICENCE b/LICENCE
index ae03eb3a7..5def839e5 100644
--- a/LICENCE
+++ b/LICENCE
@@ -255,6 +255,7 @@ OpenSSH contains no GPL code.
255 Damien Miller 255 Damien Miller
256 Eric P. Allman 256 Eric P. Allman
257 The Regents of the University of California 257 The Regents of the University of California
258 Constantin S. Svintsoff
258 259
259 * Redistribution and use in source and binary forms, with or without 260 * Redistribution and use in source and binary forms, with or without
260 * modification, are permitted provided that the following conditions 261 * modification, are permitted provided that the following conditions
diff --git a/configure.ac b/configure.ac
index 60dbd0c34..a62ee8c43 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
1# $Id: configure.ac,v 1.284 2005/08/10 10:34:15 dtucker Exp $ 1# $Id: configure.ac,v 1.285 2005/08/10 11:52:36 dtucker Exp $
2# 2#
3# Copyright (c) 1999-2004 Damien Miller 3# Copyright (c) 1999-2004 Damien Miller
4# 4#
@@ -1085,7 +1085,6 @@ AC_CHECK_FUNCS( \
1085 clock \ 1085 clock \
1086 closefrom \ 1086 closefrom \
1087 dirfd \ 1087 dirfd \
1088 fchdir \
1089 fchmod \ 1088 fchmod \
1090 fchown \ 1089 fchown \
1091 freeaddrinfo \ 1090 freeaddrinfo \
diff --git a/defines.h b/defines.h
index f7029abb4..39d18e3d3 100644
--- a/defines.h
+++ b/defines.h
@@ -25,7 +25,7 @@
25#ifndef _DEFINES_H 25#ifndef _DEFINES_H
26#define _DEFINES_H 26#define _DEFINES_H
27 27
28/* $Id: defines.h,v 1.122 2005/07/14 07:22:11 dtucker Exp $ */ 28/* $Id: defines.h,v 1.123 2005/08/10 11:52:36 dtucker Exp $ */
29 29
30 30
31/* Constants */ 31/* Constants */
@@ -62,6 +62,10 @@ enum
62# endif /* PATH_MAX */ 62# endif /* PATH_MAX */
63#endif /* MAXPATHLEN */ 63#endif /* MAXPATHLEN */
64 64
65#ifndef MAXSYMLINKS
66# define MAXSYMLINKS 5
67#endif
68
65#ifndef STDIN_FILENO 69#ifndef STDIN_FILENO
66# define STDIN_FILENO 0 70# define STDIN_FILENO 0
67#endif 71#endif
diff --git a/openbsd-compat/realpath.c b/openbsd-compat/realpath.c
index 7f73bd998..8430bec24 100644
--- a/openbsd-compat/realpath.c
+++ b/openbsd-compat/realpath.c
@@ -1,11 +1,7 @@
1/* OPENBSD ORIGINAL: lib/libc/stdlib/realpath.c */ 1/* OPENBSD ORIGINAL: lib/libc/stdlib/realpath.c */
2 2
3/* 3/*
4 * Copyright (c) 1994 4 * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Jan-Simon Pendry.
9 * 5 *
10 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
@@ -15,14 +11,14 @@
15 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 14 * 3. The names of the authors may not be used to endorse or promote
19 * may be used to endorse or promote products derived from this software 15 * products derived from this software without specific prior written
20 * without specific prior written permission. 16 * permission.
21 * 17 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -36,169 +32,165 @@
36 32
37#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) 33#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH)
38 34
39#if defined(LIBC_SCCS) && !defined(lint)
40static char *rcsid = "$OpenBSD: realpath.c,v 1.11 2004/11/30 15:12:59 millert Exp $";
41#endif /* LIBC_SCCS and not lint */
42
43#include <sys/param.h> 35#include <sys/param.h>
44#include <sys/stat.h> 36#include <sys/stat.h>
45 37
46#include <errno.h> 38#include <errno.h>
47#include <fcntl.h>
48#include <stdlib.h> 39#include <stdlib.h>
49#include <string.h> 40#include <string.h>
50#include <unistd.h> 41#include <unistd.h>
51 42
52/* 43/*
53 * MAXSYMLINKS 44 * char *realpath(const char *path, char resolved[PATH_MAX]);
54 */
55#ifndef MAXSYMLINKS
56#define MAXSYMLINKS 5
57#endif
58
59/*
60 * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
61 * 45 *
62 * Find the real name of path, by removing all ".", ".." and symlink 46 * Find the real name of path, by removing all ".", ".." and symlink
63 * components. Returns (resolved) on success, or (NULL) on failure, 47 * components. Returns (resolved) on success, or (NULL) on failure,
64 * in which case the path which caused trouble is left in (resolved). 48 * in which case the path which caused trouble is left in (resolved).
65 */ 49 */
66char * 50char *
67realpath(const char *path, char *resolved) 51realpath(const char *path, char resolved[PATH_MAX])
68{ 52{
69 struct stat sb; 53 struct stat sb;
70 int fd, n, needslash, serrno; 54 char *p, *q, *s;
71 char *p, *q, wbuf[MAXPATHLEN]; 55 size_t left_len, resolved_len;
72 int symlinks = 0; 56 unsigned symlinks;
73 57 int serrno, slen;
74 /* Save the starting point. */ 58 char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
75#ifndef HAVE_FCHDIR 59
76 char start[MAXPATHLEN]; 60 serrno = errno;
77 /* this is potentially racy but without fchdir we have no option */ 61 symlinks = 0;
78 if (getcwd(start, sizeof(start)) == NULL) { 62 if (path[0] == '/') {
79 resolved[0] = '.'; 63 resolved[0] = '/';
80 resolved[1] = '\0'; 64 resolved[1] = '\0';
81 return (NULL); 65 if (path[1] == '\0')
66 return (resolved);
67 resolved_len = 1;
68 left_len = strlcpy(left, path + 1, sizeof(left));
69 } else {
70 if (getcwd(resolved, PATH_MAX) == NULL) {
71 strlcpy(resolved, ".", PATH_MAX);
72 return (NULL);
73 }
74 resolved_len = strlen(resolved);
75 left_len = strlcpy(left, path, sizeof(left));
82 } 76 }
83#endif 77 if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
84 if ((fd = open(".", O_RDONLY)) < 0) { 78 errno = ENAMETOOLONG;
85 resolved[0] = '.';
86 resolved[1] = '\0';
87 return (NULL); 79 return (NULL);
88 } 80 }
89 81
90 /* Convert "." -> "" to optimize away a needless lstat() and chdir() */
91 if (path[0] == '.' && path[1] == '\0')
92 path = "";
93
94 /* 82 /*
95 * Find the dirname and basename from the path to be resolved. 83 * Iterate over path components in `left'.
96 * Change directory to the dirname component.
97 * lstat the basename part.
98 * if it is a symlink, read in the value and loop.
99 * if it is a directory, then change to that directory.
100 * get the current directory name and append the basename.
101 */ 84 */
102 if (strlcpy(resolved, path, MAXPATHLEN) >= MAXPATHLEN) { 85 while (left_len != 0) {
103 serrno = ENAMETOOLONG; 86 /*
104 goto err2; 87 * Extract the next path component and adjust `left'
105 } 88 * and its length.
106loop: 89 */
107 q = strrchr(resolved, '/'); 90 p = strchr(left, '/');
108 if (q != NULL) { 91 s = p ? p : left + left_len;
109 p = q + 1; 92 if (s - left >= sizeof(next_token)) {
110 if (q == resolved) 93 errno = ENAMETOOLONG;
111 q = "/"; 94 return (NULL);
112 else {
113 do {
114 --q;
115 } while (q > resolved && *q == '/');
116 q[1] = '\0';
117 q = resolved;
118 } 95 }
119 if (chdir(q) < 0) 96 memcpy(next_token, left, s - left);
120 goto err1; 97 next_token[s - left] = '\0';
121 } else 98 left_len -= s - left;
122 p = resolved; 99 if (p != NULL)
123 100 memmove(left, s + 1, left_len + 1);
124 /* Deal with the last component. */ 101 if (resolved[resolved_len - 1] != '/') {
125 if (*p != '\0' && lstat(p, &sb) == 0) { 102 if (resolved_len + 1 >= PATH_MAX) {
126 if (S_ISLNK(sb.st_mode)) { 103 errno = ENAMETOOLONG;
127 if (++symlinks > MAXSYMLINKS) { 104 return (NULL);
128 errno = ELOOP;
129 goto err1;
130 } 105 }
131 if ((n = readlink(p, resolved, MAXPATHLEN-1)) < 0) 106 resolved[resolved_len++] = '/';
132 goto err1; 107 resolved[resolved_len] = '\0';
133 resolved[n] = '\0';
134 goto loop;
135 } 108 }
136 if (S_ISDIR(sb.st_mode)) { 109 if (next_token[0] == '\0')
137 if (chdir(p) < 0) 110 continue;
138 goto err1; 111 else if (strcmp(next_token, ".") == 0)
139 p = ""; 112 continue;
113 else if (strcmp(next_token, "..") == 0) {
114 /*
115 * Strip the last path component except when we have
116 * single "/"
117 */
118 if (resolved_len > 1) {
119 resolved[resolved_len - 1] = '\0';
120 q = strrchr(resolved, '/') + 1;
121 *q = '\0';
122 resolved_len = q - resolved;
123 }
124 continue;
140 } 125 }
141 }
142
143 /*
144 * Save the last component name and get the full pathname of
145 * the current directory.
146 */
147 if (strlcpy(wbuf, p, sizeof(wbuf)) >= sizeof(wbuf)) {
148 errno = ENAMETOOLONG;
149 goto err1;
150 }
151 if (getcwd(resolved, MAXPATHLEN) == NULL)
152 goto err1;
153
154 /*
155 * Join the two strings together, ensuring that the right thing
156 * happens if the last component is empty, or the dirname is root.
157 */
158 if (resolved[0] == '/' && resolved[1] == '\0')
159 needslash = 0;
160 else
161 needslash = 1;
162 126
163 if (*wbuf) { 127 /*
164 if (strlen(resolved) + strlen(wbuf) + needslash >= MAXPATHLEN) { 128 * Append the next path component and lstat() it. If
129 * lstat() fails we still can return successfully if
130 * there are no more path components left.
131 */
132 resolved_len = strlcat(resolved, next_token, PATH_MAX);
133 if (resolved_len >= PATH_MAX) {
165 errno = ENAMETOOLONG; 134 errno = ENAMETOOLONG;
166 goto err1; 135 return (NULL);
167 } 136 }
168 if (needslash) { 137 if (lstat(resolved, &sb) != 0) {
169 if (strlcat(resolved, "/", MAXPATHLEN) >= MAXPATHLEN) { 138 if (errno == ENOENT && p == NULL) {
170 errno = ENAMETOOLONG; 139 errno = serrno;
171 goto err1; 140 return (resolved);
172 } 141 }
142 return (NULL);
173 } 143 }
174 if (strlcat(resolved, wbuf, MAXPATHLEN) >= MAXPATHLEN) { 144 if (S_ISLNK(sb.st_mode)) {
175 errno = ENAMETOOLONG; 145 if (symlinks++ > MAXSYMLINKS) {
176 goto err1; 146 errno = ELOOP;
177 } 147 return (NULL);
178 } 148 }
149 slen = readlink(resolved, symlink, sizeof(symlink) - 1);
150 if (slen < 0)
151 return (NULL);
152 symlink[slen] = '\0';
153 if (symlink[0] == '/') {
154 resolved[1] = 0;
155 resolved_len = 1;
156 } else if (resolved_len > 1) {
157 /* Strip the last path component. */
158 resolved[resolved_len - 1] = '\0';
159 q = strrchr(resolved, '/') + 1;
160 *q = '\0';
161 resolved_len = q - resolved;
162 }
179 163
180 /* Go back to where we came from. */ 164 /*
181#ifdef HAVE_FCHDIR 165 * If there are any path components left, then
182 if (fchdir(fd) < 0) { 166 * append them to symlink. The result is placed
183#else 167 * in `left'.
184 if (chdir(start) < 0) { 168 */
185#endif 169 if (p != NULL) {
186 serrno = errno; 170 if (symlink[slen - 1] != '/') {
187 goto err2; 171 if (slen + 1 >= sizeof(symlink)) {
172 errno = ENAMETOOLONG;
173 return (NULL);
174 }
175 symlink[slen] = '/';
176 symlink[slen + 1] = 0;
177 }
178 left_len = strlcat(symlink, left, sizeof(left));
179 if (left_len >= sizeof(left)) {
180 errno = ENAMETOOLONG;
181 return (NULL);
182 }
183 }
184 left_len = strlcpy(left, symlink, sizeof(left));
185 }
188 } 186 }
189 187
190 /* It's okay if the close fails, what's an fd more or less? */ 188 /*
191 (void)close(fd); 189 * Remove trailing slash except when the resolved pathname
190 * is a single "/".
191 */
192 if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
193 resolved[resolved_len - 1] = '\0';
192 return (resolved); 194 return (resolved);
193
194err1: serrno = errno;
195#ifdef HAVE_FCHDIR
196 (void)fchdir(fd);
197#else
198 chdir(start);
199#endif
200err2: (void)close(fd);
201 errno = serrno;
202 return (NULL);
203} 195}
204#endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */ 196#endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */