summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2024-07-15 09:01:07 +0000
committerCoprDistGit <infra@openeuler.org>2024-07-15 09:01:07 +0000
commita69ae46c92199effdb2f0903e5416af42fd8ad69 (patch)
tree3700124d2256f460e93567fa6f3cfa6ec0d44787
parent908f6497506278a654656b2ed78b9cf08a892218 (diff)
-rw-r--r--.gitignore1
-rw-r--r--0001-Don-t-use-the-provided-script-to-locate-libraries.patch27
-rw-r--r--0001-Fix-timestamp-handling-in-MDTM.patch151
-rw-r--r--0001-Move-closing-standard-FDs-after-listen.patch46
-rw-r--r--0001-Remove-a-hint-about-the-ftp_home_dir-SELinux-boolean.patch25
-rw-r--r--0001-Repeat-pututxline-until-it-succeeds-if-it-fails-with.patch108
-rw-r--r--0001-Set-s_uwtmp_inserted-only-after-record-insertion-rem.patch53
-rw-r--r--0002-Drop-an-unused-global-variable.patch56
-rw-r--r--0002-Enable-build-with-SSL.patch25
-rw-r--r--0002-Prevent-recursion-in-bug.patch107
-rw-r--r--0002-Repeat-pututxline-if-it-fails-with-EINTR.patch105
-rw-r--r--0003-Enable-build-with-TCP-Wrapper.patch25
-rw-r--r--0004-Use-etc-vsftpd-dir-for-config-files-instead-of-etc.patch483
-rw-r--r--0005-Use-hostname-when-calling-PAM-authentication-module.patch75
-rw-r--r--0006-Close-stdin-out-err-before-listening-for-incoming-co.patch35
-rw-r--r--0007-Make-filename-filters-smarter.patch102
-rw-r--r--0008-Write-denied-logins-into-the-log.patch147
-rw-r--r--0009-Trim-whitespaces-when-reading-configuration.patch99
-rw-r--r--0010-Improve-daemonizing.patch209
-rw-r--r--0011-Fix-listing-with-more-than-one-star.patch38
-rw-r--r--0012-Replace-syscall-__NR_clone-.-with-clone.patch35
-rw-r--r--0013-Extend-man-pages-with-systemd-info.patch86
-rw-r--r--0014-Add-support-for-square-brackets-in-ls.patch277
-rw-r--r--0015-Listen-on-IPv6-by-default.patch55
-rw-r--r--0016-Increase-VSFTP_AS_LIMIT-from-200UL-to-400UL.patch27
-rw-r--r--0017-Fix-an-issue-with-timestamps-during-DST.patch161
-rw-r--r--0018-Change-the-default-log-file-in-configuration.patch43
-rw-r--r--0019-Introduce-reverse_lookup_enable-option.patch109
-rw-r--r--0020-Use-unsigned-int-for-uid-and-gid-representation.patch250
-rw-r--r--0021-Introduce-support-for-DHE-based-cipher-suites.patch226
-rw-r--r--0022-Introduce-support-for-EDDHE-based-cipher-suites.patch136
-rw-r--r--0023-Add-documentation-for-isolate_-options.-Correct-defa.patch63
-rw-r--r--0024-Introduce-new-return-value-450.patch77
-rw-r--r--0025-Improve-local_max_rate-option.patch90
-rw-r--r--0026-Prevent-hanging-in-SIGCHLD-handler.patch81
-rw-r--r--0027-Delete-files-when-upload-fails.patch138
-rw-r--r--0028-Fix-man-page-rendering.patch26
-rw-r--r--0029-Fix-segfault-in-config-file-parser.patch25
-rw-r--r--0030-Fix-logging-into-syslog-when-enabled-in-config.patch25
-rw-r--r--0031-Fix-question-mark-wildcard-withing-a-file-name.patch28
-rw-r--r--0032-Propagate-errors-from-nfs-with-quota-to-client.patch147
-rw-r--r--0034-Turn-off-seccomp-sandbox-because-it-is-too-strict.patch25
-rw-r--r--0035-Modify-DH-enablement-patch-to-build-with-OpenSSL-1.1.patch74
-rw-r--r--0036-Redefine-VSFTP_COMMAND_FD-to-1.patch29
-rw-r--r--0037-Document-the-relationship-of-text_userdb_names-and-c.patch29
-rw-r--r--0038-Document-allow_writeable_chroot-in-the-man-page.patch32
-rw-r--r--0039-Improve-documentation-of-ASCII-mode-in-the-man-page.patch34
-rw-r--r--0040-Use-system-wide-crypto-policy.patch27
-rw-r--r--0041-Document-the-new-default-for-ssl_ciphers-in-the-man-.patch31
-rw-r--r--0044-Disable-anonymous_enable-in-default-config-file.patch26
-rw-r--r--0045-Expand-explanation-of-ascii_-options-behaviour-in-ma.patch52
-rw-r--r--0046-vsftpd.conf-Refer-to-the-man-page-regarding-the-asci.patch27
-rw-r--r--0047-Disable-tcp_wrappers-support.patch49
-rw-r--r--0048-Fix-default-value-of-strict_ssl_read_eof-in-man-page.patch29
-rw-r--r--0049-Add-new-filename-generation-algorithm-for-STOU-comma.patch322
-rw-r--r--0050-Don-t-link-with-libnsl.patch27
-rw-r--r--0051-Improve-documentation-of-better_stou-in-the-man-page.patch30
-rw-r--r--0052-Fix-rDNS-with-IPv6.patch195
-rw-r--r--0053-Always-do-chdir-after-chroot.patch32
-rw-r--r--0054-vsf_sysutil_rcvtimeo-Check-return-value-of-setsockop.patch33
-rw-r--r--0055-vsf_sysutil_get_tz-Check-the-return-value-of-syscall.patch108
-rw-r--r--0056-Log-die-calls-to-syslog.patch206
-rw-r--r--0057-Improve-error-message-when-max-number-of-bind-attemp.patch27
-rw-r--r--0058-Make-the-max-number-of-bind-retries-tunable.patch103
-rw-r--r--0059-Fix-SEGFAULT-when-running-in-a-container-as-PID-1.patch58
-rw-r--r--0072-support-clang-build.patch23
-rw-r--r--bugfix-change-the-default-value-of-tunable_reverse_lookup_e.patch26
-rw-r--r--fix-str_open.patch28
-rw-r--r--sources1
-rw-r--r--vsftpd-3.0.5-enable_wc_logs-replace_unprintable_with_hex.patch215
-rw-r--r--vsftpd-generator15
-rw-r--r--vsftpd.default.log5
-rw-r--r--vsftpd.ftpusers15
-rw-r--r--vsftpd.pam8
-rw-r--r--vsftpd.service10
-rw-r--r--vsftpd.spec188
-rw-r--r--vsftpd.target6
-rw-r--r--vsftpd.user_list20
-rw-r--r--vsftpd.xinetd14
-rw-r--r--vsftpd@.service11
-rw-r--r--vsftpd_conf_migrate.sh13
81 files changed, 6225 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..9a45f20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/vsftpd-3.0.5.tar.gz
diff --git a/0001-Don-t-use-the-provided-script-to-locate-libraries.patch b/0001-Don-t-use-the-provided-script-to-locate-libraries.patch
new file mode 100644
index 0000000..f4a67e3
--- /dev/null
+++ b/0001-Don-t-use-the-provided-script-to-locate-libraries.patch
@@ -0,0 +1,27 @@
+From 7bd573d76e9c1996ad5a96f0289731a253a24301 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Tue, 6 Sep 2016 13:35:51 +0200
+Subject: [PATCH 01/59] Don't use the provided script to locate libraries.
+
+This branch is Fedora (RHEL) specific, so we know what
+libraries we have and want to use.
+---
+ Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Makefile b/Makefile
+index c63ed1b..98118dc 100644
+--- a/Makefile
++++ b/Makefile
+@@ -8,7 +8,7 @@ CFLAGS = -O2 -fPIE -fstack-protector --param=ssp-buffer-size=4 \
+ -D_FORTIFY_SOURCE=2 \
+ #-pedantic -Wconversion
+
+-LIBS = `./vsf_findlibs.sh`
++LIBS = -lwrap -lnsl -lpam -lcap -ldl -lcrypto
+ LINK = -Wl,-s
+ LDFLAGS = -fPIE -pie -Wl,-z,relro -Wl,-z,now
+
+--
+2.14.4
+
diff --git a/0001-Fix-timestamp-handling-in-MDTM.patch b/0001-Fix-timestamp-handling-in-MDTM.patch
new file mode 100644
index 0000000..3975bf3
--- /dev/null
+++ b/0001-Fix-timestamp-handling-in-MDTM.patch
@@ -0,0 +1,151 @@
+From 6a4dc470e569df38b8a7ea09ee6aace3c73b7353 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Wed, 28 Mar 2018 09:06:34 +0200
+Subject: [PATCH 1/2] Fix timestamp handling in MDTM
+
+There were two problems with the timestamp handling with MDTM:
+
+1. In vsf_sysutil_parse_time(), the `the_time.tm_isdst` attribute was
+ always set to 0, regardless of whether DST (daylight saving time)
+ is active on the given date or not.
+
+ This made glibc shift the timestamp when DST was in fact active on
+ the given date, in an attempt to correct the discrepancy between
+ the given timestamp and the `tm_isdst` attribute. The shifting
+ produced incorrect results however.
+
+ We fix this by setting `tm_isdst` to -1 to let glibc decide if DST
+ is active or not at the time of the timestamp. glibc won't touch
+ the timestamp then.
+
+2. vsftpd used to record the offset from UTC of the current timezone
+ in the global variable `s_timezone`. This variable was then
+ subtracted from the variable `the_time` in vsf_sysutil_setmodtime()
+ when the config option use_localtime=NO was set. This was done to
+ compensate for the fact that mktime(), used in
+ vsf_sysutil_parse_time(), expects a timestamp expressed as local
+ time, whereas vsftpd is dealing with universal time.
+
+ However, this did not work in the case when the offset stored in
+ `s_timezone` did not match the timezone of the timestamp given to
+ mktime() - this happens when DST is active at the current time, but
+ DST is not active at the time of the timestamp, or vice versa.
+
+ We fix this by subtracting the real timezone offset directly in
+ vsf_sysutil_parse_time().
+
+ Note that the `tm_gmtoff` attribute, used in this fix, is a
+ BSD/glic extension. However, using `tm_gmtoff` seems like the
+ simplest solution and we need to make this work only with glibc
+ anyway.
+
+The fix was tested in the following way. We checked that the timestamp
+given to the MDTM command when setting modification time exactly
+matches the timestamp received as response from MDTM when reading back
+the modification time. Additionally, we checked that the modification
+time was set correctly on the given file on disk.
+
+These two checks were performed under various conditions - all the
+combinations of DST/non-DST system time, DST/non-DST modification
+time, use_localtime=YES/NO.
+
+Note that (I think) this will still not work if the rules for when DST
+is active change. For example, if DST is ever completely cancelled in
+the Europe/Prague timezone, and vsftpd is dealing with a timestamp
+from a time when DST was active, it will produce incorrect results. I
+think we would need the full zone file to fix this, but the zone file
+is hard to provide when we're chroot-ed.
+
+Resolves: rhbz#1567855
+---
+ postlogin.c | 5 +++--
+ sysutil.c | 17 ++++++++++-------
+ sysutil.h | 4 ++--
+ 3 files changed, 15 insertions(+), 11 deletions(-)
+
+diff --git a/postlogin.c b/postlogin.c
+index 7c749ef..8a3d9d2 100644
+--- a/postlogin.c
++++ b/postlogin.c
+@@ -1788,7 +1788,8 @@ handle_mdtm(struct vsf_session* p_sess)
+ if (do_write != 0)
+ {
+ str_split_char(&p_sess->ftp_arg_str, &s_filename_str, ' ');
+- modtime = vsf_sysutil_parse_time(str_getbuf(&p_sess->ftp_arg_str));
++ modtime = vsf_sysutil_parse_time(
++ str_getbuf(&p_sess->ftp_arg_str), tunable_use_localtime);
+ str_copy(&p_sess->ftp_arg_str, &s_filename_str);
+ }
+ resolve_tilde(&p_sess->ftp_arg_str, p_sess);
+@@ -1809,7 +1810,7 @@ handle_mdtm(struct vsf_session* p_sess)
+ else
+ {
+ retval = vsf_sysutil_setmodtime(
+- str_getbuf(&p_sess->ftp_arg_str), modtime, tunable_use_localtime);
++ str_getbuf(&p_sess->ftp_arg_str), modtime);
+ if (retval != 0)
+ {
+ vsf_cmdio_write(p_sess, FTP_FILEFAIL,
+diff --git a/sysutil.c b/sysutil.c
+index e847650..66d4c5e 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -2819,11 +2819,13 @@ vsf_sysutil_syslog(const char* p_text, int severe)
+ }
+
+ long
+-vsf_sysutil_parse_time(const char* p_text)
++vsf_sysutil_parse_time(const char* p_text, int is_localtime)
+ {
++ long res;
+ struct tm the_time;
+ unsigned int len = vsf_sysutil_strlen(p_text);
+ vsf_sysutil_memclr(&the_time, sizeof(the_time));
++ the_time.tm_isdst = -1;
+ if (len >= 8)
+ {
+ char yr[5];
+@@ -2848,17 +2850,18 @@ vsf_sysutil_parse_time(const char* p_text)
+ the_time.tm_min = vsf_sysutil_atoi(mins);
+ the_time.tm_sec = vsf_sysutil_atoi(sec);
+ }
+- return mktime(&the_time);
++ res = mktime(&the_time);
++ if (!is_localtime)
++ {
++ res += the_time.tm_gmtoff;
++ }
++ return res;
+ }
+
+ int
+-vsf_sysutil_setmodtime(const char* p_file, long the_time, int is_localtime)
++vsf_sysutil_setmodtime(const char* p_file, long the_time)
+ {
+ struct utimbuf new_times;
+- if (!is_localtime)
+- {
+- the_time -= s_timezone;
+- }
+ vsf_sysutil_memclr(&new_times, sizeof(new_times));
+ new_times.actime = the_time;
+ new_times.modtime = the_time;
+diff --git a/sysutil.h b/sysutil.h
+index 7a59f13..b90f6ca 100644
+--- a/sysutil.h
++++ b/sysutil.h
+@@ -349,9 +349,9 @@ void vsf_sysutil_chroot(const char* p_root_path);
+ */
+ long vsf_sysutil_get_time_sec(void);
+ long vsf_sysutil_get_time_usec(void);
+-long vsf_sysutil_parse_time(const char* p_text);
++long vsf_sysutil_parse_time(const char* p_text, int is_localtime);
+ void vsf_sysutil_sleep(double seconds);
+-int vsf_sysutil_setmodtime(const char* p_file, long the_time, int is_localtime);
++int vsf_sysutil_setmodtime(const char* p_file, long the_time);
+
+ /* Limits */
+ void vsf_sysutil_set_address_space_limit(unsigned long bytes);
+--
+2.24.1
+
diff --git a/0001-Move-closing-standard-FDs-after-listen.patch b/0001-Move-closing-standard-FDs-after-listen.patch
new file mode 100644
index 0000000..12511e7
--- /dev/null
+++ b/0001-Move-closing-standard-FDs-after-listen.patch
@@ -0,0 +1,46 @@
+From 40fea4552377504ce69935149e64e39a595f4600 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Sat, 3 Aug 2019 17:50:14 +0200
+Subject: [PATCH 1/2] Move closing standard FDs after listen()
+
+The vsf_sysutil_close() calls need to be moved a bit further so that
+die() works properly in case listen() fails.
+
+I see no reason the calls should be placed before listen()
+specifically, as they are now. My guess is that the author who added
+the calls thought that listen() is a blocking call, which is not the
+case. The only thing we need to satisfy is that close() is called
+before accept, because that is a blocking call. That's all that is
+needed to fix the bug that was fixed by adding the close() calls.
+
+Resolves: rhbz#1666380
+---
+ standalone.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/standalone.c b/standalone.c
+index 3f35e9e..b358ca1 100644
+--- a/standalone.c
++++ b/standalone.c
+@@ -152,15 +152,15 @@ vsf_standalone_main(void)
+ vsf_sysutil_kill(vsf_sysutil_getppid(), kVSFSysUtilSigUSR1);
+ }
+ }
+- vsf_sysutil_close(0);
+- vsf_sysutil_close(1);
+- vsf_sysutil_close(2);
+ retval = vsf_sysutil_listen(listen_sock, VSFTP_LISTEN_BACKLOG);
+ if (vsf_sysutil_retval_is_error(retval))
+ {
+ die("could not listen");
+ }
+ vsf_sysutil_sockaddr_alloc(&p_accept_addr);
++ vsf_sysutil_close(0);
++ vsf_sysutil_close(1);
++ vsf_sysutil_close(2);
+ while (1)
+ {
+ struct vsf_client_launch child_info;
+--
+2.20.1
+
diff --git a/0001-Remove-a-hint-about-the-ftp_home_dir-SELinux-boolean.patch b/0001-Remove-a-hint-about-the-ftp_home_dir-SELinux-boolean.patch
new file mode 100644
index 0000000..88640ac
--- /dev/null
+++ b/0001-Remove-a-hint-about-the-ftp_home_dir-SELinux-boolean.patch
@@ -0,0 +1,25 @@
+From ab797dcffc855b05c9e7c8db4e5be2fc7510831b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Tue, 17 Mar 2020 12:57:36 +0100
+Subject: [PATCH] Remove a hint about the ftp_home_dir SELinux boolean
+
+The boolean has been removed from SELinux.
+---
+ vsftpd.conf | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/vsftpd.conf b/vsftpd.conf
+index 6b8eebb..ea20a72 100644
+--- a/vsftpd.conf
++++ b/vsftpd.conf
+@@ -12,7 +12,6 @@
+ anonymous_enable=NO
+ #
+ # Uncomment this to allow local users to log in.
+-# When SELinux is enforcing check for SE bool ftp_home_dir
+ local_enable=YES
+ #
+ # Uncomment this to enable any form of FTP write command.
+--
+2.25.1
+
diff --git a/0001-Repeat-pututxline-until-it-succeeds-if-it-fails-with.patch b/0001-Repeat-pututxline-until-it-succeeds-if-it-fails-with.patch
new file mode 100644
index 0000000..63d555e
--- /dev/null
+++ b/0001-Repeat-pututxline-until-it-succeeds-if-it-fails-with.patch
@@ -0,0 +1,108 @@
+From 7957425ef5ab365fc96ea0615f99705581c6dbd8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Mon, 12 Aug 2019 18:15:36 +0200
+Subject: [PATCH] Repeat pututxline() until it succeeds if it fails with EINTR
+
+Since the pututxline() bug rhbz#1749439 is now fixed in glibc in
+Fedora and RHEL-8, we can implement a complete solution for the stale
+utmp entries issue originally reported as rhbz#1688848.
+
+This patch is a followup to commit 896b3694ca062d7.
+
+Resolves: rhbz#1688852
+Resolves: rhbz#1737433
+---
+ sysdeputil.c | 53 +++++++++++++---------------------------------------
+ 1 file changed, 13 insertions(+), 40 deletions(-)
+
+diff --git a/sysdeputil.c b/sysdeputil.c
+index 4fbcca7..75be680 100644
+--- a/sysdeputil.c
++++ b/sysdeputil.c
+@@ -1203,7 +1203,7 @@ void
+ vsf_insert_uwtmp(const struct mystr* p_user_str,
+ const struct mystr* p_host_str)
+ {
+- int attempts;
++ struct utmpx* p_res;
+
+ if (sizeof(s_utent.ut_line) < 16)
+ {
+@@ -1233,34 +1233,21 @@ vsf_insert_uwtmp(const struct mystr* p_user_str,
+ vsf_sysutil_strcpy(s_utent.ut_host, str_getbuf(p_host_str),
+ sizeof(s_utent.ut_host));
+ s_utent.ut_tv.tv_sec = vsf_sysutil_get_time_sec();
+- for (attempts = 2; attempts > 0; --attempts)
++ setutxent();
++ do
+ {
+- struct utmpx* p_res;
+- setutxent();
+ p_res = pututxline(&s_utent);
+ /* For now we'll ignore errors other than EINTR and EAGAIN */
+- if (p_res != NULL || (errno != EINTR && errno != EAGAIN))
+- {
+- break;
+- }
+- }
+- if (attempts == 0)
+- {
+- /* This makes us skip pututxline() in vsf_remove_uwtmp() */
+- s_uwtmp_inserted = -1;
+- }
+- else
+- {
+- s_uwtmp_inserted = 1;
+- endutxent();
+- }
++ } while (p_res == NULL && (errno == EINTR || errno == EAGAIN));
++ s_uwtmp_inserted = 1;
++ endutxent();
+ updwtmpx(WTMPX_FILE, &s_utent);
+ }
+
+ void
+ vsf_remove_uwtmp(void)
+ {
+- int attempts;
++ struct utmpx* p_res;
+
+ if (!s_uwtmp_inserted)
+ {
+@@ -1270,27 +1257,13 @@ vsf_remove_uwtmp(void)
+ vsf_sysutil_memclr(s_utent.ut_user, sizeof(s_utent.ut_user));
+ vsf_sysutil_memclr(s_utent.ut_host, sizeof(s_utent.ut_host));
+ s_utent.ut_tv.tv_sec = 0;
+- if (s_uwtmp_inserted == 1)
++ setutxent();
++ do
+ {
+- for (attempts = 2; attempts > 0; --attempts)
+- {
+- struct utmpx* p_res;
+- setutxent();
+- p_res = pututxline(&s_utent);
+- /* For now we'll ignore errors other than EINTR and EAGAIN */
+- if (p_res != NULL || (errno != EINTR && errno != EAGAIN))
+- {
+- break;
+- }
+- }
+- if (attempts != 0)
+- {
+- endutxent();
+- }
+- }
+- /* Set s_uwtmp_inserted to 0 regardless of the result of
+- * pututxline() to make sure we won't run this function twice.
+- */
++ p_res = pututxline(&s_utent);
++ /* For now we'll ignore errors other than EINTR and EAGAIN */
++ } while (p_res == NULL && (errno == EINTR || errno == EAGAIN));
++ endutxent();
+ s_uwtmp_inserted = 0;
+ s_utent.ut_tv.tv_sec = vsf_sysutil_get_time_sec();
+ updwtmpx(WTMPX_FILE, &s_utent);
+--
+2.20.1
+
diff --git a/0001-Set-s_uwtmp_inserted-only-after-record-insertion-rem.patch b/0001-Set-s_uwtmp_inserted-only-after-record-insertion-rem.patch
new file mode 100644
index 0000000..00bf82c
--- /dev/null
+++ b/0001-Set-s_uwtmp_inserted-only-after-record-insertion-rem.patch
@@ -0,0 +1,53 @@
+From 96698a525784ad91cb27b572dd5f871c183fdfa5 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Sun, 28 Jul 2019 12:25:35 +0200
+Subject: [PATCH 1/2] Set s_uwtmp_inserted only after record insertion/removal
+
+pututxline() is the function that actually inserts the new record, so
+setting 's_uwtmp_inserted' before calling pututxline() doesn't make
+sense.
+
+We'll need this change for other fixes.
+---
+ sysdeputil.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/sysdeputil.c b/sysdeputil.c
+index 4fe56c2..bd1e8c9 100644
+--- a/sysdeputil.c
++++ b/sysdeputil.c
+@@ -1224,7 +1224,6 @@ vsf_insert_uwtmp(const struct mystr* p_user_str,
+ sizeof(s_utent.ut_line));
+ str_free(&line_str);
+ }
+- s_uwtmp_inserted = 1;
+ s_utent.ut_type = USER_PROCESS;
+ s_utent.ut_pid = vsf_sysutil_getpid();
+ vsf_sysutil_strcpy(s_utent.ut_user, str_getbuf(p_user_str),
+@@ -1235,6 +1234,7 @@ vsf_insert_uwtmp(const struct mystr* p_user_str,
+ setutxent();
+ (void) pututxline(&s_utent);
+ endutxent();
++ s_uwtmp_inserted = 1;
+ updwtmpx(WTMPX_FILE, &s_utent);
+ }
+
+@@ -1245,7 +1245,6 @@ vsf_remove_uwtmp(void)
+ {
+ return;
+ }
+- s_uwtmp_inserted = 0;
+ s_utent.ut_type = DEAD_PROCESS;
+ vsf_sysutil_memclr(s_utent.ut_user, sizeof(s_utent.ut_user));
+ vsf_sysutil_memclr(s_utent.ut_host, sizeof(s_utent.ut_host));
+@@ -1253,6 +1252,7 @@ vsf_remove_uwtmp(void)
+ setutxent();
+ (void) pututxline(&s_utent);
+ endutxent();
++ s_uwtmp_inserted = 0;
+ s_utent.ut_tv.tv_sec = vsf_sysutil_get_time_sec();
+ updwtmpx(WTMPX_FILE, &s_utent);
+ }
+--
+2.20.1
+
diff --git a/0002-Drop-an-unused-global-variable.patch b/0002-Drop-an-unused-global-variable.patch
new file mode 100644
index 0000000..53af589
--- /dev/null
+++ b/0002-Drop-an-unused-global-variable.patch
@@ -0,0 +1,56 @@
+From d0045e35674d64d166d17c3c079ae03e8c2e6361 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Thu, 13 Feb 2020 17:29:06 +0100
+Subject: [PATCH 2/2] Drop an unused global variable
+
+The global variable `s_timezone` is not used anymore, so we can drop
+it.
+---
+ sysutil.c | 17 +++--------------
+ 1 file changed, 3 insertions(+), 14 deletions(-)
+
+diff --git a/sysutil.c b/sysutil.c
+index 66d4c5e..0ccf551 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -72,8 +72,6 @@ static struct timeval s_current_time;
+ static int s_current_pid = -1;
+ /* Exit function */
+ static exitfunc_t s_exit_func;
+-/* Difference in timezone from GMT in seconds */
+-static long s_timezone;
+
+ /* Our internal signal handling implementation details */
+ static struct vsf_sysutil_sig_details
+@@ -2661,7 +2659,6 @@ char* vsf_sysutil_get_tz()
+ void
+ vsf_sysutil_tzset(void)
+ {
+- int retval;
+ char *tz=NULL, tzbuf[sizeof("+HHMM!")];
+ time_t the_time = time(NULL);
+ struct tm* p_tm;
+@@ -2681,17 +2678,9 @@ vsf_sysutil_tzset(void)
+ {
+ die("localtime");
+ }
+- retval = strftime(tzbuf, sizeof(tzbuf), "%z", p_tm);
+- tzbuf[sizeof(tzbuf) - 1] = '\0';
+- if (retval == 5)
+- {
+- s_timezone = ((tzbuf[1] - '0') * 10 + (tzbuf[2] - '0')) * 60 * 60;
+- s_timezone += ((tzbuf[3] - '0') * 10 + (tzbuf[4] - '0')) * 60;
+- if (tzbuf[0] == '+')
+- {
+- s_timezone *= -1;
+- }
+- }
++ /* Not sure if the following call to strftime() has any desired side
++ effects, so I'm keeping it to be safe. */
++ (void) strftime(tzbuf, sizeof(tzbuf), "%z", p_tm);
+ /* Call in to the time subsystem again now that TZ is set, trying to force
+ * caching of the actual zoneinfo for the timezone.
+ */
+--
+2.24.1
+
diff --git a/0002-Enable-build-with-SSL.patch b/0002-Enable-build-with-SSL.patch
new file mode 100644
index 0000000..e772099
--- /dev/null
+++ b/0002-Enable-build-with-SSL.patch
@@ -0,0 +1,25 @@
+From 6fe24bc56694808ac7f8038855883a971967f0fb Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Tue, 6 Sep 2016 13:40:53 +0200
+Subject: [PATCH 02/59] Enable build with SSL.
+
+---
+ builddefs.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/builddefs.h b/builddefs.h
+index e908352..63cc62b 100644
+--- a/builddefs.h
++++ b/builddefs.h
+@@ -3,7 +3,7 @@
+
+ #undef VSF_BUILD_TCPWRAPPERS
+ #define VSF_BUILD_PAM
+-#undef VSF_BUILD_SSL
++#define VSF_BUILD_SSL
+
+ #endif /* VSF_BUILDDEFS_H */
+
+--
+2.14.4
+
diff --git a/0002-Prevent-recursion-in-bug.patch b/0002-Prevent-recursion-in-bug.patch
new file mode 100644
index 0000000..061fd1e
--- /dev/null
+++ b/0002-Prevent-recursion-in-bug.patch
@@ -0,0 +1,107 @@
+From e679a3ce0f2cf1558da31e0bccd9e2398b89c7e9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Tue, 30 Jul 2019 16:07:01 +0200
+Subject: [PATCH 2/2] Prevent recursion in bug()
+
+Resolves: rhbz#1666380
+---
+ sysutil.c | 35 +++++++++++++++++++++++++++++++----
+ sysutil.h | 1 +
+ utility.c | 12 +++++++-----
+ 3 files changed, 39 insertions(+), 9 deletions(-)
+
+diff --git a/sysutil.c b/sysutil.c
+index fd07d99..e2df671 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -774,21 +774,48 @@ vsf_sysutil_deactivate_linger_failok(int fd)
+ (void) setsockopt(fd, SOL_SOCKET, SO_LINGER, &the_linger, sizeof(the_linger));
+ }
+
+-void
+-vsf_sysutil_activate_noblock(int fd)
++static int
++vsf_sysutil_activate_noblock_internal(int fd, int return_err)
+ {
+ int retval;
+ int curr_flags = fcntl(fd, F_GETFL);
+ if (vsf_sysutil_retval_is_error(curr_flags))
+ {
+- die("fcntl");
++ if (return_err)
++ {
++ return -1;
++ }
++ else
++ {
++ die("fcntl");
++ }
+ }
+ curr_flags |= O_NONBLOCK;
+ retval = fcntl(fd, F_SETFL, curr_flags);
+ if (retval != 0)
+ {
+- die("fcntl");
++ if (return_err)
++ {
++ return -1;
++ }
++ else
++ {
++ die("fcntl");
++ }
+ }
++ return 0;
++}
++
++void
++vsf_sysutil_activate_noblock(int fd)
++{
++ (void) vsf_sysutil_activate_noblock_internal(fd, 0);
++}
++
++int
++vsf_sysutil_activate_noblock_no_die(int fd)
++{
++ return vsf_sysutil_activate_noblock_internal(fd, 1);
+ }
+
+ void
+diff --git a/sysutil.h b/sysutil.h
+index 2df14ed..0772423 100644
+--- a/sysutil.h
++++ b/sysutil.h
+@@ -281,6 +281,7 @@ void vsf_sysutil_activate_oobinline(int fd);
+ void vsf_sysutil_activate_linger(int fd);
+ void vsf_sysutil_deactivate_linger_failok(int fd);
+ void vsf_sysutil_activate_noblock(int fd);
++int vsf_sysutil_activate_noblock_no_die(int fd);
+ void vsf_sysutil_deactivate_noblock(int fd);
+ /* This does SHUT_RDWR */
+ void vsf_sysutil_shutdown_failok(int fd);
+diff --git a/utility.c b/utility.c
+index 75e5bdd..5619a04 100644
+--- a/utility.c
++++ b/utility.c
+@@ -47,11 +47,13 @@ bug(const char* p_text)
+ {
+ vsf_log_die(p_text);
+ }
+- vsf_sysutil_activate_noblock(VSFTP_COMMAND_FD);
+- (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, "500 OOPS: ", 10);
+- (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, p_text,
+- vsf_sysutil_strlen(p_text));
+- (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, "\r\n", 2);
++ if (vsf_sysutil_activate_noblock_no_die(VSFTP_COMMAND_FD) == 0)
++ {
++ (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, "500 OOPS: ", 10);
++ (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, p_text,
++ vsf_sysutil_strlen(p_text));
++ (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, "\r\n", 2);
++ }
+ if (tunable_log_die)
+ {
+ /* Workaround for https://github.com/systemd/systemd/issues/2913 */
+--
+2.20.1
+
diff --git a/0002-Repeat-pututxline-if-it-fails-with-EINTR.patch b/0002-Repeat-pututxline-if-it-fails-with-EINTR.patch
new file mode 100644
index 0000000..e89efcf
--- /dev/null
+++ b/0002-Repeat-pututxline-if-it-fails-with-EINTR.patch
@@ -0,0 +1,105 @@
+From 896b3694ca062d747cd67e9e9ba246adb3fc706b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Mon, 5 Aug 2019 13:55:37 +0200
+Subject: [PATCH 2/2] Repeat pututxline() if it fails with EINTR
+
+This is a partial fix for rhbz#1688848. We cannot resolve it
+completely until glibc bug rhbz#1734791 is fixed. See
+https://bugzilla.redhat.com/show_bug.cgi?id=1688848#c13.
+
+The maximum number of attempts is currently 2, which might seem
+low. However setting it to 2 was a decision based on data - see
+https://bugzilla.redhat.com/show_bug.cgi?id=1688848#c16.
+
+Resolves: rhbz#1688848
+---
+ sysdeputil.c | 53 +++++++++++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 46 insertions(+), 7 deletions(-)
+
+diff --git a/sysdeputil.c b/sysdeputil.c
+index bd1e8c9..4fbcca7 100644
+--- a/sysdeputil.c
++++ b/sysdeputil.c
+@@ -1203,6 +1203,8 @@ void
+ vsf_insert_uwtmp(const struct mystr* p_user_str,
+ const struct mystr* p_host_str)
+ {
++ int attempts;
++
+ if (sizeof(s_utent.ut_line) < 16)
+ {
+ return;
+@@ -1231,16 +1233,35 @@ vsf_insert_uwtmp(const struct mystr* p_user_str,
+ vsf_sysutil_strcpy(s_utent.ut_host, str_getbuf(p_host_str),
+ sizeof(s_utent.ut_host));
+ s_utent.ut_tv.tv_sec = vsf_sysutil_get_time_sec();
+- setutxent();
+- (void) pututxline(&s_utent);
+- endutxent();
+- s_uwtmp_inserted = 1;
++ for (attempts = 2; attempts > 0; --attempts)
++ {
++ struct utmpx* p_res;
++ setutxent();
++ p_res = pututxline(&s_utent);
++ /* For now we'll ignore errors other than EINTR and EAGAIN */
++ if (p_res != NULL || (errno != EINTR && errno != EAGAIN))
++ {
++ break;
++ }
++ }
++ if (attempts == 0)
++ {
++ /* This makes us skip pututxline() in vsf_remove_uwtmp() */
++ s_uwtmp_inserted = -1;
++ }
++ else
++ {
++ s_uwtmp_inserted = 1;
++ endutxent();
++ }
+ updwtmpx(WTMPX_FILE, &s_utent);
+ }
+
+ void
+ vsf_remove_uwtmp(void)
+ {
++ int attempts;
++
+ if (!s_uwtmp_inserted)
+ {
+ return;
+@@ -1249,9 +1270,27 @@ vsf_remove_uwtmp(void)
+ vsf_sysutil_memclr(s_utent.ut_user, sizeof(s_utent.ut_user));
+ vsf_sysutil_memclr(s_utent.ut_host, sizeof(s_utent.ut_host));
+ s_utent.ut_tv.tv_sec = 0;
+- setutxent();
+- (void) pututxline(&s_utent);
+- endutxent();
++ if (s_uwtmp_inserted == 1)
++ {
++ for (attempts = 2; attempts > 0; --attempts)
++ {
++ struct utmpx* p_res;
++ setutxent();
++ p_res = pututxline(&s_utent);
++ /* For now we'll ignore errors other than EINTR and EAGAIN */
++ if (p_res != NULL || (errno != EINTR && errno != EAGAIN))
++ {
++ break;
++ }
++ }
++ if (attempts != 0)
++ {
++ endutxent();
++ }
++ }
++ /* Set s_uwtmp_inserted to 0 regardless of the result of
++ * pututxline() to make sure we won't run this function twice.
++ */
+ s_uwtmp_inserted = 0;
+ s_utent.ut_tv.tv_sec = vsf_sysutil_get_time_sec();
+ updwtmpx(WTMPX_FILE, &s_utent);
+--
+2.20.1
+
diff --git a/0003-Enable-build-with-TCP-Wrapper.patch b/0003-Enable-build-with-TCP-Wrapper.patch
new file mode 100644
index 0000000..e656776
--- /dev/null
+++ b/0003-Enable-build-with-TCP-Wrapper.patch
@@ -0,0 +1,25 @@
+From 1e0e2b13836d40f5a3f4cb20f2b3ea8204115b51 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Tue, 6 Sep 2016 13:42:09 +0200
+Subject: [PATCH 03/59] Enable build with TCP Wrapper
+
+---
+ builddefs.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/builddefs.h b/builddefs.h
+index 63cc62b..83de674 100644
+--- a/builddefs.h
++++ b/builddefs.h
+@@ -1,7 +1,7 @@
+ #ifndef VSF_BUILDDEFS_H
+ #define VSF_BUILDDEFS_H
+
+-#undef VSF_BUILD_TCPWRAPPERS
++#define VSF_BUILD_TCPWRAPPERS
+ #define VSF_BUILD_PAM
+ #define VSF_BUILD_SSL
+
+--
+2.14.4
+
diff --git a/0004-Use-etc-vsftpd-dir-for-config-files-instead-of-etc.patch b/0004-Use-etc-vsftpd-dir-for-config-files-instead-of-etc.patch
new file mode 100644
index 0000000..e82cd84
--- /dev/null
+++ b/0004-Use-etc-vsftpd-dir-for-config-files-instead-of-etc.patch
@@ -0,0 +1,483 @@
+From fff93602a4b252be8d674e27083dde68a7acf038 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Tue, 6 Sep 2016 13:46:03 +0200
+Subject: [PATCH 04/59] Use /etc/vsftpd/ dir for config files instead of /etc.
+
+---
+ EXAMPLE/INTERNET_SITE/README | 6 +++---
+ EXAMPLE/INTERNET_SITE_NOINETD/README | 4 ++--
+ EXAMPLE/PER_IP_CONFIG/README | 4 ++--
+ EXAMPLE/VIRTUAL_USERS/README | 14 +++++++-------
+ FAQ | 8 ++++----
+ INSTALL | 10 +++++-----
+ README | 5 +++++
+ defs.h | 2 +-
+ tunables.c | 10 +++++-----
+ vsftpd.8 | 10 +++++-----
+ vsftpd.conf | 20 +++++++++++++-------
+ vsftpd.conf.5 | 22 +++++++++++-----------
+ 12 files changed, 63 insertions(+), 52 deletions(-)
+
+diff --git a/EXAMPLE/INTERNET_SITE/README b/EXAMPLE/INTERNET_SITE/README
+index 12b10a5..fe3d7ca 100644
+--- a/EXAMPLE/INTERNET_SITE/README
++++ b/EXAMPLE/INTERNET_SITE/README
+@@ -41,13 +41,13 @@ no_access = 192.168.1.3
+ As an example of how to ban certain sites from connecting, 192.168.1.3 will
+ be denied access.
+
+-banner_fail = /etc/vsftpd.busy_banner
++banner_fail = /etc/vsftpd/busy_banner
+
+ This is the file to display to users if the connection is refused for whatever
+ reason (too many users, IP banned).
+
+ Example of how to populate it:
+-echo "421 Server busy, please try later." > /etc/vsftpd.busy_banner
++echo "421 Server busy, please try later." > /etc/vsftpd/busy_banner
+
+ log_on_success += PID HOST DURATION
+ log_on_failure += HOST
+@@ -62,7 +62,7 @@ Step 2) Set up your vsftpd configuration file.
+
+ An example file is supplied. Install it like this:
+
+-cp vsftpd.conf /etc
++cp vsftpd.conf /etc/vsftpd
+
+ Let's example the contents of the file:
+
+diff --git a/EXAMPLE/INTERNET_SITE_NOINETD/README b/EXAMPLE/INTERNET_SITE_NOINETD/README
+index ce17af2..9198c5f 100644
+--- a/EXAMPLE/INTERNET_SITE_NOINETD/README
++++ b/EXAMPLE/INTERNET_SITE_NOINETD/README
+@@ -17,7 +17,7 @@ even per-connect-IP configurability.
+
+ To use this example config:
+
+-1) Copy the vsftpd.conf file in this directory to /etc/vsftpd.conf.
++1) Copy the vsftpd.conf file in this directory to /etc/vsftpd/vsftpd.conf.
+
+ 2) Start up vsftpd, e.g.
+ vsftpd &
+@@ -51,5 +51,5 @@ in the vsftpd.conf:
+ listen_address=192.168.1.2
+
+ And launch vsftpd with a specific config file like this:
+-vsftpd /etc/vsftpd.conf.site1 &
++vsftpd /etc/vsftpd/vsftpd.conf.site1 &
+
+diff --git a/EXAMPLE/PER_IP_CONFIG/README b/EXAMPLE/PER_IP_CONFIG/README
+index a9ef352..34924d5 100644
+--- a/EXAMPLE/PER_IP_CONFIG/README
++++ b/EXAMPLE/PER_IP_CONFIG/README
+@@ -20,12 +20,12 @@ directory: hosts.allow. It lives at /etc/hosts.allow.
+
+ Let's have a look at the example:
+
+-vsftpd: 192.168.1.3: setenv VSFTPD_LOAD_CONF /etc/vsftpd_tcp_wrap.conf
++vsftpd: 192.168.1.3: setenv VSFTPD_LOAD_CONF /etc/vsftpd/tcp_wrap.conf
+ vsftpd: 192.168.1.4: DENY
+
+ The first line:
+ If a client connects from 192.168.1.3, then vsftpd will apply the vsftpd
+-config file /etc/vsftpd_tcp_wrap.conf to the session! These settings are
++config file /etc/vsftpd/tcp_wrap.conf to the session! These settings are
+ applied ON TOP of the default vsftpd.conf.
+ This is obviously very powerful. You might use this to apply different
+ access restrictions for some IPs (e.g. the ability to upload).
+diff --git a/EXAMPLE/VIRTUAL_USERS/README b/EXAMPLE/VIRTUAL_USERS/README
+index b48995d..72972fa 100644
+--- a/EXAMPLE/VIRTUAL_USERS/README
++++ b/EXAMPLE/VIRTUAL_USERS/README
+@@ -15,7 +15,7 @@ See example file "logins.txt" - this specifies "tom" with password "foo" and
+ "fred" with password "bar".
+ Whilst logged in as root, create the actual database file like this:
+
+-db_load -T -t hash -f logins.txt /etc/vsftpd_login.db
++db_load -T -t hash -f logins.txt /etc/vsftpd/login.db
+ (Requires the Berkeley db program installed).
+ NOTE: Many systems have multiple versions of "db" installed, so you may
+ need to use e.g. db3_load for correct operation. This is known to affect
+@@ -23,10 +23,10 @@ some Debian systems. The core issue is that pam_userdb expects its login
+ database to be a specific db version (often db3, whereas db4 may be installed
+ on your system).
+
+-This will create /etc/vsftpd_login.db. Obviously, you may want to make sure
++This will create /etc/vsftpd/login.db. Obviously, you may want to make sure
+ the permissions are restricted:
+
+-chmod 600 /etc/vsftpd_login.db
++chmod 600 /etc/vsftpd/login.db
+
+ For more information on maintaing your login database, look around for
+ documentation on "Berkeley DB", e.g.
+@@ -37,8 +37,8 @@ Step 2) Create a PAM file which uses your new database.
+
+ See the example file vsftpd.pam. It contains two lines:
+
+-auth required /lib/security/pam_userdb.so db=/etc/vsftpd_login
+-account required /lib/security/pam_userdb.so db=/etc/vsftpd_login
++auth required /lib/security/pam_userdb.so db=/etc/vsftpd/login
++account required /lib/security/pam_userdb.so db=/etc/vsftpd/login
+
+ This tells PAM to authenticate users using our new database. Copy this PAM
+ file to the PAM directory - typically /etc/pam.d/
+@@ -108,9 +108,9 @@ pasv_max_port=30999
+ These put a port range on passive FTP incoming requests - very useful if
+ you are configuring a firewall.
+
+-Copy the example vsftpd.conf file to /etc:
++Copy the example vsftpd.conf file to /etc/vsftpd:
+
+-cp vsftpd.conf /etc/
++cp vsftpd.conf /etc/vsftpd/
+
+
+ Step 5) Start up vsftpd.
+diff --git a/FAQ b/FAQ
+index 59fe56b..0142a0d 100644
+--- a/FAQ
++++ b/FAQ
+@@ -35,7 +35,7 @@ needs this user to run bits of itself with no privilege.
+ Q) Help! Local users cannot log in.
+ A) There are various possible problems.
+ A1) By default, vsftpd disables any logins other than anonymous logins. Put
+-local_enable=YES in your /etc/vsftpd.conf to allow local users to log in.
++local_enable=YES in your /etc/vsftpd/vsftpd.conf to allow local users to log in.
+ A2) vsftpd tries to link with PAM. (Run "ldd vsftpd" and look for libpam to
+ find out whether this has happened or not). If vsftpd links with PAM, then
+ you will need to have a PAM file installed for the vsftpd service. There is
+@@ -47,12 +47,12 @@ system have a "shadow.h" file in the include path?
+ A4) If you are not using PAM, then vsftpd will do its own check for a valid
+ user shell in /etc/shells. You may need to disable this if you use an invalid
+ shell to disable logins other than FTP logins. Put check_shell=NO in your
+-/etc/vsftpd.conf.
++/etc/vsftpd/vsftpd.conf.
+
+ Q) Help! Uploads or other write commands give me "500 Unknown command.".
+ A) By default, write commands, including uploads and new directories, are
+ disabled. This is a security measure. To enable writes, put write_enable=YES
+-in your /etc/vsftpd.conf.
++in your /etc/vsftpd/vsftpd.conf.
+
+ Q) Help! What are the security implications referred to in the
+ "chroot_local_user" option?
+@@ -88,7 +88,7 @@ A2) Alternatively, run as many copies as vsftpd as necessary, in standalone
+ mode. Use "listen_address=x.x.x.x" to set the virtual IP.
+
+ Q) Help! Does vsftpd support virtual users?
+-A) Yes, via PAM integration. Set "guest_enable=YES" in /etc/vsftpd.conf. This
++A) Yes, via PAM integration. Set "guest_enable=YES" in /etc/vsftpd/vsftpd.conf. This
+ has the effect of mapping every non-anonymous successful login to the local
+ username specified in "guest_username". Then, use PAM and (e.g.) its pam_userdb
+ module to provide authentication against an external (i.e. non-/etc/passwd)
+diff --git a/INSTALL b/INSTALL
+index 4f811aa..93a8a81 100644
+--- a/INSTALL
++++ b/INSTALL
+@@ -56,14 +56,14 @@ cp vsftpd.8 /usr/local/man/man8
+
+ "make install" doesn't copy the sample config file. It is recommended you
+ do this:
+-cp vsftpd.conf /etc
++cp vsftpd.conf /etc/vsftpd
+
+ Step 4) Smoke test (without an inetd).
+
+ vsftpd can run standalone or via an inetd (such as inetd or xinetd). You will
+ typically get more control running vsftpd from an inetd. But first we will run
+ it without, so we can check things are going well so far.
+-Edit /etc/vsftpd.conf, and add this line at the bottom:
++Edit /etc/vsftpd/vsftpd.conf, and add this line at the bottom:
+
+ listen=YES
+
+@@ -135,11 +135,11 @@ cp RedHat/vsftpd.pam /etc/pam.d/ftp
+ Step 7) Customize your configuration
+
+ As well as the above three pre-requisites, you are recommended to install a
+-config file. The default location for the config file is /etc/vsftpd.conf.
++config file. The default location for the config file is /etc/vsftpd/vsftpd.conf.
+ There is a sample vsftpd.conf in the distribution tarball. You probably want
+-to copy that to /etc/vsftpd.conf as a basis for modification, i.e.:
++to copy that to /etc/vsftpd/vsftpd.conf as a basis for modification, i.e.:
+
+-cp vsftpd.conf /etc
++cp vsftpd.conf /etc/vsftpd
+
+ The default configuration allows neither local user logins nor anonymous
+ uploads. You may wish to change these defaults.
+diff --git a/README b/README
+index 86643c1..adc7f42 100644
+--- a/README
++++ b/README
+@@ -37,3 +37,8 @@ All configuration options are documented in the manual page vsftpd.conf.5.
+ Various example configurations are discussed in the EXAMPLE directory.
+ Frequently asked questions are tackled in the FAQ file.
+
++Important Note
++==============
++The location of configuration files was changed to /etc/vsftpd/. If you want
++to migrate your old conf files from /etc (files vsftpd.xxxx.rpmsave) use
++/etc/vsfptd/vsftpd_conf_migrate.sh
+diff --git a/defs.h b/defs.h
+index 0ff5864..ca11eac 100644
+--- a/defs.h
++++ b/defs.h
+@@ -1,7 +1,7 @@
+ #ifndef VSF_DEFS_H
+ #define VSF_DEFS_H
+
+-#define VSFTP_DEFAULT_CONFIG "/etc/vsftpd.conf"
++#define VSFTP_DEFAULT_CONFIG "/etc/vsftpd/vsftpd.conf"
+
+ #define VSFTP_COMMAND_FD 0
+
+diff --git a/tunables.c b/tunables.c
+index 284a10d..0ac4c34 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -190,7 +190,7 @@ tunables_load_defaults()
+ tunable_listen_ipv6 = 0;
+ tunable_dual_log_enable = 0;
+ tunable_syslog_enable = 0;
+- tunable_background = 0;
++ tunable_background = 1;
+ tunable_virtual_use_local_privs = 0;
+ tunable_session_support = 0;
+ tunable_download_enable = 1;
+@@ -262,11 +262,11 @@ tunables_load_defaults()
+ install_str_setting(".message", &tunable_message_file);
+ install_str_setting("nobody", &tunable_nopriv_user);
+ install_str_setting(0, &tunable_ftpd_banner);
+- install_str_setting("/etc/vsftpd.banned_emails", &tunable_banned_email_file);
+- install_str_setting("/etc/vsftpd.chroot_list", &tunable_chroot_list_file);
++ install_str_setting("/etc/vsftpd/banned_emails", &tunable_banned_email_file);
++ install_str_setting("/etc/vsftpd/chroot_list", &tunable_chroot_list_file);
+ install_str_setting("ftp", &tunable_pam_service_name);
+ install_str_setting("ftp", &tunable_guest_username);
+- install_str_setting("/etc/vsftpd.user_list", &tunable_userlist_file);
++ install_str_setting("/etc/vsftpd/user_list", &tunable_userlist_file);
+ install_str_setting(0, &tunable_anon_root);
+ install_str_setting(0, &tunable_local_root);
+ install_str_setting(0, &tunable_banner_file);
+@@ -279,7 +279,7 @@ tunables_load_defaults()
+ install_str_setting(0, &tunable_hide_file);
+ install_str_setting(0, &tunable_deny_file);
+ install_str_setting(0, &tunable_user_sub_token);
+- install_str_setting("/etc/vsftpd.email_passwords",
++ install_str_setting("/etc/vsftpd/email_passwords",
+ &tunable_email_password_file);
+ install_str_setting("/usr/share/ssl/certs/vsftpd.pem",
+ &tunable_rsa_cert_file);
+diff --git a/vsftpd.8 b/vsftpd.8
+index 6640b57..c920e7d 100644
+--- a/vsftpd.8
++++ b/vsftpd.8
+@@ -21,7 +21,7 @@ itself will listen on the network. This latter mode is easier to use, and
+ recommended. It is activated by setting
+ .Pa listen=YES
+ in
+-.Pa /etc/vsftpd.conf .
++.Pa /etc/vsftpd/vsftpd.conf .
+ Direct execution of the
+ .Nm vsftpd
+ binary will then launch the FTP service ready for immediate client connections.
+@@ -33,7 +33,7 @@ as root. Any command line option not starting with a "-" character is treated
+ as a config file that will be loaded. Note that config files are loaded in the
+ strict order that they are encountered on the command line.
+ If no config files are specified, the default configuration file of
+-.Pa /etc/vsftpd.conf
++.Pa /etc/vsftpd/vsftpd.conf
+ will be loaded, after all other command line options are processed.
+ .Pp
+ Supported options are:
+@@ -47,14 +47,14 @@ their appearance on the command line, including intermingling with loading of
+ config files.
+ .El
+ .Sh EXAMPLES
+-vsftpd -olisten=NO /etc/vsftpd.conf -oftpd_banner=blah
++vsftpd -olisten=NO /etc/vsftpd/vsftpd.conf -oftpd_banner=blah
+ .Pp
+ That example overrides vsftpd's built-in default for the "listen" option to be
+-NO, but then loads /etc/vsftpd.conf which may override that setting. Finally,
++NO, but then loads /etc/vsftpd/vsftpd.conf which may override that setting. Finally,
+ the "ftpd_banner" setting is set to "blah", which overrides any default vsftpd
+ setting and any identical setting that was in the config file.
+ .Sh FILES
+-.Pa /etc/vsftpd.conf
++.Pa /etc/vsftpd/vsftpd.conf
+ .Sh SEE ALSO
+ .Xr vsftpd.conf 5
+ .end
+diff --git a/vsftpd.conf b/vsftpd.conf
+index cc1c607..db44170 100644
+--- a/vsftpd.conf
++++ b/vsftpd.conf
+@@ -1,4 +1,4 @@
+-# Example config file /etc/vsftpd.conf
++# Example config file /etc/vsftpd/vsftpd.conf
+ #
+ # The default compiled in settings are fairly paranoid. This sample file
+ # loosens things up a bit, to make the ftp daemon more usable.
+@@ -12,18 +12,20 @@
+ anonymous_enable=YES
+ #
+ # Uncomment this to allow local users to log in.
+-#local_enable=YES
++# When SELinux is enforcing check for SE bool ftp_home_dir
++local_enable=YES
+ #
+ # Uncomment this to enable any form of FTP write command.
+-#write_enable=YES
++write_enable=YES
+ #
+ # Default umask for local users is 077. You may wish to change this to 022,
+ # if your users expect that (022 is used by most other ftpd's)
+-#local_umask=022
++local_umask=022
+ #
+ # Uncomment this to allow the anonymous FTP user to upload files. This only
+ # has an effect if the above global write enable is activated. Also, you will
+ # obviously need to create a directory writable by the FTP user.
++# When SELinux is enforcing check for SE bool allow_ftpd_anon_write, allow_ftpd_full_access
+ #anon_upload_enable=YES
+ #
+ # Uncomment this if you want the anonymous FTP user to be able to create
+@@ -52,7 +54,7 @@ connect_from_port_20=YES
+ #
+ # If you want, you can have your log file in standard ftpd xferlog format.
+ # Note that the default log file location is /var/log/xferlog in this case.
+-#xferlog_std_format=YES
++xferlog_std_format=YES
+ #
+ # You may change the default value for timing out an idle session.
+ #idle_session_timeout=600
+@@ -87,7 +89,7 @@ connect_from_port_20=YES
+ # useful for combatting certain DoS attacks.
+ #deny_email_enable=YES
+ # (default follows)
+-#banned_email_file=/etc/vsftpd.banned_emails
++#banned_email_file=/etc/vsftpd/banned_emails
+ #
+ # You may specify an explicit list of local users to chroot() to their home
+ # directory. If chroot_local_user is YES, then this list becomes a list of
+@@ -98,7 +100,7 @@ connect_from_port_20=YES
+ #chroot_local_user=YES
+ #chroot_list_enable=YES
+ # (default follows)
+-#chroot_list_file=/etc/vsftpd.chroot_list
++#chroot_list_file=/etc/vsftpd/chroot_list
+ #
+ # You may activate the "-R" option to the builtin ls. This is disabled by
+ # default to avoid remote users being able to cause excessive I/O on large
+@@ -115,3 +117,7 @@ listen=YES
+ # sockets, you must run two copies of vsftpd with two configuration files.
+ # Make sure, that one of the listen options is commented !!
+ #listen_ipv6=YES
++
++pam_service_name=vsftpd
++userlist_enable=YES
++tcp_wrappers=YES
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index fcc6022..5e46a2f 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -4,7 +4,7 @@ vsftpd.conf \- config file for vsftpd
+ .SH DESCRIPTION
+ vsftpd.conf may be used to control various aspects of vsftpd's behaviour. By
+ default, vsftpd looks for this file at the location
+-.BR /etc/vsftpd.conf .
++.BR /etc/vsftpd/vsftpd.conf .
+ However, you may override this by specifying a command line argument to
+ vsftpd. The command line argument is the pathname of the configuration file
+ for vsftpd. This behaviour is useful because you may wish to use an advanced
+@@ -110,7 +110,7 @@ When enabled, and vsftpd is started in "listen" mode, vsftpd will background
+ the listener process. i.e. control will immediately be returned to the shell
+ which launched vsftpd.
+
+-Default: NO
++Default: YES
+ .TP
+ .B check_shell
+ Note! This option only has an effect for non-PAM builds of vsftpd. If disabled,
+@@ -138,7 +138,7 @@ chroot() jail in their home directory upon login. The meaning is slightly
+ different if chroot_local_user is set to YES. In this case, the list becomes
+ a list of users which are NOT to be placed in a chroot() jail.
+ By default, the file containing this list is
+-/etc/vsftpd.chroot_list, but you may override this with the
++/etc/vsftpd/chroot_list, but you may override this with the
+ .BR chroot_list_file
+ setting.
+
+@@ -177,7 +177,7 @@ Default: NO
+ .B deny_email_enable
+ If activated, you may provide a list of anonymous password e-mail responses
+ which cause login to be denied. By default, the file containing this list is
+-/etc/vsftpd.banned_emails, but you may override this with the
++/etc/vsftpd/banned_emails, but you may override this with the
+ .BR banned_email_file
+ setting.
+
+@@ -433,7 +433,7 @@ anonymous logins are prevented unless the password provided is listed in the
+ file specified by the
+ .BR email_password_file
+ setting. The file format is one password per line, no extra whitespace. The
+-default filename is /etc/vsftpd.email_passwords.
++default filename is /etc/vsftpd/email_passwords.
+
+ Default: NO
+ .TP
+@@ -764,7 +764,7 @@ passwords which are not permitted. This file is consulted if the option
+ .BR deny_email_enable
+ is enabled.
+
+-Default: /etc/vsftpd.banned_emails
++Default: /etc/vsftpd/banned_emails
+ .TP
+ .B banner_file
+ This option is the name of a file containing text to display when someone
+@@ -803,7 +803,7 @@ is enabled. If the option
+ is enabled, then the list file becomes a list of users to NOT place in a
+ chroot() jail.
+
+-Default: /etc/vsftpd.chroot_list
++Default: /etvsftpd.confc/vsftpd.chroot_list
+ .TP
+ .B cmds_allowed
+ This options specifies a comma separated list of allowed FTP commands (post
+@@ -864,7 +864,7 @@ This option can be used to provide an alternate file for usage by the
+ .BR secure_email_list_enable
+ setting.
+
+-Default: /etc/vsftpd.email_passwords
++Default: /etc/vsftpd/email_passwords
+ .TP
+ .B ftp_username
+ This is the name of the user we use for handling anonymous FTP. The home
+@@ -987,10 +987,10 @@ the manual page, on a per-user basis. Usage is simple, and is best illustrated
+ with an example. If you set
+ .BR user_config_dir
+ to be
+-.BR /etc/vsftpd_user_conf
++.BR /etc/vsftpd/user_conf
+ and then log on as the user "chris", then vsftpd will apply the settings in
+ the file
+-.BR /etc/vsftpd_user_conf/chris
++.BR /etc/vsftpd/user_conf/chris
+ for the duration of the session. The format of this file is as detailed in
+ this manual page! PLEASE NOTE that not all settings are effective on a
+ per-user basis. For example, many settings only prior to the user's session
+@@ -1026,7 +1026,7 @@ This option is the name of the file loaded when the
+ .BR userlist_enable
+ option is active.
+
+-Default: /etc/vsftpd.user_list
++Default: /etc/vsftpd/user_list
+ .TP
+ .B vsftpd_log_file
+ This option is the name of the file to which we write the vsftpd style
+--
+2.14.4
+
diff --git a/0005-Use-hostname-when-calling-PAM-authentication-module.patch b/0005-Use-hostname-when-calling-PAM-authentication-module.patch
new file mode 100644
index 0000000..af842f5
--- /dev/null
+++ b/0005-Use-hostname-when-calling-PAM-authentication-module.patch
@@ -0,0 +1,75 @@
+From 08c49b78942d40c99fae8c40e7668aa73e1bd695 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Tue, 6 Sep 2016 15:01:23 +0200
+Subject: [PATCH 05/59] Use hostname when calling PAM authentication module.
+
+Currently the vsftpd passes all logins as IP addresses
+into PAM. This prevents administrators from setting up
+ACLs based on domain (e.g. .example.com). This patch
+enables reverse host lookup and use hostname instead
+of address if there is one.
+---
+ sysdeputil.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/sysdeputil.c b/sysdeputil.c
+index 06f01f4..b2782da 100644
+--- a/sysdeputil.c
++++ b/sysdeputil.c
+@@ -16,6 +16,10 @@
+ #include "tunables.h"
+ #include "builddefs.h"
+
++/* For gethostbyaddr, inet_addr */
++#include <netdb.h>
++#include <arpa/inet.h>
++
+ /* For Linux, this adds nothing :-) */
+ #include "port/porting_junk.h"
+
+@@ -323,6 +327,10 @@ vsf_sysdep_check_auth(struct mystr* p_user_str,
+ const struct mystr* p_remote_host)
+ {
+ int retval = -1;
++#ifdef PAM_RHOST
++ struct sockaddr_in sin;
++ struct hostent *host;
++#endif
+ pam_item_t item;
+ const char* pam_user_name = 0;
+ struct pam_conv the_conv =
+@@ -346,7 +354,12 @@ vsf_sysdep_check_auth(struct mystr* p_user_str,
+ return 0;
+ }
+ #ifdef PAM_RHOST
+- retval = pam_set_item(s_pamh, PAM_RHOST, str_getbuf(p_remote_host));
++ sin.sin_addr.s_addr = inet_addr(str_getbuf(p_remote_host));
++ host = gethostbyaddr((char*)&sin.sin_addr.s_addr,sizeof(struct in_addr),AF_INET);
++ if (host != (struct hostent*)0)
++ retval = pam_set_item(s_pamh, PAM_RHOST, host->h_name);
++ else
++ retval = pam_set_item(s_pamh, PAM_RHOST, str_getbuf(p_remote_host));
+ if (retval != PAM_SUCCESS)
+ {
+ (void) pam_end(s_pamh, retval);
+@@ -559,7 +572,7 @@ vsf_sysdep_has_capabilities(void)
+ }
+ return s_runtime_has_caps;
+ }
+-
++
+ #ifndef VSF_SYSDEP_HAVE_LIBCAP
+ static int
+ do_checkcap(void)
+@@ -1081,7 +1094,7 @@ vsf_sysutil_recv_fd(const int sock_fd)
+ msg.msg_flags = 0;
+ /* In case something goes wrong, set the fd to -1 before the syscall */
+ p_fd = (int*)CMSG_DATA(CMSG_FIRSTHDR(&msg));
+- *p_fd = -1;
++ *p_fd = -1;
+ retval = recvmsg(sock_fd, &msg, 0);
+ if (retval != 1)
+ {
+--
+2.14.4
+
diff --git a/0006-Close-stdin-out-err-before-listening-for-incoming-co.patch b/0006-Close-stdin-out-err-before-listening-for-incoming-co.patch
new file mode 100644
index 0000000..f030f35
--- /dev/null
+++ b/0006-Close-stdin-out-err-before-listening-for-incoming-co.patch
@@ -0,0 +1,35 @@
+From 423cbf4ddca6578b87e0f8a3fc425688cd1ca89c Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Tue, 6 Sep 2016 16:18:39 +0200
+Subject: [PATCH 06/59] Close stdin/out/err before listening for incoming
+ connections.
+
+When running vsftpd as a stand-alone FTP daemon, vsftpd
+did not close stdin/out/err. This caused the start script
+to hang waiting for stdin to close. Before this patch was
+applied, one had to hit ctrl+c in order to get shell prompt
+back. Correct behavior:
+$ /etc/init.d/vsftpd start | tee
+Starting vsftpd for vsftpd: [ OK ]
+$
+---
+ standalone.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/standalone.c b/standalone.c
+index ba01ab1..e0f2d5b 100644
+--- a/standalone.c
++++ b/standalone.c
+@@ -130,6 +130,9 @@ vsf_standalone_main(void)
+ die("could not bind listening IPv6 socket");
+ }
+ }
++ vsf_sysutil_close(0);
++ vsf_sysutil_close(1);
++ vsf_sysutil_close(2);
+ retval = vsf_sysutil_listen(listen_sock, VSFTP_LISTEN_BACKLOG);
+ if (vsf_sysutil_retval_is_error(retval))
+ {
+--
+2.14.4
+
diff --git a/0007-Make-filename-filters-smarter.patch b/0007-Make-filename-filters-smarter.patch
new file mode 100644
index 0000000..6db2d1a
--- /dev/null
+++ b/0007-Make-filename-filters-smarter.patch
@@ -0,0 +1,102 @@
+From 548375b2122f83771dc0b8571f16e5b5adabba98 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Wed, 7 Sep 2016 10:04:31 +0200
+Subject: [PATCH 07/59] Make filename filters smarter.
+
+In the original version vsftpd was not able to prevent
+users from downloading for instance /etc/passwd by
+defining filters such as deny_file=/etc/passwd or /etc*
+or passwd. Example of erroneous behavior:
+230 Login successful.
+Remote system type is UNIX.
+Using binary mode to transfer files.
+ftp> cd /
+250 Directory successfully changed.
+ftp> cd /etc
+550 Permission denied.
+ftp> cd etc
+250 Directory successfully changed.
+ftp> get passwd
+local: passwd remote: passwd
+227 Entering Passive Mode (127,0,0,1,99,251)
+150 Opening BINARY mode data connection for passwd (2813 bytes).
+226 File send OK.
+2813 bytes received in 0.00016 seconds (1.7e+04 Kbytes/s)
+ftp> quit
+221 Goodbye.
+---
+ ls.c | 24 +++++++++++++++++++++++-
+ str.c | 11 +++++++++++
+ str.h | 1 +
+ 3 files changed, 35 insertions(+), 1 deletion(-)
+
+diff --git a/ls.c b/ls.c
+index 7e1376d..f489478 100644
+--- a/ls.c
++++ b/ls.c
+@@ -246,8 +246,30 @@ vsf_filename_passes_filter(const struct mystr* p_filename_str,
+ 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);
++
++ 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(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, p_filename_str);
++ }
++ else
++ str_copy (&name_remain_str, p_filename_str);
++ } else {
++ if (str_get_char_at(p_filter_str, 0) != '{')
++ str_basename (&name_remain_str, p_filename_str);
++ else
++ str_copy (&name_remain_str, p_filename_str);
++ }
++ } else
++ str_copy(&name_remain_str, p_filename_str);
+
+ while (!str_isempty(&filter_remain_str) && *iters < VSFTP_MATCHITERS_MAX)
+ {
+diff --git a/str.c b/str.c
+index 6596204..ba4b92a 100644
+--- a/str.c
++++ b/str.c
+@@ -711,3 +711,14 @@ str_replace_unprintable(struct mystr* p_str, char new_char)
+ }
+ }
+
++void
++str_basename (struct mystr* d_str, const struct mystr* path)
++{
++ static struct mystr tmp;
++
++ str_copy (&tmp, path);
++ str_split_char_reverse(&tmp, d_str, '/');
++
++ if (str_isempty(d_str))
++ str_copy (d_str, path);
++}
+diff --git a/str.h b/str.h
+index ab0a9a4..3a21b50 100644
+--- a/str.h
++++ b/str.h
+@@ -100,6 +100,7 @@ void str_replace_unprintable(struct mystr* p_str, char new_char);
+ 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);
+
+ /* 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
+--
+2.14.4
+
diff --git a/0008-Write-denied-logins-into-the-log.patch b/0008-Write-denied-logins-into-the-log.patch
new file mode 100644
index 0000000..5e16953
--- /dev/null
+++ b/0008-Write-denied-logins-into-the-log.patch
@@ -0,0 +1,147 @@
+From 75c172596aa9e7a9f32062579f7f98783341c924 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Wed, 7 Sep 2016 10:17:17 +0200
+Subject: [PATCH 08/59] Write denied logins into the log.
+
+This patch adds a new option 'userlist_log'. If enabled,
+every login denial based on the user list will be logged.
+---
+ logging.c | 7 +++++++
+ logging.h | 11 +++++++++++
+ parseconf.c | 1 +
+ prelogin.c | 14 ++++++++++++++
+ tunables.c | 2 ++
+ tunables.h | 1 +
+ vsftpd.conf.5 | 8 ++++++++
+ 7 files changed, 44 insertions(+)
+
+diff --git a/logging.c b/logging.c
+index ad531d6..99671b4 100644
+--- a/logging.c
++++ b/logging.c
+@@ -103,6 +103,13 @@ vsf_log_line(struct vsf_session* p_sess, enum EVSFLogEntryType what,
+ vsf_log_common(p_sess, 1, what, p_str);
+ }
+
++void
++vsf_log_failed_line(struct vsf_session* p_sess, enum EVSFLogEntryType what,
++ struct mystr* p_str)
++{
++ vsf_log_common(p_sess, 0, what, p_str);
++}
++
+ int
+ vsf_log_entry_pending(struct vsf_session* p_sess)
+ {
+diff --git a/logging.h b/logging.h
+index 48f88ec..1ff57d1 100644
+--- a/logging.h
++++ b/logging.h
+@@ -80,5 +80,16 @@ void vsf_log_do_log(struct vsf_session* p_sess, int succeeded);
+ void vsf_log_line(struct vsf_session* p_sess, enum EVSFLogEntryType what,
+ struct mystr* p_str);
+
++/* vsf_log_failed_line()
++ * PURPOSE
++ * Same as vsf_log_line(), except that it logs the line as failed operation.
++ * PARAMETERS
++ * p_sess - the current session object
++ * what - the type of operation to log
++ * p_str - the string to log
++ */
++void vsf_log_failed_line(struct vsf_session* p_sess, enum EVSFLogEntryType what,
++ struct mystr* p_str);
++
+ #endif /* VSF_LOGGING_H */
+
+diff --git a/parseconf.c b/parseconf.c
+index ea2242b..385afd2 100644
+--- a/parseconf.c
++++ b/parseconf.c
+@@ -91,6 +91,7 @@ parseconf_bool_array[] =
+ { "mdtm_write", &tunable_mdtm_write },
+ { "lock_upload_files", &tunable_lock_upload_files },
+ { "pasv_addr_resolve", &tunable_pasv_addr_resolve },
++ { "userlist_log", &tunable_userlist_log },
+ { "debug_ssl", &tunable_debug_ssl },
+ { "require_cert", &tunable_require_cert },
+ { "validate_cert", &tunable_validate_cert },
+diff --git a/prelogin.c b/prelogin.c
+index df4aade..1588bc1 100644
+--- a/prelogin.c
++++ b/prelogin.c
+@@ -246,6 +246,20 @@ handle_user_command(struct vsf_session* p_sess)
+ check_login_delay();
+ vsf_cmdio_write(p_sess, FTP_LOGINERR, "Permission denied.");
+ check_login_fails(p_sess);
++ if (tunable_userlist_log)
++ {
++ struct mystr str_log_line = INIT_MYSTR;
++ if (tunable_userlist_deny)
++ {
++ str_alloc_text(&str_log_line, "User is in the deny user list.");
++ }
++ else
++ {
++ str_alloc_text(&str_log_line, "User is not in the allow user list.");
++ }
++ vsf_log_failed_line(p_sess, kVSFLogEntryLogin, &str_log_line);
++ str_free(&str_log_line);
++ }
+ str_empty(&p_sess->user_str);
+ return;
+ }
+diff --git a/tunables.c b/tunables.c
+index 0ac4c34..b30fca1 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -72,6 +72,7 @@ int tunable_force_anon_data_ssl;
+ int tunable_mdtm_write;
+ int tunable_lock_upload_files;
+ int tunable_pasv_addr_resolve;
++int tunable_userlist_log;
+ int tunable_debug_ssl;
+ int tunable_require_cert;
+ int tunable_validate_cert;
+@@ -212,6 +213,7 @@ tunables_load_defaults()
+ tunable_mdtm_write = 1;
+ tunable_lock_upload_files = 1;
+ tunable_pasv_addr_resolve = 0;
++ tunable_userlist_log = 0;
+ tunable_debug_ssl = 0;
+ tunable_require_cert = 0;
+ tunable_validate_cert = 0;
+diff --git a/tunables.h b/tunables.h
+index 05d2456..e44d64c 100644
+--- a/tunables.h
++++ b/tunables.h
+@@ -73,6 +73,7 @@ extern int tunable_force_anon_data_ssl; /* Require anon data uses SSL */
+ extern int tunable_mdtm_write; /* Allow MDTM to set timestamps */
+ extern int tunable_lock_upload_files; /* Lock uploading files */
+ extern int tunable_pasv_addr_resolve; /* DNS resolve pasv_addr */
++extern int tunable_userlist_log; /* Log every failed login attempt */
+ extern int tunable_debug_ssl; /* Verbose SSL logging */
+ extern int tunable_require_cert; /* SSL client cert required */
+ extern int tunable_validate_cert; /* SSL certs must be valid */
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index 5e46a2f..9d767b1 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -586,6 +586,14 @@ Default: NO
+ If set to yes, all SSL client certificates received must validate OK.
+ Self-signed certs do not constitute OK validation. (New in v2.0.6).
+
++Default: NO
++.TP
++.B userlist_log
++This option is examined if
++.BR userlist_enable
++is activated. If enabled, every login denial based on the user list will be
++logged.
++
+ Default: NO
+ .TP
+ .B virtual_use_local_privs
+--
+2.14.4
+
diff --git a/0009-Trim-whitespaces-when-reading-configuration.patch b/0009-Trim-whitespaces-when-reading-configuration.patch
new file mode 100644
index 0000000..97f3e4f
--- /dev/null
+++ b/0009-Trim-whitespaces-when-reading-configuration.patch
@@ -0,0 +1,99 @@
+From d024bc27cee40f21e6a3841266062408c44e56fb Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Wed, 7 Sep 2016 10:35:54 +0200
+Subject: [PATCH 09/59] Trim whitespaces when reading configuration.
+
+---
+ parseconf.c | 2 +-
+ str.c | 12 ++++++++++++
+ str.h | 1 +
+ sysutil.c | 12 ++++++++++++
+ sysutil.h | 1 +
+ 5 files changed, 27 insertions(+), 1 deletion(-)
+
+diff --git a/parseconf.c b/parseconf.c
+index 385afd2..30df598 100644
+--- a/parseconf.c
++++ b/parseconf.c
+@@ -280,7 +280,7 @@ vsf_parseconf_load_setting(const char* p_setting, int errs_fatal)
+ }
+ else
+ {
+- *p_curr_setting = str_strdup(&s_value_str);
++ *p_curr_setting = str_strdup_trimmed(&s_value_str);
+ }
+ return;
+ }
+diff --git a/str.c b/str.c
+index ba4b92a..41b27db 100644
+--- a/str.c
++++ b/str.c
+@@ -104,6 +104,18 @@ str_strdup(const struct mystr* p_str)
+ return vsf_sysutil_strdup(str_getbuf(p_str));
+ }
+
++const char*
++str_strdup_trimmed(const struct mystr* p_str)
++{
++ const char* p_trimmed = str_getbuf(p_str);
++ int h, t, newlen;
++
++ for (h = 0; h < (int)str_getlen(p_str) && vsf_sysutil_isspace(p_trimmed[h]); h++) ;
++ for (t = str_getlen(p_str) - 1; t >= 0 && vsf_sysutil_isspace(p_trimmed[t]); t--) ;
++ newlen = t - h + 1;
++ return newlen ? vsf_sysutil_strndup(p_trimmed+h, (unsigned int)newlen) : 0L;
++}
++
+ void
+ str_alloc_alt_term(struct mystr* p_str, const char* p_src, char term)
+ {
+diff --git a/str.h b/str.h
+index 3a21b50..44270da 100644
+--- a/str.h
++++ b/str.h
+@@ -31,6 +31,7 @@ void str_alloc_ulong(struct mystr* p_str, unsigned long the_ulong);
+ void str_alloc_filesize_t(struct mystr* p_str, filesize_t the_filesize);
+ void str_copy(struct mystr* p_dest, const struct mystr* p_src);
+ const char* str_strdup(const struct mystr* p_str);
++const char* str_strdup_trimmed(const struct mystr* p_str);
+ void str_empty(struct mystr* p_str);
+ void str_free(struct mystr* p_str);
+ void str_trunc(struct mystr* p_str, unsigned int trunc_len);
+diff --git a/sysutil.c b/sysutil.c
+index 5cdb6ef..428a34a 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -1035,6 +1035,18 @@ vsf_sysutil_strdup(const char* p_str)
+ return strdup(p_str);
+ }
+
++char*
++vsf_sysutil_strndup(const char* p_str, unsigned int p_len)
++{
++ char *new = (char *)malloc(p_len+1);
++
++ if (new == NULL)
++ return NULL;
++
++ new[p_len]='\0';
++ return (char *)memcpy(new, p_str, p_len);
++}
++
+ void
+ vsf_sysutil_memclr(void* p_dest, unsigned int size)
+ {
+diff --git a/sysutil.h b/sysutil.h
+index c34778c..c2ddd15 100644
+--- a/sysutil.h
++++ b/sysutil.h
+@@ -186,6 +186,7 @@ int vsf_sysutil_wait_get_exitcode(
+ /* Various string functions */
+ unsigned int vsf_sysutil_strlen(const char* p_text);
+ char* vsf_sysutil_strdup(const char* p_str);
++char* vsf_sysutil_strndup(const char* p_str, unsigned int p_len);
+ void vsf_sysutil_memclr(void* p_dest, unsigned int size);
+ void vsf_sysutil_memcpy(void* p_dest, const void* p_src,
+ const unsigned int size);
+--
+2.14.4
+
diff --git a/0010-Improve-daemonizing.patch b/0010-Improve-daemonizing.patch
new file mode 100644
index 0000000..d2de767
--- /dev/null
+++ b/0010-Improve-daemonizing.patch
@@ -0,0 +1,209 @@
+From 569e7078244470ac0fcc2af3947c2735338555ec Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Wed, 7 Sep 2016 11:29:29 +0200
+Subject: [PATCH 10/59] Improve daemonizing
+
+Init script gets correct return code if binding fails.
+---
+ standalone.c | 38 +++++++++++++++++++++++++++++++++++++-
+ sysutil.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ sysutil.h | 7 ++++++-
+ 3 files changed, 102 insertions(+), 2 deletions(-)
+
+diff --git a/standalone.c b/standalone.c
+index e0f2d5b..3b65ea2 100644
+--- a/standalone.c
++++ b/standalone.c
+@@ -26,6 +26,8 @@ static unsigned int s_ipaddr_size;
+
+ static void handle_sigchld(void* duff);
+ static void handle_sighup(void* duff);
++static void handle_sigusr1(int sig);
++static void handle_sigalrm(int sig);
+ static void prepare_child(int sockfd);
+ static unsigned int handle_ip_count(void* p_raw_addr);
+ static void drop_ip_count(void* p_raw_addr);
+@@ -46,11 +48,23 @@ vsf_standalone_main(void)
+ }
+ if (tunable_background)
+ {
++ vsf_sysutil_sigaction(kVSFSysUtilSigALRM, handle_sigalrm);
++ vsf_sysutil_sigaction(kVSFSysUtilSigUSR1, handle_sigusr1);
++
+ int forkret = vsf_sysutil_fork();
+ if (forkret > 0)
+ {
+ /* Parent, just exit */
+- vsf_sysutil_exit(0);
++ vsf_sysutil_set_alarm(3);
++ vsf_sysutil_pause();
++
++ vsf_sysutil_exit(1);
++ }
++ else if (forkret == 0)
++ {
++ // Son, restore original signal handler
++ vsf_sysutil_sigaction(kVSFSysUtilSigALRM, 0L);
++ vsf_sysutil_sigaction(kVSFSysUtilSigUSR1, 0L);
+ }
+ /* Son, close standard FDs to avoid SSH hang-on-exit */
+ vsf_sysutil_reopen_standard_fds();
+@@ -99,6 +113,10 @@ vsf_standalone_main(void)
+ {
+ die("could not bind listening IPv4 socket");
+ }
++ if (tunable_background)
++ {
++ vsf_sysutil_kill(vsf_sysutil_getppid(), kVSFSysUtilSigUSR1);
++ }
+ }
+ else
+ {
+@@ -129,6 +147,10 @@ vsf_standalone_main(void)
+ {
+ die("could not bind listening IPv6 socket");
+ }
++ if (tunable_background)
++ {
++ vsf_sysutil_kill(vsf_sysutil_getppid(), kVSFSysUtilSigUSR1);
++ }
+ }
+ vsf_sysutil_close(0);
+ vsf_sysutil_close(1);
+@@ -268,6 +290,20 @@ handle_sighup(void* duff)
+ vsf_parseconf_load_file(0, 0);
+ }
+
++static void
++handle_sigalrm(int sig)
++{
++ (void)sig; // avoid unused parameter error
++ vsf_sysutil_exit(1);
++}
++
++static void
++handle_sigusr1(int sig)
++{
++ (void)sig; // avoid unused parameter error
++ vsf_sysutil_exit(0);
++}
++
+ static unsigned int
+ hash_ip(unsigned int buckets, void* p_key)
+ {
+diff --git a/sysutil.c b/sysutil.c
+index 428a34a..c848356 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -201,6 +201,9 @@ vsf_sysutil_translate_sig(const enum EVSFSysUtilSignal sig)
+ case kVSFSysUtilSigHUP:
+ realsig = SIGHUP;
+ break;
++ case kVSFSysUtilSigUSR1:
++ realsig = SIGUSR1;
++ break;
+ default:
+ bug("unknown signal in vsf_sysutil_translate_sig");
+ break;
+@@ -549,6 +552,12 @@ vsf_sysutil_getpid(void)
+ return (unsigned int) s_current_pid;
+ }
+
++unsigned int
++vsf_sysutil_getppid(void)
++{
++ return (unsigned int)getppid();
++}
++
+ int
+ vsf_sysutil_fork(void)
+ {
+@@ -2871,3 +2880,53 @@ vsf_sysutil_post_fork()
+ s_sig_details[i].pending = 0;
+ }
+ }
++
++static struct sigaction sigalr, sigusr1;
++
++void
++vsf_sysutil_sigaction(const enum EVSFSysUtilSignal sig, void (*p_handlefunc)(int))
++{
++ int realsig = vsf_sysutil_translate_sig(sig);
++ int retval;
++ struct sigaction sigact, *origsigact=NULL;
++ if (realsig==SIGALRM)
++ {
++ origsigact = &sigalr;
++ }
++ else if (realsig==SIGUSR1)
++ {
++ origsigact = &sigusr1;
++ }
++ vsf_sysutil_memclr(&sigact, sizeof(sigact));
++ if (p_handlefunc != NULL)
++ {
++ sigact.sa_handler = p_handlefunc;
++ retval = sigfillset(&sigact.sa_mask);
++ if (retval != 0)
++ {
++ die("sigfillset");
++ }
++ retval = sigaction(realsig, &sigact, origsigact);
++ }
++ else
++ {
++ retval = sigaction(realsig, origsigact, NULL);
++ }
++ if (retval != 0)
++ {
++ die("sigaction");
++ }
++}
++
++int
++vsf_sysutil_kill(int pid, int sig)
++{
++ int realsig = vsf_sysutil_translate_sig(sig);
++ return kill(pid, realsig);
++}
++
++int
++vsf_sysutil_pause()
++{
++ return pause();
++}
+diff --git a/sysutil.h b/sysutil.h
+index c2ddd15..bfc92cb 100644
+--- a/sysutil.h
++++ b/sysutil.h
+@@ -30,7 +30,8 @@ enum EVSFSysUtilSignal
+ kVSFSysUtilSigCHLD,
+ kVSFSysUtilSigPIPE,
+ kVSFSysUtilSigURG,
+- kVSFSysUtilSigHUP
++ kVSFSysUtilSigHUP,
++ kVSFSysUtilSigUSR1
+ };
+ enum EVSFSysUtilInterruptContext
+ {
+@@ -165,6 +166,7 @@ void vsf_sysutil_free(void* p_ptr);
+
+ /* Process creation/exit/process handling */
+ unsigned int vsf_sysutil_getpid(void);
++unsigned int vsf_sysutil_getppid(void);
+ void vsf_sysutil_post_fork(void);
+ int vsf_sysutil_fork(void);
+ int vsf_sysutil_fork_failok(void);
+@@ -182,6 +184,9 @@ int vsf_sysutil_wait_exited_normally(
+ const struct vsf_sysutil_wait_retval* p_waitret);
+ int vsf_sysutil_wait_get_exitcode(
+ const struct vsf_sysutil_wait_retval* p_waitret);
++void vsf_sysutil_sigaction(const enum EVSFSysUtilSignal sig, void (*p_handlefunc)(int));
++int vsf_sysutil_kill(int pid, int sig);
++int vsf_sysutil_pause();
+
+ /* Various string functions */
+ unsigned int vsf_sysutil_strlen(const char* p_text);
+--
+2.14.4
+
diff --git a/0011-Fix-listing-with-more-than-one-star.patch b/0011-Fix-listing-with-more-than-one-star.patch
new file mode 100644
index 0000000..a675978
--- /dev/null
+++ b/0011-Fix-listing-with-more-than-one-star.patch
@@ -0,0 +1,38 @@
+From 32e6642640635d7305969f808b5badb706a11bff Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Wed, 7 Sep 2016 11:36:17 +0200
+Subject: [PATCH 11/59] Fix listing with more than one star '*'.
+
+This is a regression introduced by some previous patch.
+---
+ ls.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/ls.c b/ls.c
+index f489478..616b2d9 100644
+--- a/ls.c
++++ b/ls.c
+@@ -311,6 +311,20 @@ vsf_filename_passes_filter(const struct mystr* p_filename_str,
+ {
+ 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));
+--
+2.14.4
+
diff --git a/0012-Replace-syscall-__NR_clone-.-with-clone.patch b/0012-Replace-syscall-__NR_clone-.-with-clone.patch
new file mode 100644
index 0000000..84d01e6
--- /dev/null
+++ b/0012-Replace-syscall-__NR_clone-.-with-clone.patch
@@ -0,0 +1,35 @@
+From 0c3a1123c391995ab46cfde603fa025ff180a819 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Wed, 7 Sep 2016 11:43:54 +0200
+Subject: [PATCH 12/59] Replace syscall(__NR_clone ..) with clone ()
+
+in order to fix incorrect order of params on s390 arch
+---
+ sysdeputil.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/sysdeputil.c b/sysdeputil.c
+index b2782da..3bbabaa 100644
+--- a/sysdeputil.c
++++ b/sysdeputil.c
+@@ -1306,7 +1306,7 @@ vsf_sysutil_fork_isolate_failok()
+ static int cloneflags_work = 1;
+ if (cloneflags_work)
+ {
+- int ret = syscall(__NR_clone, CLONE_NEWPID | CLONE_NEWIPC | SIGCHLD, NULL);
++ int ret = clone(NULL, NULL, CLONE_NEWPID | CLONE_NEWIPC | SIGCHLD, NULL);
+ if (ret != -1 || (errno != EINVAL && errno != EPERM))
+ {
+ if (ret == 0)
+@@ -1328,7 +1328,7 @@ vsf_sysutil_fork_newnet()
+ static int cloneflags_work = 1;
+ if (cloneflags_work)
+ {
+- int ret = syscall(__NR_clone, CLONE_NEWNET | SIGCHLD, NULL);
++ int ret = clone(NULL, NULL, CLONE_NEWNET | SIGCHLD, NULL);
+ if (ret != -1 || (errno != EINVAL && errno != EPERM))
+ {
+ if (ret == 0)
+--
+2.14.4
+
diff --git a/0013-Extend-man-pages-with-systemd-info.patch b/0013-Extend-man-pages-with-systemd-info.patch
new file mode 100644
index 0000000..5dcd965
--- /dev/null
+++ b/0013-Extend-man-pages-with-systemd-info.patch
@@ -0,0 +1,86 @@
+From 813a4bc45d45f4af94c699893cb2d2ba998d5d31 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Wed, 7 Sep 2016 11:53:07 +0200
+Subject: [PATCH 13/59] Extend man pages with systemd info.
+
+Man pages now reflect how is vsftpd used as
+systemd service.
+---
+ vsftpd.8 | 24 ++++++++++++++++++++++++
+ vsftpd.conf.5 | 18 +++++++++++++++++-
+ 2 files changed, 41 insertions(+), 1 deletion(-)
+
+diff --git a/vsftpd.8 b/vsftpd.8
+index c920e7d..fbeb1a2 100644
+--- a/vsftpd.8
++++ b/vsftpd.8
+@@ -25,6 +25,23 @@ in
+ Direct execution of the
+ .Nm vsftpd
+ binary will then launch the FTP service ready for immediate client connections.
++.Pp
++Systemd changes the vsftpd daemon start-up. The vsftpd package contains vsftpd-generator script generating symbolic links to /var/run/systemd/generator/vsftpd.target.wants directory. The generator is called during e.g. 'systemctl --system daemon-reload'. All these symbolic links link /usr/lib/systemd/system/vsftpd@.service file.
++The vsftpd daemon(s) is/are controlled by one of following ways:
++.Pp
++1. Single daemon using default /etc/vsftpd/vsftpd.conf configuration file
++.br
++# systemctl {start,stop,...} vsftpd[.service]
++.Pp
++2. Single daemon using /etc/vsftpd/<conf-name>.conf
++.br
++# systemctl {start,stop,...} vsftpd@<conf-name>[.service]
++.Pp
++3. All instances together
++.br
++# systemctl {restart,stop} vsftpd.target
++.Pp
++See systemd.unit(5), systemd.target(5) for further details.
+ .Sh OPTIONS
+ An optional
+ configuration file or files
+@@ -55,6 +72,13 @@ the "ftpd_banner" setting is set to "blah", which overrides any default vsftpd
+ setting and any identical setting that was in the config file.
+ .Sh FILES
+ .Pa /etc/vsftpd/vsftpd.conf
++.Pp
++.Pa /usr/lib/systemd/system/vsftpd.service
++.Pp
++.Pa /usr/lib/systemd/system/vsftpd@.service
++.Pp
++.Pa /usr/lib/systemd/system/vsftpd.target
+ .Sh SEE ALSO
+ .Xr vsftpd.conf 5
++.Xr systemd.unit 5
+ .end
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index 9d767b1..0744f85 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -12,7 +12,23 @@ inetd such as
+ .BR xinetd
+ to launch vsftpd with different configuration files on a per virtual host
+ basis.
+-
++.P
++Systemd changes the vsftpd daemon start-up. The vsftpd package contains vsftpd-generator script generating symbolic links to /var/run/systemd/generator/vsftpd.target.wants directory. The generator is called during e. g. 'systemctl --system daemon-reload'. All these symbolic links link /usr/lib/systemd/system/vsftpd@.service file.
++The vsftpd daemon(s) is/are controlled by one of following ways:
++.P
++1. Single daemon using default /etc/vsftpd/vsftpd.conf configuration file
++.br
++# systemctl {start,stop,...} vsftpd[.service]
++.P
++2. Single daemon using /etc/vsftpd/<config-filename>.conf
++.br
++# systemctl {start,stop,...} vsftpd@<config-filename-without-extension>[.service]
++.P
++3. All instances together
++.br
++# systemctl {restart,stop} vsftpd.target
++.P
++See systemd.unit(5), systemd.target(5) for further details.
+ .SH FORMAT
+ The format of vsftpd.conf is very simple. Each line is either a comment or
+ a directive. Comment lines start with a # and are ignored. A directive line
+--
+2.14.4
+
diff --git a/0014-Add-support-for-square-brackets-in-ls.patch b/0014-Add-support-for-square-brackets-in-ls.patch
new file mode 100644
index 0000000..27f5374
--- /dev/null
+++ b/0014-Add-support-for-square-brackets-in-ls.patch
@@ -0,0 +1,277 @@
+From ba0520650ae7f9f63e48ba9fb3a94297aebe2d0c Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Wed, 7 Sep 2016 14:22:21 +0200
+Subject: [PATCH 14/59] Add support for square brackets in ls.
+
+---
+ ls.c | 222 +++++++++++++++++++++++++++++++++++++++++++++----------------------
+ 1 file changed, 150 insertions(+), 72 deletions(-)
+
+diff --git a/ls.c b/ls.c
+index 616b2d9..b840136 100644
+--- a/ls.c
++++ b/ls.c
+@@ -246,7 +246,7 @@ vsf_filename_passes_filter(const struct mystr* p_filename_str,
+ 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 mystr* p_filename_str,
+ 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 mystr* p_filename_str,
+ 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))
++ struct str_locate_result end_sqb =
++ str_locate_char(&filter_remain_str, ']');
++ must_match_at_current_pos = 1;
++ if (end_sqb.found)
+ {
+- 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))
++ 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.
+--
+2.14.4
+
diff --git a/0015-Listen-on-IPv6-by-default.patch b/0015-Listen-on-IPv6-by-default.patch
new file mode 100644
index 0000000..b762b09
--- /dev/null
+++ b/0015-Listen-on-IPv6-by-default.patch
@@ -0,0 +1,55 @@
+From c5daaedf1efe23b397a5950f5503f5cbfac871c8 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Wed, 7 Sep 2016 14:25:28 +0200
+Subject: [PATCH 15/59] Listen on IPv6 by default.
+
+---
+ vsftpd.conf | 14 +++++++++-----
+ vsftpd.conf.5 | 5 +++--
+ 2 files changed, 12 insertions(+), 7 deletions(-)
+
+diff --git a/vsftpd.conf b/vsftpd.conf
+index db44170..ae6c6c9 100644
+--- a/vsftpd.conf
++++ b/vsftpd.conf
+@@ -111,12 +111,16 @@ xferlog_std_format=YES
+ # When "listen" directive is enabled, vsftpd runs in standalone mode and
+ # listens on IPv4 sockets. This directive cannot be used in conjunction
+ # with the listen_ipv6 directive.
+-listen=YES
+-#
+-# This directive enables listening on IPv6 sockets. To listen on IPv4 and IPv6
+-# sockets, you must run two copies of vsftpd with two configuration files.
++listen=NO
++#
++# This directive enables listening on IPv6 sockets. By default, listening
++# on the IPv6 "any" address (::) will accept connections from both IPv6
++# and IPv4 clients. It is not necessary to listen on *both* IPv4 and IPv6
++# sockets. If you want that (perhaps because you want to listen on specific
++# addresses) then you must run two copies of vsftpd with two configuration
++# files.
+ # Make sure, that one of the listen options is commented !!
+-#listen_ipv6=YES
++listen_ipv6=YES
+
+ pam_service_name=vsftpd
+ userlist_enable=YES
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index 0744f85..72bb86f 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -297,8 +297,9 @@ Default: NO
+ .TP
+ .B listen_ipv6
+ Like the listen parameter, except vsftpd will listen on an IPv6 socket instead
+-of an IPv4 one. This parameter and the listen parameter are mutually
+-exclusive.
++of an IPv4 one. Note that a socket listening on the IPv6 "any" address (::)
++will accept both IPv6 and IPv4 connections by default. This parameter and the
++listen parameter are mutually exclusive.
+
+ Default: NO
+ .TP
+--
+2.14.4
+
diff --git a/0016-Increase-VSFTP_AS_LIMIT-from-200UL-to-400UL.patch b/0016-Increase-VSFTP_AS_LIMIT-from-200UL-to-400UL.patch
new file mode 100644
index 0000000..fae6b9c
--- /dev/null
+++ b/0016-Increase-VSFTP_AS_LIMIT-from-200UL-to-400UL.patch
@@ -0,0 +1,27 @@
+From 048208a4db5d7164d89ba5d7545e281d0a3472d3 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Wed, 7 Sep 2016 15:35:59 +0200
+Subject: [PATCH 16/59] Increase VSFTP_AS_LIMIT from 200UL to 400UL.
+
+When using a PAM module to get users from LDAP or database the old
+limit was insufficient.
+---
+ defs.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/defs.h b/defs.h
+index ca11eac..bde3232 100644
+--- a/defs.h
++++ b/defs.h
+@@ -19,7 +19,7 @@
+ /* Must be at least the size of VSFTP_MAX_COMMAND_LINE, VSFTP_DIR_BUFSIZE and
+ VSFTP_DATA_BUFSIZE*2 */
+ #define VSFTP_PRIVSOCK_MAXSTR VSFTP_DATA_BUFSIZE * 2
+-#define VSFTP_AS_LIMIT 200UL * 1024 * 1024
++#define VSFTP_AS_LIMIT 400UL * 1024 * 1024
+
+ #endif /* VSF_DEFS_H */
+
+--
+2.14.4
+
diff --git a/0017-Fix-an-issue-with-timestamps-during-DST.patch b/0017-Fix-an-issue-with-timestamps-during-DST.patch
new file mode 100644
index 0000000..f331433
--- /dev/null
+++ b/0017-Fix-an-issue-with-timestamps-during-DST.patch
@@ -0,0 +1,161 @@
+From 5ec0b86e5c1ff060720b5a6cd1af9d93ec993650 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 29 Sep 2016 11:14:03 +0200
+Subject: [PATCH 17/59] Fix an issue with timestamps during DST.
+
+vsftpd now checks whether a file was uploaded during DST and
+adjust the timestamp accordingly.
+---
+ sysutil.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 77 insertions(+), 27 deletions(-)
+
+diff --git a/sysutil.c b/sysutil.c
+index c848356..2abdd13 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -26,8 +26,10 @@
+ /* For Linux, this adds nothing :-) */
+ #include "port/porting_junk.h"
+
++#define F_LOCALTIME "/etc/localtime"
++#define BUFTZSIZ 64
++
+ #include <signal.h>
+-#include <string.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <sys/types.h>
+@@ -56,6 +58,11 @@
+ #include <netdb.h>
+ #include <sys/resource.h>
+
++#ifndef __USE_GNU
++ #define __USE_GNU
++#endif
++#include <string.h>
++
+ /* Private variables to this file */
+ /* Current umask() */
+ static unsigned int s_current_umask;
+@@ -2574,49 +2581,92 @@ error:
+ die("reopening standard file descriptors to /dev/null failed");
+ }
+
++char* vsf_sysutil_get_tz()
++{
++ char *ret_tz = NULL;
++ char buff[BUFTZSIZ];
++ off_t s_pos, e_pos;
++ size_t rcnt, rest;
++ int fd;
++
++ if ((fd = open(F_LOCALTIME, O_RDONLY)) > -1)
++ {
++ if ((e_pos = lseek(fd, 0, SEEK_END)) <= 0)
++ {
++ close(fd);
++ return NULL;
++ }
++ s_pos = e_pos > BUFTZSIZ ? e_pos - BUFTZSIZ : 0;
++ lseek(fd, s_pos, SEEK_SET);
++ rcnt = read(fd, buff, BUFTZSIZ);
++
++ if (rcnt && buff[rcnt-1] == '\n')
++ {
++ buff[rcnt-1] = 0;
++ e_pos--;
++ }
++
++ do {
++ char *nl = memrchr(buff, '\n', rcnt);
++ if (rcnt && nl)
++ {
++ int offset = (++nl) - buff;
++ int len = e_pos - s_pos - offset;
++ if (len)
++ {
++ lseek(fd, s_pos + offset, SEEK_SET);
++ ret_tz = calloc(1, len+4);
++ memcpy(ret_tz, "TZ=", 3);
++ rcnt = read(fd, ret_tz+3, len);
++ }
++ break;
++ }
++ if (!s_pos)
++ {
++ break;
++ }
++ rest = s_pos > BUFTZSIZ ? s_pos - BUFTZSIZ : 0;
++ s_pos -= rest;
++ lseek(fd, s_pos, SEEK_SET);
++ rcnt = read(fd, buff, rest);
++ } while (rcnt > 0);
++
++ close (fd);
++ }
++
++ return ret_tz;
++}
++
+ void
+ vsf_sysutil_tzset(void)
+ {
+ int retval;
+- char tzbuf[sizeof("+HHMM!")];
++ char *tz=NULL, tzbuf[sizeof("+HHMM!")];
+ time_t the_time = time(NULL);
+ struct tm* p_tm;
++
++ /* Set our timezone in the TZ environment variable to cater for the fact
++ * that modern glibc does not cache /etc/localtime (which becomes inaccessible
++ * when we chroot().
++ */
++ tz = vsf_sysutil_get_tz();;
++ if (tz)
++ {
++ putenv(tz);
++ }
+ tzset();
+ p_tm = localtime(&the_time);
+ if (p_tm == NULL)
+ {
+ die("localtime");
+ }
+- /* Set our timezone in the TZ environment variable to cater for the fact
+- * that modern glibc does not cache /etc/localtime (which becomes inaccessible
+- * when we chroot().
+- */
+ retval = strftime(tzbuf, sizeof(tzbuf), "%z", p_tm);
+ tzbuf[sizeof(tzbuf) - 1] = '\0';
+ if (retval == 5)
+ {
+- /* Static because putenv() does not copy the string. */
+- static char envtz[sizeof("TZ=UTC-hh:mm")];
+- /* Insert a colon so we have e.g. -05:00 instead of -0500 */
+- tzbuf[5] = tzbuf[4];
+- tzbuf[4] = tzbuf[3];
+- tzbuf[3] = ':';
+- /* Invert the sign - we just got the offset _from_ UTC but for TZ, we need
+- * the offset _to_ UTC.
+- */
+- if (tzbuf[0] == '+')
+- {
+- tzbuf[0] = '-';
+- }
+- else
+- {
+- tzbuf[0] = '+';
+- }
+- snprintf(envtz, sizeof(envtz), "TZ=UTC%s", tzbuf);
+- putenv(envtz);
+ s_timezone = ((tzbuf[1] - '0') * 10 + (tzbuf[2] - '0')) * 60 * 60;
+- s_timezone += ((tzbuf[4] - '0') * 10 + (tzbuf[5] - '0')) * 60;
+- if (tzbuf[0] == '-')
++ s_timezone += ((tzbuf[3] - '0') * 10 + (tzbuf[4] - '0')) * 60;
++ if (tzbuf[0] == '+')
+ {
+ s_timezone *= -1;
+ }
+--
+2.14.4
+
diff --git a/0018-Change-the-default-log-file-in-configuration.patch b/0018-Change-the-default-log-file-in-configuration.patch
new file mode 100644
index 0000000..369a69c
--- /dev/null
+++ b/0018-Change-the-default-log-file-in-configuration.patch
@@ -0,0 +1,43 @@
+From 61dac172bdb14c5a37713078828ea8c8f78c7eb6 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 29 Sep 2016 13:53:16 +0200
+Subject: [PATCH 18/59] Change the default log file in configuration.
+
+Previous "default" value was wrong.
+tunables.c:262 => install_str_setting("/var/log/xferlog",
+&tunable_xferlog_file);
+---
+ RedHat/vsftpd.log | 6 ++++++
+ vsftpd.conf | 2 +-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/RedHat/vsftpd.log b/RedHat/vsftpd.log
+index d338de8..14731c1 100644
+--- a/RedHat/vsftpd.log
++++ b/RedHat/vsftpd.log
+@@ -3,3 +3,9 @@
+ nocompress
+ missingok
+ }
++
++/var/log/xferlog {
++ # ftpd doesn't handle SIGHUP properly
++ nocompress
++ missingok
++}
+diff --git a/vsftpd.conf b/vsftpd.conf
+index ae6c6c9..39d1955 100644
+--- a/vsftpd.conf
++++ b/vsftpd.conf
+@@ -50,7 +50,7 @@ connect_from_port_20=YES
+ #
+ # You may override where the log file goes if you like. The default is shown
+ # below.
+-#xferlog_file=/var/log/vsftpd.log
++#xferlog_file=/var/log/xferlog
+ #
+ # If you want, you can have your log file in standard ftpd xferlog format.
+ # Note that the default log file location is /var/log/xferlog in this case.
+--
+2.14.4
+
diff --git a/0019-Introduce-reverse_lookup_enable-option.patch b/0019-Introduce-reverse_lookup_enable-option.patch
new file mode 100644
index 0000000..85023c1
--- /dev/null
+++ b/0019-Introduce-reverse_lookup_enable-option.patch
@@ -0,0 +1,109 @@
+From 721de88621100f6ed33f1602415bc249f3ed3219 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 10:22:32 +0100
+Subject: [PATCH 19/59] Introduce reverse_lookup_enable option.
+
+vsftpd can transform IP address into hostname before
+PAM authentication. You can disable it to prevent
+performance issues.
+---
+ parseconf.c | 1 +
+ sysdeputil.c | 14 +++++++++-----
+ tunables.c | 2 ++
+ tunables.h | 1 +
+ vsftpd.conf.5 | 9 +++++++++
+ 5 files changed, 22 insertions(+), 5 deletions(-)
+
+diff --git a/parseconf.c b/parseconf.c
+index 30df598..3e0dba4 100644
+--- a/parseconf.c
++++ b/parseconf.c
+@@ -91,6 +91,7 @@ parseconf_bool_array[] =
+ { "mdtm_write", &tunable_mdtm_write },
+ { "lock_upload_files", &tunable_lock_upload_files },
+ { "pasv_addr_resolve", &tunable_pasv_addr_resolve },
++ { "reverse_lookup_enable", &tunable_reverse_lookup_enable },
+ { "userlist_log", &tunable_userlist_log },
+ { "debug_ssl", &tunable_debug_ssl },
+ { "require_cert", &tunable_require_cert },
+diff --git a/sysdeputil.c b/sysdeputil.c
+index 3bbabaa..2063c87 100644
+--- a/sysdeputil.c
++++ b/sysdeputil.c
+@@ -354,12 +354,16 @@ vsf_sysdep_check_auth(struct mystr* p_user_str,
+ return 0;
+ }
+ #ifdef PAM_RHOST
+- sin.sin_addr.s_addr = inet_addr(str_getbuf(p_remote_host));
+- host = gethostbyaddr((char*)&sin.sin_addr.s_addr,sizeof(struct in_addr),AF_INET);
+- if (host != (struct hostent*)0)
+- retval = pam_set_item(s_pamh, PAM_RHOST, host->h_name);
+- else
++ if (tunable_reverse_lookup_enable) {
++ sin.sin_addr.s_addr = inet_addr(str_getbuf(p_remote_host));
++ host = gethostbyaddr((char*)&sin.sin_addr.s_addr,sizeof(struct in_addr),AF_INET);
++ if (host != (struct hostent*)0)
++ retval = pam_set_item(s_pamh, PAM_RHOST, host->h_name);
++ else
++ retval = pam_set_item(s_pamh, PAM_RHOST, str_getbuf(p_remote_host));
++ } else {
+ retval = pam_set_item(s_pamh, PAM_RHOST, str_getbuf(p_remote_host));
++ }
+ if (retval != PAM_SUCCESS)
+ {
+ (void) pam_end(s_pamh, retval);
+diff --git a/tunables.c b/tunables.c
+index b30fca1..c737465 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -72,6 +72,7 @@ int tunable_force_anon_data_ssl;
+ int tunable_mdtm_write;
+ int tunable_lock_upload_files;
+ int tunable_pasv_addr_resolve;
++int tunable_reverse_lookup_enable;
+ int tunable_userlist_log;
+ int tunable_debug_ssl;
+ int tunable_require_cert;
+@@ -213,6 +214,7 @@ tunables_load_defaults()
+ tunable_mdtm_write = 1;
+ tunable_lock_upload_files = 1;
+ tunable_pasv_addr_resolve = 0;
++ tunable_reverse_lookup_enable = 1;
+ tunable_userlist_log = 0;
+ tunable_debug_ssl = 0;
+ tunable_require_cert = 0;
+diff --git a/tunables.h b/tunables.h
+index e44d64c..9553038 100644
+--- a/tunables.h
++++ b/tunables.h
+@@ -73,6 +73,7 @@ extern int tunable_force_anon_data_ssl; /* Require anon data uses SSL */
+ extern int tunable_mdtm_write; /* Allow MDTM to set timestamps */
+ extern int tunable_lock_upload_files; /* Lock uploading files */
+ extern int tunable_pasv_addr_resolve; /* DNS resolve pasv_addr */
++extern int tunable_reverse_lookup_enable; /* Get hostname before pam auth */
+ extern int tunable_userlist_log; /* Log every failed login attempt */
+ extern int tunable_debug_ssl; /* Verbose SSL logging */
+ extern int tunable_require_cert; /* SSL client cert required */
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index 72bb86f..fb6324e 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -423,6 +423,15 @@ so you may want to disable it. For a discussion of the consequences, see
+ http://scarybeastsecurity.blogspot.com/2009/02/vsftpd-210-released.html
+ (Added in v2.1.0).
+
++Default: YES
++.TP
++.B reverse_lookup_enable
++Set to YES if you want vsftpd to transform the ip address into the hostname,
++before pam authentication. This is useful if you use pam_access including the
++hostname. If you want vsftpd to run on the environment where the reverse lookup
++for some hostname is available and the name server doesn't respond for a while,
++you should set this to NO to avoid a performance issue.
++
+ Default: YES
+ .TP
+ .B run_as_launching_user
+--
+2.14.4
+
diff --git a/0020-Use-unsigned-int-for-uid-and-gid-representation.patch b/0020-Use-unsigned-int-for-uid-and-gid-representation.patch
new file mode 100644
index 0000000..ac3ac1f
--- /dev/null
+++ b/0020-Use-unsigned-int-for-uid-and-gid-representation.patch
@@ -0,0 +1,250 @@
+From dcaaf1e0dd3985e229a87de18b83f301d30b6ce9 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 10:31:39 +0100
+Subject: [PATCH 20/59] Use unsigned int for uid and gid representation.
+
+---
+ ls.c | 4 ++--
+ privops.c | 3 +--
+ session.h | 6 +++---
+ sysutil.c | 44 ++++++++++++++------------------------------
+ sysutil.h | 20 ++++++++++----------
+ 5 files changed, 30 insertions(+), 47 deletions(-)
+
+diff --git a/ls.c b/ls.c
+index b840136..3c0988c 100644
+--- a/ls.c
++++ b/ls.c
+@@ -503,7 +503,7 @@ build_dir_line(struct mystr* p_str, const struct mystr* p_filename_str,
+ }
+ else
+ {
+- int uid = vsf_sysutil_statbuf_get_uid(p_stat);
++ unsigned int uid = vsf_sysutil_statbuf_get_uid(p_stat);
+ struct vsf_sysutil_user* p_user = 0;
+ if (tunable_text_userdb_names)
+ {
+@@ -528,7 +528,7 @@ build_dir_line(struct mystr* p_str, const struct mystr* p_filename_str,
+ }
+ else
+ {
+- int gid = vsf_sysutil_statbuf_get_gid(p_stat);
++ unsigned int gid = vsf_sysutil_statbuf_get_gid(p_stat);
+ struct vsf_sysutil_group* p_group = 0;
+ if (tunable_text_userdb_names)
+ {
+diff --git a/privops.c b/privops.c
+index 21d7267..f27c5c4 100644
+--- a/privops.c
++++ b/privops.c
+@@ -236,8 +236,7 @@ vsf_privop_do_file_chown(struct vsf_session* p_sess, int fd)
+ /* Drop it like a hot potato unless it's a regular file owned by
+ * the the anonymous ftp user
+ */
+- if (p_sess->anon_upload_chown_uid == -1 ||
+- !vsf_sysutil_statbuf_is_regfile(s_p_statbuf) ||
++ if (!vsf_sysutil_statbuf_is_regfile(s_p_statbuf) ||
+ (vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->anon_ftp_uid &&
+ vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->guest_user_uid))
+ {
+diff --git a/session.h b/session.h
+index 27a488f..956bfb7 100644
+--- a/session.h
++++ b/session.h
+@@ -54,9 +54,9 @@ struct vsf_session
+ struct mystr_list* p_visited_dir_list;
+
+ /* Details of userids which are interesting to us */
+- int anon_ftp_uid;
+- int guest_user_uid;
+- int anon_upload_chown_uid;
++ unsigned int anon_ftp_uid;
++ unsigned int guest_user_uid;
++ unsigned int anon_upload_chown_uid;
+
+ /* Things we need to cache before we chroot() */
+ struct mystr banned_email_str;
+diff --git a/sysutil.c b/sysutil.c
+index 2abdd13..9881a66 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -1454,14 +1454,14 @@ vsf_sysutil_statbuf_get_size(const struct vsf_sysutil_statbuf* p_statbuf)
+ return p_stat->st_size;
+ }
+
+-int
++unsigned int
+ vsf_sysutil_statbuf_get_uid(const struct vsf_sysutil_statbuf* p_statbuf)
+ {
+ const struct stat* p_stat = (const struct stat*) p_statbuf;
+ return p_stat->st_uid;
+ }
+
+-int
++unsigned int
+ vsf_sysutil_statbuf_get_gid(const struct vsf_sysutil_statbuf* p_statbuf)
+ {
+ const struct stat* p_stat = (const struct stat*) p_statbuf;
+@@ -1502,7 +1502,7 @@ vsf_sysutil_statbuf_get_sortkey_mtime(
+ }
+
+ void
+-vsf_sysutil_fchown(const int fd, const int uid, const int gid)
++vsf_sysutil_fchown(const int fd, const unsigned int uid, const unsigned int gid)
+ {
+ if (fchown(fd, uid, gid) != 0)
+ {
+@@ -2320,13 +2320,9 @@ vsf_sysutil_dns_resolve(struct vsf_sysutil_sockaddr** p_sockptr,
+ }
+
+ struct vsf_sysutil_user*
+-vsf_sysutil_getpwuid(const int uid)
++vsf_sysutil_getpwuid(const unsigned int uid)
+ {
+- if (uid < 0)
+- {
+- bug("negative uid in vsf_sysutil_getpwuid");
+- }
+- return (struct vsf_sysutil_user*) getpwuid((unsigned int) uid);
++ return (struct vsf_sysutil_user*) getpwuid(uid);
+ }
+
+ struct vsf_sysutil_user*
+@@ -2349,14 +2345,14 @@ vsf_sysutil_user_get_homedir(const struct vsf_sysutil_user* p_user)
+ return p_passwd->pw_dir;
+ }
+
+-int
++unsigned int
+ vsf_sysutil_user_getuid(const struct vsf_sysutil_user* p_user)
+ {
+ const struct passwd* p_passwd = (const struct passwd*) p_user;
+ return p_passwd->pw_uid;
+ }
+
+-int
++unsigned int
+ vsf_sysutil_user_getgid(const struct vsf_sysutil_user* p_user)
+ {
+ const struct passwd* p_passwd = (const struct passwd*) p_user;
+@@ -2364,13 +2360,9 @@ vsf_sysutil_user_getgid(const struct vsf_sysutil_user* p_user)
+ }
+
+ struct vsf_sysutil_group*
+-vsf_sysutil_getgrgid(const int gid)
++vsf_sysutil_getgrgid(const unsigned int gid)
+ {
+- if (gid < 0)
+- {
+- die("negative gid in vsf_sysutil_getgrgid");
+- }
+- return (struct vsf_sysutil_group*) getgrgid((unsigned int) gid);
++ return (struct vsf_sysutil_group*) getgrgid(gid);
+ }
+
+ const char*
+@@ -2445,25 +2437,17 @@ vsf_sysutil_setgid_numeric(int gid)
+ }
+ }
+
+-int
++unsigned int
+ vsf_sysutil_geteuid(void)
+ {
+- int retval = geteuid();
+- if (retval < 0)
+- {
+- die("geteuid");
+- }
++ unsigned int retval = geteuid();
+ return retval;
+ }
+
+-int
++unsigned int
+ vsf_sysutil_getegid(void)
+ {
+- int retval = getegid();
+- if (retval < 0)
+- {
+- die("getegid");
+- }
++ unsigned int retval = getegid();
+ return retval;
+ }
+
+@@ -2854,7 +2838,7 @@ vsf_sysutil_ftruncate(int fd)
+ }
+ }
+
+-int
++unsigned int
+ vsf_sysutil_getuid(void)
+ {
+ return getuid();
+diff --git a/sysutil.h b/sysutil.h
+index bfc92cb..79b5514 100644
+--- a/sysutil.h
++++ b/sysutil.h
+@@ -129,15 +129,15 @@ const char* vsf_sysutil_statbuf_get_numeric_date(
+ const struct vsf_sysutil_statbuf* p_stat, int use_localtime);
+ unsigned int vsf_sysutil_statbuf_get_links(
+ const struct vsf_sysutil_statbuf* p_stat);
+-int vsf_sysutil_statbuf_get_uid(const struct vsf_sysutil_statbuf* p_stat);
+-int vsf_sysutil_statbuf_get_gid(const struct vsf_sysutil_statbuf* p_stat);
++unsigned int vsf_sysutil_statbuf_get_uid(const struct vsf_sysutil_statbuf* p_stat);
++unsigned int vsf_sysutil_statbuf_get_gid(const struct vsf_sysutil_statbuf* p_stat);
+ int vsf_sysutil_statbuf_is_readable_other(
+ const struct vsf_sysutil_statbuf* p_stat);
+ const char* vsf_sysutil_statbuf_get_sortkey_mtime(
+ const struct vsf_sysutil_statbuf* p_stat);
+
+ int vsf_sysutil_chmod(const char* p_filename, unsigned int mode);
+-void vsf_sysutil_fchown(const int fd, const int uid, const int gid);
++void vsf_sysutil_fchown(const int fd, const unsigned int uid, const unsigned int gid);
+ void vsf_sysutil_fchmod(const int fd, unsigned int mode);
+ int vsf_sysutil_readlink(const char* p_filename, char* p_dest,
+ unsigned int bufsiz);
+@@ -290,15 +290,15 @@ int vsf_sysutil_inet_aton(
+ struct vsf_sysutil_user;
+ struct vsf_sysutil_group;
+
+-struct vsf_sysutil_user* vsf_sysutil_getpwuid(const int uid);
++struct vsf_sysutil_user* vsf_sysutil_getpwuid(const unsigned int uid);
+ struct vsf_sysutil_user* vsf_sysutil_getpwnam(const char* p_user);
+ const char* vsf_sysutil_user_getname(const struct vsf_sysutil_user* p_user);
+ const char* vsf_sysutil_user_get_homedir(
+ const struct vsf_sysutil_user* p_user);
+-int vsf_sysutil_user_getuid(const struct vsf_sysutil_user* p_user);
+-int vsf_sysutil_user_getgid(const struct vsf_sysutil_user* p_user);
++unsigned int vsf_sysutil_user_getuid(const struct vsf_sysutil_user* p_user);
++unsigned int vsf_sysutil_user_getgid(const struct vsf_sysutil_user* p_user);
+
+-struct vsf_sysutil_group* vsf_sysutil_getgrgid(const int gid);
++struct vsf_sysutil_group* vsf_sysutil_getgrgid(const unsigned int gid);
+ const char* vsf_sysutil_group_getname(const struct vsf_sysutil_group* p_group);
+
+ /* More random things */
+@@ -316,7 +316,7 @@ void vsf_sysutil_qsort(void* p_base, unsigned int num_elem,
+ char* vsf_sysutil_getenv(const char* p_var);
+ typedef void (*exitfunc_t)(void);
+ void vsf_sysutil_set_exit_func(exitfunc_t exitfunc);
+-int vsf_sysutil_getuid(void);
++unsigned int vsf_sysutil_getuid(void);
+
+ /* Syslogging (bah) */
+ void vsf_sysutil_openlog(int force);
+@@ -329,8 +329,8 @@ void vsf_sysutil_setuid(const struct vsf_sysutil_user* p_user);
+ void vsf_sysutil_setgid(const struct vsf_sysutil_user* p_user);
+ void vsf_sysutil_setuid_numeric(int uid);
+ void vsf_sysutil_setgid_numeric(int gid);
+-int vsf_sysutil_geteuid(void);
+-int vsf_sysutil_getegid(void);
++unsigned int vsf_sysutil_geteuid(void);
++unsigned int vsf_sysutil_getegid(void);
+ void vsf_sysutil_seteuid(const struct vsf_sysutil_user* p_user);
+ void vsf_sysutil_setegid(const struct vsf_sysutil_user* p_user);
+ void vsf_sysutil_seteuid_numeric(int uid);
+--
+2.14.4
+
diff --git a/0021-Introduce-support-for-DHE-based-cipher-suites.patch b/0021-Introduce-support-for-DHE-based-cipher-suites.patch
new file mode 100644
index 0000000..0475e12
--- /dev/null
+++ b/0021-Introduce-support-for-DHE-based-cipher-suites.patch
@@ -0,0 +1,226 @@
+From 4eac1dbb5f70a652d31847eec7c28d245f36cdbb Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 10:48:28 +0100
+Subject: [PATCH 21/59] Introduce support for DHE based cipher suites.
+
+---
+ parseconf.c | 1 +
+ ssl.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ tunables.c | 5 +++-
+ tunables.h | 1 +
+ vsftpd.conf.5 | 6 ++++
+ 5 files changed, 104 insertions(+), 2 deletions(-)
+
+diff --git a/parseconf.c b/parseconf.c
+index 3e0dba4..38e3182 100644
+--- a/parseconf.c
++++ b/parseconf.c
+@@ -176,6 +176,7 @@ parseconf_str_array[] =
+ { "email_password_file", &tunable_email_password_file },
+ { "rsa_cert_file", &tunable_rsa_cert_file },
+ { "dsa_cert_file", &tunable_dsa_cert_file },
++ { "dh_param_file", &tunable_dh_param_file },
+ { "ssl_ciphers", &tunable_ssl_ciphers },
+ { "rsa_private_key_file", &tunable_rsa_private_key_file },
+ { "dsa_private_key_file", &tunable_dsa_private_key_file },
+diff --git a/ssl.c b/ssl.c
+index c362983..22b69b3 100644
+--- a/ssl.c
++++ b/ssl.c
+@@ -28,6 +28,8 @@
+ #include <openssl/err.h>
+ #include <openssl/rand.h>
+ #include <openssl/bio.h>
++#include <openssl/dh.h>
++#include <openssl/bn.h>
+ #include <errno.h>
+ #include <limits.h>
+
+@@ -38,6 +40,7 @@ static void setup_bio_callbacks();
+ static long bio_callback(
+ BIO* p_bio, int oper, const char* p_arg, int argi, long argl, long retval);
+ static int ssl_verify_callback(int verify_ok, X509_STORE_CTX* p_ctx);
++static DH *ssl_tmp_dh_callback(SSL *ssl, int is_export, int keylength);
+ static int ssl_alpn_callback(SSL* p_ssl,
+ const unsigned char** p_out,
+ unsigned char* outlen,
+@@ -51,6 +54,60 @@ static int ssl_read_common(struct vsf_session* p_sess,
+ static int ssl_inited;
+ static struct mystr debug_str;
+
++
++// Grab prime number from OpenSSL; <openssl/bn.h>
++// (get_rfc*) for all available primes.
++// wraps selection of comparable algorithm strength
++#if !defined(match_dh_bits)
++ #define match_dh_bits(keylen) \
++ keylen >= 8191 ? 8192 : \
++ keylen >= 6143 ? 6144 : \
++ keylen >= 4095 ? 4096 : \
++ keylen >= 3071 ? 3072 : \
++ keylen >= 2047 ? 2048 : \
++ keylen >= 1535 ? 1536 : \
++ keylen >= 1023 ? 1024 : 768
++#endif
++
++#if !defined(DH_get_prime)
++ BIGNUM *
++ DH_get_prime(int bits)
++ {
++ switch (bits) {
++ case 768: return get_rfc2409_prime_768(NULL);
++ case 1024: return get_rfc2409_prime_1024(NULL);
++ case 1536: return get_rfc3526_prime_1536(NULL);
++ case 2048: return get_rfc3526_prime_2048(NULL);
++ case 3072: return get_rfc3526_prime_3072(NULL);
++ case 4096: return get_rfc3526_prime_4096(NULL);
++ case 6144: return get_rfc3526_prime_6144(NULL);
++ case 8192: return get_rfc3526_prime_8192(NULL);
++ // shouldn't happen when used match_dh_bits; strict compiler
++ default: return NULL;
++ }
++}
++#endif
++
++#if !defined(DH_get_dh)
++ // Grab DH parameters
++ DH *
++ DH_get_dh(int size)
++ {
++ DH *dh = DH_new();
++ if (!dh) {
++ return NULL;
++ }
++ dh->p = DH_get_prime(match_dh_bits(size));
++ BN_dec2bn(&dh->g, "2");
++ if (!dh->p || !dh->g)
++ {
++ DH_free(dh);
++ return NULL;
++ }
++ return dh;
++ }
++#endif
++
+ void
+ ssl_init(struct vsf_session* p_sess)
+ {
+@@ -65,7 +122,7 @@ ssl_init(struct vsf_session* p_sess)
+ {
+ die("SSL: could not allocate SSL context");
+ }
+- options = SSL_OP_ALL;
++ options = SSL_OP_ALL | SSL_OP_SINGLE_DH_USE;
+ if (!tunable_sslv2)
+ {
+ options |= SSL_OP_NO_SSLv2;
+@@ -111,6 +168,25 @@ ssl_init(struct vsf_session* p_sess)
+ die("SSL: cannot load DSA private key");
+ }
+ }
++ if (tunable_dh_param_file)
++ {
++ BIO *bio;
++ DH *dhparams = NULL;
++ if ((bio = BIO_new_file(tunable_dh_param_file, "r")) == NULL)
++ {
++ die("SSL: cannot load custom DH params");
++ }
++ else
++ {
++ dhparams = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
++ BIO_free(bio);
++
++ if (!SSL_CTX_set_tmp_dh(p_ctx, dhparams))
++ {
++ die("SSL: setting custom DH params failed");
++ }
++ }
++ }
+ if (tunable_ssl_ciphers &&
+ SSL_CTX_set_cipher_list(p_ctx, tunable_ssl_ciphers) != 1)
+ {
+@@ -165,6 +241,9 @@ ssl_init(struct vsf_session* p_sess)
+ /* Ensure cached session doesn't expire */
+ SSL_CTX_set_timeout(p_ctx, INT_MAX);
+ }
++
++ SSL_CTX_set_tmp_dh_callback(p_ctx, ssl_tmp_dh_callback);
++
+ /* Set up ALPN to check for FTP protocol intention of client. */
+ SSL_CTX_set_alpn_select_cb(p_ctx, ssl_alpn_callback, p_sess);
+ /* Set up SNI callback for an optional hostname check. */
+@@ -702,6 +781,18 @@ ssl_verify_callback(int verify_ok, X509_STORE_CTX* p_ctx)
+ }
+ }
+
++#define UNUSED(x) ( (void)(x) )
++
++static DH *
++ssl_tmp_dh_callback(SSL *ssl, int is_export, int keylength)
++{
++ // strict compiler bypassing
++ UNUSED(ssl);
++ UNUSED(is_export);
++
++ return DH_get_dh(keylength);
++}
++
+ void
+ ssl_add_entropy(struct vsf_session* p_sess)
+ {
+diff --git a/tunables.c b/tunables.c
+index c737465..1ea7227 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -140,6 +140,7 @@ const char* tunable_user_sub_token;
+ const char* tunable_email_password_file;
+ const char* tunable_rsa_cert_file;
+ const char* tunable_dsa_cert_file;
++const char* tunable_dh_param_file;
+ const char* tunable_ssl_ciphers;
+ const char* tunable_rsa_private_key_file;
+ const char* tunable_dsa_private_key_file;
+@@ -288,7 +289,9 @@ tunables_load_defaults()
+ install_str_setting("/usr/share/ssl/certs/vsftpd.pem",
+ &tunable_rsa_cert_file);
+ install_str_setting(0, &tunable_dsa_cert_file);
+- install_str_setting("ECDHE-RSA-AES256-GCM-SHA384", &tunable_ssl_ciphers);
++ install_str_setting(0, &tunable_dh_param_file);
++ install_str_setting("AES128-SHA:DES-CBC3-SHA:DHE-RSA-AES256-SHA",
++ &tunable_ssl_ciphers);
+ install_str_setting(0, &tunable_rsa_private_key_file);
+ install_str_setting(0, &tunable_dsa_private_key_file);
+ install_str_setting(0, &tunable_ca_certs_file);
+diff --git a/tunables.h b/tunables.h
+index 9553038..3995472 100644
+--- a/tunables.h
++++ b/tunables.h
+@@ -142,6 +142,7 @@ extern const char* tunable_user_sub_token;
+ extern const char* tunable_email_password_file;
+ extern const char* tunable_rsa_cert_file;
+ extern const char* tunable_dsa_cert_file;
++extern const char* tunable_dh_param_file;
+ extern const char* tunable_ssl_ciphers;
+ extern const char* tunable_rsa_private_key_file;
+ extern const char* tunable_dsa_private_key_file;
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index fb6324e..ff94eca 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -893,6 +893,12 @@ to be in the same file as the certificate.
+
+ Default: (none)
+ .TP
++.B dh_param_file
++This option specifies the location of the custom parameters used for
++ephemeral Diffie-Hellman key exchange in SSL.
++
++Default: (none - use built in parameters appropriate for certificate key size)
++.TP
+ .B email_password_file
+ This option can be used to provide an alternate file for usage by the
+ .BR secure_email_list_enable
+--
+2.14.4
+
diff --git a/0022-Introduce-support-for-EDDHE-based-cipher-suites.patch b/0022-Introduce-support-for-EDDHE-based-cipher-suites.patch
new file mode 100644
index 0000000..4e4527b
--- /dev/null
+++ b/0022-Introduce-support-for-EDDHE-based-cipher-suites.patch
@@ -0,0 +1,136 @@
+From a6d641a0ccba1033587f6faa0e5e6749fa35f5c4 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 10:49:22 +0100
+Subject: [PATCH 22/59] Introduce support for EDDHE based cipher suites.
+
+---
+ parseconf.c | 1 +
+ ssl.c | 37 ++++++++++++++++++++++++++++++++++++-
+ tunables.c | 4 +++-
+ tunables.h | 1 +
+ vsftpd.conf.5 | 8 ++++++++
+ 5 files changed, 49 insertions(+), 2 deletions(-)
+
+diff --git a/parseconf.c b/parseconf.c
+index 38e3182..a2c715b 100644
+--- a/parseconf.c
++++ b/parseconf.c
+@@ -177,6 +177,7 @@ parseconf_str_array[] =
+ { "rsa_cert_file", &tunable_rsa_cert_file },
+ { "dsa_cert_file", &tunable_dsa_cert_file },
+ { "dh_param_file", &tunable_dh_param_file },
++ { "ecdh_param_file", &tunable_ecdh_param_file },
+ { "ssl_ciphers", &tunable_ssl_ciphers },
+ { "rsa_private_key_file", &tunable_rsa_private_key_file },
+ { "dsa_private_key_file", &tunable_dsa_private_key_file },
+diff --git a/ssl.c b/ssl.c
+index 22b69b3..96bf8ad 100644
+--- a/ssl.c
++++ b/ssl.c
+@@ -122,7 +122,7 @@ ssl_init(struct vsf_session* p_sess)
+ {
+ die("SSL: could not allocate SSL context");
+ }
+- options = SSL_OP_ALL | SSL_OP_SINGLE_DH_USE;
++ options = SSL_OP_ALL | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE;
+ if (!tunable_sslv2)
+ {
+ options |= SSL_OP_NO_SSLv2;
+@@ -244,6 +244,41 @@ ssl_init(struct vsf_session* p_sess)
+
+ SSL_CTX_set_tmp_dh_callback(p_ctx, ssl_tmp_dh_callback);
+
++ if (tunable_ecdh_param_file)
++ {
++ BIO *bio;
++ int nid;
++ EC_GROUP *ecparams = NULL;
++ EC_KEY *eckey;
++
++ if ((bio = BIO_new_file(tunable_ecdh_param_file, "r")) == NULL)
++ die("SSL: cannot load custom ec params");
++ else
++ {
++ ecparams = PEM_read_bio_ECPKParameters(bio, NULL, NULL, NULL);
++ BIO_free(bio);
++
++ if (ecparams && (nid = EC_GROUP_get_curve_name(ecparams)) &&
++ (eckey = EC_KEY_new_by_curve_name(nid)))
++ {
++ if (!SSL_CTX_set_tmp_ecdh(p_ctx, eckey))
++ die("SSL: setting custom EC params failed");
++ }
++ else
++ {
++ die("SSL: getting ec group or key failed");
++ }
++ }
++ }
++ else
++ {
++#if defined(SSL_CTX_set_ecdh_auto)
++ SSL_CTX_set_ecdh_auto(p_ctx, 1);
++#else
++ SSL_CTX_set_tmp_ecdh(p_ctx, EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
++#endif
++ }
++
+ /* Set up ALPN to check for FTP protocol intention of client. */
+ SSL_CTX_set_alpn_select_cb(p_ctx, ssl_alpn_callback, p_sess);
+ /* Set up SNI callback for an optional hostname check. */
+diff --git a/tunables.c b/tunables.c
+index 1ea7227..93f85b1 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -141,6 +141,7 @@ const char* tunable_email_password_file;
+ const char* tunable_rsa_cert_file;
+ const char* tunable_dsa_cert_file;
+ const char* tunable_dh_param_file;
++const char* tunable_ecdh_param_file;
+ const char* tunable_ssl_ciphers;
+ const char* tunable_rsa_private_key_file;
+ const char* tunable_dsa_private_key_file;
+@@ -290,7 +291,8 @@ tunables_load_defaults()
+ &tunable_rsa_cert_file);
+ install_str_setting(0, &tunable_dsa_cert_file);
+ install_str_setting(0, &tunable_dh_param_file);
+- install_str_setting("AES128-SHA:DES-CBC3-SHA:DHE-RSA-AES256-SHA",
++ install_str_setting(0, &tunable_ecdh_param_file);
++ install_str_setting("AES128-SHA:DES-CBC3-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA",
+ &tunable_ssl_ciphers);
+ install_str_setting(0, &tunable_rsa_private_key_file);
+ install_str_setting(0, &tunable_dsa_private_key_file);
+diff --git a/tunables.h b/tunables.h
+index 3995472..3e2d40c 100644
+--- a/tunables.h
++++ b/tunables.h
+@@ -143,6 +143,7 @@ extern const char* tunable_email_password_file;
+ extern const char* tunable_rsa_cert_file;
+ extern const char* tunable_dsa_cert_file;
+ extern const char* tunable_dh_param_file;
++extern const char* tunable_ecdh_param_file;
+ extern const char* tunable_ssl_ciphers;
+ extern const char* tunable_rsa_private_key_file;
+ extern const char* tunable_dsa_private_key_file;
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index ff94eca..e242873 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -899,6 +899,14 @@ ephemeral Diffie-Hellman key exchange in SSL.
+
+ Default: (none - use built in parameters appropriate for certificate key size)
+ .TP
++.B ecdh_param_file
++This option specifies the location of custom parameters for ephemeral
++Elliptic Curve Diffie-Hellman (ECDH) key exchange.
++
++Default: (none - use built in parameters, NIST P-256 with OpenSSL 1.0.1 and
++automatically selected curve based on client preferences with OpenSSL 1.0.2
++and later)
++.TP
+ .B email_password_file
+ This option can be used to provide an alternate file for usage by the
+ .BR secure_email_list_enable
+--
+2.14.4
+
diff --git a/0023-Add-documentation-for-isolate_-options.-Correct-defa.patch b/0023-Add-documentation-for-isolate_-options.-Correct-defa.patch
new file mode 100644
index 0000000..7cc0bfa
--- /dev/null
+++ b/0023-Add-documentation-for-isolate_-options.-Correct-defa.patch
@@ -0,0 +1,63 @@
+From 3d02ef3be17f37baf729e786a8f36af4982f70ad Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 10:52:16 +0100
+Subject: [PATCH 23/59] Add documentation for isolate_* options. Correct
+ default
+
+values of max_clients, max_per_ip.
+---
+ vsftpd.conf.5 | 22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index e242873..31d317f 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -652,6 +652,21 @@ change it with the setting
+ .BR xferlog_file .
+
+ Default: NO
++.TP
++.B isolate_network
++If enabled, use CLONE_NEWNET to isolate the untrusted processes so that
++they can't do arbitrary connect() and instead have to ask the privileged
++process for sockets (
++.BR port_promiscuous
++have to be disabled).
++
++Default: YES
++.TP
++.B isolate
++If enabled, use CLONE_NEWPID and CLONE_NEWIPC to isolate processes to their
++ipc and pid namespaces. So separated processes can not interact with each other.
++
++Default: YES
+
+ .SH NUMERIC OPTIONS
+ Below is a list of numeric options. A numeric option must be set to a non
+@@ -749,8 +764,9 @@ Default: 077
+ .B max_clients
+ If vsftpd is in standalone mode, this is the maximum number of clients which
+ may be connected. Any additional clients connecting will get an error message.
++The value 0 switches off the limit.
+
+-Default: 0 (unlimited)
++Default: 2000
+ .TP
+ .B max_login_fails
+ After this many login failures, the session is killed.
+@@ -760,9 +776,9 @@ Default: 3
+ .B max_per_ip
+ If vsftpd is in standalone mode, this is the maximum number of clients which
+ may be connected from the same source internet address. A client will get an
+-error message if they go over this limit.
++error message if they go over this limit. The value 0 switches off the limit.
+
+-Default: 0 (unlimited)
++Default: 50
+ .TP
+ .B pasv_max_port
+ The maximum port to allocate for PASV style data connections. Can be used to
+--
+2.14.4
+
diff --git a/0024-Introduce-new-return-value-450.patch b/0024-Introduce-new-return-value-450.patch
new file mode 100644
index 0000000..86c5f8e
--- /dev/null
+++ b/0024-Introduce-new-return-value-450.patch
@@ -0,0 +1,77 @@
+From 1d5cdf309387ff92988ab17d746f015d833a4b92 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 11:08:52 +0100
+Subject: [PATCH 24/59] Introduce new return value 450:
+
+ *450 Requested file action not taken.
+ File unavailable (e.g., file busy).
+---
+ ftpcodes.h | 1 +
+ postlogin.c | 9 ++++++++-
+ sysutil.c | 3 +++
+ sysutil.h | 3 ++-
+ 4 files changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/ftpcodes.h b/ftpcodes.h
+index 93290c0..81e25c5 100644
+--- a/ftpcodes.h
++++ b/ftpcodes.h
+@@ -52,6 +52,7 @@
+ #define FTP_TLS_FAIL 421
+ #define FTP_BADSENDCONN 425
+ #define FTP_BADSENDNET 426
++#define FTP_FILETMPFAIL 450
+ #define FTP_BADSENDFILE 451
+
+ #define FTP_BADCMD 500
+diff --git a/postlogin.c b/postlogin.c
+index bf12970..29958c0 100644
+--- a/postlogin.c
++++ b/postlogin.c
+@@ -679,7 +679,14 @@ handle_retr(struct vsf_session* p_sess, int is_http)
+ opened_file = str_open(&p_sess->ftp_arg_str, kVSFSysStrOpenReadOnly);
+ if (vsf_sysutil_retval_is_error(opened_file))
+ {
+- vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
++ if (kVSFSysUtilErrAGAIN == vsf_sysutil_get_error())
++ {
++ vsf_cmdio_write(p_sess, FTP_FILETMPFAIL, "Temporarily failed to open file");
++ }
++ else
++ {
++ vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
++ }
+ return;
+ }
+ /* Lock file if required */
+diff --git a/sysutil.c b/sysutil.c
+index 9881a66..6d7cb3f 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -1632,6 +1632,9 @@ vsf_sysutil_get_error(void)
+ case ENOENT:
+ retval = kVSFSysUtilErrNOENT;
+ break;
++ case EAGAIN:
++ retval = kVSFSysUtilErrAGAIN;
++ break;
+ default:
+ break;
+ }
+diff --git a/sysutil.h b/sysutil.h
+index 79b5514..c145bdf 100644
+--- a/sysutil.h
++++ b/sysutil.h
+@@ -18,7 +18,8 @@ enum EVSFSysUtilError
+ kVSFSysUtilErrINVAL,
+ kVSFSysUtilErrOPNOTSUPP,
+ kVSFSysUtilErrACCES,
+- kVSFSysUtilErrNOENT
++ kVSFSysUtilErrNOENT,
++ kVSFSysUtilErrAGAIN
+ };
+ enum EVSFSysUtilError vsf_sysutil_get_error(void);
+
+--
+2.14.4
+
diff --git a/0025-Improve-local_max_rate-option.patch b/0025-Improve-local_max_rate-option.patch
new file mode 100644
index 0000000..d53d1ef
--- /dev/null
+++ b/0025-Improve-local_max_rate-option.patch
@@ -0,0 +1,90 @@
+From 386db86fe865fb552b1867af4bf4b78dbf9080cf Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 12:44:26 +0100
+Subject: [PATCH 25/59] Improve local_max_rate option.
+
+Now it should work as expected.
+---
+ ftpdataio.c | 14 +++++++-------
+ main.c | 2 +-
+ session.h | 3 ++-
+ 3 files changed, 10 insertions(+), 9 deletions(-)
+
+diff --git a/ftpdataio.c b/ftpdataio.c
+index 3e4e9c9..00f9021 100644
+--- a/ftpdataio.c
++++ b/ftpdataio.c
+@@ -249,7 +249,7 @@ handle_io(int retval, int fd, void* p_private)
+ {
+ long curr_sec;
+ long curr_usec;
+- unsigned int bw_rate;
++ unsigned long bw_rate;
+ double elapsed;
+ double pause_time;
+ double rate_ratio;
+@@ -276,19 +276,16 @@ handle_io(int retval, int fd, void* p_private)
+ {
+ elapsed = (double) 0.01;
+ }
+- bw_rate = (unsigned int) ((double) retval / elapsed);
+- if (bw_rate <= p_sess->bw_rate_max)
++ p_sess->bw_retval += retval;
++ bw_rate = (unsigned long) ((double) p_sess->bw_retval / elapsed);
++ if (bw_rate <= p_sess->bw_rate_max || p_sess->bw_retval < (unsigned long)(10*retval))
+ {
+- p_sess->bw_send_start_sec = curr_sec;
+- p_sess->bw_send_start_usec = curr_usec;
+ return;
+ }
+ /* Tut! Rate exceeded, calculate a pause to bring things back into line */
+ rate_ratio = (double) bw_rate / (double) p_sess->bw_rate_max;
+ pause_time = (rate_ratio - (double) 1) * elapsed;
+ vsf_sysutil_sleep(pause_time);
+- p_sess->bw_send_start_sec = vsf_sysutil_get_time_sec();
+- p_sess->bw_send_start_usec = vsf_sysutil_get_time_usec();
+ }
+
+ int
+@@ -441,6 +438,9 @@ struct vsf_transfer_ret
+ vsf_ftpdataio_transfer_file(struct vsf_session* p_sess, int remote_fd,
+ int file_fd, int is_recv, int is_ascii)
+ {
++ p_sess->bw_send_start_sec = vsf_sysutil_get_time_sec();
++ p_sess->bw_send_start_usec = vsf_sysutil_get_time_usec();
++ p_sess->bw_retval = 0;
+ if (!is_recv)
+ {
+ if (is_ascii || p_sess->data_use_ssl)
+diff --git a/main.c b/main.c
+index eaba265..f1e2f69 100644
+--- a/main.c
++++ b/main.c
+@@ -40,7 +40,7 @@ main(int argc, const char* argv[])
+ /* Control connection */
+ 0, 0, 0, 0, 0, 0,
+ /* Data connection */
+- -1, 0, -1, 0, 0, 0, 0,
++ -1, 0, -1, 0, 0, 0, 0, 0,
+ /* Login */
+ 1, 0, INIT_MYSTR, INIT_MYSTR,
+ /* Protocol state */
+diff --git a/session.h b/session.h
+index 956bfb7..3e8fdd5 100644
+--- a/session.h
++++ b/session.h
+@@ -29,9 +29,10 @@ struct vsf_session
+ struct vsf_sysutil_sockaddr* p_port_sockaddr;
+ int data_fd;
+ int data_progress;
+- unsigned int bw_rate_max;
++ unsigned long bw_rate_max;
+ long bw_send_start_sec;
+ long bw_send_start_usec;
++ unsigned long bw_retval;
+
+ /* Details of the login */
+ int is_anonymous;
+--
+2.14.4
+
diff --git a/0026-Prevent-hanging-in-SIGCHLD-handler.patch b/0026-Prevent-hanging-in-SIGCHLD-handler.patch
new file mode 100644
index 0000000..f928cbc
--- /dev/null
+++ b/0026-Prevent-hanging-in-SIGCHLD-handler.patch
@@ -0,0 +1,81 @@
+From 1e65a0a15f819b8bf1b551bd84f71d0da1f5a00c Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 13:02:27 +0100
+Subject: [PATCH 26/59] Prevent hanging in SIGCHLD handler.
+
+vsftpd can now handle pam_exec.so in pam.d config without hanging
+in SIGCHLD handler.
+---
+ sysutil.c | 4 ++--
+ sysutil.h | 2 +-
+ twoprocess.c | 13 +++++++++++--
+ 3 files changed, 14 insertions(+), 5 deletions(-)
+
+diff --git a/sysutil.c b/sysutil.c
+index 6d7cb3f..099748f 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -608,13 +608,13 @@ vsf_sysutil_exit(int exit_code)
+ }
+
+ struct vsf_sysutil_wait_retval
+-vsf_sysutil_wait(void)
++vsf_sysutil_wait(int hang)
+ {
+ struct vsf_sysutil_wait_retval retval;
+ vsf_sysutil_memclr(&retval, sizeof(retval));
+ while (1)
+ {
+- int sys_ret = wait(&retval.exit_status);
++ int sys_ret = waitpid(-1, &retval.exit_status, hang ? 0 : WNOHANG);
+ if (sys_ret < 0 && errno == EINTR)
+ {
+ vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown, 0, 0);
+diff --git a/sysutil.h b/sysutil.h
+index c145bdf..13153cd 100644
+--- a/sysutil.h
++++ b/sysutil.h
+@@ -177,7 +177,7 @@ struct vsf_sysutil_wait_retval
+ int PRIVATE_HANDS_OFF_syscall_retval;
+ int PRIVATE_HANDS_OFF_exit_status;
+ };
+-struct vsf_sysutil_wait_retval vsf_sysutil_wait(void);
++struct vsf_sysutil_wait_retval vsf_sysutil_wait(int hang);
+ int vsf_sysutil_wait_reap_one(void);
+ int vsf_sysutil_wait_get_retval(
+ const struct vsf_sysutil_wait_retval* p_waitret);
+diff --git a/twoprocess.c b/twoprocess.c
+index 33d84dc..b1891e7 100644
+--- a/twoprocess.c
++++ b/twoprocess.c
+@@ -47,8 +47,17 @@ static void
+ handle_sigchld(void* duff)
+ {
+
+- struct vsf_sysutil_wait_retval wait_retval = vsf_sysutil_wait();
++ struct vsf_sysutil_wait_retval wait_retval = vsf_sysutil_wait(0);
+ (void) duff;
++ if (!vsf_sysutil_wait_get_exitcode(&wait_retval) &&
++ !vsf_sysutil_wait_get_retval(&wait_retval))
++ /* There was nobody to wait for, possibly caused by underlying library
++ * which created a new process through fork()/vfork() and already picked
++ * it up, e.g. by pam_exec.so or integrity check routines for libraries
++ * when FIPS mode is on (nss freebl), which can lead to calling prelink
++ * if the prelink package is installed.
++ */
++ return;
+ /* Child died, so we'll do the same! Report it as an error unless the child
+ * exited normally with zero exit code
+ */
+@@ -390,7 +399,7 @@ common_do_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
+ priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
+ if (!p_sess->control_use_ssl)
+ {
+- (void) vsf_sysutil_wait();
++ (void) vsf_sysutil_wait(1);
+ }
+ else
+ {
+--
+2.14.4
+
diff --git a/0027-Delete-files-when-upload-fails.patch b/0027-Delete-files-when-upload-fails.patch
new file mode 100644
index 0000000..94a00bf
--- /dev/null
+++ b/0027-Delete-files-when-upload-fails.patch
@@ -0,0 +1,138 @@
+From 6224ecc5ac209323baa775880c0602c3fde3590a Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 13:10:41 +0100
+Subject: [PATCH 27/59] Delete files when upload fails.
+
+Previously the uploaded file wasn't removed when the network was
+disconnected. Now it is successfully deleted.
+---
+ ftpcodes.h | 3 ++-
+ ftpdataio.c | 8 ++++++++
+ main.c | 2 +-
+ postlogin.c | 9 ++++++++-
+ session.h | 1 +
+ sysutil.c | 10 ++++++++++
+ sysutil.h | 1 +
+ 7 files changed, 31 insertions(+), 3 deletions(-)
+
+diff --git a/ftpcodes.h b/ftpcodes.h
+index 81e25c5..54dfae7 100644
+--- a/ftpcodes.h
++++ b/ftpcodes.h
+@@ -15,7 +15,8 @@
+ #define FTP_PBSZOK 200
+ #define FTP_PROTOK 200
+ #define FTP_OPTSOK 200
+-#define FTP_ALLOOK 202
++#define FTP_ALLOOK 200
++#define FTP_ALLOIGN 202
+ #define FTP_FEAT 211
+ #define FTP_STATOK 211
+ #define FTP_SIZEOK 213
+diff --git a/ftpdataio.c b/ftpdataio.c
+index 00f9021..c859d80 100644
+--- a/ftpdataio.c
++++ b/ftpdataio.c
+@@ -242,6 +242,10 @@ init_data_sock_params(struct vsf_session* p_sess, int sock_fd)
+ /* Start the timeout monitor */
+ vsf_sysutil_install_io_handler(handle_io, p_sess);
+ start_data_alarm(p_sess);
++ if(tunable_delete_failed_uploads)
++ {
++ vsf_sysutil_rcvtimeo(sock_fd);
++ }
+ }
+
+ static void
+@@ -615,6 +619,10 @@ do_file_recv(struct vsf_session* p_sess, int file_fd, int is_ascii)
+ else if (retval == 0 && !prev_cr)
+ {
+ /* Transfer done, nifty */
++ if (tunable_delete_failed_uploads &&
++ !is_ascii && p_sess->upload_size > 0 &&
++ p_sess->upload_size != ret_struct.transferred)
++ ret_struct.retval = -2;
+ return ret_struct;
+ }
+ num_to_write = (unsigned int) retval;
+diff --git a/main.c b/main.c
+index f1e2f69..f039081 100644
+--- a/main.c
++++ b/main.c
+@@ -44,7 +44,7 @@ main(int argc, const char* argv[])
+ /* Login */
+ 1, 0, INIT_MYSTR, INIT_MYSTR,
+ /* Protocol state */
+- 0, 1, INIT_MYSTR, 0, 0,
++ 0, 0, 1, INIT_MYSTR, 0, 0,
+ /* HTTP hacks */
+ 0, INIT_MYSTR,
+ /* Session state */
+diff --git a/postlogin.c b/postlogin.c
+index 29958c0..e473c34 100644
+--- a/postlogin.c
++++ b/postlogin.c
+@@ -356,7 +356,14 @@ process_post_login(struct vsf_session* p_sess)
+ }
+ else if (str_equal_text(&p_sess->ftp_cmd_str, "ALLO"))
+ {
+- vsf_cmdio_write(p_sess, FTP_ALLOOK, "ALLO command ignored.");
++ if (tunable_delete_failed_uploads && !p_sess->is_ascii)
++ {
++ p_sess->upload_size = (filesize_t)vsf_sysutil_atoi(str_getbuf(&p_sess->ftp_cmd_str)+5);
++ vsf_cmdio_write(p_sess, FTP_ALLOOK, "The filesize has been allocated.");
++ }
++ else {
++ vsf_cmdio_write(p_sess, FTP_ALLOIGN, "ALLO command ignored.");
++ }
+ }
+ else if (str_equal_text(&p_sess->ftp_cmd_str, "REIN"))
+ {
+diff --git a/session.h b/session.h
+index 3e8fdd5..4eccf46 100644
+--- a/session.h
++++ b/session.h
+@@ -41,6 +41,7 @@ struct vsf_session
+ struct mystr anon_pass_str;
+
+ /* Details of the FTP protocol state */
++ filesize_t upload_size;
+ filesize_t restart_pos;
+ int is_ascii;
+ struct mystr rnfr_filename_str;
+diff --git a/sysutil.c b/sysutil.c
+index 099748f..42bcdf8 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -680,6 +680,16 @@ vsf_sysutil_activate_keepalive(int fd)
+ }
+ }
+
++void
++vsf_sysutil_rcvtimeo(int fd)
++{
++ struct timeval tv;
++
++ tv.tv_sec = tunable_data_connection_timeout;
++ tv.tv_usec = 0;
++ setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
++}
++
+ void
+ vsf_sysutil_activate_reuseaddr(int fd)
+ {
+diff --git a/sysutil.h b/sysutil.h
+index 13153cd..2886bbc 100644
+--- a/sysutil.h
++++ b/sysutil.h
+@@ -266,6 +266,7 @@ void vsf_sysutil_dns_resolve(struct vsf_sysutil_sockaddr** p_sockptr,
+ const char* p_name);
+ /* Option setting on sockets */
+ void vsf_sysutil_activate_keepalive(int fd);
++void vsf_sysutil_rcvtimeo(int fd);
+ void vsf_sysutil_set_iptos_throughput(int fd);
+ void vsf_sysutil_activate_reuseaddr(int fd);
+ void vsf_sysutil_set_nodelay(int fd);
+--
+2.14.4
+
diff --git a/0028-Fix-man-page-rendering.patch b/0028-Fix-man-page-rendering.patch
new file mode 100644
index 0000000..e91d6dc
--- /dev/null
+++ b/0028-Fix-man-page-rendering.patch
@@ -0,0 +1,26 @@
+From ea99be1a7a5973bbe8ed798b65abe5ce3b92f5df Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 13:12:52 +0100
+Subject: [PATCH 28/59] Fix man page rendering.
+
+---
+ vsftpd.conf.5 | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index 31d317f..cf1ae34 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -495,7 +495,8 @@ Default: NO
+ .TP
+ .B ssl_request_cert
+ If enabled, vsftpd will request (but not necessarily require; see
+-.BR require_cert) a certificate on incoming SSL connections. Normally this
++.BR require_cert )
++a certificate on incoming SSL connections. Normally this
+ should not cause any trouble at all, but IBM zOS seems to have issues.
+ (New in v2.0.7).
+
+--
+2.14.4
+
diff --git a/0029-Fix-segfault-in-config-file-parser.patch b/0029-Fix-segfault-in-config-file-parser.patch
new file mode 100644
index 0000000..65cb571
--- /dev/null
+++ b/0029-Fix-segfault-in-config-file-parser.patch
@@ -0,0 +1,25 @@
+From 34b9e1d10c6be736f1b20be8795c655446f38c5e Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 13:14:55 +0100
+Subject: [PATCH 29/59] Fix segfault in config file parser.
+
+---
+ str.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/str.c b/str.c
+index 41b27db..82b8ae4 100644
+--- a/str.c
++++ b/str.c
+@@ -113,7 +113,7 @@ str_strdup_trimmed(const struct mystr* p_str)
+ for (h = 0; h < (int)str_getlen(p_str) && vsf_sysutil_isspace(p_trimmed[h]); h++) ;
+ for (t = str_getlen(p_str) - 1; t >= 0 && vsf_sysutil_isspace(p_trimmed[t]); t--) ;
+ newlen = t - h + 1;
+- return newlen ? vsf_sysutil_strndup(p_trimmed+h, (unsigned int)newlen) : 0L;
++ return (newlen > 0) ? vsf_sysutil_strndup(p_trimmed+h, (unsigned int)newlen) : 0L;
+ }
+
+ void
+--
+2.14.4
+
diff --git a/0030-Fix-logging-into-syslog-when-enabled-in-config.patch b/0030-Fix-logging-into-syslog-when-enabled-in-config.patch
new file mode 100644
index 0000000..04669c7
--- /dev/null
+++ b/0030-Fix-logging-into-syslog-when-enabled-in-config.patch
@@ -0,0 +1,25 @@
+From 03ff061f18f555d7bec62fa6a597a275b4b3f1c7 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 13:18:22 +0100
+Subject: [PATCH 30/59] Fix logging into syslog when enabled in config.
+
+---
+ logging.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/logging.c b/logging.c
+index 99671b4..c4461f7 100644
+--- a/logging.c
++++ b/logging.c
+@@ -32,7 +32,7 @@ vsf_log_init(struct vsf_session* p_sess)
+ {
+ if (tunable_syslog_enable || tunable_tcp_wrappers)
+ {
+- vsf_sysutil_openlog(1);
++ vsf_sysutil_openlog(0);
+ }
+ if (!tunable_xferlog_enable && !tunable_dual_log_enable)
+ {
+--
+2.14.4
+
diff --git a/0031-Fix-question-mark-wildcard-withing-a-file-name.patch b/0031-Fix-question-mark-wildcard-withing-a-file-name.patch
new file mode 100644
index 0000000..acc8f6d
--- /dev/null
+++ b/0031-Fix-question-mark-wildcard-withing-a-file-name.patch
@@ -0,0 +1,28 @@
+From 0da42468ac9518a544aad57d22d7697d6bdfa969 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 13:25:12 +0100
+Subject: [PATCH 31/59] Fix question mark wildcard withing a file name.
+
+Previously '?' worked only at the end of a file name, now it can
+be used anywhere.
+---
+ ls.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/ls.c b/ls.c
+index 3c0988c..35c15c7 100644
+--- a/ls.c
++++ b/ls.c
+@@ -459,7 +459,8 @@ vsf_filename_passes_filter(const struct mystr* p_filename_str,
+ must_match_at_current_pos = 0;
+ }
+ } while (locate_result.found &&
+- str_getlen(&name_remain_str) > 0 && last_token != '*');
++ str_getlen(&name_remain_str) > 0 &&
++ last_token != '*' && last_token != '?');
+ }
+ /* Any incoming string left means no match unless we ended on the correct
+ * type of wildcard.
+--
+2.14.4
+
diff --git a/0032-Propagate-errors-from-nfs-with-quota-to-client.patch b/0032-Propagate-errors-from-nfs-with-quota-to-client.patch
new file mode 100644
index 0000000..de56aa7
--- /dev/null
+++ b/0032-Propagate-errors-from-nfs-with-quota-to-client.patch
@@ -0,0 +1,147 @@
+From aa9cb48373018502ef99a57aad70b69c0c75ff65 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Thu, 17 Nov 2016 13:29:59 +0100
+Subject: [PATCH 32/59] Propagate errors from nfs with quota to client.
+
+vsftpd now checks for errors when closing newly uploaded file and
+forward errors to the client (e.g. when file system quota was
+exceeded)
+---
+ ftpcodes.h | 1 +
+ postlogin.c | 32 ++++++++++++++++++++++++++++++--
+ sysutil.c | 21 +++++++++++++++++++++
+ sysutil.h | 1 +
+ 4 files changed, 53 insertions(+), 2 deletions(-)
+
+diff --git a/ftpcodes.h b/ftpcodes.h
+index 54dfae7..97801f3 100644
+--- a/ftpcodes.h
++++ b/ftpcodes.h
+@@ -74,6 +74,7 @@
+ #define FTP_NOHANDLEPROT 536
+ #define FTP_FILEFAIL 550
+ #define FTP_NOPERM 550
++#define FTP_DISKQUOTA 552
+ #define FTP_UPLOADFAIL 553
+
+ #endif /* VSF_FTPCODES_H */
+diff --git a/postlogin.c b/postlogin.c
+index e473c34..8363c9c 100644
+--- a/postlogin.c
++++ b/postlogin.c
+@@ -28,6 +28,8 @@
+ #include "vsftpver.h"
+ #include "opts.h"
+
++#include <errno.h>
++
+ /* Private local functions */
+ static void handle_pwd(struct vsf_session* p_sess);
+ static void handle_cwd(struct vsf_session* p_sess);
+@@ -1035,8 +1037,10 @@ handle_upload_common(struct vsf_session* p_sess, int is_append, int is_unique)
+ struct vsf_transfer_ret trans_ret;
+ int new_file_fd;
+ int remote_fd;
++ int close_errno;
+ int success = 0;
+ int created = 0;
++ int closed = 0;
+ int do_truncate = 0;
+ filesize_t offset = p_sess->restart_pos;
+ p_sess->restart_pos = 0;
+@@ -1149,6 +1153,18 @@ handle_upload_common(struct vsf_session* p_sess, int is_append, int is_unique)
+ trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
+ new_file_fd, 1, 0);
+ }
++
++ /* Need to check close operation here because some errors
++ * like EIO, EDQUOT, ENOSPC can be detected only on close
++ * when using NFS
++ */
++ close_errno = vsf_sysutil_close_errno(new_file_fd);
++ closed = 1;
++ if (close_errno != 0)
++ {
++ trans_ret.retval = -1;
++ }
++
+ if (vsf_ftpdataio_dispose_transfer_fd(p_sess) != 1 && trans_ret.retval == 0)
+ {
+ trans_ret.retval = -2;
+@@ -1161,7 +1177,16 @@ handle_upload_common(struct vsf_session* p_sess, int is_append, int is_unique)
+ }
+ if (trans_ret.retval == -1)
+ {
+- vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure writing to local file.");
++ /* Disk quota exceeded */
++ if (close_errno == EDQUOT)
++ {
++ vsf_cmdio_write(p_sess, FTP_DISKQUOTA, "Disk quota exceeded.");
++ }
++ /* any other local error */
++ else
++ {
++ vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure writing to local file.");
++ }
+ }
+ else if (trans_ret.retval == -2)
+ {
+@@ -1183,7 +1208,10 @@ port_pasv_cleanup_out:
+ {
+ str_unlink(p_filename);
+ }
+- vsf_sysutil_close(new_file_fd);
++ if (!closed)
++ {
++ vsf_sysutil_close(new_file_fd);
++ }
+ }
+
+ static void
+diff --git a/sysutil.c b/sysutil.c
+index 42bcdf8..1c0422e 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -1268,6 +1268,27 @@ vsf_sysutil_close(int fd)
+ }
+ }
+
++int
++vsf_sysutil_close_errno(int fd)
++{
++ while (1)
++ {
++ int retval = close(fd);
++ if (retval != 0)
++ {
++ if (errno == EINTR)
++ {
++ vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown, 0, 0);
++ continue;
++ }
++ else {
++ return errno;
++ }
++ }
++ return 0;
++ }
++}
++
+ int
+ vsf_sysutil_close_failok(int fd)
+ {
+diff --git a/sysutil.h b/sysutil.h
+index 2886bbc..be727f5 100644
+--- a/sysutil.h
++++ b/sysutil.h
+@@ -92,6 +92,7 @@ int vsf_sysutil_create_or_open_file_append(const char* p_filename,
+ int vsf_sysutil_create_or_open_file(const char* p_filename, unsigned int mode);
+ void vsf_sysutil_dupfd2(int old_fd, int new_fd);
+ void vsf_sysutil_close(int fd);
++int vsf_sysutil_close_errno(int fd);
+ int vsf_sysutil_close_failok(int fd);
+ int vsf_sysutil_unlink(const char* p_dead);
+ int vsf_sysutil_write_access(const char* p_filename);
+--
+2.14.4
+
diff --git a/0034-Turn-off-seccomp-sandbox-because-it-is-too-strict.patch b/0034-Turn-off-seccomp-sandbox-because-it-is-too-strict.patch
new file mode 100644
index 0000000..0c0bdb7
--- /dev/null
+++ b/0034-Turn-off-seccomp-sandbox-because-it-is-too-strict.patch
@@ -0,0 +1,25 @@
+From 4922e60589326540b2ee4f0bdfd6cb95f645f3d5 Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Fri, 18 Nov 2016 10:23:29 +0100
+Subject: [PATCH 34/59] Turn off seccomp sandbox, because it is too strict.
+
+---
+ tunables.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tunables.c b/tunables.c
+index 78f2bcd..5440c00 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -237,7 +237,7 @@ tunables_load_defaults()
+ tunable_isolate_network = 1;
+ tunable_ftp_enable = 1;
+ tunable_http_enable = 0;
+- tunable_seccomp_sandbox = 1;
++ tunable_seccomp_sandbox = 0;
+ tunable_allow_writeable_chroot = 0;
+
+ tunable_accept_timeout = 60;
+--
+2.14.4
+
diff --git a/0035-Modify-DH-enablement-patch-to-build-with-OpenSSL-1.1.patch b/0035-Modify-DH-enablement-patch-to-build-with-OpenSSL-1.1.patch
new file mode 100644
index 0000000..1cebc18
--- /dev/null
+++ b/0035-Modify-DH-enablement-patch-to-build-with-OpenSSL-1.1.patch
@@ -0,0 +1,74 @@
+From 6c8dd87f311e411bcb1c72c1c780497881a5621c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Mon, 4 Sep 2017 11:32:03 +0200
+Subject: [PATCH 35/59] Modify DH enablement patch to build with OpenSSL 1.1
+
+---
+ ssl.c | 41 ++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 38 insertions(+), 3 deletions(-)
+
+diff --git a/ssl.c b/ssl.c
+index ba8a613..09ec96a 100644
+--- a/ssl.c
++++ b/ssl.c
+@@ -88,19 +88,54 @@ static struct mystr debug_str;
+ }
+ #endif
+
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
++{
++ /* If the fields p and g in d are NULL, the corresponding input
++ * parameters MUST be non-NULL. q may remain NULL.
++ */
++ if ((dh->p == NULL && p == NULL)
++ || (dh->g == NULL && g == NULL))
++ return 0;
++
++ if (p != NULL) {
++ BN_free(dh->p);
++ dh->p = p;
++ }
++ if (q != NULL) {
++ BN_free(dh->q);
++ dh->q = q;
++ }
++ if (g != NULL) {
++ BN_free(dh->g);
++ dh->g = g;
++ }
++
++ if (q != NULL) {
++ dh->length = BN_num_bits(q);
++ }
++
++ return 1;
++}
++#endif
++
+ #if !defined(DH_get_dh)
+ // Grab DH parameters
+ DH *
+ DH_get_dh(int size)
+ {
++ BIGNUM *g = NULL;
++ BIGNUM *p = NULL;
+ DH *dh = DH_new();
+ if (!dh) {
+ return NULL;
+ }
+- dh->p = DH_get_prime(match_dh_bits(size));
+- BN_dec2bn(&dh->g, "2");
+- if (!dh->p || !dh->g)
++ p = DH_get_prime(match_dh_bits(size));
++ BN_dec2bn(&g, "2");
++ if (!p || !g || !DH_set0_pqg(dh, p, NULL, g))
+ {
++ BN_free(g);
++ BN_free(p);
+ DH_free(dh);
+ return NULL;
+ }
+--
+2.14.4
+
diff --git a/0036-Redefine-VSFTP_COMMAND_FD-to-1.patch b/0036-Redefine-VSFTP_COMMAND_FD-to-1.patch
new file mode 100644
index 0000000..4299b23
--- /dev/null
+++ b/0036-Redefine-VSFTP_COMMAND_FD-to-1.patch
@@ -0,0 +1,29 @@
+From 18e0ab25a0d66088728b506cf64f5545637eda26 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Tue, 5 Sep 2017 14:26:08 +0200
+Subject: [PATCH 36/59] Redefine VSFTP_COMMAND_FD to 1
+
+Redefine VSFTP_COMMAND_FD to 1 (stdout) so that error messages generated
+during startup are picked up by systemd.
+
+Resolves: rhbz#1443055
+---
+ defs.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/defs.h b/defs.h
+index bde3232..315f0f0 100644
+--- a/defs.h
++++ b/defs.h
+@@ -3,7 +3,7 @@
+
+ #define VSFTP_DEFAULT_CONFIG "/etc/vsftpd/vsftpd.conf"
+
+-#define VSFTP_COMMAND_FD 0
++#define VSFTP_COMMAND_FD 1
+
+ #define VSFTP_PASSWORD_MAX 128
+ #define VSFTP_USERNAME_MAX 128
+--
+2.14.4
+
diff --git a/0037-Document-the-relationship-of-text_userdb_names-and-c.patch b/0037-Document-the-relationship-of-text_userdb_names-and-c.patch
new file mode 100644
index 0000000..ae188d7
--- /dev/null
+++ b/0037-Document-the-relationship-of-text_userdb_names-and-c.patch
@@ -0,0 +1,29 @@
+From 221f35f302d53f5a89f8e79592492e7cb322e81a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Thu, 26 Oct 2017 13:08:32 +0200
+Subject: [PATCH 37/59] Document the relationship of text_userdb_names and
+ chroot_local_user
+
+Note in vsftpd.conf(5) that text_userdb_names may not work when
+chroot_local_user is set to YES.
+---
+ vsftpd.conf.5 | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index a3d569e..45b3f9c 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -578,6 +578,9 @@ Default: NO
+ By default, numeric IDs are shown in the user and group fields of directory
+ listings. You can get textual names by enabling this parameter. It is off
+ by default for performance reasons.
++Note that textual names are not guaranteed when
++.BR chroot_local_user
++is set to YES.
+
+ Default: NO
+ .TP
+--
+2.14.4
+
diff --git a/0038-Document-allow_writeable_chroot-in-the-man-page.patch b/0038-Document-allow_writeable_chroot-in-the-man-page.patch
new file mode 100644
index 0000000..ca073d3
--- /dev/null
+++ b/0038-Document-allow_writeable_chroot-in-the-man-page.patch
@@ -0,0 +1,32 @@
+From 35ec3be5427a54facd5f6299fda2da4c146d4846 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Fri, 24 Nov 2017 11:22:43 +0100
+Subject: [PATCH 38/59] Document allow_writeable_chroot in the man page
+
+---
+ vsftpd.conf.5 | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index 45b3f9c..d1f0db5 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -56,6 +56,15 @@ Only applies if
+ is active. If set to YES, anonymous users will be allowed to use secured SSL
+ connections.
+
++Default: NO
++.TP
++.B allow_writeable_chroot
++Allow chroot()'ing a user to a directory writable by that user. Note that
++setting this to YES is potentially dangerous. For example, if the user
++creates an 'etc' directory in the new root directory, they could potentially
++trick the C library into loading a user-created configuration file from the
++/etc/ directory.
++
+ Default: NO
+ .TP
+ .B anon_mkdir_write_enable
+--
+2.14.4
+
diff --git a/0039-Improve-documentation-of-ASCII-mode-in-the-man-page.patch b/0039-Improve-documentation-of-ASCII-mode-in-the-man-page.patch
new file mode 100644
index 0000000..307ce35
--- /dev/null
+++ b/0039-Improve-documentation-of-ASCII-mode-in-the-man-page.patch
@@ -0,0 +1,34 @@
+From 7d4b76abb437184fa692533cb5537318026a30e8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Fri, 24 Nov 2017 11:26:37 +0100
+Subject: [PATCH 39/59] Improve documentation of ASCII mode in the man page
+
+---
+ vsftpd.conf.5 | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index d1f0db5..3ca55e4 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -113,11 +113,17 @@ Default: YES
+ .TP
+ .B ascii_download_enable
+ When enabled, ASCII mode data transfers will be honoured on downloads.
++When disabled, the server will pretend to allow ASCII mode but in fact
++ignore the request. Turn this option on to have the server actually do
++ASCII mangling on files when in ASCII mode.
+
+ Default: NO
+ .TP
+ .B ascii_upload_enable
+ When enabled, ASCII mode data transfers will be honoured on uploads.
++See also
++.BR ascii_download_enable
++for more details.
+
+ Default: NO
+ .TP
+--
+2.14.4
+
diff --git a/0040-Use-system-wide-crypto-policy.patch b/0040-Use-system-wide-crypto-policy.patch
new file mode 100644
index 0000000..7de0781
--- /dev/null
+++ b/0040-Use-system-wide-crypto-policy.patch
@@ -0,0 +1,27 @@
+From b83be8b4f86bf1a8a6de4802a9486d084c4a46cd Mon Sep 17 00:00:00 2001
+From: Martin Sehnoutka <msehnout@redhat.com>
+Date: Tue, 29 Aug 2017 10:32:16 +0200
+Subject: [PATCH 40/59] Use system wide crypto policy
+
+Resolves: rhbz#1483970
+---
+ tunables.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/tunables.c b/tunables.c
+index 5440c00..354251c 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -297,8 +297,7 @@ tunables_load_defaults()
+ install_str_setting(0, &tunable_dsa_cert_file);
+ install_str_setting(0, &tunable_dh_param_file);
+ install_str_setting(0, &tunable_ecdh_param_file);
+- install_str_setting("AES128-SHA:DES-CBC3-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA",
+- &tunable_ssl_ciphers);
++ install_str_setting("PROFILE=SYSTEM", &tunable_ssl_ciphers);
+ install_str_setting(0, &tunable_rsa_private_key_file);
+ install_str_setting(0, &tunable_dsa_private_key_file);
+ install_str_setting(0, &tunable_ca_certs_file);
+--
+2.14.4
+
diff --git a/0041-Document-the-new-default-for-ssl_ciphers-in-the-man-.patch b/0041-Document-the-new-default-for-ssl_ciphers-in-the-man-.patch
new file mode 100644
index 0000000..93e2ce8
--- /dev/null
+++ b/0041-Document-the-new-default-for-ssl_ciphers-in-the-man-.patch
@@ -0,0 +1,31 @@
+From 2369d1ea5144d525d315aba90da528e7d9bfd1cc Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Thu, 21 Dec 2017 14:19:18 +0100
+Subject: [PATCH 41/59] Document the new default for ssl_ciphers in the man
+ page
+
+Related: rhbz#1483970
+---
+ vsftpd.conf.5 | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index 3ca55e4..2a7662e 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -1078,7 +1078,11 @@ man page for further details. Note that restricting ciphers can be a useful
+ security precaution as it prevents malicious remote parties forcing a cipher
+ which they have found problems with.
+
+-Default: DES-CBC3-SHA
++By default, the system-wide crypto policy is used. See
++.BR update-crypto-policies(8)
++for further details.
++
++Default: PROFILE=SYSTEM
+ .TP
+ .B ssl_sni_hostname
+ If set, SSL connections will be rejected unless the SNI hostname in the
+--
+2.14.4
+
diff --git a/0044-Disable-anonymous_enable-in-default-config-file.patch b/0044-Disable-anonymous_enable-in-default-config-file.patch
new file mode 100644
index 0000000..4e62d76
--- /dev/null
+++ b/0044-Disable-anonymous_enable-in-default-config-file.patch
@@ -0,0 +1,26 @@
+From ffaeebcfdb56ba75392af21c68c0bac78a226b55 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Tue, 2 Jan 2018 09:54:43 +0100
+Subject: [PATCH 44/59] Disable anonymous_enable in default config file
+
+Resolves: rhbz#1338637
+---
+ vsftpd.conf | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/vsftpd.conf b/vsftpd.conf
+index 39d1955..4626c1b 100644
+--- a/vsftpd.conf
++++ b/vsftpd.conf
+@@ -9,7 +9,7 @@
+ # capabilities.
+ #
+ # Allow anonymous FTP? (Beware - allowed by default if you comment this out).
+-anonymous_enable=YES
++anonymous_enable=NO
+ #
+ # Uncomment this to allow local users to log in.
+ # When SELinux is enforcing check for SE bool ftp_home_dir
+--
+2.14.4
+
diff --git a/0045-Expand-explanation-of-ascii_-options-behaviour-in-ma.patch b/0045-Expand-explanation-of-ascii_-options-behaviour-in-ma.patch
new file mode 100644
index 0000000..2243790
--- /dev/null
+++ b/0045-Expand-explanation-of-ascii_-options-behaviour-in-ma.patch
@@ -0,0 +1,52 @@
+From 61327320b54a59e319c522151f7a61c74ec94f2f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Tue, 2 Jan 2018 16:25:55 +0100
+Subject: [PATCH 45/59] Expand explanation of ascii_* options behaviour in man
+ page
+
+---
+ vsftpd.conf.5 | 22 ++++++++++++++++++----
+ 1 file changed, 18 insertions(+), 4 deletions(-)
+
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index df14027..a5abeb2 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -114,16 +114,30 @@ Default: YES
+ .B ascii_download_enable
+ When enabled, ASCII mode data transfers will be honoured on downloads.
+ When disabled, the server will pretend to allow ASCII mode but in fact
+-ignore the request. Turn this option on to have the server actually do
++ignore requests to activate it. So the client will think the ASCII mode
++is active and therefore may still translate any
++.BR <CRLF>
++character sequences in the received file. See the following article for
++a detailed explanation of the behaviour:
++https://access.redhat.com/articles/3250241.
++
++Turn this option on to have the server actually do
+ ASCII mangling on files when in ASCII mode.
+
+ Default: NO
+ .TP
+ .B ascii_upload_enable
+ When enabled, ASCII mode data transfers will be honoured on uploads.
+-See also
+-.BR ascii_download_enable
+-for more details.
++When disabled, the server will pretend to allow ASCII mode but in fact
++ignore requests to activate it. So the client will think the ASCII mode
++is active and will translate native line terminators to the standard
++.BR <CRLF>
++line terminators for transmission, but the server will not do
++any translation. See the following article for a detailed explanation
++of the behaviour: https://access.redhat.com/articles/3250241.
++
++Turn this option on to have the server actually do
++ASCII mangling on files when in ASCII mode.
+
+ Default: NO
+ .TP
+--
+2.14.4
+
diff --git a/0046-vsftpd.conf-Refer-to-the-man-page-regarding-the-asci.patch b/0046-vsftpd.conf-Refer-to-the-man-page-regarding-the-asci.patch
new file mode 100644
index 0000000..61ed691
--- /dev/null
+++ b/0046-vsftpd.conf-Refer-to-the-man-page-regarding-the-asci.patch
@@ -0,0 +1,27 @@
+From 446f7c1ec54e06b5da2e890e0cd8fbd7308322c9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Tue, 2 Jan 2018 16:33:18 +0100
+Subject: [PATCH 46/59] vsftpd.conf: Refer to the man page regarding the
+ ascii_* options
+
+---
+ vsftpd.conf | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/vsftpd.conf b/vsftpd.conf
+index 4626c1b..e70bc6d 100644
+--- a/vsftpd.conf
++++ b/vsftpd.conf
+@@ -73,7 +73,8 @@ xferlog_std_format=YES
+ #
+ # By default the server will pretend to allow ASCII mode but in fact ignore
+ # the request. Turn on the below options to have the server actually do ASCII
+-# mangling on files when in ASCII mode.
++# mangling on files when in ASCII mode. The vsftpd.conf(5) man page explains
++# the behaviour when these options are disabled.
+ # Beware that on some FTP servers, ASCII support allows a denial of service
+ # attack (DoS) via the command "SIZE /big/file" in ASCII mode. vsftpd
+ # predicted this attack and has always been safe, reporting the size of the
+--
+2.14.4
+
diff --git a/0047-Disable-tcp_wrappers-support.patch b/0047-Disable-tcp_wrappers-support.patch
new file mode 100644
index 0000000..f71aab0
--- /dev/null
+++ b/0047-Disable-tcp_wrappers-support.patch
@@ -0,0 +1,49 @@
+From b383ec42bb750419fea102fccf36af5216145eb2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Fri, 5 Jan 2018 09:17:13 +0100
+Subject: [PATCH 47/59] Disable tcp_wrappers support
+
+Resolves: rhbz#1518796
+---
+ Makefile | 2 +-
+ builddefs.h | 1 -
+ vsftpd.conf | 1 -
+ 3 files changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index 98118dc..612994e 100644
+--- a/Makefile
++++ b/Makefile
+@@ -8,7 +8,7 @@ CFLAGS = -O2 -fPIE -fstack-protector --param=ssp-buffer-size=4 \
+ -D_FORTIFY_SOURCE=2 \
+ #-pedantic -Wconversion
+
+-LIBS = -lwrap -lnsl -lpam -lcap -ldl -lcrypto
++LIBS = -lnsl -lpam -lcap -ldl -lcrypto
+ LINK = -Wl,-s
+ LDFLAGS = -fPIE -pie -Wl,-z,relro -Wl,-z,now
+
+diff --git a/builddefs.h b/builddefs.h
+index 83de674..2aa3a4c 100644
+--- a/builddefs.h
++++ b/builddefs.h
+@@ -1,7 +1,6 @@
+ #ifndef VSF_BUILDDEFS_H
+ #define VSF_BUILDDEFS_H
+
+-#define VSF_BUILD_TCPWRAPPERS
+ #define VSF_BUILD_PAM
+ #define VSF_BUILD_SSL
+
+diff --git a/vsftpd.conf b/vsftpd.conf
+index e70bc6d..6b8eebb 100644
+--- a/vsftpd.conf
++++ b/vsftpd.conf
+@@ -125,4 +125,3 @@ listen_ipv6=YES
+
+ pam_service_name=vsftpd
+ userlist_enable=YES
+-tcp_wrappers=YES
+--
+2.14.4
+
diff --git a/0048-Fix-default-value-of-strict_ssl_read_eof-in-man-page.patch b/0048-Fix-default-value-of-strict_ssl_read_eof-in-man-page.patch
new file mode 100644
index 0000000..513e128
--- /dev/null
+++ b/0048-Fix-default-value-of-strict_ssl_read_eof-in-man-page.patch
@@ -0,0 +1,29 @@
+From 9cba9e81aa96e1d64ae2eaaf88330e09dadfce79 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Fri, 5 Jan 2018 09:40:09 +0100
+Subject: [PATCH 48/59] Fix default value of strict_ssl_read_eof in man page
+
+---
+ vsftpd.conf.5 | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index a5abeb2..43b0435 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -574,10 +574,9 @@ Default: YES
+ .B strict_ssl_read_eof
+ If enabled, SSL data uploads are required to terminate via SSL, not an
+ EOF on the socket. This option is required to be sure that an attacker did
+-not terminate an upload prematurely with a faked TCP FIN. Unfortunately, it
+-is not enabled by default because so few clients get it right. (New in v2.0.7).
++not terminate an upload prematurely with a faked TCP FIN. (New in v2.0.7).
+
+-Default: NO
++Default: YES
+ .TP
+ .B strict_ssl_write_shutdown
+ If enabled, SSL data downloads are required to terminate via SSL, not an
+--
+2.14.4
+
diff --git a/0049-Add-new-filename-generation-algorithm-for-STOU-comma.patch b/0049-Add-new-filename-generation-algorithm-for-STOU-comma.patch
new file mode 100644
index 0000000..22745b5
--- /dev/null
+++ b/0049-Add-new-filename-generation-algorithm-for-STOU-comma.patch
@@ -0,0 +1,322 @@
+From 1203b943b369651d96d057f8190f14f015e6ff0b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Tue, 6 Feb 2018 13:30:44 +0100
+Subject: [PATCH 49/59] Add new filename generation algorithm for STOU command
+
+A new configuration option 'better_stou' can be used to enable
+a better algorithm for generating unique filenames.
+
+Resolves: rhbz#1479237
+---
+ parseconf.c | 1 +
+ postlogin.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++---------
+ sysutil.c | 3 +
+ sysutil.h | 3 +-
+ tunables.c | 2 +
+ tunables.h | 3 +
+ vsftpd.conf.5 | 5 ++
+ 7 files changed, 166 insertions(+), 27 deletions(-)
+
+diff --git a/parseconf.c b/parseconf.c
+index 33a1349..47b54f1 100644
+--- a/parseconf.c
++++ b/parseconf.c
+@@ -111,6 +111,7 @@ parseconf_bool_array[] =
+ { "http_enable", &tunable_http_enable },
+ { "seccomp_sandbox", &tunable_seccomp_sandbox },
+ { "allow_writeable_chroot", &tunable_allow_writeable_chroot },
++ { "better_stou", &tunable_better_stou },
+ { 0, 0 }
+ };
+
+diff --git a/postlogin.c b/postlogin.c
+index 8363c9c..7c749ef 100644
+--- a/postlogin.c
++++ b/postlogin.c
+@@ -29,6 +29,7 @@
+ #include "opts.h"
+
+ #include <errno.h>
++#include <stdio.h>
+
+ /* Private local functions */
+ static void handle_pwd(struct vsf_session* p_sess);
+@@ -1028,6 +1029,114 @@ handle_stor(struct vsf_session* p_sess)
+ handle_upload_common(p_sess, 0, 0);
+ }
+
++/* Based on __gen_tempname() from glibc - thanks, glibc! Relicensed
++ * from LGPL2.1+ to GPL2.
++ */
++static int
++create_unique_file(struct vsf_session* p_sess, struct mystr* p_outstr,
++ const struct mystr* p_base_str,
++ int (*access_checker)(const struct mystr*))
++{
++ struct mystr s_result = INIT_MYSTR;
++ const int suffix_len = 6;
++ unsigned int count;
++ static unsigned long long int value;
++ unsigned long long int random_time_bits;
++ int fd = -1;
++ /* These are the characters used in temporary file names. */
++ struct mystr s_letters = INIT_MYSTR;
++ unsigned int s_letters_len;
++ int base_len;
++
++ str_alloc_text(&s_letters,
++ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
++ s_letters_len = str_getlen(&s_letters);
++
++ /* A lower bound on the number of temporary files to attempt to
++ generate. The maximum total number of temporary file names that
++ can exist for a given template is 62**6. It should never be
++ necessary to try all of these combinations. Instead if a reasonable
++ number of names is tried (we define reasonable as 62**3) fail to
++ give the system administrator the chance to remove the problems. */
++#define ATTEMPTS_MIN (62 * 62 * 62)
++
++ /* The number of times to attempt to generate a temporary file. */
++#if ATTEMPTS_MIN < TMP_MAX
++ unsigned int attempts = TMP_MAX;
++#else
++ unsigned int attempts = ATTEMPTS_MIN;
++#endif
++#undef ATTEMPTS_MIN
++
++ {
++ long sec = vsf_sysutil_get_time_sec();
++ long usec = vsf_sysutil_get_time_usec();
++ random_time_bits = ((unsigned long long int) usec << 16) ^ sec;
++ value += random_time_bits ^ vsf_sysutil_getpid();
++ }
++
++ if (str_isempty(p_base_str))
++ {
++ const char *base = "STOU.";
++ base_len = vsf_sysutil_strlen(base);
++ str_reserve(&s_result, base_len + suffix_len);
++ str_alloc_text(&s_result, base);
++ }
++ else
++ {
++ str_reserve(&s_result, str_getlen(p_base_str) + suffix_len + 1);
++ str_copy(&s_result, p_base_str);
++ str_append_char(&s_result, '.');
++ base_len = str_getlen(&s_result);
++ }
++
++ for (count = 0; count < attempts; value += 7777, ++count)
++ {
++ unsigned long long v = value;
++ str_trunc(&s_result, base_len);
++ for (int i = 0; i < suffix_len; ++i)
++ {
++ char c;
++ c = str_get_char_at(&s_letters, v % s_letters_len);
++ v /= s_letters_len;
++ str_append_char(&s_result, c);
++ }
++ if (!access_checker(&s_result))
++ {
++ /* If we generate a filename which is not allowed, we fail immediatelly,
++ * without trying any other possibilities. This is to prevent attackers
++ * from keeping us busy.
++ */
++ vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
++ break;
++ }
++ fd = str_create_exclusive(&s_result);
++ if (vsf_sysutil_retval_is_error(fd))
++ {
++ if (kVSFSysUtilErrEXIST == vsf_sysutil_get_error())
++ {
++ continue;
++ }
++ else
++ {
++ vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, "Could not create file.");
++ break;
++ }
++ }
++ else
++ {
++ break;
++ }
++ }
++ if (!vsf_sysutil_retval_is_error(fd))
++ {
++ str_copy(p_outstr, &s_result);
++ }
++ str_free(&s_letters);
++ str_free(&s_result);
++ return fd;
++}
++
+ static void
+ handle_upload_common(struct vsf_session* p_sess, int is_append, int is_unique)
+ {
+@@ -1049,41 +1158,56 @@ handle_upload_common(struct vsf_session* p_sess, int is_append, int is_unique)
+ return;
+ }
+ resolve_tilde(&p_sess->ftp_arg_str, p_sess);
+- p_filename = &p_sess->ftp_arg_str;
+- if (is_unique)
+- {
+- get_unique_filename(&s_filename, p_filename);
+- p_filename = &s_filename;
+- }
+ vsf_log_start_entry(p_sess, kVSFLogEntryUpload);
+ str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
+ prepend_path_to_filename(&p_sess->log_str);
+- if (!vsf_access_check_file(p_filename))
+- {
+- vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
+- return;
+- }
+- /* NOTE - actual file permissions will be governed by the tunable umask */
+- /* XXX - do we care about race between create and chown() of anonymous
+- * upload?
+- */
+- if (is_unique || (p_sess->is_anonymous && !tunable_anon_other_write_enable))
++ p_filename = &p_sess->ftp_arg_str;
++ if (is_unique && tunable_better_stou)
+ {
+- new_file_fd = str_create_exclusive(p_filename);
++ new_file_fd = create_unique_file(p_sess, &s_filename, p_filename,
++ vsf_access_check_file);
++ if (vsf_sysutil_retval_is_error(new_file_fd))
++ {
++ return;
++ }
++ p_filename = &s_filename;
+ }
+ else
+ {
+- /* For non-anonymous, allow open() to overwrite or append existing files */
+- new_file_fd = str_create(p_filename);
+- if (!is_append && offset == 0)
++ if (is_unique)
+ {
+- do_truncate = 1;
++ get_unique_filename(&s_filename, p_filename);
++ p_filename = &s_filename;
++ }
++ if (!vsf_access_check_file(p_filename))
++ {
++ vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
++ return;
++ }
++ /* NOTE - actual file permissions will be governed by the tunable umask */
++ /* XXX - do we care about race between create and chown() of anonymous
++ * upload?
++ */
++ if (is_unique || (p_sess->is_anonymous && !tunable_anon_other_write_enable))
++ {
++ new_file_fd = str_create_exclusive(p_filename);
++ }
++ else
++ {
++ /* For non-anonymous, allow open() to overwrite or append existing
++ * files
++ */
++ new_file_fd = str_create(p_filename);
++ if (!is_append && offset == 0)
++ {
++ do_truncate = 1;
++ }
++ }
++ if (vsf_sysutil_retval_is_error(new_file_fd))
++ {
++ vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, "Could not create file.");
++ return;
+ }
+- }
+- if (vsf_sysutil_retval_is_error(new_file_fd))
+- {
+- vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, "Could not create file.");
+- return;
+ }
+ created = 1;
+ vsf_sysutil_fstat(new_file_fd, &s_p_statbuf);
+diff --git a/sysutil.c b/sysutil.c
+index 1c0422e..e847650 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -1666,6 +1666,9 @@ vsf_sysutil_get_error(void)
+ case EAGAIN:
+ retval = kVSFSysUtilErrAGAIN;
+ break;
++ case EEXIST:
++ retval = kVSFSysUtilErrEXIST;
++ break;
+ default:
+ break;
+ }
+diff --git a/sysutil.h b/sysutil.h
+index be727f5..7a59f13 100644
+--- a/sysutil.h
++++ b/sysutil.h
+@@ -19,7 +19,8 @@ enum EVSFSysUtilError
+ kVSFSysUtilErrOPNOTSUPP,
+ kVSFSysUtilErrACCES,
+ kVSFSysUtilErrNOENT,
+- kVSFSysUtilErrAGAIN
++ kVSFSysUtilErrAGAIN,
++ kVSFSysUtilErrEXIST
+ };
+ enum EVSFSysUtilError vsf_sysutil_get_error(void);
+
+diff --git a/tunables.c b/tunables.c
+index 9680528..5ec2bdc 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -92,6 +92,7 @@ int tunable_ftp_enable;
+ int tunable_http_enable;
+ int tunable_seccomp_sandbox;
+ int tunable_allow_writeable_chroot;
++int tunable_better_stou;
+
+ unsigned int tunable_accept_timeout;
+ unsigned int tunable_connect_timeout;
+@@ -239,6 +240,7 @@ tunables_load_defaults()
+ tunable_http_enable = 0;
+ tunable_seccomp_sandbox = 0;
+ tunable_allow_writeable_chroot = 0;
++ tunable_better_stou = 0;
+
+ tunable_accept_timeout = 60;
+ tunable_connect_timeout = 60;
+diff --git a/tunables.h b/tunables.h
+index a466427..85ea1a8 100644
+--- a/tunables.h
++++ b/tunables.h
+@@ -93,6 +93,9 @@ extern int tunable_ftp_enable; /* Allow FTP protocol */
+ extern int tunable_http_enable; /* Allow HTTP protocol */
+ extern int tunable_seccomp_sandbox; /* seccomp filter sandbox */
+ extern int tunable_allow_writeable_chroot; /* Allow misconfiguration */
++extern int tunable_better_stou; /* Use better file name generation
++ * algorithm for the STOU command
++ */
+
+ /* Integer/numeric defines */
+ extern unsigned int tunable_accept_timeout;
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index 43b0435..6911a73 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -65,6 +65,11 @@ creates an 'etc' directory in the new root directory, they could potentially
+ trick the C library into loading a user-created configuration file from the
+ /etc/ directory.
+
++Default: NO
++.TP
++.B better_stou
++Use better file name generation algorithm for the STOU command.
++
+ Default: NO
+ .TP
+ .B anon_mkdir_write_enable
+--
+2.14.4
+
diff --git a/0050-Don-t-link-with-libnsl.patch b/0050-Don-t-link-with-libnsl.patch
new file mode 100644
index 0000000..8b626bb
--- /dev/null
+++ b/0050-Don-t-link-with-libnsl.patch
@@ -0,0 +1,27 @@
+From f8663f35d5d150f0533bb052e48306b9a5111d87 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Tue, 6 Feb 2018 18:04:53 +0100
+Subject: [PATCH 50/59] Don't link with libnsl
+
+Don't link with libnsl. It builds just fine without it and
+vsf_findlibs.sh enables it only when tcp_wrappers is enabled.
+---
+ Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Makefile b/Makefile
+index 612994e..0f7411c 100644
+--- a/Makefile
++++ b/Makefile
+@@ -8,7 +8,7 @@ CFLAGS = -O2 -fPIE -fstack-protector --param=ssp-buffer-size=4 \
+ -D_FORTIFY_SOURCE=2 \
+ #-pedantic -Wconversion
+
+-LIBS = -lnsl -lpam -lcap -ldl -lcrypto
++LIBS = -lpam -lcap -ldl -lcrypto
+ LINK = -Wl,-s
+ LDFLAGS = -fPIE -pie -Wl,-z,relro -Wl,-z,now
+
+--
+2.14.4
+
diff --git a/0051-Improve-documentation-of-better_stou-in-the-man-page.patch b/0051-Improve-documentation-of-better_stou-in-the-man-page.patch
new file mode 100644
index 0000000..c2593be
--- /dev/null
+++ b/0051-Improve-documentation-of-better_stou-in-the-man-page.patch
@@ -0,0 +1,30 @@
+From 765f99b26705c8d6fe2be4feb07f4c91e7eb96f9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Thu, 5 Apr 2018 12:29:03 +0200
+Subject: [PATCH 51/59] Improve documentation of better_stou in the man page
+
+---
+ vsftpd.conf.5 | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index 6911a73..e9ae474 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -68,7 +68,12 @@ trick the C library into loading a user-created configuration file from the
+ Default: NO
+ .TP
+ .B better_stou
+-Use better file name generation algorithm for the STOU command.
++Use a better file name generation algorithm for the STOU command. The default
++original algorithm simply adds an increasing number suffix to the file name,
++which is prone to race conditions if multiple uploaders use the STOU command
++with the same file name simultaneously, which can result in failure of the
++command. The new algorithm adds a unique random six character suffix to
++the file name, which works much better in face of concurrent uploads.
+
+ Default: NO
+ .TP
+--
+2.14.4
+
diff --git a/0052-Fix-rDNS-with-IPv6.patch b/0052-Fix-rDNS-with-IPv6.patch
new file mode 100644
index 0000000..eca9474
--- /dev/null
+++ b/0052-Fix-rDNS-with-IPv6.patch
@@ -0,0 +1,195 @@
+From 01b646d2af0ed885d01d31a6479898a3c423a630 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Thu, 26 Apr 2018 10:00:19 +0200
+Subject: [PATCH 52/59] Fix rDNS with IPv6
+
+Previously IPv6 addresses were not translated to hostnames for PAM to use.
+---
+ privops.c | 3 ++-
+ sysdeputil.c | 28 +++++++++++++++-------------
+ sysdeputil.h | 5 ++++-
+ sysutil.c | 35 +++++++++++++++++++++++++++++++++++
+ sysutil.h | 4 ++++
+ 5 files changed, 60 insertions(+), 15 deletions(-)
+
+diff --git a/privops.c b/privops.c
+index f27c5c4..e577a27 100644
+--- a/privops.c
++++ b/privops.c
+@@ -383,7 +383,8 @@ handle_local_login(struct vsf_session* p_sess,
+ struct mystr* p_user_str,
+ const struct mystr* p_pass_str)
+ {
+- if (!vsf_sysdep_check_auth(p_user_str, p_pass_str, &p_sess->remote_ip_str))
++ if (!vsf_sysdep_check_auth(p_sess, p_user_str, p_pass_str,
++ &p_sess->remote_ip_str))
+ {
+ return kVSFLoginFail;
+ }
+diff --git a/sysdeputil.c b/sysdeputil.c
+index 2063c87..4fe56c2 100644
+--- a/sysdeputil.c
++++ b/sysdeputil.c
+@@ -16,10 +16,6 @@
+ #include "tunables.h"
+ #include "builddefs.h"
+
+-/* For gethostbyaddr, inet_addr */
+-#include <netdb.h>
+-#include <arpa/inet.h>
+-
+ /* For Linux, this adds nothing :-) */
+ #include "port/porting_junk.h"
+
+@@ -242,13 +238,15 @@ void vsf_remove_uwtmp(void);
+
+ #ifndef VSF_SYSDEP_HAVE_PAM
+ int
+-vsf_sysdep_check_auth(struct mystr* p_user_str,
++vsf_sysdep_check_auth(struct vsf_session* p_sess,
++ struct mystr* p_user_str,
+ const struct mystr* p_pass_str,
+ const struct mystr* p_remote_host)
+ {
+ const char* p_crypted;
+ const struct passwd* p_pwd = getpwnam(str_getbuf(p_user_str));
+ (void) p_remote_host;
++ (void) p_sess;
+ if (p_pwd == NULL)
+ {
+ return 0;
+@@ -322,14 +320,14 @@ static int pam_conv_func(int nmsg, const struct pam_message** p_msg,
+ static void vsf_auth_shutdown(void);
+
+ int
+-vsf_sysdep_check_auth(struct mystr* p_user_str,
++vsf_sysdep_check_auth(struct vsf_session* p_sess,
++ struct mystr* p_user_str,
+ const struct mystr* p_pass_str,
+ const struct mystr* p_remote_host)
+ {
+ int retval = -1;
+ #ifdef PAM_RHOST
+- struct sockaddr_in sin;
+- struct hostent *host;
++ struct mystr hostname = INIT_MYSTR;
+ #endif
+ pam_item_t item;
+ const char* pam_user_name = 0;
+@@ -354,13 +352,17 @@ vsf_sysdep_check_auth(struct mystr* p_user_str,
+ return 0;
+ }
+ #ifdef PAM_RHOST
+- if (tunable_reverse_lookup_enable) {
+- sin.sin_addr.s_addr = inet_addr(str_getbuf(p_remote_host));
+- host = gethostbyaddr((char*)&sin.sin_addr.s_addr,sizeof(struct in_addr),AF_INET);
+- if (host != (struct hostent*)0)
+- retval = pam_set_item(s_pamh, PAM_RHOST, host->h_name);
++ if (tunable_reverse_lookup_enable)
++ {
++ if (vsf_sysutil_get_hostname(p_sess->p_remote_addr, &hostname) == 0)
++ {
++ retval = pam_set_item(s_pamh, PAM_RHOST, str_getbuf(&hostname));
++ str_free(&hostname);
++ }
+ else
++ {
+ retval = pam_set_item(s_pamh, PAM_RHOST, str_getbuf(p_remote_host));
++ }
+ } else {
+ retval = pam_set_item(s_pamh, PAM_RHOST, str_getbuf(p_remote_host));
+ }
+diff --git a/sysdeputil.h b/sysdeputil.h
+index 3b6b30a..6f2aa0a 100644
+--- a/sysdeputil.h
++++ b/sysdeputil.h
+@@ -5,6 +5,8 @@
+ #include "filesize.h"
+ #endif
+
++#include "session.h"
++
+ /* VSF_SYSDEPUTIL_H:
+ * Support for highly system dependent features, and querying for support
+ * or lack thereof
+@@ -15,7 +17,8 @@ struct mystr;
+
+ /* Authentication of local users */
+ /* Return 0 for fail, 1 for success */
+-int vsf_sysdep_check_auth(struct mystr* p_user,
++int vsf_sysdep_check_auth(struct vsf_session* p_sess,
++ struct mystr* p_user,
+ const struct mystr* p_pass,
+ const struct mystr* p_remote_host);
+
+diff --git a/sysutil.c b/sysutil.c
+index e847650..b68583b 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -2356,6 +2356,41 @@ vsf_sysutil_dns_resolve(struct vsf_sysutil_sockaddr** p_sockptr,
+ }
+ }
+
++int
++vsf_sysutil_get_hostname(struct vsf_sysutil_sockaddr *p_addr,
++ struct mystr* p_str)
++{
++ struct sockaddr *sa;
++ socklen_t sa_len = 0;
++ char hostname[NI_MAXHOST];
++ int res;
++
++ sa = &p_addr->u.u_sockaddr;
++ if (sa->sa_family == AF_INET)
++ {
++ sa_len = sizeof(struct sockaddr_in);
++ }
++ else if (sa->sa_family == AF_INET6)
++ {
++ sa_len = sizeof(struct sockaddr_in6);
++ }
++ else
++ {
++ die("can only support ipv4 and ipv6 currently");
++ }
++ res = getnameinfo(sa, sa_len, hostname, sizeof(hostname), NULL, 0,
++ NI_NAMEREQD);
++ if (res == 0)
++ {
++ str_alloc_text(p_str, hostname);
++ return 0;
++ }
++ else
++ {
++ return -1;
++ }
++}
++
+ struct vsf_sysutil_user*
+ vsf_sysutil_getpwuid(const unsigned int uid)
+ {
+diff --git a/sysutil.h b/sysutil.h
+index 7a59f13..2df14ed 100644
+--- a/sysutil.h
++++ b/sysutil.h
+@@ -7,6 +7,8 @@
+ #include "filesize.h"
+ #endif
+
++#include "str.h"
++
+ /* Return value queries */
+ int vsf_sysutil_retval_is_error(int retval);
+ enum EVSFSysUtilError
+@@ -266,6 +268,8 @@ int vsf_sysutil_connect_timeout(int fd,
+ unsigned int wait_seconds);
+ void vsf_sysutil_dns_resolve(struct vsf_sysutil_sockaddr** p_sockptr,
+ const char* p_name);
++int vsf_sysutil_get_hostname(struct vsf_sysutil_sockaddr *p_addr,
++ struct mystr* p_str);
+ /* Option setting on sockets */
+ void vsf_sysutil_activate_keepalive(int fd);
+ void vsf_sysutil_rcvtimeo(int fd);
+--
+2.14.4
+
diff --git a/0053-Always-do-chdir-after-chroot.patch b/0053-Always-do-chdir-after-chroot.patch
new file mode 100644
index 0000000..e1c0105
--- /dev/null
+++ b/0053-Always-do-chdir-after-chroot.patch
@@ -0,0 +1,32 @@
+From 315f9720db94af3319c9550feaf473b9cf09aeac Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Thu, 3 May 2018 13:20:28 +0200
+Subject: [PATCH 53/59] Always do chdir("/") after chroot()
+
+Always do chdir("/") after chroot() to be more sure we'll never get out
+of it. This will not affect the working directory after calling
+vsf_sysutil_chroot(), because in the current state vsftpd always calls
+vsf_sysutil_chroot(".").
+---
+ sysutil.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/sysutil.c b/sysutil.c
+index b68583b..3014c05 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -2588,6 +2588,11 @@ vsf_sysutil_chroot(const char* p_root_path)
+ {
+ die("chroot");
+ }
++ retval = chdir("/");
++ if (retval != 0)
++ {
++ die("chdir");
++ }
+ }
+
+ unsigned int
+--
+2.14.4
+
diff --git a/0054-vsf_sysutil_rcvtimeo-Check-return-value-of-setsockop.patch b/0054-vsf_sysutil_rcvtimeo-Check-return-value-of-setsockop.patch
new file mode 100644
index 0000000..d67db00
--- /dev/null
+++ b/0054-vsf_sysutil_rcvtimeo-Check-return-value-of-setsockop.patch
@@ -0,0 +1,33 @@
+From ca27e6e34d89fc247a164ed7330735644f97d7d8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Wed, 9 May 2018 20:15:29 +0200
+Subject: [PATCH 54/59] vsf_sysutil_rcvtimeo: Check return value of setsockopt
+
+---
+ sysutil.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/sysutil.c b/sysutil.c
+index 3014c05..de5f876 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -684,10 +684,15 @@ void
+ vsf_sysutil_rcvtimeo(int fd)
+ {
+ struct timeval tv;
++ int retval;
+
+ tv.tv_sec = tunable_data_connection_timeout;
+ tv.tv_usec = 0;
+- setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
++ retval = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
++ if (retval != 0)
++ {
++ die("setsockopt: rcvtimeo");
++ }
+ }
+
+ void
+--
+2.14.4
+
diff --git a/0055-vsf_sysutil_get_tz-Check-the-return-value-of-syscall.patch b/0055-vsf_sysutil_get_tz-Check-the-return-value-of-syscall.patch
new file mode 100644
index 0000000..85d4f2f
--- /dev/null
+++ b/0055-vsf_sysutil_get_tz-Check-the-return-value-of-syscall.patch
@@ -0,0 +1,108 @@
+From c7ac05fdf2a7b53d901bfc3afeb9a61916aaaaf1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Wed, 9 May 2018 20:26:37 +0200
+Subject: [PATCH 55/59] vsf_sysutil_get_tz: Check the return value of syscalls
+
+Check the return value of syscalls. There's always the possibility that
+they'll fail. (Failure of close() is not handled though, apart from EINTR.
+The file is open read-only so it shouldn't fail, and even if it does,
+it's not tragic.)
+
+We return NULL in case of syscall failure. One might be tempted to simply
+call die() when any kind of error occurs when parsing the timezone data,
+but I think it's more in line with the behaviour of tzset(3) not to do
+anything drastic in such a case (tzset() will silently use UTC when
+the value given in the TZ environment variable is invalid).
+---
+ sysutil.c | 46 +++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 37 insertions(+), 9 deletions(-)
+
+diff --git a/sysutil.c b/sysutil.c
+index de5f876..fd07d99 100644
+--- a/sysutil.c
++++ b/sysutil.c
+@@ -2647,12 +2647,12 @@ error:
+ die("reopening standard file descriptors to /dev/null failed");
+ }
+
+-char* vsf_sysutil_get_tz()
++char* vsf_sysutil_get_tz(void)
+ {
+ char *ret_tz = NULL;
+ char buff[BUFTZSIZ];
+ off_t s_pos, e_pos;
+- size_t rcnt, rest;
++ ssize_t rcnt, rest;
+ int fd;
+
+ if ((fd = open(F_LOCALTIME, O_RDONLY)) > -1)
+@@ -2663,8 +2663,12 @@ char* vsf_sysutil_get_tz()
+ return NULL;
+ }
+ s_pos = e_pos > BUFTZSIZ ? e_pos - BUFTZSIZ : 0;
+- lseek(fd, s_pos, SEEK_SET);
+- rcnt = read(fd, buff, BUFTZSIZ);
++ if (lseek(fd, s_pos, SEEK_SET) == -1 ||
++ (rcnt = vsf_sysutil_read(fd, buff, BUFTZSIZ)) == -1)
++ {
++ close(fd);
++ return NULL;
++ }
+
+ if (rcnt && buff[rcnt-1] == '\n')
+ {
+@@ -2680,10 +2684,25 @@ char* vsf_sysutil_get_tz()
+ int len = e_pos - s_pos - offset;
+ if (len)
+ {
+- lseek(fd, s_pos + offset, SEEK_SET);
++ if (lseek(fd, s_pos + offset, SEEK_SET) == -1)
++ {
++ close(fd);
++ return NULL;
++ }
+ ret_tz = calloc(1, len+4);
++ if (ret_tz == NULL)
++ {
++ close(fd);
++ return NULL;
++ }
+ memcpy(ret_tz, "TZ=", 3);
+- rcnt = read(fd, ret_tz+3, len);
++ rcnt = vsf_sysutil_read(fd, ret_tz+3, len);
++ if (rcnt == -1)
++ {
++ free(ret_tz);
++ close(fd);
++ return NULL;
++ }
+ }
+ break;
+ }
+@@ -2693,11 +2712,20 @@ char* vsf_sysutil_get_tz()
+ }
+ rest = s_pos > BUFTZSIZ ? s_pos - BUFTZSIZ : 0;
+ s_pos -= rest;
+- lseek(fd, s_pos, SEEK_SET);
+- rcnt = read(fd, buff, rest);
++ if (lseek(fd, s_pos, SEEK_SET) == -1)
++ {
++ close(fd);
++ return NULL;
++ }
++ rcnt = vsf_sysutil_read(fd, buff, rest);
++ if (rcnt == -1)
++ {
++ close(fd);
++ return NULL;
++ }
+ } while (rcnt > 0);
+
+- close (fd);
++ (void) vsf_sysutil_close_errno(fd);
+ }
+
+ return ret_tz;
+--
+2.14.4
+
diff --git a/0056-Log-die-calls-to-syslog.patch b/0056-Log-die-calls-to-syslog.patch
new file mode 100644
index 0000000..46b93f6
--- /dev/null
+++ b/0056-Log-die-calls-to-syslog.patch
@@ -0,0 +1,206 @@
+From ee6af258e8cb1a7fada5e6d3e54429b89f12b158 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Fri, 15 Jun 2018 12:02:21 +0200
+Subject: [PATCH 56/59] Log die() calls to syslog
+
+Pass messages given to die(), die2() and bug() to syslog. Currently this
+functionality requires waiting for a short amount of time (1 second is
+used) after logging the message and before exiting. This is a workaround
+for the following systemd bug:
+https://github.com/systemd/systemd/issues/2913
+
+The need for this workaround is the main reason why I decided not to
+enable this functionality by default.
+
+Resolves: rhbz#1318198
+Resolves: rhbz#1582672
+---
+ logging.c | 13 +++++++++----
+ logging.h | 2 ++
+ main.c | 4 ++++
+ parseconf.c | 1 +
+ tcpwrap.c | 3 ---
+ tunables.c | 2 ++
+ tunables.h | 2 ++
+ utility.c | 11 +++++++++++
+ vsftpd.conf.5 | 10 ++++++++++
+ 9 files changed, 41 insertions(+), 7 deletions(-)
+
+diff --git a/logging.c b/logging.c
+index c4461f7..9e86808 100644
+--- a/logging.c
++++ b/logging.c
+@@ -30,10 +30,6 @@ static void vsf_log_do_log_to_file(int fd, struct mystr* p_str);
+ void
+ vsf_log_init(struct vsf_session* p_sess)
+ {
+- if (tunable_syslog_enable || tunable_tcp_wrappers)
+- {
+- vsf_sysutil_openlog(0);
+- }
+ if (!tunable_xferlog_enable && !tunable_dual_log_enable)
+ {
+ return;
+@@ -389,3 +385,12 @@ vsf_log_do_log_vsftpd_format(struct vsf_session* p_sess, struct mystr* p_str,
+ }
+ }
+
++void
++vsf_log_die(const char* p_text)
++{
++ struct mystr log_str = INIT_MYSTR;
++
++ str_append_text(&log_str, "ERROR: ");
++ str_append_text(&log_str, p_text);
++ str_syslog(&log_str, 1);
++}
+diff --git a/logging.h b/logging.h
+index 1ff57d1..75f06c1 100644
+--- a/logging.h
++++ b/logging.h
+@@ -91,5 +91,7 @@ void vsf_log_line(struct vsf_session* p_sess, enum EVSFLogEntryType what,
+ void vsf_log_failed_line(struct vsf_session* p_sess, enum EVSFLogEntryType what,
+ struct mystr* p_str);
+
++void vsf_log_die(const char* p_text);
++
+ #endif /* VSF_LOGGING_H */
+
+diff --git a/main.c b/main.c
+index f039081..1178d44 100644
+--- a/main.c
++++ b/main.c
+@@ -120,6 +120,10 @@ main(int argc, const char* argv[])
+ }
+ vsf_sysutil_free(p_statbuf);
+ }
++ if (tunable_log_die || tunable_syslog_enable || tunable_tcp_wrappers)
++ {
++ vsf_sysutil_openlog(0);
++ }
+ /* Resolve pasv_address if required */
+ if (tunable_pasv_address && tunable_pasv_addr_resolve)
+ {
+diff --git a/parseconf.c b/parseconf.c
+index 47b54f1..aeb401a 100644
+--- a/parseconf.c
++++ b/parseconf.c
+@@ -112,6 +112,7 @@ parseconf_bool_array[] =
+ { "seccomp_sandbox", &tunable_seccomp_sandbox },
+ { "allow_writeable_chroot", &tunable_allow_writeable_chroot },
+ { "better_stou", &tunable_better_stou },
++ { "log_die", &tunable_log_die },
+ { 0, 0 }
+ };
+
+diff --git a/tcpwrap.c b/tcpwrap.c
+index 5bf57d3..132b771 100644
+--- a/tcpwrap.c
++++ b/tcpwrap.c
+@@ -27,15 +27,12 @@ int
+ vsf_tcp_wrapper_ok(int remote_fd)
+ {
+ struct request_info req;
+- vsf_sysutil_openlog(0);
+ request_init(&req, RQ_DAEMON, "vsftpd", RQ_FILE, remote_fd, 0);
+ fromhost(&req);
+ if (!hosts_access(&req))
+ {
+- vsf_sysutil_closelog();
+ return 0;
+ }
+- vsf_sysutil_closelog();
+ return 1;
+ }
+
+diff --git a/tunables.c b/tunables.c
+index 5ec2bdc..63de8e6 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -93,6 +93,7 @@ int tunable_http_enable;
+ int tunable_seccomp_sandbox;
+ int tunable_allow_writeable_chroot;
+ int tunable_better_stou;
++int tunable_log_die;
+
+ unsigned int tunable_accept_timeout;
+ unsigned int tunable_connect_timeout;
+@@ -241,6 +242,7 @@ tunables_load_defaults()
+ tunable_seccomp_sandbox = 0;
+ tunable_allow_writeable_chroot = 0;
+ tunable_better_stou = 0;
++ tunable_log_die = 0;
+
+ tunable_accept_timeout = 60;
+ tunable_connect_timeout = 60;
+diff --git a/tunables.h b/tunables.h
+index 85ea1a8..8a4b8b2 100644
+--- a/tunables.h
++++ b/tunables.h
+@@ -96,6 +96,8 @@ extern int tunable_allow_writeable_chroot; /* Allow misconfiguration */
+ extern int tunable_better_stou; /* Use better file name generation
+ * algorithm for the STOU command
+ */
++extern int tunable_log_die; /* Log calls to die(), die2()
++ * and bug() */
+
+ /* Integer/numeric defines */
+ extern unsigned int tunable_accept_timeout;
+diff --git a/utility.c b/utility.c
+index 5fd714d..75e5bdd 100644
+--- a/utility.c
++++ b/utility.c
+@@ -9,6 +9,8 @@
+ #include "sysutil.h"
+ #include "str.h"
+ #include "defs.h"
++#include "logging.h"
++#include "tunables.h"
+
+ #define DIE_DEBUG
+
+@@ -41,11 +43,20 @@ void
+ bug(const char* p_text)
+ {
+ /* Rats. Try and write the reason to the network for diagnostics */
++ if (tunable_log_die)
++ {
++ vsf_log_die(p_text);
++ }
+ vsf_sysutil_activate_noblock(VSFTP_COMMAND_FD);
+ (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, "500 OOPS: ", 10);
+ (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, p_text,
+ vsf_sysutil_strlen(p_text));
+ (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, "\r\n", 2);
++ if (tunable_log_die)
++ {
++ /* Workaround for https://github.com/systemd/systemd/issues/2913 */
++ vsf_sysutil_sleep(1.0);
++ }
+ vsf_sysutil_exit(2);
+ }
+
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index e9ae474..f246906 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -358,6 +358,16 @@ wanting to e.g. append a file.
+
+ Default: YES
+ .TP
++.B log_die
++Log an error to syslog when some error condition occurs and vsftpd decides
++to quit. Internally, the error messages given to the functions die(), die2()
++and bug() are passed to syslog. Currently this functionality requires waiting
++for a short amount of time (1 second is used) after logging the message and
++before exiting. This is a workaround for the following systemd bug:
++https://github.com/systemd/systemd/issues/2913
++
++Default: NO
++.TP
+ .B log_ftp_protocol
+ When enabled, all FTP requests and responses are logged, providing the option
+ xferlog_std_format is not enabled. Useful for debugging.
+--
+2.14.4
+
diff --git a/0057-Improve-error-message-when-max-number-of-bind-attemp.patch b/0057-Improve-error-message-when-max-number-of-bind-attemp.patch
new file mode 100644
index 0000000..3a0effe
--- /dev/null
+++ b/0057-Improve-error-message-when-max-number-of-bind-attemp.patch
@@ -0,0 +1,27 @@
+From 380e40930661d643c865bace4e1791ca8f9d74cf Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Mon, 18 Jun 2018 14:01:46 +0200
+Subject: [PATCH 57/59] Improve error message when max number of bind attempts
+ is exceeded
+
+Resolves: rhbz#1318198
+---
+ privops.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/privops.c b/privops.c
+index e577a27..010d28d 100644
+--- a/privops.c
++++ b/privops.c
+@@ -183,7 +183,7 @@ vsf_privop_pasv_listen(struct vsf_session* p_sess)
+ }
+ if (!bind_retries)
+ {
+- die("vsf_sysutil_bind");
++ die("vsf_sysutil_bind, maximum number of attempts to find a listening port exceeded");
+ }
+ return the_port;
+ }
+--
+2.14.4
+
diff --git a/0058-Make-the-max-number-of-bind-retries-tunable.patch b/0058-Make-the-max-number-of-bind-retries-tunable.patch
new file mode 100644
index 0000000..1350470
--- /dev/null
+++ b/0058-Make-the-max-number-of-bind-retries-tunable.patch
@@ -0,0 +1,103 @@
+From be7c2d639127dd8af0139caf94f8c29f431d3753 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Mon, 18 Jun 2018 10:13:48 +0200
+Subject: [PATCH 58/59] Make the max number of bind retries tunable
+
+Resolves: rhbz#1318198
+---
+ parseconf.c | 1 +
+ privops.c | 8 ++++++--
+ tunables.c | 2 ++
+ tunables.h | 1 +
+ vsftpd.conf.5 | 5 +++++
+ 5 files changed, 15 insertions(+), 2 deletions(-)
+
+diff --git a/parseconf.c b/parseconf.c
+index aeb401a..3cfe7da 100644
+--- a/parseconf.c
++++ b/parseconf.c
+@@ -143,6 +143,7 @@ parseconf_uint_array[] =
+ { "delay_successful_login", &tunable_delay_successful_login },
+ { "max_login_fails", &tunable_max_login_fails },
+ { "chown_upload_mode", &tunable_chown_upload_mode },
++ { "bind_retries", &tunable_bind_retries },
+ { 0, 0 }
+ };
+
+diff --git a/privops.c b/privops.c
+index 010d28d..83b25c7 100644
+--- a/privops.c
++++ b/privops.c
+@@ -120,8 +120,8 @@ unsigned short
+ vsf_privop_pasv_listen(struct vsf_session* p_sess)
+ {
+ static struct vsf_sysutil_sockaddr* s_p_sockaddr;
+- int bind_retries = 10;
+- unsigned short the_port;
++ int bind_retries = tunable_bind_retries + 1;
++ unsigned short the_port = 0;
+ /* IPPORT_RESERVED */
+ unsigned short min_port = 1024;
+ unsigned short max_port = 65535;
+@@ -131,6 +131,10 @@ vsf_privop_pasv_listen(struct vsf_session* p_sess)
+ die("listed fd already active");
+ }
+
++ if (bind_retries < 2)
++ {
++ bind_retries = 2;
++ }
+ if (tunable_pasv_min_port > min_port && tunable_pasv_min_port <= max_port)
+ {
+ min_port = (unsigned short) tunable_pasv_min_port;
+diff --git a/tunables.c b/tunables.c
+index 63de8e6..a7ce9c8 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -115,6 +115,7 @@ unsigned int tunable_delay_failed_login;
+ unsigned int tunable_delay_successful_login;
+ unsigned int tunable_max_login_fails;
+ unsigned int tunable_chown_upload_mode;
++unsigned int tunable_bind_retries;
+
+ const char* tunable_secure_chroot_dir;
+ const char* tunable_ftp_username;
+@@ -268,6 +269,7 @@ tunables_load_defaults()
+ tunable_max_login_fails = 3;
+ /* -rw------- */
+ tunable_chown_upload_mode = 0600;
++ tunable_bind_retries = 9;
+
+ install_str_setting("/usr/share/empty", &tunable_secure_chroot_dir);
+ install_str_setting("ftp", &tunable_ftp_username);
+diff --git a/tunables.h b/tunables.h
+index 8a4b8b2..029d645 100644
+--- a/tunables.h
++++ b/tunables.h
+@@ -120,6 +120,7 @@ extern unsigned int tunable_delay_failed_login;
+ extern unsigned int tunable_delay_successful_login;
+ extern unsigned int tunable_max_login_fails;
+ extern unsigned int tunable_chown_upload_mode;
++extern unsigned int tunable_bind_retries;
+
+ /* String defines */
+ extern const char* tunable_secure_chroot_dir;
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index f246906..ce3fba3 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -760,6 +760,11 @@ value will be treated as a base 10 integer!
+
+ Default: 077
+ .TP
++.B bind_retries
++Maximum number of attempts to find a free listening port in passive mode.
++
++Default: 9
++.TP
+ .B chown_upload_mode
+ The file mode to force for chown()ed anonymous uploads. (Added in v2.0.6).
+
+--
+2.14.4
+
diff --git a/0059-Fix-SEGFAULT-when-running-in-a-container-as-PID-1.patch b/0059-Fix-SEGFAULT-when-running-in-a-container-as-PID-1.patch
new file mode 100644
index 0000000..3adbd4c
--- /dev/null
+++ b/0059-Fix-SEGFAULT-when-running-in-a-container-as-PID-1.patch
@@ -0,0 +1,58 @@
+From 970711fde95bee3de1e4a5e0b557c3132d0c3e3f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
+Date: Tue, 6 Feb 2018 11:39:01 +0100
+Subject: [PATCH 59/59] Fix SEGFAULT when running in a container as PID 1
+
+When vsftpd is running in a container as PID 1, it is possible
+that it will get SIGCHILD for processes, which were not directly
+created by it, but by some of its children. These processes will
+not be in the s_p_pid_ip_hash hash table, and thus trying to
+delete the entry from the hash table in standalone.c:handle_sigchld()
+will result in segmentation fault.
+
+I can quite easily reproduce it with the upstream vsftpd and default
+configuration, except for isolate=NO and isolate_network=NO being set
+(it seems to me that network namespaces take a long time to create
+and destroy, which hides the race condition), on a quad-core machine.
+When connecting to vsftpd in a loop like this:
+$ while true; do echo -en '' | nc localhost 21; done
+
+vsftpd crashes after a couple of seconds.
+---
+ standalone.c | 18 +++++++++++++-----
+ 1 file changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/standalone.c b/standalone.c
+index 3b65ea2..3f35e9e 100644
+--- a/standalone.c
++++ b/standalone.c
+@@ -270,13 +270,21 @@ handle_sigchld(void* duff)
+ if (reap_one)
+ {
+ struct vsf_sysutil_ipaddr* p_ip;
+- /* Account total number of instances */
+- --s_children;
+- /* Account per-IP limit */
+ p_ip = (struct vsf_sysutil_ipaddr*)
+ hash_lookup_entry(s_p_pid_ip_hash, (void*)&reap_one);
+- drop_ip_count(p_ip);
+- hash_free_entry(s_p_pid_ip_hash, (void*)&reap_one);
++ /* If we are running in a container as PID 1, it is possible
++ * that we will get SIGCHILD for processes, which were not
++ * created directly by our process and which are not in the
++ * s_p_pid_ip_hash hash table.
++ */
++ if (p_ip)
++ {
++ /* Account total number of instances */
++ --s_children;
++ /* Account per-IP limit */
++ drop_ip_count(p_ip);
++ hash_free_entry(s_p_pid_ip_hash, (void*)&reap_one);
++ }
+ }
+ }
+ }
+--
+2.14.4
+
diff --git a/0072-support-clang-build.patch b/0072-support-clang-build.patch
new file mode 100644
index 0000000..701c52f
--- /dev/null
+++ b/0072-support-clang-build.patch
@@ -0,0 +1,23 @@
+From 82e326f7edba4ea35bf4d5488664947e36de5de7 Mon Sep 17 00:00:00 2001
+From: luofeng <luofeng13@huawei.com>
+Date: Mon, 11 Mar 2024 11:12:24 +0800
+Subject: [PATCH] support clang build
+
+---
+ Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Makefile b/Makefile
+index 0f7411c..3f736e2 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,5 +1,5 @@
+ # Makefile for systems with GNU tools
+-CC = gcc
++CC ?= gcc
+ INSTALL = install
+ IFLAGS = -idirafter dummyinc
+ #CFLAGS = -g
+--
+2.19.1
+
diff --git a/bugfix-change-the-default-value-of-tunable_reverse_lookup_e.patch b/bugfix-change-the-default-value-of-tunable_reverse_lookup_e.patch
new file mode 100644
index 0000000..1e59bc6
--- /dev/null
+++ b/bugfix-change-the-default-value-of-tunable_reverse_lookup_e.patch
@@ -0,0 +1,26 @@
+From 7d22eb654825b78b7affe4c7ce95f934e4d63800 Mon Sep 17 00:00:00 2001
+From: xuchunmei <xuchunmei@huawei.com>
+Date: Fri, 1 Feb 2019 03:05:22 -0500
+Subject: [PATCH] change the default value of tunable_reverse_lookup_enable
+
+Signed-off-by: xuchunmei <xuchunmei@huawei.com>
+---
+ tunables.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tunables.c b/tunables.c
+index a7ce9c8..eeec860 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -224,7 +224,7 @@ tunables_load_defaults()
+ tunable_mdtm_write = 1;
+ tunable_lock_upload_files = 1;
+ tunable_pasv_addr_resolve = 0;
+- tunable_reverse_lookup_enable = 1;
++ tunable_reverse_lookup_enable = 0;
+ tunable_userlist_log = 0;
+ tunable_debug_ssl = 0;
+ tunable_require_cert = 0;
+--
+1.8.3.1
+
diff --git a/fix-str_open.patch b/fix-str_open.patch
new file mode 100644
index 0000000..0c17d23
--- /dev/null
+++ b/fix-str_open.patch
@@ -0,0 +1,28 @@
+diff -ruN vsftpd-3.0.3.orig/sysstr.c vsftpd-3.0.3/sysstr.c
+--- vsftpd-3.0.3.orig/sysstr.c 2020-11-17 09:47:03.872923383 +0100
++++ vsftpd-3.0.3/sysstr.c 2020-11-17 09:48:41.219754145 +0100
+@@ -74,19 +74,11 @@
+ int
+ str_open(const struct mystr* p_str, const enum EVSFSysStrOpenMode mode)
+ {
+- enum EVSFSysUtilOpenMode open_mode = kVSFSysUtilOpenUnknown;
+- switch (mode)
+- {
+- case kVSFSysStrOpenReadOnly:
+- open_mode = kVSFSysUtilOpenReadOnly;
+- break;
+- case kVSFSysStrOpenUnknown:
+- /* Fall through */
+- default:
+- bug("unknown mode value in str_open");
+- break;
+- }
+- return vsf_sysutil_open_file(str_getbuf(p_str), open_mode);
++ if (mode == kVSFSysStrOpenReadOnly)
++ return vsf_sysutil_open_file(str_getbuf(p_str), kVSFSysUtilOpenReadOnly);
++
++ bug("unknown mode value in str_open");
++ return -1;
+ }
+
+ int
diff --git a/sources b/sources
new file mode 100644
index 0000000..e89c24c
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+efbf362a65bec771bc15ad311f5a982e vsftpd-3.0.5.tar.gz
diff --git a/vsftpd-3.0.5-enable_wc_logs-replace_unprintable_with_hex.patch b/vsftpd-3.0.5-enable_wc_logs-replace_unprintable_with_hex.patch
new file mode 100644
index 0000000..914aebd
--- /dev/null
+++ b/vsftpd-3.0.5-enable_wc_logs-replace_unprintable_with_hex.patch
@@ -0,0 +1,215 @@
+diff --git a/logging.c b/logging.c
+index 9e86808..613ff4b 100644
+--- a/logging.c
++++ b/logging.c
+@@ -171,7 +171,14 @@ vsf_log_do_log_to_file(int fd, struct mystr* p_str)
+ return;
+ }
+ }
+- str_replace_unprintable(p_str, '?');
++ if (tunable_wc_logs_enable)
++ {
++ str_replace_unprintable_with_hex_wc(p_str);
++ }
++ else
++ {
++ str_replace_unprintable_with_hex(p_str);
++ }
+ str_append_char(p_str, '\n');
+ /* Ignore write failure; maybe the disk filled etc. */
+ (void) str_write_loop(p_str, fd);
+diff --git a/parseconf.c b/parseconf.c
+index 3cfe7da..3729818 100644
+--- a/parseconf.c
++++ b/parseconf.c
+@@ -113,6 +113,7 @@ parseconf_bool_array[] =
+ { "allow_writeable_chroot", &tunable_allow_writeable_chroot },
+ { "better_stou", &tunable_better_stou },
+ { "log_die", &tunable_log_die },
++ { "wc_logs_enable", &tunable_wc_logs_enable },
+ { 0, 0 }
+ };
+
+diff --git a/str.c b/str.c
+index 82b8ae4..c03e7d8 100644
+--- a/str.c
++++ b/str.c
+@@ -20,6 +20,11 @@
+ #include "utility.h"
+ #include "sysutil.h"
+
++#include <stdio.h>
++#include <string.h>
++#include <wchar.h>
++#include <wctype.h>
++
+ /* File local functions */
+ static void str_split_text_common(struct mystr* p_src, struct mystr* p_rhs,
+ const char* p_text, int is_reverse);
+@@ -723,6 +728,102 @@ str_replace_unprintable(struct mystr* p_str, char new_char)
+ }
+ }
+
++void
++str_replace_unprintable_with_hex(struct mystr* p_str)
++{
++ unsigned int ups_size = sizeof(unsigned int) * (p_str->len);
++ if (ups_size < p_str->len)
++ {
++ str_replace_unprintable(p_str, '?');
++ str_append_text(p_str, ": BUG: string is too long");
++ bug(p_str->p_buf);
++ }
++ unsigned int* ups = vsf_sysutil_malloc(ups_size);
++ unsigned int up_count = 0;
++ for (unsigned int i=0; i < p_str->len; i++)
++ {
++ if (!vsf_sysutil_isprint(p_str->p_buf[i]))
++ {
++ ups[up_count++] = i;
++ }
++ }
++ str_replace_positions_with_hex(p_str, ups, up_count);
++ vsf_sysutil_free(ups);
++}
++
++void str_replace_unprintable_with_hex_wc(struct mystr* p_str)
++{
++ unsigned int ups_size = sizeof(unsigned int) * (p_str->len);
++ if (ups_size < p_str->len)
++ {
++ str_replace_unprintable(p_str, '?');
++ str_append_text(p_str, ": BUG: string is too long");
++ bug(p_str->p_buf);
++ }
++ unsigned int* ups = vsf_sysutil_malloc(ups_size);
++ unsigned int up_count = 0;
++
++ size_t current = 0;
++ wchar_t pwc;
++ mbstate_t ps;
++ memset(&ps, 0, sizeof(ps));
++ ssize_t len = 0;
++ while ((len = mbrtowc(&pwc, p_str->p_buf, p_str->len - current, &ps)) > 0)
++ {
++ if (!iswprint(pwc))
++ {
++ for (int i = 0; i < len; i++)
++ {
++ ups[up_count++] = current++;
++ }
++ }
++ else
++ {
++ current += len;
++ }
++ }
++ if (len < 0)
++ {
++ while (current < p_str->len)
++ {
++ ups[up_count++] = current++;
++ }
++ }
++ str_replace_positions_with_hex(p_str, ups, up_count);
++ vsf_sysutil_free(ups);
++}
++
++void
++str_replace_positions_with_hex(struct mystr* p_str, const unsigned int* poss, const unsigned int pos_count)
++{
++ if (pos_count == 0)
++ return;
++
++ struct mystr tmp_str = INIT_MYSTR;
++ str_reserve(&tmp_str, p_str->len + 3 * pos_count);
++ unsigned int current = 0;
++
++ for (unsigned int i=0; i < pos_count; i++)
++ {
++ unsigned int pos = poss[i];
++
++ if (current < pos)
++ private_str_append_memchunk(&tmp_str, p_str->p_buf + current, pos - current);
++
++ char hex_buf[5];
++ memset(hex_buf, 0, sizeof(hex_buf));
++ sprintf(hex_buf, "\\x%02X", (unsigned char) p_str->p_buf[pos]);
++ str_append_text(&tmp_str, hex_buf);
++ current = pos + 1;
++ }
++
++ if (current < p_str->len)
++ private_str_append_memchunk(&tmp_str, p_str->p_buf + current, p_str->len - current);
++
++ str_copy(p_str, &tmp_str);
++ str_free(&tmp_str);
++}
++
+ void
+ str_basename (struct mystr* d_str, const struct mystr* path)
+ {
+diff --git a/str.h b/str.h
+index 44270da..95a83b5 100644
+--- a/str.h
++++ b/str.h
+@@ -98,6 +98,10 @@ int str_contains_space(const struct mystr* p_str);
+ int str_all_space(const struct mystr* p_str);
+ int str_contains_unprintable(const struct mystr* p_str);
+ void str_replace_unprintable(struct mystr* p_str, char new_char);
++void str_replace_unprintable_with_hex(struct mystr* p_str);
++void str_replace_unprintable_with_hex_wc(struct mystr* p_str);
++void str_replace_positions_with_hex(struct mystr* p_str, const unsigned int* poss,
++ const unsigned int pos_count);
+ 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);
+diff --git a/tunables.c b/tunables.c
+index a7ce9c8..c96c1ac 100644
+--- a/tunables.c
++++ b/tunables.c
+@@ -94,6 +94,7 @@ int tunable_seccomp_sandbox;
+ int tunable_allow_writeable_chroot;
+ int tunable_better_stou;
+ int tunable_log_die;
++int tunable_wc_logs_enable;
+
+ unsigned int tunable_accept_timeout;
+ unsigned int tunable_connect_timeout;
+@@ -244,6 +245,7 @@ tunables_load_defaults()
+ tunable_allow_writeable_chroot = 0;
+ tunable_better_stou = 0;
+ tunable_log_die = 0;
++ tunable_wc_logs_enable = 0;
+
+ tunable_accept_timeout = 60;
+ tunable_connect_timeout = 60;
+diff --git a/tunables.h b/tunables.h
+index 029d645..8d50150 100644
+--- a/tunables.h
++++ b/tunables.h
+@@ -98,6 +98,7 @@ extern int tunable_better_stou; /* Use better file name generation
+ */
+ extern int tunable_log_die; /* Log calls to die(), die2()
+ * and bug() */
++extern int tunable_wc_logs_enable; /* Allow non ASCII characters in logs */
+
+ /* Integer/numeric defines */
+ extern unsigned int tunable_accept_timeout;
+diff --git a/vsftpd.conf.5 b/vsftpd.conf.5
+index ce3fba3..815773f 100644
+--- a/vsftpd.conf.5
++++ b/vsftpd.conf.5
+@@ -735,6 +735,12 @@ If enabled, use CLONE_NEWPID and CLONE_NEWIPC to isolate processes to their
+ ipc and pid namespaces. So separated processes can not interact with each other.
+
+ Default: YES
++.TP
++.B wc_logs_enable
++If enabled, logs will be treated as wide-character strings and not just
++ASCII strings when filtering out non-printable characters.
++
++Default: NO
+
+ .SH NUMERIC OPTIONS
+ Below is a list of numeric options. A numeric option must be set to a non
diff --git a/vsftpd-generator b/vsftpd-generator
new file mode 100644
index 0000000..f1c4cdc
--- /dev/null
+++ b/vsftpd-generator
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+confdir=/etc/vsftpd
+unitdir=/usr/lib/systemd/system
+targetdir=$1/vsftpd.target.wants
+
+mkdir -p ${targetdir}
+
+for f in $(ls -1 ${confdir}/*.conf | awk -F "." '{print $1}' | awk -F "/" '{print $4}')
+do
+ echo "Generating systemd units for $f"
+ ln -s ${unitdir}/vsftpd\@.service ${targetdir}/vsftpd\@$f.service > /dev/null 2>&1
+done
+
+exit 0
diff --git a/vsftpd.default.log b/vsftpd.default.log
new file mode 100644
index 0000000..d338de8
--- /dev/null
+++ b/vsftpd.default.log
@@ -0,0 +1,5 @@
+/var/log/vsftpd.log {
+ # ftpd doesn't handle SIGHUP properly
+ nocompress
+ missingok
+}
diff --git a/vsftpd.ftpusers b/vsftpd.ftpusers
new file mode 100644
index 0000000..096142f
--- /dev/null
+++ b/vsftpd.ftpusers
@@ -0,0 +1,15 @@
+# Users that are not allowed to login via ftp
+root
+bin
+daemon
+adm
+lp
+sync
+shutdown
+halt
+mail
+news
+uucp
+operator
+games
+nobody
diff --git a/vsftpd.pam b/vsftpd.pam
new file mode 100644
index 0000000..080abc3
--- /dev/null
+++ b/vsftpd.pam
@@ -0,0 +1,8 @@
+#%PAM-1.0
+session optional pam_keyinit.so force revoke
+auth required pam_listfile.so item=user sense=deny file=/etc/vsftpd/ftpusers onerr=succeed
+auth required pam_shells.so
+auth include password-auth
+account include password-auth
+session required pam_loginuid.so
+session include password-auth
diff --git a/vsftpd.service b/vsftpd.service
new file mode 100644
index 0000000..4a41b72
--- /dev/null
+++ b/vsftpd.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Vsftpd ftp daemon
+After=network-online.target
+
+[Service]
+Type=forking
+ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
+
+[Install]
+WantedBy=multi-user.target
diff --git a/vsftpd.spec b/vsftpd.spec
new file mode 100644
index 0000000..28877f6
--- /dev/null
+++ b/vsftpd.spec
@@ -0,0 +1,188 @@
+%define generator_dir %{_prefix}/lib/systemd/system-generators
+
+Name: vsftpd
+Version: 3.0.5
+Release: 2
+Summary: It is a secure FTP server for Unix-like systems
+# OpenSSL link exception
+License: GPLv2 with exceptions
+URL: https://security.appspot.com/vsftpd.html
+Source0: https://security.appspot.com/downloads/%{name}-%{version}.tar.gz
+Source1: vsftpd.xinetd
+Source2: vsftpd.pam
+Source3: vsftpd.ftpusers
+Source4: vsftpd.user_list
+Source5: vsftpd_conf_migrate.sh
+Source6: vsftpd.service
+Source7: vsftpd@.service
+Source8: vsftpd.target
+Source9: vsftpd-generator
+Source10: vsftpd.default.log
+BuildRequires: pam-devel libcap-devel openssl-devel systemd vim make gcc
+Requires: logrotate
+
+Patch1: 0001-Don-t-use-the-provided-script-to-locate-libraries.patch
+Patch2: 0002-Enable-build-with-SSL.patch
+Patch3: 0003-Enable-build-with-TCP-Wrapper.patch
+Patch4: 0004-Use-etc-vsftpd-dir-for-config-files-instead-of-etc.patch
+Patch5: 0005-Use-hostname-when-calling-PAM-authentication-module.patch
+Patch6: 0006-Close-stdin-out-err-before-listening-for-incoming-co.patch
+Patch7: 0007-Make-filename-filters-smarter.patch
+Patch8: 0008-Write-denied-logins-into-the-log.patch
+Patch9: 0009-Trim-whitespaces-when-reading-configuration.patch
+Patch10: 0010-Improve-daemonizing.patch
+Patch11: 0011-Fix-listing-with-more-than-one-star.patch
+Patch12: 0012-Replace-syscall-__NR_clone-.-with-clone.patch
+Patch13: 0013-Extend-man-pages-with-systemd-info.patch
+Patch14: 0014-Add-support-for-square-brackets-in-ls.patch
+Patch15: 0015-Listen-on-IPv6-by-default.patch
+Patch16: 0016-Increase-VSFTP_AS_LIMIT-from-200UL-to-400UL.patch
+Patch17: 0017-Fix-an-issue-with-timestamps-during-DST.patch
+Patch18: 0018-Change-the-default-log-file-in-configuration.patch
+Patch19: 0019-Introduce-reverse_lookup_enable-option.patch
+Patch20: 0020-Use-unsigned-int-for-uid-and-gid-representation.patch
+Patch21: 0021-Introduce-support-for-DHE-based-cipher-suites.patch
+Patch22: 0022-Introduce-support-for-EDDHE-based-cipher-suites.patch
+Patch23: 0023-Add-documentation-for-isolate_-options.-Correct-defa.patch
+Patch24: 0024-Introduce-new-return-value-450.patch
+Patch25: 0025-Improve-local_max_rate-option.patch
+Patch26: 0026-Prevent-hanging-in-SIGCHLD-handler.patch
+Patch27: 0027-Delete-files-when-upload-fails.patch
+Patch28: 0028-Fix-man-page-rendering.patch
+Patch29: 0029-Fix-segfault-in-config-file-parser.patch
+Patch30: 0030-Fix-logging-into-syslog-when-enabled-in-config.patch
+Patch31: 0031-Fix-question-mark-wildcard-withing-a-file-name.patch
+Patch32: 0032-Propagate-errors-from-nfs-with-quota-to-client.patch
+Patch34: 0034-Turn-off-seccomp-sandbox-because-it-is-too-strict.patch
+Patch35: 0035-Modify-DH-enablement-patch-to-build-with-OpenSSL-1.1.patch
+Patch36: 0036-Redefine-VSFTP_COMMAND_FD-to-1.patch
+Patch37: 0037-Document-the-relationship-of-text_userdb_names-and-c.patch
+Patch38: 0038-Document-allow_writeable_chroot-in-the-man-page.patch
+Patch39: 0039-Improve-documentation-of-ASCII-mode-in-the-man-page.patch
+Patch40: 0040-Use-system-wide-crypto-policy.patch
+Patch41: 0041-Document-the-new-default-for-ssl_ciphers-in-the-man-.patch
+Patch44: 0044-Disable-anonymous_enable-in-default-config-file.patch
+Patch45: 0045-Expand-explanation-of-ascii_-options-behaviour-in-ma.patch
+Patch46: 0046-vsftpd.conf-Refer-to-the-man-page-regarding-the-asci.patch
+Patch47: 0047-Disable-tcp_wrappers-support.patch
+Patch48: 0048-Fix-default-value-of-strict_ssl_read_eof-in-man-page.patch
+Patch49: 0049-Add-new-filename-generation-algorithm-for-STOU-comma.patch
+Patch50: 0050-Don-t-link-with-libnsl.patch
+Patch51: 0051-Improve-documentation-of-better_stou-in-the-man-page.patch
+Patch52: 0052-Fix-rDNS-with-IPv6.patch
+Patch53: 0053-Always-do-chdir-after-chroot.patch
+Patch54: 0054-vsf_sysutil_rcvtimeo-Check-return-value-of-setsockop.patch
+Patch55: 0055-vsf_sysutil_get_tz-Check-the-return-value-of-syscall.patch
+Patch56: 0056-Log-die-calls-to-syslog.patch
+Patch57: 0057-Improve-error-message-when-max-number-of-bind-attemp.patch
+Patch58: 0058-Make-the-max-number-of-bind-retries-tunable.patch
+Patch59: 0059-Fix-SEGFAULT-when-running-in-a-container-as-PID-1.patch
+Patch61: 0001-Move-closing-standard-FDs-after-listen.patch
+Patch62: 0002-Prevent-recursion-in-bug.patch
+Patch63: 0001-Set-s_uwtmp_inserted-only-after-record-insertion-rem.patch
+Patch64: 0002-Repeat-pututxline-if-it-fails-with-EINTR.patch
+Patch65: 0001-Repeat-pututxline-until-it-succeeds-if-it-fails-with.patch
+Patch67: 0001-Fix-timestamp-handling-in-MDTM.patch
+Patch68: 0002-Drop-an-unused-global-variable.patch
+Patch69: 0001-Remove-a-hint-about-the-ftp_home_dir-SELinux-boolean.patch
+Patch70: fix-str_open.patch
+Patch71: vsftpd-3.0.5-enable_wc_logs-replace_unprintable_with_hex.patch
+Patch72: 0072-support-clang-build.patch
+
+Patch9000: bugfix-change-the-default-value-of-tunable_reverse_lookup_e.patch
+
+%description
+Vsftpd, (or very secure FTP daemon), is an FTP server for Unix-like systems, including Linux.
+It is licensed under the GNU General Public License. It supports IPv6 and SSL.
+Vsftpd supports explicit (since 2.0.0) and implicit (since 2.1.0) FTPS.
+
+%package help
+Summary: Help package for package %{name}
+
+%description help
+This package contains man directory manuals.
+
+%prep
+%autosetup -p1
+
+%build
+make CFLAGS="$RPM_OPT_FLAGS -fpie -pipe -Wextra" LINK="-pie -lssl $RPM_LD_FLAGS" %{?_smp_mflags}
+
+%install
+install -d %{buildroot}{%{_unitdir},%{generator_dir},%{_var}/ftp/pub}
+install -Dm755 vsftpd %{buildroot}%{_sbindir}/vsftpd
+install -Dm600 vsftpd.conf %{buildroot}%{_sysconfdir}/vsftpd/vsftpd.conf
+install -Dm644 vsftpd.conf.5 %{buildroot}/%{_mandir}/man5/vsftpd.conf.5
+install -Dm644 vsftpd.8 %{buildroot}/%{_mandir}/man8/vsftpd.8
+install -Dm644 %{SOURCE10} %{buildroot}%{_sysconfdir}/logrotate.d/vsftpd
+install -Dm644 %{SOURCE2} %{buildroot}%{_sysconfdir}/pam.d/vsftpd
+install -m600 %{SOURCE3} %{buildroot}%{_sysconfdir}/vsftpd/ftpusers
+install -m600 %{SOURCE4} %{buildroot}%{_sysconfdir}/vsftpd/user_list
+install -m744 %{SOURCE5} %{buildroot}%{_sysconfdir}/vsftpd/vsftpd_conf_migrate.sh
+install -m644 {%{SOURCE6},%{SOURCE7},%{SOURCE8}} %{buildroot}%{_unitdir}
+install -m755 %{SOURCE9} %{buildroot}%{generator_dir}
+cp -f %{SOURCE1} ./
+
+%post
+%systemd_post vsftpd.service
+
+%preun
+%systemd_preun vsftpd.service
+%systemd_preun vsftpd.target
+
+%postun
+%systemd_postun_with_restart vsftpd.service
+
+%files
+%doc LICENSE README.security COPYING SECURITY/
+%{_sysconfdir}/vsftpd/vsftpd_conf_migrate.sh
+%config(noreplace) %{_sysconfdir}/vsftpd/ftpusers
+%config(noreplace) %{_sysconfdir}/vsftpd/user_list
+%config(noreplace) %{_sysconfdir}/vsftpd/vsftpd.conf
+%config(noreplace) %{_sysconfdir}/pam.d/vsftpd
+%config(noreplace) %{_sysconfdir}/logrotate.d/vsftpd
+%{_unitdir}/*
+%{generator_dir}/*
+%{_sbindir}/vsftpd
+%{_sysconfdir}/vsftpd/*
+%{_var}/ftp
+
+%files help
+%doc FAQ INSTALL BUGS AUDIT Changelog README REWARD
+%doc SPEED TODO BENCHMARKS EXAMPLE/ TUNING SIZE vsftpd.xinetd
+%{_mandir}/man5/vsftpd.conf.*
+%{_mandir}/man8/vsftpd.*
+
+%changelog
+* Fri Mar 1 2024 luofeng <luofeng13@huawei.com> - 3.0.5-2
+- support clang build
+
+* Thu Nov 17 2022 zhouyihang <zhouyihang3@h-partners.com> - 3.0.5-1
+- Type:requirement
+- ID:NA
+- SUG:NA
+- DESC:update vsftpd to 3.0.5
+
+* Tue Jan 26 2021 orange-snn <songnannan2@huawei.com> - 3.0.3-33
+- remove Werror in build flags to fix building error.
+
+* Tue Dec 15 2020 xihaochen <xihaochen@huawei.com> - 3.0.3-32
+- Type:requirement
+- ID:NA
+- SUG:NA
+- DESC:remove redhat keyword
+
+* Sat Sep 05 2020 zengwefeng<zwfeng@huawei.com> - 3.0.3-31
+- Type:NA
+- Id:NA
+- SUG:NA
+- DESC: add yaml file
+
+* Fri Dec 20 2019 openEuler Buildteam <buildteam@openeuler.org> - 3.0.3-30
+- Type:bugfix
+- Id:NA
+- SUG:NA
+- DESC: add vsftpd.default.log
+
+* Tue Sep 10 2019 huzhiyu<huzhiyu1@huawei.com> - 3.0.3-29
+- Package init
diff --git a/vsftpd.target b/vsftpd.target
new file mode 100644
index 0000000..3828bf8
--- /dev/null
+++ b/vsftpd.target
@@ -0,0 +1,6 @@
+[Unit]
+Description=FTP daemon
+After=network-online.target
+
+[Install]
+WantedBy=multi-user.target
diff --git a/vsftpd.user_list b/vsftpd.user_list
new file mode 100644
index 0000000..3e2760f
--- /dev/null
+++ b/vsftpd.user_list
@@ -0,0 +1,20 @@
+# vsftpd userlist
+# If userlist_deny=NO, only allow users in this file
+# If userlist_deny=YES (default), never allow users in this file, and
+# do not even prompt for a password.
+# Note that the default vsftpd pam config also checks /etc/vsftpd/ftpusers
+# for users that are denied.
+root
+bin
+daemon
+adm
+lp
+sync
+shutdown
+halt
+mail
+news
+uucp
+operator
+games
+nobody
diff --git a/vsftpd.xinetd b/vsftpd.xinetd
new file mode 100644
index 0000000..9b22b5b
--- /dev/null
+++ b/vsftpd.xinetd
@@ -0,0 +1,14 @@
+# default: off
+# description: The vsftpd FTP server serves FTP connections. It uses \
+# normal, unencrypted usernames and passwords for authentication.
+service ftp
+{
+ socket_type = stream
+ wait = no
+ user = root
+ server = /usr/sbin/vsftpd
+ server_args = /etc/vsftpd/vsftpd.conf
+ nice = 10
+ disable = yes
+ flags = IPv4
+}
diff --git a/vsftpd@.service b/vsftpd@.service
new file mode 100644
index 0000000..b063f8f
--- /dev/null
+++ b/vsftpd@.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Vsftpd ftp daemon
+After=network-online.target
+PartOf=vsftpd.target
+
+[Service]
+Type=forking
+ExecStart=/usr/sbin/vsftpd /etc/vsftpd/%i.conf
+
+[Install]
+WantedBy=vsftpd.target
diff --git a/vsftpd_conf_migrate.sh b/vsftpd_conf_migrate.sh
new file mode 100644
index 0000000..582c20d
--- /dev/null
+++ b/vsftpd_conf_migrate.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+#move old config files and symlink them
+#shipped with vsftpd-2.0.1-6
+shopt -s nullglob
+PREFIX="vsftpd"
+for file in /etc/${PREFIX}.*; do
+ if [ ! -L $file ]; then
+ new=`echo $file | sed s/${PREFIX}\./${PREFIX}\\\\//g | sed s/\.rpmsave//g`
+ mv -f ${file} ${new}
+ ln -s ${new} ${file}
+ echo $file moved to $new
+ fi
+done