Blame alp2/alp2.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 <stdio.h>
Packit Service 384592
#include <stdlib.h>
Packit Service 384592
#include <ctype.h>
Packit Service 384592
#include <strings.h>
Packit Service 384592
#include <sys/param.h>
Packit Service 384592
Packit Service 384592
#include "alp2.h"
Packit Service 384592
Packit Service 384592
#ifdef DEBUG
Packit Service 384592
#define alp_debug(...) fprintf(stderr, __VA_ARGS__)
Packit Service 384592
#else
Packit Service 384592
#define alp_debug(...)
Packit Service 384592
#endif /* DEBUG */
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Add one error to the audit log entry.
Packit Service 384592
 */
Packit Service 384592
static void add_error(alp2_t *alp, int is_fatal, const char *text, ...)
Packit Service 384592
{
Packit Service 384592
    char *str = NULL;
Packit Service 384592
    va_list ap;
Packit Service 384592
Packit Service 384592
    if (is_fatal) {
Packit Service 384592
        alp->parse_error = 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    va_start(ap, text);
Packit Service 384592
    str = apr_pvsprintf(alp->auditlog->mp, text, ap);
Packit Service 384592
    va_end(ap);
Packit Service 384592
Packit Service 384592
    *(char **)apr_array_push(alp->errors) = str;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Parse the Response-Body-Transformed trailer header.
Packit Service 384592
 */
Packit Service 384592
static int handle_part_H_parse_ResponseTFN(alp2_t *alp, const char *s)
Packit Service 384592
{
Packit Service 384592
    char *capture = NULL;
Packit Service 384592
    int ovector[33];
Packit Service 384592
    int rc;
Packit Service 384592
Packit Service 384592
    // TODO This header is optional, but is not allowed to appear more than once.
Packit Service 384592
Packit Service 384592
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Parse the Action trailer header.
Packit Service 384592
 */
Packit Service 384592
static int handle_part_H_parse_Action(alp2_t *alp, const char *s)
Packit Service 384592
{
Packit Service 384592
    char *capture = NULL;
Packit Service 384592
    int ovector[33];
Packit Service 384592
    int rc;
Packit Service 384592
Packit Service 384592
    // TODO This header is optional, but is not allowed to appear more than once.
Packit Service 384592
Packit Service 384592
    alp->auditlog->was_intercepted = 1;
Packit Service 384592
Packit Service 384592
    rc = pcre_exec(alp->trailer_action_pattern, NULL, s, strlen(s), 0, 0, ovector, 30);
Packit Service 384592
    if (rc < 0) {
Packit Service 384592
        add_error(alp, 1, "Part H: Failed to parse Action header");
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    capture = apr_pstrmemdup(alp->auditlog->mp, s + ovector[2 * 1],
Packit Service 384592
        ovector[2 * 1 + 1] - ovector[2 * 1]);
Packit Service 384592
Packit Service 384592
    alp->auditlog->intercept_phase = atoi(capture);
Packit Service 384592
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Convert two hexadecimal characters into a character.
Packit Service 384592
 */
Packit Service 384592
static uint8_t x2c(uint8_t *what)
Packit Service 384592
{
Packit Service 384592
    register uint8_t digit;
Packit Service 384592
Packit Service 384592
    digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
Packit Service 384592
    digit *= 16;
Packit Service 384592
    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
Packit Service 384592
Packit Service 384592
    return digit;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Remove a layer of encoding from a string. This function needs to be used
Packit Service 384592
 * for every piece of data ModSecurity encoded for a message.
Packit Service 384592
 */
Packit Service 384592
static int remove_slashes(uint8_t *s)
Packit Service 384592
{
Packit Service 384592
    uint8_t *d = s;
Packit Service 384592
Packit Service 384592
    while(*s != '\0') {
Packit Service 384592
        if ((*s == '\\')&&(*(s + 1) != '\0')) {
Packit Service 384592
            s++;
Packit Service 384592
Packit Service 384592
            switch(*s) {
Packit Service 384592
                case 'b' :
Packit Service 384592
                    *d = '\b';
Packit Service 384592
                    break;
Packit Service 384592
                case 'n' :
Packit Service 384592
                    *d = '\n';
Packit Service 384592
                    break;
Packit Service 384592
                case 'r' :
Packit Service 384592
                    *d = '\r';
Packit Service 384592
                    break;
Packit Service 384592
                case 't' :
Packit Service 384592
                    *d = '\t';
Packit Service 384592
                    break;
Packit Service 384592
                case 'v' :
Packit Service 384592
                    *d = '\v';
Packit Service 384592
                    break;
Packit Service 384592
                case '\\' :
Packit Service 384592
                    *d = '\\';
Packit Service 384592
                    break;
Packit Service 384592
                case '"' :
Packit Service 384592
                    *d = '"';
Packit Service 384592
                    break;
Packit Service 384592
                case 'x' :
Packit Service 384592
                    if (  (*(s + 1) != '\0')
Packit Service 384592
                        &&(*(s + 2) != '\0')
Packit Service 384592
                        &&(isxdigit(*(s + 1)))
Packit Service 384592
                        &&(isxdigit(*(s + 2)))
Packit Service 384592
                    ) {
Packit Service 384592
                        *d = x2c(s + 1);
Packit Service 384592
                        s += 2;
Packit Service 384592
                    }
Packit Service 384592
                    else {
Packit Service 384592
                        /* Invalid encoding. */
Packit Service 384592
                        return -1;
Packit Service 384592
                    }
Packit Service 384592
                    break;
Packit Service 384592
                default :
Packit Service 384592
                    /* Invalid encoding. */
Packit Service 384592
                    return -1;
Packit Service 384592
                    break;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        else {
Packit Service 384592
            *d = *s;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        s++;
Packit Service 384592
        d++;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    *d = '\0';
Packit Service 384592
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Process one (ModSecurity message) meta-data fragment.
Packit Service 384592
 */
Packit Service 384592
static int handle_part_H_parse_Message_meta(alp2_t *alp, alp2_msg_t *message,
Packit Service 384592
    const char *l, const char *string_start, const char *string_end)
Packit Service 384592
{
Packit Service 384592
    const char *value;
Packit Service 384592
Packit Service 384592
    // XXX if ((*string_start != '"')||(*string_end != '"')||(string_end <= string_start)) {
Packit Service 384592
    if (string_end <= string_start) {
Packit Service 384592
        add_error(alp, 1, "Part H: Invalid handle_part_H_parse_Message_meta invocation");
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if ((*string_start != '"')||(*string_end != '"')) {
Packit Service 384592
        value = apr_pstrndup(alp->auditlog->mp, string_start, (string_end - string_start) + 1);
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        value = apr_pstrndup(alp->auditlog->mp, string_start + 1, (string_end - string_start - 1));
Packit Service 384592
    }
Packit Service 384592
    if (value == NULL) {
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (remove_slashes((uint8_t *)value) < 0) {
Packit Service 384592
        add_error(alp, 1, "Part H: Invalid encoding in meta-data fragment");
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Target ( at THE_TARGET) */
Packit Service 384592
    if (strncmp(l, "at ", 3) == 0) {
Packit Service 384592
        if (message->target != NULL) {
Packit Service 384592
            add_error(alp, 1, "Part H: Already seen target");
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        message->target = value;
Packit Service 384592
Packit Service 384592
        return 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* id */
Packit Service 384592
    if (strncmp(l, "id ", 3) == 0) {
Packit Service 384592
        if (message->id != NULL) {
Packit Service 384592
            add_error(alp, 1, "Part H: Already seen meta-data: id");
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        message->id = value;
Packit Service 384592
Packit Service 384592
        return 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* rev */
Packit Service 384592
    if (strncmp(l, "rev ", 4) == 0) {
Packit Service 384592
        if (message->rev != NULL) {
Packit Service 384592
            add_error(alp, 1, "Part H: Already seen meta-data: rev");
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        message->rev = value;
Packit Service 384592
Packit Service 384592
        return 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* msg */
Packit Service 384592
    if (strncmp(l, "msg ", 4) == 0) {
Packit Service 384592
        if (message->msg != NULL) {
Packit Service 384592
            add_error(alp, 1, "Part H: Already seen meta-data: msg");
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        message->msg = value;
Packit Service 384592
Packit Service 384592
        return 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* data */
Packit Service 384592
    if (strncmp(l, "data ", 4) == 0) {
Packit Service 384592
        if (message->data != NULL) {
Packit Service 384592
            add_error(alp, 1, "Part H: Already seen meta-data: data");
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        message->data = value;
Packit Service 384592
Packit Service 384592
        return 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* file */
Packit Service 384592
    if (strncmp(l, "file ", 5) == 0) {
Packit Service 384592
        if (message->file != NULL) {
Packit Service 384592
            add_error(alp, 1, "Part H: Already seen meta-data: file");
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        message->file = value;
Packit Service 384592
Packit Service 384592
        return 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* line */
Packit Service 384592
    if (strncmp(l, "line ", 5) == 0) {
Packit Service 384592
        if (message->file_line != (unsigned long)-1) {
Packit Service 384592
            add_error(alp, 1, "Part H: Already seen meta-data: line");
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        // TODO Validate.
Packit Service 384592
        message->file_line = atoi(value);
Packit Service 384592
Packit Service 384592
        return 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* tag */
Packit Service 384592
    if (strncmp(l, "tag ", 4) == 0) {
Packit Service 384592
        *(char **)apr_array_push(message->tags) = (char *)value;
Packit Service 384592
        return 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* severity */
Packit Service 384592
    if (strncmp(l, "severity ", 9) == 0) {
Packit Service 384592
        if (  (strcmp(value, "0") == 0)
Packit Service 384592
            ||(strcasecmp(value, "EMERGENCY") == 0))
Packit Service 384592
        {
Packit Service 384592
            message->severity = 0;
Packit Service 384592
            return 1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (  (strcmp(value, "1") == 0)
Packit Service 384592
            ||(strcasecmp(value, "ALERT") == 0))
Packit Service 384592
        {
Packit Service 384592
            message->severity = 1;
Packit Service 384592
            return 1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (  (strcmp(value, "2") == 0)
Packit Service 384592
            ||(strcasecmp(value, "CRITICAL") == 0))
Packit Service 384592
        {
Packit Service 384592
            message->severity = 2;
Packit Service 384592
            return 1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (  (strcmp(value, "3") == 0)
Packit Service 384592
            ||(strcasecmp(value, "ERROR") == 0))
Packit Service 384592
        {
Packit Service 384592
            message->severity = 3;
Packit Service 384592
            return 1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (  (strcmp(value, "4") == 0)
Packit Service 384592
            ||(strcasecmp(value, "WARNING") == 0))
Packit Service 384592
        {
Packit Service 384592
            message->severity = 4;
Packit Service 384592
            return 1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (  (strcmp(value, "5") == 0)
Packit Service 384592
            ||(strcasecmp(value, "NOTICE") == 0))
Packit Service 384592
        {
Packit Service 384592
            message->severity = 5;
Packit Service 384592
            return 1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (  (strcmp(value, "6") == 0)
Packit Service 384592
            ||(strcasecmp(value, "INFO") == 0))
Packit Service 384592
        {
Packit Service 384592
            message->severity = 6;
Packit Service 384592
            return 1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (  (strcmp(value, "7") == 0)
Packit Service 384592
            ||(strcasecmp(value, "DEBUG") == 0))
Packit Service 384592
        {
Packit Service 384592
            message->severity = 7;
Packit Service 384592
            return 1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        add_error(alp, 1, "Part H: Invalid severity value: %s", value);
Packit Service 384592
        
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* offset */
Packit Service 384592
    if (strncmp(l, "offset ", 7) == 0) {
Packit Service 384592
        if (message->offset != (size_t)-1) {
Packit Service 384592
            /* Already seen "offset". */
Packit Service 384592
            add_error(alp, 1, "Part H: Already seen fragment offset");
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        // TODO Validate.
Packit Service 384592
        message->offset = atoi(value);
Packit Service 384592
Packit Service 384592
        return 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Ignore unknown meta-data information. */
Packit Service 384592
    
Packit Service 384592
    return 0;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Parse the Message trailer header. More than one such header
Packit Service 384592
 * can exist in an audit log, and each represents one ModSecurity
Packit Service 384592
 * message.
Packit Service 384592
 */
Packit Service 384592
static int handle_part_H_parse_Message(alp2_t *alp, const char *s)
Packit Service 384592
{
Packit Service 384592
    alp2_msg_t *message = NULL;
Packit Service 384592
    char *l = (char *)(s + strlen(s) - 1);
Packit Service 384592
    char *engine_message_start = (char *)s;
Packit Service 384592
    char *engine_message_end = NULL;
Packit Service 384592
    char *string_start = NULL, *string_end = NULL;
Packit Service 384592
    char *fragment_end = NULL;
Packit Service 384592
    char *tptr;
Packit Service 384592
    int in_string;
Packit Service 384592
    int done;
Packit Service 384592
Packit Service 384592
    /* Create one new message structure. */
Packit Service 384592
    message = apr_pcalloc(alp->auditlog->mp, sizeof(alp2_msg_t));
Packit Service 384592
    if (message == NULL) {
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    message->file_line = (unsigned long)-1;
Packit Service 384592
    message->offset = (size_t)-1;
Packit Service 384592
    message->severity = -1;
Packit Service 384592
    message->warning = 0;
Packit Service 384592
Packit Service 384592
    if (strncasecmp("warning. ", s, 9) == 0) {
Packit Service 384592
        message->warning = 1;
Packit Service 384592
        engine_message_start += 9;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    message->tags = apr_array_make(alp->auditlog->mp, 4, sizeof(const char *));
Packit Service 384592
Packit Service 384592
    /* Start at the end of the message and go back identifying
Packit Service 384592
     * the meta-data fragments as we go. Stop when we find the
Packit Service 384592
     * end of the engine message.
Packit Service 384592
     */
Packit Service 384592
    done = in_string = 0;
Packit Service 384592
    while ((l >= s)&&(!done)) {
Packit Service 384592
        if (in_string == 0) {
Packit Service 384592
            /* Outside string. */
Packit Service 384592
Packit Service 384592
            // TODO Make sure this is not an escaped char
Packit Service 384592
            switch(*l) {
Packit Service 384592
                case ' ' :
Packit Service 384592
                    /* Do nothing. */
Packit Service 384592
                    break;
Packit Service 384592
                case ']' :
Packit Service 384592
                    fragment_end = l;
Packit Service 384592
                    break;
Packit Service 384592
                case '[' :
Packit Service 384592
                    if (fragment_end) {
Packit Service 384592
                        /* Found one meta-data fragment. */
Packit Service 384592
                        // TODO This parser implementation allows for invalid
Packit Service 384592
                        //      meta-data fragments to be accepted. It would be
Packit Service 384592
                        //      nice to check the format of the fragment (e.g.
Packit Service 384592
                        //      by matching it against a regular expression
Packit Service 384592
                        //      pattern) before we accept any data. At this point
Packit Service 384592
                        //      l points to the first byte of the fragment, and
Packit Service 384592
                        //      fragment_end to the last.
Packit Service 384592
                        handle_part_H_parse_Message_meta(alp, message,
Packit Service 384592
                            l + 1, string_start, string_end);
Packit Service 384592
Packit Service 384592
                        fragment_end = NULL;
Packit Service 384592
                        string_start = NULL;
Packit Service 384592
                        string_end = NULL;
Packit Service 384592
                    }
Packit Service 384592
                    break;
Packit Service 384592
                case '"' :
Packit Service 384592
                    /* Found the end of a string. */
Packit Service 384592
                    in_string = 1;
Packit Service 384592
                    string_end = l;
Packit Service 384592
                    break;
Packit Service 384592
                default :
Packit Service 384592
                    if (!fragment_end) {
Packit Service 384592
                        /* There are no more meta-data fragments. */
Packit Service 384592
                        engine_message_end = l;
Packit Service 384592
                        done = 1;
Packit Service 384592
                    }
Packit Service 384592
                    break;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        else {
Packit Service 384592
            /* In string. We are only interested
Packit Service 384592
             * in where the string ends.
Packit Service 384592
             */
Packit Service 384592
            if ((*l == '"')&&((l - 1) >= s)&&(*(l - 1) != '\\')) {
Packit Service 384592
                in_string = 0;
Packit Service 384592
                string_start = l;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    
Packit Service 384592
        l--;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Target is between " at " and "." */
Packit Service 384592
    tptr = engine_message_start;
Packit Service 384592
    while ((tptr = strstr(tptr, " at ")) && (tptr < engine_message_end)) {
Packit Service 384592
        char *tend = strchr(tptr, '.');
Packit Service 384592
        if ((tend <= engine_message_end) && (tend - tptr > 5)) {
Packit Service 384592
            int rc = handle_part_H_parse_Message_meta(alp, message, tptr + 1,
Packit Service 384592
                                                      tptr + 4, tend - 1);
Packit Service 384592
            if (rc == 1) {
Packit Service 384592
                /* Remove the target data from the message */
Packit Service 384592
                engine_message_end = tptr;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        break;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (engine_message_end == NULL) {
Packit Service 384592
        add_error(alp, 1, "Part H: Failed parsing ModSecurity message: %s", s);
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    message->engine_message = apr_pstrndup(alp->auditlog->mp, engine_message_start, (engine_message_end - engine_message_start + 1));
Packit Service 384592
Packit Service 384592
    /* Add this message to the audit log. */
Packit Service 384592
    *(alp2_msg_t **)apr_array_push(alp->auditlog->messages) = message;
Packit Service 384592
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Parse the Stopwatch trailer header.
Packit Service 384592
 */
Packit Service 384592
static int handle_part_H_parse_Stopwatch(alp2_t *alp, const char *s)
Packit Service 384592
{
Packit Service 384592
    int ovector[33];
Packit Service 384592
    int i, rc;
Packit Service 384592
Packit Service 384592
    // TODO This header is required (a check for its appearance is made when
Packit Service 384592
    //      handling the end of an H part), and is not allowed to appear
Packit Service 384592
    //      more than once.
Packit Service 384592
Packit Service 384592
    rc = pcre_exec(alp->trailer_stopwatch_pattern, NULL, s, strlen(s), 0, 0, ovector, 30);
Packit Service 384592
    if (rc < 0) {
Packit Service 384592
        add_error(alp, 1, "Part H: Failed to parse Stopwatch header");
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Loop through the captures. */
Packit Service 384592
    for (i = 0; i < rc; i++) {
Packit Service 384592
        char *capture = apr_pstrmemdup(alp->auditlog->mp, s + ovector[2 * i],
Packit Service 384592
            ovector[2 * i + 1] - ovector[2 * i]);
Packit Service 384592
Packit Service 384592
        switch (i) {
Packit Service 384592
            case 1 : /* timestamp */
Packit Service 384592
                // TODO Validate
Packit Service 384592
                alp->auditlog->timestamp = apr_atoi64(capture);
Packit Service 384592
                break;
Packit Service 384592
            case 2 : /* duration */
Packit Service 384592
                // TODO Validate
Packit Service 384592
                alp->auditlog->duration = apr_atoi64(capture);
Packit Service 384592
                break;
Packit Service 384592
            case 3 : /* ignore (group of three further time elements)*/
Packit Service 384592
                break;
Packit Service 384592
            case 4 : /* t1 */
Packit Service 384592
                break;
Packit Service 384592
            case 5 : /* t2 */
Packit Service 384592
                break;
Packit Service 384592
            case 6 : /* t3 */
Packit Service 384592
                break;
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
 * Parse the WebApp-Info trailer header.
Packit Service 384592
 */
Packit Service 384592
static int handle_part_H_parse_WebAppInfo(alp2_t *alp, const char *s)
Packit Service 384592
{
Packit Service 384592
    int ovector[33];
Packit Service 384592
    int i, rc;
Packit Service 384592
Packit Service 384592
    // TODO This header is optional, but it is not allowed to appear more than once.
Packit Service 384592
Packit Service 384592
    rc = pcre_exec(alp->trailer_webappinfo_pattern, NULL, s, strlen(s), 0, 0, ovector, 30);
Packit Service 384592
    if (rc < 0) {
Packit Service 384592
        add_error(alp, 1, "Part H: Failed to parse WebApp-Info header");
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Loop through the captures. */
Packit Service 384592
    for (i = 0; i < rc; i++) {
Packit Service 384592
        char *capture = apr_pstrmemdup(alp->auditlog->mp, s + ovector[2 * i],
Packit Service 384592
            ovector[2 * i + 1] - ovector[2 * i]);
Packit Service 384592
Packit Service 384592
        switch (i) {
Packit Service 384592
            case 1 : /* application ID */
Packit Service 384592
                // TODO Validate
Packit Service 384592
                alp->auditlog->application_id = capture;
Packit Service 384592
                break;
Packit Service 384592
            case 2 : /* session ID */
Packit Service 384592
                // TODO Validate
Packit Service 384592
                if (strcmp(capture, "-") != 0) {
Packit Service 384592
                    alp->auditlog->session_id = capture;
Packit Service 384592
                }
Packit Service 384592
                break;
Packit Service 384592
            case 3 : /* user ID */
Packit Service 384592
                // TODO Validate
Packit Service 384592
                if (strcmp(capture, "-") != 0) {
Packit Service 384592
                    alp->auditlog->user_id = capture;
Packit Service 384592
                }
Packit Service 384592
                break;
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
 * Handle part H events.
Packit Service 384592
 */
Packit Service 384592
static void handle_part_H(alp2_t *alp, int event_type)
Packit Service 384592
{
Packit Service 384592
    /* Part data. */
Packit Service 384592
    if (event_type == ALP2_EVENT_PART_DATA) {
Packit Service 384592
        char *line = alp2_pp_line_chomp(alp->pp);
Packit Service 384592
Packit Service 384592
        /* This part ends with an empty line. */
Packit Service 384592
        if (strlen(line) == 0) {
Packit Service 384592
            alp->part_data_done = 1;
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Extract the header information. */
Packit Service 384592
        {
Packit Service 384592
            char *name = NULL, *value = NULL;
Packit Service 384592
            int ovector[33];
Packit Service 384592
            int i, rc;
Packit Service 384592
Packit Service 384592
            /* Header line. */
Packit Service 384592
Packit Service 384592
            /* Extract the fields. */
Packit Service 384592
            rc = pcre_exec(alp->header_pattern, NULL, line, strlen(line), 0, 0, ovector, 30);
Packit Service 384592
            if (rc < 0) {
Packit Service 384592
                add_error(alp, 1, "Part H: Failed to parse header: %i", rc);
Packit Service 384592
                return;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Loop through the captures. */
Packit Service 384592
            for (i = 0; i < rc; i++) {
Packit Service 384592
                char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i],
Packit Service 384592
                    ovector[2 * i + 1] - ovector[2 * i]);
Packit Service 384592
Packit Service 384592
                switch(i) {
Packit Service 384592
                    case 1 :
Packit Service 384592
                        name = capture;
Packit Service 384592
                        break;
Packit Service 384592
                    case 2 :
Packit Service 384592
                        value = capture;
Packit Service 384592
                        break;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Add header to the table. */
Packit Service 384592
            apr_table_addn(alp->auditlog->trailer_headers, name, value);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Part end. */
Packit Service 384592
    if (event_type == ALP2_EVENT_PART_END) {
Packit Service 384592
        const apr_array_header_t *tarr = apr_table_elts(alp->auditlog->trailer_headers);
Packit Service 384592
        apr_table_entry_t *te = NULL;
Packit Service 384592
        const char *s = NULL;
Packit Service 384592
        int stopwatch = 0;
Packit Service 384592
        int rc = 0;
Packit Service 384592
        int i;
Packit Service 384592
Packit Service 384592
        if ((tarr == NULL) || (tarr->nelts == 0)) {
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
        
Packit Service 384592
        /* Here we are going to extract certain headers and
Packit Service 384592
         * parse them to populate the corresponding fields in
Packit Service 384592
         * the auditlog structure.
Packit Service 384592
         */
Packit Service 384592
Packit Service 384592
        te = (apr_table_entry_t *)tarr->elts;
Packit Service 384592
        for (i = 0; i < tarr->nelts; i++) {
Packit Service 384592
            const char *key = te[i].key;
Packit Service 384592
            const char *val = te[i].val;
Packit Service 384592
Packit Service 384592
            if ((key == NULL) || (val == NULL)) {
Packit Service 384592
                continue;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Action: optional */
Packit Service 384592
            else if (strcmp("Action", key) == 0) {
Packit Service 384592
                rc = handle_part_H_parse_Action(alp, val);
Packit Service 384592
            }
Packit Service 384592
        
Packit Service 384592
            /* Message: optional */
Packit Service 384592
            else if (strcmp("Message", key) == 0) {
Packit Service 384592
                rc = handle_part_H_parse_Message(alp, val);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Apache-Handler: optional */
Packit Service 384592
            else if (strcmp("Apache-Handler", key) == 0) {
Packit Service 384592
                rc = 0;
Packit Service 384592
                // TODO Only one allowed
Packit Service 384592
                alp->auditlog->handler = apr_pstrdup(alp->auditlog->mp, val);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Producer: optional */
Packit Service 384592
            else if (strcmp("Producer", key) == 0) {
Packit Service 384592
                rc = 0;
Packit Service 384592
                // TODO Only one allowed
Packit Service 384592
                alp->auditlog->producer = apr_pstrdup(alp->auditlog->mp, val);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Server: optional */
Packit Service 384592
            else if (strcmp("Server", key) == 0) {
Packit Service 384592
                rc = 0;
Packit Service 384592
                // TODO Only one allowed
Packit Service 384592
                alp->auditlog->server = apr_pstrdup(alp->auditlog->mp, val);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Response-Body-Transformed: optional */
Packit Service 384592
            else if (strcmp("Response-Body-Transformed", key) == 0) {
Packit Service 384592
                rc = 0;
Packit Service 384592
                // TODO Only one allowed
Packit Service 384592
                alp->auditlog->response_tfn = apr_pstrdup(alp->auditlog->mp, val);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Stopwatch: required */
Packit Service 384592
            else if (strcmp("Stopwatch", key) == 0) {
Packit Service 384592
                stopwatch = 1;
Packit Service 384592
                rc = handle_part_H_parse_Stopwatch(alp, val);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* WebApp-Info: optional */
Packit Service 384592
            else if (strcmp("WebApp-Info", key) == 0) {
Packit Service 384592
                rc = handle_part_H_parse_WebAppInfo(alp, val);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            if (rc < 0) {
Packit Service 384592
                /* No need to report anything, it's already been reported. */
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (stopwatch == 0) {
Packit Service 384592
            add_error(alp, 1, "Part H: Stopwatch header missing");
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Handle part F events.
Packit Service 384592
 */
Packit Service 384592
static void handle_part_F(alp2_t *alp, int event_type)
Packit Service 384592
{
Packit Service 384592
    /* Part data. */
Packit Service 384592
    if (event_type == ALP2_EVENT_PART_DATA) {
Packit Service 384592
        char *line = alp2_pp_line_chomp(alp->pp);
Packit Service 384592
Packit Service 384592
        /* This part ends with an empty line. */
Packit Service 384592
        if (strlen(line) == 0) {
Packit Service 384592
            alp->part_data_done = 1;
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* The first line should be the response line. */
Packit Service 384592
        if (alp->part_line_counter == 1) {
Packit Service 384592
            int ovector[33];
Packit Service 384592
            int i, rc;
Packit Service 384592
Packit Service 384592
            /* Response line. */
Packit Service 384592
Packit Service 384592
            /* Extract the fields. */
Packit Service 384592
            rc = pcre_exec(alp->response_line_pattern, NULL, line, strlen(line), 0, 0, ovector, 30);
Packit Service 384592
            if (rc < 0) {
Packit Service 384592
                add_error(alp, 1, "Part F: Failed to parse response line: %i", rc);
Packit Service 384592
                return;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Loop through the captures. */
Packit Service 384592
            for (i = 0; i < rc; i++) {
Packit Service 384592
                char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i],
Packit Service 384592
                    ovector[2 * i + 1] - ovector[2 * i]);
Packit Service 384592
Packit Service 384592
                switch(i) {
Packit Service 384592
                    case 1 :
Packit Service 384592
                        alp->auditlog->response_protocol = capture;
Packit Service 384592
                        break;
Packit Service 384592
                    case 2 :
Packit Service 384592
                        alp->auditlog->response_status = atoi(capture);
Packit Service 384592
                        break;
Packit Service 384592
                    case 4 :
Packit Service 384592
                        alp->auditlog->response_message = capture;
Packit Service 384592
                        break;
Packit Service 384592
                        break;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        else {
Packit Service 384592
            char *name = NULL, *value = NULL;
Packit Service 384592
            int ovector[33];
Packit Service 384592
            int i, rc;
Packit Service 384592
Packit Service 384592
            /* Response header line. */
Packit Service 384592
Packit Service 384592
            /* Extract the fields. */
Packit Service 384592
            rc = pcre_exec(alp->header_pattern, NULL, line, strlen(line), 0, 0, ovector, 30);
Packit Service 384592
            if (rc < 0) {
Packit Service 384592
                add_error(alp, 1, "Part F: Failed to parse response header: %i", rc);
Packit Service 384592
                return;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Loop through the captures. */
Packit Service 384592
            for (i = 0; i < rc; i++) {
Packit Service 384592
                char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i],
Packit Service 384592
                    ovector[2 * i + 1] - ovector[2 * i]);
Packit Service 384592
Packit Service 384592
                switch(i) {
Packit Service 384592
                    case 1 :
Packit Service 384592
                        name = capture;
Packit Service 384592
                        break;
Packit Service 384592
                    case 2 :
Packit Service 384592
                        value = capture;
Packit Service 384592
                        break;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Add header to the table. */
Packit Service 384592
            apr_table_addn(alp->auditlog->response_headers, name, value);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Part end. */
Packit Service 384592
    if (event_type == ALP2_EVENT_PART_END) {
Packit Service 384592
        /* If any of the response headers need
Packit Service 384592
         * special handling, place the code here.
Packit Service 384592
         */
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Parse the URI. APR-Util does most of the work here.
Packit Service 384592
 */
Packit Service 384592
static int handle_part_B_parse_uri(alp2_t *alp)
Packit Service 384592
{
Packit Service 384592
    char *u = (char *)alp->auditlog->request_uri;
Packit Service 384592
    apr_uri_t *uri = NULL;
Packit Service 384592
Packit Service 384592
    if ((  alp->auditlog->request_method == NULL)
Packit Service 384592
        ||(alp->auditlog->request_uri == NULL))
Packit Service 384592
    {
Packit Service 384592
        return 0;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Since this is not a proper URI but a path, handle
Packit Service 384592
     * the leading double slash.
Packit Service 384592
     */
Packit Service 384592
    while ((u[0] == '/') && (u[1] == '/')) {
Packit Service 384592
        u++;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    uri = apr_pcalloc(alp->auditlog->mp, sizeof(apr_uri_t));    
Packit Service 384592
Packit Service 384592
    if (strcasecmp(alp->auditlog->request_method, "CONNECT") == 0) {
Packit Service 384592
        if (apr_uri_parse_hostinfo(alp->auditlog->mp, u, uri) != APR_SUCCESS) {
Packit Service 384592
            add_error(alp, 0, "Info: Failed to parse request URI (hostinfo)");
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        if (apr_uri_parse(alp->auditlog->mp, u, uri) != APR_SUCCESS) {
Packit Service 384592
            add_error(alp, 0, "Info: Failed to parse request URI");
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    alp->auditlog->parsed_uri = uri;
Packit Service 384592
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Handle part B events.
Packit Service 384592
 */
Packit Service 384592
static void handle_part_B(alp2_t *alp, int event_type)
Packit Service 384592
{
Packit Service 384592
    /* Part data. */
Packit Service 384592
    if (event_type == ALP2_EVENT_PART_DATA) {
Packit Service 384592
        char *line = alp2_pp_line_chomp(alp->pp);
Packit Service 384592
Packit Service 384592
        /* This part ends with an empty line. */
Packit Service 384592
        if (strlen(line) == 0) {
Packit Service 384592
            alp->part_data_done = 1;
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* The first line should be the request line. */
Packit Service 384592
        if (alp->part_line_counter == 1) {
Packit Service 384592
            int ovector[33];
Packit Service 384592
            int i, rc;
Packit Service 384592
Packit Service 384592
            /* Request line. */
Packit Service 384592
Packit Service 384592
            /* Extract the fields. */
Packit Service 384592
            rc = pcre_exec(alp->request_line_pattern, NULL, line, strlen(line), 0, 0, ovector, 30);
Packit Service 384592
            if (rc < 0) {
Packit Service 384592
                add_error(alp, 1, "Part B: Failed to parse request line: %i", rc);
Packit Service 384592
                return;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            alp->auditlog->request_line_valid = 1;
Packit Service 384592
Packit Service 384592
            /* Loop through the captures. */
Packit Service 384592
            for (i = 0; i < rc; i++) {
Packit Service 384592
                char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i],
Packit Service 384592
                    ovector[2 * i + 1] - ovector[2 * i]);
Packit Service 384592
Packit Service 384592
                switch(i) {
Packit Service 384592
                    case 0 :
Packit Service 384592
                        alp->auditlog->request_line = capture;
Packit Service 384592
                        break;
Packit Service 384592
                    case 1 :
Packit Service 384592
                        alp->auditlog->request_method = capture;
Packit Service 384592
                        break;
Packit Service 384592
                    case 2 :
Packit Service 384592
                        alp->auditlog->request_uri = capture;
Packit Service 384592
                        if (handle_part_B_parse_uri(alp) != 1) {
Packit Service 384592
                            // TODO Do we want to do anything on error?
Packit Service 384592
                        }
Packit Service 384592
                        break;
Packit Service 384592
                    case 3 :
Packit Service 384592
                        alp->auditlog->request_protocol = capture;
Packit Service 384592
                        break;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        else {
Packit Service 384592
            char *name = NULL, *value = NULL;
Packit Service 384592
            int ovector[33];
Packit Service 384592
            int i, rc;
Packit Service 384592
Packit Service 384592
            /* Header line. */
Packit Service 384592
Packit Service 384592
            /* Extract the fields. */
Packit Service 384592
            rc = pcre_exec(alp->header_pattern, NULL, line, strlen(line), 0, 0, ovector, 30);
Packit Service 384592
            if (rc < 0) {
Packit Service 384592
                add_error(alp, 1, "Part B: Failed to parse request header: %i", rc);
Packit Service 384592
                return;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Loop through the captures. */
Packit Service 384592
            for (i = 0; i < rc; i++) {
Packit Service 384592
                char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i],
Packit Service 384592
                    ovector[2 * i + 1] - ovector[2 * i]);
Packit Service 384592
Packit Service 384592
                switch(i) {
Packit Service 384592
                    case 1 :
Packit Service 384592
                        name = capture;
Packit Service 384592
                        break;
Packit Service 384592
                    case 2 :
Packit Service 384592
                        value = capture;
Packit Service 384592
                        break;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* ModSecurity 1.9.x adds some requests headers of
Packit Service 384592
             * its own, and we don't want them.
Packit Service 384592
             */
Packit Service 384592
            if (strncmp(name, "mod_security-", 13) != 0) {
Packit Service 384592
                /* Add header to the table. */
Packit Service 384592
                apr_table_addn(alp->auditlog->request_headers, name, value);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Part end. */
Packit Service 384592
    if (event_type == ALP2_EVENT_PART_END) {
Packit Service 384592
        /* Determine hostname. */
Packit Service 384592
Packit Service 384592
        // TODO I think the right thing to do is use the port numbers
Packit Service 384592
        //      only when the host itself is a numerical IP.
Packit Service 384592
Packit Service 384592
        /* Try the URI first. */
Packit Service 384592
        if (  (alp->auditlog->parsed_uri != NULL)
Packit Service 384592
            &&(alp->auditlog->parsed_uri->hostname != NULL))
Packit Service 384592
        {
Packit Service 384592
            if (   (alp->auditlog->parsed_uri->port != 0)
Packit Service 384592
                && (alp->auditlog->parsed_uri->port != 80)
Packit Service 384592
                && (alp->auditlog->parsed_uri->port != 443) )
Packit Service 384592
            {
Packit Service 384592
                // TODO Do not use the port number if the hostname
Packit Service 384592
                //      is not numeric.
Packit Service 384592
                alp->auditlog->hostname = apr_psprintf(alp->auditlog->mp, "%s:%i", 
Packit Service 384592
                    alp->auditlog->parsed_uri->hostname,  alp->auditlog->parsed_uri->port);
Packit Service 384592
            }
Packit Service 384592
            else {
Packit Service 384592
                // TODO Always use the port number if the hostname
Packit Service 384592
                //      is numeric.
Packit Service 384592
                alp->auditlog->hostname = alp->auditlog->parsed_uri->hostname;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        else {
Packit Service 384592
            /* Try the Host header. */
Packit Service 384592
            char *s = (char *)apr_table_get(alp->auditlog->request_headers, "Host");
Packit Service 384592
            if (s != NULL) {
Packit Service 384592
                // TODO If the hostname is not numeric, remove the port
Packit Service 384592
                //      numbers if present.
Packit Service 384592
                alp->auditlog->hostname = s;
Packit Service 384592
            }
Packit Service 384592
            else {
Packit Service 384592
                /* Use the destination IP and port. */
Packit Service 384592
                alp->auditlog->hostname = apr_psprintf(alp->auditlog->mp, "%s:%i",
Packit Service 384592
                alp->auditlog->dst_ip, alp->auditlog->dst_port);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Handle part A events.
Packit Service 384592
 */
Packit Service 384592
static void handle_part_A(alp2_t *alp, int event_type)
Packit Service 384592
{
Packit Service 384592
    /* Part data. */
Packit Service 384592
    if (event_type == ALP2_EVENT_PART_DATA) {
Packit Service 384592
        char *line = alp2_pp_line_chomp(alp->pp);
Packit Service 384592
        int ovector[33];
Packit Service 384592
        int i, rc;
Packit Service 384592
Packit Service 384592
        /* This part can have only one line,
Packit Service 384592
         * so we don't expect to be here again.
Packit Service 384592
         */
Packit Service 384592
        alp->part_data_done = 1;
Packit Service 384592
Packit Service 384592
        /* Extract the fields. */
Packit Service 384592
        rc = pcre_exec(alp->part_a_pattern, NULL, line, strlen(line), 0, 0, ovector, 30);
Packit Service 384592
        if (rc < 0) {
Packit Service 384592
            add_error(alp, 1, "Part A: Parsing failed: %i", rc);
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Loop through the captures. */
Packit Service 384592
        for (i = 0; i < rc; i++) {
Packit Service 384592
            char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i],
Packit Service 384592
                ovector[2 * i + 1] - ovector[2 * i]);
Packit Service 384592
Packit Service 384592
            switch(i) {
Packit Service 384592
                case 1 : /* timestamp in Apache format */
Packit Service 384592
                    /* We don't need it as we use the one from the H part. */
Packit Service 384592
                    break;
Packit Service 384592
                case 2 : /* transaction ID */
Packit Service 384592
                    alp->auditlog->id = capture;
Packit Service 384592
                    break;
Packit Service 384592
                case 3 : /* source address */
Packit Service 384592
                    // TODO Validate
Packit Service 384592
                    alp->auditlog->src_ip = capture;
Packit Service 384592
                    break;
Packit Service 384592
                case 4 : /* source port */
Packit Service 384592
                    // TODO Validate
Packit Service 384592
                    alp->auditlog->src_port = atoi(capture);
Packit Service 384592
                    break;
Packit Service 384592
                case 5 : /* destination address */
Packit Service 384592
                    // TODO Validate
Packit Service 384592
                    alp->auditlog->dst_ip = capture;
Packit Service 384592
                    break;
Packit Service 384592
                case 6 : /* destinatio port */
Packit Service 384592
                    // TODO Validate
Packit Service 384592
                    alp->auditlog->dst_port = atoi(capture);
Packit Service 384592
                    break;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Part end. */
Packit Service 384592
    if (event_type == ALP2_EVENT_PART_END) {
Packit Service 384592
        /* Place part post-validation here. */
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Create a new audit log data structure, allocating
Packit Service 384592
 * memory from the provided memory pool.
Packit Service 384592
 */
Packit Service 384592
auditlog2_t *alp2_auditlog_create(apr_pool_t *mp)
Packit Service 384592
{
Packit Service 384592
    auditlog2_t *al;
Packit Service 384592
Packit Service 384592
    /* Create a new memory pool and the
Packit Service 384592
     * auditlog structure in it. We will use the
Packit Service 384592
     * parent pool of the parser pool, in order to
Packit Service 384592
     * ensure the auditlog memory structures survive
Packit Service 384592
     * the death of the parser.
Packit Service 384592
     */
Packit Service 384592
    al = apr_pcalloc(mp, sizeof(auditlog2_t));
Packit Service 384592
    al->mp = mp;
Packit Service 384592
    
Packit Service 384592
Packit Service 384592
    al->request_headers = apr_table_make(al->mp, 20);
Packit Service 384592
    al->response_headers = apr_table_make(al->mp, 20);
Packit Service 384592
    al->trailer_headers = apr_table_make(al->mp, 20);
Packit Service 384592
    al->messages = apr_array_make(al->mp, 10, sizeof(const alp2_msg_t *));
Packit Service 384592
    al->intercept_phase = -1;
Packit Service 384592
Packit Service 384592
    return al;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Destroy the provided audit log entry.
Packit Service 384592
 */
Packit Service 384592
void alp2_auditlog_destroy(auditlog2_t *al)
Packit Service 384592
{
Packit Service 384592
    apr_pool_destroy(al->mp);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Handle ALP2_EVENT_ENTRY_START.
Packit Service 384592
 */
Packit Service 384592
static void handle_entry_start(alp2_t *alp)
Packit Service 384592
{
Packit Service 384592
    /* Create a new data structure to hold the entry. */
Packit Service 384592
    alp->auditlog = alp2_auditlog_create(alp->pp->current_entry->mp);
Packit Service 384592
    alp->auditlog->pp_entry = alp->pp->current_entry;
Packit Service 384592
Packit Service 384592
    /* Reset entry flags. */
Packit Service 384592
    alp->previous_part_id = 0;
Packit Service 384592
    alp->seen_part_h = 0;    
Packit Service 384592
    alp->parse_error = 0;
Packit Service 384592
    alp->errors = apr_array_make(alp->auditlog->mp, 4, sizeof(const char *));
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Handle ALP2_EVENT_ENTRY_END.
Packit Service 384592
 */
Packit Service 384592
static void handle_entry_end(alp2_t *alp)
Packit Service 384592
{
Packit Service 384592
    if (alp->parse_error) {
Packit Service 384592
        /* No need to validate the entry since we've
Packit Service 384592
         * previously encountered a problem with it.
Packit Service 384592
         */
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        /* Final entry validation. */
Packit Service 384592
Packit Service 384592
        /* Have we seen the H part? (We must have seen the A
Packit Service 384592
         * part, otherwise the entry would have begain in
Packit Service 384592
         * the first place.
Packit Service 384592
         */
Packit Service 384592
        if (alp->seen_part_h == 0) {
Packit Service 384592
            add_error(alp, 1, "Entry does not have part H.");
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Invoke the upstream callback to handle the entry. */
Packit Service 384592
    if (alp->user_callback(alp) == 0) {
Packit Service 384592
        alp->done = 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Upstream owns the audit log entry now. */
Packit Service 384592
    alp->auditlog = NULL;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Handle ALP2_EVENT_PART_START.
Packit Service 384592
 */
Packit Service 384592
static void handle_part_start(alp2_t *alp)
Packit Service 384592
{
Packit Service 384592
    if (alp->parse_error) {
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Reset part flags. */
Packit Service 384592
    alp->part_line_counter = 0;
Packit Service 384592
    alp->part_data_done = 0;
Packit Service 384592
Packit Service 384592
    /* Is this part allowed/expected? */
Packit Service 384592
    if (alp->previous_part_id == 0) {
Packit Service 384592
        if (alp->pp->current_part->id != 'A') {
Packit Service 384592
            add_error(alp, 1, "Expected part A but got %c.", alp->pp->current_part->id);
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Invoke the appropriate part handler. */
Packit Service 384592
    switch(alp->pp->current_part->id) {
Packit Service 384592
        case 'A' :
Packit Service 384592
            handle_part_A(alp, ALP2_EVENT_PART_START);
Packit Service 384592
            break;
Packit Service 384592
        case 'B' :
Packit Service 384592
            handle_part_B(alp, ALP2_EVENT_PART_START);
Packit Service 384592
            break;
Packit Service 384592
        case 'F' :
Packit Service 384592
            handle_part_F(alp, ALP2_EVENT_PART_START);
Packit Service 384592
            break;
Packit Service 384592
        case 'H' :
Packit Service 384592
            alp->seen_part_h = 1;
Packit Service 384592
            handle_part_H(alp, ALP2_EVENT_PART_START);
Packit Service 384592
            break;
Packit Service 384592
        default :
Packit Service 384592
            /* Ignore unknown part. */
Packit Service 384592
            break;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * Handle ALP2_EVENT_PART_END.
Packit Service 384592
 */
Packit Service 384592
static void handle_part_end(alp2_t *alp)
Packit Service 384592
{
Packit Service 384592
    if (alp->parse_error) {
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Invoke the appropriate part handler. */
Packit Service 384592
    switch(alp->pp->current_part->id) {
Packit Service 384592
        case 'A' :
Packit Service 384592
            handle_part_A(alp, ALP2_EVENT_PART_END);
Packit Service 384592
            break;
Packit Service 384592
        case 'B' :
Packit Service 384592
            handle_part_B(alp, ALP2_EVENT_PART_END);
Packit Service 384592
        case 'F' :
Packit Service 384592
            handle_part_F(alp, ALP2_EVENT_PART_END);
Packit Service 384592
            break;
Packit Service 384592
        case 'H' :
Packit Service 384592
            handle_part_H(alp, ALP2_EVENT_PART_END);
Packit Service 384592
            break;
Packit Service 384592
        default :
Packit Service 384592
            /* Ignore unknown part. */
Packit Service 384592
            break;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Remember the last part processed. */
Packit Service 384592
    alp->previous_part_id = alp->pp->current_part->id;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * Handle ALP2_EVENT_PART_DATA.
Packit Service 384592
 */
Packit Service 384592
static void handle_part_data(alp2_t *alp)
Packit Service 384592
{
Packit Service 384592
    if (alp->parse_error) {
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    alp->part_line_counter++;
Packit Service 384592
Packit Service 384592
    if (alp->part_data_done) {
Packit Service 384592
        add_error(alp, 1, "Unexpected data for part %c.", alp->pp->current_part->id);
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Invoke the appropriate part handler. */
Packit Service 384592
    switch(alp->pp->current_part->id) {
Packit Service 384592
        case 'A' :
Packit Service 384592
            handle_part_A(alp, ALP2_EVENT_PART_DATA);
Packit Service 384592
            break;
Packit Service 384592
        case 'B' :
Packit Service 384592
            handle_part_B(alp, ALP2_EVENT_PART_DATA);
Packit Service 384592
            break;
Packit Service 384592
        case 'F' :
Packit Service 384592
            handle_part_F(alp, ALP2_EVENT_PART_DATA);
Packit Service 384592
            break;
Packit Service 384592
        case 'H' :
Packit Service 384592
            handle_part_H(alp, ALP2_EVENT_PART_DATA);
Packit Service 384592
            break;
Packit Service 384592
        default :
Packit Service 384592
            /* Ignore unknown part. */
Packit Service 384592
            break;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * This function handles callbacks from
Packit Service 384592
 * the lower-level (part) parser.
Packit Service 384592
 */
Packit Service 384592
static int alp2_callback(alp2_pp_t *pp, int event_type)
Packit Service 384592
{
Packit Service 384592
    alp2_t *alp = (alp2_t *)pp->user_data;
Packit Service 384592
Packit Service 384592
    /* Choose where to dispatch the event based
Packit Service 384592
     * on the event type.
Packit Service 384592
     */
Packit Service 384592
    switch(event_type) {
Packit Service 384592
        case ALP2_EVENT_ENTRY_START :
Packit Service 384592
            handle_entry_start(alp);
Packit Service 384592
            break;
Packit Service 384592
        case ALP2_EVENT_ENTRY_END :
Packit Service 384592
            handle_entry_end(alp);
Packit Service 384592
            break;
Packit Service 384592
        case ALP2_EVENT_PART_START :
Packit Service 384592
            handle_part_start(alp);
Packit Service 384592
            break;
Packit Service 384592
        case ALP2_EVENT_PART_END :
Packit Service 384592
            handle_part_end(alp);
Packit Service 384592
            break;
Packit Service 384592
        case ALP2_EVENT_PART_DATA :
Packit Service 384592
            handle_part_data(alp);
Packit Service 384592
            break;
Packit Service 384592
        default :
Packit Service 384592
            /* Unexpected event type. */
Packit Service 384592
            break;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (alp->done) {
Packit Service 384592
        /* Stop parsing. */
Packit Service 384592
        return 0; 
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        /* Go on. */
Packit Service 384592
        return 1; 
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Initialise parser.
Packit Service 384592
 */
Packit Service 384592
// XXX Make callback a typedef
Packit Service 384592
int alp2_create(alp2_t **_alp, apr_pool_t *mp,
Packit Service 384592
                void *user_data, int (*user_callback)(alp2_t *alp))
Packit Service 384592
{
Packit Service 384592
    alp2_t *alp;
Packit Service 384592
    apr_pool_t *new_pool;
Packit Service 384592
    const char *errptr = NULL;
Packit Service 384592
    int erroffset;
Packit Service 384592
Packit Service 384592
    /* We require a callback. */
Packit Service 384592
    if (user_callback == NULL) {
Packit Service 384592
        return -1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* We will use our own memory pool. */
Packit Service 384592
    apr_pool_create(&new_pool, mp);
Packit Service 384592
    alp = apr_pcalloc(mp, sizeof(alp2_t));
Packit Service 384592
    *_alp = alp;
Packit Service 384592
    alp->mp = new_pool;
Packit Service 384592
Packit Service 384592
    alp->user_data = user_data;
Packit Service 384592
    alp->user_callback = user_callback;
Packit Service 384592
Packit Service 384592
    /* Initialise the part parser. */
Packit Service 384592
    alp->pp = apr_pcalloc(mp, sizeof(alp2_pp_t));
Packit Service 384592
    if (alp->pp == NULL) return -1;
Packit Service 384592
    if (alp2_pp_init(alp->pp, alp, alp2_callback, mp) < 0) {
Packit Service 384592
        return -2;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Compile the patterns we use for parsing. */
Packit Service 384592
Packit Service 384592
    /* part A pattern */
Packit Service 384592
    if ((alp->part_a_pattern = pcre_compile(
Packit Service 384592
        "^\\[(.+)\\] (\\S+) ([.:0-9a-f]+) (\\d+) ([.:0-9a-f]+) (\\d+)$",
Packit Service 384592
        PCRE_DOTALL, &errptr, &erroffset, NULL)) ==  NULL)
Packit Service 384592
    {
Packit Service 384592
        return -3;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* request line pattern */
Packit Service 384592
    if ((alp->request_line_pattern = pcre_compile(
Packit Service 384592
        // TODO Needs improving (e.g. to support simplified HTTP/0.9 requests
Packit Service 384592
        "^(\\S+) (.*?) (HTTP/\\d\\.\\d)$", 
Packit Service 384592
        PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL)
Packit Service 384592
    {
Packit Service 384592
        return -4;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* header pattern */
Packit Service 384592
    if ((alp->header_pattern = pcre_compile(
Packit Service 384592
        "^([^:]+):\\s*(.+)$",
Packit Service 384592
        PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL)
Packit Service 384592
    {
Packit Service 384592
        return -5;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* response line pattern */
Packit Service 384592
    if ((alp->response_line_pattern = pcre_compile(
Packit Service 384592
        "^(HTTP/\\d\\.\\d) (\\d{3})( (.+))?$",
Packit Service 384592
        PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL)
Packit Service 384592
    {
Packit Service 384592
        return -6;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Action trailer header pattern */
Packit Service 384592
    if ((alp->trailer_action_pattern = pcre_compile(
Packit Service 384592
        "^Intercepted \\(phase (\\d)\\)$",
Packit Service 384592
        PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL)
Packit Service 384592
    {
Packit Service 384592
        return -7;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Stopwatch trailer header pattern */
Packit Service 384592
    if ((alp->trailer_stopwatch_pattern = pcre_compile(
Packit Service 384592
        "^(\\d+) (\\d+)( \\((-|\\d+)\\*? (-|\\d+) (-|\\d+)\\))?$",
Packit Service 384592
        PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL)
Packit Service 384592
    {
Packit Service 384592
        return -8;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* WebApp-Info trailer header pattern */
Packit Service 384592
    if ((alp->trailer_webappinfo_pattern = pcre_compile(
Packit Service 384592
        "^\"(.*)\" \"(.*)\" \"(.*)\"$",
Packit Service 384592
        PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL)
Packit Service 384592
    {
Packit Service 384592
        return -9;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Process a piece of a stream of audit log entries.
Packit Service 384592
 */
Packit Service 384592
int alp2_process(alp2_t *alp, const char *data, size_t len)
Packit Service 384592
{
Packit Service 384592
    alp2_pp_process(alp->pp, data, len);
Packit Service 384592
Packit Service 384592
    if (alp->done) {
Packit Service 384592
        return 0;
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        return 1;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Destroy the parser.
Packit Service 384592
 */
Packit Service 384592
void alp2_destroy(alp2_t *alp)
Packit Service 384592
{
Packit Service 384592
    apr_pool_destroy(alp->mp);
Packit Service 384592
}
Packit Service 384592