]> granicus.if.org Git - apache/commitdiff
Avoid calling access control hooks for internal requests with
authorChris Darroch <chrisd@apache.org>
Thu, 3 Apr 2008 21:51:07 +0000 (21:51 +0000)
committerChris Darroch <chrisd@apache.org>
Thu, 3 Apr 2008 21:51:07 +0000 (21:51 +0000)
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

25 files changed:
CHANGES
include/http_request.h
modules/aaa/mod_access_compat.c
modules/aaa/mod_auth_basic.c
modules/aaa/mod_auth_digest.c
modules/aaa/mod_authn_anon.c
modules/aaa/mod_authn_core.c
modules/aaa/mod_authn_dbd.c
modules/aaa/mod_authn_dbm.c
modules/aaa/mod_authn_default.c
modules/aaa/mod_authn_file.c
modules/aaa/mod_authnz_ldap.c
modules/aaa/mod_authz_core.c
modules/aaa/mod_authz_dbd.c
modules/aaa/mod_authz_dbm.c
modules/aaa/mod_authz_default.c
modules/aaa/mod_authz_groupfile.c
modules/aaa/mod_authz_host.c
modules/aaa/mod_authz_owner.c
modules/aaa/mod_authz_user.c
modules/examples/mod_example_hooks.c
modules/ssl/mod_ssl.c
server/core.c
server/main.c
server/request.c

diff --git a/CHANGES b/CHANGES
index 8bf9b084cfd8a08d616f2c3574c3802478c878d2..516cf225b658450af1690972cae45aed9fe519d5 100644 (file)
--- 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]
 
index edad37087e0cb66d493d766d9e9679bde42c6651..ce491da76c2b56c53807d3af7f53f0e3cbe92ee2 100644 (file)
  * @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 */
+/** @} */
index b93e9fcac9aa8e713271d8f168f04945e05b2273..bd56c8ed2c195fd9989c7db5357fcf7c3e42c2f7 100644 (file)
@@ -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 =
index 4ae1c4665cd9fc771bacabefac71cc34f47f6da3..628e7a2dd490e9a406d594ec810a5f4bc2bf93ee 100644 (file)
@@ -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 =
index fc2b684ccacd780a6cecb2ac8e30f740ebe69f11..ad2e0e9159996abc4fe800a79212914ea72e35d9 100644 (file)
@@ -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);
 }
index 07f48b35b300d833e68eba321f7452c1c486bf5c..ce8510f6057282b837bf0151eacc715988addb9e 100644 (file)
@@ -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 =
index e421e1375d94219c507418da46af68563e04f7fc..66e204e0d07b2e4df854f9bf6cc2d0917a5d2748 100644 (file)
@@ -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 =
index 3341171e67d9fca3d202bee875fc2ad244a7e1bd..47ce2aa49c93589f9c8e0d675d9a7a15fe9f63f9 100644 (file)
@@ -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 =
 {
index 9221752fa2148c624cbbeb9eb5848c6d3c47c988..abb8df482a8aaff82156b8af8788f90917eb5724 100644 (file)
@@ -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 =
index 46c78cd79aad4f83e5a09e5c8b924f67e801ef8e..0155c6e298f452f5c0d20240f4363466aa7825e9 100644 (file)
@@ -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 =
index 018733e1ead0b29d6091846d474000a9f18b212a..2cab61ca9085c6f6603affef2b2b9f2a30b53c9a 100644 (file)
@@ -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 =
index 4034f5efb875e37d50b6bb43527e6ce1719168cb..9c6ac6f60050674a630cd18729f5c8009c09aeb3 100644 (file)
@@ -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);
 
index 15557f4e4b3395c41cb5c58d4d5761bc89cd08ac..5b7c40986174c61e92b298ba95582e3c4c49c4c4 100644 (file)
@@ -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 =
index d01d83bd670988c36b1c0fde6c5bfa0ace6dc8ba..8164a5eeac6847608b46a6b522af33a6324afad2 100644 (file)
@@ -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 =
index c71e4a338c2a1d0bb6321b6c3d783eb9277b09b9..e67f699594f7a37625214249cda144289b2a9e3f 100644 (file)
@@ -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 =
index 8a234f97950016a36aaa4716af351f5b19782252..82588ea0f5eac37dba18dd24a2330ea50e943446 100644 (file)
@@ -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 =
index 6ff3e1783231b43de6a5b230b63a28283480e1f8..fabf6cdd25b67f959551bcb475949a62a452a164 100644 (file)
@@ -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 =
index 77af8965686a86aed0b8a1dbc5bf9952451b37b4..e6d6ec79d314a9fa384eb7ceb16795c354a3efbf 100644 (file)
@@ -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 =
index 26eec14289619b543c2ff8c49accbe01bf1fa93b..50cbbcae56d52b5286984bf7e6c3eded8ba04dc9 100644 (file)
@@ -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 =
index 8607a033d18d526bce152d6c81fd1575ce7432b3..75c21589b0868394b15d24128d8af2c3af339087 100644 (file)
@@ -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 =
index 824de41dd731304f474352c87ef58473d819fba4..30ea60fe781631def056050b7db1dc3571c13b5f 100644 (file)
@@ -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
index 573255d2a8e79fbc6e224ea80d908d2be70b2be6..379c8274715d48bbb38feb0b9b0566649ac2e47a 100644 (file)
@@ -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);
index cfa9fc4ad68bddf0b6e9dd7260bd8eb24ac0cf08..f6c987643ce5ab988536f1deb52ea6797291dcc6 100644 (file)
@@ -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);
index e758211375e4eff3491ea43210eabc20c49beadd..0f3e6a09fb8e13e6d65cb68ebb78b127d0c955ca 100644 (file)
@@ -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);
index d3eecbb6883450c967dd082c2985a18430b46539..bec1343733482cce771f133f396c46a287cf5aab 100644 (file)
@@ -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 <Locations > 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 <Files > 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 */
 }
+