1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Security options etc.
20 * Module derived from code originally written by Rob McCool
24 #include "apr_strings.h"
25 #include "apr_network_io.h"
28 #define APR_WANT_STRFUNC
29 #define APR_WANT_BYTEFUNC
32 #include "ap_config.h"
34 #include "http_config.h"
35 #include "http_core.h"
37 #include "http_request.h"
38 #include "http_protocol.h"
39 #include "ap_provider.h"
44 #if APR_HAVE_NETINET_IN_H
45 #include <netinet/in.h>
48 #undef AUTHZ_EXTRA_CONFIGS
50 typedef struct provider_alias_rec {
54 const void *provider_parsed_args;
55 ap_conf_vector_t *sec_auth;
56 const authz_provider *provider;
66 typedef struct authz_section_conf authz_section_conf;
68 struct authz_section_conf {
69 const char *provider_name;
70 const char *provider_args;
71 const void *provider_parsed_args;
72 const authz_provider *provider;
76 /** true if this is not a real container but produced by AuthMerging;
77 * only used for logging */
79 authz_section_conf *first;
80 authz_section_conf *next;
83 typedef struct authz_core_dir_conf authz_core_dir_conf;
85 struct authz_core_dir_conf {
86 authz_section_conf *section;
87 authz_core_dir_conf *next;
89 signed char authz_forbidden_on_fail;
94 typedef struct authz_core_srv_conf {
95 apr_hash_t *alias_rec;
96 } authz_core_srv_conf;
98 module AP_MODULE_DECLARE_DATA authz_core_module;
100 static authz_core_dir_conf *authz_core_first_dir_conf;
102 static void *create_authz_core_dir_config(apr_pool_t *p, char *dummy)
104 authz_core_dir_conf *conf = apr_pcalloc(p, sizeof(*conf));
106 conf->op = AUTHZ_LOGIC_UNSET;
107 conf->authz_forbidden_on_fail = UNSET;
109 conf->next = authz_core_first_dir_conf;
110 authz_core_first_dir_conf = conf;
115 static void *merge_authz_core_dir_config(apr_pool_t *p,
116 void *basev, void *newv)
118 authz_core_dir_conf *base = (authz_core_dir_conf *)basev;
119 authz_core_dir_conf *new = (authz_core_dir_conf *)newv;
120 authz_core_dir_conf *conf;
122 if (new->op == AUTHZ_LOGIC_UNSET && !new->section && base->section ) {
123 /* Only authz_forbidden_on_fail has been set in new. Don't treat
124 * it as a new auth config w.r.t. AuthMerging */
125 conf = apr_pmemdup(p, base, sizeof(*base));
127 else if (new->op == AUTHZ_LOGIC_OFF || new->op == AUTHZ_LOGIC_UNSET ||
128 !(base->section || new->section)) {
129 conf = apr_pmemdup(p, new, sizeof(*new));
132 authz_section_conf *section;
136 section = apr_pcalloc(p, sizeof(*section));
139 base->section->limited | new->section->limited;
141 section->op = new->op;
142 section->is_merged = 1;
144 section->first = apr_pmemdup(p, base->section,
145 sizeof(*base->section));
146 section->first->next = apr_pmemdup(p, new->section,
147 sizeof(*new->section));
149 section = apr_pmemdup(p, base->section,
150 sizeof(*base->section));
154 section = apr_pmemdup(p, new->section, sizeof(*new->section));
157 conf = apr_pcalloc(p, sizeof(*conf));
159 conf->section = section;
163 if (new->authz_forbidden_on_fail == UNSET)
164 conf->authz_forbidden_on_fail = base->authz_forbidden_on_fail;
166 conf->authz_forbidden_on_fail = new->authz_forbidden_on_fail;
171 /* Only per-server directive we have is GLOBAL_ONLY */
172 static void *merge_authz_core_svr_config(apr_pool_t *p,
173 void *basev, void *newv)
178 static void *create_authz_core_svr_config(apr_pool_t *p, server_rec *s)
180 authz_core_srv_conf *authcfg;
182 authcfg = apr_pcalloc(p, sizeof(*authcfg));
183 authcfg->alias_rec = apr_hash_make(p);
185 return (void *)authcfg;
188 /* This is a fake authz provider that really merges various authz alias
189 * configurations and then invokes them.
191 static authz_status authz_alias_check_authorization(request_rec *r,
192 const char *require_args,
193 const void *parsed_require_args)
195 const char *provider_name;
196 authz_status ret = AUTHZ_DENIED;
198 /* Look up the provider alias in the alias list.
199 * Get the dir_config and call ap_Merge_per_dir_configs()
200 * Call the real provider->check_authorization() function
201 * return the result of the above function call
204 provider_name = apr_table_get(r->notes, AUTHZ_PROVIDER_NAME_NOTE);
207 authz_core_srv_conf *authcfg;
208 provider_alias_rec *prvdraliasrec;
210 authcfg = ap_get_module_config(r->server->module_config,
213 prvdraliasrec = apr_hash_get(authcfg->alias_rec, provider_name,
214 APR_HASH_KEY_STRING);
216 /* If we found the alias provider in the list, then merge the directory
217 configurations and call the real provider */
219 ap_conf_vector_t *orig_dir_config = r->per_dir_config;
222 ap_merge_per_dir_configs(r->pool, orig_dir_config,
223 prvdraliasrec->sec_auth);
225 ret = prvdraliasrec->provider->
226 check_authorization(r, prvdraliasrec->provider_args,
227 prvdraliasrec->provider_parsed_args);
229 r->per_dir_config = orig_dir_config;
232 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02305)
233 "no alias provider found for '%s' (BUG?)",
238 ap_assert(provider_name != NULL);
244 static const authz_provider authz_alias_provider =
246 &authz_alias_check_authorization,
250 static const char *authz_require_alias_section(cmd_parms *cmd, void *mconfig,
253 const char *endp = ap_strrchr_c(args, '>');
255 char *provider_alias;
257 ap_conf_vector_t *new_authz_config;
258 int old_overrides = cmd->override;
261 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
267 return apr_pstrcat(cmd->pool, cmd->cmd->name,
268 "> directive missing closing '>'", NULL);
271 args = apr_pstrndup(cmd->temp_pool, args, endp - args);
274 return apr_pstrcat(cmd->pool, cmd->cmd->name,
275 "> directive requires additional arguments", NULL);
278 /* Pull the real provider name and the alias name from the block header */
279 provider_name = ap_getword_conf(cmd->pool, &args);
280 provider_alias = ap_getword_conf(cmd->pool, &args);
281 provider_args = ap_getword_conf(cmd->pool, &args);
283 if (!provider_name[0] || !provider_alias[0]) {
284 return apr_pstrcat(cmd->pool, cmd->cmd->name,
285 "> directive requires additional arguments", NULL);
288 new_authz_config = ap_create_per_dir_config(cmd->pool);
290 /* Walk the subsection configuration to get the per_dir config that we will
291 * merge just before the real provider is called.
293 cmd->override = OR_AUTHCFG | ACCESS_CONF;
294 errmsg = ap_walk_config(cmd->directive->first_child, cmd,
296 cmd->override = old_overrides;
299 provider_alias_rec *prvdraliasrec;
300 authz_core_srv_conf *authcfg;
302 prvdraliasrec = apr_pcalloc(cmd->pool, sizeof(*prvdraliasrec));
304 /* Save off the new directory config along with the original
305 * provider name and function pointer data
307 prvdraliasrec->provider_name = provider_name;
308 prvdraliasrec->provider_alias = provider_alias;
309 prvdraliasrec->provider_args = provider_args;
310 prvdraliasrec->sec_auth = new_authz_config;
311 prvdraliasrec->provider =
312 ap_lookup_provider(AUTHZ_PROVIDER_GROUP, provider_name,
313 AUTHZ_PROVIDER_VERSION);
315 /* by the time the config file is used, the provider should be loaded
316 * and registered with us.
318 if (!prvdraliasrec->provider) {
319 return apr_psprintf(cmd->pool,
320 "Unknown Authz provider: %s",
323 if (prvdraliasrec->provider->parse_require_line) {
324 err = prvdraliasrec->provider->parse_require_line(cmd,
325 provider_args, &prvdraliasrec->provider_parsed_args);
327 return apr_psprintf(cmd->pool,
328 "Can't parse 'Require %s %s': %s",
329 provider_name, provider_args, err);
332 authcfg = ap_get_module_config(cmd->server->module_config,
335 apr_hash_set(authcfg->alias_rec, provider_alias,
336 APR_HASH_KEY_STRING, prvdraliasrec);
338 /* Register the fake provider so that we get called first */
339 ap_register_auth_provider(cmd->pool, AUTHZ_PROVIDER_GROUP,
340 provider_alias, AUTHZ_PROVIDER_VERSION,
341 &authz_alias_provider,
342 AP_AUTH_INTERNAL_PER_CONF);
348 static const char* format_authz_result(authz_status result)
350 return ((result == AUTHZ_DENIED)
352 : ((result == AUTHZ_GRANTED)
354 : ((result == AUTHZ_DENIED_NO_USER)
355 ? "denied (no authenticated user yet)"
359 static const char* format_authz_command(apr_pool_t *p,
360 authz_section_conf *section)
362 return (section->provider
363 ? apr_pstrcat(p, "Require ", (section->negate ? "not " : ""),
364 section->provider_name, " ",
365 section->provider_args, NULL)
366 : apr_pstrcat(p, section->is_merged ? "AuthMerging " : "<Require",
367 ((section->op == AUTHZ_LOGIC_AND)
368 ? (section->negate ? "NotAll" : "All")
369 : (section->negate ? "None" : "Any")),
370 section->is_merged ? "" : ">", NULL));
373 static authz_section_conf* create_default_section(apr_pool_t *p)
375 authz_section_conf *section = apr_pcalloc(p, sizeof(*section));
377 section->op = AUTHZ_LOGIC_OR;
382 static const char *add_authz_provider(cmd_parms *cmd, void *config,
385 authz_core_dir_conf *conf = (authz_core_dir_conf*)config;
386 authz_section_conf *section = apr_pcalloc(cmd->pool, sizeof(*section));
387 authz_section_conf *child;
389 section->provider_name = ap_getword_conf(cmd->pool, &args);
391 if (!strcasecmp(section->provider_name, "not")) {
392 section->provider_name = ap_getword_conf(cmd->pool, &args);
396 section->provider_args = args;
398 /* lookup and cache the actual provider now */
399 section->provider = ap_lookup_provider(AUTHZ_PROVIDER_GROUP,
400 section->provider_name,
401 AUTHZ_PROVIDER_VERSION);
403 /* by the time the config file is used, the provider should be loaded
404 * and registered with us.
406 if (!section->provider) {
407 return apr_psprintf(cmd->pool,
408 "Unknown Authz provider: %s",
409 section->provider_name);
412 /* if the provider doesn't provide the appropriate function, reject it */
413 if (!section->provider->check_authorization) {
414 return apr_psprintf(cmd->pool,
415 "The '%s' Authz provider is not supported by any "
416 "of the loaded authorization modules",
417 section->provider_name);
420 section->limited = cmd->limited;
422 if (section->provider->parse_require_line) {
424 apr_pool_userdata_setn(section->provider_name,
425 AUTHZ_PROVIDER_NAME_NOTE,
426 apr_pool_cleanup_null,
428 err = section->provider->parse_require_line(cmd, args,
429 §ion->provider_parsed_args);
435 if (!conf->section) {
436 conf->section = create_default_section(cmd->pool);
439 if (section->negate && conf->section->op == AUTHZ_LOGIC_OR) {
440 return apr_psprintf(cmd->pool, "negative %s directive has no effect "
443 format_authz_command(cmd->pool, conf->section));
446 conf->section->limited |= section->limited;
448 child = conf->section->first;
451 while (child->next) {
455 child->next = section;
458 conf->section->first = section;
464 static const char *add_authz_section(cmd_parms *cmd, void *mconfig,
467 authz_core_dir_conf *conf = mconfig;
468 const char *endp = ap_strrchr_c(args, '>');
469 authz_section_conf *old_section = conf->section;
470 authz_section_conf *section;
471 int old_overrides = cmd->override;
472 apr_int64_t old_limited = cmd->limited;
476 return apr_pstrcat(cmd->pool, cmd->cmd->name,
477 "> directive missing closing '>'", NULL);
480 args = apr_pstrndup(cmd->temp_pool, args, endp - args);
483 return apr_pstrcat(cmd->pool, cmd->cmd->name,
484 "> directive doesn't take additional arguments",
488 section = apr_pcalloc(cmd->pool, sizeof(*section));
490 if (!strcasecmp(cmd->cmd->name, "<RequireAll")) {
491 section->op = AUTHZ_LOGIC_AND;
493 else if (!strcasecmp(cmd->cmd->name, "<RequireAny")) {
494 section->op = AUTHZ_LOGIC_OR;
496 else if (!strcasecmp(cmd->cmd->name, "<RequireNotAll")) {
497 section->op = AUTHZ_LOGIC_AND;
501 section->op = AUTHZ_LOGIC_OR;
505 conf->section = section;
507 /* trigger NOT_IN_LIMIT errors as if this were a <Limit> directive */
508 cmd->limited &= ~(AP_METHOD_BIT << (METHODS - 1));
510 cmd->override = OR_AUTHCFG;
511 errmsg = ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
512 cmd->override = old_overrides;
514 cmd->limited = old_limited;
516 conf->section = old_section;
522 if (section->first) {
523 authz_section_conf *child;
526 old_section = conf->section = create_default_section(cmd->pool);
529 if (section->negate && old_section->op == AUTHZ_LOGIC_OR) {
530 return apr_psprintf(cmd->pool, "%s directive has "
531 "no effect in %s directive",
532 format_authz_command(cmd->pool, section),
533 format_authz_command(cmd->pool, old_section));
536 old_section->limited |= section->limited;
538 if (!section->negate && section->op == old_section->op) {
540 section = section->first;
543 child = old_section->first;
546 while (child->next) {
550 child->next = section;
553 old_section->first = section;
557 return apr_pstrcat(cmd->pool,
558 format_authz_command(cmd->pool, section),
559 " directive contains no authorization directives",
566 static const char *authz_merge_sections(cmd_parms *cmd, void *mconfig,
569 authz_core_dir_conf *conf = mconfig;
571 if (!strcasecmp(arg, "Off")) {
572 conf->op = AUTHZ_LOGIC_OFF;
574 else if (!strcasecmp(arg, "And")) {
575 conf->op = AUTHZ_LOGIC_AND;
577 else if (!strcasecmp(arg, "Or")) {
578 conf->op = AUTHZ_LOGIC_OR;
581 return apr_pstrcat(cmd->pool, cmd->cmd->name, " must be one of: "
582 "Off | And | Or", NULL);
588 static int authz_core_check_section(apr_pool_t *p, server_rec *s,
589 authz_section_conf *section, int is_conf)
591 authz_section_conf *prev = NULL;
592 authz_section_conf *child = section->first;
597 if (authz_core_check_section(p, s, child, 0) != OK) {
601 if (child->negate && child->op != section->op) {
602 authz_section_conf *next = child->next;
604 /* avoid one level of recursion when De Morgan permits */
605 child = child->first;
611 section->first = child;
615 child->negate = !child->negate;
616 } while (child->next && (child = child->next));
626 child = section->first;
629 if (!child->negate) {
638 ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, APR_SUCCESS, s, APLOGNO(01624)
639 "%s directive contains only negative authorization directives",
640 is_conf ? "<Directory>, <Location>, or similar"
641 : format_authz_command(p, section));
647 static int authz_core_pre_config(apr_pool_t *p, apr_pool_t *plog,
650 authz_core_first_dir_conf = NULL;
655 static int authz_core_check_config(apr_pool_t *p, apr_pool_t *plog,
656 apr_pool_t *ptemp, server_rec *s)
658 authz_core_dir_conf *conf = authz_core_first_dir_conf;
662 if (authz_core_check_section(p, s, conf->section, 1) != OK) {
673 static const command_rec authz_cmds[] =
675 AP_INIT_RAW_ARGS("<AuthzProviderAlias", authz_require_alias_section,
677 "container for grouping an authorization provider's "
678 "directives under a provider alias"),
679 AP_INIT_RAW_ARGS("Require", add_authz_provider, NULL, OR_AUTHCFG,
680 "specifies authorization directives "
681 "which one must pass (or not) for a request to suceeed"),
682 AP_INIT_RAW_ARGS("<RequireAll", add_authz_section, NULL, OR_AUTHCFG,
683 "container for grouping authorization directives "
684 "of which none must fail and at least one must pass "
685 "for a request to succeed"),
686 AP_INIT_RAW_ARGS("<RequireAny", add_authz_section, NULL, OR_AUTHCFG,
687 "container for grouping authorization directives "
688 "of which one must pass "
689 "for a request to succeed"),
690 #ifdef AUTHZ_EXTRA_CONFIGS
691 AP_INIT_RAW_ARGS("<RequireNotAll", add_authz_section, NULL, OR_AUTHCFG,
692 "container for grouping authorization directives "
693 "of which some must fail or none must pass "
694 "for a request to succeed"),
696 AP_INIT_RAW_ARGS("<RequireNone", add_authz_section, NULL, OR_AUTHCFG,
697 "container for grouping authorization directives "
698 "of which none must pass "
699 "for a request to succeed"),
700 AP_INIT_TAKE1("AuthMerging", authz_merge_sections, NULL, OR_AUTHCFG,
701 "controls how a <Directory>, <Location>, or similar "
702 "directive's authorization directives are combined with "
703 "those of its predecessor"),
704 AP_INIT_FLAG("AuthzSendForbiddenOnFailure", ap_set_flag_slot_char,
705 (void *)APR_OFFSETOF(authz_core_dir_conf, authz_forbidden_on_fail),
707 "Controls if an authorization failure should result in a "
708 "'403 FORBIDDEN' response instead of the HTTP-conforming "
709 "'401 UNAUTHORIZED'"),
713 static authz_status apply_authz_sections(request_rec *r,
714 authz_section_conf *section,
715 authz_logic_op parent_op)
717 authz_status auth_result;
719 /* check to make sure that the request method requires authorization */
720 if (!(section->limited & (AP_METHOD_BIT << r->method_number))) {
722 (parent_op == AUTHZ_LOGIC_AND) ? AUTHZ_GRANTED : AUTHZ_NEUTRAL;
724 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(01625)
725 "authorization result of %s: %s "
726 "(directive limited to other methods)",
727 format_authz_command(r->pool, section),
728 format_authz_result(auth_result));
733 if (section->provider) {
734 apr_table_setn(r->notes, AUTHZ_PROVIDER_NAME_NOTE,
735 section->provider_name);
738 section->provider->check_authorization(r, section->provider_args,
739 section->provider_parsed_args);
741 apr_table_unset(r->notes, AUTHZ_PROVIDER_NAME_NOTE);
744 authz_section_conf *child = section->first;
746 auth_result = AUTHZ_NEUTRAL;
749 authz_status child_result;
751 child_result = apply_authz_sections(r, child, section->op);
753 if (child_result == AUTHZ_GENERAL_ERROR) {
754 return AUTHZ_GENERAL_ERROR;
757 if (child_result != AUTHZ_NEUTRAL) {
759 * Handling of AUTHZ_DENIED/AUTHZ_DENIED_NO_USER: Return
760 * AUTHZ_DENIED_NO_USER if providing a user may change the
761 * result, AUTHZ_DENIED otherwise.
763 if (section->op == AUTHZ_LOGIC_AND) {
764 if (child_result == AUTHZ_DENIED) {
765 auth_result = child_result;
768 if ((child_result == AUTHZ_DENIED_NO_USER
769 && auth_result != AUTHZ_DENIED)
770 || (auth_result == AUTHZ_NEUTRAL)) {
771 auth_result = child_result;
776 if (child_result == AUTHZ_GRANTED) {
777 auth_result = child_result;
780 if ((child_result == AUTHZ_DENIED_NO_USER
781 && auth_result == AUTHZ_DENIED)
782 || (auth_result == AUTHZ_NEUTRAL)) {
783 auth_result = child_result;
792 if (section->negate) {
793 if (auth_result == AUTHZ_GRANTED) {
794 auth_result = AUTHZ_DENIED;
796 else if (auth_result == AUTHZ_DENIED ||
797 auth_result == AUTHZ_DENIED_NO_USER) {
798 /* For negated directives, if the original result was denied
799 * then the new result is neutral since we can not grant
800 * access simply because authorization was not rejected.
802 auth_result = AUTHZ_NEUTRAL;
806 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(01626)
807 "authorization result of %s: %s",
808 format_authz_command(r->pool, section),
809 format_authz_result(auth_result));
814 static int authorize_user_core(request_rec *r, int after_authn)
816 authz_core_dir_conf *conf;
817 authz_status auth_result;
819 conf = ap_get_module_config(r->per_dir_config, &authz_core_module);
821 if (!conf->section) {
822 if (ap_auth_type(r)) {
823 /* there's an AuthType configured, but no authorization
824 * directives applied to support it
827 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r, APLOGNO(01627)
828 "AuthType configured with no corresponding "
829 "authorization directives");
831 return HTTP_INTERNAL_SERVER_ERROR;
834 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(01628)
835 "authorization result: granted (no directives)");
840 auth_result = apply_authz_sections(r, conf->section, AUTHZ_LOGIC_AND);
842 if (auth_result == AUTHZ_GRANTED) {
845 else if (auth_result == AUTHZ_DENIED_NO_USER) {
847 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r, APLOGNO(01629)
848 "authorization failure (no authenticated user): %s",
851 * If we're returning 401 to an authenticated user, tell them to
852 * try again. If unauthenticated, note_auth_failure has already
853 * been called during auth.
856 ap_note_auth_failure(r);
858 return HTTP_UNAUTHORIZED;
862 * We need a user before we can decide what to do.
863 * Get out of the way and proceed with authentication.
868 else if (auth_result == AUTHZ_DENIED || auth_result == AUTHZ_NEUTRAL) {
869 if (!after_authn || ap_auth_type(r) == NULL) {
870 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r, APLOGNO(01630)
871 "client denied by server configuration: %s%s",
872 r->filename ? "" : "uri ",
873 r->filename ? r->filename : r->uri);
875 return HTTP_FORBIDDEN;
878 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r, APLOGNO(01631)
879 "user %s: authorization failure for \"%s\": ",
882 if (conf->authz_forbidden_on_fail > 0) {
883 return HTTP_FORBIDDEN;
887 * If we're returning 401 to an authenticated user, tell them to
888 * try again. If unauthenticated, note_auth_failure has already
889 * been called during auth.
892 ap_note_auth_failure(r);
893 return HTTP_UNAUTHORIZED;
898 /* We'll assume that the module has already said what its
899 * error was in the logs.
901 return HTTP_INTERNAL_SERVER_ERROR;
905 static int authorize_userless(request_rec *r)
907 return authorize_user_core(r, 0);
910 static int authorize_user(request_rec *r)
912 return authorize_user_core(r, 1);
915 static int authz_some_auth_required(request_rec *r)
917 authz_core_dir_conf *conf;
919 conf = ap_get_module_config(r->per_dir_config, &authz_core_module);
922 && (conf->section->limited & (AP_METHOD_BIT << r->method_number))) {
933 static authz_status env_check_authorization(request_rec *r,
934 const char *require_line,
935 const void *parsed_require_line)
939 /* The 'env' provider will allow the configuration to specify a list of
940 env variables to check rather than a single variable. This is different
941 from the previous host based syntax. */
943 while ((w = ap_getword_conf(r->pool, &t)) && w[0]) {
944 if (apr_table_get(r->subprocess_env, w)) {
945 return AUTHZ_GRANTED;
952 static const authz_provider authz_env_provider =
954 &env_check_authorization,
963 static authz_status all_check_authorization(request_rec *r,
964 const char *require_line,
965 const void *parsed_require_line)
967 if (parsed_require_line) {
968 return AUTHZ_GRANTED;
973 static const char *all_parse_config(cmd_parms *cmd, const char *require_line,
974 const void **parsed_require_line)
977 * If the argument to the 'all' provider is 'granted' then just let
978 * everybody in. This would be equivalent to the previous syntax of
979 * 'allow from all'. If the argument is 'denied' we reject everbody,
980 * which is equivalent to 'deny from all'.
982 if (strcasecmp(require_line, "granted") == 0) {
983 *parsed_require_line = (void *)1;
986 else if (strcasecmp(require_line, "denied") == 0) {
987 /* *parsed_require_line is already NULL */
991 return "Argument for 'Require all' must be 'granted' or 'denied'";
995 static const authz_provider authz_all_provider =
997 &all_check_authorization,
1003 * method authz provider
1006 static authz_status method_check_authorization(request_rec *r,
1007 const char *require_line,
1008 const void *parsed_require_line)
1010 const apr_int64_t *allowed = parsed_require_line;
1011 if (*allowed & (AP_METHOD_BIT << r->method_number))
1012 return AUTHZ_GRANTED;
1014 return AUTHZ_DENIED;
1017 static const char *method_parse_config(cmd_parms *cmd, const char *require_line,
1018 const void **parsed_require_line)
1021 apr_int64_t *allowed = apr_pcalloc(cmd->pool, sizeof(apr_int64_t));
1025 while ((w = ap_getword_conf(cmd->temp_pool, &t)) && w[0]) {
1026 int m = ap_method_number_of(w);
1027 if (m == M_INVALID) {
1028 return apr_pstrcat(cmd->pool, "Invalid Method '", w, "'", NULL);
1031 *allowed |= (AP_METHOD_BIT << m);
1034 *parsed_require_line = allowed;
1038 static const authz_provider authz_method_provider =
1040 &method_check_authorization,
1041 &method_parse_config,
1045 * expr authz provider
1048 #define REQUIRE_EXPR_NOTE "Require_expr_info"
1049 struct require_expr_info {
1050 ap_expr_info_t *expr;
1054 static int expr_lookup_fn(ap_expr_lookup_parms *parms)
1056 if (parms->type == AP_EXPR_FUNC_VAR
1057 && strcasecmp(parms->name, "REMOTE_USER") == 0) {
1058 struct require_expr_info *info;
1059 apr_pool_userdata_get((void**)&info, REQUIRE_EXPR_NOTE, parms->ptemp);
1060 AP_DEBUG_ASSERT(info != NULL);
1061 info->want_user = 1;
1063 return ap_expr_lookup_default(parms);
1066 static const char *expr_parse_config(cmd_parms *cmd, const char *require_line,
1067 const void **parsed_require_line)
1069 const char *expr_err = NULL;
1070 struct require_expr_info *info = apr_pcalloc(cmd->pool, sizeof(*info));
1072 /* if the expression happens to be surrounded by quotes, skip them */
1073 if (require_line[0] == '"') {
1074 apr_size_t len = strlen(require_line);
1076 if (require_line[len-1] == '"')
1077 require_line = apr_pstrndup(cmd->temp_pool,
1082 apr_pool_userdata_setn(info, REQUIRE_EXPR_NOTE, apr_pool_cleanup_null,
1084 info->expr = ap_expr_parse_cmd(cmd, require_line, 0, &expr_err,
1088 return apr_pstrcat(cmd->temp_pool,
1089 "Cannot parse expression in require line: ",
1092 *parsed_require_line = info;
1097 static authz_status expr_check_authorization(request_rec *r,
1098 const char *require_line,
1099 const void *parsed_require_line)
1101 const char *err = NULL;
1102 const struct require_expr_info *info = parsed_require_line;
1103 int rc = ap_expr_exec(r, info->expr, &err);
1106 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02320)
1107 "Error evaluating expression in 'Require expr': %s",
1109 return AUTHZ_GENERAL_ERROR;
1112 if (info->want_user)
1113 return AUTHZ_DENIED_NO_USER;
1115 return AUTHZ_DENIED;
1118 return AUTHZ_GRANTED;
1122 static const authz_provider authz_expr_provider =
1124 &expr_check_authorization,
1129 static void register_hooks(apr_pool_t *p)
1131 APR_REGISTER_OPTIONAL_FN(authz_some_auth_required);
1133 ap_hook_pre_config(authz_core_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
1134 ap_hook_check_config(authz_core_check_config, NULL, NULL, APR_HOOK_MIDDLE);
1135 ap_hook_check_authz(authorize_user, NULL, NULL, APR_HOOK_LAST,
1136 AP_AUTH_INTERNAL_PER_CONF);
1137 ap_hook_check_access_ex(authorize_userless, NULL, NULL, APR_HOOK_LAST,
1138 AP_AUTH_INTERNAL_PER_CONF);
1140 ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "env",
1141 AUTHZ_PROVIDER_VERSION,
1142 &authz_env_provider, AP_AUTH_INTERNAL_PER_CONF);
1143 ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "all",
1144 AUTHZ_PROVIDER_VERSION,
1145 &authz_all_provider, AP_AUTH_INTERNAL_PER_CONF);
1146 ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "method",
1147 AUTHZ_PROVIDER_VERSION,
1148 &authz_method_provider, AP_AUTH_INTERNAL_PER_CONF);
1149 ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "expr",
1150 AUTHZ_PROVIDER_VERSION,
1151 &authz_expr_provider, AP_AUTH_INTERNAL_PER_CONF);
1154 AP_DECLARE_MODULE(authz_core) =
1156 STANDARD20_MODULE_STUFF,
1157 create_authz_core_dir_config, /* dir config creater */
1158 merge_authz_core_dir_config, /* dir merger */
1159 create_authz_core_svr_config, /* server config */
1160 merge_authz_core_svr_config , /* merge server config */
1162 register_hooks /* register hooks */