|
Packit Service |
384592 |
/*
|
|
Packit Service |
384592 |
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
|
Packit Service |
384592 |
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
|
Packit Service |
384592 |
*
|
|
Packit Service |
384592 |
* You may not use this file except in compliance with
|
|
Packit Service |
384592 |
* the License. You may obtain a copy of the License at
|
|
Packit Service |
384592 |
*
|
|
Packit Service |
384592 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit Service |
384592 |
*
|
|
Packit Service |
384592 |
* If any of the files related to licensing are missing or if you have any
|
|
Packit Service |
384592 |
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
|
Packit Service |
384592 |
* directly using the email address security@modsecurity.org.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
#include "modsecurity.h"
|
|
Packit Service |
384592 |
#include "re.h"
|
|
Packit Service |
384592 |
#include "msc_parsers.h"
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
#define CHUNK_CAPACITY 8192
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
*
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
void msre_engine_reqbody_processor_register(msre_engine *engine,
|
|
Packit Service |
384592 |
const char *name, void *fn_init, void *fn_process, void *fn_complete)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
msre_reqbody_processor_metadata *metadata =
|
|
Packit Service |
384592 |
(msre_reqbody_processor_metadata *)apr_pcalloc(engine->mp,
|
|
Packit Service |
384592 |
sizeof(msre_reqbody_processor_metadata));
|
|
Packit Service |
384592 |
if (metadata == NULL) return;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
metadata->name = name;
|
|
Packit Service |
384592 |
metadata->init = fn_init;
|
|
Packit Service |
384592 |
metadata->process = fn_process;
|
|
Packit Service |
384592 |
metadata->complete = fn_complete;
|
|
Packit Service |
384592 |
apr_table_setn(engine->reqbody_processors, name, (void *)metadata);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Prepare to accept the request body (part 2).
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr, char **error_msg) {
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if(msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
|
Packit Service |
384592 |
/* Prepare to store request body in memory. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp,
|
|
Packit Service |
384592 |
32, sizeof(msc_data_chunk *));
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_chunks == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to prepare in-memory storage.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* Prepare to store request body on disk. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_filename = apr_psprintf(msr->mp, "%s/%s-%s-request_body-XXXXXX",
|
|
Packit Service |
384592 |
msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid);
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_filename == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to generate an on-disk filename.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_fd = msc_mkstemp((char *)msr->msc_reqbody_filename);
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_fd < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to create temporary file: %s",
|
|
Packit Service |
384592 |
msr->msc_reqbody_filename);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Input filter: Created temporary file to store request body: %s",
|
|
Packit Service |
384592 |
msr->msc_reqbody_filename);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Prepare to accept the request body (part 1).
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
apr_status_t modsecurity_request_body_start(modsec_rec *msr, char **error_msg) {
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
msr->msc_reqbody_length = 0;
|
|
Packit Service |
384592 |
msr->stream_input_length = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Create a separate memory pool that will be used
|
|
Packit Service |
384592 |
* to allocate structures from (not data, which is allocated
|
|
Packit Service |
384592 |
* via malloc).
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
apr_pool_create(&msr->msc_reqbody_mp, NULL);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Initialise request body processors, if any. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_processor != NULL) {
|
|
Packit Service |
384592 |
char *my_error_msg = NULL;
|
|
Packit Service |
384592 |
msre_reqbody_processor_metadata *metadata =
|
|
Packit Service |
384592 |
(msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (metadata != NULL) {
|
|
Packit Service |
384592 |
if ( (metadata->init != NULL)
|
|
Packit Service |
384592 |
&& (metadata->init(msr, &my_error_msg) < 0))
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp,
|
|
Packit Service |
384592 |
"%s parsing error (init): %s",
|
|
Packit Service |
384592 |
msr->msc_reqbody_processor,
|
|
Packit Service |
384592 |
my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = my_error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
// TODO: All these below need to be registered in the same way as above
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
|
Packit Service |
384592 |
if (multipart_init(msr, &my_error_msg) < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart parsing error (init): %s", my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = my_error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
|
Packit Service |
384592 |
if (xml_init(msr, &my_error_msg) < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "XML parsing error (init): %s", my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = my_error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
|
|
Packit Service |
384592 |
#ifdef WITH_YAJL
|
|
Packit Service |
384592 |
if (json_init(msr, &my_error_msg) < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "JSON parsing error (init): %s", my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = my_error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
#else
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "JSON support was not enabled");
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = my_error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
#endif
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
|
Packit Service |
384592 |
/* Do nothing, URLENCODED processor does not support streaming yet. */
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s",
|
|
Packit Service |
384592 |
msr->msc_reqbody_processor);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return modsecurity_request_body_start_init(msr, error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Stores a chunk of request body data to disk.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr,
|
|
Packit Service |
384592 |
const char *data, apr_size_t length, char **error_msg)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
apr_size_t i;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
i = write(msr->msc_reqbody_fd, data, length);
|
|
Packit Service |
384592 |
if (i != length) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed writing %" APR_SIZE_T_FMT
|
|
Packit Service |
384592 |
" bytes to temporary file (rc %" APR_SIZE_T_FMT ").", length, i);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Stores one chunk of request body data in memory.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr,
|
|
Packit Service |
384592 |
const char *data, apr_size_t length, char **error_msg)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Would storing this chunk mean going over the limit? */
|
|
Packit Service |
384592 |
if ((msr->msc_reqbody_spilltodisk)
|
|
Packit Service |
384592 |
&& (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_ON)
|
|
Packit Service |
384592 |
&& (msr->msc_reqbody_length + length > (apr_size_t)msr->txcfg->reqbody_inmemory_limit))
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
msc_data_chunk **chunks;
|
|
Packit Service |
384592 |
unsigned int disklen = 0;
|
|
Packit Service |
384592 |
int i;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Input filter: Request too large to store in memory, switching to disk.");
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* NOTE Must use modsecurity_request_body_store_disk() here
|
|
Packit Service |
384592 |
* to prevent data to be sent to the streaming
|
|
Packit Service |
384592 |
* processors again.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Initialise disk storage */
|
|
Packit Service |
384592 |
msr->msc_reqbody_storage = MSC_REQBODY_DISK;
|
|
Packit Service |
384592 |
if (modsecurity_request_body_start_init(msr, error_msg) < 0) return -1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Write the data we keep in memory */
|
|
Packit Service |
384592 |
chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
|
Packit Service |
384592 |
for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
|
|
Packit Service |
384592 |
disklen += chunks[i]->length;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (modsecurity_request_body_store_disk(msr, chunks[i]->data, chunks[i]->length, error_msg) < 0) {
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
free(chunks[i]->data);
|
|
Packit Service |
384592 |
chunks[i]->data = NULL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Clear the memory pool as we no longer need the bits. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* IMP1 But since we only used apr_pool_clear memory might
|
|
Packit Service |
384592 |
* not be released back to the OS straight away?
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunks = NULL;
|
|
Packit Service |
384592 |
apr_pool_clear(msr->msc_reqbody_mp);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Input filter: Wrote %u bytes from memory to disk.", disklen);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Continue with disk storage from now on */
|
|
Packit Service |
384592 |
return modsecurity_request_body_store_disk(msr, data, length, error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* If we're here that means we are not over the
|
|
Packit Service |
384592 |
* request body in-memory limit yet.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
unsigned long int bucket_offset, bucket_left;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
bucket_offset = 0;
|
|
Packit Service |
384592 |
bucket_left = length;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Although we store the request body in chunks we don't
|
|
Packit Service |
384592 |
* want to use the same chunk sizes as the incoming memory
|
|
Packit Service |
384592 |
* buffers. They are often of very small sizes and that
|
|
Packit Service |
384592 |
* would make us waste a lot of memory. That's why we
|
|
Packit Service |
384592 |
* use our own chunks of CHUNK_CAPACITY sizes.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Loop until we empty this bucket into our chunks. */
|
|
Packit Service |
384592 |
while(bucket_left > 0) {
|
|
Packit Service |
384592 |
/* Allocate a new chunk if we have to. */
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_chunk_current == NULL) {
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_current = (msc_data_chunk *)
|
|
Packit Service |
384592 |
apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_chunk_current == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to allocate %lu bytes "
|
|
Packit Service |
384592 |
"for request body chunk.", (unsigned long)sizeof(msc_data_chunk));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_current->data = malloc(CHUNK_CAPACITY);
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_chunk_current->data == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to allocate %d bytes "
|
|
Packit Service |
384592 |
"for request body chunk data.", CHUNK_CAPACITY);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_current->length = 0;
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_current->is_permanent = 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*(const msc_data_chunk **)apr_array_push(msr->msc_reqbody_chunks)
|
|
Packit Service |
384592 |
= msr->msc_reqbody_chunk_current;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (bucket_left < (CHUNK_CAPACITY - msr->msc_reqbody_chunk_current->length)) {
|
|
Packit Service |
384592 |
/* There's enough space in the current chunk. */
|
|
Packit Service |
384592 |
memcpy(msr->msc_reqbody_chunk_current->data +
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_current->length, data + bucket_offset, bucket_left);
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_current->length += bucket_left;
|
|
Packit Service |
384592 |
bucket_left = 0;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* Fill the existing chunk. */
|
|
Packit Service |
384592 |
unsigned long int copy_length = CHUNK_CAPACITY -
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_current->length;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
memcpy(msr->msc_reqbody_chunk_current->data +
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_current->length, data + bucket_offset, copy_length);
|
|
Packit Service |
384592 |
bucket_offset += copy_length;
|
|
Packit Service |
384592 |
bucket_left -= copy_length;
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_current->length += copy_length;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* We're done with this chunk. Setting the pointer
|
|
Packit Service |
384592 |
* to NULL is going to force a new chunk to be allocated
|
|
Packit Service |
384592 |
* on the next go.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_current = NULL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_length += length;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Stores one chunk of request body data. Returns -1 on error.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
apr_status_t modsecurity_request_body_store(modsec_rec *msr,
|
|
Packit Service |
384592 |
const char *data, apr_size_t length, char **error_msg)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* If we have a processor for this request body send
|
|
Packit Service |
384592 |
* data to it first (but only if it did not report an
|
|
Packit Service |
384592 |
* error on previous invocations).
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if ((msr->msc_reqbody_processor != NULL) && (msr->msc_reqbody_error == 0)) {
|
|
Packit Service |
384592 |
char *my_error_msg = NULL;
|
|
Packit Service |
384592 |
msre_reqbody_processor_metadata *metadata =
|
|
Packit Service |
384592 |
(msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (metadata != NULL) {
|
|
Packit Service |
384592 |
if ( (metadata->process != NULL)
|
|
Packit Service |
384592 |
&& (metadata->process(msr, data, length, &my_error_msg) < 0))
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp,
|
|
Packit Service |
384592 |
"%s parsing error: %s",
|
|
Packit Service |
384592 |
msr->msc_reqbody_processor,
|
|
Packit Service |
384592 |
my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = my_error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
// TODO: All these below need to be registered in the same way as above
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
|
Packit Service |
384592 |
/* The per-request data length counter will
|
|
Packit Service |
384592 |
* be updated by the multipart parser.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Process data as multipart/form-data. */
|
|
Packit Service |
384592 |
if (multipart_process_chunk(msr, data, length, &my_error_msg) < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart parsing error: %s", my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = *error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
|
Packit Service |
384592 |
/* Increase per-request data length counter. */
|
|
Packit Service |
384592 |
msr->msc_reqbody_no_files_length += length;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Process data as XML. */
|
|
Packit Service |
384592 |
if (xml_process_chunk(msr, data, length, &my_error_msg) < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "XML parsing error: %s", my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = *error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
|
|
Packit Service |
384592 |
/* Increase per-request data length counter. */
|
|
Packit Service |
384592 |
msr->msc_reqbody_no_files_length += length;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Process data as JSON. */
|
|
Packit Service |
384592 |
#ifdef WITH_YAJL
|
|
Packit Service |
384592 |
if (json_process_chunk(msr, data, length, &my_error_msg) < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "JSON parsing error: %s", my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = *error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
#else
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "JSON support was not enabled");
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = *error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
#endif
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
|
Packit Service |
384592 |
/* Increase per-request data length counter. */
|
|
Packit Service |
384592 |
msr->msc_reqbody_no_files_length += length;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Do nothing else, URLENCODED processor does not support streaming. */
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s",
|
|
Packit Service |
384592 |
msr->msc_reqbody_processor);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) {
|
|
Packit Service |
384592 |
/* Increase per-request data length counter if forcing buffering. */
|
|
Packit Service |
384592 |
msr->msc_reqbody_no_files_length += length;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Check that we are not over the request body no files limit. */
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_no_files_length >= (unsigned long) msr->txcfg->reqbody_no_files_limit) {
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the "
|
|
Packit Service |
384592 |
"configured limit (%ld).", msr->txcfg->reqbody_no_files_limit);
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 1) {
|
|
Packit Service |
384592 |
msr_log(msr, 1, "%s", *error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if ((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) {
|
|
Packit Service |
384592 |
return -5;
|
|
Packit Service |
384592 |
} else if (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL) {
|
|
Packit Service |
384592 |
if(msr->txcfg->is_enabled == MODSEC_ENABLED)
|
|
Packit Service |
384592 |
return -5;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Store data. */
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
|
Packit Service |
384592 |
return modsecurity_request_body_store_memory(msr, data, length, error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
|
Packit Service |
384592 |
return modsecurity_request_body_store_disk(msr, data, length, error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Should never happen. */
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Internal error, unknown value for msc_reqbody_storage: %u",
|
|
Packit Service |
384592 |
msr->msc_reqbody_storage);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buffer, int buflen, char **error_msg) {
|
|
Packit Service |
384592 |
char *stream_input_body = NULL;
|
|
Packit Service |
384592 |
char *data = NULL;
|
|
Packit Service |
384592 |
int first_pkt = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if(msr->stream_input_data == NULL) {
|
|
Packit Service |
384592 |
msr->stream_input_data = (char *)calloc(sizeof(char), msr->stream_input_length + 1);
|
|
Packit Service |
384592 |
first_pkt = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
data = (char *)malloc(msr->stream_input_length + 1 - buflen);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if(data == NULL)
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
memset(data, 0, msr->stream_input_length + 1 - buflen);
|
|
Packit Service |
384592 |
memcpy(data, msr->stream_input_data, msr->stream_input_length - buflen);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
stream_input_body = (char *)realloc(msr->stream_input_data, msr->stream_input_length + 1);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->stream_input_data = (char *)stream_input_body;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->stream_input_data == NULL) {
|
|
Packit Service |
384592 |
if(data) {
|
|
Packit Service |
384592 |
free(data);
|
|
Packit Service |
384592 |
data = NULL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.",
|
|
Packit Service |
384592 |
msr->stream_input_length + 1);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
memset(msr->stream_input_data, 0, msr->stream_input_length+1);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if(first_pkt) {
|
|
Packit Service |
384592 |
memcpy(msr->stream_input_data, buffer, msr->stream_input_length);
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
memcpy(msr->stream_input_data, data, msr->stream_input_length - buflen);
|
|
Packit Service |
384592 |
memcpy(msr->stream_input_data+(msr->stream_input_length - buflen), buffer, buflen);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if(data) {
|
|
Packit Service |
384592 |
free(data);
|
|
Packit Service |
384592 |
data = NULL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Replace a bunch of chunks holding a request body with a single large chunk.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
static apr_status_t modsecurity_request_body_end_raw(modsec_rec *msr, char **error_msg) {
|
|
Packit Service |
384592 |
msc_data_chunk **chunks, *one_chunk;
|
|
Packit Service |
384592 |
char *d;
|
|
Packit Service |
384592 |
int i, sofar;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Allocate a buffer large enough to hold the request body. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_length + 1 == 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Internal error, request body length will overflow: %u",
|
|
Packit Service |
384592 |
msr->msc_reqbody_length);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_buffer = malloc(msr->msc_reqbody_length + 1);
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_buffer == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body. Asked for %u bytes.",
|
|
Packit Service |
384592 |
msr->msc_reqbody_length + 1);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_buffer[msr->msc_reqbody_length] = '\0';
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Copy the data we keep in chunks into the new buffer. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
sofar = 0;
|
|
Packit Service |
384592 |
d = msr->msc_reqbody_buffer;
|
|
Packit Service |
384592 |
chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
|
Packit Service |
384592 |
for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
|
|
Packit Service |
384592 |
if (sofar + chunks[i]->length <= msr->msc_reqbody_length) {
|
|
Packit Service |
384592 |
memcpy(d, chunks[i]->data, chunks[i]->length);
|
|
Packit Service |
384592 |
d += chunks[i]->length;
|
|
Packit Service |
384592 |
sofar += chunks[i]->length;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Internal error, request body buffer overflow.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Now free the memory used by the chunks. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
|
Packit Service |
384592 |
for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
|
|
Packit Service |
384592 |
free(chunks[i]->data);
|
|
Packit Service |
384592 |
chunks[i]->data = NULL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Create a new array with only one chunk in it. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp, 2, sizeof(msc_data_chunk *));
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_chunks == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_pstrdup(msr->mp, "Failed to create structure to hold request body.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
one_chunk = (msc_data_chunk *)apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
|
Packit Service |
384592 |
one_chunk->data = msr->msc_reqbody_buffer;
|
|
Packit Service |
384592 |
one_chunk->length = msr->msc_reqbody_length;
|
|
Packit Service |
384592 |
one_chunk->is_permanent = 1;
|
|
Packit Service |
384592 |
*(const msc_data_chunk **)apr_array_push(msr->msc_reqbody_chunks) = one_chunk;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if(msr->txcfg->reqbody_limit > 0 && msr->txcfg->reqbody_limit < msr->msc_reqbody_length) {
|
|
Packit Service |
384592 |
msr->msc_reqbody_length = msr->txcfg->reqbody_limit;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
*
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr, char **error_msg) {
|
|
Packit Service |
384592 |
int invalid_count = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Create the raw buffer */
|
|
Packit Service |
384592 |
if (modsecurity_request_body_end_raw(msr, error_msg) != 1) {
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Parse URL-encoded arguments in the request body. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (parse_arguments(msr, msr->msc_reqbody_buffer, msr->msc_reqbody_length,
|
|
Packit Service |
384592 |
msr->txcfg->argument_separator, "BODY", msr->arguments, &invalid_count) < 0)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
*error_msg = apr_pstrdup(msr->mp, "Initialisation: Error occurred while parsing BODY arguments.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (invalid_count) {
|
|
Packit Service |
384592 |
msr->urlencoded_error = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Stops receiving the request body.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) {
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Close open file descriptors, if any. */
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_fd > 0) {
|
|
Packit Service |
384592 |
close(msr->msc_reqbody_fd);
|
|
Packit Service |
384592 |
msr->msc_reqbody_fd = -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Note that we've read the body. */
|
|
Packit Service |
384592 |
msr->msc_reqbody_read = 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Finalise body processing. */
|
|
Packit Service |
384592 |
if ((msr->msc_reqbody_processor != NULL) && (msr->msc_reqbody_error == 0)) {
|
|
Packit Service |
384592 |
char *my_error_msg = NULL;
|
|
Packit Service |
384592 |
msre_reqbody_processor_metadata *metadata =
|
|
Packit Service |
384592 |
(msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (metadata != NULL) {
|
|
Packit Service |
384592 |
if ( (metadata->complete != NULL)
|
|
Packit Service |
384592 |
&& (metadata->complete(msr, &my_error_msg) < 0))
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp,
|
|
Packit Service |
384592 |
"%s parsing error (complete): %s",
|
|
Packit Service |
384592 |
msr->msc_reqbody_processor,
|
|
Packit Service |
384592 |
my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = my_error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
// TODO: All these below need to be registered in the same way as above
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
|
Packit Service |
384592 |
if (multipart_complete(msr, &my_error_msg) < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart parsing error: %s", my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = *error_msg;
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 4) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "%s", *error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (multipart_get_arguments(msr, "BODY", msr->arguments) < 0) {
|
|
Packit Service |
384592 |
*error_msg = "Multipart parsing error: Failed to retrieve arguments.";
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = *error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
|
|
Packit Service |
384592 |
#ifdef WITH_YAJL
|
|
Packit Service |
384592 |
if (json_complete(msr, &my_error_msg) < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "JSON parser error: %s", my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = *error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
#else
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "JSON support was not enabled");
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = *error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
#endif
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
|
Packit Service |
384592 |
return modsecurity_request_body_end_urlencoded(msr, error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
|
Packit Service |
384592 |
if (xml_complete(msr, &my_error_msg) < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "XML parser error: %s", my_error_msg);
|
|
Packit Service |
384592 |
msr->msc_reqbody_error = 1;
|
|
Packit Service |
384592 |
msr->msc_reqbody_error_msg = *error_msg;
|
|
Packit Service |
384592 |
msr_log(msr, 2, "%s", *error_msg);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) {
|
|
Packit Service |
384592 |
/* Convert to a single continous buffer, but don't do anything else. */
|
|
Packit Service |
384592 |
return modsecurity_request_body_end_raw(msr, error_msg);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Note the request body no files length. */
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Request body no files length: %" APR_SIZE_T_FMT, msr->msc_reqbody_no_files_length);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
* Prepares to forward the request body.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
apr_status_t modsecurity_request_body_retrieve_start(modsec_rec *msr, char **error_msg) {
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_position = 0;
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_offset = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_disk_chunk == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Failed to allocate %lu bytes for request body disk chunk.",
|
|
Packit Service |
384592 |
(unsigned long)sizeof(msc_data_chunk));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
msr->msc_reqbody_disk_chunk->is_permanent = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
|
Packit Service |
384592 |
msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_disk_chunk == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Failed to allocate %lu bytes for request body disk chunk.",
|
|
Packit Service |
384592 |
(unsigned long)sizeof(msc_data_chunk));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_disk_chunk->is_permanent = 0;
|
|
Packit Service |
384592 |
msr->msc_reqbody_disk_chunk->data = apr_palloc(msr->msc_reqbody_mp, CHUNK_CAPACITY);
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_disk_chunk->data == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Failed to allocate %d bytes for request body disk chunk data.",
|
|
Packit Service |
384592 |
CHUNK_CAPACITY);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_fd = open(msr->msc_reqbody_filename, O_RDONLY | O_BINARY);
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_fd < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Failed to open temporary file for reading: %s",
|
|
Packit Service |
384592 |
msr->msc_reqbody_filename);
|
|
Packit Service |
384592 |
return -1;
|
|
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 |
*
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
apr_status_t modsecurity_request_body_retrieve_end(modsec_rec *msr) {
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_fd > 0) {
|
|
Packit Service |
384592 |
close(msr->msc_reqbody_fd);
|
|
Packit Service |
384592 |
msr->msc_reqbody_fd = -1;
|
|
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 |
* Returns one chunk of request body data. It stores a NULL
|
|
Packit Service |
384592 |
* in the chunk pointer when there is no data to return. The
|
|
Packit Service |
384592 |
* return code is 1 if more calls can be made to retrieve more
|
|
Packit Service |
384592 |
* data, 0 if there is no more data to retrieve, or -1 on error.
|
|
Packit Service |
384592 |
*
|
|
Packit Service |
384592 |
* The caller can limit the amount of data returned by providing
|
|
Packit Service |
384592 |
* a non-negative value in nbytes.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr,
|
|
Packit Service |
384592 |
msc_data_chunk **chunk, long int nbytes, char **error_msg)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
msc_data_chunk **chunks;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (chunk == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_pstrdup(msr->mp, "Internal error, retrieving request body chunk.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
*chunk = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
|
Packit Service |
384592 |
/* Are there any chunks left? */
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_chunk_position >= msr->msc_reqbody_chunks->nelts) {
|
|
Packit Service |
384592 |
/* No more chunks. */
|
|
Packit Service |
384592 |
return 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* We always respond with the same chunk, just different information in it. */
|
|
Packit Service |
384592 |
*chunk = msr->msc_reqbody_disk_chunk;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Advance to the current chunk and position on the
|
|
Packit Service |
384592 |
* next byte we need to send.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
|
Packit Service |
384592 |
msr->msc_reqbody_disk_chunk->data = chunks[msr->msc_reqbody_chunk_position]->data
|
|
Packit Service |
384592 |
+ msr->msc_reqbody_chunk_offset;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (nbytes < 0) {
|
|
Packit Service |
384592 |
/* Send what's left in this chunk as there is no limit on the size. */
|
|
Packit Service |
384592 |
msr->msc_reqbody_disk_chunk->length = chunks[msr->msc_reqbody_chunk_position]->length;
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_position++;
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_offset = 0;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* We have a limit we must obey. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (chunks[msr->msc_reqbody_chunk_position]->length -
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_offset <= (unsigned int)nbytes)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
/* If what's left in our chunk is less than the limit
|
|
Packit Service |
384592 |
* then send it all back.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
msr->msc_reqbody_disk_chunk->length =
|
|
Packit Service |
384592 |
chunks[msr->msc_reqbody_chunk_position]->length -
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_offset;
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_position++;
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_offset = 0;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* If we have more data in our chunk, send the
|
|
Packit Service |
384592 |
* maximum bytes we can (nbytes).
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
msr->msc_reqbody_disk_chunk->length = nbytes;
|
|
Packit Service |
384592 |
msr->msc_reqbody_chunk_offset += nbytes;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* If we've advanced beyond our last chunk then
|
|
Packit Service |
384592 |
* we have no more data to send.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_chunk_position >= msr->msc_reqbody_chunks->nelts) {
|
|
Packit Service |
384592 |
return 0; /* No more chunks. */
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* More data available. */
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
|
Packit Service |
384592 |
long int my_nbytes = CHUNK_CAPACITY;
|
|
Packit Service |
384592 |
int i;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Send CHUNK_CAPACITY bytes at a time unless a lower limit was requested. */
|
|
Packit Service |
384592 |
if ((nbytes != -1)&&(my_nbytes > nbytes)) {
|
|
Packit Service |
384592 |
my_nbytes = nbytes;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
i = read(msr->msc_reqbody_fd, msr->msc_reqbody_disk_chunk->data, my_nbytes);
|
|
Packit Service |
384592 |
if (i < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Input filter: Error reading from temporary file: %s",
|
|
Packit Service |
384592 |
strerror(errno));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*chunk = msr->msc_reqbody_disk_chunk;
|
|
Packit Service |
384592 |
msr->msc_reqbody_disk_chunk->length = i;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (i == 0) return 0; /* No more data available. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1; /* More data available. */
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Should never happen. */
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Internal error, invalid msc_reqbody_storage value: %u",
|
|
Packit Service |
384592 |
msr->msc_reqbody_storage);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
*
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) {
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Release memory we used to store request body data. */
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_chunks != NULL) {
|
|
Packit Service |
384592 |
msc_data_chunk **chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
|
Packit Service |
384592 |
int i;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
|
|
Packit Service |
384592 |
if (chunks[i]->data != NULL) {
|
|
Packit Service |
384592 |
free(chunks[i]->data);
|
|
Packit Service |
384592 |
chunks[i]->data = NULL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
|
Packit Service |
384592 |
int keep_body = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Should we keep the body? This normally
|
|
Packit Service |
384592 |
* happens when a PUT method was used, which
|
|
Packit Service |
384592 |
* means the body is actually a file.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if ((msr->upload_remove_files == 0)&&(strcasecmp(msr->request_method, "PUT") == 0)) {
|
|
Packit Service |
384592 |
if (msr->txcfg->upload_dir != NULL) {
|
|
Packit Service |
384592 |
keep_body = 1;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Input filter: SecUploadDir is undefined, "
|
|
Packit Service |
384592 |
"unable to store PUT file.");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Deal with a request body stored in a file. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_filename != NULL) {
|
|
Packit Service |
384592 |
if (keep_body) {
|
|
Packit Service |
384592 |
/* Move request body (which is a file) to the storage area. */
|
|
Packit Service |
384592 |
const char *put_filename = NULL;
|
|
Packit Service |
384592 |
const char *put_basename = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (strcmp(msr->txcfg->upload_dir, msr->txcfg->tmp_dir) == 0) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Not moving file to identical location.");
|
|
Packit Service |
384592 |
goto nullify;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Construct the new filename. */
|
|
Packit Service |
384592 |
put_basename = file_basename(msr->msc_reqbody_mp, msr->msc_reqbody_filename);
|
|
Packit Service |
384592 |
if (put_basename == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to generate basename to PUT file \"%s\"", log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
put_filename = apr_psprintf(msr->msc_reqbody_mp, "%s/%s",
|
|
Packit Service |
384592 |
msr->txcfg->upload_dir, put_basename);
|
|
Packit Service |
384592 |
if (put_filename == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to generate filename to PUT file \"%s\"", log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (apr_file_rename(msr->msc_reqbody_filename, put_filename,
|
|
Packit Service |
384592 |
msr->msc_reqbody_mp) != APR_SUCCESS)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to rename file from \"%s\" to \"%s\".",
|
|
Packit Service |
384592 |
log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename),
|
|
Packit Service |
384592 |
log_escape(msr->msc_reqbody_mp, put_filename));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Input filter: Moved file from \"%s\" to \"%s\".",
|
|
Packit Service |
384592 |
log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename),
|
|
Packit Service |
384592 |
log_escape(msr->msc_reqbody_mp, put_filename));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* make sure it is closed first */
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_fd > 0) {
|
|
Packit Service |
384592 |
close(msr->msc_reqbody_fd);
|
|
Packit Service |
384592 |
msr->msc_reqbody_fd = -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* We do not want to keep the request body. */
|
|
Packit Service |
384592 |
if (apr_file_remove(msr->msc_reqbody_filename,
|
|
Packit Service |
384592 |
msr->msc_reqbody_mp) != APR_SUCCESS)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to delete temporary file: %s",
|
|
Packit Service |
384592 |
log_escape(msr->mp, msr->msc_reqbody_filename));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Input filter: Removed temporary file: %s",
|
|
Packit Service |
384592 |
msr->msc_reqbody_filename);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
nullify:
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->msc_reqbody_filename = NULL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->msc_reqbody_mp != NULL) {
|
|
Packit Service |
384592 |
apr_pool_destroy(msr->msc_reqbody_mp);
|
|
Packit Service |
384592 |
msr->msc_reqbody_mp = NULL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|