Blame apache2/re.c

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