Imported Upstream version 2.5.11
[libapache-mod-security.git] / apache2 / mod_security2.c
1 /*
2  * ModSecurity for Apache 2.x, http://www.modsecurity.org/
3  * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/)
4  *
5  * This product is released under the terms of the General Public Licence,
6  * version 2 (GPLv2). Please refer to the file LICENSE (included with this
7  * distribution) which contains the complete text of the licence.
8  *
9  * There are special exceptions to the terms and conditions of the GPL
10  * as it is applied to this software. View the full text of the exception in
11  * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software
12  * distribution.
13  *
14  * If any of the files related to licensing are missing or if you have any
15  * other questions related to licensing please contact Breach Security, Inc.
16  * directly using the email address support@breach.com.
17  *
18  */
19 #include <limits.h>
20
21 #include "http_core.h"
22 #include "http_request.h"
23
24 #include "modsecurity.h"
25 #include "apache2.h"
26 #include "http_main.h"
27 #include "pdf_protect.h"
28
29 #include "msc_logging.h"
30 #include "msc_util.h"
31
32
33 /* ModSecurity structure */
34
35 msc_engine DSOLOCAL *modsecurity = NULL;
36
37 /* Global module variables; these are used for the Apache-specific functionality */
38
39 char DSOLOCAL *chroot_dir = NULL;
40
41 unsigned int DSOLOCAL chroot_completed = 0;
42
43 char DSOLOCAL *new_server_signature = NULL;
44
45 char DSOLOCAL *real_server_signature = NULL;
46
47 char DSOLOCAL *guardianlog_name = NULL;
48
49 apr_file_t DSOLOCAL *guardianlog_fd = NULL;
50
51 char DSOLOCAL *guardianlog_condition = NULL;
52
53
54 /* -- Miscellaneous functions -- */
55
56 /**
57  * Intercepts transaction, using the method specified
58  * in the structure itself. MUST return an HTTP status code,
59  * which will be used to terminate the transaction.
60  */
61 int perform_interception(modsec_rec *msr) {
62     msre_actionset *actionset = NULL;
63     const char *message = NULL;
64     const char *phase_text = "";
65     int status = DECLINED;
66     int log_level = 1;
67
68     /* Sanity checks first. */
69
70     if (msr->was_intercepted == 0) {
71         msr_log(msr, 1, "Internal Error: Asked to intercept request but was_intercepted is zero");
72         return DECLINED;
73     }
74
75     if (msr->phase > 4) {
76         msr_log(msr, 1, "Internal Error: Asked to intercept request in phase %d.", msr->phase);
77         msr->was_intercepted = 0;
78         return DECLINED;
79     }
80
81     /* OK, we're good to go. */
82
83     actionset = msr->intercept_actionset;
84     phase_text = apr_psprintf(msr->mp, " (phase %d)", msr->phase);
85
86     /* By default we log at level 1 but we switch to 4
87      * if a nolog action was used or this is not the initial request
88      * to hide the message.
89      */
90     log_level = (actionset->log != 1) ? 4 : 1;
91
92     /* Pause the request first (if configured and the initial request). */
93     if (actionset->intercept_pause) {
94         msr_log(msr, (log_level > 3 ? log_level : log_level + 1), "Pausing transaction for "
95             "%d msec.", actionset->intercept_pause);
96         /* apr_sleep accepts microseconds */
97         apr_sleep((apr_interval_time_t)(actionset->intercept_pause * 1000));
98     }
99
100     /* Determine how to respond and prepare the log message. */
101     switch(actionset->intercept_action) {
102         case ACTION_DENY :
103             if (actionset->intercept_status != 0) {
104                 status = actionset->intercept_status;
105                 message = apr_psprintf(msr->mp, "Access denied with code %d%s.",
106                     status, phase_text);
107             } else {
108                 log_level = 1;
109                 status = HTTP_INTERNAL_SERVER_ERROR;
110                 message = apr_psprintf(msr->mp, "Access denied with code 500%s "
111                     "(Internal Error: Invalid status code requested %d).",
112                     phase_text, actionset->intercept_status);
113             }
114             break;
115
116         case ACTION_PROXY :
117             if (msr->phase < 3) {
118                 if (ap_find_linked_module("mod_proxy.c") == NULL) {
119                     log_level = 1;
120                     status = HTTP_INTERNAL_SERVER_ERROR;
121                     message = apr_psprintf(msr->mp, "Access denied with code 500%s "
122                         "(Configuration Error: Proxy action to %s requested but mod_proxy not found).",
123                         phase_text,
124                         log_escape_nq(msr->mp, actionset->intercept_uri));
125                 } else {
126                     msr->r->filename = apr_psprintf(msr->mp, "proxy:%s", actionset->intercept_uri);
127                     msr->r->proxyreq = PROXYREQ_REVERSE;
128                     msr->r->handler = "proxy-server";
129                     status = OK;
130                     message = apr_psprintf(msr->mp, "Access denied using proxy to%s %s.",
131                         phase_text,
132                         log_escape_nq(msr->mp, actionset->intercept_uri));
133                 }
134             } else {
135                 log_level = 1;
136                 status = HTTP_INTERNAL_SERVER_ERROR;
137                 message = apr_psprintf(msr->mp, "Access denied with code 500%s "
138                     "(Configuration Error: Proxy action requested but it does not work in output phases).",
139                     phase_text);
140             }
141             break;
142
143         case ACTION_DROP :
144             /* ENH This does not seem to work on Windows. Is there a
145              *     better way to drop a connection anyway?
146              */
147             #ifndef WIN32
148             {
149                 extern module core_module;
150                 apr_socket_t *csd = ap_get_module_config(msr->r->connection->conn_config,
151                     &core_module);
152
153                 if (csd) {
154                     if (apr_socket_close(csd) == APR_SUCCESS) {
155                         status = HTTP_FORBIDDEN;
156                         message = apr_psprintf(msr->mp, "Access denied with connection close%s.",
157                             phase_text);
158                     } else {
159                         log_level = 1;
160                         status = HTTP_INTERNAL_SERVER_ERROR;
161                         message = apr_psprintf(msr->mp, "Access denied with code 500%s "
162                             "(Error: Connection drop requested but failed to close the "
163                             " socket).",
164                             phase_text);
165                     }
166                 } else {
167                     log_level = 1;
168                     status = HTTP_INTERNAL_SERVER_ERROR;
169                     message = apr_psprintf(msr->mp, "Access denied with code 500%s "
170                         "(Error: Connection drop requested but socket not found.",
171                         phase_text);
172                 }
173             }
174             #else
175             log_level = 1;
176             status = HTTP_INTERNAL_SERVER_ERROR;
177             message = apr_psprintf(msr->mp, "Access denied with code 500%s "
178                 "(Error: Connection drop not implemented on this platform).",
179                 phase_text);
180             #endif
181             break;
182
183         case ACTION_REDIRECT :
184             apr_table_setn(msr->r->headers_out, "Location", actionset->intercept_uri);
185             if ((actionset->intercept_status == 301)||(actionset->intercept_status == 302)
186                 ||(actionset->intercept_status == 303)||(actionset->intercept_status == 307))
187             {
188                 status = actionset->intercept_status;
189             } else {
190                 status = HTTP_MOVED_TEMPORARILY;
191             }
192             message = apr_psprintf(msr->mp, "Access denied with redirection to %s using "
193                 "status %d%s.",
194                 log_escape_nq(msr->mp, actionset->intercept_uri), status,
195                 phase_text);
196             break;
197
198         case ACTION_ALLOW :
199             status = DECLINED;
200             message = apr_psprintf(msr->mp, "Access allowed%s.", phase_text);
201             msr->was_intercepted = 0;
202             msr->allow_scope = ACTION_ALLOW;
203             break;
204
205         case ACTION_ALLOW_PHASE :
206             status = DECLINED;
207             message = apr_psprintf(msr->mp, "Access to phase allowed%s.", phase_text);
208             msr->was_intercepted = 0;
209             msr->allow_scope = ACTION_ALLOW_PHASE;
210             break;
211
212         case ACTION_ALLOW_REQUEST :
213             status = DECLINED;
214             message = apr_psprintf(msr->mp, "Access to request allowed%s.", phase_text);
215             msr->was_intercepted = 0;
216             msr->allow_scope = ACTION_ALLOW_REQUEST;
217             break;
218
219         default :
220             log_level = 1;
221             status = HTTP_INTERNAL_SERVER_ERROR;
222             message = apr_psprintf(msr->mp, "Access denied with code 500%s "
223                 "(Internal Error: invalid interception action %d).",
224                 phase_text, actionset->intercept_action);
225             break;
226     }
227
228     /* Log the message now. */
229     msc_alert(msr, log_level, actionset, message, msr->intercept_message);
230
231     return status;
232 }
233
234 /**
235  * Retrieves a previously stored transaction context by
236  * looking at the main request, and the previous requests.
237  */
238 static modsec_rec *retrieve_tx_context(request_rec *r) {
239     modsec_rec *msr = NULL;
240     request_rec *rx = NULL;
241
242     /* Look in the current request first. */
243     msr = (modsec_rec *)apr_table_get(r->notes, NOTE_MSR);
244     if (msr != NULL) {
245         msr->r = r;
246         return msr;
247     }
248
249     /* If this is a subrequest then look in the main request. */
250     if (r->main != NULL) {
251         msr = (modsec_rec *)apr_table_get(r->main->notes, NOTE_MSR);
252         if (msr != NULL) {
253             msr->r = r;
254             return msr;
255         }
256     }
257
258     /* If the request was redirected then look in the previous requests. */
259     rx = r->prev;
260     while(rx != NULL) {
261         msr = (modsec_rec *)apr_table_get(rx->notes, NOTE_MSR);
262         if (msr != NULL) {
263             msr->r = r;
264             return msr;
265         }
266         rx = rx->prev;
267     }
268
269     return NULL;
270 }
271
272 /**
273  * Stores transaction context where it can be found in subsequent
274  * phases, redirections, or subrequests.
275  */
276 static void store_tx_context(modsec_rec *msr, request_rec *r) {
277     apr_table_setn(r->notes, NOTE_MSR, (void *)msr);
278 }
279
280 /**
281  * Creates a new transaction context.
282  */
283 static modsec_rec *create_tx_context(request_rec *r) {
284     apr_allocator_t *allocator = NULL;
285     modsec_rec *msr = NULL;
286
287     msr = (modsec_rec *)apr_pcalloc(r->pool, sizeof(modsec_rec));
288     if (msr == NULL) return NULL;
289
290     apr_allocator_create(&allocator);
291     apr_allocator_max_free_set(allocator, 1024);
292     apr_pool_create_ex(&msr->mp, r->pool, NULL, allocator);
293     if (msr->mp == NULL) return NULL;
294     apr_allocator_owner_set(allocator, msr->mp);
295
296     msr->modsecurity = modsecurity;
297     msr->r = r;
298     msr->r_early = r;
299     msr->request_time = r->request_time;
300     msr->dcfg1 = (directory_config *)ap_get_module_config(r->per_dir_config,
301         &security2_module);
302
303     /**
304      * Create a special user configuration. This is where
305      * explicit instructions will be stored. This will be used
306      * to override the default settings (and to override the
307      * configuration in the second phase, dcfg2, with the user
308      * setting executed in the first phase.
309      */
310     msr->usercfg = create_directory_config(msr->mp, NULL);
311     if (msr->usercfg == NULL) return NULL;
312
313     /* Create a transaction context and populate
314      * it using the directory config we just
315      * got from Apache.
316      */
317     msr->txcfg = create_directory_config(msr->mp, NULL);
318     if (msr->txcfg == NULL) return NULL;
319
320     if (msr->dcfg1 != NULL) {
321         msr->txcfg = merge_directory_configs(msr->mp, msr->txcfg, msr->dcfg1);
322         if (msr->txcfg == NULL) return NULL;
323     }
324     init_directory_config(msr->txcfg);
325
326     msr->txid = get_env_var(r, "UNIQUE_ID");
327     if (msr->txid == NULL) {
328         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server,
329             "ModSecurity: ModSecurity requires mod_unique_id to be installed.");
330         return NULL;
331     }
332
333     if (msr->txcfg->debuglog_level >= 4) {
334         msr_log(msr, 4, "Initialising transaction (txid %s).", msr->txid);
335     }
336
337     /* Populate tx fields */
338     msr->error_messages = apr_array_make(msr->mp, 5, sizeof(error_message *));
339     msr->alerts = apr_array_make(msr->mp, 5, sizeof(char *));
340
341     msr->server_software = real_server_signature;
342     msr->local_addr = r->connection->local_ip;
343     msr->local_port = r->connection->local_addr->port;
344
345     msr->remote_addr = r->connection->remote_ip;
346     msr->remote_port = r->connection->remote_addr->port;
347
348     msr->request_line = r->the_request;
349     msr->request_uri = r->uri;
350     msr->request_method = r->method;
351     msr->query_string = r->args;
352     msr->request_protocol = r->protocol;
353     msr->request_headers = apr_table_copy(msr->mp, r->headers_in);
354     msr->hostname = ap_get_server_name(r);
355
356     msr->msc_rule_mptmp = NULL;
357
358     /* Invoke the engine to continue with initialisation */
359     if (modsecurity_tx_init(msr) < 0) {
360         msr_log(msr, 1, "Failed to initialise transaction (txid %s).", msr->txid);
361         return NULL;
362     }
363
364     store_tx_context(msr, r);
365
366     if (msr->txcfg->debuglog_level >= 4) {
367         msr_log(msr, 4, "Transaction context created (dcfg %pp).", msr->dcfg1);
368     }
369
370     return msr;
371 }
372
373
374 /* -- Hooks -- */
375
376 /*
377  * Change the signature of the server if change was requested in
378  * configuration. We do this by locating the signature in server
379  * memory and writing over it.
380  */
381 static apr_status_t change_server_signature(server_rec *s) {
382     char *server_version = NULL;
383
384     if (new_server_signature == NULL) return 0;
385
386     server_version = (char *)apache_get_server_version();
387
388     if (server_version == NULL) {
389         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
390             "SecServerSignature: Apache returned null as signature.");
391         return -1;
392     }
393
394     if (strlen(server_version) >= strlen(new_server_signature)) {
395         strcpy(server_version, new_server_signature);
396     }
397     else {
398         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
399             "SecServerSignature: original signature too short. Please set "
400             "ServerTokens to Full.");
401         return -1;
402     }
403
404     /* Check that it really changed.  This assumes that what we got was
405      * not a copy and this could change in future versions of Apache.
406      */
407     server_version = (char *)apache_get_server_version();
408     if ((server_version == NULL) || (strcmp(server_version, new_server_signature) != 0)) {
409         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s, "SecServerSignature: Failed to change server signature to \"%s\".", new_server_signature);
410         return 0;
411     }
412     else {
413         ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, s, "SecServerSignature: Changed server signature to \"%s\".", server_version);
414     }
415
416     return 1;
417 }
418
419 /**
420  * Executed at the end of server lifetime to cleanup the allocated resources.
421  */
422 static apr_status_t module_cleanup(void *data) {
423     modsecurity_shutdown(modsecurity);
424     return APR_SUCCESS;
425 }
426
427 /**
428  * Pre-configuration initialisation hook.
429  */
430 static int hook_pre_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_temp) {
431     /* Initialise ModSecurity engine */
432     modsecurity = modsecurity_create(mp, MODSEC_ONLINE);
433     if (modsecurity == NULL) {
434         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
435             "ModSecurity: Failed to initialise engine.");
436         return HTTP_INTERNAL_SERVER_ERROR;
437     }
438
439     return OK;
440 }
441
442 /**
443  * Main (post-configuration) module initialisation.
444  */
445 static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_temp, server_rec *s) {
446     void *init_flag = NULL;
447     int first_time = 0;
448
449     /* ENH Figure out a way to validate config before we start
450      * - skipafter: need to make sure we found all of our targets
451      */
452
453     /* Figure out if we are here for the first time */
454     apr_pool_userdata_get(&init_flag, "modsecurity-init-flag", s->process->pool);
455     if (init_flag == NULL) {
456         first_time = 1;
457         apr_pool_userdata_set((const void *)1, "modsecurity-init-flag",
458             apr_pool_cleanup_null, s->process->pool);
459     } else {
460         modsecurity_init(modsecurity, mp);
461     }
462
463     /* Store the original server signature */
464     real_server_signature = apr_pstrdup(mp, apache_get_server_version());
465
466     /* Make some space in the server signature for later */
467     if (new_server_signature != NULL) {
468         ap_add_version_component(mp, new_server_signature);
469         change_server_signature(s);
470     }
471
472     #if (!(defined(WIN32) || defined(NETWARE)))
473
474     /* Internal chroot functionality */
475
476     if (chroot_dir != NULL) {
477
478         /* ENH Is it safe to simply return with an error, instead
479          *      of using exit()?
480          */
481
482         if (first_time == 0) {
483             ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
484                 "ModSecurity: chroot checkpoint #2 (pid=%ld ppid=%ld)", (long)getpid(), (long)getppid());
485
486             if (chdir(chroot_dir) < 0) {
487                 ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
488                     "ModSecurity: chroot failed, unable to chdir to %s, errno=%d (%s)",
489                     chroot_dir, errno, strerror(errno));
490                 exit(1);
491             }
492
493             if (chroot(chroot_dir) < 0) {
494                 ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
495                     "ModSecurity: chroot failed, path=%s, errno=%d(%s)",
496                     chroot_dir, errno, strerror(errno));
497                 exit(1);
498             }
499
500             if (chdir("/") < 0) {
501                 ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
502                     "ModSecurity: chdoot failed, unable to chdir to /, errno=%d (%s)",
503                     errno, strerror(errno));
504                 exit(1);
505             }
506
507             chroot_completed = 1;
508
509             ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
510                 "ModSecurity: chroot successful, path=%s", chroot_dir);
511         } else {
512             ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
513                 "ModSecurity: chroot checkpoint #1 (pid=%ld ppid=%ld)", (long)getpid(), (long)getppid());
514         }
515     }
516     #endif
517
518     /* Schedule main cleanup for later, when the main pool is destroyed. */
519     apr_pool_cleanup_register(mp, (void *)s, module_cleanup, apr_pool_cleanup_null);
520
521     /* Log our presence to the error log. */
522     if (first_time) {
523         ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
524                 "%s configured.", MODSEC_MODULE_NAME_FULL);
525
526         /* If we've changed the server signature make note of the original. */
527         if (new_server_signature != NULL) {
528             ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
529                 "Original server signature: %s", real_server_signature);
530         }
531     }
532
533     srand((unsigned int)(time(NULL) * getpid()));
534
535     return OK;
536 }
537
538 /**
539  * Initialisation performed for every new child process.
540  */
541 static void hook_child_init(apr_pool_t *mp, server_rec *s) {
542     modsecurity_child_init(modsecurity);
543 }
544
545 /**
546  * Initial request processing, executed immediatelly after
547  * Apache receives the request headers.
548  */
549 static int hook_request_early(request_rec *r) {
550     modsec_rec *msr = NULL;
551     int rc;
552
553     /* This function needs to run only once per transaction
554      * (i.e. subrequests and redirects are excluded).
555      */
556     if ((r->main != NULL)||(r->prev != NULL)) {
557         return DECLINED;
558     }
559
560     /* Initialise transaction context and
561      * create the initial configuration.
562      */
563     msr = create_tx_context(r);
564     if (msr == NULL) return DECLINED;
565
566     /* Are we allowed to continue? */
567     if (msr->txcfg->is_enabled == MODSEC_DISABLED) {
568         if (msr->txcfg->debuglog_level >= 4) {
569             msr_log(msr, 4, "Processing disabled, skipping (hook request_early).");
570         }
571         return DECLINED;
572     }
573
574     /* Process phase REQUEST_HEADERS */
575     rc = DECLINED;
576     if (modsecurity_process_phase(msr, PHASE_REQUEST_HEADERS) > 0) {
577         rc = perform_interception(msr);
578     }
579
580     if (    (msr->txcfg->is_enabled != MODSEC_DISABLED)
581          && (msr->txcfg->reqbody_access == 1)
582          && (rc == DECLINED))
583     {
584         /* Check request body limit (non-chunked requests only). */
585         if (msr->request_content_length > msr->txcfg->reqbody_limit) {
586             msr_log(msr, 1, "Request body (Content-Length) is larger than the "
587                          "configured limit (%ld).", msr->txcfg->reqbody_limit);
588             return HTTP_REQUEST_ENTITY_TOO_LARGE;
589         }
590     }
591
592     return rc;
593 }
594
595 /**
596  * Invoked as the first hook in the handler chain, this function
597  * executes the second phase of ModSecurity request processing.
598  */
599 static int hook_request_late(request_rec *r) {
600     char *my_error_msg = NULL;
601     modsec_rec *msr = NULL;
602     int rc;
603
604     /* This function needs to run only once per transaction
605      * (i.e. subrequests and redirects are excluded).
606      */
607     if ((r->main != NULL)||(r->prev != NULL)) {
608         return DECLINED;
609     }
610
611     /* Find the transaction context and make sure
612      * we are supposed to proceed.
613      */
614     msr = retrieve_tx_context(r);
615     if (msr == NULL) {
616         /* If we can't find the context that probably means it's
617          * a subrequest that was not initiated from the outside.
618          */
619         return DECLINED;
620     }
621
622     /* Has this phase been completed already? */
623     if (msr->phase_request_body_complete) {
624         msr_log(msr, 1, "Internal Error: Attempted to process the request body more than once.");
625         return DECLINED;
626     }
627     msr->phase_request_body_complete = 1;
628
629     msr->remote_user = r->user;
630
631     /* Get the second configuration context. */
632     msr->dcfg2 = (directory_config *)ap_get_module_config(r->per_dir_config,
633         &security2_module);
634
635     /* Create a transaction context. */
636     msr->txcfg = create_directory_config(msr->mp, NULL);
637     if (msr->txcfg == NULL) return DECLINED;
638     if (msr->dcfg2 != NULL) {
639         msr->txcfg = merge_directory_configs(msr->mp, msr->txcfg, msr->dcfg2);
640         if (msr->txcfg == NULL) return DECLINED;
641     }
642
643     /* Update with the explicit user settings. */
644     msr->txcfg = merge_directory_configs(msr->mp, msr->txcfg, msr->usercfg);
645
646     init_directory_config(msr->txcfg);
647
648     /* Perform the PDF tests now. */
649     rc = pdfp_check(msr);
650     if (rc > 0) {
651         /* The PDF protection module has decided it needs to
652          * redirect the current transaction. So we let it do that.
653          */
654         return rc;
655     }
656
657     if (msr->txcfg->is_enabled == 0) {
658         if (msr->txcfg->debuglog_level >= 4) {
659             msr_log(msr, 4, "Processing disabled, skipping (hook request_late).");
660         }
661         return DECLINED;
662     }
663
664     if (msr->txcfg->debuglog_level >= 4) {
665         msr_log(msr, 4, "Second phase starting (dcfg %pp).", msr->dcfg2);
666     }
667
668     /* Figure out whether or not to extract multipart files. */
669     if ((msr->txcfg->upload_keep_files != KEEP_FILES_OFF) /* user might want to keep them */
670         || (msr->txcfg->upload_validates_files)) /* user might want to validate them */
671     {
672         msr->upload_extract_files = 1;
673         msr->upload_remove_files = 1;
674     }
675
676     rc = read_request_body(msr, &my_error_msg);
677     if (rc < 0) {
678         switch(rc) {
679             case -1 :
680                 if (my_error_msg != NULL) {
681                     msr_log(msr, 1, "%s", my_error_msg);
682                 }
683                 return HTTP_INTERNAL_SERVER_ERROR;
684                 break;
685             case -4 : /* Timeout. */
686                 if (my_error_msg != NULL) {
687                     msr_log(msr, 4, "%s", my_error_msg);
688                 }
689                 r->connection->keepalive = AP_CONN_CLOSE;
690                 return HTTP_REQUEST_TIME_OUT;
691                 break;
692             case -5 : /* Request body limit reached. */
693                 if (my_error_msg != NULL) {
694                     msr_log(msr, 1, "%s", my_error_msg);
695                 }
696                 r->connection->keepalive = AP_CONN_CLOSE;
697                 return HTTP_REQUEST_ENTITY_TOO_LARGE;
698                 break;
699             default :
700                 /* allow through */
701                 break;
702         }
703
704         msr->msc_reqbody_error = 1;
705         msr->msc_reqbody_error_msg = my_error_msg;
706     }
707
708     /* Update the request headers. They might have changed after
709      * the body was read (trailers).
710      */
711     /* NOTE We still need to keep a copy of the original headers
712      *      to log in the audit log.
713      */
714     msr->request_headers = apr_table_copy(msr->mp, r->headers_in);
715
716     /* Process phase REQUEST_BODY */
717     record_time_checkpoint(msr, 1);
718
719     rc = DECLINED;
720     if (modsecurity_process_phase(msr, PHASE_REQUEST_BODY) > 0) {
721         rc = perform_interception(msr);
722     }
723
724     record_time_checkpoint(msr, 2);
725
726     return rc;
727 }
728
729 /**
730  * Invoked every time Apache has something to write to the error log.
731  */
732 static void hook_error_log(const char *file, int line, int level, apr_status_t status,
733     const server_rec *s, const request_rec *r, apr_pool_t *mp, const char *fmt)
734 {
735     modsec_rec *msr = NULL;
736     error_message *em = NULL;
737
738     if (r == NULL) return;
739     msr = retrieve_tx_context((request_rec *)r);
740
741     /* Create a context for requests we never had the chance to process */
742     if ((msr == NULL)
743         && ((level & APLOG_LEVELMASK) < APLOG_DEBUG)
744         && apr_table_get(r->subprocess_env, "UNIQUE_ID"))
745     {
746         msr = create_tx_context((request_rec *)r);
747         if (msr->txcfg->debuglog_level >= 9) {
748             if (msr == NULL) {
749                 msr_log(msr, 9, "Failed to create context after request failure.");
750             }
751             else {
752                 msr_log(msr, 9, "Context created after request failure.");
753             }
754         }
755     }
756
757     if (msr == NULL) return;
758
759     /* Store the error message for later */
760     em = (error_message *)apr_pcalloc(msr->mp, sizeof(error_message));
761     if (em == NULL) return;
762
763     if (file != NULL) em->file = apr_pstrdup(msr->mp, file);
764     em->line = line;
765     em->level = level;
766     em->status = status;
767     if (fmt != NULL) em->message = apr_pstrdup(msr->mp, fmt);
768
769     /* Remove \n from the end of the message */
770     if (em->message != NULL) {
771         char *p = (char *)em->message;
772         while(*p != '\0') {
773             if ((*(p + 1) == '\0')&&(*p == '\n')) {
774                 *p = '\0';
775                 break;
776             }
777             p++;
778         }
779     }
780
781     *(const error_message **)apr_array_push(msr->error_messages) = em;
782 }
783
784 /**
785  * Guardian logger is used to interface to the external
786  * script for web server protection - httpd_guardian.
787  */
788 static void sec_guardian_logger(request_rec *r, request_rec *origr, modsec_rec *msr) {
789     char *str1, *str2, *text;
790     char *modsec_message = "-";
791     int modsec_rating = 0; /* not used yet */
792     apr_size_t nbytes, nbytes_written;
793     apr_time_t duration = (apr_time_now() - origr->request_time);
794     int limit, was_limited;
795
796     /* bail out if we do not have where to write */
797     if ((guardianlog_name == NULL)||(guardianlog_fd == NULL)) return;
798
799     /* process the condition, if we have one */
800     if (guardianlog_condition != NULL) {
801         if (*guardianlog_condition == '!') {
802             if (apr_table_get(r->subprocess_env, guardianlog_condition + 1) != NULL) {
803                 return;
804             }
805         }
806         else {
807             if (apr_table_get(r->subprocess_env, guardianlog_condition) == NULL) {
808                 return;
809             }
810         }
811     }
812
813     /*
814      * Log format is as follows:
815      *
816      * %V %h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-agent}i" %{UNIQUE_ID}e
817      * "SESSION_ID" %T %D "MODSEC_MESSAGE" MODSEC_RATING
818      *
819      * The fields SESSION_ID, MODSEC_MESSAGE, and MODSEC_RATING are not used at the moment.
820      */
821
822     str2 = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT " %" APR_TIME_T_FMT " \"%s\" %d",
823         duration, apr_time_sec(duration), log_escape(msr->mp, modsec_message), modsec_rating);
824     if (str2 == NULL) return;
825
826     /* We do not want the index line to be longer than 3980 bytes. */
827     limit = 3980;
828     was_limited = 0;
829
830     /* If we are logging to a pipe we need to observe and
831      * obey the pipe atomic write limit - PIPE_BUF. For
832      * more details see the discussion in sec_guardian_logger,
833      * above.
834      */
835     if (msr->txcfg->auditlog_name[0] == '|') {
836         if (PIPE_BUF < limit) {
837             limit = PIPE_BUF;
838         }
839     }
840
841     limit = limit - strlen(str2) - 5;
842     if (limit <= 0) {
843         msr_log(msr, 1, "Audit Log: Atomic PIPE write buffer too small: %d", PIPE_BUF);
844         return;
845     }
846
847     str1 = construct_log_vcombinedus_limited(msr, limit, &was_limited);
848     if (str1 == NULL) return;
849
850     if (was_limited == 0) {
851         text = apr_psprintf(msr->mp, "%s %s \n", str1, str2);
852     } else {
853         text = apr_psprintf(msr->mp, "%s %s L\n", str1, str2);
854     }
855     if (text == NULL) return;
856
857     nbytes = strlen(text);
858     apr_file_write_full(guardianlog_fd, text, nbytes, &nbytes_written);
859 }
860
861 /**
862  * Invoked at the end of each transaction.
863  */
864 static int hook_log_transaction(request_rec *r) {
865     const apr_array_header_t *arr = NULL;
866     request_rec *origr = NULL;
867     modsec_rec *msr = NULL;
868
869     msr = retrieve_tx_context(r);
870     if (msr == NULL) {
871         return DECLINED;
872     }
873
874     if (msr->txcfg->debuglog_level >= 4) {
875         msr_log(msr, 4, "Initialising logging.");
876     }
877
878     /* Find the first (origr) and the last (r) request */
879     origr = r;
880     while(origr->prev) {
881         origr = origr->prev;
882     }
883     while(r->next) {
884         r = r->next;
885     }
886
887     /* At this point r is the last request in the
888      * chain. However, we now need to detect a case when
889      * a bad ErrorDocument was used and back out of it. That's
890      * how Apache does it internally. Except where Apache knows
891      * exactly what is happening we will have to rely on the missing
892      * headers in the final request to detect this condition.
893      */
894     arr = apr_table_elts(r->headers_out);
895     while ((arr->nelts == 0)&&(r->prev != NULL)) {
896         r = r->prev;
897         arr = apr_table_elts(r->headers_out);
898     }
899
900     msr->r = r;
901     msr->response_status = r->status;
902     msr->status_line = ((r->status_line != NULL)
903         ? r->status_line : ap_get_status_line(r->status));
904     msr->response_protocol = get_response_protocol(origr);
905     msr->response_headers = apr_table_copy(msr->mp, r->headers_out);
906     if (!r->assbackwards) msr->response_headers_sent = 1;
907     msr->bytes_sent = r->bytes_sent;
908     msr->local_user = r->user;
909     msr->remote_user = r->connection->remote_logname;
910
911     /* -- Guardian -- */
912
913     sec_guardian_logger(r, origr, msr);
914
915     /* Invoke the engine to do the rest of the work now. */
916     modsecurity_process_phase(msr, PHASE_LOGGING);
917
918     return DECLINED;
919 }
920
921 /**
922  * Invoked right before request processing begins. This is
923  * when we need to decide if we want to hook into the output
924  * filter chain.
925  */
926 static void hook_insert_filter(request_rec *r) {
927     modsec_rec *msr = NULL;
928
929     /* Find the transaction context first. */
930     msr = retrieve_tx_context(r);
931     if (msr == NULL) return;
932
933     /* Add the input filter, but only if we need it to run. */
934     if (msr->if_status == IF_STATUS_WANTS_TO_RUN) {
935         if (msr->txcfg->debuglog_level >= 4) {
936             msr_log(msr, 4, "Hook insert_filter: Adding input forwarding filter %s(r %pp).",
937                 (((r->main != NULL)||(r->prev != NULL)) ? "for subrequest " : ""), r);
938         }
939
940         ap_add_input_filter("MODSECURITY_IN", msr, r, r->connection);
941     }
942
943     /* The output filters only need to be added only once per transaction
944      * (i.e. subrequests and redirects are excluded).
945      */
946     if ((r->main != NULL)||(r->prev != NULL)) {
947         return;
948     }
949
950     /* We always add the PDF XSS protection filter. */
951     if (msr->txcfg->debuglog_level >= 4) {
952         msr_log(msr, 4, "Hook insert_filter: Adding PDF XSS protection output filter (r %pp).", r);
953     }
954
955     ap_add_output_filter("PDFP_OUT", msr, r, r->connection);
956
957     /* Only proceed to add the second filter if the engine is enabled. */
958     if (msr->txcfg->is_enabled == 0) {
959         if (msr->txcfg->debuglog_level >= 4) {
960             msr_log(msr, 4, "Hook insert_filter: Processing disabled, skipping.");
961         }
962
963         return;
964     }
965
966     /* We always add the output filter because that's where we need to
967      * initiate our 3rd and 4th processing phases from. The filter is
968      * smart enough not to buffer the data if it is not supposed to.
969      */
970     if (msr->of_status != OF_STATUS_COMPLETE) {
971         if (msr->txcfg->debuglog_level >= 4) {
972             msr_log(msr, 4, "Hook insert_filter: Adding output filter (r %pp).", r);
973         }
974
975         ap_add_output_filter("MODSECURITY_OUT", msr, r, r->connection);
976     }
977 }
978
979 // TODO: Holding off on this for now (needs more testing)
980 #if 0
981 /**
982  * Invoked whenever Apache starts processing an error. A chance
983  * to insert ourselves into the output filter chain.
984  */
985 static void hook_insert_error_filter(request_rec *r) {
986     modsec_rec *msr = NULL;
987
988     /* Find the transaction context and make sure we are
989      * supposed to proceed.
990      */
991     msr = retrieve_tx_context(r);
992     if (msr == NULL) return;
993
994     /* Do not run if not enabled. */
995     if (msr->txcfg->is_enabled == 0) {
996         if (msr->txcfg->debuglog_level >= 4) {
997             msr_log(msr, 4, "Hook insert_error_filter: Processing disabled, skipping.");
998         }
999         return;
1000     }
1001
1002     /* Do not run if the output filter already completed. This will
1003      * happen if we intercept in phase 4.
1004      */
1005     if (msr->of_status != OF_STATUS_COMPLETE) {
1006         if (msr->txcfg->debuglog_level >= 4) {
1007             msr_log(msr, 4, "Hook insert_error_filter: Adding output filter (r %pp).", r);
1008         }
1009
1010         /* Make a note that the output we will be receiving is a
1011          * result of error processing.
1012          */
1013         msr->of_is_error = 1;
1014
1015         ap_add_output_filter("MODSECURITY_OUT", msr, r, r->connection);
1016     } else {
1017         if (msr->txcfg->debuglog_level >= 4) {
1018             msr_log(msr, 4, "Hook insert_error_filter: Output buffering already complete.");
1019         }
1020     }
1021 }
1022 #endif
1023
1024 #if (!defined(NO_MODSEC_API))
1025 /**
1026  * This function is exported for other Apache modules to
1027  * register new transformation functions.
1028  */
1029 static void modsec_register_tfn(const char *name, void *fn) {
1030     if (modsecurity != NULL) {
1031         msre_engine_tfn_register(modsecurity->msre, name, (fn_tfn_execute_t)fn);
1032     }
1033 }
1034
1035 /**
1036  * This function is exported for other Apache modules to
1037  * register new operators.
1038  */
1039 static void modsec_register_operator(const char *name, void *fn_init, void *fn_exec) {
1040     if (modsecurity != NULL) {
1041         msre_engine_op_register(modsecurity->msre, name, (fn_op_param_init_t)fn_init, (fn_op_execute_t)fn_exec);
1042     }
1043 }
1044
1045 /**
1046  * This function is exported for other Apache modules to
1047  * register new variables.
1048  */
1049 static void modsec_register_variable(const char *name, unsigned int type,
1050                                      unsigned int argc_min, unsigned int argc_max,
1051                                      void *fn_validate, void *fn_generate,
1052                                      unsigned int is_cacheable, unsigned int availability) {
1053     if (modsecurity != NULL) {
1054         msre_engine_variable_register(modsecurity->msre, name, type, argc_min, argc_max, (fn_var_validate_t)fn_validate, (fn_var_generate_t)fn_generate, is_cacheable, availability);
1055     }
1056     else {
1057         fprintf(stderr,"modsecurity is NULL\n");
1058     }
1059 }
1060 #endif
1061
1062 /**
1063  * Registers module hooks with Apache.
1064  */
1065 static void register_hooks(apr_pool_t *mp) {
1066     static const char *postconfig_beforeme_list[] = {
1067         "mod_unique_id.c",
1068         "mod_ssl.c",
1069         NULL
1070     };
1071     static const char *postconfig_afterme_list[] = {
1072         "mod_fcgid.c",
1073         "mod_cgid.c",
1074         NULL
1075     };
1076     static const char *postread_beforeme_list[] = {
1077         "mod_rpaf.c",
1078         "mod_rpaf-2.0.c",
1079         "mod_extract_forwarded2.c",
1080         "mod_custom_header.c",
1081         "mod_breach_realip.c",
1082         "mod_breach_trans.c",
1083         "mod_unique_id.c",
1084         NULL
1085     };
1086     static const char *postread_afterme_list[] = {
1087         "mod_log_forensic.c",
1088         NULL
1089     };
1090
1091     /* Add the MODSEC_a.b define */
1092     *(char **)apr_array_push(ap_server_config_defines) = apr_psprintf(mp, "MODSEC_%s.%s", MODSEC_VERSION_MAJOR, MODSEC_VERSION_MINOR);
1093
1094 #if (!defined(NO_MODSEC_API))
1095     /* Export optional functions. */
1096     APR_REGISTER_OPTIONAL_FN(modsec_register_tfn);
1097     APR_REGISTER_OPTIONAL_FN(modsec_register_operator);
1098     APR_REGISTER_OPTIONAL_FN(modsec_register_variable);
1099 #endif
1100
1101     /* Main hooks */
1102     ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_FIRST);
1103     ap_hook_post_config(hook_post_config, postconfig_beforeme_list,
1104         postconfig_afterme_list, APR_HOOK_REALLY_LAST);
1105     ap_hook_child_init(hook_child_init, NULL, NULL, APR_HOOK_MIDDLE);
1106
1107     /* Our own hook to handle RPC transactions (not used at the moment).
1108      * // ap_hook_handler(hook_handler, NULL, NULL, APR_HOOK_MIDDLE);
1109      */
1110
1111     /* Transaction processing hooks */
1112     ap_hook_post_read_request(hook_request_early,
1113         postread_beforeme_list, postread_afterme_list, APR_HOOK_REALLY_FIRST);
1114
1115     ap_hook_fixups(hook_request_late, NULL, NULL, APR_HOOK_REALLY_FIRST);
1116
1117     /* Logging */
1118     ap_hook_error_log(hook_error_log, NULL, NULL, APR_HOOK_MIDDLE);
1119     ap_hook_log_transaction(hook_log_transaction, NULL, NULL, APR_HOOK_MIDDLE);
1120
1121     /* Filter hooks */
1122     ap_hook_insert_filter(hook_insert_filter, NULL, NULL, APR_HOOK_FIRST);
1123 #if 0
1124     ap_hook_insert_error_filter(hook_insert_error_filter, NULL, NULL, APR_HOOK_FIRST);
1125 #endif
1126
1127     ap_register_input_filter("MODSECURITY_IN", input_filter,
1128         NULL, AP_FTYPE_CONTENT_SET);
1129
1130     /* Ensure that the output filter runs before other modules so that
1131      * we get a request that has a better chance of not being modified:
1132      *
1133      * Currently:
1134      *   mod_expires = -2
1135      *   mod_cache   = -1
1136      *   mod_deflate = -1
1137      *   mod_headers =  0
1138      */
1139     ap_register_output_filter("MODSECURITY_OUT", output_filter,
1140         NULL, AP_FTYPE_CONTENT_SET - 3);
1141
1142     ap_register_output_filter("PDFP_OUT", pdfp_output_filter,
1143         NULL, AP_FTYPE_CONTENT_SET);
1144 }
1145
1146 /* Defined in apache2_config.c */
1147 extern const command_rec module_directives[];
1148
1149 /* Module entry points */
1150 module AP_MODULE_DECLARE_DATA security2_module = {
1151     STANDARD20_MODULE_STUFF,
1152     create_directory_config,
1153     merge_directory_configs,
1154     NULL,    /* create_server_config */
1155     NULL,    /* merge_server_configs */
1156     module_directives,
1157     register_hooks
1158 };