~ubuntu-branches/ubuntu/raring/modsecurity-apache/raring

« back to all changes in this revision

Viewing changes to .pc/CVE-2013-1915.patch/apache2/apache2_config.c

  • Committer: Package Import Robot
  • Author(s): Alberto Gonzalez Iniesta
  • Date: 2013-04-06 11:09:12 UTC
  • Revision ID: package-import@ubuntu.com-20130406110912-yaj5o9pgrbwhq9w2
Tags: 2.6.6-6
Applied upstream patch to fix XXE attacks. CVE-2013-1915
Thanks Thomas Goirand for backporting the patch.
(Closes: #704625)
Adds new SecXmlExternalEntity option which by default (Off) disables
the external entity load task executed by libxml2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
 
3
* Copyright (c) 2004-2011 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
 
 
22
#if defined(WITH_LUA)
 
23
#include "msc_lua.h"
 
24
#endif
 
25
 
 
26
 
 
27
/* -- Directory context creation and initialisation -- */
 
28
 
 
29
/**
 
30
 * Creates a fresh directory configuration.
 
31
 */
 
32
void *create_directory_config(apr_pool_t *mp, char *path)
 
33
{
 
34
    directory_config *dcfg = (directory_config *)apr_pcalloc(mp, sizeof(directory_config));
 
35
    if (dcfg == NULL) return NULL;
 
36
 
 
37
    #ifdef DEBUG_CONF
 
38
    ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Created directory config %pp path %s", dcfg, path);
 
39
    #endif
 
40
 
 
41
    dcfg->mp = mp;
 
42
    dcfg->is_enabled = NOT_SET;
 
43
 
 
44
    dcfg->reqbody_access = NOT_SET;
 
45
    dcfg->reqintercept_oe = NOT_SET;
 
46
    dcfg->reqbody_buffering = NOT_SET;
 
47
    dcfg->reqbody_inmemory_limit = NOT_SET;
 
48
    dcfg->reqbody_limit = NOT_SET;
 
49
    dcfg->reqbody_no_files_limit = NOT_SET;
 
50
    dcfg->resbody_access = NOT_SET;
 
51
 
 
52
    dcfg->debuglog_name = NOT_SET_P;
 
53
    dcfg->debuglog_level = NOT_SET;
 
54
    dcfg->debuglog_fd = NOT_SET_P;
 
55
 
 
56
    dcfg->of_limit = NOT_SET;
 
57
    dcfg->if_limit_action = NOT_SET;
 
58
    dcfg->of_limit_action = NOT_SET;
 
59
    dcfg->of_mime_types = NOT_SET_P;
 
60
    dcfg->of_mime_types_cleared = NOT_SET;
 
61
 
 
62
    dcfg->cookie_format = NOT_SET;
 
63
    dcfg->argument_separator = NOT_SET;
 
64
 
 
65
    dcfg->rule_inheritance = NOT_SET;
 
66
    dcfg->rule_exceptions = apr_array_make(mp, 16, sizeof(rule_exception *));
 
67
 
 
68
    /* audit log variables */
 
69
    dcfg->auditlog_flag = NOT_SET;
 
70
    dcfg->auditlog_type = NOT_SET;
 
71
    dcfg->auditlog_dirperms = NOT_SET;
 
72
    dcfg->auditlog_fileperms = NOT_SET;
 
73
    dcfg->auditlog_name = NOT_SET_P;
 
74
    dcfg->auditlog2_name = NOT_SET_P;
 
75
    dcfg->auditlog_fd = NOT_SET_P;
 
76
    dcfg->auditlog2_fd = NOT_SET_P;
 
77
    dcfg->auditlog_storage_dir = NOT_SET_P;
 
78
    dcfg->auditlog_parts = NOT_SET_P;
 
79
    dcfg->auditlog_relevant_regex = NOT_SET_P;
 
80
 
 
81
    dcfg->ruleset = NULL;
 
82
 
 
83
    /* Upload */
 
84
    dcfg->tmp_dir = NOT_SET_P;
 
85
    dcfg->upload_dir = NOT_SET_P;
 
86
    dcfg->upload_keep_files = NOT_SET;
 
87
    dcfg->upload_validates_files = NOT_SET;
 
88
    dcfg->upload_filemode = NOT_SET;
 
89
    dcfg->upload_file_limit = NOT_SET;
 
90
 
 
91
    /* These are only used during the configuration process. */
 
92
    dcfg->tmp_chain_starter = NULL;
 
93
    dcfg->tmp_default_actionset = NULL;
 
94
    dcfg->tmp_rule_placeholders = NULL;
 
95
 
 
96
    /* Misc */
 
97
    dcfg->data_dir = NOT_SET_P;
 
98
    dcfg->webappid = NOT_SET_P;
 
99
 
 
100
    /* Content injection. */
 
101
    dcfg->content_injection_enabled = NOT_SET;
 
102
 
 
103
    /* Stream inspection */
 
104
    dcfg->stream_inbody_inspection = NOT_SET;
 
105
    dcfg->stream_outbody_inspection = NOT_SET;
 
106
 
 
107
    /* Geo Lookups */
 
108
    dcfg->geo = NOT_SET_P;
 
109
 
 
110
    /* Gsb Lookups */
 
111
    dcfg->gsb = NOT_SET_P;
 
112
 
 
113
    /* Unicode Map */
 
114
    dcfg->u_map = NOT_SET_P;
 
115
 
 
116
    /* Cache */
 
117
    dcfg->cache_trans = NOT_SET;
 
118
    dcfg->cache_trans_incremental = NOT_SET;
 
119
    dcfg->cache_trans_min = NOT_SET;
 
120
    dcfg->cache_trans_max = NOT_SET;
 
121
    dcfg->cache_trans_maxitems = NOT_SET;
 
122
 
 
123
    dcfg->component_signatures = apr_array_make(mp, 16, sizeof(char *));
 
124
 
 
125
    dcfg->request_encoding = NOT_SET_P;
 
126
    dcfg->disable_backend_compression = NOT_SET;
 
127
 
 
128
    /* Collection timeout */
 
129
    dcfg->col_timeout = NOT_SET;
 
130
 
 
131
    return dcfg;
 
132
}
 
133
 
 
134
/**
 
135
 * Copies rules between one phase of two configuration contexts,
 
136
 * taking exceptions into account.
 
137
 */
 
138
static void copy_rules_phase(apr_pool_t *mp,
 
139
                             apr_array_header_t *parent_phase_arr,
 
140
                             apr_array_header_t *child_phase_arr,
 
141
                             apr_array_header_t *exceptions_arr)
 
142
{
 
143
    rule_exception **exceptions;
 
144
    msre_rule **rules;
 
145
    int i, j;
 
146
    int mode = 0;
 
147
 
 
148
    rules = (msre_rule **)parent_phase_arr->elts;
 
149
    for(i = 0; i < parent_phase_arr->nelts; i++) {
 
150
        msre_rule *rule = (msre_rule *)rules[i];
 
151
        int copy = 1;
 
152
 
 
153
        if (mode == 0) {
 
154
            /* First rule in the chain. */
 
155
            exceptions = (rule_exception **)exceptions_arr->elts;
 
156
            for(j = 0; j < exceptions_arr->nelts; j++) {
 
157
 
 
158
                /* Process exceptions. */
 
159
                switch(exceptions[j]->type) {
 
160
                    case RULE_EXCEPTION_REMOVE_ID :
 
161
                        if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) {
 
162
                            int ruleid = atoi(rule->actionset->id);
 
163
                            if (rule_id_in_range(ruleid, exceptions[j]->param)) copy--;
 
164
                        }
 
165
                        break;
 
166
                    case RULE_EXCEPTION_REMOVE_MSG :
 
167
                        if ((rule->actionset != NULL)&&(rule->actionset->msg != NULL)) {
 
168
                            char *my_error_msg = NULL;
 
169
 
 
170
                            int rc = msc_regexec(exceptions[j]->param_data,
 
171
                                    rule->actionset->msg, strlen(rule->actionset->msg),
 
172
                                    &my_error_msg);
 
173
                            if (rc >= 0) copy--;
 
174
                        }
 
175
                        break;
 
176
                    case RULE_EXCEPTION_REMOVE_TAG :
 
177
                        if ((rule->actionset != NULL)&&(apr_is_empty_table(rule->actionset->actions) == 0)) {
 
178
                            char *my_error_msg = NULL;
 
179
                            const apr_array_header_t *tarr = NULL;
 
180
                            const apr_table_entry_t *telts = NULL;
 
181
                            int c;
 
182
 
 
183
                            tarr = apr_table_elts(rule->actionset->actions);
 
184
                            telts = (const apr_table_entry_t*)tarr->elts;
 
185
 
 
186
                            for (c = 0; c < tarr->nelts; c++) {
 
187
                                msre_action *action = (msre_action *)telts[c].val;
 
188
                                if(strcmp("tag", action->metadata->name) == 0)  {
 
189
 
 
190
                                    int rc = msc_regexec(exceptions[j]->param_data,
 
191
                                            action->param, strlen(action->param),
 
192
                                            &my_error_msg);
 
193
                                    if (rc >= 0) copy--;
 
194
                                }
 
195
                            }
 
196
                        }
 
197
                        break;
 
198
                }
 
199
            }
 
200
 
 
201
            if (copy > 0) {
 
202
#ifdef DEBUG_CONF
 
203
                ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, rule->actionset->id);
 
204
#endif
 
205
 
 
206
                /* Copy the rule. */
 
207
                *(msre_rule **)apr_array_push(child_phase_arr) = rule;
 
208
                if (rule->actionset->is_chained) mode = 2;
 
209
            } else {
 
210
                if (rule->actionset->is_chained) mode = 1;
 
211
            }
 
212
        } else {
 
213
            if (mode == 2) {
 
214
#ifdef DEBUG_CONF
 
215
                ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy chain %pp for rule %pp [id \"%s\"]", rule, rule->chain_starter, rule->chain_starter->actionset->id);
 
216
#endif
 
217
 
 
218
                /* Copy the rule (it belongs to the chain we want to include. */
 
219
                *(msre_rule **)apr_array_push(child_phase_arr) = rule;
 
220
            }
 
221
 
 
222
            if ((rule->actionset == NULL)||(rule->actionset->is_chained == 0)) mode = 0;
 
223
        }
 
224
    }
 
225
}
 
226
 
 
227
/**
 
228
 * Copies rules between two configuration contexts,
 
229
 * taking exceptions into account.
 
230
 */
 
231
static int copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset,
 
232
                      msre_ruleset *child_ruleset,
 
233
                      apr_array_header_t *exceptions_arr)
 
234
{
 
235
    copy_rules_phase(mp, parent_ruleset->phase_request_headers,
 
236
        child_ruleset->phase_request_headers, exceptions_arr);
 
237
    copy_rules_phase(mp, parent_ruleset->phase_request_body,
 
238
        child_ruleset->phase_request_body, exceptions_arr);
 
239
    copy_rules_phase(mp, parent_ruleset->phase_response_headers,
 
240
        child_ruleset->phase_response_headers, exceptions_arr);
 
241
    copy_rules_phase(mp, parent_ruleset->phase_response_body,
 
242
        child_ruleset->phase_response_body, exceptions_arr);
 
243
    copy_rules_phase(mp, parent_ruleset->phase_logging,
 
244
        child_ruleset->phase_logging, exceptions_arr);
 
245
 
 
246
    return 1;
 
247
}
 
248
 
 
249
/**
 
250
 * Merges two directory configurations.
 
251
 */
 
252
void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
 
253
{
 
254
    directory_config *parent = (directory_config *)_parent;
 
255
    directory_config *child = (directory_config *)_child;
 
256
    directory_config *merged = create_directory_config(mp, NULL);
 
257
 
 
258
    #ifdef DEBUG_CONF
 
259
    ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Merge parent %pp child %pp RESULT %pp", _parent, _child, merged);
 
260
    #endif
 
261
 
 
262
    if (merged == NULL) return NULL;
 
263
 
 
264
    /* Use values from the child configuration where possible,
 
265
     * otherwise use the parent's.
 
266
     */
 
267
 
 
268
    merged->is_enabled = (child->is_enabled == NOT_SET
 
269
        ? parent->is_enabled : child->is_enabled);
 
270
 
 
271
    /* IO parameters */
 
272
    merged->reqbody_access = (child->reqbody_access == NOT_SET
 
273
        ? parent->reqbody_access : child->reqbody_access);
 
274
    merged->reqbody_buffering = (child->reqbody_buffering == NOT_SET
 
275
        ? parent->reqbody_buffering : child->reqbody_buffering);
 
276
    merged->reqbody_inmemory_limit = (child->reqbody_inmemory_limit == NOT_SET
 
277
        ? parent->reqbody_inmemory_limit : child->reqbody_inmemory_limit);
 
278
    merged->reqbody_limit = (child->reqbody_limit == NOT_SET
 
279
        ? parent->reqbody_limit : child->reqbody_limit);
 
280
    merged->reqbody_no_files_limit = (child->reqbody_no_files_limit == NOT_SET
 
281
        ? parent->reqbody_no_files_limit : child->reqbody_no_files_limit);
 
282
    merged->resbody_access = (child->resbody_access == NOT_SET
 
283
        ? parent->resbody_access : child->resbody_access);
 
284
 
 
285
    merged->of_limit = (child->of_limit == NOT_SET
 
286
        ? parent->of_limit : child->of_limit);
 
287
    merged->if_limit_action = (child->if_limit_action == NOT_SET
 
288
        ? parent->if_limit_action : child->if_limit_action);
 
289
    merged->of_limit_action = (child->of_limit_action == NOT_SET
 
290
        ? parent->of_limit_action : child->of_limit_action);
 
291
    merged->reqintercept_oe = (child->reqintercept_oe == NOT_SET
 
292
        ? parent->reqintercept_oe : child->reqintercept_oe);
 
293
 
 
294
    if (child->of_mime_types != NOT_SET_P) {
 
295
        /* Child added to the table */
 
296
 
 
297
        if (child->of_mime_types_cleared == 1) {
 
298
            /* The list of MIME types was cleared in the child,
 
299
             * which means the parent's MIME types went away and
 
300
             * we should not take them into consideration here.
 
301
             */
 
302
            merged->of_mime_types = child->of_mime_types;
 
303
            merged->of_mime_types_cleared = 1;
 
304
        } else {
 
305
            /* Add MIME types defined in the child to those
 
306
             * defined in the parent context.
 
307
             */
 
308
            if (parent->of_mime_types == NOT_SET_P) {
 
309
                merged->of_mime_types = child->of_mime_types;
 
310
                merged->of_mime_types_cleared = NOT_SET;
 
311
            } else {
 
312
                merged->of_mime_types = apr_table_overlay(mp, parent->of_mime_types,
 
313
                    child->of_mime_types);
 
314
                if (merged->of_mime_types == NULL) return NULL;
 
315
            }
 
316
        }
 
317
    } else {
 
318
        /* Child did not add to the table */
 
319
 
 
320
        if (child->of_mime_types_cleared == 1) {
 
321
            merged->of_mime_types_cleared = 1;
 
322
        } else {
 
323
            merged->of_mime_types = parent->of_mime_types;
 
324
            merged->of_mime_types_cleared = parent->of_mime_types_cleared;
 
325
        }
 
326
    }
 
327
 
 
328
    /* debug log */
 
329
    if (child->debuglog_fd == NOT_SET_P) {
 
330
        merged->debuglog_name = parent->debuglog_name;
 
331
        merged->debuglog_fd = parent->debuglog_fd;
 
332
    } else {
 
333
        merged->debuglog_name = child->debuglog_name;
 
334
        merged->debuglog_fd = child->debuglog_fd;
 
335
    }
 
336
 
 
337
    merged->debuglog_level = (child->debuglog_level == NOT_SET
 
338
        ? parent->debuglog_level : child->debuglog_level);
 
339
 
 
340
    merged->cookie_format = (child->cookie_format == NOT_SET
 
341
        ? parent->cookie_format : child->cookie_format);
 
342
    merged->argument_separator = (child->argument_separator == NOT_SET
 
343
        ? parent->argument_separator : child->argument_separator);
 
344
 
 
345
 
 
346
    /* rule inheritance */
 
347
    if ((child->rule_inheritance == NOT_SET)||(child->rule_inheritance == 1)) {
 
348
        merged->rule_inheritance = parent->rule_inheritance;
 
349
        if ((child->ruleset == NULL)&&(parent->ruleset == NULL)) {
 
350
            #ifdef DEBUG_CONF
 
351
            ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "No rules in this context.");
 
352
            #endif
 
353
 
 
354
            /* Do nothing, there are no rules in either context. */
 
355
        } else
 
356
        if (child->ruleset == NULL) {
 
357
            #ifdef DEBUG_CONF
 
358
            ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent rules in this context.");
 
359
            #endif
 
360
 
 
361
            /* Copy the rules from the parent context. */
 
362
            merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp);
 
363
            copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions);
 
364
        } else
 
365
        if (parent->ruleset == NULL) {
 
366
            #ifdef DEBUG_CONF
 
367
            ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using child rules in this context.");
 
368
            #endif
 
369
 
 
370
            /* Copy child rules. */
 
371
            merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp);
 
372
            merged->ruleset->phase_request_headers = apr_array_copy(mp,
 
373
                child->ruleset->phase_request_headers);
 
374
            merged->ruleset->phase_request_body = apr_array_copy(mp,
 
375
                child->ruleset->phase_request_body);
 
376
            merged->ruleset->phase_response_headers = apr_array_copy(mp,
 
377
                child->ruleset->phase_response_headers);
 
378
            merged->ruleset->phase_response_body = apr_array_copy(mp,
 
379
                child->ruleset->phase_response_body);
 
380
            merged->ruleset->phase_logging = apr_array_copy(mp,
 
381
                child->ruleset->phase_logging);
 
382
        } else {
 
383
            #ifdef DEBUG_CONF
 
384
            ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent then child rules in this context.");
 
385
            #endif
 
386
 
 
387
            /* Copy parent rules, then add child rules to it. */
 
388
            merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp);
 
389
            copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions);
 
390
 
 
391
            apr_array_cat(merged->ruleset->phase_request_headers,
 
392
                child->ruleset->phase_request_headers);
 
393
            apr_array_cat(merged->ruleset->phase_request_body,
 
394
                child->ruleset->phase_request_body);
 
395
            apr_array_cat(merged->ruleset->phase_response_headers,
 
396
                child->ruleset->phase_response_headers);
 
397
            apr_array_cat(merged->ruleset->phase_response_body,
 
398
                child->ruleset->phase_response_body);
 
399
            apr_array_cat(merged->ruleset->phase_logging,
 
400
                child->ruleset->phase_logging);
 
401
        }
 
402
    } else {
 
403
        merged->rule_inheritance = 0;
 
404
        if (child->ruleset != NULL) {
 
405
            /* Copy child rules. */
 
406
            merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp);
 
407
            merged->ruleset->phase_request_headers = apr_array_copy(mp,
 
408
                child->ruleset->phase_request_headers);
 
409
            merged->ruleset->phase_request_body = apr_array_copy(mp,
 
410
                child->ruleset->phase_request_body);
 
411
            merged->ruleset->phase_response_headers = apr_array_copy(mp,
 
412
                child->ruleset->phase_response_headers);
 
413
            merged->ruleset->phase_response_body = apr_array_copy(mp,
 
414
                child->ruleset->phase_response_body);
 
415
            merged->ruleset->phase_logging = apr_array_copy(mp,
 
416
                child->ruleset->phase_logging);
 
417
        }
 
418
    }
 
419
 
 
420
    /* Merge rule exceptions. */
 
421
    merged->rule_exceptions = apr_array_append(mp, parent->rule_exceptions,
 
422
        child->rule_exceptions);
 
423
 
 
424
    /* audit log variables */
 
425
    merged->auditlog_flag = (child->auditlog_flag == NOT_SET
 
426
        ? parent->auditlog_flag : child->auditlog_flag);
 
427
    merged->auditlog_type = (child->auditlog_type == NOT_SET
 
428
        ? parent->auditlog_type : child->auditlog_type);
 
429
    merged->auditlog_dirperms = (child->auditlog_dirperms == NOT_SET
 
430
        ? parent->auditlog_dirperms : child->auditlog_dirperms);
 
431
    merged->auditlog_fileperms = (child->auditlog_fileperms == NOT_SET
 
432
        ? parent->auditlog_fileperms : child->auditlog_fileperms);
 
433
    if (child->auditlog_fd != NOT_SET_P) {
 
434
        merged->auditlog_fd = child->auditlog_fd;
 
435
        merged->auditlog_name = child->auditlog_name;
 
436
    } else {
 
437
        merged->auditlog_fd = parent->auditlog_fd;
 
438
        merged->auditlog_name = parent->auditlog_name;
 
439
    }
 
440
    if (child->auditlog2_fd != NOT_SET_P) {
 
441
        merged->auditlog2_fd = child->auditlog2_fd;
 
442
        merged->auditlog2_name = child->auditlog2_name;
 
443
    } else {
 
444
        merged->auditlog2_fd = parent->auditlog2_fd;
 
445
        merged->auditlog2_name = parent->auditlog2_name;
 
446
    }
 
447
    merged->auditlog_storage_dir = (child->auditlog_storage_dir == NOT_SET_P
 
448
        ? parent->auditlog_storage_dir : child->auditlog_storage_dir);
 
449
    merged->auditlog_parts = (child->auditlog_parts == NOT_SET_P
 
450
        ? parent->auditlog_parts : child->auditlog_parts);
 
451
    merged->auditlog_relevant_regex = (child->auditlog_relevant_regex == NOT_SET_P
 
452
        ? parent->auditlog_relevant_regex : child->auditlog_relevant_regex);
 
453
 
 
454
    /* Upload */
 
455
    merged->tmp_dir = (child->tmp_dir == NOT_SET_P
 
456
        ? parent->tmp_dir : child->tmp_dir);
 
457
    merged->upload_dir = (child->upload_dir == NOT_SET_P
 
458
        ? parent->upload_dir : child->upload_dir);
 
459
    merged->upload_keep_files = (child->upload_keep_files == NOT_SET
 
460
        ? parent->upload_keep_files : child->upload_keep_files);
 
461
    merged->upload_validates_files = (child->upload_validates_files == NOT_SET
 
462
        ? parent->upload_validates_files : child->upload_validates_files);
 
463
    merged->upload_filemode = (child->upload_filemode == NOT_SET
 
464
        ? parent->upload_filemode : child->upload_filemode);
 
465
    merged->upload_file_limit = (child->upload_file_limit == NOT_SET
 
466
        ? parent->upload_file_limit : child->upload_file_limit);
 
467
 
 
468
    /* Misc */
 
469
    merged->data_dir = (child->data_dir == NOT_SET_P
 
470
        ? parent->data_dir : child->data_dir);
 
471
    merged->webappid = (child->webappid == NOT_SET_P
 
472
        ? parent->webappid : child->webappid);
 
473
 
 
474
    /* Content injection. */
 
475
    merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET
 
476
        ? parent->content_injection_enabled : child->content_injection_enabled);
 
477
 
 
478
    /* Stream inspection */
 
479
    merged->stream_inbody_inspection = (child->stream_inbody_inspection == NOT_SET
 
480
        ? parent->stream_inbody_inspection : child->stream_inbody_inspection);
 
481
    merged->stream_outbody_inspection = (child->stream_outbody_inspection == NOT_SET
 
482
        ? parent->stream_outbody_inspection : child->stream_outbody_inspection);
 
483
 
 
484
    /* Geo Lookup */
 
485
    merged->geo = (child->geo == NOT_SET_P
 
486
        ? parent->geo : child->geo);
 
487
 
 
488
    /* Gsb Lookup */
 
489
    merged->gsb = (child->gsb == NOT_SET_P
 
490
        ? parent->gsb : child->gsb);
 
491
 
 
492
    /* Unicode Map */
 
493
    merged->u_map = (child->u_map == NOT_SET_P
 
494
        ? parent->u_map : child->u_map);
 
495
 
 
496
    /* Cache */
 
497
    merged->cache_trans = (child->cache_trans == NOT_SET
 
498
        ? parent->cache_trans : child->cache_trans);
 
499
    merged->cache_trans_incremental = (child->cache_trans_incremental == NOT_SET
 
500
        ? parent->cache_trans_incremental : child->cache_trans_incremental);
 
501
    merged->cache_trans_min = (child->cache_trans_min == (apr_size_t)NOT_SET
 
502
        ? parent->cache_trans_min : child->cache_trans_min);
 
503
    merged->cache_trans_max = (child->cache_trans_max == (apr_size_t)NOT_SET
 
504
        ? parent->cache_trans_max : child->cache_trans_max);
 
505
    merged->cache_trans_maxitems = (child->cache_trans_maxitems == (apr_size_t)NOT_SET
 
506
        ? parent->cache_trans_maxitems : child->cache_trans_maxitems);
 
507
 
 
508
    /* Merge component signatures. */
 
509
    merged->component_signatures = apr_array_append(mp, parent->component_signatures,
 
510
        child->component_signatures);
 
511
 
 
512
    merged->request_encoding = (child->request_encoding == NOT_SET_P
 
513
        ? parent->request_encoding : child->request_encoding);
 
514
 
 
515
    merged->disable_backend_compression = (child->disable_backend_compression == NOT_SET
 
516
        ? parent->disable_backend_compression : child->disable_backend_compression);
 
517
 
 
518
    merged->col_timeout = (child->col_timeout == NOT_SET
 
519
        ? parent->col_timeout : child->col_timeout);
 
520
 
 
521
    return merged;
 
522
}
 
523
 
 
524
/**
 
525
 * Initialise directory configuration. This function is *not* meant
 
526
 * to be called for directory configuration instances created during
 
527
 * the configuration phase. It can only be called on copies of those
 
528
 * (created fresh for every transaction).
 
529
 */
 
530
void init_directory_config(directory_config *dcfg)
 
531
{
 
532
    if (dcfg == NULL) return;
 
533
 
 
534
    if (dcfg->is_enabled == NOT_SET) dcfg->is_enabled = 0;
 
535
 
 
536
    if (dcfg->reqbody_access == NOT_SET) dcfg->reqbody_access = 0;
 
537
    if (dcfg->reqintercept_oe == NOT_SET) dcfg->reqintercept_oe = 0;
 
538
    if (dcfg->reqbody_buffering == NOT_SET) dcfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_OFF;
 
539
    if (dcfg->reqbody_inmemory_limit == NOT_SET)
 
540
        dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT;
 
541
    if (dcfg->reqbody_limit == NOT_SET) dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT;
 
542
    if (dcfg->reqbody_no_files_limit == NOT_SET) dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT;
 
543
    if (dcfg->resbody_access == NOT_SET) dcfg->resbody_access = 0;
 
544
    if (dcfg->of_limit == NOT_SET) dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT;
 
545
    if (dcfg->if_limit_action == NOT_SET) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT;
 
546
    if (dcfg->of_limit_action == NOT_SET) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
 
547
 
 
548
    if (dcfg->of_mime_types == NOT_SET_P) {
 
549
        dcfg->of_mime_types = apr_table_make(dcfg->mp, 3);
 
550
        if (dcfg->of_mime_types_cleared != 1) {
 
551
            apr_table_setn(dcfg->of_mime_types, "text/plain", "1");
 
552
            apr_table_setn(dcfg->of_mime_types, "text/html", "1");
 
553
        }
 
554
    }
 
555
 
 
556
    if (dcfg->debuglog_fd == NOT_SET_P) dcfg->debuglog_fd = NULL;
 
557
    if (dcfg->debuglog_name == NOT_SET_P) dcfg->debuglog_name = NULL;
 
558
    if (dcfg->debuglog_level == NOT_SET) dcfg->debuglog_level = 0;
 
559
 
 
560
    if (dcfg->cookie_format == NOT_SET) dcfg->cookie_format = 0;
 
561
    if (dcfg->argument_separator == NOT_SET) dcfg->argument_separator = '&';
 
562
 
 
563
    if (dcfg->rule_inheritance == NOT_SET) dcfg->rule_inheritance = 1;
 
564
 
 
565
    /* audit log variables */
 
566
    if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0;
 
567
    if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL;
 
568
    if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR;
 
569
    if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE;
 
570
    if (dcfg->auditlog_fd == NOT_SET_P) dcfg->auditlog_fd = NULL;
 
571
    if (dcfg->auditlog2_fd == NOT_SET_P) dcfg->auditlog2_fd = NULL;
 
572
    if (dcfg->auditlog_name == NOT_SET_P) dcfg->auditlog_name = NULL;
 
573
    if (dcfg->auditlog2_name == NOT_SET_P) dcfg->auditlog2_name = NULL;
 
574
    if (dcfg->auditlog_storage_dir == NOT_SET_P) dcfg->auditlog_storage_dir = NULL;
 
575
    if (dcfg->auditlog_parts == NOT_SET_P) dcfg->auditlog_parts = "ABCFHZ";
 
576
    if (dcfg->auditlog_relevant_regex == NOT_SET_P) dcfg->auditlog_relevant_regex = NULL;
 
577
 
 
578
    /* Upload */
 
579
    if (dcfg->tmp_dir == NOT_SET_P) dcfg->tmp_dir = guess_tmp_dir(dcfg->mp);
 
580
    if (dcfg->upload_dir == NOT_SET_P) dcfg->upload_dir = NULL;
 
581
    if (dcfg->upload_keep_files == NOT_SET) dcfg->upload_keep_files = KEEP_FILES_OFF;
 
582
    if (dcfg->upload_validates_files == NOT_SET) dcfg->upload_validates_files = 0;
 
583
    if (dcfg->upload_filemode == NOT_SET) dcfg->upload_filemode = 0600;
 
584
    if (dcfg->upload_file_limit == NOT_SET) dcfg->upload_file_limit = 100;
 
585
 
 
586
    /* Misc */
 
587
    if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL;
 
588
    if (dcfg->webappid == NOT_SET_P) dcfg->webappid = "default";
 
589
 
 
590
    /* Content injection. */
 
591
    if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0;
 
592
 
 
593
    /* Stream inspection */
 
594
    if (dcfg->stream_inbody_inspection == NOT_SET) dcfg->stream_inbody_inspection = 0;
 
595
    if (dcfg->stream_outbody_inspection == NOT_SET) dcfg->stream_outbody_inspection = 0;
 
596
 
 
597
    /* Geo Lookup */
 
598
    if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL;
 
599
 
 
600
    /* Gsb Lookup */
 
601
    if (dcfg->gsb == NOT_SET_P) dcfg->gsb = NULL;
 
602
 
 
603
    /* Unicode Map */
 
604
    if (dcfg->u_map == NOT_SET_P) dcfg->u_map = NULL;
 
605
 
 
606
    /* Cache */
 
607
    if (dcfg->cache_trans == NOT_SET) dcfg->cache_trans = MODSEC_CACHE_DISABLED;
 
608
    if (dcfg->cache_trans_incremental == NOT_SET) dcfg->cache_trans_incremental = 0;
 
609
    if (dcfg->cache_trans_min == (apr_size_t)NOT_SET) dcfg->cache_trans_min = 32;
 
610
    if (dcfg->cache_trans_max == (apr_size_t)NOT_SET) dcfg->cache_trans_max = 1024;
 
611
    if (dcfg->cache_trans_maxitems == (apr_size_t)NOT_SET) dcfg->cache_trans_maxitems = 512;
 
612
 
 
613
    if (dcfg->request_encoding == NOT_SET_P) dcfg->request_encoding = NULL;
 
614
 
 
615
    if (dcfg->disable_backend_compression == NOT_SET) dcfg->disable_backend_compression = 0;
 
616
 
 
617
    if (dcfg->col_timeout == NOT_SET) dcfg->col_timeout = 3600;
 
618
}
 
619
 
 
620
/**
 
621
 *
 
622
 */
 
623
static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
 
624
                            const char *p1, const char *p2, const char *p3)
 
625
{
 
626
    char *my_error_msg = NULL;
 
627
    msre_rule *rule = NULL;
 
628
    extern msc_engine *modsecurity;
 
629
 
 
630
    #ifdef DEBUG_CONF
 
631
    ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
 
632
        "Rule: type=%d p1='%s' p2='%s' p3='%s'", type, p1, p2, p3);
 
633
    #endif
 
634
 
 
635
    /* Create a ruleset if one does not exist. */
 
636
    if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) {
 
637
        dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool);
 
638
        if (dcfg->ruleset == NULL) return FATAL_ERROR;
 
639
    }
 
640
 
 
641
    /* Create the rule now. */
 
642
    switch(type) {
 
643
        #if defined(WITH_LUA)
 
644
        case RULE_TYPE_LUA :
 
645
            rule = msre_rule_lua_create(dcfg->ruleset, cmd->directive->filename,
 
646
                cmd->directive->line_num, p1, p2, &my_error_msg);
 
647
            break;
 
648
        #endif
 
649
        default :
 
650
            rule = msre_rule_create(dcfg->ruleset, type, cmd->directive->filename,
 
651
                cmd->directive->line_num, p1, p2, p3, &my_error_msg);
 
652
            break;
 
653
    }
 
654
 
 
655
    if (rule == NULL) {
 
656
        return my_error_msg;
 
657
    }
 
658
 
 
659
    /* Create default actionset if one does not already exist. */
 
660
    if (dcfg->tmp_default_actionset == NULL) {
 
661
        dcfg->tmp_default_actionset = msre_actionset_create_default(modsecurity->msre);
 
662
        if (dcfg->tmp_default_actionset == NULL) return FATAL_ERROR;
 
663
    }
 
664
 
 
665
    /* Check some cases prior to merging so we know where it came from */
 
666
 
 
667
    /* Check syntax for chained rules */
 
668
    if ((rule->actionset != NULL) && (dcfg->tmp_chain_starter != NULL)) {
 
669
        /* Must NOT specify a disruptive action. */
 
670
        if (rule->actionset->intercept_action != NOT_SET) {
 
671
            return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions can only "
 
672
                "be specified by chain starter rules.");
 
673
        }
 
674
 
 
675
        /* Must NOT specify a skipafter action. */
 
676
        if (rule->actionset->skip_after != NOT_SET_P) {
 
677
            return apr_psprintf(cmd->pool, "ModSecurity: SkipAfter actions can only "
 
678
                "be specified by chain starter rules.");
 
679
        }
 
680
 
 
681
        /* Must NOT specify a phase. */
 
682
        if (rule->actionset->phase != NOT_SET) {
 
683
            return apr_psprintf(cmd->pool, "ModSecurity: Execution phases can only be "
 
684
                "specified by chain starter rules.");
 
685
        }
 
686
 
 
687
        /* Must NOT use metadata actions. */
 
688
        /* ENH: loop through to check for tags */
 
689
        if ((rule->actionset->id != NOT_SET_P)
 
690
            ||(rule->actionset->rev != NOT_SET_P)
 
691
            ||(rule->actionset->msg != NOT_SET_P)
 
692
            ||(rule->actionset->severity != NOT_SET)
 
693
            ||(rule->actionset->logdata != NOT_SET_P))
 
694
        {
 
695
            return apr_psprintf(cmd->pool, "ModSecurity: Metadata actions (id, rev, msg, tag, severity, logdata) "
 
696
                " can only be specified by chain starter rules.");
 
697
        }
 
698
 
 
699
        /* Must NOT use skip. */
 
700
        if (rule->actionset->skip_count != NOT_SET) {
 
701
            return apr_psprintf(cmd->pool, "ModSecurity: The skip action can only be used "
 
702
                " by chain starter rules. ");
 
703
        }
 
704
    }
 
705
 
 
706
    /* Merge actions with the parent.
 
707
     *
 
708
     * ENH Probably do not want this done fully for chained rules.
 
709
     */
 
710
    rule->actionset = msre_actionset_merge(modsecurity->msre, dcfg->tmp_default_actionset,
 
711
        rule->actionset, 1);
 
712
 
 
713
    /* Keep track of the parent action for "block" */
 
714
    rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec;
 
715
    rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action;
 
716
 
 
717
    /* Must NOT specify a disruptive action in logging phase. */
 
718
    if ((rule->actionset != NULL)
 
719
        && (rule->actionset->phase == PHASE_LOGGING)
 
720
        && (rule->actionset->intercept_action != ACTION_ALLOW)
 
721
        && (rule->actionset->intercept_action != ACTION_ALLOW_REQUEST)
 
722
        && (rule->actionset->intercept_action != ACTION_NONE)
 
723
    ) {
 
724
        return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions "
 
725
            "cannot be specified in the logging phase.");
 
726
    }
 
727
 
 
728
    if (dcfg->tmp_chain_starter != NULL) {
 
729
        rule->chain_starter = dcfg->tmp_chain_starter;
 
730
        rule->actionset->phase = rule->chain_starter->actionset->phase;
 
731
    }
 
732
 
 
733
    if (rule->actionset->is_chained != 1) {
 
734
        /* If this rule is part of the chain but does
 
735
         * not want more rules to follow in the chain
 
736
         * then cut it (the chain).
 
737
         */
 
738
        dcfg->tmp_chain_starter = NULL;
 
739
    } else {
 
740
        /* On the other hand, if this rule wants other
 
741
         * rules to follow it, then start a new chain
 
742
         * if there isn't one already.
 
743
         */
 
744
        if (dcfg->tmp_chain_starter == NULL) {
 
745
            dcfg->tmp_chain_starter = rule;
 
746
        }
 
747
    }
 
748
 
 
749
    /* Optimisation */
 
750
    if ((rule->op_name != NULL)&&(strcasecmp(rule->op_name, "inspectFile") == 0)) {
 
751
        dcfg->upload_validates_files = 1;
 
752
    }
 
753
 
 
754
    /* Create skip table if one does not already exist. */
 
755
    if (dcfg->tmp_rule_placeholders == NULL) {
 
756
        dcfg->tmp_rule_placeholders = apr_table_make(cmd->pool, 10);
 
757
        if (dcfg->tmp_rule_placeholders == NULL) return FATAL_ERROR;
 
758
    }
 
759
 
 
760
    /* Keep track of any rule IDs we need to skip after */
 
761
    if (rule->actionset->skip_after != NOT_SET_P) {
 
762
        char *tmp_id = apr_pstrdup(cmd->pool, rule->actionset->skip_after);
 
763
        apr_table_setn(dcfg->tmp_rule_placeholders, tmp_id, tmp_id);
 
764
 
 
765
        #ifdef DEBUG_CONF
 
766
        ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
 
767
            "Watching for skipafter target rule id=\"%s\".", tmp_id);
 
768
        #endif
 
769
 
 
770
    }
 
771
 
 
772
    #ifdef DEBUG_CONF
 
773
    ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
 
774
        "Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, (rule->actionset->id == NOT_SET_P
 
775
        ? "(none)" : rule->actionset->id));
 
776
    #endif
 
777
 
 
778
    /* Add rule to the recipe. */
 
779
    if (msre_ruleset_rule_add(dcfg->ruleset, rule, rule->actionset->phase) < 0) {
 
780
        return "Internal Error: Failed to add rule to the ruleset.";
 
781
    }
 
782
 
 
783
    /* Add an additional placeholder if this rule ID is on the list */
 
784
    if ((rule->actionset->id != NULL) && apr_table_get(dcfg->tmp_rule_placeholders, rule->actionset->id)) {
 
785
        msre_rule *phrule = apr_palloc(rule->ruleset->mp, sizeof(msre_rule));
 
786
        if (phrule == NULL) {
 
787
            return FATAL_ERROR;
 
788
        }
 
789
 
 
790
        #ifdef DEBUG_CONF
 
791
        ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
 
792
            "Adding placeholder %pp for rule %pp id=\"%s\".", phrule, rule, rule->actionset->id);
 
793
        #endif
 
794
 
 
795
        /* shallow copy of original rule with placeholder marked as target */
 
796
        memcpy(phrule, rule, sizeof(msre_rule));
 
797
        phrule->placeholder = RULE_PH_SKIPAFTER;
 
798
 
 
799
        /* Add placeholder. */
 
800
        if (msre_ruleset_rule_add(dcfg->ruleset, phrule, phrule->actionset->phase) < 0) {
 
801
            return "Internal Error: Failed to add placeholder to the ruleset.";
 
802
        }
 
803
 
 
804
        /* No longer need to search for the ID */
 
805
        apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id);
 
806
    }
 
807
 
 
808
    /* Update the unparsed rule */
 
809
    rule->unparsed = msre_rule_generate_unparsed(dcfg->ruleset->mp, rule, NULL, NULL, NULL);
 
810
 
 
811
    return NULL;
 
812
}
 
813
 
 
814
/**
 
815
 *
 
816
 */
 
817
static const char *add_marker(cmd_parms *cmd, directory_config *dcfg,
 
818
                              const char *p1, const char *p2, const char *p3)
 
819
{
 
820
    char *my_error_msg = NULL;
 
821
    msre_rule *rule = NULL;
 
822
    extern msc_engine *modsecurity;
 
823
    int p;
 
824
 
 
825
    #ifdef DEBUG_CONF
 
826
    ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
 
827
        "Rule: type=%d p1='%s' p2='%s' p3='%s'", RULE_TYPE_MARKER, p1, p2, p3);
 
828
    #endif
 
829
 
 
830
    /* Create a ruleset if one does not exist. */
 
831
    if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) {
 
832
        dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool);
 
833
        if (dcfg->ruleset == NULL) return FATAL_ERROR;
 
834
    }
 
835
 
 
836
    /* Create the rule now. */
 
837
    rule = msre_rule_create(dcfg->ruleset, RULE_TYPE_MARKER, cmd->directive->filename, cmd->directive->line_num, p1, p2, p3, &my_error_msg);
 
838
    if (rule == NULL) {
 
839
        return my_error_msg;
 
840
    }
 
841
 
 
842
    /* This is a marker */
 
843
    rule->placeholder = RULE_PH_MARKER;
 
844
 
 
845
    /* Add placeholder to each phase */
 
846
    for (p = PHASE_FIRST; p <= PHASE_LAST; p++) {
 
847
        #ifdef DEBUG_CONF
 
848
        ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
 
849
            "Adding marker %pp phase=%d id=\"%s\".", rule, p, (rule->actionset->id == NOT_SET_P
 
850
            ? "(none)" : rule->actionset->id));
 
851
        #endif
 
852
 
 
853
        if (msre_ruleset_rule_add(dcfg->ruleset, rule, p) < 0) {
 
854
            return "Internal Error: Failed to add marker to the ruleset.";
 
855
        }
 
856
    }
 
857
 
 
858
    /* No longer need to search for the ID */
 
859
    if (dcfg->tmp_rule_placeholders != NULL) {
 
860
        apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id);
 
861
    }
 
862
 
 
863
    return NULL;
 
864
}
 
865
 
 
866
/**
 
867
 *
 
868
 */
 
869
static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg,
 
870
                                      const char *p1, const char *p2, int offset)
 
871
{
 
872
    char *my_error_msg = NULL;
 
873
    msre_rule *rule = NULL;
 
874
    msre_actionset *new_actionset = NULL;
 
875
    msre_ruleset *ruleset = dcfg->ruleset;
 
876
    extern msc_engine *modsecurity;
 
877
 
 
878
    /* Get the ruleset if one exists */
 
879
    if ((ruleset == NULL)||(ruleset == NOT_SET_P)) {
 
880
        return NULL;
 
881
    }
 
882
 
 
883
    #ifdef DEBUG_CONF
 
884
    ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
 
885
        "Update rule id=\"%s\" with action \"%s\".", p1, p2);
 
886
    #endif
 
887
 
 
888
    /* Fetch the rule */
 
889
    rule = msre_ruleset_fetch_rule(ruleset, p1, offset);
 
890
    if (rule == NULL) {
 
891
        #ifdef DEBUG_CONF
 
892
        ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
 
893
            "Update rule id=\"%s\" with action \"%s\" failed: Rule not found.", p1, p2);
 
894
        #endif
 
895
        return NULL;
 
896
    }
 
897
 
 
898
    /* Check the rule actionset */
 
899
    /* ENH: Can this happen? */
 
900
    if (rule->actionset == NULL) {
 
901
        return apr_psprintf(cmd->pool, "ModSecurity: Attempt to update action for rule \"%s\" failed: Rule does not have an actionset.", p1);
 
902
    }
 
903
 
 
904
    /* Create a new actionset */
 
905
    new_actionset = msre_actionset_create(modsecurity->msre, p2, &my_error_msg);
 
906
    if (new_actionset == NULL) return FATAL_ERROR;
 
907
    if (my_error_msg != NULL) return my_error_msg;
 
908
 
 
909
    /* Must NOT change an id */
 
910
    if ((new_actionset->id != NOT_SET_P) && (rule->actionset->id != NULL) && (strcmp(rule->actionset->id, new_actionset->id) != 0)) {
 
911
        return apr_psprintf(cmd->pool, "ModSecurity: Rule IDs cannot be updated via SecRuleUpdateActionById.");
 
912
    }
 
913
 
 
914
    /* Must NOT alter the phase */
 
915
    if ((new_actionset->phase != NOT_SET) && (rule->actionset->phase != new_actionset->phase)) {
 
916
        return apr_psprintf(cmd->pool, "ModSecurity: Rule phases cannot be updated via SecRuleUpdateActionById.");
 
917
    }
 
918
 
 
919
    #ifdef DEBUG_CONF
 
920
    {
 
921
        char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
 
922
        ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
 
923
            "Update rule %pp id=\"%s\" old action: \"%s\"",
 
924
            rule,
 
925
            (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
 
926
            actions);
 
927
    }
 
928
    #endif
 
929
 
 
930
    /* Merge new actions with the rule */
 
931
    /* ENH: Will this leak the old actionset? */
 
932
    rule->actionset = msre_actionset_merge(modsecurity->msre, rule->actionset,
 
933
        new_actionset, 1);
 
934
    msre_actionset_set_defaults(rule->actionset);
 
935
 
 
936
    /* Update the unparsed rule */
 
937
    rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, NULL, NULL, NULL);
 
938
 
 
939
    #ifdef DEBUG_CONF
 
940
    {
 
941
        char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
 
942
        ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
 
943
            "Update rule %pp id=\"%s\" new action: \"%s\"",
 
944
            rule,
 
945
            (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
 
946
            actions);
 
947
    }
 
948
    #endif
 
949
 
 
950
    return NULL;
 
951
}
 
952
 
 
953
/* -- Configuration directives -- */
 
954
 
 
955
static const char *cmd_action(cmd_parms *cmd, void *_dcfg, const char *p1)
 
956
{
 
957
    return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_ACTION, SECACTION_TARGETS, SECACTION_ARGS, p1);
 
958
}
 
959
 
 
960
static const char *cmd_marker(cmd_parms *cmd, void *_dcfg, const char *p1)
 
961
{
 
962
    directory_config *dcfg = (directory_config *)_dcfg;
 
963
    const char *action = apr_pstrcat(dcfg->mp, SECMARKER_BASE_ACTIONS, p1, NULL);
 
964
    return add_marker(cmd, (directory_config *)_dcfg, SECMARKER_TARGETS, SECMARKER_ARGS, action);
 
965
}
 
966
 
 
967
static const char *cmd_argument_separator(cmd_parms *cmd, void *_dcfg,
 
968
        const char *p1)
 
969
{
 
970
    directory_config *dcfg = (directory_config *)_dcfg;
 
971
 
 
972
    if (strlen(p1) != 1) {
 
973
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid argument separator: %s", p1);
 
974
    }
 
975
 
 
976
    dcfg->argument_separator = p1[0];
 
977
 
 
978
    return NULL;
 
979
}
 
980
 
 
981
static const char *cmd_audit_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
 
982
{
 
983
    directory_config *dcfg = _dcfg;
 
984
 
 
985
    if (strcasecmp(p1, "On") == 0) dcfg->auditlog_flag = AUDITLOG_ON;
 
986
    else
 
987
        if (strcasecmp(p1, "Off") == 0) dcfg->auditlog_flag = AUDITLOG_OFF;
 
988
        else
 
989
            if (strcasecmp(p1, "RelevantOnly") == 0) dcfg->auditlog_flag = AUDITLOG_RELEVANT;
 
990
            else
 
991
                return (const char *)apr_psprintf(cmd->pool,
 
992
                        "ModSecurity: Unrecognised parameter value for SecAuditEngine: %s", p1);
 
993
 
 
994
    return NULL;
 
995
}
 
996
 
 
997
static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1)
 
998
{
 
999
    directory_config *dcfg = _dcfg;
 
1000
 
 
1001
    dcfg->auditlog_name = (char *)p1;
 
1002
 
 
1003
    if (dcfg->auditlog_name[0] == '|') {
 
1004
        const char *pipe_name = dcfg->auditlog_name + 1;
 
1005
        piped_log *pipe_log;
 
1006
 
 
1007
        pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
 
1008
        if (pipe_log == NULL) {
 
1009
            return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log pipe: %s",
 
1010
                    pipe_name);
 
1011
        }
 
1012
        dcfg->auditlog_fd = ap_piped_log_write_fd(pipe_log);
 
1013
    }
 
1014
    else {
 
1015
        const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog_name);
 
1016
        apr_status_t rc;
 
1017
 
 
1018
        rc = apr_file_open(&dcfg->auditlog_fd, file_name,
 
1019
                APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
 
1020
                CREATEMODE, cmd->pool);
 
1021
 
 
1022
        if (rc != APR_SUCCESS) {
 
1023
            return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log file: %s",
 
1024
                    file_name);
 
1025
        }
 
1026
    }
 
1027
 
 
1028
    return NULL;
 
1029
}
 
1030
 
 
1031
static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1)
 
1032
{
 
1033
    directory_config *dcfg = _dcfg;
 
1034
 
 
1035
    if (dcfg->auditlog_name == NOT_SET_P) {
 
1036
        return apr_psprintf(cmd->pool, "ModSecurity: Cannot configure a secondary audit log without a primary defined: %s", p1);
 
1037
    }
 
1038
 
 
1039
    dcfg->auditlog2_name = (char *)p1;
 
1040
 
 
1041
    if (dcfg->auditlog2_name[0] == '|') {
 
1042
        const char *pipe_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name + 1);
 
1043
        piped_log *pipe_log;
 
1044
 
 
1045
        pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
 
1046
        if (pipe_log == NULL) {
 
1047
            return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log pipe: %s",
 
1048
                    pipe_name);
 
1049
        }
 
1050
        dcfg->auditlog2_fd = ap_piped_log_write_fd(pipe_log);
 
1051
    }
 
1052
    else {
 
1053
        const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name);
 
1054
        apr_status_t rc;
 
1055
 
 
1056
        rc = apr_file_open(&dcfg->auditlog2_fd, file_name,
 
1057
                APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
 
1058
                CREATEMODE, cmd->pool);
 
1059
 
 
1060
        if (rc != APR_SUCCESS) {
 
1061
            return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log file: %s",
 
1062
                    file_name);
 
1063
        }
 
1064
    }
 
1065
 
 
1066
    return NULL;
 
1067
}
 
1068
 
 
1069
static const char *cmd_audit_log_parts(cmd_parms *cmd, void *_dcfg,
 
1070
        const char *p1)
 
1071
{
 
1072
    directory_config *dcfg = _dcfg;
 
1073
 
 
1074
    if (is_valid_parts_specification((char *)p1) != 1) {
 
1075
        return apr_psprintf(cmd->pool, "Invalid parts specification for SecAuditLogParts: %s", p1);
 
1076
    }
 
1077
 
 
1078
    dcfg->auditlog_parts = (char *)p1;
 
1079
    return NULL;
 
1080
}
 
1081
 
 
1082
static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg,
 
1083
        const char *p1)
 
1084
{
 
1085
    directory_config *dcfg = _dcfg;
 
1086
 
 
1087
    dcfg->auditlog_relevant_regex = msc_pregcomp(cmd->pool, p1, PCRE_DOTALL, NULL, NULL);
 
1088
    if (dcfg->auditlog_relevant_regex == NULL) {
 
1089
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
 
1090
    }
 
1091
 
 
1092
    return NULL;
 
1093
}
 
1094
 
 
1095
static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg,
 
1096
        const char *p1)
 
1097
{
 
1098
    directory_config *dcfg = _dcfg;
 
1099
 
 
1100
    if (strcasecmp(p1, "Serial") == 0) dcfg->auditlog_type = AUDITLOG_SERIAL;
 
1101
    else
 
1102
        if (strcasecmp(p1, "Concurrent") == 0) dcfg->auditlog_type = AUDITLOG_CONCURRENT;
 
1103
        else
 
1104
            return (const char *)apr_psprintf(cmd->pool,
 
1105
                    "ModSecurity: Unrecognised parameter value for SecAuditLogType: %s", p1);
 
1106
 
 
1107
    return NULL;
 
1108
}
 
1109
 
 
1110
static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg,
 
1111
        const char *p1)
 
1112
{
 
1113
    directory_config *dcfg = (directory_config *)_dcfg;
 
1114
 
 
1115
    if (dcfg == NULL) return NULL;
 
1116
 
 
1117
    if (strcasecmp(p1, "default") == 0) {
 
1118
        dcfg->auditlog_dirperms = NOT_SET;
 
1119
    }
 
1120
    else {
 
1121
        long int mode = strtol(p1, NULL, 8); /* expects octal mode */
 
1122
        if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
 
1123
            return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogDirMode: %s", p1);
 
1124
        }
 
1125
 
 
1126
        dcfg->auditlog_dirperms = mode2fileperms(mode);
 
1127
    }
 
1128
 
 
1129
    return NULL;
 
1130
}
 
1131
 
 
1132
static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg,
 
1133
        const char *p1)
 
1134
{
 
1135
    directory_config *dcfg = (directory_config *)_dcfg;
 
1136
 
 
1137
    if (dcfg == NULL) return NULL;
 
1138
 
 
1139
    if (strcasecmp(p1, "default") == 0) {
 
1140
        dcfg->auditlog_fileperms = NOT_SET;
 
1141
    }
 
1142
    else {
 
1143
        long int mode = strtol(p1, NULL, 8); /* expects octal mode */
 
1144
        if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
 
1145
            return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogFileMode: %s", p1);
 
1146
        }
 
1147
 
 
1148
        dcfg->auditlog_fileperms = mode2fileperms(mode);
 
1149
    }
 
1150
 
 
1151
    return NULL;
 
1152
}
 
1153
 
 
1154
static const char *cmd_audit_log_storage_dir(cmd_parms *cmd, void *_dcfg,
 
1155
                                             const char *p1)
 
1156
{
 
1157
    directory_config *dcfg = _dcfg;
 
1158
 
 
1159
    dcfg->auditlog_storage_dir = ap_server_root_relative(cmd->pool, p1);
 
1160
 
 
1161
    return NULL;
 
1162
}
 
1163
 
 
1164
static const char *cmd_cookie_format(cmd_parms *cmd, void *_dcfg,
 
1165
                                     const char *p1)
 
1166
{
 
1167
    directory_config *dcfg = (directory_config *)_dcfg;
 
1168
 
 
1169
    if (strcmp(p1, "0") == 0) dcfg->cookie_format = COOKIES_V0;
 
1170
    else
 
1171
    if (strcmp(p1, "1") == 0) dcfg->cookie_format = COOKIES_V1;
 
1172
    else {
 
1173
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid cookie format: %s", p1);
 
1174
    }
 
1175
 
 
1176
    return NULL;
 
1177
}
 
1178
 
 
1179
static const char *cmd_chroot_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
 
1180
{
 
1181
    char cwd[1025] = "";
 
1182
 
 
1183
    if (cmd->server->is_virtual) {
 
1184
        return "ModSecurity: SecChrootDir not allowed in VirtualHost";
 
1185
    }
 
1186
 
 
1187
    chroot_dir = (char *)p1;
 
1188
 
 
1189
    if (getcwd(cwd, 1024) == NULL) {
 
1190
        return "ModSecurity: Failed to get the current working directory";
 
1191
    }
 
1192
 
 
1193
    if (chdir(chroot_dir) < 0) {
 
1194
        return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)",
 
1195
            chroot_dir, errno, strerror(errno));
 
1196
    }
 
1197
 
 
1198
    if (chdir(cwd) < 0) {
 
1199
        return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)",
 
1200
            cwd, errno, strerror(errno));
 
1201
    }
 
1202
 
 
1203
    return NULL;
 
1204
}
 
1205
 
 
1206
/**
 
1207
 * Adds component signature to the list of signatures kept in configuration.
 
1208
 */
 
1209
static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg,
 
1210
                                           const char *p1)
 
1211
{
 
1212
    directory_config *dcfg = (directory_config *)_dcfg;
 
1213
 
 
1214
    /* ENH Enforce "Name/VersionX.Y.Z (comment)" format. */
 
1215
    *(char **)apr_array_push(dcfg->component_signatures) = (char *)p1;
 
1216
 
 
1217
    return NULL;
 
1218
}
 
1219
 
 
1220
static const char *cmd_content_injection(cmd_parms *cmd, void *_dcfg, int flag)
 
1221
{
 
1222
    directory_config *dcfg = (directory_config *)_dcfg;
 
1223
    if (dcfg == NULL) return NULL;
 
1224
    dcfg->content_injection_enabled = flag;
 
1225
    return NULL;
 
1226
}
 
1227
 
 
1228
static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
 
1229
{
 
1230
    directory_config *dcfg = (directory_config *)_dcfg;
 
1231
 
 
1232
    if (cmd->server->is_virtual) {
 
1233
        return "ModSecurity: SecDataDir not allowed in VirtualHost.";
 
1234
    }
 
1235
 
 
1236
    dcfg->data_dir = ap_server_root_relative(cmd->pool, p1);
 
1237
 
 
1238
    return NULL;
 
1239
}
 
1240
 
 
1241
static const char *cmd_debug_log(cmd_parms *cmd, void *_dcfg, const char *p1)
 
1242
{
 
1243
    directory_config *dcfg = (directory_config *)_dcfg;
 
1244
    apr_status_t rc;
 
1245
 
 
1246
    dcfg->debuglog_name = ap_server_root_relative(cmd->pool, p1);
 
1247
 
 
1248
    rc = apr_file_open(&dcfg->debuglog_fd, dcfg->debuglog_name,
 
1249
                   APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
 
1250
                   CREATEMODE, cmd->pool);
 
1251
 
 
1252
    if (rc != APR_SUCCESS) {
 
1253
        return apr_psprintf(cmd->pool, "ModSecurity: Failed to open debug log file: %s",
 
1254
            dcfg->debuglog_name);
 
1255
    }
 
1256
 
 
1257
    return NULL;
 
1258
}
 
1259
 
 
1260
static const char *cmd_collection_timeout(cmd_parms *cmd, void *_dcfg,
 
1261
                                       const char *p1)
 
1262
{
 
1263
    directory_config *dcfg = (directory_config *)_dcfg;
 
1264
 
 
1265
    dcfg->col_timeout = atoi(p1);
 
1266
    /* max 30 days */
 
1267
    if ((dcfg->col_timeout >= 0)&&(dcfg->col_timeout <= 2592000)) return NULL;
 
1268
 
 
1269
    return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecCollectionTimeout: %s", p1);
 
1270
}
 
1271
 
 
1272
static const char *cmd_debug_log_level(cmd_parms *cmd, void *_dcfg,
 
1273
                                       const char *p1)
 
1274
{
 
1275
    directory_config *dcfg = (directory_config *)_dcfg;
 
1276
 
 
1277
    dcfg->debuglog_level = atoi(p1);
 
1278
    if ((dcfg->debuglog_level >= 0)&&(dcfg->debuglog_level <= 9)) return NULL;
 
1279
 
 
1280
    return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecDebugLogLevel: %s", p1);
 
1281
}
 
1282
 
 
1283
static const char *cmd_default_action(cmd_parms *cmd, void *_dcfg,
 
1284
                                      const char *p1)
 
1285
{
 
1286
    directory_config *dcfg = (directory_config *)_dcfg;
 
1287
    extern msc_engine *modsecurity;
 
1288
    char *my_error_msg = NULL;
 
1289
 
 
1290
    dcfg->tmp_default_actionset = msre_actionset_create(modsecurity->msre, p1, &my_error_msg);
 
1291
    if (dcfg->tmp_default_actionset == NULL) {
 
1292
        if (my_error_msg != NULL) return my_error_msg;
 
1293
        else return FATAL_ERROR;
 
1294
    }
 
1295
 
 
1296
    /* Must specify a disruptive action. */
 
1297
    /* ENH: Remove this requirement? */
 
1298
    if (dcfg->tmp_default_actionset->intercept_action == NOT_SET) {
 
1299
        return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a disruptive action.");
 
1300
    }
 
1301
 
 
1302
    /* Must specify a phase. */
 
1303
    /* ENH: Remove this requirement? */
 
1304
    if (dcfg->tmp_default_actionset->phase == NOT_SET) {
 
1305
        return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a phase.");
 
1306
    }
 
1307
 
 
1308
    /* Must not use metadata actions. */
 
1309
    /* ENH: loop through to check for tags */
 
1310
    if ((dcfg->tmp_default_actionset->id != NOT_SET_P)
 
1311
        ||(dcfg->tmp_default_actionset->rev != NOT_SET_P)
 
1312
        ||(dcfg->tmp_default_actionset->msg != NOT_SET_P))
 
1313
    {
 
1314
        return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
 
1315
            "contain any metadata actions (id, rev, msg, tag, severity, logdata).");
 
1316
    }
 
1317
    /* These are just a warning for now. */
 
1318
    if ((dcfg->tmp_default_actionset->severity != NOT_SET)
 
1319
        ||(dcfg->tmp_default_actionset->logdata != NOT_SET_P))
 
1320
    {
 
1321
        ap_log_perror(APLOG_MARK,
 
1322
            APLOG_STARTUP|APLOG_WARNING|APLOG_NOERRNO, 0, cmd->pool,
 
1323
            "ModSecurity: WARNING Using \"severity\" or \"logdata\" in "
 
1324
            "SecDefaultAction is deprecated (%s:%d).",
 
1325
            cmd->directive->filename, cmd->directive->line_num);
 
1326
    }
 
1327
 
 
1328
    /* Must not use chain. */
 
1329
    if (dcfg->tmp_default_actionset->is_chained != NOT_SET) {
 
1330
        return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
 
1331
            "contain a chain action.");
 
1332
    }
 
1333
 
 
1334
    /* Must not use skip. */
 
1335
    if (dcfg->tmp_default_actionset->skip_count != NOT_SET) {
 
1336
        return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
 
1337
            "contain a skip action.");
 
1338
    }
 
1339
 
 
1340
    /* Must not use skipAfter. */
 
1341
    if (dcfg->tmp_default_actionset->skip_after != NOT_SET_P) {
 
1342
        return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
 
1343
            "contain a skipAfter action.");
 
1344
    }
 
1345
 
 
1346
    return NULL;
 
1347
}
 
1348
 
 
1349
static const char *cmd_disable_backend_compression(cmd_parms *cmd, void *_dcfg, int flag)
 
1350
{
 
1351
    directory_config *dcfg = (directory_config *)_dcfg;
 
1352
    if (dcfg == NULL) return NULL;
 
1353
    dcfg->disable_backend_compression = flag;
 
1354
    return NULL;
 
1355
}
 
1356
 
 
1357
static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg,
 
1358
                                    const char *p1, const char *p2)
 
1359
{
 
1360
    extern char *guardianlog_name;
 
1361
    extern apr_file_t *guardianlog_fd;
 
1362
    extern char *guardianlog_condition;
 
1363
 
 
1364
    if (cmd->server->is_virtual) {
 
1365
        return "ModSecurity: SecGuardianLog not allowed in VirtualHost";
 
1366
    }
 
1367
 
 
1368
    if (p2 != NULL) {
 
1369
        if (strncmp(p2, "env=", 4) != 0) {
 
1370
            return "ModSecurity: Error in condition clause";
 
1371
        }
 
1372
        if ( (p2[4] == '\0') || ((p2[4] == '!')&&(p2[5] == '\0')) ) {
 
1373
            return "ModSecurity: Missing variable name";
 
1374
        }
 
1375
        guardianlog_condition = apr_pstrdup(cmd->pool, p2 + 4);
 
1376
    }
 
1377
 
 
1378
    guardianlog_name = (char *)p1;
 
1379
 
 
1380
    if (guardianlog_name[0] == '|') {
 
1381
        const char *pipe_name = ap_server_root_relative(cmd->pool, guardianlog_name + 1);
 
1382
        piped_log *pipe_log;
 
1383
 
 
1384
        pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
 
1385
        if (pipe_log == NULL) {
 
1386
            return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log pipe: %s",
 
1387
                pipe_name);
 
1388
        }
 
1389
        guardianlog_fd = ap_piped_log_write_fd(pipe_log);
 
1390
    }
 
1391
    else {
 
1392
        const char *file_name = ap_server_root_relative(cmd->pool, guardianlog_name);
 
1393
        apr_status_t rc;
 
1394
 
 
1395
        rc = apr_file_open(&guardianlog_fd, file_name,
 
1396
            APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
 
1397
            CREATEMODE, cmd->pool);
 
1398
 
 
1399
        if (rc != APR_SUCCESS) {
 
1400
            return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log file: %s",
 
1401
                file_name);
 
1402
        }
 
1403
    }
 
1404
 
 
1405
    return NULL;
 
1406
}
 
1407
 
 
1408
/*
 
1409
* \brief Add SecStreamInBodyInspection configuration option
 
1410
*
 
1411
* \param cmd Pointer to configuration data
 
1412
* \param _dcfg Pointer to directory configuration
 
1413
* \param p1 Pointer to configuration option
 
1414
*
 
1415
* \retval NULL On failure
 
1416
* \retval apr_psprintf On Success
 
1417
*/
 
1418
static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int flag)
 
1419
{
 
1420
    directory_config *dcfg = (directory_config *)_dcfg;
 
1421
    if (dcfg == NULL) return NULL;
 
1422
    dcfg->stream_inbody_inspection = flag;
 
1423
    return NULL;
 
1424
}
 
1425
 
 
1426
 
 
1427
/*
 
1428
* \brief Add SecStreamOutBodyInspection configuration option
 
1429
*
 
1430
* \param cmd Pointer to configuration data
 
1431
* \param _dcfg Pointer to directory configuration
 
1432
* \param p1 Pointer to configuration option
 
1433
*
 
1434
* \retval NULL On failure
 
1435
* \retval apr_psprintf On Success
 
1436
*/
 
1437
static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, int flag)
 
1438
{
 
1439
    directory_config *dcfg = (directory_config *)_dcfg;
 
1440
    if (dcfg == NULL) return NULL;
 
1441
    dcfg->stream_outbody_inspection = flag;
 
1442
    return NULL;
 
1443
}
 
1444
 
 
1445
/*
 
1446
* \brief Add SecReadStateLimit configuration option
 
1447
*
 
1448
* \param cmd Pointer to configuration data
 
1449
* \param _dcfg Pointer to directory configuration
 
1450
* \param p1 Pointer to configuration option
 
1451
*
 
1452
* \retval NULL On failure
 
1453
* \retval apr_psprintf On Success
 
1454
*/
 
1455
static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg,
 
1456
        const char *p1)
 
1457
{
 
1458
    directory_config *dcfg = (directory_config *)_dcfg;
 
1459
    long int limit;
 
1460
 
 
1461
    if (dcfg == NULL) return NULL;
 
1462
 
 
1463
    limit = strtol(p1, NULL, 10);
 
1464
    if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
 
1465
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecReadStateLimit: %s", p1);
 
1466
    }
 
1467
 
 
1468
    conn_read_state_limit = limit;
 
1469
 
 
1470
    return NULL;
 
1471
}
 
1472
 
 
1473
/*
 
1474
* \brief Add SecWriteStateLimit configuration option
 
1475
*
 
1476
* \param cmd Pointer to configuration data
 
1477
* \param _dcfg Pointer to directory configuration
 
1478
* \param p1 Pointer to configuration option
 
1479
*
 
1480
* \retval NULL On failure
 
1481
* \retval apr_psprintf On Success
 
1482
*/
 
1483
static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg,
 
1484
        const char *p1)
 
1485
{
 
1486
    directory_config *dcfg = (directory_config *)_dcfg;
 
1487
    long int limit;
 
1488
 
 
1489
    if (dcfg == NULL) return NULL;
 
1490
 
 
1491
    limit = strtol(p1, NULL, 10);
 
1492
    if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
 
1493
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecWriteStateLimit: %s", p1);
 
1494
    }
 
1495
 
 
1496
    conn_write_state_limit = limit;
 
1497
 
 
1498
    return NULL;
 
1499
}
 
1500
 
 
1501
 
 
1502
static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg,
 
1503
                                                   const char *p1)
 
1504
{
 
1505
    directory_config *dcfg = (directory_config *)_dcfg;
 
1506
    long int limit;
 
1507
 
 
1508
    if (dcfg == NULL) return NULL;
 
1509
 
 
1510
    limit = strtol(p1, NULL, 10);
 
1511
    if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
 
1512
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyInMemoryLimit: %s", p1);
 
1513
    }
 
1514
 
 
1515
    dcfg->reqbody_inmemory_limit = limit;
 
1516
 
 
1517
    return NULL;
 
1518
}
 
1519
 
 
1520
static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg,
 
1521
                                          const char *p1)
 
1522
{
 
1523
    directory_config *dcfg = (directory_config *)_dcfg;
 
1524
    long int limit;
 
1525
 
 
1526
    if (dcfg == NULL) return NULL;
 
1527
 
 
1528
    limit = strtol(p1, NULL, 10);
 
1529
    if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
 
1530
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimit: %s", p1);
 
1531
    }
 
1532
 
 
1533
    dcfg->reqbody_limit = limit;
 
1534
 
 
1535
    return NULL;
 
1536
}
 
1537
 
 
1538
static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg,
 
1539
                                                   const char *p1)
 
1540
{
 
1541
    directory_config *dcfg = (directory_config *)_dcfg;
 
1542
    long int limit;
 
1543
 
 
1544
    if (dcfg == NULL) return NULL;
 
1545
 
 
1546
    limit = strtol(p1, NULL, 10);
 
1547
    if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
 
1548
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyNoFilesLimit: %s", p1);
 
1549
    }
 
1550
 
 
1551
    dcfg->reqbody_no_files_limit = limit;
 
1552
 
 
1553
    return NULL;
 
1554
}
 
1555
 
 
1556
static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg,
 
1557
                                           const char *p1)
 
1558
{
 
1559
    directory_config *dcfg = (directory_config *)_dcfg;
 
1560
    if (dcfg == NULL) return NULL;
 
1561
 
 
1562
    if (strcasecmp(p1, "on") == 0) dcfg->reqbody_access = 1;
 
1563
    else
 
1564
    if (strcasecmp(p1, "off") == 0) dcfg->reqbody_access = 0;
 
1565
    else
 
1566
    return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyAccess: %s", p1);
 
1567
 
 
1568
    return NULL;
 
1569
}
 
1570
 
 
1571
static const char *cmd_request_intercept_on_error(cmd_parms *cmd, void *_dcfg,
 
1572
                                           const char *p1)
 
1573
{
 
1574
    directory_config *dcfg = (directory_config *)_dcfg;
 
1575
    if (dcfg == NULL) return NULL;
 
1576
 
 
1577
    if (strcasecmp(p1, "on") == 0) dcfg->reqintercept_oe = 1;
 
1578
    else
 
1579
    if (strcasecmp(p1, "off") == 0) dcfg->reqintercept_oe = 0;
 
1580
    else
 
1581
    return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecInterceptOnError: %s", p1);
 
1582
 
 
1583
    return NULL;
 
1584
}
 
1585
 
 
1586
 
 
1587
static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg,
 
1588
                                        const char *p1)
 
1589
{
 
1590
    directory_config *dcfg = (directory_config *)_dcfg;
 
1591
    if (dcfg == NULL) return NULL;
 
1592
 
 
1593
    /* ENH Validate encoding */
 
1594
 
 
1595
    dcfg->request_encoding = p1;
 
1596
 
 
1597
    return NULL;
 
1598
}
 
1599
 
 
1600
static const char *cmd_response_body_access(cmd_parms *cmd, void *_dcfg,
 
1601
                                            const char *p1)
 
1602
{
 
1603
    directory_config *dcfg = (directory_config *)_dcfg;
 
1604
    if (dcfg == NULL) return NULL;
 
1605
 
 
1606
    if (strcasecmp(p1, "on") == 0) dcfg->resbody_access = 1;
 
1607
    else
 
1608
    if (strcasecmp(p1, "off") == 0) dcfg->resbody_access = 0;
 
1609
    else
 
1610
    return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyAccess: %s", p1);
 
1611
 
 
1612
    return NULL;
 
1613
}
 
1614
 
 
1615
static const char *cmd_response_body_limit(cmd_parms *cmd, void *_dcfg,
 
1616
                                           const char *p1)
 
1617
{
 
1618
    directory_config *dcfg = (directory_config *)_dcfg;
 
1619
    long int limit;
 
1620
 
 
1621
    limit = strtol(p1, NULL, 10);
 
1622
    if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
 
1623
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimit: %s", p1);
 
1624
    }
 
1625
 
 
1626
    if (limit > RESPONSE_BODY_HARD_LIMIT) {
 
1627
        return apr_psprintf(cmd->pool, "ModSecurity: Response size limit can not exceed the hard limit: %li", RESPONSE_BODY_HARD_LIMIT);
 
1628
    }
 
1629
 
 
1630
    dcfg->of_limit = limit;
 
1631
 
 
1632
    return NULL;
 
1633
}
 
1634
 
 
1635
static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg,
 
1636
                                                  const char *p1)
 
1637
{
 
1638
    directory_config *dcfg = (directory_config *)_dcfg;
 
1639
    if (dcfg == NULL) return NULL;
 
1640
 
 
1641
    if (dcfg->is_enabled == MODSEC_DETECTION_ONLY)  {
 
1642
        dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
 
1643
        return NULL;
 
1644
    }
 
1645
 
 
1646
    if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
 
1647
    else
 
1648
    if (strcasecmp(p1, "Reject") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
 
1649
    else
 
1650
    return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimitAction: %s", p1);
 
1651
 
 
1652
    return NULL;
 
1653
}
 
1654
 
 
1655
static const char *cmd_resquest_body_limit_action(cmd_parms *cmd, void *_dcfg,
 
1656
                                                  const char *p1)
 
1657
{
 
1658
    directory_config *dcfg = (directory_config *)_dcfg;
 
1659
    if (dcfg == NULL) return NULL;
 
1660
 
 
1661
    if (dcfg->is_enabled == MODSEC_DETECTION_ONLY)  {
 
1662
        dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
 
1663
        return NULL;
 
1664
    }
 
1665
 
 
1666
    if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
 
1667
    else
 
1668
    if (strcasecmp(p1, "Reject") == 0) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT;
 
1669
    else
 
1670
    return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimitAction: %s", p1);
 
1671
 
 
1672
    return NULL;
 
1673
}
 
1674
 
 
1675
static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg,
 
1676
                                               const char *_p1)
 
1677
{
 
1678
    directory_config *dcfg = (directory_config *)_dcfg;
 
1679
    char *p1 = apr_pstrdup(cmd->pool, _p1);
 
1680
 
 
1681
    /* TODO check whether the parameter is a valid MIME type of "???" */
 
1682
 
 
1683
    if ((dcfg->of_mime_types == NULL)||(dcfg->of_mime_types == NOT_SET_P)) {
 
1684
        dcfg->of_mime_types = apr_table_make(cmd->pool, 10);
 
1685
    }
 
1686
 
 
1687
    strtolower_inplace((unsigned char *)p1);
 
1688
    apr_table_setn(dcfg->of_mime_types, p1, "1");
 
1689
 
 
1690
    return NULL;
 
1691
}
 
1692
 
 
1693
static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd,
 
1694
                                                      void *_dcfg)
 
1695
{
 
1696
    directory_config *dcfg = (directory_config *)_dcfg;
 
1697
    if (dcfg == NULL) return NULL;
 
1698
 
 
1699
    dcfg->of_mime_types_cleared = 1;
 
1700
 
 
1701
    if ((dcfg->of_mime_types != NULL)&&(dcfg->of_mime_types != NOT_SET_P)) {
 
1702
        apr_table_clear(dcfg->of_mime_types);
 
1703
    }
 
1704
 
 
1705
    return NULL;
 
1706
}
 
1707
 
 
1708
/*
 
1709
* \brief Add SecRuleUpdateTargetById
 
1710
*
 
1711
* \param cmd Pointer to configuration data
 
1712
* \param _dcfg Pointer to directory configuration
 
1713
* \param p1 Pointer to configuration option
 
1714
* \param p2 Pointer to configuration option
 
1715
* \param p3 Pointer to configuration option
 
1716
*
 
1717
* \retval NULL On failure|Success
 
1718
*/
 
1719
static const char *cmd_rule_update_target_by_id(cmd_parms *cmd, void *_dcfg,
 
1720
        const char *p1, const char *p2, const char *p3)
 
1721
{
 
1722
    return update_rule_target(cmd, (directory_config *)_dcfg, NULL, p1, p2, p3);
 
1723
}
 
1724
 
 
1725
static const char *cmd_rule(cmd_parms *cmd, void *_dcfg,
 
1726
        const char *p1, const char *p2, const char *p3)
 
1727
{
 
1728
    return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_NORMAL, p1, p2, p3);
 
1729
}
 
1730
 
 
1731
static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
 
1732
{
 
1733
    directory_config *dcfg = (directory_config *)_dcfg;
 
1734
    if (dcfg == NULL) return NULL;
 
1735
 
 
1736
    if (strcasecmp(p1, "on") == 0) dcfg->is_enabled = MODSEC_ENABLED;
 
1737
    else
 
1738
    if (strcasecmp(p1, "off") == 0) dcfg->is_enabled = MODSEC_DISABLED;
 
1739
    else
 
1740
    if (strcasecmp(p1, "detectiononly") == 0) {
 
1741
        dcfg->is_enabled = MODSEC_DETECTION_ONLY;
 
1742
        dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
 
1743
        dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
 
1744
    } else
 
1745
    return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRuleEngine: %s", p1);
 
1746
 
 
1747
    return NULL;
 
1748
}
 
1749
 
 
1750
static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag)
 
1751
{
 
1752
    directory_config *dcfg = (directory_config *)_dcfg;
 
1753
    if (dcfg == NULL) return NULL;
 
1754
    dcfg->rule_inheritance = flag;
 
1755
    return NULL;
 
1756
}
 
1757
 
 
1758
static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg,
 
1759
                                   const char *p1, const char *p2)
 
1760
{
 
1761
    #if defined(WITH_LUA)
 
1762
    const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
 
1763
    return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL);
 
1764
    #else
 
1765
    ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Ignoring SecRuleScript \"%s\" directive (%s:%d): No Lua scripting support.", p1, cmd->directive->filename, cmd->directive->line_num);
 
1766
    return NULL;
 
1767
    #endif
 
1768
}
 
1769
 
 
1770
static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg,
 
1771
                                         const char *p1)
 
1772
{
 
1773
    directory_config *dcfg = (directory_config *)_dcfg;
 
1774
    rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
 
1775
    if (dcfg == NULL) return NULL;
 
1776
 
 
1777
    re->type = RULE_EXCEPTION_REMOVE_ID;
 
1778
    re->param = p1;
 
1779
    *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
 
1780
 
 
1781
    /* Remove the corresponding rules from the context straight away. */
 
1782
    msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
 
1783
 
 
1784
    return NULL;
 
1785
}
 
1786
 
 
1787
static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg,
 
1788
                                          const char *p1)
 
1789
{
 
1790
    directory_config *dcfg = (directory_config *)_dcfg;
 
1791
    rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
 
1792
    if (dcfg == NULL) return NULL;
 
1793
 
 
1794
    re->type = RULE_EXCEPTION_REMOVE_TAG;
 
1795
    re->param = p1;
 
1796
    re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
 
1797
    if (re->param_data == NULL) {
 
1798
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
 
1799
    }
 
1800
    *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
 
1801
 
 
1802
    /* Remove the corresponding rules from the context straight away. */
 
1803
    msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
 
1804
 
 
1805
    #ifdef DEBUG_CONF
 
1806
    ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Added exception %pp (%d %s) to dcfg %pp.", re, re->type, re->param, dcfg);
 
1807
    #endif
 
1808
 
 
1809
    return NULL;
 
1810
}
 
1811
 
 
1812
static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg,
 
1813
                                          const char *p1)
 
1814
{
 
1815
    directory_config *dcfg = (directory_config *)_dcfg;
 
1816
    rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
 
1817
    if (dcfg == NULL) return NULL;
 
1818
 
 
1819
    re->type = RULE_EXCEPTION_REMOVE_MSG;
 
1820
    re->param = p1;
 
1821
    re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
 
1822
    if (re->param_data == NULL) {
 
1823
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
 
1824
    }
 
1825
    *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
 
1826
 
 
1827
    /* Remove the corresponding rules from the context straight away. */
 
1828
    msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
 
1829
 
 
1830
    #ifdef DEBUG_CONF
 
1831
    ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Added exception %pp (%d %s) to dcfg %pp.", re, re->type, re->param, dcfg);
 
1832
    #endif
 
1833
 
 
1834
    return NULL;
 
1835
}
 
1836
 
 
1837
static const char *cmd_rule_update_action_by_id(cmd_parms *cmd, void *_dcfg,
 
1838
        const char *p1, const char *p2)
 
1839
{
 
1840
    int offset = 0, rule_id = atoi(p1);
 
1841
    char *opt = strchr(p1,':');
 
1842
    char *savedptr = NULL;
 
1843
    char *param = apr_pstrdup(cmd->pool, p1);
 
1844
 
 
1845
    if ((rule_id == LONG_MAX)||(rule_id == LONG_MIN)||(rule_id <= 0)) {
 
1846
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for ID for update action: %s", p1);
 
1847
    }
 
1848
 
 
1849
    if(opt != NULL) {
 
1850
        opt++;
 
1851
        offset = atoi(opt);
 
1852
        opt = apr_strtok(param,":", &savedptr);
 
1853
        return update_rule_action(cmd, (directory_config *)_dcfg, (const char *)opt, p2, offset);
 
1854
    }
 
1855
 
 
1856
    return update_rule_action(cmd, (directory_config *)_dcfg, p1, p2, offset);
 
1857
}
 
1858
 
 
1859
static const char *cmd_server_signature(cmd_parms *cmd, void *_dcfg,
 
1860
                                        const char *p1)
 
1861
{
 
1862
    if (cmd->server->is_virtual) {
 
1863
        return "ModSecurity: SecServerSignature not allowed in VirtualHost";
 
1864
    }
 
1865
    new_server_signature = (char *)p1;
 
1866
    return NULL;
 
1867
}
 
1868
 
 
1869
static const char *cmd_tmp_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
 
1870
{
 
1871
    directory_config *dcfg = (directory_config *)_dcfg;
 
1872
 
 
1873
    if (dcfg == NULL) return NULL;
 
1874
 
 
1875
    if (strcasecmp(p1, "none") == 0) dcfg->tmp_dir = NULL;
 
1876
    else dcfg->tmp_dir = ap_server_root_relative(cmd->pool, p1);
 
1877
 
 
1878
    return NULL;
 
1879
}
 
1880
 
 
1881
static const char *cmd_upload_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
 
1882
{
 
1883
    directory_config *dcfg = (directory_config *)_dcfg;
 
1884
 
 
1885
    if (dcfg == NULL) return NULL;
 
1886
 
 
1887
    if (strcasecmp(p1, "none") == 0) dcfg->upload_dir = NULL;
 
1888
    else dcfg->upload_dir = ap_server_root_relative(cmd->pool, p1);
 
1889
 
 
1890
    return NULL;
 
1891
}
 
1892
 
 
1893
static const char *cmd_upload_file_limit(cmd_parms *cmd, void *_dcfg,
 
1894
                                         const char *p1)
 
1895
{
 
1896
    directory_config *dcfg = (directory_config *)_dcfg;
 
1897
 
 
1898
    if (dcfg == NULL) return NULL;
 
1899
 
 
1900
    if (strcasecmp(p1, "default") == 0) {
 
1901
        dcfg->upload_file_limit = NOT_SET;
 
1902
    }
 
1903
    else {
 
1904
        dcfg->upload_file_limit = atoi(p1);
 
1905
    }
 
1906
 
 
1907
    return NULL;
 
1908
}
 
1909
 
 
1910
static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg,
 
1911
                                       const char *p1)
 
1912
{
 
1913
    directory_config *dcfg = (directory_config *)_dcfg;
 
1914
 
 
1915
    if (dcfg == NULL) return NULL;
 
1916
 
 
1917
    if (strcasecmp(p1, "default") == 0) {
 
1918
        dcfg->upload_filemode = NOT_SET;
 
1919
    }
 
1920
    else {
 
1921
        long int mode = strtol(p1, NULL, 8); /* expects octal mode */
 
1922
        if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
 
1923
            return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecUploadFileMode: %s", p1);
 
1924
        }
 
1925
 
 
1926
        dcfg->upload_filemode = (int)mode;
 
1927
    }
 
1928
 
 
1929
    return NULL;
 
1930
}
 
1931
 
 
1932
static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg,
 
1933
                                         const char *p1)
 
1934
{
 
1935
    directory_config *dcfg = (directory_config *)_dcfg;
 
1936
 
 
1937
    if (dcfg == NULL) return NULL;
 
1938
 
 
1939
    if (strcasecmp(p1, "on") == 0) {
 
1940
        dcfg->upload_keep_files = KEEP_FILES_ON;
 
1941
    } else
 
1942
    if (strcasecmp(p1, "off") == 0) {
 
1943
        dcfg->upload_keep_files = KEEP_FILES_OFF;
 
1944
    } else
 
1945
    if (strcasecmp(p1, "relevantonly") == 0) {
 
1946
        dcfg->upload_keep_files = KEEP_FILES_RELEVANT_ONLY;
 
1947
    } else {
 
1948
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for SecUploadKeepFiles: %s",
 
1949
            p1);
 
1950
    }
 
1951
    return NULL;
 
1952
}
 
1953
 
 
1954
static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1)
 
1955
{
 
1956
    directory_config *dcfg = (directory_config *)_dcfg;
 
1957
 
 
1958
    /* ENH enforce format (letters, digits, ., _, -) */
 
1959
    dcfg->webappid = p1;
 
1960
 
 
1961
    return NULL;
 
1962
}
 
1963
 
 
1964
/* PCRE Limits */
 
1965
 
 
1966
static const char *cmd_pcre_match_limit(cmd_parms *cmd,
 
1967
                                        void *_dcfg, const char *p1)
 
1968
{
 
1969
    long val;
 
1970
 
 
1971
    if (cmd->server->is_virtual) {
 
1972
        return "ModSecurity: SecPcreMatchLimit not allowed in VirtualHost";
 
1973
    }
 
1974
 
 
1975
    val = atol(p1);
 
1976
    if (val <= 0) {
 
1977
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
 
1978
                                       "SecPcreMatchLimit: %s", p1);
 
1979
    }
 
1980
    msc_pcre_match_limit = (unsigned long int)val;
 
1981
 
 
1982
    return NULL;
 
1983
}
 
1984
 
 
1985
static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd,
 
1986
                                        void *_dcfg, const char *p1)
 
1987
{
 
1988
    long val;
 
1989
 
 
1990
    if (cmd->server->is_virtual) {
 
1991
        return "ModSecurity: SecPcreMatchLimitRecursion not allowed in VirtualHost";
 
1992
    }
 
1993
 
 
1994
    val = atol(p1);
 
1995
    if (val <= 0) {
 
1996
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
 
1997
                                       "SecPcreMatchLimitRecursion: %s", p1);
 
1998
    }
 
1999
    msc_pcre_match_limit_recursion = (unsigned long int)val;
 
2000
 
 
2001
    return NULL;
 
2002
}
 
2003
 
 
2004
 
 
2005
/* -- Geo Lookup configuration -- */
 
2006
 
 
2007
static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg,
 
2008
                                     const char *p1)
 
2009
{
 
2010
    const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
 
2011
    char *error_msg;
 
2012
    directory_config *dcfg = (directory_config *)_dcfg;
 
2013
    if (dcfg == NULL) return NULL;
 
2014
 
 
2015
    if (geo_init(dcfg, filename, &error_msg) <= 0) {
 
2016
        return error_msg;
 
2017
    }
 
2018
 
 
2019
    return NULL;
 
2020
}
 
2021
 
 
2022
/* Unicode CodePage */
 
2023
 
 
2024
static const char *cmd_unicode_codepage(cmd_parms *cmd,
 
2025
                                        void *_dcfg, const char *p1)
 
2026
{
 
2027
    long val;
 
2028
 
 
2029
    val = atol(p1);
 
2030
    if (val <= 0) {
 
2031
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
 
2032
                                       "SecUnicodeCodePage: %s", p1);
 
2033
    }
 
2034
 
 
2035
    unicode_codepage = (unsigned long int)val;
 
2036
 
 
2037
    return NULL;
 
2038
}
 
2039
 
 
2040
/* Unicode Map */
 
2041
 
 
2042
static const char *cmd_unicode_map(cmd_parms *cmd, void *_dcfg,
 
2043
                                     const char *p1)
 
2044
{
 
2045
    const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
 
2046
    char *error_msg;
 
2047
    directory_config *dcfg = (directory_config *)_dcfg;
 
2048
    if (dcfg == NULL) return NULL;
 
2049
 
 
2050
    if (unicode_map_init(dcfg, filename, &error_msg) <= 0) {
 
2051
        return error_msg;
 
2052
    }
 
2053
 
 
2054
    return NULL;
 
2055
}
 
2056
 
 
2057
/* Google safe browsing */
 
2058
 
 
2059
static const char *cmd_gsb_lookup_db(cmd_parms *cmd, void *_dcfg,
 
2060
                                     const char *p1)
 
2061
{
 
2062
    const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
 
2063
    char *error_msg;
 
2064
    directory_config *dcfg = (directory_config *)_dcfg;
 
2065
    if (dcfg == NULL) return NULL;
 
2066
 
 
2067
    if (gsb_db_init(dcfg, filename, &error_msg) <= 0) {
 
2068
        return error_msg;
 
2069
    }
 
2070
 
 
2071
    return NULL;
 
2072
}
 
2073
 
 
2074
/* -- Cache -- */
 
2075
 
 
2076
static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg,
 
2077
                                             const char *p1, const char *p2)
 
2078
{
 
2079
    directory_config *dcfg = (directory_config *)_dcfg;
 
2080
 
 
2081
    if (dcfg == NULL) return NULL;
 
2082
 
 
2083
    if (strcasecmp(p1, "on") == 0)
 
2084
        dcfg->cache_trans = MODSEC_CACHE_ENABLED;
 
2085
    else if (strcasecmp(p1, "off") == 0)
 
2086
        dcfg->cache_trans = MODSEC_CACHE_DISABLED;
 
2087
    else
 
2088
        return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecCacheTransformations: %s", p1);
 
2089
 
 
2090
    /* Process options */
 
2091
    if (p2 != NULL) {
 
2092
        apr_table_t *vartable = apr_table_make(cmd->pool, 4);
 
2093
        apr_status_t rc;
 
2094
        char *error_msg = NULL;
 
2095
        const char *charval = NULL;
 
2096
        apr_int64_t intval = 0;
 
2097
 
 
2098
        if (vartable == NULL) {
 
2099
            return apr_psprintf(cmd->pool, "ModSecurity: Unable to process options for SecCacheTransformations");
 
2100
        }
 
2101
        rc = msre_parse_generic(cmd->pool, p2, vartable, &error_msg);
 
2102
        if (rc < 0) {
 
2103
            return apr_psprintf(cmd->pool, "ModSecurity: Unable to parse options for SecCacheTransformations: %s", error_msg);
 
2104
        }
 
2105
 
 
2106
        /* incremental */
 
2107
        charval = apr_table_get(vartable, "incremental");
 
2108
        if (charval != NULL) {
 
2109
            if (strcasecmp(charval, "on") == 0)
 
2110
                dcfg->cache_trans_incremental = 1;
 
2111
            else if (strcasecmp(charval, "off") == 0)
 
2112
                dcfg->cache_trans_incremental = 0;
 
2113
            else
 
2114
                return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations invalid incremental value: %s", charval);
 
2115
        }
 
2116
 
 
2117
        /* minlen */
 
2118
        charval = apr_table_get(vartable, "minlen");
 
2119
        if (charval != NULL) {
 
2120
            intval = apr_atoi64(charval);
 
2121
            if (errno == ERANGE) {
 
2122
                return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen out of range: %s", charval);
 
2123
            }
 
2124
            if (intval < 0) {
 
2125
                return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be positive: %s", charval);
 
2126
            }
 
2127
 
 
2128
            /* The NOT_SET indicator is -1, a signed long, and therfore
 
2129
             * we cannot be >= the unsigned value of NOT_SET.
 
2130
             */
 
2131
            if ((unsigned long)intval >= (unsigned long)NOT_SET) {
 
2132
                return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be less than: %lu", (unsigned long)NOT_SET);
 
2133
            }
 
2134
            dcfg->cache_trans_min = (apr_size_t)intval;
 
2135
        }
 
2136
 
 
2137
        /* maxlen */
 
2138
        charval = apr_table_get(vartable, "maxlen");
 
2139
        if (charval != NULL) {
 
2140
            intval = apr_atoi64(charval);
 
2141
            if (errno == ERANGE) {
 
2142
                return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen out of range: %s", charval);
 
2143
            }
 
2144
            if (intval < 0) {
 
2145
                return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be positive: %s", charval);
 
2146
            }
 
2147
 
 
2148
            /* The NOT_SET indicator is -1, a signed long, and therfore
 
2149
             * we cannot be >= the unsigned value of NOT_SET.
 
2150
             */
 
2151
            if ((unsigned long)intval >= (unsigned long)NOT_SET) {
 
2152
                return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be less than: %lu", (unsigned long)NOT_SET);
 
2153
            }
 
2154
            if ((intval != 0) && ((apr_size_t)intval < dcfg->cache_trans_min)) {
 
2155
                return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must not be less than minlen: %lu < %" APR_SIZE_T_FMT, (unsigned long)intval, dcfg->cache_trans_min);
 
2156
            }
 
2157
            dcfg->cache_trans_max = (apr_size_t)intval;
 
2158
 
 
2159
        }
 
2160
 
 
2161
        /* maxitems */
 
2162
        charval = apr_table_get(vartable, "maxitems");
 
2163
        if (charval != NULL) {
 
2164
            intval = apr_atoi64(charval);
 
2165
            if (errno == ERANGE) {
 
2166
                return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems out of range: %s", charval);
 
2167
            }
 
2168
            if (intval < 0) {
 
2169
                return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems must be positive: %s", charval);
 
2170
            }
 
2171
            dcfg->cache_trans_maxitems = (apr_size_t)intval;
 
2172
        }
 
2173
    }
 
2174
 
 
2175
    return NULL;
 
2176
}
 
2177
 
 
2178
 
 
2179
/* -- Configuration directives definitions -- */
 
2180
 
 
2181
#define CMD_SCOPE_MAIN  (RSRC_CONF)
 
2182
#define CMD_SCOPE_ANY   (RSRC_CONF | ACCESS_CONF)
 
2183
 
 
2184
const command_rec module_directives[] = {
 
2185
 
 
2186
    AP_INIT_TAKE1 (
 
2187
        "SecAction",
 
2188
        cmd_action,
 
2189
        NULL,
 
2190
        CMD_SCOPE_ANY,
 
2191
        "an action list"
 
2192
    ),
 
2193
 
 
2194
    AP_INIT_TAKE1 (
 
2195
        "SecArgumentSeparator",
 
2196
        cmd_argument_separator,
 
2197
        NULL,
 
2198
        CMD_SCOPE_MAIN,
 
2199
        "character that will be used as separator when parsing application/x-www-form-urlencoded content."
 
2200
    ),
 
2201
 
 
2202
    AP_INIT_TAKE1 (
 
2203
        "SecAuditEngine",
 
2204
        cmd_audit_engine,
 
2205
        NULL,
 
2206
        CMD_SCOPE_ANY,
 
2207
        "On, Off or RelevantOnly to determine the level of audit logging"
 
2208
    ),
 
2209
 
 
2210
    AP_INIT_TAKE1 (
 
2211
        "SecAuditLog",
 
2212
        cmd_audit_log,
 
2213
        NULL,
 
2214
        CMD_SCOPE_ANY,
 
2215
        "filename of the primary audit log file"
 
2216
    ),
 
2217
 
 
2218
    AP_INIT_TAKE1 (
 
2219
        "SecAuditLog2",
 
2220
        cmd_audit_log2,
 
2221
        NULL,
 
2222
        CMD_SCOPE_ANY,
 
2223
        "filename of the secondary audit log file"
 
2224
    ),
 
2225
 
 
2226
    AP_INIT_TAKE1 (
 
2227
        "SecAuditLogParts",
 
2228
        cmd_audit_log_parts,
 
2229
        NULL,
 
2230
        CMD_SCOPE_ANY,
 
2231
        "list of audit log parts that go into the log."
 
2232
    ),
 
2233
 
 
2234
    AP_INIT_TAKE1 (
 
2235
        "SecAuditLogRelevantStatus",
 
2236
        cmd_audit_log_relevant_status,
 
2237
        NULL,
 
2238
        CMD_SCOPE_ANY,
 
2239
        "regular expression that will be used to determine if the response status is relevant for audit logging"
 
2240
    ),
 
2241
 
 
2242
    AP_INIT_TAKE1 (
 
2243
        "SecAuditLogType",
 
2244
        cmd_audit_log_type,
 
2245
        NULL,
 
2246
        CMD_SCOPE_ANY,
 
2247
        "whether to use the old audit log format (Serial) or new (Concurrent)"
 
2248
    ),
 
2249
 
 
2250
    AP_INIT_TAKE1 (
 
2251
        "SecAuditLogStorageDir",
 
2252
        cmd_audit_log_storage_dir,
 
2253
        NULL,
 
2254
        CMD_SCOPE_ANY,
 
2255
        "path to the audit log storage area; absolute, or relative to the root of the server"
 
2256
    ),
 
2257
 
 
2258
    AP_INIT_TAKE1 (
 
2259
        "SecAuditLogDirMode",
 
2260
        cmd_audit_log_dirmode,
 
2261
        NULL,
 
2262
        CMD_SCOPE_ANY,
 
2263
        "octal permissions mode for concurrent audit log directories"
 
2264
    ),
 
2265
 
 
2266
    AP_INIT_TAKE1 (
 
2267
        "SecAuditLogFileMode",
 
2268
        cmd_audit_log_filemode,
 
2269
        NULL,
 
2270
        CMD_SCOPE_ANY,
 
2271
        "octal permissions mode for concurrent audit log files"
 
2272
    ),
 
2273
 
 
2274
    AP_INIT_TAKE12 (
 
2275
        "SecCacheTransformations",
 
2276
        cmd_cache_transformations,
 
2277
        NULL,
 
2278
        CMD_SCOPE_ANY,
 
2279
        "whether or not to cache transformations. Defaults to true."
 
2280
    ),
 
2281
 
 
2282
    AP_INIT_TAKE1 (
 
2283
        "SecChrootDir",
 
2284
        cmd_chroot_dir,
 
2285
        NULL,
 
2286
        CMD_SCOPE_MAIN,
 
2287
        "path of the directory to which server will be chrooted"
 
2288
    ),
 
2289
 
 
2290
    AP_INIT_TAKE1 (
 
2291
        "SecComponentSignature",
 
2292
        cmd_component_signature,
 
2293
        NULL,
 
2294
        CMD_SCOPE_MAIN,
 
2295
        "component signature to add to ModSecurity signature."
 
2296
    ),
 
2297
 
 
2298
    AP_INIT_FLAG (
 
2299
        "SecContentInjection",
 
2300
        cmd_content_injection,
 
2301
        NULL,
 
2302
        CMD_SCOPE_ANY,
 
2303
        "On or Off"
 
2304
    ),
 
2305
 
 
2306
    AP_INIT_FLAG (
 
2307
        "SecStreamOutBodyInspection",
 
2308
        cmd_stream_outbody_inspection,
 
2309
        NULL,
 
2310
        CMD_SCOPE_ANY,
 
2311
        "On or Off"
 
2312
    ),
 
2313
 
 
2314
    AP_INIT_FLAG (
 
2315
        "SecStreamInBodyInspection",
 
2316
        cmd_stream_inbody_inspection,
 
2317
        NULL,
 
2318
        CMD_SCOPE_ANY,
 
2319
        "On or Off"
 
2320
    ),
 
2321
 
 
2322
    AP_INIT_TAKE1 (
 
2323
        "SecCookieFormat",
 
2324
        cmd_cookie_format,
 
2325
        NULL,
 
2326
        CMD_SCOPE_ANY,
 
2327
        "version of the Cookie specification to use for parsing. Possible values are 0 and 1."
 
2328
    ),
 
2329
 
 
2330
    AP_INIT_TAKE1 (
 
2331
        "SecDataDir",
 
2332
        cmd_data_dir,
 
2333
        NULL,
 
2334
        CMD_SCOPE_MAIN,
 
2335
        "path to the persistent data storage area" // TODO
 
2336
    ),
 
2337
 
 
2338
    AP_INIT_TAKE1 (
 
2339
        "SecDebugLog",
 
2340
        cmd_debug_log,
 
2341
        NULL,
 
2342
        CMD_SCOPE_ANY,
 
2343
        "path to the debug log file"
 
2344
    ),
 
2345
 
 
2346
    AP_INIT_TAKE1 (
 
2347
        "SecDebugLogLevel",
 
2348
        cmd_debug_log_level,
 
2349
        NULL,
 
2350
        CMD_SCOPE_ANY,
 
2351
        "debug log level, which controls the verbosity of logging."
 
2352
        " Use values from 0 (no logging) to 9 (a *lot* of logging)."
 
2353
    ),
 
2354
 
 
2355
    AP_INIT_TAKE1 (
 
2356
        "SecCollectionTimeout",
 
2357
        cmd_collection_timeout,
 
2358
        NULL,
 
2359
        CMD_SCOPE_ANY,
 
2360
        "set default collections timeout. default it 3600"
 
2361
    ),
 
2362
 
 
2363
    AP_INIT_TAKE1 (
 
2364
        "SecDefaultAction",
 
2365
        cmd_default_action,
 
2366
        NULL,
 
2367
        CMD_SCOPE_ANY,
 
2368
        "default action list"
 
2369
    ),
 
2370
 
 
2371
    AP_INIT_FLAG (
 
2372
        "SecDisableBackendCompression",
 
2373
        cmd_disable_backend_compression,
 
2374
        NULL,
 
2375
        CMD_SCOPE_ANY,
 
2376
        "When set to On, removes the compression headers from the backend requests."
 
2377
    ),
 
2378
 
 
2379
    AP_INIT_TAKE1 (
 
2380
        "SecGsbLookupDB",
 
2381
        cmd_gsb_lookup_db,
 
2382
        NULL,
 
2383
        RSRC_CONF,
 
2384
        "database google safe browsing"
 
2385
    ),
 
2386
 
 
2387
    AP_INIT_TAKE1 (
 
2388
        "SecUnicodeCodePage",
 
2389
        cmd_unicode_codepage,
 
2390
        NULL,
 
2391
        CMD_SCOPE_MAIN,
 
2392
        "Unicode CodePage"
 
2393
    ),
 
2394
 
 
2395
    AP_INIT_TAKE1 (
 
2396
        "SecUnicodeMapFile",
 
2397
        cmd_unicode_map,
 
2398
        NULL,
 
2399
        CMD_SCOPE_MAIN,
 
2400
        "Unicode Map file"
 
2401
    ),
 
2402
 
 
2403
    AP_INIT_TAKE1 (
 
2404
        "SecGeoLookupDB",
 
2405
        cmd_geo_lookup_db,
 
2406
        NULL,
 
2407
        RSRC_CONF,
 
2408
        "database for geographical lookups module."
 
2409
    ),
 
2410
 
 
2411
    AP_INIT_TAKE12 (
 
2412
        "SecGuardianLog",
 
2413
        cmd_guardian_log,
 
2414
        NULL,
 
2415
        CMD_SCOPE_MAIN,
 
2416
        "The filename of the filter debugging log file"
 
2417
    ),
 
2418
 
 
2419
    AP_INIT_TAKE1 (
 
2420
        "SecMarker",
 
2421
        cmd_marker,
 
2422
        NULL,
 
2423
        CMD_SCOPE_ANY,
 
2424
        "marker for a skipAfter target"
 
2425
    ),
 
2426
 
 
2427
    AP_INIT_TAKE1 (
 
2428
        "SecPcreMatchLimit",
 
2429
        cmd_pcre_match_limit,
 
2430
        NULL,
 
2431
        CMD_SCOPE_MAIN,
 
2432
        "PCRE match limit"
 
2433
    ),
 
2434
 
 
2435
    AP_INIT_TAKE1 (
 
2436
        "SecPcreMatchLimitRecursion",
 
2437
        cmd_pcre_match_limit_recursion,
 
2438
        NULL,
 
2439
        CMD_SCOPE_MAIN,
 
2440
        "PCRE match limit recursion"
 
2441
    ),
 
2442
 
 
2443
    AP_INIT_TAKE1 (
 
2444
        "SecRequestBodyAccess",
 
2445
        cmd_request_body_access,
 
2446
        NULL,
 
2447
        CMD_SCOPE_ANY,
 
2448
        "On or Off"
 
2449
    ),
 
2450
 
 
2451
    AP_INIT_TAKE1 (
 
2452
        "SecInterceptOnError",
 
2453
        cmd_request_intercept_on_error,
 
2454
        NULL,
 
2455
        CMD_SCOPE_ANY,
 
2456
        "On or Off"
 
2457
    ),
 
2458
 
 
2459
    AP_INIT_TAKE1 (
 
2460
        "SecReadStateLimit",
 
2461
        cmd_conn_read_state_limit,
 
2462
        NULL,
 
2463
        CMD_SCOPE_ANY,
 
2464
        "maximum number of threads in READ_BUSY state per ip address"
 
2465
    ),
 
2466
 
 
2467
    AP_INIT_TAKE1 (
 
2468
        "SecWriteStateLimit",
 
2469
        cmd_conn_write_state_limit,
 
2470
        NULL,
 
2471
        CMD_SCOPE_ANY,
 
2472
        "maximum number of threads in WRITE_BUSY state per ip address"
 
2473
    ),
 
2474
 
 
2475
    AP_INIT_TAKE1 (
 
2476
        "SecRequestBodyInMemoryLimit",
 
2477
        cmd_request_body_inmemory_limit,
 
2478
        NULL,
 
2479
        CMD_SCOPE_ANY,
 
2480
        "maximum request body size that will be placed in memory (except for POST urlencoded requests)."
 
2481
    ),
 
2482
 
 
2483
    AP_INIT_TAKE1 (
 
2484
        "SecRequestBodyLimit",
 
2485
        cmd_request_body_limit,
 
2486
        NULL,
 
2487
        CMD_SCOPE_ANY,
 
2488
        "maximum request body size ModSecurity will accept."
 
2489
    ),
 
2490
 
 
2491
    AP_INIT_TAKE1 (
 
2492
        "SecRequestBodyNoFilesLimit",
 
2493
        cmd_request_body_no_files_limit,
 
2494
        NULL,
 
2495
        CMD_SCOPE_ANY,
 
2496
        "maximum request body size ModSecurity will accept, but excluding the size of uploaded files."
 
2497
    ),
 
2498
 
 
2499
    AP_INIT_TAKE1 (
 
2500
        "SecRequestEncoding",
 
2501
        cmd_request_encoding,
 
2502
        NULL,
 
2503
        CMD_SCOPE_ANY,
 
2504
        "character encoding used in request."
 
2505
    ),
 
2506
 
 
2507
    AP_INIT_TAKE1 (
 
2508
        "SecResponseBodyAccess",
 
2509
        cmd_response_body_access,
 
2510
        NULL,
 
2511
        CMD_SCOPE_ANY,
 
2512
        "On or Off"
 
2513
    ),
 
2514
 
 
2515
    AP_INIT_TAKE1 (
 
2516
        "SecResponseBodyLimit",
 
2517
        cmd_response_body_limit,
 
2518
        NULL,
 
2519
        CMD_SCOPE_ANY,
 
2520
        "byte limit for response body"
 
2521
    ),
 
2522
 
 
2523
    AP_INIT_TAKE1 (
 
2524
        "SecResponseBodyLimitAction",
 
2525
        cmd_response_body_limit_action,
 
2526
        NULL,
 
2527
        CMD_SCOPE_ANY,
 
2528
        "what happens when the response body limit is reached"
 
2529
    ),
 
2530
 
 
2531
    AP_INIT_TAKE1 (
 
2532
        "SecRequestBodyLimitAction",
 
2533
        cmd_resquest_body_limit_action,
 
2534
        NULL,
 
2535
        CMD_SCOPE_ANY,
 
2536
        "what happens when the request body limit is reached"
 
2537
    ),
 
2538
 
 
2539
    AP_INIT_ITERATE (
 
2540
        "SecResponseBodyMimeType",
 
2541
        cmd_response_body_mime_type,
 
2542
        NULL,
 
2543
        CMD_SCOPE_ANY,
 
2544
        "adds given MIME types to the list of types that will be buffered on output"
 
2545
    ),
 
2546
 
 
2547
    AP_INIT_NO_ARGS (
 
2548
        "SecResponseBodyMimeTypesClear",
 
2549
        cmd_response_body_mime_types_clear,
 
2550
        NULL,
 
2551
        CMD_SCOPE_ANY,
 
2552
        "clears the list of MIME types that will be buffered on output"
 
2553
    ),
 
2554
 
 
2555
    AP_INIT_TAKE23 (
 
2556
        "SecRule",
 
2557
        cmd_rule,
 
2558
        NULL,
 
2559
        CMD_SCOPE_ANY,
 
2560
        "rule target, operator and optional action list"
 
2561
    ),
 
2562
 
 
2563
    AP_INIT_TAKE1 (
 
2564
        "SecRuleEngine",
 
2565
        cmd_rule_engine,
 
2566
        NULL,
 
2567
        CMD_SCOPE_ANY,
 
2568
        "On or Off"
 
2569
    ),
 
2570
 
 
2571
    AP_INIT_FLAG (
 
2572
        "SecRuleInheritance",
 
2573
        cmd_rule_inheritance,
 
2574
        NULL,
 
2575
        CMD_SCOPE_ANY,
 
2576
        "On or Off"
 
2577
    ),
 
2578
 
 
2579
    AP_INIT_TAKE12 (
 
2580
        "SecRuleScript",
 
2581
        cmd_rule_script,
 
2582
        NULL,
 
2583
        CMD_SCOPE_ANY,
 
2584
        "rule script and optional actionlist"
 
2585
    ),
 
2586
 
 
2587
    AP_INIT_ITERATE (
 
2588
        "SecRuleRemoveById",
 
2589
        cmd_rule_remove_by_id,
 
2590
        NULL,
 
2591
        CMD_SCOPE_ANY,
 
2592
        "rule ID for removal"
 
2593
    ),
 
2594
 
 
2595
    AP_INIT_ITERATE (
 
2596
        "SecRuleRemoveByTag",
 
2597
        cmd_rule_remove_by_tag,
 
2598
        NULL,
 
2599
        CMD_SCOPE_ANY,
 
2600
        "rule tag for removal"
 
2601
    ),
 
2602
 
 
2603
    AP_INIT_ITERATE (
 
2604
        "SecRuleRemoveByMsg",
 
2605
        cmd_rule_remove_by_msg,
 
2606
        NULL,
 
2607
        CMD_SCOPE_ANY,
 
2608
        "rule message for removal"
 
2609
    ),
 
2610
 
 
2611
    AP_INIT_TAKE2 (
 
2612
        "SecRuleUpdateActionById",
 
2613
        cmd_rule_update_action_by_id,
 
2614
        NULL,
 
2615
        CMD_SCOPE_ANY,
 
2616
        "updated action list"
 
2617
    ),
 
2618
 
 
2619
    AP_INIT_TAKE23 (
 
2620
        "SecRuleUpdateTargetById",
 
2621
        cmd_rule_update_target_by_id,
 
2622
        NULL,
 
2623
        CMD_SCOPE_ANY,
 
2624
        "updated target list"
 
2625
    ),
 
2626
 
 
2627
    AP_INIT_TAKE1 (
 
2628
        "SecServerSignature",
 
2629
        cmd_server_signature,
 
2630
        NULL,
 
2631
        CMD_SCOPE_MAIN,
 
2632
        "the new signature of the server"
 
2633
    ),
 
2634
 
 
2635
    AP_INIT_TAKE1 (
 
2636
        "SecTmpDir",
 
2637
        cmd_tmp_dir,
 
2638
        NULL,
 
2639
        CMD_SCOPE_ANY,
 
2640
        "path to the temporary storage area"
 
2641
    ),
 
2642
 
 
2643
    AP_INIT_TAKE1 (
 
2644
        "SecUploadDir",
 
2645
        cmd_upload_dir,
 
2646
        NULL,
 
2647
        CMD_SCOPE_ANY,
 
2648
        "path to the file upload area"
 
2649
    ),
 
2650
 
 
2651
    AP_INIT_TAKE1 (
 
2652
        "SecUploadFileLimit",
 
2653
        cmd_upload_file_limit,
 
2654
        NULL,
 
2655
        CMD_SCOPE_ANY,
 
2656
        "limit the number of uploaded files processed"
 
2657
    ),
 
2658
 
 
2659
    AP_INIT_TAKE1 (
 
2660
        "SecUploadFileMode",
 
2661
        cmd_upload_filemode,
 
2662
        NULL,
 
2663
        CMD_SCOPE_ANY,
 
2664
        "octal permissions mode for uploaded files"
 
2665
    ),
 
2666
 
 
2667
    AP_INIT_TAKE1 (
 
2668
        "SecUploadKeepFiles",
 
2669
        cmd_upload_keep_files,
 
2670
        NULL,
 
2671
        CMD_SCOPE_ANY,
 
2672
        "On or Off"
 
2673
    ),
 
2674
 
 
2675
    AP_INIT_TAKE1 (
 
2676
        "SecWebAppId",
 
2677
        cmd_web_app_id,
 
2678
        NULL,
 
2679
        CMD_SCOPE_ANY,
 
2680
        "id"
 
2681
    ),
 
2682
 
 
2683
    { NULL }
 
2684
};