components/proftpd/patches/17599705.patch
branchs11-update
changeset 3224 589e0e82672d
parent 3216 d8137835c0b4
child 3225 7bbaa2f97cd1
equal deleted inserted replaced
3216:d8137835c0b4 3224:589e0e82672d
     1 http://bugs.proftpd.org/show_bug.cgi?id=4011
       
     2 
       
     3 diff --git a/include/fsio.h b/include/fsio.h
       
     4 index 07c18c1..a4c395e 100644
       
     5 --- a/include/fsio.h
       
     6 +++ b/include/fsio.h
       
     7 @@ -189,6 +189,9 @@ struct fh_rec {
       
     8    size_t fh_iosz;
       
     9  };
       
    10  
       
    11 +/* Maximum symlink count, for loop detection. */
       
    12 +#define PR_FSIO_MAX_LINK_COUNT         32
       
    13 +
       
    14  /* Macros for that code that needs to get into the internals of pr_fs_t.
       
    15   * (These will help keep the internals as opaque as possible).
       
    16   */
       
    17 @@ -319,7 +322,11 @@ char *pr_fs_encode_path(pool *, const char *);
       
    18  int pr_fs_use_encoding(int bool);
       
    19  int pr_fs_valid_path(const char *);
       
    20  void pr_fs_virtual_path(const char *, char *, size_t);
       
    21 +
       
    22  void pr_fs_clean_path(const char *, char *, size_t);
       
    23 +int pr_fs_clean_path2(const char *, char *, size_t, int);
       
    24 +#define PR_FSIO_CLEAN_PATH_FL_MAKE_ABS_PATH    0x001
       
    25 +
       
    26  int pr_fs_glob(const char *, int, int (*errfunc)(const char *, int), glob_t *);
       
    27  void pr_fs_globfree(glob_t *);
       
    28  void pr_resolve_fs_map(void);
       
    29 diff --git a/modules/mod_ls.c b/modules/mod_ls.c
       
    30 index 50e8035..58e81d7 100644
       
    31 --- a/modules/mod_ls.c
       
    32 +++ b/modules/mod_ls.c
       
    33 @@ -2571,46 +2571,6 @@ MODRET ls_nlst(cmd_rec *cmd) {
       
    34      }
       
    35    }
       
    36  
       
    37 -  /* Clean the path. */
       
    38 -  if (*target != '/') {
       
    39 -    size_t cwdlen = strlen(pr_fs_getcwd());
       
    40 -
       
    41 -    pr_fs_clean_path(pdircat(cmd->tmp_pool, pr_fs_getcwd(), target, NULL),
       
    42 -      buf, sizeof(buf));
       
    43 -
       
    44 -    target = buf;
       
    45 -
       
    46 -    /* If the given target was not an absolute path, advance past the
       
    47 -     * current working directory prefix in the cleaned up target path.
       
    48 -     */
       
    49 -    target += cwdlen;
       
    50 -
       
    51 -    /* If the length of the current working directory (cwdlen) is one,
       
    52 -     * it means that the current working directory is the root ('/'),
       
    53 -     * and so we don't want to advance past that into the file name
       
    54 -     * portion of the path.
       
    55 -     */
       
    56 -    if (cwdlen > 1)
       
    57 -      target += 1;
       
    58 -
       
    59 -  } else {
       
    60 -    pr_fs_clean_path(target, buf, sizeof(buf));
       
    61 -    target = buf;
       
    62 -  }
       
    63 -
       
    64 -  /* Remove any trailing separators. */
       
    65 -  targetlen = strlen(target);
       
    66 -  while (targetlen >= 1 &&
       
    67 -         target[targetlen-1] == '/') {
       
    68 -
       
    69 -    if (strcmp(target, "/") == 0) {
       
    70 -      break;
       
    71 -    }
       
    72 -
       
    73 -    target[targetlen-1] = '\0';
       
    74 -    targetlen = strlen(target);
       
    75 -  }
       
    76 -
       
    77    /* If the target is a glob, get the listing of files/dirs to send. */
       
    78    if (use_globbing &&
       
    79        pr_str_is_fnmatch(target)) {
       
    80 @@ -2715,12 +2675,36 @@ MODRET ls_nlst(cmd_rec *cmd) {
       
    81      }
       
    82  
       
    83    } else {
       
    84 -
       
    85      /* A single target. If it's a directory, list the contents; if it's a
       
    86       * file, just list the file.
       
    87       */
       
    88      struct stat st;
       
    89  
       
    90 +    if (!is_dotdir(target)) {
       
    91 +      /* Clean the path. */
       
    92 +      if (*target != '/') {
       
    93 +        pr_fs_clean_path2(target, buf, sizeof(buf), 0);
       
    94 +
       
    95 +      } else {
       
    96 +        pr_fs_clean_path(target, buf, sizeof(buf));
       
    97 +      }
       
    98 +
       
    99 +      target = buf;
       
   100 +
       
   101 +    } else {
       
   102 +      /* Remove any trailing separators. */
       
   103 +      targetlen = strlen(target);
       
   104 +      while (targetlen >= 1 &&
       
   105 +             target[targetlen-1] == '/') {
       
   106 +        if (strncmp(target, "/", 2) == 0) {
       
   107 +          break;
       
   108 +        }
       
   109 +
       
   110 +        target[targetlen-1] = '\0';
       
   111 +        targetlen = strlen(target);
       
   112 +      }
       
   113 +    }
       
   114 +
       
   115      if (!ls_perms_full(cmd->tmp_pool, cmd, target, &hidden)) {
       
   116        int xerrno = errno;
       
   117  
       
   118 diff --git a/src/fsio.c b/src/fsio.c
       
   119 index 782168d..4d191fe 100644
       
   120 --- a/src/fsio.c
       
   121 +++ b/src/fsio.c
       
   122 @@ -1627,8 +1627,8 @@ int pr_fs_resolve_partial(const char *path, char *buf, size_t buflen, int op) {
       
   123  
       
   124    pr_fs_t *fs = NULL;
       
   125    int len = 0, fini = 1, link_cnt = 0;
       
   126 -  ino_t last_inode = 0;
       
   127 -  dev_t last_device = 0;
       
   128 +  ino_t prev_inode = 0;
       
   129 +  dev_t prev_device = 0;
       
   130    struct stat sbuf;
       
   131  
       
   132    if (!path) {
       
   133 @@ -1740,16 +1740,16 @@ int pr_fs_resolve_partial(const char *path, char *buf, size_t buflen, int op) {
       
   134          char linkpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
       
   135  
       
   136          /* Detect an obvious recursive symlink */
       
   137 -        if (sbuf.st_ino && (ino_t) sbuf.st_ino == last_inode &&
       
   138 -            sbuf.st_dev && (dev_t) sbuf.st_dev == last_device) {
       
   139 +        if (sbuf.st_ino && (ino_t) sbuf.st_ino == prev_inode &&
       
   140 +            sbuf.st_dev && (dev_t) sbuf.st_dev == prev_device) {
       
   141            errno = ELOOP;
       
   142            return -1;
       
   143          }
       
   144  
       
   145 -        last_inode = (ino_t) sbuf.st_ino;
       
   146 -        last_device = (dev_t) sbuf.st_dev;
       
   147 +        prev_inode = (ino_t) sbuf.st_ino;
       
   148 +        prev_device = (dev_t) sbuf.st_dev;
       
   149  
       
   150 -        if (++link_cnt > 32) {
       
   151 +        if (++link_cnt > PR_FSIO_MAX_LINK_COUNT) {
       
   152            errno = ELOOP;
       
   153            return -1;
       
   154          }
       
   155 @@ -1820,8 +1820,8 @@ int pr_fs_resolve_path(const char *path, char *buf, size_t buflen, int op) {
       
   156    pr_fs_t *fs = NULL;
       
   157  
       
   158    int len = 0, fini = 1, link_cnt = 0;
       
   159 -  ino_t last_inode = 0;
       
   160 -  dev_t last_device = 0;
       
   161 +  ino_t prev_inode = 0;
       
   162 +  dev_t prev_device = 0;
       
   163    struct stat sbuf;
       
   164  
       
   165    if (!path) {
       
   166 @@ -1906,16 +1906,16 @@ int pr_fs_resolve_path(const char *path, char *buf, size_t buflen, int op) {
       
   167          char linkpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
       
   168  
       
   169          /* Detect an obvious recursive symlink */
       
   170 -        if (sbuf.st_ino && (ino_t) sbuf.st_ino == last_inode &&
       
   171 -            sbuf.st_dev && (dev_t) sbuf.st_dev == last_device) {
       
   172 +        if (sbuf.st_ino && (ino_t) sbuf.st_ino == prev_inode &&
       
   173 +            sbuf.st_dev && (dev_t) sbuf.st_dev == prev_device) {
       
   174            errno = ELOOP;
       
   175            return -1;
       
   176          }
       
   177  
       
   178 -        last_inode = (ino_t) sbuf.st_ino;
       
   179 -        last_device = (dev_t) sbuf.st_dev;
       
   180 +        prev_inode = (ino_t) sbuf.st_ino;
       
   181 +        prev_device = (dev_t) sbuf.st_dev;
       
   182  
       
   183 -        if (++link_cnt > 32) {
       
   184 +        if (++link_cnt > PR_FSIO_MAX_LINK_COUNT) {
       
   185            errno = ELOOP;
       
   186            return -1;
       
   187          }
       
   188 @@ -1977,22 +1977,33 @@ int pr_fs_resolve_path(const char *path, char *buf, size_t buflen, int op) {
       
   189    return 0;
       
   190  }
       
   191  
       
   192 -void pr_fs_clean_path(const char *path, char *buf, size_t buflen) {
       
   193 +int pr_fs_clean_path2(const char *path, char *buf, size_t buflen, int flags) {
       
   194    char workpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
       
   195    char curpath[PR_TUNABLE_PATH_MAX + 1]  = {'\0'};
       
   196    char namebuf[PR_TUNABLE_PATH_MAX + 1]  = {'\0'};
       
   197 -  char *where = NULL, *ptr = NULL, *last = NULL;
       
   198 -  int fini = 1;
       
   199 +  int fini = 1, have_abs_path = FALSE; 
       
   200  
       
   201 -  if (!path)
       
   202 -    return;
       
   203 +  if (path == NULL ||
       
   204 +      buf == NULL) {
       
   205 +    errno = EINVAL;
       
   206 +    return -1;
       
   207 +  }
       
   208 +
       
   209 +  if (buflen == 0) {
       
   210 +    return 0;
       
   211 +  }
       
   212  
       
   213    sstrncpy(curpath, path, sizeof(curpath));
       
   214  
       
   215 +  if (*curpath == '/') {
       
   216 +    have_abs_path = TRUE;
       
   217 +  }
       
   218 +
       
   219    /* main loop */
       
   220    while (fini--) {
       
   221 -    where = curpath;
       
   222 +    char *where = NULL, *ptr = NULL, *last = NULL;
       
   223  
       
   224 +    where = curpath;
       
   225      while (*where != '\0') {
       
   226        pr_signals_handle();
       
   227  
       
   228 @@ -2013,8 +2024,12 @@ void pr_fs_clean_path(const char *path, char *buf, size_t buflen) {
       
   229          ptr = last = workpath;
       
   230  
       
   231          while (*ptr) {
       
   232 -          if (*ptr == '/')
       
   233 +          pr_signals_handle();
       
   234 +
       
   235 +          if (*ptr == '/') {
       
   236              last = ptr;
       
   237 +          }
       
   238 +
       
   239            ptr++;
       
   240          }
       
   241  
       
   242 @@ -2028,34 +2043,46 @@ void pr_fs_clean_path(const char *path, char *buf, size_t buflen) {
       
   243          ptr = last = workpath;
       
   244  
       
   245          while (*ptr) {
       
   246 -          if (*ptr == '/')
       
   247 +          pr_signals_handle();
       
   248 +
       
   249 +          if (*ptr == '/') {
       
   250              last = ptr;
       
   251 +          }
       
   252            ptr++;
       
   253          }
       
   254 +
       
   255          *last = '\0';
       
   256          continue;
       
   257        }
       
   258 -      ptr = strchr(where, '/');
       
   259  
       
   260 -      if (!ptr) {
       
   261 +      ptr = strchr(where, '/');
       
   262 +      if (ptr == NULL) {
       
   263          size_t wherelen = strlen(where);
       
   264  
       
   265          ptr = where;
       
   266 -        if (wherelen >= 1)
       
   267 +        if (wherelen >= 1) {
       
   268            ptr += (wherelen - 1);
       
   269 +        }
       
   270  
       
   271 -      } else
       
   272 +      } else {
       
   273          *ptr = '\0';
       
   274 +      }
       
   275  
       
   276        sstrncpy(namebuf, workpath, sizeof(namebuf));
       
   277  
       
   278        if (*namebuf) {
       
   279          for (last = namebuf; *last; last++);
       
   280 -        if (*--last != '/')
       
   281 +        if (*--last != '/') {
       
   282            sstrcat(namebuf, "/", sizeof(namebuf)-1);
       
   283 +        }
       
   284  
       
   285 -      } else
       
   286 -        sstrcat(namebuf, "/", sizeof(namebuf)-1);
       
   287 +      } else {
       
   288 +        if (have_abs_path ||
       
   289 +            (flags & PR_FSIO_CLEAN_PATH_FL_MAKE_ABS_PATH)) {
       
   290 +          sstrcat(namebuf, "/", sizeof(namebuf)-1);
       
   291 +          have_abs_path = FALSE;
       
   292 +        }
       
   293 +      }
       
   294  
       
   295        sstrcat(namebuf, where, sizeof(namebuf)-1);
       
   296        namebuf[sizeof(namebuf)-1] = '\0';
       
   297 @@ -2066,10 +2093,16 @@ void pr_fs_clean_path(const char *path, char *buf, size_t buflen) {
       
   298      }
       
   299    }
       
   300  
       
   301 -  if (!workpath[0])
       
   302 +  if (!workpath[0]) {
       
   303      sstrncpy(workpath, "/", sizeof(workpath));
       
   304 +  }
       
   305  
       
   306    sstrncpy(buf, workpath, buflen);
       
   307 +  return 0;
       
   308 +}
       
   309 +
       
   310 +void pr_fs_clean_path(const char *path, char *buf, size_t buflen) {
       
   311 +  pr_fs_clean_path2(path, buf, buflen, PR_FSIO_CLEAN_PATH_FL_MAKE_ABS_PATH);
       
   312  }
       
   313  
       
   314  int pr_fs_use_encoding(int bool) {
       
   315