in apache2/msc_multipart.c [1059:1284]
int multipart_process_chunk(modsec_rec *msr, const char *buf,
unsigned int size, char **error_msg)
{
char *inptr = (char *)buf;
unsigned int inleft = size;
if (error_msg == NULL) return -1;
*error_msg = NULL;
if (size == 0) return 1;
msr->mpd->seen_data = 1;
if (msr->mpd->is_complete) {
msr->mpd->flag_data_before = 1;
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Multipart: Ignoring data after last boundary (received %u bytes)", size);
}
return 1;
}
if (msr->mpd->bufleft == 0) {
msr->mpd->flag_error = 1;
*error_msg = apr_psprintf(msr->mp,
"Multipart: Internal error in process_chunk: no space left in the buffer");
return -1;
}
/* here we loop through the available data, one byte at a time */
while(inleft > 0) {
char c = *inptr;
int process_buffer = 0;
if ((c == '\r') && (msr->mpd->bufleft == 1)) {
/* we don't want to take \r as the last byte in the buffer */
process_buffer = 1;
} else {
inptr++;
inleft = inleft - 1;
*(msr->mpd->bufptr) = c;
msr->mpd->bufptr++;
msr->mpd->bufleft--;
}
/* until we either reach the end of the line
* or the end of our internal buffer
*/
if ((c == '\n') || (msr->mpd->bufleft == 0) || (process_buffer)) {
int processed_as_boundary = 0;
*(msr->mpd->bufptr) = 0;
/* Do we have something that looks like a boundary? */
if ( msr->mpd->buf_contains_line
&& (strlen(msr->mpd->buf) > 3)
&& (*(msr->mpd->buf) == '-')
&& (*(msr->mpd->buf + 1) == '-') )
{
/* Does it match our boundary? */
if ( (strlen(msr->mpd->buf) >= strlen(msr->mpd->boundary) + 2)
&& (strncmp(msr->mpd->buf + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) )
{
char *boundary_end = msr->mpd->buf + 2 + strlen(msr->mpd->boundary);
int is_final = 0;
/* Is this the final boundary? */
if ((*boundary_end == '-') && (*(boundary_end + 1)== '-')) {
is_final = 1;
boundary_end += 2;
if (msr->mpd->is_complete != 0) {
msr->mpd->flag_error = 1;
*error_msg = apr_psprintf(msr->mp,
"Multipart: Invalid boundary (final duplicate).");
return -1;
}
}
/* Allow for CRLF and LF line endings. */
if ( ( (*boundary_end == '\r')
&& (*(boundary_end + 1) == '\n')
&& (*(boundary_end + 2) == '\0') )
|| ( (*boundary_end == '\n')
&& (*(boundary_end + 1) == '\0') ) )
{
if (*boundary_end == '\n') {
msr->mpd->flag_lf_line = 1;
} else {
msr->mpd->flag_crlf_line = 1;
}
if (multipart_process_boundary(msr, (is_final ? 1 : 0), error_msg) < 0) {
msr->mpd->flag_error = 1;
return -1;
}
if (is_final) {
msr->mpd->is_complete = 1;
}
processed_as_boundary = 1;
msr->mpd->boundary_count++;
}
else {
/* error */
msr->mpd->flag_error = 1;
*error_msg = apr_psprintf(msr->mp,
"Multipart: Invalid boundary: %s",
log_escape_nq(msr->mp, msr->mpd->buf));
return -1;
}
} else { /* It looks like a boundary but we couldn't match it. */
char *p = NULL;
/* Check if an attempt to use quotes around the boundary was made. */
if ( (msr->mpd->flag_boundary_quoted)
&& (strlen(msr->mpd->buf) >= strlen(msr->mpd->boundary) + 3)
&& (*(msr->mpd->buf + 2) == '"')
&& (strncmp(msr->mpd->buf + 3, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0)
) {
msr->mpd->flag_error = 1;
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary (quotes).");
return -1;
}
/* Check the beginning of the boundary for whitespace. */
p = msr->mpd->buf + 2;
while(isspace(*p)) {
p++;
}
if ( (p != msr->mpd->buf + 2)
&& (strncmp(p, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0)
) {
/* Found whitespace in front of a boundary. */
msr->mpd->flag_error = 1;
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary (whitespace).");
return -1;
}
msr->mpd->flag_unmatched_boundary = 1;
}
} else { /* We do not think the buffer contains a boundary. */
/* Look into the buffer to see if there's anything
* there that resembles a boundary.
*/
if (msr->mpd->buf_contains_line) {
int i, len = (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
char *p = msr->mpd->buf;
for(i = 0; i < len; i++) {
if ((p[i] == '-') && (i + 1 < len) && (p[i + 1] == '-'))
{
if (strncmp(p + i + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) {
msr->mpd->flag_unmatched_boundary = 1;
break;
}
}
}
}
}
/* Process as data if it was not a boundary. */
if (processed_as_boundary == 0) {
if (msr->mpd->mpp == NULL) {
msr->mpd->flag_data_before = 1;
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Multipart: Ignoring data before first boundary.");
}
} else {
if (msr->mpd->mpp_state == 0) {
if ((msr->mpd->bufleft == 0) || (process_buffer)) {
/* part header lines must be shorter than
* MULTIPART_BUF_SIZE bytes
*/
msr->mpd->flag_error = 1;
*error_msg = apr_psprintf(msr->mp,
"Multipart: Part header line over %d bytes long",
MULTIPART_BUF_SIZE);
return -1;
}
if (multipart_process_part_header(msr, error_msg) < 0) {
msr->mpd->flag_error = 1;
return -1;
}
} else {
if (multipart_process_part_data(msr, error_msg) < 0) {
msr->mpd->flag_error = 1;
return -1;
}
}
}
}
/* Update the offset of the data we are about
* to process. This is to allow us to know the
* offsets of individual files and variables.
*/
msr->mpd->buf_offset += (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
/* reset the pointer to the beginning of the buffer
* and continue to accept input data
*/
msr->mpd->bufptr = msr->mpd->buf;
msr->mpd->bufleft = MULTIPART_BUF_SIZE;
msr->mpd->buf_contains_line = (c == 0x0a) ? 1 : 0;
}
if ((msr->mpd->is_complete) && (inleft != 0)) {
msr->mpd->flag_data_after = 1;
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Multipart: Ignoring data after last boundary (%u bytes left)", inleft);
}
return 1;
}
}
return 1;
}