diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index b4f3c207..228e3754 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -46,6 +46,7 @@ void *create_directory_config(apr_pool_t *mp, char *path) dcfg->is_enabled = NOT_SET; dcfg->reqbody_access = NOT_SET; + dcfg->reqintercept_oe = NOT_SET; dcfg->reqbody_buffering = NOT_SET; dcfg->reqbody_inmemory_limit = NOT_SET; dcfg->reqbody_limit = NOT_SET; @@ -254,6 +255,8 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) ? parent->of_limit : child->of_limit); merged->of_limit_action = (child->of_limit_action == NOT_SET ? parent->of_limit_action : child->of_limit_action); + merged->reqintercept_oe = (child->reqintercept_oe == NOT_SET + ? parent->reqintercept_oe : child->reqintercept_oe); if (child->of_mime_types != NOT_SET_P) { /* Child added to the table */ @@ -481,6 +484,7 @@ void init_directory_config(directory_config *dcfg) if (dcfg->is_enabled == NOT_SET) dcfg->is_enabled = 0; if (dcfg->reqbody_access == NOT_SET) dcfg->reqbody_access = 0; + if (dcfg->reqintercept_oe == NOT_SET) dcfg->reqintercept_oe = 0; if (dcfg->reqbody_buffering == NOT_SET) dcfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_OFF; if (dcfg->reqbody_inmemory_limit == NOT_SET) dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT; @@ -1395,6 +1399,22 @@ static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg, return NULL; } +static const char *cmd_request_intercept_on_error(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) dcfg->reqintercept_oe = 1; + else + if (strcasecmp(p1, "off") == 0) dcfg->reqintercept_oe = 0; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecInterceptOnError: %s", p1); + + return NULL; +} + + static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg, const char *p1) { @@ -2074,6 +2094,14 @@ const command_rec module_directives[] = { "On or Off" ), + AP_INIT_TAKE1 ( + "SecInterceptOnError", + cmd_request_intercept_on_error, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + AP_INIT_TAKE1 ( "SecRequestBodyInMemoryLimit", cmd_request_body_inmemory_limit, diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index cb357cf1..175ff2e2 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -384,6 +384,7 @@ struct directory_config { int is_enabled; int reqbody_access; + int reqintercept_oe; int reqbody_buffering; long int reqbody_inmemory_limit; long int reqbody_limit; diff --git a/apache2/re.c b/apache2/re.c index 2b2a6a1a..91ca9688 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -1173,7 +1173,31 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) } else if (rc < 0) { msr_log(msr, 1, "Rule processing failed."); - return -1; + + if (msr->txcfg->reqintercept_oe == 1) { + return -1; + } else { + if (rule->actionset->is_chained) { + /* If the current rule is part of a chain then + * we need to skip over all the rules in the chain. + */ + mode = NEXT_CHAIN; + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Ruled failed, chained -> mode NEXT_CHAIN."); + } + } else { + /* This rule is not part of a chain so we simply + * move to the next rule. + */ + mode = NEXT_RULE; + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Rule failed, not chained -> mode NEXT_RULE."); + } + } + + skipped = 0; + saw_starter = 0; + } } else { msr_log(msr, 1, "Rule processing failed with unknown return code: %d.", rc);