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