24793845 proftpd 1.3.5b needs TransferOptions IgnoreASCII
authorJiri David <jiri.david@oracle.com>
Wed, 23 Nov 2016 00:29:59 -0800
changeset 7392 b622c682317d
parent 7391 df75a8cb8663
child 7393 f4f5642f74fa
24793845 proftpd 1.3.5b needs TransferOptions IgnoreASCII
components/proftpd/patches/013.24793845-ignoreascii.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/proftpd/patches/013.24793845-ignoreascii.patch	Wed Nov 23 00:29:59 2016 -0800
@@ -0,0 +1,263 @@
+This patch is a backport of proftpd Bug#4159 from 1.3.6.rc2 to 1.3.5b. It should
+be removed as soon as we sync with stable 1.3.6 release.
+
+This patch is hand crafted combination of following two commits. No test files
+are included.
+
+Fix regression, caused by change for Bug#4159 with the ASCII translation handling of LIST/NLST output
+https://github.com/proftpd/proftpd/commit/3892250b429661dd8d166a55230f9a0da923a26b
+
+Bug#4159: Support ability to disable ASCII translation transparently to FTP clients.
+https://github.com/proftpd/proftpd/commit/68229c0bc839260a43ac1c9b9f7ed68e39aa0f1a
+
+http://bugs.proftpd.org/show_bug.cgi?id=4159
+
+diff --git a/doc/modules/mod_xfer.html b/doc/modules/mod_xfer.html
+index 19179fa..52b02c0 100644
+--- a/doc/modules/mod_xfer.html
++++ b/doc/modules/mod_xfer.html
+@@ -33,6 +33,7 @@ file transfers.
+   <li><a href="#StoreUniquePrefix">StoreUniquePrefix</a>
+   <li><a href="#TimeoutNoTransfer">TimeoutNoTransfer</a>
+   <li><a href="#TimeoutStalled">TimeoutStalled</a>
++  <li><a href="#TransferOptions">TransferOptions</a>
+   <li><a href="#TransferPriority">TransferPriority</a>
+   <li><a href="#TransferRate">TransferRate</a>
+   <li><a href="#UseSendfile">UseSendfile</a>
+@@ -330,6 +331,36 @@ The maximum allowed <em>seconds</em> value is 65535 (108 minutes).
+ 
+ <p>
+ <hr>
++<h2><a name="TransferOptions">TransferOptions</a></h2>
++<strong>Syntax:</strong> TransferOptions <em>opt1 ...</em><br>
++<strong>Default:</strong> None<br>
++<strong>Context:</strong> server config, <code>&lt;VirtualHost&gt;</code>, <code>&lt;Global&gt;</code><br>
++<strong>Module:</strong> mod_xfer<br>
++<strong>Compatibility:</strong> 1.3.5b and later
++
++<p>
++The <code>TransferOptions</code> directive to configure various optional data
++transfer behaviors.
++
++<p>
++The currently implemented options are:
++<ul>
++  <li><code>IgnoreASCII</code><br>
++      <p>
++      This option causes proftpd to silently ignore any client requests to
++      perform ASCII translations via the <code>TYPE</code> command.  That is,
++      FTP clients can request ASCII translations, and proftpd will respond
++      as the client expects, but will <b>not</b> actually perform the translation
++      for either uploads <i>or</i> downloads.  This behavior can be useful in
++      circumstances involving older/mainframe clients and EBCDIC files.
++
++      <p>
++      <b>Note</b> that this option first appeared in
++      <code>proftpd-1.3.5b</code>.
++</ul>
++
++<p>
++<hr>
+ <h2><a name="TransferPriority">TransferPriority</a></h2>
+ <strong>Syntax:</strong> TransferPriority <em>cmd-list "low"|"medium"|"high"|number</em><br>
+ <strong>Default:</strong> None<br>
+diff --git a/include/data.h b/include/data.h
+index 4eaf5d9..fd5f9d9 100644
+--- a/include/data.h
++++ b/include/data.h
+@@ -31,6 +31,11 @@
+ #ifndef PR_DATACONN_H
+ #define PR_DATACONN_H
+ 
++/* Toggles whether to actually perform ASCII translation during the data
++ * transfer.
++ */
++int pr_data_ignore_ascii(int);
++
+ void pr_data_init(char *, int);
+ void pr_data_cleanup(void);
+ int pr_data_open(char *, char *, int, off_t);
+@@ -40,6 +45,7 @@ int pr_data_xfer(char *, size_t);
+ void pr_data_reset(void);
+ void pr_data_set_linger(long);
+ 
++
+ /* Clear the session.xfer.p pool, if present, and reset any associated
+  * state.
+  */
+diff --git a/modules/mod_xfer.c b/modules/mod_xfer.c
+index de5c52a..4b75034 100644
+--- a/modules/mod_xfer.c
++++ b/modules/mod_xfer.c
+@@ -61,6 +61,7 @@ static int xfer_check_limit(cmd_rec *);
+ 
+ /* TransferOptions */
+ #define PR_XFER_OPT_HANDLE_ALLO		0x0001
++#define PR_XFER_OPT_IGNORE_ASCII	0x0002
+ static unsigned long xfer_opts = PR_XFER_OPT_HANDLE_ALLO;
+ 
+ /* Transfer priority */
+@@ -1923,7 +1924,8 @@ MODRET xfer_rest(cmd_rec *cmd) {
+    * clients.
+    */
+   if ((session.sf_flags & SF_ASCII) &&
+-      pos != 0) {
++      pos != 0 &&
++      !(xfer_opts & PR_XFER_OPT_IGNORE_ASCII)) {
+     pr_log_debug(DEBUG5, "%s not allowed in ASCII mode", cmd->argv[0]);
+     pr_response_add_err(R_501,
+       _("%s: Resuming transfers not allowed in ASCII mode"), cmd->argv[0]);
+@@ -2587,6 +2589,26 @@ MODRET xfer_post_pass(cmd_rec *cmd) {
+      */
+   }
+ 
++  /*
++   * Check for TransferOptions
++   */
++  c = find_config(main_server->conf, CONF_PARAM, "TransferOptions", FALSE);
++  while (c != NULL) {
++    unsigned long opts = 0;
++
++    pr_signals_handle();
++
++    opts = *((unsigned long *) c->argv[0]);
++    xfer_opts |= opts;
++
++    c = find_config_next(c, c->next, CONF_PARAM, "TransferOptions", FALSE);
++  }
++
++  if (xfer_opts & PR_XFER_OPT_IGNORE_ASCII) {
++    pr_log_debug(DEBUG8, "Ignoring ASCII translation for this session");
++    pr_data_ignore_ascii(TRUE);
++  }
++
+   /* Check for TransferPriority. */
+   c = find_config(TOPLEVEL_CONF, CONF_PARAM, "TransferPriority", FALSE);
+   if (c) {
+@@ -2999,6 +3021,36 @@ MODRET set_timeoutstalled(cmd_rec *cmd) {
+   return PR_HANDLED(cmd);
+ }
+ 
++/* usage: TransferOptions opt1 opt2 ... */
++MODRET set_transferoptions(cmd_rec *cmd) {
++  config_rec *c = NULL;
++  register unsigned int i = 0;
++  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 (strcasecmp(cmd->argv[i], "IgnoreASCII") == 0) {
++      opts |= PR_XFER_OPT_IGNORE_ASCII;
++
++    } else {
++      CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown TransferOption '",
++      cmd->argv[i], "'", NULL));
++    }
++  }
++
++  c->argv[0] = pcalloc(c->pool, sizeof(unsigned long));
++  *((unsigned long *) c->argv[0]) = opts;
++
++  return PR_HANDLED(cmd);
++}
++
+ /* usage: TransferPriority cmds "low"|"medium"|"high"|number
+  */
+ MODRET set_transferpriority(cmd_rec *cmd) {
+@@ -3459,6 +3511,7 @@ static conftable xfer_conftab[] = {
+   { "StoreUniquePrefix",	set_storeuniqueprefix,		NULL },
+   { "TimeoutNoTransfer",	set_timeoutnoxfer,		NULL },
+   { "TimeoutStalled",		set_timeoutstalled,		NULL },
++  { "TransferOptions",		set_transferoptions,		NULL },
+   { "TransferPriority",		set_transferpriority,		NULL },
+   { "TransferRate",		set_transferrate,		NULL },
+   { "UseSendfile",		set_usesendfile,		NULL },
+diff --git a/src/data.c b/src/data.c
+index 5136f5f..0c45c77 100644
+--- a/src/data.c
++++ b/src/data.c
+@@ -40,6 +40,9 @@
+ 
+ static const char *trace_channel = "data";
+ 
++#define PR_DATA_OPT_IGNORE_ASCII	0x0001
++static unsigned long data_opts = 0UL;
++
+ /* local macro */
+ 
+ #define MODE_STRING	(session.sf_flags & (SF_ASCII|SF_ASCII_OVERRIDE) ? \
+@@ -580,6 +583,33 @@ void pr_data_reset(void) {
+   session.sf_flags &= (SF_ALL^(SF_ABORT|SF_POST_ABORT|SF_XFER|SF_PASSIVE|SF_ASCII_OVERRIDE|SF_EPSV_ALL));
+ }
+ 
++int pr_data_ignore_ascii(int ignore_ascii) {
++  int res;
++
++  if (ignore_ascii != TRUE &&
++      ignore_ascii != FALSE) {
++    errno = EINVAL;
++    return -1;
++  }
++
++  if (data_opts & PR_DATA_OPT_IGNORE_ASCII) {
++    if (!ignore_ascii) {
++      data_opts &= ~PR_DATA_OPT_IGNORE_ASCII;
++    }
++
++    res = TRUE;
++
++    } else {
++      if (ignore_ascii) {
++        data_opts |= PR_DATA_OPT_IGNORE_ASCII;
++      }
++
++      res = FALSE;
++    }
++
++  return res;
++}
++
+ void pr_data_init(char *filename, int direction) {
+   if (session.xfer.p == NULL) {
+     data_new_xfer(filename, direction);
+@@ -1155,7 +1185,15 @@ int pr_data_xfer(char *cl_buf, size_t cl_size) {
+     char *buf = session.xfer.buf;
+     pr_buffer_t *pbuf;
+ 
+-    if (session.sf_flags & (SF_ASCII|SF_ASCII_OVERRIDE)) {
++    /* We use ASCII translation if:
++     *
++     * - SF_ASCII_OVERRIDE session flag is set (e.g. for LIST/NLST)
++     * - SF_ASCII session flag is set, AND IGNORE_ASCII data opt NOT set
++     */
++    if ((session.sf_flags & SF_ASCII_OVERRIDE) ||
++	((session.sf_flags & SF_ASCII) &&
++	 !(data_opts & PR_DATA_OPT_IGNORE_ASCII))) {
++
+       int adjlen, buflen;
+ 
+       do {
+@@ -1330,8 +1368,14 @@ int pr_data_xfer(char *cl_buf, size_t cl_size) {
+ 
+       /* Fill up our internal buffer. */
+       memcpy(session.xfer.buf, cl_buf, buflen);
+-
+-      if (session.sf_flags & (SF_ASCII|SF_ASCII_OVERRIDE)) {
++    /* We use ASCII translation if:
++     *
++     * - SF_ASCII_OVERRIDE session flag is set (e.g. for LIST/NLST)
++     * - SF_ASCII session flag is set, AND IGNORE_ASCII data opt NOT set
++     */
++     if ((session.sf_flags & SF_ASCII_OVERRIDE) ||
++	 ((session.sf_flags & SF_ASCII) &&
++	  !(data_opts & PR_DATA_OPT_IGNORE_ASCII))) {
+         /* Scan the internal buffer, looking for LFs with no preceding CRs.
+          * Add CRs (and expand the internal buffer) as necessary. xferbuflen
+          * will be adjusted so that it contains the length of data in