From 9707ff9fde84d3cbe49a511ea8469dc65231f207 Mon Sep 17 00:00:00 2001 From: Stefan Fritsch Date: Wed, 7 Nov 2012 13:27:54 +0000 Subject: [PATCH] mod_allowhandlers: New module to forbid specific handlers for specific directories. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1406617 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 5 +- docs/log-message-tags/next-number | 2 +- docs/manual/mod/mod_allowhandlers.xml | 87 ++++++++++++++++ modules/aaa/config.m4 | 1 + modules/aaa/mod_allowhandlers.c | 143 ++++++++++++++++++++++++++ 5 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 docs/manual/mod/mod_allowhandlers.xml create mode 100644 modules/aaa/mod_allowhandlers.c diff --git a/CHANGES b/CHANGES index e52da26a06..8cf7cee214 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,10 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 - *) Be more correct about rejecting directives that cannot work in + *) mod_allowhandlers: New module to forbid specific handlers for specific + directories. [Stefan Fritsch] + + *) core: Be more correct about rejecting directives that cannot work in sections. [Stefan Fritsch] *) core: Fix directives like LogLevel that need to know if they are invoked diff --git a/docs/log-message-tags/next-number b/docs/log-message-tags/next-number index 38ac9c5946..44085c5057 100644 --- a/docs/log-message-tags/next-number +++ b/docs/log-message-tags/next-number @@ -1 +1 @@ -2398 +2401 diff --git a/docs/manual/mod/mod_allowhandlers.xml b/docs/manual/mod/mod_allowhandlers.xml new file mode 100644 index 0000000000..589a281c03 --- /dev/null +++ b/docs/manual/mod/mod_allowhandlers.xml @@ -0,0 +1,87 @@ + + + + + + + + + + +mod_allowhandlers +Easily restrict what HTTP handlers can be used on the server +Experimental +mod_allowhandlers.c +allowhandlers_module + + + +

This module makes it easy to restrict which handlers may be used for a +request. A possible configuration would be:

+ + +<Location /> + AllowHandlers not server-info server-status balancer-manager ldap-status +</Location> + + +

It also registers a handler named forbidden that simply +returns 403 FORBIDDEN to the client. This can be used with directives like +AddHandler.

+ +
+ +SetHandler +AddHandler + + +AllowHandlers +Restrict access to the listed handlers +AllowHandlers [not] none|handler-name +[none|handler-name]... +AllowHandlers all +directory +Experimental + + + +

The handler names are case sensitive. The special name +none can be used to match the case where no handler has been +set. The special vallue all can be used to allow all +handlers again in a later config section, even if some headers were denied +earlier in the configuration merge order:

+ + +<Location /server-status> + AllowHandlers all + SetHandler server-status +</Location> + + +
+
+ +
diff --git a/modules/aaa/config.m4 b/modules/aaa/config.m4 index 4f3ba4f739..b5727401b1 100644 --- a/modules/aaa/config.m4 +++ b/modules/aaa/config.m4 @@ -74,6 +74,7 @@ APACHE_MODULE(auth_digest, RFC2617 Digest authentication, , , most, [ ]) APACHE_MODULE(allowmethods, restrict allowed HTTP methods, , , most) +APACHE_MODULE(allowhandlers, restrict allowed handlers, , , most) APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current]) diff --git a/modules/aaa/mod_allowhandlers.c b/modules/aaa/mod_allowhandlers.c new file mode 100644 index 0000000000..1bfd2da4ef --- /dev/null +++ b/modules/aaa/mod_allowhandlers.c @@ -0,0 +1,143 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_request.h" +#include "http_log.h" + +module AP_MODULE_DECLARE_DATA allowhandlers_module; + +typedef enum { + AH_ALLOW = 0, + AH_DENY = 1, +} ah_op_e; +typedef struct { + apr_table_t *handlers; + ah_op_e op; +} ah_conf_t; + +static const char * const forbidden_handler = "forbidden"; +static const char * const no_handler = "none"; + +static int ah_fixups(request_rec *r) +{ + ah_conf_t *conf = ap_get_module_config(r->per_dir_config, + &allowhandlers_module); + int match = 0; + const char *handler_name; + if (!r->handler || r->handler[0] == '\0') { + handler_name = no_handler; + } + else if (strcasecmp(r->handler, forbidden_handler) == 0) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + APLOGNO(02398) "Handler 'forbidden' denied by " + "server configuration: URI %s (file %s)", + r->uri, r->filename); + return HTTP_FORBIDDEN; + } + else { + handler_name = r->handler; + } + + if (!conf) + return DECLINED; + if (conf->handlers && apr_table_get(conf->handlers, handler_name)) + match = 1; + + if ((match && conf->op == AH_ALLOW) || (!match && conf->op == AH_DENY)) { + return DECLINED; + } + else { + if (handler_name != no_handler) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + APLOGNO(02399) "Handler '%s' denied by " + "server configuration: URI %s (file %s)", + r->handler, r->uri, r->filename); + } + else { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + APLOGNO(02400) "Handler denied by server " + "configuration: No handler set for URI %s (file %s)", + r->uri, r->filename); + } + return HTTP_FORBIDDEN; + } +} + +static void *ah_create_conf(apr_pool_t * p, char *dummy) +{ + ah_conf_t *conf = apr_pcalloc(p, sizeof(ah_conf_t)); + conf->op = AH_DENY; + return conf; +} + +static const char *set_allowed_handlers(cmd_parms *cmd, void *d, int argc, char *const argv[]) +{ + int i; + ah_conf_t* conf = (ah_conf_t*) d; + const char *err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS); + if (err) + return err; + if (argc == 0) + return "AllowHandlers: No handler name given"; + conf->op = AH_ALLOW; + if (conf->handlers) + apr_table_clear(conf->handlers); + for (i = 0; i < argc; i++) { + if (strcasecmp(argv[i], forbidden_handler) == 0 && conf->op != AH_DENY) + return "Handler name 'forbidden' cannot be changed."; + if (strcasecmp(argv[i], "all") == 0) { + if (argc != 1) + return "'all' not possible with specific handler names"; + conf->op = AH_DENY; + return NULL; + } + else if (strcasecmp(argv[i], "not") == 0) { + if (i != 0 || argc == 1) + return "'not' must come before specific handler names"; + conf->op = AH_DENY; + } + else { + if (!conf->handlers) + conf->handlers = apr_table_make(cmd->pool, 4); + apr_table_setn(conf->handlers, argv[i], "1"); + } + } + return NULL; +} + +static void ah_register_hooks(apr_pool_t * p) +{ + ap_hook_fixups(ah_fixups, NULL, NULL, APR_HOOK_REALLY_LAST); +} + +static const command_rec ah_cmds[] = { + AP_INIT_TAKE_ARGV("AllowHandlers", set_allowed_handlers, NULL, ACCESS_CONF, + "only allow specific handlers (use 'not' to negate)"), + {NULL} +}; + +AP_DECLARE_MODULE(allowhandlers) = { + STANDARD20_MODULE_STUFF, + ah_create_conf, + NULL, + NULL, + NULL, + ah_cmds, + ah_register_hooks, +}; + -- 2.40.0