diff options
author | Eric Covener <covener@apache.org> | 2020-11-08 15:25:15 +0000 |
---|---|---|
committer | Eric Covener <covener@apache.org> | 2020-11-08 15:25:15 +0000 |
commit | 07e2875374bf367d191b2ed2b20dcd658c7d1509 (patch) | |
tree | b996cbf54f2d6780fdef40cd30c72a8c7835a61c | |
parent | fb945ce6ec9bd3b29e06c5af4a698a47cb2274f4 (diff) | |
download | httpd-07e2875374bf367d191b2ed2b20dcd658c7d1509.tar.gz |
PR64785: mod_allowmethods: Allow methods to be added/removed with +/- prefix
Committed By: covener
Submitted By: Marcel Montes <spiceman gmail.com>
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1883203 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | changes-entries/pr64785.txt | 3 | ||||
-rw-r--r-- | docs/manual/mod/mod_allowmethods.xml | 28 | ||||
-rw-r--r-- | modules/aaa/mod_allowmethods.c | 109 |
3 files changed, 122 insertions, 18 deletions
diff --git a/changes-entries/pr64785.txt b/changes-entries/pr64785.txt new file mode 100644 index 0000000000..4f015c4b68 --- /dev/null +++ b/changes-entries/pr64785.txt @@ -0,0 +1,3 @@ + *) mod_allowmethods: Allow methods to be added/removed with +/- prefix. PR64785. + [Marcel Montes <spiceman gmail.com>] + diff --git a/docs/manual/mod/mod_allowmethods.xml b/docs/manual/mod/mod_allowmethods.xml index 42e0aa5f52..33944f46ef 100644 --- a/docs/manual/mod/mod_allowmethods.xml +++ b/docs/manual/mod/mod_allowmethods.xml @@ -46,6 +46,10 @@ used on a server. The most common configuration would be:</p> <Location "/"> AllowMethods GET POST OPTIONS </Location> + +<Location "/nopost"> + AllowMethods -POST +</Location> </highlight> </summary> @@ -53,11 +57,12 @@ used on a server. The most common configuration would be:</p> <directivesynopsis> <name>AllowMethods</name> <description>Restrict access to the listed HTTP methods</description> -<syntax>AllowMethods reset|<em>HTTP-method</em> -[<em>HTTP-method</em>]...</syntax> +<syntax>AllowMethods reset | [+|-]<var>HTTP-method</var> +[ [+|-]<var>HTTP-method</var> ] ...</syntax> <default>AllowMethods reset</default> <contextlist><context>directory</context></contextlist> <status>Experimental</status> +<compatibility>+/- added in 2.5.1</compatibility> <usage> @@ -77,9 +82,28 @@ turn off <module>mod_allowmethods</module> in a deeper nested context:</p> use <directive module="core">TraceEnable</directive> instead.</p> </note> +<p>Normally, if multiple <directive>AllowMethods</directive> could +apply to a directory, then the most specific one is used and +others are ignored; the methods are not merged. (See <a +href="../sections.html#merging">how sections are merged</a>.) +However if <em>all</em> the methods on the +<directive>AllowMethods</directive> directive are preceded by a +<code>+</code> or <code>-</code> symbol, the options are +merged. Any method preceded by a <code>+</code> are added to the +methods currently in force, and any method preceded by a +<code>-</code> are removed from the methods currently in +force. </p> + +<note><title>Note</title> +<p>Mixing <directive>AllowMethods</directive> with a <code>+</code> or +<code>-</code> with those without is not valid syntax and will be +rejected during server startup by the syntax check with an abort.</p> +</note> + <p><module>mod_allowmethods</module> was written to replace the rather kludgy implementation of <directive module="core">Limit</directive> and <directive module="core">LimitExcept</directive>.</p> + </usage> </directivesynopsis> diff --git a/modules/aaa/mod_allowmethods.c b/modules/aaa/mod_allowmethods.c index 3062efd323..7e490593c6 100644 --- a/modules/aaa/mod_allowmethods.c +++ b/modules/aaa/mod_allowmethods.c @@ -44,8 +44,11 @@ */ typedef struct am_conf_t { - int allowed_set; - ap_method_mask_t allowed; + int allowed_set; /* AllowMethods has been set/changed flag */ + int enforce_methods; /* Enforce AllowMethods flag */ + ap_method_mask_t add; /* Methods Added by +METHOD mask */ + ap_method_mask_t remove; /* Methods Removed by -METHOD mask */ + ap_method_mask_t allowed; /* Allowed Methods mask */ } am_conf_t; module AP_MODULE_DECLARE_DATA allowmethods_module; @@ -57,7 +60,8 @@ static int am_check_access(request_rec *r) conf = (am_conf_t *) ap_get_module_config(r->per_dir_config, &allowmethods_module); - if (!conf || conf->allowed == 0) { + + if (!conf || conf->enforce_methods == 0) { return DECLINED; } @@ -80,8 +84,11 @@ static void *am_create_conf(apr_pool_t *p, char *dummy) { am_conf_t *conf = apr_pcalloc(p, sizeof(am_conf_t)); - conf->allowed = 0; - conf->allowed_set = 0; + conf->allowed = INT_MAX; + conf->allowed_set = 0; + conf->add = 0; + conf->remove = 0; + conf->enforce_methods = 0; return conf; } @@ -92,12 +99,37 @@ static void *am_merge_conf(apr_pool_t *pool, void *a, void *b) am_conf_t *conf = apr_palloc(pool, sizeof(am_conf_t)); if (add->allowed_set) { - conf->allowed = add->allowed; - conf->allowed_set = add->allowed_set; + conf->add = 0; + conf->remove = 0; + + /* Add/Remove AllowedMethods set with + or - */ + if( add->add || add->remove ) { + conf->allowed = base->allowed | add->allowed; + + if( add->add ) { + conf->allowed |= add->add; + } + if( add->remove ) { + conf->allowed &= ~(add->remove); + } + + conf->enforce_methods = 1; + conf->allowed_set = 1; + } + /* Straightforward AllowMethods settings, just set it */ + else + { + conf->allowed = add->allowed; + conf->allowed_set = add->allowed_set; + conf->enforce_methods = add->enforce_methods; + } } else { - conf->allowed = base->allowed; - conf->allowed_set = base->allowed_set; + conf->allowed = base->allowed; + conf->add = base->add; + conf->remove = base->remove; + conf->allowed_set = base->allowed_set; + conf->enforce_methods = base->enforce_methods; } return conf; @@ -108,30 +140,75 @@ static const char *am_allowmethods(cmd_parms *cmd, void *d, int argc, { int i; am_conf_t *conf = (am_conf_t *)d; + int merge = 0; + int first = 1; + char *method; + char action; if (argc == 0) { return "AllowMethods: No method or 'reset' keyword given"; } if (argc == 1) { - if (strcasecmp("reset", argv[0]) == 0) { - conf->allowed = 0; - conf->allowed_set = 1; + if (!ap_cstr_casecmp(argv[0], "reset")) { + conf->allowed = 0; + conf->enforce_methods = 0; + conf->add = 0; + conf->remove = 0; + conf->allowed_set = 1; return NULL; } } + conf->allowed = 0; + conf->add = 0; + conf->remove = 0; + for (i = 0; i < argc; i++) { int m; + char *w = argv[i]; + + if( *w == '-' || *w == '+' ) { + if (!merge && !first) { + return "Either all methods in AllowMethods must start with + or -, or no methods may."; + } + + action = *(w++); + method = w; + merge = 1; + } + else if (merge) { + return "Either all methods in AllowMethods must start with + or -, or no methods may."; + } + else { + method = w; + } + + m = ap_method_number_of((char const*)method); - m = ap_method_number_of(argv[i]); if (m == M_INVALID) { return apr_pstrcat(cmd->pool, "AllowMethods: Invalid Method '", - argv[i], "'", NULL); + method, "'", NULL); + } + + if (action == '-' ) { + conf->remove |= (AP_METHOD_BIT << m); + conf->add &= ~(AP_METHOD_BIT << m); + conf->allowed &= ~(AP_METHOD_BIT << m); + } + else if (action == '+' ) { + conf->remove &= ~(AP_METHOD_BIT << m); + conf->add |= (AP_METHOD_BIT << m); + conf->allowed |= (AP_METHOD_BIT << m); + } + else { + conf->allowed |= (AP_METHOD_BIT << m); } - conf->allowed |= (AP_METHOD_BIT << m); + first = 0; } - conf->allowed_set = 1; + conf->allowed_set = 1; + conf->enforce_methods = 1; + return NULL; } |