diff options
Diffstat (limited to 'server/request.c')
-rw-r--r-- | server/request.c | 149 |
1 files changed, 105 insertions, 44 deletions
diff --git a/server/request.c b/server/request.c index dbe3e07..5599b2c 100644 --- a/server/request.c +++ b/server/request.c @@ -59,6 +59,7 @@ #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX APR_HOOK_STRUCT( + APR_HOOK_LINK(pre_translate_name) APR_HOOK_LINK(translate_name) APR_HOOK_LINK(map_to_storage) APR_HOOK_LINK(check_user_id) @@ -74,6 +75,8 @@ APR_HOOK_STRUCT( APR_HOOK_LINK(force_authn) ) +AP_IMPLEMENT_HOOK_RUN_FIRST(int,pre_translate_name, + (request_rec *r), (r), DECLINED) AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name, (request_rec *r), (r), DECLINED) AP_IMPLEMENT_HOOK_RUN_FIRST(int,map_to_storage, @@ -157,6 +160,25 @@ AP_DECLARE(int) ap_some_authn_required(request_rec *r) return rv; } +static int walk_location_and_if(request_rec *r) +{ + int access_status; + core_dir_config *d; + + if ((access_status = ap_location_walk(r))) { + return access_status; + } + if ((access_status = ap_if_walk(r))) { + return access_status; + } + + d = ap_get_core_module_config(r->per_dir_config); + if (d->log) + r->log = d->log; + + return OK; +} + /* This is the master logic for processing requests. Do NOT duplicate * this logic elsewhere, or the security model will be broken by future * API changes. Each phase must be individually optimized to pick up @@ -164,51 +186,95 @@ AP_DECLARE(int) ap_some_authn_required(request_rec *r) */ AP_DECLARE(int) ap_process_request_internal(request_rec *r) { + int access_status = DECLINED; int file_req = (r->main && r->filename); - int access_status; - core_dir_config *d; + core_server_config *sconf = + ap_get_core_module_config(r->server->module_config); + unsigned int normalize_flags; + + normalize_flags = AP_NORMALIZE_NOT_ABOVE_ROOT; + if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) { + normalize_flags |= AP_NORMALIZE_MERGE_SLASHES; + } + if (file_req) { + /* File subrequests can have a relative path. */ + normalize_flags |= AP_NORMALIZE_ALLOW_RELATIVE; + } - /* Ignore embedded %2F's in path for proxy requests */ - if (!r->proxyreq && r->parsed_uri.path) { - d = ap_get_core_module_config(r->per_dir_config); - if (d->allow_encoded_slashes) { - access_status = ap_unescape_url_keep2f(r->parsed_uri.path, d->decode_encoded_slashes); + if (r->parsed_uri.path) { + /* Normalize: remove /./ and shrink /../ segments, plus + * decode unreserved chars (first time only to avoid + * double decoding after ap_unescape_url() below). + */ + if (!ap_normalize_path(r->parsed_uri.path, + normalize_flags | + AP_NORMALIZE_DECODE_UNRESERVED)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10244) + "invalid URI path (%s)", r->unparsed_uri); + return HTTP_BAD_REQUEST; } - else { - access_status = ap_unescape_url(r->parsed_uri.path); + } + + /* All file subrequests are a huge pain... they cannot bubble through the + * next several steps. Only file subrequests are allowed an empty uri, + * otherwise let (pre_)translate_name kill the request. + */ + if (!file_req) { + ap_conf_vector_t *per_dir_config = r->per_dir_config; + + if ((access_status = walk_location_and_if(r))) { + return access_status; + } + + /* Let pre_translate_name hooks work with non-decoded URIs, and + * eventually prevent further URI transformations (return DONE). + */ + access_status = ap_run_pre_translate_name(r); + if (ap_is_HTTP_ERROR(access_status)) { + return access_status; + } + + /* Throw away pre_trans only merging */ + r->per_dir_config = per_dir_config; + } + + /* Ignore URL unescaping for translated URIs already */ + if (access_status != DONE && r->parsed_uri.path) { + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + /* Unreserved chars were already decoded by ap_normalize_path() */ + unsigned int unescape_flags = AP_UNESCAPE_URL_KEEP_UNRESERVED; + if (!d->allow_encoded_slashes) { + unescape_flags |= AP_UNESCAPE_URL_FORBID_SLASHES; + } + else if (!d->decode_encoded_slashes) { + unescape_flags |= AP_UNESCAPE_URL_KEEP_SLASHES; } + access_status = ap_unescape_url_ex(r->parsed_uri.path, unescape_flags); if (access_status) { if (access_status == HTTP_NOT_FOUND) { if (! d->allow_encoded_slashes) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00026) - "found %%2f (encoded '/') in URI " - "(decoded='%s'), returning 404", - r->parsed_uri.path); + "found %%2f (encoded '/') in URI path (%s), " + "returning 404", r->unparsed_uri); } } return access_status; } - } - ap_getparents(r->uri); /* OK --- shrinking transformations... */ + if (d->allow_encoded_slashes && d->decode_encoded_slashes) { + /* Decoding slashes might have created new // or /./ or /../ + * segments (e.g. "/.%2F/"), so re-normalize. + */ + ap_normalize_path(r->parsed_uri.path, normalize_flags); + } + } - /* All file subrequests are a huge pain... they cannot bubble through the - * next several steps. Only file subrequests are allowed an empty uri, - * otherwise let translate_name kill the request. - */ + /* Same, translate_name is not suited for file subrequests */ if (!file_req) { - if ((access_status = ap_location_walk(r))) { - return access_status; - } - if ((access_status = ap_if_walk(r))) { + if ((access_status = walk_location_and_if(r))) { return access_status; } - d = ap_get_core_module_config(r->per_dir_config); - if (d->log) { - r->log = d->log; - } - if ((access_status = ap_run_translate_name(r))) { return decl_die(access_status, "translate", r); } @@ -225,17 +291,9 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r) /* Rerun the location walk, which overrides any map_to_storage config. */ - if ((access_status = ap_location_walk(r))) { + if ((access_status = walk_location_and_if(r))) { return access_status; } - if ((access_status = ap_if_walk(r))) { - return access_status; - } - - d = ap_get_core_module_config(r->per_dir_config); - if (d->log) { - r->log = d->log; - } if ((access_status = ap_run_post_perdir_config(r))) { return access_status; @@ -1256,6 +1314,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) if (entry_core->refs && entry_core->refs->nelts) { if (!rxpool) { apr_pool_create(&rxpool, r->pool); + apr_pool_tag(rxpool, "directory_walk_rxpool"); } nmatch = entry_core->refs->nelts; pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); @@ -1361,7 +1420,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) r->canonical_filename = r->filename; if (r->finfo.filetype == APR_DIR) { - cache->cached = r->filename; + cache->cached = apr_pstrdup(r->pool, r->filename); } else { cache->cached = ap_make_dirstr_parent(r->pool, r->filename); @@ -1412,12 +1471,12 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) cache = prep_walk_cache(AP_NOTE_LOCATION_WALK, r); cached = (cache->cached != NULL); - /* Location and LocationMatch differ on their behaviour w.r.t. multiple - * slashes. Location matches multiple slashes with a single slash, - * LocationMatch doesn't. An exception, for backwards brokenness is - * absoluteURIs... in which case neither match multiple slashes. - */ - if (r->uri[0] != '/') { + /* + * When merge_slashes is set to AP_CORE_CONFIG_OFF the slashes in r->uri + * have not been merged. But for Location walks we always go with merged + * slashes no matter what merge_slashes is set to. + */ + if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) { entry_uri = r->uri; } else { @@ -1458,7 +1517,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) apr_pool_t *rxpool = NULL; cached &= auth_internal_per_conf; - cache->cached = entry_uri; + cache->cached = apr_pstrdup(r->pool, entry_uri); /* Go through the location entries, and check for matches. * We apply the directive sections in given order, we should @@ -1486,6 +1545,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) if (entry_core->refs && entry_core->refs->nelts) { if (!rxpool) { apr_pool_create(&rxpool, r->pool); + apr_pool_tag(rxpool, "location_walk_rxpool"); } nmatch = entry_core->refs->nelts; pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); @@ -1688,6 +1748,7 @@ AP_DECLARE(int) ap_file_walk(request_rec *r) if (entry_core->refs && entry_core->refs->nelts) { if (!rxpool) { apr_pool_create(&rxpool, r->pool); + apr_pool_tag(rxpool, "file_walk_rxpool"); } nmatch = entry_core->refs->nelts; pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); |