Blame apache2/msc_logging.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 "modsecurity.h"
Packit Service 384592
#include <sys/stat.h>
Packit Service 384592
Packit Service 384592
#include "re.h"
Packit Service 384592
#include "msc_logging.h"
Packit Service 384592
#include "httpd.h"
Packit Service 384592
#include "apr_strings.h"
Packit Service 384592
#include "apr_global_mutex.h"
Packit Service 384592
#include "msc_util.h"
Packit Service 384592
Packit Service 384592
#include "apr_version.h"
Packit Service 384592
#include <libxml/xmlversion.h>
Packit Service 384592
Packit Service 384592
#ifdef WITH_YAJL
Packit Service 384592
#include <yajl/yajl_gen.h>
Packit Service 384592
#include "msc_logging_json.h"
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Write the supplied data to the audit log (if the FD is ready), update
Packit Service 384592
 * the size counters, update the hash context.
Packit Service 384592
 */
Packit Service 384592
static int sec_auditlog_write(modsec_rec *msr, const char *data, unsigned int len) {
Packit Service 384592
    apr_size_t nbytes_written, nbytes = len;
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
Packit Service 384592
    /* Do nothing if there's no data. */
Packit Service 384592
    if (data == NULL) return -1;
Packit Service 384592
Packit Service 384592
    /* Update size counters and the hash calculation. We always do this,
Packit Service 384592
     * even in cases where write fails. That will make it easier to detect
Packit Service 384592
     * problems with partial writes.
Packit Service 384592
     */
Packit Service 384592
    msr->new_auditlog_size += len;
Packit Service 384592
    apr_md5_update(&msr->new_auditlog_md5ctx, data, len);
Packit Service 384592
Packit Service 384592
    /* Do not write if we do not have a file descriptor. */
Packit Service 384592
    if (msr->new_auditlog_fd == NULL) return -1;
Packit Service 384592
Packit Service 384592
    /* Write data to file. */
Packit Service 384592
    rc = apr_file_write_full(msr->new_auditlog_fd, data, nbytes, &nbytes_written);
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        char errstr[1024];
Packit Service 384592
Packit Service 384592
        msr_log(msr, 1, "Audit log: Failed writing (requested %" APR_SIZE_T_FMT
Packit Service 384592
            " bytes, written %" APR_SIZE_T_FMT "): %s", nbytes, nbytes_written,
Packit Service 384592
            apr_strerror(rc, errstr, sizeof(errstr)));
Packit Service 384592
Packit Service 384592
        /* Concurrent log format: don't leak file handle. */
Packit Service 384592
        if (msr->txcfg->auditlog_type == AUDITLOG_CONCURRENT) {
Packit Service 384592
            apr_file_close(msr->new_auditlog_fd);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Set to NULL to prevent more than one error message on
Packit Service 384592
         * out-of-disk-space events and to prevent further attempts
Packit Service 384592
         * to write to the same file in this request.
Packit Service 384592
         *
Packit Service 384592
         * Serial log format: Note that, as we opened the file through the
Packit Service 384592
         * pool mechanism of the APR, we do not need to close the file
Packit Service 384592
         * here. It will be closed automatically at the end of the request.
Packit Service 384592
         */
Packit Service 384592
        msr->new_auditlog_fd = NULL;
Packit Service 384592
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Constructs a log line in vcombined log format trying to truncate
Packit Service 384592
 * some of the fields to make the log line shorter than _limit bytes.
Packit Service 384592
 */
Packit Service 384592
char *construct_log_vcombinedus_limited(modsec_rec *msr, int _limit, int *was_limited) {
Packit Service 384592
    char *hostname;
Packit Service 384592
    char *local_user, *remote_user;
Packit Service 384592
    char *referer, *user_agent, *uniqueid;
Packit Service 384592
    const char *sessionid;
Packit Service 384592
    char *the_request, *bytes_sent;
Packit Service 384592
    int limit = _limit;
Packit Service 384592
Packit Service 384592
    /* hostname */
Packit Service 384592
    hostname = (msr->hostname == NULL ? "-" : log_escape_nq(msr->mp, msr->hostname));
Packit Service 384592
Packit Service 384592
    /* remote log name */
Packit Service 384592
    if (msr->remote_user == NULL) remote_user = "-";
Packit Service 384592
    else remote_user = log_escape_nq(msr->mp, msr->remote_user);
Packit Service 384592
Packit Service 384592
    /* authenticated user */
Packit Service 384592
    if (msr->local_user == NULL) local_user = "-";
Packit Service 384592
    else local_user = log_escape_nq(msr->mp, msr->local_user);
Packit Service 384592
Packit Service 384592
    /* unique id */
Packit Service 384592
    if (msr->txid == NULL) uniqueid = "-";
Packit Service 384592
    else uniqueid = log_escape(msr->mp, msr->txid);
Packit Service 384592
Packit Service 384592
    /* referer */
Packit Service 384592
    referer = "-";
Packit Service 384592
    /*
Packit Service 384592
    referer = (char *)apr_table_get(msr->request_headers, "Referer");
Packit Service 384592
    if (referer == NULL) referer = "-";
Packit Service 384592
    else referer = log_escape(msr->mp, referer);
Packit Service 384592
    */
Packit Service 384592
Packit Service 384592
    /* user agent */
Packit Service 384592
    user_agent = "-";
Packit Service 384592
    /*
Packit Service 384592
    user_agent = (char *)apr_table_get(msr->request_headers, "User-Agent");
Packit Service 384592
    if (user_agent == NULL) user_agent = "-";
Packit Service 384592
    else user_agent = log_escape(msr->mp, user_agent);
Packit Service 384592
    */
Packit Service 384592
Packit Service 384592
    /* sessionid */
Packit Service 384592
    sessionid = (msr->sessionid == NULL) ? "-" : log_escape(msr->mp, msr->sessionid);
Packit Service 384592
Packit Service 384592
    the_request = (msr->request_line == NULL) ? "" : log_escape(msr->mp, msr->request_line);
Packit Service 384592
Packit Service 384592
    bytes_sent = apr_psprintf(msr->mp, "%" APR_OFF_T_FMT, msr->bytes_sent);
Packit Service 384592
Packit Service 384592
    /* first take away the size of the
Packit Service 384592
     * information we must log
Packit Service 384592
     */
Packit Service 384592
    limit -= 22;                                 /* spaces and double quotes */
Packit Service 384592
    limit -= strlen(hostname);                   /* server name or IP */
Packit Service 384592
    limit -= strlen(msr->remote_addr);           /* remote IP */
Packit Service 384592
    limit -= 28;                                 /* current_logtime */
Packit Service 384592
    limit -= 3;                                  /* status */
Packit Service 384592
    limit -= strlen(bytes_sent);                 /* bytes sent */
Packit Service 384592
    limit -= strlen(uniqueid);                   /* unique id */
Packit Service 384592
    limit -= strlen(sessionid);                  /* session id */
Packit Service 384592
Packit Service 384592
    if (limit <= 0) {
Packit Service 384592
        msr_log(msr, 1, "GuardianLog: Atomic pipe write size too small: %d", PIPE_BUF);
Packit Service 384592
        return NULL;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* we hope to be able to squeeze everything in */
Packit Service 384592
    if (limit < (int)(strlen(remote_user) + strlen(local_user) + strlen(referer)
Packit Service 384592
        + strlen(user_agent) + strlen(the_request)))
Packit Service 384592
    {
Packit Service 384592
        /* Boo hoo hoo, there's not enough space available. */
Packit Service 384592
        *was_limited = 1;
Packit Service 384592
Packit Service 384592
        /* Let's see if we can reduce the size of something. This
Packit Service 384592
         * is a very crude approach but it seems to work for our
Packit Service 384592
         * needs.
Packit Service 384592
         */
Packit Service 384592
        if (strlen(remote_user) > 32) {
Packit Service 384592
            msr_log(msr, 9, "GuardianLog: Reduced remote_user to 32.");
Packit Service 384592
            remote_user[32] = '\0';
Packit Service 384592
        }
Packit Service 384592
        limit -= strlen(remote_user);
Packit Service 384592
Packit Service 384592
        if (strlen(local_user) > 32) {
Packit Service 384592
            msr_log(msr, 9, "GuardianLog: Reduced local_user to 32.");
Packit Service 384592
            local_user[32] = '\0';
Packit Service 384592
        }
Packit Service 384592
        limit -= strlen(local_user);
Packit Service 384592
Packit Service 384592
        if (strlen(referer) > 64) {
Packit Service 384592
            msr_log(msr, 9, "GuardianLog: Reduced referer to 64.");
Packit Service 384592
            referer[64] = '\0';
Packit Service 384592
        }
Packit Service 384592
        limit -= strlen(referer);
Packit Service 384592
Packit Service 384592
        if (strlen(user_agent) > 64) {
Packit Service 384592
            msr_log(msr, 9, "GuardianLog: Reduced user_agent to 64.");
Packit Service 384592
            user_agent[64] = '\0';
Packit Service 384592
        }
Packit Service 384592
        limit -= strlen(user_agent);
Packit Service 384592
Packit Service 384592
        if (limit <= 0) {
Packit Service 384592
            msr_log(msr, 1, "GuardianLog: Atomic pipe write size too small: %d.", PIPE_BUF);
Packit Service 384592
            return NULL;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* use what's left for the request line */
Packit Service 384592
        if ((int)strlen(the_request) > limit) {
Packit Service 384592
            the_request[limit] = '\0';
Packit Service 384592
            msr_log(msr, 9, "GuardianLog: Reduced the_request to %d bytes.", limit);
Packit Service 384592
        }
Packit Service 384592
    } else {
Packit Service 384592
        /* Yay! We have enough space! */
Packit Service 384592
        *was_limited = 0;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return apr_psprintf(msr->mp, "%s %s %s %s [%s] \"%s\" %u %s \"%s\" \"%s\" %s \"%s\"",
Packit Service 384592
        hostname, msr->remote_addr, remote_user,
Packit Service 384592
        local_user, current_logtime(msr->mp), the_request,
Packit Service 384592
        msr->response_status, bytes_sent, referer, user_agent,
Packit Service 384592
        uniqueid, sessionid
Packit Service 384592
    );
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Checks if the provided string is a valid audit log parts specification.
Packit Service 384592
 */
Packit Service 384592
int is_valid_parts_specification(char *p) {
Packit Service 384592
    char c, *t = p;
Packit Service 384592
Packit Service 384592
    while((c = *(t++)) != '\0') {
Packit Service 384592
        if ((c != AUDITLOG_PART_ENDMARKER)&&((c < AUDITLOG_PART_FIRST)||(c > AUDITLOG_PART_LAST))) {
Packit Service 384592
            return 0;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Constructs a filename that will be used to store an
Packit Service 384592
 * audit log entry.
Packit Service 384592
 */
Packit Service 384592
static char *construct_auditlog_filename(apr_pool_t *mp, const char *uniqueid) {
Packit Service 384592
    apr_time_exp_t t;
Packit Service 384592
    char tstr[300];
Packit Service 384592
    apr_size_t len;
Packit Service 384592
Packit Service 384592
    apr_time_exp_lt(&t, apr_time_now());
Packit Service 384592
Packit Service 384592
    apr_strftime(tstr, &len, 299, "/%Y%m%d/%Y%m%d-%H%M/%Y%m%d-%H%M%S", &t);
Packit Service 384592
    return apr_psprintf(mp, "%s-%s", tstr, uniqueid);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Creates a random 8-character string that
Packit Service 384592
 * consists of hexadecimal numbers, to be used
Packit Service 384592
 * as an audit log boundary.
Packit Service 384592
 */
Packit Service 384592
static char *create_auditlog_boundary(request_rec *r) {
Packit Service 384592
#ifdef LINUX_S390
Packit Service 384592
    int data = swap_int32(rand());
Packit Service 384592
#else
Packit Service 384592
    unsigned long data = rand();
Packit Service 384592
#endif
Packit Service 384592
    /* Do note that I tried using apr_generate_random_bytes but it turned
Packit Service 384592
     * out to be terribly slow for some reason. Needs further investigation.
Packit Service 384592
     */
Packit Service 384592
    return bytes2hex(r->pool, (void *)&data, 4);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Sanitises the request line by removing the parameters
Packit Service 384592
 * that have been marked as sensitive.
Packit Service 384592
 */
Packit Service 384592
static void sanitize_request_line(modsec_rec *msr) {
Packit Service 384592
    const apr_array_header_t *tarr = NULL;
Packit Service 384592
    const apr_table_entry_t *telts = NULL;
Packit Service 384592
    const apr_array_header_t *tarr_pattern = NULL;
Packit Service 384592
    const apr_table_entry_t *telts_pattern = NULL;
Packit Service 384592
    msc_parm *mparm = NULL;
Packit Service 384592
    int i, k;
Packit Service 384592
    char *qspos;
Packit Service 384592
    char *buf = NULL;
Packit Service 384592
    int sanitized_partial = 0;
Packit Service 384592
    int sanitize_matched = 0;
Packit Service 384592
Packit Service 384592
    /* Locate the query string. */
Packit Service 384592
    qspos = strstr(msr->request_line, "?");
Packit Service 384592
    if (qspos == NULL) return;
Packit Service 384592
    qspos++;
Packit Service 384592
Packit Service 384592
    /* Loop through the list of sensitive parameters. */
Packit Service 384592
    tarr = apr_table_elts(msr->arguments_to_sanitize);
Packit Service 384592
    telts = (const apr_table_entry_t*)tarr->elts;
Packit Service 384592
    for (i = 0; i < tarr->nelts; i++) {
Packit Service 384592
        msc_arg *arg = (msc_arg *)telts[i].val;
Packit Service 384592
        /* Only look at the parameters that appeared in the query string. */
Packit Service 384592
        if (strcmp(arg->origin, "QUERY_STRING") == 0) {
Packit Service 384592
            char *pat = NULL;
Packit Service 384592
            char *p;
Packit Service 384592
            int j, arg_min, arg_max;
Packit Service 384592
Packit Service 384592
            /* Go to the beginning of the parameter. */
Packit Service 384592
            p = qspos;
Packit Service 384592
            j = arg->value_origin_offset;
Packit Service 384592
            while((*p != '\0')&&(j--)) p++;
Packit Service 384592
            if (*p == '\0') {
Packit Service 384592
                msr_log(msr, 1, "Unable to sanitize variable \"%s\" at offset %u of QUERY_STRING"
Packit Service 384592
                        "because the request line is too short.",
Packit Service 384592
                        log_escape_ex(msr->mp, arg->name, arg->name_len),
Packit Service 384592
                        arg->value_origin_offset);
Packit Service 384592
                continue;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            tarr_pattern = apr_table_elts(msr->pattern_to_sanitize);
Packit Service 384592
            telts_pattern = (const apr_table_entry_t*)tarr_pattern->elts;
Packit Service 384592
Packit Service 384592
            sanitized_partial = 0;
Packit Service 384592
            sanitize_matched = 0;
Packit Service 384592
            buf = apr_psprintf(msr->mp, "%s",p);
Packit Service 384592
            for ( k = 0; k < tarr_pattern->nelts; k++)  {
Packit Service 384592
                if(strncmp(telts_pattern[k].key,arg->name,strlen(arg->name)) ==0 ) {
Packit Service 384592
                    mparm = (msc_parm *)telts_pattern[k].val;
Packit Service 384592
                    pat = strstr(buf,mparm->value);
Packit Service 384592
                    if(mparm->pad_1 == -1)
Packit Service 384592
                        sanitize_matched = 1;
Packit Service 384592
Packit Service 384592
                    if (pat != NULL) {
Packit Service 384592
                        j = strlen(mparm->value);
Packit Service 384592
                        arg_min = j;
Packit Service 384592
                        arg_max = 1;
Packit Service 384592
                        while((*pat != '\0')&&(j--)) {
Packit Service 384592
                            if(arg_max > mparm->pad_2)  {
Packit Service 384592
                                int off = (strlen(mparm->value) - arg_max);
Packit Service 384592
                                int pos = (mparm->pad_1-1);
Packit Service 384592
                                if(off > pos)    {
Packit Service 384592
                                    *pat = '*';
Packit Service 384592
                                }
Packit Service 384592
                            }
Packit Service 384592
                            arg_max++;
Packit Service 384592
                            arg_min--;
Packit Service 384592
                            pat++;
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
                    sanitized_partial = 1;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            if(sanitized_partial == 1 && sanitize_matched == 0)  {
Packit Service 384592
                while(*buf != '\0') {
Packit Service 384592
                    *p++ = *buf++;
Packit Service 384592
                }
Packit Service 384592
                continue;
Packit Service 384592
            } else {
Packit Service 384592
                /* Write over the value. */
Packit Service 384592
                j = arg->value_origin_len;
Packit Service 384592
                while((*p != '\0')&&(j--)) {
Packit Service 384592
                    *p++ = '*';
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                if (*p == '\0') {
Packit Service 384592
                    msr_log(msr, 1, "Unable to sanitize variable \"%s\" at offset %u (size %d) "
Packit Service 384592
                            "of QUERY_STRING because the request line is too short.",
Packit Service 384592
                            log_escape_ex(msr->mp, arg->name, arg->name_len),
Packit Service 384592
                            arg->value_origin_offset, arg->value_origin_len);
Packit Service 384592
                    continue;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Output the Producer header.
Packit Service 384592
 */
Packit Service 384592
static void sec_auditlog_write_producer_header(modsec_rec *msr) {
Packit Service 384592
    char **signatures = NULL;
Packit Service 384592
    char *text = NULL;
Packit Service 384592
    int i;
Packit Service 384592
Packit Service 384592
    /* Try to write everything in one go. */
Packit Service 384592
    if (msr->txcfg->component_signatures->nelts == 0) {
Packit Service 384592
        text = apr_psprintf(msr->mp, "Producer: %s.\n", MODSEC_MODULE_NAME_FULL);
Packit Service 384592
        sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Start with the ModSecurity signature. */
Packit Service 384592
    text = apr_psprintf(msr->mp, "Producer: %s", MODSEC_MODULE_NAME_FULL);
Packit Service 384592
    sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
Packit Service 384592
    /* Then loop through the components and output individual signatures. */
Packit Service 384592
    signatures = (char **)msr->txcfg->component_signatures->elts;
Packit Service 384592
    for(i = 0; i < msr->txcfg->component_signatures->nelts; i++) {
Packit Service 384592
        text = apr_psprintf(msr->mp, "; %s", (char *)signatures[i]);
Packit Service 384592
        sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    sec_auditlog_write(msr, ".\n", 2);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
#ifdef WITH_YAJL
Packit Service 384592
/**
Packit Service 384592
 * Ouput the Producer header into a JSON generator
Packit Service 384592
 */
Packit Service 384592
static void sec_auditlog_write_producer_header_json(modsec_rec *msr, yajl_gen g) {
Packit Service 384592
    char **signatures = NULL;
Packit Service 384592
    int i;
Packit Service 384592
Packit Service 384592
    // this is written no matter what
Packit Service 384592
    yajl_string(g, "producer");
Packit Service 384592
Packit Service 384592
    /* Try to write verything in one go. */
Packit Service 384592
    if (msr->txcfg->component_signatures->nelts == 0) {
Packit Service 384592
        yajl_string(g, MODSEC_MODULE_NAME_FULL);
Packit Service 384592
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    // we'll need an array if there are component signatures
Packit Service 384592
    yajl_gen_array_open(g);
Packit Service 384592
Packit Service 384592
    /* Start with the ModSecurity signature. */
Packit Service 384592
    yajl_string(g, MODSEC_MODULE_NAME_FULL);
Packit Service 384592
Packit Service 384592
    /* Then loop through the components and output individual signatures. */
Packit Service 384592
    signatures = (char **)msr->txcfg->component_signatures->elts;
Packit Service 384592
    for(i = 0; i < msr->txcfg->component_signatures->nelts; i++) {
Packit Service 384592
        yajl_string(g, (char *)signatures[i]);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    yajl_gen_array_close(g); // array for producers is finished
Packit Service 384592
}
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
* \brief This function will returns the next chain node
Packit Service 384592
*
Packit Service 384592
* \param current Pointer to current chined rule
Packit Service 384592
* \param msr Pointer to modsec_rec
Packit Service 384592
*
Packit Service 384592
* \retval NULL On failure
Packit Service 384592
* \retval next_rule On Success
Packit Service 384592
*/
Packit Service 384592
static msre_rule *return_chained_rule(const msre_rule *current, modsec_rec *msr)   {
Packit Service 384592
    apr_array_header_t *arr = NULL;
Packit Service 384592
    msre_rule **rules = NULL;
Packit Service 384592
    msre_rule *rule = NULL, *next_rule = NULL;
Packit Service 384592
    int i;
Packit Service 384592
    int phase;
Packit Service 384592
Packit Service 384592
    if (current == NULL || current->actionset == NULL || current->ruleset == NULL)
Packit Service 384592
        return NULL;
Packit Service 384592
Packit Service 384592
    phase = current->actionset->phase;
Packit Service 384592
Packit Service 384592
    switch (phase) {
Packit Service 384592
        case PHASE_REQUEST_HEADERS :
Packit Service 384592
            arr = current->ruleset->phase_request_headers;
Packit Service 384592
            break;
Packit Service 384592
        case PHASE_REQUEST_BODY :
Packit Service 384592
            arr = current->ruleset->phase_request_body;
Packit Service 384592
            break;
Packit Service 384592
        case PHASE_RESPONSE_HEADERS :
Packit Service 384592
            arr = current->ruleset->phase_response_headers;
Packit Service 384592
            break;
Packit Service 384592
        case PHASE_RESPONSE_BODY :
Packit Service 384592
            arr = current->ruleset->phase_response_body;
Packit Service 384592
            break;
Packit Service 384592
        case PHASE_LOGGING :
Packit Service 384592
            arr = current->ruleset->phase_logging;
Packit Service 384592
            break;
Packit Service 384592
        default :
Packit Service 384592
            msr_log(msr, 1, "Logging: Invalid phase %d",phase);
Packit Service 384592
            return NULL;
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
        rule = rules[i];
Packit Service 384592
        if (rule != NULL)    {
Packit Service 384592
            if (strncmp(current->unparsed,rule->unparsed,strlen(current->unparsed)) == 0) {
Packit Service 384592
Packit Service 384592
                if (i < arr->nelts -1)   {
Packit Service 384592
                    next_rule = rules[i+1];
Packit Service 384592
                } else  {
Packit Service 384592
                    next_rule = rules[i];
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                if (next_rule == NULL || next_rule->chain_starter == NULL)
Packit Service 384592
                    return NULL;
Packit Service 384592
Packit Service 384592
                if(current->chain_starter == NULL && next_rule->chain_starter != NULL)  {
Packit Service 384592
                    if (strncmp(current->unparsed, next_rule->chain_starter->unparsed, strlen(current->unparsed)) != 0)
Packit Service 384592
                        return NULL;
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                if(current->chain_starter != NULL && next_rule->chain_starter != NULL)  {
Packit Service 384592
                    if (strncmp(current->chain_starter->unparsed, rule->chain_starter->unparsed, strlen(current->chain_starter->unparsed)) != 0)
Packit Service 384592
                        return NULL;
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                return next_rule;
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
* \brief This function will check if a chained rule
Packit Service 384592
* appears into matched array.
Packit Service 384592
*
Packit Service 384592
* \param msr Pointer to modsec_rec
Packit Service 384592
* \param next_rule Pointer to chained rule
Packit Service 384592
*
Packit Service 384592
* \retval 0 On failure
Packit Service 384592
* \retval 1 On Success
Packit Service 384592
*/
Packit Service 384592
static int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) {
Packit Service 384592
    int i = 0;
Packit Service 384592
    const msre_rule *rule = NULL;
Packit Service 384592
Packit Service 384592
    for (i = 0; i < msr->matched_rules->nelts; i++) {
Packit Service 384592
        rule = ((msre_rule **)msr->matched_rules->elts)[i];
Packit Service 384592
        if (rule != NULL && (strncmp(rule->unparsed,next_rule->unparsed,strlen(rule->unparsed)) == 0))  {
Packit Service 384592
            return 1;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return 0;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
#ifdef WITH_YAJL
Packit Service 384592
/**
Packit Service 384592
 * Write detailed information about performance metrics into a JSON generator
Packit Service 384592
 */
Packit Service 384592
static void format_performance_variables_json(modsec_rec *msr, yajl_gen g) {
Packit Service 384592
    yajl_string(g, "stopwatch");
Packit Service 384592
    yajl_gen_map_open(g);
Packit Service 384592
Packit Service 384592
    yajl_kv_int(g, "p1", msr->time_phase1);
Packit Service 384592
    yajl_kv_int(g, "p2", msr->time_phase2);
Packit Service 384592
    yajl_kv_int(g, "p3", msr->time_phase3);
Packit Service 384592
    yajl_kv_int(g, "p4", msr->time_phase4);
Packit Service 384592
    yajl_kv_int(g, "p5", msr->time_phase5);
Packit Service 384592
    yajl_kv_int(g, "sr", msr->time_storage_read);
Packit Service 384592
    yajl_kv_int(g, "sw", msr->time_storage_write);
Packit Service 384592
    yajl_kv_int(g, "l", msr->time_logging);
Packit Service 384592
    yajl_kv_int(g, "gc", msr->time_gc);
Packit Service 384592
Packit Service 384592
    yajl_gen_map_close(g);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Write detailed information about a rule and its actionset into a JSON generator
Packit Service 384592
 */
Packit Service 384592
static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) {
Packit Service 384592
    const apr_array_header_t *tarr;
Packit Service 384592
    const apr_table_entry_t *telts;
Packit Service 384592
    int been_opened = 0;
Packit Service 384592
    int k;
Packit Service 384592
Packit Service 384592
    yajl_gen_map_open(g);
Packit Service 384592
Packit Service 384592
    yajl_string(g, "actionset");
Packit Service 384592
    yajl_gen_map_open(g);
Packit Service 384592
    if (rule->actionset->id) {
Packit Service 384592
        yajl_kv_string(g, "id", log_escape(msr->mp, rule->actionset->id));
Packit Service 384592
    }
Packit Service 384592
    if (rule->actionset->rev) {
Packit Service 384592
        yajl_kv_string(g, "rev", log_escape(msr->mp, rule->actionset->rev));
Packit Service 384592
    }
Packit Service 384592
    if (rule->actionset->version) {
Packit Service 384592
        yajl_kv_string(g, "version", log_escape(msr->mp, rule->actionset->version));
Packit Service 384592
    }
Packit Service 384592
    if (rule->actionset->severity != NOT_SET) {
Packit Service 384592
        yajl_kv_int(g, "severity", rule->actionset->severity);
Packit Service 384592
    }
Packit Service 384592
    if (rule->actionset->accuracy != NOT_SET) {
Packit Service 384592
        yajl_kv_int(g, "accuracy", rule->actionset->accuracy);
Packit Service 384592
    }
Packit Service 384592
    if (rule->actionset->maturity != NOT_SET) {
Packit Service 384592
        yajl_kv_int(g, "maturity", rule->actionset->maturity);
Packit Service 384592
    }
Packit Service 384592
    if (rule->actionset->phase != NOT_SET) {
Packit Service 384592
        yajl_kv_int(g, "phase", rule->actionset->phase);
Packit Service 384592
    }
Packit Service 384592
    yajl_kv_bool(g, "is_chained", rule->actionset->is_chained || (rule->chain_starter != NULL));
Packit Service 384592
    if (rule->actionset->is_chained && (rule->chain_starter == NULL)) {
Packit Service 384592
        yajl_kv_bool(g, "chain_starter", 1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    // tags, lazily opened
Packit Service 384592
    tarr = apr_table_elts(rule->actionset->actions);
Packit Service 384592
    telts = (const apr_table_entry_t*)tarr->elts;
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
            msc_string *var = NULL;
Packit Service 384592
            if (been_opened == 0) {
Packit Service 384592
                yajl_string(g, "tags");
Packit Service 384592
                yajl_gen_array_open(g);
Packit Service 384592
                been_opened = 1;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            // expand variables in the tag
Packit Service 384592
            var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
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
            yajl_string(g, log_escape(msr->mp, var->value));
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (been_opened == 1) {
Packit Service 384592
        yajl_gen_array_close(g);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    yajl_gen_map_close(g);
Packit Service 384592
Packit Service 384592
    yajl_string(g, "operator");
Packit Service 384592
    yajl_gen_map_open(g);
Packit Service 384592
    yajl_kv_string(g, "operator", rule->op_name);
Packit Service 384592
    yajl_kv_string(g, "operator_param", rule->op_param);
Packit Service 384592
    yajl_kv_string(g, "target", rule->p1);
Packit Service 384592
    yajl_kv_bool(g, "negated", rule->op_negated);
Packit Service 384592
    yajl_gen_map_close(g);
Packit Service 384592
Packit Service 384592
    yajl_string(g, "config");
Packit Service 384592
    yajl_gen_map_open(g);
Packit Service 384592
    yajl_kv_string(g, "filename", rule->filename);
Packit Service 384592
    yajl_kv_int(g, "line_num", rule->line_num);
Packit Service 384592
    yajl_gen_map_close(g);
Packit Service 384592
Packit Service 384592
    yajl_kv_string(g, "unparsed", rule->unparsed);
Packit Service 384592
    yajl_kv_bool(g, "is_matched", chained_is_matched(msr, rule));
Packit Service 384592
Packit Service 384592
    yajl_gen_map_close(g);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * Produce an audit log entry in JSON format.
Packit Service 384592
 */
Packit Service 384592
void sec_audit_logger_json(modsec_rec *msr) {
Packit Service 384592
    const apr_array_header_t *arr = NULL;
Packit Service 384592
    apr_table_entry_t *te = NULL;
Packit Service 384592
    const apr_array_header_t *tarr_pattern = NULL;
Packit Service 384592
    const apr_table_entry_t *telts_pattern = NULL;
Packit Service 384592
    char *str1 = NULL, *str2 = NULL, *text = NULL;
Packit Service 384592
    const msre_rule *rule = NULL, *next_rule = NULL;
Packit Service 384592
    apr_size_t nbytes, nbytes_written;
Packit Service 384592
    unsigned char md5hash[APR_MD5_DIGESTSIZE];
Packit Service 384592
    int was_limited = 0;
Packit Service 384592
    int present = 0;
Packit Service 384592
    int wrote_response_body = 0;
Packit Service 384592
    char *entry_filename, *entry_basename;
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
    int i, limit, k, sanitized_partial, j;
Packit Service 384592
    char *buf = NULL, *pat = NULL;
Packit Service 384592
    msc_parm *mparm = NULL;
Packit Service 384592
    int arg_min, arg_max, sanitize_matched;
Packit Service 384592
    yajl_gen g;
Packit Service 384592
    int been_opened = 0; // helper flag for conditionally opening maps
Packit Service 384592
    const unsigned char *final_buf;
Packit Service 384592
    size_t len;
Packit Service 384592
Packit Service 384592
Packit Service 384592
    /* Return silently if we don't have a request line. This
Packit Service 384592
     * means we will not be logging request timeouts.
Packit Service 384592
     */
Packit Service 384592
    if (msr->request_line == NULL) {
Packit Service 384592
        msr_log(msr, 4, "Audit log: Skipping request whose request_line is null.");
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Also return silently if we don't have a file descriptor. */
Packit Service 384592
    if (msr->txcfg->auditlog_fd == NULL) {
Packit Service 384592
        msr_log(msr, 4, "Audit log: Skipping request since there is nowhere to write to.");
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
Packit Service 384592
        /* Serial logging - we already have an open file
Packit Service 384592
         * descriptor to write to.
Packit Service 384592
         */
Packit Service 384592
        msr->new_auditlog_fd = msr->txcfg->auditlog_fd;
Packit Service 384592
    } else {
Packit Service 384592
        /* Concurrent logging - we need to create a brand
Packit Service 384592
         * new file for this request.
Packit Service 384592
         */
Packit Service 384592
        apr_md5_init(&msr->new_auditlog_md5ctx);
Packit Service 384592
Packit Service 384592
        msr->new_auditlog_filename = construct_auditlog_filename(msr->mp, msr->txid);
Packit Service 384592
        if (msr->new_auditlog_filename == NULL) return;
Packit Service 384592
Packit Service 384592
        /* The audit log storage directory should be explicitly
Packit Service 384592
         * defined. But if it isn't try to write to the same
Packit Service 384592
         * directory where the index file is placed. Of course,
Packit Service 384592
         * it is *very* bad practice to allow the Apache user
Packit Service 384592
         * to write to the same directory where a root user is
Packit Service 384592
         * writing to but it's not us that's causing the problem
Packit Service 384592
         * and there isn't anything we can do about that.
Packit Service 384592
         *
Packit Service 384592
         * ENH Actually there is something we can do! We will make
Packit Service 384592
         * SecAuditStorageDir mandatory, ask the user to explicitly
Packit Service 384592
         * define the storage location *and* refuse to work if the
Packit Service 384592
         * index and the storage location are in the same folder.
Packit Service 384592
         */
Packit Service 384592
        if (msr->txcfg->auditlog_storage_dir == NULL) {
Packit Service 384592
            entry_filename = file_dirname(msr->mp, msr->txcfg->auditlog_name);
Packit Service 384592
        }
Packit Service 384592
        else {
Packit Service 384592
            entry_filename = msr->txcfg->auditlog_storage_dir;
Packit Service 384592
        }
Packit Service 384592
        if (entry_filename == NULL) return;
Packit Service 384592
Packit Service 384592
        entry_filename = apr_psprintf(msr->mp, "%s%s", entry_filename, msr->new_auditlog_filename);
Packit Service 384592
        if (entry_filename == NULL) return;
Packit Service 384592
        entry_basename = file_dirname(msr->mp, entry_filename);
Packit Service 384592
        if (entry_basename == NULL) return;
Packit Service 384592
Packit Service 384592
        /* IMP1 Surely it would be more efficient to check the folders for
Packit Service 384592
         * the audit log repository base path in the configuration phase, to reduce
Packit Service 384592
         * the work we do on every request. Also, since our path depends on time,
Packit Service 384592
         * we could cache the time we last checked and don't check if we know
Packit Service 384592
         * the folder is there.
Packit Service 384592
         */
Packit Service 384592
        rc = apr_dir_make_recursive(entry_basename, msr->txcfg->auditlog_dirperms, msr->mp);
Packit Service 384592
        if ((rc != APR_SUCCESS) && (rc != APR_EEXIST)) {
Packit Service 384592
            msr_log(msr, 1, "Audit log: Failed to create subdirectories: %s (%s)",
Packit Service 384592
                entry_basename, get_apr_error(msr->mp, rc));
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        rc = apr_file_open(&msr->new_auditlog_fd, entry_filename,
Packit Service 384592
            APR_WRITE | APR_TRUNCATE | APR_CREATE | APR_BINARY | APR_FILE_NOCLEANUP,
Packit Service 384592
            msr->txcfg->auditlog_fileperms, msr->mp);
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            msr_log(msr, 1, "Audit log: Failed to create file: %s (%s)",
Packit Service 384592
                entry_filename, get_apr_error(msr->mp, rc));
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Lock the mutex, but only if we are using serial format. */
Packit Service 384592
    if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
Packit Service 384592
        rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock);
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s",
Packit Service 384592
                get_apr_error(msr->mp, rc));
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /**
Packit Service 384592
     * allocate the buffer for the JSON generator
Packit Service 384592
     * passing null will force yajl to use malloc/realloc/free
Packit Service 384592
     * need to perf test using APR routines
Packit Service 384592
     */
Packit Service 384592
    g = yajl_gen_alloc(NULL);
Packit Service 384592
Packit Service 384592
    /**
Packit Service 384592
     * don't pretty print JSON
Packit Service 384592
     * this is harder to eyeball but much easier to parse programmatically
Packit Service 384592
     */
Packit Service 384592
    yajl_gen_config(g, yajl_gen_beautify, 0);
Packit Service 384592
Packit Service 384592
    yajl_gen_map_open(g); // IT BEGINS
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_HEADER */
Packit Service 384592
    yajl_string(g, "transaction");
Packit Service 384592
    yajl_gen_map_open(g); // transaction top-level key
Packit Service 384592
Packit Service 384592
    yajl_kv_string(g, "time", current_logtime(msr->mp));
Packit Service 384592
    yajl_kv_string(g, "transaction_id", msr->txid);
Packit Service 384592
    yajl_kv_string(g, "remote_address", msr->remote_addr);
Packit Service 384592
    yajl_kv_int(g, "remote_port", (int)msr->remote_port); // msr->remote_port is unsigned, yajl wants signed
Packit Service 384592
    yajl_kv_string(g, "local_address", msr->local_addr);
Packit Service 384592
    yajl_kv_int(g, "local_port", (int)msr->local_port);
Packit Service 384592
Packit Service 384592
    yajl_gen_map_close(g); // transaction top-level key is finished
Packit Service 384592
Packit Service 384592
    yajl_string(g, "request");
Packit Service 384592
    yajl_gen_map_open(g); // request top-level key
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_REQUEST_HEADERS */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_HEADERS) != NULL) {
Packit Service 384592
        sanitize_request_line(msr);
Packit Service 384592
        yajl_kv_string(g, "request_line", msr->request_line);
Packit Service 384592
Packit Service 384592
        yajl_string(g, "headers");
Packit Service 384592
        yajl_gen_map_open(g); // separate map for request headers
Packit Service 384592
Packit Service 384592
        arr = apr_table_elts(msr->request_headers);
Packit Service 384592
        te = (apr_table_entry_t *)arr->elts;
Packit Service 384592
Packit Service 384592
        tarr_pattern = apr_table_elts(msr->pattern_to_sanitize);
Packit Service 384592
        telts_pattern = (const apr_table_entry_t*)tarr_pattern->elts;
Packit Service 384592
Packit Service 384592
        for (i = 0; i < arr->nelts; i++) {
Packit Service 384592
            sanitized_partial = 0;
Packit Service 384592
            sanitize_matched = 0;
Packit Service 384592
            text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val);
Packit Service 384592
            // write the key no matter what
Packit Service 384592
            // since sanitization only occurs on the value
Packit Service 384592
            yajl_string(g, te[i].key);
Packit Service 384592
            if (apr_table_get(msr->request_headers_to_sanitize, te[i].key) != NULL) {
Packit Service 384592
                buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2);
Packit Service 384592
                for ( k = 0; k < tarr_pattern->nelts; k++)  {
Packit Service 384592
                    if(strncmp(telts_pattern[k].key,te[i].key,strlen(te[i].key)) ==0 ) {
Packit Service 384592
                        mparm = (msc_parm *)telts_pattern[k].val;
Packit Service 384592
                        if(mparm->pad_1 == -1)
Packit Service 384592
                            sanitize_matched = 1;
Packit Service 384592
                        pat = strstr(buf,mparm->value);
Packit Service 384592
                        if (pat != NULL)    {
Packit Service 384592
                            j = strlen(mparm->value);
Packit Service 384592
                            arg_min = j;
Packit Service 384592
                            arg_max = 1;
Packit Service 384592
                            while((*pat != '\0')&&(j--)) {
Packit Service 384592
                                if(arg_max > mparm->pad_2)  {
Packit Service 384592
                                    int off = strlen(mparm->value) - arg_max;
Packit Service 384592
                                    int pos = mparm->pad_1-1;
Packit Service 384592
                                    if(off > pos)    {
Packit Service 384592
                                        *pat = '*';
Packit Service 384592
                                    }
Packit Service 384592
                                }
Packit Service 384592
                                arg_max++;
Packit Service 384592
                                arg_min--;
Packit Service 384592
                                pat++;
Packit Service 384592
                            }
Packit Service 384592
                            sanitized_partial = 1;
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                if(sanitized_partial == 1 && sanitize_matched == 0)  {
Packit Service 384592
                    yajl_string(g, buf);
Packit Service 384592
                } else {
Packit Service 384592
                    memset(buf, '*', strlen(buf)); // strlen also includes the appended newline on the header
Packit Service 384592
                    yajl_string(g, buf);
Packit Service 384592
                }
Packit Service 384592
            } else {
Packit Service 384592
            // we diverge from the original logic a bit because we always print the key
Packit Service 384592
            // at this no point sanitization had occured, so we just print the value
Packit Service 384592
                yajl_string(g, te[i].val);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        yajl_gen_map_close(g); // request headers map is finished
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_REQUEST_BODY */
Packit Service 384592
Packit Service 384592
    /* Output this part of it was explicitly requested (C) or if it was the faked
Packit Service 384592
     * request body that was requested (I) but we have no reason to fake it (it's
Packit Service 384592
     * already in the correct format).
Packit Service 384592
     */
Packit Service 384592
    if ( (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_BODY) != NULL)
Packit Service 384592
        || ( (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_FAKE_REQUEST_BODY) != NULL)
Packit Service 384592
            && (msr->mpd == NULL) ) )
Packit Service 384592
    {
Packit Service 384592
        if (msr->msc_reqbody_read) {
Packit Service 384592
            const apr_array_header_t *tarr;
Packit Service 384592
            const apr_table_entry_t *telts;
Packit Service 384592
            apr_array_header_t *sorted_args;
Packit Service 384592
            unsigned int offset = 0, last_offset = 0;
Packit Service 384592
            msc_arg *nextarg = NULL;
Packit Service 384592
            int sanitize = 0; /* IMP1 Use constants for "sanitize" values. */
Packit Service 384592
            char *my_error_msg = NULL;
Packit Service 384592
Packit Service 384592
            sorted_args = apr_array_make(msr->mp, 25, sizeof(const msc_arg *));
Packit Service 384592
Packit Service 384592
            /* First we need to sort the arguments that need to be
Packit Service 384592
             * sanitized in descending order (we are using a stack structure
Packit Service 384592
             * to store then so the order will be ascending when we start
Packit Service 384592
             * popping them out). This is because we will
Packit Service 384592
             * be reading the request body sequentially and must
Packit Service 384592
             * sanitize it as we go.
Packit Service 384592
             */
Packit Service 384592
Packit Service 384592
            for(;;) {
Packit Service 384592
                nextarg = NULL;
Packit Service 384592
Packit Service 384592
                /* Find the next largest offset (excluding
Packit Service 384592
                 * the ones we've used up already).
Packit Service 384592
                 */
Packit Service 384592
                tarr = apr_table_elts(msr->arguments_to_sanitize);
Packit Service 384592
                telts = (const apr_table_entry_t*)tarr->elts;
Packit Service 384592
                for(i = 0; i < tarr->nelts; i++) {
Packit Service 384592
                    msc_arg *arg = (msc_arg *)telts[i].val;
Packit Service 384592
                    if (arg->origin != NULL &&
Packit Service 384592
                            strcmp(arg->origin, "BODY") != 0)
Packit Service 384592
                        continue;
Packit Service 384592
Packit Service 384592
                    if (last_offset == 0) { /* The first time we're here. */
Packit Service 384592
                        if (arg->value_origin_offset > offset) {
Packit Service 384592
                            offset = arg->value_origin_offset;
Packit Service 384592
                            nextarg = arg;
Packit Service 384592
                        }
Packit Service 384592
                    } else { /* Not the first time. */
Packit Service 384592
                        if ((arg->value_origin_offset > offset)
Packit Service 384592
                            &&(arg->value_origin_offset < last_offset))
Packit Service 384592
                        {
Packit Service 384592
                            offset = arg->value_origin_offset;
Packit Service 384592
                            nextarg = arg;
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                /* If we don't have the next argument that means
Packit Service 384592
                 * we're done here.
Packit Service 384592
                 */
Packit Service 384592
                if (nextarg == NULL) break;
Packit Service 384592
Packit Service 384592
                sanitize = 2; /* Means time to pop the next argument out. */
Packit Service 384592
                last_offset = offset;
Packit Service 384592
                offset = 0;
Packit Service 384592
                { /* IMP1 Fix this ugly bit here. */
Packit Service 384592
                    msc_arg **x = apr_array_push(sorted_args);
Packit Service 384592
                    *x = nextarg;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Now start retrieving the body chunk by chunk and
Packit Service 384592
             * sanitize data in pieces.
Packit Service 384592
             */
Packit Service 384592
Packit Service 384592
            rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg);
Packit Service 384592
            if (rc < 0) {
Packit Service 384592
                msr_log(msr, 1, "Audit log: %s", my_error_msg);
Packit Service 384592
            } else {
Packit Service 384592
                msc_data_chunk *chunk = NULL;
Packit Service 384592
                unsigned int chunk_offset = 0;
Packit Service 384592
                unsigned int sanitize_offset = 0;
Packit Service 384592
                unsigned int sanitize_length = 0;
Packit Service 384592
                yajl_string(g, "body");
Packit Service 384592
                yajl_gen_array_open(g); // use an array here because we're writing in chunks
Packit Service 384592
Packit Service 384592
                for(;;) {
Packit Service 384592
                    rc = modsecurity_request_body_retrieve(msr, &chunk, -1, &my_error_msg);
Packit Service 384592
                    if (chunk != NULL) {
Packit Service 384592
                        /* Anything greater than 1 means we have more data to sanitize. */
Packit Service 384592
                        while (sanitize > 1) {
Packit Service 384592
                            msc_arg **arg = NULL;
Packit Service 384592
Packit Service 384592
                            if (sanitize == 2) {
Packit Service 384592
                                /* Get the next argument from the stack. */
Packit Service 384592
                                arg = (msc_arg **)apr_array_pop(sorted_args);
Packit Service 384592
                                if (arg == NULL) sanitize = 0; /* We're done sanitising. */
Packit Service 384592
                                else {
Packit Service 384592
                                    /* Continue with sanitation to process the
Packit Service 384592
                                     * retrieved argument.
Packit Service 384592
                                     */
Packit Service 384592
                                    sanitize = 1;
Packit Service 384592
                                    sanitize_offset = (*arg)->value_origin_offset;
Packit Service 384592
                                    sanitize_length = (*arg)->value_origin_len;
Packit Service 384592
                                }
Packit Service 384592
                            }
Packit Service 384592
Packit Service 384592
                            if (sanitize) {
Packit Service 384592
                                /* Check if the data we want to sanitize is
Packit Service 384592
                                 * stored in the current chunk.
Packit Service 384592
                                 */
Packit Service 384592
                                if (chunk_offset + chunk->length > sanitize_offset) {
Packit Service 384592
                                    unsigned int soff; /* data offset within chunk */
Packit Service 384592
                                    unsigned int len;  /* amount in this chunk to sanitize */
Packit Service 384592
Packit Service 384592
                                    soff = sanitize_offset - chunk_offset;
Packit Service 384592
Packit Service 384592
                                    if (soff + sanitize_length <= chunk->length) {
Packit Service 384592
                                        /* The entire argument resides in the current chunk. */
Packit Service 384592
                                        len = sanitize_length;
Packit Service 384592
                                        sanitize = 2; /* Get another parameter to sanitize. */
Packit Service 384592
                                    } else {
Packit Service 384592
                                        /* Some work to do here but we'll need to seek
Packit Service 384592
                                         * another chunk.
Packit Service 384592
                                         */
Packit Service 384592
                                        len = chunk->length - soff;
Packit Service 384592
                                        sanitize_offset += len;
Packit Service 384592
                                        sanitize_length -= len;
Packit Service 384592
                                        sanitize = 1; /* It's OK to go to the next chunk. */
Packit Service 384592
                                    }
Packit Service 384592
Packit Service 384592
                                    /* Yes, we actually write over the original data.
Packit Service 384592
                                     * We shouldn't be needing it any more.
Packit Service 384592
                                     */
Packit Service 384592
                                    if (soff + len <= chunk->length) { /* double check */
Packit Service 384592
                                        memset((char *)chunk->data + soff, '*', len);
Packit Service 384592
                                    }
Packit Service 384592
                                }
Packit Service 384592
                            }
Packit Service 384592
                        }
Packit Service 384592
Packit Service 384592
                        /* Write the sanitized chunk to the log
Packit Service 384592
                         * and advance to the next chunk. */
Packit Service 384592
                        yajl_string(g, chunk->data);
Packit Service 384592
                        chunk_offset += chunk->length;
Packit Service 384592
                    }
Packit Service 384592
Packit Service 384592
                    if (rc <= 0) {
Packit Service 384592
                        break;
Packit Service 384592
                    }
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                yajl_gen_array_close(g); // request body chunks array is finished
Packit Service 384592
Packit Service 384592
                if (rc < 0) {
Packit Service 384592
                    msr_log(msr, 1, "Audit log: %s", my_error_msg);
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                modsecurity_request_body_retrieve_end(msr);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_FAKE_REQUEST_BODY */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_FAKE_REQUEST_BODY) != NULL) {
Packit Service 384592
        if ((msr->msc_reqbody_read)&&(msr->mpd != NULL)) {
Packit Service 384592
            char *buffer = NULL;
Packit Service 384592
Packit Service 384592
            buffer = multipart_reconstruct_urlencoded_body_sanitize(msr);
Packit Service 384592
            if (buffer == NULL) {
Packit Service 384592
                msr_log(msr, 1, "Audit log: Failed to reconstruct request body.");
Packit Service 384592
            } else {
Packit Service 384592
                yajl_kv_string(g, "fake_body", buffer);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    yajl_gen_map_close(g); // request top-level key is finished
Packit Service 384592
Packit Service 384592
    yajl_string(g, "response");
Packit Service 384592
    yajl_gen_map_open(g); // response top-level key
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_A_RESPONSE_HEADERS */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_A_RESPONSE_HEADERS) != NULL) {
Packit Service 384592
Packit Service 384592
        /* There are no response headers (or the status line) in HTTP 0.9 */
Packit Service 384592
        if (msr->response_headers_sent) {
Packit Service 384592
            yajl_kv_string(g, "protocol", msr->response_protocol);
Packit Service 384592
            // as an integer, response status is easier to parse than status_line
Packit Service 384592
            yajl_kv_int(g, "status", (int)msr->response_status);
Packit Service 384592
            yajl_string(g, "headers");
Packit Service 384592
            yajl_gen_map_open(g); // separate map for response headers
Packit Service 384592
Packit Service 384592
            /* Output headers */
Packit Service 384592
Packit Service 384592
            arr = apr_table_elts(msr->response_headers);
Packit Service 384592
            te = (apr_table_entry_t *)arr->elts;
Packit Service 384592
Packit Service 384592
            tarr_pattern = apr_table_elts(msr->pattern_to_sanitize);
Packit Service 384592
            telts_pattern = (const apr_table_entry_t*)tarr_pattern->elts;
Packit Service 384592
Packit Service 384592
            for (i = 0; i < arr->nelts; i++) {
Packit Service 384592
                sanitized_partial = 0;
Packit Service 384592
                sanitize_matched = 0;
Packit Service 384592
                text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val);
Packit Service 384592
                // write the key no matter what
Packit Service 384592
                // since sanitization only occurs on the value
Packit Service 384592
                yajl_string(g, te[i].key);
Packit Service 384592
                if (apr_table_get(msr->response_headers_to_sanitize, te[i].key) != NULL) {
Packit Service 384592
                    buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2);
Packit Service 384592
Packit Service 384592
                    for ( k = 0; k < tarr_pattern->nelts; k++)  {
Packit Service 384592
                        if(strncmp(telts_pattern[k].key,te[i].key,strlen(te[i].key)) ==0 ) {
Packit Service 384592
                            mparm = (msc_parm *)telts_pattern[k].val;
Packit Service 384592
                            if(mparm->pad_1 == -1)
Packit Service 384592
                                sanitize_matched = 1;
Packit Service 384592
                            pat = strstr(buf,mparm->value);
Packit Service 384592
                            if (pat != NULL)    {
Packit Service 384592
                                j = strlen(mparm->value);
Packit Service 384592
                                arg_min = j;
Packit Service 384592
                                arg_max = 1;
Packit Service 384592
                                while((*pat != '\0')&&(j--)) {
Packit Service 384592
                                    if(arg_max > mparm->pad_2)  {
Packit Service 384592
                                        int off = strlen(mparm->value) - arg_max;
Packit Service 384592
                                        int pos = mparm->pad_1-1;
Packit Service 384592
                                        if(off > pos)    {
Packit Service 384592
                                            *pat = '*';
Packit Service 384592
                                        }
Packit Service 384592
                                    }
Packit Service 384592
                                    arg_max++;
Packit Service 384592
                                    arg_min--;
Packit Service 384592
                                    pat++;
Packit Service 384592
                                }
Packit Service 384592
                                sanitized_partial = 1;
Packit Service 384592
                            }
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
Packit Service 384592
                    if(sanitized_partial == 1 && sanitize_matched == 0)  {
Packit Service 384592
                        yajl_string(g, buf);
Packit Service 384592
                    } else {
Packit Service 384592
                        memset(buf, '*', strlen(buf));
Packit Service 384592
                        yajl_string(g, buf);
Packit Service 384592
                    }
Packit Service 384592
                } else {
Packit Service 384592
                    // we diverge from the original logic a bit because we always print the key
Packit Service 384592
                    // at this point no sanitization had occured, so we just print the value
Packit Service 384592
                    yajl_string(g, te[i].val);
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
            yajl_gen_map_close(g); // response headers map is finised
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    apr_table_clear(msr->pattern_to_sanitize);
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_RESPONSE_BODY */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_RESPONSE_BODY) != NULL) {
Packit Service 384592
        if (msr->resbody_data != NULL) {
Packit Service 384592
            yajl_kv_string(g, "body", msr->resbody_data);
Packit Service 384592
            wrote_response_body = 1;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    yajl_gen_map_close(g); // response top-level key is finished
Packit Service 384592
Packit Service 384592
    yajl_string(g, "audit_data");
Packit Service 384592
    yajl_gen_map_open(g); // audit_data top-level key
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_TRAILER */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_TRAILER) != NULL) {
Packit Service 384592
        apr_time_t now = apr_time_now();
Packit Service 384592
Packit Service 384592
        /* Messages */
Packit Service 384592
        been_opened = 0;
Packit Service 384592
        if (msr->alerts->nelts > 0) {
Packit Service 384592
            yajl_string(g, "messages");
Packit Service 384592
            yajl_gen_array_open(g);
Packit Service 384592
            been_opened = 1;
Packit Service 384592
        }
Packit Service 384592
        for(i = 0; i < msr->alerts->nelts; i++) {
Packit Service 384592
            yajl_string(g, ((char **)msr->alerts->elts)[i]);
Packit Service 384592
        }
Packit Service 384592
        if (been_opened == 1) {
Packit Service 384592
            yajl_gen_array_close(g);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Apache error messages */
Packit Service 384592
        been_opened = 0;
Packit Service 384592
        if (msr->error_messages->nelts > 0) {
Packit Service 384592
            yajl_string(g, "error_messages");
Packit Service 384592
            yajl_gen_array_open(g);
Packit Service 384592
            been_opened = 1;
Packit Service 384592
        }
Packit Service 384592
        for(i = 0; i < msr->error_messages->nelts; i++) {
Packit Service 384592
            error_message_t *em = (((error_message_t **)msr->error_messages->elts)[i]);
Packit Service 384592
            yajl_string(g, format_error_log_message(msr->mp, em));
Packit Service 384592
        }
Packit Service 384592
        if (been_opened == 1) {
Packit Service 384592
            yajl_gen_array_close(g);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Action */
Packit Service 384592
        if (msr->was_intercepted) {
Packit Service 384592
            yajl_string(g, "action");
Packit Service 384592
            yajl_gen_map_open(g);
Packit Service 384592
            yajl_kv_bool(g, "intercepted", 1);
Packit Service 384592
            yajl_kv_int(g, "phase", msr->intercept_phase);
Packit Service 384592
            yajl_kv_string(g, "message", msr->intercept_message);
Packit Service 384592
            yajl_gen_map_close(g);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Apache-Handler */
Packit Service 384592
#ifdef LOG_NO_HANDLER
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 9)
Packit Service 384592
#endif
Packit Service 384592
        if (msr->r->handler != NULL) {
Packit Service 384592
            yajl_kv_string(g, "handler", msr->r->handler);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
Packit Service 384592
        /* Stopwatch2 */
Packit Service 384592
#ifdef DLOG_NO_STOPWATCH
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 9)
Packit Service 384592
#endif
Packit Service 384592
        format_performance_variables_json(msr, g);
Packit Service 384592
Packit Service 384592
        /* Our response body does not contain chunks */
Packit Service 384592
        /* ENH Only write this when the output was chunked. */
Packit Service 384592
        /* ENH Add info when request body was decompressed, dechunked too. */
Packit Service 384592
#ifdef LOG_NO_DECHUNK
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 9)
Packit Service 384592
#endif
Packit Service 384592
        if (wrote_response_body) {
Packit Service 384592
            yajl_kv_bool(g, "response_body_dechunked", 1);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
#ifdef LOG_NO_SERVER_CONTEXT
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 9) {
Packit Service 384592
#endif
Packit Service 384592
        sec_auditlog_write_producer_header_json(msr, g);
Packit Service 384592
Packit Service 384592
        /* Server */
Packit Service 384592
        if (msr->server_software != NULL) {
Packit Service 384592
            yajl_kv_string(g, "server", msr->server_software);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        been_opened = 0;
Packit Service 384592
        /* Sanitised arguments */
Packit Service 384592
        {
Packit Service 384592
            const apr_array_header_t *tarr;
Packit Service 384592
            const apr_table_entry_t *telts;
Packit Service 384592
Packit Service 384592
            tarr = apr_table_elts(msr->arguments_to_sanitize);
Packit Service 384592
            telts = (const apr_table_entry_t*)tarr->elts;
Packit Service 384592
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                if (been_opened == 0) {
Packit Service 384592
                    yajl_string(g, "sanitized");
Packit Service 384592
                    yajl_gen_map_open(g);
Packit Service 384592
                    been_opened = 1;
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                yajl_string(g, "args");
Packit Service 384592
                yajl_gen_array_open(g);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            for(i = 0; i < tarr->nelts; i++) {
Packit Service 384592
                msc_arg *arg = (msc_arg *)telts[i].val;
Packit Service 384592
                // yay arrays actually make it easier here
Packit Service 384592
                yajl_string(g, log_escape(msr->mp, arg->name));
Packit Service 384592
            }
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                yajl_gen_array_close(g);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Sanitised request headers */
Packit Service 384592
        {
Packit Service 384592
            const apr_array_header_t *tarr;
Packit Service 384592
            const apr_table_entry_t *telts;
Packit Service 384592
Packit Service 384592
            tarr = apr_table_elts(msr->request_headers_to_sanitize);
Packit Service 384592
            telts = (const apr_table_entry_t*)tarr->elts;
Packit Service 384592
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                if (been_opened == 0) {
Packit Service 384592
                    yajl_string(g, "sanitized");
Packit Service 384592
                    yajl_gen_map_open(g);
Packit Service 384592
                    been_opened = 1;
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                yajl_string(g, "request_headers");
Packit Service 384592
                yajl_gen_array_open(g);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            for(i = 0; i < tarr->nelts; i++) {
Packit Service 384592
                yajl_string(g, log_escape(msr->mp, telts[i].key));
Packit Service 384592
            }
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                yajl_gen_array_close(g);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Sanitised response headers */
Packit Service 384592
        {
Packit Service 384592
            const apr_array_header_t *tarr;
Packit Service 384592
            const apr_table_entry_t *telts;
Packit Service 384592
Packit Service 384592
            tarr = apr_table_elts(msr->response_headers_to_sanitize);
Packit Service 384592
            telts = (const apr_table_entry_t*)tarr->elts;
Packit Service 384592
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                if (been_opened == 0) {
Packit Service 384592
                    yajl_string(g, "sanitized");
Packit Service 384592
                    yajl_gen_map_open(g);
Packit Service 384592
                    been_opened = 1;
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                yajl_string(g, "response_headers");
Packit Service 384592
                yajl_gen_array_open(g);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            for(i = 0; i < tarr->nelts; i++) {
Packit Service 384592
                yajl_string(g, log_escape(msr->mp, telts[i].key));
Packit Service 384592
            }
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                yajl_gen_array_close(g);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (been_opened == 1) {
Packit Service 384592
            yajl_gen_map_close(g); // sanitized args map is finished
Packit Service 384592
        }
Packit Service 384592
#ifdef LOG_NO_SERVER_CONTEXT
Packit Service 384592
	}
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
        /* Web application info. */
Packit Service 384592
        if ( ((msr->txcfg->webappid != NULL)&&(strcmp(msr->txcfg->webappid, "default") != 0))
Packit Service 384592
            || (msr->sessionid != NULL) || (msr->userid != NULL))
Packit Service 384592
        {
Packit Service 384592
            yajl_string(g, "webapp_info");
Packit Service 384592
            yajl_gen_map_open(g);
Packit Service 384592
Packit Service 384592
            if (msr->txcfg->webappid != NULL) {
Packit Service 384592
                yajl_kv_string(g, "id", log_escape(msr->mp, msr->txcfg->webappid));
Packit Service 384592
            }
Packit Service 384592
            if (msr->sessionid != NULL) {
Packit Service 384592
                yajl_kv_string(g, "session", log_escape(msr->mp, msr->sessionid));
Packit Service 384592
            }
Packit Service 384592
            if (msr->userid != NULL) {
Packit Service 384592
                yajl_kv_string(g, "user_id", log_escape(msr->mp, msr->userid));
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            yajl_gen_map_close(g);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if ( ((msr->txcfg->sensor_id != NULL)&&(strcmp(msr->txcfg->sensor_id, "default") != 0)))
Packit Service 384592
        {
Packit Service 384592
            if(msr->txcfg->sensor_id != NULL) {
Packit Service 384592
                yajl_kv_string(g, "sensor_id", log_escape(msr->mp, msr->txcfg->sensor_id));
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
Packit Service 384592
        if (msr->txcfg->is_enabled > 0) {
Packit Service 384592
            yajl_kv_string(g, "engine_mode", (msr->txcfg->is_enabled == 1 ? "DETECTION_ONLY" : "ENABLED"));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Rule performance time */
Packit Service 384592
        if(msr->txcfg->max_rule_time > 0)   {
Packit Service 384592
            const apr_array_header_t *tarr;
Packit Service 384592
            const apr_table_entry_t *telts;
Packit Service 384592
Packit Service 384592
            tarr = apr_table_elts(msr->perf_rules);
Packit Service 384592
            telts = (const apr_table_entry_t*)tarr->elts;
Packit Service 384592
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                yajl_string(g, "rules_performance_info");
Packit Service 384592
                yajl_gen_map_open(g); // separate map for rule perf info
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            for(i = 0; i < tarr->nelts; i++) {
Packit Service 384592
                yajl_kv_string(g, log_escape(msr->mp, telts[i].key), log_escape(msr->mp, telts[i].val));
Packit Service 384592
            }
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                yajl_gen_map_close(g); // map for rule perf info is finished
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    yajl_gen_map_close(g); // audit_data top-level key is finished
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_UPLOADS */
Packit Service 384592
    if ((strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_UPLOADS) != NULL) && (msr->mpd != NULL)) {
Packit Service 384592
        multipart_part **parts = NULL;
Packit Service 384592
        unsigned int total_size = 0;
Packit Service 384592
        int cfiles = 0;
Packit Service 384592
Packit Service 384592
        yajl_string(g, "uploads");
Packit Service 384592
        yajl_gen_map_open(g);
Packit Service 384592
Packit Service 384592
        parts = (multipart_part **)msr->mpd->parts->elts;
Packit Service 384592
        yajl_string(g, "info");
Packit Service 384592
        yajl_gen_array_open(g); // separate array for upload info
Packit Service 384592
        for(cfiles = 0; cfiles < msr->mpd->parts->nelts; cfiles++) {
Packit Service 384592
            if (parts[cfiles]->type == MULTIPART_FILE) {
Packit Service 384592
                if(parts[cfiles]->filename != NULL) {
Packit Service 384592
                    yajl_gen_map_open(g);
Packit Service 384592
                    yajl_kv_int(g, "file_size", parts[cfiles]->tmp_file_size);
Packit Service 384592
                    yajl_kv_string(g, "file_name", log_escape(msr->mp, parts[cfiles]->filename));
Packit Service 384592
                    yajl_kv_string(g, "content_type", parts[cfiles]->content_type ? parts[cfiles]->content_type : "<Unknown Content-Type>");
Packit Service 384592
                    total_size += parts[cfiles]->tmp_file_size;
Packit Service 384592
                    yajl_gen_map_close(g);
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        yajl_gen_array_close(g); // array for upload info is finished
Packit Service 384592
        yajl_kv_int(g, "total", total_size);
Packit Service 384592
Packit Service 384592
        yajl_gen_map_close(g); // uploads top-level key is finished
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_MATCHEDRULES */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_MATCHEDRULES) != NULL) {
Packit Service 384592
        yajl_string(g, "matched_rules");
Packit Service 384592
        yajl_gen_array_open(g); // matched_rules top-level key
Packit Service 384592
Packit Service 384592
        /* Matched Rules */
Packit Service 384592
Packit Service 384592
        for(i = 0; i < msr->matched_rules->nelts; i++) {
Packit Service 384592
            rule = ((msre_rule **)msr->matched_rules->elts)[i];
Packit Service 384592
            if ((rule != NULL) && (rule->actionset != NULL) && rule->actionset->is_chained && (rule->chain_starter == NULL)) {
Packit Service 384592
                /*
Packit Service 384592
                 * create a separate map for each rule chain
Packit Service 384592
                 * this makes it a lot easier to search for partial chains
Packit Service 384592
                 */
Packit Service 384592
                yajl_gen_map_open(g); // map for this chain
Packit Service 384592
                yajl_kv_bool(g, "chain", 1);
Packit Service 384592
                yajl_string(g, "rules");
Packit Service 384592
                yajl_gen_array_open(g); // array for the rules
Packit Service 384592
Packit Service 384592
                write_rule_json(msr, rule, g);
Packit Service 384592
                do {
Packit Service 384592
                    if (rule->ruleset != NULL)   {
Packit Service 384592
Packit Service 384592
                        next_rule = return_chained_rule(rule,msr);
Packit Service 384592
Packit Service 384592
                        if (next_rule != NULL)  {
Packit Service 384592
Packit Service 384592
                            present = chained_is_matched(msr,next_rule);
Packit Service 384592
Packit Service 384592
                            if (present == 1)   {
Packit Service 384592
                                i++;
Packit Service 384592
                            }
Packit Service 384592
                            write_rule_json(msr, next_rule, g);
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
                    rule = next_rule;
Packit Service 384592
                } while (rule != NULL && rule->actionset != NULL && rule->actionset->is_chained);
Packit Service 384592
                yajl_gen_array_close(g);
Packit Service 384592
Packit Service 384592
                yajl_kv_bool(g, "full_chain_match", present); // if one of the rules didnt match, present is set to 0
Packit Service 384592
                yajl_gen_map_close(g); // close the map for this chain
Packit Service 384592
            } else  {
Packit Service 384592
                yajl_gen_map_open(g);
Packit Service 384592
Packit Service 384592
                yajl_kv_bool(g, "chain", 0);
Packit Service 384592
                yajl_string(g, "rules"); // this really should be 'rule', but we're keeping in line with other chain maps
Packit Service 384592
Packit Service 384592
                yajl_gen_array_open(g);
Packit Service 384592
                if ((rule != NULL) && (rule->actionset != NULL) && !rule->actionset->is_chained && (rule->chain_starter == NULL)) {
Packit Service 384592
                    write_rule_json(msr, rule, g);
Packit Service 384592
                }
Packit Service 384592
                yajl_gen_array_close(g);
Packit Service 384592
Packit Service 384592
                yajl_gen_map_close(g);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        yajl_gen_array_close(g); // matched_rules top-level key is finished
Packit Service 384592
Packit Service 384592
    }
Packit Service 384592
    /* AUDITLOG_PART_ENDMARKER */
Packit Service 384592
Packit Service 384592
    /* finished building JSON */
Packit Service 384592
    yajl_gen_map_close(g); // box it up!
Packit Service 384592
Packit Service 384592
    yajl_gen_get_buf(g, &final_buf, &len;;
Packit Service 384592
    sec_auditlog_write(msr, final_buf, len);
Packit Service 384592
Packit Service 384592
    yajl_gen_clear(g);
Packit Service 384592
    yajl_gen_free(g);
Packit Service 384592
Packit Service 384592
    sec_auditlog_write(msr, "\n", 1);
Packit Service 384592
Packit Service 384592
    /* Return here if we were writing to a serial log
Packit Service 384592
     * as it does not need an index file.
Packit Service 384592
     */
Packit Service 384592
    if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
Packit Service 384592
Packit Service 384592
        /* Unlock the mutex we used to serialise access to the audit log file. */
Packit Service 384592
        rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock);
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s",
Packit Service 384592
                    get_apr_error(msr->mp, rc));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* From here on only concurrent-style processing. */
Packit Service 384592
Packit Service 384592
    /* File handle might already be closed after write failure. */
Packit Service 384592
    if (msr->new_auditlog_fd) {
Packit Service 384592
        apr_file_close(msr->new_auditlog_fd);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Write an entry to the index file */
Packit Service 384592
Packit Service 384592
    /* Calculate hash of the entry. */
Packit Service 384592
    apr_md5_final(md5hash, &msr->new_auditlog_md5ctx);
Packit Service 384592
Packit Service 384592
    str2 = apr_psprintf(msr->mp, "%s %d %d md5:%s", msr->new_auditlog_filename, 0,
Packit Service 384592
            msr->new_auditlog_size, bytes2hex(msr->mp, md5hash, 16));
Packit Service 384592
    if (str2 == NULL) return;
Packit Service 384592
Packit Service 384592
    /* We do not want the index line to be longer than 3980 bytes. */
Packit Service 384592
    limit = 3980;
Packit Service 384592
    was_limited = 0;
Packit Service 384592
Packit Service 384592
    /* If we are logging to a pipe we need to observe and
Packit Service 384592
     * obey the pipe atomic write limit - PIPE_BUF. For
Packit Service 384592
     * more details see the discussion in sec_guardian_logger code.
Packit Service 384592
     */
Packit Service 384592
    if (msr->txcfg->auditlog_name[0] == '|') {
Packit Service 384592
        if (PIPE_BUF < limit) {
Packit Service 384592
            limit = PIPE_BUF;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    limit = limit - strlen(str2) - 5;
Packit Service 384592
    if (limit <= 0) {
Packit Service 384592
        msr_log(msr, 1, "Audit Log: Atomic PIPE write buffer too small: %d", PIPE_BUF);
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    str1 = construct_log_vcombinedus_limited(msr, limit, &was_limited);
Packit Service 384592
    if (str1 == NULL) return;
Packit Service 384592
Packit Service 384592
    if (was_limited == 0) {
Packit Service 384592
        text = apr_psprintf(msr->mp, "%s %s \n", str1, str2);
Packit Service 384592
    } else {
Packit Service 384592
        text = apr_psprintf(msr->mp, "%s %s L\n", str1, str2);
Packit Service 384592
    }
Packit Service 384592
    if (text == NULL) return;
Packit Service 384592
Packit Service 384592
    nbytes = strlen(text);
Packit Service 384592
    if (msr->txcfg->debuglog_level >= 9) {
Packit Service 384592
        msr_log(msr, 9, "Audit Log: Writing %" APR_SIZE_T_FMT " bytes to primary concurrent index", nbytes);
Packit Service 384592
    }
Packit Service 384592
    apr_file_write_full(msr->txcfg->auditlog_fd, text, nbytes, &nbytes_written);
Packit Service 384592
Packit Service 384592
    /* Write to the secondary audit log if we have one */
Packit Service 384592
    if (msr->txcfg->auditlog2_fd != NULL) {
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 9) {
Packit Service 384592
            msr_log(msr, 9, "Audit Log: Writing %" APR_SIZE_T_FMT " bytes to secondary concurrent index", nbytes);
Packit Service 384592
        }
Packit Service 384592
        apr_file_write_full(msr->txcfg->auditlog2_fd, text, nbytes, &nbytes_written);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * Produce an audit log entry in native format.
Packit Service 384592
 */
Packit Service 384592
void sec_audit_logger_native(modsec_rec *msr) {
Packit Service 384592
    const apr_array_header_t *arr = NULL;
Packit Service 384592
    apr_table_entry_t *te = NULL;
Packit Service 384592
    const apr_array_header_t *tarr_pattern = NULL;
Packit Service 384592
    const apr_table_entry_t *telts_pattern = NULL;
Packit Service 384592
    char *str1 = NULL, *str2 = NULL, *text = NULL;
Packit Service 384592
    const msre_rule *rule = NULL, *next_rule = NULL;
Packit Service 384592
    apr_size_t nbytes, nbytes_written;
Packit Service 384592
    unsigned char md5hash[APR_MD5_DIGESTSIZE];
Packit Service 384592
    int was_limited = 0;
Packit Service 384592
    int present = 0;
Packit Service 384592
    int wrote_response_body = 0;
Packit Service 384592
    char *entry_filename, *entry_basename;
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
    int i, limit, k, sanitized_partial, j;
Packit Service 384592
    char *buf = NULL, *pat = NULL;
Packit Service 384592
    msc_parm *mparm = NULL;
Packit Service 384592
    int arg_min, arg_max, sanitize_matched;
Packit Service 384592
Packit Service 384592
    /* the boundary is used by both audit log types */
Packit Service 384592
    msr->new_auditlog_boundary = create_auditlog_boundary(msr->r);
Packit Service 384592
Packit Service 384592
    /* Return silently if we don't have a request line. This
Packit Service 384592
     * means we will not be logging request timeouts.
Packit Service 384592
     */
Packit Service 384592
    if (msr->request_line == NULL) {
Packit Service 384592
        msr_log(msr, 4, "Audit log: Skipping request whose request_line is null.");
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Also return silently if we don't have a file descriptor. */
Packit Service 384592
    if (msr->txcfg->auditlog_fd == NULL) {
Packit Service 384592
        msr_log(msr, 4, "Audit log: Skipping request since there is nowhere to write to.");
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
Packit Service 384592
        /* Serial logging - we already have an open file
Packit Service 384592
         * descriptor to write to.
Packit Service 384592
         */
Packit Service 384592
        msr->new_auditlog_fd = msr->txcfg->auditlog_fd;
Packit Service 384592
    } else {
Packit Service 384592
        /* Concurrent logging - we need to create a brand
Packit Service 384592
         * new file for this request.
Packit Service 384592
         */
Packit Service 384592
        apr_md5_init(&msr->new_auditlog_md5ctx);
Packit Service 384592
Packit Service 384592
        msr->new_auditlog_filename = construct_auditlog_filename(msr->mp, msr->txid);
Packit Service 384592
        if (msr->new_auditlog_filename == NULL) return;
Packit Service 384592
Packit Service 384592
        /* The audit log storage directory should be explicitly
Packit Service 384592
         * defined. But if it isn't try to write to the same
Packit Service 384592
         * directory where the index file is placed. Of course,
Packit Service 384592
         * it is *very* bad practice to allow the Apache user
Packit Service 384592
         * to write to the same directory where a root user is
Packit Service 384592
         * writing to but it's not us that's causing the problem
Packit Service 384592
         * and there isn't anything we can do about that.
Packit Service 384592
         *
Packit Service 384592
         * ENH Actually there is something we can do! We will make
Packit Service 384592
         * SecAuditStorageDir mandatory, ask the user to explicitly
Packit Service 384592
         * define the storage location *and* refuse to work if the
Packit Service 384592
         * index and the storage location are in the same folder.
Packit Service 384592
         */
Packit Service 384592
        if (msr->txcfg->auditlog_storage_dir == NULL) {
Packit Service 384592
            entry_filename = file_dirname(msr->mp, msr->txcfg->auditlog_name);
Packit Service 384592
        }
Packit Service 384592
        else {
Packit Service 384592
            entry_filename = msr->txcfg->auditlog_storage_dir;
Packit Service 384592
        }
Packit Service 384592
        if (entry_filename == NULL) return;
Packit Service 384592
Packit Service 384592
        entry_filename = apr_psprintf(msr->mp, "%s%s", entry_filename, msr->new_auditlog_filename);
Packit Service 384592
        if (entry_filename == NULL) return;
Packit Service 384592
        entry_basename = file_dirname(msr->mp, entry_filename);
Packit Service 384592
        if (entry_basename == NULL) return;
Packit Service 384592
Packit Service 384592
        /* IMP1 Surely it would be more efficient to check the folders for
Packit Service 384592
         * the audit log repository base path in the configuration phase, to reduce
Packit Service 384592
         * the work we do on every request. Also, since our path depends on time,
Packit Service 384592
         * we could cache the time we last checked and don't check if we know
Packit Service 384592
         * the folder is there.
Packit Service 384592
         */
Packit Service 384592
        rc = apr_dir_make_recursive(entry_basename, msr->txcfg->auditlog_dirperms, msr->mp);
Packit Service 384592
        if ((rc != APR_SUCCESS) && (rc != APR_EEXIST)) {
Packit Service 384592
            msr_log(msr, 1, "Audit log: Failed to create subdirectories: %s (%s)",
Packit Service 384592
                entry_basename, get_apr_error(msr->mp, rc));
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        rc = apr_file_open(&msr->new_auditlog_fd, entry_filename,
Packit Service 384592
            APR_WRITE | APR_TRUNCATE | APR_CREATE | APR_BINARY | APR_FILE_NOCLEANUP,
Packit Service 384592
            msr->txcfg->auditlog_fileperms, msr->mp);
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            msr_log(msr, 1, "Audit log: Failed to create file: %s (%s)",
Packit Service 384592
                entry_filename, get_apr_error(msr->mp, rc));
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Lock the mutex, but only if we are using serial format. */
Packit Service 384592
    if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
Packit Service 384592
        rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock);
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s",
Packit Service 384592
                get_apr_error(msr->mp, rc));
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_HEADER */
Packit Service 384592
    text = apr_psprintf(msr->mp, "--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_HEADER);
Packit Service 384592
    sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
    /* Format: time transaction_id remote_addr remote_port local_addr local_port */
Packit Service 384592
Packit Service 384592
    text = apr_psprintf(msr->mp, "[%s] %s %s %u %s %u",
Packit Service 384592
        current_logtime(msr->mp), msr->txid, msr->remote_addr, msr->remote_port,
Packit Service 384592
        msr->local_addr, msr->local_port);
Packit Service 384592
    sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_REQUEST_HEADERS */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_HEADERS) != NULL) {
Packit Service 384592
        text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_HEADERS);
Packit Service 384592
        sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
        sanitize_request_line(msr);
Packit Service 384592
        sec_auditlog_write(msr, msr->request_line, strlen(msr->request_line));
Packit Service 384592
        sec_auditlog_write(msr, "\n", 1);
Packit Service 384592
Packit Service 384592
Packit Service 384592
        arr = apr_table_elts(msr->request_headers);
Packit Service 384592
        te = (apr_table_entry_t *)arr->elts;
Packit Service 384592
Packit Service 384592
        tarr_pattern = apr_table_elts(msr->pattern_to_sanitize);
Packit Service 384592
        telts_pattern = (const apr_table_entry_t*)tarr_pattern->elts;
Packit Service 384592
Packit Service 384592
        for (i = 0; i < arr->nelts; i++) {
Packit Service 384592
            sanitized_partial = 0;
Packit Service 384592
            sanitize_matched = 0;
Packit Service 384592
            text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val);
Packit Service 384592
            if (apr_table_get(msr->request_headers_to_sanitize, te[i].key) != NULL) {
Packit Service 384592
                buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2);
Packit Service 384592
                for ( k = 0; k < tarr_pattern->nelts; k++)  {
Packit Service 384592
                    if(strncmp(telts_pattern[k].key,te[i].key,strlen(te[i].key)) ==0 ) {
Packit Service 384592
                        mparm = (msc_parm *)telts_pattern[k].val;
Packit Service 384592
                        if(mparm->pad_1 == -1)
Packit Service 384592
                            sanitize_matched = 1;
Packit Service 384592
                        pat = strstr(buf,mparm->value);
Packit Service 384592
                        if (pat != NULL)    {
Packit Service 384592
                            j = strlen(mparm->value);
Packit Service 384592
                            arg_min = j;
Packit Service 384592
                            arg_max = 1;
Packit Service 384592
                            while((*pat != '\0')&&(j--)) {
Packit Service 384592
                                if(arg_max > mparm->pad_2)  {
Packit Service 384592
                                    int off = strlen(mparm->value) - arg_max;
Packit Service 384592
                                    int pos = mparm->pad_1-1;
Packit Service 384592
                                    if(off > pos)    {
Packit Service 384592
                                        *pat = '*';
Packit Service 384592
                                    }
Packit Service 384592
                                }
Packit Service 384592
                                arg_max++;
Packit Service 384592
                                arg_min--;
Packit Service 384592
                                pat++;
Packit Service 384592
                            }
Packit Service 384592
                            sanitized_partial = 1;
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                if(sanitized_partial == 1 && sanitize_matched == 0)  {
Packit Service 384592
                    text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, buf);
Packit Service 384592
                } else {
Packit Service 384592
                    memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val));
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_REQUEST_BODY */
Packit Service 384592
Packit Service 384592
    /* Output this part of it was explicitly requested (C) or if it was the faked
Packit Service 384592
     * request body that was requested (I) but we have no reason to fake it (it's
Packit Service 384592
     * already in the correct format).
Packit Service 384592
     */
Packit Service 384592
    if ( (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_BODY) != NULL)
Packit Service 384592
        || ( (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_FAKE_REQUEST_BODY) != NULL)
Packit Service 384592
            && (msr->mpd == NULL) ) )
Packit Service 384592
    {
Packit Service 384592
        if (msr->msc_reqbody_read) {
Packit Service 384592
            const apr_array_header_t *tarr;
Packit Service 384592
            const apr_table_entry_t *telts;
Packit Service 384592
            apr_array_header_t *sorted_args;
Packit Service 384592
            unsigned int offset = 0, last_offset = 0;
Packit Service 384592
            msc_arg *nextarg = NULL;
Packit Service 384592
            int sanitize = 0; /* IMP1 Use constants for "sanitize" values. */
Packit Service 384592
            char *my_error_msg = NULL;
Packit Service 384592
Packit Service 384592
            sorted_args = apr_array_make(msr->mp, 25, sizeof(const msc_arg *));
Packit Service 384592
Packit Service 384592
            /* First we need to sort the arguments that need to be
Packit Service 384592
             * sanitized in descending order (we are using a stack structure
Packit Service 384592
             * to store then so the order will be ascending when we start
Packit Service 384592
             * popping them out). This is because we will
Packit Service 384592
             * be reading the request body sequentially and must
Packit Service 384592
             * sanitize it as we go.
Packit Service 384592
             */
Packit Service 384592
Packit Service 384592
            for(;;) {
Packit Service 384592
                nextarg = NULL;
Packit Service 384592
Packit Service 384592
                /* Find the next largest offset (excluding
Packit Service 384592
                 * the ones we've used up already).
Packit Service 384592
                 */
Packit Service 384592
                tarr = apr_table_elts(msr->arguments_to_sanitize);
Packit Service 384592
                telts = (const apr_table_entry_t*)tarr->elts;
Packit Service 384592
                for(i = 0; i < tarr->nelts; i++) {
Packit Service 384592
                    msc_arg *arg = (msc_arg *)telts[i].val;
Packit Service 384592
                    if (arg->origin != NULL &&
Packit Service 384592
                            strcmp(arg->origin, "BODY") != 0)
Packit Service 384592
                        continue;
Packit Service 384592
Packit Service 384592
                    if (last_offset == 0) { /* The first time we're here. */
Packit Service 384592
                        if (arg->value_origin_offset > offset) {
Packit Service 384592
                            offset = arg->value_origin_offset;
Packit Service 384592
                            nextarg = arg;
Packit Service 384592
                        }
Packit Service 384592
                    } else { /* Not the first time. */
Packit Service 384592
                        if ((arg->value_origin_offset > offset)
Packit Service 384592
                            &&(arg->value_origin_offset < last_offset))
Packit Service 384592
                        {
Packit Service 384592
                            offset = arg->value_origin_offset;
Packit Service 384592
                            nextarg = arg;
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                /* If we don't have the next argument that means
Packit Service 384592
                 * we're done here.
Packit Service 384592
                 */
Packit Service 384592
                if (nextarg == NULL) break;
Packit Service 384592
Packit Service 384592
                sanitize = 2; /* Means time to pop the next argument out. */
Packit Service 384592
                last_offset = offset;
Packit Service 384592
                offset = 0;
Packit Service 384592
                { /* IMP1 Fix this ugly bit here. */
Packit Service 384592
                    msc_arg **x = apr_array_push(sorted_args);
Packit Service 384592
                    *x = nextarg;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Now start retrieving the body chunk by chunk and
Packit Service 384592
             * sanitize data in pieces.
Packit Service 384592
             */
Packit Service 384592
Packit Service 384592
            rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg);
Packit Service 384592
            if (rc < 0) {
Packit Service 384592
                msr_log(msr, 1, "Audit log: %s", my_error_msg);
Packit Service 384592
            } else {
Packit Service 384592
                msc_data_chunk *chunk = NULL;
Packit Service 384592
                unsigned int chunk_offset = 0;
Packit Service 384592
                unsigned int sanitize_offset = 0;
Packit Service 384592
                unsigned int sanitize_length = 0;
Packit Service 384592
                text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_BODY);
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
                for(;;) {
Packit Service 384592
                    rc = modsecurity_request_body_retrieve(msr, &chunk, -1, &my_error_msg);
Packit Service 384592
                    if (chunk != NULL) {
Packit Service 384592
                        /* Anything greater than 1 means we have more data to sanitize. */
Packit Service 384592
                        while (sanitize > 1) {
Packit Service 384592
                            msc_arg **arg = NULL;
Packit Service 384592
Packit Service 384592
                            if (sanitize == 2) {
Packit Service 384592
                                /* Get the next argument from the stack. */
Packit Service 384592
                                arg = (msc_arg **)apr_array_pop(sorted_args);
Packit Service 384592
                                if (arg == NULL) sanitize = 0; /* We're done sanitising. */
Packit Service 384592
                                else {
Packit Service 384592
                                    /* Continue with sanitation to process the
Packit Service 384592
                                     * retrieved argument.
Packit Service 384592
                                     */
Packit Service 384592
                                    sanitize = 1;
Packit Service 384592
                                    sanitize_offset = (*arg)->value_origin_offset;
Packit Service 384592
                                    sanitize_length = (*arg)->value_origin_len;
Packit Service 384592
                                }
Packit Service 384592
                            }
Packit Service 384592
Packit Service 384592
                            if (sanitize) {
Packit Service 384592
                                /* Check if the data we want to sanitize is
Packit Service 384592
                                 * stored in the current chunk.
Packit Service 384592
                                 */
Packit Service 384592
                                if (chunk_offset + chunk->length > sanitize_offset) {
Packit Service 384592
                                    unsigned int soff; /* data offset within chunk */
Packit Service 384592
                                    unsigned int len;  /* amount in this chunk to sanitize */
Packit Service 384592
Packit Service 384592
                                    soff = sanitize_offset - chunk_offset;
Packit Service 384592
Packit Service 384592
                                    if (soff + sanitize_length <= chunk->length) {
Packit Service 384592
                                        /* The entire argument resides in the current chunk. */
Packit Service 384592
                                        len = sanitize_length;
Packit Service 384592
                                        sanitize = 2; /* Get another parameter to sanitize. */
Packit Service 384592
                                    } else {
Packit Service 384592
                                        /* Some work to do here but we'll need to seek
Packit Service 384592
                                         * another chunk.
Packit Service 384592
                                         */
Packit Service 384592
                                        len = chunk->length - soff;
Packit Service 384592
                                        sanitize_offset += len;
Packit Service 384592
                                        sanitize_length -= len;
Packit Service 384592
                                        sanitize = 1; /* It's OK to go to the next chunk. */
Packit Service 384592
                                    }
Packit Service 384592
Packit Service 384592
                                    /* Yes, we actually write over the original data.
Packit Service 384592
                                     * We shouldn't be needing it any more.
Packit Service 384592
                                     */
Packit Service 384592
                                    if (soff + len <= chunk->length) { /* double check */
Packit Service 384592
                                        memset((char *)chunk->data + soff, '*', len);
Packit Service 384592
                                    }
Packit Service 384592
                                }
Packit Service 384592
                            }
Packit Service 384592
                        }
Packit Service 384592
Packit Service 384592
                        /* Write the sanitized chunk to the log
Packit Service 384592
                         * and advance to the next chunk. */
Packit Service 384592
                        sec_auditlog_write(msr, chunk->data, chunk->length);
Packit Service 384592
                        chunk_offset += chunk->length;
Packit Service 384592
                    }
Packit Service 384592
Packit Service 384592
                    if (rc <= 0) {
Packit Service 384592
                        break;
Packit Service 384592
                    }
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                if (rc < 0) {
Packit Service 384592
                    msr_log(msr, 1, "Audit log: %s", my_error_msg);
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                modsecurity_request_body_retrieve_end(msr);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_FAKE_REQUEST_BODY */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_FAKE_REQUEST_BODY) != NULL) {
Packit Service 384592
        if ((msr->msc_reqbody_read)&&(msr->mpd != NULL)) {
Packit Service 384592
            char *buffer = NULL;
Packit Service 384592
Packit Service 384592
            buffer = multipart_reconstruct_urlencoded_body_sanitize(msr);
Packit Service 384592
            if (buffer == NULL) {
Packit Service 384592
                msr_log(msr, 1, "Audit log: Failed to reconstruct request body.");
Packit Service 384592
            } else {
Packit Service 384592
                text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_FAKE_REQUEST_BODY);
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
                sec_auditlog_write(msr, buffer, strlen(buffer));
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_A_RESPONSE_HEADERS */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_A_RESPONSE_HEADERS) != NULL) {
Packit Service 384592
        text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_A_RESPONSE_HEADERS);
Packit Service 384592
        sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
        /* There are no response headers (or the status line) in HTTP 0.9 */
Packit Service 384592
        if (msr->response_headers_sent) {
Packit Service 384592
            if (msr->status_line != NULL && msr->status_line[0] != '\0') {
Packit Service 384592
                text = apr_psprintf(msr->mp, "%s %s\n", msr->response_protocol,
Packit Service 384592
                        msr->status_line);
Packit Service 384592
            } else {
Packit Service 384592
                text = apr_psprintf(msr->mp, "%s %u\n", msr->response_protocol,
Packit Service 384592
                        msr->response_status);
Packit Service 384592
            }
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
            /* Output headers */
Packit Service 384592
Packit Service 384592
            arr = apr_table_elts(msr->response_headers);
Packit Service 384592
            te = (apr_table_entry_t *)arr->elts;
Packit Service 384592
Packit Service 384592
            tarr_pattern = apr_table_elts(msr->pattern_to_sanitize);
Packit Service 384592
            telts_pattern = (const apr_table_entry_t*)tarr_pattern->elts;
Packit Service 384592
Packit Service 384592
            for (i = 0; i < arr->nelts; i++) {
Packit Service 384592
                sanitized_partial = 0;
Packit Service 384592
                sanitize_matched = 0;
Packit Service 384592
                text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val);
Packit Service 384592
                if (apr_table_get(msr->response_headers_to_sanitize, te[i].key) != NULL) {
Packit Service 384592
                    buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2);
Packit Service 384592
Packit Service 384592
                    for ( k = 0; k < tarr_pattern->nelts; k++)  {
Packit Service 384592
                        if(strncmp(telts_pattern[k].key,te[i].key,strlen(te[i].key)) ==0 ) {
Packit Service 384592
                            mparm = (msc_parm *)telts_pattern[k].val;
Packit Service 384592
                            if(mparm->pad_1 == -1)
Packit Service 384592
                                sanitize_matched = 1;
Packit Service 384592
                            pat = strstr(buf,mparm->value);
Packit Service 384592
                            if (pat != NULL)    {
Packit Service 384592
                                j = strlen(mparm->value);
Packit Service 384592
                                arg_min = j;
Packit Service 384592
                                arg_max = 1;
Packit Service 384592
                                while((*pat != '\0')&&(j--)) {
Packit Service 384592
                                    if(arg_max > mparm->pad_2)  {
Packit Service 384592
                                        int off = strlen(mparm->value) - arg_max;
Packit Service 384592
                                        int pos = mparm->pad_1-1;
Packit Service 384592
                                        if(off > pos)    {
Packit Service 384592
                                            *pat = '*';
Packit Service 384592
                                        }
Packit Service 384592
                                    }
Packit Service 384592
                                    arg_max++;
Packit Service 384592
                                    arg_min--;
Packit Service 384592
                                    pat++;
Packit Service 384592
                                }
Packit Service 384592
                                sanitized_partial = 1;
Packit Service 384592
                            }
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
Packit Service 384592
                    if(sanitized_partial == 1 && sanitize_matched == 0)  {
Packit Service 384592
                        text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, buf);
Packit Service 384592
                    } else {
Packit Service 384592
                        memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val));
Packit Service 384592
                    }
Packit Service 384592
                }
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    apr_table_clear(msr->pattern_to_sanitize);
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_RESPONSE_BODY */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_RESPONSE_BODY) != NULL) {
Packit Service 384592
        if (msr->resbody_data != NULL) {
Packit Service 384592
            text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_RESPONSE_BODY);
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
            sec_auditlog_write(msr, msr->resbody_data, msr->resbody_length);
Packit Service 384592
            wrote_response_body = 1;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_TRAILER */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_TRAILER) != NULL) {
Packit Service 384592
        apr_time_t now = apr_time_now();
Packit Service 384592
        text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_TRAILER);
Packit Service 384592
        sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
        /* Messages */
Packit Service 384592
        for(i = 0; i < msr->alerts->nelts; i++) {
Packit Service 384592
            text = apr_psprintf(msr->mp, "Message: %s\n", ((char **)msr->alerts->elts)[i]);
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Apache error messages */
Packit Service 384592
        for(i = 0; i < msr->error_messages->nelts; i++) {
Packit Service 384592
            error_message_t *em = (((error_message_t **)msr->error_messages->elts)[i]);
Packit Service 384592
            text = apr_psprintf(msr->mp, "Apache-Error: %s\n",
Packit Service 384592
                format_error_log_message(msr->mp, em));
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Action */
Packit Service 384592
        if (msr->was_intercepted) {
Packit Service 384592
            text = apr_psprintf(msr->mp, "Action: Intercepted (phase %d)\n", msr->intercept_phase);
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Apache-Handler */
Packit Service 384592
#ifdef LOG_NO_HANDLER
Packit Service 384592
	if (msr->txcfg->debuglog_level >= 9)
Packit Service 384592
#endif
Packit Service 384592
	if (msr->r->handler != NULL) {
Packit Service 384592
            text = apr_psprintf(msr->mp, "Apache-Handler: %s\n", msr->r->handler);
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Stopwatch; left in for compatibility reasons */
Packit Service 384592
#ifdef DLOG_NO_STOPWATCH
Packit Service 384592
	if (msr->txcfg->debuglog_level >= 9) {
Packit Service 384592
#endif
Packit Service 384592
        text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n",
Packit Service 384592
            msr->request_time, (now - msr->request_time));
Packit Service 384592
        sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
        /* Stopwatch2 */
Packit Service 384592
        {
Packit Service 384592
            char *perf_all = format_all_performance_variables(msr, msr->mp);
Packit Service 384592
Packit Service 384592
            text = apr_psprintf(msr->mp, "Stopwatch2: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT
Packit Service 384592
                "; %s\n", msr->request_time, (now - msr->request_time), perf_all);
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
        }
Packit Service 384592
#ifdef DLOG_NO_STOPWATCH
Packit Service 384592
        }
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
        /* Our response body does not contain chunks */
Packit Service 384592
        /* ENH Only write this when the output was chunked. */
Packit Service 384592
        /* ENH Add info when request body was decompressed, dechunked too. */
Packit Service 384592
#ifdef LOG_NO_DECHUNK
Packit Service 384592
	if (msr->txcfg->debuglog_level >= 9)
Packit Service 384592
#endif
Packit Service 384592
        if (wrote_response_body) {
Packit Service 384592
            text = apr_psprintf(msr->mp, "Response-Body-Transformed: Dechunked\n");
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
#ifdef LOG_NO_SERVER_CONTEXT
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 9) {
Packit Service 384592
#endif
Packit Service 384592
        sec_auditlog_write_producer_header(msr);
Packit Service 384592
Packit Service 384592
        /* Server */
Packit Service 384592
        if (msr->server_software != NULL) {
Packit Service 384592
            text = apr_psprintf(msr->mp, "Server: %s\n", msr->server_software);
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Sanitised arguments */
Packit Service 384592
        {
Packit Service 384592
            const apr_array_header_t *tarr;
Packit Service 384592
            const apr_table_entry_t *telts;
Packit Service 384592
Packit Service 384592
            tarr = apr_table_elts(msr->arguments_to_sanitize);
Packit Service 384592
            telts = (const apr_table_entry_t*)tarr->elts;
Packit Service 384592
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                text = apr_psprintf(msr->mp, "Sanitised-Args: ");
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            for(i = 0; i < tarr->nelts; i++) {
Packit Service 384592
                msc_arg *arg = (msc_arg *)telts[i].val;
Packit Service 384592
                text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "),
Packit Service 384592
                    log_escape(msr->mp, arg->name), ((i == (tarr->nelts - 1)) ? ".\n" : ""));
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Sanitised request headers */
Packit Service 384592
        {
Packit Service 384592
            const apr_array_header_t *tarr;
Packit Service 384592
            const apr_table_entry_t *telts;
Packit Service 384592
Packit Service 384592
            tarr = apr_table_elts(msr->request_headers_to_sanitize);
Packit Service 384592
            telts = (const apr_table_entry_t*)tarr->elts;
Packit Service 384592
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                text = apr_psprintf(msr->mp, "Sanitised-Request-Headers: ");
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            for(i = 0; i < tarr->nelts; i++) {
Packit Service 384592
                text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "),
Packit Service 384592
                    log_escape(msr->mp, telts[i].key), ((i == (tarr->nelts - 1)) ? ".\n" : ""));
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Sanitised response headers */
Packit Service 384592
        {
Packit Service 384592
            const apr_array_header_t *tarr;
Packit Service 384592
            const apr_table_entry_t *telts;
Packit Service 384592
Packit Service 384592
            tarr = apr_table_elts(msr->response_headers_to_sanitize);
Packit Service 384592
            telts = (const apr_table_entry_t*)tarr->elts;
Packit Service 384592
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                text = apr_psprintf(msr->mp, "Sanitised-Response-Headers: ");
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            for(i = 0; i < tarr->nelts; i++) {
Packit Service 384592
                text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "),
Packit Service 384592
                    log_escape(msr->mp, telts[i].key), ((i == (tarr->nelts - 1)) ? ".\n" : ""));
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
#ifdef LOG_NO_SERVER_CONTEXT
Packit Service 384592
	}
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
	/* Web application info. */
Packit Service 384592
        if ( ((msr->txcfg->webappid != NULL)&&(strcmp(msr->txcfg->webappid, "default") != 0))
Packit Service 384592
            || (msr->sessionid != NULL) || (msr->userid != NULL))
Packit Service 384592
        {
Packit Service 384592
            text = apr_psprintf(msr->mp, "WebApp-Info: \"%s\" \"%s\" \"%s\"\n",
Packit Service 384592
                msr->txcfg->webappid == NULL ? "-" : log_escape(msr->mp, msr->txcfg->webappid),
Packit Service 384592
                msr->sessionid == NULL ? "-" : log_escape(msr->mp, msr->sessionid),
Packit Service 384592
                msr->userid == NULL ? "-" : log_escape(msr->mp, msr->userid));
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if ( ((msr->txcfg->sensor_id != NULL)&&(strcmp(msr->txcfg->sensor_id, "default") != 0)))
Packit Service 384592
        {
Packit Service 384592
            text = apr_psprintf(msr->mp, "Sensor-Id: \"%s\"\n",
Packit Service 384592
                msr->txcfg->sensor_id == NULL ? "-" : log_escape(msr->mp, msr->txcfg->sensor_id)),
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
Packit Service 384592
        if (msr->txcfg->is_enabled > 0) {
Packit Service 384592
            text = apr_psprintf(msr->mp, "Engine-Mode: \"%s\"\n",
Packit Service 384592
                msr->txcfg->is_enabled == 1 ? "DETECTION_ONLY" : "ENABLED"),
Packit Service 384592
            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Rule performance time */
Packit Service 384592
        if(msr->txcfg->max_rule_time > 0)   {
Packit Service 384592
            const apr_array_header_t *tarr;
Packit Service 384592
            const apr_table_entry_t *telts;
Packit Service 384592
Packit Service 384592
            tarr = apr_table_elts(msr->perf_rules);
Packit Service 384592
            telts = (const apr_table_entry_t*)tarr->elts;
Packit Service 384592
Packit Service 384592
            if (tarr->nelts > 0) {
Packit Service 384592
                text = apr_psprintf(msr->mp, "Rules-Performance-Info: ");
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            for(i = 0; i < tarr->nelts; i++) {
Packit Service 384592
                text = apr_psprintf(msr->mp, "%s\"%s=%s\"%s", ((i == 0) ? "" : ", "),
Packit Service 384592
                    log_escape(msr->mp, telts[i].key), log_escape(msr->mp, telts[i].val), ((i == (tarr->nelts - 1)) ? ".\n" : ""));
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_UPLOADS */
Packit Service 384592
    if ((strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_UPLOADS) != NULL) && (msr->mpd != NULL)) {
Packit Service 384592
        multipart_part **parts = NULL;
Packit Service 384592
        unsigned int total_size = 0;
Packit Service 384592
        int cfiles = 0;
Packit Service 384592
Packit Service 384592
        text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_UPLOADS);
Packit Service 384592
        sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
        parts = (multipart_part **)msr->mpd->parts->elts;
Packit Service 384592
        for(cfiles = 0; cfiles < msr->mpd->parts->nelts; cfiles++) {
Packit Service 384592
            if (parts[cfiles]->type == MULTIPART_FILE) {
Packit Service 384592
                if(parts[cfiles]->filename != NULL) {
Packit Service 384592
                    text = apr_psprintf(msr->mp, "%d,%u,\"%s\",\"%s\"\n", cfiles+1, parts[cfiles]->tmp_file_size, log_escape(msr->mp, parts[cfiles]->filename), log_escape(msr->mp, parts[cfiles]->content_type ? parts[cfiles]->content_type : "<Unknown ContentType>"));
Packit Service 384592
                    sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
                    total_size += parts[cfiles]->tmp_file_size;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        text = apr_psprintf(msr->mp, "Total,%u\n", total_size);
Packit Service 384592
        sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* AUDITLOG_PART_MATCHEDRULES */
Packit Service 384592
Packit Service 384592
    if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_MATCHEDRULES) != NULL) {
Packit Service 384592
        text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_MATCHEDRULES);
Packit Service 384592
        sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
        /* Matched Rules */
Packit Service 384592
Packit Service 384592
        for(i = 0; i < msr->matched_rules->nelts; i++) {
Packit Service 384592
            rule = ((msre_rule **)msr->matched_rules->elts)[i];
Packit Service 384592
            if ((rule != NULL) && (rule->actionset != NULL) && rule->actionset->is_chained && (rule->chain_starter == NULL)) {
Packit Service 384592
                text = apr_psprintf(msr->mp, "%s\n", rule->unparsed);
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
                do {
Packit Service 384592
                    if (rule->ruleset != NULL)   {
Packit Service 384592
Packit Service 384592
                        next_rule = return_chained_rule(rule,msr);
Packit Service 384592
Packit Service 384592
                        if (next_rule != NULL)  {
Packit Service 384592
Packit Service 384592
                            present = chained_is_matched(msr,next_rule);
Packit Service 384592
Packit Service 384592
                            if (present == 0)   {
Packit Service 384592
                                text = apr_psprintf(msr->mp, "#%s\n",next_rule->unparsed);
Packit Service 384592
                            } else  {
Packit Service 384592
                                text = apr_psprintf(msr->mp, "%s\n",next_rule->unparsed);
Packit Service 384592
                                i++;
Packit Service 384592
                            }
Packit Service 384592
                            sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
                    rule = next_rule;
Packit Service 384592
                } while (rule != NULL && rule->actionset != NULL && rule->actionset->is_chained);
Packit Service 384592
                text = apr_psprintf(msr->mp, "\n");
Packit Service 384592
                sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
            } else  {
Packit Service 384592
                if ((rule != NULL) && (rule->actionset != NULL) && !rule->actionset->is_chained && (rule->chain_starter == NULL)) {
Packit Service 384592
                    text = apr_psprintf(msr->mp, "%s\n\n", rule->unparsed);
Packit Service 384592
                    sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    /* AUDITLOG_PART_ENDMARKER */
Packit Service 384592
    text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_ENDMARKER);
Packit Service 384592
    sec_auditlog_write(msr, text, strlen(text));
Packit Service 384592
Packit Service 384592
    /* Return here if we were writing to a serial log
Packit Service 384592
     * as it does not need an index file.
Packit Service 384592
     */
Packit Service 384592
    if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
Packit Service 384592
        sec_auditlog_write(msr, "\n", 1);
Packit Service 384592
Packit Service 384592
        /* Unlock the mutex we used to serialise access to the audit log file. */
Packit Service 384592
        rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock);
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s",
Packit Service 384592
                    get_apr_error(msr->mp, rc));
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* From here on only concurrent-style processing. */
Packit Service 384592
Packit Service 384592
    /* File handle might already be closed after write failure. */
Packit Service 384592
    if (msr->new_auditlog_fd) {
Packit Service 384592
        apr_file_close(msr->new_auditlog_fd);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Write an entry to the index file */
Packit Service 384592
Packit Service 384592
    /* Calculate hash of the entry. */
Packit Service 384592
    apr_md5_final(md5hash, &msr->new_auditlog_md5ctx);
Packit Service 384592
Packit Service 384592
    str2 = apr_psprintf(msr->mp, "%s %d %d md5:%s", msr->new_auditlog_filename, 0,
Packit Service 384592
            msr->new_auditlog_size, bytes2hex(msr->mp, md5hash, 16));
Packit Service 384592
    if (str2 == NULL) return;
Packit Service 384592
Packit Service 384592
    /* We do not want the index line to be longer than 3980 bytes. */
Packit Service 384592
    limit = 3980;
Packit Service 384592
    was_limited = 0;
Packit Service 384592
Packit Service 384592
    /* If we are logging to a pipe we need to observe and
Packit Service 384592
     * obey the pipe atomic write limit - PIPE_BUF. For
Packit Service 384592
     * more details see the discussion in sec_guardian_logger code.
Packit Service 384592
     */
Packit Service 384592
    if (msr->txcfg->auditlog_name[0] == '|') {
Packit Service 384592
        if (PIPE_BUF < limit) {
Packit Service 384592
            limit = PIPE_BUF;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    limit = limit - strlen(str2) - 5;
Packit Service 384592
    if (limit <= 0) {
Packit Service 384592
        msr_log(msr, 1, "Audit Log: Atomic PIPE write buffer too small: %d", PIPE_BUF);
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    str1 = construct_log_vcombinedus_limited(msr, limit, &was_limited);
Packit Service 384592
    if (str1 == NULL) return;
Packit Service 384592
Packit Service 384592
    if (was_limited == 0) {
Packit Service 384592
        text = apr_psprintf(msr->mp, "%s %s \n", str1, str2);
Packit Service 384592
    } else {
Packit Service 384592
        text = apr_psprintf(msr->mp, "%s %s L\n", str1, str2);
Packit Service 384592
    }
Packit Service 384592
    if (text == NULL) return;
Packit Service 384592
Packit Service 384592
    nbytes = strlen(text);
Packit Service 384592
    if (msr->txcfg->debuglog_level >= 9) {
Packit Service 384592
        msr_log(msr, 9, "Audit Log: Writing %" APR_SIZE_T_FMT " bytes to primary concurrent index", nbytes);
Packit Service 384592
    }
Packit Service 384592
    apr_file_write_full(msr->txcfg->auditlog_fd, text, nbytes, &nbytes_written);
Packit Service 384592
Packit Service 384592
    /* Write to the secondary audit log if we have one */
Packit Service 384592
    if (msr->txcfg->auditlog2_fd != NULL) {
Packit Service 384592
        if (msr->txcfg->debuglog_level >= 9) {
Packit Service 384592
            msr_log(msr, 9, "Audit Log: Writing %" APR_SIZE_T_FMT " bytes to secondary concurrent index", nbytes);
Packit Service 384592
        }
Packit Service 384592
        apr_file_write_full(msr->txcfg->auditlog2_fd, text, nbytes, &nbytes_written);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * Handler for audit log writers.
Packit Service 384592
 */
Packit Service 384592
void sec_audit_logger(modsec_rec *msr) {
Packit Service 384592
    #ifdef WITH_YAJL
Packit Service 384592
    if (msr->txcfg->auditlog_format == AUDITLOGFORMAT_JSON) {
Packit Service 384592
        sec_audit_logger_json(msr);
Packit Service 384592
    } else {
Packit Service 384592
    #endif
Packit Service 384592
        sec_audit_logger_native(msr);
Packit Service 384592
    #ifdef WITH_YAJL
Packit Service 384592
    }
Packit Service 384592
    #endif
Packit Service 384592
}