1 /*
2 * ModSecurity for Apache 2.x, http://www.modsecurity.org/
3 * Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
4 *
5 * You may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * If any of the files related to licensing are missing or if you have any
11 * other questions related to licensing please contact Trustwave Holdings, Inc.
12 * directly using the email address security@modsecurity.org.
13 */
14 
15 #include "modsecurity.h"
16 #include "re.h"
17 #include "msc_parsers.h"
18 
19 #define CHUNK_CAPACITY 8192
20 
21 
22 /**
23  *
24  */
msre_engine_reqbody_processor_register(msre_engine * engine,const char * name,void * fn_init,void * fn_process,void * fn_complete)25 void msre_engine_reqbody_processor_register(msre_engine *engine,
26     const char *name, void *fn_init, void *fn_process, void *fn_complete)
27 {
28     msre_reqbody_processor_metadata *metadata =
29         (msre_reqbody_processor_metadata *)apr_pcalloc(engine->mp,
30             sizeof(msre_reqbody_processor_metadata));
31     if (metadata == NULL) return;
32 
33     metadata->name = name;
34     metadata->init = fn_init;
35     metadata->process = fn_process;
36     metadata->complete = fn_complete;
37     apr_table_setn(engine->reqbody_processors, name, (void *)metadata);
38 }
39 
40 /**
41  * Prepare to accept the request body (part 2).
42  */
modsecurity_request_body_start_init(modsec_rec * msr,char ** error_msg)43 static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr, char **error_msg) {
44     *error_msg = NULL;
45 
46     if(msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
47         /* Prepare to store request body in memory. */
48 
49         msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp,
50             32, sizeof(msc_data_chunk *));
51         if (msr->msc_reqbody_chunks == NULL) {
52             *error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to prepare in-memory storage.");
53             return -1;
54         }
55     } else {
56         /* Prepare to store request body on disk. */
57 
58         msr->msc_reqbody_filename = apr_psprintf(msr->mp, "%s/%s-%s-request_body-XXXXXX",
59             msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid);
60         if (msr->msc_reqbody_filename == NULL) {
61             *error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to generate an on-disk filename.");
62             return -1;
63         }
64 
65         msr->msc_reqbody_fd = msc_mkstemp((char *)msr->msc_reqbody_filename);
66         if (msr->msc_reqbody_fd < 0) {
67             *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to create temporary file: %s",
68                 msr->msc_reqbody_filename);
69             return -1;
70         }
71 
72         msr_log(msr, 4, "Input filter: Created temporary file to store request body: %s",
73             msr->msc_reqbody_filename);
74     }
75 
76     return 1;
77 }
78 
79 /**
80  * Prepare to accept the request body (part 1).
81  */
modsecurity_request_body_start(modsec_rec * msr,char ** error_msg)82 apr_status_t modsecurity_request_body_start(modsec_rec *msr, char **error_msg) {
83     *error_msg = NULL;
84     msr->msc_reqbody_length = 0;
85     msr->stream_input_length = 0;
86 
87     /* Create a separate memory pool that will be used
88      * to allocate structures from (not data, which is allocated
89      * via malloc).
90      */
91     apr_pool_create(&msr->msc_reqbody_mp, NULL);
92 
93     /* Initialise request body processors, if any. */
94 
95     if (msr->msc_reqbody_processor != NULL) {
96         char *my_error_msg = NULL;
97         msre_reqbody_processor_metadata *metadata =
98             (msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor);
99 
100         if (metadata != NULL) {
101             if (   (metadata->init != NULL)
102                 && (metadata->init(msr, &my_error_msg) < 0))
103             {
104                 *error_msg = apr_psprintf(msr->mp,
105                                           "%s parsing error (init): %s",
106                                           msr->msc_reqbody_processor,
107                                           my_error_msg);
108                 msr->msc_reqbody_error = 1;
109                 msr->msc_reqbody_error_msg = my_error_msg;
110                 msr_log(msr, 2, "%s", *error_msg);
111             }
112         }
113         // TODO: All these below need to be registered in the same way as above
114         else if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
115             if (multipart_init(msr, &my_error_msg) < 0) {
116                 *error_msg = apr_psprintf(msr->mp, "Multipart parsing error (init): %s", my_error_msg);
117                 msr->msc_reqbody_error = 1;
118                 msr->msc_reqbody_error_msg = my_error_msg;
119                 msr_log(msr, 2, "%s", *error_msg);
120             }
121         }
122         else if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
123             if (xml_init(msr, &my_error_msg) < 0) {
124                 *error_msg = apr_psprintf(msr->mp, "XML parsing error (init): %s", my_error_msg);
125                 msr->msc_reqbody_error = 1;
126                 msr->msc_reqbody_error_msg = my_error_msg;
127                 msr_log(msr, 2, "%s", *error_msg);
128             }
129         }
130         else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
131 #ifdef WITH_YAJL
132             if (json_init(msr, &my_error_msg) < 0) {
133                 *error_msg = apr_psprintf(msr->mp, "JSON parsing error (init): %s", my_error_msg);
134                 msr->msc_reqbody_error = 1;
135                 msr->msc_reqbody_error_msg = my_error_msg;
136                 msr_log(msr, 2, "%s", *error_msg);
137             }
138 #else
139             *error_msg = apr_psprintf(msr->mp, "JSON support was not enabled");
140             msr->msc_reqbody_error = 1;
141             msr->msc_reqbody_error_msg = my_error_msg;
142             msr_log(msr, 2, "%s", *error_msg);
143 #endif
144         }
145         else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
146             /* Do nothing, URLENCODED processor does not support streaming yet. */
147         }
148         else {
149             *error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s",
150                 msr->msc_reqbody_processor);
151             return -1;
152         }
153     }
154 
155     return modsecurity_request_body_start_init(msr, error_msg);
156 }
157 
158 /**
159  * Stores a chunk of request body data to disk.
160  */
modsecurity_request_body_store_disk(modsec_rec * msr,const char * data,apr_size_t length,char ** error_msg)161 static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr,
162     const char *data, apr_size_t length, char **error_msg)
163 {
164     apr_size_t i;
165 
166     *error_msg = NULL;
167 
168     i = write(msr->msc_reqbody_fd, data, length);
169     if (i != length) {
170         *error_msg = apr_psprintf(msr->mp, "Input filter: Failed writing %" APR_SIZE_T_FMT
171             " bytes to temporary file (rc %" APR_SIZE_T_FMT ").", length, i);
172         return -1;
173     }
174 
175     return 1;
176 }
177 
178 /**
179  * Stores one chunk of request body data in memory.
180  */
modsecurity_request_body_store_memory(modsec_rec * msr,const char * data,apr_size_t length,char ** error_msg)181 static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr,
182     const char *data, apr_size_t length, char **error_msg)
183 {
184     *error_msg = NULL;
185 
186     /* Would storing this chunk mean going over the limit? */
187     if ((msr->msc_reqbody_spilltodisk)
188         && (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_ON)
189         && (msr->msc_reqbody_length + length > (apr_size_t)msr->txcfg->reqbody_inmemory_limit))
190     {
191         msc_data_chunk **chunks;
192         unsigned int disklen = 0;
193         int i;
194 
195         msr_log(msr, 4, "Input filter: Request too large to store in memory, switching to disk.");
196 
197         /* NOTE Must use modsecurity_request_body_store_disk() here
198          *      to prevent data to be sent to the streaming
199          *      processors again.
200          */
201 
202         /* Initialise disk storage */
203         msr->msc_reqbody_storage = MSC_REQBODY_DISK;
204         if (modsecurity_request_body_start_init(msr, error_msg) < 0) return -1;
205 
206         /* Write the data we keep in memory */
207         chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
208         for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
209             disklen += chunks[i]->length;
210 
211             if (modsecurity_request_body_store_disk(msr, chunks[i]->data, chunks[i]->length, error_msg) < 0) {
212                 return -1;
213             }
214 
215             free(chunks[i]->data);
216             chunks[i]->data = NULL;
217         }
218 
219         /* Clear the memory pool as we no longer need the bits. */
220 
221         /* IMP1 But since we only used apr_pool_clear memory might
222          * not be released back to the OS straight away?
223          */
224         msr->msc_reqbody_chunks = NULL;
225         apr_pool_clear(msr->msc_reqbody_mp);
226 
227         msr_log(msr, 4, "Input filter: Wrote %u bytes from memory to disk.", disklen);
228 
229         /* Continue with disk storage from now on */
230         return modsecurity_request_body_store_disk(msr, data, length, error_msg);
231     }
232 
233     /* If we're here that means we are not over the
234      * request body in-memory limit yet.
235      */
236     {
237         unsigned long int bucket_offset, bucket_left;
238 
239         bucket_offset = 0;
240         bucket_left = length;
241 
242         /* Although we store the request body in chunks we don't
243          * want to use the same chunk sizes as the incoming memory
244          * buffers. They are often of very small sizes and that
245          * would make us waste a lot of memory. That's why we
246          * use our own chunks of CHUNK_CAPACITY sizes.
247          */
248 
249         /* Loop until we empty this bucket into our chunks. */
250         while(bucket_left > 0) {
251             /* Allocate a new chunk if we have to. */
252             if (msr->msc_reqbody_chunk_current == NULL) {
253                 msr->msc_reqbody_chunk_current = (msc_data_chunk *)
254                     apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
255                 if (msr->msc_reqbody_chunk_current == NULL) {
256                     *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to allocate %lu bytes "
257                         "for request body chunk.", (unsigned long)sizeof(msc_data_chunk));
258                     return -1;
259                 }
260 
261                 msr->msc_reqbody_chunk_current->data = malloc(CHUNK_CAPACITY);
262                 if (msr->msc_reqbody_chunk_current->data == NULL) {
263                     *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to allocate %d bytes "
264                         "for request body chunk data.", CHUNK_CAPACITY);
265                     return -1;
266                 }
267 
268                 msr->msc_reqbody_chunk_current->length = 0;
269                 msr->msc_reqbody_chunk_current->is_permanent = 1;
270 
271                 *(const msc_data_chunk **)apr_array_push(msr->msc_reqbody_chunks)
272                     = msr->msc_reqbody_chunk_current;
273             }
274 
275             if (bucket_left < (CHUNK_CAPACITY - msr->msc_reqbody_chunk_current->length)) {
276                 /* There's enough space in the current chunk. */
277                 memcpy(msr->msc_reqbody_chunk_current->data +
278                     msr->msc_reqbody_chunk_current->length, data + bucket_offset, bucket_left);
279                 msr->msc_reqbody_chunk_current->length += bucket_left;
280                 bucket_left = 0;
281             } else {
282                 /* Fill the existing chunk. */
283                 unsigned long int copy_length = CHUNK_CAPACITY -
284                     msr->msc_reqbody_chunk_current->length;
285 
286                 memcpy(msr->msc_reqbody_chunk_current->data +
287                     msr->msc_reqbody_chunk_current->length, data + bucket_offset, copy_length);
288                 bucket_offset += copy_length;
289                 bucket_left -= copy_length;
290                 msr->msc_reqbody_chunk_current->length += copy_length;
291 
292                 /* We're done with this chunk. Setting the pointer
293                  * to NULL is going to force a new chunk to be allocated
294                  * on the next go.
295                  */
296                 msr->msc_reqbody_chunk_current = NULL;
297             }
298         }
299 
300         msr->msc_reqbody_length += length;
301     }
302 
303     return 1;
304 }
305 
306 /**
307  * Stores one chunk of request body data. Returns -1 on error.
308  */
modsecurity_request_body_store(modsec_rec * msr,const char * data,apr_size_t length,char ** error_msg)309 apr_status_t modsecurity_request_body_store(modsec_rec *msr,
310     const char *data, apr_size_t length, char **error_msg)
311 {
312     *error_msg = NULL;
313 
314     /* If we have a processor for this request body send
315      * data to it first (but only if it did not report an
316      * error on previous invocations).
317      */
318     if ((msr->msc_reqbody_processor != NULL) && (msr->msc_reqbody_error == 0)) {
319         char *my_error_msg = NULL;
320         msre_reqbody_processor_metadata *metadata =
321             (msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor);
322 
323         if (metadata != NULL) {
324             if (   (metadata->process != NULL)
325                 && (metadata->process(msr, data, length, &my_error_msg) < 0))
326             {
327                 *error_msg = apr_psprintf(msr->mp,
328                                           "%s parsing error: %s",
329                                           msr->msc_reqbody_processor,
330                                           my_error_msg);
331                 msr->msc_reqbody_error = 1;
332                 msr->msc_reqbody_error_msg = my_error_msg;
333                 msr_log(msr, 2, "%s", *error_msg);
334             }
335         }
336         // TODO: All these below need to be registered in the same way as above
337         else if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
338             /* The per-request data length counter will
339              * be updated by the multipart parser.
340              */
341 
342             /* Process data as multipart/form-data. */
343             if (multipart_process_chunk(msr, data, length, &my_error_msg) < 0) {
344                 *error_msg = apr_psprintf(msr->mp, "Multipart parsing error: %s", my_error_msg);
345                 msr->msc_reqbody_error = 1;
346                 msr->msc_reqbody_error_msg = *error_msg;
347                 msr_log(msr, 2, "%s", *error_msg);
348             }
349         }
350         else if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
351             /* Increase per-request data length counter. */
352             msr->msc_reqbody_no_files_length += length;
353 
354             /* Process data as XML. */
355             if (xml_process_chunk(msr, data, length, &my_error_msg) < 0) {
356                 *error_msg = apr_psprintf(msr->mp, "XML parsing error: %s", my_error_msg);
357                 msr->msc_reqbody_error = 1;
358                 msr->msc_reqbody_error_msg = *error_msg;
359                 msr_log(msr, 2, "%s", *error_msg);
360             }
361         }
362         else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
363             /* Increase per-request data length counter. */
364             msr->msc_reqbody_no_files_length += length;
365 
366             /* Process data as JSON. */
367 #ifdef WITH_YAJL
368             if (json_process_chunk(msr, data, length, &my_error_msg) < 0) {
369                 *error_msg = apr_psprintf(msr->mp, "JSON parsing error: %s", my_error_msg);
370                 msr->msc_reqbody_error = 1;
371                 msr->msc_reqbody_error_msg = *error_msg;
372                 msr_log(msr, 2, "%s", *error_msg);
373             }
374 #else
375             *error_msg = apr_psprintf(msr->mp, "JSON support was not enabled");
376             msr->msc_reqbody_error = 1;
377             msr->msc_reqbody_error_msg = *error_msg;
378             msr_log(msr, 2, "%s", *error_msg);
379 #endif
380         }
381         else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
382             /* Increase per-request data length counter. */
383             msr->msc_reqbody_no_files_length += length;
384 
385             /* Do nothing else, URLENCODED processor does not support streaming. */
386         }
387         else {
388             *error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s",
389                 msr->msc_reqbody_processor);
390             return -1;
391         }
392     } else if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) {
393         /* Increase per-request data length counter if forcing buffering. */
394         msr->msc_reqbody_no_files_length += length;
395     }
396 
397     /* Check that we are not over the request body no files limit. */
398     if (msr->msc_reqbody_no_files_length >= (unsigned long) msr->txcfg->reqbody_no_files_limit) {
399         *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the "
400                 "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit);
401         if (msr->txcfg->debuglog_level >= 1) {
402             msr_log(msr, 1, "%s", *error_msg);
403         }
404 
405         msr->msc_reqbody_error = 1;
406 
407         if ((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT))   {
408             return -5;
409         } else if (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL)  {
410             if(msr->txcfg->is_enabled == MODSEC_ENABLED)
411                 return -5;
412         }
413     }
414 
415     /* Store data. */
416     if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
417         return modsecurity_request_body_store_memory(msr, data, length, error_msg);
418     }
419     else
420         if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
421         return modsecurity_request_body_store_disk(msr, data, length, error_msg);
422     }
423 
424     /* Should never happen. */
425     *error_msg = apr_psprintf(msr->mp, "Internal error, unknown value for msc_reqbody_storage: %u",
426         msr->msc_reqbody_storage);
427     return -1;
428 }
429 
modsecurity_request_body_to_stream(modsec_rec * msr,const char * buffer,int buflen,char ** error_msg)430 apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buffer, int buflen, char **error_msg) {
431 #ifndef MSC_LARGE_STREAM_INPUT
432     char *stream_input_body = NULL;
433     char *data = NULL;
434     int first_pkt = 0;
435 #else
436     apr_size_t allocate_length = 0;
437     char* allocated = NULL;
438 #endif
439 
440 #ifndef MSC_LARGE_STREAM_INPUT
441     if(msr->stream_input_data == NULL)  {
442         msr->stream_input_data = (char *)calloc(sizeof(char), msr->stream_input_length + 1);
443         first_pkt = 1;
444     }
445     else    {
446 
447         data = (char *)malloc(msr->stream_input_length + 1 - buflen);
448 
449         if(data == NULL)
450             return -1;
451 
452         memset(data, 0, msr->stream_input_length + 1 - buflen);
453         memcpy(data, msr->stream_input_data, msr->stream_input_length - buflen);
454 
455         stream_input_body = (char *)realloc(msr->stream_input_data, msr->stream_input_length + 1);
456 
457         msr->stream_input_data = (char *)stream_input_body;
458     }
459 
460     if (msr->stream_input_data == NULL) {
461         if(data)    {
462             free(data);
463             data = NULL;
464         }
465         *error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.",
466                 msr->stream_input_length + 1);
467         return -1;
468     }
469 
470     memset(msr->stream_input_data, 0, msr->stream_input_length+1);
471 
472     if(first_pkt)   {
473         memcpy(msr->stream_input_data, buffer, msr->stream_input_length);
474     } else {
475         memcpy(msr->stream_input_data, data, msr->stream_input_length - buflen);
476         memcpy(msr->stream_input_data+(msr->stream_input_length - buflen), buffer, buflen);
477     }
478 
479     if(data)    {
480         free(data);
481         data = NULL;
482     }
483 #else
484     if (msr->stream_input_data == NULL)  {
485         // Is the request body length known beforehand? (requests that are not Transfer-Encoding: chunked)
486         if (msr->request_content_length > 0) {
487             // Use min of Content-Length and SecRequestBodyLimit
488             allocate_length = msr->request_content_length < msr->txcfg->reqbody_limit ? msr->request_content_length : msr->txcfg->reqbody_limit;
489         }
490         else {
491             // We don't know how this request is going to be, so hope for just buflen to begin with (requests that are Transfer-Encoding: chunked)
492             allocate_length = buflen;
493         }
494 
495         allocated = (char*) calloc(allocate_length, sizeof(char));
496         if (allocated) {
497             msr->stream_input_data = allocated;
498             msr->stream_input_allocated_length = allocate_length;
499         }
500         else {
501             *error_msg = apr_psprintf(
502                 msr->mp,
503                 "Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.",
504                 allocate_length);
505             return -1;
506         }
507     }
508     else {
509         // Do we need to expand the space we have previously allocated?
510         if ((msr->stream_input_length + buflen) > msr->stream_input_allocated_length) {
511             // If this becomes a hotspot again, consider increasing by some percent extra each time, for fewer reallocs
512             allocate_length = msr->stream_input_length + buflen;
513 
514             allocated = (char*) realloc(msr->stream_input_data, allocate_length);
515             if (allocated) {
516                 msr->stream_input_data = allocated;
517                 msr->stream_input_allocated_length = allocate_length;
518             }
519             else {
520                 *error_msg = apr_psprintf(
521                     msr->mp,
522                     "Unable to reallocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.",
523                     allocate_length);
524                 free(msr->stream_input_data);
525                 msr->stream_input_data = NULL;
526                 msr->stream_input_length = 0;
527                 msr->stream_input_allocated_length = 0;
528                 return -1;
529             }
530         }
531     }
532     // Append buffer to msr->stream_input_data
533     memcpy(msr->stream_input_data + msr->stream_input_length, buffer, buflen);
534     msr->stream_input_length += buflen;
535 #endif
536 
537     return 1;
538 }
539 
540 /**
541  * Replace a bunch of chunks holding a request body with a single large chunk.
542  */
modsecurity_request_body_end_raw(modsec_rec * msr,char ** error_msg)543 static apr_status_t modsecurity_request_body_end_raw(modsec_rec *msr, char **error_msg) {
544     msc_data_chunk **chunks, *one_chunk;
545     char *d;
546     int i, sofar;
547 
548     *error_msg = NULL;
549 
550     /* Allocate a buffer large enough to hold the request body. */
551 
552     if (msr->msc_reqbody_length + 1 == 0) {
553         *error_msg = apr_psprintf(msr->mp, "Internal error, request body length will overflow: %u",
554             msr->msc_reqbody_length);
555         return -1;
556     }
557 
558     msr->msc_reqbody_buffer = malloc(msr->msc_reqbody_length + 1);
559     if (msr->msc_reqbody_buffer == NULL) {
560         *error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body. Asked for %u bytes.",
561             msr->msc_reqbody_length + 1);
562         return -1;
563     }
564 
565     msr->msc_reqbody_buffer[msr->msc_reqbody_length] = '\0';
566 
567     /* Copy the data we keep in chunks into the new buffer. */
568 
569     sofar = 0;
570     d = msr->msc_reqbody_buffer;
571     chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
572     for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
573         if (sofar + chunks[i]->length <= msr->msc_reqbody_length) {
574             memcpy(d, chunks[i]->data, chunks[i]->length);
575             d += chunks[i]->length;
576             sofar += chunks[i]->length;
577         } else {
578             *error_msg = apr_psprintf(msr->mp, "Internal error, request body buffer overflow.");
579             return -1;
580         }
581     }
582 
583 
584     /* Now free the memory used by the chunks. */
585 
586     chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
587     for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
588         free(chunks[i]->data);
589         chunks[i]->data = NULL;
590     }
591 
592     /* Create a new array with only one chunk in it. */
593 
594     msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp, 2, sizeof(msc_data_chunk *));
595     if (msr->msc_reqbody_chunks == NULL) {
596         *error_msg = apr_pstrdup(msr->mp, "Failed to create structure to hold request body.");
597         return -1;
598     }
599 
600     one_chunk = (msc_data_chunk *)apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
601     one_chunk->data = msr->msc_reqbody_buffer;
602     one_chunk->length = msr->msc_reqbody_length;
603     one_chunk->is_permanent = 1;
604     *(const msc_data_chunk **)apr_array_push(msr->msc_reqbody_chunks) = one_chunk;
605 
606     if(msr->txcfg->reqbody_limit > 0 && msr->txcfg->reqbody_limit < msr->msc_reqbody_length)    {
607         msr->msc_reqbody_length = msr->txcfg->reqbody_limit;
608     }
609 
610     return 1;
611 }
612 
613 /**
614  *
615  */
modsecurity_request_body_end_urlencoded(modsec_rec * msr,char ** error_msg)616 static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr, char **error_msg) {
617     int invalid_count = 0;
618 
619     *error_msg = NULL;
620 
621     /* Create the raw buffer */
622     if (modsecurity_request_body_end_raw(msr, error_msg) != 1) {
623         return -1;
624     }
625 
626     /* Parse URL-encoded arguments in the request body. */
627 
628     if (parse_arguments(msr, msr->msc_reqbody_buffer, msr->msc_reqbody_length,
629         msr->txcfg->argument_separator, "BODY", msr->arguments, &invalid_count) < 0)
630     {
631         *error_msg = apr_pstrdup(msr->mp, "Initialisation: Error occurred while parsing BODY arguments.");
632         return -1;
633     }
634 
635     if (invalid_count) {
636         msr->urlencoded_error = 1;
637     }
638 
639     return 1;
640 }
641 
642 /**
643  * Stops receiving the request body.
644  */
modsecurity_request_body_end(modsec_rec * msr,char ** error_msg)645 apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) {
646     *error_msg = NULL;
647 
648     /* Close open file descriptors, if any. */
649     if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
650         if (msr->msc_reqbody_fd > 0) {
651             close(msr->msc_reqbody_fd);
652             msr->msc_reqbody_fd = -1;
653         }
654     }
655 
656     /* Note that we've read the body. */
657     msr->msc_reqbody_read = 1;
658 
659 
660     /* Check that we are not over the request body no files limit. */
661     if (msr->msc_reqbody_no_files_length >= (unsigned long)msr->txcfg->reqbody_no_files_limit) {
662         *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the "
663             "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit);
664         if (msr->txcfg->debuglog_level >= 1) {
665             msr_log(msr, 1, "%s", *error_msg);
666         }
667 
668         return -5;
669     }
670 
671 
672     /* Finalise body processing. */
673     if ((msr->msc_reqbody_processor != NULL) && (msr->msc_reqbody_error == 0)) {
674         char *my_error_msg = NULL;
675         msre_reqbody_processor_metadata *metadata =
676             (msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor);
677 
678         if (metadata != NULL) {
679             if (   (metadata->complete != NULL)
680                 && (metadata->complete(msr, &my_error_msg) < 0))
681             {
682                 *error_msg = apr_psprintf(msr->mp,
683                                           "%s parsing error (complete): %s",
684                                           msr->msc_reqbody_processor,
685                                           my_error_msg);
686                 msr->msc_reqbody_error = 1;
687                 msr->msc_reqbody_error_msg = my_error_msg;
688                 msr_log(msr, 2, "%s", *error_msg);
689             }
690         }
691         // TODO: All these below need to be registered in the same way as above
692         else if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
693             if (multipart_complete(msr, &my_error_msg) < 0) {
694                 *error_msg = apr_psprintf(msr->mp, "Multipart parsing error: %s", my_error_msg);
695                 msr->msc_reqbody_error = 1;
696                 msr->msc_reqbody_error_msg = *error_msg;
697                 if (msr->txcfg->debuglog_level >= 4) {
698                     msr_log(msr, 4, "%s", *error_msg);
699                 }
700                 return -1;
701             }
702 
703             if (multipart_get_arguments(msr, "BODY", msr->arguments) < 0) {
704                 *error_msg = "Multipart parsing error: Failed to retrieve arguments.";
705                 msr->msc_reqbody_error = 1;
706                 msr->msc_reqbody_error_msg = *error_msg;
707                 msr_log(msr, 2, "%s", *error_msg);
708                 return -1;
709             }
710         }
711         else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
712 #ifdef WITH_YAJL
713             if (json_complete(msr, &my_error_msg) < 0 && msr->msc_reqbody_length > 0) {
714                 *error_msg = apr_psprintf(msr->mp, "JSON parser error: %s", my_error_msg);
715                 msr->msc_reqbody_error = 1;
716                 msr->msc_reqbody_error_msg = *error_msg;
717                 msr_log(msr, 2, "%s", *error_msg);
718                  return -1;
719              }
720 #else
721             *error_msg = apr_psprintf(msr->mp, "JSON support was not enabled");
722             msr->msc_reqbody_error = 1;
723             msr->msc_reqbody_error_msg = *error_msg;
724             msr_log(msr, 2, "%s", *error_msg);
725             return -1;
726 #endif
727 
728         }
729         else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
730             return modsecurity_request_body_end_urlencoded(msr, error_msg);
731         }
732         else if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
733             if (xml_complete(msr, &my_error_msg) < 0) {
734                 *error_msg = apr_psprintf(msr->mp, "XML parser error: %s", my_error_msg);
735                 msr->msc_reqbody_error = 1;
736                 msr->msc_reqbody_error_msg = *error_msg;
737                 msr_log(msr, 2, "%s", *error_msg);
738                 return -1;
739             }
740         }
741     } else if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) {
742         /* Convert to a single continous buffer, but don't do anything else. */
743         return modsecurity_request_body_end_raw(msr, error_msg);
744     }
745 
746     /* Note the request body no files length. */
747     msr_log(msr, 4, "Request body no files length: %" APR_SIZE_T_FMT, msr->msc_reqbody_no_files_length);
748 
749     return 1;
750 }
751 
752 /**
753  * Prepares to forward the request body.
754  */
modsecurity_request_body_retrieve_start(modsec_rec * msr,char ** error_msg)755 apr_status_t modsecurity_request_body_retrieve_start(modsec_rec *msr, char **error_msg) {
756     *error_msg = NULL;
757 
758     if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
759         msr->msc_reqbody_chunk_position = 0;
760         msr->msc_reqbody_chunk_offset = 0;
761 
762         msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
763         if (msr->msc_reqbody_disk_chunk == NULL) {
764             *error_msg = apr_psprintf(msr->mp, "Failed to allocate %lu bytes for request body disk chunk.",
765                 (unsigned long)sizeof(msc_data_chunk));
766             return -1;
767         }
768         msr->msc_reqbody_disk_chunk->is_permanent = 1;
769     }
770     else
771     if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
772         msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
773         if (msr->msc_reqbody_disk_chunk == NULL) {
774             *error_msg = apr_psprintf(msr->mp, "Failed to allocate %lu bytes for request body disk chunk.",
775                 (unsigned long)sizeof(msc_data_chunk));
776             return -1;
777         }
778 
779         msr->msc_reqbody_disk_chunk->is_permanent = 0;
780         msr->msc_reqbody_disk_chunk->data = apr_palloc(msr->msc_reqbody_mp, CHUNK_CAPACITY);
781         if (msr->msc_reqbody_disk_chunk->data == NULL) {
782             *error_msg = apr_psprintf(msr->mp, "Failed to allocate %d bytes for request body disk chunk data.",
783                 CHUNK_CAPACITY);
784             return -1;
785         }
786 
787         msr->msc_reqbody_fd = open(msr->msc_reqbody_filename, O_RDONLY | O_BINARY);
788         if (msr->msc_reqbody_fd < 0) {
789             *error_msg = apr_psprintf(msr->mp, "Failed to open temporary file for reading: %s",
790                 msr->msc_reqbody_filename);
791             return -1;
792         }
793     }
794 
795     return 1;
796 }
797 
798 /**
799  *
800  */
modsecurity_request_body_retrieve_end(modsec_rec * msr)801 apr_status_t modsecurity_request_body_retrieve_end(modsec_rec *msr) {
802     if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
803         if (msr->msc_reqbody_fd > 0) {
804             close(msr->msc_reqbody_fd);
805             msr->msc_reqbody_fd = -1;
806         }
807     }
808 
809     return 1;
810 }
811 
812 /**
813  * Returns one chunk of request body data. It stores a NULL
814  * in the chunk pointer when there is no data to return. The
815  * return code is 1 if more calls can be made to retrieve more
816  * data, 0 if there is no more data to retrieve, or -1 on error.
817  *
818  * The caller can limit the amount of data returned by providing
819  * a non-negative value in nbytes.
820  */
modsecurity_request_body_retrieve(modsec_rec * msr,msc_data_chunk ** chunk,long int nbytes,char ** error_msg)821 apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr,
822     msc_data_chunk **chunk, long int nbytes, char **error_msg)
823 {
824     msc_data_chunk **chunks;
825 
826     *error_msg = NULL;
827 
828     if (chunk == NULL) {
829         *error_msg = apr_pstrdup(msr->mp, "Internal error, retrieving request body chunk.");
830         return -1;
831     }
832     *chunk = NULL;
833 
834     if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
835         /* Are there any chunks left? */
836         if (msr->msc_reqbody_chunk_position >= msr->msc_reqbody_chunks->nelts) {
837             /* No more chunks. */
838             return 0;
839         }
840 
841         /* We always respond with the same chunk, just different information in it. */
842         *chunk = msr->msc_reqbody_disk_chunk;
843 
844         /* Advance to the current chunk and position on the
845          * next byte we need to send.
846          */
847         chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
848         msr->msc_reqbody_disk_chunk->data = chunks[msr->msc_reqbody_chunk_position]->data
849             + msr->msc_reqbody_chunk_offset;
850 
851         if (nbytes < 0) {
852             /* Send what's left in this chunk as there is no limit on the size. */
853             msr->msc_reqbody_disk_chunk->length = chunks[msr->msc_reqbody_chunk_position]->length;
854             msr->msc_reqbody_chunk_position++;
855             msr->msc_reqbody_chunk_offset = 0;
856         } else {
857             /* We have a limit we must obey. */
858 
859             if (chunks[msr->msc_reqbody_chunk_position]->length -
860                 msr->msc_reqbody_chunk_offset <= (unsigned int)nbytes)
861             {
862                 /* If what's left in our chunk is less than the limit
863                  * then send it all back.
864                  */
865                 msr->msc_reqbody_disk_chunk->length =
866                     chunks[msr->msc_reqbody_chunk_position]->length -
867                     msr->msc_reqbody_chunk_offset;
868                 msr->msc_reqbody_chunk_position++;
869                 msr->msc_reqbody_chunk_offset = 0;
870             } else {
871                 /* If we have more data in our chunk, send the
872                  * maximum bytes we can (nbytes).
873                  */
874                 msr->msc_reqbody_disk_chunk->length = nbytes;
875                 msr->msc_reqbody_chunk_offset += nbytes;
876             }
877         }
878 
879         /* If we've advanced beyond our last chunk then
880          * we have no more data to send.
881          */
882         if (msr->msc_reqbody_chunk_position >= msr->msc_reqbody_chunks->nelts) {
883             return 0; /* No more chunks. */
884         }
885 
886         /* More data available. */
887         return 1;
888     }
889 
890     if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
891         long int my_nbytes = CHUNK_CAPACITY;
892         int i;
893 
894         /* Send CHUNK_CAPACITY bytes at a time unless a lower limit was requested. */
895         if ((nbytes != -1)&&(my_nbytes > nbytes)) {
896             my_nbytes = nbytes;
897         }
898 
899         i = read(msr->msc_reqbody_fd, msr->msc_reqbody_disk_chunk->data, my_nbytes);
900         if (i < 0) {
901             *error_msg = apr_psprintf(msr->mp, "Input filter: Error reading from temporary file: %s",
902                 strerror(errno));
903             return -1;
904         }
905 
906         *chunk = msr->msc_reqbody_disk_chunk;
907         msr->msc_reqbody_disk_chunk->length = i;
908 
909         if (i == 0) return 0; /* No more data available. */
910 
911         return 1; /* More data available. */
912     }
913 
914     /* Should never happen. */
915     *error_msg = apr_psprintf(msr->mp, "Internal error, invalid msc_reqbody_storage value: %u",
916         msr->msc_reqbody_storage);
917 
918     return -1;
919 }
920 
921 /**
922  *
923  */
modsecurity_request_body_clear(modsec_rec * msr,char ** error_msg)924 apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) {
925     *error_msg = NULL;
926 
927     /* Release memory we used to store request body data. */
928     if (msr->msc_reqbody_chunks != NULL) {
929         msc_data_chunk **chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
930         int i;
931 
932         for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
933             if (chunks[i]->data != NULL) {
934                 free(chunks[i]->data);
935                 chunks[i]->data = NULL;
936             }
937         }
938     }
939 
940     if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
941         int keep_body = 0;
942 
943         /* Should we keep the body? This normally
944          * happens when a PUT method was used, which
945          * means the body is actually a file.
946          */
947         if ((msr->upload_remove_files == 0)&&(strcasecmp(msr->request_method, "PUT") == 0)) {
948             if (msr->txcfg->upload_dir != NULL) {
949                 keep_body = 1;
950             } else {
951                 *error_msg = apr_psprintf(msr->mp, "Input filter: SecUploadDir is undefined, "
952                     "unable to store PUT file.");
953             }
954         }
955 
956         /* Deal with a request body stored in a file. */
957 
958         if (msr->msc_reqbody_filename != NULL) {
959             if (keep_body) {
960                 /* Move request body (which is a file) to the storage area. */
961                 const char *put_filename = NULL;
962                 const char *put_basename = NULL;
963 
964                 if (strcmp(msr->txcfg->upload_dir, msr->txcfg->tmp_dir) == 0) {
965                     msr_log(msr, 4, "Not moving file to identical location.");
966                     goto nullify;
967                 }
968 
969                 /* Construct the new filename. */
970                 put_basename = file_basename(msr->msc_reqbody_mp, msr->msc_reqbody_filename);
971                 if (put_basename == NULL) {
972                     *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));
973                     return -1;
974                 }
975                 put_filename = apr_psprintf(msr->msc_reqbody_mp, "%s/%s",
976                     msr->txcfg->upload_dir, put_basename);
977                 if (put_filename == NULL) {
978                     *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));
979                     return -1;
980                 }
981 
982                 if (apr_file_rename(msr->msc_reqbody_filename, put_filename,
983                     msr->msc_reqbody_mp) != APR_SUCCESS)
984                 {
985                     *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to rename file from \"%s\" to \"%s\".",
986                         log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename),
987                         log_escape(msr->msc_reqbody_mp, put_filename));
988                     return -1;
989                 } else {
990                     msr_log(msr, 4, "Input filter: Moved file from \"%s\" to \"%s\".",
991                         log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename),
992                         log_escape(msr->msc_reqbody_mp, put_filename));
993                 }
994             } else {
995                 /* make sure it is closed first */
996                 if (msr->msc_reqbody_fd > 0) {
997                     close(msr->msc_reqbody_fd);
998                     msr->msc_reqbody_fd = -1;
999                 }
1000 
1001                 /* We do not want to keep the request body. */
1002                 if (apr_file_remove(msr->msc_reqbody_filename,
1003                     msr->msc_reqbody_mp) != APR_SUCCESS)
1004                 {
1005                     *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to delete temporary file: %s",
1006                         log_escape(msr->mp, msr->msc_reqbody_filename));
1007                     return -1;
1008                 }
1009 
1010                 msr_log(msr, 4, "Input filter: Removed temporary file: %s",
1011                     msr->msc_reqbody_filename);
1012             }
1013 
1014 nullify:
1015 
1016             msr->msc_reqbody_filename = NULL;
1017         }
1018     }
1019 
1020     if (msr->msc_reqbody_mp != NULL) {
1021         apr_pool_destroy(msr->msc_reqbody_mp);
1022         msr->msc_reqbody_mp = NULL;
1023     }
1024 
1025     return 1;
1026 }
1027