2 * ModSecurity for Apache 2.x, http://www.modsecurity.org/
3 * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/)
5 * This product is released under the terms of the General Public Licence,
6 * version 2 (GPLv2). Please refer to the file LICENSE (included with this
7 * distribution) which contains the complete text of the licence.
9 * There are special exceptions to the terms and conditions of the GPL
10 * as it is applied to this software. View the full text of the exception in
11 * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software
14 * If any of the files related to licensing are missing or if you have any
15 * other questions related to licensing please contact Breach Security, Inc.
16 * directly using the email address support@breach.com.
21 #include "modsecurity.h"
22 #include "msc_logging.h"
24 #include "pdf_protect.h"
32 /* -- Directory context creation and initialisation -- */
35 * Creates a fresh directory configuration.
37 void *create_directory_config(apr_pool_t *mp, char *path) {
38 directory_config *dcfg = (directory_config *)apr_pcalloc(mp, sizeof(directory_config));
39 if (dcfg == NULL) return NULL;
42 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Created directory config %pp path %s", dcfg, path);
46 dcfg->is_enabled = NOT_SET;
48 dcfg->reqbody_access = NOT_SET;
49 dcfg->reqbody_buffering = NOT_SET;
50 dcfg->reqbody_inmemory_limit = NOT_SET;
51 dcfg->reqbody_limit = NOT_SET;
52 dcfg->reqbody_no_files_limit = NOT_SET;
53 dcfg->resbody_access = NOT_SET;
55 dcfg->debuglog_name = NOT_SET_P;
56 dcfg->debuglog_level = NOT_SET;
57 dcfg->debuglog_fd = NOT_SET_P;
59 dcfg->of_limit = NOT_SET;
60 dcfg->of_limit_action = NOT_SET;
61 dcfg->of_mime_types = NOT_SET_P;
62 dcfg->of_mime_types_cleared = NOT_SET;
64 dcfg->cookie_format = NOT_SET;
65 dcfg->argument_separator = NOT_SET;
67 dcfg->rule_inheritance = NOT_SET;
68 dcfg->rule_exceptions = apr_array_make(mp, 16, sizeof(rule_exception *));
70 /* audit log variables */
71 dcfg->auditlog_flag = NOT_SET;
72 dcfg->auditlog_type = NOT_SET;
73 dcfg->auditlog_dirperms = NOT_SET;
74 dcfg->auditlog_fileperms = NOT_SET;
75 dcfg->auditlog_name = NOT_SET_P;
76 dcfg->auditlog2_name = NOT_SET_P;
77 dcfg->auditlog_fd = NOT_SET_P;
78 dcfg->auditlog2_fd = NOT_SET_P;
79 dcfg->auditlog_storage_dir = NOT_SET_P;
80 dcfg->auditlog_parts = NOT_SET_P;
81 dcfg->auditlog_relevant_regex = NOT_SET_P;
86 dcfg->tmp_dir = NOT_SET_P;
87 dcfg->upload_dir = NOT_SET_P;
88 dcfg->upload_keep_files = NOT_SET;
89 dcfg->upload_validates_files = NOT_SET;
90 dcfg->upload_filemode = NOT_SET;
92 /* These are only used during the configuration process. */
93 dcfg->tmp_chain_starter = NULL;
94 dcfg->tmp_default_actionset = NULL;
95 dcfg->tmp_rule_placeholders = NULL;
98 dcfg->data_dir = NOT_SET_P;
99 dcfg->webappid = NOT_SET_P;
101 /* Content injection. */
102 dcfg->content_injection_enabled = NOT_SET;
104 /* PDF XSS protection. */
105 dcfg->pdfp_enabled = NOT_SET;
106 dcfg->pdfp_secret = NOT_SET_P;
107 dcfg->pdfp_timeout = NOT_SET;
108 dcfg->pdfp_token_name = NOT_SET_P;
109 dcfg->pdfp_only_get = NOT_SET;
110 dcfg->pdfp_method = NOT_SET;
113 dcfg->geo = NOT_SET_P;
116 dcfg->cache_trans = NOT_SET;
117 dcfg->cache_trans_incremental = NOT_SET;
118 dcfg->cache_trans_min = NOT_SET;
119 dcfg->cache_trans_max = NOT_SET;
120 dcfg->cache_trans_maxitems = NOT_SET;
122 dcfg->component_signatures = apr_array_make(mp, 16, sizeof(char *));
124 dcfg->request_encoding = NOT_SET_P;
130 * Copies rules between one phase of two configuration contexts,
131 * taking exceptions into account.
133 static void copy_rules_phase(apr_pool_t *mp, apr_array_header_t *parent_phase_arr,
134 apr_array_header_t *child_phase_arr, apr_array_header_t *exceptions_arr)
136 rule_exception **exceptions;
141 rules = (msre_rule **)parent_phase_arr->elts;
142 for(i = 0; i < parent_phase_arr->nelts; i++) {
143 msre_rule *rule = (msre_rule *)rules[i];
147 /* First rule in the chain. */
148 exceptions = (rule_exception **)exceptions_arr->elts;
149 for(j = 0; j < exceptions_arr->nelts; j++) {
151 /* Process exceptions. */
152 switch(exceptions[j]->type) {
153 case RULE_EXCEPTION_REMOVE_ID :
154 if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) {
155 int ruleid = atoi(rule->actionset->id);
156 if (rule_id_in_range(ruleid, exceptions[j]->param)) copy--;
159 case RULE_EXCEPTION_REMOVE_MSG :
160 if ((rule->actionset != NULL)&&(rule->actionset->msg != NULL)) {
161 char *my_error_msg = NULL;
163 int rc = msc_regexec(exceptions[j]->param_data,
164 rule->actionset->msg, strlen(rule->actionset->msg),
174 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, rule->actionset->id);
178 *(msre_rule **)apr_array_push(child_phase_arr) = rule;
179 if (rule->actionset->is_chained) mode = 2;
181 if (rule->actionset->is_chained) mode = 1;
186 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);
189 /* Copy the rule (it belongs to the chain we want to include. */
190 *(msre_rule **)apr_array_push(child_phase_arr) = rule;
193 if ((rule->actionset == NULL)||(rule->actionset->is_chained == 0)) mode = 0;
199 * Copies rules between two configuration contexts,
200 * taking exceptions into account.
202 static int copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset, msre_ruleset *child_ruleset,
203 apr_array_header_t *exceptions_arr)
205 copy_rules_phase(mp, parent_ruleset->phase_request_headers,
206 child_ruleset->phase_request_headers, exceptions_arr);
207 copy_rules_phase(mp, parent_ruleset->phase_request_body,
208 child_ruleset->phase_request_body, exceptions_arr);
209 copy_rules_phase(mp, parent_ruleset->phase_response_headers,
210 child_ruleset->phase_response_headers, exceptions_arr);
211 copy_rules_phase(mp, parent_ruleset->phase_response_body,
212 child_ruleset->phase_response_body, exceptions_arr);
213 copy_rules_phase(mp, parent_ruleset->phase_logging,
214 child_ruleset->phase_logging, exceptions_arr);
220 * Merges two directory configurations.
222 void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) {
223 directory_config *parent = (directory_config *)_parent;
224 directory_config *child = (directory_config *)_child;
225 directory_config *merged = create_directory_config(mp, NULL);
228 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Merge parent %pp child %pp RESULT %pp", _parent, _child, merged);
231 if (merged == NULL) return NULL;
233 /* Use values from the child configuration where possible,
234 * otherwise use the parent's.
237 merged->is_enabled = (child->is_enabled == NOT_SET
238 ? parent->is_enabled : child->is_enabled);
241 merged->reqbody_access = (child->reqbody_access == NOT_SET
242 ? parent->reqbody_access : child->reqbody_access);
243 merged->reqbody_buffering = (child->reqbody_buffering == NOT_SET
244 ? parent->reqbody_buffering : child->reqbody_buffering);
245 merged->reqbody_inmemory_limit = (child->reqbody_inmemory_limit == NOT_SET
246 ? parent->reqbody_inmemory_limit : child->reqbody_inmemory_limit);
247 merged->reqbody_limit = (child->reqbody_limit == NOT_SET
248 ? parent->reqbody_limit : child->reqbody_limit);
249 merged->reqbody_no_files_limit = (child->reqbody_no_files_limit == NOT_SET
250 ? parent->reqbody_no_files_limit : child->reqbody_no_files_limit);
251 merged->resbody_access = (child->resbody_access == NOT_SET
252 ? parent->resbody_access : child->resbody_access);
254 merged->of_limit = (child->of_limit == NOT_SET
255 ? parent->of_limit : child->of_limit);
256 merged->of_limit_action = (child->of_limit_action == NOT_SET
257 ? parent->of_limit_action : child->of_limit_action);
259 if (child->of_mime_types != NOT_SET_P) {
260 /* Child added to the table */
262 if (child->of_mime_types_cleared == 1) {
263 /* The list of MIME types was cleared in the child,
264 * which means the parent's MIME types went away and
265 * we should not take them into consideration here.
267 merged->of_mime_types = child->of_mime_types;
268 merged->of_mime_types_cleared = 1;
270 /* Add MIME types defined in the child to those
271 * defined in the parent context.
273 if (parent->of_mime_types == NOT_SET_P) {
274 merged->of_mime_types = child->of_mime_types;
275 merged->of_mime_types_cleared = NOT_SET;
277 merged->of_mime_types = apr_table_overlay(mp, parent->of_mime_types,
278 child->of_mime_types);
279 if (merged->of_mime_types == NULL) return NULL;
283 /* Child did not add to the table */
285 if (child->of_mime_types_cleared == 1) {
286 merged->of_mime_types_cleared = 1;
288 merged->of_mime_types = parent->of_mime_types;
289 merged->of_mime_types_cleared = parent->of_mime_types_cleared;
294 if (child->debuglog_fd == NOT_SET_P) {
295 merged->debuglog_name = parent->debuglog_name;
296 merged->debuglog_fd = parent->debuglog_fd;
298 merged->debuglog_name = child->debuglog_name;
299 merged->debuglog_fd = child->debuglog_fd;
302 merged->debuglog_level = (child->debuglog_level == NOT_SET
303 ? parent->debuglog_level : child->debuglog_level);
305 merged->cookie_format = (child->cookie_format == NOT_SET
306 ? parent->cookie_format : child->cookie_format);
307 merged->argument_separator = (child->argument_separator == NOT_SET
308 ? parent->argument_separator : child->argument_separator);
311 /* rule inheritance */
312 if ((child->rule_inheritance == NOT_SET)||(child->rule_inheritance == 1)) {
313 merged->rule_inheritance = parent->rule_inheritance;
314 if ((child->ruleset == NULL)&&(parent->ruleset == NULL)) {
316 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "No rules in this context.");
319 /* Do nothing, there are no rules in either context. */
321 if (child->ruleset == NULL) {
323 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent rules in this context.");
326 /* Copy the rules from the parent context. */
327 merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp);
328 copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions);
330 if (parent->ruleset == NULL) {
332 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using child rules in this context.");
335 /* Copy child rules. */
336 merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp);
337 merged->ruleset->phase_request_headers = apr_array_copy(mp,
338 child->ruleset->phase_request_headers);
339 merged->ruleset->phase_request_body = apr_array_copy(mp,
340 child->ruleset->phase_request_body);
341 merged->ruleset->phase_response_headers = apr_array_copy(mp,
342 child->ruleset->phase_response_headers);
343 merged->ruleset->phase_response_body = apr_array_copy(mp,
344 child->ruleset->phase_response_body);
345 merged->ruleset->phase_logging = apr_array_copy(mp,
346 child->ruleset->phase_logging);
349 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent then child rules in this context.");
352 /* Copy parent rules, then add child rules to it. */
353 merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp);
354 copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions);
356 apr_array_cat(merged->ruleset->phase_request_headers,
357 child->ruleset->phase_request_headers);
358 apr_array_cat(merged->ruleset->phase_request_body,
359 child->ruleset->phase_request_body);
360 apr_array_cat(merged->ruleset->phase_response_headers,
361 child->ruleset->phase_response_headers);
362 apr_array_cat(merged->ruleset->phase_response_body,
363 child->ruleset->phase_response_body);
364 apr_array_cat(merged->ruleset->phase_logging,
365 child->ruleset->phase_logging);
368 merged->rule_inheritance = 0;
369 if (child->ruleset != NULL) {
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);
385 /* Merge rule exceptions. */
386 merged->rule_exceptions = apr_array_append(mp, parent->rule_exceptions,
387 child->rule_exceptions);
389 /* audit log variables */
390 merged->auditlog_flag = (child->auditlog_flag == NOT_SET
391 ? parent->auditlog_flag : child->auditlog_flag);
392 merged->auditlog_type = (child->auditlog_type == NOT_SET
393 ? parent->auditlog_type : child->auditlog_type);
394 merged->auditlog_dirperms = (child->auditlog_dirperms == NOT_SET
395 ? parent->auditlog_dirperms : child->auditlog_dirperms);
396 merged->auditlog_fileperms = (child->auditlog_fileperms == NOT_SET
397 ? parent->auditlog_fileperms : child->auditlog_fileperms);
398 if (child->auditlog_fd != NOT_SET_P) {
399 merged->auditlog_fd = child->auditlog_fd;
400 merged->auditlog_name = child->auditlog_name;
402 merged->auditlog_fd = parent->auditlog_fd;
403 merged->auditlog_name = parent->auditlog_name;
405 if (child->auditlog2_fd != NOT_SET_P) {
406 merged->auditlog2_fd = child->auditlog2_fd;
407 merged->auditlog2_name = child->auditlog2_name;
409 merged->auditlog2_fd = parent->auditlog2_fd;
410 merged->auditlog2_name = parent->auditlog2_name;
412 merged->auditlog_storage_dir = (child->auditlog_storage_dir == NOT_SET_P
413 ? parent->auditlog_storage_dir : child->auditlog_storage_dir);
414 merged->auditlog_parts = (child->auditlog_parts == NOT_SET_P
415 ? parent->auditlog_parts : child->auditlog_parts);
416 merged->auditlog_relevant_regex = (child->auditlog_relevant_regex == NOT_SET_P
417 ? parent->auditlog_relevant_regex : child->auditlog_relevant_regex);
420 merged->tmp_dir = (child->tmp_dir == NOT_SET_P
421 ? parent->tmp_dir : child->tmp_dir);
422 merged->upload_dir = (child->upload_dir == NOT_SET_P
423 ? parent->upload_dir : child->upload_dir);
424 merged->upload_keep_files = (child->upload_keep_files == NOT_SET
425 ? parent->upload_keep_files : child->upload_keep_files);
426 merged->upload_validates_files = (child->upload_validates_files == NOT_SET
427 ? parent->upload_validates_files : child->upload_validates_files);
428 merged->upload_filemode = (child->upload_filemode == NOT_SET
429 ? parent->upload_filemode : child->upload_filemode);
432 merged->data_dir = (child->data_dir == NOT_SET_P
433 ? parent->data_dir : child->data_dir);
434 merged->webappid = (child->webappid == NOT_SET_P
435 ? parent->webappid : child->webappid);
437 /* Content injection. */
438 merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET
439 ? parent->content_injection_enabled : child->content_injection_enabled);
441 /* PDF XSS protection. */
442 merged->pdfp_enabled = (child->pdfp_enabled == NOT_SET
443 ? parent->pdfp_enabled : child->pdfp_enabled);
444 merged->pdfp_secret = (child->pdfp_secret == NOT_SET_P
445 ? parent->pdfp_secret : child->pdfp_secret);
446 merged->pdfp_timeout = (child->pdfp_timeout == NOT_SET
447 ? parent->pdfp_timeout : child->pdfp_timeout);
448 merged->pdfp_token_name = (child->pdfp_token_name == NOT_SET_P
449 ? parent->pdfp_token_name : child->pdfp_token_name);
450 merged->pdfp_only_get = (child->pdfp_only_get == NOT_SET
451 ? parent->pdfp_only_get : child->pdfp_only_get);
452 merged->pdfp_method = (child->pdfp_method == NOT_SET
453 ? parent->pdfp_method : child->pdfp_method);
456 merged->geo = (child->geo == NOT_SET_P
457 ? parent->geo : child->geo);
460 merged->cache_trans = (child->cache_trans == NOT_SET
461 ? parent->cache_trans : child->cache_trans);
462 merged->cache_trans_incremental = (child->cache_trans_incremental == NOT_SET
463 ? parent->cache_trans_incremental : child->cache_trans_incremental);
464 merged->cache_trans_min = (child->cache_trans_min == (apr_size_t)NOT_SET
465 ? parent->cache_trans_min : child->cache_trans_min);
466 merged->cache_trans_max = (child->cache_trans_max == (apr_size_t)NOT_SET
467 ? parent->cache_trans_max : child->cache_trans_max);
468 merged->cache_trans_maxitems = (child->cache_trans_maxitems == (apr_size_t)NOT_SET
469 ? parent->cache_trans_maxitems : child->cache_trans_maxitems);
471 /* Merge component signatures. */
472 merged->component_signatures = apr_array_append(mp, parent->component_signatures,
473 child->component_signatures);
475 merged->request_encoding = (child->request_encoding == NOT_SET_P
476 ? parent->request_encoding : child->request_encoding);
482 * Initialise directory configuration. This function is *not* meant
483 * to be called for directory configuration instances created during
484 * the configuration phase. It can only be called on copies of those
485 * (created fresh for every transaction).
487 void init_directory_config(directory_config *dcfg) {
488 if (dcfg == NULL) return;
490 if (dcfg->is_enabled == NOT_SET) dcfg->is_enabled = 0;
492 if (dcfg->reqbody_access == NOT_SET) dcfg->reqbody_access = 0;
493 if (dcfg->reqbody_buffering == NOT_SET) dcfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_OFF;
494 if (dcfg->reqbody_inmemory_limit == NOT_SET)
495 dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT;
496 if (dcfg->reqbody_limit == NOT_SET) dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT;
497 if (dcfg->reqbody_no_files_limit == NOT_SET) dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT;
498 if (dcfg->resbody_access == NOT_SET) dcfg->resbody_access = 0;
499 if (dcfg->of_limit == NOT_SET) dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT;
500 if (dcfg->of_limit_action == NOT_SET) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
502 if (dcfg->of_mime_types == NOT_SET_P) {
503 dcfg->of_mime_types = apr_table_make(dcfg->mp, 3);
504 if (dcfg->of_mime_types_cleared != 1) {
505 apr_table_setn(dcfg->of_mime_types, "text/plain", "1");
506 apr_table_setn(dcfg->of_mime_types, "text/html", "1");
510 if (dcfg->debuglog_fd == NOT_SET_P) dcfg->debuglog_fd = NULL;
511 if (dcfg->debuglog_name == NOT_SET_P) dcfg->debuglog_name = NULL;
512 if (dcfg->debuglog_level == NOT_SET) dcfg->debuglog_level = 0;
514 if (dcfg->cookie_format == NOT_SET) dcfg->cookie_format = 0;
515 if (dcfg->argument_separator == NOT_SET) dcfg->argument_separator = '&';
517 if (dcfg->rule_inheritance == NOT_SET) dcfg->rule_inheritance = 1;
519 /* audit log variables */
520 if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0;
521 if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL;
522 if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR;
523 if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE;
524 if (dcfg->auditlog_fd == NOT_SET_P) dcfg->auditlog_fd = NULL;
525 if (dcfg->auditlog2_fd == NOT_SET_P) dcfg->auditlog2_fd = NULL;
526 if (dcfg->auditlog_name == NOT_SET_P) dcfg->auditlog_name = NULL;
527 if (dcfg->auditlog2_name == NOT_SET_P) dcfg->auditlog2_name = NULL;
528 if (dcfg->auditlog_storage_dir == NOT_SET_P) dcfg->auditlog_storage_dir = NULL;
529 if (dcfg->auditlog_parts == NOT_SET_P) dcfg->auditlog_parts = "ABCFHZ";
530 if (dcfg->auditlog_relevant_regex == NOT_SET_P) dcfg->auditlog_relevant_regex = NULL;
533 if (dcfg->tmp_dir == NOT_SET_P) dcfg->tmp_dir = guess_tmp_dir(dcfg->mp);
534 if (dcfg->upload_dir == NOT_SET_P) dcfg->upload_dir = NULL;
535 if (dcfg->upload_keep_files == NOT_SET) dcfg->upload_keep_files = KEEP_FILES_OFF;
536 if (dcfg->upload_validates_files == NOT_SET) dcfg->upload_validates_files = 0;
537 if (dcfg->upload_filemode == NOT_SET) dcfg->upload_filemode = mode2fileperms(0600);
540 if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL;
541 if (dcfg->webappid == NOT_SET_P) dcfg->webappid = "default";
543 /* Content injection. */
544 if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0;
546 /* PDF XSS protection. */
547 if (dcfg->pdfp_enabled == NOT_SET) dcfg->pdfp_enabled = 0;
548 if (dcfg->pdfp_secret == NOT_SET_P) dcfg->pdfp_secret = NULL;
549 if (dcfg->pdfp_timeout == NOT_SET) dcfg->pdfp_timeout = 10;
550 if (dcfg->pdfp_token_name == NOT_SET_P) dcfg->pdfp_token_name = "PDFPTOKEN";
551 if (dcfg->pdfp_only_get == NOT_SET) dcfg->pdfp_only_get = 1;
552 if (dcfg->pdfp_method == NOT_SET) dcfg->pdfp_method = PDF_PROTECT_METHOD_TOKEN_REDIRECTION;
555 if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL;
558 if (dcfg->cache_trans == NOT_SET) dcfg->cache_trans = MODSEC_CACHE_DISABLED;
559 if (dcfg->cache_trans_incremental == NOT_SET) dcfg->cache_trans_incremental = 0;
560 if (dcfg->cache_trans_min == (apr_size_t)NOT_SET) dcfg->cache_trans_min = 32;
561 if (dcfg->cache_trans_max == (apr_size_t)NOT_SET) dcfg->cache_trans_max = 1024;
562 if (dcfg->cache_trans_maxitems == (apr_size_t)NOT_SET) dcfg->cache_trans_maxitems = 512;
564 if (dcfg->request_encoding == NOT_SET_P) dcfg->request_encoding = NULL;
570 static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
571 const char *p1, const char *p2, const char *p3)
573 char *my_error_msg = NULL;
574 msre_rule *rule = NULL;
575 extern msc_engine *modsecurity;
578 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
579 "Rule: type=%d p1='%s' p2='%s' p3='%s'", type, p1, p2, p3);
582 /* Create a ruleset if one does not exist. */
583 if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) {
584 dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool);
585 if (dcfg->ruleset == NULL) return FATAL_ERROR;
588 /* Create the rule now. */
590 #if defined(WITH_LUA)
592 rule = msre_rule_lua_create(dcfg->ruleset, cmd->directive->filename,
593 cmd->directive->line_num, p1, p2, &my_error_msg);
597 rule = msre_rule_create(dcfg->ruleset, type, cmd->directive->filename,
598 cmd->directive->line_num, p1, p2, p3, &my_error_msg);
606 /* Create default actionset if one does not already exist. */
607 if (dcfg->tmp_default_actionset == NULL) {
608 dcfg->tmp_default_actionset = msre_actionset_create_default(modsecurity->msre);
609 if (dcfg->tmp_default_actionset == NULL) return FATAL_ERROR;
612 /* Check some cases prior to merging so we know where it came from */
614 /* Check syntax for chained rules */
615 if ((rule->actionset != NULL) && (dcfg->tmp_chain_starter != NULL)) {
616 /* Must NOT specify a disruptive action. */
617 if (rule->actionset->intercept_action != NOT_SET) {
618 return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions can only "
619 "be specified by chain starter rules.");
622 /* Must NOT specify a phase. */
623 if (rule->actionset->phase != NOT_SET) {
624 return apr_psprintf(cmd->pool, "ModSecurity: Execution phases can only be "
625 "specified by chain starter rules.");
628 /* Must NOT use metadata actions. */
629 /* ENH: loop through to check for tags */
630 if ((rule->actionset->id != NOT_SET_P)
631 ||(rule->actionset->rev != NOT_SET_P)
632 ||(rule->actionset->msg != NOT_SET_P)
633 ||(rule->actionset->severity != NOT_SET)
634 ||(rule->actionset->logdata != NOT_SET_P))
636 return apr_psprintf(cmd->pool, "ModSecurity: Metadata actions (id, rev, msg, tag, severity, logdata) "
637 " can only be specified by chain starter rules.");
640 /* Must NOT use skip. */
641 if (rule->actionset->skip_count != NOT_SET) {
642 return apr_psprintf(cmd->pool, "ModSecurity: The skip action can only be used "
643 " by chain starter rules. ");
647 /* Merge actions with the parent.
649 * ENH Probably do not want this done fully for chained rules.
651 rule->actionset = msre_actionset_merge(modsecurity->msre, dcfg->tmp_default_actionset,
654 /* Keep track of the parent action for "block" */
655 rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec;
656 rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action;
658 /* Must NOT specify a disruptive action in logging phase. */
659 if ((rule->actionset != NULL)
660 && (rule->actionset->phase == PHASE_LOGGING)
661 && (rule->actionset->intercept_action != ACTION_ALLOW)
662 && (rule->actionset->intercept_action != ACTION_ALLOW_REQUEST)
663 && (rule->actionset->intercept_action != ACTION_NONE)
665 return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions "
666 "cannot be specified in the logging phase.");
669 if (dcfg->tmp_chain_starter != NULL) {
670 rule->chain_starter = dcfg->tmp_chain_starter;
671 rule->actionset->phase = rule->chain_starter->actionset->phase;
674 if (rule->actionset->is_chained != 1) {
675 /* If this rule is part of the chain but does
676 * not want more rules to follow in the chain
677 * then cut it (the chain).
679 dcfg->tmp_chain_starter = NULL;
681 /* On the other hand, if this rule wants other
682 * rules to follow it, then start a new chain
683 * if there isn't one already.
685 if (dcfg->tmp_chain_starter == NULL) {
686 dcfg->tmp_chain_starter = rule;
691 if ((rule->op_name != NULL)&&(strcasecmp(rule->op_name, "inspectFile") == 0)) {
692 dcfg->upload_validates_files = 1;
695 /* Create skip table if one does not already exist. */
696 if (dcfg->tmp_rule_placeholders == NULL) {
697 dcfg->tmp_rule_placeholders = apr_table_make(cmd->pool, 10);
698 if (dcfg->tmp_rule_placeholders == NULL) return FATAL_ERROR;
701 /* Keep track of any rule IDs we need to skip after */
702 if (rule->actionset->skip_after != NOT_SET_P) {
703 char *tmp_id = apr_pstrdup(cmd->pool, rule->actionset->skip_after);
704 apr_table_setn(dcfg->tmp_rule_placeholders, tmp_id, tmp_id);
707 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
708 "Watching for skipafter target rule id=\"%s\".", tmp_id);
714 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
715 "Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, (rule->actionset->id == NOT_SET_P
716 ? "(none)" : rule->actionset->id));
719 /* Add rule to the recipe. */
720 if (msre_ruleset_rule_add(dcfg->ruleset, rule, rule->actionset->phase) < 0) {
721 return "Internal Error: Failed to add rule to the ruleset.";
724 /* Add an additional placeholder if this rule ID is on the list */
725 if ((rule->actionset->id != NULL) && apr_table_get(dcfg->tmp_rule_placeholders, rule->actionset->id)) {
726 msre_rule *phrule = apr_palloc(rule->ruleset->mp, sizeof(msre_rule));
727 if (phrule == NULL) {
732 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
733 "Adding placeholder %pp for rule %pp id=\"%s\".", phrule, rule, rule->actionset->id);
736 /* shallow copy of original rule with placeholder marked as target */
737 memcpy(phrule, rule, sizeof(msre_rule));
738 phrule->placeholder = RULE_PH_SKIPAFTER;
740 /* Add placeholder. */
741 if (msre_ruleset_rule_add(dcfg->ruleset, phrule, phrule->actionset->phase) < 0) {
742 return "Internal Error: Failed to add placeholder to the ruleset.";
745 /* No longer need to search for the ID */
746 apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id);
749 /* Update the unparsed rule */
750 rule->unparsed = msre_rule_generate_unparsed(dcfg->ruleset->mp, rule, NULL, NULL, NULL);
758 static const char *add_marker(cmd_parms *cmd, directory_config *dcfg, const char *p1,
759 const char *p2, const char *p3)
761 char *my_error_msg = NULL;
762 msre_rule *rule = NULL;
763 extern msc_engine *modsecurity;
767 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
768 "Rule: type=%d p1='%s' p2='%s' p3='%s'", RULE_TYPE_MARKER, p1, p2, p3);
771 /* Create a ruleset if one does not exist. */
772 if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) {
773 dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool);
774 if (dcfg->ruleset == NULL) return FATAL_ERROR;
777 /* Create the rule now. */
778 rule = msre_rule_create(dcfg->ruleset, RULE_TYPE_MARKER, cmd->directive->filename, cmd->directive->line_num, p1, p2, p3, &my_error_msg);
783 /* This is a marker */
784 rule->placeholder = RULE_PH_MARKER;
786 /* Add placeholder to each phase */
787 for (p = PHASE_FIRST; p <= PHASE_LAST; p++) {
789 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
790 "Adding marker %pp phase=%d id=\"%s\".", rule, p, (rule->actionset->id == NOT_SET_P
791 ? "(none)" : rule->actionset->id));
794 if (msre_ruleset_rule_add(dcfg->ruleset, rule, p) < 0) {
795 return "Internal Error: Failed to add marker to the ruleset.";
799 /* No longer need to search for the ID */
800 if (dcfg->tmp_rule_placeholders != NULL) {
801 apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id);
810 static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg,
811 const char *p1, const char *p2)
813 char *my_error_msg = NULL;
814 msre_rule *rule = NULL;
815 msre_actionset *new_actionset = NULL;
816 msre_ruleset *ruleset = dcfg->ruleset;
817 extern msc_engine *modsecurity;
819 /* Get the ruleset if one exists */
820 if ((ruleset == NULL)||(ruleset == NOT_SET_P)) {
825 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
826 "Update rule id=\"%s\" with action \"%s\".", p1, p2);
830 rule = msre_ruleset_fetch_rule(ruleset, p1);
833 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
834 "Update rule id=\"%s\" with action \"%s\" failed: Rule not found.", p1, p2);
839 /* Check the rule actionset */
840 /* ENH: Can this happen? */
841 if (rule->actionset == NULL) {
842 return apr_psprintf(cmd->pool, "ModSecurity: Attempt to update action for rule \"%s\" failed: Rule does not have an actionset.", p1);
845 /* Create a new actionset */
846 new_actionset = msre_actionset_create(modsecurity->msre, p2, &my_error_msg);
847 if (new_actionset == NULL) return FATAL_ERROR;
848 if (my_error_msg != NULL) return my_error_msg;
850 /* Must NOT change an id */
851 if ((new_actionset->id != NOT_SET_P) && (rule->actionset->id != NULL) && (strcmp(rule->actionset->id, new_actionset->id) != 0)) {
852 return apr_psprintf(cmd->pool, "ModSecurity: Rule IDs cannot be updated via SecRuleUpdateActionById.");
855 /* Must NOT alter the phase */
856 if ((new_actionset->phase != NOT_SET) && (rule->actionset->phase != new_actionset->phase)) {
857 return apr_psprintf(cmd->pool, "ModSecurity: Rule phases cannot be updated via SecRuleUpdateActionById.");
862 char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
863 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
864 "Update rule %pp id=\"%s\" old action: \"%s\"",
866 (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
871 /* Merge new actions with the rule */
872 /* ENH: Will this leak the old actionset? */
873 rule->actionset = msre_actionset_merge(modsecurity->msre, rule->actionset,
875 msre_actionset_set_defaults(rule->actionset);
877 /* Update the unparsed rule */
878 rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, NULL, NULL, NULL);
882 char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
883 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
884 "Update rule %pp id=\"%s\" new action: \"%s\"",
886 (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
894 /* -- Configuration directives -- */
896 static const char *cmd_action(cmd_parms *cmd, void *_dcfg, const char *p1) {
897 return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_ACTION, SECACTION_TARGETS, SECACTION_ARGS, p1);
900 static const char *cmd_marker(cmd_parms *cmd, void *_dcfg, const char *p1) {
901 directory_config *dcfg = (directory_config *)_dcfg;
902 const char *action = apr_pstrcat(dcfg->mp, SECMARKER_BASE_ACTIONS, p1, NULL);
903 return add_marker(cmd, (directory_config *)_dcfg, SECMARKER_TARGETS, SECMARKER_ARGS, action);
906 static const char *cmd_argument_separator(cmd_parms *cmd, void *_dcfg, const char *p1) {
907 directory_config *dcfg = (directory_config *)_dcfg;
909 if (strlen(p1) != 1) {
910 return apr_psprintf(cmd->pool, "ModSecurity: Invalid argument separator: %s", p1);
913 dcfg->argument_separator = p1[0];
918 static const char *cmd_audit_engine(cmd_parms *cmd, void *_dcfg, const char *p1) {
919 directory_config *dcfg = _dcfg;
921 if (strcasecmp(p1, "On") == 0) dcfg->auditlog_flag = AUDITLOG_ON;
923 if (strcasecmp(p1, "Off") == 0) dcfg->auditlog_flag = AUDITLOG_OFF;
925 if (strcasecmp(p1, "RelevantOnly") == 0) dcfg->auditlog_flag = AUDITLOG_RELEVANT;
927 return (const char *)apr_psprintf(cmd->pool,
928 "ModSecurity: Unrecognised parameter value for SecAuditEngine: %s", p1);
933 static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1) {
934 directory_config *dcfg = _dcfg;
936 dcfg->auditlog_name = (char *)p1;
938 if (dcfg->auditlog_name[0] == '|') {
939 const char *pipe_name = ap_server_root_relative(cmd->pool, dcfg->auditlog_name + 1);
942 pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
943 if (pipe_log == NULL) {
944 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log pipe: %s",
947 dcfg->auditlog_fd = ap_piped_log_write_fd(pipe_log);
950 const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog_name);
953 rc = apr_file_open(&dcfg->auditlog_fd, file_name,
954 APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
955 CREATEMODE, cmd->pool);
957 if (rc != APR_SUCCESS) {
958 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log file: %s",
966 static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1) {
967 directory_config *dcfg = _dcfg;
969 if (dcfg->auditlog_name == NOT_SET_P) {
970 return apr_psprintf(cmd->pool, "ModSecurity: Cannot configure a secondary audit log without a primary defined: %s", p1);
973 dcfg->auditlog2_name = (char *)p1;
975 if (dcfg->auditlog2_name[0] == '|') {
976 const char *pipe_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name + 1);
979 pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
980 if (pipe_log == NULL) {
981 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log pipe: %s",
984 dcfg->auditlog2_fd = ap_piped_log_write_fd(pipe_log);
987 const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name);
990 rc = apr_file_open(&dcfg->auditlog2_fd, file_name,
991 APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
992 CREATEMODE, cmd->pool);
994 if (rc != APR_SUCCESS) {
995 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log file: %s",
1003 static const char *cmd_audit_log_parts(cmd_parms *cmd, void *_dcfg, const char *p1) {
1004 directory_config *dcfg = _dcfg;
1006 if (is_valid_parts_specification((char *)p1) != 1) {
1007 return apr_psprintf(cmd->pool, "Invalid parts specification for SecAuditLogParts: %s", p1);
1010 dcfg->auditlog_parts = (char *)p1;
1014 static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg, const char *p1) {
1015 directory_config *dcfg = _dcfg;
1017 dcfg->auditlog_relevant_regex = msc_pregcomp(cmd->pool, p1, PCRE_DOTALL, NULL, NULL);
1018 if (dcfg->auditlog_relevant_regex == NULL) {
1019 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
1025 static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg, const char *p1) {
1026 directory_config *dcfg = _dcfg;
1028 if (strcasecmp(p1, "Serial") == 0) dcfg->auditlog_type = AUDITLOG_SERIAL;
1030 if (strcasecmp(p1, "Concurrent") == 0) dcfg->auditlog_type = AUDITLOG_CONCURRENT;
1032 return (const char *)apr_psprintf(cmd->pool,
1033 "ModSecurity: Unrecognised parameter value for SecAuditLogType: %s", p1);
1038 static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg, const char *p1) {
1039 directory_config *dcfg = (directory_config *)_dcfg;
1041 if (dcfg == NULL) return NULL;
1043 if (strcasecmp(p1, "default") == 0) {
1044 dcfg->auditlog_dirperms = NOT_SET;
1047 long int mode = strtol(p1, NULL, 8); /* expects octal mode */
1048 if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
1049 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogDirMode: %s", p1);
1052 dcfg->auditlog_dirperms = mode2fileperms(mode);
1058 static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg, const char *p1) {
1059 directory_config *dcfg = (directory_config *)_dcfg;
1061 if (dcfg == NULL) return NULL;
1063 if (strcasecmp(p1, "default") == 0) {
1064 dcfg->auditlog_fileperms = NOT_SET;
1067 long int mode = strtol(p1, NULL, 8); /* expects octal mode */
1068 if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
1069 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogFileMode: %s", p1);
1072 dcfg->auditlog_fileperms = mode2fileperms(mode);
1078 static const char *cmd_audit_log_storage_dir(cmd_parms *cmd, void *_dcfg, const char *p1) {
1079 directory_config *dcfg = _dcfg;
1081 dcfg->auditlog_storage_dir = ap_server_root_relative(cmd->pool, p1);
1086 static const char *cmd_cookie_format(cmd_parms *cmd, void *_dcfg, const char *p1) {
1087 directory_config *dcfg = (directory_config *)_dcfg;
1089 if (strcmp(p1, "0") == 0) dcfg->cookie_format = COOKIES_V0;
1091 if (strcmp(p1, "1") == 0) dcfg->cookie_format = COOKIES_V1;
1093 return apr_psprintf(cmd->pool, "ModSecurity: Invalid cookie format: %s", p1);
1099 static const char *cmd_chroot_dir(cmd_parms *cmd, void *_dcfg, const char *p1) {
1100 char cwd[1025] = "";
1102 if (cmd->server->is_virtual) {
1103 return "ModSecurity: SecChrootDir not allowed in VirtualHost";
1106 chroot_dir = (char *)p1;
1108 if (getcwd(cwd, 1024) == NULL) {
1109 return "ModSecurity: Failed to get the current working directory";
1112 if (chdir(chroot_dir) < 0) {
1113 return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)",
1114 chroot_dir, errno, strerror(errno));
1117 if (chdir(cwd) < 0) {
1118 return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)",
1119 cwd, errno, strerror(errno));
1126 * Adds component signature to the list of signatures kept in configuration.
1128 static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg, const char *p1) {
1129 directory_config *dcfg = (directory_config *)_dcfg;
1131 /* ENH Enforce "Name/VersionX.Y.Z (comment)" format. */
1132 *(char **)apr_array_push(dcfg->component_signatures) = (char *)p1;
1137 static const char *cmd_content_injection(cmd_parms *cmd, void *_dcfg, int flag) {
1138 directory_config *dcfg = (directory_config *)_dcfg;
1139 if (dcfg == NULL) return NULL;
1140 dcfg->content_injection_enabled = flag;
1144 static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1) {
1145 directory_config *dcfg = (directory_config *)_dcfg;
1147 if (cmd->server->is_virtual) {
1148 return "ModSecurity: SecDataDir not allowed in VirtualHost.";
1151 dcfg->data_dir = ap_server_root_relative(cmd->pool, p1);
1156 static const char *cmd_debug_log(cmd_parms *cmd, void *_dcfg, const char *p1) {
1157 directory_config *dcfg = (directory_config *)_dcfg;
1160 dcfg->debuglog_name = ap_server_root_relative(cmd->pool, p1);
1162 rc = apr_file_open(&dcfg->debuglog_fd, dcfg->debuglog_name,
1163 APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
1164 CREATEMODE, cmd->pool);
1166 if (rc != APR_SUCCESS) {
1167 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open debug log file: %s",
1168 dcfg->debuglog_name);
1174 static const char *cmd_debug_log_level(cmd_parms *cmd, void *_dcfg, const char *p1) {
1175 directory_config *dcfg = (directory_config *)_dcfg;
1177 dcfg->debuglog_level = atoi(p1);
1178 if ((dcfg->debuglog_level >= 0)&&(dcfg->debuglog_level <= 9)) return NULL;
1180 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecDebugLogLevel: %s", p1);
1183 static const char *cmd_default_action(cmd_parms *cmd, void *_dcfg, const char *p1) {
1184 directory_config *dcfg = (directory_config *)_dcfg;
1185 extern msc_engine *modsecurity;
1186 char *my_error_msg = NULL;
1188 dcfg->tmp_default_actionset = msre_actionset_create(modsecurity->msre, p1, &my_error_msg);
1189 if (dcfg->tmp_default_actionset == NULL) {
1190 if (my_error_msg != NULL) return my_error_msg;
1191 else return FATAL_ERROR;
1194 /* Must specify a disruptive action. */
1195 /* ENH: Remove this requirement? */
1196 if (dcfg->tmp_default_actionset->intercept_action == NOT_SET) {
1197 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a disruptive action.");
1200 /* Must specify a phase. */
1201 /* ENH: Remove this requirement? */
1202 if (dcfg->tmp_default_actionset->phase == NOT_SET) {
1203 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a phase.");
1206 /* Must not use metadata actions. */
1207 /* ENH: loop through to check for tags */
1208 if ((dcfg->tmp_default_actionset->id != NOT_SET_P)
1209 ||(dcfg->tmp_default_actionset->rev != NOT_SET_P)
1210 ||(dcfg->tmp_default_actionset->msg != NOT_SET_P))
1212 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1213 "contain any metadata actions (id, rev, msg, tag, severity, logdata).");
1215 /* These are just a warning for now. */
1216 if ((dcfg->tmp_default_actionset->severity != NOT_SET)
1217 ||(dcfg->tmp_default_actionset->logdata != NOT_SET_P))
1219 ap_log_perror(APLOG_MARK,
1220 APLOG_STARTUP|APLOG_WARNING|APLOG_NOERRNO, 0, cmd->pool,
1221 "ModSecurity: WARNING Using \"severity\" or \"logdata\" in "
1222 "SecDefaultAction is deprecated (%s:%d).",
1223 cmd->directive->filename, cmd->directive->line_num);
1226 /* Must not use chain. */
1227 if (dcfg->tmp_default_actionset->is_chained != NOT_SET) {
1228 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1229 "contain a chain action.");
1232 /* Must not use skip. */
1233 if (dcfg->tmp_default_actionset->skip_count != NOT_SET) {
1234 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1235 "contain a skip action.");
1238 /* Must not use skipAfter. */
1239 if (dcfg->tmp_default_actionset->skip_after != NOT_SET_P) {
1240 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1241 "contain a skipAfter action.");
1247 static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) {
1248 extern char *guardianlog_name;
1249 extern apr_file_t *guardianlog_fd;
1250 extern char *guardianlog_condition;
1252 if (cmd->server->is_virtual) {
1253 return "ModSecurity: SecGuardianLog not allowed in VirtualHost";
1257 if (strncmp(p2, "env=", 4) != 0) {
1258 return "ModSecurity: Error in condition clause";
1260 if ( (p2[4] == '\0') || ((p2[4] == '!')&&(p2[5] == '\0')) ) {
1261 return "ModSecurity: Missing variable name";
1263 guardianlog_condition = apr_pstrdup(cmd->pool, p2 + 4);
1266 guardianlog_name = (char *)p1;
1268 if (guardianlog_name[0] == '|') {
1269 const char *pipe_name = ap_server_root_relative(cmd->pool, guardianlog_name + 1);
1270 piped_log *pipe_log;
1272 pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
1273 if (pipe_log == NULL) {
1274 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log pipe: %s",
1277 guardianlog_fd = ap_piped_log_write_fd(pipe_log);
1280 const char *file_name = ap_server_root_relative(cmd->pool, guardianlog_name);
1283 rc = apr_file_open(&guardianlog_fd, file_name,
1284 APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
1285 CREATEMODE, cmd->pool);
1287 if (rc != APR_SUCCESS) {
1288 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log file: %s",
1296 static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg, const char *p1) {
1297 directory_config *dcfg = (directory_config *)_dcfg;
1300 if (dcfg == NULL) return NULL;
1302 limit = strtol(p1, NULL, 10);
1303 if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1304 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyInMemoryLimit: %s", p1);
1307 dcfg->reqbody_inmemory_limit = limit;
1312 static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg, const char *p1) {
1313 directory_config *dcfg = (directory_config *)_dcfg;
1316 if (dcfg == NULL) return NULL;
1318 limit = strtol(p1, NULL, 10);
1319 if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1320 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimit: %s", p1);
1323 dcfg->reqbody_limit = limit;
1328 static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg, const char *p1) {
1329 directory_config *dcfg = (directory_config *)_dcfg;
1332 if (dcfg == NULL) return NULL;
1334 limit = strtol(p1, NULL, 10);
1335 if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1336 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyNoFilesLimit: %s", p1);
1339 dcfg->reqbody_no_files_limit = limit;
1344 static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg, const char *p1) {
1345 directory_config *dcfg = (directory_config *)_dcfg;
1346 if (dcfg == NULL) return NULL;
1348 if (strcasecmp(p1, "on") == 0) dcfg->reqbody_access = 1;
1350 if (strcasecmp(p1, "off") == 0) dcfg->reqbody_access = 0;
1352 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyAccess: %s", p1);
1357 static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg, const char *p1) {
1358 directory_config *dcfg = (directory_config *)_dcfg;
1359 if (dcfg == NULL) return NULL;
1361 /* ENH Validate encoding */
1363 dcfg->request_encoding = p1;
1368 static const char *cmd_response_body_access(cmd_parms *cmd, void *_dcfg, const char *p1) {
1369 directory_config *dcfg = (directory_config *)_dcfg;
1370 if (dcfg == NULL) return NULL;
1372 if (strcasecmp(p1, "on") == 0) dcfg->resbody_access = 1;
1374 if (strcasecmp(p1, "off") == 0) dcfg->resbody_access = 0;
1376 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyAccess: %s", p1);
1381 static const char *cmd_response_body_limit(cmd_parms *cmd, void *_dcfg, const char *p1) {
1382 directory_config *dcfg = (directory_config *)_dcfg;
1385 limit = strtol(p1, NULL, 10);
1386 if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1387 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimit: %s", p1);
1390 if (limit > RESPONSE_BODY_HARD_LIMIT) {
1391 return apr_psprintf(cmd->pool, "ModSecurity: Response size limit can not exceed the hard limit: %li", RESPONSE_BODY_HARD_LIMIT);
1394 dcfg->of_limit = limit;
1399 static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg, const char *p1) {
1400 directory_config *dcfg = (directory_config *)_dcfg;
1401 if (dcfg == NULL) return NULL;
1403 if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
1405 if (strcasecmp(p1, "Reject") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
1407 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimitAction: %s", p1);
1412 static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg, const char *_p1) {
1413 directory_config *dcfg = (directory_config *)_dcfg;
1414 char *p1 = apr_pstrdup(cmd->pool, _p1);
1416 /* TODO check whether the parameter is a valid MIME type of "???" */
1418 if ((dcfg->of_mime_types == NULL)||(dcfg->of_mime_types == NOT_SET_P)) {
1419 dcfg->of_mime_types = apr_table_make(cmd->pool, 10);
1422 strtolower_inplace((unsigned char *)p1);
1423 apr_table_setn(dcfg->of_mime_types, p1, "1");
1428 static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd, void *_dcfg) {
1429 directory_config *dcfg = (directory_config *)_dcfg;
1430 if (dcfg == NULL) return NULL;
1432 dcfg->of_mime_types_cleared = 1;
1434 if ((dcfg->of_mime_types != NULL)&&(dcfg->of_mime_types != NOT_SET_P)) {
1435 apr_table_clear(dcfg->of_mime_types);
1441 static const char *cmd_rule(cmd_parms *cmd, void *_dcfg, const char *p1,
1442 const char *p2, const char *p3)
1444 return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_NORMAL, p1, p2, p3);
1447 static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1) {
1448 directory_config *dcfg = (directory_config *)_dcfg;
1449 if (dcfg == NULL) return NULL;
1451 if (strcasecmp(p1, "on") == 0) dcfg->is_enabled = MODSEC_ENABLED;
1453 if (strcasecmp(p1, "off") == 0) dcfg->is_enabled = MODSEC_DISABLED;
1455 if (strcasecmp(p1, "detectiononly") == 0) dcfg->is_enabled = MODSEC_DETECTION_ONLY;
1457 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRuleEngine: %s", p1);
1463 static const char *cmd_rule_import_by_id(cmd_parms *cmd, void *_dcfg, const char *p1) {
1464 directory_config *dcfg = (directory_config *)_dcfg;
1465 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
1466 if (dcfg == NULL) return NULL;
1468 re->type = RULE_EXCEPTION_IMPORT_ID;
1471 *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
1476 static const char *cmd_rule_import_by_msg(cmd_parms *cmd, void *_dcfg, const char *p1) {
1477 directory_config *dcfg = (directory_config *)_dcfg;
1478 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
1479 if (dcfg == NULL) return NULL;
1481 re->type = RULE_EXCEPTION_IMPORT_MSG;
1484 *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
1490 static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag) {
1491 directory_config *dcfg = (directory_config *)_dcfg;
1492 if (dcfg == NULL) return NULL;
1493 dcfg->rule_inheritance = flag;
1497 static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg, const char *p1,
1500 #if defined(WITH_LUA)
1501 const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
1502 return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL);
1504 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);
1509 static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, const char *p1) {
1510 directory_config *dcfg = (directory_config *)_dcfg;
1511 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
1512 if (dcfg == NULL) return NULL;
1514 re->type = RULE_EXCEPTION_REMOVE_ID;
1516 *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
1518 /* Remove the corresponding rules from the context straight away. */
1519 msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
1524 static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg, const char *p1) {
1525 directory_config *dcfg = (directory_config *)_dcfg;
1526 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
1527 if (dcfg == NULL) return NULL;
1529 re->type = RULE_EXCEPTION_REMOVE_MSG;
1531 re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
1532 if (re->param_data == NULL) {
1533 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
1535 *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
1537 /* Remove the corresponding rules from the context straight away. */
1538 msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
1541 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);
1547 static const char *cmd_rule_update_action_by_id(cmd_parms *cmd, void *_dcfg,
1548 const char *p1, const char *p2)
1550 return update_rule_action(cmd, (directory_config *)_dcfg, p1, p2);
1553 static const char *cmd_server_signature(cmd_parms *cmd, void *_dcfg, const char *p1) {
1554 if (cmd->server->is_virtual) {
1555 return "ModSecurity: SecServerSignature not allowed in VirtualHost";
1557 new_server_signature = (char *)p1;
1561 static const char *cmd_tmp_dir(cmd_parms *cmd, void *_dcfg, const char *p1) {
1562 directory_config *dcfg = (directory_config *)_dcfg;
1564 if (dcfg == NULL) return NULL;
1566 if (strcasecmp(p1, "none") == 0) dcfg->tmp_dir = NULL;
1567 else dcfg->tmp_dir = ap_server_root_relative(cmd->pool, p1);
1572 static const char *cmd_upload_dir(cmd_parms *cmd, void *_dcfg, const char *p1) {
1573 directory_config *dcfg = (directory_config *)_dcfg;
1575 if (dcfg == NULL) return NULL;
1577 if (strcasecmp(p1, "none") == 0) dcfg->upload_dir = NULL;
1578 else dcfg->upload_dir = ap_server_root_relative(cmd->pool, p1);
1583 static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg, const char *p1) {
1584 directory_config *dcfg = (directory_config *)_dcfg;
1586 if (dcfg == NULL) return NULL;
1588 if (strcasecmp(p1, "default") == 0) {
1589 dcfg->upload_filemode = NOT_SET;
1592 long int mode = strtol(p1, NULL, 8); /* expects octal mode */
1593 if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
1594 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecUploadFileMode: %s", p1);
1597 dcfg->upload_filemode = (int)mode;
1603 static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg, const char *p1) {
1604 directory_config *dcfg = (directory_config *)_dcfg;
1606 if (dcfg == NULL) return NULL;
1608 if (strcasecmp(p1, "on") == 0) {
1609 dcfg->upload_keep_files = KEEP_FILES_ON;
1611 if (strcasecmp(p1, "off") == 0) {
1612 dcfg->upload_keep_files = KEEP_FILES_OFF;
1614 if (strcasecmp(p1, "relevantonly") == 0) {
1615 dcfg->upload_keep_files = KEEP_FILES_RELEVANT_ONLY;
1617 return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for SecUploadKeepFiles: %s",
1623 static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1) {
1624 directory_config *dcfg = (directory_config *)_dcfg;
1626 /* ENH enforce format (letters, digits, ., _, -) */
1627 dcfg->webappid = p1;
1632 /* -- PDF Protection configuration -- */
1634 static const char *cmd_pdf_protect(cmd_parms *cmd, void *_dcfg, int flag) {
1635 directory_config *dcfg = (directory_config *)_dcfg;
1636 if (dcfg == NULL) return NULL;
1638 dcfg->pdfp_enabled = flag;
1643 static const char *cmd_pdf_protect_secret(cmd_parms *cmd, void *_dcfg,
1646 directory_config *dcfg = (directory_config *)_dcfg;
1647 if (dcfg == NULL) return NULL;
1649 dcfg->pdfp_secret = p1;
1654 static const char *cmd_pdf_protect_timeout(cmd_parms *cmd, void *_dcfg,
1657 directory_config *dcfg = (directory_config *)_dcfg;
1658 if (dcfg == NULL) return NULL;
1660 dcfg->pdfp_timeout = atoi(p1);
1665 static const char *cmd_pdf_protect_token_name(cmd_parms *cmd, void *_dcfg,
1668 directory_config *dcfg = (directory_config *)_dcfg;
1669 if (dcfg == NULL) return NULL;
1671 dcfg->pdfp_token_name = p1;
1676 static const char *cmd_pdf_protect_intercept_get_only(cmd_parms *cmd, void *_dcfg,
1679 directory_config *dcfg = (directory_config *)_dcfg;
1680 if (dcfg == NULL) return NULL;
1682 dcfg->pdfp_only_get = flag;
1687 static const char *cmd_pdf_protect_method(cmd_parms *cmd, void *_dcfg,
1690 directory_config *dcfg = (directory_config *)_dcfg;
1691 if (dcfg == NULL) return NULL;
1693 if (strcasecmp(p1, "TokenRedirection") == 0) {
1694 dcfg->pdfp_method = PDF_PROTECT_METHOD_TOKEN_REDIRECTION;
1696 if (strcasecmp(p1, "ForcedDownload") == 0) {
1697 dcfg->pdfp_method = PDF_PROTECT_METHOD_FORCED_DOWNLOAD;
1699 return (const char *)apr_psprintf(cmd->pool,
1700 "ModSecurity: Unrecognised parameter value for SecPdfProtectMethod: %s", p1);
1706 /* -- Geo Lookup configuration -- */
1708 static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg,
1711 const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
1713 directory_config *dcfg = (directory_config *)_dcfg;
1714 if (dcfg == NULL) return NULL;
1716 if (geo_init(dcfg, filename, &error_msg) <= 0) {
1726 static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) {
1727 directory_config *dcfg = (directory_config *)_dcfg;
1729 if (dcfg == NULL) return NULL;
1731 if (strcasecmp(p1, "on") == 0)
1732 dcfg->cache_trans = MODSEC_CACHE_ENABLED;
1733 else if (strcasecmp(p1, "off") == 0)
1734 dcfg->cache_trans = MODSEC_CACHE_DISABLED;
1736 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecCacheTransformations: %s", p1);
1738 /* Process options */
1740 apr_table_t *vartable = apr_table_make(cmd->pool, 4);
1742 char *error_msg = NULL;
1743 const char *charval = NULL;
1744 apr_int64_t intval = 0;
1746 if (vartable == NULL) {
1747 return apr_psprintf(cmd->pool, "ModSecurity: Unable to process options for SecCacheTransformations");
1749 rc = msre_parse_generic(cmd->pool, p2, vartable, &error_msg);
1751 return apr_psprintf(cmd->pool, "ModSecurity: Unable to parse options for SecCacheTransformations: %s", error_msg);
1755 charval = apr_table_get(vartable, "incremental");
1756 if (charval != NULL) {
1757 if (strcasecmp(charval, "on") == 0)
1758 dcfg->cache_trans_incremental = 1;
1759 else if (strcasecmp(charval, "off") == 0)
1760 dcfg->cache_trans_incremental = 0;
1762 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations invalid incremental value: %s", charval);
1766 charval = apr_table_get(vartable, "minlen");
1767 if (charval != NULL) {
1768 intval = apr_atoi64(charval);
1769 if (errno == ERANGE) {
1770 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen out of range: %s", charval);
1773 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be positive: %s", charval);
1776 /* The NOT_SET indicator is -1, a signed long, and therfore
1777 * we cannot be >= the unsigned value of NOT_SET.
1779 if ((unsigned long)intval >= (unsigned long)NOT_SET) {
1780 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be less than: %lu", (unsigned long)NOT_SET);
1782 dcfg->cache_trans_min = (apr_size_t)intval;
1786 charval = apr_table_get(vartable, "maxlen");
1787 if (charval != NULL) {
1788 intval = apr_atoi64(charval);
1789 if (errno == ERANGE) {
1790 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen out of range: %s", charval);
1793 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be positive: %s", charval);
1796 /* The NOT_SET indicator is -1, a signed long, and therfore
1797 * we cannot be >= the unsigned value of NOT_SET.
1799 if ((unsigned long)intval >= (unsigned long)NOT_SET) {
1800 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be less than: %lu", (unsigned long)NOT_SET);
1802 if ((intval != 0) && ((apr_size_t)intval < dcfg->cache_trans_min)) {
1803 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);
1805 dcfg->cache_trans_max = (apr_size_t)intval;
1810 charval = apr_table_get(vartable, "maxitems");
1811 if (charval != NULL) {
1812 intval = apr_atoi64(charval);
1813 if (errno == ERANGE) {
1814 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems out of range: %s", charval);
1817 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems must be positive: %s", charval);
1819 dcfg->cache_trans_maxitems = (apr_size_t)intval;
1827 /* -- Configuration directives definitions -- */
1829 #define CMD_SCOPE_MAIN (RSRC_CONF)
1830 #define CMD_SCOPE_ANY (RSRC_CONF | ACCESS_CONF)
1832 const command_rec module_directives[] = {
1843 "SecArgumentSeparator",
1844 cmd_argument_separator,
1847 "character that will be used as separator when parsing application/x-www-form-urlencoded content."
1855 "On, Off or RelevantOnly to determine the level of audit logging"
1863 "filename of the primary audit log file"
1871 "filename of the secondary audit log file"
1876 cmd_audit_log_parts,
1879 "list of audit log parts that go into the log."
1883 "SecAuditLogRelevantStatus",
1884 cmd_audit_log_relevant_status,
1887 "regular expression that will be used to determine if the response status is relevant for audit logging"
1895 "whether to use the old audit log format (Serial) or new (Concurrent)"
1899 "SecAuditLogStorageDir",
1900 cmd_audit_log_storage_dir,
1903 "path to the audit log storage area; absolute, or relative to the root of the server"
1907 "SecAuditLogDirMode",
1908 cmd_audit_log_dirmode,
1911 "octal permissions mode for concurrent audit log directories"
1915 "SecAuditLogFileMode",
1916 cmd_audit_log_filemode,
1919 "octal permissions mode for concurrent audit log files"
1923 "SecCacheTransformations",
1924 cmd_cache_transformations,
1927 "whether or not to cache transformations. Defaults to true."
1935 "path of the directory to which server will be chrooted"
1939 "SecComponentSignature",
1940 cmd_component_signature,
1943 "component signature to add to ModSecurity signature."
1947 "SecContentInjection",
1948 cmd_content_injection,
1959 "version of the Cookie specification to use for parsing. Possible values are 0 and 1."
1967 "path to the persistent data storage area" // TODO
1975 "path to the debug log file"
1980 cmd_debug_log_level,
1983 "debug log level, which controls the verbosity of logging."
1984 " Use values from 0 (no logging) to 9 (a *lot* of logging)."
1992 "default action list"
2000 "database for geographical lookups module."
2008 "The filename of the filter debugging log file"
2016 "marker for a skipAfter target"
2024 "enable PDF protection module."
2028 "SecPdfProtectSecret",
2029 cmd_pdf_protect_secret,
2032 "secret that will be used to construct protection tokens."
2036 "SecPdfProtectTimeout",
2037 cmd_pdf_protect_timeout,
2040 "duration for which protection tokens will be valid."
2044 "SecPdfProtectTokenName",
2045 cmd_pdf_protect_token_name,
2048 "name of the protection token. The name 'PDFTOKEN' is used by default."
2052 "SecPdfProtectInterceptGETOnly",
2053 cmd_pdf_protect_intercept_get_only,
2056 "whether or not to intercept only GET and HEAD requess. Defaults to true."
2060 "SecPdfProtectMethod",
2061 cmd_pdf_protect_method,
2064 "protection method to use. Can be 'TokenRedirection' (default) or 'ForcedDownload'"
2068 "SecRequestBodyAccess",
2069 cmd_request_body_access,
2076 "SecRequestBodyInMemoryLimit",
2077 cmd_request_body_inmemory_limit,
2080 "maximum request body size that will be placed in memory (except for POST urlencoded requests)."
2084 "SecRequestBodyLimit",
2085 cmd_request_body_limit,
2088 "maximum request body size ModSecurity will accept."
2092 "SecRequestBodyNoFilesLimit",
2093 cmd_request_body_no_files_limit,
2096 "maximum request body size ModSecurity will accept, but excluding the size of uploaded files."
2100 "SecRequestEncoding",
2101 cmd_request_encoding,
2104 "character encoding used in request."
2108 "SecResponseBodyAccess",
2109 cmd_response_body_access,
2116 "SecResponseBodyLimit",
2117 cmd_response_body_limit,
2120 "byte limit for response body"
2124 "SecResponseBodyLimitAction",
2125 cmd_response_body_limit_action,
2128 "what happens when the response body limit is reached"
2132 "SecResponseBodyMimeType",
2133 cmd_response_body_mime_type,
2136 "adds given MIME types to the list of types that will be buffered on output"
2140 "SecResponseBodyMimeTypesClear",
2141 cmd_response_body_mime_types_clear,
2144 "clears the list of MIME types that will be buffered on output"
2152 "rule target, operator and optional action list"
2164 "SecRuleInheritance",
2165 cmd_rule_inheritance,
2176 "rule script and optional actionlist"
2180 "SecRuleRemoveById",
2181 cmd_rule_remove_by_id,
2184 "rule ID for removal"
2188 "SecRuleRemoveByMsg",
2189 cmd_rule_remove_by_msg,
2192 "rule message for removal"
2196 "SecRuleUpdateActionById",
2197 cmd_rule_update_action_by_id,
2200 "updated action list"
2204 "SecServerSignature",
2205 cmd_server_signature,
2208 "the new signature of the server"
2216 "path to the temporary storage area"
2224 "path to the file upload area"
2228 "SecUploadFileMode",
2229 cmd_upload_filemode,
2232 "octal permissions mode for uploaded files"
2236 "SecUploadKeepFiles",
2237 cmd_upload_keep_files,