Blame alp2/alp2.c

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