[proftpd] Add a number of fixes for bugs reported upstream

Paul Howarth pghmcfc at fedoraproject.org
Tue May 17 14:03:49 UTC 2011


commit 9c2f73d95e50072de8dee4ba02d02c90c01cf4fc
Author: Paul Howarth <paul at city-fan.org>
Date:   Tue May 17 14:02:24 2011 +0100

    Add a number of fixes for bugs reported upstream
    
    - Avoid spinning proftpd process if read(2) returns EAGAIN (bug 3639)
    - SITE CPFR/CPTO does not update quota tally (bug 3641)
    - Segfault in mod_sql_mysql if "SQLAuthenticate groupsetfast" used (bug 3642)
    - Disable signal handling for exiting session processes (bug 3644)
    - Ensure that SQLNamedConnectInfos with PERSESSION connection policies are
      opened before chroot (bug 3645)
    - MaxStoreFileSize can be bypassed using REST/APPE (bug 3649)
    - Fix TCPAccessSyslogLevel directive (bug 3652)
    - Segfault with "DefaultServer off" and no matching server for incoming IP
      address (bug 3653)

 proftpd-1.3.4rc2-bug3639.patch |   37 ++++++
 proftpd-1.3.4rc2-bug3641.patch |  245 ++++++++++++++++++++++++++++++++++++++++
 proftpd-1.3.4rc2-bug3642.patch |   18 +++
 proftpd-1.3.4rc2-bug3644.patch |   42 +++++++
 proftpd-1.3.4rc2-bug3645.patch |  104 +++++++++++++++++
 proftpd-1.3.4rc2-bug3649.patch |   77 +++++++++++++
 proftpd-1.3.4rc2-bug3652.patch |   75 ++++++++++++
 proftpd-1.3.4rc2-bug3653.patch |  112 ++++++++++++++++++
 proftpd.spec                   |   47 ++++++++-
 9 files changed, 756 insertions(+), 1 deletions(-)
---
diff --git a/proftpd-1.3.4rc2-bug3639.patch b/proftpd-1.3.4rc2-bug3639.patch
new file mode 100644
index 0000000..438ff8f
--- /dev/null
+++ b/proftpd-1.3.4rc2-bug3639.patch
@@ -0,0 +1,37 @@
+--- proftpd/src/netio.c	2011/02/26 02:31:36	1.50
++++ proftpd/src/netio.c	2011/04/06 17:16:09	1.51
+@@ -23,7 +23,7 @@
+  */
+ 
+ /* NetIO routines
+- * $Id: netio.c,v 1.50 2011/02/26 02:31:36 castaglia Exp $
++ * $Id: netio.c,v 1.51 2011/04/06 17:16:09 castaglia Exp $
+  */
+ 
+ #include "conf.h"
+@@ -922,8 +922,24 @@
+           }
+ 
+ #ifdef EAGAIN
+-	  if (bread == -1 && errno == EAGAIN)
++	  if (bread == -1 &&
++              errno == EAGAIN) {
++            int xerrno = EAGAIN;
++
++            /* Treat this as an interrupted call, call pr_signals_handle()
++             * (which will delay for a few msecs because of EINTR), and try
++             * again.
++             *
++             * This should avoid a tightly spinning loop if read(2) returns
++             * EAGAIN, as on a data transfer (Bug#3639).
++             */
++
++            errno = EINTR;
++            pr_signals_handle();
++
++            errno = xerrno;
+             goto polling;
++          }
+ #endif
+ 
+         } while (bread == -1 && errno == EINTR);
diff --git a/proftpd-1.3.4rc2-bug3641.patch b/proftpd-1.3.4rc2-bug3641.patch
new file mode 100644
index 0000000..fc922e6
--- /dev/null
+++ b/proftpd-1.3.4rc2-bug3641.patch
@@ -0,0 +1,245 @@
+--- proftpd/contrib/mod_copy.c	2010/03/10 19:24:04	1.2
++++ proftpd/contrib/mod_copy.c	2011/04/09 20:26:30	1.3
+@@ -2,7 +2,7 @@
+  * ProFTPD: mod_copy -- a module supporting copying of files on the server
+  *                      without transferring the data to the client and back
+  *
+- * Copyright (c) 2009-2010 TJ Saunders
++ * Copyright (c) 2009-2011 TJ Saunders
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -26,12 +26,12 @@
+  * This is mod_copy, contrib software for proftpd 1.3.x and above.
+  * For more information contact TJ Saunders <tj at castaglia.org>.
+  *
+- * $Id: mod_copy.c,v 1.2 2010/03/10 19:24:04 castaglia Exp $
++ * $Id: mod_copy.c,v 1.3 2011/04/09 20:26:30 castaglia Exp $
+  */
+ 
+ #include "conf.h"
+ 
+-#define MOD_COPY_VERSION	"mod_copy/0.2"
++#define MOD_COPY_VERSION	"mod_copy/0.3"
+ 
+ /* Make sure the version of proftpd is as necessary. */
+ #if PROFTPD_VERSION_NUMBER < 0x0001030401
+@@ -319,7 +319,7 @@
+     return PR_DECLINED(cmd);
+   }
+ 
+-  if (strcasecmp(cmd->argv[1], "COPY") == 0) {
++  if (strncasecmp(cmd->argv[1], "COPY", 5) == 0) {
+     char *cmd_name, *from, *to;
+     unsigned char *authenticated;
+ 
+@@ -363,7 +363,7 @@
+     return PR_HANDLED(cmd);
+   }
+ 
+-  if (strcasecmp(cmd->argv[1], "HELP") == 0) {
++  if (strncasecmp(cmd->argv[1], "HELP", 5) == 0) {
+     pr_response_add(R_214, _("CPFR <sp> pathname"));
+     pr_response_add(R_214, _("CPTO <sp> pathname"));
+   }
+@@ -376,7 +376,7 @@
+   int res;
+   char *path = "";
+ 
+-  if (strcasecmp(cmd->argv[1], "CPFR") != 0) {
++  if (strncasecmp(cmd->argv[1], "CPFR", 5) != 0) {
+     return PR_DECLINED(cmd);
+   }
+ 
+@@ -430,7 +430,7 @@
+   register unsigned int i;
+   char *from, *to = "";
+ 
+-  if (strcasecmp(cmd->argv[1], "CPTO") != 0) {
++  if (strncasecmp(cmd->argv[1], "CPTO", 5) != 0) {
+     return PR_DECLINED(cmd);
+   }
+ 
+@@ -459,12 +459,21 @@
+     return PR_ERROR(cmd);
+   }
+ 
+-  pr_table_remove(session.notes, "mod_copy.cpfr-path", NULL);
+-
+   pr_response_add(R_250, _("Copy successful"));
+   return PR_HANDLED(cmd);
+ }
+ 
++MODRET copy_log_site(cmd_rec *cmd) {
++  if (strncasecmp(cmd->argv[1], "CPTO", 5) != 0) {
++    return PR_DECLINED(cmd);
++  }
++
++  /* Delete the stashed CPFR path from the session.notes table. */
++  (void) pr_table_remove(session.notes, "mod_copy.cpfr-path", NULL);
++
++  return PR_HANDLED(cmd);
++}
++
+ /* Initialization functions
+  */
+ 
+@@ -479,9 +488,12 @@
+  */
+ 
+ static cmdtable copy_cmdtab[] = {
+-  { CMD, C_SITE, G_WRITE,	copy_copy,	FALSE,	FALSE, CL_MISC },
+-  { CMD, C_SITE, G_DIRS,	copy_cpfr,	FALSE,	FALSE, CL_MISC },
+-  { CMD, C_SITE, G_WRITE,	copy_cpto,	FALSE,	FALSE, CL_MISC },
++  { CMD, 	C_SITE, G_WRITE,	copy_copy,	FALSE,	FALSE, CL_MISC },
++  { CMD, 	C_SITE, G_DIRS,		copy_cpfr,	FALSE,	FALSE, CL_MISC },
++  { CMD, 	C_SITE, G_WRITE,	copy_cpto,	FALSE,	FALSE, CL_MISC },
++  { LOG_CMD, 	C_SITE, G_NONE,		copy_log_site,	FALSE,	FALSE },
++  { LOG_CMD_ERR, C_SITE, G_NONE,	copy_log_site,	FALSE,	FALSE },
++
+   { 0, NULL }
+ };
+ 
+--- proftpd/contrib/mod_quotatab.c	2011/03/21 01:01:34	1.72
++++ proftpd/contrib/mod_quotatab.c	2011/04/09 20:26:30	1.73
+@@ -28,7 +28,7 @@
+  * ftp://pooh.urbanrage.com/pub/c/.  This module, however, has been written
+  * from scratch to implement quotas in a different way.
+  *
+- * $Id: mod_quotatab.c,v 1.72 2011/03/21 01:01:34 castaglia Exp $
++ * $Id: mod_quotatab.c,v 1.73 2011/04/09 20:26:30 castaglia Exp $
+  */
+ 
+ #include "mod_quotatab.h"
+@@ -3584,12 +3584,37 @@
+   if (cmd->argc < 2)
+     return PR_DECLINED(cmd);
+ 
+-  if (strcasecmp(cmd->argv[1], "COPY") == 0) {
++  if (strncasecmp(cmd->argv[1], "COPY", 5) == 0) {
+     cmd_rec *copy_cmd;
+ 
+     copy_cmd = pr_cmd_alloc(cmd->tmp_pool, 3, cmd->argv[1], cmd->argv[2],
+       cmd->argv[3]);
+     return quotatab_pre_copy(copy_cmd);
++
++  } else if (strncasecmp(cmd->argv[1], "CPTO", 5) == 0) {
++    register unsigned int i;
++    cmd_rec *copy_cmd;
++    char *from, *to = "";
++
++    if (cmd->argc < 3)
++      return PR_DECLINED(cmd);
++
++    from = pr_table_get(session.notes, "mod_copy.cpfr-path", NULL);
++    if (from == NULL) {
++      pr_response_add_err(R_503, _("Bad sequence of commands"));
++      return PR_ERROR(cmd);
++    }
++
++    /* Construct the target file name by concatenating all the parameters after
++     * the "SITE CPTO", separating them with spaces.
++     */
++    for (i = 2; i <= cmd->argc-1; i++) {
++      to = pstrcat(cmd->tmp_pool, to, *to ? " " : "",
++        pr_fs_decode_path(cmd->tmp_pool, cmd->argv[i]), NULL);
++    }
++
++    copy_cmd = pr_cmd_alloc(cmd->tmp_pool, 3, "COPY", from, to);
++    return quotatab_pre_copy(copy_cmd);
+   }
+ 
+   return PR_DECLINED(cmd);
+@@ -3601,7 +3626,7 @@
+   if (cmd->argc < 2)
+     return PR_DECLINED(cmd);
+ 
+-  if (strcasecmp(cmd->argv[1], "QUOTA") == 0) {
++  if (strncasecmp(cmd->argv[1], "QUOTA", 6) == 0) {
+     char *cmd_name;
+     unsigned char *authenticated = get_param_ptr(cmd->server->conf,
+       "authenticated", FALSE);
+@@ -3686,7 +3711,7 @@
+     return PR_HANDLED(cmd);
+   }
+ 
+-  if (strcasecmp(cmd->argv[1], "HELP") == 0) {
++  if (strncasecmp(cmd->argv[1], "HELP", 5) == 0) {
+ 
+     /* Add a description of SITE QUOTA to the output. */
+     pr_response_add(R_214, "QUOTA");
+@@ -3701,12 +3726,37 @@
+   if (cmd->argc < 2)
+     return PR_DECLINED(cmd);
+ 
+-  if (strcasecmp(cmd->argv[1], "COPY") == 0) {
++  if (strncasecmp(cmd->argv[1], "COPY", 5) == 0) {
+     cmd_rec *copy_cmd;
+ 
+     copy_cmd = pr_cmd_alloc(cmd->tmp_pool, 3, cmd->argv[1], cmd->argv[2],
+       cmd->argv[3]);
+     return quotatab_post_copy(copy_cmd);
++
++  } else if (strncasecmp(cmd->argv[1], "CPTO", 5) == 0) {
++    register unsigned int i;
++    cmd_rec *copy_cmd;
++    char *from, *to = "";
++
++    if (cmd->argc < 3)
++      return PR_DECLINED(cmd);
++
++    from = pr_table_get(session.notes, "mod_copy.cpfr-path", NULL);
++    if (from == NULL) {
++      pr_response_add_err(R_503, _("Bad sequence of commands"));
++      return PR_ERROR(cmd);
++    }
++
++    /* Construct the target file name by concatenating all the parameters after
++     * the "SITE CPTO", separating them with spaces.
++     */
++    for (i = 2; i <= cmd->argc-1; i++) {
++      to = pstrcat(cmd->tmp_pool, to, *to ? " " : "",
++        pr_fs_decode_path(cmd->tmp_pool, cmd->argv[i]), NULL);
++    }
++
++    copy_cmd = pr_cmd_alloc(cmd->tmp_pool, 3, "COPY", from, to);
++    return quotatab_post_copy(copy_cmd);
+   }
+ 
+   return PR_DECLINED(cmd);
+@@ -3718,12 +3768,34 @@
+   if (cmd->argc < 2)
+     return PR_DECLINED(cmd);
+ 
+-  if (strcasecmp(cmd->argv[1], "COPY") == 0) {
++  if (strncasecmp(cmd->argv[1], "COPY", 5) == 0) {
+     cmd_rec *copy_cmd;
+ 
+     copy_cmd = pr_cmd_alloc(cmd->tmp_pool, 3, cmd->argv[1], cmd->argv[2],
+       cmd->argv[3]);
+     return quotatab_post_copy_err(copy_cmd);
++
++  } else if (strncasecmp(cmd->argv[1], "CPTO", 5) == 0) {
++    register unsigned int i;
++    cmd_rec *copy_cmd;
++    char *from, *to = "";
++
++    from = pr_table_get(session.notes, "mod_copy.cpfr-path", NULL);
++    if (from == NULL) {
++      pr_response_add_err(R_503, _("Bad sequence of commands"));
++      return PR_ERROR(cmd);
++    }
++
++    /* Construct the target file name by concatenating all the parameters after
++     * the "SITE CPTO", separating them with spaces.
++     */
++    for (i = 2; i <= cmd->argc-1; i++) {
++      to = pstrcat(cmd->tmp_pool, to, *to ? " " : "",
++        pr_fs_decode_path(cmd->tmp_pool, cmd->argv[i]), NULL);
++    }
++
++    copy_cmd = pr_cmd_alloc(cmd->tmp_pool, 3, "COPY", from, to);
++    return quotatab_post_copy_err(copy_cmd);
+   }
+ 
+   return PR_DECLINED(cmd);
diff --git a/proftpd-1.3.4rc2-bug3642.patch b/proftpd-1.3.4rc2-bug3642.patch
new file mode 100644
index 0000000..8c08e8b
--- /dev/null
+++ b/proftpd-1.3.4rc2-bug3642.patch
@@ -0,0 +1,18 @@
+Index: proftpd/contrib/mod_sql.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_sql.c,v
+retrieving revision 1.210
+diff -u -r1.210 mod_sql.c
+--- proftpd/contrib/mod_sql.c	26 Mar 2011 00:43:27 -0000	1.210
++++ proftpd/contrib/mod_sql.c	12 Apr 2011 22:07:41 -0000
+@@ -4045,8 +4045,8 @@
+     if (!cmap.groupcustomgroupsetfast) {
+       where = sql_prepare_where(0, cmd, 1, cmap.groupwhere, NULL);
+ 
+-      mr = _sql_dispatch(_sql_make_cmd(cmd->tmp_pool, 6, MOD_SQL_DEF_CONN_NAME,
+-        cmap.grptable, cmap.grpfields, where, NULL), "sql_select");
++      mr = _sql_dispatch(_sql_make_cmd(cmd->tmp_pool, 5, MOD_SQL_DEF_CONN_NAME,
++        cmap.grptable, cmap.grpfields, where, "1"), "sql_select");
+       if (check_response(mr) < 0) {
+         return mr;
+       }
diff --git a/proftpd-1.3.4rc2-bug3644.patch b/proftpd-1.3.4rc2-bug3644.patch
new file mode 100644
index 0000000..7b1336b
--- /dev/null
+++ b/proftpd-1.3.4rc2-bug3644.patch
@@ -0,0 +1,42 @@
+Index: proftpd/src/main.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/src/main.c,v
+retrieving revision 1.427
+diff -u -r1.427 main.c
+--- proftpd/src/main.c	14 Apr 2011 23:15:53 -0000	1.427
++++ proftpd/src/main.c	14 Apr 2011 23:20:11 -0000
+@@ -1868,12 +1868,6 @@
+ 
+ static RETSIGTYPE sig_terminate(int signo) {
+ 
+-  /* Make sure the scoreboard slot is properly cleared.  Note that this is
+-   * possibly redundant, as it should already be handled properly in
+-   * pr_session_end().
+-   */
+-  pr_scoreboard_entry_del(FALSE);
+-
+   /* Capture the signal number for later display purposes. */
+   term_signo = signo;
+ 
+@@ -1904,11 +1898,8 @@
+     pr_log_pri(PR_LOG_INFO, "%s session closed.",
+       pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT));
+ 
+-    /* Restore the default signal handlers. */
+ #ifdef PR_DEVEL_STACK_TRACE
+     install_stacktrace_handler();
+-#else
+-    signal(signo, SIG_DFL);
+ #endif /* PR_DEVEL_STACK_TRACE */
+ 
+   } else if (signo == SIGTERM) {
+@@ -1917,6 +1908,9 @@
+   } else {
+     recvd_signal_flags |= RECEIVED_SIG_TERM_OTHER;
+   }
++
++  /* Ignore future occurrences of this signal; we'll be terminating anyway. */
++  signal(signo, SIG_IGN);
+ }
+ 
+ static void handle_chld(void) {
diff --git a/proftpd-1.3.4rc2-bug3645.patch b/proftpd-1.3.4rc2-bug3645.patch
new file mode 100644
index 0000000..733df2a
--- /dev/null
+++ b/proftpd-1.3.4rc2-bug3645.patch
@@ -0,0 +1,104 @@
+Index: proftpd/contrib/mod_sql.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/contrib/mod_sql.c,v
+retrieving revision 1.212
+diff -u -r1.212 mod_sql.c
+--- proftpd/contrib/mod_sql.c	12 Apr 2011 22:47:46 -0000	1.212
++++ proftpd/contrib/mod_sql.c	15 Apr 2011 17:29:27 -0000
+@@ -256,6 +256,7 @@
+   struct sql_named_conn *next, *prev;
+   const char *conn_name;
+   const char *backend;
++  unsigned int conn_policy;
+ };
+ 
+ static struct sql_named_conn *sql_named_conns = NULL;
+@@ -5588,6 +5589,32 @@
+ /* Event handlers
+  */
+ 
++static void sql_chroot_ev(const void *event_data, void *user_data) {
++  /* Loop through our list of named connections, making sure that any
++   * with a connection policy of PERSESSION are opened.
++   */
++  if (sql_named_conns != NULL) {
++    pool *tmp_pool;
++    struct sql_named_conn *snc;
++
++    tmp_pool = make_sub_pool(session.pool);
++
++    for (snc = sql_named_conns; snc; snc = snc->next) {
++      if (snc->conn_policy == SQL_CONN_POLICY_PERSESSION) {
++        cmd_rec *cmd;
++        modret_t *mr; 
++
++        cmd = _sql_make_cmd(tmp_pool, 1, snc->conn_name);
++        mr = _sql_dispatch(cmd, "sql_open");
++        (void) check_response(mr);
++        SQL_FREE_CMD(cmd);
++      }
++    }
++
++    destroy_pool(tmp_pool);
++  }
++}
++
+ static void sql_exit_ev(const void *event_data, void *user_data) {
+   config_rec *c;
+   cmd_rec *cmd;
+@@ -6113,11 +6140,11 @@
+       if (get_named_conn_backend(conn_name) == NULL) {
+         pr_sql_conn_policy = SQL_CONN_POLICY_PERSESSION;
+ 
+-        if (strcasecmp(c->argv[5], "perconn") == 0 ||
+-            strcasecmp(c->argv[5], "perconnection") == 0) {
++        if (strncasecmp(c->argv[5], "perconn", 8) == 0 ||
++            strncasecmp(c->argv[5], "perconnection", 14) == 0) {
+           pr_sql_conn_policy = SQL_CONN_POLICY_PERCONN;
+ 
+-        } else if (strcasecmp(c->argv[5], "percall") == 0) {
++        } else if (strncasecmp(c->argv[5], "percall", 8) == 0) {
+           pr_sql_conn_policy = SQL_CONN_POLICY_PERCALL;
+         }
+ 
+@@ -6129,17 +6156,12 @@
+           return -1;
+         }
+ 
+-        /* Restore the default connection policy. */
+-        pr_sql_conn_policy = default_conn_policy;
+-
+-        sql_log(DEBUG_INFO, "connection '%s' successfully established",
+-          conn_name );
+-
+         /* Add the mapping of the connection name to the backend to the
+          * lookup list.
+          */
+         snc = pcalloc(sql_pool, sizeof(struct sql_named_conn));
+         snc->conn_name = conn_name;
++        snc->conn_policy = pr_sql_conn_policy;
+         snc->backend = c->argv[1];
+ 
+         if (sql_named_conns != NULL) {
+@@ -6149,6 +6171,12 @@
+ 
+         sql_named_conns = snc;
+ 
++        /* Restore the default connection policy. */
++        pr_sql_conn_policy = default_conn_policy;
++
++        sql_log(DEBUG_INFO, "connection '%s' successfully established",
++          conn_name );
++
+       } else {
+         sql_log(DEBUG_INFO, MOD_SQL_VERSION
+           ": unable to open SQLNamedConnectInfo '%s': another connection "
+@@ -6255,7 +6283,7 @@
+ 
+   destroy_pool(tmp_pool);
+ 
+-  /* Add our exit handler */
++  pr_event_register(&sql_module, "core.chroot", sql_chroot_ev, NULL);
+   pr_event_register(&sql_module, "core.exit", sql_exit_ev, NULL);
+ 
+   return 0;
diff --git a/proftpd-1.3.4rc2-bug3649.patch b/proftpd-1.3.4rc2-bug3649.patch
new file mode 100644
index 0000000..0bd30ec
--- /dev/null
+++ b/proftpd-1.3.4rc2-bug3649.patch
@@ -0,0 +1,77 @@
+Index: proftpd/modules/mod_xfer.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/modules/mod_xfer.c,v
+retrieving revision 1.288
+diff -u -r1.288 mod_xfer.c
+--- proftpd/modules/mod_xfer.c	19 Mar 2011 23:39:29 -0000	1.288
++++ proftpd/modules/mod_xfer.c	28 Apr 2011 04:05:57 -0000
+@@ -1588,7 +1588,7 @@
+     }
+   }
+ 
+-  if (stor_fh &&
++  if (stor_fh != NULL &&
+       session.restart_pos) {
+     int xerrno = 0;
+ 
+@@ -1612,7 +1612,7 @@
+     /* Make sure that the requested offset is valid (within the size of the
+      * file being resumed).
+      */
+-    if (stor_fh &&
++    if (stor_fh != NULL &&
+         session.restart_pos > st.st_size) {
+       pr_response_add_err(R_554, _("%s: invalid REST argument"), cmd->arg);
+       (void) pr_fsio_close(stor_fh);
+@@ -1624,13 +1624,18 @@
+     session.restart_pos = 0L;
+   }
+ 
+-  if (!stor_fh) {
++  if (stor_fh == NULL) {
+     pr_log_debug(DEBUG4, "unable to open '%s' for writing: %s", cmd->arg,
+       strerror(ferrno));
+     pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(ferrno));
+     return PR_ERROR(cmd);
+   }
+ 
++  /* Get the latest stats on the file.  If the file already existed, we
++   * want to know its current size.
++   */
++  (void) pr_fsio_fstat(stor_fh, &st);
++
+   /* Perform the actual transfer now */
+   pr_data_init(cmd->arg, PR_NETIO_IO_RD);
+ 
+@@ -1659,10 +1664,13 @@
+    * This check is needed during the pr_data_xfer() loop, below, because
+    * the size of the file being uploaded isn't known in advance
+    */
+-  if ((nbytes_max_store = find_max_nbytes("MaxStoreFileSize")) == 0UL)
++  nbytes_max_store = find_max_nbytes("MaxStoreFileSize");
++  if (nbytes_max_store == 0UL) {
+     have_limit = FALSE;
+-  else
++
++  } else {
+     have_limit = TRUE;
++  }
+ 
+   /* Check the MaxStoreFileSize, and abort now if zero. */
+   if (have_limit &&
+@@ -1699,11 +1707,12 @@
+ 
+     nbytes_stored += len;
+ 
+-    /* Double-check the current number of bytes stored against the
+-     * MaxStoreFileSize, if configured.
++    /* If MaxStoreFileSize is configured, double-check the number of bytes
++     * uploaded so far against the configured limit.  Also make sure that
++     * we take into account the size of the file, i.e. if it already existed.
+      */
+     if (have_limit &&
+-        nbytes_stored > nbytes_max_store) {
++        (nbytes_stored + st.st_size > nbytes_max_store)) {
+ 
+       pr_log_pri(PR_LOG_INFO, "MaxStoreFileSize (%" PR_LU " bytes) reached: "
+         "aborting transfer of '%s'", (pr_off_t) nbytes_max_store, path);
diff --git a/proftpd-1.3.4rc2-bug3652.patch b/proftpd-1.3.4rc2-bug3652.patch
new file mode 100644
index 0000000..672527c
--- /dev/null
+++ b/proftpd-1.3.4rc2-bug3652.patch
@@ -0,0 +1,75 @@
+--- proftpd/contrib/mod_wrap.c	2009/12/10 17:59:14	1.23
++++ proftpd/contrib/mod_wrap.c	2011/05/11 02:14:25	1.25
+@@ -2,7 +2,7 @@
+  * ProFTPD: mod_wrap -- use Wietse Venema's TCP wrappers library for
+  *                      access control
+  *
+- * Copyright (c) 2000-2009 TJ Saunders
++ * Copyright (c) 2000-2011 TJ Saunders
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -24,10 +24,10 @@
+  *
+  * -- DO NOT MODIFY THE TWO LINES BELOW --
+  * $Libraries: -lwrap -lnsl$
+- * $Id: mod_wrap.c,v 1.23 2009/12/10 17:59:14 castaglia Exp $
++ * $Id: mod_wrap.c,v 1.25 2011/05/11 02:14:25 castaglia Exp $
+  */
+ 
+-#define MOD_WRAP_VERSION "mod_wrap/1.2.3"
++#define MOD_WRAP_VERSION "mod_wrap/1.2.4"
+ 
+ #include "conf.h"
+ #include "privs.h"
+@@ -157,13 +157,12 @@
+   return TRUE;
+ }
+ 
+-static void wrap_log_request_allowed(int priority,
++static void wrap_log_request_allowed(int severity,
+     struct request_info *request) {
+-  int facility;
++  int priority;
+ 
+-  /* Mask off the facility bit. */
+-  facility = log_getfacility();
+-  priority &= ~facility;
++  /* Mask off the facility bits. */
++  priority = (severity & PR_LOG_PRIMASK);
+ 
+   pr_log_pri(priority, MOD_WRAP_VERSION ": allowed connection from %s",
+     eval_client(request));
+@@ -172,13 +171,12 @@
+   return;
+ }
+ 
+-static void wrap_log_request_denied(int priority,
++static void wrap_log_request_denied(int severity,
+     struct request_info *request) {
+-  int facility;
++  int priority;
+ 
+-  /* Mask off the facility bit. */
+-  facility = log_getfacility();
+-  priority &= ~facility;
++  /* Mask off the facility bits. */
++  priority = (severity & PR_LOG_PRIMASK);
+ 
+   pr_log_pri(priority, MOD_WRAP_VERSION ": refused connection from %s",
+     eval_client(request));
+@@ -911,9 +909,13 @@
+    *
+    *  "The priority argument is formed by ORing the facility and the level
+    *   values..."
++   *
++   * Note that we do this OR here because the allow_severity/deny_severity
++   * values are ALSO used by the libwrap library; it is also why we need
++   * to mask off some bits later, when using proftpd's logging functions.
+    */
+   allow_severity = log_getfacility() | allow_severity;
+-  deny_severity = log_getfacility() | deny_severity ;
++  deny_severity = log_getfacility() | deny_severity;
+ 
+   pr_log_debug(DEBUG4, MOD_WRAP_VERSION ": checking under service name '%s'",
+     wrap_service_name);
diff --git a/proftpd-1.3.4rc2-bug3653.patch b/proftpd-1.3.4rc2-bug3653.patch
new file mode 100644
index 0000000..b0928bc
--- /dev/null
+++ b/proftpd-1.3.4rc2-bug3653.patch
@@ -0,0 +1,112 @@
+Index: proftpd/src/main.c
+===================================================================
+RCS file: /cvsroot/proftp/proftpd/src/main.c,v
+retrieving revision 1.428
+diff -u -r1.428 main.c
+--- proftpd/src/main.c	21 Apr 2011 16:27:08 -0000	1.428
++++ proftpd/src/main.c	13 May 2011 15:48:04 -0000
+@@ -1207,42 +1207,9 @@
+   /* Find the server for this connection. */
+   main_server = pr_ipbind_get_server(conn->local_addr, conn->local_port);
+ 
+-  pr_inet_set_proto_opts(permanent_pool, conn, 0, 1, IPTOS_LOWDELAY, 0);
+-
+-  /* The follow code was ostensibly used to conserve memory, to free all other
+-   * servers and associated configurations.  However, when large numbers of
+-   * servers are configured, this process adds significant time to the
+-   * establishment of a session.  More importantly, I do not think it is
+-   * really necessary; copy-on-write semantics mean that those portions of
+-   * memory won't actually be in this process' space until changed.  And if
+-   * those configurations will never be reached, the only time the associated
+-   * memory would change is now, when it is attempted to be freed.
+-   *
+-   * s = main_server;
+-   * while (s) {
+-   *   s_saved = s->next;
+-   *   if (s != serv) {
+-   *     if (s->listen && s->listen != l) {
+-   *       if (s->listen->listen_fd == conn->rfd ||
+-   *           s->listen->listen_fd == conn->wfd)
+-   *         s->listen->listen_fd = -1;
+-   *       else
+-   *         inet_close(s->pool,s->listen);
+-   *     }
+-   *
+-   *     if (s->listen) {
+-   *       if (s->listen->listen_fd == conn->rfd ||
+-   *          s->listen->listen_fd == conn->wfd)
+-   *            s->listen->listen_fd = -1;
+-   *     }
+-   *
+-   *     xaset_remove(server_list,(xasetmember_t*)s);
+-   *     destroy_pool(s->pool);
+-   *   }
+-   *   s = s_saved;
+-   * }
++  /* Make sure we allocate a session pool, even if this connection will
++   * dropped soon.
+    */
+-
+   session.pool = make_sub_pool(permanent_pool);
+   pr_pool_tag(session.pool, "Session Pool");
+ 
+@@ -1252,6 +1219,23 @@
+   session.sp_flags = 0;
+   session.proc_prefix = "(connecting)";
+ 
++  /* If no server is configured to handle the addr the user is connected to,
++   * drop them.
++   */
++  if (main_server == NULL) {
++    pr_log_debug(DEBUG2, "No server configuration found for IP address %s",
++      pr_netaddr_get_ipstr(conn->local_addr));
++    pr_log_debug(DEBUG2, "Use the DefaultServer directive to designate "
++      "a default server configuration to handle requests like this");
++
++    pr_response_send(R_500,
++      _("Sorry, no server available to handle request on %s"),
++      pr_netaddr_get_dnsstr(conn->local_addr));
++    exit(0);
++  }
++
++  pr_inet_set_proto_opts(permanent_pool, conn, 0, 1, IPTOS_LOWDELAY, 0);
++
+   /* Close the write side of the semaphore pipe to tell the parent
+    * we are all grown up and have finished housekeeping (closing
+    * former listen sockets).
+@@ -1284,9 +1268,9 @@
+         pr_netaddr_get_ipstr(session.c->local_addr) :
+         main_server->ServerAddress;
+ 
+-      if ((c = find_config(main_server->conf, CONF_PARAM, "MasqueradeAddress",
+-        FALSE)) != NULL) {
+-
++      c = find_config(main_server->conf, CONF_PARAM, "MasqueradeAddress",
++        FALSE);
++      if (c != NULL) {
+         pr_netaddr_t *masq_addr = (pr_netaddr_t *) c->argv[0];
+         serveraddress = pr_netaddr_get_ipstr(masq_addr);
+       }
+@@ -1314,21 +1298,6 @@
+     }
+   }
+ 
+-  /* If no server is configured to handle the addr the user is
+-   * connected to, drop them.
+-   */
+-  if (!main_server) {
+-    pr_log_debug(DEBUG2, "No server configuration found for IP address %s",
+-      pr_netaddr_get_ipstr(conn->local_addr));
+-    pr_log_debug(DEBUG2, "Use the DefaultServer directive to designate "
+-      "a default server configuration to handle requests like this");
+-
+-    pr_response_send(R_500,
+-      _("Sorry, no server available to handle request on %s"),
+-      pr_netaddr_get_dnsstr(conn->local_addr));
+-    exit(0);
+-  }
+-
+   if (main_server->listen) {
+     if (main_server->listen->listen_fd == conn->rfd ||
+         main_server->listen->listen_fd == conn->wfd)
+ 
diff --git a/proftpd.spec b/proftpd.spec
index 1bf168e..e09cebe 100644
--- a/proftpd.spec
+++ b/proftpd.spec
@@ -22,7 +22,7 @@
 %endif
 
 %global prever rc2
-%global rpmrel 8
+%global rpmrel 9
 
 Summary:		Flexible, stable and highly-configurable FTP server
 Name:			proftpd
@@ -54,6 +54,14 @@ Patch0:			proftpd-1.3.2rc3-nostrip.patch
 Patch1:			proftpd-1.3.4rc2-apitests.patch
 Patch2:			proftpd.conf-no-memcached.patch
 Patch4:			proftpd-1.3.4rc1-mod_vroot-test.patch
+Patch5:			proftpd-1.3.4rc2-bug3639.patch
+Patch6:			proftpd-1.3.4rc2-bug3641.patch
+Patch7:			proftpd-1.3.4rc2-bug3642.patch
+Patch8:			proftpd-1.3.4rc2-bug3644.patch
+Patch9:			proftpd-1.3.4rc2-bug3645.patch
+Patch10:		proftpd-1.3.4rc2-bug3649.patch
+Patch11:		proftpd-1.3.4rc2-bug3652.patch
+Patch12:		proftpd-1.3.4rc2-bug3653.patch
 BuildRoot:		%{_tmppath}/%{name}-%{version}-%{release}-root
 Requires(post):		/sbin/chkconfig
 Requires(preun):	/sbin/service, /sbin/chkconfig, coreutils, findutils
@@ -143,6 +151,30 @@ cp -p mod_geoip/mod_geoip.html doc/contrib/
 # If we're running the full test suite, include the mod_vroot test
 %patch4 -p1 -b .test_vroot
 
+# Avoid spinning proftpd process if read(2) returns EAGAIN (bug 3639)
+%patch5 -p1 -b .bug3639
+
+# SITE CPFR/CPTO does not update quota tally (bug 3641)
+%patch6 -p1 -b .bug3641
+
+# Segfault seen in mod_sql_mysql if "SQLAuthenticate groupsetfast" used (bug 3642)
+%patch7 -p1 -b .bug3642
+
+# Disable signal handling for exiting session processes (bug 3644)
+%patch8 -p1 -b .bug3644
+
+# Ensure that SQLNamedConnectInfos with PERSESSION connection policies are opened before chroot (bug 3645)
+%patch9 -p1 -b .bug3645
+
+# MaxStoreFileSize can be bypassed using REST/APPE (bug 3649)
+%patch10 -p1 -b .bug3649
+
+# Fix TCPAccessSyslogLevel directive (bug 3652)
+%patch11 -p1 -b .bug3652
+
+# Segfault with "DefaultServer off" and no matching server for incoming IP address (bug 3653)
+%patch12 -p1 -b .bug3653
+
 # Avoid documentation name conflicts
 mv contrib/README contrib/README.contrib
 
@@ -394,6 +426,19 @@ fi
 %{_libexecdir}/proftpd/mod_sql_postgres.so
 
 %changelog
+* Tue May 17 2011 Paul Howarth <paul at city-fan.org> 1.3.4-0.9.rc2
+- Add a number of fixes for bugs reported upstream:
+  - Avoid spinning proftpd process if read(2) returns EAGAIN (bug 3639)
+  - SITE CPFR/CPTO does not update quota tally (bug 3641)
+  - Segfault in mod_sql_mysql if "SQLAuthenticate groupsetfast" used (bug 3642)
+  - Disable signal handling for exiting session processes (bug 3644)
+  - Ensure that SQLNamedConnectInfos with PERSESSION connection policies are
+    opened before chroot (bug 3645)
+  - MaxStoreFileSize can be bypassed using REST/APPE (bug 3649)
+  - Fix TCPAccessSyslogLevel directive (bug 3652)
+  - Segfault with "DefaultServer off" and no matching server for incoming IP
+    address (bug 3653)
+
 * Fri Apr  8 2011 Paul Howarth <paul at city-fan.org> 1.3.4-0.8.rc2
 - Update mod_geoip to 0.3 (update for new regexp API)
 - Drop patch for mod_geoip API fix


More information about the scm-commits mailing list