You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ch...@apache.org on 2008/11/02 05:01:32 UTC
svn commit: r709838 - in /httpd/httpd/trunk: CHANGES include/ap_mmn.h
include/mod_auth.h modules/aaa/mod_access_compat.c
modules/aaa/mod_authz_core.c modules/aaa/mod_authz_default.c
Author: chrisd
Date: Sat Nov 1 21:01:32 2008
New Revision: 709838
URL: http://svn.apache.org/viewvc?rev=709838&view=rev
Log:
Fix handling of authz configurations, make default authz logic replicate
2.2.x authz logic and support existing configurations (including .htaccess
files), and replace <Satisfy*>, Reject, and AuthzMergeRules directives
with Match, <Match*>, and AuthzMerge directives.
Modified:
httpd/httpd/trunk/CHANGES
httpd/httpd/trunk/include/ap_mmn.h
httpd/httpd/trunk/include/mod_auth.h
httpd/httpd/trunk/modules/aaa/mod_access_compat.c
httpd/httpd/trunk/modules/aaa/mod_authz_core.c
httpd/httpd/trunk/modules/aaa/mod_authz_default.c
Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=709838&r1=709837&r2=709838&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Sat Nov 1 21:01:32 2008
@@ -2,6 +2,11 @@
Changes with Apache 2.3.0
[ When backported to 2.2.x, remove entry from this file ]
+ *) authz: Fix handling of authz configurations, make default authz
+ logic replicate 2.2.x authz logic, and replace <Satisfy*>, Reject,
+ and AuthzMergeRules directives with Match, <Match*>, and AuthzMerge
+ directives. [Chris Darroch]
+
*) mod_proxy_ajp: Do not fail if response data is sent before all request
data is read. PR 45911 [Ruediger Pluem]
Modified: httpd/httpd/trunk/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_mmn.h?rev=709838&r1=709837&r2=709838&view=diff
==============================================================================
--- httpd/httpd/trunk/include/ap_mmn.h (original)
+++ httpd/httpd/trunk/include/ap_mmn.h Sat Nov 1 21:01:32 2008
@@ -172,13 +172,15 @@
* 20080920.1 (2.3.0-dev) Export mod_rewrite.h in the public API.
* 20080920.2 (2.3.0-dev) Added ap_timeout_parameter_parse to util.c / httpd.h
* 20081101.0 (2.3.0-dev) Remove unused AUTHZ_GROUP_NOTE define.
+ * 20081102.0 (2.3.0-dev) Remove authz_provider_list, authz_request_state,
+ * and AUTHZ_ACCESS_PASSED_NOTE.
*
*/
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
#ifndef MODULE_MAGIC_NUMBER_MAJOR
-#define MODULE_MAGIC_NUMBER_MAJOR 20081101
+#define MODULE_MAGIC_NUMBER_MAJOR 20081102
#endif
#define MODULE_MAGIC_NUMBER_MINOR 0 /* 0...n */
Modified: httpd/httpd/trunk/include/mod_auth.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/mod_auth.h?rev=709838&r1=709837&r2=709838&view=diff
==============================================================================
--- httpd/httpd/trunk/include/mod_auth.h (original)
+++ httpd/httpd/trunk/include/mod_auth.h Sat Nov 1 21:01:32 2008
@@ -44,7 +44,6 @@
#define AUTHN_PROVIDER_NAME_NOTE "authn_provider_name"
#define AUTHZ_PROVIDER_NAME_NOTE "authz_provider_name"
-#define AUTHZ_ACCESS_PASSED_NOTE "authz_access_passed"
#define AUTHN_PREFIX "AUTHENTICATE_"
@@ -72,15 +71,10 @@
typedef enum {
AUTHZ_DENIED,
AUTHZ_GRANTED,
- AUTHZ_GENERAL_ERROR,
- AUTHZ_NEUTRAL
+ AUTHZ_NEUTRAL,
+ AUTHZ_GENERAL_ERROR
} authz_status;
-typedef enum {
- AUTHZ_REQSTATE_ONE,
- AUTHZ_REQSTATE_ALL
-} authz_request_state;
-
typedef struct {
/* Given a username and password, expected to return AUTH_GRANTED
* if we can validate this user/password combination.
@@ -112,23 +106,6 @@
const char *require_line);
} authz_provider;
-/* A linked-list of authn providers. */
-typedef struct authz_provider_list authz_provider_list;
-
-struct authz_provider_list {
- const char *provider_name;
- const authz_provider *provider;
- authz_provider_list *one_next;
- authz_provider_list *all_next;
- /** If a Limit method is in effect, this field will be set */
- apr_int64_t method_mask;
- authz_request_state req_state;
- int req_state_level;
- /** String following 'require <provider>' from config file */
- char *requirement;
- int is_reject;
-};
-
#ifdef __cplusplus
}
#endif
Modified: httpd/httpd/trunk/modules/aaa/mod_access_compat.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_access_compat.c?rev=709838&r1=709837&r2=709838&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/aaa/mod_access_compat.c (original)
+++ httpd/httpd/trunk/modules/aaa/mod_access_compat.c Sat Nov 1 21:01:32 2008
@@ -349,18 +349,6 @@
}
}
- if (ret == OK) {
- apr_table_setn(r->notes, AUTHZ_ACCESS_PASSED_NOTE, "Y");
- }
- else {
- apr_table_setn(r->notes, AUTHZ_ACCESS_PASSED_NOTE, "N");
- /* If Satisfy is not Any and authorization is required, then
- defer to the authorization stage */
- if ((access_compat_ap_satisfies(r) != SATISFY_ANY) && ap_some_auth_required(r)) {
- ret = OK;
- }
- }
-
if (ret == HTTP_FORBIDDEN) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"client denied by server configuration: %s%s",
Modified: httpd/httpd/trunk/modules/aaa/mod_authz_core.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_authz_core.c?rev=709838&r1=709837&r2=709838&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/aaa/mod_authz_core.c (original)
+++ httpd/httpd/trunk/modules/aaa/mod_authz_core.c Sat Nov 1 21:01:32 2008
@@ -44,49 +44,24 @@
#include <netinet/in.h>
#endif
-/* TODO List
-
-X- Convert all of the authz modules to providers
-X- Remove the ap_requires field from the core_dir_config structure
-X- Remove the ap_requires field from authz_dir_conf
-X- Remove the function ap_requires() and authz_ap_requires()
- since their functionality is no longer supported
- or necessary in the refactoring
-X- Remove the calls to ap_some_auth_required() in the
- core request handling to allow the hooks to be called
- in all cases. Is this function even necessary
- anymore?
-X- Determine of merge_authz_dir_config is even
- necessary and remove if not
-X- Split the authz type from the arguments when the
- authz provider is registered and store the type
- in ->provider_name and the arguments in ->requirement
-X- Move the check for METHOD_MASK out of the authz
- providers and into the provider vector
-X- Change the status code to AUTHZ_DENIED, AUTHZ_GRANTED
- and AUTHZ_GENERAL_ERROR
-- Determine if setting the AUTHZ_PROVIDER_NAME_NOTE note
- is even necessary. This was used in authn to support
- authn_alias. Is there a need for an authz_alias?
-X- Remove the Satisfy directive functionality and replace it with the
- <SatisfyAll>, <SatisfyOne> directives
-X- Remove the Satisfy directive
-X- Implement the <SatisfyAll> <SatisfyOne> block directives
- to handle the 'and' and 'or' logic for authorization.
-X- Remove the AuthzXXXAuthoritative directives from all of
- the authz providers
-X- Implement the Reject directive that will deny authorization
- if the argument is true
-X- Fold the Reject directive into the <SatisfyAll> <SatisfyOne>
- logic
-X- Reimplement the host based authorization 'allow', 'deny'
- and 'order' as authz providers
-X- Remove the 'allow', 'deny' and 'order' directives
-- Merge mod_authn_alias into mod_authn_core
-X- Remove all of the references to the authzxxxAuthoritative
- directives from the documentation
-X- Remove the Satisfy directive from the documentation
-*/
+#define FORMAT_AUTHZ_RESULT(result) \
+ (((result) == AUTHZ_DENIED) \
+ ? "denied" \
+ : (((result) == AUTHZ_GRANTED) \
+ ? "granted" : "neutral"))
+
+#define FORMAT_AUTHZ_COMMAND(p,section) \
+ ((section)->provider \
+ ? apr_pstrcat((p), \
+ ((section)->negate ? \
+ "Match not " : "Match "), \
+ (section)->provider_name, " ", \
+ (section)->provider_args, NULL) \
+ : apr_pstrcat((p), "<Match", \
+ ((section)->negate ? "Not" : ""), \
+ (((section)->op == AUTHZ_LOGIC_AND) \
+ ? "All" : "Any"), \
+ ">", NULL)) \
typedef struct provider_alias_rec {
char *provider_name;
@@ -96,31 +71,50 @@
const authz_provider *provider;
} provider_alias_rec;
-typedef struct {
- authz_provider_list *providers;
- authz_request_state req_state;
- int req_state_level;
- int merge_rules;
-} authz_core_dir_conf;
+typedef enum {
+ AUTHZ_LOGIC_AND,
+ AUTHZ_LOGIC_OR,
+ AUTHZ_LOGIC_OFF
+} authz_logic_op;
+
+typedef struct authz_section_conf authz_section_conf;
+
+struct authz_section_conf {
+ const char *provider_name;
+ const char *provider_args;
+ const authz_provider *provider;
+ apr_int64_t limited;
+ authz_logic_op op;
+ int negate;
+ authz_section_conf *first;
+ authz_section_conf *next;
+};
+
+typedef struct authz_core_dir_conf authz_core_dir_conf;
+
+struct authz_core_dir_conf {
+ authz_section_conf *section;
+ authz_logic_op op;
+ int old_require;
+ authz_core_dir_conf *next;
+};
typedef struct authz_core_srv_conf {
apr_hash_t *alias_rec;
} authz_core_srv_conf;
module AP_MODULE_DECLARE_DATA authz_core_module;
-static const char *merge_authz_provider(authz_core_dir_conf *conf, authz_provider_list *newp);
-static void walk_merge_provider_list(apr_pool_t *a, authz_core_dir_conf *conf, authz_provider_list *providers);
-#define BASE_REQ_STATE AUTHZ_REQSTATE_ALL
-#define BASE_REQ_LEVEL 0
+static authz_core_dir_conf *authz_core_first_dir_conf;
static void *create_authz_core_dir_config(apr_pool_t *p, char *dummy)
{
authz_core_dir_conf *conf = apr_pcalloc(p, sizeof(*conf));
- conf->req_state = BASE_REQ_STATE;
- conf->req_state_level = BASE_REQ_LEVEL;
- conf->merge_rules = 1;
+ conf->op = AUTHZ_LOGIC_OFF;
+
+ conf->next = authz_core_first_dir_conf;
+ authz_core_first_dir_conf = conf;
return (void *)conf;
}
@@ -132,22 +126,38 @@
authz_core_dir_conf *new = (authz_core_dir_conf *)newv;
authz_core_dir_conf *conf;
- /* Create this conf by duplicating the base, replacing elements
- * (or creating copies for merging) where new-> values exist.
- */
- conf = (authz_core_dir_conf *)apr_pmemdup(p, base, sizeof(authz_core_dir_conf));
-
- /* Wipe out the providers and rejects lists so that
- they can be recreated by the merge process. */
- conf->providers = NULL;
-
- /* Only merge the base providers in if the merge_rules
- directive has been set. */
- if (base->providers && new->merge_rules) {
- walk_merge_provider_list (p, conf, base->providers);
+ if (new->op == AUTHZ_LOGIC_OFF || !(base->section || new->section)) {
+ conf = apr_pmemdup(p, new, sizeof(*new));
}
- if (new->providers) {
- walk_merge_provider_list (p, conf, new->providers);
+ else {
+ authz_section_conf *section;
+
+ if (base->section) {
+ if (new->section) {
+ section = apr_pcalloc(p, sizeof(*section));
+
+ section->limited =
+ base->section->limited | new->section->limited;
+
+ section->op = new->op;
+
+ section->first = apr_pmemdup(p, base->section,
+ sizeof(*base->section));
+ section->first->next = apr_pmemdup(p, new->section,
+ sizeof(*new->section));
+ } else {
+ section = apr_pmemdup(p, base->section,
+ sizeof(*base->section));
+ }
+ }
+ else {
+ section = apr_pmemdup(p, new->section, sizeof(*new->section));
+ }
+
+ conf = apr_palloc(p, sizeof(*conf));
+
+ conf->section = section;
+ conf->op = new->op;
}
return (void*)conf;
@@ -257,7 +267,7 @@
/* Walk the subsection configuration to get the per_dir config that we will
* merge just before the real provider is called.
*/
- cmd->override = OR_ALL|ACCESS_CONF;
+ cmd->override = OR_AUTHCFG | ACCESS_CONF;
errmsg = ap_walk_config(cmd->directive->first_child, cmd,
new_authz_config);
cmd->override = old_overrides;
@@ -304,239 +314,95 @@
return errmsg;
}
-static void walk_merge_provider_list(apr_pool_t *a, authz_core_dir_conf *conf, authz_provider_list *providers)
+static authz_section_conf* create_default_section(apr_pool_t *p,
+ int old_require)
{
- authz_provider_list *newp = (authz_provider_list *)apr_palloc(a, sizeof(authz_provider_list));
- memcpy(newp, providers, sizeof(authz_provider_list));
+ authz_section_conf *section = apr_pcalloc(p, sizeof(*section));
- /* Since the merge is being done at a later time rather than
- at configuration time, we need to fake the current
- state of the list so that the new element get merged
- into the correct location. The current state is
- derived from the state of the object to be merged. */
- conf->req_state = newp->req_state;
- conf->req_state_level = newp->req_state_level;
- newp->one_next = NULL;
- newp->all_next = NULL;
-
- /* Merge it into the existing provider logic. */
- merge_authz_provider(conf, newp);
-
- /* Walk all of the elements recursively to allow each existing
- element to be copied and merged into the final configuration.*/
- if (BASE_REQ_STATE == AUTHZ_REQSTATE_ONE) {
- if (providers->one_next) {
- walk_merge_provider_list (a, conf, providers->one_next);
- }
- if (providers->all_next) {
- walk_merge_provider_list (a, conf, providers->all_next);
- }
- }
- else {
- if (providers->all_next) {
- walk_merge_provider_list (a, conf, providers->all_next);
- }
- if (providers->one_next) {
- walk_merge_provider_list (a, conf, providers->one_next);
- }
- }
+ section->op = old_require ? AUTHZ_LOGIC_OR : AUTHZ_LOGIC_AND;
- return;
+ return section;
}
-static const char *merge_authz_provider(authz_core_dir_conf *conf, authz_provider_list *newp)
+static const char *add_authz_provider(cmd_parms *cmd, void *config,
+ const char *args)
{
- /* Add it to the list now. */
- if (!conf->providers) {
- conf->providers = newp;
- }
- else {
- authz_provider_list *last = conf->providers;
- int level = conf->req_state_level;
-
- /* if the level is the base level then take care of the implicit
- * operation at this level.
- */
- if (level == BASE_REQ_LEVEL) {
- if (conf->req_state == AUTHZ_REQSTATE_ONE) {
- /* Just run through the Require_one list and add the
- * node
- */
- while (last->one_next) {
- last = last->one_next;
- }
- last->one_next = newp;
- }
- else {
- /* Just run through the Require_all list and add the
- * node
- */
- while (last->all_next) {
- last = last->all_next;
- }
- last->all_next = newp;
- }
- }
+ authz_core_dir_conf *conf = (authz_core_dir_conf*)config;
+ authz_section_conf *section = apr_pcalloc(cmd->pool, sizeof(*section));
+ authz_section_conf *child;
- /* if the last nodes level is greater than the new nodes
- * level, then we need to insert the new node at this
- * point. The req_state of the new node determine
- * how it is inserted into the list.
- */
- else if (last->req_state_level > newp->req_state_level) {
- if (newp->req_state == AUTHZ_REQSTATE_ONE)
- newp->one_next = last;
- else
- newp->all_next = last;
- conf->providers = newp;
+ if (!strcasecmp(cmd->cmd->name, "Require")) {
+ if (conf->section && !conf->old_require) {
+ return "Require directive not allowed with "
+ "Match and related directives";
}
- else {
- /* Traverse the list to find the last entry.Each level
- * indicates a transition in the logic.
- */
- for (;level;level--) {
- /* if we are in a Require_all block then run through
- * all of the Require_all nodes to the end of the list.
- * Stop if we run into a node whose level is greater than
- * the level of the node that is being inserted.
- */
- if (last->req_state == AUTHZ_REQSTATE_ALL) {
- while ((last->all_next) && (last->all_next->req_state_level <= conf->req_state_level)) {
- last = last->all_next;
- }
- /* If the end of the list contains a node state
- * change then run through all of the Require_one
- * nodes to the end of that list
- */
- if (level >= last->req_state_level) {
- while (last->one_next) {
- last = last->one_next;
- }
- }
- continue;
- }
- /* if we are in a Require_one block then run through
- * all of the Require_one nodes to the end of the list
- */
- if (last->req_state == AUTHZ_REQSTATE_ONE) {
- while (last->one_next) {
- last = last->one_next;
- }
- /* If the end of the list contains a node state
- * change then run through all of the Require_all
- * nodes to the end of that list
- */
- if (level >= last->req_state_level) {
- while (last->all_next) {
- last = last->all_next;
- }
- }
- continue;
- }
- }
- /* The current state flag indicates which way the transition should
- * go. If ALL then take the all_next path, otherwise one_next
- */
- if (last->req_state == AUTHZ_REQSTATE_ALL) {
- /* If we already have an all_next node, then
- * we must have dropped back a level so assign
- * the node to one_next
- */
- if (!last->all_next) {
- last->all_next = newp;
- }
- /* If the level of the new node is greater than the
- * last node, then insert the new node at this point.
- * The req_state of the new node will determine
- * how the node is added to the list.
- */
- else if (last->req_state_level <= newp->req_state_level) {
- if (newp->req_state == AUTHZ_REQSTATE_ONE)
- newp->one_next = last->all_next;
- else
- newp->all_next = last->all_next;
- last->all_next = newp;
- }
- else {
- last->one_next = newp;
- }
- }
- else {
- /* If we already have a one_next node, then
- * we must have dropped back a level so assign
- * the node to all_next
- */
- if (!last->one_next) {
- last->one_next = newp;
- }
- /* If the level of the new node is greater than the
- * last node, then insert the new node at this point.
- * The req_state of the new node will determine
- * how the node is added to the list.
- */
- else if (last->req_state_level <= newp->req_state_level) {
- if (newp->req_state == AUTHZ_REQSTATE_ONE)
- newp->one_next = last->one_next;
- else
- newp->all_next = last->one_next;
- last->one_next = newp;
- }
- else {
- last->all_next = newp;
- }
- }
- }
+ conf->old_require = 1;
+ }
+ else if (conf->old_require) {
+ return "Match directive not allowed with Require directives";
}
- return NULL;
-}
-
-static const char *add_authz_provider(cmd_parms *cmd, void *config,
- const char *args)
-{
- authz_core_dir_conf *conf = (authz_core_dir_conf*)config;
- authz_provider_list *newp;
- const char *t, *w;
-
- newp = apr_pcalloc(cmd->pool, sizeof(authz_provider_list));
+ section->provider_name = ap_getword_conf(cmd->pool, &args);
- t = args;
- w = ap_getword_white(cmd->pool, &t);
+ if (!conf->old_require && !strcasecmp(section->provider_name, "not")) {
+ section->provider_name = ap_getword_conf(cmd->pool, &args);
+ section->negate = 1;
+ }
- if (w)
- newp->provider_name = apr_pstrdup(cmd->pool, w);
- if (t)
- newp->requirement = apr_pstrdup(cmd->pool, t);
- newp->method_mask = cmd->limited;
+ section->provider_args = args;
/* lookup and cache the actual provider now */
- newp->provider = ap_lookup_provider(AUTHZ_PROVIDER_GROUP,
- newp->provider_name,
- AUTHZ_PROVIDER_VERSION);
- newp->req_state = conf->req_state;
- newp->req_state_level = conf->req_state_level;
- newp->is_reject = (cmd->info != NULL);
+ section->provider = ap_lookup_provider(AUTHZ_PROVIDER_GROUP,
+ section->provider_name,
+ AUTHZ_PROVIDER_VERSION);
/* by the time the config file is used, the provider should be loaded
* and registered with us.
*/
- if (newp->provider == NULL) {
+ if (!section->provider) {
return apr_psprintf(cmd->pool,
"Unknown Authz provider: %s",
- newp->provider_name);
+ section->provider_name);
}
/* if the provider doesn't provide the appropriate function, reject it */
- if (!newp->provider->check_authorization) {
+ if (!section->provider->check_authorization) {
return apr_psprintf(cmd->pool,
"The '%s' Authz provider is not supported by any "
- "of the loaded authorization modules ",
- newp->provider_name);
+ "of the loaded authorization modules",
+ section->provider_name);
+ }
+
+ section->limited = cmd->limited;
+
+ if (!conf->section) {
+ conf->section = create_default_section(cmd->pool, conf->old_require);
+ }
+
+ if (section->negate && conf->section->op == AUTHZ_LOGIC_OR) {
+ return apr_psprintf(cmd->pool, "negative %s directive has no effect "
+ "in %s directive",
+ cmd->cmd->name,
+ FORMAT_AUTHZ_COMMAND(cmd->pool, conf->section));
}
- /* Add the element to the list. */
- return merge_authz_provider(conf, newp);
+ conf->section->limited |= section->limited;
+
+ child = conf->section->first;
+
+ if (child) {
+ while (child->next) {
+ child = child->next;
+ }
+
+ child->next = section;
+ }
+ else {
+ conf->section->first = section;
+ }
+
+ return NULL;
}
static const char *add_authz_section(cmd_parms *cmd, void *mconfig,
@@ -544,10 +410,18 @@
{
authz_core_dir_conf *conf = mconfig;
const char *endp = ap_strrchr_c(args, '>');
- authz_request_state old_reqstate;
+ authz_section_conf *old_section = conf->section;
+ authz_section_conf *section;
int old_overrides = cmd->override;
+ apr_int64_t old_limited = cmd->limited;
const char *errmsg;
+ if (conf->old_require) {
+ return apr_pstrcat(cmd->pool, cmd->cmd->name,
+ "> directive not allowed with "
+ "Require directives", NULL);
+ }
+
if (endp == NULL) {
return apr_pstrcat(cmd->pool, cmd->cmd->name,
"> directive missing closing '>'", NULL);
@@ -557,203 +431,310 @@
if (args[0]) {
return apr_pstrcat(cmd->pool, cmd->cmd->name,
- "> directive doesn't take additional arguments", NULL);
+ "> directive doesn't take additional arguments",
+ NULL);
}
- /* Save off the current request state so that we can go back to it after walking
- * the subsection. Indicate a transition in the logic incrementing the level.
- * After the subsection walk the level will be decremented to indicate the
- * path to follow. As the require directives are read by the configuration
- * the req_state and the level will allow it to traverse the list to find
- * the last element in the provider calling list.
- */
- old_reqstate = conf->req_state;
- if (strcasecmp (cmd->directive->directive, "<SatisfyAll") == 0) {
- conf->req_state = AUTHZ_REQSTATE_ALL;
+ section = apr_pcalloc(cmd->pool, sizeof(*section));
+
+ if (!strcasecmp(cmd->cmd->name, "<MatchAll")) {
+ section->op = AUTHZ_LOGIC_AND;
+ }
+ else if (!strcasecmp(cmd->cmd->name, "<MatchAny")) {
+ section->op = AUTHZ_LOGIC_OR;
+ }
+ else if (!strcasecmp(cmd->cmd->name, "<MatchNotAll")) {
+ section->op = AUTHZ_LOGIC_AND;
+ section->negate = 1;
}
else {
- conf->req_state = AUTHZ_REQSTATE_ONE;
+ section->op = AUTHZ_LOGIC_OR;
+ section->negate = 1;
}
- conf->req_state_level++;
- cmd->override = OR_ALL|ACCESS_CONF;
- /* Walk the subsection configuration to get the per_dir config that we will
- * merge just before the real provider is called.
- */
- errmsg = ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
+ conf->section = section;
+
+ /* trigger NOT_IN_LIMIT errors as if this were a <Limit> directive */
+ cmd->limited &= ~(AP_METHOD_BIT << (METHODS - 1));
- conf->req_state_level--;
- conf->req_state = old_reqstate;
+ cmd->override = OR_AUTHCFG;
+ errmsg = ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
cmd->override = old_overrides;
- return errmsg;
+ cmd->limited = old_limited;
+
+ conf->section = old_section;
+
+ if (errmsg) {
+ return errmsg;
+ }
+
+ if (section->first) {
+ authz_section_conf *child;
+
+ if (!old_section) {
+ old_section = conf->section = create_default_section(cmd->pool, 0);
+ }
+
+ if (section->negate && old_section->op == AUTHZ_LOGIC_OR) {
+ return apr_psprintf(cmd->pool, "%s directive has "
+ "no effect in %s directive",
+ FORMAT_AUTHZ_COMMAND(cmd->pool, section),
+ FORMAT_AUTHZ_COMMAND(cmd->pool, old_section));
+ }
+
+ old_section->limited |= section->limited;
+
+ if (!section->negate && section->op == old_section->op) {
+ /* be associative */
+ section = section->first;
+ }
+
+ child = old_section->first;
+
+ if (child) {
+ while (child->next) {
+ child = child->next;
+ }
+
+ child->next = section;
+ }
+ else {
+ old_section->first = section;
+ }
+ }
+ else {
+ return apr_pstrcat(cmd->pool,
+ FORMAT_AUTHZ_COMMAND(cmd->pool, section),
+ " directive contains no authorization directives",
+ NULL);
+ }
+
+ return NULL;
}
-static const command_rec authz_cmds[] =
+static const char *authz_merge_sections(cmd_parms *cmd, void *mconfig,
+ const char *arg)
{
- AP_INIT_RAW_ARGS("Require", add_authz_provider, NULL, OR_AUTHCFG,
- "Selects which authenticated users or groups may access "
- "a protected space"),
- AP_INIT_RAW_ARGS("Reject", add_authz_provider, (void*)1, OR_AUTHCFG,
- "Rejects the specified authenticated users groups or "
- "host based requests from accessing a protected space"),
- AP_INIT_RAW_ARGS("<RequireAlias", authz_require_alias_section, NULL, RSRC_CONF,
- "Container for authorization directives grouped under "
- "an authz provider alias"),
- AP_INIT_RAW_ARGS("<SatisfyAll", add_authz_section, NULL, OR_AUTHCFG,
- "Container for grouping require statements that must all "
- "succeed for authorization to be granted"),
- AP_INIT_RAW_ARGS("<SatisfyOne", add_authz_section, NULL, OR_AUTHCFG,
- "Container for grouping require statements of which one "
- "must succeed for authorization to be granted"),
- AP_INIT_FLAG("AuthzMergeRules", ap_set_flag_slot,
- (void *)APR_OFFSETOF(authz_core_dir_conf, merge_rules), OR_AUTHCFG,
- "Set to 'on' to allow the parent's <Directory> or <Location> authz rules "
- "to be merged into the current <Directory> or <Location>. Set to 'off' "
- "to disable merging. If set to 'off', only the authz rules defined in "
- "the current <Directory> or <Location> block will apply. The default is 'on'."),
- {NULL}
-};
+ authz_core_dir_conf *conf = mconfig;
+
+ if (!strcasecmp(arg, "Off")) {
+ conf->op = AUTHZ_LOGIC_OFF;
+ }
+ else if (!strcasecmp(arg, "MatchAll")) {
+ conf->op = AUTHZ_LOGIC_AND;
+ }
+ else if (!strcasecmp(arg, "MatchAny")) {
+ conf->op = AUTHZ_LOGIC_OR;
+ }
+ else {
+ return apr_pstrcat(cmd->pool, cmd->cmd->name, " must be one of: "
+ "Off | MatchAll | MatchAny", NULL);
+ }
-#define RESOLVE_NEUTRAL(orig,new) (new == AUTHZ_NEUTRAL) ? orig : new;
+ return NULL;
+}
-static authz_status check_provider_list (request_rec *r, authz_provider_list *current_provider, int prev_level)
+static int authz_core_check_section(apr_pool_t *p, server_rec *s,
+ authz_section_conf *section, int is_conf)
{
- authz_status auth_result = AUTHZ_DENIED;
+ authz_section_conf *prev = NULL;
+ authz_section_conf *child = section->first;
+ int ret = !OK;
- const authz_provider *provider;
-
- provider = current_provider->provider;
- apr_table_setn(r->notes, AUTHZ_PROVIDER_NAME_NOTE,
- current_provider->provider_name);
+ while (child) {
+ if (!child->negate) {
+ ret = OK;
+ break;
+ }
- /* check to make sure that the request method requires
- * authorization before calling the provider
- */
- if (!(current_provider->method_mask &
- (AP_METHOD_BIT << r->method_number))) {
- return AUTHZ_DENIED;
+ child = child->next;
}
- auth_result = provider->check_authorization(r,
- current_provider->requirement);
+ if (ret != OK) {
+ ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, APR_SUCCESS, s,
+ apr_pstrcat(p, (is_conf
+ ? "<Directory>, <Location>, or similar"
+ : FORMAT_AUTHZ_COMMAND(p, section)),
+ " directive contains only negative "
+ "authorization directives", NULL));
- if (auth_result == AUTHZ_GENERAL_ERROR) {
- return auth_result;
+ return ret;
}
- if (current_provider->is_reject) {
- /* If the provider was called through a reject directive, then
- alter the result accordingly. If the original result was
- Denied then the new result is Neutral since we can not grant
- access simply because authorization was not rejected. */
- auth_result = auth_result == AUTHZ_DENIED ? AUTHZ_NEUTRAL : AUTHZ_DENIED;
- }
+ child = section->first;
- apr_table_unset(r->notes, AUTHZ_PROVIDER_NAME_NOTE);
-
- /* If the current node is a Require_One type */
- if (current_provider->req_state == AUTHZ_REQSTATE_ONE) {
- /* If the auth_result of *this* node was GRANTED and we are
- * embedded in a Require_all block then look to see if there
- * is another Require_all node that needs to be satisfied
- */
- if ((auth_result == AUTHZ_GRANTED) || (auth_result == AUTHZ_NEUTRAL)) {
- if ((current_provider->all_next) &&
- (current_provider->all_next->req_state_level < current_provider->req_state_level)) {
- authz_status temp_result = check_provider_list (r, current_provider->all_next,
- current_provider->req_state_level);
- auth_result = RESOLVE_NEUTRAL(auth_result, temp_result);
+ while (child) {
+ if (child->first) {
+ if (authz_core_check_section(p, s, child, 0) != OK) {
+ return !OK;
+ }
+
+ if (child->negate && child->op != section->op) {
+ authz_section_conf *next = child->next;
+
+ /* avoid one level of recursion when De Morgan permits */
+ child = child->first;
+
+ if (prev) {
+ prev->next = child;
+ }
+ else {
+ section->first = child;
+ }
+
+ do {
+ child->negate = !child->negate;
+ } while (child->next && (child = child->next));
+
+ child->next = next;
}
- return auth_result;
}
- one_next:
- /* Traverse forward to the next Require_one node it one exists
- * otherwise just return the auth_result
- */
- if (current_provider->one_next) {
- authz_status temp_result = check_provider_list (r, current_provider->one_next,
- current_provider->req_state_level);
- auth_result = RESOLVE_NEUTRAL(auth_result, temp_result);
- }
- else
- return auth_result;
-
- /* If the *last* auth_result was GRANTED and we are embedded in
- * a Require_all block then look to see if there is another
- * Require_all node that needs to be satisfied
- */
- if (((auth_result == AUTHZ_GRANTED) || (auth_result == AUTHZ_NEUTRAL))
- && (current_provider->all_next)
- && (current_provider->all_next->req_state_level < current_provider->req_state_level)) {
- authz_status temp_result = check_provider_list (r, current_provider->all_next,
- current_provider->req_state_level);
- auth_result = RESOLVE_NEUTRAL(auth_result, temp_result);
- }
- /* If the *last* auth_result was DENIED and we are inside of a
- * Require_one block then look to see if there is another
- * Require_one node that can be satisfied
- */
- else if ((auth_result == AUTHZ_DENIED)
- && (current_provider->one_next)
- && (current_provider->one_next->req_state_level < current_provider->req_state_level)) {
- goto one_next;
+ prev = child;
+ child = child->next;
+ }
+
+ return OK;
+}
+
+static int authz_core_pre_config(apr_pool_t *p, apr_pool_t *plog,
+ apr_pool_t *ptemp)
+{
+ authz_core_first_dir_conf = NULL;
+
+ return OK;
+}
+
+static int authz_core_check_config(apr_pool_t *p, apr_pool_t *plog,
+ apr_pool_t *ptemp, server_rec *s)
+{
+ authz_core_dir_conf *conf = authz_core_first_dir_conf;
+
+ while (conf) {
+ if (conf->section && !conf->old_require) {
+ if (authz_core_check_section(p, s, conf->section, 1) != OK) {
+ return !OK;
+ }
}
+ conf = conf->next;
+ }
+
+ return OK;
+}
+
+static const command_rec authz_cmds[] =
+{
+ AP_INIT_RAW_ARGS("<AuthzProviderAlias", authz_require_alias_section,
+ NULL, RSRC_CONF,
+ "container for grouping an authorization provider's "
+ "directives under a provider alias"),
+ AP_INIT_RAW_ARGS("Require", add_authz_provider, NULL, OR_AUTHCFG,
+ "specifies legacy authorization directives "
+ "of which one must pass "
+ "for a request to suceeed"),
+ AP_INIT_RAW_ARGS("Match", add_authz_provider, NULL, OR_AUTHCFG,
+ "specifies authorization directives that must pass "
+ "(or not) for a request to suceeed"),
+ AP_INIT_RAW_ARGS("<MatchAll", add_authz_section, NULL, OR_AUTHCFG,
+ "container for grouping authorization directives "
+ "of which none must fail and at least one must pass " "for a request to succeed"),
+ AP_INIT_RAW_ARGS("<MatchAny", add_authz_section, NULL, OR_AUTHCFG,
+ "container for grouping authorization directives "
+ "of which one must pass "
+ "for a request to succeed"),
+ AP_INIT_RAW_ARGS("<MatchNotAll", add_authz_section, NULL, OR_AUTHCFG,
+ "container for grouping authorization directives "
+ "of which some must fail or none must pass "
+ "for a request to succeed"),
+ AP_INIT_RAW_ARGS("<MatchNotAny", add_authz_section, NULL, OR_AUTHCFG,
+ "container for grouping authorization directives "
+ "of which none must pass "
+ "for a request to succeed"),
+ AP_INIT_TAKE1("MergeAuthz", authz_merge_sections, NULL, OR_AUTHCFG,
+ "controls how a <Directory>, <Location>, or similar "
+ "directive's authorization directives are combined with "
+ "those of its predecessor"),
+ {NULL}
+};
+
+static authz_status apply_authz_sections(request_rec *r,
+ authz_section_conf *section,
+ authz_logic_op parent_op)
+{
+ authz_status auth_result;
+
+ /* check to make sure that the request method requires authorization */
+ if (!(section->limited & (AP_METHOD_BIT << r->method_number))) {
+ auth_result =
+ (parent_op == AUTHZ_LOGIC_AND) ? AUTHZ_GRANTED : AUTHZ_NEUTRAL;
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
+ "authorization result of %s: %s "
+ "(directive limited to other methods)",
+ FORMAT_AUTHZ_COMMAND(r->pool, section),
+ FORMAT_AUTHZ_RESULT(auth_result));
+
return auth_result;
}
- /* If the current node is a Require_All type */
- if (current_provider->req_state == AUTHZ_REQSTATE_ALL) {
- /* if the auth_result of *this* node was DENIED and we are
- * embedded in a Require_one block then look to see if there
- * is another Require_one node that can be satisfied
- */
- if (auth_result == AUTHZ_DENIED) {
- if ((current_provider->one_next) &&
- (current_provider->one_next->req_state_level < current_provider->req_state_level)) {
- authz_status temp_result = check_provider_list (r, current_provider->one_next,
- current_provider->req_state_level);
- auth_result = RESOLVE_NEUTRAL(auth_result, temp_result);
+ if (section->provider) {
+ apr_table_setn(r->notes, AUTHZ_PROVIDER_NAME_NOTE,
+ section->provider_name);
+
+ auth_result =
+ section->provider->check_authorization(r, section->provider_args);
+
+ apr_table_unset(r->notes, AUTHZ_PROVIDER_NAME_NOTE);
+ }
+ else {
+ authz_section_conf *child = section->first;
+
+ auth_result = AUTHZ_NEUTRAL;
+
+ while (child) {
+ authz_status child_result;
+
+ child_result = apply_authz_sections(r, child, section->op);
+
+ if (child_result == AUTHZ_GENERAL_ERROR) {
+ return AUTHZ_GENERAL_ERROR;
+ }
+
+ if (child_result != AUTHZ_NEUTRAL) {
+ auth_result = child_result;
+
+ if ((section->op == AUTHZ_LOGIC_AND
+ && child_result == AUTHZ_DENIED)
+ || (section->op == AUTHZ_LOGIC_OR
+ && child_result == AUTHZ_GRANTED)) {
+ break;
+ }
}
- return auth_result;
+
+ child = child->next;
}
- all_next:
+ }
- /* Traverse forward to the next Require_all node it one exists
- * otherwise just return the auth_result
- */
- if (current_provider->all_next) {
- authz_status temp_result = check_provider_list (r, current_provider->all_next,
- current_provider->req_state_level);
- auth_result = RESOLVE_NEUTRAL(auth_result, temp_result);
- }
- else
- return auth_result;
-
- /* if the *last* auth_result was DENIED and we are embedded
- * in a Require_one block then look to see if there is another
- * Require_one node that can be satisfied
- */
- if ((auth_result == AUTHZ_DENIED)
- && (current_provider->one_next)
- && (current_provider->one_next->req_state_level < current_provider->req_state_level)) {
- authz_status temp_result = check_provider_list (r, current_provider->one_next,
- current_provider->req_state_level);
- auth_result = RESOLVE_NEUTRAL(auth_result, temp_result);
- }
- /* If the *last* auth_result was GRANTED and we are inside of a
- * Require_all block then look to see if there is another
- * Require_all node that needs to be satisfied
- */
- else if (((auth_result == AUTHZ_GRANTED) || (auth_result == AUTHZ_NEUTRAL))
- && (current_provider->all_next)
- && (current_provider->all_next->req_state_level < current_provider->req_state_level)) {
- goto all_next;
+ if (section->negate) {
+ if (auth_result == AUTHZ_GRANTED) {
+ auth_result = AUTHZ_DENIED;
+ }
+ else if (auth_result == AUTHZ_DENIED) {
+ /* For negated directives, if the original result was denied
+ * then the new result is neutral since we can not grant
+ * access simply because authorization was not rejected.
+ */
+ auth_result = AUTHZ_NEUTRAL;
}
}
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
+ "authorization result of %s: %s",
+ FORMAT_AUTHZ_COMMAND(r->pool, section),
+ FORMAT_AUTHZ_RESULT(auth_result));
+
return auth_result;
}
@@ -761,89 +742,70 @@
{
authz_core_dir_conf *conf;
authz_status auth_result;
- authz_provider_list *current_provider;
- const char *note = apr_table_get(r->notes, AUTHZ_ACCESS_PASSED_NOTE);
conf = ap_get_module_config(r->per_dir_config, &authz_core_module);
- /* If we're not really configured for providers, stop now. */
- if (!conf->providers) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "no authorization providers configured");
- return DECLINED;
- }
-
- /* run through the require logic. */
- current_provider = conf->providers;
- auth_result = check_provider_list (r, current_provider, 0);
-
- if (auth_result != AUTHZ_GRANTED) {
- int return_code;
-
- switch (auth_result) {
- case AUTHZ_DENIED:
- case AUTHZ_NEUTRAL:
- /* XXX If the deprecated Satisfy directive is set to anything
- but ANY a failure in access control or authz will cause
- an HTTP_UNAUTHORIZED. Just the if statement
- should be removed in 3.0 when the Satisfy directive
- goes away. */
- if (!note || (ap_satisfies(r) != SATISFY_ANY) || (note[0] == 'N')) {
- if (r->ap_auth_type == NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "client denied by server configuration: %s%s",
- r->filename ? "" : "uri ",
- r->filename ? r->filename : r->uri);
- return_code = HTTP_FORBIDDEN;
- }
- else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "user %s: authorization failure for \"%s\": ",
- r->user, r->uri);
- return_code = HTTP_UNAUTHORIZED;
- }
- }
- else {
- return_code = DECLINED;
- }
- break;
- case AUTHZ_GENERAL_ERROR:
- default:
- /* We'll assume that the module has already said what its
- * error was in the logs.
- */
- return_code = HTTP_INTERNAL_SERVER_ERROR;
- break;
- }
+ if (!conf->section) {
+ if (ap_auth_type(r)) {
+ /* there's an AuthType configured, but no authorization
+ * directives applied to support it
+ */
- /* If we're returning 403, tell them to try again. */
- if (return_code == HTTP_UNAUTHORIZED) {
- ap_note_auth_failure (r);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r,
+ "AuthType configured with no corresponding "
+ "authorization directives");
+
+ return HTTP_INTERNAL_SERVER_ERROR;
}
- return return_code;
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
+ "authorization result: granted (no directives)");
+
+ return OK;
}
- return OK;
+ auth_result = apply_authz_sections(r, conf->section, AUTHZ_LOGIC_AND);
+
+ if (auth_result == AUTHZ_GRANTED) {
+ return OK;
+ }
+ else if (auth_result == AUTHZ_DENIED || auth_result == AUTHZ_NEUTRAL) {
+ if (r->ap_auth_type == NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r,
+ "client denied by server configuration: %s%s",
+ r->filename ? "" : "uri ",
+ r->filename ? r->filename : r->uri);
+
+ return HTTP_FORBIDDEN;
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r,
+ "user %s: authorization failure for \"%s\": ",
+ r->user, r->uri);
+
+ /* If we're returning 403, tell them to try again. */
+ ap_note_auth_failure(r);
+
+ return HTTP_UNAUTHORIZED;
+ }
+ }
+ else {
+ /* We'll assume that the module has already said what its
+ * error was in the logs.
+ */
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
}
static int authz_some_auth_required(request_rec *r)
{
authz_core_dir_conf *conf;
- authz_provider_list *current_provider;
conf = ap_get_module_config(r->per_dir_config, &authz_core_module);
- current_provider = conf->providers;
-
- while (current_provider) {
-
- /* Does this provider config apply for this method */
- if (current_provider->method_mask &
- (AP_METHOD_BIT << r->method_number)) {
- return 1;
- }
-
- current_provider = current_provider->one_next;
+ if (conf->section
+ && (conf->section->limited & (AP_METHOD_BIT << r->method_number))) {
+ return 1;
}
return 0;
@@ -853,7 +815,9 @@
{
APR_REGISTER_OPTIONAL_FN(authz_some_auth_required);
- ap_hook_check_authz(authorize_user, NULL, NULL, APR_HOOK_MIDDLE,
+ ap_hook_pre_config(authz_core_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_check_config(authz_core_check_config, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_check_authz(authorize_user, NULL, NULL, APR_HOOK_LAST,
AP_AUTH_INTERNAL_PER_CONF);
}
Modified: httpd/httpd/trunk/modules/aaa/mod_authz_default.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_authz_default.c?rev=709838&r1=709837&r2=709838&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/aaa/mod_authz_default.c (original)
+++ httpd/httpd/trunk/modules/aaa/mod_authz_default.c Sat Nov 1 21:01:32 2008
@@ -56,12 +56,6 @@
{
authz_default_config_rec *conf = ap_get_module_config(r->per_dir_config,
&authz_default_module);
- const char *note = apr_table_get(r->notes, AUTHZ_ACCESS_PASSED_NOTE);
-
- /* If we got here and access checker passed, assume access is OK */
- if (note && (note[0] == 'Y') && (ap_satisfies(r) == SATISFY_ANY)) {
- return OK;
- }
/* If we got here and there isn't any authz required, assume access is OK */
if (!ap_some_auth_required(r)) {