Blame apache2/re.c

Packit 284210
/*
Packit 284210
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
Packit 284210
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
Packit 284210
*
Packit 284210
* You may not use this file except in compliance with
Packit 284210
* the License.  You may obtain a copy of the License at
Packit 284210
*
Packit 284210
*     http://www.apache.org/licenses/LICENSE-2.0
Packit 284210
*
Packit 284210
* If any of the files related to licensing are missing or if you have any
Packit 284210
* other questions related to licensing please contact Trustwave Holdings, Inc.
Packit 284210
* directly using the email address security@modsecurity.org.
Packit 284210
*/
Packit 284210
Packit 284210
#include <ctype.h>
Packit 284210
Packit 284210
#include "re.h"
Packit 284210
Packit 284210
#if defined(WITH_LUA)
Packit 284210
#include "msc_lua.h"
Packit 284210
#endif
Packit 284210
Packit 284210
static const char *const severities[] = {
Packit 284210
    "EMERGENCY",
Packit 284210
    "ALERT",
Packit 284210
    "CRITICAL",
Packit 284210
    "ERROR",
Packit 284210
    "WARNING",
Packit 284210
    "NOTICE",
Packit 284210
    "INFO",
Packit 284210
    "DEBUG",
Packit 284210
    NULL,
Packit 284210
};
Packit 284210
Packit 284210
static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *var, const char *exceptions);
Packit 284210
static apr_status_t msre_parse_targets(msre_ruleset *ruleset, const char *text,
Packit 284210
    apr_array_header_t *arr, char **error_msg);
Packit 284210
static char *msre_generate_target_string(apr_pool_t *pool, msre_rule *rule);
Packit 284210
static msre_var *msre_create_var(msre_ruleset *ruleset, const char *name, const char *param,
Packit 284210
    modsec_rec *msr, char **error_msg);
Packit 284210
static msre_action *msre_create_action(msre_engine *engine, apr_pool_t *mp, const char *name,
Packit 284210
    const char *param, char **error_msg);
Packit 284210
static apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr);
Packit 284210
Packit 284210
/* -- Actions, variables, functions and operator functions ----------------- */
Packit 284210
Packit 284210
/**
Packit 284210
 * \brief Remove rule targets to be processed
Packit 284210
 *
Packit 284210
 * \param rule Pointer to the rule
Packit 284210
 * \param msr ModSecurity transaction resource
Packit 284210
 * \param var Pointer to target structure.
Packit 284210
 * \param targets Exception list.
Packit 284210
 */
Packit 284210
static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *var, const char *exceptions)   {
Packit 284210
    const char *targets = NULL;
Packit 284210
    char *savedptr = NULL, *target = NULL;
Packit 284210
    char *c = NULL, *name = NULL, *value = NULL;
Packit 284210
    char *variable = NULL, *myvar = NULL;
Packit 284210
    char *myvalue = NULL, *myname = NULL;
Packit 284210
    int match = 0;
Packit 284210
Packit 284210
    if(msr == NULL)
Packit 284210
        return 0;
Packit 284210
Packit 284210
    if(var == NULL)
Packit 284210
        return 0;
Packit 284210
Packit 284210
    if(rule == NULL)
Packit 284210
        return 0;
Packit 284210
Packit 284210
    if(rule->actionset == NULL)
Packit 284210
        return 0;
Packit 284210
Packit 284210
    if(rule->actionset->id !=NULL)    {
Packit 284210
Packit 284210
        myvar = apr_pstrdup(msr->mp, var->name);
Packit 284210
Packit 284210
        c = strchr(myvar,':');
Packit 284210
Packit 284210
        if(c != NULL) {
Packit 284210
            myname = apr_strtok(myvar,":",&myvalue);
Packit 284210
        } else {
Packit 284210
            myname = myvar;
Packit 284210
        }
Packit 284210
Packit 284210
        match = 0;
Packit 284210
Packit 284210
        targets = apr_pstrdup(msr->mp, exceptions);
Packit 284210
Packit 284210
        if(targets != NULL) {
Packit 284210
            if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                msr_log(msr, 9, "fetch_target_exception: Found exception target list [%s] for rule id %s", targets, rule->actionset->id);
Packit 284210
            }
Packit 284210
            target = apr_strtok((char *)targets, ",", &savedptr);
Packit 284210
Packit 284210
            while(target != NULL)   {
Packit 284210
Packit 284210
                variable = apr_pstrdup(msr->mp, target);
Packit 284210
Packit 284210
                c = strchr(variable,':');
Packit 284210
Packit 284210
                if(c != NULL) {
Packit 284210
                    name = apr_strtok(variable,":",&value);
Packit 284210
                } else {
Packit 284210
                    name = variable;
Packit 284210
                    value = NULL;
Packit 284210
                }
Packit 284210
Packit 284210
                if((strlen(myname) == strlen(name)) &&
Packit 284210
                        (strncasecmp(myname, name,strlen(myname)) == 0))   {
Packit 284210
Packit 284210
                    if(value != NULL && myvalue != NULL)  {
Packit 284210
                        if((strlen(myvalue) == strlen(value)) &&
Packit 284210
                                strncasecmp(myvalue,value,strlen(myvalue)) == 0) {
Packit 284210
                            if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                                msr_log(msr, 9, "fetch_target_exception: Target %s will not be processed.", target);
Packit 284210
                            }
Packit 284210
                            match = 1;
Packit 284210
                        }
Packit 284210
                    } else if (value == NULL && myvalue == NULL)    {
Packit 284210
                        if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                            msr_log(msr, 9, "fetch_target_exception: Target %s will not be processed.", target);
Packit 284210
                        }
Packit 284210
                        match = 1;
Packit 284210
                    } else if (value == NULL && myvalue != NULL)   {
Packit 284210
                        if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                            msr_log(msr, 9, "fetch_target_exception: Target %s will not be processed.", target);
Packit 284210
                        }
Packit 284210
                        match = 1;
Packit 284210
                    }
Packit 284210
                }
Packit 284210
Packit 284210
                target = apr_strtok(NULL, ",", &savedptr);
Packit 284210
            }
Packit 284210
        } else  {
Packit 284210
            if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                msr_log(msr, 9, "fetch_target_exception: No exception target found for rule id %s.", rule->actionset->id);
Packit 284210
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
    }
Packit 284210
Packit 284210
    if(match == 1)
Packit 284210
        return 1;
Packit 284210
Packit 284210
    return 0;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * \brief Update target for all matching rules in set, in any phase
Packit 284210
 *
Packit 284210
 * \param msr ModSecurity transaction resource
Packit 284210
 * \param ruleset Pointer to set of rules to modify
Packit 284210
 * \param re Pointer to exception object describing which rules to modify
Packit 284210
 * \param p2 Pointer to configuration option TARGET
Packit 284210
 * \param p3 Pointer to configuration option REPLACED_TARGET
Packit 284210
 */
Packit 284210
char *msre_ruleset_rule_update_target_matching_exception(modsec_rec *msr, msre_ruleset *ruleset, rule_exception *re, const char *p2, const char *p3) {
Packit 284210
    char *err;
Packit 284210
Packit 284210
    if(ruleset == NULL)
Packit 284210
        return NULL;
Packit 284210
Packit 284210
    if(p2 == NULL)  {
Packit 284210
        return apr_psprintf(ruleset->mp, "Trying to update without a target");
Packit 284210
    }
Packit 284210
Packit 284210
    if (NULL != (err = msre_ruleset_phase_rule_update_target_matching_exception(msr, ruleset, re, ruleset->phase_request_headers, p2, p3)))
Packit 284210
        return err;
Packit 284210
    if (NULL != (err = msre_ruleset_phase_rule_update_target_matching_exception(msr, ruleset, re, ruleset->phase_request_body, p2, p3)))
Packit 284210
        return err;
Packit 284210
    if (NULL != (err = msre_ruleset_phase_rule_update_target_matching_exception(msr, ruleset, re, ruleset->phase_response_headers, p2, p3)))
Packit 284210
        return err;
Packit 284210
    if (NULL != (err = msre_ruleset_phase_rule_update_target_matching_exception(msr, ruleset, re, ruleset->phase_response_body, p2, p3)))
Packit 284210
        return err;
Packit 284210
    if (NULL != (err = msre_ruleset_phase_rule_update_target_matching_exception(msr, ruleset, re, ruleset->phase_logging, p2, p3)))
Packit 284210
        return err;
Packit 284210
Packit 284210
    /* Everything worked! */
Packit 284210
    return NULL;
Packit 284210
}
Packit 284210
Packit 284210
Packit 284210
/**
Packit 284210
 * \brief Update target for all matching rules in set for a specific phase
Packit 284210
 *
Packit 284210
 * \param msr ModSecurity transaction resource
Packit 284210
 * \param ruleset Pointer to set of rules to modify
Packit 284210
 * \param re Pointer to exception object describing which rules to modify
Packit 284210
 * \param phase_arr Pointer to phase that should be edited
Packit 284210
 * \param p2 Pointer to configuration option TARGET
Packit 284210
 * \param p3 Pointer to configuration option REPLACED_TARGET
Packit 284210
 *
Packit 284210
 * \todo Figure out error checking
Packit 284210
 */
Packit 284210
char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, msre_ruleset *ruleset, rule_exception *re,
Packit 284210
        apr_array_header_t *phase_arr, const char *p2,
Packit 284210
        const char *p3)
Packit 284210
{
Packit 284210
    msre_rule **rules;
Packit 284210
    int i, j, mode;
Packit 284210
    char *err;
Packit 284210
Packit 284210
    j = 0;
Packit 284210
    mode = 0;
Packit 284210
    rules = (msre_rule **)phase_arr->elts;
Packit 284210
    for (i = 0; i < phase_arr->nelts; i++) {
Packit 284210
        msre_rule *rule = (msre_rule *)rules[i];
Packit 284210
Packit 284210
        if (mode == 0) { /* Looking for next rule. */
Packit 284210
            if (msre_ruleset_rule_matches_exception(rule, re)) {
Packit 284210
Packit 284210
                err = update_rule_target_ex(NULL, ruleset, rule, p2, p3);
Packit 284210
                if (err) return err;
Packit 284210
                if (rule->actionset->is_chained) mode = 2; /* Match all rules in this chain. */
Packit 284210
            } else {
Packit 284210
                if (rule->actionset->is_chained) mode = 1; /* Skip all rules in this chain. */
Packit 284210
            }
Packit 284210
        } else { /* Handling rule that is part of a chain. */
Packit 284210
            if (mode == 2) { /* We want to change the rule. */
Packit 284210
                err = update_rule_target_ex(msr, ruleset, rule, p2, p3);
Packit 284210
                if (err) return err;
Packit 284210
            }
Packit 284210
Packit 284210
            if ((rule->actionset == NULL)||(rule->actionset->is_chained == 0)) mode = 0;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    return NULL;
Packit 284210
}
Packit 284210
Packit 284210
Packit 284210
char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *rule, const char *p2,
Packit 284210
        const char *p3)   {
Packit 284210
Packit 284210
    msre_var **targets = NULL;
Packit 284210
    const char *current_targets = NULL;
Packit 284210
    char *my_error_msg = NULL, *target = NULL;
Packit 284210
    char *p = NULL, *savedptr = NULL;
Packit 284210
    unsigned int is_negated = 0, is_counting = 0;
Packit 284210
    int name_len = 0, value_len = 0;
Packit 284210
    char *name = NULL, *value = NULL;
Packit 284210
    char *opt = NULL, *param = NULL;
Packit 284210
    char *target_list = NULL, *replace = NULL;
Packit 284210
    int i, rc, match = 0, var_appended = 0;
Packit 284210
Packit 284210
    if(rule != NULL)    {
Packit 284210
Packit 284210
        target_list = strdup(p2);
Packit 284210
        if(target_list == NULL)
Packit 284210
            return apr_psprintf(ruleset->mp, "Error to update target - memory allocation");;
Packit 284210
Packit 284210
        if(p3 != NULL)  {
Packit 284210
            replace = strdup(p3);
Packit 284210
            if(replace == NULL) {
Packit 284210
                free(target_list);
Packit 284210
                target_list = NULL;
Packit 284210
                return apr_psprintf(ruleset->mp, "Error to update target - memory allocation");;
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        if(replace != NULL) {
Packit 284210
Packit 284210
            opt = strchr(replace,'!');
Packit 284210
Packit 284210
            if(opt != NULL)  {
Packit 284210
                *opt = '\0';
Packit 284210
                opt++;
Packit 284210
                param = opt;
Packit 284210
                is_negated = 1;
Packit 284210
            } else if ((opt = strchr(replace,'&')) != NULL)  {
Packit 284210
                *opt = '\0';
Packit 284210
                opt++;
Packit 284210
                param = opt;
Packit 284210
                is_counting = 1;
Packit 284210
            } else  {
Packit 284210
                param = replace;
Packit 284210
            }
Packit 284210
Packit 284210
            opt = strchr(param,':');
Packit 284210
Packit 284210
            if(opt != NULL) {
Packit 284210
                name = apr_strtok(param,":",&value);
Packit 284210
            } else {
Packit 284210
                name = param;
Packit 284210
            }
Packit 284210
Packit 284210
            if(apr_table_get(ruleset->engine->variables, name) == NULL)   {
Packit 284210
                if(target_list != NULL)
Packit 284210
                    free(target_list);
Packit 284210
                if(replace != NULL)
Packit 284210
                    free(replace);
Packit 284210
                if(msr) {
Packit 284210
                    msr_log(msr, 9, "Error to update target - [%s] is not valid target", name);
Packit 284210
                }
Packit 284210
                return apr_psprintf(ruleset->mp, "Error to update target - [%s] is not valid target", name);
Packit 284210
            }
Packit 284210
Packit 284210
            name_len = strlen(name);
Packit 284210
Packit 284210
            if(value != NULL)
Packit 284210
                value_len = strlen(value);
Packit 284210
Packit 284210
            if(msr) {
Packit 284210
                msr_log(msr, 9, "Trying to replace by variable name [%s] value [%s]", name, value);
Packit 284210
            }
Packit 284210
#if !defined(MSC_TEST)
Packit 284210
            else {
Packit 284210
                ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Trying to replace by variable name [%s] value [%s]", name, value);
Packit 284210
            }
Packit 284210
#endif
Packit 284210
Packit 284210
            targets = (msre_var **)rule->targets->elts;
Packit 284210
            // TODO need a good way to remove the element from array, maybe change array by tables or rings
Packit 284210
            for (i = 0; i < rule->targets->nelts; i++) {
Packit 284210
                if((strlen(targets[i]->name) == strlen(name)) &&
Packit 284210
                        (strncasecmp(targets[i]->name,name,strlen(targets[i]->name)) == 0) &&
Packit 284210
                        (targets[i]->is_negated == is_negated) &&
Packit 284210
                        (targets[i]->is_counting == is_counting))    {
Packit 284210
Packit 284210
                    if(value != NULL && targets[i]->param != NULL)  {
Packit 284210
                        if((strlen(targets[i]->param) == strlen(value)) &&
Packit 284210
                                strncasecmp(targets[i]->param,value,strlen(targets[i]->param)) == 0) {
Packit 284210
                            memset(targets[i]->name,0,strlen(targets[i]->name));
Packit 284210
                            memset(targets[i]->param,0,strlen(targets[i]->param));
Packit 284210
                            targets[i]->is_counting = 0;
Packit 284210
                            targets[i]->is_negated = 1;
Packit 284210
                            match = 1;
Packit 284210
                        }
Packit 284210
                    } else if (value == NULL && targets[i]->param == NULL){
Packit 284210
                        memset(targets[i]->name,0,strlen(targets[i]->name));
Packit 284210
                        targets[i]->is_counting = 0;
Packit 284210
                        targets[i]->is_negated = 1;
Packit 284210
                        match = 1;
Packit 284210
                    } else
Packit 284210
                        continue;
Packit 284210
Packit 284210
                }
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        p = apr_strtok(target_list, ",", &savedptr);
Packit 284210
Packit 284210
        while(p != NULL) {
Packit 284210
            if(replace != NULL) {
Packit 284210
                if(match == 1)  {
Packit 284210
                    rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg);
Packit 284210
                    if (rc < 0) {
Packit 284210
                        if(msr) {
Packit 284210
                            msr_log(msr, 9, "Error parsing rule targets to replace variable");
Packit 284210
                        }
Packit 284210
#if !defined(MSC_TEST)
Packit 284210
                        else {
Packit 284210
                            ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Error parsing rule targets to replace variable");
Packit 284210
                        }
Packit 284210
#endif
Packit 284210
                        goto end;
Packit 284210
                    }
Packit 284210
                    if(msr) {
Packit 284210
                        msr_log(msr, 9, "Successfully replaced variable");
Packit 284210
                    }
Packit 284210
#if !defined(MSC_TEST)
Packit 284210
                    else {
Packit 284210
                        ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Successfully replaced variable");
Packit 284210
                    }
Packit 284210
#endif
Packit 284210
                var_appended = 1;
Packit 284210
Packit 284210
                } else  {
Packit 284210
                    if(msr) {
Packit 284210
                        msr_log(msr, 9, "Cannot find variable to replace");
Packit 284210
                    }
Packit 284210
#if !defined(MSC_TEST)
Packit 284210
                    else {
Packit 284210
                        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Cannot find varibale to replace");
Packit 284210
                    }
Packit 284210
#endif
Packit 284210
                    goto end;
Packit 284210
                }
Packit 284210
            } else {
Packit 284210
Packit 284210
                target = strdup(p);
Packit 284210
                if(target == NULL)
Packit 284210
                    return NULL;
Packit 284210
Packit 284210
                is_negated = is_counting = 0;
Packit 284210
                param = name = value = NULL;
Packit 284210
Packit 284210
                opt = strchr(target,'!');
Packit 284210
Packit 284210
                if(opt != NULL)  {
Packit 284210
                    *opt = '\0';
Packit 284210
                    opt++;
Packit 284210
                    param = opt;
Packit 284210
                    is_negated = 1;
Packit 284210
                } else if ((opt = strchr(target,'&')) != NULL)  {
Packit 284210
                    *opt = '\0';
Packit 284210
                    opt++;
Packit 284210
                    param = opt;
Packit 284210
                    is_counting = 1;
Packit 284210
                } else  {
Packit 284210
                    param = target;
Packit 284210
                }
Packit 284210
Packit 284210
                opt = strchr(param,':');
Packit 284210
Packit 284210
                if(opt != NULL) {
Packit 284210
                    name = apr_strtok(param,":",&value);
Packit 284210
                } else {
Packit 284210
                    name = param;
Packit 284210
                }
Packit 284210
Packit 284210
                if(apr_table_get(ruleset->engine->variables, name) == NULL)   {
Packit 284210
                    if(target_list != NULL)
Packit 284210
                        free(target_list);
Packit 284210
                    if(replace != NULL)
Packit 284210
                        free(replace);
Packit 284210
                    if(msr) {
Packit 284210
                        msr_log(msr, 9, "Error to update target - [%s] is not valid target", name);
Packit 284210
                    }
Packit 284210
                    return apr_psprintf(ruleset->mp, "Error to update target - [%s] is not valid target", name);
Packit 284210
                }
Packit 284210
Packit 284210
                name_len = strlen(name);
Packit 284210
Packit 284210
                if(value != NULL)
Packit 284210
                    value_len = strlen(value);
Packit 284210
Packit 284210
                if(msr) {
Packit 284210
                    msr_log(msr, 9, "Trying to append variable name [%s] value [%s]", name, value);
Packit 284210
                }
Packit 284210
#if !defined(MSC_TEST)
Packit 284210
                else {
Packit 284210
                    ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Trying to append variable name [%s] value [%s]", name, value);
Packit 284210
                }
Packit 284210
#endif
Packit 284210
                match = 0;
Packit 284210
Packit 284210
                targets = (msre_var **)rule->targets->elts;
Packit 284210
                for (i = 0; i < rule->targets->nelts; i++) {
Packit 284210
                    if((strlen(targets[i]->name) == strlen(name)) &&
Packit 284210
                            (strncasecmp(targets[i]->name,name,strlen(targets[i]->name)) == 0) &&
Packit 284210
                            (targets[i]->is_negated == is_negated) &&
Packit 284210
                            (targets[i]->is_counting == is_counting))    {
Packit 284210
Packit 284210
                        if(value != NULL && targets[i]->param != NULL)  {
Packit 284210
                            if((strlen(targets[i]->param) == strlen(value)) &&
Packit 284210
                                    strncasecmp(targets[i]->param,value,strlen(targets[i]->param)) == 0) {
Packit 284210
                                match = 1;
Packit 284210
                            }
Packit 284210
                        } else if (value == NULL && targets[i]->param == NULL){
Packit 284210
                            match = 1;
Packit 284210
                        } else
Packit 284210
                            continue;
Packit 284210
Packit 284210
                    }
Packit 284210
                }
Packit 284210
Packit 284210
                if(target != NULL)  {
Packit 284210
                    free(target);
Packit 284210
                    target = NULL;
Packit 284210
                }
Packit 284210
Packit 284210
                if(match == 0 ) {
Packit 284210
                    rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg);
Packit 284210
                    if (rc < 0) {
Packit 284210
                        if(msr) {
Packit 284210
                            msr_log(msr, 9, "Error parsing rule targets to append variable");
Packit 284210
                        }
Packit 284210
#if !defined(MSC_TEST)
Packit 284210
                        else {
Packit 284210
                            ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Error parsing rule targets to append variable");
Packit 284210
                        }
Packit 284210
#endif
Packit 284210
                        goto end;
Packit 284210
                    }
Packit 284210
                    var_appended = 1;
Packit 284210
                } else {
Packit 284210
                    if(msr) {
Packit 284210
                        msr_log(msr, 9, "Skipping variable, already appended");
Packit 284210
                    }
Packit 284210
#if !defined(MSC_TEST)
Packit 284210
                    else {
Packit 284210
                        ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Skipping variable, already appended");
Packit 284210
                    }
Packit 284210
#endif
Packit 284210
                }
Packit 284210
            }
Packit 284210
Packit 284210
            p = apr_strtok(NULL,",",&savedptr);
Packit 284210
        }
Packit 284210
Packit 284210
        if(var_appended == 1)  {
Packit 284210
            current_targets = msre_generate_target_string(ruleset->mp, rule);
Packit 284210
            rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, current_targets, NULL, NULL);
Packit 284210
            rule->p1 = apr_pstrdup(ruleset->mp, current_targets);
Packit 284210
            if(msr) {
Packit 284210
                msr_log(msr, 9, "Successfully appended variable");
Packit 284210
            }
Packit 284210
#if !defined(MSC_TEST)
Packit 284210
            else {
Packit 284210
                ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Successfully appended variable");
Packit 284210
            }
Packit 284210
#endif
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
end:
Packit 284210
    if(target_list != NULL) {
Packit 284210
        free(target_list);
Packit 284210
        target_list = NULL;
Packit 284210
    }
Packit 284210
    if(replace != NULL) {
Packit 284210
        free(replace);
Packit 284210
        replace = NULL;
Packit 284210
    }
Packit 284210
    if(target != NULL)  {
Packit 284210
        free(target);
Packit 284210
        target = NULL;
Packit 284210
    }
Packit 284210
    return NULL;
Packit 284210
}
Packit 284210
Packit 284210
int msre_ruleset_rule_matches_exception(msre_rule *rule, rule_exception *re)   {
Packit 284210
    int match = 0;
Packit 284210
Packit 284210
    /* Only remove non-placeholder rules */
Packit 284210
    if (rule->placeholder == RULE_PH_NONE) {
Packit 284210
        switch(re->type) {
Packit 284210
            case RULE_EXCEPTION_REMOVE_ID :
Packit 284210
                if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) {
Packit 284210
                    int ruleid = atoi(rule->actionset->id);
Packit 284210
Packit 284210
                    if (rule_id_in_range(ruleid, re->param)) {
Packit 284210
                        match = 1;
Packit 284210
                    }
Packit 284210
                }
Packit 284210
Packit 284210
                break;
Packit 284210
            case RULE_EXCEPTION_REMOVE_MSG :
Packit 284210
                if ((rule->actionset != NULL)&&(rule->actionset->msg != NULL)) {
Packit 284210
                    char *my_error_msg = NULL;
Packit 284210
Packit 284210
                    int rc = msc_regexec(re->param_data,
Packit 284210
                            rule->actionset->msg, strlen(rule->actionset->msg),
Packit 284210
                            &my_error_msg);
Packit 284210
                    if (rc >= 0) {
Packit 284210
                        match = 1;
Packit 284210
                    }
Packit 284210
                }
Packit 284210
Packit 284210
                break;
Packit 284210
            case RULE_EXCEPTION_REMOVE_TAG :
Packit 284210
                if ((rule->actionset != NULL)&&(apr_is_empty_table(rule->actionset->actions) == 0)) {
Packit 284210
                    char *my_error_msg = NULL;
Packit 284210
                    const apr_array_header_t *tarr = NULL;
Packit 284210
                    const apr_table_entry_t *telts = NULL;
Packit 284210
                    int act;
Packit 284210
Packit 284210
                    tarr = apr_table_elts(rule->actionset->actions);
Packit 284210
                    telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
Packit 284210
                    for (act = 0; act < tarr->nelts; act++) {
Packit 284210
                        msre_action *action = (msre_action *)telts[act].val;
Packit 284210
                        if((action != NULL) && (action->metadata != NULL) && (strcmp("tag", action->metadata->name) == 0))  {
Packit 284210
Packit 284210
                            int rc = msc_regexec(re->param_data,
Packit 284210
                                    action->param, strlen(action->param),
Packit 284210
                                    &my_error_msg);
Packit 284210
                            if (rc >= 0)    {
Packit 284210
                                match = 1;
Packit 284210
                            }
Packit 284210
                        }
Packit 284210
                    }
Packit 284210
                }
Packit 284210
                break;
Packit 284210
        }
Packit 284210
    }
Packit 284210
    return match;
Packit 284210
}
Packit 284210
Packit 284210
Packit 284210
Packit 284210
/**
Packit 284210
 * Remove actions with the same cardinality group from the actionset.
Packit 284210
 */
Packit 284210
static void msre_actionset_cardinality_fixup(msre_actionset *actionset, msre_action *action) {
Packit 284210
    const apr_array_header_t *tarr = NULL;
Packit 284210
    const apr_table_entry_t *telts = NULL;
Packit 284210
    int i;
Packit 284210
Packit 284210
    if ((actionset == NULL) || (action == NULL)) return;
Packit 284210
Packit 284210
    tarr = apr_table_elts(actionset->actions);
Packit 284210
    telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
Packit 284210
    for (i = 0; i < tarr->nelts; i++) {
Packit 284210
        msre_action *target = (msre_action *)telts[i].val;
Packit 284210
        if (target->metadata->cardinality_group == action->metadata->cardinality_group) {
Packit 284210
Packit 284210
            apr_table_unset(actionset->actions, target->metadata->name);
Packit 284210
        }
Packit 284210
    }
Packit 284210
}
Packit 284210
Packit 284210
static char *msre_generate_target_string(apr_pool_t *pool, msre_rule *rule)  {
Packit 284210
Packit 284210
    char *target_str = NULL;
Packit 284210
    msre_var **targets = NULL;
Packit 284210
    int i = 0;
Packit 284210
Packit 284210
    targets = (msre_var **)rule->targets->elts;
Packit 284210
Packit 284210
    for (i = 0; i < rule->targets->nelts; i++) {
Packit 284210
Packit 284210
        if(targets[i]->name != NULL && strlen(targets[i]->name) > 0)    {
Packit 284210
            target_str = apr_pstrcat(pool,
Packit 284210
                    (target_str == NULL) ? "" : apr_psprintf(pool, "%s|", target_str),
Packit 284210
                    (targets[i]->is_negated == 0) ? "" : "!",
Packit 284210
                    (targets[i]->is_counting == 0) ? "" : "&",
Packit 284210
                    (targets[i]->name == NULL) ? "" : targets[i]->name,
Packit 284210
                    (targets[i]->param == NULL) ? "" : apr_psprintf(pool, ":%s", targets[i]->param),
Packit 284210
                    NULL);
Packit 284210
        }
Packit 284210
Packit 284210
    }
Packit 284210
Packit 284210
    return target_str;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Generate an action string from an actionset.
Packit 284210
 */
Packit 284210
static char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset)  {
Packit 284210
    const apr_array_header_t *tarr = NULL;
Packit 284210
    const apr_table_entry_t *telts = NULL;
Packit 284210
    char *actions = NULL;
Packit 284210
    int chain;
Packit 284210
    int i;
Packit 284210
Packit 284210
    if (actionset == NULL) return NULL;
Packit 284210
Packit 284210
    chain = ((actionset->rule != NOT_SET_P) && actionset->rule->chain_starter) ? 1 : 0;
Packit 284210
Packit 284210
    tarr = apr_table_elts(actionset->actions);
Packit 284210
    telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
Packit 284210
    for (i = 0; i < tarr->nelts; i++) {
Packit 284210
        msre_action *action = (msre_action *)telts[i].val;
Packit 284210
        int use_quotes = 0;
Packit 284210
Packit 284210
        if (chain) {
Packit 284210
            /* Skip some actions that are not used in a chain. */
Packit 284210
            if (   (action->metadata->type == ACTION_DISRUPTIVE)
Packit 284210
                    || (action->metadata->type == ACTION_METADATA)
Packit 284210
                    || (strcmp("log", action->metadata->name) == 0)
Packit 284210
                    || (strcmp("auditlog", action->metadata->name) == 0)
Packit 284210
                    || (strcmp("nolog", action->metadata->name) == 0)
Packit 284210
                    || (strcmp("noauditlog", action->metadata->name) == 0)
Packit 284210
                    || (strcmp("severity", action->metadata->name) == 0)
Packit 284210
                    || (strcmp("ver", action->metadata->name) == 0)
Packit 284210
                    || (strcmp("maturity", action->metadata->name) == 0)
Packit 284210
                    || (strcmp("accuracy", action->metadata->name) == 0)
Packit 284210
                    || (strcmp("tag", action->metadata->name) == 0)
Packit 284210
                    || (strcmp("phase", action->metadata->name) == 0)) 
Packit 284210
            {
Packit 284210
                continue;
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        /* Check if we need any quotes */
Packit 284210
        if (action->param != NULL) {
Packit 284210
            int j;
Packit 284210
            for(j = 0; action->param[j] != '\0'; j++) {
Packit 284210
                if (isspace(action->param[j])) {
Packit 284210
                    use_quotes = 1;
Packit 284210
                    break;
Packit 284210
                }
Packit 284210
            }
Packit 284210
            if (j == 0) use_quotes = 1;
Packit 284210
        }
Packit 284210
Packit 284210
        actions = apr_pstrcat(pool,
Packit 284210
                (actions == NULL) ? "" : actions,
Packit 284210
                (actions == NULL) ? "" : ",",
Packit 284210
                action->metadata->name,
Packit 284210
                (action->param == NULL) ? "" : ":",
Packit 284210
                (use_quotes) ? "'" : "",
Packit 284210
                (action->param == NULL) ? "" : action->param,
Packit 284210
                (use_quotes) ? "'" : "",
Packit 284210
                NULL);
Packit 284210
    }
Packit 284210
Packit 284210
    return actions;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Add an action to an actionset.
Packit 284210
 */
Packit 284210
static void msre_actionset_action_add(msre_actionset *actionset, msre_action *action)
Packit 284210
{
Packit 284210
    msre_action *add_action = action;
Packit 284210
Packit 284210
    if ((actionset == NULL)) return;
Packit 284210
Packit 284210
    /**
Packit 284210
     * The "block" action is just a placeholder for the parent action.
Packit 284210
     */
Packit 284210
    if ((actionset->parent_intercept_action_rec != NULL) && (actionset->parent_intercept_action_rec != NOT_SET_P) && (strcmp("block", action->metadata->name) == 0) && (strcmp("block", action->metadata->name) == 0)) {
Packit 284210
        /* revert back to parent */
Packit 284210
        actionset->intercept_action = actionset->parent_intercept_action;
Packit 284210
        add_action = actionset->parent_intercept_action_rec;
Packit 284210
    }
Packit 284210
Packit 284210
    if ((add_action == NULL)) return;
Packit 284210
Packit 284210
    if (add_action->metadata->cardinality_group != ACTION_CGROUP_NONE) {
Packit 284210
        msre_actionset_cardinality_fixup(actionset, add_action);
Packit 284210
    }
Packit 284210
Packit 284210
    if (add_action->metadata->cardinality == ACTION_CARDINALITY_ONE) {
Packit 284210
        /* One action per actionlist. */
Packit 284210
        apr_table_setn(actionset->actions, add_action->metadata->name, (void *)add_action);
Packit 284210
    } else {
Packit 284210
        /* Multiple actions per actionlist. */
Packit 284210
        apr_table_addn(actionset->actions, add_action->metadata->name, (void *)add_action);
Packit 284210
    }
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Creates msre_var instances (rule variables) out of the
Packit 284210
 * given text string and places them into the supplied table.
Packit 284210
 */
Packit 284210
static apr_status_t msre_parse_targets(msre_ruleset *ruleset, const char *text,
Packit 284210
        apr_array_header_t *arr, char **error_msg)
Packit 284210
{
Packit 284210
    const apr_array_header_t *tarr;
Packit 284210
    const apr_table_entry_t *telts;
Packit 284210
    apr_table_t *vartable;
Packit 284210
    unsigned int count = 0;
Packit 284210
    apr_status_t rc;
Packit 284210
    msre_var *var;
Packit 284210
    int i;
Packit 284210
Packit 284210
    if (text == NULL) return -1;
Packit 284210
Packit 284210
    /* Extract name & value pairs first */
Packit 284210
    vartable = apr_table_make(ruleset->mp, 10);
Packit 284210
    if (vartable == NULL) return -1;
Packit 284210
    rc = msre_parse_generic(ruleset->mp, text, vartable, error_msg);
Packit 284210
    if (rc < 0) return rc;
Packit 284210
Packit 284210
    /* Loop through the table and create variables */
Packit 284210
    tarr = apr_table_elts(vartable);
Packit 284210
    telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
    for (i = 0; i < tarr->nelts; i++) {
Packit 284210
        var = msre_create_var(ruleset, telts[i].key, telts[i].val, NULL, error_msg);
Packit 284210
        if (var == NULL) return -1;
Packit 284210
        *(msre_var **)apr_array_push(arr) = var;
Packit 284210
        count++;
Packit 284210
    }
Packit 284210
Packit 284210
    return count;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Creates msre_action instances by parsing the given string, placing
Packit 284210
 * them into the supplied array.
Packit 284210
 */
Packit 284210
static apr_status_t msre_parse_actions(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset,
Packit 284210
        const char *text, char **error_msg)
Packit 284210
{
Packit 284210
    const apr_array_header_t *tarr;
Packit 284210
    const apr_table_entry_t *telts;
Packit 284210
    apr_table_t *vartable;
Packit 284210
    unsigned int count = 0;
Packit 284210
    apr_status_t rc;
Packit 284210
    msre_action *action;
Packit 284210
    int i;
Packit 284210
Packit 284210
Packit 284210
    if (error_msg == NULL) {
Packit 284210
        return -1;
Packit 284210
    }
Packit 284210
    *error_msg = NULL;
Packit 284210
Packit 284210
Packit 284210
    if (text == NULL) {
Packit 284210
        *error_msg = apr_psprintf(mp, "Internal error: " \
Packit 284210
            "msre_parse_actions, variable text is NULL");
Packit 284210
        return -1;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Extract name & value pairs first */
Packit 284210
    vartable = apr_table_make(mp, 10);
Packit 284210
    if (vartable == NULL) {
Packit 284210
        *error_msg = apr_psprintf(mp, "Internal error: " \
Packit 284210
            "msre_parse_actions, failed to create vartable");
Packit 284210
Packit 284210
        return -1;
Packit 284210
    }
Packit 284210
    rc = msre_parse_generic(mp, text, vartable, error_msg);
Packit 284210
    if (rc < 0) {
Packit 284210
        if (*error_msg == NULL)
Packit 284210
            *error_msg = apr_psprintf(mp, "Internal error: " \
Packit 284210
                "msre_parse_actions, msre_parse_generic failed. Return " \
Packit 284210
                "code: %d", rc);
Packit 284210
Packit 284210
        return rc;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Loop through the table and create actions */
Packit 284210
    tarr = apr_table_elts(vartable);
Packit 284210
    telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
    for (i = 0; i < tarr->nelts; i++) {
Packit 284210
        /* Create action. */
Packit 284210
        action = msre_create_action(engine, mp, telts[i].key, telts[i].val, error_msg);
Packit 284210
        if (action == NULL) {
Packit 284210
            if (*error_msg == NULL)
Packit 284210
                *error_msg = apr_psprintf(mp, "Internal error: " \
Packit 284210
                    "msre_parse_actions, msre_create_action failed.");
Packit 284210
            return -1;
Packit 284210
        }
Packit 284210
Packit 284210
        /* Initialise action (option). */
Packit 284210
        if (action->metadata->init != NULL) {
Packit 284210
            action->metadata->init(engine, mp, actionset, action);
Packit 284210
        }
Packit 284210
Packit 284210
        msre_actionset_action_add(actionset, action);
Packit 284210
Packit 284210
        count++;
Packit 284210
    }
Packit 284210
Packit 284210
    return count;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Locates variable metadata given the variable name.
Packit 284210
 */
Packit 284210
msre_var_metadata *msre_resolve_var(msre_engine *engine, const char *name)
Packit 284210
{
Packit 284210
    return (msre_var_metadata *)apr_table_get(engine->variables, name);
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Locates action metadata given the action name.
Packit 284210
 */
Packit 284210
static msre_action_metadata *msre_resolve_action(msre_engine *engine, const char *name)
Packit 284210
{
Packit 284210
    return (msre_action_metadata *)apr_table_get(engine->actions, name);
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Creates a new variable instance given the variable name
Packit 284210
 * and an (optional) parameter.
Packit 284210
 */
Packit 284210
msre_var *msre_create_var_ex(apr_pool_t *pool, msre_engine *engine, const char *name, const char *param,
Packit 284210
        modsec_rec *msr, char **error_msg)
Packit 284210
{
Packit 284210
    const char *varparam = param;
Packit 284210
    msre_var *var = apr_pcalloc(pool, sizeof(msre_var));
Packit 284210
    if (var == NULL) return NULL;
Packit 284210
Packit 284210
    if (error_msg == NULL) return NULL;
Packit 284210
    *error_msg = NULL;
Packit 284210
Packit 284210
    /* Handle negation and member counting */
Packit 284210
    if (name[0] == '!') {
Packit 284210
        var->is_negated = 1;
Packit 284210
        var->name = (char *)name + 1;
Packit 284210
    }
Packit 284210
    else
Packit 284210
        if (name[0] == '&') {
Packit 284210
            var->is_counting = 1;
Packit 284210
            var->name = (char *)name + 1;
Packit 284210
        }
Packit 284210
        else {
Packit 284210
            var->name = (char *)name;
Packit 284210
        }
Packit 284210
Packit 284210
    /* Treat HTTP_* targets as an alias for REQUEST_HEADERS:* */
Packit 284210
    if (   (var->name != NULL)
Packit 284210
            && (strlen(var->name) > 5)
Packit 284210
            && (strncmp("HTTP_", var->name, 5) == 0))
Packit 284210
    {
Packit 284210
        const char *oldname = var->name;
Packit 284210
        var->name = apr_pstrdup(pool, "REQUEST_HEADERS");
Packit 284210
        varparam = apr_pstrdup(pool, oldname + 5);
Packit 284210
    }
Packit 284210
Packit 284210
Packit 284210
    /* Resolve variable */
Packit 284210
    var->metadata = msre_resolve_var(engine, var->name);
Packit 284210
    if (var->metadata == NULL) {
Packit 284210
        *error_msg = apr_psprintf(pool, "Unknown variable: %s", name);
Packit 284210
        return NULL;
Packit 284210
    }
Packit 284210
Packit 284210
    /* The counting operator "&" can only be used against collections. */
Packit 284210
    if (var->is_counting) {
Packit 284210
        if (var->metadata->type == VAR_SIMPLE) {
Packit 284210
            *error_msg = apr_psprintf(pool, "The & modificator does not apply to "
Packit 284210
                    "non-collection variables.");
Packit 284210
            return NULL;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* Check the parameter. */
Packit 284210
    if (varparam == NULL) {
Packit 284210
        if (var->metadata->argc_min > 0) {
Packit 284210
            *error_msg = apr_psprintf(pool, "Missing mandatory parameter for variable %s.",
Packit 284210
                    name);
Packit 284210
            return NULL;
Packit 284210
        }
Packit 284210
    } else { /* Parameter present */
Packit 284210
Packit 284210
        /* Do we allow a parameter? */
Packit 284210
        if (var->metadata->argc_max == 0) {
Packit 284210
            *error_msg = apr_psprintf(pool, "Variable %s does not support parameters.",
Packit 284210
                    name);
Packit 284210
            return NULL;
Packit 284210
        }
Packit 284210
Packit 284210
        var->param = (char *)varparam;
Packit 284210
Packit 284210
    }
Packit 284210
Packit 284210
    return var;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Create a new variable object from the provided name and value.
Packit 284210
 *
Packit 284210
 * NOTE: this allocates out of the global pool and should not be used
Packit 284210
 *       per-request
Packit 284210
 */
Packit 284210
static msre_var *msre_create_var(msre_ruleset *ruleset, const char *name, const char *param,
Packit 284210
        modsec_rec *msr, char **error_msg)
Packit 284210
{
Packit 284210
    msre_var *var = msre_create_var_ex(ruleset->mp, ruleset->engine, name, param, msr, error_msg);
Packit 284210
    if (var == NULL) return NULL;
Packit 284210
Packit 284210
    /* Validate & initialise variable */
Packit 284210
    if (var->metadata->validate != NULL) {
Packit 284210
        *error_msg = var->metadata->validate(ruleset, var);
Packit 284210
        if (*error_msg != NULL) {
Packit 284210
            return NULL;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    return var;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Creates a new action instance given its name and an (optional) parameter.
Packit 284210
 */
Packit 284210
msre_action *msre_create_action(msre_engine *engine, apr_pool_t *mp, const char *name, const char *param,
Packit 284210
        char **error_msg)
Packit 284210
{
Packit 284210
    msre_action *action = NULL;
Packit 284210
Packit 284210
    if (error_msg == NULL) {
Packit 284210
        return NULL;
Packit 284210
    }
Packit 284210
    *error_msg = NULL;
Packit 284210
Packit 284210
Packit 284210
    action = apr_pcalloc(mp, sizeof(msre_action));
Packit 284210
Packit 284210
    if (action == NULL) {
Packit 284210
        *error_msg = apr_psprintf(mp, "Internal error: " \
Packit 284210
            "msre_create_action, not able to allocate action");
Packit 284210
Packit 284210
        return NULL;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Resolve action */
Packit 284210
    action->metadata = msre_resolve_action(engine, name);
Packit 284210
    if (action->metadata == NULL) {
Packit 284210
        *error_msg = apr_psprintf(mp, "Unknown action: %s", name);
Packit 284210
        return NULL;
Packit 284210
    }
Packit 284210
Packit 284210
    if (param == NULL) { /* Parameter not present */
Packit 284210
        if (action->metadata->argc_min > 0) {
Packit 284210
            *error_msg = apr_psprintf(mp, "Missing mandatory parameter for action %s",
Packit 284210
                    name);
Packit 284210
            return NULL;
Packit 284210
        }
Packit 284210
    } else { /* Parameter present */
Packit 284210
Packit 284210
        /* Should we allow the parameter? */
Packit 284210
        if (action->metadata->argc_max == 0) {
Packit 284210
            *error_msg = apr_psprintf(mp, "Extra parameter provided to action %s", name);
Packit 284210
            return NULL;
Packit 284210
        }
Packit 284210
Packit 284210
        /* Handle +/- modificators */
Packit 284210
        if ((param[0] == '+')||(param[0] == '-')) {
Packit 284210
            if (action->metadata->allow_param_plusminus == 0) {
Packit 284210
                *error_msg = apr_psprintf(mp,
Packit 284210
                        "Action %s does not allow +/- modificators.", name);
Packit 284210
                return NULL;
Packit 284210
            }
Packit 284210
            else { /* Modificators allowed. */
Packit 284210
                if (param[0] == '+') {
Packit 284210
                    action->param = param + 1;
Packit 284210
                    action->param_plusminus = POSITIVE_VALUE;
Packit 284210
                } else
Packit 284210
                    if (param[0] == '-') {
Packit 284210
                        action->param = param + 1;
Packit 284210
                        action->param_plusminus = NEGATIVE_VALUE;
Packit 284210
                    }
Packit 284210
            }
Packit 284210
        } else {
Packit 284210
            action->param = param;
Packit 284210
        }
Packit 284210
Packit 284210
        /* Validate parameter */
Packit 284210
        if (action->metadata->validate != NULL) {
Packit 284210
            *error_msg = action->metadata->validate(engine, mp, action);
Packit 284210
            if (*error_msg != NULL) return NULL;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    return action;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Generic parser that is used as basis for target and action parsing.
Packit 284210
 * It breaks up the input string into name-parameter pairs and places
Packit 284210
 * them into the given table.
Packit 284210
 */
Packit 284210
int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable,
Packit 284210
        char **error_msg)
Packit 284210
{
Packit 284210
    char *p = (char *)text;
Packit 284210
    int count = 0;
Packit 284210
Packit 284210
    if (error_msg == NULL) return -1;
Packit 284210
    *error_msg = NULL;
Packit 284210
Packit 284210
    count = 0;
Packit 284210
    while(*p != '\0') {
Packit 284210
        char *name = NULL, *value = NULL;
Packit 284210
Packit 284210
        /* ignore whitespace */
Packit 284210
        while(isspace(*p)) p++;
Packit 284210
        if (*p == '\0') return count;
Packit 284210
Packit 284210
        /* we are at the beginning of the name */
Packit 284210
        name = p;
Packit 284210
        while((*p != '\0')&&(*p != '|')&&(*p != ':')&&(*p != ',')&&(!isspace(*p))) p++; /* ENH replace with isvarnamechar() */
Packit 284210
Packit 284210
        /* get the name */
Packit 284210
        name = apr_pstrmemdup(mp, name, p - name);
Packit 284210
Packit 284210
        if (*p != ':') { /* we don't have a parameter */
Packit 284210
            /* add to the table with no value */
Packit 284210
            apr_table_addn(vartable, name, NULL);
Packit 284210
            count++;
Packit 284210
Packit 284210
            /* go over any whitespace present */
Packit 284210
            while(isspace(*p)) p++;
Packit 284210
Packit 284210
            /* we're done */
Packit 284210
            if (*p == '\0') {
Packit 284210
                return count;
Packit 284210
            }
Packit 284210
Packit 284210
            /* skip over the separator character and continue */
Packit 284210
            if ((*p == ',')||(*p == '|')) {
Packit 284210
                p++;
Packit 284210
                continue;
Packit 284210
            }
Packit 284210
Packit 284210
            *error_msg = apr_psprintf(mp, "Unexpected character at position %d: %s",
Packit 284210
                    (int)(p - text), text);
Packit 284210
            return -1;
Packit 284210
        }
Packit 284210
Packit 284210
        /* we have a parameter */
Packit 284210
Packit 284210
        p++; /* move over the colon */
Packit 284210
Packit 284210
        /* we'll allow empty values */
Packit 284210
        if (*p == '\0') {
Packit 284210
            apr_table_addn(vartable, name, NULL);
Packit 284210
            count++;
Packit 284210
            return count;
Packit 284210
        }
Packit 284210
Packit 284210
        if ((*p == ',')||(*p == '|')) {
Packit 284210
            apr_table_addn(vartable, name, NULL);
Packit 284210
            count++;
Packit 284210
            /* move over the separator char and continue */
Packit 284210
            p++;
Packit 284210
            continue;
Packit 284210
        }
Packit 284210
Packit 284210
        /* we really have a parameter */
Packit 284210
Packit 284210
        if (*p == '\'') { /* quoted value */
Packit 284210
            char *d = NULL;
Packit 284210
Packit 284210
            p++; /* go over the openning quote */
Packit 284210
            value = d = strdup(p);
Packit 284210
            if (d == NULL) return -1;
Packit 284210
Packit 284210
            for(;;) {
Packit 284210
                if (*p == '\0') {
Packit 284210
                    *error_msg = apr_psprintf(mp, "Missing closing quote at position %d: %s",
Packit 284210
                            (int)(p - text), text);
Packit 284210
                    free(value);
Packit 284210
                    return -1;
Packit 284210
                } else
Packit 284210
                    if (*p == '\\') {
Packit 284210
                        if ( (*(p + 1) == '\0') || ((*(p + 1) != '\'')&&(*(p + 1) != '\\')) ) {
Packit 284210
                            *error_msg = apr_psprintf(mp, "Invalid quoted pair at position %d: %s",
Packit 284210
                                    (int)(p - text), text);
Packit 284210
                            free(value);
Packit 284210
                            return -1;
Packit 284210
                        }
Packit 284210
                        p++;
Packit 284210
                        *(d++) = *(p++);
Packit 284210
                    } else
Packit 284210
                        if (*p == '\'') {
Packit 284210
                            *d = '\0';
Packit 284210
                            p++;
Packit 284210
                            break;
Packit 284210
                        }
Packit 284210
                        else {
Packit 284210
                            *(d++) = *(p++);
Packit 284210
                        }
Packit 284210
            }
Packit 284210
Packit 284210
            d = value;
Packit 284210
            value = apr_pstrdup(mp, d);
Packit 284210
            free(d);
Packit 284210
        } else { /* non-quoted value */
Packit 284210
            value = p;
Packit 284210
            while((*p != '\0')&&(*p != ',')&&(*p != '|')&&(!isspace(*p))) p++;
Packit 284210
            value = apr_pstrmemdup(mp, value, p - value);
Packit 284210
        }
Packit 284210
Packit 284210
        /* add to table */
Packit 284210
        apr_table_addn(vartable, name, value);
Packit 284210
        count++;
Packit 284210
Packit 284210
        /* move to the first character of the next name-value pair */
Packit 284210
        while(isspace(*p)||(*p == ',')||(*p == '|')) p++;
Packit 284210
    }
Packit 284210
Packit 284210
    return count;
Packit 284210
}
Packit 284210
Packit 284210
Packit 284210
/* -- Actionset functions -------------------------------------------------- */
Packit 284210
Packit 284210
/**
Packit 284210
 * Creates an actionset instance and (as an option) populates it by
Packit 284210
 * parsing the given string which contains a list of actions.
Packit 284210
 */
Packit 284210
msre_actionset *msre_actionset_create(msre_engine *engine, apr_pool_t *mp, const char *text,
Packit 284210
        char **error_msg)
Packit 284210
{
Packit 284210
    msre_actionset *actionset = NULL;
Packit 284210
Packit 284210
    if (error_msg == NULL) {
Packit 284210
        return NULL;
Packit 284210
    }
Packit 284210
Packit 284210
    *error_msg = NULL;
Packit 284210
Packit 284210
    actionset = (msre_actionset *)apr_pcalloc(mp,
Packit 284210
            sizeof(msre_actionset));
Packit 284210
Packit 284210
    if (actionset == NULL) {
Packit 284210
        *error_msg = apr_psprintf(mp, "Internal error: " \
Packit 284210
                "msre_actionset_create, not able to allocate msre_actionset");
Packit 284210
        return NULL;
Packit 284210
    }
Packit 284210
Packit 284210
    actionset->actions = apr_table_make(mp, 25);
Packit 284210
    if (actionset->actions == NULL) {
Packit 284210
        *error_msg = apr_psprintf(mp, "Internal error: " \
Packit 284210
                "msre_actionset_create, not able to create actions table");
Packit 284210
        return NULL;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Metadata */
Packit 284210
    actionset->id = NOT_SET_P;
Packit 284210
    actionset->rev = NOT_SET_P;
Packit 284210
    actionset->msg = NOT_SET_P;
Packit 284210
    actionset->version = NOT_SET_P;
Packit 284210
    actionset->logdata = NOT_SET_P;
Packit 284210
    actionset->phase = NOT_SET;
Packit 284210
    actionset->severity = -1;
Packit 284210
    actionset->accuracy = -1;
Packit 284210
    actionset->maturity = -1;
Packit 284210
    actionset->rule = NOT_SET_P;
Packit 284210
    actionset->arg_max = -1;
Packit 284210
    actionset->arg_min = -1;
Packit 284210
Packit 284210
    /* Flow */
Packit 284210
    actionset->is_chained = NOT_SET;
Packit 284210
    actionset->skip_count = NOT_SET;
Packit 284210
    actionset->skip_after = NOT_SET_P;
Packit 284210
Packit 284210
    /* Disruptive */
Packit 284210
    actionset->parent_intercept_action_rec = NOT_SET_P;
Packit 284210
    actionset->intercept_action_rec = NOT_SET_P;
Packit 284210
    actionset->parent_intercept_action = NOT_SET;
Packit 284210
    actionset->intercept_action = NOT_SET;
Packit 284210
    actionset->intercept_uri = NOT_SET_P;
Packit 284210
    actionset->intercept_status = NOT_SET;
Packit 284210
    actionset->intercept_pause = NOT_SET_P;
Packit 284210
Packit 284210
    /* Other */
Packit 284210
    actionset->auditlog = NOT_SET;
Packit 284210
    actionset->log = NOT_SET;
Packit 284210
Packit 284210
    /* Parse the list of actions, if it's present */
Packit 284210
    if (text != NULL) {
Packit 284210
        int ret = msre_parse_actions(engine, mp, actionset, text, error_msg);
Packit 284210
        if (ret < 0) {
Packit 284210
            if (*error_msg == NULL) 
Packit 284210
                *error_msg = apr_psprintf(mp, "Internal error: " \
Packit 284210
                        "msre_actionset_create, msre_parse_actions failed " \
Packit 284210
                        "without further information. Return code: %d", ret);
Packit 284210
            return NULL;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    return actionset;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Create a (shallow) copy of the supplied actionset.
Packit 284210
 */
Packit 284210
static msre_actionset *msre_actionset_copy(apr_pool_t *mp, msre_actionset *orig) {
Packit 284210
    msre_actionset *copy = NULL;
Packit 284210
Packit 284210
    if (orig == NULL) return NULL;
Packit 284210
    copy = (msre_actionset *)apr_pmemdup(mp, orig, sizeof(msre_actionset));
Packit 284210
    if (copy == NULL) return NULL;
Packit 284210
    copy->actions = apr_table_copy(mp, orig->actions);
Packit 284210
Packit 284210
    return copy;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Merges two actionsets into one.
Packit 284210
 */
Packit 284210
msre_actionset *msre_actionset_merge(msre_engine *engine, apr_pool_t *mp, msre_actionset *parent,
Packit 284210
        msre_actionset *child, int inherit_by_default)
Packit 284210
{
Packit 284210
    msre_actionset *merged = NULL;
Packit 284210
    const apr_array_header_t *tarr;
Packit 284210
    const apr_table_entry_t *telts;
Packit 284210
    int i;
Packit 284210
Packit 284210
    if (inherit_by_default == 0) {
Packit 284210
        /* There is nothing to merge in this case. */
Packit 284210
	    return msre_actionset_copy(mp, child);
Packit 284210
    }
Packit 284210
Packit 284210
    /* Start with a copy of the parent configuration. */
Packit 284210
    merged = msre_actionset_copy(mp, parent);
Packit 284210
    if (merged == NULL) return NULL;
Packit 284210
Packit 284210
    if (child == NULL) {
Packit 284210
        /* The child actionset does not exist, hence
Packit 284210
         * go with the parent one.
Packit 284210
         */
Packit 284210
        return merged;
Packit 284210
    }
Packit 284210
Packit 284210
    /* First merge the hard-coded stuff. */
Packit 284210
Packit 284210
    /* Metadata */
Packit 284210
    if (child->id != NOT_SET_P) merged->id = child->id;
Packit 284210
    if (child->rev != NOT_SET_P) merged->rev = child->rev;
Packit 284210
    if (child->msg != NOT_SET_P) merged->msg = child->msg;
Packit 284210
    if (child->version != NOT_SET_P) merged->version = child->version;
Packit 284210
    if (child->logdata != NOT_SET_P) merged->logdata = child->logdata;
Packit 284210
    if (child->severity != NOT_SET) merged->severity = child->severity;
Packit 284210
    if (child->accuracy != NOT_SET) merged->accuracy = child->accuracy;
Packit 284210
    if (child->maturity != NOT_SET) merged->maturity = child->maturity;
Packit 284210
    if (child->phase != NOT_SET) merged->phase = child->phase;
Packit 284210
    if (child->rule != NOT_SET_P) merged->rule = child->rule;
Packit 284210
    if (child->arg_min != NOT_SET) merged->arg_min = child->arg_min;
Packit 284210
    if (child->arg_max != NOT_SET) merged->arg_max = child->arg_max;
Packit 284210
Packit 284210
    /* Flow */
Packit 284210
    merged->is_chained = child->is_chained;
Packit 284210
    if (child->skip_count != NOT_SET) merged->skip_count = child->skip_count;
Packit 284210
    if (child->skip_after != NOT_SET_P) merged->skip_after = child->skip_after;
Packit 284210
Packit 284210
    /* Disruptive */
Packit 284210
    if (child->intercept_action != NOT_SET) {
Packit 284210
        merged->intercept_action_rec = child->intercept_action_rec;
Packit 284210
        merged->intercept_action = child->intercept_action;
Packit 284210
        merged->intercept_uri = child->intercept_uri;
Packit 284210
    }
Packit 284210
Packit 284210
    if (child->intercept_status != NOT_SET) merged->intercept_status = child->intercept_status;
Packit 284210
    if (child->intercept_pause != NOT_SET_P) merged->intercept_pause = child->intercept_pause;
Packit 284210
Packit 284210
    /* Other */
Packit 284210
    if (child->auditlog != NOT_SET) merged->auditlog = child->auditlog;
Packit 284210
    if (child->log != NOT_SET) merged->log = child->log;
Packit 284210
Packit 284210
Packit 284210
    /* Now merge the actions. */
Packit 284210
Packit 284210
    tarr = apr_table_elts(child->actions);
Packit 284210
    telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
    for (i = 0; i < tarr->nelts; i++) {
Packit 284210
        msre_actionset_action_add(merged, (msre_action *)telts[i].val);
Packit 284210
    }
Packit 284210
Packit 284210
    return merged;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Creates an actionset that contains a default list of actions.
Packit 284210
 */
Packit 284210
msre_actionset *msre_actionset_create_default(msre_engine *engine) {
Packit 284210
    char  *my_error_msg = NULL;
Packit 284210
    return msre_actionset_create(engine,
Packit 284210
            engine->mp,
Packit 284210
            "phase:2,log,auditlog,pass",
Packit 284210
            &my_error_msg);
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Sets the default values for the hard-coded actionset configuration.
Packit 284210
 */
Packit 284210
void msre_actionset_set_defaults(msre_actionset *actionset) {
Packit 284210
Packit 284210
    if (actionset == NULL) {
Packit 284210
        return;
Packit 284210
    }
Packit 284210
    /* Metadata */
Packit 284210
    if (actionset->id == NOT_SET_P) actionset->id = NULL;
Packit 284210
    if (actionset->rev == NOT_SET_P) actionset->rev = NULL;
Packit 284210
    if (actionset->msg == NOT_SET_P) actionset->msg = NULL;
Packit 284210
    if (actionset->version == NOT_SET_P) actionset->version = NULL;
Packit 284210
    if (actionset->logdata == NOT_SET_P) actionset->logdata = NULL;
Packit 284210
    if (actionset->phase == NOT_SET) actionset->phase = 2;
Packit 284210
    if (actionset->severity == -1) {} /* leave at -1 */
Packit 284210
    if (actionset->accuracy == -1) {} /* leave at -1 */
Packit 284210
    if (actionset->maturity == -1) {} /* leave at -1 */
Packit 284210
    if (actionset->rule == NOT_SET_P) actionset->rule = NULL;
Packit 284210
    if (actionset->arg_max == NOT_SET) actionset->arg_max = -1;
Packit 284210
    if (actionset->arg_min == NOT_SET) actionset->arg_min = -1;
Packit 284210
Packit 284210
    /* Flow */
Packit 284210
    if (actionset->is_chained == NOT_SET) actionset->is_chained = 0;
Packit 284210
    if (actionset->skip_count == NOT_SET) actionset->skip_count = 0;
Packit 284210
    if (actionset->skip_after == NOT_SET_P) actionset->skip_after = NULL;
Packit 284210
Packit 284210
    /* Disruptive */
Packit 284210
    if (actionset->parent_intercept_action_rec == NOT_SET_P) actionset->parent_intercept_action_rec = NULL;
Packit 284210
    if (actionset->intercept_action_rec == NOT_SET_P) actionset->intercept_action_rec = NULL;
Packit 284210
    if (actionset->parent_intercept_action == NOT_SET) actionset->parent_intercept_action = ACTION_NONE;
Packit 284210
    if (actionset->intercept_action == NOT_SET) actionset->intercept_action = ACTION_NONE;
Packit 284210
    if (actionset->intercept_uri == NOT_SET_P) actionset->intercept_uri = NULL;
Packit 284210
    if (actionset->intercept_status == NOT_SET) actionset->intercept_status = 403;
Packit 284210
    if (actionset->intercept_pause == NOT_SET_P) actionset->intercept_pause = NULL;
Packit 284210
Packit 284210
    /* Other */
Packit 284210
    if (actionset->auditlog == NOT_SET) actionset->auditlog = 1;
Packit 284210
    if (actionset->log == NOT_SET) actionset->log = 1;
Packit 284210
}
Packit 284210
Packit 284210
/* -- Engine functions ----------------------------------------------------- */
Packit 284210
Packit 284210
/**
Packit 284210
 * Creates a new engine instance.
Packit 284210
 */
Packit 284210
msre_engine *msre_engine_create(apr_pool_t *parent_pool) {
Packit 284210
    msre_engine *engine;
Packit 284210
    apr_pool_t *mp;
Packit 284210
Packit 284210
    /* Create new memory pool */
Packit 284210
    if (apr_pool_create(&mp, parent_pool) != APR_SUCCESS) return NULL;
Packit 284210
Packit 284210
    /* Init fields */
Packit 284210
    engine = apr_pcalloc(mp, sizeof(msre_engine));
Packit 284210
    if (engine == NULL) return NULL;
Packit 284210
    engine->mp = mp;
Packit 284210
    engine->tfns = apr_table_make(mp, 50);
Packit 284210
    if (engine->tfns == NULL) return NULL;
Packit 284210
    engine->operators = apr_table_make(mp, 25);
Packit 284210
    if (engine->operators == NULL) return NULL;
Packit 284210
    engine->variables = apr_table_make(mp, 100);
Packit 284210
    if (engine->variables == NULL) return NULL;
Packit 284210
    engine->actions = apr_table_make(mp, 50);
Packit 284210
    if (engine->actions == NULL) return NULL;
Packit 284210
    engine->reqbody_processors = apr_table_make(mp, 10);
Packit 284210
    if (engine->reqbody_processors == NULL) return NULL;
Packit 284210
Packit 284210
    return engine;
Packit 284210
}
Packit 284210
Packit 284210
Packit 284210
/* -- Recipe functions ----------------------------------------------------- */
Packit 284210
Packit 284210
#define NEXT_CHAIN  1
Packit 284210
#define NEXT_RULE   2
Packit 284210
#define SKIP_RULES  3
Packit 284210
Packit 284210
Packit 284210
Packit 284210
/**
Packit 284210
 * Default implementation of the ruleset phase processing; it processes
Packit 284210
 * the rules in the ruleset attached to the currently active
Packit 284210
 * transaction phase.
Packit 284210
 */
Packit 284210
#if defined(PERFORMANCE_MEASUREMENT)
Packit 284210
Packit 284210
#define PERFORMANCE_MEASUREMENT_LOOP 5000
Packit 284210
Packit 284210
static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_rec *msr);
Packit 284210
Packit 284210
apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) {
Packit 284210
    apr_array_header_t *arr = NULL;
Packit 284210
    msre_rule **rules = NULL;
Packit 284210
    apr_status_t rc;
Packit 284210
    int i;
Packit 284210
Packit 284210
    switch (msr->phase) {
Packit 284210
        case PHASE_REQUEST_HEADERS :
Packit 284210
            arr = ruleset->phase_request_headers;
Packit 284210
            break;
Packit 284210
        case PHASE_REQUEST_BODY :
Packit 284210
            arr = ruleset->phase_request_body;
Packit 284210
            break;
Packit 284210
        case PHASE_RESPONSE_HEADERS :
Packit 284210
            arr = ruleset->phase_response_headers;
Packit 284210
            break;
Packit 284210
        case PHASE_RESPONSE_BODY :
Packit 284210
            arr = ruleset->phase_response_body;
Packit 284210
            break;
Packit 284210
        case PHASE_LOGGING :
Packit 284210
            arr = ruleset->phase_logging;
Packit 284210
            break;
Packit 284210
        default :
Packit 284210
            msr_log(msr, 1, "Internal Error: Invalid phase %d", msr->phase);
Packit 284210
            return -1;
Packit 284210
    }
Packit 284210
Packit 284210
    rules = (msre_rule **)arr->elts;
Packit 284210
    for (i = 0; i < arr->nelts; i++) {
Packit 284210
        msre_rule *rule = rules[i];
Packit 284210
        rule->execution_time = 0;
Packit 284210
    }
Packit 284210
Packit 284210
    for (i = 0; i < PERFORMANCE_MEASUREMENT_LOOP; i++) {
Packit 284210
        rc = msre_ruleset_process_phase_(ruleset, msr);
Packit 284210
    }
Packit 284210
Packit 284210
    msr_log(msr, 1, "Phase %d", msr->phase);
Packit 284210
Packit 284210
    rules = (msre_rule **)arr->elts;
Packit 284210
    for (i = 0; i < arr->nelts; i++) {
Packit 284210
        msre_rule *rule = rules[i];
Packit 284210
Packit 284210
        /* Ignore markers, which are never processed. */
Packit 284210
        if (rule->placeholder == RULE_PH_MARKER) continue;
Packit 284210
Packit 284210
        msr_log(msr, 1, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"]: %u usec", rule,
Packit 284210
                ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) ? rule->actionset->id : "-",
Packit 284210
                rule->filename != NULL ? rule->filename : "-",
Packit 284210
                rule->line_num,
Packit 284210
                (rule->execution_time / PERFORMANCE_MEASUREMENT_LOOP));
Packit 284210
    }
Packit 284210
Packit 284210
    return rc;
Packit 284210
}
Packit 284210
Packit 284210
static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_rec *msr) {
Packit 284210
#else
Packit 284210
    apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) {
Packit 284210
#endif
Packit 284210
        apr_array_header_t *arr = NULL;
Packit 284210
        msre_rule **rules;
Packit 284210
        apr_status_t rc;
Packit 284210
        const char *skip_after = NULL;
Packit 284210
        msre_rule *last_rule = NULL;
Packit 284210
        msre_rule *rule_starter = NULL;
Packit 284210
        int i, mode, skip, skipped, saw_starter;
Packit 284210
Packit 284210
        /* First determine which set of rules we need to use. */
Packit 284210
        switch (msr->phase) {
Packit 284210
            case PHASE_REQUEST_HEADERS :
Packit 284210
                arr = ruleset->phase_request_headers;
Packit 284210
                break;
Packit 284210
            case PHASE_REQUEST_BODY :
Packit 284210
                arr = ruleset->phase_request_body;
Packit 284210
                break;
Packit 284210
            case PHASE_RESPONSE_HEADERS :
Packit 284210
                arr = ruleset->phase_response_headers;
Packit 284210
                break;
Packit 284210
            case PHASE_RESPONSE_BODY :
Packit 284210
                arr = ruleset->phase_response_body;
Packit 284210
                break;
Packit 284210
            case PHASE_LOGGING :
Packit 284210
                arr = ruleset->phase_logging;
Packit 284210
                break;
Packit 284210
            default :
Packit 284210
                msr_log(msr, 1, "Internal Error: Invalid phase %d", msr->phase);
Packit 284210
                return -1;
Packit 284210
        }
Packit 284210
Packit 284210
        if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
            msr_log(msr, 9, "This phase consists of %d rule(s).", arr->nelts);
Packit 284210
        }
Packit 284210
Packit 284210
        apr_table_clear(msr->matched_vars);
Packit 284210
Packit 284210
        /* Loop through the rules in the selected set. */
Packit 284210
        skip = 0;
Packit 284210
        skipped = 0;
Packit 284210
        saw_starter = 0;
Packit 284210
        mode = NEXT_RULE;
Packit 284210
        rules = (msre_rule **)arr->elts;
Packit 284210
        for (i = 0; i < arr->nelts; i++) {
Packit 284210
            msre_rule *rule = rules[i];
Packit 284210
#if defined(PERFORMANCE_MEASUREMENT)
Packit 284210
            apr_time_t time1 = 0;
Packit 284210
#endif
Packit 284210
Packit 284210
            /* Reset the rule interception flag */
Packit 284210
            msr->rule_was_intercepted = 0;
Packit 284210
Packit 284210
            /* SKIP_RULES is used to skip all rules until we hit a placeholder
Packit 284210
             * with the specified rule ID and then resume execution after that.
Packit 284210
             */
Packit 284210
            if (mode == SKIP_RULES) {
Packit 284210
                /* Go to the next rule if we have not yet hit the skip_after ID */
Packit 284210
Packit 284210
                if ((rule->placeholder == RULE_PH_NONE) || (rule->actionset->id == NULL) || (strcmp(skip_after, rule->actionset->id) != 0)) {
Packit 284210
Packit 284210
                    if(i-1 >=0)
Packit 284210
                        last_rule = rules[i-1];
Packit 284210
                    else
Packit 284210
                        last_rule = rules[0];
Packit 284210
Packit 284210
                    if((last_rule != NULL) && (last_rule->actionset != NULL) && last_rule->actionset->is_chained && (saw_starter == 1)) {
Packit 284210
                        mode = NEXT_RULE;
Packit 284210
                        skipped = 1;
Packit 284210
                        --i;
Packit 284210
                    } else {
Packit 284210
                        mode = SKIP_RULES;
Packit 284210
                        skipped = 0;
Packit 284210
                        saw_starter = 0;
Packit 284210
Packit 284210
                        if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                            msr_log(msr, 9, "Current rule is id=\"%s\" [chained %d] is trying to find the SecMarker=\"%s\" [stater %d]",rule->actionset->id,last_rule->actionset->is_chained,skip_after,saw_starter);
Packit 284210
                        }
Packit 284210
Packit 284210
                    }
Packit 284210
Packit 284210
                    continue;
Packit 284210
                }
Packit 284210
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "Found rule %pp id=\"%s\".", rule, skip_after);
Packit 284210
                }
Packit 284210
Packit 284210
                /* Go to the rule *after* this one to continue execution. */
Packit 284210
                if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
                    msr_log(msr, 4, "Continuing execution after rule id=\"%s\".", skip_after);
Packit 284210
                }
Packit 284210
Packit 284210
                saw_starter = 0;
Packit 284210
                skipped = 0;
Packit 284210
                skip_after = NULL;
Packit 284210
                mode = NEXT_RULE;
Packit 284210
                apr_table_clear(msr->matched_vars);
Packit 284210
                continue;
Packit 284210
            }
Packit 284210
Packit 284210
            /* Skip any rule marked as a placeholder */
Packit 284210
            if (rule->placeholder != RULE_PH_NONE) {
Packit 284210
                continue;
Packit 284210
            }
Packit 284210
Packit 284210
            /* NEXT_CHAIN is used when one of the rules in a chain
Packit 284210
             * fails to match and then we need to skip the remaining
Packit 284210
             * rules in that chain in order to get to the next
Packit 284210
             * rule that can execute.
Packit 284210
             */
Packit 284210
            if (mode == NEXT_CHAIN) {
Packit 284210
                if (rule->actionset->is_chained == 0) {
Packit 284210
                    mode = NEXT_RULE;
Packit 284210
                }
Packit 284210
Packit 284210
                /* Go to the next rule. */
Packit 284210
                apr_table_clear(msr->matched_vars);
Packit 284210
                continue;
Packit 284210
            }
Packit 284210
Packit 284210
            /* If we are here that means the mode is NEXT_RULE, which
Packit 284210
             * then means we have done processing any chains. However,
Packit 284210
             * if the "skip" parameter is set we need to skip over.
Packit 284210
             */
Packit 284210
            if ((mode == NEXT_RULE)&&(skip > 0)) {
Packit 284210
                /* Decrement the skip counter by one. */
Packit 284210
                skip--;
Packit 284210
Packit 284210
                /* If the current rule is part of a chain then
Packit 284210
                 * we need to skip over the entire chain. Thus
Packit 284210
                 * we change the mode to NEXT_CHAIN. The skip
Packit 284210
                 * counter will not decrement as we are moving
Packit 284210
                 * over the rules belonging to the chain.
Packit 284210
                 */
Packit 284210
                if (rule->actionset->is_chained) {
Packit 284210
                    mode = NEXT_CHAIN;
Packit 284210
                }
Packit 284210
Packit 284210
                /* Go to the next rule. */
Packit 284210
                apr_table_clear(msr->matched_vars);
Packit 284210
                continue;
Packit 284210
            }
Packit 284210
Packit 284210
            /* Check if this rule was removed at runtime */
Packit 284210
        if (((rule->actionset->id !=NULL) && !apr_is_empty_array(msr->removed_rules)) ||
Packit 284210
                 (apr_is_empty_array(msr->removed_rules_tag)==0) || (apr_is_empty_array(msr->removed_rules_msg)==0)) {
Packit 284210
            int j, act, rc;
Packit 284210
            int do_process = 1;
Packit 284210
            const char *range = NULL;
Packit 284210
            rule_exception *re = NULL;
Packit 284210
            char *my_error_msg;
Packit 284210
            const apr_array_header_t *tag_tarr = NULL;
Packit 284210
            const apr_table_entry_t *tag_telts = NULL;
Packit 284210
Packit 284210
            for(j = 0; j < msr->removed_rules_msg->nelts; j++) {
Packit 284210
                re = ((rule_exception **)msr->removed_rules_msg->elts)[j];
Packit 284210
Packit 284210
                if(rule->actionset->msg !=NULL)  {
Packit 284210
Packit 284210
                    if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                        msr_log(msr, 9, "Checking removal of rule msg=\"%s\" against: %s", rule->actionset->msg, re->param);
Packit 284210
                    }
Packit 284210
Packit 284210
                    rc = msc_regexec(re->param_data,
Packit 284210
                            rule->actionset->msg, strlen(rule->actionset->msg),
Packit 284210
                            &my_error_msg);
Packit 284210
                    if (rc >= 0)    {
Packit 284210
                        do_process = 0;
Packit 284210
                        break;
Packit 284210
                    }
Packit 284210
                }
Packit 284210
            }
Packit 284210
Packit 284210
            for(j = 0; j < msr->removed_rules->nelts; j++) {
Packit 284210
                range = ((const char**)msr->removed_rules->elts)[j];
Packit 284210
Packit 284210
                if(rule->actionset->id !=NULL)  {
Packit 284210
Packit 284210
                    if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                        msr_log(msr, 9, "Checking removal of rule id=\"%s\" against: %s", rule->actionset->id, range);
Packit 284210
                    }
Packit 284210
Packit 284210
                    if (rule_id_in_range(atoi(rule->actionset->id), range)) {
Packit 284210
                        do_process = 0;
Packit 284210
                        break;
Packit 284210
                    }
Packit 284210
                }
Packit 284210
            }
Packit 284210
Packit 284210
            tag_tarr = apr_table_elts(rule->actionset->actions);
Packit 284210
            tag_telts = (const apr_table_entry_t*)tag_tarr->elts;
Packit 284210
Packit 284210
            for (act = 0; act < tag_tarr->nelts; act++) {
Packit 284210
                msre_action *action = (msre_action *)tag_telts[act].val;
Packit 284210
Packit 284210
                if((action != NULL) && (action->metadata != NULL ) && strcmp("tag", action->metadata->name) == 0)  {
Packit 284210
Packit 284210
                    for(j = 0; j < msr->removed_rules_tag->nelts; j++) {
Packit 284210
                        re = ((rule_exception **)msr->removed_rules_tag->elts)[j];
Packit 284210
Packit 284210
Packit 284210
                        if(action->param != NULL)   {
Packit 284210
                            /* Expand variables in the tag argument. */
Packit 284210
                            msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
Packit 284210
Packit 284210
                            var->value = (char *)action->param;
Packit 284210
                            var->value_len = strlen(action->param);
Packit 284210
                            expand_macros(msr, var, NULL, msr->mp);
Packit 284210
Packit 284210
                            if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                                msr_log(msr, 9, "Checking removal of rule tag=\"%s\" against: %s", var->value, re->param);
Packit 284210
                            }
Packit 284210
Packit 284210
                            rc = msc_regexec(re->param_data,
Packit 284210
                                    var->value, strlen(var->value),
Packit 284210
                                    &my_error_msg);
Packit 284210
                            if (rc >= 0)    {
Packit 284210
                                do_process = 0;
Packit 284210
                                break;
Packit 284210
                            }
Packit 284210
Packit 284210
                        }
Packit 284210
                    }
Packit 284210
                }
Packit 284210
            }
Packit 284210
Packit 284210
            /* Go to the next rule if this one has been removed. */
Packit 284210
            if (do_process == 0) {
Packit 284210
                if (msr->txcfg->debuglog_level >= 5) {
Packit 284210
                    msr_log(msr, 5, "Not processing %srule id=\"%s\": "
Packit 284210
                            "removed by ctl action",
Packit 284210
                            rule->actionset->is_chained ? "chained " : "",
Packit 284210
                            rule->actionset->id);
Packit 284210
                }
Packit 284210
Packit 284210
                /* Skip the whole chain, if this is a chained rule */
Packit 284210
                if (rule->actionset->is_chained) {
Packit 284210
                    mode = NEXT_CHAIN;
Packit 284210
                }
Packit 284210
Packit 284210
                skipped = 0;
Packit 284210
                saw_starter = 0;
Packit 284210
                apr_table_clear(msr->matched_vars);
Packit 284210
                continue;
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        if(msr->txcfg->is_enabled == MODSEC_DISABLED)   {
Packit 284210
            saw_starter = 0;
Packit 284210
            skipped = 0;
Packit 284210
            skip_after = NULL;
Packit 284210
            mode = NEXT_RULE;
Packit 284210
            apr_table_clear(msr->matched_vars);
Packit 284210
            continue;
Packit 284210
        }
Packit 284210
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            apr_pool_t *p = msr->mp;
Packit 284210
            const char *fn = NULL;
Packit 284210
            const char *id = NULL;
Packit 284210
            const char *rev = NULL;
Packit 284210
Packit 284210
            if (rule->filename != NULL) {
Packit 284210
                fn = apr_psprintf(p, " [file \"%s\"] [line \"%d\"]", rule->filename, rule->line_num);
Packit 284210
            }
Packit 284210
Packit 284210
            if (rule->actionset != NULL && rule->actionset->id != NULL) {
Packit 284210
                id = apr_psprintf(p, " [id \"%s\"]", rule->actionset->id);
Packit 284210
            }
Packit 284210
Packit 284210
            if (rule->actionset != NULL && rule->actionset->rev != NULL) {
Packit 284210
                rev = apr_psprintf(p, " [rev \"%s\"]", rule->actionset->rev);
Packit 284210
            }
Packit 284210
Packit 284210
            msr_log(msr, 4, "Recipe: Invoking rule %pp;%s%s%s.",
Packit 284210
                    rule, (fn ? fn : ""), (id ? id : ""), (rev ? rev : ""));
Packit 284210
            msr_log(msr, 5, "Rule %pp: %s", rule, rule->unparsed);
Packit 284210
        }
Packit 284210
Packit 284210
#if defined(PERFORMANCE_MEASUREMENT)
Packit 284210
        time1 = apr_time_now();
Packit 284210
#endif
Packit 284210
Packit 284210
        rc = msre_rule_process(rule, msr);
Packit 284210
Packit 284210
#if defined(PERFORMANCE_MEASUREMENT)
Packit 284210
        rule->execution_time += (apr_time_now() - time1);
Packit 284210
#endif
Packit 284210
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            msr_log(msr, 4, "Rule returned %d.", rc);
Packit 284210
        }
Packit 284210
Packit 284210
        if (rc == RULE_NO_MATCH) {
Packit 284210
            if (rule->actionset->is_chained) {
Packit 284210
                /* If the current rule is part of a chain then
Packit 284210
                 * we need to skip over all the rules in the chain.
Packit 284210
                 */
Packit 284210
                mode = NEXT_CHAIN;
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "No match, chained -> mode NEXT_CHAIN.");
Packit 284210
                }
Packit 284210
            } else {
Packit 284210
                /* This rule is not part of a chain so we simply
Packit 284210
                 * move to the next rule.
Packit 284210
                 */
Packit 284210
                mode = NEXT_RULE;
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "No match, not chained -> mode NEXT_RULE.");
Packit 284210
                }
Packit 284210
            }
Packit 284210
Packit 284210
            apr_table_clear(msr->matched_vars);
Packit 284210
            skipped = 0;
Packit 284210
            saw_starter = 0;
Packit 284210
        }
Packit 284210
        else if (rc == RULE_MATCH) {
Packit 284210
            if (msr->rule_was_intercepted) {
Packit 284210
                /* If the transaction was intercepted by this rule we will
Packit 284210
                 * go back. Do note that we are relying on the
Packit 284210
                 * rule to know if it is a part of a chain and
Packit 284210
                 * not intercept if it is.
Packit 284210
                 */
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "Match, intercepted -> returning.");
Packit 284210
                }
Packit 284210
Packit 284210
                if(i-1 >= 0)
Packit 284210
                    last_rule = rules[i-1];
Packit 284210
                else
Packit 284210
                    last_rule = rules[0];
Packit 284210
Packit 284210
                if((last_rule != NULL) && (last_rule->actionset != NULL) && last_rule->actionset->is_chained) {
Packit 284210
Packit 284210
                    int st = 0;
Packit 284210
Packit 284210
                    for(st=i;st>=0;st--)  {
Packit 284210
Packit 284210
                        rule_starter = rules[st];
Packit 284210
Packit 284210
                        if(rule_starter != NULL && rule_starter->chain_starter != NULL)    {
Packit 284210
                            if((msr != NULL) && (msr->intercept_actionset != NULL) && (rule_starter->actionset != NULL))
Packit 284210
                                msr->intercept_actionset->intercept_uri = rule_starter->actionset->intercept_uri;
Packit 284210
                            break;
Packit 284210
                        }
Packit 284210
                    }
Packit 284210
Packit 284210
                }
Packit 284210
Packit 284210
                apr_table_clear(msr->matched_vars);
Packit 284210
                return 1;
Packit 284210
            }
Packit 284210
Packit 284210
            if (rule->actionset->skip_after != NULL) {
Packit 284210
                skip_after = rule->actionset->skip_after;
Packit 284210
                mode = SKIP_RULES;
Packit 284210
                saw_starter = 1;
Packit 284210
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "Skipping after rule %pp id=\"%s\" -> mode SKIP_RULES.", rule, skip_after);
Packit 284210
                }
Packit 284210
Packit 284210
                continue;
Packit 284210
            }
Packit 284210
Packit 284210
            if(skipped == 1)    {
Packit 284210
                mode = SKIP_RULES;
Packit 284210
                continue;
Packit 284210
            }
Packit 284210
Packit 284210
            /* We had a match but the transaction was not
Packit 284210
             * intercepted. In that case we proceed with the
Packit 284210
             * next rule...
Packit 284210
             */
Packit 284210
            mode = NEXT_RULE;
Packit 284210
            if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                msr_log(msr, 9, "Match -> mode NEXT_RULE.");
Packit 284210
            }
Packit 284210
Packit 284210
            /* ...unless we need to skip, in which case we
Packit 284210
             * determine how many rules/chains we need to
Packit 284210
             * skip and configure the counter accordingly.
Packit 284210
             */
Packit 284210
            if (rule->actionset->is_chained == 0) {
Packit 284210
                apr_table_clear(msr->matched_vars);
Packit 284210
                if (rule->chain_starter != NULL) {
Packit 284210
                    if (rule->chain_starter->actionset->skip_count > 0) {
Packit 284210
                        skip = rule->chain_starter->actionset->skip_count;
Packit 284210
                        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
                            msr_log(msr, 4, "Skipping %d rules/chains (from a chain).", skip);
Packit 284210
                        }
Packit 284210
                    }
Packit 284210
                }
Packit 284210
                else if (rule->actionset->skip_count > 0) {
Packit 284210
                    skip = rule->actionset->skip_count;
Packit 284210
                    if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
                        msr_log(msr, 4, "Skipping %d rules/chains.", skip);
Packit 284210
                    }
Packit 284210
                }
Packit 284210
            }
Packit 284210
        }
Packit 284210
        else if (rc < 0) {
Packit 284210
            const char *id = "";
Packit 284210
            const char *msg = "";
Packit 284210
            if (rule->actionset) {
Packit 284210
                if (rule->actionset->id) {
Packit 284210
                    id = rule->actionset->id;
Packit 284210
                }
Packit 284210
                if (rule->actionset->msg) {
Packit 284210
                    msg = rule->actionset->msg;
Packit 284210
                }
Packit 284210
            }
Packit 284210
            msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", id, msg);
Packit 284210
Packit 284210
            if (msr->txcfg->reqintercept_oe == 1)   {
Packit 284210
                apr_table_clear(msr->matched_vars);
Packit 284210
                return -1;
Packit 284210
            } else  {
Packit 284210
                if (rule->actionset->is_chained) {
Packit 284210
                    /* If the current rule is part of a chain then
Packit 284210
                     * we need to skip over all the rules in the chain.
Packit 284210
                     */
Packit 284210
                    mode = NEXT_CHAIN;
Packit 284210
                    if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                        msr_log(msr, 9, "Ruled failed, chained -> mode NEXT_CHAIN.");
Packit 284210
                    }
Packit 284210
                } else {
Packit 284210
                    /* This rule is not part of a chain so we simply
Packit 284210
                     * move to the next rule.
Packit 284210
                     */
Packit 284210
                    mode = NEXT_RULE;
Packit 284210
                    if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                        msr_log(msr, 9, "Rule failed, not chained -> mode NEXT_RULE.");
Packit 284210
                    }
Packit 284210
                }
Packit 284210
Packit 284210
                apr_table_clear(msr->matched_vars);
Packit 284210
                skipped = 0;
Packit 284210
                saw_starter = 0;
Packit 284210
            }
Packit 284210
        }
Packit 284210
        else {
Packit 284210
            const char *id = "";
Packit 284210
            const char *msg = "";
Packit 284210
            if (rule->actionset) {
Packit 284210
                if (rule->actionset->id) {
Packit 284210
                    id = rule->actionset->id;
Packit 284210
                }
Packit 284210
                if (rule->actionset->msg) {
Packit 284210
                    msg = rule->actionset->msg;
Packit 284210
                }
Packit 284210
            }
Packit 284210
            msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, id, msg);
Packit 284210
            apr_table_clear(msr->matched_vars);
Packit 284210
            return -1;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* ENH warn if chained rules are missing. */
Packit 284210
    apr_table_clear(msr->matched_vars);
Packit 284210
    return 0;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Creates a ruleset that will be handled by the default
Packit 284210
 * implementation.
Packit 284210
 */
Packit 284210
msre_ruleset *msre_ruleset_create(msre_engine *engine, apr_pool_t *mp) {
Packit 284210
    msre_ruleset *ruleset;
Packit 284210
Packit 284210
    ruleset = apr_pcalloc(mp, sizeof(msre_ruleset));
Packit 284210
    if (ruleset == NULL) return NULL;
Packit 284210
    ruleset->mp = mp;
Packit 284210
    ruleset->engine = engine;
Packit 284210
Packit 284210
    ruleset->phase_request_headers = apr_array_make(ruleset->mp, 25, sizeof(const msre_rule *));
Packit 284210
    ruleset->phase_request_body = apr_array_make(ruleset->mp, 25, sizeof(const msre_rule *));
Packit 284210
    ruleset->phase_response_headers = apr_array_make(ruleset->mp, 25, sizeof(const msre_rule *));
Packit 284210
    ruleset->phase_response_body = apr_array_make(ruleset->mp, 25, sizeof(const msre_rule *));
Packit 284210
    ruleset->phase_logging = apr_array_make(ruleset->mp, 25, sizeof(const msre_rule *));
Packit 284210
Packit 284210
    return ruleset;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Adds one rule to the given phase of the ruleset.
Packit 284210
 */
Packit 284210
int msre_ruleset_rule_add(msre_ruleset *ruleset, msre_rule *rule, int phase) {
Packit 284210
    apr_array_header_t *arr = NULL;
Packit 284210
Packit 284210
    switch (phase) {
Packit 284210
        case PHASE_REQUEST_HEADERS :
Packit 284210
            arr = ruleset->phase_request_headers;
Packit 284210
            break;
Packit 284210
        case PHASE_REQUEST_BODY :
Packit 284210
            arr = ruleset->phase_request_body;
Packit 284210
            break;
Packit 284210
        case PHASE_RESPONSE_HEADERS :
Packit 284210
            arr = ruleset->phase_response_headers;
Packit 284210
            break;
Packit 284210
        case PHASE_RESPONSE_BODY :
Packit 284210
            arr = ruleset->phase_response_body;
Packit 284210
            break;
Packit 284210
        case PHASE_LOGGING :
Packit 284210
            arr = ruleset->phase_logging;
Packit 284210
            break;
Packit 284210
        default :
Packit 284210
            return -1;
Packit 284210
    }
Packit 284210
Packit 284210
    /* ENH verify the rule's use of targets is consistent with
Packit 284210
     * the phase it selected to run at.
Packit 284210
     */
Packit 284210
Packit 284210
    msre_actionset_set_defaults(rule->actionset);
Packit 284210
    rule->actionset->rule = rule;
Packit 284210
Packit 284210
    *(const msre_rule **)apr_array_push(arr) = rule;
Packit 284210
Packit 284210
    return 1;
Packit 284210
}
Packit 284210
Packit 284210
static msre_rule * msre_ruleset_fetch_phase_rule(const msre_ruleset *ruleset, const char *id,
Packit 284210
        const apr_array_header_t *phase_arr, int offset)
Packit 284210
{
Packit 284210
    msre_rule **rules = (msre_rule **)phase_arr->elts;
Packit 284210
    int i;
Packit 284210
Packit 284210
    for (i = 0; i < phase_arr->nelts; i++) {
Packit 284210
        msre_rule *rule = (msre_rule *)rules[i];
Packit 284210
Packit 284210
        /* Rule with an action, not a sub-rule (chain) and a matching id */
Packit 284210
        if (  (rule->actionset != NULL)
Packit 284210
                && (!rule->actionset->is_chained || !rule->chain_starter)
Packit 284210
                && (rule->actionset->id != NULL)
Packit 284210
                && (strcmp(rule->actionset->id, id) == 0))
Packit 284210
        {
Packit 284210
            /* Return rule that matched unless it is a placeholder */
Packit 284210
            if(offset == 0) {
Packit 284210
                return (rule->placeholder == RULE_PH_NONE) ? rule : NULL;
Packit 284210
            }
Packit 284210
            else    {
Packit 284210
                if (i+offset < phase_arr->nelts)    {
Packit 284210
                    msre_rule *rule_off = (msre_rule *)rules[i+offset];
Packit 284210
                    return (rule_off->placeholder == RULE_PH_NONE) ? rule_off : NULL;
Packit 284210
                }
Packit 284210
            }
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    return NULL;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Fetches rule from the ruleset all rules that match the given exception.
Packit 284210
 */
Packit 284210
msre_rule * msre_ruleset_fetch_rule(msre_ruleset *ruleset, const char *id, int offset) {
Packit 284210
    msre_rule *rule = NULL;
Packit 284210
Packit 284210
    if (ruleset == NULL) return NULL;
Packit 284210
Packit 284210
    rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_request_headers, offset);
Packit 284210
    if (rule != NULL) return rule;
Packit 284210
Packit 284210
    rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_request_body, offset);
Packit 284210
    if (rule != NULL) return rule;
Packit 284210
Packit 284210
    rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_response_headers, offset);
Packit 284210
    if (rule != NULL) return rule;
Packit 284210
Packit 284210
    rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_response_body, offset);
Packit 284210
    if (rule != NULL) return rule;
Packit 284210
Packit 284210
    rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_logging, offset);
Packit 284210
Packit 284210
    return rule;
Packit 284210
}
Packit 284210
Packit 284210
static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re,
Packit 284210
        apr_array_header_t *phase_arr)
Packit 284210
{
Packit 284210
    msre_rule **rules;
Packit 284210
    int i, j, mode, removed_count;
Packit 284210
Packit 284210
    j = 0;
Packit 284210
    mode = 0;
Packit 284210
    removed_count = 0;
Packit 284210
    rules = (msre_rule **)phase_arr->elts;
Packit 284210
    for (i = 0; i < phase_arr->nelts; i++) {
Packit 284210
        msre_rule *rule = (msre_rule *)rules[i];
Packit 284210
Packit 284210
        if (mode == 0) { /* Looking for next rule. */
Packit 284210
            int remove_rule = 0;
Packit 284210
Packit 284210
            /* Only remove non-placeholder rules */
Packit 284210
            if (rule->placeholder == RULE_PH_NONE) {
Packit 284210
                switch(re->type) {
Packit 284210
                    case RULE_EXCEPTION_REMOVE_ID :
Packit 284210
                        if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) {
Packit 284210
                            int ruleid = atoi(rule->actionset->id);
Packit 284210
Packit 284210
                            if (rule_id_in_range(ruleid, re->param)) {
Packit 284210
                                remove_rule = 1;
Packit 284210
                            }
Packit 284210
                        }
Packit 284210
Packit 284210
                        break;
Packit 284210
Packit 284210
                    case RULE_EXCEPTION_REMOVE_MSG :
Packit 284210
                        if ((rule->actionset != NULL)&&(rule->actionset->msg != NULL)) {
Packit 284210
                            char *my_error_msg = NULL;
Packit 284210
Packit 284210
                            int rc = msc_regexec(re->param_data,
Packit 284210
                                    rule->actionset->msg, strlen(rule->actionset->msg),
Packit 284210
                                    &my_error_msg);
Packit 284210
                            if (rc >= 0) {
Packit 284210
                                remove_rule = 1;
Packit 284210
                            }
Packit 284210
                        }
Packit 284210
Packit 284210
                        break;
Packit 284210
                    case RULE_EXCEPTION_REMOVE_TAG :
Packit 284210
                        if ((rule->actionset != NULL)&&(apr_is_empty_table(rule->actionset->actions) == 0)) {
Packit 284210
                            char *my_error_msg = NULL;
Packit 284210
                            const apr_array_header_t *tarr = NULL;
Packit 284210
                            const apr_table_entry_t *telts = NULL;
Packit 284210
                            int act;
Packit 284210
Packit 284210
                            tarr = apr_table_elts(rule->actionset->actions);
Packit 284210
                            telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
Packit 284210
                            for (act = 0; act < tarr->nelts; act++) {
Packit 284210
                                msre_action *action = (msre_action *)telts[act].val;
Packit 284210
                                if((action != NULL) && (action->metadata != NULL) && (strcmp("tag", action->metadata->name) == 0))  {
Packit 284210
Packit 284210
                                    int rc = msc_regexec(re->param_data,
Packit 284210
                                            action->param, strlen(action->param),
Packit 284210
                                            &my_error_msg);
Packit 284210
                                    if (rc >= 0)    {
Packit 284210
                                        remove_rule = 1;
Packit 284210
                                    }
Packit 284210
                                }
Packit 284210
                            }
Packit 284210
                        }
Packit 284210
                        break;
Packit 284210
                }
Packit 284210
            }
Packit 284210
Packit 284210
            if (remove_rule) {
Packit 284210
                /* Do not increment j. */
Packit 284210
                removed_count++;
Packit 284210
                if (rule->actionset->is_chained) mode = 2; /* Remove rules in this chain. */
Packit 284210
            } else {
Packit 284210
                if (rule->actionset->is_chained) mode = 1; /* Keep rules in this chain. */
Packit 284210
                rules[j++] = rules[i];
Packit 284210
            }
Packit 284210
        } else { /* Handling rule that is part of a chain. */
Packit 284210
            if (mode == 2) { /* We want to remove the rule. */
Packit 284210
                /* Do not increment j. */
Packit 284210
                removed_count++;
Packit 284210
            } else {
Packit 284210
                rules[j++] = rules[i];
Packit 284210
            }
Packit 284210
Packit 284210
            if ((rule->actionset == NULL)||(rule->actionset->is_chained == 0)) mode = 0;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* Update the number of rules in the array. */
Packit 284210
    phase_arr->nelts -= removed_count;
Packit 284210
Packit 284210
    return 0;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Removes from the ruleset all rules that match the given exception.
Packit 284210
 */
Packit 284210
int msre_ruleset_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re) {
Packit 284210
    int count = 0;
Packit 284210
Packit 284210
    if (ruleset == NULL) return 0;
Packit 284210
Packit 284210
    count += msre_ruleset_phase_rule_remove_with_exception(ruleset, re, ruleset->phase_request_headers);
Packit 284210
    count += msre_ruleset_phase_rule_remove_with_exception(ruleset, re, ruleset->phase_request_body);
Packit 284210
    count += msre_ruleset_phase_rule_remove_with_exception(ruleset, re, ruleset->phase_response_headers);
Packit 284210
    count += msre_ruleset_phase_rule_remove_with_exception(ruleset, re, ruleset->phase_response_body);
Packit 284210
    count += msre_ruleset_phase_rule_remove_with_exception(ruleset, re, ruleset->phase_logging);
Packit 284210
Packit 284210
    return count;
Packit 284210
}
Packit 284210
Packit 284210
Packit 284210
/* -- Rule functions ------------------------------------------------------- */
Packit 284210
Packit 284210
/**
Packit 284210
 * Returns the name of the supplied severity level.
Packit 284210
 */
Packit 284210
static const char *msre_format_severity(int severity) {
Packit 284210
    if ((severity >= 0)&&(severity <= 7)) {
Packit 284210
        return severities[severity];
Packit 284210
    }
Packit 284210
    else {
Packit 284210
        return "(invalid value)";
Packit 284210
    }
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Creates a string containing the metadata of the supplied rule.
Packit 284210
 */
Packit 284210
char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
Packit 284210
    const apr_array_header_t *tarr;
Packit 284210
    const apr_table_entry_t *telts;
Packit 284210
    char *id = "";
Packit 284210
    char *rev = "";
Packit 284210
    char *msg = "";
Packit 284210
    char *logdata = "";
Packit 284210
    char *severity = "";
Packit 284210
    char *accuracy = "";
Packit 284210
    char *maturity = "";
Packit 284210
    char *version = "";
Packit 284210
    char *tags = "";
Packit 284210
    char *fn = "";
Packit 284210
    int k;
Packit 284210
Packit 284210
    if (actionset == NULL) return "";
Packit 284210
Packit 284210
#ifndef LOG_NO_FILENAME
Packit 284210
    if ((actionset->rule != NULL) && (actionset->rule->filename != NULL)) {
Packit 284210
        fn = apr_psprintf(msr->mp, " [file \"%s\"] [line \"%d\"]",
Packit 284210
                actionset->rule->filename, actionset->rule->line_num);
Packit 284210
    }
Packit 284210
#endif
Packit 284210
    if (actionset->id != NULL) {
Packit 284210
        id = apr_psprintf(msr->mp, " [id \"%s\"]",
Packit 284210
                log_escape(msr->mp, actionset->id));
Packit 284210
    }
Packit 284210
    if (actionset->rev != NULL) {
Packit 284210
        rev = apr_psprintf(msr->mp, " [rev \"%s\"]",
Packit 284210
                log_escape(msr->mp, actionset->rev));
Packit 284210
    }
Packit 284210
    if (actionset->msg != NULL) {
Packit 284210
        /* Expand variables in the message string. */
Packit 284210
        msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
Packit 284210
        var->value = (char *)actionset->msg;
Packit 284210
        var->value_len = strlen(actionset->msg);
Packit 284210
        expand_macros(msr, var, NULL, msr->mp);
Packit 284210
Packit 284210
        msg = apr_psprintf(msr->mp, " [msg \"%s\"]",
Packit 284210
                log_escape_ex(msr->mp, var->value, var->value_len));
Packit 284210
    }
Packit 284210
    if (actionset->logdata != NULL) {
Packit 284210
        /* Expand variables in the message string. */
Packit 284210
        msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
Packit 284210
        var->value = (char *)actionset->logdata;
Packit 284210
        var->value_len = strlen(actionset->logdata);
Packit 284210
        expand_macros(msr, var, NULL, msr->mp);
Packit 284210
Packit 284210
        logdata = apr_psprintf(msr->mp, " [data \"%s",
Packit 284210
                log_escape_hex(msr->mp, (unsigned char *)var->value, var->value_len));
Packit 284210
        logdata = apr_pstrcat(msr->mp, logdata, "\"]", NULL);
Packit 284210
Packit 284210
        /* If it is > 512 bytes, then truncate at 512 with ellipsis.
Packit 284210
         * NOTE: 512 actual data + 9 bytes of label = 521
Packit 284210
         */
Packit 284210
        if (strlen(logdata) > 521) {
Packit 284210
            logdata[517] = '.';
Packit 284210
            logdata[518] = '.';
Packit 284210
            logdata[519] = '.';
Packit 284210
            logdata[520] = '"';
Packit 284210
            logdata[521] = ']';
Packit 284210
            logdata[522] = '\0';
Packit 284210
        }
Packit 284210
    }
Packit 284210
    if ((actionset->severity >= 0)&&(actionset->severity <= 7)) {
Packit 284210
        severity = apr_psprintf(msr->mp, " [severity \"%s\"]",
Packit 284210
                msre_format_severity(actionset->severity));
Packit 284210
    }
Packit 284210
    if (actionset->version != NULL) {
Packit 284210
        version = apr_psprintf(msr->mp, " [ver \"%s\"]",
Packit 284210
                log_escape(msr->mp, actionset->version));
Packit 284210
    }
Packit 284210
    if (actionset->maturity >= 0) {
Packit 284210
        maturity = apr_psprintf(msr->mp, " [maturity \"%d\"]",
Packit 284210
                actionset->maturity);
Packit 284210
    }
Packit 284210
    if (actionset->accuracy >= 0) {
Packit 284210
        accuracy = apr_psprintf(msr->mp, " [accuracy \"%d\"]",
Packit 284210
                actionset->accuracy);
Packit 284210
    }
Packit 284210
Packit 284210
    /* Extract rule tags from the action list. */
Packit 284210
    tarr = apr_table_elts(actionset->actions);
Packit 284210
    telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
Packit 284210
    for (k = 0; k < tarr->nelts; k++) {
Packit 284210
        msre_action *action = (msre_action *)telts[k].val;
Packit 284210
        if (strcmp(telts[k].key, "tag") == 0) {
Packit 284210
            /* Expand variables in the tag argument. */
Packit 284210
            msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
Packit 284210
Packit 284210
            var->value = (char *)action->param;
Packit 284210
            var->value_len = strlen(action->param);
Packit 284210
            expand_macros(msr, var, NULL, msr->mp);
Packit 284210
Packit 284210
            tags = apr_psprintf(msr->mp, "%s [tag \"%s\"]", tags,
Packit 284210
               log_escape(msr->mp, var->value));
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    return apr_pstrcat(msr->mp, fn, id, rev, msg, logdata, severity, version, maturity, accuracy, tags, NULL);
Packit 284210
}
Packit 284210
Packit 284210
char * msre_rule_generate_unparsed(apr_pool_t *pool,  const msre_rule *rule, const char *targets,
Packit 284210
        const char *args, const char *actions)
Packit 284210
{
Packit 284210
    char *unparsed = NULL;
Packit 284210
    const char *r_targets = targets;
Packit 284210
    const char *r_args = args;
Packit 284210
    const char *r_actions = actions;
Packit 284210
Packit 284210
    if (r_targets == NULL) {
Packit 284210
        r_targets = rule->p1;
Packit 284210
    }
Packit 284210
    if (r_args == NULL) {
Packit 284210
        r_args = apr_pstrcat(pool, (rule->op_negated ? "!" : ""), "@", rule->op_name, " ", rule->op_param, NULL);
Packit 284210
    }
Packit 284210
    if (r_actions == NULL) {
Packit 284210
        r_actions = msre_actionset_generate_action_string(pool, rule->actionset);
Packit 284210
    }
Packit 284210
Packit 284210
    switch (rule->type) {
Packit 284210
        case RULE_TYPE_NORMAL:
Packit 284210
            if (r_actions == NULL) {
Packit 284210
                unparsed = apr_psprintf(pool, "SecRule \"%s\" \"%s\"",
Packit 284210
                        log_escape(pool, r_targets), log_escape(pool, r_args));
Packit 284210
            }
Packit 284210
            else {
Packit 284210
                unparsed = apr_psprintf(pool, "SecRule \"%s\" \"%s\" \"%s\"",
Packit 284210
                        log_escape(pool, r_targets), log_escape(pool, r_args),
Packit 284210
                        log_escape(pool, r_actions));
Packit 284210
            }
Packit 284210
            break;
Packit 284210
        case RULE_TYPE_ACTION:
Packit 284210
            unparsed = apr_psprintf(pool, "SecAction \"%s\"",
Packit 284210
                    log_escape(pool, r_actions));
Packit 284210
            break;
Packit 284210
        case RULE_TYPE_MARKER:
Packit 284210
            unparsed = apr_psprintf(pool, "SecMarker \"%s\"", rule->actionset->id);
Packit 284210
            break;
Packit 284210
#if defined(WITH_LUA)
Packit 284210
        case RULE_TYPE_LUA:
Packit 284210
            /* SecRuleScript */
Packit 284210
            if (r_actions == NULL) {
Packit 284210
                unparsed = apr_psprintf(pool, "SecRuleScript \"%s\"", r_args);
Packit 284210
            }
Packit 284210
            else {
Packit 284210
                unparsed = apr_psprintf(pool, "SecRuleScript \"%s\" \"%s\"",
Packit 284210
                        r_args, log_escape(pool, r_actions));
Packit 284210
            }
Packit 284210
            break;
Packit 284210
#endif
Packit 284210
    }
Packit 284210
Packit 284210
    return unparsed;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Assembles a new rule using the strings that contain a list
Packit 284210
 * of targets (variables), arguments, and actions.
Packit 284210
 */
Packit 284210
msre_rule *msre_rule_create(msre_ruleset *ruleset, int type,
Packit 284210
        const char *fn, int line, const char *targets,
Packit 284210
        const char *args, const char *actions, char **error_msg)
Packit 284210
{
Packit 284210
    msre_rule *rule;
Packit 284210
    char *my_error_msg;
Packit 284210
    const char *argsp;
Packit 284210
    int rc;
Packit 284210
Packit 284210
    if (error_msg == NULL) return NULL;
Packit 284210
    *error_msg = NULL;
Packit 284210
Packit 284210
    rule = (msre_rule *)apr_pcalloc(ruleset->mp, sizeof(msre_rule));
Packit 284210
    if (rule == NULL) return NULL;
Packit 284210
Packit 284210
    rule->type = type;
Packit 284210
    rule->ruleset = ruleset;
Packit 284210
    rule->targets = apr_array_make(ruleset->mp, 10, sizeof(const msre_var *));
Packit 284210
    rule->p1 = apr_pstrdup(ruleset->mp, targets);
Packit 284210
    rule->filename = apr_pstrdup(ruleset->mp, fn);
Packit 284210
    rule->line_num = line;
Packit 284210
Packit 284210
    /* Parse targets */
Packit 284210
    rc = msre_parse_targets(ruleset, targets, rule->targets, &my_error_msg);
Packit 284210
    if (rc < 0) {
Packit 284210
        *error_msg = apr_psprintf(ruleset->mp, "Error creating rule: %s", my_error_msg);
Packit 284210
        return NULL;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Parse args */
Packit 284210
    argsp = args;
Packit 284210
Packit 284210
    /* Is negation used? */
Packit 284210
    if (*argsp == '!') {
Packit 284210
        rule->op_negated = 1;
Packit 284210
        argsp++;
Packit 284210
        while((isspace(*argsp))&&(*argsp != '\0')) argsp++;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Is the operator explicitly selected? */
Packit 284210
    if (*argsp != '@') {
Packit 284210
        /* Go with a regular expression. */
Packit 284210
        rule->op_name = "rx";
Packit 284210
        rule->op_param = argsp;
Packit 284210
    } else  {
Packit 284210
        /* Explicitly selected operator. */
Packit 284210
        char *p = (char *)(argsp + 1);
Packit 284210
        while((!isspace(*p))&&(*p != '\0')) p++;
Packit 284210
        rule->op_name = apr_pstrmemdup(ruleset->mp, argsp + 1, p - (argsp + 1));
Packit 284210
        while(isspace(*p)) p++; /* skip over the whitespace at the end*/
Packit 284210
        rule->op_param = p; /* IMP1 So we always have a parameter even when it's empty? */
Packit 284210
    }
Packit 284210
Packit 284210
    /* Find the operator. */
Packit 284210
    rule->op_metadata = msre_engine_op_resolve(ruleset->engine, rule->op_name);
Packit 284210
    if (rule->op_metadata == NULL) {
Packit 284210
        *error_msg = apr_psprintf(ruleset->mp,
Packit 284210
                "Error creating rule: Failed to resolve operator: %s", rule->op_name);
Packit 284210
        return NULL;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Initialise & validate parameter */
Packit 284210
    if (rule->op_metadata->param_init != NULL) {
Packit 284210
        if (rule->op_metadata->param_init(rule, &my_error_msg) <= 0) {
Packit 284210
            *error_msg = apr_psprintf(ruleset->mp, "Error creating rule: %s", my_error_msg);
Packit 284210
            return NULL;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* Parse actions */
Packit 284210
    if (actions != NULL) {
Packit 284210
        /* Create per-rule actionset */
Packit 284210
        rule->actionset = msre_actionset_create(ruleset->engine, ruleset->mp, actions, &my_error_msg);
Packit 284210
        if (rule->actionset == NULL) {
Packit 284210
            *error_msg = apr_psprintf(ruleset->mp, "Error parsing actions: %s", my_error_msg);
Packit 284210
            return NULL;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* Add the unparsed rule */
Packit 284210
    rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, targets, args, NULL);
Packit 284210
Packit 284210
    return rule;
Packit 284210
}
Packit 284210
Packit 284210
#if defined(WITH_LUA)
Packit 284210
/**
Packit 284210
 *
Packit 284210
 */
Packit 284210
msre_rule *msre_rule_lua_create(msre_ruleset *ruleset,
Packit 284210
        const char *fn, int line, const char *script_filename,
Packit 284210
        const char *actions, char **error_msg)
Packit 284210
{
Packit 284210
    msre_rule *rule;
Packit 284210
    char *my_error_msg;
Packit 284210
Packit 284210
    if (error_msg == NULL) return NULL;
Packit 284210
    *error_msg = NULL;
Packit 284210
Packit 284210
    rule = (msre_rule *)apr_pcalloc(ruleset->mp, sizeof(msre_rule));
Packit 284210
    if (rule == NULL) return NULL;
Packit 284210
Packit 284210
    rule->type = RULE_TYPE_LUA;
Packit 284210
    rule->ruleset = ruleset;
Packit 284210
    rule->filename = apr_pstrdup(ruleset->mp, fn);
Packit 284210
    rule->line_num = line;
Packit 284210
Packit 284210
    /* Compile script. */
Packit 284210
    *error_msg = lua_compile(&rule->script, script_filename, ruleset->mp);
Packit 284210
    if (*error_msg != NULL) {
Packit 284210
        return NULL;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Parse actions */
Packit 284210
    if (actions != NULL) {
Packit 284210
        /* Create per-rule actionset */
Packit 284210
        rule->actionset = msre_actionset_create(ruleset->engine, ruleset->mp, actions, &my_error_msg);
Packit 284210
        if (rule->actionset == NULL) {
Packit 284210
            *error_msg = apr_psprintf(ruleset->mp, "Error parsing actions: %s", my_error_msg);
Packit 284210
            return NULL;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* Add the unparsed rule */
Packit 284210
    rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, NULL, script_filename, NULL);
Packit 284210
Packit 284210
    return rule;
Packit 284210
}
Packit 284210
#endif
Packit 284210
Packit 284210
/**
Packit 284210
 * Perform non-disruptive actions associated with the provided actionset.
Packit 284210
 */
Packit 284210
static void msre_perform_nondisruptive_actions(modsec_rec *msr, msre_rule *rule,
Packit 284210
        msre_actionset *actionset, apr_pool_t *mptmp)
Packit 284210
{
Packit 284210
    const apr_array_header_t *tarr;
Packit 284210
    const apr_table_entry_t *telts;
Packit 284210
    int i;
Packit 284210
Packit 284210
    tarr = apr_table_elts(actionset->actions);
Packit 284210
    telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
    for (i = 0; i < tarr->nelts; i++) {
Packit 284210
        msre_action *action = (msre_action *)telts[i].val;
Packit 284210
        if (action->metadata->type == ACTION_NON_DISRUPTIVE) {
Packit 284210
            if (action->metadata->execute != NULL) {
Packit 284210
                action->metadata->execute(msr, mptmp, rule, action);
Packit 284210
            }
Packit 284210
        }
Packit 284210
    }
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Perform the disruptive actions associated with the given actionset.
Packit 284210
 */
Packit 284210
static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule,
Packit 284210
        msre_actionset *actionset, apr_pool_t *mptmp, const char *message)
Packit 284210
{
Packit 284210
    const apr_array_header_t *tarr;
Packit 284210
    const apr_table_entry_t *telts;
Packit 284210
    int i;
Packit 284210
Packit 284210
    /* Execute the disruptive actions. Do note that this does
Packit 284210
     * not mean the request will be interrupted straight away. All
Packit 284210
     * disruptive actions need to do here is update the information
Packit 284210
     * that will be used to act later.
Packit 284210
     */
Packit 284210
    tarr = apr_table_elts(actionset->actions);
Packit 284210
    telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
    for (i = 0; i < tarr->nelts; i++) {
Packit 284210
        msre_action *action = (msre_action *)telts[i].val;
Packit 284210
        if (action->metadata->type == ACTION_DISRUPTIVE) {
Packit 284210
            if (action->metadata->execute != NULL) {
Packit 284210
                action->metadata->execute(msr, mptmp, rule, action);
Packit 284210
            }
Packit 284210
        }
Packit 284210
    }
Packit 284210
    if (actionset->intercept_action_rec->metadata->type == ACTION_DISRUPTIVE) {
Packit 284210
        if (actionset->intercept_action_rec->metadata->execute != NULL) {
Packit 284210
            actionset->intercept_action_rec->metadata->execute(msr, mptmp, rule, actionset->intercept_action_rec);
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* If "noauditlog" was used do not mark the transaction relevant. */
Packit 284210
    if (actionset->auditlog != 0) {
Packit 284210
        msr->is_relevant++;
Packit 284210
    }
Packit 284210
Packit 284210
    /* We only do stuff when in ONLINE mode. In all other
Packit 284210
     * cases we only emit warnings.
Packit 284210
     */
Packit 284210
    if ((msr->phase == PHASE_LOGGING)
Packit 284210
            || (msr->txcfg->is_enabled == MODSEC_DETECTION_ONLY)
Packit 284210
            || (msr->modsecurity->processing_mode == MODSEC_OFFLINE)
Packit 284210
            || (actionset->intercept_action == ACTION_NONE))
Packit 284210
    {
Packit 284210
        int log_level;
Packit 284210
Packit 284210
        /* If "nolog" was used log at a higher level to prevent an "alert". */
Packit 284210
        if (actionset->log == 0) {
Packit 284210
            log_level = 4;
Packit 284210
Packit 284210
            /* But, if "auditlog" is enabled, then still add the message. */
Packit 284210
            if (actionset->auditlog != 0) {
Packit 284210
                *(const char **)apr_array_push(msr->alerts) = msc_alert_message(msr, actionset, NULL, message);
Packit 284210
            }
Packit 284210
Packit 284210
        }
Packit 284210
        else {
Packit 284210
            log_level = 2;
Packit 284210
        }
Packit 284210
Packit 284210
        msc_alert(msr, log_level, actionset, "Warning.", message);
Packit 284210
Packit 284210
        /* However, this will mark the txn relevant again if it is <= 3,
Packit 284210
         * which will mess up noauditlog.  We need to compensate for this
Packit 284210
         * so that we do not increment twice when auditlog is enabled and
Packit 284210
         * prevent incrementing when auditlog is disabled.
Packit 284210
         */
Packit 284210
        if (log_level <= 3) {
Packit 284210
            msr->is_relevant--;
Packit 284210
        }
Packit 284210
Packit 284210
        return;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Signal to the engine we need to intercept this
Packit 284210
     * transaction, and rememer the rule that caused it.
Packit 284210
     */
Packit 284210
    msr->was_intercepted = 1;
Packit 284210
    msr->rule_was_intercepted = 1;
Packit 284210
    msr->intercept_phase = msr->phase;
Packit 284210
    msr->intercept_actionset = actionset;
Packit 284210
    msr->intercept_message = message;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Invokes the rule operator against the given value.
Packit 284210
 */
Packit 284210
static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr,
Packit 284210
    msre_actionset *acting_actionset, apr_pool_t *mptmp)
Packit 284210
{
Packit 284210
    apr_time_t time_before_op = 0;
Packit 284210
    char *my_error_msg = NULL;
Packit 284210
    const char *full_varname = NULL;
Packit 284210
    const apr_array_header_t *tarr = NULL;
Packit 284210
    const apr_table_entry_t *telts = NULL;
Packit 284210
    rule_exception *re = NULL;
Packit 284210
    char *exceptions = NULL;
Packit 284210
    int rc, i;
Packit 284210
Packit 284210
    /* determine the full var name if not already resolved
Packit 284210
     *
Packit 284210
     * NOTE: this can happen if the var does not match but it is
Packit 284210
     * being tested for non-existance as in:
Packit 284210
     *   @REQUEST_HEADERS:Foo "@eq 0"
Packit 284210
     *   @REQUEST_HEADERS:Foo "!@eq 1"
Packit 284210
     */
Packit 284210
    if ((var->param != NULL) && (var->name != NULL) && (strchr(var->name,':') == NULL)) {
Packit 284210
        full_varname = apr_psprintf(mptmp, "%s%s:%s",
Packit 284210
                                    (var->is_counting ? "&" : ""),
Packit 284210
                                    var->name, var->param);
Packit 284210
    }
Packit 284210
    else if ((var->name != NULL) && var->is_counting && (*var->name != '&')) {
Packit 284210
        full_varname = apr_pstrcat(mptmp, "&", var->name, NULL);
Packit 284210
    }
Packit 284210
    else {
Packit 284210
        full_varname = var->name;
Packit 284210
    }
Packit 284210
Packit 284210
    tarr = apr_table_elts(msr->removed_targets);
Packit 284210
    telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
Packit 284210
    for (i = 0; i < tarr->nelts; i++) {
Packit 284210
        exceptions = (char *)telts[i].key;
Packit 284210
        re = (rule_exception *)telts[i].val;
Packit 284210
Packit 284210
        rc = msre_ruleset_rule_matches_exception(rule, re);
Packit 284210
Packit 284210
        if (rc > 0) {
Packit 284210
            rc = fetch_target_exception(rule, msr, var, exceptions);
Packit 284210
Packit 284210
            if(rc > 0)  {
Packit 284210
Packit 284210
                if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
                    msr_log(msr, 4, "Executing operator \"%s%s\" with param \"%s\" against %s skipped.",
Packit 284210
                            (rule->op_negated ? "!" : ""), rule->op_name,
Packit 284210
                            log_escape(msr->mp, rule->op_param), full_varname);
Packit 284210
                }
Packit 284210
Packit 284210
                return RULE_NO_MATCH;
Packit 284210
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
    }
Packit 284210
Packit 284210
    if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
        msr_log(msr, 4, "Executing operator \"%s%s\" with param \"%s\" against %s.",
Packit 284210
                (rule->op_negated ? "!" : ""), rule->op_name,
Packit 284210
                log_escape(msr->mp, rule->op_param), full_varname);
Packit 284210
    }
Packit 284210
Packit 284210
    if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
        msr_log(msr, 9, "Target value: \"%s\"", log_escape_nq_ex(msr->mp, var->value,
Packit 284210
                    var->value_len));
Packit 284210
    }
Packit 284210
Packit 284210
#if defined(PERFORMANCE_MEASUREMENT)
Packit 284210
    time_before_op = apr_time_now();
Packit 284210
#else
Packit 284210
    if (msr->txcfg->debuglog_level >= 4 || msr->txcfg->max_rule_time > 0) {
Packit 284210
        time_before_op = apr_time_now();
Packit 284210
    }
Packit 284210
#endif
Packit 284210
Packit 284210
    rc = rule->op_metadata->execute(msr, rule, var, &my_error_msg);
Packit 284210
Packit 284210
#if defined(PERFORMANCE_MEASUREMENT)
Packit 284210
    {
Packit 284210
        /* Record performance but do not log anything. */
Packit 284210
        apr_time_t t1 = apr_time_now();
Packit 284210
        rule->op_time += (t1 - time_before_op);
Packit 284210
    }
Packit 284210
    #else
Packit 284210
    if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
        apr_time_t t1 = apr_time_now();
Packit 284210
        msr_log(msr, 4, "Operator completed in %" APR_TIME_T_FMT " usec.", (t1 - time_before_op));
Packit 284210
    }
Packit 284210
Packit 284210
    if(msr->txcfg->max_rule_time > 0)  {
Packit 284210
        apr_time_t t1 = apr_time_now();
Packit 284210
        apr_time_t rule_time = 0;
Packit 284210
        const char *rt_time = NULL;
Packit 284210
Packit 284210
        if(rule->actionset->id != NULL) {
Packit 284210
            rt_time = apr_table_get(msr->perf_rules, rule->actionset->id);
Packit 284210
            if(rt_time == NULL) {
Packit 284210
                rt_time = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (t1 - time_before_op));
Packit 284210
                rule_time = (apr_time_t)atoi(rt_time);
Packit 284210
                if(rule_time >= msr->txcfg->max_rule_time)
Packit 284210
                    apr_table_setn(msr->perf_rules, rule->actionset->id, rt_time);
Packit 284210
            } else  {
Packit 284210
                rule_time = (apr_time_t)atoi(rt_time);
Packit 284210
                rule_time += (t1 - time_before_op);
Packit 284210
                if(rule_time >= msr->txcfg->max_rule_time)  {
Packit 284210
                    rt_time = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, rule_time);
Packit 284210
                    apr_table_setn(msr->perf_rules, rule->actionset->id, rt_time);
Packit 284210
                }
Packit 284210
            }
Packit 284210
        }
Packit 284210
    }
Packit 284210
#endif
Packit 284210
Packit 284210
    if (rc < 0) {
Packit 284210
        msr_log(msr, 4, "Operator error: %s", my_error_msg);
Packit 284210
        return -1;
Packit 284210
    }
Packit 284210
Packit 284210
    if (((rc == 0)&&(rule->op_negated == 0))||((rc == 1)&&(rule->op_negated == 1))) {
Packit 284210
        /* No match, do nothing. */
Packit 284210
        return RULE_NO_MATCH;
Packit 284210
    }
Packit 284210
    else {
Packit 284210
        /* Match. */
Packit 284210
        if (rc == 0) {
Packit 284210
            char *op_param = log_escape(msr->mp, rule->op_param);
Packit 284210
Packit 284210
            /* Truncate op parameter. */
Packit 284210
            if (strlen(op_param) > 252) {
Packit 284210
                op_param = apr_psprintf(msr->mp, "%.252s ...", op_param);
Packit 284210
            }
Packit 284210
Packit 284210
            /* Operator did not match so we need to provide a message. */
Packit 284210
            my_error_msg = apr_psprintf(msr->mp, "Match of \"%s %s\" against \"%s\" required.",
Packit 284210
                log_escape(msr->mp, rule->op_name), op_param,
Packit 284210
                log_escape(msr->mp, full_varname));
Packit 284210
        }
Packit 284210
Packit 284210
        /* Save the rules that match */
Packit 284210
        *(const msre_rule **)apr_array_push(msr->matched_rules) = rule;
Packit 284210
Packit 284210
        /* Save the last matched var data */
Packit 284210
        if(var != NULL && msr != NULL)   {
Packit 284210
            msc_string *mvar = NULL;
Packit 284210
Packit 284210
            msr->matched_var->name = apr_pstrdup(msr->mp, var->name);
Packit 284210
            msr->matched_var->name_len = strlen(msr->matched_var->name);
Packit 284210
            msr->matched_var->value = apr_pmemdup(msr->mp, var->value, var->value_len);
Packit 284210
            msr->matched_var->value_len = var->value_len;
Packit 284210
Packit 284210
            mvar = apr_palloc(msr->mp, sizeof(msc_string));
Packit 284210
            mvar->name = apr_pstrdup(msr->mp, var->name);
Packit 284210
            mvar->name_len = strlen(mvar->name);
Packit 284210
            mvar->value = apr_pmemdup(msr->mp, var->value, var->value_len);
Packit 284210
            mvar->value_len = var->value_len;
Packit 284210
Packit 284210
            apr_table_addn(msr->matched_vars, mvar->name, (void *)mvar);
Packit 284210
Packit 284210
        }
Packit 284210
Packit 284210
        /* Keep track of the highest severity matched so far */
Packit 284210
        if ((acting_actionset->severity > 0) && (acting_actionset->severity < msr->highest_severity)
Packit 284210
            && !rule->actionset->is_chained)   {
Packit 284210
            msr->highest_severity = acting_actionset->severity;
Packit 284210
        }
Packit 284210
Packit 284210
Packit 284210
        /* Perform non-disruptive actions. */
Packit 284210
        msre_perform_nondisruptive_actions(msr, rule, rule->actionset, mptmp);
Packit 284210
Packit 284210
        /* Perform disruptive actions, but only if
Packit 284210
         * this rule is not part of a chain.
Packit 284210
         */
Packit 284210
        if (rule->actionset->is_chained == 0) {
Packit 284210
            msre_perform_disruptive_actions(msr, rule, acting_actionset, mptmp, my_error_msg);
Packit 284210
        }
Packit 284210
Packit 284210
        return RULE_MATCH;
Packit 284210
    }
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Executes rule against the given transaction.
Packit 284210
 */
Packit 284210
static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) {
Packit 284210
    const apr_array_header_t *arr = NULL;
Packit 284210
    const apr_table_entry_t *te = NULL;
Packit 284210
    msre_actionset *acting_actionset = NULL;
Packit 284210
    msre_var **targets = NULL;
Packit 284210
    apr_pool_t *mptmp = msr->msc_rule_mptmp;
Packit 284210
    apr_table_t *tartab = NULL;
Packit 284210
    apr_table_t *vartab = NULL;
Packit 284210
    int i, rc = 0, match_count = 0;
Packit 284210
    int invocations = 0;
Packit 284210
    int multi_match = 0;
Packit 284210
Packit 284210
    /* Choose the correct metadata/disruptive action actionset. */
Packit 284210
    acting_actionset = rule->actionset;
Packit 284210
    if (rule->chain_starter != NULL) {
Packit 284210
        acting_actionset = rule->chain_starter->actionset;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Configure recursive matching. */
Packit 284210
    if (apr_table_get(rule->actionset->actions, "multiMatch") != NULL) {
Packit 284210
        multi_match = 1;
Packit 284210
    }
Packit 284210
Packit 284210
    /* ENH: What is a good initial size? */
Packit 284210
    tartab = apr_table_make(mptmp, 24);
Packit 284210
    if (tartab == NULL) return -1;
Packit 284210
    vartab = apr_table_make(mptmp, 24);
Packit 284210
    if (vartab == NULL) return -1;
Packit 284210
Packit 284210
    /* Expand variables to create a list of targets. */
Packit 284210
Packit 284210
    targets = (msre_var **)rule->targets->elts;
Packit 284210
    for (i = 0; i < rule->targets->nelts; i++) {
Packit 284210
        int j, list_count;
Packit 284210
Packit 284210
        apr_table_clear(vartab);
Packit 284210
Packit 284210
        /* ENH Introduce a new variable hook that would allow the code
Packit 284210
         *     behind the variable to return the size of the collection
Packit 284210
         *     without having to generate the variables.
Packit 284210
         */
Packit 284210
Packit 284210
        /* Expand individual variables first. */
Packit 284210
        list_count = targets[i]->metadata->generate(msr, targets[i], rule, vartab, mptmp);
Packit 284210
Packit 284210
        if (targets[i]->is_counting) {
Packit 284210
            /* Count how many there are and just add the score to the target list. */
Packit 284210
            msre_var *newvar = (msre_var *)apr_pmemdup(mptmp, targets[i], sizeof(msre_var));
Packit 284210
            newvar->value = apr_psprintf(mptmp, "%d", list_count);
Packit 284210
            newvar->value_len = strlen(newvar->value);
Packit 284210
            apr_table_addn(tartab, newvar->name, (void *)newvar);
Packit 284210
        } else {
Packit 284210
            /* And either add them or remove from the final target list. */
Packit 284210
            arr = apr_table_elts(vartab);
Packit 284210
            te = (apr_table_entry_t *)arr->elts;
Packit 284210
            for(j = 0; j < arr->nelts; j++) {
Packit 284210
                if (targets[i]->is_negated == 0) {
Packit 284210
                    apr_table_addn(tartab, te[j].key, te[j].val);
Packit 284210
                } else {
Packit 284210
                    apr_table_unset(tartab, te[j].key);
Packit 284210
                }
Packit 284210
            }
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* Log the target variable expansion */
Packit 284210
    if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
        const char *expnames = NULL;
Packit 284210
Packit 284210
        arr = apr_table_elts(tartab);
Packit 284210
        if (arr->nelts > 1) {
Packit 284210
            te = (apr_table_entry_t *)arr->elts;
Packit 284210
            expnames = apr_pstrdup(mptmp, ((msre_var *)te[0].val)->name);
Packit 284210
            for(i = 1; i < arr->nelts; i++) {
Packit 284210
                expnames = apr_psprintf(mptmp, "%s|%s", expnames, ((msre_var *)te[i].val)->name);
Packit 284210
            }
Packit 284210
            if (strcmp(rule->p1, expnames) != 0) {
Packit 284210
                msr_log(msr, 4, "Expanded \"%s\" to \"%s\".", rule->p1, expnames);
Packit 284210
            }
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* Loop through targets on the final target list,
Packit 284210
     * perform transformations as necessary, and invoke
Packit 284210
     * the operator.
Packit 284210
     */
Packit 284210
Packit 284210
    arr = apr_table_elts(tartab);
Packit 284210
    te = (apr_table_entry_t *)arr->elts;
Packit 284210
    for (i = 0; i < arr->nelts; i++) {
Packit 284210
        /* Variable was modified by *any* transformation */
Packit 284210
        int changed;
Packit 284210
        /* Variable was modified by *last applied* transformation (needed by multimatch) */
Packit 284210
        int tfnchanged;
Packit 284210
        int usecache = 0;
Packit 284210
        apr_table_t *cachetab = NULL;
Packit 284210
        apr_time_t time_before_trans = 0;
Packit 284210
        msre_var *var;
Packit 284210
Packit 284210
        /* Take one target. */
Packit 284210
        var = (msre_var *)te[i].val;
Packit 284210
Packit 284210
        /* Is this var cacheable? */
Packit 284210
        if (msr->txcfg->cache_trans != MODSEC_CACHE_DISABLED) {
Packit 284210
            usecache = 1;
Packit 284210
Packit 284210
            /* Counting vars are not cacheable due to them being created
Packit 284210
             * in a local per-rule pool.
Packit 284210
             */
Packit 284210
            if (var->is_counting) {
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "CACHE: Disabled - &%s is dynamic", var->name);
Packit 284210
                }
Packit 284210
Packit 284210
                usecache = 0;
Packit 284210
            }
Packit 284210
            /* Only cache if if the variable is available in this phase */
Packit 284210
            else if (msr->phase < var->metadata->availability) {
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "CACHE: Disabled - %s is not yet available in phase %d (requires phase %d or later)", var->name, msr->phase, var->metadata->availability);
Packit 284210
                }
Packit 284210
Packit 284210
                usecache = 0;
Packit 284210
            }
Packit 284210
            /* check the cache options */
Packit 284210
            else if (var->value_len < msr->txcfg->cache_trans_min) {
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "CACHE: Disabled - %s value length=%u, smaller than minlen=%" APR_SIZE_T_FMT, var->name, var->value_len, msr->txcfg->cache_trans_min);
Packit 284210
                }
Packit 284210
Packit 284210
                usecache = 0;
Packit 284210
            }
Packit 284210
            else if ((msr->txcfg->cache_trans_max != 0) && (var->value_len > msr->txcfg->cache_trans_max)) {
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "CACHE: Disabled - %s value length=%u, larger than maxlen=%" APR_SIZE_T_FMT, var->name, var->value_len, msr->txcfg->cache_trans_max);
Packit 284210
                }
Packit 284210
Packit 284210
                usecache = 0;
Packit 284210
            }
Packit 284210
Packit 284210
            /* if cache is still enabled, check the VAR for cacheablity */
Packit 284210
            if (usecache) {
Packit 284210
                if (var->metadata->is_cacheable == VAR_CACHE) {
Packit 284210
                    if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                        msr_log(msr, 9, "CACHE: Enabled");
Packit 284210
                    }
Packit 284210
Packit 284210
                    #ifdef CACHE_DEBUG
Packit 284210
                    msr_log(msr, 9, "CACHE: Fetching cache entry from hash=%pp: %pp=%s", msr->tcache, var, var->name);
Packit 284210
                    #endif
Packit 284210
Packit 284210
                    /* Fetch cache table for this target */
Packit 284210
                    cachetab = (apr_table_t *)apr_hash_get(msr->tcache, var->value, sizeof(var->value));
Packit 284210
Packit 284210
                    /* Create an empty cache table if this is the first time */
Packit 284210
                    #ifdef CACHE_DEBUG
Packit 284210
                    if (cachetab) {
Packit 284210
                        msr_log(msr, 9, "CACHE: Using cache table %pp", cachetab);
Packit 284210
                    }
Packit 284210
                    else
Packit 284210
                    #else
Packit 284210
                    if (cachetab == NULL)
Packit 284210
                    #endif
Packit 284210
                    {
Packit 284210
                        /* NOTE: We use the pointer to the var value as a hash
Packit 284210
                         *       key as it is unique. This pointer *must*
Packit 284210
                         *       remain valid through the entire phase. If
Packit 284210
                         *       it does not, then we will not receive a cache
Packit 284210
                         *       hit and just wasted RAM. So, it is important
Packit 284210
                         *       that any such vars be marked as VAR_DONT_CACHE.
Packit 284210
                         *
Packit 284210
                         * ENH: Only use pointer for non-scalar vars
Packit 284210
                         */
Packit 284210
                        cachetab = apr_table_make(msr->mp, 3);
Packit 284210
                        apr_hash_set(msr->tcache, var->value, sizeof(var->value), cachetab);
Packit 284210
Packit 284210
                        #ifdef CACHE_DEBUG
Packit 284210
                        msr_log(msr, 9, "CACHE: Created a new cache table %pp for %pp", cachetab, var->value);
Packit 284210
                        #endif
Packit 284210
                    }
Packit 284210
Packit 284210
                }
Packit 284210
                else {
Packit 284210
                    usecache = 0;
Packit 284210
Packit 284210
                    if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                        msr_log(msr, 9, "CACHE: %s transformations are not cacheable", var->name);
Packit 284210
                    }
Packit 284210
                }
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        #if defined(PERFORMANCE_MEASUREMENT)
Packit 284210
        time_before_trans = apr_time_now();
Packit 284210
        #else
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            time_before_trans = apr_time_now();
Packit 284210
        }
Packit 284210
        #endif
Packit 284210
Packit 284210
        /* Transform target. */
Packit 284210
        {
Packit 284210
            const apr_array_header_t *tarr;
Packit 284210
            const apr_table_entry_t *telts;
Packit 284210
            const char *tfnspath = NULL;
Packit 284210
            char *tfnskey = NULL;
Packit 284210
            int tfnscount = 0;
Packit 284210
            int last_cached_tfn = 0;
Packit 284210
            msre_cache_rec *crec = NULL;
Packit 284210
            msre_cache_rec *last_crec = NULL;
Packit 284210
            int k;
Packit 284210
            msre_action *action;
Packit 284210
            msre_tfn_metadata *metadata;
Packit 284210
            apr_table_t *normtab;
Packit 284210
            const char *lastvarval = NULL;
Packit 284210
            apr_size_t lastvarlen = 0;
Packit 284210
Packit 284210
            tfnchanged = 0;
Packit 284210
            changed = 0;
Packit 284210
            normtab = apr_table_make(mptmp, 10);
Packit 284210
            if (normtab == NULL) return -1;
Packit 284210
            tarr = apr_table_elts(rule->actionset->actions);
Packit 284210
            telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
Packit 284210
            /* Build the final list of transformation functions. */
Packit 284210
            for (k = 0; k < tarr->nelts; k++) {
Packit 284210
                action = (msre_action *)telts[k].val;
Packit 284210
Packit 284210
                if (strcmp(telts[k].key, "t") == 0) {
Packit 284210
                    if (strcmp(action->param, "none") == 0) {
Packit 284210
                        apr_table_clear(normtab);
Packit 284210
                        tfnspath = NULL;
Packit 284210
                        tfnskey = NULL;
Packit 284210
                        tfnscount = 0;
Packit 284210
                        last_crec = NULL;
Packit 284210
                        last_cached_tfn = 0;
Packit 284210
                        continue;
Packit 284210
                    }
Packit 284210
Packit 284210
                    if (action->param_plusminus == NEGATIVE_VALUE) {
Packit 284210
                        apr_table_unset(normtab, action->param);
Packit 284210
                    }
Packit 284210
                    else {
Packit 284210
                        tfnscount++;
Packit 284210
Packit 284210
                        apr_table_addn(normtab, action->param, (void *)action);
Packit 284210
Packit 284210
                        /* Check the cache, saving the 'most complete' as a
Packit 284210
                         * starting point
Packit 284210
                         */
Packit 284210
                        if (usecache) {
Packit 284210
                            tfnspath = apr_psprintf(mptmp, "%s%s%s", (tfnspath?tfnspath:""), (tfnspath?",":""), action->param);
Packit 284210
                            tfnskey = apr_psprintf(mptmp, "%x;%s", tfnscount, tfnspath);
Packit 284210
                            crec = (msre_cache_rec *)apr_table_get(cachetab, tfnskey);
Packit 284210
Packit 284210
                            #ifdef CACHE_DEBUG
Packit 284210
                            msr_log(msr, 9, "CACHE: %s %s cached=%d", var->name, tfnskey, (crec ? 1 : 0));
Packit 284210
                            #endif
Packit 284210
Packit 284210
                            if (crec != NULL) {
Packit 284210
                                last_crec = crec;
Packit 284210
                                last_cached_tfn = tfnscount;
Packit 284210
                            }
Packit 284210
                        }
Packit 284210
                    }
Packit 284210
                }
Packit 284210
            }
Packit 284210
Packit 284210
            /* If the last cached tfn is the last in the list
Packit 284210
             * then we can stop here and just execute the action immediatly
Packit 284210
             */
Packit 284210
            if (usecache && !multi_match &&
Packit 284210
                (crec != NULL) && (crec == last_crec))
Packit 284210
            {
Packit 284210
                crec->hits++;
Packit 284210
Packit 284210
                if (crec->changed) {
Packit 284210
                    var->value = apr_pmemdup(mptmp, crec->val, crec->val_len);
Packit 284210
                    var->value_len = crec->val_len;
Packit 284210
                }
Packit 284210
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "T (%d) %s: \"%s\" [fully cached hits=%d]", crec->changed, crec->path,
Packit 284210
                        log_escape_nq_ex(mptmp, var->value, var->value_len), crec->hits);
Packit 284210
                }
Packit 284210
Packit 284210
                #if defined(PERFORMANCE_MEASUREMENT) 
Packit 284210
                {
Packit 284210
                    apr_time_t t1 = apr_time_now();
Packit 284210
                    rule->trans_time += (t1 - time_before_trans);
Packit 284210
                }
Packit 284210
                #else
Packit 284210
                if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
                    apr_time_t t1 = apr_time_now();
Packit 284210
Packit 284210
                    msr_log(msr, 4, "Transformation completed in %" APR_TIME_T_FMT " usec.",
Packit 284210
                        (t1 - time_before_trans));
Packit 284210
                }
Packit 284210
                #endif
Packit 284210
Packit 284210
                rc = execute_operator(var, rule, msr, acting_actionset, mptmp);
Packit 284210
Packit 284210
                if (rc < 0) {
Packit 284210
                    return -1;
Packit 284210
                }
Packit 284210
Packit 284210
                if (rc == RULE_MATCH) {
Packit 284210
                    match_count++;
Packit 284210
Packit 284210
                    /* Return straight away if the transaction
Packit 284210
                     * was intercepted - no need to process the remaining
Packit 284210
                     * targets.
Packit 284210
                     */
Packit 284210
                    if (msr->rule_was_intercepted) {
Packit 284210
                        return RULE_MATCH;
Packit 284210
                    }
Packit 284210
                }
Packit 284210
Packit 284210
                continue; /* next target */
Packit 284210
            }
Packit 284210
Packit 284210
Packit 284210
            /* Perform transformations. */
Packit 284210
Packit 284210
            tarr = apr_table_elts(normtab);
Packit 284210
Packit 284210
            /* Execute transformations in a loop. */
Packit 284210
Packit 284210
            /* Start after the last known cached transformation if we can */
Packit 284210
            if (!multi_match && (last_crec != NULL)) {
Packit 284210
                k = last_cached_tfn;
Packit 284210
                tfnspath = last_crec->path;
Packit 284210
                last_crec->hits++;
Packit 284210
Packit 284210
                if ((changed = last_crec->changed) > 0) {
Packit 284210
                    var->value = last_crec->val;
Packit 284210
                    var->value_len = last_crec->val_len;
Packit 284210
                }
Packit 284210
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "T (%d) %s: \"%s\" [partially cached hits=%d]", last_crec->changed,
Packit 284210
                        tfnspath, log_escape_nq_ex(mptmp, var->value, var->value_len), last_crec->hits);
Packit 284210
                }
Packit 284210
            }
Packit 284210
            else {
Packit 284210
                tfnspath = NULL;
Packit 284210
                k = 0;
Packit 284210
            }
Packit 284210
Packit 284210
            /* Make a copy of the value so that we can change it in-place. */
Packit 284210
            if (tarr->nelts) {
Packit 284210
                var->value = apr_pstrmemdup(mptmp, var->value, var->value_len);
Packit 284210
                /* var->value_len remains the same */
Packit 284210
            }
Packit 284210
Packit 284210
            telts = (const apr_table_entry_t*)tarr->elts;
Packit 284210
            for (; k < tarr->nelts; k++) {
Packit 284210
                char *rval = NULL;
Packit 284210
                long int rval_length = -1;
Packit 284210
Packit 284210
                /* In multi-match mode we execute the operator
Packit 284210
                 * once at the beginning and then once every
Packit 284210
                 * time the variable is changed by the transformation
Packit 284210
                 * function.
Packit 284210
                 */
Packit 284210
                if (multi_match && (k == 0 || tfnchanged)) {
Packit 284210
                    invocations++;
Packit 284210
Packit 284210
                    #if defined(PERFORMANCE_MEASUREMENT)
Packit 284210
                    {
Packit 284210
                        apr_time_t t1 = apr_time_now();
Packit 284210
                        rule->trans_time += (t1 - time_before_trans);
Packit 284210
                    }
Packit 284210
                    #else
Packit 284210
                    if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
                        apr_time_t t1 = apr_time_now();
Packit 284210
Packit 284210
                        msr_log(msr, 4, "Transformation completed in %" APR_TIME_T_FMT " usec.",
Packit 284210
                            (t1 - time_before_trans));
Packit 284210
                    }
Packit 284210
                    #endif
Packit 284210
Packit 284210
                    rc = execute_operator(var, rule, msr, acting_actionset, mptmp);
Packit 284210
Packit 284210
                    if (rc < 0) {
Packit 284210
                        return -1;
Packit 284210
                    }
Packit 284210
Packit 284210
                    if (rc == RULE_MATCH) {
Packit 284210
                        match_count++;
Packit 284210
Packit 284210
                        /* Return straight away if the transaction
Packit 284210
                        * was intercepted - no need to process the remaining
Packit 284210
                        * targets.
Packit 284210
                        */
Packit 284210
                        if (msr->rule_was_intercepted) {
Packit 284210
                            return RULE_MATCH;
Packit 284210
                        }
Packit 284210
                    }
Packit 284210
                }
Packit 284210
Packit 284210
                /* Perform one transformation. */
Packit 284210
                action = (msre_action *)telts[k].val;
Packit 284210
                metadata = (msre_tfn_metadata *)action->param_data;
Packit 284210
                tfnchanged = metadata->execute(mptmp,
Packit 284210
                    (unsigned char *)var->value, var->value_len,
Packit 284210
                    &rval, &rval_length);
Packit 284210
Packit 284210
                if (tfnchanged < 0) {
Packit 284210
                    return -1;
Packit 284210
                }
Packit 284210
Packit 284210
                if (tfnchanged) {
Packit 284210
                    changed++;
Packit 284210
                }
Packit 284210
Packit 284210
                /* Use the new values */
Packit 284210
                var->value = rval;
Packit 284210
                var->value_len = rval_length;
Packit 284210
Packit 284210
                /* Cache the transformation */
Packit 284210
                if (usecache) {
Packit 284210
                    int tfnsnum = k + 1;
Packit 284210
Packit 284210
                    /* Generate the cache key */
Packit 284210
                    tfnspath = apr_psprintf(msr->mp, "%s%s%s", (tfnspath ? tfnspath : ""),
Packit 284210
                        (tfnspath ? "," : ""), action->param);
Packit 284210
                    tfnskey = apr_psprintf(msr->mp, "%x;%s", tfnsnum, tfnspath);
Packit 284210
Packit 284210
                    if ((msr->txcfg->cache_trans_maxitems != 0) &&
Packit 284210
                        (msr->tcache_items >= msr->txcfg->cache_trans_maxitems))
Packit 284210
                    {
Packit 284210
                        /* Warn only once if we attempt to go over the cache limit. */
Packit 284210
                        if (msr->tcache_items == msr->txcfg->cache_trans_maxitems) {
Packit 284210
                            msr->tcache_items++;
Packit 284210
                            msr_log(msr, 4, "CACHE: Disabled - phase=%d"
Packit 284210
                                            " maxitems=%" APR_SIZE_T_FMT
Packit 284210
                                            " limit reached.",
Packit 284210
                                            msr->phase,
Packit 284210
                                            msr->txcfg->cache_trans_maxitems);
Packit 284210
                        }
Packit 284210
                    }
Packit 284210
                    else if (msr->txcfg->cache_trans_incremental ||
Packit 284210
                        (tfnsnum == tarr->nelts))
Pac