|
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 <ctype.h>
|
|
Packit Service |
384592 |
#include <sys/stat.h>
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
#include "msc_multipart.h"
|
|
Packit Service |
384592 |
#include "msc_util.h"
|
|
Packit Service |
384592 |
#include "msc_parsers.h"
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
void validate_quotes(modsec_rec *msr, char *data) {
|
|
Packit Service |
384592 |
int i, len;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if(msr == NULL)
|
|
Packit Service |
384592 |
return;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if(msr->mpd == NULL)
|
|
Packit Service |
384592 |
return;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if(data == NULL)
|
|
Packit Service |
384592 |
return;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
len = strlen(data);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
for(i = 0; i < len; i++) {
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if(data[i] == '\'') {
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit Service |
384592 |
msr_log(msr, 9, "Multipart: Invalid quoting detected: %s length %d bytes",
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, data), len);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
msr->mpd->flag_invalid_quoting = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
#if 0
|
|
Packit Service |
384592 |
static char *multipart_construct_filename(modsec_rec *msr) {
|
|
Packit Service |
384592 |
char c, *p, *q = msr->mpd->mpp->filename;
|
|
Packit Service |
384592 |
char *filename;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* find the last backward slash and consider the
|
|
Packit Service |
384592 |
* filename to be only what's right from it
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
p = strrchr(q, '\\');
|
|
Packit Service |
384592 |
if (p != NULL) q = p + 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* do the same for the forward slash */
|
|
Packit Service |
384592 |
p = strrchr(q, '/');
|
|
Packit Service |
384592 |
if (p != NULL) q = p + 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* allow letters, digits and dots, replace
|
|
Packit Service |
384592 |
* everything else with underscores
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
p = filename = apr_pstrdup(msr->mp, q);
|
|
Packit Service |
384592 |
while((c = *p) != 0) {
|
|
Packit Service |
384592 |
if (!( isalnum(c) || (c == '.') )) *p = '_';
|
|
Packit Service |
384592 |
p++;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return filename;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
#endif
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
*
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value) {
|
|
Packit Service |
384592 |
char *p = NULL, *t = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* accept only what we understand */
|
|
Packit Service |
384592 |
if (strncmp(c_d_value, "form-data", 9) != 0) {
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* see if there are any other parts to parse */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
p = c_d_value + 9;
|
|
Packit Service |
384592 |
while((*p == '\t') || (*p == ' ')) p++;
|
|
Packit Service |
384592 |
if (*p == '\0') return 1; /* this is OK */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (*p != ';') return -2;
|
|
Packit Service |
384592 |
p++;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* parse the appended parts */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
while(*p != '\0') {
|
|
Packit Service |
384592 |
char *name = NULL, *value = NULL, *start = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* go over the whitespace */
|
|
Packit Service |
384592 |
while((*p == '\t') || (*p == ' ')) p++;
|
|
Packit Service |
384592 |
if (*p == '\0') return -3;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
start = p;
|
|
Packit Service |
384592 |
while((*p != '\0') && (*p != '=') && (*p != '\t') && (*p != ' ')) p++;
|
|
Packit Service |
384592 |
if (*p == '\0') return -4;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
name = apr_pstrmemdup(msr->mp, start, (p - start));
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
while((*p == '\t') || (*p == ' ')) p++;
|
|
Packit Service |
384592 |
if (*p == '\0') return -5;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (*p != '=') return -13;
|
|
Packit Service |
384592 |
p++;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
while((*p == '\t') || (*p == ' ')) p++;
|
|
Packit Service |
384592 |
if (*p == '\0') return -6;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Accept both quotes as some backends will accept them, but
|
|
Packit Service |
384592 |
* technically "'" is invalid and so flag_invalid_quoting is
|
|
Packit Service |
384592 |
* set so the user can deal with it in the rules if they so wish.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if ((*p == '"') || (*p == '\'')) {
|
|
Packit Service |
384592 |
/* quoted */
|
|
Packit Service |
384592 |
char quote = *p;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (quote == '\'') {
|
|
Packit Service |
384592 |
msr->mpd->flag_invalid_quoting = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
p++;
|
|
Packit Service |
384592 |
if (*p == '\0') return -7;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
start = p;
|
|
Packit Service |
384592 |
value = apr_pstrdup(msr->mp, p);
|
|
Packit Service |
384592 |
t = value;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
while(*p != '\0') {
|
|
Packit Service |
384592 |
if (*p == '\\') {
|
|
Packit Service |
384592 |
if (*(p + 1) == '\0') {
|
|
Packit Service |
384592 |
/* improper escaping */
|
|
Packit Service |
384592 |
return -8;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
/* only quote and \ can be escaped */
|
|
Packit Service |
384592 |
if ((*(p + 1) == quote) || (*(p + 1) == '\\')) {
|
|
Packit Service |
384592 |
p++;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
/* improper escaping */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* We allow for now because IE sends
|
|
Packit Service |
384592 |
* improperly escaped content and there's
|
|
Packit Service |
384592 |
* nothing we can do about it.
|
|
Packit Service |
384592 |
*
|
|
Packit Service |
384592 |
* return -9;
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (*p == quote) {
|
|
Packit Service |
384592 |
*t = '\0';
|
|
Packit Service |
384592 |
break;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*(t++) = *(p++);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
if (*p == '\0') return -10;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
p++; /* go over the quote at the end */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* not quoted */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
start = p;
|
|
Packit Service |
384592 |
while((*p != '\0') && (is_token_char(*p))) p++;
|
|
Packit Service |
384592 |
value = apr_pstrmemdup(msr->mp, start, (p - start));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* evaluate part */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (strcmp(name, "name") == 0) {
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
validate_quotes(msr, value);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->multipart_name = apr_pstrdup(msr->mp, value);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->name != NULL) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: Duplicate Content-Disposition name: %s",
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, value));
|
|
Packit Service |
384592 |
return -14;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
msr->mpd->mpp->name = value;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit Service |
384592 |
msr_log(msr, 9, "Multipart: Content-Disposition name: %s",
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, value));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else
|
|
Packit Service |
384592 |
if (strcmp(name, "filename") == 0) {
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
validate_quotes(msr, value);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->multipart_filename = apr_pstrdup(msr->mp, value);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->filename != NULL) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: Duplicate Content-Disposition filename: %s",
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, value));
|
|
Packit Service |
384592 |
return -15;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
msr->mpd->mpp->filename = value;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit Service |
384592 |
msr_log(msr, 9, "Multipart: Content-Disposition filename: %s",
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, value));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else return -11;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (*p != '\0') {
|
|
Packit Service |
384592 |
while((*p == '\t') || (*p == ' ')) p++;
|
|
Packit Service |
384592 |
/* the next character must be a zero or a semi-colon */
|
|
Packit Service |
384592 |
if (*p == '\0') return 1; /* this is OK */
|
|
Packit Service |
384592 |
if (*p != ';') {
|
|
Packit Service |
384592 |
p--;
|
|
Packit Service |
384592 |
if(*p == '\'' || *p == '\"') {
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit Service |
384592 |
msr_log(msr, 9, "Multipart: Invalid quoting detected: %s length %zu bytes",
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, p), strlen(p));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
msr->mpd->flag_invalid_quoting = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
p++;
|
|
Packit Service |
384592 |
return -12;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
p++; /* move over the semi-colon */
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* loop will stop when (*p == '\0') */
|
|
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 int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
|
|
Packit Service |
384592 |
int i, len, rc;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (error_msg == NULL) return -1;
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Check for nul bytes. */
|
|
Packit Service |
384592 |
len = MULTIPART_BUF_SIZE - msr->mpd->bufleft;
|
|
Packit Service |
384592 |
for(i = 0; i < len; i++) {
|
|
Packit Service |
384592 |
if (msr->mpd->buf[i] == '\0') {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Nul byte in part headers.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* The buffer is data so increase the data length counter. */
|
|
Packit Service |
384592 |
msr->msc_reqbody_no_files_length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (len > 1) {
|
|
Packit Service |
384592 |
if (msr->mpd->buf[len - 2] == '\r') {
|
|
Packit Service |
384592 |
msr->mpd->flag_crlf_line = 1;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
msr->mpd->flag_lf_line = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
msr->mpd->flag_lf_line = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Is this an empty line? */
|
|
Packit Service |
384592 |
if ( ((msr->mpd->buf[0] == '\r')
|
|
Packit Service |
384592 |
&&(msr->mpd->buf[1] == '\n')
|
|
Packit Service |
384592 |
&&(msr->mpd->buf[2] == '\0') )
|
|
Packit Service |
384592 |
|| ((msr->mpd->buf[0] == '\n')
|
|
Packit Service |
384592 |
&&(msr->mpd->buf[1] == '\0') ) )
|
|
Packit Service |
384592 |
{ /* Empty line. */
|
|
Packit Service |
384592 |
char *header_value = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
header_value = (char *)apr_table_get(msr->mpd->mpp->headers, "Content-Disposition");
|
|
Packit Service |
384592 |
if (header_value == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Part missing Content-Disposition header.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
rc = multipart_parse_content_disposition(msr, header_value);
|
|
Packit Service |
384592 |
if (rc < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid Content-Disposition header (%d): %s.",
|
|
Packit Service |
384592 |
rc, log_escape_nq(msr->mp, header_value));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->name == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Content-Disposition header missing name field.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->filename != NULL) {
|
|
Packit Service |
384592 |
/* Some parsers use crude methods to extract the name and filename
|
|
Packit Service |
384592 |
* values from the C-D header. We need to check for the case where they
|
|
Packit Service |
384592 |
* didn't understand C-D but we did.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if (strstr(header_value, "filename=") == NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid Content-Disposition header (filename).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->mpp->type = MULTIPART_FILE;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
msr->mpd->mpp->type = MULTIPART_FORMDATA;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->mpp_state = 1;
|
|
Packit Service |
384592 |
msr->mpd->mpp->last_header_name = NULL;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* Header line. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (isspace(msr->mpd->buf[0])) {
|
|
Packit Service |
384592 |
char *header_value, *new_value, *data;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* header folding, add data to the header we are building */
|
|
Packit Service |
384592 |
msr->mpd->flag_header_folding = 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* RFC-2557 states header folding is SP / HTAB, but PHP and
|
|
Packit Service |
384592 |
* perhaps others will take any whitespace. So, we accept,
|
|
Packit Service |
384592 |
* but with a flag set.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if ((msr->mpd->buf[0] != '\t') && (msr->mpd->buf[0] != ' ')) {
|
|
Packit Service |
384592 |
msr->mpd->flag_invalid_header_folding = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->last_header_name == NULL) {
|
|
Packit Service |
384592 |
/* we are not building a header at this moment */
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid part header (folding error).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* locate the beginning of data */
|
|
Packit Service |
384592 |
data = msr->mpd->buf;
|
|
Packit Service |
384592 |
while(isspace(*data)) {
|
|
Packit Service |
384592 |
/* Flag invalid header folding if an invalid RFC-2557 character is used anywhere
|
|
Packit Service |
384592 |
* in the folding prefix.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if ((*data != '\t') && (*data != ' ')) {
|
|
Packit Service |
384592 |
msr->mpd->flag_invalid_header_folding = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
data++;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
new_value = apr_pstrdup(msr->mp, data);
|
|
Packit Service |
384592 |
remove_lf_crlf_inplace(new_value);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* update the header value in the table */
|
|
Packit Service |
384592 |
header_value = (char *)apr_table_get(msr->mpd->mpp->headers, msr->mpd->mpp->last_header_name);
|
|
Packit Service |
384592 |
new_value = apr_pstrcat(msr->mp, header_value, " ", new_value, NULL);
|
|
Packit Service |
384592 |
apr_table_set(msr->mpd->mpp->headers, msr->mpd->mpp->last_header_name, new_value);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit Service |
384592 |
msr_log(msr, 9, "Multipart: Continued folder header \"%s\" with \"%s\"",
|
|
Packit Service |
384592 |
log_escape(msr->mp, msr->mpd->mpp->last_header_name),
|
|
Packit Service |
384592 |
log_escape(msr->mp, data));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (strlen(new_value) > MULTIPART_BUF_SIZE) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Part header too long.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
char *header_name, *header_value, *data;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* new header */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
data = msr->mpd->buf;
|
|
Packit Service |
384592 |
while((*data != ':') && (*data != '\0')) data++;
|
|
Packit Service |
384592 |
if (*data == '\0') {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid part header (colon missing): %s.",
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, msr->mpd->buf));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* extract header name */
|
|
Packit Service |
384592 |
header_name = apr_pstrmemdup(msr->mp, msr->mpd->buf, (data - msr->mpd->buf));
|
|
Packit Service |
384592 |
if (data == msr->mpd->buf) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid part header (header name missing).");
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* extract the value value */
|
|
Packit Service |
384592 |
data++;
|
|
Packit Service |
384592 |
while((*data == '\t') || (*data == ' ')) data++;
|
|
Packit Service |
384592 |
header_value = apr_pstrdup(msr->mp, data);
|
|
Packit Service |
384592 |
remove_lf_crlf_inplace(header_value);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* error if the name already exists */
|
|
Packit Service |
384592 |
if (apr_table_get(msr->mpd->mpp->headers, header_name) != NULL) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Duplicate part header: %s.",
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, header_name));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
apr_table_setn(msr->mpd->mpp->headers, header_name, header_value);
|
|
Packit Service |
384592 |
msr->mpd->mpp->last_header_name = header_name;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit Service |
384592 |
msr_log(msr, 9, "Multipart: Added part header \"%s\" \"%s\"",
|
|
Packit Service |
384592 |
log_escape(msr->mp, header_name),
|
|
Packit Service |
384592 |
log_escape(msr->mp, header_value));
|
|
Packit Service |
384592 |
}
|
|
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 |
static int multipart_process_part_data(modsec_rec *msr, char **error_msg) {
|
|
Packit Service |
384592 |
char *p = msr->mpd->buf + (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
|
Packit Service |
384592 |
char localreserve[2] = { '\0', '\0' }; /* initialized to quiet warning */
|
|
Packit Service |
384592 |
int bytes_reserved = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (error_msg == NULL) return -1;
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Preserve some bytes for later. */
|
|
Packit Service |
384592 |
if ( ((MULTIPART_BUF_SIZE - msr->mpd->bufleft) >= 1)
|
|
Packit Service |
384592 |
&& (*(p - 1) == '\n') )
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
if ( ((MULTIPART_BUF_SIZE - msr->mpd->bufleft) >= 2)
|
|
Packit Service |
384592 |
&& (*(p - 2) == '\r') )
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
/* Two bytes. */
|
|
Packit Service |
384592 |
bytes_reserved = 2;
|
|
Packit Service |
384592 |
localreserve[0] = *(p - 2);
|
|
Packit Service |
384592 |
localreserve[1] = *(p - 1);
|
|
Packit Service |
384592 |
msr->mpd->bufleft += 2;
|
|
Packit Service |
384592 |
*(p - 2) = 0;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* Only one byte. */
|
|
Packit Service |
384592 |
bytes_reserved = 1;
|
|
Packit Service |
384592 |
localreserve[0] = *(p - 1);
|
|
Packit Service |
384592 |
localreserve[1] = 0;
|
|
Packit Service |
384592 |
msr->mpd->bufleft += 1;
|
|
Packit Service |
384592 |
*(p - 1) = 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* add data to the part we are building */
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->type == MULTIPART_FILE) {
|
|
Packit Service |
384592 |
int extract = msr->upload_extract_files;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* remember where we started */
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->length == 0) {
|
|
Packit Service |
384592 |
msr->mpd->mpp->offset = msr->mpd->buf_offset;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* check if the file limit has been reached */
|
|
Packit Service |
384592 |
if (extract && (msr->mpd->nfiles >= msr->txcfg->upload_file_limit)) {
|
|
Packit Service |
384592 |
if (msr->mpd->flag_file_limit_exceeded == 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp,
|
|
Packit Service |
384592 |
"Multipart: Upload file limit exceeded "
|
|
Packit Service |
384592 |
"SecUploadFileLimit %d.",
|
|
Packit Service |
384592 |
msr->txcfg->upload_file_limit);
|
|
Packit Service |
384592 |
msr_log(msr, 3, "%s", *error_msg);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->flag_file_limit_exceeded = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
extract = 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* only store individual files on disk if we are going
|
|
Packit Service |
384592 |
* to keep them or if we need to have them approved later
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if (extract) {
|
|
Packit Service |
384592 |
/* first create a temporary file if we don't have it already */
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->tmp_file_fd == 0) {
|
|
Packit Service |
384592 |
/* construct temporary file name */
|
|
Packit Service |
384592 |
msr->mpd->mpp->tmp_file_name = apr_psprintf(msr->mp, "%s/%s-%s-file-XXXXXX",
|
|
Packit Service |
384592 |
msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid);
|
|
Packit Service |
384592 |
msr->mpd->mpp->tmp_file_fd = msc_mkstemp_ex(msr->mpd->mpp->tmp_file_name, msr->txcfg->upload_filemode);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* do we have an opened file? */
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->tmp_file_fd < 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Failed to create file: %s",
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, msr->mpd->mpp->tmp_file_name));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* keep track of the files count */
|
|
Packit Service |
384592 |
msr->mpd->nfiles++;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 4) {
|
|
Packit Service |
384592 |
msr_log(msr, 4,
|
|
Packit Service |
384592 |
"Multipart: Created temporary file %d (mode %04o): %s",
|
|
Packit Service |
384592 |
msr->mpd->nfiles,
|
|
Packit Service |
384592 |
(unsigned int)msr->txcfg->upload_filemode,
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, msr->mpd->mpp->tmp_file_name));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* write the reserve first */
|
|
Packit Service |
384592 |
if (msr->mpd->reserve[0] != 0) {
|
|
Packit Service |
384592 |
if (write(msr->mpd->mpp->tmp_file_fd, &msr->mpd->reserve[1], msr->mpd->reserve[0]) != msr->mpd->reserve[0]) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: writing to \"%s\" failed",
|
|
Packit Service |
384592 |
log_escape(msr->mp, msr->mpd->mpp->tmp_file_name));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->mpp->tmp_file_size += msr->mpd->reserve[0];
|
|
Packit Service |
384592 |
msr->mpd->mpp->length += msr->mpd->reserve[0];
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* write data to the file */
|
|
Packit Service |
384592 |
if (write(msr->mpd->mpp->tmp_file_fd, msr->mpd->buf, MULTIPART_BUF_SIZE - msr->mpd->bufleft)
|
|
Packit Service |
384592 |
!= (MULTIPART_BUF_SIZE - msr->mpd->bufleft))
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: writing to \"%s\" failed",
|
|
Packit Service |
384592 |
log_escape(msr->mp, msr->mpd->mpp->tmp_file_name));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->mpp->tmp_file_size += (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
|
Packit Service |
384592 |
msr->mpd->mpp->length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* just keep track of the file size */
|
|
Packit Service |
384592 |
msr->mpd->mpp->tmp_file_size += (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0];
|
|
Packit Service |
384592 |
msr->mpd->mpp->length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0];
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (msr->mpd->mpp->type == MULTIPART_FORMDATA) {
|
|
Packit Service |
384592 |
value_part_t *value_part = apr_pcalloc(msr->mp, sizeof(value_part_t));
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* The buffer contains data so increase the data length counter. */
|
|
Packit Service |
384592 |
msr->msc_reqbody_no_files_length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0];
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* add this part to the list of parts */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* remember where we started */
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->length == 0) {
|
|
Packit Service |
384592 |
msr->mpd->mpp->offset = msr->mpd->buf_offset;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->reserve[0] != 0) {
|
|
Packit Service |
384592 |
value_part->data = apr_palloc(msr->mp, (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0]);
|
|
Packit Service |
384592 |
memcpy(value_part->data, &(msr->mpd->reserve[1]), msr->mpd->reserve[0]);
|
|
Packit Service |
384592 |
memcpy(value_part->data + msr->mpd->reserve[0], msr->mpd->buf, (MULTIPART_BUF_SIZE - msr->mpd->bufleft));
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
value_part->length = (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0];
|
|
Packit Service |
384592 |
msr->mpd->mpp->length += value_part->length;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
value_part->length = (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
|
Packit Service |
384592 |
value_part->data = apr_pstrmemdup(msr->mp, msr->mpd->buf, value_part->length);
|
|
Packit Service |
384592 |
msr->mpd->mpp->length += value_part->length;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*(value_part_t **)apr_array_push(msr->mpd->mpp->value_parts) = value_part;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit Service |
384592 |
msr_log(msr, 9, "Multipart: Added data to variable: %s",
|
|
Packit Service |
384592 |
log_escape_nq_ex(msr->mp, value_part->data, value_part->length));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: unknown part type %d", msr->mpd->mpp->type);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* store the reserved bytes to the multipart
|
|
Packit Service |
384592 |
* context so that they don't get lost
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if (bytes_reserved) {
|
|
Packit Service |
384592 |
msr->mpd->reserve[0] = bytes_reserved;
|
|
Packit Service |
384592 |
msr->mpd->reserve[1] = localreserve[0];
|
|
Packit Service |
384592 |
msr->mpd->reserve[2] = localreserve[1];
|
|
Packit Service |
384592 |
msr->mpd->buf_offset += bytes_reserved;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
msr->mpd->buf_offset -= msr->mpd->reserve[0];
|
|
Packit Service |
384592 |
msr->mpd->reserve[0] = 0;
|
|
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 char *multipart_combine_value_parts(modsec_rec *msr, apr_array_header_t *value_parts) {
|
|
Packit Service |
384592 |
value_part_t **parts = NULL;
|
|
Packit Service |
384592 |
char *rval = apr_palloc(msr->mp, msr->mpd->mpp->length + 1);
|
|
Packit Service |
384592 |
unsigned long int offset;
|
|
Packit Service |
384592 |
int i;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (rval == NULL) return NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
offset = 0;
|
|
Packit Service |
384592 |
parts = (value_part_t **)value_parts->elts;
|
|
Packit Service |
384592 |
for(i = 0; i < value_parts->nelts; i++) {
|
|
Packit Service |
384592 |
if (offset + parts[i]->length <= msr->mpd->mpp->length) {
|
|
Packit Service |
384592 |
memcpy(rval + offset, parts[i]->data, parts[i]->length);
|
|
Packit Service |
384592 |
offset += parts[i]->length;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
rval[offset] = '\0';
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return rval;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
*
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
static int multipart_process_boundary(modsec_rec *msr, int last_part, char **error_log) {
|
|
Packit Service |
384592 |
/* if there was a part being built finish it */
|
|
Packit Service |
384592 |
if (msr->mpd->mpp != NULL) {
|
|
Packit Service |
384592 |
/* close the temp file */
|
|
Packit Service |
384592 |
if ((msr->mpd->mpp->type == MULTIPART_FILE)
|
|
Packit Service |
384592 |
&&(msr->mpd->mpp->tmp_file_name != NULL)
|
|
Packit Service |
384592 |
&&(msr->mpd->mpp->tmp_file_fd != 0))
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
close(msr->mpd->mpp->tmp_file_fd);
|
|
Packit Service |
384592 |
msr->mpd->mpp->tmp_file_fd = -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->type != MULTIPART_FILE) {
|
|
Packit Service |
384592 |
/* now construct a single string out of the parts */
|
|
Packit Service |
384592 |
msr->mpd->mpp->value = multipart_combine_value_parts(msr, msr->mpd->mpp->value_parts);
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->value == NULL) return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->name) {
|
|
Packit Service |
384592 |
/* add the part to the list of parts */
|
|
Packit Service |
384592 |
*(multipart_part **)apr_array_push(msr->mpd->parts) = msr->mpd->mpp;
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->type == MULTIPART_FILE) {
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit Service |
384592 |
msr_log(msr, 9, "Multipart: Added file part %pp to the list: name \"%s\" "
|
|
Packit Service |
384592 |
"file name \"%s\" (offset %u, length %u)",
|
|
Packit Service |
384592 |
msr->mpd->mpp, log_escape(msr->mp, msr->mpd->mpp->name),
|
|
Packit Service |
384592 |
log_escape(msr->mp, msr->mpd->mpp->filename),
|
|
Packit Service |
384592 |
msr->mpd->mpp->offset, msr->mpd->mpp->length);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit Service |
384592 |
msr_log(msr, 9, "Multipart: Added part %pp to the list: name \"%s\" "
|
|
Packit Service |
384592 |
"(offset %u, length %u)", msr->mpd->mpp, log_escape(msr->mp, msr->mpd->mpp->name),
|
|
Packit Service |
384592 |
msr->mpd->mpp->offset, msr->mpd->mpp->length);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
msr->mpd->flag_invalid_part = 1;
|
|
Packit Service |
384592 |
msr_log(msr, 3, "Multipart: Skipping invalid part %pp (part name missing): "
|
|
Packit Service |
384592 |
"(offset %u, length %u)", msr->mpd->mpp,
|
|
Packit Service |
384592 |
msr->mpd->mpp->offset, msr->mpd->mpp->length);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->mpp = NULL;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (last_part == 0) {
|
|
Packit Service |
384592 |
/* start building a new part */
|
|
Packit Service |
384592 |
msr->mpd->mpp = (multipart_part *)apr_pcalloc(msr->mp, sizeof(multipart_part));
|
|
Packit Service |
384592 |
if (msr->mpd->mpp == NULL) return -1;
|
|
Packit Service |
384592 |
msr->mpd->mpp->type = MULTIPART_FORMDATA;
|
|
Packit Service |
384592 |
msr->mpd->mpp_state = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->mpp->headers = apr_table_make(msr->mp, 10);
|
|
Packit Service |
384592 |
if (msr->mpd->mpp->headers == NULL) return -1;
|
|
Packit Service |
384592 |
msr->mpd->mpp->last_header_name = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->reserve[0] = 0;
|
|
Packit Service |
384592 |
msr->mpd->reserve[1] = 0;
|
|
Packit Service |
384592 |
msr->mpd->reserve[2] = 0;
|
|
Packit Service |
384592 |
msr->mpd->reserve[3] = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->mpp->value_parts = apr_array_make(msr->mp, 10, sizeof(value_part_t *));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
static int multipart_boundary_characters_valid(char *boundary) {
|
|
Packit Service |
384592 |
unsigned char *p = (unsigned char *)boundary;
|
|
Packit Service |
384592 |
unsigned char c;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (p == NULL) return -1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
while((c = *p) != '\0') {
|
|
Packit Service |
384592 |
/* Control characters and space not allowed. */
|
|
Packit Service |
384592 |
if (c < 32) {
|
|
Packit Service |
384592 |
return 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Non-ASCII characters not allowed. */
|
|
Packit Service |
384592 |
if (c > 126) {
|
|
Packit Service |
384592 |
return 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
switch(c) {
|
|
Packit Service |
384592 |
/* Special characters not allowed. */
|
|
Packit Service |
384592 |
case '(' :
|
|
Packit Service |
384592 |
case ')' :
|
|
Packit Service |
384592 |
case '<' :
|
|
Packit Service |
384592 |
case '>' :
|
|
Packit Service |
384592 |
case '@' :
|
|
Packit Service |
384592 |
case ',' :
|
|
Packit Service |
384592 |
case ';' :
|
|
Packit Service |
384592 |
case ':' :
|
|
Packit Service |
384592 |
case '\\' :
|
|
Packit Service |
384592 |
case '"' :
|
|
Packit Service |
384592 |
case '/' :
|
|
Packit Service |
384592 |
case '[' :
|
|
Packit Service |
384592 |
case ']' :
|
|
Packit Service |
384592 |
case '?' :
|
|
Packit Service |
384592 |
case '=' :
|
|
Packit Service |
384592 |
return 0;
|
|
Packit Service |
384592 |
break;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
default :
|
|
Packit Service |
384592 |
/* Do nothing. */
|
|
Packit Service |
384592 |
break;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
p++;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
static int multipart_count_boundary_params(apr_pool_t *mp, const char *header_value) {
|
|
Packit Service |
384592 |
char *duplicate = NULL;
|
|
Packit Service |
384592 |
char *s = NULL;
|
|
Packit Service |
384592 |
int count = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (header_value == NULL) return -1;
|
|
Packit Service |
384592 |
duplicate = apr_pstrdup(mp, header_value);
|
|
Packit Service |
384592 |
if (duplicate == NULL) return -1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Performing a case-insensitive search. */
|
|
Packit Service |
384592 |
strtolower_inplace((unsigned char *)duplicate);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
s = duplicate;
|
|
Packit Service |
384592 |
while((s = strstr(s, "boundary")) != NULL) {
|
|
Packit Service |
384592 |
s += 8;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (strchr(s, '=') != NULL) {
|
|
Packit Service |
384592 |
count++;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return count;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/**
|
|
Packit Service |
384592 |
*
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
int multipart_init(modsec_rec *msr, char **error_msg) {
|
|
Packit Service |
384592 |
if (error_msg == NULL) return -1;
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd = (multipart_data *)apr_pcalloc(msr->mp, sizeof(multipart_data));
|
|
Packit Service |
384592 |
if (msr->mpd == NULL) return -1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->parts = apr_array_make(msr->mp, 10, sizeof(multipart_part *));
|
|
Packit Service |
384592 |
msr->mpd->bufleft = MULTIPART_BUF_SIZE;
|
|
Packit Service |
384592 |
msr->mpd->bufptr = msr->mpd->buf;
|
|
Packit Service |
384592 |
msr->mpd->buf_contains_line = 1;
|
|
Packit Service |
384592 |
msr->mpd->mpp = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->request_content_type == NULL) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Content-Type header not available.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (strlen(msr->request_content_type) > 1024) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (length).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (strncasecmp(msr->request_content_type, "multipart/form-data", 19) != 0) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid MIME type.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Count how many times the word "boundary" appears in the C-T header. */
|
|
Packit Service |
384592 |
if (multipart_count_boundary_params(msr->mp, msr->request_content_type) > 1) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Multiple boundary parameters in C-T.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->boundary = strstr(msr->request_content_type, "boundary");
|
|
Packit Service |
384592 |
if (msr->mpd->boundary != NULL) {
|
|
Packit Service |
384592 |
char *p = NULL;
|
|
Packit Service |
384592 |
char *b = NULL;
|
|
Packit Service |
384592 |
int seen_semicolon = 0;
|
|
Packit Service |
384592 |
int len = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Check for extra characters before the boundary. */
|
|
Packit Service |
384592 |
for (p = (char *)(msr->request_content_type + 19); p < msr->mpd->boundary; p++) {
|
|
Packit Service |
384592 |
if (!isspace(*p)) {
|
|
Packit Service |
384592 |
if ((seen_semicolon == 0) && (*p == ';')) {
|
|
Packit Service |
384592 |
seen_semicolon = 1; /* It is OK to have one semicolon. */
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (malformed).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Have we seen the semicolon in the header? */
|
|
Packit Service |
384592 |
if (seen_semicolon == 0) {
|
|
Packit Service |
384592 |
msr->mpd->flag_missing_semicolon = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
b = strchr(msr->mpd->boundary + 8, '=');
|
|
Packit Service |
384592 |
if (b == NULL) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (malformed).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Check parameter name ends well. */
|
|
Packit Service |
384592 |
if (b != (msr->mpd->boundary + 8)) {
|
|
Packit Service |
384592 |
/* Check all characters between the end of the boundary
|
|
Packit Service |
384592 |
* and the = character.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
for (p = msr->mpd->boundary + 8; p < b; p++) {
|
|
Packit Service |
384592 |
if (isspace(*p)) {
|
|
Packit Service |
384592 |
/* Flag for whitespace after parameter name. */
|
|
Packit Service |
384592 |
msr->mpd->flag_boundary_whitespace = 1;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (parameter name).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
b++; /* Go over the = character. */
|
|
Packit Service |
384592 |
len = strlen(b);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Flag for whitespace before parameter value. */
|
|
Packit Service |
384592 |
if (isspace(*b)) {
|
|
Packit Service |
384592 |
msr->mpd->flag_boundary_whitespace = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Is the boundary quoted? */
|
|
Packit Service |
384592 |
if ((len >= 2) && (*b == '"') && (*(b + len - 1) == '"')) {
|
|
Packit Service |
384592 |
/* Quoted. */
|
|
Packit Service |
384592 |
msr->mpd->boundary = apr_pstrndup(msr->mp, b + 1, len - 2);
|
|
Packit Service |
384592 |
if (msr->mpd->boundary == NULL) return -1;
|
|
Packit Service |
384592 |
msr->mpd->flag_boundary_quoted = 1;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* Not quoted. */
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Test for partial quoting. */
|
|
Packit Service |
384592 |
if ( (*b == '"')
|
|
Packit Service |
384592 |
|| ((len >= 2) && (*(b + len - 1) == '"')) )
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (quote).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->boundary = apr_pstrdup(msr->mp, b);
|
|
Packit Service |
384592 |
if (msr->mpd->boundary == NULL) return -1;
|
|
Packit Service |
384592 |
msr->mpd->flag_boundary_quoted = 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Case-insensitive test for the string "boundary" in the boundary. */
|
|
Packit Service |
384592 |
if (multipart_count_boundary_params(msr->mp, msr->mpd->boundary) != 0) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (content).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Validate the characters used in the boundary. */
|
|
Packit Service |
384592 |
if (multipart_boundary_characters_valid(msr->mpd->boundary) != 1) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (characters).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit Service |
384592 |
msr_log(msr, 9, "Multipart: Boundary%s: %s",
|
|
Packit Service |
384592 |
(msr->mpd->flag_boundary_quoted ? " (quoted)" : ""),
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, msr->mpd->boundary));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (strlen(msr->mpd->boundary) == 0) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (empty).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else { /* Could not find boundary in the C-T header. */
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Test for case-insensitive boundary. Allowed by the RFC but highly unusual. */
|
|
Packit Service |
384592 |
if (multipart_count_boundary_params(msr->mp, msr->request_content_type) > 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (case sensitivity).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Boundary not found in C-T.");
|
|
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 |
* Finalise multipart processing. This method is invoked at the end, when it
|
|
Packit Service |
384592 |
* is clear that there is no more data to be processed.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
int multipart_complete(modsec_rec *msr, char **error_msg) {
|
|
Packit Service |
384592 |
if (msr->mpd == NULL) return 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 4) {
|
|
Packit Service |
384592 |
if (msr->mpd->flag_data_before) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: seen data before first boundary.");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->flag_data_after) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: seen data after last boundary.");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->flag_boundary_quoted) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: boundary was quoted.");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->flag_boundary_whitespace) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: boundary whitespace in C-T header.");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->flag_header_folding) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: header folding used.");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->flag_crlf_line && msr->mpd->flag_lf_line) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: mixed line endings used (CRLF/LF).");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else if (msr->mpd->flag_lf_line) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: incorrect line endings used (LF).");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->flag_missing_semicolon) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: missing semicolon in C-T header.");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->flag_invalid_quoting) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: invalid quoting used.");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->flag_invalid_part) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: invalid part parsing.");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->flag_invalid_header_folding) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Warning: invalid header folding used.");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if ((msr->mpd->seen_data != 0) && (msr->mpd->is_complete == 0)) {
|
|
Packit Service |
384592 |
if (msr->mpd->boundary_count > 0) {
|
|
Packit Service |
384592 |
/* Check if we have the final boundary (that we haven't
|
|
Packit Service |
384592 |
* processed yet) in the buffer.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if (msr->mpd->buf_contains_line) {
|
|
Packit Service |
384592 |
if ( ((unsigned int)(MULTIPART_BUF_SIZE - msr->mpd->bufleft) == (4 + strlen(msr->mpd->boundary)))
|
|
Packit Service |
384592 |
&& (*(msr->mpd->buf) == '-')
|
|
Packit Service |
384592 |
&& (*(msr->mpd->buf + 1) == '-')
|
|
Packit Service |
384592 |
&& (strncmp(msr->mpd->buf + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0)
|
|
Packit Service |
384592 |
&& (*(msr->mpd->buf + 2 + strlen(msr->mpd->boundary)) == '-')
|
|
Packit Service |
384592 |
&& (*(msr->mpd->buf + 2 + strlen(msr->mpd->boundary) + 1) == '-') )
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
/* Looks like the final boundary - process it. */
|
|
Packit Service |
384592 |
if (multipart_process_boundary(msr, 1 /* final */, error_msg) < 0) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* The payload is complete after all. */
|
|
Packit Service |
384592 |
msr->mpd->is_complete = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->is_complete == 0) {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Final boundary missing.");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: No boundaries found in payload.");
|
|
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 |
int multipart_process_chunk(modsec_rec *msr, const char *buf,
|
|
Packit Service |
384592 |
unsigned int size, char **error_msg)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
char *inptr = (char *)buf;
|
|
Packit Service |
384592 |
unsigned int inleft = size;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (error_msg == NULL) return -1;
|
|
Packit Service |
384592 |
*error_msg = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (size == 0) return 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->seen_data = 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->is_complete) {
|
|
Packit Service |
384592 |
msr->mpd->flag_data_before = 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 4) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Ignoring data after last boundary (received %u bytes)", size);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->bufleft == 0) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp,
|
|
Packit Service |
384592 |
"Multipart: Internal error in process_chunk: no space left in the buffer");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* here we loop through the available data, one byte at a time */
|
|
Packit Service |
384592 |
while(inleft > 0) {
|
|
Packit Service |
384592 |
char c = *inptr;
|
|
Packit Service |
384592 |
int process_buffer = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if ((c == '\r') && (msr->mpd->bufleft == 1)) {
|
|
Packit Service |
384592 |
/* we don't want to take \r as the last byte in the buffer */
|
|
Packit Service |
384592 |
process_buffer = 1;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
inptr++;
|
|
Packit Service |
384592 |
inleft = inleft - 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*(msr->mpd->bufptr) = c;
|
|
Packit Service |
384592 |
msr->mpd->bufptr++;
|
|
Packit Service |
384592 |
msr->mpd->bufleft--;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* until we either reach the end of the line
|
|
Packit Service |
384592 |
* or the end of our internal buffer
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if ((c == '\n') || (msr->mpd->bufleft == 0) || (process_buffer)) {
|
|
Packit Service |
384592 |
int processed_as_boundary = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
*(msr->mpd->bufptr) = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Do we have something that looks like a boundary? */
|
|
Packit Service |
384592 |
if ( msr->mpd->buf_contains_line
|
|
Packit Service |
384592 |
&& (strlen(msr->mpd->buf) > 3)
|
|
Packit Service |
384592 |
&& (*(msr->mpd->buf) == '-')
|
|
Packit Service |
384592 |
&& (*(msr->mpd->buf + 1) == '-') )
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
/* Does it match our boundary? */
|
|
Packit Service |
384592 |
if ( (strlen(msr->mpd->buf) >= strlen(msr->mpd->boundary) + 2)
|
|
Packit Service |
384592 |
&& (strncmp(msr->mpd->buf + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) )
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
char *boundary_end = msr->mpd->buf + 2 + strlen(msr->mpd->boundary);
|
|
Packit Service |
384592 |
int is_final = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Is this the final boundary? */
|
|
Packit Service |
384592 |
if ((*boundary_end == '-') && (*(boundary_end + 1)== '-')) {
|
|
Packit Service |
384592 |
is_final = 1;
|
|
Packit Service |
384592 |
boundary_end += 2;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd->is_complete != 0) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp,
|
|
Packit Service |
384592 |
"Multipart: Invalid boundary (final duplicate).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Allow for CRLF and LF line endings. */
|
|
Packit Service |
384592 |
if ( ( (*boundary_end == '\r')
|
|
Packit Service |
384592 |
&& (*(boundary_end + 1) == '\n')
|
|
Packit Service |
384592 |
&& (*(boundary_end + 2) == '\0') )
|
|
Packit Service |
384592 |
|| ( (*boundary_end == '\n')
|
|
Packit Service |
384592 |
&& (*(boundary_end + 1) == '\0') ) )
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
if (*boundary_end == '\n') {
|
|
Packit Service |
384592 |
msr->mpd->flag_lf_line = 1;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
msr->mpd->flag_crlf_line = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (multipart_process_boundary(msr, (is_final ? 1 : 0), error_msg) < 0) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (is_final) {
|
|
Packit Service |
384592 |
msr->mpd->is_complete = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
processed_as_boundary = 1;
|
|
Packit Service |
384592 |
msr->mpd->boundary_count++;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
else {
|
|
Packit Service |
384592 |
/* error */
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp,
|
|
Packit Service |
384592 |
"Multipart: Invalid boundary: %s",
|
|
Packit Service |
384592 |
log_escape_nq(msr->mp, msr->mpd->buf));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else { /* It looks like a boundary but we couldn't match it. */
|
|
Packit Service |
384592 |
char *p = NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Check if an attempt to use quotes around the boundary was made. */
|
|
Packit Service |
384592 |
if ( (msr->mpd->flag_boundary_quoted)
|
|
Packit Service |
384592 |
&& (strlen(msr->mpd->buf) >= strlen(msr->mpd->boundary) + 3)
|
|
Packit Service |
384592 |
&& (*(msr->mpd->buf + 2) == '"')
|
|
Packit Service |
384592 |
&& (strncmp(msr->mpd->buf + 3, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0)
|
|
Packit Service |
384592 |
) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary (quotes).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Check the beginning of the boundary for whitespace. */
|
|
Packit Service |
384592 |
p = msr->mpd->buf + 2;
|
|
Packit Service |
384592 |
while(isspace(*p)) {
|
|
Packit Service |
384592 |
p++;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if ( (p != msr->mpd->buf + 2)
|
|
Packit Service |
384592 |
&& (strncmp(p, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0)
|
|
Packit Service |
384592 |
) {
|
|
Packit Service |
384592 |
/* Found whitespace in front of a boundary. */
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary (whitespace).");
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
msr->mpd->flag_unmatched_boundary = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else { /* We do not think the buffer contains a boundary. */
|
|
Packit Service |
384592 |
/* Look into the buffer to see if there's anything
|
|
Packit Service |
384592 |
* there that resembles a boundary.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if (msr->mpd->buf_contains_line) {
|
|
Packit Service |
384592 |
int i, len = (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
|
Packit Service |
384592 |
char *p = msr->mpd->buf;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
for(i = 0; i < len; i++) {
|
|
Packit Service |
384592 |
if ((p[i] == '-') && (i + 1 < len) && (p[i + 1] == '-'))
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
if (strncmp(p + i + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) {
|
|
Packit Service |
384592 |
msr->mpd->flag_unmatched_boundary = 1;
|
|
Packit Service |
384592 |
break;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Process as data if it was not a boundary. */
|
|
Packit Service |
384592 |
if (processed_as_boundary == 0) {
|
|
Packit Service |
384592 |
if (msr->mpd->mpp == NULL) {
|
|
Packit Service |
384592 |
msr->mpd->flag_data_before = 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 4) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Ignoring data before first boundary.");
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
if (msr->mpd->mpp_state == 0) {
|
|
Packit Service |
384592 |
if ((msr->mpd->bufleft == 0) || (process_buffer)) {
|
|
Packit Service |
384592 |
/* part header lines must be shorter than
|
|
Packit Service |
384592 |
* MULTIPART_BUF_SIZE bytes
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
*error_msg = apr_psprintf(msr->mp,
|
|
Packit Service |
384592 |
"Multipart: Part header line over %d bytes long",
|
|
Packit Service |
384592 |
MULTIPART_BUF_SIZE);
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (multipart_process_part_header(msr, error_msg) < 0) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
if (multipart_process_part_data(msr, error_msg) < 0) {
|
|
Packit Service |
384592 |
msr->mpd->flag_error = 1;
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Update the offset of the data we are about
|
|
Packit Service |
384592 |
* to process. This is to allow us to know the
|
|
Packit Service |
384592 |
* offsets of individual files and variables.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
msr->mpd->buf_offset += (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* reset the pointer to the beginning of the buffer
|
|
Packit Service |
384592 |
* and continue to accept input data
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
msr->mpd->bufptr = msr->mpd->buf;
|
|
Packit Service |
384592 |
msr->mpd->bufleft = MULTIPART_BUF_SIZE;
|
|
Packit Service |
384592 |
msr->mpd->buf_contains_line = (c == 0x0a) ? 1 : 0;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if ((msr->mpd->is_complete) && (inleft != 0)) {
|
|
Packit Service |
384592 |
msr->mpd->flag_data_after = 1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 4) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Ignoring data after last boundary (%u bytes left)", inleft);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
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 multipart_cleanup(modsec_rec *msr) {
|
|
Packit Service |
384592 |
int keep_files = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd == NULL) return -1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 4) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Cleanup started (remove files %d).", msr->upload_remove_files);
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->upload_remove_files == 0) {
|
|
Packit Service |
384592 |
if (msr->txcfg->upload_dir == NULL) {
|
|
Packit Service |
384592 |
msr_log(msr, 1, "Input filter: SecUploadDir is undefined, unable to store "
|
|
Packit Service |
384592 |
"multipart files.");
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
keep_files = 1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Loop through the list of parts
|
|
Packit Service |
384592 |
* and delete the temporary files, but only if
|
|
Packit Service |
384592 |
* file storage was not requested, or if storage
|
|
Packit Service |
384592 |
* of relevant files was requested and this isn't
|
|
Packit Service |
384592 |
* such a request.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if (keep_files == 0) {
|
|
Packit Service |
384592 |
multipart_part **parts;
|
|
Packit Service |
384592 |
int i;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
parts = (multipart_part **)msr->mpd->parts->elts;
|
|
Packit Service |
384592 |
for(i = 0; i < msr->mpd->parts->nelts; i++) {
|
|
Packit Service |
384592 |
if (parts[i]->type == MULTIPART_FILE) {
|
|
Packit Service |
384592 |
if (parts[i]->tmp_file_name != NULL) {
|
|
Packit Service |
384592 |
/* make sure it is closed first */
|
|
Packit Service |
384592 |
if (parts[i]->tmp_file_fd > 0) {
|
|
Packit Service |
384592 |
close(parts[i]->tmp_file_fd);
|
|
Packit Service |
384592 |
parts[i]->tmp_file_fd = -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (unlink(parts[i]->tmp_file_name) < 0) {
|
|
Packit Service |
384592 |
msr_log(msr, 1, "Multipart: Failed to delete file (part) \"%s\" because %d(%s)",
|
|
Packit Service |
384592 |
log_escape(msr->mp, parts[i]->tmp_file_name), errno, strerror(errno));
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 4) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Deleted file (part) \"%s\"",
|
|
Packit Service |
384592 |
log_escape(msr->mp, parts[i]->tmp_file_name));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* delete empty files, move the others to the upload dir */
|
|
Packit Service |
384592 |
multipart_part **parts;
|
|
Packit Service |
384592 |
int i;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
parts = (multipart_part **)msr->mpd->parts->elts;
|
|
Packit Service |
384592 |
for(i = 0; i < msr->mpd->parts->nelts; i++) {
|
|
Packit Service |
384592 |
if ( (parts[i]->type == MULTIPART_FILE)
|
|
Packit Service |
384592 |
&& (parts[i]->tmp_file_size == 0))
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
/* Delete empty file. */
|
|
Packit Service |
384592 |
if (parts[i]->tmp_file_name != NULL) {
|
|
Packit Service |
384592 |
/* make sure it is closed first */
|
|
Packit Service |
384592 |
if (parts[i]->tmp_file_fd > 0) {
|
|
Packit Service |
384592 |
close(parts[i]->tmp_file_fd);
|
|
Packit Service |
384592 |
parts[i]->tmp_file_fd = -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (unlink(parts[i]->tmp_file_name) < 0) {
|
|
Packit Service |
384592 |
msr_log(msr, 1, "Multipart: Failed to delete empty file (part) \"%s\" because %d(%s)",
|
|
Packit Service |
384592 |
log_escape(msr->mp, parts[i]->tmp_file_name), errno, strerror(errno));
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 4) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Multipart: Deleted empty file (part) \"%s\"",
|
|
Packit Service |
384592 |
log_escape(msr->mp, parts[i]->tmp_file_name));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
/* Move file to the upload dir. */
|
|
Packit Service |
384592 |
if (parts[i]->tmp_file_name != NULL) {
|
|
Packit Service |
384592 |
const char *new_filename = NULL;
|
|
Packit Service |
384592 |
const char *new_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 part to identical location");
|
|
Packit Service |
384592 |
continue;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* make sure it is closed first */
|
|
Packit Service |
384592 |
if (parts[i]->tmp_file_fd > 0) {
|
|
Packit Service |
384592 |
close(parts[i]->tmp_file_fd);
|
|
Packit Service |
384592 |
parts[i]->tmp_file_fd = -1;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
new_basename = file_basename(msr->mp, parts[i]->tmp_file_name);
|
|
Packit Service |
384592 |
if (new_basename == NULL) return -1;
|
|
Packit Service |
384592 |
new_filename = apr_psprintf(msr->mp, "%s/%s", msr->txcfg->upload_dir,
|
|
Packit Service |
384592 |
new_basename);
|
|
Packit Service |
384592 |
if (new_filename == NULL) return -1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (apr_file_rename(parts[i]->tmp_file_name, new_filename,
|
|
Packit Service |
384592 |
msr->msc_reqbody_mp) != APR_SUCCESS)
|
|
Packit Service |
384592 |
{
|
|
Packit Service |
384592 |
msr_log(msr, 1, "Input filter: Failed to rename file from \"%s\" to \"%s\".",
|
|
Packit Service |
384592 |
log_escape(msr->mp, parts[i]->tmp_file_name),
|
|
Packit Service |
384592 |
log_escape(msr->mp, new_filename));
|
|
Packit Service |
384592 |
return -1;
|
|
Packit Service |
384592 |
} else {
|
|
Packit Service |
384592 |
if (msr->txcfg->debuglog_level >= 4) {
|
|
Packit Service |
384592 |
msr_log(msr, 4, "Input filter: Moved file from \"%s\" to \"%s\".",
|
|
Packit Service |
384592 |
log_escape(msr->mp, parts[i]->tmp_file_name),
|
|
Packit Service |
384592 |
log_escape(msr->mp, new_filename));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
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 |
int multipart_get_arguments(modsec_rec *msr, char *origin, apr_table_t *arguments) {
|
|
Packit Service |
384592 |
multipart_part **parts;
|
|
Packit Service |
384592 |
int i;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
parts = (multipart_part **)msr->mpd->parts->elts;
|
|
Packit Service |
384592 |
for(i = 0; i < msr->mpd->parts->nelts; i++) {
|
|
Packit Service |
384592 |
if (parts[i]->type == MULTIPART_FORMDATA) {
|
|
Packit Service |
384592 |
msc_arg *arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg));
|
|
Packit Service |
384592 |
if (arg == NULL) return -1;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
arg->name = parts[i]->name;
|
|
Packit Service |
384592 |
arg->name_len = strlen(parts[i]->name);
|
|
Packit Service |
384592 |
arg->value = parts[i]->value;
|
|
Packit Service |
384592 |
arg->value_len = parts[i]->length;
|
|
Packit Service |
384592 |
arg->value_origin_offset = parts[i]->offset;
|
|
Packit Service |
384592 |
arg->value_origin_len = parts[i]->length;
|
|
Packit Service |
384592 |
arg->origin = origin;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
add_argument(msr, arguments, arg);
|
|
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 |
char *multipart_reconstruct_urlencoded_body_sanitize(modsec_rec *msr) {
|
|
Packit Service |
384592 |
multipart_part **parts;
|
|
Packit Service |
384592 |
char *body;
|
|
Packit Service |
384592 |
unsigned int body_len;
|
|
Packit Service |
384592 |
int i;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
if (msr->mpd == NULL) return NULL;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* calculate the size of the buffer */
|
|
Packit Service |
384592 |
body_len = 1;
|
|
Packit Service |
384592 |
parts = (multipart_part **)msr->mpd->parts->elts;
|
|
Packit Service |
384592 |
for(i = 0; i < msr->mpd->parts->nelts; i++) {
|
|
Packit Service |
384592 |
if (parts[i]->type == MULTIPART_FORMDATA) {
|
|
Packit Service |
384592 |
body_len += 4;
|
|
Packit Service |
384592 |
body_len += strlen(parts[i]->name) * 3;
|
|
Packit Service |
384592 |
body_len += strlen(parts[i]->value) * 3;
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* allocate the buffer */
|
|
Packit Service |
384592 |
body = apr_palloc(msr->mp, body_len + 1);
|
|
Packit Service |
384592 |
if ((body == NULL) || (body_len + 1 == 0)) return NULL;
|
|
Packit Service |
384592 |
*body = 0;
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
parts = (multipart_part **)msr->mpd->parts->elts;
|
|
Packit Service |
384592 |
for(i = 0; i < msr->mpd->parts->nelts; i++) {
|
|
Packit Service |
384592 |
if (parts[i]->type == MULTIPART_FORMDATA) {
|
|
Packit Service |
384592 |
if (*body != 0) {
|
|
Packit Service |
384592 |
strncat(body, "&", body_len - strlen(body));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
strnurlencat(body, parts[i]->name, body_len - strlen(body));
|
|
Packit Service |
384592 |
strncat(body, "=", body_len - strlen(body));
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
/* Sanitise the variable. Since we are only doing this for
|
|
Packit Service |
384592 |
* the logging we will actually write over the data we keep
|
|
Packit Service |
384592 |
* in the memory.
|
|
Packit Service |
384592 |
*/
|
|
Packit Service |
384592 |
if (msr->phase >= PHASE_LOGGING) {
|
|
Packit Service |
384592 |
if (apr_table_get(msr->arguments_to_sanitize, parts[i]->name) != NULL) {
|
|
Packit Service |
384592 |
memset(parts[i]->value, '*', strlen(parts[i]->value));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
strnurlencat(body, parts[i]->value, body_len - strlen(body));
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
}
|
|
Packit Service |
384592 |
|
|
Packit Service |
384592 |
return body;
|
|
Packit Service |
384592 |
}
|