okey, here is the patch. i have been unable to detect any security flaws in my testing. please apply and test this as fixing the existing issue in a 'good enough' way until a rework/redesign of the filesystem intertwingling is addressed.
in addition to 2.1 (where it might become obviated by a better solution), i would like to put this into 2.0 and possibly 1.3. and, if it doesn't open any security exposures, i don't see why that shouldn't happen. Index: include/ap_mmn.h =================================================================== RCS file: /home/cvs/httpd-2.0/include/ap_mmn.h,v retrieving revision 1.52 diff -u -r1.52 ap_mmn.h --- include/ap_mmn.h 3 Sep 2002 23:39:43 -0000 1.52 +++ include/ap_mmn.h 14 Jan 2003 16:49:53 -0000 @@ -111,6 +111,7 @@ * 20020625 (2.0.40-dev) Changed conn_rec->keepalive to an enumeration * 20020628 (2.0.40-dev) Added filter_init to filter registration functions * 20020903 (2.0.41-dev) APR's error constants changed + * 20020903.1 (2.0.44-dev) allow_encoded_slashes added to core_dir_config */ #define MODULE_MAGIC_COOKIE 0x41503230UL /* "AP20" */ @@ -118,7 +119,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20020903 #endif -#define MODULE_MAGIC_NUMBER_MINOR 0 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 1 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a Index: include/http_core.h =================================================================== RCS file: /home/cvs/httpd-2.0/include/http_core.h,v retrieving revision 1.71 diff -u -r1.71 http_core.h --- include/http_core.h 15 Dec 2002 20:05:23 -0000 1.71 +++ include/http_core.h 14 Jan 2003 16:49:53 -0000 @@ -539,7 +539,8 @@ #define ENABLE_SENDFILE_ON (1) #define ENABLE_SENDFILE_UNSET (2) unsigned int enable_sendfile : 2; /* files in this dir can be mmap'ed */ - + unsigned int allow_encoded_slashes : 1; /* URLs may contain %2f w/o being + * pitched indiscriminately */ } core_dir_config; /* Per-server core configuration */ Index: include/httpd.h =================================================================== RCS file: /home/cvs/httpd-2.0/include/httpd.h,v retrieving revision 1.191 diff -u -r1.191 httpd.h --- include/httpd.h 8 Nov 2002 17:19:10 -0000 1.191 +++ include/httpd.h 14 Jan 2003 16:49:53 -0000 @@ -1314,10 +1314,16 @@ /** * Unescape a URL - * @param url The url to unescapte + * @param url The url to unescape * @return 0 on success, non-zero otherwise */ AP_DECLARE(int) ap_unescape_url(char *url); +/** + * Unescape a URL, but leaving %2f (slashes) escaped + * @param url The url to unescape + * @return 0 on success, non-zero otherwise + */ +AP_DECLARE(int) ap_unescape_url_keep2f(char *url); /** * Convert all double slashes to single slashes * @param name The string to convert Index: server/core.c =================================================================== RCS file: /home/cvs/httpd-2.0/server/core.c,v retrieving revision 1.227 diff -u -r1.227 core.c --- server/core.c 14 Jan 2003 03:01:51 -0000 1.227 +++ server/core.c 14 Jan 2003 16:49:54 -0000 @@ -182,6 +182,7 @@ conf->enable_mmap = ENABLE_MMAP_UNSET; conf->enable_sendfile = ENABLE_SENDFILE_UNSET; + conf->allow_encoded_slashes = 0; return (void *)conf; } @@ -452,6 +453,8 @@ conf->enable_sendfile = new->enable_sendfile; } + conf->allow_encoded_slashes = new->allow_encoded_slashes; + return (void*)conf; } @@ -2087,6 +2090,19 @@ return NULL; } +static const char *set_allow2f(cmd_parms *cmd, void *d_, int arg) +{ + core_dir_config *d = d_; + const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); + + if (err != NULL) { + return err; + } + + d->allow_encoded_slashes = arg != 0; + return NULL; +} + static const char *set_hostname_lookups(cmd_parms *cmd, void *d_, const char *arg) { @@ -3080,6 +3096,8 @@ AP_INIT_ITERATE2("AddOutputFilterByType", add_ct_output_filters, (void *)APR_OFFSETOF(core_dir_config, ct_output_filters), OR_FILEINFO, "output filter name followed by one or more content-types"), +AP_INIT_FLAG("AllowEncodedSlashes", set_allow2f, NULL, RSRC_CONF, + "Allow URLs containing '/' encoded as '%2F'"), /* * These are default configuration directives that mpms can/should Index: server/request.c =================================================================== RCS file: /home/cvs/httpd-2.0/server/request.c,v retrieving revision 1.122 diff -u -r1.122 request.c --- server/request.c 12 Dec 2002 07:05:54 -0000 1.122 +++ server/request.c 14 Jan 2003 16:49:54 -0000 @@ -147,13 +147,22 @@ /* Ignore embedded %2F's in path for proxy requests */ if (!r->proxyreq && r->parsed_uri.path) { - access_status = ap_unescape_url(r->parsed_uri.path); + core_dir_config *d; + d = ap_get_module_config(r->per_dir_config, &core_module); + if (d->allow_encoded_slashes) { + access_status = ap_unescape_url_keep2f(r->parsed_uri.path); + } + else { + access_status = ap_unescape_url(r->parsed_uri.path); + } if (access_status) { if (access_status == HTTP_NOT_FOUND) { - ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, - "found %%2f (encoded '/') in URI " - "(decoded='%s'), returning 404", - r->parsed_uri.path); + if (! d->allow_encoded_slashes) { + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, + "found %%2f (encoded '/') in URI " + "(decoded='%s'), returning 404", + r->parsed_uri.path); + } } return access_status; } Index: server/util.c =================================================================== RCS file: /home/cvs/httpd-2.0/server/util.c,v retrieving revision 1.134 diff -u -r1.134 util.c --- server/util.c 8 Dec 2002 21:05:57 -0000 1.134 +++ server/util.c 14 Jan 2003 16:49:54 -0000 @@ -1595,6 +1595,57 @@ return OK; } +AP_DECLARE(int) ap_unescape_url_keep2f(char *url) +{ + register int badesc, badpath; + char *x, *y; + + badesc = 0; + badpath = 0; + /* Initial scan for first '%'. Don't bother writing values before + * seeing a '%' */ + y = strchr(url, '%'); + if (y == NULL) { + return OK; + } + for (x = y; *y; ++x, ++y) { + if (*y != '%') { + *x = *y; + } + else { + if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) { + badesc = 1; + *x = '%'; + } + else { + char decoded; + decoded = x2c(y + 1); + if (IS_SLASH(decoded)) { + *x++ = *y++; + *x = *y; + } + else { + *x = decoded; + y += 2; + if (decoded == '\0') { + badpath = 1; + } + } + } + } + } + *x = '\0'; + if (badesc) { + return HTTP_BAD_REQUEST; + } + else if (badpath) { + return HTTP_NOT_FOUND; + } + else { + return OK; + } +} + AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname, apr_port_t port, const request_rec *r) { -- #ken P-)} Ken Coar, Sanagendamgagwedweinini http://Golux.Com/coar/ Author, developer, opinionist http://Apache-Server.Com/ "Millennium hand and shrimp!"