17599705 proftpd NLST ../ returns ./
authorTomas Klacko <tomas.klacko@oracle.com>
Wed, 22 Jan 2014 05:24:38 -0800
changeset 1653 4cb88404a32d
parent 1652 eedad834c07d
child 1654 6f9989ec7bd5
17599705 proftpd NLST ../ returns ./
components/proftpd/patches/17599705.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/proftpd/patches/17599705.patch	Wed Jan 22 05:24:38 2014 -0800
@@ -0,0 +1,315 @@
+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
[email protected]@ -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).
+  */
[email protected]@ -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
[email protected]@ -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)) {
[email protected]@ -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
[email protected]@ -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) {
[email protected]@ -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;
+         }
[email protected]@ -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) {
[email protected]@ -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;
+         }
[email protected]@ -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();
+ 
[email protected]@ -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++;
+         }
+ 
[email protected]@ -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';
[email protected]@ -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) {
+