15825705 SUNBT7206929 all of the ftp test cases with "-f" are timeouted in krb5_r_apps
17599705 proftpd NLST ../ returns ./
http://bugs.proftpd.org/show_bug.cgi?id=4011
diff --git a/include/fsio.h b/include/fsio.h
index 07c18c1..a4c395e 100644
--- a/include/fsio.h
+++ b/include/fsio.h
@@ -189,6 +189,9 @@ struct fh_rec {
size_t fh_iosz;
};
+/* Maximum symlink count, for loop detection. */
+#define PR_FSIO_MAX_LINK_COUNT 32
+
/* Macros for that code that needs to get into the internals of pr_fs_t.
* (These will help keep the internals as opaque as possible).
*/
@@ -319,7 +322,11 @@ char *pr_fs_encode_path(pool *, const char *);
int pr_fs_use_encoding(int bool);
int pr_fs_valid_path(const char *);
void pr_fs_virtual_path(const char *, char *, size_t);
+
void pr_fs_clean_path(const char *, char *, size_t);
+int pr_fs_clean_path2(const char *, char *, size_t, int);
+#define PR_FSIO_CLEAN_PATH_FL_MAKE_ABS_PATH 0x001
+
int pr_fs_glob(const char *, int, int (*errfunc)(const char *, int), glob_t *);
void pr_fs_globfree(glob_t *);
void pr_resolve_fs_map(void);
diff --git a/modules/mod_ls.c b/modules/mod_ls.c
index 50e8035..58e81d7 100644
--- a/modules/mod_ls.c
+++ b/modules/mod_ls.c
@@ -2571,46 +2571,6 @@ MODRET ls_nlst(cmd_rec *cmd) {
}
}
- /* Clean the path. */
- if (*target != '/') {
- size_t cwdlen = strlen(pr_fs_getcwd());
-
- pr_fs_clean_path(pdircat(cmd->tmp_pool, pr_fs_getcwd(), target, NULL),
- buf, sizeof(buf));
-
- target = buf;
-
- /* If the given target was not an absolute path, advance past the
- * current working directory prefix in the cleaned up target path.
- */
- target += cwdlen;
-
- /* If the length of the current working directory (cwdlen) is one,
- * it means that the current working directory is the root ('/'),
- * and so we don't want to advance past that into the file name
- * portion of the path.
- */
- if (cwdlen > 1)
- target += 1;
-
- } else {
- pr_fs_clean_path(target, buf, sizeof(buf));
- target = buf;
- }
-
- /* Remove any trailing separators. */
- targetlen = strlen(target);
- while (targetlen >= 1 &&
- target[targetlen-1] == '/') {
-
- if (strcmp(target, "/") == 0) {
- break;
- }
-
- target[targetlen-1] = '\0';
- targetlen = strlen(target);
- }
-
/* If the target is a glob, get the listing of files/dirs to send. */
if (use_globbing &&
pr_str_is_fnmatch(target)) {
@@ -2715,12 +2675,36 @@ MODRET ls_nlst(cmd_rec *cmd) {
}
} else {
-
/* A single target. If it's a directory, list the contents; if it's a
* file, just list the file.
*/
struct stat st;
+ if (!is_dotdir(target)) {
+ /* Clean the path. */
+ if (*target != '/') {
+ pr_fs_clean_path2(target, buf, sizeof(buf), 0);
+
+ } else {
+ pr_fs_clean_path(target, buf, sizeof(buf));
+ }
+
+ target = buf;
+
+ } else {
+ /* Remove any trailing separators. */
+ targetlen = strlen(target);
+ while (targetlen >= 1 &&
+ target[targetlen-1] == '/') {
+ if (strncmp(target, "/", 2) == 0) {
+ break;
+ }
+
+ target[targetlen-1] = '\0';
+ targetlen = strlen(target);
+ }
+ }
+
if (!ls_perms_full(cmd->tmp_pool, cmd, target, &hidden)) {
int xerrno = errno;
diff --git a/src/fsio.c b/src/fsio.c
index 782168d..4d191fe 100644
--- a/src/fsio.c
+++ b/src/fsio.c
@@ -1627,8 +1627,8 @@ int pr_fs_resolve_partial(const char *path, char *buf, size_t buflen, int op) {
pr_fs_t *fs = NULL;
int len = 0, fini = 1, link_cnt = 0;
- ino_t last_inode = 0;
- dev_t last_device = 0;
+ ino_t prev_inode = 0;
+ dev_t prev_device = 0;
struct stat sbuf;
if (!path) {
@@ -1740,16 +1740,16 @@ int pr_fs_resolve_partial(const char *path, char *buf, size_t buflen, int op) {
char linkpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
/* Detect an obvious recursive symlink */
- if (sbuf.st_ino && (ino_t) sbuf.st_ino == last_inode &&
- sbuf.st_dev && (dev_t) sbuf.st_dev == last_device) {
+ if (sbuf.st_ino && (ino_t) sbuf.st_ino == prev_inode &&
+ sbuf.st_dev && (dev_t) sbuf.st_dev == prev_device) {
errno = ELOOP;
return -1;
}
- last_inode = (ino_t) sbuf.st_ino;
- last_device = (dev_t) sbuf.st_dev;
+ prev_inode = (ino_t) sbuf.st_ino;
+ prev_device = (dev_t) sbuf.st_dev;
- if (++link_cnt > 32) {
+ if (++link_cnt > PR_FSIO_MAX_LINK_COUNT) {
errno = ELOOP;
return -1;
}
@@ -1820,8 +1820,8 @@ int pr_fs_resolve_path(const char *path, char *buf, size_t buflen, int op) {
pr_fs_t *fs = NULL;
int len = 0, fini = 1, link_cnt = 0;
- ino_t last_inode = 0;
- dev_t last_device = 0;
+ ino_t prev_inode = 0;
+ dev_t prev_device = 0;
struct stat sbuf;
if (!path) {
@@ -1906,16 +1906,16 @@ int pr_fs_resolve_path(const char *path, char *buf, size_t buflen, int op) {
char linkpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
/* Detect an obvious recursive symlink */
- if (sbuf.st_ino && (ino_t) sbuf.st_ino == last_inode &&
- sbuf.st_dev && (dev_t) sbuf.st_dev == last_device) {
+ if (sbuf.st_ino && (ino_t) sbuf.st_ino == prev_inode &&
+ sbuf.st_dev && (dev_t) sbuf.st_dev == prev_device) {
errno = ELOOP;
return -1;
}
- last_inode = (ino_t) sbuf.st_ino;
- last_device = (dev_t) sbuf.st_dev;
+ prev_inode = (ino_t) sbuf.st_ino;
+ prev_device = (dev_t) sbuf.st_dev;
- if (++link_cnt > 32) {
+ if (++link_cnt > PR_FSIO_MAX_LINK_COUNT) {
errno = ELOOP;
return -1;
}
@@ -1977,22 +1977,33 @@ int pr_fs_resolve_path(const char *path, char *buf, size_t buflen, int op) {
return 0;
}
-void pr_fs_clean_path(const char *path, char *buf, size_t buflen) {
+int pr_fs_clean_path2(const char *path, char *buf, size_t buflen, int flags) {
char workpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
char curpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
char namebuf[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
- char *where = NULL, *ptr = NULL, *last = NULL;
- int fini = 1;
+ int fini = 1, have_abs_path = FALSE;
- if (!path)
- return;
+ if (path == NULL ||
+ buf == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (buflen == 0) {
+ return 0;
+ }
sstrncpy(curpath, path, sizeof(curpath));
+ if (*curpath == '/') {
+ have_abs_path = TRUE;
+ }
+
/* main loop */
while (fini--) {
- where = curpath;
+ char *where = NULL, *ptr = NULL, *last = NULL;
+ where = curpath;
while (*where != '\0') {
pr_signals_handle();
@@ -2013,8 +2024,12 @@ void pr_fs_clean_path(const char *path, char *buf, size_t buflen) {
ptr = last = workpath;
while (*ptr) {
- if (*ptr == '/')
+ pr_signals_handle();
+
+ if (*ptr == '/') {
last = ptr;
+ }
+
ptr++;
}
@@ -2028,34 +2043,46 @@ void pr_fs_clean_path(const char *path, char *buf, size_t buflen) {
ptr = last = workpath;
while (*ptr) {
- if (*ptr == '/')
+ pr_signals_handle();
+
+ if (*ptr == '/') {
last = ptr;
+ }
ptr++;
}
+
*last = '\0';
continue;
}
- ptr = strchr(where, '/');
- if (!ptr) {
+ ptr = strchr(where, '/');
+ if (ptr == NULL) {
size_t wherelen = strlen(where);
ptr = where;
- if (wherelen >= 1)
+ if (wherelen >= 1) {
ptr += (wherelen - 1);
+ }
- } else
+ } else {
*ptr = '\0';
+ }
sstrncpy(namebuf, workpath, sizeof(namebuf));
if (*namebuf) {
for (last = namebuf; *last; last++);
- if (*--last != '/')
+ if (*--last != '/') {
sstrcat(namebuf, "/", sizeof(namebuf)-1);
+ }
- } else
- sstrcat(namebuf, "/", sizeof(namebuf)-1);
+ } else {
+ if (have_abs_path ||
+ (flags & PR_FSIO_CLEAN_PATH_FL_MAKE_ABS_PATH)) {
+ sstrcat(namebuf, "/", sizeof(namebuf)-1);
+ have_abs_path = FALSE;
+ }
+ }
sstrcat(namebuf, where, sizeof(namebuf)-1);
namebuf[sizeof(namebuf)-1] = '\0';
@@ -2066,10 +2093,16 @@ void pr_fs_clean_path(const char *path, char *buf, size_t buflen) {
}
}
- if (!workpath[0])
+ if (!workpath[0]) {
sstrncpy(workpath, "/", sizeof(workpath));
+ }
sstrncpy(buf, workpath, buflen);
+ return 0;
+}
+
+void pr_fs_clean_path(const char *path, char *buf, size_t buflen) {
+ pr_fs_clean_path2(path, buf, buflen, PR_FSIO_CLEAN_PATH_FL_MAKE_ABS_PATH);
}
int pr_fs_use_encoding(int bool) {