mod_authz_core.c revision 3d81f57512275ca06a60a9bcbd23c1f8b429fdf2
/* Copyright 2002-2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Security options etc.
*
* Module derived from code originally written by Rob McCool
*
*/
#include "apr_strings.h"
#include "apr_network_io.h"
#include "apr_md5.h"
#define APR_WANT_STRFUNC
#define APR_WANT_BYTEFUNC
#include "apr_want.h"
#define CORE_PRIVATE
#include "ap_config.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_request.h"
#include "http_protocol.h"
#include "ap_provider.h"
#include "mod_auth.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?
- 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
*/
typedef struct provider_alias_rec {
char *provider_name;
char *provider_alias;
char *provider_args;
const authz_provider *provider;
typedef struct {
int req_state_level;
typedef struct authz_core_srv_conf {
{
conf->req_state_level = 0;
return (void *)conf;
}
#if 0
{
/* Create this conf by duplicating the base, replacing elements
* (or creating copies for merging) where new-> values exist.
*/
return (void*)conf;
}
#endif
{
return (void *) authcfg;
}
const char *arg)
{
const char *t, *w;
t = arg;
if (w)
if (t)
/* lookup and cache the actual provider now */
/* by the time the config file is used, the provider should be loaded
* and registered with us.
*/
"Unknown Authz provider: %s",
}
/* if the provider doesn't provide the appropriate function, reject it */
"The '%s' Authz provider is not supported by any "
"of the loaded authorization modules ",
}
/* Add it to the list now. */
}
else {
/* if the level is 0 then take care of the implicit 'or'
* operation at this level.
*/
if (level == 0) {
/* Just run through the Require_one list and add the
* node
*/
}
}
else {
/* Traverse the list to find the last entry.Each level
* indicates a transition in the logic.
*/
/* if we are in a Require_all block then run through
* all of the Require_all nodes to the end of the list
*/
}
/* 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
*/
}
}
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 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
*/
}
}
continue;
}
}
/* The current state flag indicates which way the transition should
* go. If ALL then take the all_next path, otherwise one_next
*/
/* If we already have an all_next node, then
* we must have dropped back a level so assign
* the node to one_next
*/
}
else
}
else {
/* If we already have a one_next node, then
* we must have dropped back a level so assign
* the node to all_next
*/
}
else
}
}
}
return NULL;
}
/* This is a fake authz provider that really merges various authz alias
* configurations and then envokes them.
*/
const char *require_args)
{
/* Look up the provider alias in the alias list.
* Get the the dir_config and call ap_Merge_per_dir_configs()
* Call the real provider->check_authorization() function
* return the result of the above function call
*/
if (provider_name) {
/* If we found the alias provider in the list, then merge the directory
configurations and call the real provider */
if (prvdraliasrec) {
}
}
return ret;
}
static const authz_provider authz_alias_provider =
{
};
const char *arg)
{
const char *args;
char *provider_alias;
char *provider_name;
char *provider_args;
const char *errmsg;
return err;
}
"> directive missing closing '>'", NULL);
}
if (!args[0]) {
"> directive requires additional arguments", NULL);
}
/* Pull the real provider name and the alias name from the block header */
if (!provider_name[0] || !provider_alias[0]) {
"> directive requires additional arguments", NULL);
}
/* walk the subsection configuration to get the per_dir config that we will
* merge just before the real provider is called.
*/
if (!errmsg) {
sizeof(provider_alias_rec));
provider_name,"0");
/* Save off the new directory config along with the original provider name
* and function pointer data
*/
/* Register the fake provider so that we get called first */
}
return errmsg;
}
{
const char *args;
const char *errmsg;
"> directive missing closing '>'", NULL);
}
if (args[0]) {
"> 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.
*/
}
else {
}
conf->req_state_level++;
/* Walk the subsection configuration to get the per_dir config that we will
* merge just before the real provider is called.
*/
conf->req_state_level--;
return errmsg;
}
static const command_rec authz_cmds[] =
{
"Selects which authenticated users or groups may access "
"a protected space"),
"Rejects the specified authenticated users or groups "
"from accessing "
"a protected space"),
"Container for authorization directives grouped under "
"an authz provider alias"),
"Container for grouping require statements that must all "
"succeed for authorization to be granted"),
"Container for grouping require statements of which one "
"must succeed for authorization to be granted"),
{NULL}
};
static authz_status check_provider_list (request_rec *r, authz_provider_list *current_provider, int prev_level)
{
const authz_provider *provider;
/* 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;
}
if (auth_result == AUTHZ_GENERAL_ERROR) {
return auth_result;
}
if (current_provider->is_reject) {
}
/* If the current node is a Require_One type */
/* 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) {
if ((current_provider->all_next) &&
}
return auth_result;
}
/* Traverse forward to the next Require_one node it one exists
* otherwise just return the auth_result
*/
if (current_provider->one_next) {
}
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 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
*/
goto one_next;
}
return auth_result;
}
/* If the current node is a Require_All type */
/* 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) &&
}
return auth_result;
}
/* Traverse forward to the next Require_all node it one exists
* otherwise just return the auth_result
*/
if (current_provider->all_next) {
}
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 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
*/
goto all_next;
}
}
return auth_result;
}
static int authorize_user(request_rec *r)
{
/* If we're not really configured for providers, stop now. */
"no authorization providers configured");
return DECLINED;
}
if (auth_result != AUTHZ_GRANTED) {
int return_code;
switch (auth_result) {
case AUTHZ_DENIED:
/* 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. */
"user %s: authorization failure for \"%s\": ",
}
else {
}
break;
case AUTHZ_GENERAL_ERROR:
default:
/* We'll assume that the module has already said what its
* error was in the logs.
*/
break;
}
/* If we're returning 403, tell them to try again. */
if (return_code == HTTP_UNAUTHORIZED) {
ap_note_auth_failure (r);
}
return return_code;
}
return OK;
}
static int authz_some_auth_required(request_rec *r)
{
int req_authz = 0;
while (current_provider) {
/* Does this provider config apply for this method */
if (current_provider->method_mask &
(AP_METHOD_BIT << r->method_number)) {
req_authz = 1;
break;
}
}
return req_authz;
}
static void ImportAuthzCoreOptFn(void)
{
}
static void register_hooks(apr_pool_t *p)
{
}
{
create_authz_core_dir_config, /* dir config creater */
NULL, /* dir merger --- default is to override */
create_authz_core_svr_config, /* server config */
NULL, /* merge server config */
register_hooks /* register hooks */
};