Blame apache2/modsecurity.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 <stdlib.h>
Packit Service 384592
Packit Service 384592
#include "apr_global_mutex.h"
Packit Service 384592
Packit Service 384592
#include "modsecurity.h"
Packit Service 384592
#include "msc_parsers.h"
Packit Service 384592
#include "msc_util.h"
Packit Service 384592
#include "msc_json.h"
Packit Service 384592
#include "msc_xml.h"
Packit Service 384592
#include "apr_version.h"
Packit Service 384592
Packit Service 384592
#ifdef WITH_CURL
Packit Service 384592
#include <curl/curl.h>
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
unsigned long int DSOLOCAL unicode_codepage = 0;
Packit Service 384592
Packit Service 384592
int DSOLOCAL *unicode_map_table = NULL;
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Format an alert message.
Packit Service 384592
 */
Packit Service 384592
const char * msc_alert_message(modsec_rec *msr, msre_actionset *actionset, const char *action_message,
Packit Service 384592
    const char *rule_message)
Packit Service 384592
{
Packit Service 384592
    const char *message = NULL;
Packit Service 384592
Packit Service 384592
    if (rule_message == NULL) rule_message = "Unknown error.";
Packit Service 384592
Packit Service 384592
    if (action_message == NULL) {
Packit Service 384592
        message = apr_psprintf(msr->mp, "%s%s",
Packit Service 384592
            rule_message, msre_format_metadata(msr, actionset));
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        message = apr_psprintf(msr->mp, "%s %s%s", action_message,
Packit Service 384592
            rule_message, msre_format_metadata(msr, actionset));
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return message;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Log an alert message to the log, adding the rule metadata at the end.
Packit Service 384592
 */
Packit Service 384592
void msc_alert(modsec_rec *msr, int level, msre_actionset *actionset, const char *action_message,
Packit Service 384592
    const char *rule_message)
Packit Service 384592
{
Packit Service 384592
    const char *message = msc_alert_message(msr, actionset, action_message, rule_message);
Packit Service 384592
Packit Service 384592
    msr_log(msr, level, "%s", message);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
#if 0
Packit Service 384592
/**
Packit Service 384592
 * Return phase name associated with the given phase number.
Packit Service 384592
 */
Packit Service 384592
static const char *phase_name(int phase) {
Packit Service 384592
    switch(phase) {
Packit Service 384592
        case 1 :
Packit Service 384592
            return "REQUEST_HEADERS";
Packit Service 384592
            break;
Packit Service 384592
        case 2 :
Packit Service 384592
            return "REQUEST_BODY";
Packit Service 384592
            break;
Packit Service 384592
        case 3 :
Packit Service 384592
            return "RESPONSE_HEADERS";
Packit Service 384592
            break;
Packit Service 384592
        case 4 :
Packit Service 384592
            return "RESPONSE_BODY";
Packit Service 384592
            break;
Packit Service 384592
        case 5 :
Packit Service 384592
            return "LOGGING";
Packit Service 384592
            break;
Packit Service 384592
    }
Packit Service 384592
    
Packit Service 384592
    return "INVALID";
Packit Service 384592
}
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Creates and initialises a ModSecurity engine instance.
Packit Service 384592
 */
Packit Service 384592
msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) {
Packit Service 384592
    msc_engine *msce = NULL;
Packit Service 384592
Packit Service 384592
    msce = apr_pcalloc(mp, sizeof(msc_engine));
Packit Service 384592
    if (msce == NULL) return NULL;
Packit Service 384592
Packit Service 384592
    msce->mp = mp;
Packit Service 384592
    msce->processing_mode = processing_mode;
Packit Service 384592
Packit Service 384592
    msce->msre = msre_engine_create(msce->mp);
Packit Service 384592
    if (msce->msre == NULL) return NULL;
Packit Service 384592
    msre_engine_register_default_variables(msce->msre);
Packit Service 384592
    msre_engine_register_default_operators(msce->msre);
Packit Service 384592
    msre_engine_register_default_tfns(msce->msre);
Packit Service 384592
    msre_engine_register_default_actions(msce->msre);
Packit Service 384592
    // TODO: msre_engine_register_default_reqbody_processors(msce->msre);
Packit Service 384592
Packit Service 384592
    return msce;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Initialise the modsecurity engine. This function must be invoked
Packit Service 384592
 * after configuration processing is complete as Apache needs to know the
Packit Service 384592
 * username it is running as.
Packit Service 384592
 */
Packit Service 384592
int modsecurity_init(msc_engine *msce, apr_pool_t *mp) {
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
Packit Service 384592
    /**
Packit Service 384592
     * Notice that curl is initialized here but never cleaned up. First version
Packit Service 384592
     * of this implementation curl was initialized and cleaned for every
Packit Service 384592
     * utilization. Turns out that it was not only cleaning stuff that was
Packit Service 384592
     * utilized by Curl but also other OpenSSL stuff that was utilized by
Packit Service 384592
     * mod_ssl leading the SSL support to crash.
Packit Service 384592
     */
Packit Service 384592
#ifdef WITH_CURL
Packit Service 384592
    curl_global_init(CURL_GLOBAL_ALL);
Packit Service 384592
#endif
Packit Service 384592
    /* Serial audit log mutext */
Packit Service 384592
    rc = apr_global_mutex_create(&msce->auditlog_lock, NULL, APR_LOCK_DEFAULT, mp);
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        //ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "mod_security: Could not create modsec_auditlog_lock");
Packit Service 384592
        //return HTTP_INTERNAL_SERVER_ERROR;
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
#if !defined(MSC_TEST)
Packit Service 384592
#ifdef __SET_MUTEX_PERMS
Packit Service 384592
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
Packit Service 384592
    rc = ap_unixd_set_global_mutex_perms(msce->auditlog_lock);
Packit Service 384592
#else
Packit Service 384592
    rc = unixd_set_global_mutex_perms(msce->auditlog_lock);
Packit Service 384592
#endif
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        // ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, "mod_security: Could not set permissions on modsec_auditlog_lock; check User and Group directives");
Packit Service 384592
        // return HTTP_INTERNAL_SERVER_ERROR;
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
#endif /* SET_MUTEX_PERMS */
Packit Service 384592
Packit Service 384592
    rc = apr_global_mutex_create(&msce->geo_lock, NULL, APR_LOCK_DEFAULT, mp);
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
#ifdef __SET_MUTEX_PERMS
Packit Service 384592
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
Packit Service 384592
    rc = ap_unixd_set_global_mutex_perms(msce->geo_lock);
Packit Service 384592
#else
Packit Service 384592
    rc = unixd_set_global_mutex_perms(msce->geo_lock);
Packit Service 384592
#endif
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
#endif /* SET_MUTEX_PERMS */
Packit Service 384592
Packit Service 384592
#ifdef GLOBAL_COLLECTION_LOCK
Packit Service 384592
    rc = apr_global_mutex_create(&msce->dbm_lock, NULL, APR_LOCK_DEFAULT, mp);
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
#ifdef __SET_MUTEX_PERMS
Packit Service 384592
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
Packit Service 384592
    rc = ap_unixd_set_global_mutex_perms(msce->dbm_lock);
Packit Service 384592
#else
Packit Service 384592
    rc = unixd_set_global_mutex_perms(msce->dbm_lock);
Packit Service 384592
#endif
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
#endif /* SET_MUTEX_PERMS */
Packit Service 384592
#endif
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Performs per-child (new process) initialisation.
Packit Service 384592
 */
Packit Service 384592
void modsecurity_child_init(msc_engine *msce) {
Packit Service 384592
    /* Need to call this once per process before any other XML calls. */
Packit Service 384592
    xmlInitParser();
Packit Service 384592
Packit Service 384592
    if (msce->auditlog_lock != NULL) {
Packit Service 384592
        apr_status_t rc = apr_global_mutex_child_init(&msce->auditlog_lock, NULL, msce->mp);
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            // ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, "Failed to child-init auditlog mutex");
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (msce->geo_lock != NULL) {
Packit Service 384592
        apr_status_t rc = apr_global_mutex_child_init(&msce->geo_lock, NULL, msce->mp);
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            // ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, "Failed to child-init geo mutex");
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
#ifdef GLOBAL_COLLECTION_LOCK
Packit Service 384592
    if (msce->dbm_lock != NULL) {
Packit Service 384592
        apr_status_t rc = apr_global_mutex_child_init(&msce->dbm_lock, NULL, msce->mp);
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            // ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, "Failed to child-init dbm mutex");
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Releases resources held by engine instance.
Packit Service 384592
 */
Packit Service 384592
void modsecurity_shutdown(msc_engine *msce) {
Packit Service 384592
    if (msce == NULL) return;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static void modsecurity_persist_data(modsec_rec *msr) {
Packit Service 384592
    const apr_array_header_t *arr;
Packit Service 384592
    apr_table_entry_t *te;
Packit Service 384592
    apr_time_t time_before, time_after;
Packit Service 384592
    int i;
Packit Service 384592
Packit Service 384592
    time_before = apr_time_now();
Packit Service 384592
Packit Service 384592
    /* Collections, store & remove stale. */
Packit Service 384592
    arr = apr_table_elts(msr->collections);
Packit Service 384592
    te = (apr_table_entry_t *)arr->elts;
Packit Service 384592
    for (i = 0; i < arr->nelts; i++) {
Packit Service 384592
        apr_table_t *col = (apr_table_t *)te[i].val;
Packit Service 384592
Packit Service 384592
        /* Only store those collections that changed. */
Packit Service 384592
        if (apr_table_get(msr->collections_dirty, te[i].key)) {
Packit Service 384592
            collection_store(msr, col);
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    time_after = apr_time_now();
Packit Service 384592
Packit Service 384592
    msr->time_storage_write += time_after - time_before;
Packit Service 384592
Packit Service 384592
    if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
        msr_log(msr, 4, "Recording persistent data took %" APR_TIME_T_FMT
Packit Service 384592
            " microseconds.", msr->time_gc);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Remove stale collections. */
Packit Service 384592
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 3
Packit Service 384592
    if (ap_random_pick(0, RAND_MAX) < RAND_MAX/100) {
Packit Service 384592
#else
Packit Service 384592
    if (rand() < RAND_MAX/100) {
Packit Service 384592
#endif
Packit Service 384592
        arr = apr_table_elts(msr->collections);
Packit Service 384592
        te = (apr_table_entry_t *)arr->elts;
Packit Service 384592
        for (i = 0; i < arr->nelts; i++) {
Packit Service 384592
            collections_remove_stale(msr, te[i].key);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        msr->time_gc = apr_time_now() - time_after;
Packit Service 384592
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
            msr_log(msr, 4, "Garbage collection took %" APR_TIME_T_FMT
Packit Service 384592
                " microseconds.", msr->time_gc);
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static apr_status_t modsecurity_tx_cleanup(void *data) {
Packit Service 384592
    modsec_rec *msr = (modsec_rec *)data;
Packit Service 384592
    char *my_error_msg = NULL;
Packit Service 384592
    
Packit Service 384592
    if (msr == NULL) return APR_SUCCESS;    
Packit Service 384592
Packit Service 384592
    /* Multipart processor cleanup. */
Packit Service 384592
    if (msr->mpd != NULL) multipart_cleanup(msr);
Packit Service 384592
Packit Service 384592
    /* XML processor cleanup. */
Packit Service 384592
    if (msr->xml != NULL) xml_cleanup(msr);
Packit Service 384592
Packit Service 384592
#ifdef WITH_YAJL
Packit Service 384592
    /* JSON processor cleanup. */
Packit Service 384592
    if (msr->json != NULL) json_cleanup(msr);
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
    // TODO: Why do we ignore return code here?
Packit Service 384592
    modsecurity_request_body_clear(msr, &my_error_msg);
Packit Service 384592
    if (my_error_msg != NULL) {
Packit Service 384592
        msr_log(msr, 1, "%s", my_error_msg);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (msr->msc_full_request_length > 0 &&
Packit Service 384592
            msr->msc_full_request_buffer != NULL) {
Packit Service 384592
        msr->msc_full_request_length = 0;
Packit Service 384592
        free(msr->msc_full_request_buffer);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
#if defined(WITH_LUA)
Packit Service 384592
    #ifdef CACHE_LUA
Packit Service 384592
    if(msr->L != NULL)  lua_close(msr->L);
Packit Service 384592
    #endif
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
    return APR_SUCCESS;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
apr_status_t modsecurity_tx_init(modsec_rec *msr) {
Packit Service 384592
    const char *s = NULL;
Packit Service 384592
    const apr_array_header_t *arr;
Packit Service 384592
    char *semicolon = NULL;
Packit Service 384592
    char *comma = NULL;
Packit Service 384592
    apr_table_entry_t *te;
Packit Service 384592
    int i;
Packit Service 384592
Packit Service 384592
    /* Register TX cleanup */
Packit Service 384592
    apr_pool_cleanup_register(msr->mp, msr, modsecurity_tx_cleanup, apr_pool_cleanup_null);
Packit Service 384592
Packit Service 384592
    /* Initialise C-L */
Packit Service 384592
    msr->request_content_length = -1;
Packit Service 384592
    s = apr_table_get(msr->request_headers, "Content-Length");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        msr->request_content_length = strtol(s, NULL, 10);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Figure out whether this request has a body */
Packit Service 384592
    msr->reqbody_chunked = 0;
Packit Service 384592
    msr->reqbody_should_exist = 0;
Packit Service 384592
    if (msr->request_content_length == -1) {
Packit Service 384592
        /* There's no C-L, but is chunked encoding used? */
Packit Service 384592
        char *transfer_encoding = (char *)apr_table_get(msr->request_headers, "Transfer-Encoding");
Packit Service 384592
        if ((transfer_encoding != NULL)&&(m_strcasestr(transfer_encoding, "chunked") != NULL)) {
Packit Service 384592
            msr->reqbody_should_exist = 1;
Packit Service 384592
            msr->reqbody_chunked = 1;
Packit Service 384592
        }
Packit Service 384592
    } else {
Packit Service 384592
        /* C-L found */
Packit Service 384592
        msr->reqbody_should_exist = 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Initialise C-T */
Packit Service 384592
    msr->request_content_type = NULL;
Packit Service 384592
    s = apr_table_get(msr->request_headers, "Content-Type");
Packit Service 384592
    if (s != NULL) msr->request_content_type = s;
Packit Service 384592
Packit Service 384592
    /* Decide what to do with the request body. */
Packit Service 384592
    if ((msr->request_content_type != NULL)
Packit Service 384592
       && (strncasecmp(msr->request_content_type, "application/x-www-form-urlencoded", 33) == 0))
Packit Service 384592
    {
Packit Service 384592
        /* Always place POST requests with
Packit Service 384592
         * "application/x-www-form-urlencoded" payloads in memory.
Packit Service 384592
         */
Packit Service 384592
        msr->msc_reqbody_storage = MSC_REQBODY_MEMORY;
Packit Service 384592
        msr->msc_reqbody_spilltodisk = 0;
Packit Service 384592
        msr->msc_reqbody_processor = "URLENCODED";
Packit Service 384592
    } else {
Packit Service 384592
        /* If the C-L is known and there's more data than
Packit Service 384592
         * our limit go to disk straight away.
Packit Service 384592
         */
Packit Service 384592
        if ((msr->request_content_length != -1)
Packit Service 384592
           && (msr->request_content_length > msr->txcfg->reqbody_inmemory_limit))
Packit Service 384592
        {
Packit Service 384592
            msr->msc_reqbody_storage = MSC_REQBODY_DISK;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* In all other cases, try using the memory first
Packit Service 384592
         * but switch over to disk for larger bodies.
Packit Service 384592
         */
Packit Service 384592
        msr->msc_reqbody_storage = MSC_REQBODY_MEMORY;
Packit Service 384592
        msr->msc_reqbody_spilltodisk = 1;
Packit Service 384592
Packit Service 384592
        if (msr->request_content_type != NULL) {
Packit Service 384592
            if (strncasecmp(msr->request_content_type, "multipart/form-data", 19) == 0) {
Packit Service 384592
                msr->msc_reqbody_processor = "MULTIPART";
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Check if we are forcing buffering, then use memory only. */
Packit Service 384592
    if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) {
Packit Service 384592
        msr->msc_reqbody_storage = MSC_REQBODY_MEMORY;
Packit Service 384592
        msr->msc_reqbody_spilltodisk = 0;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Initialise arguments */
Packit Service 384592
    msr->arguments = apr_table_make(msr->mp, 32);
Packit Service 384592
    if (msr->arguments == NULL) return -1;
Packit Service 384592
    if (msr->query_string != NULL) {
Packit Service 384592
        int invalid_count = 0;
Packit Service 384592
Packit Service 384592
        if (parse_arguments(msr, msr->query_string, strlen(msr->query_string),
Packit Service 384592
            msr->txcfg->argument_separator, "QUERY_STRING", msr->arguments,
Packit Service 384592
            &invalid_count) < 0)
Packit Service 384592
        {
Packit Service 384592
            msr_log(msr, 1, "Initialisation: Error occurred while parsing QUERY_STRING arguments.");
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (invalid_count) {
Packit Service 384592
            msr->urlencoded_error = 1;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    msr->arguments_to_sanitize = apr_table_make(msr->mp, 16);
Packit Service 384592
    if (msr->arguments_to_sanitize == NULL) return -1;
Packit Service 384592
    msr->request_headers_to_sanitize = apr_table_make(msr->mp, 16);
Packit Service 384592
    if (msr->request_headers_to_sanitize == NULL) return -1;
Packit Service 384592
    msr->response_headers_to_sanitize = apr_table_make(msr->mp, 16);
Packit Service 384592
    if (msr->response_headers_to_sanitize == NULL) return -1;
Packit Service 384592
    msr->pattern_to_sanitize = apr_table_make(msr->mp, 32);
Packit Service 384592
    if (msr->pattern_to_sanitize == NULL) return -1;
Packit Service 384592
Packit Service 384592
    /* remove targets */
Packit Service 384592
    msr->removed_targets = apr_table_make(msr->mp, 16);
Packit Service 384592
    if (msr->removed_targets == NULL) return -1;
Packit Service 384592
Packit Service 384592
    /* Initialise cookies */
Packit Service 384592
    msr->request_cookies = apr_table_make(msr->mp, 16);
Packit Service 384592
    if (msr->request_cookies == NULL) return -1;
Packit Service 384592
Packit Service 384592
    /* Initialize matched vars */
Packit Service 384592
    msr->matched_vars = apr_table_make(msr->mp, 8);
Packit Service 384592
    if (msr->matched_vars == NULL) return -1;
Packit Service 384592
    apr_table_clear(msr->matched_vars);
Packit Service 384592
Packit Service 384592
    msr->perf_rules = apr_table_make(msr->mp, 8);
Packit Service 384592
    if (msr->perf_rules == NULL) return -1;
Packit Service 384592
    apr_table_clear(msr->perf_rules);
Packit Service 384592
Packit Service 384592
    /* Locate the cookie headers and parse them */
Packit Service 384592
    arr = apr_table_elts(msr->request_headers);
Packit Service 384592
    te = (apr_table_entry_t *)arr->elts;
Packit Service 384592
    for (i = 0; i < arr->nelts; i++) {
Packit Service 384592
        if (strcasecmp(te[i].key, "Cookie") == 0) {
Packit Service 384592
            if (msr->txcfg->cookie_format == COOKIES_V0) {
Packit Service 384592
                semicolon = apr_pstrdup(msr->mp, te[i].val);
Packit Service 384592
                while((*semicolon != 0)&&(*semicolon != ';')) semicolon++;
Packit Service 384592
                if(*semicolon == ';')    {
Packit Service 384592
                    parse_cookies_v0(msr, te[i].val, msr->request_cookies, ";");
Packit Service 384592
                } else  {
Packit Service 384592
                    comma = apr_pstrdup(msr->mp, te[i].val);
Packit Service 384592
                    while((*comma != 0)&&(*comma != ',')) comma++;
Packit Service 384592
                    if(*comma == ',')    {
Packit Service 384592
                        comma++;
Packit Service 384592
                        if(*comma == 0x20)   {// looks like comma is the separator
Packit Service 384592
                            if (msr->txcfg->debuglog_level >= 5) {
Packit Service 384592
                                msr_log(msr, 5, "Cookie v0 parser: Using comma as a separator. Semi-colon was not identified!");
Packit Service 384592
                            }
Packit Service 384592
                            parse_cookies_v0(msr, te[i].val, msr->request_cookies, ",");
Packit Service 384592
                        } else {
Packit Service 384592
                            parse_cookies_v0(msr, te[i].val, msr->request_cookies, ";");
Packit Service 384592
                        }
Packit Service 384592
                    } else  {
Packit Service 384592
                        parse_cookies_v0(msr, te[i].val, msr->request_cookies, ";");
Packit Service 384592
                    }
Packit Service 384592
                }
Packit Service 384592
            } else {
Packit Service 384592
                parse_cookies_v1(msr, te[i].val, msr->request_cookies);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Collections. */
Packit Service 384592
    msr->tx_vars = apr_table_make(msr->mp, 32);
Packit Service 384592
    if (msr->tx_vars == NULL) return -1;
Packit Service 384592
Packit Service 384592
    msr->geo_vars = apr_table_make(msr->mp, 8);
Packit Service 384592
    if (msr->geo_vars == NULL) return -1;
Packit Service 384592
Packit Service 384592
    msr->collections_original = apr_table_make(msr->mp, 8);
Packit Service 384592
    if (msr->collections_original == NULL) return -1;
Packit Service 384592
    msr->collections = apr_table_make(msr->mp, 8);
Packit Service 384592
    if (msr->collections == NULL) return -1;
Packit Service 384592
    msr->collections_dirty = apr_table_make(msr->mp, 8);
Packit Service 384592
    if (msr->collections_dirty == NULL) return -1;
Packit Service 384592
Packit Service 384592
    /* Other */
Packit Service 384592
    msr->tcache = NULL;
Packit Service 384592
    msr->tcache_items = 0;
Packit Service 384592
Packit Service 384592
    msr->matched_rules = apr_array_make(msr->mp, 16, sizeof(void *));
Packit Service 384592
    if (msr->matched_rules == NULL) return -1;
Packit Service 384592
Packit Service 384592
    msr->matched_var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
Packit Service 384592
    if (msr->matched_var == NULL) return -1;
Packit Service 384592
Packit Service 384592
    msr->highest_severity = 255; /* high, invalid value */
Packit Service 384592
Packit Service 384592
    msr->removed_rules = apr_array_make(msr->mp, 16, sizeof(char *));
Packit Service 384592
    if (msr->removed_rules == NULL) return -1;
Packit Service 384592
Packit Service 384592
    msr->removed_rules_tag = apr_array_make(msr->mp, 16, sizeof(char *));
Packit Service 384592
    if (msr->removed_rules_tag == NULL) return -1;
Packit Service 384592
Packit Service 384592
    msr->removed_rules_msg = apr_array_make(msr->mp, 16, sizeof(char *));
Packit Service 384592
    if (msr->removed_rules_msg == NULL) return -1;
Packit Service 384592
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static int is_response_status_relevant(modsec_rec *msr, int status) {
Packit Service 384592
    char *my_error_msg = NULL;
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
    char buf[32];
Packit Service 384592
Packit Service 384592
    /* ENH: Setting is_relevant here will cause an audit even if noauditlog
Packit Service 384592
     * was set for the last rule that matched.  Is this what we want?
Packit Service 384592
     */
Packit Service 384592
Packit Service 384592
    if ((msr->txcfg->auditlog_relevant_regex == NULL)
Packit Service 384592
        ||(msr->txcfg->auditlog_relevant_regex == NOT_SET_P))
Packit Service 384592
    {
Packit Service 384592
        return 0;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    apr_snprintf(buf, sizeof(buf), "%d", status);
Packit Service 384592
Packit Service 384592
    rc = msc_regexec(msr->txcfg->auditlog_relevant_regex, buf, strlen(buf), &my_error_msg);
Packit Service 384592
    if (rc >= 0) return 1;
Packit Service 384592
    if (rc == PCRE_ERROR_NOMATCH) return 0;
Packit Service 384592
Packit Service 384592
    msr_log(msr, 1, "Regex processing failed (rc %d): %s", rc, my_error_msg);
Packit Service 384592
    
Packit Service 384592
    return 0;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static apr_status_t modsecurity_process_phase_request_headers(modsec_rec *msr) {
Packit Service 384592
    apr_time_t time_before;
Packit Service 384592
    apr_status_t rc = 0;
Packit Service 384592
    
Packit Service 384592
    if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
        msr_log(msr, 4, "Starting phase REQUEST_HEADERS.");
Packit Service 384592
    }
Packit Service 384592
    
Packit Service 384592
    time_before = apr_time_now();
Packit Service 384592
Packit Service 384592
    if (msr->txcfg->ruleset != NULL) {
Packit Service 384592
        rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
Packit Service 384592
    }
Packit Service 384592
    
Packit Service 384592
    msr->time_phase1 = apr_time_now() - time_before;
Packit Service 384592
Packit Service 384592
    return rc;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static apr_status_t modsecurity_process_phase_request_body(modsec_rec *msr) {
Packit Service 384592
    apr_time_t time_before;
Packit Service 384592
    apr_status_t rc = 0;
Packit Service 384592
Packit Service 384592
Packit Service 384592
    if ((msr->allow_scope == ACTION_ALLOW_REQUEST)||(msr->allow_scope == ACTION_ALLOW)) {
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
            msr_log(msr, 4, "Skipping phase REQUEST_BODY (allow used).");
Packit Service 384592
        }
Packit Service 384592
        
Packit Service 384592
        return 0;
Packit Service 384592
    } else {
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
            msr_log(msr, 4, "Starting phase REQUEST_BODY.");
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    
Packit Service 384592
    time_before = apr_time_now();
Packit Service 384592
Packit Service 384592
    if (msr->txcfg->ruleset != NULL) {
Packit Service 384592
        rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
Packit Service 384592
    }
Packit Service 384592
    
Packit Service 384592
    msr->time_phase2 = apr_time_now() - time_before;
Packit Service 384592
Packit Service 384592
    return rc;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static apr_status_t modsecurity_process_phase_response_headers(modsec_rec *msr) {
Packit Service 384592
    apr_time_t time_before;
Packit Service 384592
    apr_status_t rc = 0;
Packit Service 384592
    
Packit Service 384592
    if (msr->allow_scope == ACTION_ALLOW) {
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
            msr_log(msr, 4, "Skipping phase RESPONSE_HEADERS (allow used).");
Packit Service 384592
        }
Packit Service 384592
        
Packit Service 384592
        return 0;
Packit Service 384592
    } else {
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
            msr_log(msr, 4, "Starting phase RESPONSE_HEADERS.");
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    
Packit Service 384592
    time_before = apr_time_now();
Packit Service 384592
Packit Service 384592
    if (msr->txcfg->ruleset != NULL) {
Packit Service 384592
        rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
Packit Service 384592
    }
Packit Service 384592
    
Packit Service 384592
    msr->time_phase3 = apr_time_now() - time_before;
Packit Service 384592
Packit Service 384592
    return rc;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static apr_status_t modsecurity_process_phase_response_body(modsec_rec *msr) {
Packit Service 384592
    apr_time_t time_before;
Packit Service 384592
    apr_status_t rc = 0;
Packit Service 384592
    
Packit Service 384592
    if (msr->allow_scope == ACTION_ALLOW) {
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
            msr_log(msr, 4, "Skipping phase RESPONSE_BODY (allow used).");
Packit Service 384592
        }
Packit Service 384592
        
Packit Service 384592
        return 0;
Packit Service 384592
    } else {
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
            msr_log(msr, 4, "Starting phase RESPONSE_BODY.");
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    
Packit Service 384592
    time_before = apr_time_now();
Packit Service 384592
Packit Service 384592
    if (msr->txcfg->ruleset != NULL) {
Packit Service 384592
        rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
Packit Service 384592
    }
Packit Service 384592
    
Packit Service 384592
    msr->time_phase4 = apr_time_now() - time_before;
Packit Service 384592
Packit Service 384592
Packit Service 384592
    return rc;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) {
Packit Service 384592
    apr_time_t time_before, time_after;
Packit Service 384592
Packit Service 384592
    if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
        msr_log(msr, 4, "Starting phase LOGGING.");
Packit Service 384592
    }
Packit Service 384592
    
Packit Service 384592
    time_before = apr_time_now();
Packit Service 384592
Packit Service 384592
    if (msr->txcfg->ruleset != NULL) {
Packit Service 384592
        msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
Packit Service 384592
    }
Packit Service 384592
    
Packit Service 384592
    modsecurity_persist_data(msr);
Packit Service 384592
    
Packit Service 384592
    time_after = apr_time_now();
Packit Service 384592
    msr->time_phase5 = time_after - time_before;
Packit Service 384592
Packit Service 384592
    /* Is this request relevant for logging purposes? */
Packit Service 384592
    if (msr->is_relevant == 0) {
Packit Service 384592
        /* Check the status */
Packit Service 384592
        msr->is_relevant += is_response_status_relevant(msr, msr->r->status);
Packit Service 384592
Packit Service 384592
        /* If we processed two requests and statuses are different then
Packit Service 384592
         * check the other status too.
Packit Service 384592
         */
Packit Service 384592
        if (msr->r_early->status != msr->r->status) {
Packit Service 384592
            msr->is_relevant += is_response_status_relevant(msr, msr->r_early->status);
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Figure out if we want to keep the files (if there are any, of course). */
Packit Service 384592
    if ((msr->txcfg->upload_keep_files == KEEP_FILES_ON)
Packit Service 384592
        || ((msr->txcfg->upload_keep_files == KEEP_FILES_RELEVANT_ONLY)&&(msr->is_relevant)))
Packit Service 384592
    {
Packit Service 384592
        msr->upload_remove_files = 0;
Packit Service 384592
    } else {
Packit Service 384592
        msr->upload_remove_files = 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Are we configured for audit logging? */
Packit Service 384592
    switch(msr->txcfg->auditlog_flag) {
Packit Service 384592
        case AUDITLOG_OFF :
Packit Service 384592
            if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
                msr_log(msr, 4, "Audit log: Not configured to run for this request.");
Packit Service 384592
            }
Packit Service 384592
            
Packit Service 384592
            return DECLINED;
Packit Service 384592
            break;
Packit Service 384592
Packit Service 384592
        case AUDITLOG_RELEVANT :
Packit Service 384592
            if (msr->is_relevant == 0) {
Packit Service 384592
                if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
                    msr_log(msr, 4, "Audit log: Ignoring a non-relevant request.");
Packit Service 384592
                }
Packit Service 384592
                
Packit Service 384592
                return DECLINED;
Packit Service 384592
            }
Packit Service 384592
            break;
Packit Service 384592
Packit Service 384592
        case AUDITLOG_ON :
Packit Service 384592
            /* All right, do nothing */
Packit Service 384592
            break;
Packit Service 384592
Packit Service 384592
        default :
Packit Service 384592
            msr_log(msr, 1, "Internal error: Could not determine if auditing is needed, so forcing auditing.");
Packit Service 384592
            break;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Invoke the Audit logger */
Packit Service 384592
    if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
        msr_log(msr, 4, "Audit log: Logging this transaction.");
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    sec_audit_logger(msr);
Packit Service 384592
    
Packit Service 384592
    msr->time_logging = apr_time_now() - time_after;    
Packit Service 384592
Packit Service 384592
    return 0;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Processes one transaction phase. The phase number does not
Packit Service 384592
 * need to be explicitly provided since it's already available
Packit Service 384592
 * in the modsec_rec structure.
Packit Service 384592
 */
Packit Service 384592
apr_status_t modsecurity_process_phase(modsec_rec *msr, unsigned int phase) {
Packit Service 384592
    /* Check if we should run. */
Packit Service 384592
    if ((msr->was_intercepted)&&(phase != PHASE_LOGGING)) {
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
            msr_log(msr, 4, "Skipping phase %d as request was already intercepted.", phase);
Packit Service 384592
        }
Packit Service 384592
        
Packit Service 384592
        return 0;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Do not process the same phase twice. */
Packit Service 384592
    if (msr->phase >= phase) {
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 4) {
Packit Service 384592
            msr_log(msr, 4, "Skipping phase %d because it was previously run (at %d now).",
Packit Service 384592
                phase, msr->phase);
Packit Service 384592
        }
Packit Service 384592
        
Packit Service 384592
        return 0;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    msr->phase = phase;
Packit Service 384592
Packit Service 384592
    /* Clear out the transformation cache at the start of each phase */
Packit Service 384592
    if (msr->txcfg->cache_trans == MODSEC_CACHE_ENABLED) {
Packit Service 384592
        if (msr->tcache) {
Packit Service 384592
            apr_hash_index_t *hi;
Packit Service 384592
            void *dummy;
Packit Service 384592
            apr_table_t *tab;
Packit Service 384592
            const void *key;
Packit Service 384592
            apr_ssize_t klen;
Packit Service 384592
            #ifdef CACHE_DEBUG
Packit Service 384592
            apr_pool_t *mp = msr->msc_rule_mptmp;
Packit Service 384592
            const apr_array_header_t *ctarr;
Packit Service 384592
            const apr_table_entry_t *ctelts;
Packit Service 384592
            msre_cache_rec *rec;
Packit Service 384592
            int cn = 0;
Packit Service 384592
            int ri;
Packit Service 384592
            #else
Packit Service 384592
            apr_pool_t *mp = msr->mp;
Packit Service 384592
            #endif
Packit Service 384592
Packit Service 384592
            for (hi = apr_hash_first(mp, msr->tcache); hi; hi = apr_hash_next(hi)) {
Packit Service 384592
                apr_hash_this(hi, &key, &klen, &dummy);
Packit Service 384592
                tab = (apr_table_t *)dummy;
Packit Service 384592
Packit Service 384592
                if (tab == NULL) continue;
Packit Service 384592
Packit Service 384592
                #ifdef CACHE_DEBUG
Packit Service 384592
                /* Dump the cache out as we clear */
Packit Service 384592
                ctarr = apr_table_elts(tab);
Packit Service 384592
                ctelts = (const apr_table_entry_t*)ctarr->elts;
Packit Service 384592
                for (ri = 0; ri < ctarr->nelts; ri++) {
Packit Service 384592
                    cn++;
Packit Service 384592
                    rec = (msre_cache_rec *)ctelts[ri].val;
Packit Service 384592
                    if (rec->changed) {
Packit Service 384592
                        if (msr->txcfg->debuglog_level >= 9) {
Packit Service 384592
                            msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=\"%s\" (%pp - %pp)",
Packit Service 384592
                                cn, rec->hits, key, rec->num, rec->path, log_escape_nq_ex(mp, rec->val, rec->val_len),
Packit Service 384592
                                rec->val, rec->val + rec->val_len);
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
                    else {
Packit Service 384592
                        if (msr->txcfg->debuglog_level >= 9) {
Packit Service 384592
                            msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=<no change>",
Packit Service 384592
                                cn, rec->hits, key, rec->num, rec->path);
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
                }
Packit Service 384592
                #endif
Packit Service 384592
Packit Service 384592
                apr_table_clear(tab);
Packit Service 384592
                apr_hash_set(msr->tcache, key, klen, NULL);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            if (msr->txcfg->debuglog_level >= 9) {
Packit Service 384592
                msr_log(msr, 9, "Cleared transformation cache for phase %d", msr->phase);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        msr->tcache_items = 0;
Packit Service 384592
        msr->tcache = apr_hash_make(msr->mp);
Packit Service 384592
        if (msr->tcache == NULL) return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    switch(phase) {
Packit Service 384592
        case 1 :
Packit Service 384592
            return modsecurity_process_phase_request_headers(msr);
Packit Service 384592
        case 2 :
Packit Service 384592
            return modsecurity_process_phase_request_body(msr);
Packit Service 384592
        case 3 :
Packit Service 384592
            return modsecurity_process_phase_response_headers(msr);
Packit Service 384592
        case 4 :
Packit Service 384592
            return modsecurity_process_phase_response_body(msr);
Packit Service 384592
        case 5 :
Packit Service 384592
            return modsecurity_process_phase_logging(msr);
Packit Service 384592
        default :
Packit Service 384592
            msr_log(msr, 1, "Invalid processing phase: %d", msr->phase);
Packit Service 384592
            break;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return -1;
Packit Service 384592
}