diff --git a/apache2/re.c b/apache2/re.c index d067c68419..943d9b6810 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -986,6 +986,47 @@ msre_action *msre_create_action(msre_engine *engine, apr_pool_t *mp, const char return action; } +/** + * Helper function for action_exists. It checks if "name=value" is present in table for supplied action. + */ +static int apr_table_action_exists(apr_pool_t* p, const apr_table_t* vartable, const char* action, const char* name, const char* value) { + if (strcmp(name, action) != 0) return 0; + + const char* vars = apr_table_getm(p, vartable, name); + if (!vars) return 0; + + char pattern[200]; + apr_snprintf(pattern, sizeof(pattern), "(?:^|,)%.185s(?:,|$)", value); + + char* error_msg = NULL; + msc_regex_t* regex = msc_pregcomp(p, pattern, 0, NULL, NULL); + if (regex == NULL) return 0; + + return (msc_regexec(regex, vars, strlen(vars), &error_msg) >= 0); +} + +/** + * Checks if "name=value" is present in table for tags, logdata (and others). + */ +static int action_exists(apr_pool_t* p, const apr_table_t* vartable, const char* name, const char* value) { + /* logdata & msg cannot be used because ',' is used as entries separators */ + if (apr_table_action_exists(p, vartable, "capture", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "chain", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "initcol", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "multiMatch", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "phase", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitizeArg", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitizeMatched", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitizeMatchedBytes", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitizeRequestHeader", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitizeResponseHeader", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "setrsc", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "setsid", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "setuid", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "tag", name, value)) return 1; + return 0; +} + /** * Generic parser that is used as basis for target and action parsing. * It breaks up the input string into name-parameter pairs and places @@ -1103,9 +1144,11 @@ int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable, value = apr_pstrmemdup(mp, value, p - value); } - /* add to table */ - apr_table_addn(vartable, name, value); - count++; + /* add to table (only if not already present) */ + if (!action_exists(mp, vartable, name, value)) { + apr_table_addn(vartable, name, value); + count++; + } /* move to the first character of the next name-value pair */ while(isspace(*p)||(*p == ',')||(*p == '|')) p++;