1 /*
2 * ModSecurity for Apache 2.x, http://www.modsecurity.org/
3 * Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
4 *
5 * You may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * If any of the files related to licensing are missing or if you have any
11 * other questions related to licensing please contact Trustwave Holdings, Inc.
12 * directly using the email address security@modsecurity.org.
13 */
14
15 #include <limits.h>
16
17 #include "modsecurity.h"
18 #include "msc_logging.h"
19 #include "msc_util.h"
20 #include "http_log.h"
21 #include "apr_lib.h"
22 #include "acmp.h"
23 #include "msc_crypt.h"
24
25 #if defined(WITH_LUA)
26 #include "msc_lua.h"
27 #endif
28
29
30 /* -- Directory context creation and initialisation -- */
31
32 /**
33 * Creates a fresh directory configuration.
34 */
create_directory_config(apr_pool_t * mp,char * path)35 void *create_directory_config(apr_pool_t *mp, char *path)
36 {
37 directory_config *dcfg = (directory_config *)apr_pcalloc(mp, sizeof(directory_config));
38 if (dcfg == NULL) return NULL;
39
40 #ifdef DEBUG_CONF
41 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Created directory config %pp path %s", dcfg, path);
42 #endif
43
44 dcfg->mp = mp;
45 dcfg->is_enabled = NOT_SET;
46
47 dcfg->reqbody_access = NOT_SET;
48 dcfg->reqintercept_oe = 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;
54
55 dcfg->debuglog_name = NOT_SET_P;
56 dcfg->debuglog_level = NOT_SET;
57 dcfg->debuglog_fd = NOT_SET_P;
58
59 dcfg->of_limit = NOT_SET;
60 dcfg->if_limit_action = NOT_SET;
61 dcfg->of_limit_action = NOT_SET;
62 dcfg->of_mime_types = NOT_SET_P;
63 dcfg->of_mime_types_cleared = NOT_SET;
64
65 dcfg->cookie_format = NOT_SET;
66 dcfg->argument_separator = NOT_SET;
67 dcfg->cookiev0_separator = NOT_SET_P;
68
69 dcfg->rule_inheritance = NOT_SET;
70 dcfg->rule_exceptions = apr_array_make(mp, 16, sizeof(rule_exception *));
71 dcfg->hash_method = apr_array_make(mp, 16, sizeof(hash_method *));
72
73 /* audit log variables */
74 dcfg->auditlog_flag = NOT_SET;
75 dcfg->auditlog_type = NOT_SET;
76 #ifdef WITH_YAJL
77 dcfg->auditlog_format = NOT_SET;
78 #endif
79 dcfg->max_rule_time = NOT_SET;
80 dcfg->auditlog_dirperms = NOT_SET;
81 dcfg->auditlog_fileperms = NOT_SET;
82 dcfg->auditlog_name = NOT_SET_P;
83 dcfg->auditlog2_name = NOT_SET_P;
84 dcfg->auditlog_fd = NOT_SET_P;
85 dcfg->auditlog2_fd = NOT_SET_P;
86 dcfg->auditlog_storage_dir = NOT_SET_P;
87 dcfg->auditlog_parts = NOT_SET_P;
88 dcfg->auditlog_relevant_regex = NOT_SET_P;
89
90 dcfg->ruleset = NULL;
91
92 /* Upload */
93 dcfg->tmp_dir = NOT_SET_P;
94 dcfg->upload_dir = NOT_SET_P;
95 dcfg->upload_keep_files = NOT_SET;
96 dcfg->upload_validates_files = NOT_SET;
97 dcfg->upload_filemode = NOT_SET;
98 dcfg->upload_file_limit = NOT_SET;
99
100 /* These are only used during the configuration process. */
101 dcfg->tmp_chain_starter = NULL;
102 dcfg->tmp_default_actionset = NULL;
103 dcfg->tmp_rule_placeholders = NULL;
104
105 /* Misc */
106 dcfg->data_dir = NOT_SET_P;
107 dcfg->webappid = NOT_SET_P;
108 dcfg->sensor_id = NOT_SET_P;
109 dcfg->httpBlkey = NOT_SET_P;
110
111 /* Content injection. */
112 dcfg->content_injection_enabled = NOT_SET;
113
114 /* Stream inspection */
115 dcfg->stream_inbody_inspection = NOT_SET;
116 dcfg->stream_outbody_inspection = NOT_SET;
117
118 /* Geo Lookups */
119 dcfg->geo = NOT_SET_P;
120
121 /* Gsb Lookups */
122 dcfg->gsb = NOT_SET_P;
123
124 /* Unicode Map */
125 dcfg->u_map = NOT_SET_P;
126
127 /* Cache */
128 dcfg->cache_trans = NOT_SET;
129 dcfg->cache_trans_incremental = NOT_SET;
130 dcfg->cache_trans_min = NOT_SET;
131 dcfg->cache_trans_max = NOT_SET;
132 dcfg->cache_trans_maxitems = NOT_SET;
133
134 /* Rule ids */
135 dcfg->rule_id_htab = apr_hash_make(mp);
136 dcfg->component_signatures = apr_array_make(mp, 16, sizeof(char *));
137
138 dcfg->request_encoding = NOT_SET_P;
139 dcfg->disable_backend_compression = NOT_SET;
140
141 /* Collection timeout */
142 dcfg->col_timeout = NOT_SET;
143
144 dcfg->crypto_key = NOT_SET_P;
145 dcfg->crypto_key_len = NOT_SET;
146 dcfg->crypto_key_add = NOT_SET;
147 dcfg->crypto_param_name = NOT_SET_P;
148 dcfg->hash_is_enabled = NOT_SET;
149 dcfg->hash_enforcement = NOT_SET;
150 dcfg->crypto_hash_href_rx = NOT_SET;
151 dcfg->crypto_hash_faction_rx = NOT_SET;
152 dcfg->crypto_hash_location_rx = NOT_SET;
153 dcfg->crypto_hash_iframesrc_rx = NOT_SET;
154 dcfg->crypto_hash_framesrc_rx = NOT_SET;
155 dcfg->crypto_hash_href_pm = NOT_SET;
156 dcfg->crypto_hash_faction_pm = NOT_SET;
157 dcfg->crypto_hash_location_pm = NOT_SET;
158 dcfg->crypto_hash_iframesrc_pm = NOT_SET;
159 dcfg->crypto_hash_framesrc_pm = NOT_SET;
160
161
162 /* xml external entity */
163 dcfg->xml_external_entity = NOT_SET;
164
165 return dcfg;
166 }
167
168 /**
169 * Copies rules between one phase of two configuration contexts,
170 * taking exceptions into account.
171 */
copy_rules_phase(apr_pool_t * mp,apr_array_header_t * parent_phase_arr,apr_array_header_t * child_phase_arr,apr_array_header_t * exceptions_arr)172 static void copy_rules_phase(apr_pool_t *mp,
173 apr_array_header_t *parent_phase_arr,
174 apr_array_header_t *child_phase_arr,
175 apr_array_header_t *exceptions_arr)
176 {
177 rule_exception **exceptions;
178 msre_rule **rules;
179 int i, j;
180 int mode = 0;
181
182 rules = (msre_rule **)parent_phase_arr->elts;
183 for(i = 0; i < parent_phase_arr->nelts; i++) {
184 msre_rule *rule = (msre_rule *)rules[i];
185 int copy = 1;
186
187 if (mode == 0) {
188 /* First rule in the chain. */
189 exceptions = (rule_exception **)exceptions_arr->elts;
190 for(j = 0; j < exceptions_arr->nelts; j++) {
191
192 /* Process exceptions. */
193 switch(exceptions[j]->type) {
194 case RULE_EXCEPTION_REMOVE_ID :
195 if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) {
196 int ruleid = atoi(rule->actionset->id);
197 if (rule_id_in_range(ruleid, exceptions[j]->param)) copy--;
198 }
199 break;
200 case RULE_EXCEPTION_REMOVE_MSG :
201 if ((rule->actionset != NULL)&&(rule->actionset->msg != NULL)) {
202 char *my_error_msg = NULL;
203
204 int rc = msc_regexec(exceptions[j]->param_data,
205 rule->actionset->msg, strlen(rule->actionset->msg),
206 &my_error_msg);
207 if (rc >= 0) copy--;
208 }
209 break;
210 case RULE_EXCEPTION_REMOVE_TAG :
211 if ((rule->actionset != NULL)&&(apr_is_empty_table(rule->actionset->actions) == 0)) {
212 char *my_error_msg = NULL;
213 const apr_array_header_t *tarr = NULL;
214 const apr_table_entry_t *telts = NULL;
215 int c;
216
217 tarr = apr_table_elts(rule->actionset->actions);
218 telts = (const apr_table_entry_t*)tarr->elts;
219
220 for (c = 0; c < tarr->nelts; c++) {
221 msre_action *action = (msre_action *)telts[c].val;
222 if(strcmp("tag", action->metadata->name) == 0) {
223
224 int rc = msc_regexec(exceptions[j]->param_data,
225 action->param, strlen(action->param),
226 &my_error_msg);
227 if (rc >= 0) copy--;
228 }
229 }
230 }
231 break;
232 }
233 }
234
235 if (copy > 0) {
236 #ifdef DEBUG_CONF
237 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, rule->actionset->id);
238 #endif
239
240 /* Copy the rule. */
241 *(msre_rule **)apr_array_push(child_phase_arr) = rule;
242 if (rule->actionset && rule->actionset->is_chained) mode = 2;
243 } else {
244 if (rule->actionset && rule->actionset->is_chained) mode = 1;
245 }
246 } else {
247 if (mode == 2) {
248 #ifdef DEBUG_CONF
249 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);
250 #endif
251
252 /* Copy the rule (it belongs to the chain we want to include. */
253 *(msre_rule **)apr_array_push(child_phase_arr) = rule;
254 }
255
256 if ((rule->actionset == NULL)||(rule->actionset->is_chained == 0)) mode = 0;
257 }
258 }
259 }
260
261 /**
262 * @brief Copies rules between one phase of two configuration contexts.
263 *
264 * Copies rules between one phase of two configuration contexts,
265 * taking exceptions into account.
266 *
267 * @param mp apr pool structure
268 * @param parent_ruleset Parent's msre_ruleset
269 * @param child_ruleset Child's msre_ruleset
270 * @param exceptions_arr Exceptions' apr_array_header_t
271 * @retval 0 Everything went well.
272 * @retval -1 Something went wrong.
273 *
274 */
copy_rules(apr_pool_t * mp,msre_ruleset * parent_ruleset,msre_ruleset * child_ruleset,apr_array_header_t * exceptions_arr)275 static int copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset,
276 msre_ruleset *child_ruleset,
277 apr_array_header_t *exceptions_arr)
278 {
279 int ret = 0;
280
281 if (parent_ruleset == NULL || child_ruleset == NULL ||
282 exceptions_arr == NULL) {
283 ret = -1;
284 goto failed;
285 }
286
287 copy_rules_phase(mp, parent_ruleset->phase_request_headers,
288 child_ruleset->phase_request_headers, exceptions_arr);
289 copy_rules_phase(mp, parent_ruleset->phase_request_body,
290 child_ruleset->phase_request_body, exceptions_arr);
291 copy_rules_phase(mp, parent_ruleset->phase_response_headers,
292 child_ruleset->phase_response_headers, exceptions_arr);
293 copy_rules_phase(mp, parent_ruleset->phase_response_body,
294 child_ruleset->phase_response_body, exceptions_arr);
295 copy_rules_phase(mp, parent_ruleset->phase_logging,
296 child_ruleset->phase_logging, exceptions_arr);
297
298 failed:
299 return ret;
300 }
301
302 /**
303 * Merges two directory configurations.
304 */
merge_directory_configs(apr_pool_t * mp,void * _parent,void * _child)305 void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
306 {
307 directory_config *parent = (directory_config *)_parent;
308 directory_config *child = (directory_config *)_child;
309 directory_config *merged = create_directory_config(mp, NULL);
310
311 #ifdef DEBUG_CONF
312 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Merge parent %pp child %pp RESULT %pp", _parent, _child, merged);
313 #endif
314
315 if (merged == NULL) return NULL;
316
317 /* Use values from the child configuration where possible,
318 * otherwise use the parent's.
319 */
320
321 merged->is_enabled = (child->is_enabled == NOT_SET
322 ? parent->is_enabled : child->is_enabled);
323
324 /* IO parameters */
325 merged->reqbody_access = (child->reqbody_access == NOT_SET
326 ? parent->reqbody_access : child->reqbody_access);
327 merged->reqbody_buffering = (child->reqbody_buffering == NOT_SET
328 ? parent->reqbody_buffering : child->reqbody_buffering);
329 merged->reqbody_inmemory_limit = (child->reqbody_inmemory_limit == NOT_SET
330 ? parent->reqbody_inmemory_limit : child->reqbody_inmemory_limit);
331 merged->reqbody_limit = (child->reqbody_limit == NOT_SET
332 ? parent->reqbody_limit : child->reqbody_limit);
333 merged->reqbody_no_files_limit = (child->reqbody_no_files_limit == NOT_SET
334 ? parent->reqbody_no_files_limit : child->reqbody_no_files_limit);
335 merged->resbody_access = (child->resbody_access == NOT_SET
336 ? parent->resbody_access : child->resbody_access);
337
338 merged->of_limit = (child->of_limit == NOT_SET
339 ? parent->of_limit : child->of_limit);
340 merged->if_limit_action = (child->if_limit_action == NOT_SET
341 ? parent->if_limit_action : child->if_limit_action);
342 merged->of_limit_action = (child->of_limit_action == NOT_SET
343 ? parent->of_limit_action : child->of_limit_action);
344 merged->reqintercept_oe = (child->reqintercept_oe == NOT_SET
345 ? parent->reqintercept_oe : child->reqintercept_oe);
346
347 if (child->of_mime_types != NOT_SET_P) {
348 /* Child added to the table */
349
350 if (child->of_mime_types_cleared == 1) {
351 /* The list of MIME types was cleared in the child,
352 * which means the parent's MIME types went away and
353 * we should not take them into consideration here.
354 */
355 merged->of_mime_types = child->of_mime_types;
356 merged->of_mime_types_cleared = 1;
357 } else {
358 /* Add MIME types defined in the child to those
359 * defined in the parent context.
360 */
361 if (parent->of_mime_types == NOT_SET_P) {
362 merged->of_mime_types = child->of_mime_types;
363 merged->of_mime_types_cleared = NOT_SET;
364 } else {
365 merged->of_mime_types = apr_table_overlay(mp, parent->of_mime_types,
366 child->of_mime_types);
367 if (merged->of_mime_types == NULL) return NULL;
368 }
369 }
370 } else {
371 /* Child did not add to the table */
372
373 if (child->of_mime_types_cleared == 1) {
374 merged->of_mime_types_cleared = 1;
375 } else {
376 merged->of_mime_types = parent->of_mime_types;
377 merged->of_mime_types_cleared = parent->of_mime_types_cleared;
378 }
379 }
380
381 /* debug log */
382 if (child->debuglog_fd == NOT_SET_P) {
383 merged->debuglog_name = parent->debuglog_name;
384 merged->debuglog_fd = parent->debuglog_fd;
385 } else {
386 merged->debuglog_name = child->debuglog_name;
387 merged->debuglog_fd = child->debuglog_fd;
388 }
389
390 merged->debuglog_level = (child->debuglog_level == NOT_SET
391 ? parent->debuglog_level : child->debuglog_level);
392
393 merged->cookie_format = (child->cookie_format == NOT_SET
394 ? parent->cookie_format : child->cookie_format);
395 merged->argument_separator = (child->argument_separator == NOT_SET
396 ? parent->argument_separator : child->argument_separator);
397 merged->cookiev0_separator = (child->cookiev0_separator == NOT_SET_P
398 ? parent->cookiev0_separator : child->cookiev0_separator);
399
400
401 /* rule inheritance */
402 if ((child->rule_inheritance == NOT_SET)||(child->rule_inheritance == 1)) {
403 merged->rule_inheritance = parent->rule_inheritance;
404 if ((child->ruleset == NULL)&&(parent->ruleset == NULL)) {
405 #ifdef DEBUG_CONF
406 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "No rules in this context.");
407 #endif
408
409 /* Do nothing, there are no rules in either context. */
410 } else
411 if (child->ruleset == NULL) {
412 #ifdef DEBUG_CONF
413 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent rules in this context.");
414 #endif
415
416 /* Copy the rules from the parent context. */
417 merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp);
418 /* TODO: copy_rules return code should be taken into consideration. */
419 copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions);
420 } else
421 if (parent->ruleset == NULL) {
422 #ifdef DEBUG_CONF
423 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using child rules in this context.");
424 #endif
425
426 /* Copy child rules. */
427 merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp);
428 merged->ruleset->phase_request_headers = apr_array_copy(mp,
429 child->ruleset->phase_request_headers);
430 merged->ruleset->phase_request_body = apr_array_copy(mp,
431 child->ruleset->phase_request_body);
432 merged->ruleset->phase_response_headers = apr_array_copy(mp,
433 child->ruleset->phase_response_headers);
434 merged->ruleset->phase_response_body = apr_array_copy(mp,
435 child->ruleset->phase_response_body);
436 merged->ruleset->phase_logging = apr_array_copy(mp,
437 child->ruleset->phase_logging);
438 } else {
439 #ifdef DEBUG_CONF
440 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent then child rules in this context.");
441 #endif
442
443 /* Copy parent rules, then add child rules to it. */
444 merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp);
445 /* TODO: copy_rules return code should be taken into consideration. */
446 copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions);
447
448 apr_array_cat(merged->ruleset->phase_request_headers,
449 child->ruleset->phase_request_headers);
450 apr_array_cat(merged->ruleset->phase_request_body,
451 child->ruleset->phase_request_body);
452 apr_array_cat(merged->ruleset->phase_response_headers,
453 child->ruleset->phase_response_headers);
454 apr_array_cat(merged->ruleset->phase_response_body,
455 child->ruleset->phase_response_body);
456 apr_array_cat(merged->ruleset->phase_logging,
457 child->ruleset->phase_logging);
458 }
459 } else {
460 merged->rule_inheritance = 0;
461 if (child->ruleset != NULL) {
462 /* Copy child rules. */
463 merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp);
464 merged->ruleset->phase_request_headers = apr_array_copy(mp,
465 child->ruleset->phase_request_headers);
466 merged->ruleset->phase_request_body = apr_array_copy(mp,
467 child->ruleset->phase_request_body);
468 merged->ruleset->phase_response_headers = apr_array_copy(mp,
469 child->ruleset->phase_response_headers);
470 merged->ruleset->phase_response_body = apr_array_copy(mp,
471 child->ruleset->phase_response_body);
472 merged->ruleset->phase_logging = apr_array_copy(mp,
473 child->ruleset->phase_logging);
474 }
475 }
476
477 /* Merge rule exceptions. */
478 merged->rule_exceptions = apr_array_append(mp, parent->rule_exceptions,
479 child->rule_exceptions);
480
481 merged->hash_method = apr_array_append(mp, parent->hash_method,
482 child->hash_method);
483
484 /* audit log variables */
485 merged->auditlog_flag = (child->auditlog_flag == NOT_SET
486 ? parent->auditlog_flag : child->auditlog_flag);
487 merged->auditlog_type = (child->auditlog_type == NOT_SET
488 ? parent->auditlog_type : child->auditlog_type);
489 merged->max_rule_time = (child->max_rule_time == NOT_SET
490 ? parent->max_rule_time : child->max_rule_time);
491 merged->auditlog_dirperms = (child->auditlog_dirperms == NOT_SET
492 ? parent->auditlog_dirperms : child->auditlog_dirperms);
493 merged->auditlog_fileperms = (child->auditlog_fileperms == NOT_SET
494 ? parent->auditlog_fileperms : child->auditlog_fileperms);
495 if (child->auditlog_fd != NOT_SET_P) {
496 merged->auditlog_fd = child->auditlog_fd;
497 merged->auditlog_name = child->auditlog_name;
498 } else {
499 merged->auditlog_fd = parent->auditlog_fd;
500 merged->auditlog_name = parent->auditlog_name;
501 }
502 if (child->auditlog2_fd != NOT_SET_P) {
503 merged->auditlog2_fd = child->auditlog2_fd;
504 merged->auditlog2_name = child->auditlog2_name;
505 } else {
506 merged->auditlog2_fd = parent->auditlog2_fd;
507 merged->auditlog2_name = parent->auditlog2_name;
508 }
509 #ifdef WITH_YAJL
510 merged->auditlog_format = (child->auditlog_format == NOT_SET
511 ? parent->auditlog_format : child->auditlog_format);
512 #endif
513 merged->auditlog_storage_dir = (child->auditlog_storage_dir == NOT_SET_P
514 ? parent->auditlog_storage_dir : child->auditlog_storage_dir);
515 merged->auditlog_parts = (child->auditlog_parts == NOT_SET_P
516 ? parent->auditlog_parts : child->auditlog_parts);
517 merged->auditlog_relevant_regex = (child->auditlog_relevant_regex == NOT_SET_P
518 ? parent->auditlog_relevant_regex : child->auditlog_relevant_regex);
519
520 /* Upload */
521 merged->tmp_dir = (child->tmp_dir == NOT_SET_P
522 ? parent->tmp_dir : child->tmp_dir);
523 merged->upload_dir = (child->upload_dir == NOT_SET_P
524 ? parent->upload_dir : child->upload_dir);
525 merged->upload_keep_files = (child->upload_keep_files == NOT_SET
526 ? parent->upload_keep_files : child->upload_keep_files);
527 merged->upload_validates_files = (child->upload_validates_files == NOT_SET
528 ? parent->upload_validates_files : child->upload_validates_files);
529 merged->upload_filemode = (child->upload_filemode == NOT_SET
530 ? parent->upload_filemode : child->upload_filemode);
531 merged->upload_file_limit = (child->upload_file_limit == NOT_SET
532 ? parent->upload_file_limit : child->upload_file_limit);
533
534 /* Misc */
535 merged->data_dir = (child->data_dir == NOT_SET_P
536 ? parent->data_dir : child->data_dir);
537 merged->webappid = (child->webappid == NOT_SET_P
538 ? parent->webappid : child->webappid);
539 merged->sensor_id = (child->sensor_id == NOT_SET_P
540 ? parent->sensor_id : child->sensor_id);
541 merged->httpBlkey = (child->httpBlkey == NOT_SET_P
542 ? parent->httpBlkey : child->httpBlkey);
543
544 /* Content injection. */
545 merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET
546 ? parent->content_injection_enabled : child->content_injection_enabled);
547
548 /* Stream inspection */
549 merged->stream_inbody_inspection = (child->stream_inbody_inspection == NOT_SET
550 ? parent->stream_inbody_inspection : child->stream_inbody_inspection);
551 merged->stream_outbody_inspection = (child->stream_outbody_inspection == NOT_SET
552 ? parent->stream_outbody_inspection : child->stream_outbody_inspection);
553
554 /* Geo Lookup */
555 merged->geo = (child->geo == NOT_SET_P
556 ? parent->geo : child->geo);
557
558 /* Gsb Lookup */
559 merged->gsb = (child->gsb == NOT_SET_P
560 ? parent->gsb : child->gsb);
561
562 /* Unicode Map */
563 merged->u_map = (child->u_map == NOT_SET_P
564 ? parent->u_map : child->u_map);
565
566 /* Cache */
567 merged->cache_trans = (child->cache_trans == NOT_SET
568 ? parent->cache_trans : child->cache_trans);
569 merged->cache_trans_incremental = (child->cache_trans_incremental == NOT_SET
570 ? parent->cache_trans_incremental : child->cache_trans_incremental);
571 merged->cache_trans_min = (child->cache_trans_min == (apr_size_t)NOT_SET
572 ? parent->cache_trans_min : child->cache_trans_min);
573 merged->cache_trans_max = (child->cache_trans_max == (apr_size_t)NOT_SET
574 ? parent->cache_trans_max : child->cache_trans_max);
575 merged->cache_trans_maxitems = (child->cache_trans_maxitems == (apr_size_t)NOT_SET
576 ? parent->cache_trans_maxitems : child->cache_trans_maxitems);
577
578 /* Merge component signatures. */
579 merged->component_signatures = apr_array_append(mp, parent->component_signatures,
580 child->component_signatures);
581
582 merged->request_encoding = (child->request_encoding == NOT_SET_P
583 ? parent->request_encoding : child->request_encoding);
584
585 merged->disable_backend_compression = (child->disable_backend_compression == NOT_SET
586 ? parent->disable_backend_compression : child->disable_backend_compression);
587
588 merged->col_timeout = (child->col_timeout == NOT_SET
589 ? parent->col_timeout : child->col_timeout);
590
591 /* Hash */
592 merged->crypto_key = (child->crypto_key == NOT_SET_P
593 ? parent->crypto_key : child->crypto_key);
594 merged->crypto_key_len = (child->crypto_key_len == NOT_SET
595 ? parent->crypto_key_len : child->crypto_key_len);
596 merged->crypto_key_add = (child->crypto_key_add == NOT_SET
597 ? parent->crypto_key_add : child->crypto_key_add);
598 merged->crypto_param_name = (child->crypto_param_name == NOT_SET_P
599 ? parent->crypto_param_name : child->crypto_param_name);
600 merged->hash_is_enabled = (child->hash_is_enabled == NOT_SET
601 ? parent->hash_is_enabled : child->hash_is_enabled);
602 merged->hash_enforcement = (child->hash_enforcement == NOT_SET
603 ? parent->hash_enforcement : child->hash_enforcement);
604 merged->crypto_hash_href_rx = (child->crypto_hash_href_rx == NOT_SET
605 ? parent->crypto_hash_href_rx : child->crypto_hash_href_rx);
606 merged->crypto_hash_faction_rx = (child->crypto_hash_faction_rx == NOT_SET
607 ? parent->crypto_hash_faction_rx : child->crypto_hash_faction_rx);
608 merged->crypto_hash_location_rx = (child->crypto_hash_location_rx == NOT_SET
609 ? parent->crypto_hash_location_rx : child->crypto_hash_location_rx);
610 merged->crypto_hash_iframesrc_rx = (child->crypto_hash_iframesrc_rx == NOT_SET
611 ? parent->crypto_hash_iframesrc_rx : child->crypto_hash_iframesrc_rx);
612 merged->crypto_hash_framesrc_rx = (child->crypto_hash_framesrc_rx == NOT_SET
613 ? parent->crypto_hash_framesrc_rx : child->crypto_hash_framesrc_rx);
614 merged->crypto_hash_href_pm = (child->crypto_hash_href_pm == NOT_SET
615 ? parent->crypto_hash_href_pm : child->crypto_hash_href_pm);
616 merged->crypto_hash_faction_pm = (child->crypto_hash_faction_pm == NOT_SET
617 ? parent->crypto_hash_faction_pm : child->crypto_hash_faction_pm);
618 merged->crypto_hash_location_pm = (child->crypto_hash_location_pm == NOT_SET
619 ? parent->crypto_hash_location_pm : child->crypto_hash_location_pm);
620 merged->crypto_hash_iframesrc_pm = (child->crypto_hash_iframesrc_pm == NOT_SET
621 ? parent->crypto_hash_iframesrc_pm : child->crypto_hash_iframesrc_pm);
622 merged->crypto_hash_framesrc_pm = (child->crypto_hash_framesrc_pm == NOT_SET
623 ? parent->crypto_hash_framesrc_pm : child->crypto_hash_framesrc_pm);
624
625 /* xml external entity */
626 merged->xml_external_entity = (child->xml_external_entity == NOT_SET
627 ? parent->xml_external_entity : child->xml_external_entity);
628
629 return merged;
630 }
631
632 /**
633 * Initialise directory configuration. This function is *not* meant
634 * to be called for directory configuration instances created during
635 * the configuration phase. It can only be called on copies of those
636 * (created fresh for every transaction).
637 */
init_directory_config(directory_config * dcfg)638 void init_directory_config(directory_config *dcfg)
639 {
640 if (dcfg == NULL) return;
641
642 if (dcfg->is_enabled == NOT_SET) dcfg->is_enabled = 0;
643
644 if (dcfg->reqbody_access == NOT_SET) dcfg->reqbody_access = 0;
645 if (dcfg->reqintercept_oe == NOT_SET) dcfg->reqintercept_oe = 0;
646 if (dcfg->reqbody_buffering == NOT_SET) dcfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_OFF;
647 if (dcfg->reqbody_inmemory_limit == NOT_SET)
648 dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT;
649 if (dcfg->reqbody_limit == NOT_SET) dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT;
650 if (dcfg->reqbody_no_files_limit == NOT_SET) dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT;
651 if (dcfg->resbody_access == NOT_SET) dcfg->resbody_access = 0;
652 if (dcfg->of_limit == NOT_SET) dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT;
653 if (dcfg->if_limit_action == NOT_SET) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT;
654 if (dcfg->of_limit_action == NOT_SET) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
655
656 if (dcfg->of_mime_types == NOT_SET_P) {
657 dcfg->of_mime_types = apr_table_make(dcfg->mp, 3);
658 if (dcfg->of_mime_types_cleared != 1) {
659 apr_table_setn(dcfg->of_mime_types, "text/plain", "1");
660 apr_table_setn(dcfg->of_mime_types, "text/html", "1");
661 }
662 }
663
664 if (dcfg->debuglog_fd == NOT_SET_P) dcfg->debuglog_fd = NULL;
665 if (dcfg->debuglog_name == NOT_SET_P) dcfg->debuglog_name = NULL;
666 if (dcfg->debuglog_level == NOT_SET) dcfg->debuglog_level = 0;
667
668 if (dcfg->cookie_format == NOT_SET) dcfg->cookie_format = 0;
669 if (dcfg->argument_separator == NOT_SET) dcfg->argument_separator = '&';
670 if (dcfg->cookiev0_separator == NOT_SET_P) dcfg->cookiev0_separator = NULL;
671
672 if (dcfg->rule_inheritance == NOT_SET) dcfg->rule_inheritance = 1;
673
674 /* audit log variables */
675 if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0;
676 if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL;
677 #ifdef WITH_YAJL
678 if (dcfg->auditlog_format == NOT_SET) dcfg->auditlog_format = AUDITLOGFORMAT_NATIVE;
679 #endif
680 if (dcfg->max_rule_time == NOT_SET) dcfg->max_rule_time = 0;
681 if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR;
682 if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE;
683 if (dcfg->auditlog_fd == NOT_SET_P) dcfg->auditlog_fd = NULL;
684 if (dcfg->auditlog2_fd == NOT_SET_P) dcfg->auditlog2_fd = NULL;
685 if (dcfg->auditlog_name == NOT_SET_P) dcfg->auditlog_name = NULL;
686 if (dcfg->auditlog2_name == NOT_SET_P) dcfg->auditlog2_name = NULL;
687 if (dcfg->auditlog_storage_dir == NOT_SET_P) dcfg->auditlog_storage_dir = NULL;
688 if (dcfg->auditlog_parts == NOT_SET_P) dcfg->auditlog_parts = "ABCFHZ";
689 if (dcfg->auditlog_relevant_regex == NOT_SET_P) dcfg->auditlog_relevant_regex = NULL;
690
691 /* Upload */
692 if (dcfg->tmp_dir == NOT_SET_P) dcfg->tmp_dir = guess_tmp_dir(dcfg->mp);
693 if (dcfg->upload_dir == NOT_SET_P) dcfg->upload_dir = NULL;
694 if (dcfg->upload_keep_files == NOT_SET) dcfg->upload_keep_files = KEEP_FILES_OFF;
695 if (dcfg->upload_validates_files == NOT_SET) dcfg->upload_validates_files = 0;
696 if (dcfg->upload_filemode == NOT_SET) dcfg->upload_filemode = 0600;
697 if (dcfg->upload_file_limit == NOT_SET) dcfg->upload_file_limit = 100;
698
699 /* Misc */
700 if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL;
701 if (dcfg->webappid == NOT_SET_P) dcfg->webappid = "default";
702 if (dcfg->sensor_id == NOT_SET_P) dcfg->sensor_id = "default";
703 if (dcfg->httpBlkey == NOT_SET_P) dcfg->httpBlkey = NULL;
704
705 /* Content injection. */
706 if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0;
707
708 /* Stream inspection */
709 if (dcfg->stream_inbody_inspection == NOT_SET) dcfg->stream_inbody_inspection = 0;
710 if (dcfg->stream_outbody_inspection == NOT_SET) dcfg->stream_outbody_inspection = 0;
711
712 /* Geo Lookup */
713 if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL;
714
715 /* Gsb Lookup */
716 if (dcfg->gsb == NOT_SET_P) dcfg->gsb = NULL;
717
718 /* Unicode Map */
719 if (dcfg->u_map == NOT_SET_P) dcfg->u_map = NULL;
720
721 /* Cache */
722 if (dcfg->cache_trans == NOT_SET) dcfg->cache_trans = MODSEC_CACHE_DISABLED;
723 if (dcfg->cache_trans_incremental == NOT_SET) dcfg->cache_trans_incremental = 0;
724 if (dcfg->cache_trans_min == (apr_size_t)NOT_SET) dcfg->cache_trans_min = 32;
725 if (dcfg->cache_trans_max == (apr_size_t)NOT_SET) dcfg->cache_trans_max = 1024;
726 if (dcfg->cache_trans_maxitems == (apr_size_t)NOT_SET) dcfg->cache_trans_maxitems = 512;
727
728 if (dcfg->request_encoding == NOT_SET_P) dcfg->request_encoding = NULL;
729
730 if (dcfg->disable_backend_compression == NOT_SET) dcfg->disable_backend_compression = 0;
731
732 if (dcfg->col_timeout == NOT_SET) dcfg->col_timeout = 3600;
733
734 /* Hash */
735 if (dcfg->hash_is_enabled == HASH_ENABLED) {
736 if (dcfg->crypto_key == NOT_SET_P) dcfg->crypto_key = getkey(dcfg->mp);
737 if (dcfg->crypto_key_len == NOT_SET) dcfg->crypto_key_len = strlen(dcfg->crypto_key);
738 } else {
739 if (dcfg->crypto_key == NOT_SET_P) dcfg->crypto_key = "";
740 if (dcfg->crypto_key_len == NOT_SET) dcfg->crypto_key_len = 0;
741 }
742 if (dcfg->crypto_key_add == NOT_SET) dcfg->crypto_key_add = HASH_KEYONLY;
743 if (dcfg->crypto_param_name == NOT_SET_P) dcfg->crypto_param_name = "crypt";
744 if (dcfg->hash_is_enabled == NOT_SET) dcfg->hash_is_enabled = HASH_DISABLED;
745 if (dcfg->hash_enforcement == NOT_SET) dcfg->hash_enforcement = HASH_DISABLED;
746 if (dcfg->crypto_hash_href_rx == NOT_SET) dcfg->crypto_hash_href_rx = 0;
747 if (dcfg->crypto_hash_faction_rx == NOT_SET) dcfg->crypto_hash_faction_rx = 0;
748 if (dcfg->crypto_hash_location_rx == NOT_SET) dcfg->crypto_hash_location_rx = 0;
749 if (dcfg->crypto_hash_iframesrc_rx == NOT_SET) dcfg->crypto_hash_iframesrc_rx = 0;
750 if (dcfg->crypto_hash_framesrc_rx == NOT_SET) dcfg->crypto_hash_framesrc_rx = 0;
751 if (dcfg->crypto_hash_href_pm == NOT_SET) dcfg->crypto_hash_href_pm = 0;
752 if (dcfg->crypto_hash_faction_pm == NOT_SET) dcfg->crypto_hash_faction_pm = 0;
753 if (dcfg->crypto_hash_location_pm == NOT_SET) dcfg->crypto_hash_location_pm = 0;
754 if (dcfg->crypto_hash_iframesrc_pm == NOT_SET) dcfg->crypto_hash_iframesrc_pm = 0;
755 if (dcfg->crypto_hash_framesrc_pm == NOT_SET) dcfg->crypto_hash_framesrc_pm = 0;
756
757 /* xml external entity */
758 if (dcfg->xml_external_entity == NOT_SET) dcfg->xml_external_entity = 0;
759
760 }
761
762 /**
763 *
764 */
add_rule(cmd_parms * cmd,directory_config * dcfg,int type,const char * p1,const char * p2,const char * p3)765 static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
766 const char *p1, const char *p2, const char *p3)
767 {
768 char *my_error_msg = NULL;
769 //msre_rule *rule = NULL, *tmp_rule = NULL;
770 char *rid = NULL;
771 msre_rule *rule = NULL;
772 extern msc_engine *modsecurity;
773 int type_with_lua = 1;
774 int type_rule;
775 int rule_actionset;
776 int offset = 0;
777
778 #ifdef DEBUG_CONF
779 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
780 "Rule: type=%d p1='%s' p2='%s' p3='%s'", type, p1, p2, p3);
781 #endif
782
783 /* Create a ruleset if one does not exist. */
784 if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) {
785 dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool);
786 if (dcfg->ruleset == NULL) return FATAL_ERROR;
787 }
788
789 /* Create the rule now. */
790 switch(type) {
791 #if defined(WITH_LUA)
792 case RULE_TYPE_LUA :
793 rule = msre_rule_lua_create(dcfg->ruleset, cmd->directive->filename,
794 cmd->directive->line_num, p1, p2, &my_error_msg);
795 break;
796 #endif
797 default :
798 rule = msre_rule_create(dcfg->ruleset, type, cmd->directive->filename,
799 cmd->directive->line_num, p1, p2, p3, &my_error_msg);
800 break;
801 }
802
803 if (rule == NULL) {
804 return my_error_msg;
805 }
806
807 #ifndef ALLOW_ID_NOT_UNIQUE
808 /* Rules must have uniq ID */
809 type_rule = (dcfg->tmp_chain_starter == NULL);
810 #if defined(WITH_LUA)
811 type_rule = (type != RULE_TYPE_LUA && type_rule);
812 #endif
813 if (type_rule)
814 if(rule->actionset == NULL)
815 return "ModSecurity: Rules must have at least id action";
816
817 if(rule->actionset != NULL && (dcfg->tmp_chain_starter == NULL)) {
818 rule_actionset = (rule->actionset->id == NOT_SET_P);
819 #if defined(WITH_LUA)
820 rule_actionset = (rule_actionset && (type != RULE_TYPE_LUA));
821 #endif
822 if (rule_actionset)
823 return "ModSecurity: No action id present within the rule";
824 #if defined(WITH_LUA)
825 type_with_lua = (type != RULE_TYPE_LUA);
826 #endif
827 if (type_with_lua){
828 rid = apr_hash_get(dcfg->rule_id_htab, rule->actionset->id, APR_HASH_KEY_STRING);
829 if(rid != NULL) {
830 return "ModSecurity: Found another rule with the same id";
831 } else {
832 apr_hash_set(dcfg->rule_id_htab, apr_pstrdup(dcfg->mp, rule->actionset->id), APR_HASH_KEY_STRING, apr_pstrdup(dcfg->mp, "1"));
833 }
834
835 //tmp_rule = msre_ruleset_fetch_rule(dcfg->ruleset, rule->actionset->id, offset);
836 //if(tmp_rule != NULL)
837 // return "ModSecurity: Found another rule with the same id";
838 }
839 }
840 #endif
841
842 /* Create default actionset if one does not already exist. */
843 if (dcfg->tmp_default_actionset == NULL) {
844 dcfg->tmp_default_actionset = msre_actionset_create_default(modsecurity->msre);
845 if (dcfg->tmp_default_actionset == NULL) return FATAL_ERROR;
846 }
847
848 /* Check some cases prior to merging so we know where it came from */
849
850 /* Check syntax for chained rules */
851 if ((rule->actionset != NULL) && (dcfg->tmp_chain_starter != NULL)) {
852 /* Must NOT specify a disruptive action. */
853 if (rule->actionset->intercept_action != NOT_SET) {
854 return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions can only "
855 "be specified by chain starter rules.");
856 }
857
858 /* Must NOT specify a skipafter action. */
859 if (rule->actionset->skip_after != NOT_SET_P) {
860 return apr_psprintf(cmd->pool, "ModSecurity: SkipAfter actions can only "
861 "be specified by chain starter rules.");
862 }
863
864 /* Must NOT specify a phase. */
865 if (rule->actionset->phase != NOT_SET) {
866 return apr_psprintf(cmd->pool, "ModSecurity: Execution phases can only be "
867 "specified by chain starter rules.");
868 }
869
870 /* Must NOT use metadata actions. */
871 /* ENH: loop through to check for tags */
872 if ((rule->actionset->id != NOT_SET_P)
873 ||(rule->actionset->rev != NOT_SET_P)
874 ||(rule->actionset->msg != NOT_SET_P)
875 ||(rule->actionset->severity != NOT_SET)
876 ||(rule->actionset->version != NOT_SET_P)
877 ||(rule->actionset->accuracy != NOT_SET)
878 ||(rule->actionset->maturity != NOT_SET)
879 ||(rule->actionset->logdata != NOT_SET_P))
880 {
881 return apr_psprintf(cmd->pool, "ModSecurity: Metadata actions (id, rev, msg, tag, severity, ver, accuracy, maturity, logdata) "
882 " can only be specified by chain starter rules.");
883 }
884
885 /* Must NOT use skip. */
886 if (rule->actionset->skip_count != NOT_SET) {
887 return apr_psprintf(cmd->pool, "ModSecurity: The skip action can only be used "
888 " by chain starter rules. ");
889 }
890 }
891
892 /* Merge actions with the parent.
893 *
894 * ENH Probably do not want this done fully for chained rules.
895 */
896 rule->actionset = msre_actionset_merge(modsecurity->msre, cmd->pool, dcfg->tmp_default_actionset,
897 rule->actionset, 1);
898
899 /* Keep track of the parent action for "block" */
900 if (rule->actionset) {
901 rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec;
902 rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action;
903 }
904
905 /* Must NOT specify a disruptive action in logging phase. */
906 if ((rule->actionset != NULL)
907 && (rule->actionset->phase == PHASE_LOGGING)
908 && (rule->actionset->intercept_action != ACTION_ALLOW)
909 && (rule->actionset->intercept_action != ACTION_ALLOW_REQUEST)
910 && (rule->actionset->intercept_action != ACTION_NONE)
911 ) {
912 return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions "
913 "cannot be specified in the logging phase.");
914 }
915
916 if (dcfg->tmp_chain_starter != NULL) {
917 rule->chain_starter = dcfg->tmp_chain_starter;
918 if (rule->actionset) {
919 rule->actionset->phase = rule->chain_starter->actionset->phase;
920 }
921 }
922
923 if (rule->actionset->is_chained != 1) {
924 /* If this rule is part of the chain but does
925 * not want more rules to follow in the chain
926 * then cut it (the chain).
927 */
928 dcfg->tmp_chain_starter = NULL;
929 } else {
930 /* On the other hand, if this rule wants other
931 * rules to follow it, then start a new chain
932 * if there isn't one already.
933 */
934 if (dcfg->tmp_chain_starter == NULL) {
935 dcfg->tmp_chain_starter = rule;
936 }
937 }
938
939 /* Create skip table if one does not already exist. */
940 if (dcfg->tmp_rule_placeholders == NULL) {
941 dcfg->tmp_rule_placeholders = apr_table_make(cmd->pool, 10);
942 if (dcfg->tmp_rule_placeholders == NULL) return FATAL_ERROR;
943 }
944
945 /* Keep track of any rule IDs we need to skip after */
946 if (rule->actionset->skip_after != NOT_SET_P) {
947 char *tmp_id = apr_pstrdup(cmd->pool, rule->actionset->skip_after);
948 apr_table_setn(dcfg->tmp_rule_placeholders, tmp_id, tmp_id);
949
950 #ifdef DEBUG_CONF
951 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
952 "Watching for skipafter target rule id=\"%s\".", tmp_id);
953 #endif
954
955 }
956
957 #ifdef DEBUG_CONF
958 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
959 "Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, (rule->actionset->id == NOT_SET_P
960 ? "(none)" : rule->actionset->id));
961 #endif
962
963 /* Add rule to the recipe. */
964 if (msre_ruleset_rule_add(dcfg->ruleset, rule, rule->actionset->phase) < 0) {
965 return "Internal Error: Failed to add rule to the ruleset.";
966 }
967
968 /* Add an additional placeholder if this rule ID is on the list */
969 if ((rule->actionset->id != NULL) && apr_table_get(dcfg->tmp_rule_placeholders, rule->actionset->id)) {
970 msre_rule *phrule = apr_palloc(rule->ruleset->mp, sizeof(msre_rule));
971 if (phrule == NULL) {
972 return FATAL_ERROR;
973 }
974
975 #ifdef DEBUG_CONF
976 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
977 "Adding placeholder %pp for rule %pp id=\"%s\".", phrule, rule, rule->actionset->id);
978 #endif
979
980 /* shallow copy of original rule with placeholder marked as target */
981 memcpy(phrule, rule, sizeof(msre_rule));
982 phrule->placeholder = RULE_PH_SKIPAFTER;
983
984 /* Add placeholder. */
985 if (msre_ruleset_rule_add(dcfg->ruleset, phrule, phrule->actionset->phase) < 0) {
986 return "Internal Error: Failed to add placeholder to the ruleset.";
987 }
988
989 /* No longer need to search for the ID */
990 apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id);
991 }
992
993 /* Update the unparsed rule */
994 rule->unparsed = msre_rule_generate_unparsed(dcfg->ruleset->mp, rule, NULL, NULL, NULL);
995
996 return NULL;
997 }
998
999 /**
1000 *
1001 */
add_marker(cmd_parms * cmd,directory_config * dcfg,const char * p1,const char * p2,const char * p3)1002 static const char *add_marker(cmd_parms *cmd, directory_config *dcfg,
1003 const char *p1, const char *p2, const char *p3)
1004 {
1005 char *my_error_msg = NULL;
1006 msre_rule *rule = NULL;
1007 extern msc_engine *modsecurity;
1008 int p;
1009
1010 #ifdef DEBUG_CONF
1011 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
1012 "Rule: type=%d p1='%s' p2='%s' p3='%s'", RULE_TYPE_MARKER, p1, p2, p3);
1013 #endif
1014
1015 /* Create a ruleset if one does not exist. */
1016 if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) {
1017 dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool);
1018 if (dcfg->ruleset == NULL) return FATAL_ERROR;
1019 }
1020
1021 /* Create the rule now. */
1022 rule = msre_rule_create(dcfg->ruleset, RULE_TYPE_MARKER, cmd->directive->filename, cmd->directive->line_num, p1, p2, p3, &my_error_msg);
1023 if (rule == NULL) {
1024 return my_error_msg;
1025 }
1026
1027 /* This is a marker */
1028 rule->placeholder = RULE_PH_MARKER;
1029
1030 /* Add placeholder to each phase */
1031 for (p = PHASE_FIRST; p <= PHASE_LAST; p++) {
1032 #ifdef DEBUG_CONF
1033 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
1034 "Adding marker %pp phase=%d id=\"%s\".", rule, p, (rule->actionset->id == NOT_SET_P
1035 ? "(none)" : rule->actionset->id));
1036 #endif
1037
1038 if (msre_ruleset_rule_add(dcfg->ruleset, rule, p) < 0) {
1039 return "Internal Error: Failed to add marker to the ruleset.";
1040 }
1041 }
1042
1043 /* No longer need to search for the ID */
1044 if (dcfg->tmp_rule_placeholders != NULL) {
1045 apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id);
1046 }
1047
1048 return NULL;
1049 }
1050
1051 /**
1052 *
1053 */
update_rule_action(cmd_parms * cmd,directory_config * dcfg,const char * p1,const char * p2,int offset)1054 static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg,
1055 const char *p1, const char *p2, int offset)
1056 {
1057 char *my_error_msg = NULL;
1058 msre_rule *rule = NULL;
1059 msre_actionset *new_actionset = NULL;
1060 msre_ruleset *ruleset = dcfg->ruleset;
1061 extern msc_engine *modsecurity;
1062
1063 /* Get the ruleset if one exists */
1064 if ((ruleset == NULL)||(ruleset == NOT_SET_P)) {
1065 return NULL;
1066 }
1067
1068 #ifdef DEBUG_CONF
1069 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
1070 "Update rule id=\"%s\" with action \"%s\".", p1, p2);
1071 #endif
1072
1073 /* Fetch the rule */
1074 rule = msre_ruleset_fetch_rule(ruleset, p1, offset);
1075 if (rule == NULL) {
1076 #ifdef DEBUG_CONF
1077 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
1078 "Update rule id=\"%s\" with action \"%s\" failed: Rule not found.", p1, p2);
1079 #endif
1080 return NULL;
1081 }
1082
1083 /* Check the rule actionset */
1084 /* ENH: Can this happen? */
1085 if (rule->actionset == NULL) {
1086 return apr_psprintf(cmd->pool, "ModSecurity: Attempt to update action for rule \"%s\" failed: Rule does not have an actionset.", p1);
1087 }
1088
1089 /* Create a new actionset */
1090 new_actionset = msre_actionset_create(modsecurity->msre, cmd->pool, p2, &my_error_msg);
1091 if (new_actionset == NULL) return FATAL_ERROR;
1092 if (my_error_msg != NULL) return my_error_msg;
1093
1094 /* Must NOT change an id */
1095 if ((new_actionset->id != NOT_SET_P) && (rule->actionset->id != NULL) && (strcmp(rule->actionset->id, new_actionset->id) != 0)) {
1096 return apr_psprintf(cmd->pool, "ModSecurity: Rule IDs cannot be updated via SecRuleUpdateActionById.");
1097 }
1098
1099 /* Must NOT alter the phase */
1100 if ((new_actionset->phase != NOT_SET) && (rule->actionset->phase != new_actionset->phase)) {
1101 return apr_psprintf(cmd->pool, "ModSecurity: Rule phases cannot be updated via SecRuleUpdateActionById.");
1102 }
1103
1104 #ifdef DEBUG_CONF
1105 {
1106 char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
1107 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
1108 "Update rule %pp id=\"%s\" old action: \"%s\"",
1109 rule,
1110 (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
1111 actions);
1112 }
1113 #endif
1114
1115 /* Merge new actions with the rule */
1116 /* ENH: Will this leak the old actionset? */
1117 rule->actionset = msre_actionset_merge(modsecurity->msre, cmd->pool, rule->actionset,
1118 new_actionset, 1);
1119 msre_actionset_set_defaults(rule->actionset);
1120
1121 /* Update the unparsed rule */
1122 rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, NULL, NULL, NULL);
1123
1124 #ifdef DEBUG_CONF
1125 {
1126 char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
1127 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
1128 "Update rule %pp id=\"%s\" new action: \"%s\"",
1129 rule,
1130 (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
1131 actions);
1132 }
1133 #endif
1134
1135 return NULL;
1136 }
1137
1138 /* -- Configuration directives -- */
1139
cmd_action(cmd_parms * cmd,void * _dcfg,const char * p1)1140 static const char *cmd_action(cmd_parms *cmd, void *_dcfg, const char *p1)
1141 {
1142 return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_ACTION, SECACTION_TARGETS, SECACTION_ARGS, p1);
1143 }
1144
cmd_marker(cmd_parms * cmd,void * _dcfg,const char * p1)1145 static const char *cmd_marker(cmd_parms *cmd, void *_dcfg, const char *p1)
1146 {
1147 directory_config *dcfg = (directory_config *)_dcfg;
1148 const char *action = apr_pstrcat(dcfg->mp, SECMARKER_BASE_ACTIONS, p1, NULL);
1149 return add_marker(cmd, (directory_config *)_dcfg, SECMARKER_TARGETS, SECMARKER_ARGS, action);
1150 }
1151
cmd_cookiev0_separator(cmd_parms * cmd,void * _dcfg,const char * p1)1152 static const char *cmd_cookiev0_separator(cmd_parms *cmd, void *_dcfg,
1153 const char *p1)
1154 {
1155 directory_config *dcfg = (directory_config *)_dcfg;
1156
1157 if (strlen(p1) != 1) {
1158 return apr_psprintf(cmd->pool, "ModSecurity: Invalid cookie v0 separator: %s", p1);
1159 }
1160
1161 dcfg->cookiev0_separator = p1;
1162
1163 return NULL;
1164 }
1165
cmd_argument_separator(cmd_parms * cmd,void * _dcfg,const char * p1)1166 static const char *cmd_argument_separator(cmd_parms *cmd, void *_dcfg,
1167 const char *p1)
1168 {
1169 directory_config *dcfg = (directory_config *)_dcfg;
1170
1171 if (strlen(p1) != 1) {
1172 return apr_psprintf(cmd->pool, "ModSecurity: Invalid argument separator: %s", p1);
1173 }
1174
1175 dcfg->argument_separator = p1[0];
1176
1177 return NULL;
1178 }
1179
cmd_audit_engine(cmd_parms * cmd,void * _dcfg,const char * p1)1180 static const char *cmd_audit_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
1181 {
1182 directory_config *dcfg = _dcfg;
1183
1184 if (strcasecmp(p1, "On") == 0) dcfg->auditlog_flag = AUDITLOG_ON;
1185 else
1186 if (strcasecmp(p1, "Off") == 0) dcfg->auditlog_flag = AUDITLOG_OFF;
1187 else
1188 if (strcasecmp(p1, "RelevantOnly") == 0) dcfg->auditlog_flag = AUDITLOG_RELEVANT;
1189 else
1190 return (const char *)apr_psprintf(cmd->pool,
1191 "ModSecurity: Unrecognised parameter value for SecAuditEngine: %s", p1);
1192
1193 return NULL;
1194 }
1195
cmd_audit_log(cmd_parms * cmd,void * _dcfg,const char * p1)1196 static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1)
1197 {
1198 directory_config *dcfg = _dcfg;
1199
1200 dcfg->auditlog_name = (char *)p1;
1201
1202 if (dcfg->auditlog_name[0] == '|') {
1203 const char *pipe_name = dcfg->auditlog_name + 1;
1204 piped_log *pipe_log;
1205
1206 pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
1207 if (pipe_log == NULL) {
1208 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log pipe: %s",
1209 pipe_name);
1210 }
1211 dcfg->auditlog_fd = ap_piped_log_write_fd(pipe_log);
1212 }
1213 else {
1214 const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog_name);
1215 apr_status_t rc;
1216
1217 if (dcfg->auditlog_fileperms == NOT_SET) {
1218 dcfg->auditlog_fileperms = CREATEMODE;
1219 }
1220 rc = apr_file_open(&dcfg->auditlog_fd, file_name,
1221 APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
1222 dcfg->auditlog_fileperms, cmd->pool);
1223
1224 if (rc != APR_SUCCESS) {
1225 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log file: %s",
1226 file_name);
1227 }
1228 }
1229
1230 return NULL;
1231 }
1232
cmd_audit_log2(cmd_parms * cmd,void * _dcfg,const char * p1)1233 static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1)
1234 {
1235 directory_config *dcfg = _dcfg;
1236
1237 if (dcfg->auditlog_name == NOT_SET_P) {
1238 return apr_psprintf(cmd->pool, "ModSecurity: Cannot configure a secondary audit log without a primary defined: %s", p1);
1239 }
1240
1241 dcfg->auditlog2_name = (char *)p1;
1242
1243 if (dcfg->auditlog2_name[0] == '|') {
1244 const char *pipe_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name + 1);
1245 piped_log *pipe_log;
1246
1247 pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
1248 if (pipe_log == NULL) {
1249 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log pipe: %s",
1250 pipe_name);
1251 }
1252 dcfg->auditlog2_fd = ap_piped_log_write_fd(pipe_log);
1253 }
1254 else {
1255 const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name);
1256 apr_status_t rc;
1257
1258 if (dcfg->auditlog_fileperms == NOT_SET) {
1259 dcfg->auditlog_fileperms = CREATEMODE;
1260 }
1261 rc = apr_file_open(&dcfg->auditlog2_fd, file_name,
1262 APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
1263 dcfg->auditlog_fileperms, cmd->pool);
1264
1265 if (rc != APR_SUCCESS) {
1266 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log file: %s",
1267 file_name);
1268 }
1269 }
1270
1271 return NULL;
1272 }
1273
cmd_audit_log_parts(cmd_parms * cmd,void * _dcfg,const char * p1)1274 static const char *cmd_audit_log_parts(cmd_parms *cmd, void *_dcfg,
1275 const char *p1)
1276 {
1277 directory_config *dcfg = _dcfg;
1278
1279 if (is_valid_parts_specification((char *)p1) != 1) {
1280 return apr_psprintf(cmd->pool, "Invalid parts specification for SecAuditLogParts: %s", p1);
1281 }
1282
1283 dcfg->auditlog_parts = (char *)p1;
1284 return NULL;
1285 }
1286
cmd_audit_log_relevant_status(cmd_parms * cmd,void * _dcfg,const char * p1)1287 static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg,
1288 const char *p1)
1289 {
1290 directory_config *dcfg = _dcfg;
1291
1292 dcfg->auditlog_relevant_regex = msc_pregcomp(cmd->pool, p1, PCRE_DOTALL, NULL, NULL);
1293 if (dcfg->auditlog_relevant_regex == NULL) {
1294 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
1295 }
1296
1297 return NULL;
1298 }
1299
cmd_audit_log_type(cmd_parms * cmd,void * _dcfg,const char * p1)1300 static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg,
1301 const char *p1)
1302 {
1303 directory_config *dcfg = _dcfg;
1304
1305 if (strcasecmp(p1, "Serial") == 0) dcfg->auditlog_type = AUDITLOG_SERIAL;
1306 else
1307 if (strcasecmp(p1, "Concurrent") == 0) dcfg->auditlog_type = AUDITLOG_CONCURRENT;
1308 else
1309 return (const char *)apr_psprintf(cmd->pool,
1310 "ModSecurity: Unrecognised parameter value for SecAuditLogType: %s", p1);
1311
1312 return NULL;
1313 }
1314
1315 #ifdef WITH_YAJL
cmd_audit_log_mode(cmd_parms * cmd,void * _dcfg,const char * p1)1316 static const char *cmd_audit_log_mode(cmd_parms *cmd, void *_dcfg,
1317 const char *p1)
1318 {
1319 directory_config *dcfg = _dcfg;
1320
1321 if (strcasecmp(p1, "JSON") == 0) dcfg->auditlog_format = AUDITLOGFORMAT_JSON;
1322 else
1323 if (strcasecmp(p1, "Native") == 0) dcfg->auditlog_format = AUDITLOGFORMAT_NATIVE;
1324 else
1325 return (const char *)apr_psprintf(cmd->pool,
1326 "ModSecurity: Unrecognised parameter value for SecAuditLogFormat: %s", p1);
1327
1328 return NULL;
1329 }
1330 #endif
1331
cmd_audit_log_dirmode(cmd_parms * cmd,void * _dcfg,const char * p1)1332 static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg,
1333 const char *p1)
1334 {
1335 directory_config *dcfg = (directory_config *)_dcfg;
1336
1337 if (dcfg == NULL) return NULL;
1338
1339 if (strcasecmp(p1, "default") == 0) {
1340 dcfg->auditlog_dirperms = NOT_SET;
1341 }
1342 else {
1343 long int mode = strtol(p1, NULL, 8); /* expects octal mode */
1344 if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
1345 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogDirMode: %s", p1);
1346 }
1347
1348 dcfg->auditlog_dirperms = mode2fileperms(mode);
1349 }
1350
1351 return NULL;
1352 }
1353
cmd_audit_log_filemode(cmd_parms * cmd,void * _dcfg,const char * p1)1354 static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg,
1355 const char *p1)
1356 {
1357 directory_config *dcfg = (directory_config *)_dcfg;
1358
1359 if (dcfg == NULL) return NULL;
1360
1361 if (strcasecmp(p1, "default") == 0) {
1362 dcfg->auditlog_fileperms = NOT_SET;
1363 }
1364 else {
1365 long int mode = strtol(p1, NULL, 8); /* expects octal mode */
1366 if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
1367 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogFileMode: %s", p1);
1368 }
1369
1370 dcfg->auditlog_fileperms = mode2fileperms(mode);
1371 }
1372
1373 return NULL;
1374 }
1375
cmd_audit_log_storage_dir(cmd_parms * cmd,void * _dcfg,const char * p1)1376 static const char *cmd_audit_log_storage_dir(cmd_parms *cmd, void *_dcfg,
1377 const char *p1)
1378 {
1379 directory_config *dcfg = _dcfg;
1380
1381 dcfg->auditlog_storage_dir = ap_server_root_relative(cmd->pool, p1);
1382
1383 return NULL;
1384 }
1385
cmd_cookie_format(cmd_parms * cmd,void * _dcfg,const char * p1)1386 static const char *cmd_cookie_format(cmd_parms *cmd, void *_dcfg,
1387 const char *p1)
1388 {
1389 directory_config *dcfg = (directory_config *)_dcfg;
1390
1391 if (strcmp(p1, "0") == 0) dcfg->cookie_format = COOKIES_V0;
1392 else
1393 if (strcmp(p1, "1") == 0) dcfg->cookie_format = COOKIES_V1;
1394 else {
1395 return apr_psprintf(cmd->pool, "ModSecurity: Invalid cookie format: %s", p1);
1396 }
1397
1398 return NULL;
1399 }
1400
cmd_chroot_dir(cmd_parms * cmd,void * _dcfg,const char * p1)1401 static const char *cmd_chroot_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
1402 {
1403 char cwd[1025] = "";
1404
1405 if (cmd->server->is_virtual) {
1406 return "ModSecurity: SecChrootDir not allowed in VirtualHost";
1407 }
1408
1409 chroot_dir = (char *)p1;
1410
1411 if (getcwd(cwd, 1024) == NULL) {
1412 return "ModSecurity: Failed to get the current working directory";
1413 }
1414
1415 if (chdir(chroot_dir) < 0) {
1416 return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)",
1417 chroot_dir, errno, strerror(errno));
1418 }
1419
1420 if (chdir(cwd) < 0) {
1421 return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)",
1422 cwd, errno, strerror(errno));
1423 }
1424
1425 return NULL;
1426 }
1427
1428 /**
1429 * Adds component signature to the list of signatures kept in configuration.
1430 */
cmd_component_signature(cmd_parms * cmd,void * _dcfg,const char * p1)1431 static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg,
1432 const char *p1)
1433 {
1434 directory_config *dcfg = (directory_config *)_dcfg;
1435
1436 /* ENH Enforce "Name/VersionX.Y.Z (comment)" format. */
1437 *(char **)apr_array_push(dcfg->component_signatures) = (char *)p1;
1438
1439 return NULL;
1440 }
1441
cmd_content_injection(cmd_parms * cmd,void * _dcfg,int flag)1442 static const char *cmd_content_injection(cmd_parms *cmd, void *_dcfg, int flag)
1443 {
1444 directory_config *dcfg = (directory_config *)_dcfg;
1445 if (dcfg == NULL) return NULL;
1446 dcfg->content_injection_enabled = flag;
1447 return NULL;
1448 }
1449
cmd_data_dir(cmd_parms * cmd,void * _dcfg,const char * p1)1450 static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
1451 {
1452 directory_config *dcfg = (directory_config *)_dcfg;
1453
1454 if (cmd->server->is_virtual) {
1455 return "ModSecurity: SecDataDir not allowed in VirtualHost.";
1456 }
1457
1458 dcfg->data_dir = ap_server_root_relative(cmd->pool, p1);
1459
1460 return NULL;
1461 }
1462
cmd_debug_log(cmd_parms * cmd,void * _dcfg,const char * p1)1463 static const char *cmd_debug_log(cmd_parms *cmd, void *_dcfg, const char *p1)
1464 {
1465 directory_config *dcfg = (directory_config *)_dcfg;
1466 apr_status_t rc;
1467
1468 dcfg->debuglog_name = ap_server_root_relative(cmd->pool, p1);
1469
1470 rc = apr_file_open(&dcfg->debuglog_fd, dcfg->debuglog_name,
1471 APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
1472 CREATEMODE, cmd->pool);
1473
1474 if (rc != APR_SUCCESS) {
1475 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open debug log file: %s",
1476 dcfg->debuglog_name);
1477 }
1478
1479 return NULL;
1480 }
1481
1482 /**
1483 * \brief Add SecCollectionTimeout configuration option
1484 *
1485 * \param cmd Pointer to configuration data
1486 * \param _dcfg Pointer to directory configuration
1487 * \param p1 Pointer to configuration option
1488 *
1489 * \retval NULL On failure
1490 * \retval apr_psprintf On Success
1491 */
cmd_collection_timeout(cmd_parms * cmd,void * _dcfg,const char * p1)1492 static const char *cmd_collection_timeout(cmd_parms *cmd, void *_dcfg,
1493 const char *p1)
1494 {
1495 directory_config *dcfg = (directory_config *)_dcfg;
1496
1497 dcfg->col_timeout = atoi(p1);
1498 /* max 30 days */
1499 if ((dcfg->col_timeout >= 0)&&(dcfg->col_timeout <= 2592000)) return NULL;
1500
1501 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecCollectionTimeout: %s", p1);
1502 }
1503
cmd_debug_log_level(cmd_parms * cmd,void * _dcfg,const char * p1)1504 static const char *cmd_debug_log_level(cmd_parms *cmd, void *_dcfg,
1505 const char *p1)
1506 {
1507 directory_config *dcfg = (directory_config *)_dcfg;
1508
1509 dcfg->debuglog_level = atoi(p1);
1510 if ((dcfg->debuglog_level >= 0)&&(dcfg->debuglog_level <= 9)) return NULL;
1511
1512 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecDebugLogLevel: %s", p1);
1513 }
1514
cmd_default_action(cmd_parms * cmd,void * _dcfg,const char * p1)1515 static const char *cmd_default_action(cmd_parms *cmd, void *_dcfg,
1516 const char *p1)
1517 {
1518 directory_config *dcfg = (directory_config *)_dcfg;
1519 extern msc_engine *modsecurity;
1520 char *my_error_msg = NULL;
1521
1522 dcfg->tmp_default_actionset = msre_actionset_create(modsecurity->msre, cmd->pool, p1, &my_error_msg);
1523 if (dcfg->tmp_default_actionset == NULL) {
1524 if (my_error_msg != NULL) return my_error_msg;
1525 else return FATAL_ERROR;
1526 }
1527
1528 /* Must specify a disruptive action. */
1529 /* ENH: Remove this requirement? */
1530 if (dcfg->tmp_default_actionset->intercept_action == NOT_SET) {
1531 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a disruptive action.");
1532 }
1533
1534 /* Must specify a phase. */
1535 /* ENH: Remove this requirement? */
1536 if (dcfg->tmp_default_actionset->phase == NOT_SET) {
1537 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a phase.");
1538 }
1539
1540 /* Must not use metadata actions. */
1541 /* ENH: loop through to check for tags */
1542 if ((dcfg->tmp_default_actionset->id != NOT_SET_P)
1543 ||(dcfg->tmp_default_actionset->rev != NOT_SET_P)
1544 ||(dcfg->tmp_default_actionset->version != NOT_SET_P)
1545 ||(dcfg->tmp_default_actionset->maturity != NOT_SET)
1546 ||(dcfg->tmp_default_actionset->accuracy != NOT_SET)
1547 ||(dcfg->tmp_default_actionset->msg != NOT_SET_P))
1548 {
1549 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1550 "contain any metadata actions (id, rev, msg, tag, severity, ver, accuracy, maturity, logdata).");
1551 }
1552 /* These are just a warning for now. */
1553 if ((dcfg->tmp_default_actionset->severity != NOT_SET)
1554 ||(dcfg->tmp_default_actionset->logdata != NOT_SET_P))
1555 {
1556 ap_log_perror(APLOG_MARK,
1557 APLOG_STARTUP|APLOG_WARNING|APLOG_NOERRNO, 0, cmd->pool,
1558 "ModSecurity: WARNING Using \"severity\" or \"logdata\" in "
1559 "SecDefaultAction is deprecated (%s:%d).",
1560 cmd->directive->filename, cmd->directive->line_num);
1561 }
1562
1563 if (apr_table_get(dcfg->tmp_default_actionset->actions, "t")) {
1564 ap_log_perror(APLOG_MARK,
1565 APLOG_STARTUP|APLOG_WARNING|APLOG_NOERRNO, 0, cmd->pool,
1566 "ModSecurity: WARNING Using transformations in "
1567 "SecDefaultAction is deprecated (%s:%d).",
1568 cmd->directive->filename, cmd->directive->line_num);
1569 }
1570
1571 /* Must not use chain. */
1572 if (dcfg->tmp_default_actionset->is_chained != NOT_SET) {
1573 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1574 "contain a chain action.");
1575 }
1576
1577 /* Must not use skip. */
1578 if (dcfg->tmp_default_actionset->skip_count != NOT_SET) {
1579 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1580 "contain a skip action.");
1581 }
1582
1583 /* Must not use skipAfter. */
1584 if (dcfg->tmp_default_actionset->skip_after != NOT_SET_P) {
1585 return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
1586 "contain a skipAfter action.");
1587 }
1588
1589 return NULL;
1590 }
1591
cmd_disable_backend_compression(cmd_parms * cmd,void * _dcfg,int flag)1592 static const char *cmd_disable_backend_compression(cmd_parms *cmd, void *_dcfg, int flag)
1593 {
1594 directory_config *dcfg = (directory_config *)_dcfg;
1595 if (dcfg == NULL) return NULL;
1596 dcfg->disable_backend_compression = flag;
1597 return NULL;
1598 }
1599
cmd_guardian_log(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2)1600 static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg,
1601 const char *p1, const char *p2)
1602 {
1603 extern char *guardianlog_name;
1604 extern apr_file_t *guardianlog_fd;
1605 extern char *guardianlog_condition;
1606
1607 if (cmd->server->is_virtual) {
1608 return "ModSecurity: SecGuardianLog not allowed in VirtualHost";
1609 }
1610
1611 if (p2 != NULL) {
1612 if (strncmp(p2, "env=", 4) != 0) {
1613 return "ModSecurity: Error in condition clause";
1614 }
1615 if ( (p2[4] == '\0') || ((p2[4] == '!')&&(p2[5] == '\0')) ) {
1616 return "ModSecurity: Missing variable name";
1617 }
1618 guardianlog_condition = apr_pstrdup(cmd->pool, p2 + 4);
1619 }
1620
1621 guardianlog_name = (char *)p1;
1622
1623 if (guardianlog_name[0] == '|') {
1624 const char *pipe_name = ap_server_root_relative(cmd->pool, guardianlog_name + 1);
1625 piped_log *pipe_log;
1626
1627 pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
1628 if (pipe_log == NULL) {
1629 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log pipe: %s",
1630 pipe_name);
1631 }
1632 guardianlog_fd = ap_piped_log_write_fd(pipe_log);
1633 }
1634 else {
1635 const char *file_name = ap_server_root_relative(cmd->pool, guardianlog_name);
1636 apr_status_t rc;
1637
1638 rc = apr_file_open(&guardianlog_fd, file_name,
1639 APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
1640 CREATEMODE, cmd->pool);
1641
1642 if (rc != APR_SUCCESS) {
1643 return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log file: %s",
1644 file_name);
1645 }
1646 }
1647
1648 return NULL;
1649 }
1650
1651 /**
1652 * \brief Add SecStreamInBodyInspection configuration option
1653 *
1654 * \param cmd Pointer to configuration data
1655 * \param _dcfg Pointer to directory configuration
1656 * \param p1 Pointer to configuration option
1657 *
1658 * \retval NULL On failure
1659 * \retval apr_psprintf On Success
1660 */
cmd_stream_inbody_inspection(cmd_parms * cmd,void * _dcfg,int flag)1661 static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int flag)
1662 {
1663 directory_config *dcfg = (directory_config *)_dcfg;
1664 if (dcfg == NULL) return NULL;
1665 dcfg->stream_inbody_inspection = flag;
1666 return NULL;
1667 }
1668
1669
1670 /**
1671 * \brief Add SecStreamOutBodyInspection configuration option
1672 *
1673 * \param cmd Pointer to configuration data
1674 * \param _dcfg Pointer to directory configuration
1675 * \param p1 Pointer to configuration option
1676 *
1677 * \retval NULL On failure
1678 * \retval apr_psprintf On Success
1679 */
cmd_stream_outbody_inspection(cmd_parms * cmd,void * _dcfg,int flag)1680 static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, int flag)
1681 {
1682 directory_config *dcfg = (directory_config *)_dcfg;
1683 if (dcfg == NULL) return NULL;
1684 dcfg->stream_outbody_inspection = flag;
1685 return NULL;
1686 }
1687 /**
1688 * \brief Add SecRulePerfTime configuration option
1689 *
1690 * \param cmd Pointer to configuration data
1691 * \param _dcfg Pointer to directory configuration
1692 * \param p1 Pointer to configuration option
1693 *
1694 * \retval NULL On failure
1695 * \retval apr_psprintf On Success
1696 */
cmd_rule_perf_time(cmd_parms * cmd,void * _dcfg,const char * p1)1697 static const char *cmd_rule_perf_time(cmd_parms *cmd, void *_dcfg,
1698 const char *p1)
1699 {
1700 directory_config *dcfg = (directory_config *)_dcfg;
1701 long int limit;
1702
1703 if (dcfg == NULL) return NULL;
1704
1705 limit = strtol(p1, NULL, 10);
1706 if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1707 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRulePerfTime: %s", p1);
1708 }
1709
1710 dcfg->max_rule_time = limit;
1711
1712 return NULL;
1713 }
1714
parser_conn_limits_operator(apr_pool_t * mp,const char * p2,TreeRoot ** whitelist,TreeRoot ** suspicious_list,const char * filename)1715 char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2,
1716 TreeRoot **whitelist, TreeRoot **suspicious_list,
1717 const char *filename)
1718 {
1719 int res = 0;
1720 char *config_orig_path;
1721 char *param = strchr(p2, ' ');
1722 char *file = NULL;
1723 char *error_msg = NULL;
1724 param++;
1725
1726 config_orig_path = apr_pstrndup(mp, filename,
1727 strlen(filename) - strlen(apr_filepath_name_get(filename)));
1728
1729 apr_filepath_merge(&file, config_orig_path, param, APR_FILEPATH_TRUENAME,
1730 mp);
1731
1732 if ((strncasecmp(p2, "!@ipMatchFromFile", strlen("!@ipMatchFromFile")) == 0) ||
1733 (strncasecmp(p2, "!@ipMatchF", strlen("!@ipMatchF")) == 0)) {
1734
1735 res = ip_tree_from_file(whitelist, file, mp, &error_msg);
1736 }
1737 else if (strncasecmp(p2, "!@ipMatch", strlen("!@ipMatch")) == 0) {
1738 res = ip_tree_from_param(mp, param, whitelist, &error_msg);
1739 }
1740 else if ((strncasecmp(p2, "@ipMatchFromFile", strlen("@ipMatchFromFile")) == 0) ||
1741 (strncasecmp(p2, "@ipMatchF", strlen("@ipMatchF")) == 0)) {
1742
1743 res = ip_tree_from_file(suspicious_list, file, mp, &error_msg);
1744 }
1745 else if (strncasecmp(p2, "@ipMatch", strlen("@ipMatch")) == 0) {
1746 res = ip_tree_from_param(mp, param, suspicious_list, &error_msg);
1747 }
1748 else {
1749 return apr_psprintf(mp, "ModSecurity: Invalid operator for " \
1750 "SecConnReadStateLimit: %s, expected operators: @ipMatch, @ipMatchF " \
1751 "or @ipMatchFromFile with or without !", p2);
1752 }
1753
1754 if (res) {
1755 char *error;
1756 error = apr_psprintf(mp, "ModSecurity: failed to load IPs " \
1757 "from: %s", param);
1758
1759 if (*error_msg) {
1760 error = apr_psprintf(mp, "%s %s", error, error_msg);
1761 }
1762
1763 return error;
1764 }
1765
1766 return NULL;
1767 }
1768
1769
1770 /**
1771 * \brief Add SecConnReadStateLimit configuration option
1772 *
1773 * \param cmd Pointer to configuration data
1774 * \param _dcfg Pointer to directory configuration
1775 * \param p1 Pointer to configuration option
1776 * \param p2 Pointer to configuration option
1777 *
1778 * \retval NULL On failure
1779 * \retval apr_psprintf On Success
1780 */
cmd_conn_read_state_limit(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2)1781 static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg,
1782 const char *p1, const char *p2)
1783 {
1784 directory_config *dcfg = (directory_config *)_dcfg;
1785 long int limit;
1786
1787 if (dcfg == NULL) return NULL;
1788
1789 limit = strtol(p1, NULL, 10);
1790 if ((limit == LONG_MAX) || (limit == LONG_MIN) || (limit <= 0)) {
1791 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \
1792 "SecConnReadStateLimit: %s", p1);
1793 }
1794
1795 if (p2 != NULL) {
1796 char *param = parser_conn_limits_operator(cmd->pool, p2,
1797 &conn_read_state_whitelist, &conn_read_state_suspicious_list,
1798 cmd->directive->filename);
1799
1800 if (param)
1801 return param;
1802 }
1803
1804 conn_read_state_limit = limit;
1805
1806 return NULL;
1807 }
1808
cmd_read_state_limit(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2)1809 static const char *cmd_read_state_limit(cmd_parms *cmd, void *_dcfg,
1810 const char *p1, const char *p2)
1811 {
1812 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
1813 "SecReadStateLimit is depricated, use SecConnReadStateLimit " \
1814 "instead.");
1815
1816 return cmd_conn_read_state_limit(cmd, _dcfg, p1, p2);
1817 }
1818
1819 /**
1820 * \brief Add SecConnWriteStateLimit configuration option
1821 *
1822 * \param cmd Pointer to configuration data
1823 * \param _dcfg Pointer to directory configuration
1824 * \param p1 Pointer to configuration option
1825 * \param p2 Pointer to configuration option
1826 *
1827 * \retval NULL On failure
1828 * \retval apr_psprintf On Success
1829 */
cmd_conn_write_state_limit(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2)1830 static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg,
1831 const char *p1, const char *p2)
1832 {
1833 directory_config *dcfg = (directory_config *)_dcfg;
1834 long int limit;
1835
1836 if (dcfg == NULL) return NULL;
1837
1838 limit = strtol(p1, NULL, 10);
1839 if ((limit == LONG_MAX) || (limit == LONG_MIN) || (limit <= 0)) {
1840 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \
1841 "SecConnWriteStateLimit: %s", p1);
1842 }
1843
1844 if (p2 != NULL) {
1845 char *param = parser_conn_limits_operator(cmd->pool, p2,
1846 &conn_write_state_whitelist, &conn_write_state_suspicious_list,
1847 cmd->directive->filename);
1848
1849 if (param)
1850 return param;
1851 }
1852
1853 conn_write_state_limit = limit;
1854
1855 return NULL;
1856 }
cmd_write_state_limit(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2)1857 static const char *cmd_write_state_limit(cmd_parms *cmd, void *_dcfg,
1858 const char *p1, const char *p2)
1859 {
1860 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
1861 "SecWriteStateLimit is depricated, use SecConnWriteStateLimit " \
1862 "instead.");
1863
1864 return cmd_conn_write_state_limit(cmd, _dcfg, p1, p2);
1865 }
1866
1867
1868
cmd_request_body_inmemory_limit(cmd_parms * cmd,void * _dcfg,const char * p1)1869 static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg,
1870 const char *p1)
1871 {
1872 directory_config *dcfg = (directory_config *)_dcfg;
1873 long int limit;
1874
1875 if (dcfg == NULL) return NULL;
1876
1877 limit = strtol(p1, NULL, 10);
1878 if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1879 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyInMemoryLimit: %s", p1);
1880 }
1881
1882 dcfg->reqbody_inmemory_limit = limit;
1883
1884 return NULL;
1885 }
1886
cmd_request_body_limit(cmd_parms * cmd,void * _dcfg,const char * p1)1887 static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg,
1888 const char *p1)
1889 {
1890 directory_config *dcfg = (directory_config *)_dcfg;
1891 long int limit;
1892
1893 if (dcfg == NULL) return NULL;
1894
1895 limit = strtol(p1, NULL, 10);
1896 if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1897 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimit: %s", p1);
1898 }
1899
1900 dcfg->reqbody_limit = limit;
1901
1902 return NULL;
1903 }
1904
cmd_request_body_no_files_limit(cmd_parms * cmd,void * _dcfg,const char * p1)1905 static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg,
1906 const char *p1)
1907 {
1908 directory_config *dcfg = (directory_config *)_dcfg;
1909 long int limit;
1910
1911 if (dcfg == NULL) return NULL;
1912
1913 limit = strtol(p1, NULL, 10);
1914 if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1915 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyNoFilesLimit: %s", p1);
1916 }
1917
1918 dcfg->reqbody_no_files_limit = limit;
1919
1920 return NULL;
1921 }
1922
cmd_request_body_access(cmd_parms * cmd,void * _dcfg,const char * p1)1923 static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg,
1924 const char *p1)
1925 {
1926 directory_config *dcfg = (directory_config *)_dcfg;
1927 if (dcfg == NULL) return NULL;
1928
1929 if (strcasecmp(p1, "on") == 0) dcfg->reqbody_access = 1;
1930 else
1931 if (strcasecmp(p1, "off") == 0) dcfg->reqbody_access = 0;
1932 else
1933 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyAccess: %s", p1);
1934
1935 return NULL;
1936 }
1937
1938 /**
1939 * \brief Add SecInterceptOnError configuration option
1940 *
1941 * \param cmd Pointer to configuration data
1942 * \param _dcfg Pointer to directory configuration
1943 * \param p1 Pointer to configuration option
1944 *
1945 * \retval NULL On failure
1946 * \retval apr_psprintf On success
1947 */
cmd_request_intercept_on_error(cmd_parms * cmd,void * _dcfg,const char * p1)1948 static const char *cmd_request_intercept_on_error(cmd_parms *cmd, void *_dcfg,
1949 const char *p1)
1950 {
1951 directory_config *dcfg = (directory_config *)_dcfg;
1952 if (dcfg == NULL) return NULL;
1953
1954 if (strcasecmp(p1, "on") == 0) dcfg->reqintercept_oe = 1;
1955 else
1956 if (strcasecmp(p1, "off") == 0) dcfg->reqintercept_oe = 0;
1957 else
1958 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecInterceptOnError: %s", p1);
1959
1960 return NULL;
1961 }
1962
1963
cmd_request_encoding(cmd_parms * cmd,void * _dcfg,const char * p1)1964 static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg,
1965 const char *p1)
1966 {
1967 directory_config *dcfg = (directory_config *)_dcfg;
1968 if (dcfg == NULL) return NULL;
1969
1970 /* ENH Validate encoding */
1971
1972 dcfg->request_encoding = p1;
1973
1974 return NULL;
1975 }
1976
cmd_response_body_access(cmd_parms * cmd,void * _dcfg,const char * p1)1977 static const char *cmd_response_body_access(cmd_parms *cmd, void *_dcfg,
1978 const char *p1)
1979 {
1980 directory_config *dcfg = (directory_config *)_dcfg;
1981 if (dcfg == NULL) return NULL;
1982
1983 if (strcasecmp(p1, "on") == 0) dcfg->resbody_access = 1;
1984 else
1985 if (strcasecmp(p1, "off") == 0) dcfg->resbody_access = 0;
1986 else
1987 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyAccess: %s", p1);
1988
1989 return NULL;
1990 }
1991
cmd_response_body_limit(cmd_parms * cmd,void * _dcfg,const char * p1)1992 static const char *cmd_response_body_limit(cmd_parms *cmd, void *_dcfg,
1993 const char *p1)
1994 {
1995 directory_config *dcfg = (directory_config *)_dcfg;
1996 long int limit;
1997
1998 limit = strtol(p1, NULL, 10);
1999 if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
2000 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimit: %s", p1);
2001 }
2002
2003 if (limit > RESPONSE_BODY_HARD_LIMIT) {
2004 return apr_psprintf(cmd->pool, "ModSecurity: Response size limit can not exceed the hard limit: %li", RESPONSE_BODY_HARD_LIMIT);
2005 }
2006
2007 dcfg->of_limit = limit;
2008
2009 return NULL;
2010 }
2011
cmd_response_body_limit_action(cmd_parms * cmd,void * _dcfg,const char * p1)2012 static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg,
2013 const char *p1)
2014 {
2015 directory_config *dcfg = (directory_config *)_dcfg;
2016 if (dcfg == NULL) return NULL;
2017
2018 if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) {
2019 dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
2020 return NULL;
2021 }
2022
2023 if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
2024 else
2025 if (strcasecmp(p1, "Reject") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
2026 else
2027 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimitAction: %s", p1);
2028
2029 return NULL;
2030 }
2031
2032 /**
2033 * \brief Add SecRequestBodyLimitAction configuration option
2034 *
2035 * \param cmd Pointer to configuration data
2036 * \param _dcfg Pointer to directory configuration
2037 * \param p1 Pointer to configuration option
2038 *
2039 * \retval NULL On failure
2040 * \retval apr_psprintf On success
2041 */
cmd_resquest_body_limit_action(cmd_parms * cmd,void * _dcfg,const char * p1)2042 static const char *cmd_resquest_body_limit_action(cmd_parms *cmd, void *_dcfg,
2043 const char *p1)
2044 {
2045 directory_config *dcfg = (directory_config *)_dcfg;
2046 if (dcfg == NULL) return NULL;
2047
2048 if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) {
2049 dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
2050 return NULL;
2051 }
2052
2053 if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
2054 else
2055 if (strcasecmp(p1, "Reject") == 0) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT;
2056 else
2057 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimitAction: %s", p1);
2058
2059 return NULL;
2060 }
2061
cmd_response_body_mime_type(cmd_parms * cmd,void * _dcfg,const char * _p1)2062 static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg,
2063 const char *_p1)
2064 {
2065 directory_config *dcfg = (directory_config *)_dcfg;
2066 char *p1 = apr_pstrdup(cmd->pool, _p1);
2067
2068 /* TODO check whether the parameter is a valid MIME type of "???" */
2069
2070 if ((dcfg->of_mime_types == NULL)||(dcfg->of_mime_types == NOT_SET_P)) {
2071 dcfg->of_mime_types = apr_table_make(cmd->pool, 10);
2072 }
2073
2074 strtolower_inplace((unsigned char *)p1);
2075 apr_table_setn(dcfg->of_mime_types, p1, "1");
2076
2077 return NULL;
2078 }
2079
cmd_response_body_mime_types_clear(cmd_parms * cmd,void * _dcfg)2080 static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd,
2081 void *_dcfg)
2082 {
2083 directory_config *dcfg = (directory_config *)_dcfg;
2084 if (dcfg == NULL) return NULL;
2085
2086 dcfg->of_mime_types_cleared = 1;
2087
2088 if ((dcfg->of_mime_types != NULL)&&(dcfg->of_mime_types != NOT_SET_P)) {
2089 apr_table_clear(dcfg->of_mime_types);
2090 }
2091
2092 return NULL;
2093 }
2094
2095 /**
2096 * \brief Add SecRuleUpdateTargetById
2097 *
2098 * \param cmd Pointer to configuration data
2099 * \param _dcfg Pointer to directory configuration
2100 * \param p1 Pointer to configuration option
2101 * \param p2 Pointer to configuration option
2102 * \param p3 Pointer to configuration option
2103 *
2104 * \retval NULL On failure|Success
2105 */
cmd_rule_update_target_by_id(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2,const char * p3)2106 static const char *cmd_rule_update_target_by_id(cmd_parms *cmd, void *_dcfg,
2107 const char *p1, const char *p2, const char *p3)
2108 {
2109 directory_config *dcfg = (directory_config *)_dcfg;
2110 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
2111 if (dcfg == NULL) return NULL;
2112
2113 if(p1 == NULL) {
2114 return apr_psprintf(cmd->pool, "Updating target by ID with no ID");
2115 }
2116
2117 re->type = RULE_EXCEPTION_REMOVE_ID;
2118 /* TODO: Validate the range here, while we can still tell the user if it's invalid */
2119 re->param = p1;
2120
2121 if(dcfg->ruleset == NULL) {
2122 return apr_psprintf(cmd->pool, "Updating target by ID with no ruleset in this context");
2123 }
2124
2125 return msre_ruleset_rule_update_target_matching_exception(NULL, dcfg->ruleset, re, p2, p3);
2126 }
2127
2128 /**
2129 * \brief Add SecRuleUpdateTargetByTag configuration option
2130 *
2131 * \param cmd Pointer to configuration data
2132 * \param _dcfg Pointer to directory configuration
2133 * \param p1 Pointer to configuration option RULETAG
2134 * \param p2 Pointer to configuration option TARGET
2135 * \param p3 Pointer to configuration option REPLACED_TARGET
2136 * \todo Finish documenting
2137 *
2138 * \retval NULL On success
2139 * \retval apr_psprintf On failure
2140 *
2141 * \todo Figure out error checking
2142 */
cmd_rule_update_target_by_tag(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2,const char * p3)2143 static const char *cmd_rule_update_target_by_tag(cmd_parms *cmd, void *_dcfg,
2144 const char *p1, const char *p2, const char *p3)
2145 {
2146 directory_config *dcfg = (directory_config *)_dcfg;
2147 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
2148 if (dcfg == NULL) return NULL;
2149
2150 if(p1 == NULL) {
2151 return apr_psprintf(cmd->pool, "Updating target by tag with no tag");
2152 }
2153
2154 re->type = RULE_EXCEPTION_REMOVE_TAG;
2155 re->param = p1;
2156 re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
2157 if (re->param_data == NULL) {
2158 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
2159 }
2160
2161 return msre_ruleset_rule_update_target_matching_exception(NULL, dcfg->ruleset, re, p2, p3);
2162 }
2163 /**
2164 * \brief Add SecRuleUpdateTargetByMsg configuration option
2165 *
2166 * \param cmd Pointer to configuration data
2167 * \param _dcfg Pointer to directory configuration
2168 * \param p1 Pointer to configuration option RULEMSG
2169 * \param p2 Pointer to configuration option TARGET
2170 * \param p3 Pointer to configuration option REPLACED_TARGET
2171 * \todo Finish documenting
2172 *
2173 * \retval NULL On success
2174 * \retval apr_psprintf On failure
2175 *
2176 * \todo Figure out error checking
2177 */
cmd_rule_update_target_by_msg(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2,const char * p3)2178 static const char *cmd_rule_update_target_by_msg(cmd_parms *cmd, void *_dcfg,
2179 const char *p1, const char *p2, const char *p3)
2180 {
2181 directory_config *dcfg = (directory_config *)_dcfg;
2182 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
2183 if (dcfg == NULL) return NULL;
2184
2185 if(p1 == NULL) {
2186 return apr_psprintf(cmd->pool, "Updating target by message with no message");
2187 }
2188
2189 re->type = RULE_EXCEPTION_REMOVE_MSG;
2190 re->param = p1;
2191 re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
2192 if (re->param_data == NULL) {
2193 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
2194 }
2195
2196 return msre_ruleset_rule_update_target_matching_exception(NULL, dcfg->ruleset, re, p2, p3);
2197 }
2198
2199
cmd_rule(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2,const char * p3)2200 static const char *cmd_rule(cmd_parms *cmd, void *_dcfg,
2201 const char *p1, const char *p2, const char *p3)
2202 {
2203 return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_NORMAL, p1, p2, p3);
2204 }
2205
cmd_sever_conn_filters_engine(cmd_parms * cmd,void * _dcfg,const char * p1)2206 static const char *cmd_sever_conn_filters_engine(cmd_parms *cmd, void *_dcfg,
2207 const char *p1)
2208 {
2209 directory_config *dcfg = (directory_config *)_dcfg;
2210
2211 if (dcfg == NULL) return NULL;
2212
2213 if (strcasecmp(p1, "on") == 0)
2214 {
2215 conn_limits_filter_state = MODSEC_ENABLED;
2216 }
2217 else if (strcasecmp(p1, "off") == 0)
2218 {
2219 conn_limits_filter_state = MODSEC_DISABLED;
2220 }
2221 else if (strcasecmp(p1, "detectiononly") == 0)
2222 {
2223 conn_limits_filter_state = MODSEC_DETECTION_ONLY;
2224 }
2225 else
2226 {
2227 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \
2228 "SecConnEngine: %s", p1);
2229 }
2230
2231 return NULL;
2232 }
2233
cmd_rule_engine(cmd_parms * cmd,void * _dcfg,const char * p1)2234 static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
2235 {
2236 directory_config *dcfg = (directory_config *)_dcfg;
2237
2238 if (dcfg == NULL) return NULL;
2239
2240 if (strcasecmp(p1, "on") == 0)
2241 {
2242 dcfg->is_enabled = MODSEC_ENABLED;
2243 }
2244 else if (strcasecmp(p1, "off") == 0)
2245 {
2246 dcfg->is_enabled = MODSEC_DISABLED;
2247 }
2248 else if (strcasecmp(p1, "detectiononly") == 0)
2249 {
2250 dcfg->is_enabled = MODSEC_DETECTION_ONLY;
2251 dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
2252 dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
2253 }
2254 else
2255 {
2256 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \
2257 "SecRuleEngine: %s", p1);
2258 }
2259
2260 return NULL;
2261 }
2262
cmd_remote_rules_fail(cmd_parms * cmd,void * _dcfg,const char * p1)2263 static const char *cmd_remote_rules_fail(cmd_parms *cmd, void *_dcfg, const char *p1)
2264 {
2265 directory_config *dcfg = (directory_config *)_dcfg;
2266 if (dcfg == NULL) return NULL;
2267 if (strncasecmp(p1, "warn", 4) == 0)
2268 {
2269 remote_rules_fail_action = REMOTE_RULES_WARN_ON_FAIL;
2270 }
2271 else if (strncasecmp(p1, "abort", 5) == 0)
2272 {
2273 remote_rules_fail_action = REMOTE_RULES_ABORT_ON_FAIL;
2274 }
2275 else
2276 {
2277 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \
2278 "SecRemoteRulesFailAction, expected: Abort or Warn.");
2279 }
2280
2281 return NULL;
2282 }
2283
cmd_remote_rules(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2,const char * p3)2284 static const char *cmd_remote_rules(cmd_parms *cmd, void *_dcfg, const char *p1,
2285 const char *p2, const char *p3)
2286 {
2287 char *error_msg = NULL;
2288 directory_config *dcfg = (directory_config *)_dcfg;
2289 #ifdef WITH_REMOTE_RULES
2290 int crypto = 0;
2291 const char *uri = p2;
2292 const char *key = p1;
2293 #endif
2294
2295 if (dcfg == NULL) return NULL;
2296
2297 #ifdef WITH_REMOTE_RULES
2298 if (strncasecmp(p1, "crypto", 6) == 0)
2299 {
2300 #ifdef WITH_APU_CRYPTO
2301 uri = p3;
2302 key = p2;
2303 crypto = 1;
2304 #else
2305 return apr_psprintf(cmd->pool, "ModSecurity: SecRemoteRule using " \
2306 "`crypto' but ModSecurity was not compiled with crypto " \
2307 "support.");
2308 #endif
2309 }
2310
2311 if (uri == NULL || key == NULL)
2312 {
2313 return apr_psprintf(cmd->pool, "ModSecurity: Use SecRemoteRule with " \
2314 "Key and URI");
2315 }
2316
2317 if (strncasecmp(uri, "https", 5) != 0) {
2318 return apr_psprintf(cmd->pool, "ModSecurity: Invalid URI:" \
2319 " '%s'. Expected HTTPS.", uri);
2320 }
2321
2322 // FIXME: Should we handle more then one server at once?
2323 if (remote_rules_server != NULL)
2324 {
2325 return apr_psprintf(cmd->pool, "ModSecurity: " \
2326 "SecRemoteRules cannot be used more than once.");
2327 }
2328
2329 remote_rules_server = apr_pcalloc(cmd->pool, sizeof(msc_remote_rules_server));
2330 if (remote_rules_server == NULL)
2331 {
2332 return apr_psprintf(cmd->pool, "ModSecurity: " \
2333 "SecRemoteRules: Internal failure. Not enougth memory.");
2334 }
2335
2336 remote_rules_server->context = dcfg;
2337 remote_rules_server->context_label = apr_pstrdup(cmd->pool, "Unkwon context");
2338 remote_rules_server->key = key;
2339 remote_rules_server->uri = uri;
2340 remote_rules_server->amount_of_rules = 0;
2341 remote_rules_server->crypto = crypto;
2342
2343 msc_remote_add_rules_from_uri(cmd, remote_rules_server, &error_msg);
2344 if (error_msg != NULL)
2345 {
2346 return error_msg;
2347 }
2348 #else
2349 return apr_psprintf(cmd->pool, "ModSecurity: SecRemoteRules: " \
2350 "ModSecurity was not compiled with SecRemoteRules support.");
2351 #endif
2352
2353 return NULL;
2354 }
2355
2356
cmd_status_engine(cmd_parms * cmd,void * _dcfg,const char * p1)2357 static const char *cmd_status_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
2358 {
2359 if (strcasecmp(p1, "on") == 0) {
2360 status_engine_state = STATUS_ENGINE_ENABLED;
2361 }
2362 else if (strcasecmp(p1, "off") == 0) {
2363 status_engine_state = STATUS_ENGINE_DISABLED;
2364 }
2365 else {
2366 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \
2367 "SecStatusEngine: %s", p1);
2368 }
2369
2370 return NULL;
2371 }
2372
2373
cmd_rule_inheritance(cmd_parms * cmd,void * _dcfg,int flag)2374 static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag)
2375 {
2376 directory_config *dcfg = (directory_config *)_dcfg;
2377 if (dcfg == NULL) return NULL;
2378 dcfg->rule_inheritance = flag;
2379 return NULL;
2380 }
2381
cmd_rule_script(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2)2382 static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg,
2383 const char *p1, const char *p2)
2384 {
2385 #if defined(WITH_LUA)
2386 const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
2387 return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL);
2388 #else
2389 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);
2390 return NULL;
2391 #endif
2392 }
2393
cmd_rule_remove_by_id(cmd_parms * cmd,void * _dcfg,const char * p1)2394 static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg,
2395 const char *p1)
2396 {
2397 directory_config *dcfg = (directory_config *)_dcfg;
2398 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
2399 if (dcfg == NULL) return NULL;
2400
2401 re->type = RULE_EXCEPTION_REMOVE_ID;
2402 re->param = p1;
2403 *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
2404
2405 /* Remove the corresponding rules from the context straight away. */
2406 msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
2407
2408 return NULL;
2409 }
2410
2411 /**
2412 * \brief Add SecRuleRemoveByTag configuration option
2413 *
2414 * \param cmd Pointer to configuration data
2415 * \param _dcfg Pointer to directory configuration
2416 * \param p1 Pointer to configuration option
2417 *
2418 * \retval NULL On failure
2419 * \retval apr_psprintf On success
2420 */
cmd_rule_remove_by_tag(cmd_parms * cmd,void * _dcfg,const char * p1)2421 static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg,
2422 const char *p1)
2423 {
2424 directory_config *dcfg = (directory_config *)_dcfg;
2425 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
2426 if (dcfg == NULL) return NULL;
2427
2428 re->type = RULE_EXCEPTION_REMOVE_TAG;
2429 re->param = p1;
2430 re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
2431 if (re->param_data == NULL) {
2432 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
2433 }
2434 *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
2435
2436 /* Remove the corresponding rules from the context straight away. */
2437 msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
2438
2439 #ifdef DEBUG_CONF
2440 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);
2441 #endif
2442
2443 return NULL;
2444 }
2445
cmd_rule_remove_by_msg(cmd_parms * cmd,void * _dcfg,const char * p1)2446 static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg,
2447 const char *p1)
2448 {
2449 directory_config *dcfg = (directory_config *)_dcfg;
2450 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
2451 if (dcfg == NULL) return NULL;
2452
2453 re->type = RULE_EXCEPTION_REMOVE_MSG;
2454 re->param = p1;
2455 re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
2456 if (re->param_data == NULL) {
2457 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
2458 }
2459 *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
2460
2461 /* Remove the corresponding rules from the context straight away. */
2462 msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
2463
2464 #ifdef DEBUG_CONF
2465 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);
2466 #endif
2467
2468 return NULL;
2469 }
2470
cmd_rule_update_action_by_id(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2)2471 static const char *cmd_rule_update_action_by_id(cmd_parms *cmd, void *_dcfg,
2472 const char *p1, const char *p2)
2473 {
2474 int offset = 0, rule_id = atoi(p1);
2475 char *opt = strchr(p1,':');
2476 char *savedptr = NULL;
2477 char *param = apr_pstrdup(cmd->pool, p1);
2478
2479 if ((rule_id == LONG_MAX)||(rule_id == LONG_MIN)||(rule_id <= 0)) {
2480 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for ID for update action: %s", p1);
2481 }
2482
2483 if(opt != NULL) {
2484 opt++;
2485 offset = atoi(opt);
2486 opt = apr_strtok(param,":", &savedptr);
2487 return update_rule_action(cmd, (directory_config *)_dcfg, (const char *)opt, p2, offset);
2488 }
2489
2490 return update_rule_action(cmd, (directory_config *)_dcfg, p1, p2, offset);
2491 }
2492
cmd_server_signature(cmd_parms * cmd,void * _dcfg,const char * p1)2493 static const char *cmd_server_signature(cmd_parms *cmd, void *_dcfg,
2494 const char *p1)
2495 {
2496 if (cmd->server->is_virtual) {
2497 return "ModSecurity: SecServerSignature not allowed in VirtualHost";
2498 }
2499 new_server_signature = (char *)p1;
2500 return NULL;
2501 }
2502
cmd_tmp_dir(cmd_parms * cmd,void * _dcfg,const char * p1)2503 static const char *cmd_tmp_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
2504 {
2505 directory_config *dcfg = (directory_config *)_dcfg;
2506
2507 if (dcfg == NULL) return NULL;
2508
2509 if (strcasecmp(p1, "none") == 0) dcfg->tmp_dir = NULL;
2510 else dcfg->tmp_dir = ap_server_root_relative(cmd->pool, p1);
2511
2512 return NULL;
2513 }
2514
cmd_upload_dir(cmd_parms * cmd,void * _dcfg,const char * p1)2515 static const char *cmd_upload_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
2516 {
2517 directory_config *dcfg = (directory_config *)_dcfg;
2518
2519 if (dcfg == NULL) return NULL;
2520
2521 if (strcasecmp(p1, "none") == 0) dcfg->upload_dir = NULL;
2522 else dcfg->upload_dir = ap_server_root_relative(cmd->pool, p1);
2523
2524 return NULL;
2525 }
2526
cmd_upload_file_limit(cmd_parms * cmd,void * _dcfg,const char * p1)2527 static const char *cmd_upload_file_limit(cmd_parms *cmd, void *_dcfg,
2528 const char *p1)
2529 {
2530 directory_config *dcfg = (directory_config *)_dcfg;
2531
2532 if (dcfg == NULL) return NULL;
2533
2534 if (strcasecmp(p1, "default") == 0) {
2535 dcfg->upload_file_limit = NOT_SET;
2536 }
2537 else {
2538 dcfg->upload_file_limit = atoi(p1);
2539 }
2540
2541 return NULL;
2542 }
2543
cmd_upload_filemode(cmd_parms * cmd,void * _dcfg,const char * p1)2544 static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg,
2545 const char *p1)
2546 {
2547 directory_config *dcfg = (directory_config *)_dcfg;
2548
2549 if (dcfg == NULL) return NULL;
2550
2551 if (strcasecmp(p1, "default") == 0) {
2552 dcfg->upload_filemode = NOT_SET;
2553 }
2554 else {
2555 long int mode = strtol(p1, NULL, 8); /* expects octal mode */
2556 if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
2557 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecUploadFileMode: %s", p1);
2558 }
2559
2560 dcfg->upload_filemode = (int)mode;
2561 }
2562
2563 return NULL;
2564 }
2565
cmd_upload_keep_files(cmd_parms * cmd,void * _dcfg,const char * p1)2566 static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg,
2567 const char *p1)
2568 {
2569 directory_config *dcfg = (directory_config *)_dcfg;
2570
2571 if (dcfg == NULL) return NULL;
2572
2573 if (strcasecmp(p1, "on") == 0) {
2574 dcfg->upload_keep_files = KEEP_FILES_ON;
2575 } else
2576 if (strcasecmp(p1, "off") == 0) {
2577 dcfg->upload_keep_files = KEEP_FILES_OFF;
2578 } else
2579 if (strcasecmp(p1, "relevantonly") == 0) {
2580 dcfg->upload_keep_files = KEEP_FILES_RELEVANT_ONLY;
2581 } else {
2582 return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for SecUploadKeepFiles: %s",
2583 p1);
2584 }
2585 return NULL;
2586 }
2587
cmd_upload_save_tmp_files(cmd_parms * cmd,void * _dcfg,const char * p1)2588 static const char *cmd_upload_save_tmp_files(cmd_parms *cmd, void *_dcfg,
2589 const char *p1)
2590 {
2591 directory_config *dcfg = (directory_config *)_dcfg;
2592
2593 if (dcfg == NULL) return NULL;
2594
2595 if (strcasecmp(p1, "on") == 0)
2596 {
2597 dcfg->upload_validates_files = 1;
2598 }
2599 else if (strcasecmp(p1, "off") == 0)
2600 {
2601 dcfg->upload_validates_files = 0;
2602 }
2603 else
2604 {
2605 return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for SecTmpSaveUploadedFiles: %s",
2606 p1);
2607 }
2608
2609 return NULL;
2610 }
2611
cmd_web_app_id(cmd_parms * cmd,void * _dcfg,const char * p1)2612 static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1)
2613 {
2614 directory_config *dcfg = (directory_config *)_dcfg;
2615
2616 /* ENH enforce format (letters, digits, ., _, -) */
2617 dcfg->webappid = p1;
2618
2619 return NULL;
2620 }
2621
cmd_sensor_id(cmd_parms * cmd,void * _dcfg,const char * p1)2622 static const char *cmd_sensor_id(cmd_parms *cmd, void *_dcfg, const char *p1)
2623 {
2624 directory_config *dcfg = (directory_config *)_dcfg;
2625
2626 /* ENH enforce format (letters, digits, ., _, -) */
2627 dcfg->sensor_id = p1;
2628
2629 return NULL;
2630 }
2631
2632 /**
2633 * \brief Add SecXmlExternalEntity configuration option
2634 *
2635 * \param cmd Pointer to configuration data
2636 * \param _dcfg Pointer to directory configuration
2637 * \param p1 Pointer to configuration option
2638 *
2639 * \retval NULL On failure
2640 * \retval apr_psprintf On Success
2641 */
cmd_xml_external_entity(cmd_parms * cmd,void * _dcfg,const char * p1)2642 static const char *cmd_xml_external_entity(cmd_parms *cmd, void *_dcfg, const char *p1)
2643 {
2644 directory_config *dcfg = (directory_config *)_dcfg;
2645 if (dcfg == NULL) return NULL;
2646
2647 if (strcasecmp(p1, "on") == 0) {
2648 dcfg->xml_external_entity = 1;
2649 }
2650 else if (strcasecmp(p1, "off") == 0) {
2651 dcfg->xml_external_entity = 0;
2652 }
2653 else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecXmlExternalEntity: %s", p1);
2654
2655 return NULL;
2656 }
2657
2658
2659 /**
2660 * \brief Add SecHashEngine configuration option
2661 *
2662 * \param cmd Pointer to configuration data
2663 * \param _dcfg Pointer to directory configuration
2664 * \param p1 Pointer to configuration option
2665 *
2666 * \retval NULL On failure
2667 * \retval apr_psprintf On Success
2668 */
cmd_hash_engine(cmd_parms * cmd,void * _dcfg,const char * p1)2669 static const char *cmd_hash_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
2670 {
2671 directory_config *dcfg = (directory_config *)_dcfg;
2672 if (dcfg == NULL) return NULL;
2673
2674 if (strcasecmp(p1, "on") == 0) {
2675 dcfg->hash_is_enabled = HASH_ENABLED;
2676 dcfg->hash_enforcement = HASH_ENABLED;
2677 }
2678 else if (strcasecmp(p1, "off") == 0) {
2679 dcfg->hash_is_enabled = HASH_DISABLED;
2680 dcfg->hash_enforcement = HASH_DISABLED;
2681 }
2682 else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecHashEngine: %s", p1);
2683
2684 return NULL;
2685 }
2686
2687 /**
2688 * \brief Add SecHashPram configuration option
2689 *
2690 * \param cmd Pointer to configuration data
2691 * \param _dcfg Pointer to directory configuration
2692 * \param p1 Pointer to configuration option
2693 *
2694 * \retval NULL On success
2695 */
cmd_hash_param(cmd_parms * cmd,void * _dcfg,const char * p1)2696 static const char *cmd_hash_param(cmd_parms *cmd, void *_dcfg, const char *p1)
2697 {
2698 directory_config *dcfg = (directory_config *)_dcfg;
2699
2700 if (dcfg == NULL) return NULL;
2701
2702 if (p1 == NULL) return NULL;
2703 dcfg->crypto_param_name = p1;
2704
2705 return NULL;
2706 }
2707
2708 /**
2709 * \brief Add SecHashKey configuration option
2710 *
2711 * \param cmd Pointer to configuration data
2712 * \param _dcfg Pointer to directory configuration
2713 * \param _p1 Pointer to configuration option
2714 * \param _p2 Pointer to configuration option
2715 *
2716 * \retval NULL On success
2717 */
cmd_hash_key(cmd_parms * cmd,void * _dcfg,const char * _p1,const char * _p2)2718 static const char *cmd_hash_key(cmd_parms *cmd, void *_dcfg, const char *_p1, const char *_p2)
2719 {
2720 directory_config *dcfg = (directory_config *)_dcfg;
2721 char *p1 = NULL;
2722
2723 if (dcfg == NULL) return NULL;
2724 if (_p1 == NULL) return NULL;
2725
2726 if (strcasecmp(_p1, "Rand") == 0) {
2727 p1 = apr_pstrdup(cmd->pool, getkey(cmd->pool));
2728 dcfg->crypto_key = p1;
2729 dcfg->crypto_key_len = strlen(dcfg->crypto_key);
2730 } else {
2731 p1 = apr_pstrdup(cmd->pool, _p1);
2732 dcfg->crypto_key = p1;
2733 dcfg->crypto_key_len = strlen(p1);
2734 }
2735
2736 if(_p2 == NULL) {
2737 return NULL;
2738 } else {
2739 if (strcasecmp(_p2, "KeyOnly") == 0)
2740 dcfg->crypto_key_add = HASH_KEYONLY;
2741 else if (strcasecmp(_p2, "SessionID") == 0)
2742 dcfg->crypto_key_add = HASH_SESSIONID;
2743 else if (strcasecmp(_p2, "RemoteIP") == 0)
2744 dcfg->crypto_key_add = HASH_REMOTEIP;
2745 }
2746 return NULL;
2747 }
2748
2749 /**
2750 * \brief Add SecHashMethodPm configuration option
2751 *
2752 * \param cmd Pointer to configuration data
2753 * \param _dcfg Pointer to directory configuration
2754 * \param p1 Pointer to configuration option
2755 * \param p2 Pointer to configuration option
2756 *
2757 * \retval NULL On failure
2758 * \retval apr_psprintf On Success
2759 */
cmd_hash_method_pm(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2)2760 static const char *cmd_hash_method_pm(cmd_parms *cmd, void *_dcfg,
2761 const char *p1, const char *p2)
2762 {
2763 directory_config *dcfg = (directory_config *)_dcfg;
2764 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method));
2765 const char *_p2 = apr_pstrdup(cmd->pool, p2);
2766 ACMP *p = NULL;
2767 const char *phrase = NULL;
2768 const char *next = NULL;
2769
2770 if (dcfg == NULL) return NULL;
2771
2772 p = acmp_create(0, cmd->pool);
2773 if (p == NULL) return NULL;
2774
2775 if(phrase == NULL)
2776 phrase = apr_pstrdup(cmd->pool, _p2);
2777
2778 for (;;) {
2779 while((apr_isspace(*phrase) != 0) && (*phrase != '\0')) phrase++;
2780 if (*phrase == '\0') break;
2781 next = phrase;
2782 while((apr_isspace(*next) == 0) && (*next != 0)) next++;
2783 acmp_add_pattern(p, phrase, NULL, NULL, next - phrase);
2784 phrase = next;
2785 }
2786
2787 acmp_prepare(p);
2788
2789 if (strcasecmp(p1, "HashHref") == 0) {
2790 re->type = HASH_URL_HREF_HASH_PM;
2791 re->param = _p2;
2792 re->param_data = (void *)p;
2793 if (re->param_data == NULL) {
2794 return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2);
2795 }
2796 dcfg->crypto_hash_href_pm = 1;
2797 }
2798 else if (strcasecmp(p1, "HashFormAction") == 0) {
2799 re->type = HASH_URL_FACTION_HASH_PM;
2800 re->param = _p2;
2801 re->param_data = (void *)p;
2802 if (re->param_data == NULL) {
2803 return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2);
2804 }
2805 dcfg->crypto_hash_faction_pm = 1;
2806 }
2807 else if (strcasecmp(p1, "HashLocation") == 0) {
2808 re->type = HASH_URL_LOCATION_HASH_PM;
2809 re->param = _p2;
2810 re->param_data = (void *)p;
2811 if (re->param_data == NULL) {
2812 return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2);
2813 }
2814 dcfg->crypto_hash_location_pm = 1;
2815 }
2816 else if (strcasecmp(p1, "HashIframeSrc") == 0) {
2817 re->type = HASH_URL_IFRAMESRC_HASH_PM;
2818 re->param = _p2;
2819 re->param_data = (void *)p;
2820 if (re->param_data == NULL) {
2821 return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2);
2822 }
2823 dcfg->crypto_hash_iframesrc_pm = 1;
2824 }
2825 else if (strcasecmp(p1, "HashFrameSrc") == 0) {
2826 re->type = HASH_URL_FRAMESRC_HASH_PM;
2827 re->param = _p2;
2828 re->param_data = (void *)p;
2829 if (re->param_data == NULL) {
2830 return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2);
2831 }
2832 dcfg->crypto_hash_framesrc_pm = 1;
2833 }
2834
2835 *(hash_method **)apr_array_push(dcfg->hash_method) = re;
2836
2837 return NULL;
2838 }
2839
2840 /**
2841 * \brief Add SecHashMethodRx configuration option
2842 *
2843 * \param cmd Pointer to configuration data
2844 * \param _dcfg Pointer to directory configuration
2845 * \param p1 Pointer to configuration option
2846 * \param p2 Pointer to configuration option
2847 *
2848 * \retval NULL On failure
2849 * \retval apr_psprintf On Success
2850 */
cmd_hash_method_rx(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2)2851 static const char *cmd_hash_method_rx(cmd_parms *cmd, void *_dcfg,
2852 const char *p1, const char *p2)
2853 {
2854 directory_config *dcfg = (directory_config *)_dcfg;
2855 rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method));
2856 const char *_p2 = apr_pstrdup(cmd->pool, p2);
2857 if (dcfg == NULL) return NULL;
2858
2859 if (strcasecmp(p1, "HashHref") == 0) {
2860 re->type = HASH_URL_HREF_HASH_RX;
2861 re->param = _p2;
2862 re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL);
2863 if (re->param_data == NULL) {
2864 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2);
2865 }
2866 dcfg->crypto_hash_href_rx = 1;
2867 }
2868 else if (strcasecmp(p1, "HashFormAction") == 0) {
2869 re->type = HASH_URL_FACTION_HASH_RX;
2870 re->param = _p2;
2871 re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL);
2872 if (re->param_data == NULL) {
2873 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2);
2874 }
2875 dcfg->crypto_hash_faction_rx = 1;
2876 }
2877 else if (strcasecmp(p1, "HashLocation") == 0) {
2878 re->type = HASH_URL_LOCATION_HASH_RX;
2879 re->param = _p2;
2880 re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL);
2881 if (re->param_data == NULL) {
2882 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2);
2883 }
2884 dcfg->crypto_hash_location_rx = 1;
2885 }
2886 else if (strcasecmp(p1, "HashIframeSrc") == 0) {
2887 re->type = HASH_URL_IFRAMESRC_HASH_RX;
2888 re->param = _p2;
2889 re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL);
2890 if (re->param_data == NULL) {
2891 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2);
2892 }
2893 dcfg->crypto_hash_iframesrc_rx = 1;
2894 }
2895 else if (strcasecmp(p1, "HashFrameSrc") == 0) {
2896 re->type = HASH_URL_FRAMESRC_HASH_RX;
2897 re->param = _p2;
2898 re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL);
2899 if (re->param_data == NULL) {
2900 return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2);
2901 }
2902 dcfg->crypto_hash_framesrc_rx = 1;
2903 }
2904
2905 *(hash_method **)apr_array_push(dcfg->hash_method) = re;
2906
2907 return NULL;
2908 }
2909
2910 /**
2911 * \brief Add SecHttpBlKey configuration option
2912 *
2913 * \param cmd Pointer to configuration data
2914 * \param _dcfg Pointer to directory configuration
2915 * \param p1 Pointer to configuration option
2916 *
2917 * \retval NULL On success
2918 */
cmd_httpBl_key(cmd_parms * cmd,void * _dcfg,const char * p1)2919 static const char *cmd_httpBl_key(cmd_parms *cmd, void *_dcfg, const char *p1)
2920 {
2921 directory_config *dcfg = (directory_config *)_dcfg;
2922
2923 if (dcfg == NULL) return NULL;
2924
2925 if (p1 == NULL) return NULL;
2926 dcfg->httpBlkey = p1;
2927
2928 return NULL;
2929 }
2930
2931 /* PCRE Limits */
2932
cmd_pcre_match_limit(cmd_parms * cmd,void * _dcfg,const char * p1)2933 static const char *cmd_pcre_match_limit(cmd_parms *cmd,
2934 void *_dcfg, const char *p1)
2935 {
2936 long val;
2937
2938 if (cmd->server->is_virtual) {
2939 return "ModSecurity: SecPcreMatchLimit not allowed in VirtualHost";
2940 }
2941
2942 val = atol(p1);
2943 if (val <= 0) {
2944 return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
2945 "SecPcreMatchLimit: %s", p1);
2946 }
2947 msc_pcre_match_limit = (unsigned long int)val;
2948
2949 return NULL;
2950 }
2951
cmd_pcre_match_limit_recursion(cmd_parms * cmd,void * _dcfg,const char * p1)2952 static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd,
2953 void *_dcfg, const char *p1)
2954 {
2955 long val;
2956
2957 if (cmd->server->is_virtual) {
2958 return "ModSecurity: SecPcreMatchLimitRecursion not allowed in VirtualHost";
2959 }
2960
2961 val = atol(p1);
2962 if (val <= 0) {
2963 return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
2964 "SecPcreMatchLimitRecursion: %s", p1);
2965 }
2966 msc_pcre_match_limit_recursion = (unsigned long int)val;
2967
2968 return NULL;
2969 }
2970
2971
2972 /* -- Geo Lookup configuration -- */
2973
cmd_geo_lookup_db(cmd_parms * cmd,void * _dcfg,const char * p1)2974 static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg,
2975 const char *p1)
2976 {
2977 const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
2978 char *error_msg;
2979 directory_config *dcfg = (directory_config *)_dcfg;
2980 if (dcfg == NULL) return NULL;
2981
2982 if (geo_init(dcfg, filename, &error_msg) <= 0) {
2983 return error_msg;
2984 }
2985
2986 return NULL;
2987 }
2988
2989 /**
2990 * \brief Add SecUnicodeCodePage configuration option
2991 *
2992 * Depcrecated
2993 *
2994 * \param cmd Pointer to configuration data
2995 * \param _dcfg Pointer to directory configuration
2996 * \param p1 Pointer to configuration option
2997 *
2998 * \retval NULL On success
2999 */
cmd_unicode_codepage(cmd_parms * cmd,void * _dcfg,const char * p1)3000 static const char *cmd_unicode_codepage(cmd_parms *cmd,
3001 void *_dcfg, const char *p1)
3002 {
3003 long val;
3004
3005 val = atol(p1);
3006 if (val <= 0) {
3007 return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
3008 "SecUnicodeCodePage: %s", p1);
3009 }
3010
3011 unicode_codepage = (unsigned long int)val;
3012
3013 return NULL;
3014 }
3015
3016 /**
3017 * \brief Add SecUnicodeMapFile configuration option
3018 *
3019 * \param cmd Pointer to configuration data
3020 * \param _dcfg Pointer to directory configuration
3021 * \param p1 Pointer to configuration option
3022 *
3023 * \retval NULL On success
3024 */
cmd_unicode_map(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2)3025 static const char *cmd_unicode_map(cmd_parms *cmd, void *_dcfg,
3026 const char *p1, const char *p2)
3027 {
3028 const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
3029 char *error_msg;
3030 long val = 0;
3031 directory_config *dcfg = (directory_config *)_dcfg;
3032 if (dcfg == NULL) return NULL;
3033
3034 if(p2 != NULL) {
3035 val = atol(p2);
3036 if (val <= 0) {
3037 return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
3038 "SecUnicodeMapFile: %s", p2);
3039 }
3040
3041 unicode_codepage = (unsigned long int)val;
3042 }
3043
3044 if (unicode_map_init(dcfg, filename, &error_msg) <= 0) {
3045 return error_msg;
3046 }
3047
3048 return NULL;
3049 }
3050
3051 /**
3052 * \brief Add SecGsbLookupDb configuration option
3053 *
3054 * \param cmd Pointer to configuration data
3055 * \param _dcfg Pointer to directory configuration
3056 * \param p1 Pointer to configuration option
3057 *
3058 * \retval NULL On success
3059 */
cmd_gsb_lookup_db(cmd_parms * cmd,void * _dcfg,const char * p1)3060 static const char *cmd_gsb_lookup_db(cmd_parms *cmd, void *_dcfg,
3061 const char *p1)
3062 {
3063 const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
3064 char *error_msg;
3065 directory_config *dcfg = (directory_config *)_dcfg;
3066 if (dcfg == NULL) return NULL;
3067
3068 if (gsb_db_init(dcfg, filename, &error_msg) <= 0) {
3069 return error_msg;
3070 }
3071
3072 return NULL;
3073 }
3074
3075 /* -- Cache -- */
3076
cmd_cache_transformations(cmd_parms * cmd,void * _dcfg,const char * p1,const char * p2)3077 static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg,
3078 const char *p1, const char *p2)
3079 {
3080 directory_config *dcfg = (directory_config *)_dcfg;
3081
3082 if (dcfg == NULL) return NULL;
3083
3084 if (strcasecmp(p1, "on") == 0)
3085 dcfg->cache_trans = MODSEC_CACHE_ENABLED;
3086 else if (strcasecmp(p1, "off") == 0)
3087 dcfg->cache_trans = MODSEC_CACHE_DISABLED;
3088 else
3089 return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecCacheTransformations: %s", p1);
3090
3091 /* Process options */
3092 if (p2 != NULL) {
3093 apr_table_t *vartable = apr_table_make(cmd->pool, 4);
3094 apr_status_t rc;
3095 char *error_msg = NULL;
3096 const char *charval = NULL;
3097 apr_int64_t intval = 0;
3098
3099 if (vartable == NULL) {
3100 return apr_psprintf(cmd->pool, "ModSecurity: Unable to process options for SecCacheTransformations");
3101 }
3102 rc = msre_parse_generic(cmd->pool, p2, vartable, &error_msg);
3103 if (rc < 0) {
3104 return apr_psprintf(cmd->pool, "ModSecurity: Unable to parse options for SecCacheTransformations: %s", error_msg);
3105 }
3106
3107 /* incremental */
3108 charval = apr_table_get(vartable, "incremental");
3109 if (charval != NULL) {
3110 if (strcasecmp(charval, "on") == 0)
3111 dcfg->cache_trans_incremental = 1;
3112 else if (strcasecmp(charval, "off") == 0)
3113 dcfg->cache_trans_incremental = 0;
3114 else
3115 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations invalid incremental value: %s", charval);
3116 }
3117
3118 /* minlen */
3119 charval = apr_table_get(vartable, "minlen");
3120 if (charval != NULL) {
3121 intval = apr_atoi64(charval);
3122 if (errno == ERANGE) {
3123 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen out of range: %s", charval);
3124 }
3125 if (intval < 0) {
3126 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be positive: %s", charval);
3127 }
3128
3129 /* The NOT_SET indicator is -1, a signed long, and therfore
3130 * we cannot be >= the unsigned value of NOT_SET.
3131 */
3132 if ((unsigned long)intval >= (unsigned long)NOT_SET) {
3133 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be less than: %lu", (unsigned long)NOT_SET);
3134 }
3135 dcfg->cache_trans_min = (apr_size_t)intval;
3136 }
3137
3138 /* maxlen */
3139 charval = apr_table_get(vartable, "maxlen");
3140 if (charval != NULL) {
3141 intval = apr_atoi64(charval);
3142 if (errno == ERANGE) {
3143 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen out of range: %s", charval);
3144 }
3145 if (intval < 0) {
3146 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be positive: %s", charval);
3147 }
3148
3149 /* The NOT_SET indicator is -1, a signed long, and therfore
3150 * we cannot be >= the unsigned value of NOT_SET.
3151 */
3152 if ((unsigned long)intval >= (unsigned long)NOT_SET) {
3153 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be less than: %lu", (unsigned long)NOT_SET);
3154 }
3155 if ((intval != 0) && ((apr_size_t)intval < dcfg->cache_trans_min)) {
3156 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);
3157 }
3158 dcfg->cache_trans_max = (apr_size_t)intval;
3159
3160 }
3161
3162 /* maxitems */
3163 charval = apr_table_get(vartable, "maxitems");
3164 if (charval != NULL) {
3165 intval = apr_atoi64(charval);
3166 if (errno == ERANGE) {
3167 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems out of range: %s", charval);
3168 }
3169 if (intval < 0) {
3170 return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems must be positive: %s", charval);
3171 }
3172 dcfg->cache_trans_maxitems = (apr_size_t)intval;
3173 }
3174 }
3175
3176 return NULL;
3177 }
3178
3179
3180 /* -- Configuration directives definitions -- */
3181
3182 #define CMD_SCOPE_MAIN (RSRC_CONF)
3183 #define CMD_SCOPE_ANY (RSRC_CONF | ACCESS_CONF)
3184
3185 #if defined(HTACCESS_CONFIG)
3186 #define CMD_SCOPE_HTACCESS (OR_OPTIONS)
3187 #endif
3188
3189 const command_rec module_directives[] = {
3190
3191 #ifdef HTACCESS_CONFIG
3192 AP_INIT_TAKE1 (
3193 "SecAction",
3194 cmd_action,
3195 NULL,
3196 CMD_SCOPE_HTACCESS,
3197 "an action list"
3198 ),
3199 #else
3200 AP_INIT_TAKE1 (
3201 "SecAction",
3202 cmd_action,
3203 NULL,
3204 CMD_SCOPE_ANY,
3205 "an action list"
3206 ),
3207 #endif
3208
3209 AP_INIT_TAKE1 (
3210 "SecArgumentSeparator",
3211 cmd_argument_separator,
3212 NULL,
3213 CMD_SCOPE_ANY,
3214 "character that will be used as separator when parsing application/x-www-form-urlencoded content."
3215 ),
3216
3217 AP_INIT_TAKE1 (
3218 "SecCookiev0Separator",
3219 cmd_cookiev0_separator,
3220 NULL,
3221 CMD_SCOPE_ANY,
3222 "character that will be used as separator when parsing cookie v0 content."
3223 ),
3224
3225 AP_INIT_TAKE1 (
3226 "SecAuditEngine",
3227 cmd_audit_engine,
3228 NULL,
3229 CMD_SCOPE_ANY,
3230 "On, Off or RelevantOnly to determine the level of audit logging"
3231 ),
3232
3233 AP_INIT_TAKE1 (
3234 "SecAuditLog",
3235 cmd_audit_log,
3236 NULL,
3237 CMD_SCOPE_ANY,
3238 "filename of the primary audit log file"
3239 ),
3240
3241 AP_INIT_TAKE1 (
3242 "SecAuditLog2",
3243 cmd_audit_log2,
3244 NULL,
3245 CMD_SCOPE_ANY,
3246 "filename of the secondary audit log file"
3247 ),
3248
3249 AP_INIT_TAKE1 (
3250 "SecAuditLogParts",
3251 cmd_audit_log_parts,
3252 NULL,
3253 CMD_SCOPE_ANY,
3254 "list of audit log parts that go into the log."
3255 ),
3256
3257 AP_INIT_TAKE1 (
3258 "SecAuditLogRelevantStatus",
3259 cmd_audit_log_relevant_status,
3260 NULL,
3261 CMD_SCOPE_ANY,
3262 "regular expression that will be used to determine if the response status is relevant for audit logging"
3263 ),
3264
3265 AP_INIT_TAKE1 (
3266 "SecAuditLogType",
3267 cmd_audit_log_type,
3268 NULL,
3269 CMD_SCOPE_ANY,
3270 "whether to use the old audit log format (Serial) or new (Concurrent)"
3271 ),
3272
3273 #ifdef WITH_YAJL
3274 AP_INIT_TAKE1 (
3275 "SecAuditLogFormat",
3276 cmd_audit_log_mode,
3277 NULL,
3278 CMD_SCOPE_ANY,
3279 "whether to emit audit log data in native format or JSON"
3280 ),
3281 #endif
3282
3283 AP_INIT_TAKE1 (
3284 "SecAuditLogStorageDir",
3285 cmd_audit_log_storage_dir,
3286 NULL,
3287 CMD_SCOPE_ANY,
3288 "path to the audit log storage area; absolute, or relative to the root of the server"
3289 ),
3290
3291 AP_INIT_TAKE1 (
3292 "SecAuditLogDirMode",
3293 cmd_audit_log_dirmode,
3294 NULL,
3295 CMD_SCOPE_ANY,
3296 "octal permissions mode for concurrent audit log directories"
3297 ),
3298
3299 AP_INIT_TAKE1 (
3300 "SecAuditLogFileMode",
3301 cmd_audit_log_filemode,
3302 NULL,
3303 CMD_SCOPE_ANY,
3304 "octal permissions mode for concurrent audit log files"
3305 ),
3306
3307 AP_INIT_TAKE12 (
3308 "SecCacheTransformations",
3309 cmd_cache_transformations,
3310 NULL,
3311 CMD_SCOPE_ANY,
3312 "whether or not to cache transformations. Defaults to true."
3313 ),
3314
3315 AP_INIT_TAKE1 (
3316 "SecChrootDir",
3317 cmd_chroot_dir,
3318 NULL,
3319 CMD_SCOPE_MAIN,
3320 "path of the directory to which server will be chrooted"
3321 ),
3322
3323 AP_INIT_TAKE1 (
3324 "SecComponentSignature",
3325 cmd_component_signature,
3326 NULL,
3327 CMD_SCOPE_MAIN,
3328 "component signature to add to ModSecurity signature."
3329 ),
3330
3331 AP_INIT_FLAG (
3332 "SecContentInjection",
3333 cmd_content_injection,
3334 NULL,
3335 CMD_SCOPE_ANY,
3336 "On or Off"
3337 ),
3338
3339 AP_INIT_FLAG (
3340 "SecStreamOutBodyInspection",
3341 cmd_stream_outbody_inspection,
3342 NULL,
3343 CMD_SCOPE_ANY,
3344 "On or Off"
3345 ),
3346
3347 AP_INIT_FLAG (
3348 "SecStreamInBodyInspection",
3349 cmd_stream_inbody_inspection,
3350 NULL,
3351 CMD_SCOPE_ANY,
3352 "On or Off"
3353 ),
3354
3355 AP_INIT_TAKE1 (
3356 "SecCookieFormat",
3357 cmd_cookie_format,
3358 NULL,
3359 CMD_SCOPE_ANY,
3360 "version of the Cookie specification to use for parsing. Possible values are 0 and 1."
3361 ),
3362
3363 AP_INIT_TAKE1 (
3364 "SecDataDir",
3365 cmd_data_dir,
3366 NULL,
3367 CMD_SCOPE_MAIN,
3368 "path to the persistent data storage area" // TODO
3369 ),
3370
3371 AP_INIT_TAKE1 (
3372 "SecDebugLog",
3373 cmd_debug_log,
3374 NULL,
3375 CMD_SCOPE_ANY,
3376 "path to the debug log file"
3377 ),
3378
3379 AP_INIT_TAKE1 (
3380 "SecDebugLogLevel",
3381 cmd_debug_log_level,
3382 NULL,
3383 CMD_SCOPE_ANY,
3384 "debug log level, which controls the verbosity of logging."
3385 " Use values from 0 (no logging) to 9 (a *lot* of logging)."
3386 ),
3387
3388 AP_INIT_TAKE1 (
3389 "SecCollectionTimeout",
3390 cmd_collection_timeout,
3391 NULL,
3392 CMD_SCOPE_ANY,
3393 "set default collections timeout. default it 3600"
3394 ),
3395
3396 AP_INIT_TAKE1 (
3397 "SecDefaultAction",
3398 cmd_default_action,
3399 NULL,
3400 CMD_SCOPE_ANY,
3401 "default action list"
3402 ),
3403
3404 AP_INIT_FLAG (
3405 "SecDisableBackendCompression",
3406 cmd_disable_backend_compression,
3407 NULL,
3408 CMD_SCOPE_ANY,
3409 "When set to On, removes the compression headers from the backend requests."
3410 ),
3411
3412 AP_INIT_TAKE1 (
3413 "SecGsbLookupDB",
3414 cmd_gsb_lookup_db,
3415 NULL,
3416 RSRC_CONF,
3417 "database google safe browsing"
3418 ),
3419
3420 AP_INIT_TAKE1 (
3421 "SecUnicodeCodePage",
3422 cmd_unicode_codepage,
3423 NULL,
3424 CMD_SCOPE_MAIN,
3425 "Unicode CodePage"
3426 ),
3427
3428 AP_INIT_TAKE12 (
3429 "SecUnicodeMapFile",
3430 cmd_unicode_map,
3431 NULL,
3432 CMD_SCOPE_MAIN,
3433 "Unicode Map file"
3434 ),
3435
3436 AP_INIT_TAKE1 (
3437 "SecGeoLookupDB",
3438 cmd_geo_lookup_db,
3439 NULL,
3440 RSRC_CONF,
3441 "database for geographical lookups module."
3442 ),
3443
3444 AP_INIT_TAKE12 (
3445 "SecGuardianLog",
3446 cmd_guardian_log,
3447 NULL,
3448 CMD_SCOPE_MAIN,
3449 "The filename of the filter debugging log file"
3450 ),
3451
3452 AP_INIT_TAKE1 (
3453 "SecMarker",
3454 cmd_marker,
3455 NULL,
3456 CMD_SCOPE_ANY,
3457 "marker for a skipAfter target"
3458 ),
3459
3460 AP_INIT_TAKE1 (
3461 "SecPcreMatchLimit",
3462 cmd_pcre_match_limit,
3463 NULL,
3464 CMD_SCOPE_MAIN,
3465 "PCRE match limit"
3466 ),
3467
3468 AP_INIT_TAKE1 (
3469 "SecPcreMatchLimitRecursion",
3470 cmd_pcre_match_limit_recursion,
3471 NULL,
3472 CMD_SCOPE_MAIN,
3473 "PCRE match limit recursion"
3474 ),
3475
3476 AP_INIT_TAKE1 (
3477 "SecRequestBodyAccess",
3478 cmd_request_body_access,
3479 NULL,
3480 CMD_SCOPE_ANY,
3481 "On or Off"
3482 ),
3483
3484 AP_INIT_TAKE1 (
3485 "SecInterceptOnError",
3486 cmd_request_intercept_on_error,
3487 NULL,
3488 CMD_SCOPE_ANY,
3489 "On or Off"
3490 ),
3491
3492 AP_INIT_TAKE1 (
3493 "SecRulePerfTime",
3494 cmd_rule_perf_time,
3495 NULL,
3496 CMD_SCOPE_ANY,
3497 "Threshold to log slow rules in usecs."
3498 ),
3499
3500 AP_INIT_TAKE12 (
3501 "SecConnReadStateLimit",
3502 cmd_conn_read_state_limit,
3503 NULL,
3504 CMD_SCOPE_ANY,
3505 "maximum number of threads in READ_BUSY state per ip address"
3506 ),
3507
3508 AP_INIT_TAKE12 (
3509 "SecReadStateLimit",
3510 cmd_read_state_limit,
3511 NULL,
3512 CMD_SCOPE_ANY,
3513 "maximum number of threads in READ_BUSY state per ip address"
3514 ),
3515
3516 AP_INIT_TAKE12 (
3517 "SecConnWriteStateLimit",
3518 cmd_conn_write_state_limit,
3519 NULL,
3520 CMD_SCOPE_ANY,
3521 "maximum number of threads in WRITE_BUSY state per ip address"
3522 ),
3523
3524 AP_INIT_TAKE12 (
3525 "SecWriteStateLimit",
3526 cmd_write_state_limit,
3527 NULL,
3528 CMD_SCOPE_ANY,
3529 "maximum number of threads in WRITE_BUSY state per ip address"
3530 ),
3531
3532 AP_INIT_TAKE1 (
3533 "SecRequestBodyInMemoryLimit",
3534 cmd_request_body_inmemory_limit,
3535 NULL,
3536 CMD_SCOPE_ANY,
3537 "maximum request body size that will be placed in memory (except for POST urlencoded requests)."
3538 ),
3539
3540 AP_INIT_TAKE1 (
3541 "SecRequestBodyLimit",
3542 cmd_request_body_limit,
3543 NULL,
3544 CMD_SCOPE_ANY,
3545 "maximum request body size ModSecurity will accept."
3546 ),
3547
3548 AP_INIT_TAKE1 (
3549 "SecRequestBodyNoFilesLimit",
3550 cmd_request_body_no_files_limit,
3551 NULL,
3552 CMD_SCOPE_ANY,
3553 "maximum request body size ModSecurity will accept, but excluding the size of uploaded files."
3554 ),
3555
3556 AP_INIT_TAKE1 (
3557 "SecRequestEncoding",
3558 cmd_request_encoding,
3559 NULL,
3560 CMD_SCOPE_ANY,
3561 "character encoding used in request."
3562 ),
3563
3564 AP_INIT_TAKE1 (
3565 "SecResponseBodyAccess",
3566 cmd_response_body_access,
3567 NULL,
3568 CMD_SCOPE_ANY,
3569 "On or Off"
3570 ),
3571
3572 AP_INIT_TAKE1 (
3573 "SecResponseBodyLimit",
3574 cmd_response_body_limit,
3575 NULL,
3576 CMD_SCOPE_ANY,
3577 "byte limit for response body"
3578 ),
3579
3580 AP_INIT_TAKE1 (
3581 "SecResponseBodyLimitAction",
3582 cmd_response_body_limit_action,
3583 NULL,
3584 CMD_SCOPE_ANY,
3585 "what happens when the response body limit is reached"
3586 ),
3587
3588 AP_INIT_TAKE1 (
3589 "SecRequestBodyLimitAction",
3590 cmd_resquest_body_limit_action,
3591 NULL,
3592 CMD_SCOPE_ANY,
3593 "what happens when the request body limit is reached"
3594 ),
3595
3596 AP_INIT_ITERATE (
3597 "SecResponseBodyMimeType",
3598 cmd_response_body_mime_type,
3599 NULL,
3600 CMD_SCOPE_ANY,
3601 "adds given MIME types to the list of types that will be buffered on output"
3602 ),
3603
3604 AP_INIT_NO_ARGS (
3605 "SecResponseBodyMimeTypesClear",
3606 cmd_response_body_mime_types_clear,
3607 NULL,
3608 CMD_SCOPE_ANY,
3609 "clears the list of MIME types that will be buffered on output"
3610 ),
3611
3612 #ifdef HTACCESS_CONFIG
3613 AP_INIT_TAKE23 (
3614 "SecRule",
3615 cmd_rule,
3616 NULL,
3617 CMD_SCOPE_HTACCESS,
3618 "rule target, operator and optional action list"
3619 ),
3620 #else
3621 AP_INIT_TAKE23 (
3622 "SecRule",
3623 cmd_rule,
3624 NULL,
3625 CMD_SCOPE_ANY,
3626 "rule target, operator and optional action list"
3627 ),
3628 #endif
3629
3630 AP_INIT_TAKE1 (
3631 "SecRuleEngine",
3632 cmd_rule_engine,
3633 NULL,
3634 CMD_SCOPE_ANY,
3635 "On or Off"
3636 ),
3637
3638 AP_INIT_TAKE1 (
3639 "SecStatusEngine",
3640 cmd_status_engine,
3641 NULL,
3642 CMD_SCOPE_ANY,
3643 "On or Off"
3644 ),
3645
3646 AP_INIT_TAKE1 (
3647 "SecConnEngine",
3648 cmd_sever_conn_filters_engine,
3649 NULL,
3650 CMD_SCOPE_ANY,
3651 "On or Off"
3652 ),
3653
3654 AP_INIT_TAKE23 (
3655 "SecRemoteRules",
3656 cmd_remote_rules,
3657 NULL,
3658 CMD_SCOPE_ANY,
3659 "key and URI to the remote rules"
3660 ),
3661
3662 AP_INIT_TAKE1 (
3663 "SecRemoteRulesFailAction",
3664 cmd_remote_rules_fail,
3665 NULL,
3666 CMD_SCOPE_ANY,
3667 "Abort or Warn"
3668 ),
3669
3670
3671 AP_INIT_TAKE1 (
3672 "SecXmlExternalEntity",
3673 cmd_xml_external_entity,
3674 NULL,
3675 CMD_SCOPE_ANY,
3676 "On or Off"
3677 ),
3678
3679 AP_INIT_FLAG (
3680 "SecRuleInheritance",
3681 cmd_rule_inheritance,
3682 NULL,
3683 CMD_SCOPE_ANY,
3684 "On or Off"
3685 ),
3686
3687 AP_INIT_TAKE12 (
3688 "SecRuleScript",
3689 cmd_rule_script,
3690 NULL,
3691 CMD_SCOPE_ANY,
3692 "rule script and optional actionlist"
3693 ),
3694
3695 #ifdef HTACCESS_CONFIG
3696 AP_INIT_ITERATE (
3697 "SecRuleRemoveById",
3698 cmd_rule_remove_by_id,
3699 NULL,
3700 CMD_SCOPE_HTACCESS,
3701 "rule ID for removal"
3702 ),
3703
3704 AP_INIT_ITERATE (
3705 "SecRuleRemoveByTag",
3706 cmd_rule_remove_by_tag,
3707 NULL,
3708 CMD_SCOPE_HTACCESS,
3709 "rule tag for removal"
3710 ),
3711
3712 AP_INIT_ITERATE (
3713 "SecRuleRemoveByMsg",
3714 cmd_rule_remove_by_msg,
3715 NULL,
3716 CMD_SCOPE_HTACCESS,
3717 "rule message for removal"
3718 ),
3719 #else
3720 AP_INIT_ITERATE (
3721 "SecRuleRemoveById",
3722 cmd_rule_remove_by_id,
3723 NULL,
3724 CMD_SCOPE_ANY,
3725 "rule ID for removal"
3726 ),
3727
3728 AP_INIT_ITERATE (
3729 "SecRuleRemoveByTag",
3730 cmd_rule_remove_by_tag,
3731 NULL,
3732 CMD_SCOPE_ANY,
3733 "rule tag for removal"
3734 ),
3735
3736 AP_INIT_ITERATE (
3737 "SecRuleRemoveByMsg",
3738 cmd_rule_remove_by_msg,
3739 NULL,
3740 CMD_SCOPE_ANY,
3741 "rule message for removal"
3742 ),
3743 #endif
3744
3745 AP_INIT_TAKE2 (
3746 "SecHashMethodPm",
3747 cmd_hash_method_pm,
3748 NULL,
3749 CMD_SCOPE_ANY,
3750 "Hash method and pattern"
3751 ),
3752
3753 AP_INIT_TAKE2 (
3754 "SecHashMethodRx",
3755 cmd_hash_method_rx,
3756 NULL,
3757 CMD_SCOPE_ANY,
3758 "Hash method and regex"
3759 ),
3760
3761 #ifdef HTACCESS_CONFIG
3762 AP_INIT_TAKE2 (
3763 "SecRuleUpdateActionById",
3764 cmd_rule_update_action_by_id,
3765 NULL,
3766 CMD_SCOPE_HTACCESS,
3767 "updated action list"
3768 ),
3769
3770 AP_INIT_TAKE23 (
3771 "SecRuleUpdateTargetById",
3772 cmd_rule_update_target_by_id,
3773 NULL,
3774 CMD_SCOPE_HTACCESS,
3775 "updated target list"
3776 ),
3777
3778 AP_INIT_TAKE23 (
3779 "SecRuleUpdateTargetByTag",
3780 cmd_rule_update_target_by_tag,
3781 NULL,
3782 CMD_SCOPE_HTACCESS,
3783 "rule tag pattern and updated target list"
3784 ),
3785
3786 AP_INIT_TAKE23 (
3787 "SecRuleUpdateTargetByMsg",
3788 cmd_rule_update_target_by_msg,
3789 NULL,
3790 CMD_SCOPE_HTACCESS,
3791 "rule message pattern and updated target list"
3792 ),
3793 #else
3794 AP_INIT_TAKE2 (
3795 "SecRuleUpdateActionById",
3796 cmd_rule_update_action_by_id,
3797 NULL,
3798 CMD_SCOPE_ANY,
3799 "updated action list"
3800 ),
3801
3802 AP_INIT_TAKE23 (
3803 "SecRuleUpdateTargetById",
3804 cmd_rule_update_target_by_id,
3805 NULL,
3806 CMD_SCOPE_ANY,
3807 "updated target list"
3808 ),
3809
3810 AP_INIT_TAKE23 (
3811 "SecRuleUpdateTargetByTag",
3812 cmd_rule_update_target_by_tag,
3813 NULL,
3814 CMD_SCOPE_ANY,
3815 "rule tag pattern and updated target list"
3816 ),
3817
3818 AP_INIT_TAKE23 (
3819 "SecRuleUpdateTargetByMsg",
3820 cmd_rule_update_target_by_msg,
3821 NULL,
3822 CMD_SCOPE_ANY,
3823 "rule message pattern and updated target list"
3824 ),
3825 #endif
3826
3827 AP_INIT_TAKE1 (
3828 "SecServerSignature",
3829 cmd_server_signature,
3830 NULL,
3831 CMD_SCOPE_MAIN,
3832 "the new signature of the server"
3833 ),
3834
3835 AP_INIT_TAKE1 (
3836 "SecTmpDir",
3837 cmd_tmp_dir,
3838 NULL,
3839 CMD_SCOPE_ANY,
3840 "path to the temporary storage area"
3841 ),
3842
3843 AP_INIT_TAKE1 (
3844 "SecUploadDir",
3845 cmd_upload_dir,
3846 NULL,
3847 CMD_SCOPE_ANY,
3848 "path to the file upload area"
3849 ),
3850
3851 AP_INIT_TAKE1 (
3852 "SecUploadFileLimit",
3853 cmd_upload_file_limit,
3854 NULL,
3855 CMD_SCOPE_ANY,
3856 "limit the number of uploaded files processed"
3857 ),
3858
3859 AP_INIT_TAKE1 (
3860 "SecUploadFileMode",
3861 cmd_upload_filemode,
3862 NULL,
3863 CMD_SCOPE_ANY,
3864 "octal permissions mode for uploaded files"
3865 ),
3866
3867 AP_INIT_TAKE1 (
3868 "SecUploadKeepFiles",
3869 cmd_upload_keep_files,
3870 NULL,
3871 CMD_SCOPE_ANY,
3872 "On or Off"
3873 ),
3874
3875 AP_INIT_TAKE1 (
3876 "SecTmpSaveUploadedFiles",
3877 cmd_upload_save_tmp_files,
3878 NULL,
3879 CMD_SCOPE_ANY,
3880 "On or Off"
3881 ),
3882
3883 AP_INIT_TAKE1 (
3884 "SecWebAppId",
3885 cmd_web_app_id,
3886 NULL,
3887 CMD_SCOPE_ANY,
3888 "id"
3889 ),
3890
3891 AP_INIT_TAKE1 (
3892 "SecSensorId",
3893 cmd_sensor_id,
3894 NULL,
3895 CMD_SCOPE_MAIN,
3896 "sensor id"
3897 ),
3898
3899 AP_INIT_TAKE1 (
3900 "SecHttpBlKey",
3901 cmd_httpBl_key,
3902 NULL,
3903 CMD_SCOPE_ANY,
3904 "httpBl access key"
3905 ),
3906
3907 AP_INIT_TAKE1 (
3908 "SecHashEngine",
3909 cmd_hash_engine,
3910 NULL,
3911 CMD_SCOPE_ANY,
3912 "On or Off"
3913 ),
3914
3915 AP_INIT_TAKE2 (
3916 "SecHashKey",
3917 cmd_hash_key,
3918 NULL,
3919 CMD_SCOPE_ANY,
3920 "Set Hash key"
3921 ),
3922
3923 AP_INIT_TAKE1 (
3924 "SecHashParam",
3925 cmd_hash_param,
3926 NULL,
3927 CMD_SCOPE_ANY,
3928 "Set Hash parameter"
3929 ),
3930
3931 { NULL }
3932 };
3933