2
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
3
* Copyright (c) 2004-2011 Trustwave Holdings, Inc. (http://www.trustwave.com/)
5
* You may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
17
#include "modsecurity.h"
18
#include "msc_logging.h"
27
/* -- Directory context creation and initialisation -- */
30
* Creates a fresh directory configuration.
32
void *create_directory_config(apr_pool_t *mp, char *path)
34
directory_config *dcfg = (directory_config *)apr_pcalloc(mp, sizeof(directory_config));
35
if (dcfg == NULL) return NULL;
38
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Created directory config %pp path %s", dcfg, path);
42
dcfg->is_enabled = NOT_SET;
44
dcfg->reqbody_access = NOT_SET;
45
dcfg->reqintercept_oe = NOT_SET;
46
dcfg->reqbody_buffering = NOT_SET;
47
dcfg->reqbody_inmemory_limit = NOT_SET;
48
dcfg->reqbody_limit = NOT_SET;
49
dcfg->reqbody_no_files_limit = NOT_SET;
50
dcfg->resbody_access = NOT_SET;
52
dcfg->debuglog_name = NOT_SET_P;
53
dcfg->debuglog_level = NOT_SET;
54
dcfg->debuglog_fd = NOT_SET_P;
56
dcfg->of_limit = NOT_SET;
57
dcfg->if_limit_action = NOT_SET;
58
dcfg->of_limit_action = NOT_SET;
59
dcfg->of_mime_types = NOT_SET_P;
60
dcfg->of_mime_types_cleared = NOT_SET;
62
dcfg->cookie_format = NOT_SET;
63
dcfg->argument_separator = NOT_SET;
65
dcfg->rule_inheritance = NOT_SET;
66
dcfg->rule_exceptions = apr_array_make(mp, 16, sizeof(rule_exception *));
68
/* audit log variables */
69
dcfg->auditlog_flag = NOT_SET;
70
dcfg->auditlog_type = NOT_SET;
71
dcfg->auditlog_dirperms = NOT_SET;
72
dcfg->auditlog_fileperms = NOT_SET;
73
dcfg->auditlog_name = NOT_SET_P;
74
dcfg->auditlog2_name = NOT_SET_P;
75
dcfg->auditlog_fd = NOT_SET_P;
76
dcfg->auditlog2_fd = NOT_SET_P;
77
dcfg->auditlog_storage_dir = NOT_SET_P;
78
dcfg->auditlog_parts = NOT_SET_P;
79
dcfg->auditlog_relevant_regex = NOT_SET_P;
84
dcfg->tmp_dir = NOT_SET_P;
85
dcfg->upload_dir = NOT_SET_P;
86
dcfg->upload_keep_files = NOT_SET;
87
dcfg->upload_validates_files = NOT_SET;
88
dcfg->upload_filemode = NOT_SET;
89
dcfg->upload_file_limit = NOT_SET;
91
/* These are only used during the configuration process. */
92
dcfg->tmp_chain_starter = NULL;
93
dcfg->tmp_default_actionset = NULL;
94
dcfg->tmp_rule_placeholders = NULL;
97
dcfg->data_dir = NOT_SET_P;
98
dcfg->webappid = NOT_SET_P;
100
/* Content injection. */
101
dcfg->content_injection_enabled = NOT_SET;
103
/* Stream inspection */
104
dcfg->stream_inbody_inspection = NOT_SET;
105
dcfg->stream_outbody_inspection = NOT_SET;
108
dcfg->geo = NOT_SET_P;
111
dcfg->gsb = NOT_SET_P;
114
dcfg->u_map = NOT_SET_P;
117
dcfg->cache_trans = NOT_SET;
118
dcfg->cache_trans_incremental = NOT_SET;
119
dcfg->cache_trans_min = NOT_SET;
120
dcfg->cache_trans_max = NOT_SET;
121
dcfg->cache_trans_maxitems = NOT_SET;
123
dcfg->component_signatures = apr_array_make(mp, 16, sizeof(char *));
125
dcfg->request_encoding = NOT_SET_P;
126
dcfg->disable_backend_compression = NOT_SET;
128
/* Collection timeout */
129
dcfg->col_timeout = NOT_SET;
135
* Copies rules between one phase of two configuration contexts,
136
* taking exceptions into account.
138
static void copy_rules_phase(apr_pool_t *mp,
139
apr_array_header_t *parent_phase_arr,
140
apr_array_header_t *child_phase_arr,
141
apr_array_header_t *exceptions_arr)
143
rule_exception **exceptions;
148
rules = (msre_rule **)parent_phase_arr->elts;
149
for(i = 0; i < parent_phase_arr->nelts; i++) {
150
msre_rule *rule = (msre_rule *)rules[i];
154
/* First rule in the chain. */
155
exceptions = (rule_exception **)exceptions_arr->elts;
156
for(j = 0; j < exceptions_arr->nelts; j++) {
158
/* Process exceptions. */
159
switch(exceptions[j]->type) {
160
case RULE_EXCEPTION_REMOVE_ID :
161
if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) {
162
int ruleid = atoi(rule->actionset->id);
163
if (rule_id_in_range(ruleid, exceptions[j]->param)) copy--;
166
case RULE_EXCEPTION_REMOVE_MSG :
167
if ((rule->actionset != NULL)&&(rule->actionset->msg != NULL)) {
168
char *my_error_msg = NULL;
170
int rc = msc_regexec(exceptions[j]->param_data,
171
rule->actionset->msg, strlen(rule->actionset->msg),
176
case RULE_EXCEPTION_REMOVE_TAG :
177
if ((rule->actionset != NULL)&&(apr_is_empty_table(rule->actionset->actions) == 0)) {
178
char *my_error_msg = NULL;
179
const apr_array_header_t *tarr = NULL;
180
const apr_table_entry_t *telts = NULL;
183
tarr = apr_table_elts(rule->actionset->actions);
184
telts = (const apr_table_entry_t*)tarr->elts;
186
for (c = 0; c < tarr->nelts; c++) {
187
msre_action *action = (msre_action *)telts[c].val;
188
if(strcmp("tag", action->metadata->name) == 0) {
190
int rc = msc_regexec(exceptions[j]->param_data,
191
action->param, strlen(action->param),
203
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, rule->actionset->id);
207
*(msre_rule **)apr_array_push(child_phase_arr) = rule;
208
if (rule->actionset->is_chained) mode = 2;
210
if (rule->actionset->is_chained) mode = 1;
215
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy chain %pp for rule %pp [id \"%s\"]", rule, rule->chain_starter, rule->chain_starter->actionset->id);
218
/* Copy the rule (it belongs to the chain we want to include. */
219
*(msre_rule **)apr_array_push(child_phase_arr) = rule;
222
if ((rule->actionset == NULL)||(rule->actionset->is_chained == 0)) mode = 0;
228
* Copies rules between two configuration contexts,
229
* taking exceptions into account.
231
static int copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset,
232
msre_ruleset *child_ruleset,
233
apr_array_header_t *exceptions_arr)
235
copy_rules_phase(mp, parent_ruleset->phase_request_headers,
236
child_ruleset->phase_request_headers, exceptions_arr);
237
copy_rules_phase(mp, parent_ruleset->phase_request_body,
238
child_ruleset->phase_request_body, exceptions_arr);
239
copy_rules_phase(mp, parent_ruleset->phase_response_headers,
240
child_ruleset->phase_response_headers, exceptions_arr);
241
copy_rules_phase(mp, parent_ruleset->phase_response_body,
242
child_ruleset->phase_response_body, exceptions_arr);
243
copy_rules_phase(mp, parent_ruleset->phase_logging,
244
child_ruleset->phase_logging, exceptions_arr);
250
* Merges two directory configurations.
252
void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
254
directory_config *parent = (directory_config *)_parent;
255
directory_config *child = (directory_config *)_child;
256
directory_config *merged = create_directory_config(mp, NULL);
259
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Merge parent %pp child %pp RESULT %pp", _parent, _child, merged);
262
if (merged == NULL) return NULL;
264
/* Use values from the child configuration where possible,
265
* otherwise use the parent's.
268
merged->is_enabled = (child->is_enabled == NOT_SET
269
? parent->is_enabled : child->is_enabled);
272
merged->reqbody_access = (child->reqbody_access == NOT_SET
273
? parent->reqbody_access : child->reqbody_access);
274
merged->reqbody_buffering = (child->reqbody_buffering == NOT_SET
275
? parent->reqbody_buffering : child->reqbody_buffering);
276
merged->reqbody_inmemory_limit = (child->reqbody_inmemory_limit == NOT_SET
277
? parent->reqbody_inmemory_limit : child->reqbody_inmemory_limit);
278
merged->reqbody_limit = (child->reqbody_limit == NOT_SET
279
? parent->reqbody_limit : child->reqbody_limit);
280
merged->reqbody_no_files_limit = (child->reqbody_no_files_limit == NOT_SET
281
? parent->reqbody_no_files_limit : child->reqbody_no_files_limit);
282
merged->resbody_access = (child->resbody_access == NOT_SET
283
? parent->resbody_access : child->resbody_access);
285
merged->of_limit = (child->of_limit == NOT_SET
286
? parent->of_limit : child->of_limit);
287
merged->if_limit_action = (child->if_limit_action == NOT_SET
288
? parent->if_limit_action : child->if_limit_action);
289
merged->of_limit_action = (child->of_limit_action == NOT_SET
290
? parent->of_limit_action : child->of_limit_action);
291
merged->reqintercept_oe = (child->reqintercept_oe == NOT_SET
292
? parent->reqintercept_oe : child->reqintercept_oe);
294
if (child->of_mime_types != NOT_SET_P) {
295
/* Child added to the table */
297
if (child->of_mime_types_cleared == 1) {
298
/* The list of MIME types was cleared in the child,
299
* which means the parent's MIME types went away and
300
* we should not take them into consideration here.
302
merged->of_mime_types = child->of_mime_types;
303
merged->of_mime_types_cleared = 1;
305
/* Add MIME types defined in the child to those
306
* defined in the parent context.
308
if (parent->of_mime_types == NOT_SET_P) {
309
merged->of_mime_types = child->of_mime_types;
310
merged->of_mime_types_cleared = NOT_SET;
312
merged->of_mime_types = apr_table_overlay(mp, parent->of_mime_types,
313
child->of_mime_types);
314
if (merged->of_mime_types == NULL) return NULL;
318
/* Child did not add to the table */
320
if (child->of_mime_types_cleared == 1) {
321
merged->of_mime_types_cleared = 1;
323
merged->of_mime_types = parent->of_mime_types;
324
merged->of_mime_types_cleared = parent->of_mime_types_cleared;
329
if (child->debuglog_fd == NOT_SET_P) {
330
merged->debuglog_name = parent->debuglog_name;
331
merged->debuglog_fd = parent->debuglog_fd;
333
merged->debuglog_name = child->debuglog_name;
334
merged->debuglog_fd = child->debuglog_fd;
337
merged->debuglog_level = (child->debuglog_level == NOT_SET
338
? parent->debuglog_level : child->debuglog_level);
340
merged->cookie_format = (child->cookie_format == NOT_SET
341
? parent->cookie_format : child->cookie_format);
342
merged->argument_separator = (child->argument_separator == NOT_SET
343
? parent->argument_separator : child->argument_separator);
346
/* rule inheritance */
347
if ((child->rule_inheritance == NOT_SET)||(child->rule_inheritance == 1)) {
348
merged->rule_inheritance = parent->rule_inheritance;
349
if ((child->ruleset == NULL)&&(parent->ruleset == NULL)) {
351
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "No rules in this context.");
354
/* Do nothing, there are no rules in either context. */
356
if (child->ruleset == NULL) {
358
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent rules in this context.");
361
/* Copy the rules from the parent context. */
362
merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp);
363
copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions);
365
if (parent->ruleset == NULL) {
367
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using child rules in this context.");
370
/* Copy child rules. */
371
merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp);
372
merged->ruleset->phase_request_headers = apr_array_copy(mp,
373
child->ruleset->phase_request_headers);
374
merged->ruleset->phase_request_body = apr_array_copy(mp,
375
child->ruleset->phase_request_body);
376
merged->ruleset->phase_response_headers = apr_array_copy(mp,
377
child->ruleset->phase_response_headers);
378
merged->ruleset->phase_response_body = apr_array_copy(mp,
379
child->ruleset->phase_response_body);
380
merged->ruleset->phase_logging = apr_array_copy(mp,
381
child->ruleset->phase_logging);
384
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent then child rules in this context.");
387
/* Copy parent rules, then add child rules to it. */
388
merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp);
389
copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions);
391
apr_array_cat(merged->ruleset->phase_request_headers,
392
child->ruleset->phase_request_headers);
393
apr_array_cat(merged->ruleset->phase_request_body,
394
child->ruleset->phase_request_body);
395
apr_array_cat(merged->ruleset->phase_response_headers,
396
child->ruleset->phase_response_headers);
397
apr_array_cat(merged->ruleset->phase_response_body,
398
child->ruleset->phase_response_body);
399
apr_array_cat(merged->ruleset->phase_logging,
400
child->ruleset->phase_logging);
403
merged->rule_inheritance = 0;
404
if (child->ruleset != NULL) {
405
/* Copy child rules. */
406
merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp);
407
merged->ruleset->phase_request_headers = apr_array_copy(mp,
408
child->ruleset->phase_request_headers);
409
merged->ruleset->phase_request_body = apr_array_copy(mp,
410
child->ruleset->phase_request_body);
411
merged->ruleset->phase_response_headers = apr_array_copy(mp,
412
child->ruleset->phase_response_headers);
413
merged->ruleset->phase_response_body = apr_array_copy(mp,
414
child->ruleset->phase_response_body);
415
merged->ruleset->phase_logging = apr_array_copy(mp,
416
child->ruleset->phase_logging);
420
/* Merge rule exceptions. */
421
merged->rule_exceptions = apr_array_append(mp, parent->rule_exceptions,
422
child->rule_exceptions);
424
/* audit log variables */
425
merged->auditlog_flag = (child->auditlog_flag == NOT_SET
426
? parent->auditlog_flag : child->auditlog_flag);
427
merged->auditlog_type = (child->auditlog_type == NOT_SET
428
? parent->auditlog_type : child->auditlog_type);
429
merged->auditlog_dirperms = (child->auditlog_dirperms == NOT_SET
430
? parent->auditlog_dirperms : child->auditlog_dirperms);
431
merged->auditlog_fileperms = (child->auditlog_fileperms == NOT_SET
432
? parent->auditlog_fileperms : child->auditlog_fileperms);
433
if (child->auditlog_fd != NOT_SET_P) {
434
merged->auditlog_fd = child->auditlog_fd;
435
merged->auditlog_name = child->auditlog_name;
437
merged->auditlog_fd = parent->auditlog_fd;
438
merged->auditlog_name = parent->auditlog_name;
440
if (child->auditlog2_fd != NOT_SET_P) {
441
merged->auditlog2_fd = child->auditlog2_fd;
442
merged->auditlog2_name = child->auditlog2_name;
444
merged->auditlog2_fd = parent->auditlog2_fd;
445
merged->auditlog2_name = parent->auditlog2_name;
447
merged->auditlog_storage_dir = (child->auditlog_storage_dir == NOT_SET_P
448
? parent->auditlog_storage_dir : child->auditlog_storage_dir);
449
merged->auditlog_parts = (child->auditlog_parts == NOT_SET_P
450
? parent->auditlog_parts : child->auditlog_parts);
451
merged->auditlog_relevant_regex = (child->auditlog_relevant_regex == NOT_SET_P
452
? parent->auditlog_relevant_regex : child->auditlog_relevant_regex);
455
merged->tmp_dir = (child->tmp_dir == NOT_SET_P
456
? parent->tmp_dir : child->tmp_dir);
457
merged->upload_dir = (child->upload_dir == NOT_SET_P
458
? parent->upload_dir : child->upload_dir);
459
merged->upload_keep_files = (child->upload_keep_files == NOT_SET
460
? parent->upload_keep_files : child->upload_keep_files);
461
merged->upload_validates_files = (child->upload_validates_files == NOT_SET
462
? parent->upload_validates_files : child->upload_validates_files);
463
merged->upload_filemode = (child->upload_filemode == NOT_SET
464
? parent->upload_filemode : child->upload_filemode);
465
merged->upload_file_limit = (child->upload_file_limit == NOT_SET
466
? parent->upload_file_limit : child->upload_file_limit);
469
merged->data_dir = (child->data_dir == NOT_SET_P
470
? parent->data_dir : child->data_dir);
471
merged->webappid = (child->webappid == NOT_SET_P
472
? parent->webappid : child->webappid);
474
/* Content injection. */
475
merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET
476
? parent->content_injection_enabled : child->content_injection_enabled);
478
/* Stream inspection */
479
merged->stream_inbody_inspection = (child->stream_inbody_inspection == NOT_SET
480
? parent->stream_inbody_inspection : child->stream_inbody_inspection);
481
merged->stream_outbody_inspection = (child->stream_outbody_inspection == NOT_SET
482
? parent->stream_outbody_inspection : child->stream_outbody_inspection);
485
merged->geo = (child->geo == NOT_SET_P
486
? parent->geo : child->geo);
489
merged->gsb = (child->gsb == NOT_SET_P
490
? parent->gsb : child->gsb);
493
merged->u_map = (child->u_map == NOT_SET_P
494
? parent->u_map : child->u_map);
497
merged->cache_trans = (child->cache_trans == NOT_SET
498
? parent->cache_trans : child->cache_trans);
499
merged->cache_trans_incremental = (child->cache_trans_incremental == NOT_SET
500
? parent->cache_trans_incremental : child->cache_trans_incremental);
501
merged->cache_trans_min = (child->cache_trans_min == (apr_size_t)NOT_SET
502
? parent->cache_trans_min : child->cache_trans_min);
503
merged->cache_trans_max = (child->cache_trans_max == (apr_size_t)NOT_SET
504
? parent->cache_trans_max : child->cache_trans_max);
505
merged->cache_trans_maxitems = (child->cache_trans_maxitems == (apr_size_t)NOT_SET
506
? parent->cache_trans_maxitems : child->cache_trans_maxitems);
508
/* Merge component signatures. */
509
merged->component_signatures = apr_array_append(mp, parent->component_signatures,
510
child->component_signatures);
512
merged->request_encoding = (child->request_encoding == NOT_SET_P
513
? parent->request_encoding : child->request_encoding);
515
merged->disable_backend_compression = (child->disable_backend_compression == NOT_SET
516
? parent->disable_backend_compression : child->disable_backend_compression);
518
merged->col_timeout = (child->col_timeout == NOT_SET
519
? parent->col_timeout : child->col_timeout);
525
* Initialise directory configuration. This function is *not* meant
526
* to be called for directory configuration instances created during
527
* the configuration phase. It can only be called on copies of those
528
* (created fresh for every transaction).
530
void init_directory_config(directory_config *dcfg)
532
if (dcfg == NULL) return;
534
if (dcfg->is_enabled == NOT_SET) dcfg->is_enabled = 0;
536
if (dcfg->reqbody_access == NOT_SET) dcfg->reqbody_access = 0;
537
if (dcfg->reqintercept_oe == NOT_SET) dcfg->reqintercept_oe = 0;
538
if (dcfg->reqbody_buffering == NOT_SET) dcfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_OFF;
539
if (dcfg->reqbody_inmemory_limit == NOT_SET)
540
dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT;
541
if (dcfg->reqbody_limit == NOT_SET) dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT;
542
if (dcfg->reqbody_no_files_limit == NOT_SET) dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT;
543
if (dcfg->resbody_access == NOT_SET) dcfg->resbody_access = 0;
544
if (dcfg->of_limit == NOT_SET) dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT;
545
if (dcfg->if_limit_action == NOT_SET) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT;
546
if (dcfg->of_limit_action == NOT_SET) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
548
if (dcfg->of_mime_types == NOT_SET_P) {
549
dcfg->of_mime_types = apr_table_make(dcfg->mp, 3);
550
if (dcfg->of_mime_types_cleared != 1) {
551
apr_table_setn(dcfg->of_mime_types, "text/plain", "1");
552
apr_table_setn(dcfg->of_mime_types, "text/html", "1");
556
if (dcfg->debuglog_fd == NOT_SET_P) dcfg->debuglog_fd = NULL;
557
if (dcfg->debuglog_name == NOT_SET_P) dcfg->debuglog_name = NULL;
558
if (dcfg->debuglog_level == NOT_SET) dcfg->debuglog_level = 0;
560
if (dcfg->cookie_format == NOT_SET) dcfg->cookie_format = 0;
561
if (dcfg->argument_separator == NOT_SET) dcfg->argument_separator = '&';
563
if (dcfg->rule_inheritance == NOT_SET) dcfg->rule_inheritance = 1;
565
/* audit log variables */
566
if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0;
567
if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL;
568
if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR;
569
if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE;
570
if (dcfg->auditlog_fd == NOT_SET_P) dcfg->auditlog_fd = NULL;
571
if (dcfg->auditlog2_fd == NOT_SET_P) dcfg->auditlog2_fd = NULL;
572
if (dcfg->auditlog_name == NOT_SET_P) dcfg->auditlog_name = NULL;
573
if (dcfg->auditlog2_name == NOT_SET_P) dcfg->auditlog2_name = NULL;
574
if (dcfg->auditlog_storage_dir == NOT_SET_P) dcfg->auditlog_storage_dir = NULL;
575
if (dcfg->auditlog_parts == NOT_SET_P) dcfg->auditlog_parts = "ABCFHZ";
576
if (dcfg->auditlog_relevant_regex == NOT_SET_P) dcfg->auditlog_relevant_regex = NULL;
579
if (dcfg->tmp_dir == NOT_SET_P) dcfg->tmp_dir = guess_tmp_dir(dcfg->mp);
580
if (dcfg->upload_dir == NOT_SET_P) dcfg->upload_dir = NULL;
581
if (dcfg->upload_keep_files == NOT_SET) dcfg->upload_keep_files = KEEP_FILES_OFF;
582
if (dcfg->upload_validates_files == NOT_SET) dcfg->upload_validates_files = 0;
583
if (dcfg->upload_filemode == NOT_SET) dcfg->upload_filemode = 0600;
584
if (dcfg->upload_file_limit == NOT_SET) dcfg->upload_file_limit = 100;
587
if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL;
588
if (dcfg->webappid == NOT_SET_P) dcfg->webappid = "default";
590
/* Content injection. */
591
if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0;
593
/* Stream inspection */
594
if (dcfg->stream_inbody_inspection == NOT_SET) dcfg->stream_inbody_inspection = 0;
595
if (dcfg->stream_outbody_inspection == NOT_SET) dcfg->stream_outbody_inspection = 0;
598
if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL;
601
if (dcfg->gsb == NOT_SET_P) dcfg->gsb = NULL;
604
if (dcfg->u_map == NOT_SET_P) dcfg->u_map = NULL;
607
if (dcfg->cache_trans == NOT_SET) dcfg->cache_trans = MODSEC_CACHE_DISABLED;
608
if (dcfg->cache_trans_incremental == NOT_SET) dcfg->cache_trans_incremental = 0;
609
if (dcfg->cache_trans_min == (apr_size_t)NOT_SET) dcfg->cache_trans_min = 32;
610
if (dcfg->cache_trans_max == (apr_size_t)NOT_SET) dcfg->cache_trans_max = 1024;
611
if (dcfg->cache_trans_maxitems == (apr_size_t)NOT_SET) dcfg->cache_trans_maxitems = 512;
613
if (dcfg->request_encoding == NOT_SET_P) dcfg->request_encoding = NULL;
615
if (dcfg->disable_backend_compression == NOT_SET) dcfg->disable_backend_compression = 0;
617
if (dcfg->col_timeout == NOT_SET) dcfg->col_timeout = 3600;
623
static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
624
const char *p1, const char *p2, const char *p3)
626
char *my_error_msg = NULL;
627
msre_rule *rule = NULL;
628
extern msc_engine *modsecurity;
631
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
632
"Rule: type=%d p1='%s' p2='%s' p3='%s'", type, p1, p2, p3);
635
/* Create a ruleset if one does not exist. */
636
if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) {
637
dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool);
638
if (dcfg->ruleset == NULL) return FATAL_ERROR;
641
/* Create the rule now. */
643
#if defined(WITH_LUA)
645
rule = msre_rule_lua_create(dcfg->ruleset, cmd->directive->filename,
646
cmd->directive->line_num, p1, p2, &my_error_msg);
650
rule = msre_rule_create(dcfg->ruleset, type, cmd->directive->filename,
651
cmd->directive->line_num, p1, p2, p3, &my_error_msg);
659
/* Create default actionset if one does not already exist. */
660
if (dcfg->tmp_default_actionset == NULL) {
661
dcfg->tmp_default_actionset = msre_actionset_create_default(modsecurity->msre);
662
if (dcfg->tmp_default_actionset == NULL) return FATAL_ERROR;
665
/* Check some cases prior to merging so we know where it came from */
667
/* Check syntax for chained rules */
668
if ((rule->actionset != NULL) && (dcfg->tmp_chain_starter != NULL)) {
669
/* Must NOT specify a disruptive action. */
670
if (rule->actionset->intercept_action != NOT_SET) {
671
return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions can only "
672
"be specified by chain starter rules.");
675
/* Must NOT specify a skipafter action. */
676
if (rule->actionset->skip_after != NOT_SET_P) {
677
return apr_psprintf(cmd->pool, "ModSecurity: SkipAfter actions can only "
678
"be specified by chain starter rules.");
681
/* Must NOT specify a phase. */
682
if (rule->actionset->phase != NOT_SET) {
683
return apr_psprintf(cmd->pool, "ModSecurity: Execution phases can only be "
684
"specified by chain starter rules.");
687
/* Must NOT use metadata actions. */
688
/* ENH: loop through to check for tags */
689
if ((rule->actionset->id != NOT_SET_P)
690
||(rule->actionset->rev != NOT_SET_P)
691
||(rule->actionset->msg != NOT_SET_P)
692
||(rule->actionset->severity != NOT_SET)
693
||(rule->actionset->logdata != NOT_SET_P))
695
return apr_psprintf(cmd->pool, "ModSecurity: Metadata actions (id, rev, msg, tag, severity, logdata) "
696
" can only be specified by chain starter rules.");
699
/* Must NOT use skip. */
700
if (rule->actionset->skip_count != NOT_SET) {
701
return apr_psprintf(cmd->pool, "ModSecurity: The skip action can only be used "
702
" by chain starter rules. ");
706
/* Merge actions with the parent.
708
* ENH Probably do not want this done fully for chained rules.
710
rule->actionset = msre_actionset_merge(modsecurity->msre, dcfg->tmp_default_actionset,
713
/* Keep track of the parent action for "block" */
714
rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec;
715
rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action;
717
/* Must NOT specify a disruptive action in logging phase. */
718
if ((rule->actionset != NULL)
719
&& (rule->actionset->phase == PHASE_LOGGING)
720
&& (rule->actionset->intercept_action != ACTION_ALLOW)
721
&& (rule->actionset->intercept_action != ACTION_ALLOW_REQUEST)
722
&& (rule->actionset->intercept_action != ACTION_NONE)
724
return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions "
725
"cannot be specified in the logging phase.");
728
if (dcfg->tmp_chain_starter != NULL) {
729
rule->chain_starter = dcfg->tmp_chain_starter;
730
rule->actionset->phase = rule->chain_starter->actionset->phase;
733
if (rule->actionset->is_chained != 1) {
734
/* If this rule is part of the chain but does
735
* not want more rules to follow in the chain
736
* then cut it (the chain).
738
dcfg->tmp_chain_starter = NULL;
740
/* On the other hand, if this rule wants other
741
* rules to follow it, then start a new chain
742
* if there isn't one already.
744
if (dcfg->tmp_chain_starter == NULL) {
745
dcfg->tmp_chain_starter = rule;
750
if ((rule->op_name != NULL)&&(strcasecmp(rule->op_name, "inspectFile") == 0)) {
751
dcfg->upload_validates_files = 1;
754
/* Create skip table if one does not already exist. */
755
if (dcfg->tmp_rule_placeholders == NULL) {
756
dcfg->tmp_rule_placeholders = apr_table_make(cmd->pool, 10);
757
if (dcfg->tmp_rule_placeholders == NULL) return FATAL_ERROR;
760
/* Keep track of any rule IDs we need to skip after */
761
if (rule->actionset->skip_after != NOT_SET_P) {
762
char *tmp_id = apr_pstrdup(cmd->pool, rule->actionset->skip_after);
763
apr_table_setn(dcfg->tmp_rule_placeholders, tmp_id, tmp_id);
766
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
767
"Watching for skipafter target rule id=\"%s\".", tmp_id);
773
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
774
"Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, (rule->actionset->id == NOT_SET_P
775
? "(none)" : rule->actionset->id));
778
/* Add rule to the recipe. */
779
if (msre_ruleset_rule_add(dcfg->ruleset, rule, rule->actionset->phase) < 0) {
780
return "Internal Error: Failed to add rule to the ruleset.";
783
/* Add an additional placeholder if this rule ID is on the list */
784
if ((rule->actionset->id != NULL) && apr_table_get(dcfg->tmp_rule_placeholders, rule->actionset->id)) {
785
msre_rule *phrule = apr_palloc(rule->ruleset->mp, sizeof(msre_rule));
786
if (phrule == NULL) {
791
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
792
"Adding placeholder %pp for rule %pp id=\"%s\".", phrule, rule, rule->actionset->id);
795
/* shallow copy of original rule with placeholder marked as target */
796
memcpy(phrule, rule, sizeof(msre_rule));
797
phrule->placeholder = RULE_PH_SKIPAFTER;
799
/* Add placeholder. */
800
if (msre_ruleset_rule_add(dcfg->ruleset, phrule, phrule->actionset->phase) < 0) {
801
return "Internal Error: Failed to add placeholder to the ruleset.";
804
/* No longer need to search for the ID */
805
apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id);
808
/* Update the unparsed rule */
809
rule->unparsed = msre_rule_generate_unparsed(dcfg->ruleset->mp, rule, NULL, NULL, NULL);
817
static const char *add_marker(cmd_parms *cmd, directory_config *dcfg,
818
const char *p1, const char *p2, const char *p3)
820
char *my_error_msg = NULL;
821
msre_rule *rule = NULL;
822
extern msc_engine *modsecurity;
826
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
827
"Rule: type=%d p1='%s' p2='%s' p3='%s'", RULE_TYPE_MARKER, p1, p2, p3);
830
/* Create a ruleset if one does not exist. */
831
if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) {
832
dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool);
833
if (dcfg->ruleset == NULL) return FATAL_ERROR;
836
/* Create the rule now. */
837
rule = msre_rule_create(dcfg->ruleset, RULE_TYPE_MARKER, cmd->directive->filename, cmd->directive->line_num, p1, p2, p3, &my_error_msg);
842
/* This is a marker */
843
rule->placeholder = RULE_PH_MARKER;
845
/* Add placeholder to each phase */
846
for (p = PHASE_FIRST; p <= PHASE_LAST; p++) {
848
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
849
"Adding marker %pp phase=%d id=\"%s\".", rule, p, (rule->actionset->id == NOT_SET_P
850
? "(none)" : rule->actionset->id));
853
if (msre_ruleset_rule_add(dcfg->ruleset, rule, p) < 0) {
854
return "Internal Error: Failed to add marker to the ruleset.";
858
/* No longer need to search for the ID */
859
if (dcfg->tmp_rule_placeholders != NULL) {
860
apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id);
869
static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg,
870
const char *p1, const char *p2, int offset)
872
char *my_error_msg = NULL;
873
msre_rule *rule = NULL;
874
msre_actionset *new_actionset = NULL;
875
msre_ruleset *ruleset = dcfg->ruleset;
876
extern msc_engine *modsecurity;
878
/* Get the ruleset if one exists */
879
if ((ruleset == NULL)||(ruleset == NOT_SET_P)) {
884
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
885
"Update rule id=\"%s\" with action \"%s\".", p1, p2);
889
rule = msre_ruleset_fetch_rule(ruleset, p1, offset);
892
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
893
"Update rule id=\"%s\" with action \"%s\" failed: Rule not found.", p1, p2);
898
/* Check the rule actionset */
899
/* ENH: Can this happen? */
900
if (rule->actionset == NULL) {
901
return apr_psprintf(cmd->pool, "ModSecurity: Attempt to update action for rule \"%s\" failed: Rule does not have an actionset.", p1);
904
/* Create a new actionset */
905
new_actionset = msre_actionset_create(modsecurity->msre, p2, &my_error_msg);
906
if (new_actionset == NULL) return FATAL_ERROR;
907
if (my_error_msg != NULL) return my_error_msg;
909
/* Must NOT change an id */
910
if ((new_actionset->id != NOT_SET_P) && (rule->actionset->id != NULL) && (strcmp(rule->actionset->id, new_actionset->id) != 0)) {
911
return apr_psprintf(cmd->pool, "ModSecurity: Rule IDs cannot be updated via SecRuleUpdateActionById.");
914
/* Must NOT alter the phase */
915
if ((new_actionset->phase != NOT_SET) && (rule->actionset->phase != new_actionset->phase)) {
916
return apr_psprintf(cmd->pool, "ModSecurity: Rule phases cannot be updated via SecRuleUpdateActionById.");
921
char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
922
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
923
"Update rule %pp id=\"%s\" old action: \"%s\"",
925
(rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
930
/* Merge new actions with the rule */
931
/* ENH: Will this leak the old actionset? */
932
rule->actionset = msre_actionset_merge(modsecurity->msre, rule->actionset,
934
msre_actionset_set_defaults(rule->actionset);
936
/* Update the unparsed rule */
937
rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, NULL, NULL, NULL);
941
char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
942
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
943
"Update rule %pp id=\"%s\" new action: \"%s\"",
945
(rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
953
/* -- Configuration directives -- */
955
static const char *cmd_action(cmd_parms *cmd, void *_dcfg, const char *p1)
957
return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_ACTION, SECACTION_TARGETS, SECACTION_ARGS, p1);
960
static const char *cmd_marker(cmd_parms *cmd, void *_dcfg, const char *p1)
962
directory_config *dcfg = (directory_config *)_dcfg;
963
const char *action = apr_pstrcat(dcfg->mp, SECMARKER_BASE_ACTIONS, p1, NULL);
964
return add_marker(cmd, (directory_config *)_dcfg, SECMARKER_TARGETS, SECMARKER_ARGS, action);
967
static const char *cmd_argument_separator(cmd_parms *cmd, void *_dcfg,
970
directory_config *dcfg = (directory_config *)_dcfg;
972
if (strlen(p1) != 1) {
973
return apr_psprintf(cmd->pool, "ModSecurity: Invalid argument separator: %s", p1);
976
dcfg->argument_separator = p1[0];
981
static const char *cmd_audit_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
983
directory_config *dcfg = _dcfg;
985
if (strcasecmp(p1, "On") == 0) dcfg->auditlog_flag = AUDITLOG_ON;
987
if (strcasecmp(p1, "Off") == 0) dcfg->auditlog_flag = AUDITLOG_OFF;
989
if (strcasecmp(p1, "RelevantOnly") == 0) dcfg->auditlog_flag = AUDITLOG_RELEVANT;
991
return (const char *)apr_psprintf(cmd->pool,
992
"ModSecurity: Unrecognised parameter value for SecAuditEngine: %s", p1);
997
static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1)
999
directory_config *dcfg = _dcfg;
1001
dcfg->auditlog_name = (char *)p1;
1003
if (dcfg->auditlog_name[0] == '|') {
1004
const char *pipe_name = dcfg->auditlog_name + 1;
1005
piped_log *pipe_log;
1007
pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
1008
if (pipe_log == NULL) {
1009
return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log pipe: %s",
1012
dcfg->auditlog_fd = ap_piped_log_write_fd(pipe_log);
1015
const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog_name);
1018
rc = apr_file_open(&dcfg->auditlog_fd, file_name,
1019
APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
1020
CREATEMODE, cmd->pool);
1022
if (rc != APR_SUCCESS) {
1023
return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log file: %s",
1031
static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1)
1033
directory_config *dcfg = _dcfg;
1035
if (dcfg->auditlog_name == NOT_SET_P) {
1036
return apr_psprintf(cmd->pool, "ModSecurity: Cannot configure a secondary audit log without a primary defined: %s", p1);
1039
dcfg->auditlog2_name = (char *)p1;
1041
if (dcfg->auditlog2_name[0] == '|') {
1042
const char *pipe_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name + 1);
1043
piped_log *pipe_log;
1045
pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
1046
if (pipe_log == NULL) {
1047
return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log pipe: %s",
1050
dcfg->auditlog2_fd = ap_piped_log_write_fd(pipe_log);
1053
const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name);
1056
rc = apr_file_open(&dcfg->auditlog2_fd, file_name,
1057
APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
1058
CREATEMODE, cmd->pool);
1060
if (rc != APR_SUCCESS) {
1061
return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log file: %s",
1069
static const char *cmd_audit_log_parts(cmd_parms *cmd, void *_dcfg,
1072
directory_config *dcfg = _dcfg;
1074
if (is_valid_parts_specification((char *)p1) != 1) {
1075
return apr_psprintf(cmd->pool, "Invalid parts specification for SecAuditLogParts: %s", p1);
1078
dcfg->auditlog_parts = (char *)p1;
1082
static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg,
1085
directory_config *dcfg = _dcfg;
1087
dcfg->auditlog_relevant_regex = msc_pregcomp(cmd->pool, p1, PCRE_DOTALL, NULL, NULL);
1088
if (dcfg->auditlog_relevant_regex == NULL) {
1089
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
1095
static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg,
1098
directory_config *dcfg = _dcfg;
1100
if (strcasecmp(p1, "Serial") == 0) dcfg->auditlog_type = AUDITLOG_SERIAL;
1102
if (strcasecmp(p1, "Concurrent") == 0) dcfg->auditlog_type = AUDITLOG_CONCURRENT;
1104
return (const char *)apr_psprintf(cmd->pool,
1105
"ModSecurity: Unrecognised parameter value for SecAuditLogType: %s", p1);
1110
static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg,
1113
directory_config *dcfg = (directory_config *)_dcfg;
1115
if (dcfg == NULL) return NULL;
1117
if (strcasecmp(p1, "default") == 0) {
1118
dcfg->auditlog_dirperms = NOT_SET;
1121
long int mode = strtol(p1, NULL, 8); /* expects octal mode */
1122
if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
1123
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogDirMode: %s", p1);
1126
dcfg->auditlog_dirperms = mode2fileperms(mode);
1132
static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg,
1135
directory_config *dcfg = (directory_config *)_dcfg;
1137
if (dcfg == NULL) return NULL;
1139
if (strcasecmp(p1, "default") == 0) {
1140
dcfg->auditlog_fileperms = NOT_SET;
1143
long int mode = strtol(p1, NULL, 8); /* expects octal mode */
1144
if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
1145
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogFileMode: %s", p1);
1148
dcfg->auditlog_fileperms = mode2fileperms(mode);
1154
static const char *cmd_audit_log_storage_dir(cmd_parms *cmd, void *_dcfg,
1157
directory_config *dcfg = _dcfg;
1159
dcfg->auditlog_storage_dir = ap_server_root_relative(cmd->pool, p1);
1164
static const char *cmd_cookie_format(cmd_parms *cmd, void *_dcfg,
1167
directory_config *dcfg = (directory_config *)_dcfg;
1169
if (strcmp(p1, "0") == 0) dcfg->cookie_format = COOKIES_V0;
1171
if (strcmp(p1, "1") == 0) dcfg->cookie_format = COOKIES_V1;
1173
return apr_psprintf(cmd->pool, "ModSecurity: Invalid cookie format: %s", p1);
1179
static const char *cmd_chroot_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
1181
char cwd[1025] = "";
1183
if (cmd->server->is_virtual) {
1184
return "ModSecurity: SecChrootDir not allowed in VirtualHost";
1187
chroot_dir = (char *)p1;
1189
if (getcwd(cwd, 1024) == NULL) {
1190
return "ModSecurity: Failed to get the current working directory";
1193
if (chdir(chroot_dir) < 0) {
1194
return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)",
1195
chroot_dir, errno, strerror(errno));
1198
if (chdir(cwd) < 0) {
1199
return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)",
1200
cwd, errno, strerror(errno));
1207
* Adds component signature to the list of signatures kept in configuration.
1209
static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg,
1212
directory_config *dcfg = (directory_config *)_dcfg;
1214
/* ENH Enforce "Name/VersionX.Y.Z (comment)" format. */
1215
*(char **)apr_array_push(dcfg->component_signatures) = (char *)p1;
1220
static const char *cmd_content_injection(cmd_parms *cmd, void *_dcfg, int flag)
1222
directory_config *dcfg = (directory_config *)_dcfg;
1223
if (dcfg == NULL) return NULL;
1224
dcfg->content_injection_enabled = flag;
1228
static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
1230
directory_config *dcfg = (directory_config *)_dcfg;
1232
if (cmd->server->is_virtual) {
1233
return "ModSecurity: SecDataDir not allowed in VirtualHost.";
1236
dcfg->data_dir = ap_server_root_relative(cmd->pool, p1);
1241
static const char *cmd_debug_log(cmd_parms *cmd, void *_dcfg, const char *p1)
1243
directory_config *dcfg = (directory_config *)_dcfg;
1246
dcfg->debuglog_name = ap_server_root_relative(cmd->pool, p1);
1248
rc = apr_file_open(&dcfg->debuglog_fd, dcfg->debuglog_name,
1249
APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
1250
CREATEMODE, cmd->pool);
1252
if (rc != APR_SUCCESS) {
1253
return apr_psprintf(cmd->pool, "ModSecurity: Failed to open debug log file: %s",
1254
dcfg->debuglog_name);
1260
static const char *cmd_collection_timeout(cmd_parms *cmd, void *_dcfg,
1263
directory_config *dcfg = (directory_config *)_dcfg;
1265
dcfg->col_timeout = atoi(p1);
1267
if ((dcfg->col_timeout >= 0)&&(dcfg->col_timeout <= 2592000)) return NULL;
1269
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecCollectionTimeout: %s", p1);
1272
static const char *cmd_debug_log_level(cmd_parms *cmd, void *_dcfg,
1275
directory_config *dcfg = (directory_config *)_dcfg;
1277
dcfg->debuglog_level = atoi(p1);
1278
if ((dcfg->debuglog_level >= 0)&&(dcfg->debuglog_level <= 9)) return NULL;
1280
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecDebugLogLevel: %s", p1);
1283
static const char *cmd_default_action(cmd_parms *cmd, void *_dcfg,
1286
directory_config *dcfg = (directory_config *)_dcfg;
1287
extern msc_engine *modsecurity;
1288
char *my_error_msg = NULL;
1290
dcfg->tmp_default_actionset = msre_actionset_create(modsecurity->msre, p1, &my_error_msg);
1291
if (dcfg->tmp_default_actionset == NULL) {
1292
if (my_error_msg != NULL) return my_error_msg;
1293
else return FATAL_ERROR;
1296
/* Must specify a disruptive action. */
1297
/* ENH: Remove this requirement? */
1298
if (dcfg->tmp_default_actionset->intercept_action == NOT_SET) {
1299
return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a disruptive action.");
1302
/* Must specify a phase. */
1303
/* ENH: Remove this requirement? */
1304
if (dcfg->tmp_default_actionset->phase == NOT_SET) {
1305
return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a phase.");
1308
/* Must not use metadata actions. */
1309
/* ENH: loop through to check for tags */
1310
if ((dcfg->tmp_default_actionset->id != NOT_SET_P)
1311
||(dcfg->tmp_default_actionset->rev != NOT_SET_P)
1312
||(dcfg->tmp_default_actionset->msg != NOT_SET_P))
1314
return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1315
"contain any metadata actions (id, rev, msg, tag, severity, logdata).");
1317
/* These are just a warning for now. */
1318
if ((dcfg->tmp_default_actionset->severity != NOT_SET)
1319
||(dcfg->tmp_default_actionset->logdata != NOT_SET_P))
1321
ap_log_perror(APLOG_MARK,
1322
APLOG_STARTUP|APLOG_WARNING|APLOG_NOERRNO, 0, cmd->pool,
1323
"ModSecurity: WARNING Using \"severity\" or \"logdata\" in "
1324
"SecDefaultAction is deprecated (%s:%d).",
1325
cmd->directive->filename, cmd->directive->line_num);
1328
/* Must not use chain. */
1329
if (dcfg->tmp_default_actionset->is_chained != NOT_SET) {
1330
return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1331
"contain a chain action.");
1334
/* Must not use skip. */
1335
if (dcfg->tmp_default_actionset->skip_count != NOT_SET) {
1336
return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1337
"contain a skip action.");
1340
/* Must not use skipAfter. */
1341
if (dcfg->tmp_default_actionset->skip_after != NOT_SET_P) {
1342
return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1343
"contain a skipAfter action.");
1349
static const char *cmd_disable_backend_compression(cmd_parms *cmd, void *_dcfg, int flag)
1351
directory_config *dcfg = (directory_config *)_dcfg;
1352
if (dcfg == NULL) return NULL;
1353
dcfg->disable_backend_compression = flag;
1357
static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg,
1358
const char *p1, const char *p2)
1360
extern char *guardianlog_name;
1361
extern apr_file_t *guardianlog_fd;
1362
extern char *guardianlog_condition;
1364
if (cmd->server->is_virtual) {
1365
return "ModSecurity: SecGuardianLog not allowed in VirtualHost";
1369
if (strncmp(p2, "env=", 4) != 0) {
1370
return "ModSecurity: Error in condition clause";
1372
if ( (p2[4] == '\0') || ((p2[4] == '!')&&(p2[5] == '\0')) ) {
1373
return "ModSecurity: Missing variable name";
1375
guardianlog_condition = apr_pstrdup(cmd->pool, p2 + 4);
1378
guardianlog_name = (char *)p1;
1380
if (guardianlog_name[0] == '|') {
1381
const char *pipe_name = ap_server_root_relative(cmd->pool, guardianlog_name + 1);
1382
piped_log *pipe_log;
1384
pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
1385
if (pipe_log == NULL) {
1386
return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log pipe: %s",
1389
guardianlog_fd = ap_piped_log_write_fd(pipe_log);
1392
const char *file_name = ap_server_root_relative(cmd->pool, guardianlog_name);
1395
rc = apr_file_open(&guardianlog_fd, file_name,
1396
APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
1397
CREATEMODE, cmd->pool);
1399
if (rc != APR_SUCCESS) {
1400
return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log file: %s",
1409
* \brief Add SecStreamInBodyInspection configuration option
1411
* \param cmd Pointer to configuration data
1412
* \param _dcfg Pointer to directory configuration
1413
* \param p1 Pointer to configuration option
1415
* \retval NULL On failure
1416
* \retval apr_psprintf On Success
1418
static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int flag)
1420
directory_config *dcfg = (directory_config *)_dcfg;
1421
if (dcfg == NULL) return NULL;
1422
dcfg->stream_inbody_inspection = flag;
1428
* \brief Add SecStreamOutBodyInspection configuration option
1430
* \param cmd Pointer to configuration data
1431
* \param _dcfg Pointer to directory configuration
1432
* \param p1 Pointer to configuration option
1434
* \retval NULL On failure
1435
* \retval apr_psprintf On Success
1437
static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, int flag)
1439
directory_config *dcfg = (directory_config *)_dcfg;
1440
if (dcfg == NULL) return NULL;
1441
dcfg->stream_outbody_inspection = flag;
1446
* \brief Add SecReadStateLimit configuration option
1448
* \param cmd Pointer to configuration data
1449
* \param _dcfg Pointer to directory configuration
1450
* \param p1 Pointer to configuration option
1452
* \retval NULL On failure
1453
* \retval apr_psprintf On Success
1455
static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg,
1458
directory_config *dcfg = (directory_config *)_dcfg;
1461
if (dcfg == NULL) return NULL;
1463
limit = strtol(p1, NULL, 10);
1464
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1465
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecReadStateLimit: %s", p1);
1468
conn_read_state_limit = limit;
1474
* \brief Add SecWriteStateLimit configuration option
1476
* \param cmd Pointer to configuration data
1477
* \param _dcfg Pointer to directory configuration
1478
* \param p1 Pointer to configuration option
1480
* \retval NULL On failure
1481
* \retval apr_psprintf On Success
1483
static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg,
1486
directory_config *dcfg = (directory_config *)_dcfg;
1489
if (dcfg == NULL) return NULL;
1491
limit = strtol(p1, NULL, 10);
1492
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1493
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecWriteStateLimit: %s", p1);
1496
conn_write_state_limit = limit;
1502
static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg,
1505
directory_config *dcfg = (directory_config *)_dcfg;
1508
if (dcfg == NULL) return NULL;
1510
limit = strtol(p1, NULL, 10);
1511
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1512
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyInMemoryLimit: %s", p1);
1515
dcfg->reqbody_inmemory_limit = limit;
1520
static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg,
1523
directory_config *dcfg = (directory_config *)_dcfg;
1526
if (dcfg == NULL) return NULL;
1528
limit = strtol(p1, NULL, 10);
1529
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1530
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimit: %s", p1);
1533
dcfg->reqbody_limit = limit;
1538
static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg,
1541
directory_config *dcfg = (directory_config *)_dcfg;
1544
if (dcfg == NULL) return NULL;
1546
limit = strtol(p1, NULL, 10);
1547
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1548
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyNoFilesLimit: %s", p1);
1551
dcfg->reqbody_no_files_limit = limit;
1556
static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg,
1559
directory_config *dcfg = (directory_config *)_dcfg;
1560
if (dcfg == NULL) return NULL;
1562
if (strcasecmp(p1, "on") == 0) dcfg->reqbody_access = 1;
1564
if (strcasecmp(p1, "off") == 0) dcfg->reqbody_access = 0;
1566
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyAccess: %s", p1);
1571
static const char *cmd_request_intercept_on_error(cmd_parms *cmd, void *_dcfg,
1574
directory_config *dcfg = (directory_config *)_dcfg;
1575
if (dcfg == NULL) return NULL;
1577
if (strcasecmp(p1, "on") == 0) dcfg->reqintercept_oe = 1;
1579
if (strcasecmp(p1, "off") == 0) dcfg->reqintercept_oe = 0;
1581
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecInterceptOnError: %s", p1);
1587
static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg,
1590
directory_config *dcfg = (directory_config *)_dcfg;
1591
if (dcfg == NULL) return NULL;
1593
/* ENH Validate encoding */
1595
dcfg->request_encoding = p1;
1600
static const char *cmd_response_body_access(cmd_parms *cmd, void *_dcfg,
1603
directory_config *dcfg = (directory_config *)_dcfg;
1604
if (dcfg == NULL) return NULL;
1606
if (strcasecmp(p1, "on") == 0) dcfg->resbody_access = 1;
1608
if (strcasecmp(p1, "off") == 0) dcfg->resbody_access = 0;
1610
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyAccess: %s", p1);
1615
static const char *cmd_response_body_limit(cmd_parms *cmd, void *_dcfg,
1618
directory_config *dcfg = (directory_config *)_dcfg;
1621
limit = strtol(p1, NULL, 10);
1622
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1623
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimit: %s", p1);
1626
if (limit > RESPONSE_BODY_HARD_LIMIT) {
1627
return apr_psprintf(cmd->pool, "ModSecurity: Response size limit can not exceed the hard limit: %li", RESPONSE_BODY_HARD_LIMIT);
1630
dcfg->of_limit = limit;
1635
static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg,
1638
directory_config *dcfg = (directory_config *)_dcfg;
1639
if (dcfg == NULL) return NULL;
1641
if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) {
1642
dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
1646
if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
1648
if (strcasecmp(p1, "Reject") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
1650
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimitAction: %s", p1);
1655
static const char *cmd_resquest_body_limit_action(cmd_parms *cmd, void *_dcfg,
1658
directory_config *dcfg = (directory_config *)_dcfg;
1659
if (dcfg == NULL) return NULL;
1661
if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) {
1662
dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
1666
if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
1668
if (strcasecmp(p1, "Reject") == 0) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT;
1670
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimitAction: %s", p1);
1675
static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg,
1678
directory_config *dcfg = (directory_config *)_dcfg;
1679
char *p1 = apr_pstrdup(cmd->pool, _p1);
1681
/* TODO check whether the parameter is a valid MIME type of "???" */
1683
if ((dcfg->of_mime_types == NULL)||(dcfg->of_mime_types == NOT_SET_P)) {
1684
dcfg->of_mime_types = apr_table_make(cmd->pool, 10);
1687
strtolower_inplace((unsigned char *)p1);
1688
apr_table_setn(dcfg->of_mime_types, p1, "1");
1693
static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd,
1696
directory_config *dcfg = (directory_config *)_dcfg;
1697
if (dcfg == NULL) return NULL;
1699
dcfg->of_mime_types_cleared = 1;
1701
if ((dcfg->of_mime_types != NULL)&&(dcfg->of_mime_types != NOT_SET_P)) {
1702
apr_table_clear(dcfg->of_mime_types);
1709
* \brief Add SecRuleUpdateTargetById
1711
* \param cmd Pointer to configuration data
1712
* \param _dcfg Pointer to directory configuration
1713
* \param p1 Pointer to configuration option
1714
* \param p2 Pointer to configuration option
1715
* \param p3 Pointer to configuration option
1717
* \retval NULL On failure|Success
1719
static const char *cmd_rule_update_target_by_id(cmd_parms *cmd, void *_dcfg,
1720
const char *p1, const char *p2, const char *p3)
1722
return update_rule_target(cmd, (directory_config *)_dcfg, NULL, p1, p2, p3);
1725
static const char *cmd_rule(cmd_parms *cmd, void *_dcfg,
1726
const char *p1, const char *p2, const char *p3)
1728
return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_NORMAL, p1, p2, p3);
1731
static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
1733
directory_config *dcfg = (directory_config *)_dcfg;
1734
if (dcfg == NULL) return NULL;
1736
if (strcasecmp(p1, "on") == 0) dcfg->is_enabled = MODSEC_ENABLED;
1738
if (strcasecmp(p1, "off") == 0) dcfg->is_enabled = MODSEC_DISABLED;
1740
if (strcasecmp(p1, "detectiononly") == 0) {
1741
dcfg->is_enabled = MODSEC_DETECTION_ONLY;
1742
dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
1743
dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
1745
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRuleEngine: %s", p1);
1750
static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag)
1752
directory_config *dcfg = (directory_config *)_dcfg;
1753
if (dcfg == NULL) return NULL;
1754
dcfg->rule_inheritance = flag;
1758
static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg,
1759
const char *p1, const char *p2)
1761
#if defined(WITH_LUA)
1762
const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
1763
return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL);
1765
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Ignoring SecRuleScript \"%s\" directive (%s:%d): No Lua scripting support.", p1, cmd->directive->filename, cmd->directive->line_num);
1770
static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg,
1773
directory_config *dcfg = (directory_config *)_dcfg;
1774
rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
1775
if (dcfg == NULL) return NULL;
1777
re->type = RULE_EXCEPTION_REMOVE_ID;
1779
*(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
1781
/* Remove the corresponding rules from the context straight away. */
1782
msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
1787
static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg,
1790
directory_config *dcfg = (directory_config *)_dcfg;
1791
rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
1792
if (dcfg == NULL) return NULL;
1794
re->type = RULE_EXCEPTION_REMOVE_TAG;
1796
re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
1797
if (re->param_data == NULL) {
1798
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
1800
*(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
1802
/* Remove the corresponding rules from the context straight away. */
1803
msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
1806
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Added exception %pp (%d %s) to dcfg %pp.", re, re->type, re->param, dcfg);
1812
static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg,
1815
directory_config *dcfg = (directory_config *)_dcfg;
1816
rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
1817
if (dcfg == NULL) return NULL;
1819
re->type = RULE_EXCEPTION_REMOVE_MSG;
1821
re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
1822
if (re->param_data == NULL) {
1823
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
1825
*(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
1827
/* Remove the corresponding rules from the context straight away. */
1828
msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
1831
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Added exception %pp (%d %s) to dcfg %pp.", re, re->type, re->param, dcfg);
1837
static const char *cmd_rule_update_action_by_id(cmd_parms *cmd, void *_dcfg,
1838
const char *p1, const char *p2)
1840
int offset = 0, rule_id = atoi(p1);
1841
char *opt = strchr(p1,':');
1842
char *savedptr = NULL;
1843
char *param = apr_pstrdup(cmd->pool, p1);
1845
if ((rule_id == LONG_MAX)||(rule_id == LONG_MIN)||(rule_id <= 0)) {
1846
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for ID for update action: %s", p1);
1852
opt = apr_strtok(param,":", &savedptr);
1853
return update_rule_action(cmd, (directory_config *)_dcfg, (const char *)opt, p2, offset);
1856
return update_rule_action(cmd, (directory_config *)_dcfg, p1, p2, offset);
1859
static const char *cmd_server_signature(cmd_parms *cmd, void *_dcfg,
1862
if (cmd->server->is_virtual) {
1863
return "ModSecurity: SecServerSignature not allowed in VirtualHost";
1865
new_server_signature = (char *)p1;
1869
static const char *cmd_tmp_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
1871
directory_config *dcfg = (directory_config *)_dcfg;
1873
if (dcfg == NULL) return NULL;
1875
if (strcasecmp(p1, "none") == 0) dcfg->tmp_dir = NULL;
1876
else dcfg->tmp_dir = ap_server_root_relative(cmd->pool, p1);
1881
static const char *cmd_upload_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
1883
directory_config *dcfg = (directory_config *)_dcfg;
1885
if (dcfg == NULL) return NULL;
1887
if (strcasecmp(p1, "none") == 0) dcfg->upload_dir = NULL;
1888
else dcfg->upload_dir = ap_server_root_relative(cmd->pool, p1);
1893
static const char *cmd_upload_file_limit(cmd_parms *cmd, void *_dcfg,
1896
directory_config *dcfg = (directory_config *)_dcfg;
1898
if (dcfg == NULL) return NULL;
1900
if (strcasecmp(p1, "default") == 0) {
1901
dcfg->upload_file_limit = NOT_SET;
1904
dcfg->upload_file_limit = atoi(p1);
1910
static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg,
1913
directory_config *dcfg = (directory_config *)_dcfg;
1915
if (dcfg == NULL) return NULL;
1917
if (strcasecmp(p1, "default") == 0) {
1918
dcfg->upload_filemode = NOT_SET;
1921
long int mode = strtol(p1, NULL, 8); /* expects octal mode */
1922
if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
1923
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecUploadFileMode: %s", p1);
1926
dcfg->upload_filemode = (int)mode;
1932
static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg,
1935
directory_config *dcfg = (directory_config *)_dcfg;
1937
if (dcfg == NULL) return NULL;
1939
if (strcasecmp(p1, "on") == 0) {
1940
dcfg->upload_keep_files = KEEP_FILES_ON;
1942
if (strcasecmp(p1, "off") == 0) {
1943
dcfg->upload_keep_files = KEEP_FILES_OFF;
1945
if (strcasecmp(p1, "relevantonly") == 0) {
1946
dcfg->upload_keep_files = KEEP_FILES_RELEVANT_ONLY;
1948
return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for SecUploadKeepFiles: %s",
1954
static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1)
1956
directory_config *dcfg = (directory_config *)_dcfg;
1958
/* ENH enforce format (letters, digits, ., _, -) */
1959
dcfg->webappid = p1;
1966
static const char *cmd_pcre_match_limit(cmd_parms *cmd,
1967
void *_dcfg, const char *p1)
1971
if (cmd->server->is_virtual) {
1972
return "ModSecurity: SecPcreMatchLimit not allowed in VirtualHost";
1977
return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
1978
"SecPcreMatchLimit: %s", p1);
1980
msc_pcre_match_limit = (unsigned long int)val;
1985
static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd,
1986
void *_dcfg, const char *p1)
1990
if (cmd->server->is_virtual) {
1991
return "ModSecurity: SecPcreMatchLimitRecursion not allowed in VirtualHost";
1996
return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
1997
"SecPcreMatchLimitRecursion: %s", p1);
1999
msc_pcre_match_limit_recursion = (unsigned long int)val;
2005
/* -- Geo Lookup configuration -- */
2007
static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg,
2010
const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
2012
directory_config *dcfg = (directory_config *)_dcfg;
2013
if (dcfg == NULL) return NULL;
2015
if (geo_init(dcfg, filename, &error_msg) <= 0) {
2022
/* Unicode CodePage */
2024
static const char *cmd_unicode_codepage(cmd_parms *cmd,
2025
void *_dcfg, const char *p1)
2031
return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
2032
"SecUnicodeCodePage: %s", p1);
2035
unicode_codepage = (unsigned long int)val;
2042
static const char *cmd_unicode_map(cmd_parms *cmd, void *_dcfg,
2045
const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
2047
directory_config *dcfg = (directory_config *)_dcfg;
2048
if (dcfg == NULL) return NULL;
2050
if (unicode_map_init(dcfg, filename, &error_msg) <= 0) {
2057
/* Google safe browsing */
2059
static const char *cmd_gsb_lookup_db(cmd_parms *cmd, void *_dcfg,
2062
const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
2064
directory_config *dcfg = (directory_config *)_dcfg;
2065
if (dcfg == NULL) return NULL;
2067
if (gsb_db_init(dcfg, filename, &error_msg) <= 0) {
2076
static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg,
2077
const char *p1, const char *p2)
2079
directory_config *dcfg = (directory_config *)_dcfg;
2081
if (dcfg == NULL) return NULL;
2083
if (strcasecmp(p1, "on") == 0)
2084
dcfg->cache_trans = MODSEC_CACHE_ENABLED;
2085
else if (strcasecmp(p1, "off") == 0)
2086
dcfg->cache_trans = MODSEC_CACHE_DISABLED;
2088
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecCacheTransformations: %s", p1);
2090
/* Process options */
2092
apr_table_t *vartable = apr_table_make(cmd->pool, 4);
2094
char *error_msg = NULL;
2095
const char *charval = NULL;
2096
apr_int64_t intval = 0;
2098
if (vartable == NULL) {
2099
return apr_psprintf(cmd->pool, "ModSecurity: Unable to process options for SecCacheTransformations");
2101
rc = msre_parse_generic(cmd->pool, p2, vartable, &error_msg);
2103
return apr_psprintf(cmd->pool, "ModSecurity: Unable to parse options for SecCacheTransformations: %s", error_msg);
2107
charval = apr_table_get(vartable, "incremental");
2108
if (charval != NULL) {
2109
if (strcasecmp(charval, "on") == 0)
2110
dcfg->cache_trans_incremental = 1;
2111
else if (strcasecmp(charval, "off") == 0)
2112
dcfg->cache_trans_incremental = 0;
2114
return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations invalid incremental value: %s", charval);
2118
charval = apr_table_get(vartable, "minlen");
2119
if (charval != NULL) {
2120
intval = apr_atoi64(charval);
2121
if (errno == ERANGE) {
2122
return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen out of range: %s", charval);
2125
return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be positive: %s", charval);
2128
/* The NOT_SET indicator is -1, a signed long, and therfore
2129
* we cannot be >= the unsigned value of NOT_SET.
2131
if ((unsigned long)intval >= (unsigned long)NOT_SET) {
2132
return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be less than: %lu", (unsigned long)NOT_SET);
2134
dcfg->cache_trans_min = (apr_size_t)intval;
2138
charval = apr_table_get(vartable, "maxlen");
2139
if (charval != NULL) {
2140
intval = apr_atoi64(charval);
2141
if (errno == ERANGE) {
2142
return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen out of range: %s", charval);
2145
return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be positive: %s", charval);
2148
/* The NOT_SET indicator is -1, a signed long, and therfore
2149
* we cannot be >= the unsigned value of NOT_SET.
2151
if ((unsigned long)intval >= (unsigned long)NOT_SET) {
2152
return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be less than: %lu", (unsigned long)NOT_SET);
2154
if ((intval != 0) && ((apr_size_t)intval < dcfg->cache_trans_min)) {
2155
return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must not be less than minlen: %lu < %" APR_SIZE_T_FMT, (unsigned long)intval, dcfg->cache_trans_min);
2157
dcfg->cache_trans_max = (apr_size_t)intval;
2162
charval = apr_table_get(vartable, "maxitems");
2163
if (charval != NULL) {
2164
intval = apr_atoi64(charval);
2165
if (errno == ERANGE) {
2166
return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems out of range: %s", charval);
2169
return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems must be positive: %s", charval);
2171
dcfg->cache_trans_maxitems = (apr_size_t)intval;
2179
/* -- Configuration directives definitions -- */
2181
#define CMD_SCOPE_MAIN (RSRC_CONF)
2182
#define CMD_SCOPE_ANY (RSRC_CONF | ACCESS_CONF)
2184
const command_rec module_directives[] = {
2195
"SecArgumentSeparator",
2196
cmd_argument_separator,
2199
"character that will be used as separator when parsing application/x-www-form-urlencoded content."
2207
"On, Off or RelevantOnly to determine the level of audit logging"
2215
"filename of the primary audit log file"
2223
"filename of the secondary audit log file"
2228
cmd_audit_log_parts,
2231
"list of audit log parts that go into the log."
2235
"SecAuditLogRelevantStatus",
2236
cmd_audit_log_relevant_status,
2239
"regular expression that will be used to determine if the response status is relevant for audit logging"
2247
"whether to use the old audit log format (Serial) or new (Concurrent)"
2251
"SecAuditLogStorageDir",
2252
cmd_audit_log_storage_dir,
2255
"path to the audit log storage area; absolute, or relative to the root of the server"
2259
"SecAuditLogDirMode",
2260
cmd_audit_log_dirmode,
2263
"octal permissions mode for concurrent audit log directories"
2267
"SecAuditLogFileMode",
2268
cmd_audit_log_filemode,
2271
"octal permissions mode for concurrent audit log files"
2275
"SecCacheTransformations",
2276
cmd_cache_transformations,
2279
"whether or not to cache transformations. Defaults to true."
2287
"path of the directory to which server will be chrooted"
2291
"SecComponentSignature",
2292
cmd_component_signature,
2295
"component signature to add to ModSecurity signature."
2299
"SecContentInjection",
2300
cmd_content_injection,
2307
"SecStreamOutBodyInspection",
2308
cmd_stream_outbody_inspection,
2315
"SecStreamInBodyInspection",
2316
cmd_stream_inbody_inspection,
2327
"version of the Cookie specification to use for parsing. Possible values are 0 and 1."
2335
"path to the persistent data storage area" // TODO
2343
"path to the debug log file"
2348
cmd_debug_log_level,
2351
"debug log level, which controls the verbosity of logging."
2352
" Use values from 0 (no logging) to 9 (a *lot* of logging)."
2356
"SecCollectionTimeout",
2357
cmd_collection_timeout,
2360
"set default collections timeout. default it 3600"
2368
"default action list"
2372
"SecDisableBackendCompression",
2373
cmd_disable_backend_compression,
2376
"When set to On, removes the compression headers from the backend requests."
2384
"database google safe browsing"
2388
"SecUnicodeCodePage",
2389
cmd_unicode_codepage,
2396
"SecUnicodeMapFile",
2408
"database for geographical lookups module."
2416
"The filename of the filter debugging log file"
2424
"marker for a skipAfter target"
2428
"SecPcreMatchLimit",
2429
cmd_pcre_match_limit,
2436
"SecPcreMatchLimitRecursion",
2437
cmd_pcre_match_limit_recursion,
2440
"PCRE match limit recursion"
2444
"SecRequestBodyAccess",
2445
cmd_request_body_access,
2452
"SecInterceptOnError",
2453
cmd_request_intercept_on_error,
2460
"SecReadStateLimit",
2461
cmd_conn_read_state_limit,
2464
"maximum number of threads in READ_BUSY state per ip address"
2468
"SecWriteStateLimit",
2469
cmd_conn_write_state_limit,
2472
"maximum number of threads in WRITE_BUSY state per ip address"
2476
"SecRequestBodyInMemoryLimit",
2477
cmd_request_body_inmemory_limit,
2480
"maximum request body size that will be placed in memory (except for POST urlencoded requests)."
2484
"SecRequestBodyLimit",
2485
cmd_request_body_limit,
2488
"maximum request body size ModSecurity will accept."
2492
"SecRequestBodyNoFilesLimit",
2493
cmd_request_body_no_files_limit,
2496
"maximum request body size ModSecurity will accept, but excluding the size of uploaded files."
2500
"SecRequestEncoding",
2501
cmd_request_encoding,
2504
"character encoding used in request."
2508
"SecResponseBodyAccess",
2509
cmd_response_body_access,
2516
"SecResponseBodyLimit",
2517
cmd_response_body_limit,
2520
"byte limit for response body"
2524
"SecResponseBodyLimitAction",
2525
cmd_response_body_limit_action,
2528
"what happens when the response body limit is reached"
2532
"SecRequestBodyLimitAction",
2533
cmd_resquest_body_limit_action,
2536
"what happens when the request body limit is reached"
2540
"SecResponseBodyMimeType",
2541
cmd_response_body_mime_type,
2544
"adds given MIME types to the list of types that will be buffered on output"
2548
"SecResponseBodyMimeTypesClear",
2549
cmd_response_body_mime_types_clear,
2552
"clears the list of MIME types that will be buffered on output"
2560
"rule target, operator and optional action list"
2572
"SecRuleInheritance",
2573
cmd_rule_inheritance,
2584
"rule script and optional actionlist"
2588
"SecRuleRemoveById",
2589
cmd_rule_remove_by_id,
2592
"rule ID for removal"
2596
"SecRuleRemoveByTag",
2597
cmd_rule_remove_by_tag,
2600
"rule tag for removal"
2604
"SecRuleRemoveByMsg",
2605
cmd_rule_remove_by_msg,
2608
"rule message for removal"
2612
"SecRuleUpdateActionById",
2613
cmd_rule_update_action_by_id,
2616
"updated action list"
2620
"SecRuleUpdateTargetById",
2621
cmd_rule_update_target_by_id,
2624
"updated target list"
2628
"SecServerSignature",
2629
cmd_server_signature,
2632
"the new signature of the server"
2640
"path to the temporary storage area"
2648
"path to the file upload area"
2652
"SecUploadFileLimit",
2653
cmd_upload_file_limit,
2656
"limit the number of uploaded files processed"
2660
"SecUploadFileMode",
2661
cmd_upload_filemode,
2664
"octal permissions mode for uploaded files"
2668
"SecUploadKeepFiles",
2669
cmd_upload_keep_files,