Hello community, here is the log from the commit of package vsftpd for openSUSE:Factory checked in at 2015-04-07 09:28:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/vsftpd (Old) and /work/SRC/openSUSE:Factory/.vsftpd.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "vsftpd" Changes: -------- --- /work/SRC/openSUSE:Factory/vsftpd/vsftpd.changes 2015-02-27 11:03:47.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.vsftpd.new/vsftpd.changes 2015-04-07 09:28:56.000000000 +0200 @@ -1,0 +2,38 @@ +Sun Apr 5 10:25:50 UTC 2015 - tchva...@suse.com + +- bnc#925963 stat is sometimes run on wrong path and results with + ENOENT, ensure we sent both dir+file to filter verification: + * vsftpd-path-normalize.patch + +------------------------------------------------------------------- +Wed Mar 25 10:08:03 UTC 2015 - tchva...@suse.com + +- Update patch bit more for sanity checks. Done by rsa...@suse.de: + * vsftpd-path-normalize.patch + +------------------------------------------------------------------- +Mon Mar 23 20:13:51 UTC 2015 - tchva...@suse.com + +- Add back patch attempting to fix bnc#900326 bnc#915522 and + bnc#922538: + * vsftpd-path-normalize.patch + +------------------------------------------------------------------- +Mon Mar 23 20:08:19 UTC 2015 - tchva...@suse.com + +- Reset filter patch to match fedora, my work will be restarted + in one-off patch to make the changes stand out. Add rest of + RH filtering patches: + * vsftpd-2.2.0-wildchar.patch + * vsftpd-2.3.4-sqb.patch + * vsftpd-2.1.0-filter.patch + +------------------------------------------------------------------- +Mon Mar 23 19:56:11 UTC 2015 - tchva...@suse.com + +- Work on the filter patch and split out the normalisation of the + path to separate str function, currently commented out so I + avoid huge diffing. + * vsftpd-2.1.0-filter.patch + +------------------------------------------------------------------- New: ---- vsftpd-2.2.0-wildchar.patch vsftpd-2.3.4-sqb.patch vsftpd-path-normalize.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ vsftpd.spec ++++++ --- /var/tmp/diff_new_pack.YZCLsy/_old 2015-04-07 09:28:57.000000000 +0200 +++ /var/tmp/diff_new_pack.YZCLsy/_new 2015-04-07 09:28:57.000000000 +0200 @@ -58,8 +58,11 @@ Patch17: vsftpd-enable-gettimeofday-sec.patch #PATCH-FIX-UPSTREAM: bnc#890469 fix broken syscall on s390 Patch18: vsftpd-3.0.2-s390.patch -#PATCH-FIX-UPSTREAM: bnc#900326 deny_file filtering acts weirdly +#PATCH-FIX-UPSTREAM: bnc#900326 deny_file filtering acts weirdly (19-22) Patch19: vsftpd-2.1.0-filter.patch +Patch20: vsftpd-2.2.0-wildchar.patch +Patch21: vsftpd-2.3.4-sqb.patch +Patch22: vsftpd-path-normalize.patch BuildRequires: libcap-devel BuildRequires: openssl-devel BuildRequires: pam-devel @@ -101,6 +104,9 @@ %patch17 -p1 %patch18 -p1 %patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 %build %define seccomp_opts -D_GNU_SOURCE -DUSE_SECCOMP ++++++ vsftpd-2.1.0-filter.patch ++++++ --- /var/tmp/diff_new_pack.YZCLsy/_old 2015-04-07 09:28:57.000000000 +0200 +++ /var/tmp/diff_new_pack.YZCLsy/_new 2015-04-07 09:28:57.000000000 +0200 @@ -1,74 +1,44 @@ -Index: vsftpd-3.0.2/ls.c -=================================================================== ---- vsftpd-3.0.2.orig/ls.c -+++ vsftpd-3.0.2/ls.c -@@ -7,6 +7,7 @@ - * Would you believe, code to handle directory listing. - */ - -+#include <stdlib.h> - #include "ls.h" - #include "access.h" - #include "defs.h" -@@ -243,11 +244,42 @@ vsf_filename_passes_filter(const struct - struct mystr temp_str = INIT_MYSTR; - struct mystr brace_list_str = INIT_MYSTR; - struct mystr new_filter_str = INIT_MYSTR; -+ struct mystr normalize_filename_str = INIT_MYSTR; -+ const char *normname; -+ const char *path; +diff -up vsftpd-2.1.0/ls.c.filter vsftpd-2.1.0/ls.c +--- vsftpd-2.1.0/ls.c.filter 2008-02-02 02:30:41.000000000 +0100 ++++ vsftpd-2.1.0/ls.c 2009-01-08 19:31:15.000000000 +0100 +@@ -239,9 +239,31 @@ vsf_filename_passes_filter(const struct int ret = 0; char last_token = 0; int must_match_at_current_pos = 1; -+ ++ ++ str_copy(&filter_remain_str, p_filter_str); - str_copy(&name_remain_str, p_filename_str); -+ -+ /* normalize filepath */ -+ path = str_strdup(p_filename_str); -+ normname = realpath(path, NULL); -+ if (normname == NULL) -+ goto out; -+ str_alloc_text(&normalize_filename_str, normname); -+ -+ if (!str_isempty (&filter_remain_str) && !str_isempty(&normalize_filename_str)) { +- ++ ++ if (!str_isempty (&filter_remain_str) && !str_isempty(p_filename_str)) { + if (str_get_char_at(p_filter_str, 0) == '/') { -+ if (str_get_char_at(&normalize_filename_str, 0) != '/') { ++ if (str_get_char_at(p_filename_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, &normalize_filename_str); ++ ++ str_append_str (&name_remain_str, p_filename_str); + } + else -+ str_copy (&name_remain_str, &normalize_filename_str); ++ str_copy (&name_remain_str, p_filename_str); + } else { + if (str_get_char_at(p_filter_str, 0) != '{') -+ str_basename (&name_remain_str, &normalize_filename_str); ++ str_basename (&name_remain_str, p_filename_str); + else -+ str_copy (&name_remain_str, &normalize_filename_str); ++ str_copy (&name_remain_str, p_filename_str); + } + } else -+ str_copy(&name_remain_str, &normalize_filename_str); - ++ str_copy(&name_remain_str, p_filename_str); ++ while (!str_isempty(&filter_remain_str) && *iters < VSFTP_MATCHITERS_MAX) { -@@ -360,6 +392,9 @@ vsf_filename_passes_filter(const struct - ret = 0; - } - out: -+ free(normname); -+ free(path); -+ str_free(&normalize_filename_str); - str_free(&filter_remain_str); - str_free(&name_remain_str); - str_free(&temp_str); -Index: vsftpd-3.0.2/str.c -=================================================================== ---- vsftpd-3.0.2.orig/str.c -+++ vsftpd-3.0.2/str.c -@@ -770,3 +770,14 @@ str_replace_unprintable(struct mystr* p_ + static struct mystr s_match_needed_str; +diff -up vsftpd-2.1.0/str.c.filter vsftpd-2.1.0/str.c +--- vsftpd-2.1.0/str.c.filter 2008-12-17 06:54:16.000000000 +0100 ++++ vsftpd-2.1.0/str.c 2009-01-08 19:31:15.000000000 +0100 +@@ -680,3 +680,14 @@ str_replace_unprintable(struct mystr* p_ } } @@ -83,11 +53,10 @@ + if (str_isempty(d_str)) + str_copy (d_str, path); +} -Index: vsftpd-3.0.2/str.h -=================================================================== ---- vsftpd-3.0.2.orig/str.h -+++ vsftpd-3.0.2/str.h -@@ -101,6 +101,7 @@ void str_replace_unprintable(struct myst +diff -up vsftpd-2.1.0/str.h.filter vsftpd-2.1.0/str.h +--- vsftpd-2.1.0/str.h.filter 2008-12-17 06:53:23.000000000 +0100 ++++ vsftpd-2.1.0/str.h 2009-01-08 19:32:14.000000000 +0100 +@@ -100,6 +100,7 @@ void str_replace_unprintable(struct myst 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); ++++++ vsftpd-2.2.0-wildchar.patch ++++++ diff -up vsftpd-2.3.2/ls.c.tmp vsftpd-2.3.2/ls.c --- vsftpd-2.3.2/ls.c.tmp 2010-08-20 13:18:54.397583558 +0200 +++ vsftpd-2.3.2/ls.c 2010-08-20 13:14:59.047831385 +0200 @@ -305,6 +305,20 @@ vsf_filename_passes_filter(const struct { goto out; } + if (!must_match_at_current_pos && last_token == 0) + { + struct mystr last_str = INIT_MYSTR; + str_mid_to_end(&name_remain_str, &last_str, + str_getlen(&name_remain_str) - str_getlen(&s_match_needed_str)); + locate_result = str_locate_str(&last_str, &s_match_needed_str); + str_free(&last_str); + + if (locate_result.found) + { + ret = 1; + } + goto out; + } /* Chop matched string out of remainder */ str_mid_to_end(&name_remain_str, &temp_str, indexx + str_getlen(&s_match_needed_str)); ++++++ vsftpd-2.3.4-sqb.patch ++++++ diff -up vsftpd-3.0.2/ls.c.sqb vsftpd-3.0.2/ls.c --- vsftpd-3.0.2/ls.c.sqb 2014-07-04 09:55:57.899506894 +0200 +++ vsftpd-3.0.2/ls.c 2014-07-04 09:58:02.187569017 +0200 @@ -246,7 +246,7 @@ vsf_filename_passes_filter(const struct int ret = 0; char last_token = 0; int must_match_at_current_pos = 1; - + int matched = 0; str_copy(&filter_remain_str, p_filter_str); @@ -276,7 +276,7 @@ vsf_filename_passes_filter(const struct static struct mystr s_match_needed_str; /* Locate next special token */ struct str_locate_result locate_result = - str_locate_chars(&filter_remain_str, "*?{"); + str_locate_chars(&filter_remain_str, "*?{["); (*iters)++; /* Isolate text leading up to token (if any) - needs to be matched */ if (locate_result.found) @@ -294,94 +294,172 @@ vsf_filename_passes_filter(const struct str_empty(&filter_remain_str); last_token = 0; } - if (!str_isempty(&s_match_needed_str)) - { - /* Need to match something.. could be a match which has to start at - * current position, or we could allow it to start anywhere - */ - unsigned int indexx; - locate_result = str_locate_str(&name_remain_str, &s_match_needed_str); - if (!locate_result.found) + + matched = 0; + do { + if (!str_isempty(&s_match_needed_str)) { - /* Fail */ - goto out; + if (!matched) + { + matched = 1; + } + /* Need to match something.. could be a match which has to start at + * current position, or we could allow it to start anywhere + */ + unsigned int indexx; + locate_result = str_locate_str(&name_remain_str, &s_match_needed_str); + if (!locate_result.found) + { + /* Fail */ + goto out; + } + indexx = locate_result.index; + if (must_match_at_current_pos && indexx > 0) + { + goto out; + } + if (!must_match_at_current_pos && last_token == 0) + { + struct mystr last_str = INIT_MYSTR; + str_mid_to_end(&name_remain_str, &last_str, + str_getlen(&name_remain_str) - str_getlen(&s_match_needed_str)); + locate_result = str_locate_str(&last_str, &s_match_needed_str); + str_free(&last_str); + + if (locate_result.found) + { + ret = 1; + } + goto out; + } + /* Chop matched string out of remainder */ + str_mid_to_end(&name_remain_str, &temp_str, + indexx + str_getlen(&s_match_needed_str)); + str_copy(&name_remain_str, &temp_str); } - indexx = locate_result.index; - if (must_match_at_current_pos && indexx > 0) + if (last_token == '?') { - goto out; + if (str_isempty(&name_remain_str)) + { + goto out; + } + str_right(&name_remain_str, &temp_str, str_getlen(&name_remain_str) - 1); + str_copy(&name_remain_str, &temp_str); + must_match_at_current_pos = 1; } - if (!must_match_at_current_pos && last_token == 0) + else if (last_token == '{') { - struct mystr last_str = INIT_MYSTR; - str_mid_to_end(&name_remain_str, &last_str, - str_getlen(&name_remain_str) - str_getlen(&s_match_needed_str)); - locate_result = str_locate_str(&last_str, &s_match_needed_str); - str_free(&last_str); + struct str_locate_result end_brace = + str_locate_char(&filter_remain_str, '}'); + must_match_at_current_pos = 1; + if (end_brace.found) + { + int entire = (*iters == 1 && last_token == '{'); - if (locate_result.found) + str_split_char(&filter_remain_str, &temp_str, '}'); + str_copy(&brace_list_str, &filter_remain_str); + str_copy(&filter_remain_str, &temp_str); + str_split_char(&brace_list_str, &temp_str, ','); + while (!str_isempty(&brace_list_str)) + { + str_empty(&new_filter_str); + if (!matched && !entire) + { + str_append_char(&new_filter_str, '*'); + } + str_append_str(&new_filter_str, &brace_list_str); + str_append_str(&new_filter_str, &filter_remain_str); + if (vsf_filename_passes_filter(&name_remain_str, &new_filter_str, + iters)) + { + ret = 1; + goto out; + } + str_copy(&brace_list_str, &temp_str); + str_split_char(&brace_list_str, &temp_str, ','); + } + goto out; + } + else if (str_isempty(&name_remain_str) || + str_get_char_at(&name_remain_str, 0) != '{') { - ret = 1; + goto out; + } + else + { + str_right(&name_remain_str, &temp_str, + str_getlen(&name_remain_str) - 1); + str_copy(&name_remain_str, &temp_str); } - goto out; - } - /* Chop matched string out of remainder */ - str_mid_to_end(&name_remain_str, &temp_str, - indexx + str_getlen(&s_match_needed_str)); - str_copy(&name_remain_str, &temp_str); - } - if (last_token == '?') - { - if (str_isempty(&name_remain_str)) - { - goto out; } - str_right(&name_remain_str, &temp_str, str_getlen(&name_remain_str) - 1); - str_copy(&name_remain_str, &temp_str); - must_match_at_current_pos = 1; - } - else if (last_token == '{') - { - struct str_locate_result end_brace = - str_locate_char(&filter_remain_str, '}'); - must_match_at_current_pos = 1; - if (end_brace.found) + else if (last_token == '[') { - str_split_char(&filter_remain_str, &temp_str, '}'); - str_copy(&brace_list_str, &filter_remain_str); - str_copy(&filter_remain_str, &temp_str); - str_split_char(&brace_list_str, &temp_str, ','); - while (!str_isempty(&brace_list_str)) - { - str_copy(&new_filter_str, &brace_list_str); - str_append_str(&new_filter_str, &filter_remain_str); - if (vsf_filename_passes_filter(&name_remain_str, &new_filter_str, - iters)) + struct str_locate_result end_sqb = + str_locate_char(&filter_remain_str, ']'); + must_match_at_current_pos = 1; + if (end_sqb.found) + { + unsigned int cur_pos; + char stch, ench; + const char *p_brace; + + str_split_char(&filter_remain_str, &temp_str, ']'); + str_copy(&brace_list_str, &filter_remain_str); + str_copy(&filter_remain_str, &temp_str); + p_brace = str_getbuf(&brace_list_str); + for (cur_pos = 0; cur_pos < str_getlen(&brace_list_str);) { - ret = 1; - goto out; + stch = p_brace[cur_pos]; + // char vers. range + if (cur_pos + 2 < str_getlen(&brace_list_str) && + p_brace[cur_pos+1] == '-') + { + ench = p_brace[cur_pos+2]; + cur_pos += 3; + } + else + { + ench = stch; + cur_pos++; + } + // expand char[s] + for (;stch <= ench && !str_isempty(&brace_list_str); stch++) + { + str_empty(&new_filter_str); + if (!matched) + { + str_append_char(&new_filter_str, '*'); + } + str_append_char(&new_filter_str, stch); + str_append_str(&new_filter_str, &filter_remain_str); + if (vsf_filename_passes_filter(&name_remain_str, &new_filter_str, + iters)) + { + ret = 1; + goto out; + } + } } - str_copy(&brace_list_str, &temp_str); - str_split_char(&brace_list_str, &temp_str, ','); + goto out; + } + else if (str_isempty(&name_remain_str) || + str_get_char_at(&name_remain_str, 0) != '[') + { + goto out; + } + else + { + str_right(&name_remain_str, &temp_str, + str_getlen(&name_remain_str) - 1); + str_copy(&name_remain_str, &temp_str); } - goto out; - } - else if (str_isempty(&name_remain_str) || - str_get_char_at(&name_remain_str, 0) != '{') - { - goto out; } else { - str_right(&name_remain_str, &temp_str, - str_getlen(&name_remain_str) - 1); - str_copy(&name_remain_str, &temp_str); + must_match_at_current_pos = 0; } - } - else - { - must_match_at_current_pos = 0; - } + } while (locate_result.found && + str_getlen(&name_remain_str) > 0 && last_token != '*'); } /* Any incoming string left means no match unless we ended on the correct * type of wildcard. ++++++ vsftpd-path-normalize.patch ++++++ 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 @@ -249,6 +249,7 @@ vsf_filename_passes_filter(const struct int matched = 0; str_copy(&filter_remain_str, p_filter_str); + str_normalize_filepath(p_filename_str); if (!str_isempty (&filter_remain_str) && !str_isempty(p_filename_str)) { if (str_get_char_at(p_filter_str, 0) == '/') {