|
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 <ctype.h>
|
|
Packit Service |
384592 |
#include <stdio.h>
|
|
Packit Service |
384592 |
#include <sys/param.h>
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
#include "alp2_pp.h"
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Take the line in the buffer and replace the new line
|
|
Packit Service |
384592 |
* at the end with a NUL byte.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
char *alp2_pp_line_chomp(alp2_pp_t *pp) {
|
|
Packit Service |
384592 |
if (pp->line_pos == 0) {
|
|
Packit Service |
384592 |
pp->line_buf[0] = '\0';
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
pp->line_buf[pp->line_pos - 1] = '\0';
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return &(pp->line_buf[0]);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Look into the line buffer to determine if it
|
|
Packit Service |
384592 |
* contains a boundary line.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
static int alp2_pp_is_boundary_line(alp2_pp_t *alp_pp) {
|
|
Packit Service |
384592 |
char *new_boundary = NULL;
|
|
Packit Service |
384592 |
unsigned int id;
|
|
Packit Service |
384592 |
size_t i;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* A boundary line cannot be less than 14 characters long. */
|
|
Packit Service |
384592 |
if (alp_pp->line_pos < 15) {
|
|
Packit Service |
384592 |
return 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* The first two characters must both be dashes. */
|
|
Packit Service |
384592 |
if ((alp_pp->line_buf[0] != '-')||(alp_pp->line_buf[1] != '-')) {
|
|
Packit Service |
384592 |
return 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Extract the boundary. */
|
|
Packit Service |
384592 |
i = 2; /* Start after the second dash. */
|
|
Packit Service |
384592 |
while((isxdigit(alp_pp->line_buf[i]))&&(i < alp_pp->line_pos)) {
|
|
Packit Service |
384592 |
i++;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* The boundary cannot be shorter than 8 characters. */
|
|
Packit Service |
384592 |
if (i - 2 < 8) {
|
|
Packit Service |
384592 |
return 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
// TODO Memory leak; use a single parser buffer to avoid per-entry
|
|
Packit Service |
384592 |
// allocation from the parser pool.
|
|
Packit Service |
384592 |
new_boundary = apr_pstrndup(alp_pp->mp, &(alp_pp->line_buf[2]), i - 2);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Check if the rest of the line is valid. */
|
|
Packit Service |
384592 |
if ( (i + 5 < alp_pp->line_pos) /* Need at lest 5 more bytes. */
|
|
Packit Service |
384592 |
||(alp_pp->line_buf[i + 0] != '-')
|
|
Packit Service |
384592 |
||(alp_pp->line_buf[i + 1] < 'A')
|
|
Packit Service |
384592 |
||(alp_pp->line_buf[i + 1] > 'Z')
|
|
Packit Service |
384592 |
||(alp_pp->line_buf[i + 2] != '-')
|
|
Packit Service |
384592 |
||(alp_pp->line_buf[i + 3] != '-')
|
|
Packit Service |
384592 |
||(alp_pp->line_buf[i + 4] != '\n') )
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
return 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
id = alp_pp->line_buf[i + 1];
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Are we in a middle of an entry right now? */
|
|
Packit Service |
384592 |
if (alp_pp->current_entry == NULL) {
|
|
Packit Service |
384592 |
/* We will accept a new boundary. */
|
|
Packit Service |
384592 |
alp_pp->boundary = new_boundary;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return id;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
/* The boundary must match the boundary of
|
|
Packit Service |
384592 |
* the entry we are currently working on.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if (strcmp(alp_pp->current_entry->boundary, new_boundary) != 0) {
|
|
Packit Service |
384592 |
return 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
return id;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Process data belonging to a single part.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
static void alp2_pp_process_part_data(alp2_pp_t *alp_pp) {
|
|
Packit Service |
384592 |
if (alp_pp->current_part == NULL) {
|
|
Packit Service |
384592 |
return;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Invoke part processor. */
|
|
Packit Service |
384592 |
if (alp_pp->callback != NULL) {
|
|
Packit Service |
384592 |
if (alp_pp->callback(alp_pp, ALP2_EVENT_PART_DATA) == 0) {
|
|
Packit Service |
384592 |
alp_pp->done = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Keep track of part size. */
|
|
Packit Service |
384592 |
alp_pp->current_part->size += alp_pp->line_pos;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Update the MD5 hash calculation. */
|
|
Packit Service |
384592 |
if ((alp_pp->current_entry != NULL)&&(alp_pp->line_pos > 0)) {
|
|
Packit Service |
384592 |
apr_md5_update(alp_pp->current_entry->md5_context, &alp_pp->line_buf[0], alp_pp->line_pos - 1);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Initialise parser.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
int alp2_pp_init(alp2_pp_t *alp_pp, void *user_data,
|
|
Packit Service |
384592 |
int (*callback)(alp2_pp_t *alp_pp, int event_type), apr_pool_t *mp)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
memset(alp_pp, 0, sizeof(alp2_pp_t));
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
alp_pp->user_data = user_data;
|
|
Packit Service |
384592 |
alp_pp->callback = callback;
|
|
Packit Service |
384592 |
alp_pp->mp = mp; /* Use the parent pool directly. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Set-up the line buffer. */
|
|
Packit Service |
384592 |
alp_pp->line_buf = apr_pcalloc(mp, ALP2_MAX_LINE_SIZE);
|
|
Packit Service |
384592 |
alp_pp->line_size = ALP2_MAX_LINE_SIZE;
|
|
Packit Service |
384592 |
alp_pp->line_has_start = 1;
|
|
Packit Service |
384592 |
alp_pp->line_offset = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Process data the parser has stored in the input buffer.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
static apr_status_t alp2_pp_process_internal(alp2_pp_t *alp_pp) {
|
|
Packit Service |
384592 |
/* Do not proceed if we've previously
|
|
Packit Service |
384592 |
* encountered a fatal error.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if (alp_pp->errored != 0) {
|
|
Packit Service |
384592 |
return ALP2_ERROR_FATAL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (alp_pp->done) {
|
|
Packit Service |
384592 |
return ALP2_DONE;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Go back straight away if we don't have anything to work with. */
|
|
Packit Service |
384592 |
if (alp_pp->input_len == 0) {
|
|
Packit Service |
384592 |
return ALP2_NEED_DATA;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
while (alp_pp->input_pos < alp_pp->input_len) {
|
|
Packit Service |
384592 |
int c;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (alp_pp->done) {
|
|
Packit Service |
384592 |
return ALP2_DONE;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (alp_pp->line_pos >= alp_pp->line_size) {
|
|
Packit Service |
384592 |
/* Our line buffer is full with the
|
|
Packit Service |
384592 |
* line incomplete.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
alp2_pp_process_part_data(alp_pp);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Reset line buffer . */
|
|
Packit Service |
384592 |
alp_pp->line_pos = 0;
|
|
Packit Service |
384592 |
alp_pp->line_has_start = 0;
|
|
Packit Service |
384592 |
alp_pp->line_offset = alp_pp->current_offset;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Consume one byte. */
|
|
Packit Service |
384592 |
c = alp_pp->input_buf[alp_pp->input_pos];
|
|
Packit Service |
384592 |
alp_pp->input_pos++;
|
|
Packit Service |
384592 |
alp_pp->current_offset++;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Copy the byte to the line buffer. */
|
|
Packit Service |
384592 |
alp_pp->line_buf[alp_pp->line_pos] = c;
|
|
Packit Service |
384592 |
alp_pp->line_pos++;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Are we at the end of a line? */
|
|
Packit Service |
384592 |
if (c == '\n') {
|
|
Packit Service |
384592 |
if (alp_pp->line_has_start) {
|
|
Packit Service |
384592 |
/* We have one complete line. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
int id = alp2_pp_is_boundary_line(alp_pp);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (id != 0) {
|
|
Packit Service |
384592 |
/* The line is a boundary. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Finish with the previous part, if any. */
|
|
Packit Service |
384592 |
if (alp_pp->current_part != NULL) {
|
|
Packit Service |
384592 |
/* Update the MD5 context. */
|
|
Packit Service |
384592 |
apr_md5_update(alp_pp->current_entry->md5_context,
|
|
Packit Service |
384592 |
&alp_pp->line_buf[0], alp_pp->line_pos - 1);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Event PART_END. */
|
|
Packit Service |
384592 |
if (alp_pp->callback != NULL) {
|
|
Packit Service |
384592 |
if (alp_pp->callback(alp_pp, ALP2_EVENT_PART_END) == 0) {
|
|
Packit Service |
384592 |
alp_pp->done = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Add part to the current entry. */
|
|
Packit Service |
384592 |
*(alp2_pp_part_t **)apr_array_push(alp_pp->current_entry->parts)
|
|
Packit Service |
384592 |
= alp_pp->current_part;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Delete part. */
|
|
Packit Service |
384592 |
alp_pp->current_part = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* If the new part is part Z, then finish
|
|
Packit Service |
384592 |
* with the current entry. */
|
|
Packit Service |
384592 |
if (id == 'Z') {
|
|
Packit Service |
384592 |
alp_pp->current_entry->size = alp_pp->current_offset - alp_pp->current_entry->offset;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Create the MD5 digest. */
|
|
Packit Service |
384592 |
apr_md5_final(alp_pp->current_entry->md5_digest,
|
|
Packit Service |
384592 |
alp_pp->current_entry->md5_context);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Event ENTRY_END. */
|
|
Packit Service |
384592 |
if (alp_pp->callback != NULL) {
|
|
Packit Service |
384592 |
if (alp_pp->callback(alp_pp, ALP2_EVENT_ENTRY_END) == 0) {
|
|
Packit Service |
384592 |
alp_pp->done = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* We are about to destroy our only reference to the per-entry
|
|
Packit Service |
384592 |
* memory pool, but that is all right since we've passed all
|
|
Packit Service |
384592 |
* responsibility for the entry to the higher-level handler.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
alp_pp->current_entry = NULL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (id != 'Z') {
|
|
Packit Service |
384592 |
/* Create new entry if necessary. */
|
|
Packit Service |
384592 |
if (alp_pp->current_entry == NULL) {
|
|
Packit Service |
384592 |
apr_pool_t *new_pool = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Create a per-entry pool directly from the main memory pool. */
|
|
Packit Service |
384592 |
apr_pool_create(&new_pool, apr_pool_parent_get(alp_pp->mp));
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
alp_pp->current_entry = apr_pcalloc(new_pool, sizeof(alp2_pp_entry_t));
|
|
Packit Service |
384592 |
alp_pp->current_entry->mp = new_pool;
|
|
Packit Service |
384592 |
alp_pp->current_entry->offset = alp_pp->line_offset;
|
|
Packit Service |
384592 |
alp_pp->current_entry->boundary = apr_pstrdup(new_pool, alp_pp->boundary);
|
|
Packit Service |
384592 |
alp_pp->boundary = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
alp_pp->current_entry->parts = apr_array_make(alp_pp->current_entry->mp,
|
|
Packit Service |
384592 |
16, sizeof(alp2_pp_part_t *));
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Initialise the MD5 context. */
|
|
Packit Service |
384592 |
alp_pp->current_entry->md5_context = apr_pcalloc(alp_pp->current_entry->mp,
|
|
Packit Service |
384592 |
sizeof(apr_md5_ctx_t));
|
|
Packit Service |
384592 |
apr_md5_init(alp_pp->current_entry->md5_context);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Start calculating the has with the first line. */
|
|
Packit Service |
384592 |
apr_md5_update(alp_pp->current_entry->md5_context, &alp_pp->line_buf[0], alp_pp->line_pos - 1);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Event ENTRY_START. */
|
|
Packit Service |
384592 |
if (alp_pp->callback != NULL) {
|
|
Packit Service |
384592 |
if (alp_pp->callback(alp_pp, ALP2_EVENT_ENTRY_START) == 0) {
|
|
Packit Service |
384592 |
alp_pp->done = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Create new part, but only if we are not
|
|
Packit Service |
384592 |
* dealing with an entry terminator.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
alp_pp->current_part = apr_pcalloc(alp_pp->current_entry->mp, sizeof(alp2_pp_part_t));
|
|
Packit Service |
384592 |
alp_pp->current_part->id = id;
|
|
Packit Service |
384592 |
alp_pp->current_part->offset = alp_pp->current_offset;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Event PART_START. */
|
|
Packit Service |
384592 |
if (alp_pp->callback != NULL) {
|
|
Packit Service |
384592 |
if (alp_pp->callback(alp_pp, ALP2_EVENT_PART_START) == 0) {
|
|
Packit Service |
384592 |
alp_pp->done = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
/* The line does not contain a boundary,
|
|
Packit Service |
384592 |
* so process it as part data.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
alp2_pp_process_part_data(alp_pp);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
/* We have a chunk of data that is not a line, which
|
|
Packit Service |
384592 |
* probably means that our buffer was not big enough, either
|
|
Packit Service |
384592 |
* because the line (is a line and it) was too big, or because
|
|
Packit Service |
384592 |
* we are processing binary data. Ideally the latter.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
alp2_pp_process_part_data(alp_pp);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Reset the line buffer. */
|
|
Packit Service |
384592 |
alp_pp->line_pos = 0;
|
|
Packit Service |
384592 |
alp_pp->line_has_start = 1;
|
|
Packit Service |
384592 |
alp_pp->line_offset = alp_pp->current_offset;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (alp_pp->done) {
|
|
Packit Service |
384592 |
return ALP2_DONE;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
return ALP2_NEED_DATA;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Process the provided data.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
int alp2_pp_process(alp2_pp_t *alp_pp, const char *data, size_t len) {
|
|
Packit Service |
384592 |
/* Do not proceed if we've previously
|
|
Packit Service |
384592 |
* encountered a fatal error.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if (alp_pp->errored != 0) {
|
|
Packit Service |
384592 |
return ALP2_ERROR_FATAL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Check that we've used up the existing buffer. */
|
|
Packit Service |
384592 |
if (alp_pp->input_pos < alp_pp->input_len) {
|
|
Packit Service |
384592 |
return ALP2_ERROR_INCORRECT_STATE;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
alp_pp->input_buf = data;
|
|
Packit Service |
384592 |
alp_pp->input_len = len;
|
|
Packit Service |
384592 |
alp_pp->input_pos = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return alp2_pp_process_internal(alp_pp);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Clean-up the parser structures.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
void alp2_pp_terminate(alp2_pp_t *alp_pp) {
|
|
Packit Service |
384592 |
/* Nothing to do, but we may need
|
|
Packit Service |
384592 |
* to do something in the future.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
}
|