From f757daf1ea402ada222c16492c3720a15f86174d Mon Sep 17 00:00:00 2001 From: Martin Kraemer Date: Wed, 30 Jan 2002 22:41:59 +0000 Subject: [PATCH] Eliminate variables where unneeded; move ";type=" checking code to front; drop redundant log messages (covered by proxy_ftp_command()); do checks for /%2f as in apache-1.3.24; escape path argument in SIZE command git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@93120 13f79535-47bb-0310-9956-ffa450edef68 --- modules/proxy/proxy_ftp.c | 133 ++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 54 deletions(-) diff --git a/modules/proxy/proxy_ftp.c b/modules/proxy/proxy_ftp.c index 2f5d10c495..c05a544853 100644 --- a/modules/proxy/proxy_ftp.c +++ b/modules/proxy/proxy_ftp.c @@ -270,11 +270,8 @@ apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in) { request_rec *r = f->r; apr_pool_t *p = r->pool; - apr_bucket *e; apr_bucket_brigade *out = apr_brigade_create(p); apr_status_t rv; - regex_t *re = NULL; /* @@@ put this in the context */ - regmatch_t re_result[3]; register int n; char *dir, *path, *reldir, *site, *str, *type; @@ -291,9 +288,6 @@ apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in) ctx->state = HEADER; } - /* Compile the output format of "ls -s1" as a fallback for non-unix ftp listings */ - re = ap_pregcomp(p, "^ *([0-9]+) +([^ ]+)$", REG_EXTENDED); - /* combine the stored and the new */ APR_BRIGADE_CONCAT(ctx->in, in); @@ -354,8 +348,7 @@ apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in) site, basedir, ap_escape_uri(p, path), site, str); - e = apr_bucket_pool_create(str, strlen(str), p); - APR_BRIGADE_INSERT_TAIL(out, e); + APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p)); for (dir = path+1; (dir = strchr(dir, '/')) != NULL; ) { @@ -387,21 +380,18 @@ apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in) str = apr_psprintf(p, "\n\n(%s)\n\n
\n\n
",
                                ap_escape_html(p, pwd));
         }
-        e = apr_bucket_pool_create(str, strlen(str), p);
-        APR_BRIGADE_INSERT_TAIL(out, e);
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p));
 
         /* print README */
         if (readme) {
             str = apr_psprintf(p, "%s\n
\n\n
\n\n
\n",
                                ap_escape_html(p, readme));
 
-            e = apr_bucket_pool_create(str, strlen(str), p);
-            APR_BRIGADE_INSERT_TAIL(out, e);
+            APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p));
         }
 
         /* make sure page intro gets sent out */
-        e = apr_bucket_flush_create();
-        APR_BRIGADE_INSERT_TAIL(out, e);
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create());
         if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) {
             return rv;
         }
@@ -416,11 +406,19 @@ apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in)
         int found = 0;
         int eos = 0;
 
+        regex_t *re = NULL;
+        regmatch_t re_result[3];
+
+        /* Compile the output format of "ls -s1" as a fallback for non-unix ftp listings */
+        re = ap_pregcomp(p, "^ *([0-9]+) +([^ ]+)$", REG_EXTENDED);
+
         /* get a complete line */
         /* if the buffer overruns - throw data away */
         while (!found && !APR_BRIGADE_EMPTY(ctx->in)) {
             char *pos, *response;
             apr_size_t len, max;
+            apr_bucket *e;
+
             e = APR_BRIGADE_FIRST(ctx->in);
             if (APR_BUCKET_IS_EOS(e)) {
                 eos = 1;
@@ -544,10 +542,8 @@ apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in)
         /* erase buffer for next time around */
         ctx->buffer[0] = 0;
 
-        e = apr_bucket_pool_create(str, strlen(str), p);
-        APR_BRIGADE_INSERT_TAIL(out, e);
-        e = apr_bucket_flush_create();
-        APR_BRIGADE_INSERT_TAIL(out, e);
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p));
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create());
         if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) {
             return rv;
         }
@@ -557,15 +553,9 @@ apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in)
 
     if (FOOTER == ctx->state) {
         str = apr_psprintf(p, "
\n\n
\n\n %s\n\n \n\n", ap_psignature("", r)); - e = apr_bucket_pool_create(str, strlen(str), p); - APR_BRIGADE_INSERT_TAIL(out, e); - - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(out, e); - - e = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(out, e); - + APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p)); + APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create()); + APR_BRIGADE_INSERT_TAIL(out, apr_bucket_eos_create()); if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) { return rv; } @@ -809,6 +799,26 @@ int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, if (type_suffix != NULL) *(type_suffix++) = '\0'; + if (type_suffix != NULL && strncmp(type_suffix, "type=", 5) == 0 + && ap_isalpha(type_suffix[5])) { + /* "type=d" forces a dir listing. + * The other types (i|a|e) are directly used for the ftp TYPE command + */ + if ( ! (dirlisting = (ap_tolower(type_suffix[5]) == 'd'))) + xfer_type = ap_toupper(type_suffix[5]); + + /* Check valid types, rather than ignoring invalid types silently: */ + if (strchr("AEI", xfer_type) == NULL) + return ap_proxyerror(r, HTTP_BAD_REQUEST, ap_pstrcat(r->pool, + "ftp proxy supports only types 'a', 'i', or 'e': \"", + type_suffix, "\" is invalid.", NULL)); + } + else { + /* make binary transfers the default */ + xfer_type = 'I'; + } + + /* * The "Authorization:" header must be checked first. We allow the user * to "override" the URL-coded user [ & password ] in the Browsers' @@ -1018,7 +1028,8 @@ int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, /* Look for a number, preceded by whitespace */ while (*secs_str) - if (apr_isspace(secs_str[-1]) && apr_isdigit(secs_str[0])) + if ((secs_str==ftpmessage || apr_isspace(secs_str[-1])) && + apr_isdigit(secs_str[0])) break; if (*secs_str != '\0') { secs = atol(secs_str); @@ -1031,8 +1042,6 @@ int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, return ap_proxyerror(r, HTTP_BAD_GATEWAY, ftpmessage); } - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "proxy: FTP: connected."); rc = proxy_ftp_command(apr_pstrcat(p, "USER ", user, CRLF, NULL), r, origin, bb, &ftpmessage); @@ -1091,6 +1100,21 @@ int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, } apr_table_set(r->notes, "Directory-README", ftpmessage); + + /* Special handling for leading "%2f": this enforces a "cwd /" + * out of the $HOME directory which was the starting point after login + */ + if (strncasecmp(path, "%2f", 3) == 0) { + path += 3; + while (*path == '/') /* skip leading '/' (after root %2f) */ + ++path; + + rc = proxy_ftp_command("CWD /" CRLF, r, origin, bb, &ftpmessage); + if (rc == -1 || rc == 421) + return ap_proxyerror(r, HTTP_BAD_GATEWAY, + "Error reading from remote server"); + } + /* * set the directory (walk directory component by component): this is * what we must do if we don't know the OS type of the remote machine @@ -1101,7 +1125,12 @@ int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, break; *strp = '\0'; - len = decodeenc(path); + len = decodeenc(path); /* Note! This decodes a %2f -> "/" */ + + if (strchr(path, '/')) { /* are there now any '/' characters? */ + return ap_proxyerror(r, HTTP_BAD_REQUEST, + "Use of /%2f is only allowed at the base directory"); + } /* NOTE: FTP servers do globbing on the path. * So we need to escape the URI metacharacters. @@ -1135,26 +1164,6 @@ int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, path = strp + 1; } - if (type_suffix != NULL && strncmp(type_suffix, "type=", 5) == 0 - && ap_isalpha(type_suffix[5])) { - /* "type=d" forces a dir listing. - * The other types (i|a|e) are directly used for the ftp TYPE command - */ - if ( ! (dirlisting = (ap_tolower(type_suffix[5]) == 'd'))) - xfer_type = ap_toupper(type_suffix[5]); - - /* Check valid types, rather than ignoring invalid types silently: */ - if (strchr("AEI", xfer_type) == NULL) - return ap_proxyerror(r, HTTP_BAD_REQUEST, ap_pstrcat(r->pool, - "ftp proxy supports only types 'a', 'i', or 'e': \"", - type_suffix, "\" is invalid.", NULL)); - } - else { - /* make binary transfers the default */ - xfer_type = 'I'; - } - - /* * IV: Make Data Connection? ------------------------- * @@ -1425,6 +1434,11 @@ int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, /* set request; "path" holds last path component */ len = decodeenc(path); + if (strchr(path, '/')) { /* are there now any '/' characters? */ + return ap_proxyerror(r, HTTP_BAD_REQUEST, + "Use of /%2f is only allowed at the base directory"); + } + /* If len == 0 then it must be a directory (you can't RETR nothing) * Also, don't allow to RETR by wildcard. Instead, create a dirlisting */ @@ -1432,7 +1446,15 @@ int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, dirlisting = 1; } else { - rc = proxy_ftp_command(apr_pstrcat(p, "SIZE ", path, CRLF, NULL), + /* (from FreeBSD ftpd): + * SIZE is not in RFC959, but Postel has blessed it and + * it will be in the updated RFC. + * + * Return size of file in a format suitable for + * using with RESTART (we just count bytes). + */ + rc = proxy_ftp_command(apr_pstrcat(p, "SIZE ", + ap_escape_shell_cmd(p, path), CRLF, NULL), r, origin, bb, &ftpmessage); if (rc == -1 || rc == 421) { return ap_proxyerror(r, HTTP_BAD_GATEWAY, @@ -1500,6 +1522,11 @@ int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, else { /* switch to binary if the user did not specify ";type=a" */ ftp_set_TYPE(xfer_type, r, origin, bb, &ftpmessage); +/* FIXME: we might as well do: + rc = proxy_ftp_command(apr_pstrcat(p, "MDTM ", ap_escape_shell_cmd(p, path), CRLF, NULL), + r, origin, bb, &ftpmessage); + and extract the Last-Modified time from it (YYYYMMDDhhmmss or YYYYMMDDhhmmss.xxx GMT). +*/ /* FIXME: Handle range requests - send REST */ buf = apr_pstrcat(p, "RETR ", ap_escape_shell_cmd(p, path), CRLF, NULL); } @@ -1698,8 +1725,6 @@ int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, /* Retrieve the final response for the RETR or LIST commands */ rc = proxy_ftp_command(NULL, r, origin, bb, &ftpmessage); apr_brigade_cleanup(bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "proxy: FTP: end body send"); /* * VII: Clean Up ------------- -- 2.40.0