File vsftpd-path-normalize.patch of Package vsftpd.546

Index: vsftpd-3.0.2/str.c
===================================================================
--- vsftpd-3.0.2.orig/str.c
+++ vsftpd-3.0.2/str.c
@@ -16,6 +16,12 @@
 #define PRIVATE_HANDS_OFF_alloc_bytes alloc_bytes
 #include "str.h"
 
+/* normalize filepath */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <libgen.h>
+
 /* Ick. Its for die() */
 #include "utility.h"
 #include "sysutil.h"
@@ -781,3 +787,60 @@ str_basename (struct mystr* d_str, const
   if (str_isempty(d_str))
    str_copy (d_str, path);
 }
+
+void
+str_normalize_filepath(struct mystr* filepath)
+{
+    char *path;
+    char *normdir;
+    char *dir;
+    char *filename;
+    static struct mystr tmp;
+
+    /* normalize filepath */
+    path = str_strdup(filepath);
+    if (path == NULL)
+    {
+        return;
+    }
+    char *ch1 = strdup(path);
+    char *ch2 = strdup(path);
+    if (ch1 == NULL || ch2 == NULL)
+    {
+        goto out;
+    }
+    /* we split dir/file as realpath /home/REGEXP is NULL so we need dir
+     * dir only to function correctly, later on we need to glue back the
+     * file if there is some
+     */
+    dir = dirname(ch1);
+    filename = basename(ch2);
+    normdir = realpath(dir, NULL);
+    if (normdir == NULL)
+    {
+        goto out;
+    }
+    str_alloc_text(&tmp, normdir);
+    unsigned int len = str_getlen(&tmp);
+    if (str_get_char_at(&tmp, len - 1) != '/')
+    {
+        str_append_char(&tmp, '/');
+    }
+    /* / is special it ends in both dirname and basename so ignore it here */
+    if (strcmp(filename, "/") != 0)
+    {
+        str_append_text(&tmp, filename);
+    }
+    /* TODO: here we should run one more stat to determine if the whole thing
+     * is a directory and append trailing / (ie. /home -> /home/).
+     * This will make the deny_file=/home/<REGEXP> work contrary to currently
+     * needed /home<REGEXP>.
+     */
+    str_copy(filepath, &tmp);
+    free(normdir);
+    str_free(&tmp);
+out:
+    free(path);
+    free(ch1);
+    free(ch2);
+}
Index: vsftpd-3.0.2/str.h
===================================================================
--- vsftpd-3.0.2.orig/str.h
+++ vsftpd-3.0.2/str.h
@@ -102,6 +102,7 @@ int str_atoi(const struct mystr* p_str);
 filesize_t str_a_to_filesize_t(const struct mystr* p_str);
 unsigned int str_octal_to_uint(const struct mystr* p_str);
 void str_basename (struct mystr* d_str, const struct mystr* path);
+void str_normalize_filepath(struct mystr* filepath);
 
 /* PURPOSE: Extract a line of text (delimited by \n or EOF) from a string
  * buffer, starting at character position 'p_pos'. The extracted line will
Index: vsftpd-3.0.2/ls.c
===================================================================
--- vsftpd-3.0.2.orig/ls.c
+++ vsftpd-3.0.2/ls.c
@@ -117,11 +117,13 @@ vsf_ls_populate_dir_list(struct mystr_li
     {
       continue;
     }
+    str_copy(&s_next_path_and_filename_str, &normalised_base_dir_str);
+    str_append_str(&s_next_path_and_filename_str, &s_next_filename_str);
     /* If we have an ls option which is a filter, apply it */
     if (!str_isempty(p_filter_str))
     {
       unsigned int iters = 0;
-      if (!vsf_filename_passes_filter(&s_next_filename_str, p_filter_str,
+      if (!vsf_filename_passes_filter(&s_next_path_and_filename_str, p_filter_str,
                                       &iters))
       {
         continue;
@@ -130,8 +132,6 @@ vsf_ls_populate_dir_list(struct mystr_li
     /* Calculate the full path (relative to CWD) for lstat() and
      * output purposes
      */
-    str_copy(&s_next_path_and_filename_str, &normalised_base_dir_str);
-    str_append_str(&s_next_path_and_filename_str, &s_next_filename_str);
     if (do_stat)
     {
       /* lstat() the file. Of course there's a race condition - the
@@ -239,6 +239,7 @@ vsf_filename_passes_filter(const struct
    * for /a/?/c will not.
    */
   struct mystr filter_remain_str = INIT_MYSTR;
+  struct mystr basic_name_str = INIT_MYSTR;
   struct mystr name_remain_str = INIT_MYSTR;
   struct mystr temp_str = INIT_MYSTR;
   struct mystr brace_list_str = INIT_MYSTR;
@@ -249,27 +250,29 @@ vsf_filename_passes_filter(const struct
   int matched = 0;
   
   str_copy(&filter_remain_str, p_filter_str);
+  str_copy(&basic_name_str, p_filename_str);
+  str_normalize_filepath(&basic_name_str);
   
-  if (!str_isempty (&filter_remain_str) && !str_isempty(p_filename_str)) {
+  if (!str_isempty (&filter_remain_str) && !str_isempty(&basic_name_str)) {
     if (str_get_char_at(p_filter_str, 0) == '/') {
-      if (str_get_char_at(p_filename_str, 0) != '/') {
+      if (str_get_char_at(&basic_name_str, 0) != '/') {
         str_getcwd (&name_remain_str);
      
         if (str_getlen(&name_remain_str) > 1) /* cwd != root dir */
           str_append_char (&name_remain_str, '/');
           
-        str_append_str (&name_remain_str, p_filename_str);
+        str_append_str (&name_remain_str, &basic_name_str);
       }
       else
-       str_copy (&name_remain_str, p_filename_str);
+       str_copy (&name_remain_str, &basic_name_str);
     } else {
       if (str_get_char_at(p_filter_str, 0) != '{')
-        str_basename (&name_remain_str, p_filename_str);
+        str_basename (&name_remain_str, &basic_name_str);
       else
-        str_copy (&name_remain_str, p_filename_str);
+        str_copy (&name_remain_str, &basic_name_str);
     }
   } else
-    str_copy(&name_remain_str, p_filename_str);
+    str_copy(&name_remain_str, &basic_name_str);
   
   while (!str_isempty(&filter_remain_str) && *iters < VSFTP_MATCHITERS_MAX)
   {
openSUSE Build Service is sponsored by