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 <limits.h>
16 #include <stdio.h>
17
18 #include "http_core.h"
19 #include "http_request.h"
20
21 #include "modsecurity.h"
22 #include "apache2.h"
23 #include "http_main.h"
24 #include "http_connection.h"
25
26 #include "apr_optional.h"
27 #include "mod_log_config.h"
28
29 #include "msc_logging.h"
30 #include "msc_util.h"
31
32 #include "ap_mpm.h"
33 #include "scoreboard.h"
34
35 #include "apr_version.h"
36
37 #include "apr_lib.h"
38 #include "ap_config.h"
39 #include "http_config.h"
40
41 #include "api.h"
42
43 #ifdef WIN32
44 #include "msc_status_engine.h"
45 #endif
46
47 extern void *modsecLogObj;
48 extern void (*modsecLogHook)(void *obj, int level, char *str);
49 extern int (*modsecDropAction)(request_rec *r);
50 apr_status_t (*modsecReadBody)(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos);
51 apr_status_t (*modsecReadResponse)(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos);
52 apr_status_t (*modsecWriteBody)(request_rec *r, char *buf, unsigned int length);
53 apr_status_t (*modsecWriteResponse)(request_rec *r, char *buf, unsigned int length);
54
55 extern const char *process_command_config(server_rec *s,
56 void *mconfig,
57 apr_pool_t *p,
58 apr_pool_t *ptemp,
59 const char *filename);
60
61 #define DECLARE_EXTERNAL_HOOK(ns,link,ret,name,args) \
62 extern ns##_HOOK_##name##_t *hookfn_##name;
63
64 #define DECLARE_HOOK(ret,name,args) \
65 DECLARE_EXTERNAL_HOOK(ap,AP,ret,name,args)
66
67 DECLARE_HOOK(int,pre_config,(apr_pool_t *pconf,apr_pool_t *plog, apr_pool_t *ptemp))
68 DECLARE_HOOK(int,post_config,(apr_pool_t *pconf,apr_pool_t *plog, apr_pool_t *ptemp,server_rec *s))
69 DECLARE_HOOK(void,child_init,(apr_pool_t *pchild, server_rec *s))
70 DECLARE_HOOK(int,process_connection,(conn_rec *c))
71 DECLARE_HOOK(int,post_read_request,(request_rec *r))
72 DECLARE_HOOK(int,fixups,(request_rec *r))
73 DECLARE_HOOK(void, error_log, (const char *file, int line, int level,
74 apr_status_t status, const server_rec *s,
75 const request_rec *r, apr_pool_t *pool,
76 const char *errstr))
77 DECLARE_HOOK(int,log_transaction,(request_rec *r))
78 DECLARE_HOOK(void,insert_filter,(request_rec *r))
79 DECLARE_HOOK(void,insert_error_filter,(request_rec *r))
80
81 char *sa_name = "standalone";
82 const char *sa_name_argv[] = { "standalone", NULL };
83 server_rec *server;
84 apr_pool_t *pool = NULL;
85
86 apr_status_t ap_http_in_filter(ap_filter_t *f, apr_bucket_brigade *b,
87 ap_input_mode_t mode, apr_read_type_e block,
88 apr_off_t readbytes);
89 apr_status_t ap_http_out_filter(ap_filter_t *f, apr_bucket_brigade *b);
90
modsecInit()91 server_rec *modsecInit() {
92 apr_initialize();
93
94 apr_pool_create(&pool, NULL);
95
96 apr_hook_global_pool = pool;
97
98 server = apr_palloc(pool, sizeof(server_rec));
99
100 server->addrs = apr_palloc(pool, sizeof(server_addr_rec));
101 server->addrs->host_addr = apr_palloc(pool, sizeof(apr_sockaddr_t));
102 server->addrs->host_addr->addr_str_len = 16;
103 server->addrs->host_addr->family = AF_INET;
104 server->addrs->host_addr->hostname = sa_name;
105 #ifdef WIN32
106 server->addrs->host_addr->ipaddr_len = sizeof(IN_ADDR);
107 #else
108 server->addrs->host_addr->ipaddr_len = sizeof(struct in_addr);
109 #endif
110 server->addrs->host_addr->ipaddr_ptr = &server->addrs->host_addr->sa.sin.sin_addr;
111 server->addrs->host_addr->pool = pool;
112 server->addrs->host_addr->port = 80;
113 #ifdef WIN32
114 server->addrs->host_addr->sa.sin.sin_addr.S_un.S_addr = 0x0100007f;
115 #else
116 server->addrs->host_addr->sa.sin.sin_addr.s_addr = 0x0100007f;
117 #endif
118 server->addrs->host_addr->sa.sin.sin_family = AF_INET;
119 server->addrs->host_addr->sa.sin.sin_port = 80;
120 server->addrs->host_addr->salen = sizeof(server->addrs->host_addr->sa);
121 server->addrs->host_addr->servname = sa_name;
122 server->addrs->host_port = 80;
123 server->error_fname = "error.log";
124 server->error_log = NULL;
125 server->limit_req_fields = 1024;
126 server->limit_req_fieldsize = 1024;
127 server->limit_req_line = 1024;
128 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
129 server->loglevel = APLOG_DEBUG;
130 #endif
131 server->lookup_defaults = NULL;
132 server->module_config = NULL;
133 server->names = NULL;
134 #ifdef WIN32
135 server->path = "c:\\inetpub\\wwwroot";
136 #else
137 server->path = "/var/www";
138 #endif
139 server->pathlen = strlen(server->path);
140 server->port = 80;
141 server->process = apr_palloc(pool, sizeof(process_rec));
142 server->process->argc = 1;
143 server->process->argv = sa_name_argv;
144 server->process->pconf = pool;
145 server->process->pool = pool;
146 server->process->short_name = sa_name;
147 server->server_admin = sa_name;
148 server->server_hostname = sa_name;
149 server->server_scheme = "";
150 server->timeout = 60 * 1000000;// 60 seconds
151 server->wild_names = NULL;
152 server->is_virtual = 0;
153
154 ap_server_config_defines = apr_array_make(pool, 1, sizeof(char *));
155
156 // here we should add scoreboard handling for multiple processes and threads
157 //
158 ap_scoreboard_image = (scoreboard *)apr_palloc(pool, sizeof(scoreboard));
159
160 memset(ap_scoreboard_image, 0, sizeof(scoreboard));
161
162 // ----------
163
164 security2_module.module_index = 0;
165
166 security2_module.register_hooks(pool);
167
168 ap_register_input_filter("HTTP_IN", ap_http_in_filter, NULL, AP_FTYPE_RESOURCE);
169 ap_register_output_filter("HTTP_OUT", ap_http_out_filter, NULL, AP_FTYPE_CONTENT_SET);
170
171 return server;
172 }
173
ap_http_in_filter(ap_filter_t * f,apr_bucket_brigade * bb_out,ap_input_mode_t mode,apr_read_type_e block,apr_off_t readbytes)174 apr_status_t ap_http_in_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
175 ap_input_mode_t mode, apr_read_type_e block,
176 apr_off_t readbytes) {
177 char *tmp = NULL;
178 apr_bucket *e = NULL;
179 unsigned int readcnt = 0;
180 int is_eos = 0;
181 apr_bucket_brigade *bb_in;
182 apr_bucket *after;
183 apr_status_t rv;
184
185 bb_in = modsecGetBodyBrigade(f->r);
186
187 /* use request brigade */
188 if (bb_in != NULL) {
189 if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb_in))) {
190 e = apr_bucket_eos_create(f->c->bucket_alloc);
191 APR_BRIGADE_INSERT_TAIL(bb_in, e);
192 }
193
194 rv = apr_brigade_partition(bb_in, readbytes, &after);
195 if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
196 return rv;
197 }
198
199 for (e = APR_BRIGADE_FIRST(bb_in); e != after; e = APR_BRIGADE_FIRST(bb_in)) {
200 APR_BUCKET_REMOVE(e);
201 APR_BRIGADE_INSERT_TAIL(bb_out, e);
202 }
203
204 return APR_SUCCESS;
205 }
206
207 /* call the callback */
208 if(modsecReadBody != NULL) {
209
210 tmp = (char *)apr_palloc(f->r->pool, readbytes);
211 modsecReadBody(f->r, tmp, readbytes, &readcnt, &is_eos);
212
213 e = apr_bucket_pool_create(tmp, readcnt, f->r->pool, f->c->bucket_alloc);
214 APR_BRIGADE_INSERT_TAIL(bb_out, e);
215
216 if(is_eos) {
217 e = apr_bucket_eos_create(f->c->bucket_alloc);
218 APR_BRIGADE_INSERT_TAIL(bb_out, e);
219 }
220 return APR_SUCCESS;
221 }
222
223 /* cannot read request body */
224 e = apr_bucket_eos_create(f->c->bucket_alloc);
225 APR_BRIGADE_INSERT_TAIL(bb_out, e);
226
227 return APR_SUCCESS;
228 }
229
ap_http_out_filter(ap_filter_t * f,apr_bucket_brigade * b)230 apr_status_t ap_http_out_filter(ap_filter_t *f, apr_bucket_brigade *b) {
231 apr_bucket_brigade *bb_out = (apr_bucket_brigade *)f->ctx;
232
233 APR_BRIGADE_CONCAT(bb_out, b);
234 return APR_SUCCESS;
235 }
236
modsecTerminate()237 void modsecTerminate() {
238 apr_pool_destroy(pool);
239 pool = NULL;
240 apr_terminate();
241 }
242
modsecStartConfig()243 void modsecStartConfig() {
244 apr_pool_t *ptemp = NULL;
245
246 apr_pool_create(&ptemp, pool);
247
248 hookfn_pre_config(pool, pool, ptemp);
249
250 apr_pool_destroy(ptemp);
251 }
252
modsecGetDefaultConfig()253 directory_config *modsecGetDefaultConfig() {
254 return (directory_config *)security2_module.create_dir_config(pool, NULL);
255 }
256
modsecProcessConfig(directory_config * config,const char * file,const char * dir)257 const char *modsecProcessConfig(directory_config *config, const char *file, const char *dir) {
258 apr_pool_t *ptemp = NULL;
259 const char *err;
260 apr_status_t status;
261 const char *rootpath, *incpath;
262
263 if(dir == NULL || strlen(dir) == 0)
264 #ifdef WIN32
265 dir = "\\";
266 #else
267 dir = "/";
268 #endif
269
270 incpath = file;
271
272 /* locate the start of the directories proper */
273 status = apr_filepath_root(&rootpath, &incpath, APR_FILEPATH_TRUENAME | APR_FILEPATH_NATIVE, config->mp);
274
275 /* we allow APR_SUCCESS and APR_EINCOMPLETE */
276 if (APR_ERELATIVE == status) {
277 int li = strlen(dir) - 1;
278
279 if(dir[li] != '/' && dir[li] != '\\')
280 #ifdef WIN32
281 file = apr_pstrcat(config->mp, dir, "\\", file, NULL);
282 #else
283 file = apr_pstrcat(config->mp, dir, "/", file, NULL);
284 #endif
285 else
286 file = apr_pstrcat(config->mp, dir, file, NULL);
287 }
288 else if (APR_EBADPATH == status) {
289 return apr_pstrcat(config->mp, "Config file has a bad path, ", file, NULL);
290 }
291
292 apr_pool_create(&ptemp, config->mp);
293
294 err = process_command_config(server, config, config->mp, ptemp, file);
295
296 apr_pool_destroy(ptemp);
297
298 return err;
299 }
300
modsecFinalizeConfig()301 void modsecFinalizeConfig() {
302 apr_pool_t *ptemp = NULL;
303
304 apr_pool_create(&ptemp, pool);
305
306 hookfn_post_config(pool, pool, ptemp, server);
307 hookfn_post_config(pool, pool, ptemp, server);
308
309 apr_pool_destroy(ptemp);
310 }
311
modsecInitProcess()312 void modsecInitProcess() {
313 hookfn_child_init(pool, server);
314 }
315
modsecNewConnection()316 conn_rec *modsecNewConnection() {
317 conn_rec *c;
318 apr_pool_t *pc = NULL;
319
320 apr_pool_create(&pc, pool);
321
322 c = apr_pcalloc(pc, sizeof(conn_rec));
323
324 c->base_server = server;
325 c->id = 1;
326 c->local_addr = server->addrs->host_addr;
327 c->local_host = sa_name;
328 c->local_ip = "127.0.0.1";
329 c->pool = pc;
330 c->remote_host = sa_name;
331 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
332 c->remote_ip = "127.0.0.1";
333 c->remote_addr = server->addrs->host_addr;
334 #else
335 c->client_ip = "127.0.0.1";
336 c->client_addr = server->addrs->host_addr;
337 #endif
338 c->input_filters = NULL;
339 c->output_filters = NULL;
340 c->bucket_alloc = apr_bucket_alloc_create(pc);
341
342 return c;
343 }
344
modsecProcessConnection(conn_rec * c)345 void modsecProcessConnection(conn_rec *c) {
346 hookfn_process_connection(c);
347 }
348
modsecNewRequest(conn_rec * connection,directory_config * config)349 request_rec *modsecNewRequest(conn_rec *connection, directory_config *config) {
350 request_rec *r;
351 apr_pool_t *pr = NULL;
352
353 apr_pool_create(&pr, connection->pool);
354
355 r = apr_pcalloc(pr, sizeof(request_rec));
356
357 r->connection = connection;
358 r->server = server;
359 r->pool = pr;
360 r->main = NULL;
361 r->next = NULL;
362 r->notes = apr_table_make(pr, 10);
363 r->per_dir_config = apr_palloc(pr, sizeof(void *));
364 ((void **)r->per_dir_config)[0] = config;
365 r->prev = NULL;
366 r->subprocess_env = apr_table_make(pr, 10);
367 apr_table_setn(r->subprocess_env, "UNIQUE_ID", "unique_id");
368 r->user = NULL;
369
370 r->headers_in = apr_table_make(pr, 10);
371 r->headers_out = apr_table_make(pr, 10);
372 r->err_headers_out = apr_table_make(pr, 10);
373 //apr_table_setn(r->headers_in, "Host", "www.google.com");
374 //apr_table_setn(r->headers_in, "", "");
375
376 r->the_request = "GET /../../index.html HTTP/1.1";
377 r->method = "GET";
378 r->method_number = M_GET;
379 r->protocol = "HTTP/1.1";
380 r->uri = "http://www.google.com/../../index.html";
381 r->args = "";
382 r->filename = "/../../index.html";
383 r->handler = "IIS";
384
385 r->parsed_uri.scheme = "http";
386 r->parsed_uri.path = "/../../index.html";
387 r->parsed_uri.hostname = "www.google.com";
388 r->parsed_uri.is_initialized = 1;
389 r->parsed_uri.port = 1234;
390 r->parsed_uri.port_str = "1234";
391 r->parsed_uri.query = "";
392 r->parsed_uri.dns_looked_up = 0;
393 r->parsed_uri.dns_resolved = 0;
394 r->parsed_uri.password = NULL;
395 r->parsed_uri.user = NULL;
396 r->parsed_uri.fragment = "";
397
398 r->input_filters = NULL;
399 r->output_filters = NULL;
400
401 return r;
402 }
403
retrieve_msr(request_rec * r)404 static modsec_rec *retrieve_msr(request_rec *r) {
405 modsec_rec *msr = NULL;
406 request_rec *rx = NULL;
407
408 /* Look in the current request first. */
409 msr = (modsec_rec *)apr_table_get(r->notes, NOTE_MSR);
410 if (msr != NULL) {
411 msr->r = r;
412 return msr;
413 }
414
415 /* If this is a subrequest then look in the main request. */
416 if (r->main != NULL) {
417 msr = (modsec_rec *)apr_table_get(r->main->notes, NOTE_MSR);
418 if (msr != NULL) {
419 msr->r = r;
420 return msr;
421 }
422 }
423
424 /* If the request was redirected then look in the previous requests. */
425 rx = r->prev;
426 while(rx != NULL) {
427 msr = (modsec_rec *)apr_table_get(rx->notes, NOTE_MSR);
428 if (msr != NULL) {
429 msr->r = r;
430 return msr;
431 }
432 rx = rx->prev;
433 }
434
435 return NULL;
436 }
437
modsecProcessRequestHeaders(request_rec * r)438 int modsecProcessRequestHeaders(request_rec *r) {
439 return hookfn_post_read_request(r);
440 }
441
modsecProcessRequestBody(request_rec * r)442 int modsecProcessRequestBody(request_rec *r) {
443 int status = DECLINED;
444 modsec_rec *msr = NULL;
445
446 ap_filter_t *f = ap_add_input_filter("HTTP_IN", NULL, r, r->connection);
447 apr_bucket_brigade* bb_out;
448
449 status = hookfn_fixups(r);
450
451 ap_remove_input_filter(f);
452
453 if (status != DECLINED) {
454 return status;
455 }
456
457 hookfn_insert_filter(r);
458
459 /* Find the transaction context first. */
460 msr = retrieve_msr(r);
461
462 if (msr == NULL)
463 return status;
464
465 bb_out = modsecGetBodyBrigade(r);
466 if (bb_out) {
467 (void) apr_brigade_cleanup(bb_out);
468 status = ap_get_brigade(r->input_filters, bb_out, AP_MODE_READBYTES, APR_BLOCK_READ, -1);
469 if (status == APR_SUCCESS) {
470 return DECLINED;
471 }
472 return status;
473 }
474
475 if(msr->stream_input_data != NULL && modsecWriteBody != NULL)
476 {
477 // target is responsible for copying the data into correctly managed buffer
478 //
479 modsecWriteBody(r, msr->stream_input_data, msr->stream_input_length);
480
481 free(msr->stream_input_data);
482
483 msr->stream_input_data = NULL;
484 }
485
486 // leftover code possibly for future use
487 //
488 //if(r->input_filters != NULL && r->input_filters->frec->filter_init_func != NULL)
489 //r->input_filters->frec->filter_init_func(r->input_filters);
490 //if(r->input_filters != NULL && r->input_filters->frec->filter_func.in_func != NULL)
491 //r->input_filters->frec->filter_func.in_func(r->input_filters, NULL, 0, 0, 0);
492
493 return status;
494 }
495
modsecSetConfigForIISRequestBody(request_rec * r)496 void modsecSetConfigForIISRequestBody(request_rec *r)
497 {
498 modsec_rec *msr = retrieve_msr(r);
499
500 if(msr == NULL || msr->txcfg == NULL)
501 return;
502
503 if(msr->txcfg->reqbody_access)
504 msr->txcfg->stream_inbody_inspection = 1;
505 }
506
modsecContextState(request_rec * r)507 int modsecContextState(request_rec *r)
508 {
509 modsec_rec *msr = retrieve_msr(r);
510
511 if(msr == NULL || msr->txcfg == NULL)
512 return NOT_SET;
513
514 return msr->txcfg->is_enabled;
515 }
516
modsecIsRequestBodyAccessEnabled(request_rec * r)517 int modsecIsRequestBodyAccessEnabled(request_rec *r)
518 {
519 modsec_rec *msr = retrieve_msr(r);
520
521 if(msr == NULL || msr->txcfg == NULL)
522 return 0;
523
524 return msr->txcfg->reqbody_access;
525 }
526
modsecIsResponseBodyAccessEnabled(request_rec * r)527 int modsecIsResponseBodyAccessEnabled(request_rec *r)
528 {
529 modsec_rec *msr = retrieve_msr(r);
530
531 if(msr == NULL || msr->txcfg == NULL)
532 return 0;
533
534 return msr->txcfg->resbody_access;
535 }
536
modsecProcessResponse(request_rec * r)537 int modsecProcessResponse(request_rec *r) {
538 int status;
539 modsec_rec *msr;
540 apr_bucket *e;
541 ap_filter_t *f;
542 apr_bucket_brigade *bb_in, *bb_out, *bb;
543
544 if(r->output_filters == NULL) {
545 return DECLINED;
546 }
547
548 msr = (modsec_rec *)r->output_filters->ctx;
549 if (msr == NULL) {
550 ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server,
551 "ModSecurity: Internal Error: msr is null in output filter.");
552 ap_remove_output_filter(r->output_filters);
553 return APR_EGENERAL;
554 }
555
556 msr->r = r;
557
558 /* create input response brigade */
559 bb_in = apr_brigade_create(msr->mp, r->connection->bucket_alloc);
560
561 if (bb_in == NULL) {
562 msr_log(msr, 1, "Process response: Failed to create brigade.");
563 return APR_EGENERAL;
564 }
565
566 /* get input response brigade */
567 bb = modsecGetResponseBrigade(r);
568 if (bb != NULL) {
569 APR_BRIGADE_CONCAT(bb_in, bb);
570 if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb_in))) {
571 e = apr_bucket_eos_create(bb_in->bucket_alloc);
572 APR_BRIGADE_INSERT_TAIL(bb_in, e);
573 }
574 } else if (modsecReadResponse != NULL) {
575 unsigned int readcnt = 0;
576 int is_eos = 0;
577 char buf[8192];
578 while(!is_eos) {
579 modsecReadResponse(r, buf, 8192, &readcnt, &is_eos);
580
581 if(readcnt > 0) {
582 char *tmp = (char *)apr_palloc(r->pool, readcnt);
583 memcpy(tmp, buf, readcnt);
584 e = apr_bucket_pool_create(tmp, readcnt, r->pool, r->connection->bucket_alloc);
585 APR_BRIGADE_INSERT_TAIL(bb_in, e);
586 }
587 }
588
589 e = apr_bucket_eos_create(r->connection->bucket_alloc);
590 APR_BRIGADE_INSERT_TAIL(bb_in, e);
591 } else {
592 /* cannot read response body process header only */
593
594 e = apr_bucket_eos_create(r->connection->bucket_alloc);
595 APR_BRIGADE_INSERT_TAIL(bb_in, e);
596 }
597
598 bb_out = bb ? bb : apr_brigade_create(msr->mp, r->connection->bucket_alloc);
599
600 if (bb_out == NULL) {
601 msr_log(msr, 1, "Process response: Failed to create brigade.");
602 return APR_EGENERAL;
603 }
604
605 /* concat output bucket to bb_out */
606 f = ap_add_output_filter("HTTP_OUT", bb_out, r, r->connection);
607 status = ap_pass_brigade(r->output_filters, bb_in);
608 ap_remove_output_filter(f);
609
610 if (status == APR_EGENERAL) {
611 /* retrive response status from bb_out */
612 for(e = APR_BRIGADE_FIRST(bb_out);
613 e != APR_BRIGADE_SENTINEL(bb_out);
614 e = APR_BUCKET_NEXT(e)) {
615 if (AP_BUCKET_IS_ERROR(e)) {
616 return ((ap_bucket_error*) e->data)->status;
617 }
618 }
619 return APR_EGENERAL;
620 }
621
622 if (status != DECLINED) {
623 return status;
624 }
625
626 /* copy bb_out */
627 // is there a way to tell whether the response body was modified or not?
628 if (modsecWriteResponse != NULL
629 && (msr->txcfg->content_injection_enabled || msr->content_prepend_len != 0 || msr->content_append_len != 0)
630 && msr->txcfg->resbody_access) {
631
632 char *data = NULL;
633 apr_size_t length;
634
635 status = apr_brigade_pflatten(msr->of_brigade, &data, &length, msr->mp);
636
637 if (status != APR_SUCCESS) {
638 msr_log(msr, 1, "Output filter: Failed to flatten brigade (%d): %s", status,
639 get_apr_error(msr->mp, status));
640 return APR_EGENERAL;
641 }
642
643 if ( modsecWriteResponse(msr->r, data, msr->stream_output_length) != APR_SUCCESS) {
644 return APR_EGENERAL;
645 }
646 }
647
648 return DECLINED;
649 }
650
modsecFinishRequest(request_rec * r)651 int modsecFinishRequest(request_rec *r) {
652 // run output filter
653 //if(r->output_filters != NULL && r->output_filters->frec->filter_init_func != NULL)
654 //r->output_filters->frec->filter_init_func(r->output_filters);
655
656 hookfn_log_transaction(r);
657
658 // make sure you cleanup before calling apr_terminate()
659 // otherwise double-free might occur, because of the request body pool cleanup function
660 //
661 apr_pool_destroy(r->pool);
662
663 return DECLINED;
664 }
665
666 // destroy only the connection pool
modsecFinishConnection(conn_rec * c)667 int modsecFinishConnection(conn_rec *c)
668 {
669 apr_pool_destroy(c->pool);
670
671 return 0;
672 }
673
674
modsecSetLogHook(void * obj,void (* hook)(void * obj,int level,char * str))675 void modsecSetLogHook(void *obj, void (*hook)(void *obj, int level, char *str)) {
676 modsecLogObj = obj;
677 modsecLogHook = hook;
678 }
679
modsecSetReadBody(apr_status_t (* func)(request_rec * r,char * buf,unsigned int length,unsigned int * readcnt,int * is_eos))680 void modsecSetReadBody(apr_status_t (*func)(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)) {
681 modsecReadBody = func;
682 }
683
modsecSetReadResponse(apr_status_t (* func)(request_rec * r,char * buf,unsigned int length,unsigned int * readcnt,int * is_eos))684 void modsecSetReadResponse(apr_status_t (*func)(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)) {
685 modsecReadResponse = func;
686 }
687
modsecSetWriteBody(apr_status_t (* func)(request_rec * r,char * buf,unsigned int length))688 void modsecSetWriteBody(apr_status_t (*func)(request_rec *r, char *buf, unsigned int length)) {
689 modsecWriteBody = func;
690 }
691
modsecSetWriteResponse(apr_status_t (* func)(request_rec * r,char * buf,unsigned int length))692 void modsecSetWriteResponse(apr_status_t (*func)(request_rec *r, char *buf, unsigned int length)) {
693 modsecWriteResponse = func;
694 }
695
modsecSetDropAction(int (* func)(request_rec * r))696 void modsecSetDropAction(int (*func)(request_rec *r)) {
697 modsecDropAction = func;
698 }
699
700 /*
701 * Case SecServerSignature was used, this function returns the banner that
702 * should be used, otherwise it returns NULL.
703 */
modsecIsServerSignatureAvailale(void)704 const char *modsecIsServerSignatureAvailale(void) {
705 return new_server_signature;
706 }
707
708 #ifdef VERSION_IIS
modsecStatusEngineCall()709 void modsecStatusEngineCall()
710 {
711 if (status_engine_state != STATUS_ENGINE_DISABLED) {
712 msc_status_engine_call();
713 }
714 else {
715 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
716 "Status engine is currently disabled, enable it by set " \
717 "SecStatusEngine to On.\n");
718 }
719 }
720
modsecReportRemoteLoadedRules()721 void modsecReportRemoteLoadedRules()
722 {
723 #ifdef WITH_REMOTE_RULES
724 if (remote_rules_server != NULL)
725 {
726 if (remote_rules_server->amount_of_rules == 1)
727 {
728 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
729 "ModSecurity: Loaded %d rule from: '%s'.",
730 remote_rules_server->amount_of_rules,
731 remote_rules_server->uri);
732 }
733 else
734 {
735 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
736 "ModSecurity: Loaded %d rules from: '%s'.",
737 remote_rules_server->amount_of_rules,
738 remote_rules_server->uri);
739 }
740 }
741 #endif
742 if (remote_rules_fail_message != NULL)
743 {
744 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "ModSecurity: " \
745 "Problems loading external resources: %s",
746 remote_rules_fail_message);
747 }
748
749 }
750 #endif
751