~ubuntu-branches/ubuntu/natty/libapache-mod-security/natty-updates

« back to all changes in this revision

Viewing changes to apache2/modsecurity.c

  • Committer: Bazaar Package Importer
  • Author(s): Alberto Gonzalez Iniesta
  • Date: 2008-08-08 13:31:56 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080808133156-6jqb24apsw787v33
Tags: 2.5.6-1
* The 'Back to the archive!' Release (Closes: #487431)
* Drop '2' from package name, now libapache-mod-security
* New upstream release
  - Includes a new licensing exception that allows binary 
    distribution with licenses not compatible with GPLv2,
    such as Apache's. See MODSECURITY_LICENSING_EXCEPTION
* Removed debian/bug and debian/rules entry to install bug
  handling when out of the archive.
* Bumped Standards-Version to 3.8.0.0

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-2008 Breach Security, Inc. (http://www.breach.com/)
 
4
 *
 
5
 * This product is released under the terms of the General Public Licence,
 
6
 * version 2 (GPLv2). Please refer to the file LICENSE (included with this
 
7
 * distribution) which contains the complete text of the licence.
 
8
 *
 
9
 * There are special exceptions to the terms and conditions of the GPL
 
10
 * as it is applied to this software. View the full text of the exception in
 
11
 * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software
 
12
 * distribution.
 
13
 *
 
14
 * If any of the files related to licensing are missing or if you have any
 
15
 * other questions related to licensing please contact Breach Security, Inc.
 
16
 * directly using the email address support@breach.com.
 
17
 *
 
18
 */
 
19
#include <stdlib.h>
 
20
 
 
21
#include "apr_global_mutex.h"
 
22
 
 
23
#include "modsecurity.h"
 
24
#include "msc_parsers.h"
 
25
#include "msc_util.h"
 
26
#include "msc_xml.h"
 
27
 
 
28
modsec_build_type_rec DSOLOCAL modsec_build_type[] = {
 
29
    { "-dev", 1 },     /* Development build */
 
30
    { "-rc", 3 },      /* Release Candidate build */
 
31
    { "", 9 },         /* Production build */
 
32
    { "-breach", 9 },  /* Breach build */
 
33
    { "-trunk", 9 },   /* Trunk build */
 
34
    { NULL, -1 }       /* terminator */
 
35
};
 
36
 
 
37
/**
 
38
 * Log an alert message to the log, adding the rule metadata at the end.
 
39
 */
 
40
void msc_alert(modsec_rec *msr, int level, msre_actionset *actionset, const char *action_message,
 
41
    const char *rule_message)
 
42
{
 
43
    const char *message = NULL;
 
44
 
 
45
    if (rule_message == NULL) rule_message = "Unknown error.";
 
46
 
 
47
    message = apr_psprintf(msr->mp, "%s %s%s", action_message,
 
48
        rule_message, msre_format_metadata(msr, actionset));
 
49
 
 
50
    msr_log(msr, level, "%s", message);
 
51
}
 
52
 
 
53
#if 0
 
54
/**
 
55
 * Return phase name associated with the given phase number.
 
56
 */
 
57
static const char *phase_name(int phase) {
 
58
    switch(phase) {
 
59
        case 1 :
 
60
            return "REQUEST_HEADERS";
 
61
            break;
 
62
        case 2 :
 
63
            return "REQUEST_BODY";
 
64
            break;
 
65
        case 3 :
 
66
            return "RESPONSE_HEADERS";
 
67
            break;
 
68
        case 4 :
 
69
            return "RESPONSE_BODY";
 
70
            break;
 
71
        case 5 :
 
72
            return "LOGGING";
 
73
            break;
 
74
    }
 
75
    return "INVALID";
 
76
}
 
77
#endif
 
78
 
 
79
/**
 
80
 * Creates and initialises a ModSecurity engine instance.
 
81
 */
 
82
msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) {
 
83
    msc_engine *msce = NULL;
 
84
 
 
85
    msce = apr_pcalloc(mp, sizeof(msc_engine));
 
86
    if (msce == NULL) return NULL;
 
87
 
 
88
    msce->mp = mp;
 
89
    msce->processing_mode = processing_mode;
 
90
 
 
91
    msce->msre = msre_engine_create(msce->mp);
 
92
    if (msce->msre == NULL) return NULL;
 
93
    msre_engine_register_default_variables(msce->msre);
 
94
    msre_engine_register_default_operators(msce->msre);
 
95
    msre_engine_register_default_tfns(msce->msre);
 
96
    msre_engine_register_default_actions(msce->msre);
 
97
 
 
98
    return msce;
 
99
}
 
100
 
 
101
/**
 
102
 * Initialise the modsecurity engine. This function must be invoked
 
103
 * after configuration processing is complete as Apache needs to know the
 
104
 * username it is running as.
 
105
 */
 
106
int modsecurity_init(msc_engine *msce, apr_pool_t *mp) {
 
107
    apr_status_t rc;
 
108
 
 
109
    /* Serial audit log mutext */
 
110
    rc = apr_global_mutex_create(&msce->auditlog_lock, NULL, APR_LOCK_DEFAULT, mp);
 
111
    if (rc != APR_SUCCESS) {
 
112
        //ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "mod_security: Could not create modsec_auditlog_lock");
 
113
        //return HTTP_INTERNAL_SERVER_ERROR;
 
114
        return -1;
 
115
    }
 
116
 
 
117
    #ifdef __SET_MUTEX_PERMS
 
118
    rc = unixd_set_global_mutex_perms(msce->auditlog_lock);
 
119
    if (rc != APR_SUCCESS) {
 
120
        // ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, "mod_security: Could not set permissions on modsec_auditlog_lock; check User and Group directives");
 
121
        // return HTTP_INTERNAL_SERVER_ERROR;
 
122
        return -1;
 
123
    }
 
124
    #endif
 
125
 
 
126
    return 1;
 
127
}
 
128
 
 
129
/**
 
130
 * Performs per-child (new process) initialisation.
 
131
 */
 
132
void modsecurity_child_init(msc_engine *msce) {
 
133
    /* Need to call this once per process before any other XML calls. */
 
134
    xmlInitParser();
 
135
 
 
136
    if (msce->auditlog_lock != NULL) {
 
137
        apr_status_t rc = apr_global_mutex_child_init(&msce->auditlog_lock, NULL, msce->mp);
 
138
        if (rc != APR_SUCCESS) {
 
139
            // ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, "Failed to child-init auditlog mutex");
 
140
        }
 
141
    }
 
142
}
 
143
 
 
144
/**
 
145
 * Releases resources held by engine instance.
 
146
 */
 
147
void modsecurity_shutdown(msc_engine *msce) {
 
148
    if (msce == NULL) return;
 
149
}
 
150
 
 
151
/**
 
152
 *
 
153
 */
 
154
static apr_status_t modsecurity_tx_cleanup(void *data) {
 
155
    modsec_rec *msr = (modsec_rec *)data;
 
156
    const apr_array_header_t *arr;
 
157
    apr_table_entry_t *te;
 
158
    int collect_garbage = 0;
 
159
    int i;
 
160
    char *my_error_msg = NULL;
 
161
 
 
162
    if (msr == NULL) return APR_SUCCESS;
 
163
 
 
164
    if (rand() < RAND_MAX/100) {
 
165
        collect_garbage = 1;
 
166
    }
 
167
 
 
168
    /* Collections, store & remove stale. */
 
169
    arr = apr_table_elts(msr->collections);
 
170
    te = (apr_table_entry_t *)arr->elts;
 
171
    for (i = 0; i < arr->nelts; i++) {
 
172
        apr_table_t *col = (apr_table_t *)te[i].val;
 
173
 
 
174
        /* Only store those collections that changed. */
 
175
        if (apr_table_get(msr->collections_dirty, te[i].key)) {
 
176
            collection_store(msr, col);
 
177
        }
 
178
 
 
179
        if (collect_garbage) {
 
180
            collections_remove_stale(msr, te[i].key);
 
181
        }
 
182
    }
 
183
 
 
184
    /* Multipart processor cleanup. */
 
185
    if (msr->mpd != NULL) multipart_cleanup(msr);
 
186
 
 
187
    /* XML processor cleanup. */
 
188
    if (msr->xml != NULL) xml_cleanup(msr);
 
189
 
 
190
    // TODO: Why do we ignore return code here?
 
191
    modsecurity_request_body_clear(msr, &my_error_msg);
 
192
    if (my_error_msg != NULL) {
 
193
        msr_log(msr, 1, "%s", my_error_msg);
 
194
    }
 
195
 
 
196
    return APR_SUCCESS;
 
197
}
 
198
 
 
199
/**
 
200
 *
 
201
 */
 
202
apr_status_t modsecurity_tx_init(modsec_rec *msr) {
 
203
    const char *s = NULL;
 
204
    const apr_array_header_t *arr;
 
205
    apr_table_entry_t *te;
 
206
    int i;
 
207
 
 
208
    /* Register TX cleanup */
 
209
    apr_pool_cleanup_register(msr->mp, msr, modsecurity_tx_cleanup, apr_pool_cleanup_null);
 
210
 
 
211
    /* Initialise C-L */
 
212
    msr->request_content_length = -1;
 
213
    s = apr_table_get(msr->request_headers, "Content-Length");
 
214
    if (s != NULL) {
 
215
        msr->request_content_length = strtol(s, NULL, 10);
 
216
    }
 
217
 
 
218
    /* Figure out whether this request has a body */
 
219
    msr->reqbody_chunked = 0;
 
220
    msr->reqbody_should_exist = 0;
 
221
    if (msr->request_content_length == -1) {
 
222
        /* There's no C-L, but is chunked encoding used? */
 
223
        char *transfer_encoding = (char *)apr_table_get(msr->request_headers, "Transfer-Encoding");
 
224
        if ((transfer_encoding != NULL)&&(strstr(transfer_encoding, "chunked") != NULL)) {
 
225
            msr->reqbody_should_exist = 1;
 
226
            msr->reqbody_chunked = 1;
 
227
        }
 
228
    } else {
 
229
        /* C-L found */
 
230
        msr->reqbody_should_exist = 1;
 
231
    }
 
232
 
 
233
    /* Initialise C-T */
 
234
    msr->request_content_type = NULL;
 
235
    s = apr_table_get(msr->request_headers, "Content-Type");
 
236
    if (s != NULL) msr->request_content_type = s;
 
237
 
 
238
    /* Decide what to do with the request body. */
 
239
    if ((msr->request_content_type != NULL)
 
240
       && (strncasecmp(msr->request_content_type, "application/x-www-form-urlencoded", 33) == 0))
 
241
    {
 
242
        /* Always place POST requests with
 
243
         * "application/x-www-form-urlencoded" payloads in memory.
 
244
         */
 
245
        msr->msc_reqbody_storage = MSC_REQBODY_MEMORY;
 
246
        msr->msc_reqbody_spilltodisk = 0;
 
247
        msr->msc_reqbody_processor = "URLENCODED";
 
248
    } else {
 
249
        /* If the C-L is known and there's more data than
 
250
         * our limit go to disk straight away.
 
251
         */
 
252
        if ((msr->request_content_length != -1)
 
253
           && (msr->request_content_length > msr->txcfg->reqbody_inmemory_limit))
 
254
        {
 
255
            msr->msc_reqbody_storage = MSC_REQBODY_DISK;
 
256
        }
 
257
 
 
258
        /* In all other cases, try using the memory first
 
259
         * but switch over to disk for larger bodies.
 
260
         */
 
261
        msr->msc_reqbody_storage = MSC_REQBODY_MEMORY;
 
262
        msr->msc_reqbody_spilltodisk = 1;
 
263
 
 
264
        if (msr->request_content_type != NULL) {
 
265
            if (strncasecmp(msr->request_content_type, "multipart/form-data", 19) == 0) {
 
266
                msr->msc_reqbody_processor = "MULTIPART";
 
267
            }
 
268
        }
 
269
    }
 
270
 
 
271
    /* Initialise arguments */
 
272
    msr->arguments = apr_table_make(msr->mp, 32);
 
273
    if (msr->arguments == NULL) return -1;
 
274
    if (msr->query_string != NULL) {
 
275
        int invalid_count = 0;
 
276
 
 
277
        if (parse_arguments(msr, msr->query_string, strlen(msr->query_string),
 
278
            msr->txcfg->argument_separator, "QUERY_STRING", msr->arguments,
 
279
            &invalid_count) < 0)
 
280
        {
 
281
            msr_log(msr, 1, "Initialisation: Error occurred while parsing QUERY_STRING arguments.");
 
282
            return -1;
 
283
        }
 
284
    }
 
285
 
 
286
    msr->arguments_to_sanitise = apr_table_make(msr->mp, 16);
 
287
    if (msr->arguments_to_sanitise == NULL) return -1;
 
288
    msr->request_headers_to_sanitise = apr_table_make(msr->mp, 16);
 
289
    if (msr->request_headers_to_sanitise == NULL) return -1;
 
290
    msr->response_headers_to_sanitise = apr_table_make(msr->mp, 16);
 
291
    if (msr->response_headers_to_sanitise == NULL) return -1;
 
292
 
 
293
    /* Initialise cookies */
 
294
    msr->request_cookies = apr_table_make(msr->mp, 16);
 
295
    if (msr->request_cookies == NULL) return -1;
 
296
 
 
297
    /* Locate the cookie headers and parse them */
 
298
    arr = apr_table_elts(msr->request_headers);
 
299
    te = (apr_table_entry_t *)arr->elts;
 
300
    for (i = 0; i < arr->nelts; i++) {
 
301
        if (strcasecmp(te[i].key, "Cookie") == 0) {
 
302
            if (msr->txcfg->cookie_format == COOKIES_V0) {
 
303
                parse_cookies_v0(msr, te[i].val, msr->request_cookies);
 
304
            } else {
 
305
                parse_cookies_v1(msr, te[i].val, msr->request_cookies);
 
306
            }
 
307
        }
 
308
    }
 
309
 
 
310
    /* Collections. */
 
311
    msr->tx_vars = apr_table_make(msr->mp, 32);
 
312
    if (msr->tx_vars == NULL) return -1;
 
313
 
 
314
    msr->geo_vars = apr_table_make(msr->mp, 8);
 
315
    if (msr->geo_vars == NULL) return -1;
 
316
 
 
317
    msr->collections = apr_table_make(msr->mp, 8);
 
318
    if (msr->collections == NULL) return -1;
 
319
    msr->collections_dirty = apr_table_make(msr->mp, 8);
 
320
    if (msr->collections_dirty == NULL) return -1;
 
321
 
 
322
    /* Other */
 
323
    msr->tcache = NULL;
 
324
    msr->tcache_items = 0;
 
325
 
 
326
    msr->matched_rules = apr_array_make(msr->mp, 16, sizeof(void *));
 
327
    if (msr->matched_rules == NULL) return -1;
 
328
 
 
329
    msr->matched_var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
 
330
    if (msr->matched_var == NULL) return -1;
 
331
 
 
332
    msr->highest_severity = 255; /* high, invalid value */
 
333
 
 
334
    msr->removed_rules = apr_array_make(msr->mp, 16, sizeof(char *));
 
335
    if (msr->removed_rules == NULL) return -1;
 
336
 
 
337
    return 1;
 
338
}
 
339
 
 
340
/**
 
341
 *
 
342
 */
 
343
static int is_response_status_relevant(modsec_rec *msr, int status) {
 
344
    char *my_error_msg = NULL;
 
345
    apr_status_t rc;
 
346
    char buf[32];
 
347
 
 
348
    /* ENH: Setting is_relevant here will cause an audit even if noauditlog
 
349
     * was set for the last rule that matched.  Is this what we want?
 
350
     */
 
351
 
 
352
    if ((msr->txcfg->auditlog_relevant_regex == NULL)
 
353
        ||(msr->txcfg->auditlog_relevant_regex == NOT_SET_P))
 
354
    {
 
355
        return 0;
 
356
    }
 
357
 
 
358
    apr_snprintf(buf, sizeof(buf), "%d", status);
 
359
 
 
360
    rc = msc_regexec(msr->txcfg->auditlog_relevant_regex, buf, strlen(buf), &my_error_msg);
 
361
    if (rc >= 0) return 1;
 
362
    if (rc == PCRE_ERROR_NOMATCH) return 0;
 
363
 
 
364
    msr_log(msr, 1, "Regex processing failed (rc %d): %s", rc, my_error_msg);
 
365
    return 0;
 
366
}
 
367
 
 
368
/**
 
369
 *
 
370
 */
 
371
static apr_status_t modsecurity_process_phase_request_headers(modsec_rec *msr) {
 
372
    msr_log(msr, 4, "Starting phase REQUEST_HEADERS.");
 
373
 
 
374
    if (msr->txcfg->ruleset != NULL) {
 
375
        return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
 
376
    }
 
377
 
 
378
    return 0;
 
379
}
 
380
 
 
381
/**
 
382
 *
 
383
 */
 
384
static apr_status_t modsecurity_process_phase_request_body(modsec_rec *msr) {
 
385
    if ((msr->allow_scope == ACTION_ALLOW_REQUEST)||(msr->allow_scope == ACTION_ALLOW)) {
 
386
        msr_log(msr, 4, "Skipping phase REQUEST_BODY (allow used).");
 
387
        return 0;
 
388
    } else {
 
389
        msr_log(msr, 4, "Starting phase REQUEST_BODY.");
 
390
    }
 
391
 
 
392
    if (msr->txcfg->ruleset != NULL) {
 
393
        return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
 
394
    }
 
395
 
 
396
    return 0;
 
397
}
 
398
 
 
399
/**
 
400
 *
 
401
 */
 
402
static apr_status_t modsecurity_process_phase_response_headers(modsec_rec *msr) {
 
403
    if (msr->allow_scope == ACTION_ALLOW) {
 
404
        msr_log(msr, 4, "Skipping phase RESPONSE_HEADERS (allow used).");
 
405
        return 0;
 
406
    } else {
 
407
        msr_log(msr, 4, "Starting phase RESPONSE_HEADERS.");
 
408
    }
 
409
 
 
410
    if (msr->txcfg->ruleset != NULL) {
 
411
        return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
 
412
    }
 
413
 
 
414
    return 0;
 
415
}
 
416
 
 
417
/**
 
418
 *
 
419
 */
 
420
static apr_status_t modsecurity_process_phase_response_body(modsec_rec *msr) {
 
421
    if (msr->allow_scope == ACTION_ALLOW) {
 
422
        msr_log(msr, 4, "Skipping phase RESPONSE_BODY (allow used).");
 
423
        return 0;
 
424
    } else {
 
425
        msr_log(msr, 4, "Starting phase RESPONSE_BODY.");
 
426
    }
 
427
 
 
428
    if (msr->txcfg->ruleset != NULL) {
 
429
        return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
 
430
    }
 
431
 
 
432
    return 0;
 
433
}
 
434
 
 
435
/**
 
436
 *
 
437
 */
 
438
static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) {
 
439
    msr_log(msr, 4, "Starting phase LOGGING.");
 
440
 
 
441
    if (msr->txcfg->ruleset != NULL) {
 
442
        msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
 
443
    }
 
444
 
 
445
    /* Is this request relevant for logging purposes? */
 
446
    if (msr->is_relevant == 0) {
 
447
        /* Check the status */
 
448
        msr->is_relevant += is_response_status_relevant(msr, msr->r->status);
 
449
 
 
450
        /* If we processed two requests and statuses are different then
 
451
         * check the other status too.
 
452
         */
 
453
        if (msr->r_early->status != msr->r->status) {
 
454
            msr->is_relevant += is_response_status_relevant(msr, msr->r_early->status);
 
455
        }
 
456
    }
 
457
 
 
458
    /* Figure out if we want to keep the files (if there are any, of course). */
 
459
    if ((msr->txcfg->upload_keep_files == KEEP_FILES_ON)
 
460
        || ((msr->txcfg->upload_keep_files == KEEP_FILES_RELEVANT_ONLY)&&(msr->is_relevant)))
 
461
    {
 
462
        msr->upload_remove_files = 0;
 
463
    } else {
 
464
        msr->upload_remove_files = 1;
 
465
    }
 
466
 
 
467
    /* Are we configured for audit logging? */
 
468
    switch(msr->txcfg->auditlog_flag) {
 
469
        case AUDITLOG_OFF :
 
470
            msr_log(msr, 4, "Audit log: Not configured to run for this request.");
 
471
            return DECLINED;
 
472
            break;
 
473
 
 
474
        case AUDITLOG_RELEVANT :
 
475
            if (msr->is_relevant == 0) {
 
476
                msr_log(msr, 4, "Audit log: Ignoring a non-relevant request.");
 
477
                return DECLINED;
 
478
            }
 
479
            break;
 
480
 
 
481
        case AUDITLOG_ON :
 
482
            /* All right, do nothing */
 
483
            break;
 
484
 
 
485
        default :
 
486
            msr_log(msr, 1, "Internal error: Could not determine if auditing is needed, so forcing auditing.");
 
487
            break;
 
488
    }
 
489
 
 
490
    /* Invoke the Audit logger */
 
491
    msr_log(msr, 4, "Audit log: Logging this transaction.");
 
492
 
 
493
    sec_audit_logger(msr);
 
494
 
 
495
    return 0;
 
496
}
 
497
 
 
498
/**
 
499
 * Processes one transaction phase. The phase number does not
 
500
 * need to be explicitly provided since it's already available
 
501
 * in the modsec_rec structure.
 
502
 */
 
503
apr_status_t modsecurity_process_phase(modsec_rec *msr, unsigned int phase) {
 
504
    /* Check if we should run. */
 
505
    if ((msr->was_intercepted)&&(phase != PHASE_LOGGING)) {
 
506
        msr_log(msr, 4, "Skipping phase %d as request was already intercepted.", phase);
 
507
        return 0;
 
508
    }
 
509
 
 
510
    /* Do not process the same phase twice. */
 
511
    if (msr->phase >= phase) {
 
512
        msr_log(msr, 4, "Skipping phase %d because it was previously run (at %d now).",
 
513
            phase, msr->phase);
 
514
        return 0;
 
515
    }
 
516
 
 
517
    msr->phase = phase;
 
518
 
 
519
    /* Clear out the transformation cache at the start of each phase */
 
520
    if (msr->txcfg->cache_trans == MODSEC_CACHE_ENABLED) {
 
521
        if (msr->tcache) {
 
522
            apr_hash_index_t *hi;
 
523
            void *dummy;
 
524
            apr_table_t *tab;
 
525
            const void *key;
 
526
            apr_ssize_t klen;
 
527
            #ifdef CACHE_DEBUG
 
528
            apr_pool_t *mp = msr->msc_rule_mptmp;
 
529
            const apr_array_header_t *ctarr;
 
530
            const apr_table_entry_t *ctelts;
 
531
            msre_cache_rec *rec;
 
532
            int cn = 0;
 
533
            int ri;
 
534
            #else
 
535
            apr_pool_t *mp = msr->mp;
 
536
            #endif
 
537
 
 
538
            for (hi = apr_hash_first(mp, msr->tcache); hi; hi = apr_hash_next(hi)) {
 
539
                apr_hash_this(hi, &key, &klen, &dummy);
 
540
                tab = (apr_table_t *)dummy;
 
541
 
 
542
                if (tab == NULL) continue;
 
543
 
 
544
                #ifdef CACHE_DEBUG
 
545
                /* Dump the cache out as we clear */
 
546
                ctarr = apr_table_elts(tab);
 
547
                ctelts = (const apr_table_entry_t*)ctarr->elts;
 
548
                for (ri = 0; ri < ctarr->nelts; ri++) {
 
549
                    cn++;
 
550
                    rec = (msre_cache_rec *)ctelts[ri].val;
 
551
                    if (rec->changed) {
 
552
                        if (msr->txcfg->debuglog_level >= 9) {
 
553
                            msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=\"%s\" (%pp - %pp)", cn, rec->hits, key, rec->num, rec->path, log_escape_nq_ex(mp, rec->val, rec->val_len), rec->val, rec->val + rec->val_len);
 
554
                        }
 
555
                    }
 
556
                    else {
 
557
                        if (msr->txcfg->debuglog_level >= 9) {
 
558
                            msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=<no change>", cn, rec->hits, key, rec->num, rec->path);
 
559
                        }
 
560
                    }
 
561
                }
 
562
                #endif
 
563
 
 
564
                apr_table_clear(tab);
 
565
                apr_hash_set(msr->tcache, key, klen, NULL);
 
566
            }
 
567
 
 
568
            msr_log(msr, 9, "Cleared transformation cache for phase %d", msr->phase);
 
569
        }
 
570
 
 
571
        msr->tcache_items = 0;
 
572
        msr->tcache = apr_hash_make(msr->mp);
 
573
        if (msr->tcache == NULL) return -1;
 
574
    }
 
575
 
 
576
    switch(phase) {
 
577
        case 1 :
 
578
            return modsecurity_process_phase_request_headers(msr);
 
579
            break;
 
580
        case 2 :
 
581
            return modsecurity_process_phase_request_body(msr);
 
582
            break;
 
583
        case 3 :
 
584
            return modsecurity_process_phase_response_headers(msr);
 
585
            break;
 
586
        case 4 :
 
587
            return modsecurity_process_phase_response_body(msr);
 
588
            break;
 
589
        case 5 :
 
590
            return modsecurity_process_phase_logging(msr);
 
591
            break;
 
592
        default :
 
593
            msr_log(msr, 1, "Invalid processing phase: %d", msr->phase);
 
594
            break;
 
595
    }
 
596
 
 
597
    return -1;
 
598
}