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:17:28 UTC
svn commit: r805083 - in /httpd/mod_ftp/trunk/modules/ftp: ftp_commands.c
mod_ftp_example.c
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;
}