components/proftpd/patches/17599705.patch
author Tomas Klacko <tomas.klacko@oracle.com>
Tue, 25 Feb 2014 02:29:07 -0800
branchs11-update
changeset 2966 93b92606f5e1
permissions -rw-r--r--
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) {