You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by wr...@apache.org on 2009/08/17 20:16:53 UTC
svn commit: r805082 - in /httpd/mod_ftp/trunk: include/mod_ftp.h
modules/ftp/ftp_util.c
Author: wrowe
Date: Mon Aug 17 18:16:53 2009
New Revision: 805082
URL: http://svn.apache.org/viewvc?rev=805082&view=rev
Log:
Introduce ftp_escape_control_text for control channel text presentation
Modified:
httpd/mod_ftp/trunk/include/mod_ftp.h
httpd/mod_ftp/trunk/modules/ftp/ftp_util.c
Modified: httpd/mod_ftp/trunk/include/mod_ftp.h
URL: http://svn.apache.org/viewvc/httpd/mod_ftp/trunk/include/mod_ftp.h?rev=805082&r1=805081&r2=805082&view=diff
==============================================================================
--- httpd/mod_ftp/trunk/include/mod_ftp.h (original)
+++ httpd/mod_ftp/trunk/include/mod_ftp.h Mon Aug 17 18:16:53 2009
@@ -279,6 +279,18 @@
ftp_hook_cmd_any((feature), NULL, NULL, FTP_HOOK_LAST, \
FTP_NEW_FEAT | FTP_NO_HELP, "")
+/*
+ * This command escapes text (not containing end of line) to protect the
+ * the special characters CR and 0xFF, by trailing CR with IAC NOP (which
+ * is effectively NULL) and 0xFF with a second 0xFF, for transmission over
+ * the control connection as part of a single-line response.
+ *
+ * Note that the resulting string may be the origin string if transformation
+ * is not required.
+ */
+FTP_DECLARE(const char *) ftp_escape_control_text(const char *s,
+ apr_pool_t *pool);
+
#ifdef __cplusplus
}
#endif
Modified: httpd/mod_ftp/trunk/modules/ftp/ftp_util.c
URL: http://svn.apache.org/viewvc/httpd/mod_ftp/trunk/modules/ftp/ftp_util.c?rev=805082&r1=805081&r2=805082&view=diff
==============================================================================
--- httpd/mod_ftp/trunk/modules/ftp/ftp_util.c (original)
+++ httpd/mod_ftp/trunk/modules/ftp/ftp_util.c Mon Aug 17 18:16:53 2009
@@ -592,6 +592,49 @@
return upper;
}
+/* ftp_escape_control_text:
+ * Expand <CR> to <CR> <IAC> <NOP> (because it is impossible to
+ * distinguish <CR> <NUL> from end of string while retaining
+ * multiline C strings) and a single 0xFF to <IAC> <IAC>
+ * as documented in RFC854 and clarified by RFC2640 and RFC3659
+ *
+ * Arguments: s - The string (not deliberately multiline)
+ * pool - The pool *if required*
+ *
+ * Returns: The escaped string, which may be the origin string.
+ */
+FTP_DECLARE(const char *) ftp_escape_control_text(const char *s,
+ apr_pool_t *pool)
+{
+ int i, j;
+ char *d;
+
+ for (i = 0, j = 0; s[i]; ++i, ++j)
+ {
+ if (s[i] == APR_ASCII_CR)
+ j += 2;
+ else if (s[i] == 0xFF)
+ ++j;
+ }
+
+ if (i == j)
+ return s;
+
+ d = apr_palloc(pool, j + 1);
+
+ for (i = 0, j = 0; (d[j] = s[i]); ++i, ++j)
+ {
+ if (s[i] == APR_ASCII_CR) {
+ d[++j] = '\xFF'; /* IAC */
+ d[++j] = '\xF1'; /* NOP */
+ }
+ else if (s[i] == '\xFF')
+ d[++j] = '\xFF'; /* IAC */
+ }
+
+ return d;
+}
+
/* ftp_check_maxclients: Check the scoreboard for other available servers.
*
* Arguments: r - The current request
Re: svn commit: r805082 - in /httpd/mod_ftp/trunk: include/mod_ftp.h
modules/ftp/ftp_util.c
Posted by "William A. Rowe, Jr." <wr...@rowe-clan.net>.
Folks, if anyone has time to review my rational here, I'm trying to
determine if it is truly necessary to add a new output filter to
transform FF F1 (IAC NOP) sequences back to 00 NULL bytes.
If you look at the relevant RFC's, CR NUL LF has a distinct meaning
from CR LF (the end of a command or response line). If we encounter
a CR in a file name, or an error log message, it's necessary to
preserve the termination rules and ensure we don't confuse the client.
So my solution...
wrowe@apache.org wrote:
> Author: wrowe
> Date: Mon Aug 17 18:16:53 2009
> New Revision: 805082
>
> URL: http://svn.apache.org/viewvc?rev=805082&view=rev
> Log:
> Introduce ftp_escape_control_text for control channel text presentation
> --- httpd/mod_ftp/trunk/modules/ftp/ftp_util.c (original)
> +++ httpd/mod_ftp/trunk/modules/ftp/ftp_util.c Mon Aug 17 18:16:53 2009
> @@ -592,6 +592,49 @@
> return upper;
> }
>
> +/* ftp_escape_control_text:
> + * Expand <CR> to <CR> <IAC> <NOP> (because it is impossible to
> + * distinguish <CR> <NUL> from end of string while retaining
> + * multiline C strings) and a single 0xFF to <IAC> <IAC>
> + * as documented in RFC854 and clarified by RFC2640 and RFC3659
> + for (i = 0, j = 0; (d[j] = s[i]); ++i, ++j)
> + {
> + if (s[i] == APR_ASCII_CR) {
> + d[++j] = '\xFF'; /* IAC */
> + d[++j] = '\xF1'; /* NOP */
> + }
> + else if (s[i] == '\xFF')
> + d[++j] = '\xFF'; /* IAC */
is a bit odd, but semantically equivalent (looking at both IAC NOP and NUL,
both are documeented as 'No operation').
Clearly there is no way to embed a NUL without confusing C into thinking
this was the end of line. It's also not reasonable to do the CR NUL
transformation in an output filter, since we have no way to disambiguate
the CR in a stream from the CR LF which is the deliberate end of line (as
one might encounter in a multiline welcome response).
So the only choice remaining is to recode FF F1 into 00 in the output
filter, which can handle \0 characters. Do we feel this is necessary,
per the definitions in the RFC, or is the CR IAC NOP sequence adequate
and appropriate?
Bill