From 592ec392d1ff7da63e2618bf232aee4eeb901103 Mon Sep 17 00:00:00 2001 From: brenosilva Date: Thu, 2 Aug 2012 18:04:53 +0000 Subject: [PATCH] Remove ctl:ruleUpdateTarget* and add ctl:ruleRemovetarget* --- apache2/modsecurity.c | 4 ++ apache2/modsecurity.h | 3 + apache2/msc_crypt.c | 5 +- apache2/msc_multipart.c | 2 +- apache2/msc_util.c | 5 +- apache2/msc_util.h | 4 +- apache2/re.c | 152 +++++++++++++++++++++++++++++++++++++--- apache2/re_actions.c | 62 ++++++++-------- 8 files changed, 189 insertions(+), 48 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 5ac9ad8e..d01ea2f1 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -376,6 +376,10 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) { msr->pattern_to_sanitize = apr_table_make(msr->mp, 32); if (msr->pattern_to_sanitize == NULL) return -1; + /* remove targets */ + msr->removed_targets = apr_table_make(msr->mp, 16); + if (msr->removed_targets == NULL) return -1; + /* Initialise cookies */ msr->request_cookies = apr_table_make(msr->mp, 16); if (msr->request_cookies == NULL) return -1; diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 81317d18..bcbfec8b 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -416,6 +416,9 @@ struct modsec_rec { apr_array_header_t *removed_rules_tag; apr_array_header_t *removed_rules_msg; + /* removed targets */ + apr_table_t *removed_targets; + /* When "allow" is executed the variable below is * updated to contain the scope of the allow action. Set * at 0 by default, it will have ACTION_ALLOW if we are diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index 49cfe51c..0a3cf5fe 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -13,6 +13,7 @@ */ #include "msc_crypt.h" +#include "msc_util.h" #include "apr_sha1.h" #include "apr_uri.h" #include "acmp.h" @@ -287,7 +288,7 @@ int init_response_body_html_parser(modsec_rec *msr) { } if((msr->r->content_encoding == NULL)||(apr_strnatcasecmp(msr->r->content_encoding,"(null)")==0)){ - charset=strcasestr(msr->r->content_type,"charset="); + charset=ap_strcasestr(msr->r->content_type,"charset="); if(charset == NULL){ if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "init_response_body_html_parser: assuming ISO-8859-1."); @@ -1013,7 +1014,7 @@ int inject_encrypted_response_body(modsec_rec *msr, int elts) { encoding = (const char *) htmlGetMetaEncoding(msr->crypto_html_tree); if (ctype && encoding == NULL) { - if (ctype && (p = strcasestr(ctype, "charset=") , p != NULL)) { + if (ctype && (p = ap_strcasestr(ctype, "charset=") , p != NULL)) { p += 8 ; if (encoding = apr_pstrndup(msr->mp, p, strcspn(p, " ;") ), encoding) { xmlCharEncoding enc; diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index f86e40c3..69b37694 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -624,7 +624,7 @@ static int multipart_process_boundary(modsec_rec *msr, int last_part, char **err &&(msr->mpd->mpp->tmp_file_fd != 0)) { close(msr->mpd->mpp->tmp_file_fd); - msr->mpd->mpp->tmp_file_fd = -1; + msr->mpd->mpp->tmp_file_fd = -1; } if (msr->mpd->mpp->type != MULTIPART_FILE) { diff --git a/apache2/msc_util.c b/apache2/msc_util.c index b82270c3..d09b416f 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -569,8 +569,8 @@ char *file_basename(apr_pool_t *mp, const char *filename) { return d; } - -#if defined(WIN32) || !defined(HAVE_STRCASESTR) +/* +#if (defined(WIN32) || (HAVE_STRCASESTR == 0)) char *strcasestr(const char *haystack, const char *needle) { char aux, lower_aux; int length; @@ -589,6 +589,7 @@ char *strcasestr(const char *haystack, const char *needle) { return ((char *)haystack); } #endif +*/ #ifdef WIN32 int inet_pton(int family, const char *src, void *dst) { struct addrinfo addr; diff --git a/apache2/msc_util.h b/apache2/msc_util.h index a337a65f..adb6e8da 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -32,9 +32,11 @@ #include int DSOLOCAL inet_pton(int family, const char *src, void *dst); #endif -#if defined(WIN32) || !defined(HAVE_STRCASESTR) +/* +#if (defined(WIN32) || (HAVE_STRCASESTR == 0)) char DSOLOCAL *strcasestr(const char *haystack, const char *needle); #endif +*/ int DSOLOCAL normalize_path_inplace(unsigned char *input, int len, int win, int *changed); diff --git a/apache2/re.c b/apache2/re.c index a3d3d11a..e4b1fdee 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -32,6 +32,7 @@ static const char *const severities[] = { NULL, }; +static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *var, const char *exceptions); static apr_status_t msre_parse_targets(msre_ruleset *ruleset, const char *text, apr_array_header_t *arr, char **error_msg); static char *msre_generate_target_string(apr_pool_t *pool, msre_rule *rule); @@ -42,6 +43,110 @@ static msre_action *msre_create_action(msre_engine *engine, const char *name, static apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr); /* -- Actions, variables, functions and operator functions ----------------- */ + +/** + * \brief Remove rule targets to be processed + * + * \param rule Pointer to the rule + * \param msr ModSecurity transaction resource + * \param var Pointer to target structure. + * \param targets Exception list. + */ +static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *var, const char *exceptions) { + const char *targets = NULL; + char *savedptr = NULL, *target = NULL; + char *c = NULL, *name = NULL, *value = NULL; + char *variable = NULL, *myvar = NULL; + char *myvalue = NULL, *myname = NULL; + int match; + + if(msr == NULL) + return 0; + + if(var == NULL) + return 0; + + if(rule == NULL) + return 0; + + if(rule->actionset == NULL) + return 0; + + if(rule->actionset->id !=NULL) { + + myvar = apr_pstrdup(msr->mp, var->name); + + c = strchr(myvar,':'); + + if(c != NULL) { + myname = apr_strtok(myvar,":",&myvalue); + } else { + myname = myvar; + } + + match = 0; + + targets = apr_pstrdup(msr->mp, exceptions); + + if(targets != NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "fetch_target_exception: Found exception target list [%s] for rule id %s", targets, rule->actionset->id); + } + target = apr_strtok((char *)targets, ",", &savedptr); + + while(target != NULL) { + + variable = apr_pstrdup(msr->mp, target); + + c = strchr(variable,':'); + + if(c != NULL) { + name = apr_strtok(variable,":",&value); + } else { + name = variable; + } + + if((strlen(myname) == strlen(name)) && + (strncasecmp(myname, name,strlen(myname)) == 0)) { + + if(value != NULL && myvalue != NULL) { + if((strlen(myvalue) == strlen(value)) && + strncasecmp(myvalue,value,strlen(myvalue)) == 0) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "fetch_target_exception: Target %s will not be processed.", target); + } + match = 1; + } + } else if (value == NULL && myvalue == NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "fetch_target_exception: Target %s will not be processed.", target); + } + match = 1; + } else if (value == NULL && myvalue != NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "fetch_target_exception: Target %s will not be processed.", target); + } + match = 1; + } + } + + target = apr_strtok(NULL, ",", &savedptr); + } + } else { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "fetch_target_exception: No exception target found for rule id %s.", rule->actionset->id); + + } + } + + } + + if(match) + return 1; + + return 0; +} + /** * \brief Update target for all matching rules in set, in any phase * @@ -2406,7 +2511,11 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr, apr_time_t time_before_op = 0; char *my_error_msg = NULL; const char *full_varname = NULL; - int rc; + const apr_array_header_t *tarr = NULL; + const apr_table_entry_t *telts = NULL; + rule_exception *re = NULL; + char *exceptions = NULL; + int rc, i; /* determine the full var name if not already resolved * @@ -2427,28 +2536,55 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr, full_varname = var->name; } + tarr = apr_table_elts(msr->removed_targets); + telts = (const apr_table_entry_t*)tarr->elts; + + for (i = 0; i < tarr->nelts; i++) { + exceptions = (char *)telts[i].key; + re = (rule_exception *)telts[i].val; + + rc = msre_ruleset_rule_matches_exception(rule, re); + + if (rc > 0) { + rc = fetch_target_exception(rule, msr, var, exceptions); + + if(rc > 0) { + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Executing operator \"%s%s\" with param \"%s\" against %s skipped.", + (rule->op_negated ? "!" : ""), rule->op_name, + log_escape(msr->mp, rule->op_param), full_varname); + } + + return RULE_NO_MATCH; + + } + } + + } + if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Executing operator \"%s%s\" with param \"%s\" against %s.", - (rule->op_negated ? "!" : ""), rule->op_name, - log_escape(msr->mp, rule->op_param), full_varname); + (rule->op_negated ? "!" : ""), rule->op_name, + log_escape(msr->mp, rule->op_param), full_varname); } if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Target value: \"%s\"", log_escape_nq_ex(msr->mp, var->value, - var->value_len)); + var->value_len)); } - #if defined(PERFORMANCE_MEASUREMENT) +#if defined(PERFORMANCE_MEASUREMENT) time_before_op = apr_time_now(); - #else +#else if (msr->txcfg->debuglog_level >= 4 || msr->txcfg->max_rule_time > 0) { time_before_op = apr_time_now(); } - #endif +#endif rc = rule->op_metadata->execute(msr, rule, var, &my_error_msg); - #if defined(PERFORMANCE_MEASUREMENT) +#if defined(PERFORMANCE_MEASUREMENT) { /* Record performance but do not log anything. */ apr_time_t t1 = apr_time_now(); diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 92257129..b8dd8473 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -885,36 +885,36 @@ static char *msre_action_ctl_validate(msre_engine *engine, msre_action *action) return NULL; } else - if (strcasecmp(name, "ruleUpdateTargetById") == 0) { + if (strcasecmp(name, "ruleRemoveTargetById") == 0) { char *parm = NULL; char *savedptr = NULL; parm = apr_strtok(value,";",&savedptr); if(parm == NULL && savedptr == NULL) - return apr_psprintf(engine->mp, "ruleUpdateTargetById must has at least id;append_value"); + return apr_psprintf(engine->mp, "ruleRemoveTargetById must has at least id;append_value"); return NULL; } else - if (strcasecmp(name,"ruleUpdateTargetByTag") == 0) { + if (strcasecmp(name,"ruleRemoveTargetByTag") == 0) { char *parm = NULL; char *savedptr = NULL; parm = apr_strtok(value,";",&savedptr); if(parm == NULL && savedptr == NULL) - return apr_psprintf(engine->mp, "ruleUpdateTargetByTag must has at least tag;append_value"); + return apr_psprintf(engine->mp, "ruleRemoveTargetByTag must has at least tag;append_value"); if (!msc_pregcomp(engine->mp, parm, 0, NULL, NULL)) { return apr_psprintf(engine->mp, "ModSecurity: Invalid regular expression \"%s\"", parm); } return NULL; } else - if (strcasecmp(name,"ruleUpdateTargetByMsg") == 0) { + if (strcasecmp(name,"ruleRemoveTargetByMsg") == 0) { char *parm = NULL; char *savedptr = NULL; parm = apr_strtok(value,";",&savedptr); if(parm == NULL && savedptr == NULL) - return apr_psprintf(engine->mp, "ruleUpdateTargetByMsg must has at least msg;append_value"); + return apr_psprintf(engine->mp, "ruleRemoveTargetByMsg must has at least msg;append_value"); if (!msc_pregcomp(engine->mp, parm, 0, NULL, NULL)) { return apr_psprintf(engine->mp, "ModSecurity: Invalid regular expression \"%s\"", parm); } @@ -1017,7 +1017,7 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, if (strcasecmp(name, "ruleRemoveByTag") == 0) { rule_exception *re = apr_pcalloc(mptmp, sizeof(rule_exception)); re->type = RULE_EXCEPTION_REMOVE_TAG; - re->param = (const char *)apr_pstrdup(msr->mp, value);; + re->param = (const char *)apr_pstrdup(msr->mp, value); re->param_data = msc_pregcomp(msr->mp, re->param, 0, NULL, NULL); if (re->param_data == NULL) { msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", re->param); @@ -1035,7 +1035,7 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, if (strcasecmp(name, "ruleRemoveByMsg") == 0) { rule_exception *re = apr_pcalloc(mptmp, sizeof(rule_exception)); re->type = RULE_EXCEPTION_REMOVE_MSG; - re->param = (const char *)apr_pstrdup(msr->mp, value);; + re->param = (const char *)apr_pstrdup(msr->mp, value); re->param_data = msc_pregcomp(msr->mp, re->param, 0, NULL, NULL); if (re->param_data == NULL) { msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", re->param); @@ -1199,76 +1199,70 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, return 1; } else - if (strcasecmp(name, "ruleUpdateTargetById") == 0) { + if (strcasecmp(name, "ruleRemoveTargetById") == 0) { rule_exception *re = NULL; - char *p1 = NULL, *p2 = NULL, *p3 = NULL; + char *p1 = NULL, *p2 = NULL; char *savedptr = NULL; p1 = apr_strtok(value,";",&savedptr); p2 = apr_strtok(NULL,";",&savedptr); - p3 = apr_strtok(NULL,";",&savedptr); - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Ctl: ruleUpdateTargetById id=%s append=%s replace=%s", p1, p2, p3); + msr_log(msr, 4, "Ctl: ruleUpdateTargetById id=%s targets=%s", p1, p2); } - re = apr_pcalloc(mptmp, sizeof(rule_exception)); + re = apr_pcalloc(msr->mp, sizeof(rule_exception)); re->type = RULE_EXCEPTION_REMOVE_ID; - re->param = p1; - msre_ruleset_rule_update_target_matching_exception(msr, rule->ruleset, re, p2, p3); + re->param = (const char *)apr_pstrdup(msr->mp, p1); + apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); return 1; } else - if (strcasecmp(name, "ruleUpdateTargetByTag") == 0) { + if (strcasecmp(name, "ruleRemoveTargetByTag") == 0) { rule_exception *re = NULL; - char *p1 = NULL, *p2 = NULL, *p3 = NULL; + char *p1 = NULL, *p2 = NULL; char *savedptr = NULL; p1 = apr_strtok(value,";",&savedptr); p2 = apr_strtok(NULL,";",&savedptr); - p3 = apr_strtok(NULL,";",&savedptr); - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Ctl: ruleUpdateTargetByTag tag=%s append=%s replace=%s", p1, p2, p3); + msr_log(msr, 4, "Ctl: ruleRemoveTargetByTag tag=%s targets=%s", p1, p2); } - re = apr_pcalloc(mptmp, sizeof(rule_exception)); + re = apr_pcalloc(msr->mp, sizeof(rule_exception)); re->type = RULE_EXCEPTION_REMOVE_TAG; - re->param = p1; - re->param_data = msc_pregcomp(mptmp, p1, 0, NULL, NULL); + re->param = (const char *)apr_pstrdup(msr->mp, p1); + re->param_data = msc_pregcomp(msr->mp, p1, 0, NULL, NULL); if (re->param_data == NULL) { msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", p1); return -1; } - msre_ruleset_rule_update_target_matching_exception(msr, rule->ruleset, re, p2, p3); + apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); return 1; } else - if (strcasecmp(name, "ruleUpdateTargetByMsg") == 0) { + if (strcasecmp(name, "ruleRemoveTargetByMsg") == 0) { rule_exception *re = NULL; - char *p1 = NULL, *p2 = NULL, *p3 = NULL; + char *p1 = NULL, *p2 = NULL; char *savedptr = NULL; p1 = apr_strtok(value,";",&savedptr); p2 = apr_strtok(NULL,";",&savedptr); - p3 = apr_strtok(NULL,";",&savedptr); - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Ctl: ruleUpdateTargetByMsg tag=%s append=%s replace=%s", p1, p2, p3); + msr_log(msr, 4, "Ctl: ruleUpdateTargetByMsg msg=%s targets=%s", p1, p2); } - re = apr_pcalloc(mptmp, sizeof(rule_exception)); + re = apr_pcalloc(msr->mp, sizeof(rule_exception)); re->type = RULE_EXCEPTION_REMOVE_MSG; - re->param = p1; - re->param_data = msc_pregcomp(mptmp, p1, 0, NULL, NULL); + re->param = apr_pstrdup(msr->mp, p1); + re->param_data = msc_pregcomp(msr->mp, p1, 0, NULL, NULL); if (re->param_data == NULL) { msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", p1); return -1; } - msre_ruleset_rule_update_target_matching_exception(msr, rule->ruleset, re, p2, p3); + apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); return 1; } else {