From c8ba67fb8353858e536fd40cd9ea314a9dc54da2 Mon Sep 17 00:00:00 2001 From: Chris Darroch Date: Thu, 3 Apr 2008 21:51:07 +0000 Subject: [PATCH] Avoid calling access control hooks for internal requests with configurations which match those of the initial request. Revert to the original behaviour (call access control hooks for internal requests with URIs different from the initial request) if any access control hooks or providers are not registered as permitting this optimization. Introduce wrappers for access control hook and provider registration which can accept additional mode and flag data. The configuration walk optimizations were originally proposed a while ago (see http://marc.info/?l=apache-httpd-dev&m=116536713506234&w=2); they have been used since then in production systems and appear to be stable and effective. They permit certain combinations of modules and clients to function efficiently, especially when a deeply recursive series of internal requests, such as those generated by certain WebDAV requests, are all subject to the identical authentication and authorization directives. The major change from the original proposal is a cleaner mechanism for detecting modules which may expect the old behaviour. This has been tested successfully with Subversion's mod_authz_svn, which specifically requires the old behaviour when performing path-based authorization based against its own private access control configuration files. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@644525 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 8 + include/http_request.h | 142 ++++++++++++++- modules/aaa/mod_access_compat.c | 3 +- modules/aaa/mod_auth_basic.c | 3 +- modules/aaa/mod_auth_digest.c | 3 +- modules/aaa/mod_authn_anon.c | 4 +- modules/aaa/mod_authn_core.c | 11 +- modules/aaa/mod_authn_dbd.c | 4 +- modules/aaa/mod_authn_dbm.c | 4 +- modules/aaa/mod_authn_default.c | 3 +- modules/aaa/mod_authn_file.c | 4 +- modules/aaa/mod_authnz_ldap.c | 29 +-- modules/aaa/mod_authz_core.c | 14 +- modules/aaa/mod_authz_dbd.c | 15 +- modules/aaa/mod_authz_dbm.c | 10 +- modules/aaa/mod_authz_default.c | 3 +- modules/aaa/mod_authz_groupfile.c | 10 +- modules/aaa/mod_authz_host.c | 16 +- modules/aaa/mod_authz_owner.c | 5 +- modules/aaa/mod_authz_user.c | 9 +- modules/examples/mod_example_hooks.c | 61 ++++--- modules/ssl/mod_ssl.c | 9 +- server/core.c | 3 +- server/main.c | 2 + server/request.c | 261 ++++++++++++++++++++++----- 25 files changed, 495 insertions(+), 141 deletions(-) diff --git a/CHANGES b/CHANGES index 8bf9b084cf..516cf225b6 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,14 @@ Changes with Apache 2.3.0 [ When backported to 2.2.x, remove entry from this file ] + *) core, authn/z: Avoid calling access control hooks for internal requests + with configurations which match those of initial request. Revert to + original behaviour (call access control hooks for internal requests + with URIs different from initial request) if any access control hooks or + providers are not registered as permitting this optimization. + Introduce wrappers for access control hook and provider registration + which can accept additional mode and flag data. [Chris Darroch] + *) http_filters: Don't spin if get an error when reading the next chunk. PR 44381 [Ruediger Pluem] diff --git a/include/http_request.h b/include/http_request.h index edad37087e..ce491da76c 100644 --- a/include/http_request.h +++ b/include/http_request.h @@ -18,6 +18,12 @@ * @file http_request.h * @brief Apache Request library * + * @defgroup APACHE_CORE_REQ Apache Request Processing + * @ingroup APACHE_CORE + * @{ + */ + +/* * request.c is the code which handles the main line of request * processing, once a request has been read in (finding the right per- * directory configuration, building it if necessary, and calling all @@ -42,6 +48,7 @@ #define APACHE_HTTP_REQUEST_H #include "apr_hooks.h" +#include "apr_optional.h" #include "util_filter.h" #ifdef __cplusplus @@ -181,7 +188,73 @@ AP_DECLARE(void) ap_internal_fast_redirect(request_rec *sub_req, request_rec *r) * @return 1 if authentication is required, 0 otherwise */ AP_DECLARE(int) ap_some_auth_required(request_rec *r); - + +/** + * @defgroup APACHE_CORE_REQ_AUTH Access Control for Sub-Requests and + * Internal Redirects + * @ingroup APACHE_CORE_REQ + * @{ + */ + +#define AP_AUTH_INTERNAL_PER_URI 0 /**< Run access control hooks on all + internal requests with URIs + distinct from that of initial + request */ +#define AP_AUTH_INTERNAL_PER_CONF 1 /**< Run access control hooks only on + internal requests with + configurations distinct from + that of initial request */ +#define AP_AUTH_INTERNAL_MASK 0x000F /**< mask to extract internal request + processing mode */ + +/** + * Clear flag which determines when access control hooks will be run for + * internal requests. + */ +AP_DECLARE(void) ap_clear_auth_internal(); + +/** + * Determine whether access control hooks will be run for all internal + * requests with URIs distinct from that of the initial request, or only + * those for which different configurations apply than those which applied + * to the initial request. To accomodate legacy external modules which + * may expect access control hooks to be run for all internal requests + * with distinct URIs, this is the default behaviour unless all access + * control hooks and authentication and authorization providers are + * registered with AP_AUTH_INTERNAL_PER_CONF. + * @param ptemp Pool used for temporary allocations + */ +AP_DECLARE(void) ap_setup_auth_internal(apr_pool_t *ptemp); + +/** + * Register an authentication or authorization provider with the global + * provider pool. + * @param pool The pool to create any storage from + * @param provider_group The group to store the provider in + * @param provider_name The name for this provider + * @param provider_version The version for this provider + * @param provider Opaque structure for this provider + * @param type Internal request processing mode, either + * AP_AUTH_INTERNAL_PER_URI or AP_AUTH_INTERNAL_PER_CONF + * @return APR_SUCCESS if all went well + */ +AP_DECLARE(apr_status_t) ap_register_auth_provider(apr_pool_t *pool, + const char *provider_group, + const char *provider_name, + const char *provider_version, + const void *provider, + int type); + +/** @} */ + +/* Optional functions coming from mod_authn_core and mod_authz_core + * that list all registered authn/z providers. + */ +APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, authn_ap_list_provider_names, + (apr_pool_t *ptemp)); +APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, authz_ap_list_provider_names, + (apr_pool_t *ptemp)); + /** * Determine if the current request is the main request or a subrequest * @param r The current request @@ -300,11 +373,13 @@ AP_DECLARE_HOOK(int,map_to_storage,(request_rec *r)) * r->ap_auth_type). This hook is only run when Apache determines that * authentication/authorization is required for this resource (as determined * by the 'Require' directive). It runs after the access_checker hook, and - * before the auth_checker hook. + * before the auth_checker hook. This hook should be registered with + * ap_hook_check_authn(). * * @param r The current request * @return OK, DECLINED, or HTTP_... * @ingroup hooks + * @see ap_hook_check_authn */ AP_DECLARE_HOOK(int,check_user_id,(request_rec *r)) @@ -331,11 +406,13 @@ AP_DECLARE_HOOK(int,type_checker,(request_rec *r)) * This hook is used to apply additional access control to this resource. * It runs *before* a user is authenticated, so this hook is really to * apply additional restrictions independent of a user. It also runs - * independent of 'Require' directive usage. + * independent of 'Require' directive usage. This hook should be registered + * with ap_hook_check_access(). * * @param r the current request * @return OK, DECLINED, or HTTP_... * @ingroup hooks + * @see ap_hook_check_access */ AP_DECLARE_HOOK(int,access_checker,(request_rec *r)) @@ -344,14 +421,70 @@ AP_DECLARE_HOOK(int,access_checker,(request_rec *r)) * is available for the authenticated user (r->user and r->ap_auth_type). * It runs after the access_checker and check_user_id hooks. Note that * it will *only* be called if Apache determines that access control has - * been applied to this resource (through a 'Require' directive). + * been applied to this resource (through a 'Require' directive). This + * hook should be registered with ap_hook_check_authz(). * * @param r the current request * @return OK, DECLINED, or HTTP_... * @ingroup hooks + * @see ap_hook_check_authz */ AP_DECLARE_HOOK(int,auth_checker,(request_rec *r)) +/** + * Register a hook function that will apply additional access control to + * the current request. + * @param pf An access_checker hook function + * @param aszPre A NULL-terminated array of strings that name modules whose + * hooks should precede this one + * @param aszSucc A NULL-terminated array of strings that name modules whose + * hooks should succeed this one + * @param nOrder An integer determining order before honouring aszPre and + * aszSucc (for example, HOOK_MIDDLE) + * @param type Internal request processing mode, either + * AP_AUTH_INTERNAL_PER_URI or AP_AUTH_INTERNAL_PER_CONF + */ +AP_DECLARE(void) ap_hook_check_access(ap_HOOK_access_checker_t *pf, + const char * const *aszPre, + const char * const *aszSucc, + int nOrder, int type); + +/** + * Register a hook function that will analyze the request headers, + * authenticate the user, and set the user information in the request record. + * @param pf A check_user_id hook function + * @param aszPre A NULL-terminated array of strings that name modules whose + * hooks should precede this one + * @param aszSucc A NULL-terminated array of strings that name modules whose + * hooks should succeed this one + * @param nOrder An integer determining order before honouring aszPre and + * aszSucc (for example, HOOK_MIDDLE) + * @param type Internal request processing mode, either + * AP_AUTH_INTERNAL_PER_URI or AP_AUTH_INTERNAL_PER_CONF + */ +AP_DECLARE(void) ap_hook_check_authn(ap_HOOK_check_user_id_t *pf, + const char * const *aszPre, + const char * const *aszSucc, + int nOrder, int type); + +/** + * Register a hook function that determine if the resource being requested + * is available for the currently authenticated user. + * @param pf An auth_checker hook function + * @param aszPre A NULL-terminated array of strings that name modules whose + * hooks should precede this one + * @param aszSucc A NULL-terminated array of strings that name modules whose + * hooks should succeed this one + * @param nOrder An integer determining order before honouring aszPre and + * aszSucc (for example, HOOK_MIDDLE) + * @param type Internal request processing mode, either + * AP_AUTH_INTERNAL_PER_URI or AP_AUTH_INTERNAL_PER_CONF + */ +AP_DECLARE(void) ap_hook_check_authz(ap_HOOK_auth_checker_t *pf, + const char * const *aszPre, + const char * const *aszSucc, + int nOrder, int type); + /** * This hook allows modules to insert filters for the current request * @param r the current request @@ -398,3 +531,4 @@ AP_DECLARE(apr_bucket *) ap_bucket_eor_create(apr_bucket_alloc_t *list, #endif #endif /* !APACHE_HTTP_REQUEST_H */ +/** @} */ diff --git a/modules/aaa/mod_access_compat.c b/modules/aaa/mod_access_compat.c index b93e9fcac9..bd56c8ed2c 100644 --- a/modules/aaa/mod_access_compat.c +++ b/modules/aaa/mod_access_compat.c @@ -364,7 +364,8 @@ static void register_hooks(apr_pool_t *p) APR_REGISTER_OPTIONAL_FN(access_compat_ap_satisfies); /* This can be access checker since we don't require r->user to be set. */ - ap_hook_access_checker(check_dir_access,NULL,NULL,APR_HOOK_MIDDLE); + ap_hook_check_access(check_dir_access, NULL, NULL, APR_HOOK_MIDDLE, + AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA access_compat_module = diff --git a/modules/aaa/mod_auth_basic.c b/modules/aaa/mod_auth_basic.c index 4ae1c4665c..628e7a2dd4 100644 --- a/modules/aaa/mod_auth_basic.c +++ b/modules/aaa/mod_auth_basic.c @@ -286,7 +286,8 @@ static int authenticate_basic_user(request_rec *r) static void register_hooks(apr_pool_t *p) { - ap_hook_check_user_id(authenticate_basic_user,NULL,NULL,APR_HOOK_MIDDLE); + ap_hook_check_authn(authenticate_basic_user, NULL, NULL, APR_HOOK_MIDDLE, + AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA auth_basic_module = diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c index fc2b684cca..ad2e0e9159 100644 --- a/modules/aaa/mod_auth_digest.c +++ b/modules/aaa/mod_auth_digest.c @@ -1970,7 +1970,8 @@ static void register_hooks(apr_pool_t *p) ap_hook_post_config(initialize_module, NULL, cfgPost, APR_HOOK_MIDDLE); ap_hook_child_init(initialize_child, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_post_read_request(parse_hdr_and_update_nc, parsePre, NULL, APR_HOOK_MIDDLE); - ap_hook_check_user_id(authenticate_digest_user, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_check_authn(authenticate_digest_user, NULL, NULL, APR_HOOK_MIDDLE, + AP_AUTH_INTERNAL_PER_CONF); ap_hook_fixups(add_auth_info, NULL, NULL, APR_HOOK_MIDDLE); } diff --git a/modules/aaa/mod_authn_anon.c b/modules/aaa/mod_authn_anon.c index 07f48b35b3..ce8510f605 100644 --- a/modules/aaa/mod_authn_anon.c +++ b/modules/aaa/mod_authn_anon.c @@ -198,8 +198,8 @@ static const authn_provider authn_anon_provider = static void register_hooks(apr_pool_t *p) { - ap_register_provider(p, AUTHN_PROVIDER_GROUP, "anon", "0", - &authn_anon_provider); + ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "anon", "0", + &authn_anon_provider, AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authn_anon_module = diff --git a/modules/aaa/mod_authn_core.c b/modules/aaa/mod_authn_core.c index e421e1375d..66e204e0d0 100644 --- a/modules/aaa/mod_authn_core.c +++ b/modules/aaa/mod_authn_core.c @@ -253,8 +253,9 @@ static const char *authaliassection(cmd_parms *cmd, void *mconfig, const char *a apr_hash_set(authcfg->alias_rec, provider_alias, APR_HASH_KEY_STRING, prvdraliasrec); /* Register the fake provider so that we get called first */ - ap_register_provider(cmd->pool, AUTHN_PROVIDER_GROUP, provider_alias, "0", - &authn_alias_provider); + ap_register_auth_provider(cmd->pool, AUTHN_PROVIDER_GROUP, + provider_alias, "0", &authn_alias_provider, + AP_AUTH_INTERNAL_PER_CONF); } cmd->override = old_overrides; @@ -296,6 +297,11 @@ static const char *authn_ap_auth_name(request_rec *r) return apr_pstrdup(r->pool, conf->ap_auth_name); } +static apr_array_header_t *authn_ap_list_provider_names(apr_pool_t *ptemp) +{ + return ap_list_provider_names(ptemp, AUTHN_PROVIDER_GROUP, "0"); +} + static const command_rec authn_cmds[] = { AP_INIT_TAKE1("AuthType", ap_set_string_slot, @@ -313,6 +319,7 @@ static void register_hooks(apr_pool_t *p) { APR_REGISTER_OPTIONAL_FN(authn_ap_auth_type); APR_REGISTER_OPTIONAL_FN(authn_ap_auth_name); + APR_REGISTER_OPTIONAL_FN(authn_ap_list_provider_names); } module AP_MODULE_DECLARE_DATA authn_core_module = diff --git a/modules/aaa/mod_authn_dbd.c b/modules/aaa/mod_authn_dbd.c index 3341171e67..47ce2aa49c 100644 --- a/modules/aaa/mod_authn_dbd.c +++ b/modules/aaa/mod_authn_dbd.c @@ -18,6 +18,7 @@ #include "httpd.h" #include "http_config.h" #include "http_log.h" +#include "http_request.h" #include "apr_lib.h" #include "apr_dbd.h" #include "mod_dbd.h" @@ -268,7 +269,8 @@ static void authn_dbd_hooks(apr_pool_t *p) &authn_dbd_realm }; - ap_register_provider(p, AUTHN_PROVIDER_GROUP, "dbd", "0", &authn_dbd_provider); + ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "dbd", "0", + &authn_dbd_provider, AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authn_dbd_module = { diff --git a/modules/aaa/mod_authn_dbm.c b/modules/aaa/mod_authn_dbm.c index 9221752fa2..abb8df482a 100644 --- a/modules/aaa/mod_authn_dbm.c +++ b/modules/aaa/mod_authn_dbm.c @@ -189,8 +189,8 @@ static const authn_provider authn_dbm_provider = static void register_hooks(apr_pool_t *p) { - ap_register_provider(p, AUTHN_PROVIDER_GROUP, "dbm", "0", - &authn_dbm_provider); + ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "dbm", "0", + &authn_dbm_provider, AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authn_dbm_module = diff --git a/modules/aaa/mod_authn_default.c b/modules/aaa/mod_authn_default.c index 46c78cd79a..0155c6e298 100644 --- a/modules/aaa/mod_authn_default.c +++ b/modules/aaa/mod_authn_default.c @@ -90,7 +90,8 @@ static int authenticate_no_user(request_rec *r) static void register_hooks(apr_pool_t *p) { - ap_hook_check_user_id(authenticate_no_user,NULL,NULL,APR_HOOK_LAST); + ap_hook_check_authn(authenticate_no_user, NULL, NULL, APR_HOOK_LAST, + AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authn_default_module = diff --git a/modules/aaa/mod_authn_file.c b/modules/aaa/mod_authn_file.c index 018733e1ea..2cab61ca90 100644 --- a/modules/aaa/mod_authn_file.c +++ b/modules/aaa/mod_authn_file.c @@ -163,8 +163,8 @@ static const authn_provider authn_file_provider = static void register_hooks(apr_pool_t *p) { - ap_register_provider(p, AUTHN_PROVIDER_GROUP, "file", "0", - &authn_file_provider); + ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "file", "0", + &authn_file_provider, AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authn_file_module = diff --git a/modules/aaa/mod_authnz_ldap.c b/modules/aaa/mod_authnz_ldap.c index 4034f5efb8..9c6ac6f600 100644 --- a/modules/aaa/mod_authnz_ldap.c +++ b/modules/aaa/mod_authnz_ldap.c @@ -1582,20 +1582,25 @@ static void ImportULDAPOptFn(void) static void register_hooks(apr_pool_t *p) { /* Register authn provider */ - ap_register_provider(p, AUTHN_PROVIDER_GROUP, "ldap", "0", - &authn_ldap_provider); + ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "ldap", "0", + &authn_ldap_provider, AP_AUTH_INTERNAL_PER_CONF); /* Register authz providers */ - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "ldap-user", "0", - &authz_ldapuser_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "ldap-group", "0", - &authz_ldapgroup_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "ldap-dn", "0", - &authz_ldapdn_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "ldap-attribute", "0", - &authz_ldapattribute_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "ldap-filter", "0", - &authz_ldapfilter_provider); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ldap-user", "0", + &authz_ldapuser_provider, + AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ldap-group", "0", + &authz_ldapgroup_provider, + AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ldap-dn", "0", + &authz_ldapdn_provider, + AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ldap-attribute", "0", + &authz_ldapattribute_provider, + AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ldap-filter", "0", + &authz_ldapfilter_provider, + AP_AUTH_INTERNAL_PER_CONF); ap_hook_post_config(authnz_ldap_post_config,NULL,NULL,APR_HOOK_MIDDLE); diff --git a/modules/aaa/mod_authz_core.c b/modules/aaa/mod_authz_core.c index 15557f4e4b..5b7c409861 100644 --- a/modules/aaa/mod_authz_core.c +++ b/modules/aaa/mod_authz_core.c @@ -483,8 +483,9 @@ static const char *authz_require_alias_section(cmd_parms *cmd, void *mconfig, APR_HASH_KEY_STRING, prvdraliasrec); /* Register the fake provider so that we get called first */ - ap_register_provider(cmd->pool, AUTHZ_PROVIDER_GROUP, provider_alias, "0", - &authz_alias_provider); + ap_register_auth_provider(cmd->pool, AUTHZ_PROVIDER_GROUP, + provider_alias, "0", &authz_alias_provider, + AP_AUTH_INTERNAL_PER_CONF); } cmd->override = old_overrides; @@ -802,11 +803,18 @@ static int authz_some_auth_required(request_rec *r) return req_authz; } +static apr_array_header_t *authz_ap_list_provider_names(apr_pool_t *ptemp) +{ + return ap_list_provider_names(ptemp, AUTHZ_PROVIDER_GROUP, "0"); +} + static void register_hooks(apr_pool_t *p) { APR_REGISTER_OPTIONAL_FN(authz_some_auth_required); + APR_REGISTER_OPTIONAL_FN(authz_ap_list_provider_names); - ap_hook_auth_checker(authorize_user, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_check_authz(authorize_user, NULL, NULL, APR_HOOK_MIDDLE, + AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authz_core_module = diff --git a/modules/aaa/mod_authz_dbd.c b/modules/aaa/mod_authz_dbd.c index d01d83bd67..8164a5eeac 100644 --- a/modules/aaa/mod_authz_dbd.c +++ b/modules/aaa/mod_authz_dbd.c @@ -310,12 +310,15 @@ static const authz_provider authz_dbdlogout_provider = static void authz_dbd_hooks(apr_pool_t *p) { - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "dbd-group", "0", - &authz_dbdgroup_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "dbd-login", "0", - &authz_dbdlogin_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "dbd-logout", "0", - &authz_dbdlogout_provider); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "dbd-group", "0", + &authz_dbdgroup_provider, + AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "dbd-login", "0", + &authz_dbdlogin_provider, + AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "dbd-logout", "0", + &authz_dbdlogout_provider, + AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authz_dbd_module = diff --git a/modules/aaa/mod_authz_dbm.c b/modules/aaa/mod_authz_dbm.c index c71e4a338c..e67f699594 100644 --- a/modules/aaa/mod_authz_dbm.c +++ b/modules/aaa/mod_authz_dbm.c @@ -272,10 +272,12 @@ static void register_hooks(apr_pool_t *p) { authz_owner_get_file_group = APR_RETRIEVE_OPTIONAL_FN(authz_owner_get_file_group); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "dbm-group", "0", - &authz_dbmgroup_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "dbm-file-group", "0", - &authz_dbmfilegroup_provider); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "dbm-group", "0", + &authz_dbmgroup_provider, + AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "dbm-file-group", "0", + &authz_dbmfilegroup_provider, + AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authz_dbm_module = diff --git a/modules/aaa/mod_authz_default.c b/modules/aaa/mod_authz_default.c index 8a234f9795..82588ea0f5 100644 --- a/modules/aaa/mod_authz_default.c +++ b/modules/aaa/mod_authz_default.c @@ -89,7 +89,8 @@ static int check_user_access(request_rec *r) static void register_hooks(apr_pool_t *p) { - ap_hook_auth_checker(check_user_access,NULL,NULL,APR_HOOK_LAST); + ap_hook_check_authz(check_user_access, NULL, NULL, APR_HOOK_LAST, + AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authz_default_module = diff --git a/modules/aaa/mod_authz_groupfile.c b/modules/aaa/mod_authz_groupfile.c index 6ff3e17832..fabf6cdd25 100644 --- a/modules/aaa/mod_authz_groupfile.c +++ b/modules/aaa/mod_authz_groupfile.c @@ -266,10 +266,12 @@ static void register_hooks(apr_pool_t *p) { authz_owner_get_file_group = APR_RETRIEVE_OPTIONAL_FN(authz_owner_get_file_group); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "group", "0", - &authz_group_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "file-group", "0", - &authz_filegroup_provider); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "group", "0", + &authz_group_provider, + AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "file-group", "0", + &authz_filegroup_provider, + AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authz_groupfile_module = diff --git a/modules/aaa/mod_authz_host.c b/modules/aaa/mod_authz_host.c index 77af896568..e6d6ec79d3 100644 --- a/modules/aaa/mod_authz_host.c +++ b/modules/aaa/mod_authz_host.c @@ -241,14 +241,14 @@ static const authz_provider authz_all_provider = static void register_hooks(apr_pool_t *p) { - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "env", "0", - &authz_env_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "ip", "0", - &authz_ip_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "host", "0", - &authz_host_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "all", "0", - &authz_all_provider); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "env", "0", + &authz_env_provider, AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ip", "0", + &authz_ip_provider, AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "host", "0", + &authz_host_provider, AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "all", "0", + &authz_all_provider, AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authz_host_module = diff --git a/modules/aaa/mod_authz_owner.c b/modules/aaa/mod_authz_owner.c index 26eec14289..50cbbcae56 100644 --- a/modules/aaa/mod_authz_owner.c +++ b/modules/aaa/mod_authz_owner.c @@ -167,8 +167,9 @@ static void register_hooks(apr_pool_t *p) { APR_REGISTER_OPTIONAL_FN(authz_owner_get_file_group); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "file-owner", "0", - &authz_fileowner_provider); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "file-owner", "0", + &authz_fileowner_provider, + AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authz_owner_module = diff --git a/modules/aaa/mod_authz_user.c b/modules/aaa/mod_authz_user.c index 8607a033d1..75c21589b0 100644 --- a/modules/aaa/mod_authz_user.c +++ b/modules/aaa/mod_authz_user.c @@ -81,10 +81,11 @@ static const authz_provider authz_validuser_provider = static void register_hooks(apr_pool_t *p) { - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "user", "0", - &authz_user_provider); - ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "valid-user", "0", - &authz_validuser_provider); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "user", "0", + &authz_user_provider, AP_AUTH_INTERNAL_PER_CONF); + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "valid-user", "0", + &authz_validuser_provider, + AP_AUTH_INTERNAL_PER_CONF); } module AP_MODULE_DECLARE_DATA authz_user_module = diff --git a/modules/examples/mod_example_hooks.c b/modules/examples/mod_example_hooks.c index 824de41dd7..30ea60fe78 100644 --- a/modules/examples/mod_example_hooks.c +++ b/modules/examples/mod_example_hooks.c @@ -324,6 +324,7 @@ static x_cfg *our_cconfig(const conn_rec *c) #define EXAMPLE_LOG_EACH 0 #endif +#if EXAMPLE_LOG_EACH static void example_log_each(apr_pool_t *p, server_rec *s, const char *note) { if (s != NULL) { @@ -336,7 +337,7 @@ static void example_log_each(apr_pool_t *p, server_rec *s, const char *note) "context: %s\n", note); } } - +#endif /* * This utility routine traces the hooks called when the server starts up. @@ -564,8 +565,8 @@ static void *x_create_dir_config(apr_pool_t *p, char *dirspec) */ dname = (dname != NULL) ? dname : ""; cfg->loc = apr_pstrcat(p, "DIR(", dname, ")", NULL); - note = apr_psprintf(p, "x_create_dir_config(p == 0x%x, dirspec == %s)", - p, dirspec); + note = apr_psprintf(p, "x_create_dir_config(p == %pp, dirspec == %s)", + (void*) p, dirspec); trace_startup(p, NULL, cfg, note); return (void *) cfg; } @@ -617,9 +618,9 @@ static void *x_merge_dir_config(apr_pool_t *p, void *parent_conf, * Now just record our being called in the trace list. Include the * locations we were asked to merge. */ - note = apr_psprintf(p, "x_merge_dir_config(p == 0x%x, parent_conf == " - "0x%x, newloc_conf == 0x%x)", p, parent_conf, - newloc_conf); + note = apr_psprintf(p, "x_merge_dir_config(p == %pp, parent_conf == " + "%pp, newloc_conf == %pp)", (void*) p, + (void*) parent_conf, (void*) newloc_conf); trace_startup(p, NULL, merged_config, note); return (void *) merged_config; } @@ -1120,8 +1121,8 @@ static int x_pre_connection(conn_rec *c, void *csd) /* * Log the call and exit. */ - note = apr_psprintf(c->pool, "x_pre_connection(c = %x, p = %x)", - c, c->pool); + note = apr_psprintf(c->pool, "x_pre_connection(c = %pp, p = %pp)", + (void*) c, (void*) c->pool); trace_connection(c, note); return OK; @@ -1218,6 +1219,20 @@ static int x_header_parser(request_rec *r) } +/* + * This routine is called to check for any module-specific restrictions placed + * upon the requested resource. (See the mod_access_compat module for an + * example.) + * + * This is a RUN_ALL hook. The first handler to return a status other than OK + * or DECLINED (for instance, HTTP_FORBIDDEN) aborts the callback chain. + */ +static int x_check_access(request_rec *r) +{ + trace_request(r, "x_check_access()"); + return DECLINED; +} + /* * This routine is called to check the authentication information sent with * the request (such as looking up the user in a database and verifying that @@ -1226,12 +1241,12 @@ static int x_header_parser(request_rec *r) * This is a RUN_FIRST hook. The return value is OK, DECLINED, or some * HTTP_mumble error (typically HTTP_UNAUTHORIZED). */ -static int x_check_user_id(request_rec *r) +static int x_check_authn(request_rec *r) { /* * Don't do anything except log the call. */ - trace_request(r, "x_check_user_id()"); + trace_request(r, "x_check_authn()"); return DECLINED; } @@ -1246,26 +1261,13 @@ static int x_check_user_id(request_rec *r) * If *all* modules return DECLINED, the request is aborted with a server * error. */ -static int x_auth_checker(request_rec *r) +static int x_check_authz(request_rec *r) { /* * Log the call and return OK, or access will be denied (even though we * didn't actually do anything). */ - trace_request(r, "x_auth_checker()"); - return DECLINED; -} - -/* - * This routine is called to check for any module-specific restrictions placed - * upon the requested resource. (See the mod_access module for an example.) - * - * This is a RUN_ALL hook. The first handler to return a status other than OK - * or DECLINED (for instance, HTTP_FORBIDDEN) aborts the callback chain. - */ -static int x_access_checker(request_rec *r) -{ - trace_request(r, "x_access_checker()"); + trace_request(r, "x_check_authz()"); return DECLINED; } @@ -1456,11 +1458,14 @@ static void x_register_hooks(apr_pool_t *p) ap_hook_translate_name(x_translate_name, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_map_to_storage(x_map_to_storage, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_header_parser(x_header_parser, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_check_user_id(x_check_user_id, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_fixups(x_fixups, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_type_checker(x_type_checker, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_access_checker(x_access_checker, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_auth_checker(x_auth_checker, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_check_access(x_check_access, NULL, NULL, APR_HOOK_MIDDLE, + AP_AUTH_INTERNAL_PER_CONF); + ap_hook_check_authn(x_check_authn, NULL, NULL, APR_HOOK_MIDDLE, + AP_AUTH_INTERNAL_PER_CONF); + ap_hook_check_authz(x_check_authz, NULL, NULL, APR_HOOK_MIDDLE, + AP_AUTH_INTERNAL_PER_CONF); ap_hook_insert_filter(x_insert_filter, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_insert_error_filter(x_insert_error_filter, NULL, NULL, APR_HOOK_MIDDLE); #ifdef HAVE_UNIX_SUEXEC diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index 573255d2a8..379c827471 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -501,10 +501,13 @@ static void ssl_register_hooks(apr_pool_t *p) ap_hook_default_port (ssl_hook_default_port, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_pre_config (ssl_hook_pre_config, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_child_init (ssl_init_Child, NULL,NULL, APR_HOOK_MIDDLE); - ap_hook_check_user_id (ssl_hook_UserCheck, NULL,NULL, APR_HOOK_FIRST); + ap_hook_check_authn (ssl_hook_UserCheck, NULL,NULL, APR_HOOK_FIRST, + AP_AUTH_INTERNAL_PER_CONF); ap_hook_fixups (ssl_hook_Fixup, NULL,NULL, APR_HOOK_MIDDLE); - ap_hook_access_checker(ssl_hook_Access, NULL,NULL, APR_HOOK_MIDDLE); - ap_hook_auth_checker (ssl_hook_Auth, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_check_access (ssl_hook_Access, NULL,NULL, APR_HOOK_MIDDLE, + AP_AUTH_INTERNAL_PER_CONF); + ap_hook_check_authz (ssl_hook_Auth, NULL,NULL, APR_HOOK_MIDDLE, + AP_AUTH_INTERNAL_PER_CONF); ap_hook_post_read_request(ssl_hook_ReadReq, pre_prr,NULL, APR_HOOK_MIDDLE); ssl_var_register(p); diff --git a/server/core.c b/server/core.c index cfa9fc4ad6..f6c987643c 100644 --- a/server/core.c +++ b/server/core.c @@ -2002,7 +2002,6 @@ static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg) int old_overrides = cmd->override; char *old_path = cmd->path; core_dir_config *conf; - ap_regex_t *r = NULL; const command_rec *thiscmd = cmd->cmd; core_dir_config *c = mconfig; ap_conf_vector_t *new_file_conf = ap_create_per_dir_config(cmd->pool); @@ -3753,6 +3752,7 @@ static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte set_banner(pconf); ap_setup_make_content_type(pconf); + ap_setup_auth_internal(ptemp); return OK; } @@ -3963,7 +3963,6 @@ static void register_hooks(apr_pool_t *p) /* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */ ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST); ap_hook_fixups(core_override_type,NULL,NULL,APR_HOOK_REALLY_FIRST); - ap_hook_access_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST); ap_hook_create_request(core_create_req, NULL, NULL, APR_HOOK_MIDDLE); APR_OPTIONAL_HOOK(proxy, create_req, core_create_proxy_req, NULL, NULL, APR_HOOK_MIDDLE); diff --git a/server/main.c b/server/main.c index e758211375..0f3e6a09fb 100644 --- a/server/main.c +++ b/server/main.c @@ -35,6 +35,7 @@ #include "http_log.h" #include "http_config.h" #include "http_core.h" +#include "http_request.h" #include "http_vhost.h" #include "apr_uri.h" #include "util_ebcdic.h" @@ -713,6 +714,7 @@ int main(int argc, const char * const argv[]) for (;;) { apr_hook_deregister_all(); apr_pool_clear(pconf); + ap_clear_auth_internal(server_conf); for (mod = ap_prelinked_modules; *mod != NULL; mod++) { ap_register_hooks(*mod, pconf); diff --git a/server/request.c b/server/request.c index d3eecbb688..bec1343733 100644 --- a/server/request.c +++ b/server/request.c @@ -34,6 +34,7 @@ #define CORE_PRIVATE #include "ap_config.h" +#include "ap_provider.h" #include "httpd.h" #include "http_config.h" #include "http_request.h" @@ -82,6 +83,10 @@ AP_IMPLEMENT_HOOK_VOID(insert_filter, (request_rec *r), (r)) AP_IMPLEMENT_HOOK_RUN_ALL(int, create_request, (request_rec *r), (r), OK, DECLINED) +static int auth_internal_per_conf = 0; +static int auth_internal_per_conf_hooks = 0; +static int auth_internal_per_conf_providers = 0; + static int decl_die(int status, char *phase, request_rec *r) { @@ -171,14 +176,14 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r) * functions in map_to_storage that use the same merge results given * identical input.) If the config changes, we must re-auth. */ - if (r->main && (r->main->per_dir_config == r->per_dir_config)) { - r->user = r->main->user; - r->ap_auth_type = r->main->ap_auth_type; - } - else if (r->prev && (r->prev->per_dir_config == r->per_dir_config)) { + if (r->prev && (r->prev->per_dir_config == r->per_dir_config)) { r->user = r->prev->user; r->ap_auth_type = r->prev->ap_auth_type; } + else if (r->main && (r->main->per_dir_config == r->per_dir_config)) { + r->user = r->main->user; + r->ap_auth_type = r->main->ap_auth_type; + } else { switch (ap_satisfies(r)) { case SATISFY_ALL: @@ -248,44 +253,61 @@ typedef struct walk_cache_t { ap_conf_vector_t *dir_conf_merged; /* Base per_dir_config */ ap_conf_vector_t *per_dir_result; /* per_dir_config += walked result */ apr_array_header_t *walked; /* The list of walk_walked_t results */ + struct walk_cache_t *prev; /* Prev cache of same call in this (sub)req */ + int count; /* Number of prev invocations of same call in this (sub)req */ } walk_cache_t; static walk_cache_t *prep_walk_cache(apr_size_t t, request_rec *r) { - walk_cache_t *cache; - void **note; - - /* Find the most relevant, recent entry to work from. That would be - * this request (on the second call), or the parent request of a - * subrequest, or the prior request of an internal redirect. Provide - * this _walk()er with a copy it is allowed to munge. If there is no - * parent or prior cached request, then create a new walk cache. + void **note, **inherit_note; + walk_cache_t *cache, *prev_cache, *copy_cache; + int count; + + /* Find the most relevant, recent walk cache to work from and provide + * a copy the caller is allowed to munge. In the case of a sub-request + * or internal redirect, this is the cache corresponding to the equivalent + * invocation of the same function call in the "parent" request, if such + * a cache exists. Otherwise it is the walk cache of the previous + * invocation of the same function call in the current request, if + * that exists; if not, then create a new walk cache. */ note = ap_get_request_note(r, t); if (!note) { return NULL; } - if (!(cache = *note)) { - void **inherit_note; + copy_cache = prev_cache = *note; + count = prev_cache ? (prev_cache->count + 1) : 0; - if ((r->main - && ((inherit_note = ap_get_request_note(r->main, t))) - && *inherit_note) - || (r->prev - && ((inherit_note = ap_get_request_note(r->prev, t))) - && *inherit_note)) { - cache = apr_pmemdup(r->pool, *inherit_note, - sizeof(*cache)); - cache->walked = apr_array_copy(r->pool, cache->walked); + if ((r->prev + && (inherit_note = ap_get_request_note(r->prev, t)) + && *inherit_note) + || (r->main + && (inherit_note = ap_get_request_note(r->main, t)) + && *inherit_note)) { + walk_cache_t *inherit_cache = *inherit_note; + + while (inherit_cache->count > count) { + inherit_cache = inherit_cache->prev; } - else { - cache = apr_pcalloc(r->pool, sizeof(*cache)); - cache->walked = apr_array_make(r->pool, 4, sizeof(walk_walked_t)); + if (inherit_cache->count == count) { + copy_cache = inherit_cache; } + } - *note = cache; + if (copy_cache) { + cache = apr_pmemdup(r->pool, copy_cache, sizeof(*cache)); + cache->walked = apr_array_copy(r->pool, cache->walked); + cache->prev = prev_cache; + cache->count = count; + } + else { + cache = apr_pcalloc(r->pool, sizeof(*cache)); + cache->walked = apr_array_make(r->pool, 4, sizeof(walk_walked_t)); } + + *note = cache; + return cache; } @@ -454,6 +476,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) walk_cache_t *cache; char *entry_dir; apr_status_t rv; + int cached; /* XXX: Better (faster) tests needed!!! * @@ -491,6 +514,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) r->filename = entry_dir; cache = prep_walk_cache(AP_NOTE_DIRECTORY_WALK, r); + cached = (cache->cached != NULL); /* If this is not a dirent subrequest with a preconstructed * r->finfo value, then we can simply stat the filename to @@ -534,7 +558,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) * and the vhost's list of directory sections hasn't changed, * we can skip rewalking the directory_walk entries. */ - if (cache->cached + if (cached && ((r->finfo.filetype == APR_REG) || ((r->finfo.filetype == APR_DIR) && (!r->path_info || !*r->path_info))) @@ -619,6 +643,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) */ int sec_idx; int matches = cache->walked->nelts; + int cached_matches = matches; walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts; core_dir_config *this_dir; core_opts_t opts; @@ -628,6 +653,8 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) char *buf; unsigned int seg, startseg; + cached &= auth_internal_per_conf; + /* Invariant: from the first time filename_len is set until * it goes out of scope, filename_len==strlen(r->filename) */ @@ -827,6 +854,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) */ cache->walked->nelts -= matches; matches = 0; + cached = 0; } if (now_merged) { @@ -894,6 +922,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) */ cache->walked->nelts -= matches; matches = 0; + cached = 0; } if (now_merged) { @@ -1106,6 +1135,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) */ cache->walked->nelts -= matches; matches = 0; + cached = 0; } if (now_merged) { @@ -1122,11 +1152,16 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) last_walk->merged = now_merged; } - /* Whoops - everything matched in sequence, but the original walk - * found some additional matches. Truncate them. + /* Whoops - everything matched in sequence, but either the original + * walk found some additional matches (which we need to truncate), or + * this walk found some additional matches. */ if (matches) { cache->walked->nelts -= matches; + cached = 0; + } + else if (cache->walked->nelts > cached_matches) { + cached = 0; } } @@ -1166,6 +1201,12 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) cache->cached = ap_make_dirstr_parent(r->pool, r->filename); } + if (cached + && r->per_dir_config == cache->dir_conf_merged) { + r->per_dir_config = cache->per_dir_result; + return OK; + } + cache->dir_conf_tested = sec_ent; cache->dir_conf_merged = r->per_dir_config; @@ -1192,6 +1233,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) int num_sec = sconf->sec_url->nelts; walk_cache_t *cache; const char *entry_uri; + int cached; /* No tricks here, there are no to parse in this vhost. * We won't destroy the cache, just in case _this_ redirect is later @@ -1202,6 +1244,7 @@ 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, @@ -1221,7 +1264,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) * and the vhost's list of locations hasn't changed, we can skip * rewalking the location_walk entries. */ - if (cache->cached + if (cached && (cache->dir_conf_tested == sec_ent) && (strcmp(entry_uri, cache->cached) == 0)) { /* Well this looks really familiar! If our end-result (per_dir_result) @@ -1233,11 +1276,6 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) return OK; } - if (r->per_dir_config == cache->dir_conf_merged) { - r->per_dir_config = cache->per_dir_result; - return OK; - } - if (cache->walked->nelts) { now_merged = ((walk_walked_t*)cache->walked->elts) [cache->walked->nelts - 1].merged; @@ -1249,7 +1287,10 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) */ int len, sec_idx; int matches = cache->walked->nelts; + int cached_matches = matches; walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts; + + cached &= auth_internal_per_conf; cache->cached = entry_uri; /* Go through the location entries, and check for matches. @@ -1295,6 +1336,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) */ cache->walked->nelts -= matches; matches = 0; + cached = 0; } if (now_merged) { @@ -1311,14 +1353,25 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) last_walk->merged = now_merged; } - /* Whoops - everything matched in sequence, but the original walk - * found some additional matches. Truncate them. + /* Whoops - everything matched in sequence, but either the original + * walk found some additional matches (which we need to truncate), or + * this walk found some additional matches. */ if (matches) { cache->walked->nelts -= matches; + cached = 0; + } + else if (cache->walked->nelts > cached_matches) { + cached = 0; } } + if (cached + && r->per_dir_config == cache->dir_conf_merged) { + r->per_dir_config = cache->per_dir_result; + return OK; + } + cache->dir_conf_tested = sec_ent; cache->dir_conf_merged = r->per_dir_config; @@ -1344,6 +1397,7 @@ AP_DECLARE(int) ap_file_walk(request_rec *r) int num_sec = dconf->sec_file->nelts; walk_cache_t *cache; const char *test_file; + int cached; /* To allow broken modules to proceed, we allow missing filenames to pass. * We will catch it later if it's heading for the core handler. @@ -1354,6 +1408,7 @@ AP_DECLARE(int) ap_file_walk(request_rec *r) } cache = prep_walk_cache(AP_NOTE_FILE_WALK, r); + cached = (cache->cached != NULL); /* No tricks here, there are just no to parse in this context. * We won't destroy the cache, just in case _this_ redirect is later @@ -1378,7 +1433,7 @@ AP_DECLARE(int) ap_file_walk(request_rec *r) * and the directory's list of file sections hasn't changed, we * can skip rewalking the file_walk entries. */ - if (cache->cached + if (cached && (cache->dir_conf_tested == sec_ent) && (strcmp(test_file, cache->cached) == 0)) { /* Well this looks really familiar! If our end-result (per_dir_result) @@ -1390,11 +1445,6 @@ AP_DECLARE(int) ap_file_walk(request_rec *r) return OK; } - if (r->per_dir_config == cache->dir_conf_merged) { - r->per_dir_config = cache->per_dir_result; - return OK; - } - if (cache->walked->nelts) { now_merged = ((walk_walked_t*)cache->walked->elts) [cache->walked->nelts - 1].merged; @@ -1406,7 +1456,10 @@ AP_DECLARE(int) ap_file_walk(request_rec *r) */ int sec_idx; int matches = cache->walked->nelts; + int cached_matches = matches; walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts; + + cached &= auth_internal_per_conf; cache->cached = test_file; /* Go through the location entries, and check for matches. @@ -1449,6 +1502,7 @@ AP_DECLARE(int) ap_file_walk(request_rec *r) */ cache->walked->nelts -= matches; matches = 0; + cached = 0; } if (now_merged) { @@ -1465,14 +1519,25 @@ AP_DECLARE(int) ap_file_walk(request_rec *r) last_walk->merged = now_merged; } - /* Whoops - everything matched in sequence, but the original walk - * found some additional matches. Truncate them. + /* Whoops - everything matched in sequence, but either the original + * walk found some additional matches (which we need to truncate), or + * this walk found some additional matches. */ if (matches) { cache->walked->nelts -= matches; + cached = 0; + } + else if (cache->walked->nelts > cached_matches) { + cached = 0; } } + if (cached + && r->per_dir_config == cache->dir_conf_merged) { + r->per_dir_config = cache->per_dir_result; + return OK; + } + cache->dir_conf_tested = sec_ent; cache->dir_conf_merged = r->per_dir_config; @@ -1618,6 +1683,107 @@ AP_DECLARE(int) ap_some_auth_required(request_rec *r) return 0; } +AP_DECLARE(void) ap_clear_auth_internal(void) +{ + auth_internal_per_conf_hooks = 0; + auth_internal_per_conf_providers = 0; +} + +AP_DECLARE(void) ap_setup_auth_internal(apr_pool_t *ptemp) +{ + APR_OPTIONAL_FN_TYPE(authn_ap_list_provider_names) + *authn_ap_list_provider_names; + APR_OPTIONAL_FN_TYPE(authz_ap_list_provider_names) + *authz_ap_list_provider_names; + int total_auth_hooks = 0; + int total_auth_providers = 0; + + auth_internal_per_conf = 0; + + if (_hooks.link_access_checker) { + total_auth_hooks += _hooks.link_access_checker->nelts; + } + if (_hooks.link_check_user_id) { + total_auth_hooks += _hooks.link_check_user_id->nelts; + } + if (_hooks.link_auth_checker) { + total_auth_hooks += _hooks.link_auth_checker->nelts; + } + + if (total_auth_hooks > auth_internal_per_conf_hooks) { + return; + } + + authn_ap_list_provider_names = + APR_RETRIEVE_OPTIONAL_FN(authn_ap_list_provider_names); + authz_ap_list_provider_names = + APR_RETRIEVE_OPTIONAL_FN(authz_ap_list_provider_names); + + if (authn_ap_list_provider_names) { + total_auth_providers += authn_ap_list_provider_names(ptemp)->nelts; + } + + if (authz_ap_list_provider_names) { + total_auth_providers += authz_ap_list_provider_names(ptemp)->nelts; + } + + if (total_auth_providers > auth_internal_per_conf_providers) { + return; + } + + auth_internal_per_conf = 1; +} + +AP_DECLARE(apr_status_t) ap_register_auth_provider(apr_pool_t *pool, + const char *provider_group, + const char *provider_name, + const char *provider_version, + const void *provider, + int type) +{ + if ((type & AP_AUTH_INTERNAL_MASK) == AP_AUTH_INTERNAL_PER_CONF) { + ++auth_internal_per_conf_providers; + } + + return ap_register_provider(pool, provider_group, provider_name, + provider_version, provider); +} + +AP_DECLARE(void) ap_hook_check_access(ap_HOOK_access_checker_t *pf, + const char * const *aszPre, + const char * const *aszSucc, + int nOrder, int type) +{ + if ((type & AP_AUTH_INTERNAL_MASK) == AP_AUTH_INTERNAL_PER_CONF) { + ++auth_internal_per_conf_hooks; + } + + ap_hook_access_checker(pf, aszPre, aszSucc, nOrder); +} + +AP_DECLARE(void) ap_hook_check_authn(ap_HOOK_check_user_id_t *pf, + const char * const *aszPre, + const char * const *aszSucc, + int nOrder, int type) +{ + if ((type & AP_AUTH_INTERNAL_MASK) == AP_AUTH_INTERNAL_PER_CONF) { + ++auth_internal_per_conf_hooks; + } + + ap_hook_check_user_id(pf, aszPre, aszSucc, nOrder); +} + +AP_DECLARE(void) ap_hook_check_authz(ap_HOOK_auth_checker_t *pf, + const char * const *aszPre, + const char * const *aszSucc, + int nOrder, int type) +{ + if ((type & AP_AUTH_INTERNAL_MASK) == AP_AUTH_INTERNAL_PER_CONF) { + ++auth_internal_per_conf_hooks; + } + + ap_hook_auth_checker(pf, aszPre, aszSucc, nOrder); +} AP_DECLARE(request_rec *) ap_sub_req_method_uri(const char *method, const char *new_uri, @@ -1949,3 +2115,4 @@ AP_DECLARE(int) ap_is_initial_req(request_rec *r) return (r->main == NULL) /* otherwise, this is a sub-request */ && (r->prev == NULL); /* otherwise, this is an internal redirect */ } + -- 2.40.0