|
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 |
|