httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wr...@apache.org
Subject svn commit: r805083 - in /httpd/mod_ftp/trunk/modules/ftp: ftp_commands.c mod_ftp_example.c
Date Mon, 17 Aug 2009 18:17:28 GMT
Author: wrowe
Date: Mon Aug 17 18:17:28 2009
New Revision: 805083

URL: http://svn.apache.org/viewvc?rev=805083&view=rev
Log:
Use ftp_escape_control_text for untrusted control channel text

Modified:
    httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c
    httpd/mod_ftp/trunk/modules/ftp/mod_ftp_example.c

Modified: httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c
URL: http://svn.apache.org/viewvc/httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c?rev=805083&r1=805082&r2=805083&view=diff
==============================================================================
--- httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c (original)
+++ httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c Mon Aug 17 18:17:28 2009
@@ -165,9 +165,8 @@
          (cmd->flags & FTP_NEED_LOGIN)) ||
         ((rr->status == HTTP_FORBIDDEN) &&
          (cmd->flags & FTP_NEED_LOGIN))) {
-        fc->response_notes = apr_psprintf(r->pool,
-                                          FTP_MSG_NOTALLOWED,
-                                          r->method);
+        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOTALLOWED,
+                                 ftp_escape_control_text(r->method, r->pool));
         ap_destroy_sub_req(rr);
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -409,7 +408,8 @@
 
     if ((rr->status == HTTP_UNAUTHORIZED) || (rr->status == HTTP_FORBIDDEN)) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
+                                  ftp_escape_control_text(r->parsed_uri.path,
+                                                          r->pool));
         ap_destroy_sub_req(rr);
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -456,7 +456,8 @@
     /* Check access permissions for the new directory. */
     if (!((rr->status == HTTP_OK) || (rr->status == HTTP_MOVED_PERMANENTLY))) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
+                                  ftp_escape_control_text(r->parsed_uri.path,
+                                                          r->pool));
         ap_destroy_sub_req(rr);
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -464,7 +465,8 @@
     if (rr->finfo.filetype != 0) {
         if (rr->finfo.filetype != APR_DIR) {
             fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOT_A_DIR,
-                                              r->parsed_uri.path);
+                                  ftp_escape_control_text(r->parsed_uri.path,
+                                                          r->pool));
             response = FTP_REPLY_FILE_NOT_FOUND;
         }
         else {
@@ -501,7 +503,8 @@
     }
     else {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE,
-                                          r->parsed_uri.path);
+                                  ftp_escape_control_text(r->parsed_uri.path,
+                                                          r->pool));
         response = FTP_REPLY_FILE_NOT_FOUND;
     }
 
@@ -538,7 +541,8 @@
      */
     if ((rr->status == HTTP_UNAUTHORIZED) || (rr->status == HTTP_FORBIDDEN)) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
+                                  ftp_escape_control_text(r->parsed_uri.path,
+                                                          r->pool));
         response = FTP_REPLY_FILE_NOT_FOUND;
     }
     /* We do have permission, and the file exists.  Try to remove. */
@@ -550,8 +554,7 @@
             char error_str[120];
             char *err = apr_strerror(rv, error_str, sizeof(error_str));
             fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                              err);
-
+                                     ftp_escape_control_text(err, r->pool));
             response = FTP_REPLY_FILE_NOT_FOUND;
         }
         else {
@@ -567,7 +570,7 @@
             char error_str[120];
             char *err = apr_strerror(rv, error_str, sizeof(error_str));
             fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                              err);
+                                     ftp_escape_control_text(err, r->pool));
             response = FTP_REPLY_FILE_NOT_FOUND;
         }
         else {
@@ -577,7 +580,8 @@
     else {
         /* File does not exist */
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE,
-                                          r->parsed_uri.path);
+                                 ftp_escape_control_text(r->parsed_uri.path,
+                                                         r->pool));
         response = FTP_REPLY_FILE_NOT_FOUND;
     }
     ap_destroy_sub_req(rr);
@@ -623,7 +627,8 @@
             return FTP_REPLY_HELP_MESSAGE;
         }
         else {
-            fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOTIMPL, arg);
+            fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOTIMPL,
+                                     ftp_escape_control_text(arg, r->pool));
             return FTP_REPLY_COMMAND_NOT_IMPLEMENTED;
         }
     }
@@ -639,7 +644,8 @@
     ap_pass_brigade(c->output_filters, bb);
 
     fc->response_notes = apr_psprintf(r->pool, FTP_MSG_HELP,
-                                      r->server->server_admin);
+                              ftp_escape_control_text(r->server->server_admin,
+                                                      r->pool));
     return FTP_REPLY_HELP_MESSAGE;
 }
 
@@ -703,8 +709,8 @@
         if (found > 1) {
             ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_NOERRNO, 0, 0,
                          "Ignoring directory listing request for %s", arg);
-            fc->response_notes = apr_psprintf(r->pool,
-                                              FTP_MSG_PERM_DENIED, arg);
+            fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
+                                     ftp_escape_control_text(arg, r->pool));
             return FTP_REPLY_FILE_NOT_FOUND;
         }
     }
@@ -725,7 +731,8 @@
 
     if (rr->status != HTTP_OK) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
+                                 ftp_escape_control_text(r->parsed_uri.path,
+                                                         r->pool));
         ap_destroy_sub_req(rr);
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -745,7 +752,8 @@
 
     /* Construct the sorted array of directory contents */
     if ((direntry = ftp_direntry_get(r, pattern)) == NULL) {
-        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE, arg);
+        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE,
+                                 ftp_escape_control_text(arg, r->pool));
         return FTP_REPLY_FILE_NOT_FOUND;
     }
 
@@ -876,7 +884,8 @@
 
     if ((rr->status == HTTP_UNAUTHORIZED) || (rr->status == HTTP_FORBIDDEN)) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
+                                 ftp_escape_control_text(r->parsed_uri.path,
+                                                         r->pool));
         ap_destroy_sub_req(rr);
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -907,7 +916,8 @@
 
     if ((rr->status == HTTP_UNAUTHORIZED) || (rr->status == HTTP_FORBIDDEN)) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
+                                 ftp_escape_control_text(r->parsed_uri.path,
+                                                         r->pool));
         ap_destroy_sub_req(rr);
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -933,13 +943,15 @@
     if (rv != APR_SUCCESS) {
         char error_str[120];
         char *err = apr_strerror(rv, error_str, sizeof(error_str));
-        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED, err);
+        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED, 
+                                 ftp_escape_control_text(err, r->pool));
         return FTP_REPLY_FILE_NOT_FOUND;
     }
     else {
         apr_file_perms_set(r->filename, dirperms);
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_DIR_CREAT,
-                                          r->parsed_uri.path);
+                                 ftp_escape_control_text(r->parsed_uri.path,
+                                                         r->pool));
         return FTP_REPLY_PATH_CREATED;
     }
 }
@@ -951,11 +963,12 @@
     if (*arg && !arg[1]) {
         switch (toupper(*arg)) {
         case 'S':
-            fc->response_notes = apr_pstrdup(r->pool, "Mode set to S");
+            fc->response_notes = "Mode set to S";
             return FTP_REPLY_COMMAND_OK;
         }
     }
-    fc->response_notes = apr_pstrcat(r->pool, "Mode ", arg, " not implemented", NULL);
+    fc->response_notes = apr_psprintf(r->pool, "Mode %s not implemented", 
+                              ftp_escape_control_text(arg, r->pool));
     return FTP_REPLY_COMMAND_NOT_IMPL_PARAM;
 }
 
@@ -1013,7 +1026,8 @@
 
     if (rr->status != HTTP_OK) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
+                                 ftp_escape_control_text(r->parsed_uri.path,
+                                                         r->pool));
         ap_destroy_sub_req(rr);
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -1032,7 +1046,9 @@
 
     /* Construct the sorted array of directory contents */
     if ((direntry = ftp_direntry_get(r, pattern)) == NULL) {
-        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE, arg);
+        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE,
+                                 ftp_escape_control_text(arg, r->pool));
+
         return FTP_REPLY_FILE_NOT_FOUND;
     }
 
@@ -2060,7 +2076,8 @@
 {
     ftp_connection *fc = ftp_get_module_config(r->connection->conn_config);
 
-    fc->response_notes = apr_psprintf(r->pool, FTP_MSG_DIR_CUR, fc->cwd);
+    fc->response_notes = apr_psprintf(r->pool, FTP_MSG_DIR_CUR, 
+                                 ftp_escape_control_text(fc->cwd, r->pool));
     return FTP_REPLY_PATH_CREATED;
 }
 
@@ -2126,7 +2143,7 @@
     rr = ap_sub_req_method_uri(r->method, rfile, r, NULL);
     if (rr->status != HTTP_OK) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          rfile);
+                                 ftp_escape_control_text(rfile, r->pool));
         ap_destroy_sub_req(rr);
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -2178,7 +2195,7 @@
          * but better safe than sorry
          */
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          rfile);
+                                 ftp_escape_control_text(rfile, r->pool));
         res = FTP_REPLY_FILE_NOT_FOUND;
         goto clean_up;
     }
@@ -2195,7 +2212,7 @@
 
     /*
      * Filter manipulation.  We remove the subrequest filter so that the EOS
-     * buckets stay in tact.  We also add the content length filter so that
+     * buckets stay intact.  We also add the content length filter so that
      * we can record the bytes_sent
      */
     for (f = rr->output_filters; f; f = f->next) {
@@ -2209,7 +2226,8 @@
                                 rr, rr->connection);
 
     if ((res = ap_run_sub_req(rr)) != OK) {
-        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE, arg);
+        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE,
+                                 ftp_escape_control_text(arg, r->pool));
         res = FTP_REPLY_FILE_NOT_FOUND;
     }
 
@@ -2276,7 +2294,8 @@
 
     if ((rr->status == HTTP_UNAUTHORIZED) || (rr->status == HTTP_FORBIDDEN)) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
+                                 ftp_escape_control_text(r->parsed_uri.path,
+                                                         r->pool));
         response = FTP_REPLY_FILE_NOT_FOUND;
     }
     else if (rr->finfo.filetype != APR_NOFILE) {
@@ -2286,7 +2305,8 @@
     }
     else {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE,
-                                          r->parsed_uri.path);
+                                 ftp_escape_control_text(r->parsed_uri.path,
+                                                         r->pool));
         response = FTP_REPLY_FILE_NOT_FOUND;
     }
 
@@ -2311,7 +2331,8 @@
 
     if ((rr->status == HTTP_UNAUTHORIZED) || (rr->status == HTTP_FORBIDDEN)) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
+                                 ftp_escape_control_text(r->parsed_uri.path,
+                                                         r->pool));
         ap_destroy_sub_req(rr);
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -2350,7 +2371,8 @@
 
     if ((rr->status == HTTP_UNAUTHORIZED) || (rr->status == HTTP_FORBIDDEN)) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
+                                 ftp_escape_control_text(r->parsed_uri.path,
+                                                         r->pool));
         ap_destroy_sub_req(rr);
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -2361,7 +2383,8 @@
     if (rv != APR_SUCCESS) {
         char error_str[120];
         char *err = apr_strerror(rv, error_str, sizeof(error_str));
-        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED, err);
+        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
+                                 ftp_escape_control_text(err, r->pool));
         return FTP_REPLY_FILE_NOT_FOUND;
     }
     else {
@@ -2372,45 +2395,92 @@
 static int ftp_cmd_size(request_rec *r, const char *arg)
 {
     ftp_connection *fc = ftp_get_module_config(r->connection->conn_config);
-    int res, response;
     request_rec *rr;
+    conn_rec *c = r->connection;
+    const char *rfile;
+    ap_filter_t *f, *rinput, *routput, *rinput_proto, *routput_proto;
+    int res = FTP_REPLY_FILE_STATUS;
+    apr_off_t size;
 
-    if ((res = ftp_set_uri(r, arg))) {
+    rfile = arg;
+
+    if ((res = ftp_set_uri(r, rfile))) {
         return res;
     }
 
-    rr = ap_sub_req_method_uri(r->method, r->uri, r, NULL);
+    /* Save the original filters */
+    rinput = r->input_filters;
+    rinput_proto = r->proto_input_filters;
+    routput = r->output_filters;
+    routput_proto = r->proto_output_filters;
 
-    if ((rr->status == HTTP_UNAUTHORIZED) || (rr->status == HTTP_FORBIDDEN)) {
-        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
-        return FTP_REPLY_FILE_NOT_FOUND;
-    }
+    r->proto_input_filters = c->input_filters;
+    r->input_filters = r->proto_input_filters;
+    r->proto_output_filters = c->output_filters;
+    r->output_filters = r->proto_output_filters;
 
-    if (rr->finfo.filetype == 0) {
-        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE, arg);
-        response = FTP_REPLY_FILE_NOT_FOUND;
-    }
-    else if (rr->finfo.filetype != APR_REG) {
-        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOTPLAIN, arg);
-        response = FTP_REPLY_FILE_NOT_FOUND;
+    /*
+     * If we are sending a ASCII file, we need to run the CRLF filter.
+     * Running the CRLF filter will result in a bunch of buckets, so we
+     * should also add the COALESCE filter to put everything back into a
+     * single bucket.
+     */
+    if (fc->type == TYPE_A) {
+        fc->filter_mask += FTP_NEED_CRLF;
     }
-    else {
+
+    rr = ap_sub_req_method_uri("HEAD", rfile, r, NULL);
+
+    if (rr->status != HTTP_OK) {
         /*
-         * XXX: big bug - going back to the beginning.  We must compute size
-         * rather than stating the file... this could be done trivially with
-         * a request to a null 'data' port which simply counts up the bytes.
-         * Will be implemented as a special-case of the ftp_core_data
-         * connection endpoint-filter.
-         * See RFC3659 - especially with respect to TYPE A/I
+         * Should never get here since we have already run this subrequest,
+         * but better safe than sorry
          */
-        fc->response_notes = apr_psprintf(r->pool, "%" APR_OFF_T_FMT,
-                                          rr->finfo.size);
-        response = FTP_REPLY_FILE_STATUS;
+        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
+                                 ftp_escape_control_text(rfile, r->pool));
+        res = FTP_REPLY_FILE_NOT_FOUND;
+        goto clean_up;
     }
 
+    /*
+     * Filter manipulation.  We remove the subrequest filter so that the EOS
+     * buckets stay intact.  We also add the content length filter so that
+     * we can record the bytes_sent
+     */
+    for (f = rr->output_filters; f; f = f->next) {
+        if (strcasecmp(f->frec->name, "SUBREQ_CORE") == 0) {
+            ap_remove_output_filter(f);
+        }
+    }
+
+    /* Need content length rr->bytes_sent */
+    ap_add_output_filter_handle(ftp_content_length_filter_handle, NULL,
+                                rr, rr->connection);
+
+    rr->header_only = 1;
+    rr->assbackwards = 0;
+
+    if ((res = ap_run_sub_req(rr)) != OK) {
+        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE,
+                                 ftp_escape_control_text(arg, r->pool));
+        res = FTP_REPLY_FILE_NOT_FOUND;
+    }
+
+clean_up:
+    size = rr->clength;
     ap_destroy_sub_req(rr);
-    return response;
+
+    /* Replace the filters and connection */
+    r->input_filters = rinput;
+    r->proto_input_filters = rinput_proto;
+    r->output_filters = routput;
+    r->proto_output_filters = routput_proto;
+
+    fc->filter_mask = 0;
+
+    if (res == FTP_REPLY_FILE_STATUS)
+        fc->response_notes = apr_psprintf(r->pool, "%" APR_OFF_T_FMT, size);
+    return res;
 }
 
 static int ftp_get_client_block(conn_rec *c, ap_input_mode_t mode,
@@ -2505,7 +2575,8 @@
 
     if ((rr->status == HTTP_UNAUTHORIZED) || (rr->status == HTTP_FORBIDDEN)) {
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          r->parsed_uri.path);
+                                 ftp_escape_control_text(r->parsed_uri.path,
+                                                         r->pool));
         ap_destroy_sub_req(rr);
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -2553,7 +2624,7 @@
         char error_str[120];
         char *err = apr_strerror(rv, error_str, sizeof(error_str));
         fc->response_notes = apr_psprintf(r->pool, FTP_MSG_PERM_DENIED,
-                                          err);
+                                 ftp_escape_control_text(err, r->pool));
         fc->restart_point = 0;
         return FTP_REPLY_FILE_NOT_FOUND;
     }
@@ -2660,11 +2731,9 @@
         if (rv != APR_SUCCESS) {
             char error_str[120];
             char *err = apr_strerror(rv, error_str, sizeof(error_str));
-            fc->response_notes = apr_pstrdup(r->pool, err);
-
             ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
                          "Error writing uploaded file");
-
+            fc->response_notes = ftp_escape_control_text(err, r->pool);
             status = FTP_REPLY_LOCAL_ERROR;
             break;
         }
@@ -2739,11 +2808,13 @@
     if (*arg && !arg[1]) {
         switch (toupper(*arg)) {
         case 'F':
-            fc->response_notes = apr_pstrdup(r->pool, "Structure set to F");
+            fc->response_notes = "Structure set to F";
             return FTP_REPLY_COMMAND_OK;
         }
     }
-    fc->response_notes = apr_pstrcat(r->pool, "Structure ", arg, " not implemented",
NULL);
+    fc->response_notes = apr_pstrcat(r->pool, "Structure %s not implemented",
+                             ftp_escape_control_text(arg, r->pool));
+
     return FTP_REPLY_COMMAND_NOT_IMPL_PARAM;
 }
 
@@ -2765,7 +2836,7 @@
             return FTP_REPLY_COMMAND_OK;
         case 'I':
             fc->type = TYPE_I;
-            fc->response_notes = "Type set to I.";
+            fc->response_notes = "Type set to I";
             return FTP_REPLY_COMMAND_OK;
         }
     }
@@ -2774,7 +2845,7 @@
          * Accept Ascii Non-Print
          */
         fc->type = TYPE_A;
-        fc->response_notes = apr_pstrdup(r->pool, "Type set to A N.");
+        fc->response_notes = "Type set to A N";
         return FTP_REPLY_COMMAND_OK;
     }
     else if (!strcasecmp(arg, "L 8")) {
@@ -2782,11 +2853,13 @@
          * Treat Local 8 as indistinguishible from Image for httpd platforms
          */
         fc->type = TYPE_I;
-        fc->response_notes = apr_pstrdup(r->pool, "Type set to L 8.");
+        fc->response_notes = "Type set to L 8";
         return FTP_REPLY_COMMAND_OK;
     }
 
-    fc->response_notes = apr_pstrcat(r->pool, "Type ", arg, " not implemented", NULL);
+    fc->response_notes = apr_pstrcat(r->pool, "Type %s not implemented",
+                                 ftp_escape_control_text(arg, r->pool));
+
     return FTP_REPLY_COMMAND_NOT_IMPL_PARAM;
 }
 
@@ -2877,7 +2950,7 @@
     }
     else {
         fc->response_notes = apr_psprintf(r->pool, "Password required for %s",
-                                          fc->user);
+                                 ftp_escape_control_text(fc->user, r->pool));
     }
 
     return FTP_REPLY_USER_OK;

Modified: httpd/mod_ftp/trunk/modules/ftp/mod_ftp_example.c
URL: http://svn.apache.org/viewvc/httpd/mod_ftp/trunk/modules/ftp/mod_ftp_example.c?rev=805083&r1=805082&r2=805083&view=diff
==============================================================================
--- httpd/mod_ftp/trunk/modules/ftp/mod_ftp_example.c (original)
+++ httpd/mod_ftp/trunk/modules/ftp/mod_ftp_example.c Mon Aug 17 18:17:28 2009
@@ -59,7 +59,7 @@
     }
     else /* !strncasecmp(arg, "ECHO", 4) */
     {
-        fc->response_notes = arg + 4;
+        fc->response_notes = ftp_escape_control_text(arg + 4, r->pool);
     }
     return FTP_REPLY_COMMAND_OK;
 }



Mime
View raw message