components/proftpd/patches/15825705.patch
branchs11u2-sru
changeset 3234 1de12229da80
parent 3233 5f64fead3ff7
child 3235 eb0b103625bc
--- a/components/proftpd/patches/15825705.patch	Fri Jul 25 13:25:28 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,414 +0,0 @@
-http://bugs.proftpd.org/show_bug.cgi?id=4014
-
-I addition, this patch backports the pr_str_get_nbytes() function.
-
-diff --git a/include/options.h b/include/options.h
-index 96fa35d..0b29bf7 100644
---- a/include/options.h
-+++ b/include/options.h
-@@ -110,6 +110,13 @@
- # define PR_TUNABLE_XFER_BUFFER_SIZE	PR_TUNABLE_BUFFER_SIZE
- #endif
- 
-+/* Maximum FTP command size.  For details on this size of 512KB, see
-+ * the Bug#4014 discussion.
-+ */
-+#ifndef PR_TUNABLE_CMD_BUFFER_SIZE
-+# define PR_TUNABLE_CMD_BUFFER_SIZE    (512 * 1024)
-+#endif
-+
- /* Maximum path length.  GNU HURD (and some others) do not define
-  * MAXPATHLEN.  POSIX' PATH_MAX is mandated to be at least 256 
-  * (according to some), so 1K, in the absense of MAXPATHLEN, should be
-diff --git a/include/str.h b/include/str.h
-index b4fed7c..1cf8724 100644
---- a/include/str.h
-+++ b/include/str.h
-@@ -39,6 +39,7 @@ char *pstrndup(pool *, const char *, size_t);
- 
- char *pr_str_strip(pool *, char *);
- char *pr_str_strip_end(char *, char *);
-+int pr_str_get_nbytes(const char *, const char *, off_t *);
- char *pr_str_get_word(char **, int);
- 
- #define PR_STR_FL_PRESERVE_COMMENTS		0x0001
-diff --git a/modules/mod_core.c b/modules/mod_core.c
-index 18a47c2..922f4d1 100644
---- a/modules/mod_core.c
-+++ b/modules/mod_core.c
-@@ -2240,18 +2240,44 @@ MODRET set_allowforeignaddress(cmd_rec *cmd) {
- }
- 
- MODRET set_commandbuffersize(cmd_rec *cmd) {
--  int size = 0;
-+  int res;
-+  size_t size = 0;
-+  off_t nbytes = 0;
-   config_rec *c = NULL;
-+  const char *units = NULL;
-+
-+  if (cmd->argc < 2 || cmd->argc > 3) {
-+    CONF_ERROR(cmd, "wrong number of parameters")
-+  }
- 
--  CHECK_ARGS(cmd, 1);
-   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
- 
--  /* NOTE: need to add checks for maximum possible sizes, negative sizes. */
--  size = atoi(cmd->argv[1]);
-+  if (cmd->argc == 3) {
-+    units = cmd->argv[2];
-+  }
-+
-+  if (pr_str_get_nbytes(cmd->argv[1], units, &nbytes) < 0) {
-+    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to parse: ",
-+      cmd->argv[1], " ", units, ": ", strerror(errno), NULL));
-+  }
-+
-+  if (nbytes > PR_TUNABLE_CMD_BUFFER_SIZE) {
-+    char max[1024];
-+
-+    snprintf(max, sizeof(max)-1, "%lu", (unsigned long)
-+      PR_TUNABLE_CMD_BUFFER_SIZE);
-+    max[sizeof(max)-1] = '\0';
-+
-+    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "size ", cmd->argv[1], units,
-+      "exceeds max size ", max, NULL));
-+  }
-+
-+  /* Possible truncation here, but only for an absurdly large size. */
-+  size = (size_t) nbytes;
- 
-   c = add_config_param(cmd->argv[0], 1, NULL);
--  c->argv[0] = pcalloc(c->pool, sizeof(int));
--  *((int *) c->argv[0]) = size;
-+  c->argv[0] = pcalloc(c->pool, sizeof(size_t));
-+  *((size_t *) c->argv[0]) = size;
- 
-   return PR_HANDLED(cmd);
- }
-diff --git a/src/main.c b/src/main.c
-index 3e6d637..660e14b 100644
---- a/src/main.c
-+++ b/src/main.c
-@@ -466,42 +466,21 @@ static int _dispatch(cmd_rec *cmd, int cmd_type, int validate, char *match) {
-   return success;
- }
- 
--/* Returns the appropriate maximum buffer length to use for FTP commands
-- * from the client, taking the CommandBufferSize directive into account.
-+/* Returns the appropriate maximum buffer size to use for FTP commands
-+ * from the client.
-  */
--static long get_max_cmd_len(size_t buflen) {
--  long res;
--  int *bufsz = NULL;
--  size_t default_cmd_bufsz;
--
--  /* It's possible for the admin to select a PR_TUNABLE_BUFFER_SIZE which
--   * is smaller than PR_DEFAULT_CMD_BUFSZ.  We need to handle such cases
--   * properly.
--   */
--  default_cmd_bufsz = PR_DEFAULT_CMD_BUFSZ;
--  if (default_cmd_bufsz > buflen) {
--    default_cmd_bufsz = buflen;
--  }
-- 
-+static size_t get_max_cmd_sz(void) {
-+  size_t res;
-+  size_t *bufsz = NULL;
-+
-   bufsz = get_param_ptr(main_server->conf, "CommandBufferSize", FALSE);
-   if (bufsz == NULL) {
--    res = default_cmd_bufsz;
--
--  } else if (*bufsz <= 0) {
--    pr_log_pri(PR_LOG_WARNING, "invalid CommandBufferSize size (%d) given, "
--      "using default buffer size (%lu) instead", *bufsz,
--      (unsigned long) default_cmd_bufsz);
--    res = default_cmd_bufsz;
--
--  } else if (*bufsz + 1 > buflen) {
--    pr_log_pri(PR_LOG_WARNING, "invalid CommandBufferSize size (%d) given, "
--      "using default buffer size (%lu) instead", *bufsz,
--      (unsigned long) default_cmd_bufsz);
--    res = default_cmd_bufsz;
-+    res = PR_DEFAULT_CMD_BUFSZ;
- 
-   } else {
--    pr_log_debug(DEBUG1, "setting CommandBufferSize to %d", *bufsz);
--    res = (long) *bufsz;
-+    pr_log_debug(DEBUG1, "setting CommandBufferSize to %lu",
-+      (unsigned long) *bufsz);
-+    res = *bufsz;
-   }
- 
-   return res;
-@@ -509,21 +488,29 @@ static long get_max_cmd_len(size_t buflen) {
- 
- int pr_cmd_read(cmd_rec **res) {
-   static long cmd_bufsz = -1;
--  char buf[PR_DEFAULT_CMD_BUFSZ+1] = {'\0'};
-+  static char *cmd_buf = NULL;
-   char *cp;
--  size_t buflen;
-+  size_t cmd_buflen;
- 
-   if (res == NULL) {
-     errno = EINVAL;
-     return -1;
-   }
- 
-+  if (cmd_bufsz == -1) {
-+    cmd_bufsz = get_max_cmd_sz();
-+  }
-+
-+  if (cmd_buf == NULL) {
-+    cmd_buf = pcalloc(session.pool, cmd_bufsz + 1);
-+  }
-+
-   while (TRUE) {
-     pr_signals_handle();
- 
--    memset(buf, '\0', sizeof(buf));
-+    memset(cmd_buf, '\0', cmd_bufsz);
- 
--    if (pr_netio_telnet_gets(buf, sizeof(buf)-1, session.c->instrm,
-+    if (pr_netio_telnet_gets(cmd_buf, cmd_bufsz, session.c->instrm,
-         session.c->outstrm) == NULL) {
- 
-       if (errno == E2BIG) {
-@@ -544,9 +531,6 @@ int pr_cmd_read(cmd_rec **res) {
-     break;
-   }
- 
--  if (cmd_bufsz == -1)
--    cmd_bufsz = get_max_cmd_len(sizeof(buf));
--
-   /* This strlen(3) is guaranteed to terminate; the last byte of buf is
-    * always NUL, since pr_netio_telnet_gets() is told that the buf size is
-    * one byte less than it really is.
-@@ -554,26 +538,28 @@ int pr_cmd_read(cmd_rec **res) {
-    * If the strlen(3) says that the length is less than the cmd_bufsz, then
-    * there is no need to truncate the buffer by inserting a NUL.
-    */
--  buflen = strlen(buf);
--  if (buflen > (cmd_bufsz - 1)) {
-+  cmd_buflen = strlen(cmd_buf);
-+  if (cmd_buflen > cmd_bufsz) {
-     pr_log_debug(DEBUG0, "truncating incoming command length (%lu bytes) to "
-       "CommandBufferSize %lu; use the CommandBufferSize directive to increase "
--      "the allowed command length", (unsigned long) buflen,
-+      "the allowed command length", (unsigned long) cmd_buflen,
-       (unsigned long) cmd_bufsz);
--    buf[cmd_bufsz - 1] = '\0';
-+    cmd_buf[cmd_bufsz-1] = '\0';
-   }
- 
--  if (buflen &&
--      (buf[buflen-1] == '\n' || buf[buflen-1] == '\r')) {
--    buf[buflen-1] = '\0';
--    buflen--;
-+  if (cmd_buflen &&
-+      (cmd_buf[cmd_buflen-1] == '\n' || cmd_buf[cmd_buflen-1] == '\r')) {
-+    cmd_buf[cmd_buflen-1] = '\0';
-+    cmd_buflen--;
- 
--    if (buflen &&
--        (buf[buflen-1] == '\n' || buf[buflen-1] =='\r'))
--      buf[buflen-1] = '\0';
-+    if (cmd_buflen &&
-+        (cmd_buf[cmd_buflen-1] == '\n' || cmd_buf[cmd_buflen-1] =='\r')) {
-+      cmd_buf[cmd_buflen-1] = '\0';
-+      cmd_buflen--;
-+    }
-   }
- 
--  cp = buf;
-+  cp = cmd_buf;
-   if (*cp == '\r')
-     cp++;
- 
-@@ -587,11 +573,11 @@ int pr_cmd_read(cmd_rec **res) {
-      * command handlers themselves, via cmd->arg.  This small hack
-      * reduces the burden on SITE module developers, however.
-      */
--    if (strncasecmp(cp, C_SITE, 4) == 0)
-+    if (strncasecmp(cp, C_SITE, 4) == 0) {
-       flags |= PR_STR_FL_PRESERVE_WHITESPACE;
-+    }
- 
-     cmd = make_ftp_cmd(session.pool, cp, flags);
--
-     if (cmd) {
-       *res = cmd;
-     } 
-diff --git a/src/str.c b/src/str.c
-index d243a17..4f327bf 100644
---- a/src/str.c
-+++ b/src/str.c
-@@ -367,6 +367,81 @@ char *pr_str_strip_end(char *s, char *ch) {
-   return s;
- }
- 
-+int pr_str_get_nbytes(const char *str, const char *units, off_t *nbytes) {
-+  off_t sz;
-+  char *ptr = NULL;
-+  float factor = 0.0;
-+
-+  if (str == NULL) {
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-+  /* No negative numbers. */
-+  if (*str == '-') {
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-+  if (units == NULL ||
-+      *units == '\0') {
-+    factor = 1.0;
-+
-+  } else if (strncasecmp(units, "KB", 3) == 0) {
-+    factor = 1024.0;
-+
-+  } else if (strncasecmp(units, "MB", 3) == 0) {
-+    factor = 1024.0 * 1024.0;
-+
-+  } else if (strncasecmp(units, "GB", 3) == 0) {
-+    factor = 1024.0 * 1024.0 * 1024.0;
-+
-+  } else if (strncasecmp(units, "TB", 3) == 0) {
-+    factor = 1024.0 * 1024.0 * 1024.0 * 1024.0;
-+
-+  } else if (strncasecmp(units, "B", 2) == 0) {
-+    factor = 1.0;
-+
-+  } else {
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-+  errno = 0;
-+
-+#ifdef HAVE_STRTOULL
-+  sz = strtoull(str, &ptr, 10);
-+#else
-+  sz = strtoul(str, &ptr, 10);
-+#endif /* !HAVE_STRTOULL */
-+
-+  if (errno == ERANGE) {
-+    return -1;
-+  }
-+
-+  if (ptr != NULL && *ptr) {
-+    /* Error parsing the given string */
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-+  /* Don't bother applying the factor if the result will overflow the result. */
-+#ifdef ULLONG_MAX
-+  if (sz > (ULLONG_MAX / factor)) {
-+#else
-+  if (sz > (ULONG_MAX / factor)) {
-+#endif /* !ULLONG_MAX */
-+    errno = ERANGE;
-+    return -1;
-+  }
-+
-+  if (nbytes != NULL) {
-+    *nbytes = (off_t) (sz * factor);
-+  }
-+
-+  return 0;
-+}
-+
- char *pr_str_get_word(char **cp, int flags) {
-   char *res, *dst;
-   char quote_mode = 0;
-diff --git a/tests/t/lib/ProFTPD/Tests/Config/CommandBufferSize.pm b/tests/t/lib/ProFTPD/Tests/Config/CommandBufferSize.pm
-index ed4672a..a57c898 100644
---- a/tests/t/lib/ProFTPD/Tests/Config/CommandBufferSize.pm
-+++ b/tests/t/lib/ProFTPD/Tests/Config/CommandBufferSize.pm
-@@ -94,6 +94,8 @@ sub cmdbuffersz_small {
-     die("Can't open $test_path: $!");
-   }
- 
-+  my $idle_timeout = 3;
-+
-   my $config = {
-     PidFile => $pid_file,
-     ScoreboardFile => $scoreboard_file,
-@@ -103,6 +105,7 @@ sub cmdbuffersz_small {
-     AuthGroupFile => $auth_group_file,
- 
-     CommandBufferSize => $cmdbufsz,
-+    TimeoutIdle => $idle_timeout,
- 
-     IfModules => {
-       'mod_delay.c' => {
-@@ -128,44 +131,16 @@ sub cmdbuffersz_small {
-   defined(my $pid = fork()) or die("Can't fork: $!");
-   if ($pid) {
-     eval {
--      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
-+      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1);
-       $client->login($user, $passwd);
- 
--      my $conn = $client->list_raw($test_file);
--      unless ($conn) {
--        die("Failed to LIST $test_file: " . $client->response_code() . " " .
--          $client->response_msg());
-+      # Since our filename is longer than the CommandBufferSize, proftpd
-+      # should simply ignore this.  It will fail because of the idle timeout
-+      # first.
-+      eval { $client->stat($test_file) };
-+      unless ($@) {
-+        die("STAT command succeeded unexpectedly");
-       }
--
--      my $buf;
--      $conn->read($buf, 8192, 30);
--      eval { $conn->close() };
--
--      my $resp_code = $client->response_code();
--      my $resp_msg = $client->response_msg();
--
--      # CommandBufferSize works by truncating any input longer than the
--      # configured length.  (It should arguably reject such longer input,
--      # but that is a different consideration.)
--      #
--      # Since our file name is longer than the CommandBufferSize, it means
--      # the path will be truncated, and the LIST should return 450.
--
--      my $expected;
--
--      $expected = 450;
--      $self->assert($expected == $resp_code,
--        test_msg("Expected $expected, got $resp_code"));
--
--      # This length is CommandBufferSize - "LIST"(4) - " "(1) - 1 for
--      # the NUL reserved in the code.  Thus CommandBufferSize - 6.
--      my $truncated_name = ("A" x ($cmdbufsz - 6));
--
--      $expected = "$truncated_name: No such file or directory";
--      $self->assert($expected eq $resp_msg,
--        test_msg("Expected '$expected', got '$resp_msg'"));
--
--      $client->quit();
-     };
- 
-     if ($@) {
-@@ -176,7 +151,7 @@ sub cmdbuffersz_small {
-     $wfh->flush();
- 
-   } else {
--    eval { server_wait($config_file, $rfh) };
-+    eval { server_wait($config_file, $rfh, 15) };
-     if ($@) {
-       warn($@);
-       exit 1;
-