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]
* @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
#define APACHE_HTTP_REQUEST_H
#include "apr_hooks.h"
+#include "apr_optional.h"
#include "util_filter.h"
#ifdef __cplusplus
* @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
* 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))
* 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))
* 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
#endif
#endif /* !APACHE_HTTP_REQUEST_H */
+/** @} */
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 =
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 =
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);
}
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 =
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;
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,
{
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 =
#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"
&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 =
{
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 =
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 =
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 =
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);
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;
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 =
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 =
{
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 =
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 =
{
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 =
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 =
{
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 =
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 =
#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) {
"context: %s\n", note);
}
}
-
+#endif
/*
* This utility routine traces the hooks called when the server starts up.
*/
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;
}
* 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;
}
/*
* 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;
}
+/*
+ * 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
* 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;
}
* 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;
}
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
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);
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);
set_banner(pconf);
ap_setup_make_content_type(pconf);
+ ap_setup_auth_internal(ptemp);
return OK;
}
/* 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);
#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"
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);
#define CORE_PRIVATE
#include "ap_config.h"
+#include "ap_provider.h"
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
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)
{
* 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:
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;
}
walk_cache_t *cache;
char *entry_dir;
apr_status_t rv;
+ int cached;
/* XXX: Better (faster) tests needed!!!
*
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
* 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)))
*/
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;
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)
*/
*/
cache->walked->nelts -= matches;
matches = 0;
+ cached = 0;
}
if (now_merged) {
*/
cache->walked->nelts -= matches;
matches = 0;
+ cached = 0;
}
if (now_merged) {
*/
cache->walked->nelts -= matches;
matches = 0;
+ cached = 0;
}
if (now_merged) {
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;
}
}
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;
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
}
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,
* 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)
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;
*/
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.
*/
cache->walked->nelts -= matches;
matches = 0;
+ cached = 0;
}
if (now_merged) {
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;
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.
}
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
* 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)
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;
*/
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.
*/
cache->walked->nelts -= matches;
matches = 0;
+ cached = 0;
}
if (now_merged) {
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;
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,
return (r->main == NULL) /* otherwise, this is a sub-request */
&& (r->prev == NULL); /* otherwise, this is an internal redirect */
}
+