[proftpd] Cumulative bug fix update
Paul Howarth
pghmcfc at fedoraproject.org
Tue Feb 28 21:15:50 UTC 2012
commit 8abab907d538e0bf386195d67c2ca7a83467bf2b
Author: Paul Howarth <paul at city-fan.org>
Date: Tue Feb 28 21:06:47 2012 +0000
Cumulative bug fix update
- Document SELinux configuration for ProFTPD in proftpd.conf (#785443)
- Add support for basic and administrative controls actions using ftpdctl by
default (#786623)
- Add trace logging directives in proftpd.conf but disable them by default as
they impair performance
- Fix ftpwho/ftptop not showing command arguments (bug 3714)
- Fix MLSD/MLST fail with "DirFakeUser off" or "DirFakeGroup off" (bug 3715)
- Fix proftpd fails to run with "Abort trap" error message (bug 3717)
- Fix LIST -R can loop endlessly if bad directory symlink exists (bug 3719)
- Fix overly restrictive module logfile permissions (bug 3720)
- Fix mod_memcache segfault on server restart (bug 3723)
- Fix unloading mod_quotatab causes segfault (#757311, bug 3724)
- Fix mod_exec does not always capture stdout/stderr output from executed
command (bug 3726)
- Fix mod_wrap2 causes unexpected LogFormat %u expansion for SFTP connections
(bug 3727)
- Fix mod_ldap segfault when LDAPUsers is used with no optional filters
(bug 3729)
- Fix DirFakeUser/DirFakeGroup off with name causes SIGSEGV for MLSD/MLST
commands (bug 3734)
- Fix improper handling of self-signed certificate in client-sent cert list
when "TLSVerifyClient on" is used (bug 3742)
- Fix random stalls/segfaults seen when transferring large files via SFTP
(bug 3743)
- Support ls(1) -1 option for LIST command (bug 3744)
- Reject PASV command if no IPv4 address available (bug 3745)
- Support applying ListOptions only to NLST or to LIST commands (bug 3746)
- Support option for displaying symlinks via MLSD using syntax preferred by
FileZilla (bug 3747)
- Fix mod_ban not closing and reopening the BanLog/BanTable file descriptors
on restart, causing a file descriptor leak (bug 3751)
- Fix mod_ctrls no longer listening on ControlsSocket after restart (bug 3756)
proftpd-1.3.4a-bug3714.patch | 49 ++++++
proftpd-1.3.4a-bug3715.patch | 55 ++++++
proftpd-1.3.4a-bug3717.patch | 147 ++++++++++++++++
proftpd-1.3.4a-bug3719.patch | 31 ++++
proftpd-1.3.4a-bug3720.patch | 160 ++++++++++++++++++
proftpd-1.3.4a-bug3723.patch | 86 ++++++++++
proftpd-1.3.4a-bug3724.patch | 20 +++
proftpd-1.3.4a-bug3726.patch | 36 ++++
proftpd-1.3.4a-bug3727.patch | 133 +++++++++++++++
proftpd-1.3.4a-bug3729.patch | 27 +++
proftpd-1.3.4a-bug3734.patch | 90 ++++++++++
proftpd-1.3.4a-bug3742.patch | 33 ++++
proftpd-1.3.4a-bug3743.patch | 48 ++++++
proftpd-1.3.4a-bug3744.patch | 380 ++++++++++++++++++++++++++++++++++++++++++
proftpd-1.3.4a-bug3745.patch | 35 ++++
proftpd-1.3.4a-bug3746.patch | 157 +++++++++++++++++
proftpd-1.3.4a-bug3747.patch | 193 +++++++++++++++++++++
proftpd-1.3.4a-bug3751.patch | 93 ++++++++++
proftpd-1.3.4a-bug3756.patch | 185 ++++++++++++++++++++
proftpd.conf | 91 ++++++++++-
proftpd.spec | 131 ++++++++++++++-
21 files changed, 2178 insertions(+), 2 deletions(-)
---
diff --git a/proftpd-1.3.4a-bug3714.patch b/proftpd-1.3.4a-bug3714.patch
new file mode 100644
index 0000000..cebc7b2
--- /dev/null
+++ b/proftpd-1.3.4a-bug3714.patch
@@ -0,0 +1,49 @@
+Index: src/cmd.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/src/cmd.c,v
+retrieving revision 1.8
+diff -u -r1.8 cmd.c
+--- src/cmd.c 23 May 2011 21:22:24 -0000 1.8
++++ src/cmd.c 16 Nov 2011 19:57:43 -0000
+@@ -245,8 +245,13 @@
+ }
+
+ res = pr_table_get(cmd->notes, "displayable-str", NULL);
+- if (res)
++ if (res) {
++ if (str_len != NULL) {
++ *str_len = strlen(res);
++ }
++
+ return res;
++ }
+
+ argc = cmd->argc;
+ argv = cmd->argv;
+Index: src/main.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/src/main.c,v
+retrieving revision 1.437
+diff -u -r1.437 main.c
+--- src/main.c 9 Nov 2011 17:32:35 -0000 1.437
++++ src/main.c 16 Nov 2011 19:57:43 -0000
+@@ -318,7 +318,18 @@
+
+ /* The client has successfully authenticated... */
+ if (session.user) {
+- char *args = memchr(cmdargstr, ' ', cmdargstrlen);
++ char *args = NULL;
++
++ /* Be defensive, and check whether cmdargstrlen has a value.
++ * If it's zero, assume we need to use strchr(3), rather than
++ * memchr(2); see Bug#3714.
++ */
++ if (cmdargstrlen > 0) {
++ args = memchr(cmdargstr, ' ', cmdargstrlen);
++
++ } else {
++ args = strchr(cmdargstr, ' ');
++ }
+
+ pr_scoreboard_entry_update(session.pid,
+ PR_SCORE_CMD, "%s", cmd->argv[0], NULL, NULL);
diff --git a/proftpd-1.3.4a-bug3715.patch b/proftpd-1.3.4a-bug3715.patch
new file mode 100644
index 0000000..f01972f
--- /dev/null
+++ b/proftpd-1.3.4a-bug3715.patch
@@ -0,0 +1,55 @@
+Index: modules/mod_facts.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_facts.c,v
+retrieving revision 1.45
+diff -u -r1.45 mod_facts.c
+--- modules/mod_facts.c 23 May 2011 21:11:56 -0000 1.45
++++ modules/mod_facts.c 16 Nov 2011 23:42:05 -0000
+@@ -1034,13 +1034,19 @@
+ c = find_config(get_dir_ctxt(cmd->tmp_pool, (char *) best_path), CONF_PARAM,
+ "DirFakeUser", FALSE);
+ if (c) {
+- const char *fake_user;
++ const char *fake_user = NULL;
+
+- fake_user = c->argv[0];
+- if (strncmp(fake_user, "~", 2) != 0) {
+- fake_uid = pr_auth_name2uid(cmd->tmp_pool, fake_user);
++ if (c->argc > 0) {
++ fake_user = c->argv[0];
++ if (strncmp(fake_user, "~", 2) != 0) {
++ fake_uid = pr_auth_name2uid(cmd->tmp_pool, fake_user);
++
++ } else {
++ fake_uid = session.uid;
++ }
+
+ } else {
++ /* Handle the "DirFakeUser off" case (Bug#3715). */
+ fake_uid = session.uid;
+ }
+ }
+@@ -1048,13 +1054,19 @@
+ c = find_config(get_dir_ctxt(cmd->tmp_pool, (char *) best_path), CONF_PARAM,
+ "DirFakeGroup", FALSE);
+ if (c) {
+- const char *fake_group;
++ const char *fake_group = NULL;
+
+- fake_group = c->argv[0];
+- if (strncmp(fake_group, "~", 2) != 0) {
+- fake_gid = pr_auth_name2gid(cmd->tmp_pool, fake_group);
++ if (c->argc > 0) {
++ fake_group = c->argv[0];
++ if (strncmp(fake_group, "~", 2) != 0) {
++ fake_gid = pr_auth_name2gid(cmd->tmp_pool, fake_group);
++
++ } else {
++ fake_gid = session.gid;
++ }
+
+ } else {
++ /* Handle the "DirFakeGroup off" case (Bug#3715). */
+ fake_gid = session.gid;
+ }
+ }
diff --git a/proftpd-1.3.4a-bug3717.patch b/proftpd-1.3.4a-bug3717.patch
new file mode 100644
index 0000000..589f366
--- /dev/null
+++ b/proftpd-1.3.4a-bug3717.patch
@@ -0,0 +1,147 @@
+Index: contrib/mod_tls.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_tls.c,v
+retrieving revision 1.262
+diff -u -r1.262 mod_tls.c
+--- contrib/mod_tls.c 11 Nov 2011 23:14:13 -0000 1.262
++++ contrib/mod_tls.c 17 Nov 2011 21:26:30 -0000
+@@ -1941,13 +1941,13 @@
+ k = (tls_pkey_t *) data;
+
+ if ((k->flags & TLS_PKEY_USE_RSA) && k->rsa_pkey) {
+- strncpy(buf, k->rsa_pkey, buflen);
++ sstrncpy(buf, k->rsa_pkey, buflen);
+ buf[buflen - 1] = '\0';
+ return strlen(buf);
+ }
+
+ if ((k->flags & TLS_PKEY_USE_DSA) && k->dsa_pkey) {
+- strncpy(buf, k->dsa_pkey, buflen);
++ sstrncpy(buf, k->dsa_pkey, buflen);
+ buf[buflen - 1] = '\0';
+ return strlen(buf);
+ }
+Index: contrib/mod_sftp/keys.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_sftp/keys.c,v
+retrieving revision 1.16
+diff -u -r1.16 keys.c
+--- contrib/mod_sftp/keys.c 23 May 2011 21:03:12 -0000 1.16
++++ contrib/mod_sftp/keys.c 17 Nov 2011 21:26:30 -0000
+@@ -718,7 +718,7 @@
+ k = (struct sftp_pkey *) d;
+
+ if (k->host_pkey) {
+- strncpy(buf, k->host_pkey, buflen);
++ sstrncpy(buf, k->host_pkey, buflen);
+ buf[buflen - 1] = '\0';
+ return strlen(buf);
+ }
+Index: lib/pr-syslog.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/lib/pr-syslog.c,v
+retrieving revision 1.24
+diff -u -r1.24 pr-syslog.c
+--- lib/pr-syslog.c 1 May 2011 04:32:27 -0000 1.24
++++ lib/pr-syslog.c 17 Nov 2011 21:26:30 -0000
+@@ -324,17 +324,17 @@
+ * hold more data than 14 bytes, so...
+ */
+ if (sizeof(syslog_addr.sa_data) >= (strlen(PR_PATH_LOG) + 1)) {
+- strncpy(syslog_addr.sa_data, PR_PATH_LOG, sizeof(syslog_addr.sa_data));
++ sstrncpy(syslog_addr.sa_data, PR_PATH_LOG, sizeof(syslog_addr.sa_data));
+ syslog_addr.sa_data[sizeof(syslog_addr.sa_data)-1] = '\0';
+ addrlen = sizeof(syslog_addr);
+
+ } else {
+- strncpy(syslog_addr.sa_data, PR_PATH_LOG, strlen(PR_PATH_LOG) + 1);
++ sstrncpy(syslog_addr.sa_data, PR_PATH_LOG, strlen(PR_PATH_LOG) + 1);
+ addrlen = sizeof(syslog_addr) +
+ ((strlen(PR_PATH_LOG) + 1) - sizeof(syslog_addr.sa_data));
+ }
+ # else
+- strncpy(syslog_addr.sa_data, PR_PATH_LOG, sizeof(syslog_addr.sa_data));
++ sstrncpy(syslog_addr.sa_data, PR_PATH_LOG, sizeof(syslog_addr.sa_data));
+ syslog_addr.sa_data[sizeof(syslog_addr.sa_data)-1] = '\0';
+ addrlen = sizeof(syslog_addr);
+ # endif /* !Mac OSX */
+Index: lib/pwgrent.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/lib/pwgrent.c,v
+retrieving revision 1.16
+diff -u -r1.16 pwgrent.c
+--- lib/pwgrent.c 23 May 2011 21:08:34 -0000 1.16
++++ lib/pwgrent.c 17 Nov 2011 21:26:30 -0000
+@@ -62,7 +62,7 @@
+ buffer = pwdbuf;
+ pwd = &pwent;
+
+- strncpy(buffer, buf, BUFSIZ-1);
++ sstrncpy(buffer, buf, BUFSIZ-1);
+ buffer[BUFSIZ-1] = '\0';
+
+ for(cp = buffer, i = 0; i < NPWDFIELDS && cp; i++) {
+Index: modules/mod_auth_file.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_auth_file.c,v
+retrieving revision 1.40
+diff -u -r1.40 mod_auth_file.c
+--- modules/mod_auth_file.c 23 May 2011 21:11:56 -0000 1.40
++++ modules/mod_auth_file.c 17 Nov 2011 21:26:30 -0000
+@@ -109,7 +109,7 @@
+ buffer = pwdbuf;
+ pwd = &pwent;
+
+- strncpy(buffer, buf, BUFSIZ-1);
++ sstrncpy(buffer, buf, BUFSIZ-1);
+ buffer[BUFSIZ-1] = '\0';
+
+ for (cp = buffer, i = 0; i < NPWDFIELDS && cp; i++) {
+Index: modules/mod_ctrls.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_ctrls.c,v
+retrieving revision 1.50
+diff -u -r1.50 mod_ctrls.c
+--- modules/mod_ctrls.c 31 Jul 2011 22:07:03 -0000 1.50
++++ modules/mod_ctrls.c 17 Nov 2011 21:26:30 -0000
+@@ -486,7 +486,7 @@
+ memset(&sock, 0, sizeof(sock));
+
+ sock.sun_family = AF_UNIX;
+- strncpy(sock.sun_path, sock_file, strlen(sock_file));
++ sstrncpy(sock.sun_path, sock_file, strlen(sock_file));
+
+ len = sizeof(sock);
+
+Index: src/ctrls.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/src/ctrls.c,v
+retrieving revision 1.30
+diff -u -r1.30 ctrls.c
+--- src/ctrls.c 5 Jun 2011 22:45:14 -0000 1.30
++++ src/ctrls.c 17 Nov 2011 21:26:30 -0000
+@@ -982,7 +982,7 @@
+ memset(&ctrl_sock, 0, sizeof(ctrl_sock));
+
+ ctrl_sock.sun_family = AF_UNIX;
+- strncpy(ctrl_sock.sun_path, socket_file, strlen(socket_file));
++ sstrncpy(ctrl_sock.sun_path, socket_file, strlen(socket_file));
+ len = sizeof(ctrl_sock);
+
+ if (connect(sockfd, (struct sockaddr *) &ctrl_sock, len) < 0) {
+Index: utils/ftptop.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/utils/ftptop.c,v
+retrieving revision 1.42
+diff -u -r1.42 ftptop.c
+--- utils/ftptop.c 23 May 2011 20:46:20 -0000 1.42
++++ utils/ftptop.c 17 Nov 2011 21:26:30 -0000
+@@ -524,7 +524,7 @@
+ exit(1);
+ }
+
+- strncpy(ftp_sessions[ftp_nsessions++], buf, strlen(buf) + 1);
++ util_sstrncpy(ftp_sessions[ftp_nsessions++], buf, strlen(buf) + 1);
+ }
+
+ scoreboard_close();
diff --git a/proftpd-1.3.4a-bug3719.patch b/proftpd-1.3.4a-bug3719.patch
new file mode 100644
index 0000000..d4f363b
--- /dev/null
+++ b/proftpd-1.3.4a-bug3719.patch
@@ -0,0 +1,31 @@
+Index: modules/mod_ls.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_ls.c,v
+retrieving revision 1.190
+diff -u -r1.190 mod_ls.c
+--- modules/mod_ls.c 19 Nov 2011 02:40:12 -0000 1.190
++++ modules/mod_ls.c 21 Nov 2011 21:56:05 -0000
+@@ -460,6 +460,11 @@
+
+ m[len] = '\0';
+
++ /* If the symlink points to either '.' or '..', skip it (Bug#3719). */
++ if (is_dotdir(m)) {
++ return 0;
++ }
++
+ if (!ls_perms_full(p, cmd, m, NULL)) {
+ return 0;
+ }
+@@ -478,6 +483,11 @@
+
+ l[len] = '\0';
+
++ /* If the symlink points to either '.' or '..', skip it (Bug#3719). */
++ if (is_dotdir(l)) {
++ return 0;
++ }
++
+ if (!ls_perms_full(p, cmd, l, &hidden)) {
+ return 0;
+ }
diff --git a/proftpd-1.3.4a-bug3720.patch b/proftpd-1.3.4a-bug3720.patch
new file mode 100644
index 0000000..d6fe638
--- /dev/null
+++ b/proftpd-1.3.4a-bug3720.patch
@@ -0,0 +1,160 @@
+Index: contrib/mod_deflate.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_deflate.c,v
+retrieving revision 1.8
+diff -u -r1.8 mod_deflate.c
+--- contrib/mod_deflate.c 10 Jun 2011 02:57:35 -0000 1.8
++++ contrib/mod_deflate.c 23 Nov 2011 17:58:21 -0000
+@@ -898,7 +898,7 @@
+
+ pr_signals_block();
+ PRIVS_ROOT
+- res = pr_log_openfile(c->argv[0], &deflate_logfd, 0640);
++ res = pr_log_openfile(c->argv[0], &deflate_logfd, PR_LOG_SYSTEM_MODE);
+ PRIVS_RELINQUISH
+ pr_signals_unblock();
+
+Index: contrib/mod_exec.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_exec.c,v
+retrieving revision 1.20
+diff -u -r1.20 mod_exec.c
+--- contrib/mod_exec.c 24 Sep 2011 06:44:36 -0000 1.20
++++ contrib/mod_exec.c 23 Nov 2011 17:58:21 -0000
+@@ -192,7 +192,7 @@
+
+ pr_signals_block();
+ PRIVS_ROOT
+- res = pr_log_openfile(exec_logname, &exec_logfd, 0640);
++ res = pr_log_openfile(exec_logname, &exec_logfd, PR_LOG_SYSTEM_MODE);
+ PRIVS_RELINQUISH
+ pr_signals_unblock();
+
+Index: contrib/mod_quotatab.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_quotatab.c,v
+retrieving revision 1.76
+diff -u -r1.76 mod_quotatab.c
+--- contrib/mod_quotatab.c 26 May 2011 23:14:01 -0000 1.76
++++ contrib/mod_quotatab.c 23 Nov 2011 17:58:21 -0000
+@@ -429,7 +429,7 @@
+
+ pr_signals_block();
+ PRIVS_ROOT
+- res = pr_log_openfile(quota_logname, "a_logfd, 0640);
++ res = pr_log_openfile(quota_logname, "a_logfd, PR_LOG_SYSTEM_MODE);
+ PRIVS_RELINQUISH
+ pr_signals_unblock();
+
+Index: contrib/mod_radius.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_radius.c,v
+retrieving revision 1.66
+diff -u -r1.66 mod_radius.c
+--- contrib/mod_radius.c 16 Aug 2011 16:13:02 -0000 1.66
++++ contrib/mod_radius.c 23 Nov 2011 17:58:21 -0000
+@@ -1825,7 +1825,7 @@
+
+ pr_signals_block();
+ PRIVS_ROOT
+- res = pr_log_openfile(radius_logname, &radius_logfd, 0640);
++ res = pr_log_openfile(radius_logname, &radius_logfd, PR_LOG_SYSTEM_MODE);
+ PRIVS_RELINQUISH
+ pr_signals_unblock();
+
+Index: contrib/mod_sql.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_sql.c,v
+retrieving revision 1.218
+diff -u -r1.218 mod_sql.c
+--- contrib/mod_sql.c 4 Oct 2011 05:27:18 -0000 1.218
++++ contrib/mod_sql.c 23 Nov 2011 17:58:22 -0000
+@@ -5383,7 +5383,7 @@
+
+ pr_signals_block();
+ PRIVS_ROOT
+- res = pr_log_openfile(sql_logfile, &sql_logfd, 0640);
++ res = pr_log_openfile(sql_logfile, &sql_logfd, PR_LOG_SYSTEM_MODE);
+ PRIVS_RELINQUISH
+ pr_signals_unblock();
+
+Index: contrib/mod_tls.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_tls.c,v
+retrieving revision 1.264
+diff -u -r1.264 mod_tls.c
+--- contrib/mod_tls.c 19 Nov 2011 02:54:13 -0000 1.264
++++ contrib/mod_tls.c 23 Nov 2011 17:58:22 -0000
+@@ -6152,7 +6152,7 @@
+
+ pr_signals_block();
+ PRIVS_ROOT
+- res = pr_log_openfile(tls_logname, &tls_logfd, 0600);
++ res = pr_log_openfile(tls_logname, &tls_logfd, PR_LOG_SYSTEM_MODE);
+ PRIVS_RELINQUISH
+ pr_signals_unblock();
+
+Index: contrib/mod_sftp/mod_sftp.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_sftp/mod_sftp.c,v
+retrieving revision 1.61
+diff -u -r1.61 mod_sftp.c
+--- contrib/mod_sftp/mod_sftp.c 12 Oct 2011 17:15:56 -0000 1.61
++++ contrib/mod_sftp/mod_sftp.c 23 Nov 2011 17:58:22 -0000
+@@ -1675,7 +1675,7 @@
+
+ pr_signals_block();
+ PRIVS_ROOT
+- res = pr_log_openfile(sftp_logname, &sftp_logfd, 0600);
++ res = pr_log_openfile(sftp_logname, &sftp_logfd, PR_LOG_SYSTEM_MODE);
+ PRIVS_RELINQUISH
+ pr_signals_unblock();
+
+Index: contrib/mod_wrap2/mod_wrap2.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_wrap2/mod_wrap2.c,v
+retrieving revision 1.39
+diff -u -r1.39 mod_wrap2.c
+--- contrib/mod_wrap2/mod_wrap2.c 6 Nov 2011 21:56:12 -0000 1.39
++++ contrib/mod_wrap2/mod_wrap2.c 23 Nov 2011 17:58:22 -0000
+@@ -150,7 +150,7 @@
+
+ pr_signals_block();
+ PRIVS_ROOT
+- res = pr_log_openfile(wrap2_logname, &wrap2_logfd, 0640);
++ res = pr_log_openfile(wrap2_logname, &wrap2_logfd, PR_LOG_SYSTEM_MODE);
+ PRIVS_RELINQUISH
+ pr_signals_unblock();
+
+Index: modules/mod_ctrls.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_ctrls.c,v
+retrieving revision 1.51
+diff -u -r1.51 mod_ctrls.c
+--- modules/mod_ctrls.c 17 Nov 2011 23:40:28 -0000 1.51
++++ modules/mod_ctrls.c 23 Nov 2011 17:58:22 -0000
+@@ -110,7 +110,7 @@
+ return 0;
+
+ PRIVS_ROOT
+- res = pr_log_openfile(ctrls_logname, &logfd, 0640);
++ res = pr_log_openfile(ctrls_logname, &logfd, PR_LOG_SYSTEM_MODE);
+ PRIVS_RELINQUISH
+
+ if (res == 0) {
+Index: modules/mod_memcache.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_memcache.c,v
+retrieving revision 1.15
+diff -u -r1.15 mod_memcache.c
+--- modules/mod_memcache.c 23 May 2011 21:11:56 -0000 1.15
++++ modules/mod_memcache.c 23 Nov 2011 17:58:22 -0000
+@@ -347,7 +347,7 @@
+
+ pr_signals_block();
+ PRIVS_ROOT
+- res = pr_log_openfile(path, &memcache_logfd, 0600);
++ res = pr_log_openfile(path, &memcache_logfd, PR_LOG_SYSTEM_MODE);
+ PRIVS_RELINQUISH
+ pr_signals_unblock();
+
diff --git a/proftpd-1.3.4a-bug3723.patch b/proftpd-1.3.4a-bug3723.patch
new file mode 100644
index 0000000..30457b1
--- /dev/null
+++ b/proftpd-1.3.4a-bug3723.patch
@@ -0,0 +1,86 @@
+Index: modules/mod_memcache.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_memcache.c,v
+retrieving revision 1.15
+diff -u -r1.15 mod_memcache.c
+--- modules/mod_memcache.c 23 May 2011 21:11:56 -0000 1.15
++++ modules/mod_memcache.c 1 Dec 2011 00:54:11 -0000
+@@ -41,6 +41,8 @@
+ module memcache_module;
+
+ static int memcache_logfd = -1;
++static pool *memcache_pool = NULL;
++static array_header *memcache_server_lists = NULL;
+
+ /* Configuration handlers
+ */
+@@ -174,7 +176,7 @@
+ config_rec *c;
+ char *str = "";
+ int ctxt;
+- memcached_server_st *memcache_servers;
++ memcached_server_st *memcache_servers = NULL;
+
+ if (cmd->argc-1 < 1) {
+ CONF_ERROR(cmd, "wrong number of parameters");
+@@ -204,6 +206,9 @@
+ }
+
+ c->argv[0] = memcache_servers;
++
++ /* Add the libmemcached-allocated pointer to a list, for later freeing. */
++ *((memcached_server_st **) push_array(memcache_server_lists)) = memcache_servers;
+ return PR_HANDLED(cmd);
+ }
+
+@@ -281,19 +286,27 @@
+ }
+
+ static void mcache_restart_ev(const void *event_data, void *user_data) {
+- server_rec *s;
++ register unsigned int i;
++ memcached_server_st **mcache_servers = NULL;
+
+- for (s = (server_rec *) server_list->xas_list; s; s = s->next) {
+- config_rec *c;
++ mcache_servers = memcache_server_lists->elts;
++ for (i = 0; i < memcache_server_lists->nelts; i++) {
++ memcached_server_list_free(mcache_servers[i]);
++ }
+
+- c = find_config(s->conf, CONF_PARAM, "MemcacheServers", FALSE);
+- if (c) {
+- memcached_server_st *memcache_servers;
++ /* Make sure to clear the pointer in the Memcache API as well, to prevent
++ * a dangling pointer situation.
++ */
++ memcache_set_servers(NULL);
+
+- memcache_servers = c->argv[0];
+- memcached_server_list_free(memcache_servers);
+- }
+- }
++ /* Now we can recycle the mod_memcache pool and its associated resources. */
++ destroy_pool(memcache_pool);
++
++ memcache_pool = make_sub_pool(permanent_pool);
++ pr_pool_tag(memcache_pool, MOD_MEMCACHE_VERSION);
++
++ memcache_server_lists = make_array(memcache_pool, 2,
++ sizeof(memcached_server_st **));
+ }
+
+ /* Initialization functions
+@@ -302,6 +315,12 @@
+ static int mcache_init(void) {
+ const char *version;
+
++ memcache_pool = make_sub_pool(permanent_pool);
++ pr_pool_tag(memcache_pool, MOD_MEMCACHE_VERSION);
++
++ memcache_server_lists = make_array(memcache_pool, 2,
++ sizeof(memcached_server_st **));
++
+ memcache_init();
+
+ pr_event_register(&memcache_module, "core.restart", mcache_restart_ev, NULL);
diff --git a/proftpd-1.3.4a-bug3724.patch b/proftpd-1.3.4a-bug3724.patch
new file mode 100644
index 0000000..96c6ced
--- /dev/null
+++ b/proftpd-1.3.4a-bug3724.patch
@@ -0,0 +1,20 @@
+Index: contrib/mod_quotatab.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_quotatab.c,v
+retrieving revision 1.77
+diff -u -r1.77 mod_quotatab.c
+--- contrib/mod_quotatab.c 23 Nov 2011 18:04:37 -0000 1.77
++++ contrib/mod_quotatab.c 5 Dec 2011 19:49:15 -0000
+@@ -3940,7 +3940,11 @@
+ static void quotatab_mod_unload_ev(const void *event_data, void *user_data) {
+ if (strcmp("mod_quotatab.c", (const char *) event_data) == 0) {
+ pr_event_unregister("atab_module, NULL, NULL);
+- pr_regex_free(NULL, quota_exclude_pre);
++
++ if (quota_exclude_pre != NULL) {
++ pr_regexp_free(NULL, quota_exclude_pre);
++ quota_exclude_pre = NULL;
++ }
+
+ if (quotatab_pool) {
+ destroy_pool(quotatab_pool);
diff --git a/proftpd-1.3.4a-bug3726.patch b/proftpd-1.3.4a-bug3726.patch
new file mode 100644
index 0000000..3cc6ed4
--- /dev/null
+++ b/proftpd-1.3.4a-bug3726.patch
@@ -0,0 +1,36 @@
+Index: contrib/mod_exec.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_exec.c,v
+retrieving revision 1.24
+diff -u -r1.24 mod_exec.c
+--- contrib/mod_exec.c 12 Dec 2011 19:22:37 -0000 1.24
++++ contrib/mod_exec.c 13 Dec 2011 21:29:25 -0000
+@@ -626,7 +626,7 @@
+
+ (void) close(exec_stderr_pipe[1]);
+ exec_stderr_pipe[1] = -1;
+-
++
+ if ((exec_opts & EXEC_OPT_LOG_STDOUT) ||
+ (exec_opts & EXEC_OPT_LOG_STDERR) ||
+ (exec_opts & EXEC_OPT_SEND_STDOUT) ||
+@@ -636,7 +636,10 @@
+ struct timeval tv;
+ time_t start_time = time(NULL);
+
+- res = waitpid(pid, &status, WNOHANG);
++ /* We set the result value to zero initially, so that at least one
++ * pass through the stdout/stderr reading code happens.
++ */
++ res = 0;
+ while (res <= 0) {
+ if (res < 0) {
+ if (errno != EINTR) {
+@@ -698,7 +701,6 @@
+ tv.tv_usec = 0L;
+
+ fds = select(maxfd + 1, &readfds, NULL, NULL, &tv);
+-
+ if (fds == -1 &&
+ errno == EINTR) {
+ pr_signals_handle();
diff --git a/proftpd-1.3.4a-bug3727.patch b/proftpd-1.3.4a-bug3727.patch
new file mode 100644
index 0000000..290c2c0
--- /dev/null
+++ b/proftpd-1.3.4a-bug3727.patch
@@ -0,0 +1,133 @@
+Index: contrib/mod_sftp/auth.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_sftp/auth.c,v
+retrieving revision 1.40
+diff -u -r1.40 auth.c
+--- contrib/mod_sftp/auth.c 11 Dec 2011 02:33:14 -0000 1.40
++++ contrib/mod_sftp/auth.c 14 Dec 2011 18:45:53 -0000
+@@ -961,12 +961,12 @@
+ * queried.
+ */
+ if (send_userauth_methods() < 0) {
+- pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
+- pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
+-
+ pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
+ pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);
+
++ pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
++ pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
++
+ return -1;
+ }
+
+@@ -984,12 +984,12 @@
+ pr_trace_msg(trace_channel, 10, "auth method '%s' not enabled", method);
+
+ if (send_userauth_methods() < 0) {
+- pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
+- pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
+-
+ pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
+ pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);
+
++ pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
++ pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
++
+ return -1;
+ }
+
+@@ -1009,12 +1009,12 @@
+ pr_trace_msg(trace_channel, 10, "auth method '%s' not enabled", method);
+
+ if (send_userauth_methods() < 0) {
+- pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
+- pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
+-
+ pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
+ pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);
+
++ pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
++ pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
++
+ return -1;
+ }
+
+@@ -1034,12 +1034,12 @@
+ pr_trace_msg(trace_channel, 10, "auth method '%s' not enabled", method);
+
+ if (send_userauth_methods() < 0) {
+- pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
+- pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
+-
+ pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
+ pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);
+
++ pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
++ pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
++
+ return -1;
+ }
+
+@@ -1059,12 +1059,12 @@
+ pr_trace_msg(trace_channel, 10, "auth method '%s' not enabled", method);
+
+ if (send_userauth_methods() < 0) {
+- pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
+- pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
+-
+ pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
+ pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);
+
++ pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
++ pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
++
+ return -1;
+ }
+
+@@ -1076,12 +1076,12 @@
+ }
+
+ } else {
+- pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
+- pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
+-
+ pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
+ pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);
+
++ pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
++ pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
++
+ (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
+ "unsupported authentication method '%s' requested", method);
+ return -1;
+@@ -1095,6 +1095,9 @@
+ if (res <= 0) {
+ int xerrno = errno;
+
++ pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
++ pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);
++
+ pr_cmd_dispatch_phase(cmd, res == 0 ? POST_CMD : POST_CMD_ERR, 0);
+ pr_cmd_dispatch_phase(cmd, res == 0 ? LOG_CMD : LOG_CMD_ERR, 0);
+
+Index: contrib/mod_wrap2/mod_wrap2.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_wrap2/mod_wrap2.c,v
+retrieving revision 1.40
+diff -u -r1.40 mod_wrap2.c
+--- contrib/mod_wrap2/mod_wrap2.c 23 Nov 2011 18:04:38 -0000 1.40
++++ contrib/mod_wrap2/mod_wrap2.c 14 Dec 2011 18:45:53 -0000
+@@ -1844,6 +1844,12 @@
+ if (!wrap2_engine)
+ return PR_DECLINED(cmd);
+
++ /* Clear the values from the session struct as well, specifically
++ * session.user. Failure to do so caused Bug#3727.
++ */
++ session.user = NULL;
++ session.group = NULL;
++
+ wrap2_ctxt = NULL;
+ wrap2_allow_table = NULL;
+ wrap2_deny_table = NULL;
diff --git a/proftpd-1.3.4a-bug3729.patch b/proftpd-1.3.4a-bug3729.patch
new file mode 100644
index 0000000..b342e10
--- /dev/null
+++ b/proftpd-1.3.4a-bug3729.patch
@@ -0,0 +1,27 @@
+Index: contrib/mod_ldap.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_ldap.c,v
+retrieving revision 1.94
+diff -u -r1.94 mod_ldap.c
+--- contrib/mod_ldap.c 18 Nov 2011 17:34:02 -0000 1.94
++++ contrib/mod_ldap.c 7 Dec 2011 22:38:07 -0000
+@@ -1978,15 +1979,17 @@
+ ldap_do_users = 1;
+ ldap_user_basedn = pstrdup(session.pool, c->argv[0]);
+
+- if (c->argv[1]) {
++ if (c->argc > 1) {
+ ldap_user_name_filter = pstrdup(session.pool, c->argv[1]);
++
+ } else {
+ ldap_user_name_filter = pstrcat(session.pool,
+ "(&(", ldap_attr_uid, "=%v)(objectclass=posixAccount))", NULL);
+ }
+
+- if (c->argv[2]) {
++ if (c->argc > 2) {
+ ldap_user_uid_filter = pstrdup(session.pool, c->argv[2]);
++
+ } else {
+ ldap_user_uid_filter = pstrcat(session.pool,
+ "(&(", ldap_attr_uidnumber, "=%v)(objectclass=posixAccount))", NULL);
diff --git a/proftpd-1.3.4a-bug3734.patch b/proftpd-1.3.4a-bug3734.patch
new file mode 100644
index 0000000..9778030
--- /dev/null
+++ b/proftpd-1.3.4a-bug3734.patch
@@ -0,0 +1,90 @@
+Index: modules/mod_facts.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_facts.c,v
+retrieving revision 1.45
+diff -u -r1.45 mod_facts.c
+--- modules/mod_facts.c 23 May 2011 21:11:56 -0000 1.45
++++ modules/mod_facts.c 17 Jan 2012 00:26:59 -0000
+@@ -1034,11 +1034,12 @@
+ c = find_config(get_dir_ctxt(cmd->tmp_pool, (char *) best_path), CONF_PARAM,
+ "DirFakeUser", FALSE);
+ if (c) {
+- const char *fake_user = NULL;
+-
+ if (c->argc > 0) {
++ const char *fake_user = NULL;
++
+ fake_user = c->argv[0];
+- if (strncmp(fake_user, "~", 2) != 0) {
++ if (fake_user != NULL &&
++ strncmp(fake_user, "~", 2) != 0) {
+ fake_uid = pr_auth_name2uid(cmd->tmp_pool, fake_user);
+
+ } else {
+@@ -1054,11 +1055,12 @@
+ c = find_config(get_dir_ctxt(cmd->tmp_pool, (char *) best_path), CONF_PARAM,
+ "DirFakeGroup", FALSE);
+ if (c) {
+- const char *fake_group = NULL;
+-
+ if (c->argc > 0) {
++ const char *fake_group = NULL;
++
+ fake_group = c->argv[0];
+- if (strncmp(fake_group, "~", 2) != 0) {
++ if (fake_group != NULL &&
++ strncmp(fake_group, "~", 2) != 0) {
+ fake_gid = pr_auth_name2gid(cmd->tmp_pool, fake_group);
+
+ } else {
+@@ -1213,13 +1215,20 @@
+ c = find_config(get_dir_ctxt(cmd->tmp_pool, (char *) decoded_path),
+ CONF_PARAM, "DirFakeUser", FALSE);
+ if (c) {
+- const char *fake_user;
++ if (c->argc > 0) {
++ const char *fake_user;
+
+- fake_user = c->argv[0];
+- if (strncmp(fake_user, "~", 2) != 0) {
+- fake_uid = pr_auth_name2uid(cmd->tmp_pool, fake_user);
++ fake_user = c->argv[0];
++ if (fake_user != NULL &&
++ strncmp(fake_user, "~", 2) != 0) {
++ fake_uid = pr_auth_name2uid(cmd->tmp_pool, fake_user);
++
++ } else {
++ fake_uid = session.uid;
++ }
+
+ } else {
++ /* Handle the "DirFakeUser off" case (Bug#3715). */
+ fake_uid = session.uid;
+ }
+ }
+@@ -1227,13 +1236,20 @@
+ c = find_config(get_dir_ctxt(cmd->tmp_pool, (char *) decoded_path),
+ CONF_PARAM, "DirFakeGroup", FALSE);
+ if (c) {
+- const char *fake_group;
++ if (c->argc > 0) {
++ const char *fake_group;
++
++ fake_group = c->argv[0];
++ if (fake_group != NULL &&
++ strncmp(fake_group, "~", 2) != 0) {
++ fake_gid = pr_auth_name2gid(cmd->tmp_pool, fake_group);
+
+- fake_group = c->argv[0];
+- if (strncmp(fake_group, "~", 2) != 0) {
+- fake_gid = pr_auth_name2gid(cmd->tmp_pool, fake_group);
++ } else {
++ fake_gid = session.gid;
++ }
+
+ } else {
++ /* Handle the "DirFakeGroup off" case (Bug#3715). */
+ fake_gid = session.gid;
+ }
+ }
+
diff --git a/proftpd-1.3.4a-bug3742.patch b/proftpd-1.3.4a-bug3742.patch
new file mode 100644
index 0000000..316e335
--- /dev/null
+++ b/proftpd-1.3.4a-bug3742.patch
@@ -0,0 +1,33 @@
+Index: contrib/mod_tls.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_tls.c,v
+retrieving revision 1.268
+diff -u -r1.268 mod_tls.c
+--- contrib/mod_tls.c 23 Jan 2012 01:53:28 -0000 1.268
++++ contrib/mod_tls.c 10 Feb 2012 02:12:23 -0000
+@@ -4415,6 +4415,7 @@
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_CERT_REVOKED:
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
++ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_APPLICATION_VERIFICATION:
+@@ -4439,17 +4440,6 @@
+ break;
+ }
+
+- case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+- /* XXX this is strange. we get this error for certain clients
+- * (i.e. Jeff Altman's kftp) when all is ok. I think it's because the
+- * client is actually sending the whole CA cert. This must be figured
+- * out, but we let it pass for now. If the CA cert isn't available
+- * locally, we will fail anyway.
+- */
+- tls_log("%s", X509_verify_cert_error_string(ctx->error));
+- ok = 1;
+- break;
+-
+ default:
+ tls_log("error verifying client certificate: [%d] %s",
+ ctx->error, X509_verify_cert_error_string(ctx->error));
diff --git a/proftpd-1.3.4a-bug3743.patch b/proftpd-1.3.4a-bug3743.patch
new file mode 100644
index 0000000..30438d1
--- /dev/null
+++ b/proftpd-1.3.4a-bug3743.patch
@@ -0,0 +1,48 @@
+Index: contrib/mod_sftp/fxp.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_sftp/fxp.c,v
+retrieving revision 1.139
+diff -u -r1.139 fxp.c
+--- contrib/mod_sftp/fxp.c 15 Feb 2012 22:10:56 -0000 1.139
++++ contrib/mod_sftp/fxp.c 15 Feb 2012 22:30:19 -0000
+@@ -2511,7 +2511,18 @@
+ fxp_packet_data_allocsz += sz;
+ }
+
+- memcpy(curr_buf, data, datalen);
++ /* We explicitly want to use memmove(3) here rather than memcpy(3),
++ * since it is possible (and likely) that after reading data out
++ * of this buffer, there will be leftover data which is put back into
++ * the buffer, only at a different offset. This means that the
++ * source and destination pointers CAN overlap; using memcpy(3) would
++ * lead to subtle memory copy issue (e.g. Bug#3743).
++ *
++ * This manifested as hard-to-reproduce SFTP upload/download stalls,
++ * segfaults, etc, due to corrupted memory being read out as
++ * packet lengths and such.
++ */
++ memmove(curr_buf, data, datalen);
+ curr_buflen = datalen;
+
+ return;
+@@ -2556,8 +2567,18 @@
+ }
+ }
+
+- /* Append the SSH2 data to the current unconsumed buffer. */
+- memcpy(curr_buf + curr_buflen, data, datalen);
++ /* We explicitly want to use memmove(3) here rather than memcpy(3),
++ * since it is possible (and likely) that after reading data out
++ * of this buffer, there will be leftover data which is put back into
++ * the buffer, only at a different offset. This means that the
++ * source and destination pointers CAN overlap; using memcpy(3) would
++ * lead to subtle memory copy issue (e.g. Bug#3743).
++ *
++ * This manifested as hard-to-reproduce SFTP upload/download stalls,
++ * segfaults, etc, due to corrupted memory being read out as
++ * packet lengths and such.
++ */
++ memmove(curr_buf + curr_buflen, data, datalen);
+ curr_buflen += datalen;
+ }
+
diff --git a/proftpd-1.3.4a-bug3744.patch b/proftpd-1.3.4a-bug3744.patch
new file mode 100644
index 0000000..dc7ecac
--- /dev/null
+++ b/proftpd-1.3.4a-bug3744.patch
@@ -0,0 +1,380 @@
+Index: modules/mod_ls.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_ls.c,v
+retrieving revision 1.187
+diff -u -r1.187 mod_ls.c
+--- modules/mod_ls.c 5 Nov 2011 23:01:58 -0000 1.187
++++ modules/mod_ls.c 1 Feb 2012 18:57:20 -0000
+@@ -81,6 +81,7 @@
+
+ /* ls options */
+ static int
++ opt_1 = 0,
+ opt_a = 0,
+ opt_A = 0,
+ opt_B = 0,
+@@ -395,7 +396,6 @@
+ p = cmd->tmp_pool;
+
+ if (pr_fsio_lstat(name, &st) == 0) {
+-
+ char *display_name = NULL;
+
+ suffix[0] = suffix[1] = '\0';
+@@ -493,21 +493,24 @@
+ break;
+ }
+
+- if (list_times_gmt)
++ if (list_times_gmt) {
+ t = pr_gmtime(p, (time_t *) &sort_time);
+- else
++
++ } else {
+ t = pr_localtime(p, (time_t *) &sort_time);
++ }
+
+ if (opt_F) {
+- if (S_ISLNK(st.st_mode))
++ if (S_ISLNK(st.st_mode)) {
+ suffix[0] = '@';
+
+- else if (S_ISDIR(st.st_mode)) {
++ } else if (S_ISDIR(st.st_mode)) {
+ suffix[0] = '/';
+ rval = 1;
+
+- } else if (st.st_mode & 0111)
++ } else if (st.st_mode & 0111) {
+ suffix[0] = '*';
++ }
+ }
+
+ if (opt_l) {
+@@ -576,32 +579,38 @@
+ m[2] = (mode & S_IWUSR) ? 'w' : '-';
+ m[1] = (mode & S_IRUSR) ? 'r' : '-';
+
+- if (ls_curtime - sort_time > 180 * 24 * 60 * 60)
++ if (ls_curtime - sort_time > 180 * 24 * 60 * 60) {
+ snprintf(timeline, sizeof(timeline), "%5d", t->tm_year+1900);
+
+- else
++ } else {
+ snprintf(timeline, sizeof(timeline), "%02d:%02d", t->tm_hour,
+ t->tm_min);
++ }
+
+ ls_fmt_filesize(s, sizeof(s), st.st_size);
+
+- if (!opt_n) {
+-
+- /* Format nameline using user/group names. */
+- snprintf(nameline, sizeof(nameline)-1,
+- "%s %3d %-8s %-8s %s %s %2d %s %s", m, (int) st.st_nlink,
+- MAP_UID(st.st_uid), MAP_GID(st.st_gid), s,
+- months[t->tm_mon], t->tm_mday, timeline,
++ if (opt_1) {
++ /* One file per line, with no info other than the file name. Easy. */
++ snprintf(nameline, sizeof(nameline)-1, "%s",
+ pr_fs_encode_path(cmd->tmp_pool, display_name));
+
+ } else {
+-
+- /* Format nameline using user/group IDs. */
+- snprintf(nameline, sizeof(nameline)-1,
+- "%s %3d %-8u %-8u %s %s %2d %s %s", m, (int) st.st_nlink,
+- (unsigned) st.st_uid, (unsigned) st.st_gid, s,
+- months[t->tm_mon], t->tm_mday, timeline,
+- pr_fs_encode_path(cmd->tmp_pool, name));
++ if (!opt_n) {
++ /* Format nameline using user/group names. */
++ snprintf(nameline, sizeof(nameline)-1,
++ "%s %3d %-8s %-8s %s %s %2d %s %s", m, (int) st.st_nlink,
++ MAP_UID(st.st_uid), MAP_GID(st.st_gid), s,
++ months[t->tm_mon], t->tm_mday, timeline,
++ pr_fs_encode_path(cmd->tmp_pool, display_name));
++
++ } else {
++ /* Format nameline using user/group IDs. */
++ snprintf(nameline, sizeof(nameline)-1,
++ "%s %3d %-8u %-8u %s %s %2d %s %s", m, (int) st.st_nlink,
++ (unsigned) st.st_uid, (unsigned) st.st_gid, s,
++ months[t->tm_mon], t->tm_mday, timeline,
++ pr_fs_encode_path(cmd->tmp_pool, name));
++ }
+ }
+
+ nameline[sizeof(nameline)-1] = '\0';
+@@ -611,40 +620,45 @@
+
+ suffix[0] = '\0';
+ if (opt_F && pr_fsio_stat(name, &st) == 0) {
+- if (S_ISLNK(st.st_mode))
++ if (S_ISLNK(st.st_mode)) {
+ suffix[0] = '@';
+
+- else if (S_ISDIR(st.st_mode))
++ } else if (S_ISDIR(st.st_mode)) {
+ suffix[0] = '/';
+
+- else if (st.st_mode & 0111)
++ } else if (st.st_mode & 0111) {
+ suffix[0] = '*';
++ }
+ }
+
+ if (!opt_L && list_show_symlinks) {
+- if (sizeof(nameline) - strlen(nameline) > 4)
++ if (sizeof(nameline) - strlen(nameline) > 4) {
+ snprintf(buf, sizeof(nameline) - strlen(nameline) - 4,
+ " -> %s", l);
+- else
++ } else {
+ pr_log_pri(PR_LOG_NOTICE, "notice: symlink '%s' yields an "
+ "excessive string, ignoring", name);
++ }
+ }
+
+ nameline[sizeof(nameline)-1] = '\0';
+ }
+
+- if (opt_STAT)
++ if (opt_STAT) {
+ pr_response_add(R_211, "%s%s", nameline, suffix);
+- else
++
++ } else {
+ addfile(cmd, nameline, suffix, sort_time, st.st_size);
++ }
+ }
+
+ } else {
+ if (S_ISREG(st.st_mode) ||
+ S_ISDIR(st.st_mode) ||
+- S_ISLNK(st.st_mode))
++ S_ISLNK(st.st_mode)) {
+ addfile(cmd, pr_fs_encode_path(cmd->tmp_pool, name), suffix,
+ sort_time, st.st_size);
++ }
+ }
+ }
+
+@@ -1302,6 +1316,7 @@
+ switch (**opt) {
+ case '1':
+ if (strcmp(session.curr_cmd, C_STAT) != 0) {
++ opt_1 = 1;
+ opt_l = opt_C = 0;
+ }
+ break;
+@@ -1354,6 +1369,7 @@
+ if (strcmp(session.curr_cmd, C_NLST) != 0) {
+ opt_l = 1;
+ opt_C = 0;
++ opt_1 = 0;
+ }
+ break;
+
+@@ -1422,7 +1438,7 @@
+ while ((*opt)++ && isalnum((int) **opt)) {
+ switch (**opt) {
+ case '1':
+- opt_l = opt_C = 0;
++ opt_1 = opt_l = opt_C = 0;
+ break;
+
+ case 'A':
+@@ -1571,8 +1587,8 @@
+ ls_curtime = time(NULL);
+
+ if (clearflags) {
+- opt_A = opt_a = opt_B = opt_C = opt_d = opt_F = opt_h = opt_n = opt_r =
+- opt_R = opt_S = opt_t = opt_STAT = opt_L = 0;
++ opt_1 = opt_A = opt_a = opt_B = opt_C = opt_d = opt_F = opt_h = opt_n =
++ opt_r = opt_R = opt_S = opt_t = opt_STAT = opt_L = 0;
+ }
+
+ if (have_options(cmd, arg)) {
+@@ -1671,8 +1687,10 @@
+
+ /* Open data connection */
+ if (!opt_STAT) {
+- if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0)
++ if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ return -1;
++ }
++
+ session.sf_flags |= SF_ASCII_OVERRIDE;
+ }
+
+@@ -1705,7 +1723,6 @@
+ skiparg = TRUE;
+
+ } else {
+-
+ skiparg = FALSE;
+
+ if (use_globbing &&
+@@ -1945,6 +1962,10 @@
+ return -1;
+ }
+
++ /* XXX Note that "NLST <glob>" was sent, we might be receiving paths
++ * here, not just file names. And that is not what dir_hide_file() is
++ * expecting.
++ */
+ if (dir_hide_file(file))
+ return 1;
+
+@@ -1970,6 +1991,25 @@
+ }
+ #endif /* PR_USE_NLS */
+
++ if (opt_1) {
++ char *ptr;
++
++ /* If the -1 option is configured, we want to make sure that we only
++ * display a file, not a path. And it's possible that we given a path
++ * here.
++ */
++ ptr = strrchr(display_name, '/');
++ if (ptr != NULL) {
++ size_t display_namelen;
++
++ display_namelen = strlen(display_name);
++ if (display_namelen > 1) {
++ /* Make sure that we handle a possible display_name of '/' properly. */
++ display_name = ptr + 1;
++ }
++ }
++ }
++
+ /* Be sure to flush the output */
+ res = sendline(0, "%s\n", pr_fs_encode_path(cmd->tmp_pool, display_name));
+ if (res < 0)
+@@ -2098,8 +2138,16 @@
+ continue;
+
+ if (!curdir) {
+- char *str = pr_fs_encode_path(cmd->tmp_pool,
+- pdircat(cmd->tmp_pool, dir, p, NULL));
++ char *str = NULL;
++
++ if (opt_1) {
++ /* Send just the file name, not the path. */
++ str = pr_fs_encode_path(cmd->tmp_pool, p);
++
++ } else {
++ str = pr_fs_encode_path(cmd->tmp_pool,
++ pdircat(cmd->tmp_pool, dir, p, NULL));
++ }
+
+ if (sendline(0, "%s\n", str) < 0) {
+ count = -1;
+@@ -2204,26 +2252,32 @@
+ fakeuser = get_param_ptr(CURRENT_CONF, "DirFakeUser", FALSE);
+
+ /* Check for a configured "logged in user" DirFakeUser. */
+- if (fakeuser && strcmp(fakeuser, "~") == 0)
++ if (fakeuser != NULL &&
++ strcmp(fakeuser, "~") == 0) {
+ fakeuser = session.user;
++ }
+
+ fakegroup = get_param_ptr(CURRENT_CONF, "DirFakeGroup", FALSE);
+
+ /* Check for a configured "logged in user" DirFakeGroup. */
+- if (fakegroup && strcmp(fakegroup, "~") == 0)
++ if (fakegroup != NULL &&
++ strcmp(fakegroup, "~") == 0) {
+ fakegroup = session.group;
++ }
+
+ fake_mode = get_param_ptr(CURRENT_CONF, "DirFakeMode", FALSE);
+ if (fake_mode) {
+ fakemode = *fake_mode;
+ have_fake_mode = TRUE;
+
+- } else
++ } else {
+ have_fake_mode = FALSE;
++ }
+
+ tmp = get_param_ptr(TOPLEVEL_CONF, "TimesGMT", FALSE);
+- if (tmp != NULL)
++ if (tmp != NULL) {
+ list_times_gmt = *tmp;
++ }
+
+ res = dolist(cmd, pr_fs_decode_path(cmd->tmp_pool, cmd->arg), TRUE);
+
+@@ -2231,8 +2285,9 @@
+ pr_data_abort(0, 0);
+ res = -1;
+
+- } else if (session.sf_flags & SF_XFER)
++ } else if (session.sf_flags & SF_XFER) {
+ ls_done(cmd);
++ }
+
+ opt_l = 0;
+
+@@ -2415,8 +2470,9 @@
+ list_nfiles.logged = list_ndirs.logged = list_ndepth.logged = FALSE;
+
+ tmp = get_param_ptr(TOPLEVEL_CONF, "ShowSymlinks", FALSE);
+- if (tmp != NULL)
++ if (tmp != NULL) {
+ list_show_symlinks = *tmp;
++ }
+
+ target = cmd->argc == 1 ? "." :
+ pr_fs_decode_path(cmd->tmp_pool, cmd->arg);
+@@ -2444,8 +2500,8 @@
+ }
+
+ /* Clear the listing option flags. */
+- opt_A = opt_a = opt_B = opt_C = opt_d = opt_F = opt_n = opt_r = opt_R =
+- opt_S = opt_t = opt_STAT = opt_L = 0;
++ opt_1 = opt_A = opt_a = opt_B = opt_C = opt_d = opt_F = opt_n = opt_r =
++ opt_R = opt_S = opt_t = opt_STAT = opt_L = 0;
+
+ if (have_options(cmd, target)) {
+ if (!list_strict_opts) {
+@@ -2602,8 +2658,10 @@
+
+ } else {
+ if (list_flags & LS_FL_NO_ERROR_IF_ABSENT) {
+- if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0)
++ if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ return PR_ERROR(cmd);
++ }
++
+ session.sf_flags |= SF_ASCII_OVERRIDE;
+ pr_response_add(R_226, _("Transfer complete"));
+ ls_done(cmd);
+@@ -2617,8 +2675,10 @@
+
+ } else {
+ if (list_flags & LS_FL_NO_ERROR_IF_ABSENT) {
+- if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0)
++ if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ return PR_ERROR(cmd);
++ }
++
+ session.sf_flags |= SF_ASCII_OVERRIDE;
+ pr_response_add(R_226, _("Transfer complete"));
+ ls_done(cmd);
+@@ -2631,8 +2691,10 @@
+ }
+ }
+
+- if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0)
++ if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ return PR_ERROR(cmd);
++ }
++
+ session.sf_flags |= SF_ASCII_OVERRIDE;
+
+ /* Iterate through each matching entry */
diff --git a/proftpd-1.3.4a-bug3745.patch b/proftpd-1.3.4a-bug3745.patch
new file mode 100644
index 0000000..18ba9a4
--- /dev/null
+++ b/proftpd-1.3.4a-bug3745.patch
@@ -0,0 +1,35 @@
+Index: modules/mod_core.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_core.c,v
+retrieving revision 1.420
+diff -u -r1.420 mod_core.c
+--- modules/mod_core.c 5 Feb 2012 18:08:56 -0000 1.420
++++ modules/mod_core.c 5 Feb 2012 18:24:16 -0000
+@@ -3587,6 +3587,27 @@
+ }
+
+ if (pr_netaddr_get_family(session.c->local_addr) == pr_netaddr_get_family(session.c->remote_addr)) {
++
++#ifdef PR_USE_IPV6
++ if (pr_netaddr_use_ipv6()) {
++ /* Make sure that the family is NOT IPv6, even though the family of the
++ * local and remote ends match. The PASV command cannot be used for
++ * IPv6 addresses (Bug#3745).
++ */
++ if (pr_netaddr_get_family(session.c->local_addr) == AF_INET6) {
++ int xerrno = EPERM;
++
++ pr_log_debug(DEBUG0,
++ "Unable to handle PASV for IPv6 address '%s', rejecting command",
++ pr_netaddr_get_ipstr(session.c->local_addr));
++ pr_response_add_err(R_501, "%s: %s", cmd->argv[0], strerror(xerrno));
++
++ errno = xerrno;
++ return PR_ERROR(cmd);
++ }
++ }
++#endif /* PR_USE_IPV6 */
++
+ bind_addr = session.c->local_addr;
+
+ } else {
diff --git a/proftpd-1.3.4a-bug3746.patch b/proftpd-1.3.4a-bug3746.patch
new file mode 100644
index 0000000..d023cd7
--- /dev/null
+++ b/proftpd-1.3.4a-bug3746.patch
@@ -0,0 +1,157 @@
+Index: modules/mod_ls.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_ls.c,v
+retrieving revision 1.192
+diff -u -r1.192 mod_ls.c
+--- modules/mod_ls.c 1 Feb 2012 22:03:50 -0000 1.192
++++ modules/mod_ls.c 1 Feb 2012 23:13:14 -0000
+@@ -54,8 +54,10 @@
+ #endif
+ #define LS_SENDLINE_FL_FLUSH 0x0001
+
+-static unsigned long list_flags = 0;
+ #define LS_FL_NO_ERROR_IF_ABSENT 0x0001
++#define LS_FL_LIST_ONLY 0x0002
++#define LS_FL_NLST_ONLY 0x0004
++static unsigned long list_flags = 0;
+
+ static unsigned char list_strict_opts = FALSE;
+ static char *list_options = NULL;
+@@ -2273,15 +2275,28 @@
+ config_rec *c = NULL;
+
+ tmp = get_param_ptr(TOPLEVEL_CONF, "ShowSymlinks", FALSE);
+- if (tmp != NULL)
++ if (tmp != NULL) {
+ list_show_symlinks = *tmp;
++ }
+
+ list_strict_opts = FALSE;
+-
+ list_nfiles.max = list_ndirs.max = list_ndepth.max = 0;
+
+ c = find_config(CURRENT_CONF, CONF_PARAM, "ListOptions", FALSE);
+- if (c != NULL) {
++ while (c != NULL) {
++ pr_signals_handle();
++
++ list_flags = *((unsigned long *) c->argv[5]);
++
++ /* Make sure that this ListOptions can be applied to the LIST command.
++ * If not, keep looking for other applicable ListOptions.
++ */
++ if (list_flags & LS_FL_NLST_ONLY) {
++ pr_log_debug(DEBUG10, "%s: skipping NLSTOnly ListOptions", cmd->argv[0]);
++ c = find_config_next(c, c->next, CONF_PARAM, "ListOptions", FALSE);
++ continue;
++ }
++
+ list_options = c->argv[0];
+ list_strict_opts = *((unsigned char *) c->argv[1]);
+
+@@ -2299,7 +2314,7 @@
+ list_nfiles.max = *((unsigned int *) c->argv[3]);
+ list_ndirs.max = *((unsigned int *) c->argv[4]);
+
+- list_flags = *((unsigned long *) c->argv[5]);
++ break;
+ }
+
+ fakeuser = get_param_ptr(CURRENT_CONF, "DirFakeUser", FALSE);
+@@ -2440,7 +2455,26 @@
+ list_ndepth.max = list_nfiles.max = list_ndirs.max = 0;
+
+ c = find_config(CURRENT_CONF, CONF_PARAM, "ListOptions", FALSE);
+- if (c != NULL) {
++ while (c != NULL) {
++ pr_signals_handle();
++
++ list_flags = *((unsigned long *) c->argv[5]);
++
++ /* Make sure that this ListOptions can be applied to the STAT command.
++ * If not, keep looking for other applicable ListOptions.
++ */
++ if (list_flags & LS_FL_LIST_ONLY) {
++ pr_log_debug(DEBUG10, "%s: skipping LISTOnly ListOptions", cmd->argv[0]);
++ c = find_config_next(c, c->next, CONF_PARAM, "ListOptions", FALSE);
++ continue;
++ }
++
++ if (list_flags & LS_FL_NLST_ONLY) {
++ pr_log_debug(DEBUG10, "%s: skipping NLSTOnly ListOptions", cmd->argv[0]);
++ c = find_config_next(c, c->next, CONF_PARAM, "ListOptions", FALSE);
++ continue;
++ }
++
+ list_options = c->argv[0];
+ list_strict_opts = *((unsigned char *) c->argv[1]);
+
+@@ -2458,7 +2492,7 @@
+ list_nfiles.max = *((unsigned int *) c->argv[3]);
+ list_ndirs.max = *((unsigned int *) c->argv[4]);
+
+- list_flags = *((unsigned long *) c->argv[5]);
++ break;
+ }
+
+ fakeuser = get_param_ptr(CURRENT_CONF, "DirFakeUser", FALSE);
+@@ -2535,7 +2569,20 @@
+ pr_fs_decode_path(cmd->tmp_pool, cmd->arg);
+
+ c = find_config(CURRENT_CONF, CONF_PARAM, "ListOptions", FALSE);
+- if (c != NULL) {
++ while (c != NULL) {
++ pr_signals_handle();
++
++ list_flags = *((unsigned long *) c->argv[5]);
++
++ /* Make sure that this ListOptions can be applied to the NLST command.
++ * If not, keep looking for other applicable ListOptions.
++ */
++ if (list_flags & LS_FL_LIST_ONLY) {
++ pr_log_debug(DEBUG10, "%s: skipping LISTOnly ListOptions", cmd->argv[0]);
++ c = find_config_next(c, c->next, CONF_PARAM, "ListOptions", FALSE);
++ continue;
++ }
++
+ list_options = c->argv[0];
+ list_strict_opts = *((unsigned char *) c->argv[1]);
+
+@@ -2554,6 +2601,8 @@
+ list_ndirs.max = *((unsigned int *) c->argv[4]);
+
+ list_flags = *((unsigned long *) c->argv[5]);
++
++ break;
+ }
+
+ /* Clear the listing option flags. */
+@@ -3019,7 +3068,6 @@
+
+ /* The default flags */
+ c->argv[5] = pcalloc(c->pool, sizeof(unsigned long));
+- *((unsigned int *) c->argv[5]) = 0;
+
+ /* Check for, and handle, optional arguments. */
+ if (cmd->argc-1 >= 2) {
+@@ -3060,6 +3108,12 @@
+
+ *((unsigned int *) c->argv[4]) = maxdirs;
+
++ } else if (strcasecmp(cmd->argv[i], "LISTOnly") == 0) {
++ flags |= LS_FL_LIST_ONLY;
++
++ } else if (strcasecmp(cmd->argv[i], "NLSTOnly") == 0) {
++ flags |= LS_FL_NLST_ONLY;
++
+ } else if (strcasecmp(cmd->argv[i], "NoErrorIfAbsent") == 0) {
+ flags |= LS_FL_NO_ERROR_IF_ABSENT;
+
+@@ -3071,7 +3125,6 @@
+ }
+
+ *((unsigned long *) c->argv[5]) = flags;
+-
+ return PR_HANDLED(cmd);
+ }
+
diff --git a/proftpd-1.3.4a-bug3747.patch b/proftpd-1.3.4a-bug3747.patch
new file mode 100644
index 0000000..80d933f
--- /dev/null
+++ b/proftpd-1.3.4a-bug3747.patch
@@ -0,0 +1,193 @@
+Index: modules/mod_facts.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_facts.c,v
+retrieving revision 1.47
+diff -u -r1.47 mod_facts.c
+--- modules/mod_facts.c 17 Jan 2012 00:51:02 -0000 1.47
++++ modules/mod_facts.c 3 Feb 2012 06:56:26 -0000
+@@ -46,7 +46,9 @@
+ #define FACTS_OPT_SHOW_UNIX_MODE 0x00040
+ #define FACTS_OPT_SHOW_UNIX_OWNER 0x00080
+
+-#define FACTS_MLINFO_FL_SHOW_SYMLINKS 0x00001
++static unsigned long facts_mlinfo_opts = 0;
++#define FACTS_MLINFO_FL_SHOW_SYMLINKS 0x00001
++#define FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK 0x00002
+
+ struct mlinfo {
+ pool *pool;
+@@ -339,7 +341,56 @@
+ info->st.st_ino = target_st.st_ino;
+
+ if (flags & FACTS_MLINFO_FL_SHOW_SYMLINKS) {
+- info->type = "OS.unix=symlink";
++
++ /* Do we use the proper RFC 3659 syntax (i.e. following the BNF rules
++ * of RFC 3659), which would be:
++ *
++ * type=OS.unix=symlink
++ *
++ * See:
++ * http://www.rfc-editor.org/errata_search.php?rfc=3659
++ *
++ * and search for "OS.unix=slink".
++ *
++ * Or do we use the syntax in the _examples_ presented in RFC 3659,
++ * which is what clients such as FileZilla expect:
++ *
++ * type=OS.unix=slink:<target>
++ *
++ * See:
++ * http://trac.filezilla-project.org/ticket/4490
++ */
++
++ if (flags & FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK) {
++ char target[PR_TUNABLE_PATH_MAX+1];
++ int targetlen;
++
++ targetlen = pr_fsio_readlink(path, target, sizeof(target)-1);
++ if (targetlen < 0) {
++ int xerrno = errno;
++
++ pr_log_debug(DEBUG4, MOD_FACTS_VERSION
++ ": error reading symlink '%s': %s", path, strerror(xerrno));
++
++ errno = xerrno;
++ return -1;
++ }
++
++ if (targetlen >= sizeof(target)-1) {
++ targetlen = sizeof(target)-1;
++ }
++
++ target[targetlen] = '\0';
++
++ info->type = pstrcat(info->pool, "OS.unix=slink:",
++ dir_best_path(info->pool, target), NULL);
++
++ } else {
++ /* Use the proper syntax. Too bad for the not-really-compliant
++ * FileZilla.
++ */
++ info->type = "OS.unix=symlink";
++ }
+
+ } else {
+ info->type = "file";
+@@ -1024,6 +1075,10 @@
+ if (ptr &&
+ *ptr == TRUE) {
+ flags |= FACTS_MLINFO_FL_SHOW_SYMLINKS;
++
++ if (facts_mlinfo_opts & FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK) {
++ flags |= FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK;
++ }
+ }
+
+ best_path = dir_best_path(cmd->tmp_pool, decoded_path);
+@@ -1087,11 +1142,11 @@
+ }
+
+ /* Open data connection */
+- session.sf_flags |= SF_ASCII_OVERRIDE;
+ if (pr_data_open(NULL, C_MLSD, PR_NETIO_IO_WR, 0) < 0) {
+ pr_fsio_closedir(dirh);
+ return PR_ERROR(cmd);
+ }
++ session.sf_flags |= SF_ASCII_OVERRIDE;
+
+ pr_fs_clear_cache();
+ facts_mlinfobuf_init();
+@@ -1207,6 +1262,10 @@
+ if (ptr &&
+ *ptr == TRUE) {
+ flags |= FACTS_MLINFO_FL_SHOW_SYMLINKS;
++
++ if (facts_mlinfo_opts & FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK) {
++ flags |= FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK;
++ }
+ }
+
+ fake_mode = get_param_ptr(get_dir_ctxt(cmd->tmp_pool, (char *) decoded_path),
+@@ -1274,10 +1333,15 @@
+ /* XXX What about chroots? */
+
+ if (flags & FACTS_MLINFO_FL_SHOW_SYMLINKS) {
+- /* If we are supposed to symlinks, then use dir_best_path() to get the
+- * full path, including dereferencing the symlink.
+- */
+- info.path = dir_best_path(cmd->tmp_pool, path);
++ if (flags & FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK) {
++ info.path = dir_canonical_path(cmd->tmp_pool, path);
++
++ } else {
++ /* If we are supposed to show symlinks, then use dir_best_path() to get
++ * the full path, including dereferencing the symlink.
++ */
++ info.path = dir_best_path(cmd->tmp_pool, path);
++ }
+
+ } else {
+ info.path = dir_canonical_path(cmd->tmp_pool, path);
+@@ -1407,6 +1471,36 @@
+ return PR_HANDLED(cmd);
+ }
+
++/* usage: FactsOptions opt1 ... optN */
++MODRET set_factsoptions(cmd_rec *cmd) {
++ register unsigned int i;
++ config_rec *c;
++ unsigned long opts = 0UL;
++
++ if (cmd->argc-1 == 0) {
++ CONF_ERROR(cmd, "wrong number of parameters");
++ }
++
++ CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
++
++ c = add_config_param(cmd->argv[0], 1, NULL);
++
++ for (i = 1; i < cmd->argc; i++) {
++ if (strncmp(cmd->argv[i], "UseSlink", 9) == 0) {
++ opts |= FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK;
++
++ } else {
++ CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown FactsOption '",
++ cmd->argv[i], "'", NULL));
++ }
++ }
++
++ c->argv[0] = palloc(c->pool, sizeof(unsigned long));
++ *((unsigned long *) c->argv[0]) = opts;
++
++ return PR_HANDLED(cmd);
++}
++
+ /* Initialization functions
+ */
+
+@@ -1426,8 +1520,14 @@
+ advertise = *((int *) c->argv[0]);
+ }
+
+- if (advertise == FALSE)
++ if (advertise == FALSE) {
+ return 0;
++ }
++
++ c = find_config(main_server->conf, CONF_PARAM, "FactsOptions", FALSE);
++ if (c) {
++ facts_mlinfo_opts = *((unsigned long *) c->argv[0]);
++ }
+
+ facts_opts = FACTS_OPT_SHOW_MODIFY|FACTS_OPT_SHOW_PERM|FACTS_OPT_SHOW_SIZE|
+ FACTS_OPT_SHOW_TYPE|FACTS_OPT_SHOW_UNIQUE|FACTS_OPT_SHOW_UNIX_GROUP|
+@@ -1451,6 +1551,7 @@
+
+ static conftable facts_conftab[] = {
+ { "FactsAdvertise", set_factsadvertise, NULL },
++ { "FactsOptions", set_factsoptions, NULL },
+ { NULL }
+ };
+
+
diff --git a/proftpd-1.3.4a-bug3751.patch b/proftpd-1.3.4a-bug3751.patch
new file mode 100644
index 0000000..68350ec
--- /dev/null
+++ b/proftpd-1.3.4a-bug3751.patch
@@ -0,0 +1,93 @@
+Index: contrib/mod_ban.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_ban.c,v
+retrieving revision 1.55
+diff -u -r1.55 mod_ban.c
+--- contrib/mod_ban.c 12 Dec 2011 19:14:45 -0000 1.55
++++ contrib/mod_ban.c 15 Feb 2012 19:20:45 -0000
+@@ -2819,39 +2819,21 @@
+ pr_event_unregister(&ban_module, "mod_auth.max-users-per-host", NULL);
+ pr_event_unregister(&ban_module, "mod_ban.client-connect-rate", NULL);
+
+- /* "Bounce" the log file descriptor */
++ /* Close the BanLog file descriptor; it will be reopened by the postparse
++ * event listener.
++ */
+ close(ban_logfd);
+ ban_logfd = -1;
+
+- if (ban_log &&
+- strcasecmp(ban_log, "none") != 0) {
+- int res;
+-
+- PRIVS_ROOT
+- res = pr_log_openfile(ban_log, &ban_logfd, 0660);
+- PRIVS_RELINQUISH
+-
+- switch (res) {
+- case 0:
+- break;
+-
+- case -1:
+- pr_log_debug(DEBUG1, MOD_BAN_VERSION ": unable to open BanLog '%s': %s",
+- ban_log, strerror(errno));
+- break;
+-
+- case PR_LOG_SYMLINK:
+- pr_log_debug(DEBUG1, MOD_BAN_VERSION ": unable to open BanLog '%s': %s",
+- ban_log, "is a symlink");
+- break;
+-
+- case PR_LOG_WRITABLE_DIR:
+- pr_log_debug(DEBUG1, MOD_BAN_VERSION ": unable to open BanLog '%s': %s",
+- ban_log, "parent directory is world-writable");
+- break;
+- }
++ /* Close the BanTable file descriptor; it will be reopened by the postparse
++ * event listener.
++ */
++ if (ban_tabfh != NULL) {
++ pr_fsio_close(ban_tabfh);
++ ban_tabfh = NULL;
+ }
+
++ /* Remove the timer. */
+ if (ban_timerno > 0) {
+ (void) pr_timer_remove(ban_timerno, &ban_module);
+ ban_timerno = -1;
+Index: contrib/mod_ban.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_ban.c,v
+retrieving revision 1.55
+diff -u -r1.55 mod_ban.c
+--- contrib/mod_ban.c 12 Dec 2011 19:14:45 -0000 1.55
++++ contrib/mod_ban.c 22 Feb 2012 01:53:52 -0000
+@@ -2762,12 +2763,27 @@
+ ban_tabfh = pr_fsio_open(ban_table, O_RDWR|O_CREAT);
+ PRIVS_RELINQUISH
+
+- if (!ban_tabfh) {
++ if (ban_tabfh == NULL) {
+ pr_log_pri(PR_LOG_NOTICE, MOD_BAN_VERSION
+ ": unable to open BanTable '%s': %s", ban_table, strerror(errno));
+ pr_session_disconnect(&ban_module, PR_SESS_DISCONNECT_BAD_CONFIG, NULL);
+ }
+
++ if (ban_tabfh->fh_fd <= STDERR_FILENO) {
++ int usable_fd;
++
++ usable_fd = pr_fs_get_usable_fd(ban_tabfh->fh_fd);
++ if (usable_fd < 0) {
++ pr_log_debug(DEBUG0, MOD_BAN_VERSION
++ "warning: unable to find good fd for BanTable %s: %s", ban_table,
++ strerror(errno));
++
++ } else {
++ close(ban_tabfh->fh_fd);
++ ban_tabfh->fh_fd = usable_fd;
++ }
++ }
++
+ /* Get the shm for storing all of our ban info. */
+ lists = ban_get_shm(ban_tabfh);
+ if (lists == NULL &&
diff --git a/proftpd-1.3.4a-bug3756.patch b/proftpd-1.3.4a-bug3756.patch
new file mode 100644
index 0000000..67c6988
--- /dev/null
+++ b/proftpd-1.3.4a-bug3756.patch
@@ -0,0 +1,185 @@
+Index: modules/mod_ctrls.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_ctrls.c,v
+retrieving revision 1.53
+diff -u -r1.53 mod_ctrls.c
+--- modules/mod_ctrls.c 12 Dec 2011 04:23:33 -0000 1.53
++++ modules/mod_ctrls.c 23 Feb 2012 22:18:37 -0000
+@@ -492,19 +492,20 @@
+ /* Make sure the path to which we want to bind this socket doesn't already
+ * exist.
+ */
+- unlink(sock_file);
++ (void) unlink(sock_file);
+ }
+
+ /* Fill in the socket structure fields */
+ memset(&sock, 0, sizeof(sock));
+
+ sock.sun_family = AF_UNIX;
+- sstrncpy(sock.sun_path, sock_file, strlen(sock_file));
++ sstrncpy(sock.sun_path, sock_file, sizeof(sock.sun_path));
+
+ len = sizeof(sock);
+
+ /* Bind the name to the descriptor */
+- pr_trace_msg(trace_channel, 1, "binding ctrls socket to '%s'", sock.sun_path);
++ pr_trace_msg(trace_channel, 1, "binding ctrls socket fd %d to path '%s'",
++ sockfd, sock.sun_path);
+ if (bind(sockfd, (struct sockaddr *) &sock, len) < 0) {
+ int xerrno = errno;
+
+@@ -708,9 +709,10 @@
+ close(ctrls_sockfd);
+ ctrls_sockfd = -1;
+
+- if (is_master)
++ if (is_master) {
+ /* Remove the local socket path as well */
+- unlink(ctrls_sock_file);
++ (void) unlink(ctrls_sock_file);
++ }
+
+ return 0;
+ }
+@@ -1159,9 +1161,30 @@
+ }
+ }
+
++ close(ctrls_sockfd);
++ ctrls_sockfd = -1;
++
++ /* Remove the local socket path as well */
++ (void) unlink(ctrls_sock_file);
+ return;
+ }
+
++static void ctrls_postparse_ev(const void *event_data, void *user_data) {
++ if (!ctrls_engine) {
++ return;
++ }
++
++ /* Start listening on the ctrl socket */
++ PRIVS_ROOT
++ ctrls_sockfd = ctrls_listen(ctrls_sock_file, CTRLS_LISTEN_FL_REMOVE_SOCKET);
++ PRIVS_RELINQUISH
++
++ /* Start a timer for the checking/processing of the ctrl socket. */
++ pr_timer_remove(CTRLS_TIMER_ID, &ctrls_module);
++ pr_timer_add(ctrls_interval, CTRLS_TIMER_ID, &ctrls_module, ctrls_timer_cb,
++ "Controls polling");
++}
++
+ static void ctrls_restart_ev(const void *event_data, void *user_data) {
+ register unsigned int i;
+
+@@ -1209,26 +1232,11 @@
+ pr_ctrls_init_acl(ctrls_acttab[i].act_acl);
+ }
+
++ pr_timer_remove(CTRLS_TIMER_ID, &ctrls_module);
+ pr_alarms_unblock();
+ return;
+ }
+
+-static void ctrls_startup_ev(const void *event_data, void *user_data) {
+- if (!ctrls_engine) {
+- return;
+- }
+-
+- /* Start listening on the ctrl socket */
+- PRIVS_ROOT
+- ctrls_sockfd = ctrls_listen(ctrls_sock_file, CTRLS_LISTEN_FL_REMOVE_SOCKET);
+- PRIVS_RELINQUISH
+-
+- /* Start a timer for the checking/processing of the ctrl socket. */
+- pr_timer_remove(CTRLS_TIMER_ID, &ctrls_module);
+- pr_timer_add(ctrls_interval, CTRLS_TIMER_ID, &ctrls_module, ctrls_timer_cb,
+- "Controls polling");
+-}
+-
+ /* Initialization routines
+ */
+
+@@ -1262,7 +1270,7 @@
+
+ pr_event_register(&ctrls_module, "core.restart", ctrls_restart_ev, NULL);
+ pr_event_register(&ctrls_module, "core.shutdown", ctrls_shutdown_ev, NULL);
+- pr_event_register(&ctrls_module, "core.startup", ctrls_startup_ev, NULL);
++ pr_event_register(&ctrls_module, "core.postparse", ctrls_postparse_ev, NULL);
+
+ return 0;
+ }
+Index: src/ctrls.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/src/ctrls.c,v
+retrieving revision 1.32
+diff -u -r1.32 ctrls.c
+--- src/ctrls.c 12 Dec 2011 04:23:33 -0000 1.32
++++ src/ctrls.c 23 Feb 2012 22:18:37 -0000
+@@ -942,7 +942,11 @@
+ /* Create a Unix domain socket */
+ sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sockfd < 0) {
++ int xerrno = errno;
++
+ pr_signals_unblock();
++
++ errno = xerrno;
+ return -1;
+ }
+
+@@ -975,15 +979,23 @@
+
+ /* Make it a socket */
+ if (bind(sockfd, (struct sockaddr *) &cl_sock, len) < 0) {
++ int xerrno = errno;
++
+ unlink(cl_sock.sun_path);
+ pr_signals_unblock();
++
++ errno = xerrno;
+ return -1;
+ }
+
+ /* Set the proper mode */
+ if (chmod(cl_sock.sun_path, PR_CTRLS_CL_MODE) < 0) {
++ int xerrno = errno;
++
+ unlink(cl_sock.sun_path);
+ pr_signals_unblock();
++
++ errno = xerrno;
+ return -1;
+ }
+
+@@ -991,20 +1003,28 @@
+ memset(&ctrl_sock, 0, sizeof(ctrl_sock));
+
+ ctrl_sock.sun_family = AF_UNIX;
+- sstrncpy(ctrl_sock.sun_path, socket_file, strlen(socket_file));
++ sstrncpy(ctrl_sock.sun_path, socket_file, sizeof(ctrl_sock.sun_path));
+ len = sizeof(ctrl_sock);
+
+ if (connect(sockfd, (struct sockaddr *) &ctrl_sock, len) < 0) {
++ int xerrno = errno;
++
+ unlink(cl_sock.sun_path);
+ pr_signals_unblock();
++
++ errno = xerrno;
+ return -1;
+ }
+
+ #if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID) && \
+ !defined(HAVE_GETPEERUCRED) && defined(LOCAL_CREDS)
+ if (ctrls_connect_local_creds(sockfd) < 0) {
++ int xerrno = errno;
++
+ unlink(cl_sock.sun_path);
+ pr_signals_unblock();
++
++ errno = xerrno;
+ return -1;
+ }
+ #endif /* LOCAL_CREDS */
diff --git a/proftpd.conf b/proftpd.conf
index e6e64f9..b61c5c2 100644
--- a/proftpd.conf
+++ b/proftpd.conf
@@ -2,9 +2,78 @@
#
# See: http://www.proftpd.org/docs/directives/linked/by-name.html
+# Security-Enhanced Linux (SELinux) Notes:
+#
+# In Fedora and Red Hat Enterprise Linux, ProFTPD runs confined by SELinux
+# in order to mitigate the effects of an attacker taking advantage of an
+# unpatched vulnerability and getting control of the ftp server. By default,
+# ProFTPD cannot read or write most files on a system nor connect to many
+# external network services, but these restrictions can be relaxed by
+# setting SELinux booleans as follows:
+#
+# setsebool -P allow_ftpd_anon_write=1
+# This allows the ftp daemon to write to files and directories labelled
+# with the public_content_rw_t context type; the daemon would only have
+# read access to these files normally. Files to be made available by ftp
+# but not writeable should be labelled public_content_t.
+#
+# setsebool -P allow_ftpd_full_access=1
+# This allows the ftp daemon to read and write all files on the system.
+#
+# setsebool -P allow_ftpd_use_cifs=1
+# This allows the ftp daemon to read and write files on CIFS-mounted
+# filesystems.
+#
+# setsebool -P allow_ftpd_use_nfs=1
+# This allows the ftp daemon to read and write files on NFS-mounted
+# filesystems.
+#
+# setsebool -P ftp_home_dir=1
+# This allows the ftp daemon to read and write files in users' home
+# directories.
+#
+# setsebool -P ftpd_connect_all_unreserved=1
+# This setting is only available from Fedora 16/RHEL-7 onwards, and is
+# necessary for active-mode ftp transfers to work reliably with non-Linux
+# clients (see http://bugzilla.redhat.com/782177), which may choose to
+# use port numbers outside the "ephemeral port" range of 32768-61000.
+#
+# setsebool -P ftpd_connect_db=1
+# This setting allows the ftp daemon to connect to commonly-used database
+# ports over the network, which is necessary if you are using a database
+# back-end for user authentication, etc.
+#
+# setsebool -P ftpd_is_daemon=1
+# This setting is available only in Fedora releases 4 to 6 and Red Hat
+# Enterprise Linux 5. It should be set if ProFTPD is running in standalone
+# mode, and unset if running in inetd mode.
+#
+# setsebool -P ftpd_disable_trans=1
+# This setting is available only in Fedora releases 4 to 6 and Red Hat
+# Enterprise Linux 5, and when set it removes the SELinux confinement of the
+# ftp daemon. Needless to say, its use is not recommended.
+#
+# All of these booleans are unset by default.
+#
+# See also the "ftpd_selinux" manpage.
+#
+# Note that the "-P" option to setsebool makes the setting permanent, i.e.
+# it will still be in effect after a reboot; without the "-P" option, the
+# effect only lasts until the next reboot.
+#
+# Restrictions imposed by SELinux are on top of those imposed by ordinary
+# file ownership and access permissions; in normal operation, the ftp daemon
+# will not be able to read and/or write a file unless *all* of the ownership,
+# permission and SELinux restrictions allow it.
+
# Server Config - config used for anything outside a <VirtualHost> or <Global> context
# See: http://www.proftpd.org/docs/howto/Vhost.html
+# Trace logging, disabled by default for performance reasons
+# (http://www.proftpd.org/docs/howto/Tracing.html)
+#TraceLog /var/log/proftpd/trace.log
+#Trace DEFAULT:0
+
ServerName "ProFTPD server"
ServerIdent on "FTP Server ready."
ServerAdmin root at localhost
@@ -95,7 +164,7 @@ LogFormat auth "%v [%P] %h %t \"%r\" %s"
#
# Administrative control actions for the ftpdctl program
# (http://www.proftpd.org/docs/contrib/mod_ctrls_admin.html)
-# LoadModule mod_ctrls_admin.c
+LoadModule mod_ctrls_admin.c
#
# Support for MODE Z commands, which allows FTP clients and servers to
# compress data for transfer
@@ -194,6 +263,26 @@ LoadModule mod_vroot.c
# (http://www.proftpd.org/docs/contrib/mod_ifsession.html)
# LoadModule mod_ifsession.c
+# Allow only user root to load and unload modules, but allow everyone
+# to see which modules have been loaded
+# (http://www.proftpd.org/docs/modules/mod_dso.html#ModuleControlsACLs)
+ModuleControlsACLs insmod,rmmod allow user root
+ModuleControlsACLs lsmod allow user *
+
+# Enable basic controls via ftpdctl
+# (http://www.proftpd.org/docs/modules/mod_ctrls.html)
+ControlsEngine on
+ControlsACLs all allow user root
+ControlsSocketACL allow user *
+ControlsLog /var/log/proftpd/controls.log
+
+# Enable admin controls via ftpdctl
+# (http://www.proftpd.org/docs/contrib/mod_ctrls_admin.html)
+<IfModule mod_ctrls_admin.c>
+ AdminControlsEngine on
+ AdminControlsACLs all allow user root
+</IfModule>
+
# Enable mod_vroot by default for better compatibility with PAM
# (http://bugzilla.redhat.com/506735)
<IfModule mod_vroot.c>
diff --git a/proftpd.spec b/proftpd.spec
index 75c6b46..f98ef5d 100644
--- a/proftpd.spec
+++ b/proftpd.spec
@@ -41,7 +41,7 @@
%endif
#global prever rc3
-%global rpmrel 4
+%global rpmrel 5
Summary: Flexible, stable and highly-configurable FTP server
Name: proftpd
@@ -66,6 +66,25 @@ Patch1: proftpd-1.3.4rc3-mysql-password.patch
Patch2: proftpd.conf-no-memcached.patch
Patch4: proftpd-1.3.4rc1-mod_vroot-test.patch
Patch5: proftpd-1.3.4-utf8.patch
+Patch10: proftpd-1.3.4a-bug3714.patch
+Patch11: proftpd-1.3.4a-bug3715.patch
+Patch12: proftpd-1.3.4a-bug3717.patch
+Patch13: proftpd-1.3.4a-bug3719.patch
+Patch14: proftpd-1.3.4a-bug3720.patch
+Patch15: proftpd-1.3.4a-bug3723.patch
+Patch16: proftpd-1.3.4a-bug3724.patch
+Patch17: proftpd-1.3.4a-bug3726.patch
+Patch18: proftpd-1.3.4a-bug3727.patch
+Patch19: proftpd-1.3.4a-bug3729.patch
+Patch20: proftpd-1.3.4a-bug3734.patch
+Patch21: proftpd-1.3.4a-bug3742.patch
+Patch22: proftpd-1.3.4a-bug3743.patch
+Patch23: proftpd-1.3.4a-bug3744.patch
+Patch24: proftpd-1.3.4a-bug3745.patch
+Patch25: proftpd-1.3.4a-bug3746.patch
+Patch26: proftpd-1.3.4a-bug3747.patch
+Patch27: proftpd-1.3.4a-bug3751.patch
+Patch28: proftpd-1.3.4a-bug3756.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
Requires(preun): coreutils, findutils
%if %{use_systemd}
@@ -209,6 +228,82 @@ cp -p mod_geoip/mod_geoip.html doc/contrib/
# Fix character encoding in docs
%patch5 -p1 -b .utf8
+# ftpwho/ftptop not showing command arguments
+# http://bugs.proftpd.org/show_bug.cgi?id=3714
+%patch10 -p0
+
+# MLSD/MLST fail when "DirFakeUser off" or "DirFakeGroup off" used
+# http://bugs.proftpd.org/show_bug.cgi?id=3715
+%patch11 -p0
+
+# proftpd fails to run with "Abort trap" error message
+# http://bugs.proftpd.org/show_bug.cgi?id=3717
+%patch12 -p0
+
+# LIST -R can loop endlessly if bad directory symlink exists
+# http://bugs.proftpd.org/show_bug.cgi?id=3719
+%patch13 -p0
+
+# Various module logfile permissions are 0600 instead of 0640
+# http://bugs.proftpd.org/show_bug.cgi?id=3720
+%patch14 -p0
+
+# mod_memcache segfault on server restart
+# http://bugs.proftpd.org/show_bug.cgi?id=3723
+%patch15 -p0
+
+# Unloading mod_quotatab causes segfault
+# http://bugs.proftpd.org/show_bug.cgi?id=3724 (#757311)
+%patch16 -p0
+
+# mod_exec does not always capture stdout/stderr output from executed command
+# http://bugs.proftpd.org/show_bug.cgi?id=3726
+%patch17 -p0
+
+# mod_wrap2 causes unexpected LogFormat %u expansion for SFTP connections
+# http://bugs.proftpd.org/show_bug.cgi?id=3727
+%patch18 -p0
+
+# mod_ldap can segfault when LDAPUsers is used with no optional filters
+# http://bugs.proftpd.org/show_bug.cgi?id=3729
+%patch19 -p0
+
+# DirFakeUser/DirFakeGroup off with name causes SIGSEGV for MLSD/MLST commands
+# http://bugs.proftpd.org/show_bug.cgi?id=3734
+%patch20 -p0
+
+# Improper handling of self-signed certificate in client-sent cert list when "TLSVerifyClient on" is used
+# http://bugs.proftpd.org/show_bug.cgi?id=3742
+%patch21 -p0
+
+# Random stalls/segfaults seen when transferring large files via SFTP
+# http://bugs.proftpd.org/show_bug.cgi?id=3743
+%patch22 -p0
+
+# Support ls(1) -1 option for LIST command
+# http://bugs.proftpd.org/show_bug.cgi?id=3744
+%patch23 -p0
+
+# Reject PASV command if no IPv4 address available
+# http://bugs.proftpd.org/show_bug.cgi?id=3745
+%patch24 -p0
+
+# Support applying ListOptions only to NLST or to LIST commands
+# http://bugs.proftpd.org/show_bug.cgi?id=3746
+%patch25 -p0
+
+# Support option for displaying symlinks via MLSD using syntax preferred by FileZilla
+# http://bugs.proftpd.org/show_bug.cgi?id=3747
+%patch26 -p0
+
+# mod_ban does not close/reopen the BanLog/BanTable file descriptors on restart, causing a file descriptor leak
+# http://bugs.proftpd.org/show_bug.cgi?id=3751
+%patch27 -p0
+
+# mod_ctrls no longer listens on ControlsSocket after restart
+# http://bugs.proftpd.org/show_bug.cgi?id=3756
+%patch28 -p0
+
# Avoid documentation name conflicts
mv contrib/README contrib/README.contrib
@@ -506,6 +601,40 @@ fi
%{_mandir}/man1/ftpwho.1*
%changelog
+* Tue Feb 28 2012 Paul Howarth <paul at city-fan.org> 1.3.4a-5
+- Document SELinux configuration for ProFTPD in proftpd.conf (#785443)
+- Add support for basic and administrative controls actions using ftpdctl by
+ default (#786623)
+- Add trace logging directives in proftpd.conf but disable them by default as
+ they impair performance
+- Fix ftpwho/ftptop not showing command arguments (bug 3714)
+- Fix MLSD/MLST fail with "DirFakeUser off" or "DirFakeGroup off" (bug 3715)
+- Fix proftpd fails to run with "Abort trap" error message (bug 3717)
+- Fix LIST -R can loop endlessly if bad directory symlink exists (bug 3719)
+- Fix overly restrictive module logfile permissions (bug 3720)
+- Fix mod_memcache segfault on server restart (bug 3723)
+- Fix unloading mod_quotatab causes segfault (#757311, bug 3724)
+- Fix mod_exec does not always capture stdout/stderr output from executed
+ command (bug 3726)
+- Fix mod_wrap2 causes unexpected LogFormat %u expansion for SFTP connections
+ (bug 3727)
+- Fix mod_ldap segfault when LDAPUsers is used with no optional filters
+ (bug 3729)
+- Fix DirFakeUser/DirFakeGroup off with name causes SIGSEGV for MLSD/MLST
+ commands (bug 3734)
+- Fix improper handling of self-signed certificate in client-sent cert list
+ when "TLSVerifyClient on" is used (bug 3742)
+- Fix random stalls/segfaults seen when transferring large files via SFTP
+ (bug 3743)
+- Support ls(1) -1 option for LIST command (bug 3744)
+- Reject PASV command if no IPv4 address available (bug 3745)
+- Support applying ListOptions only to NLST or to LIST commands (bug 3746)
+- Support option for displaying symlinks via MLSD using syntax preferred by
+ FileZilla (bug 3747)
+- Fix mod_ban not closing and reopening the BanLog/BanTable file descriptors
+ on restart, causing a file descriptor leak (bug 3751)
+- Fix mod_ctrls no longer listening on ControlsSocket after restart (bug 3756)
+
* Thu Feb 9 2012 Paul Howarth <paul at city-fan.org> 1.3.4a-4
- Rebuild for new libpcre in Rawhide
More information about the scm-commits
mailing list