Imported Upstream version 2.5.11
[libapache-mod-security.git] / apache2 / re_variables.c
1 /*
2  * ModSecurity for Apache 2.x, http://www.modsecurity.org/
3  * Copyright (c) 2004-2009 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 "http_core.h"
20
21 #include "modsecurity.h"
22 #include "apache2.h"
23 #include "re.h"
24 #include "msc_util.h"
25
26 #include "libxml/xpathInternals.h"
27
28 /**
29  * Generates a variable from a string and a length.
30  */
31 static int var_simple_generate_ex(msre_var *var, apr_table_t *vartab, apr_pool_t *mptmp,
32     const char *value, int value_len)
33 {
34     msre_var *rvar = NULL;
35
36     if (value == NULL) return 0;
37
38     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
39     rvar->value = value;
40     rvar->value_len = value_len;
41     apr_table_addn(vartab, rvar->name, (void *)rvar);
42
43     return 1;
44 }
45
46 /**
47  * Generates a variable from a NULL-terminated string.
48  */
49 static int var_simple_generate(msre_var *var, apr_table_t *vartab, apr_pool_t *mptmp,
50     const char *value)
51 {
52     if (value == NULL) return 0;
53     return var_simple_generate_ex(var, vartab, mptmp, value, strlen(value));
54 }
55
56 /**
57  * Validate that a target parameter is valid. We only need to take
58  * care of the case when the parameter is a regular expression.
59  */
60 static char *var_generic_list_validate(msre_ruleset *ruleset, msre_var *var) {
61     /* It's OK if there's no parameter. */
62     if (var->param == NULL) return NULL;
63
64     /* Is it a regular expression? */
65     if ((strlen(var->param) > 2)&&(var->param[0] == '/')
66         &&(var->param[strlen(var->param) - 1] == '/'))
67     { /* Regex. */
68         msc_regex_t *regex = NULL;
69         const char *errptr = NULL;
70         const char *pattern = NULL;
71         int erroffset;
72
73         pattern = apr_pstrmemdup(ruleset->mp, var->param + 1, strlen(var->param + 1) - 1);
74         if (pattern == NULL) return FATAL_ERROR;
75
76         regex = msc_pregcomp(ruleset->mp, pattern, PCRE_DOTALL | PCRE_CASELESS | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset);
77         if (regex == NULL) {
78             return apr_psprintf(ruleset->mp, "Error compiling pattern (offset %d): %s",
79                 erroffset, errptr);
80         }
81
82         /* Store the compiled regex for later. */
83         var->param_data = regex;
84     }
85
86     /* Simple string */
87     return NULL;
88 }
89
90 /* Custom parameter validation functions */
91
92 /* ARGS */
93
94 static int var_args_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
95     apr_table_t *vartab, apr_pool_t *mptmp)
96 {
97     const apr_array_header_t *arr = NULL;
98     const apr_table_entry_t *te = NULL;
99     int i, count = 0;
100
101     /* Loop through the arguments. */
102     arr = apr_table_elts(msr->arguments);
103     te = (apr_table_entry_t *)arr->elts;
104     for (i = 0; i < arr->nelts; i++) {
105         msc_arg *arg = (msc_arg *)te[i].val;
106         int match = 0;
107
108         /* Figure out if we want to include this argument. */
109         if (var->param == NULL) match = 1; /* Unconditional inclusion. */
110         else {
111             if (var->param_data != NULL) { /* Regex. */
112                 char *my_error_msg = NULL;
113                 /* Run the regex against the argument name. */
114                 if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name,
115                     arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
116             } else { /* Simple comparison. */
117                 if (strcasecmp(arg->name, var->param) == 0) match = 1;
118             }
119         }
120
121         /* If we had a match add this argument to the collection. */
122         if (match) {
123             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
124
125             rvar->value = arg->value;
126             rvar->value_len = arg->value_len;
127             rvar->name = apr_psprintf(mptmp, "ARGS:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len));
128             apr_table_addn(vartab, rvar->name, (void *)rvar);
129
130             count++;
131         }
132     }
133
134     return count;
135 }
136
137 /* ARGS_COMBINED_SIZE */
138
139 static int var_args_combined_size_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
140     apr_table_t *vartab, apr_pool_t *mptmp)
141 {
142     const apr_array_header_t *arr = NULL;
143     const apr_table_entry_t *te = NULL;
144     unsigned int combined_size = 0;
145     int i;
146     msre_var *rvar = NULL;
147
148     arr = apr_table_elts(msr->arguments);
149     te = (apr_table_entry_t *)arr->elts;
150     for (i = 0; i < arr->nelts; i++) {
151         msc_arg *arg = (msc_arg *)te[i].val;
152         combined_size += arg->name_len;
153         combined_size += arg->value_len;
154     }
155
156     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
157     rvar->value = apr_psprintf(mptmp, "%u", combined_size);
158     rvar->value_len = strlen(rvar->value);
159     apr_table_addn(vartab, rvar->name, (void *)rvar);
160
161     return 1;
162 }
163
164 /* ARGS_NAMES */
165
166 static int var_args_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
167     apr_table_t *vartab, apr_pool_t *mptmp)
168 {
169     const apr_array_header_t *arr = NULL;
170     const apr_table_entry_t *te = NULL;
171     int i, count = 0;
172
173     arr = apr_table_elts(msr->arguments);
174     te = (apr_table_entry_t *)arr->elts;
175     for (i = 0; i < arr->nelts; i++) {
176         msc_arg *arg = (msc_arg *)te[i].val;
177         int match = 0;
178
179         /* Figure out if we want to include this variable. */
180         if (var->param == NULL) match = 1; /* Unconditional inclusion. */
181         else {
182             if (var->param_data != NULL) { /* Regex. */
183                 char *my_error_msg = NULL;
184                 if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name,
185                     arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
186             } else { /* Simple comparison. */
187                 if (strcasecmp(arg->name, var->param) == 0) match = 1;
188             }
189         }
190
191         /* If we had a match add this argument to the collection. */
192         if (match) {
193             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
194
195             rvar->value = arg->name;
196             rvar->value_len = arg->name_len;
197             rvar->name = apr_psprintf(mptmp, "ARGS_NAMES:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len));
198             apr_table_addn(vartab, rvar->name, (void *)rvar);
199
200             count++;
201         }
202     }
203
204     return count;
205 }
206
207 /* ARGS_GET */
208
209 static int var_args_get_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
210     apr_table_t *vartab, apr_pool_t *mptmp)
211 {
212     const apr_array_header_t *arr = NULL;
213     const apr_table_entry_t *te = NULL;
214     int i, count = 0;
215
216     /* Loop through the arguments. */
217     arr = apr_table_elts(msr->arguments);
218     te = (apr_table_entry_t *)arr->elts;
219     for (i = 0; i < arr->nelts; i++) {
220         msc_arg *arg = (msc_arg *)te[i].val;
221         int match = 0;
222
223         /* Only QUERY_STRING arguments */
224         if (strcmp("QUERY_STRING", arg->origin) != 0) continue;
225
226         /* Figure out if we want to include this argument. */
227         if (var->param == NULL) match = 1; /* Unconditional inclusion. */
228         else {
229             if (var->param_data != NULL) { /* Regex. */
230                 char *my_error_msg = NULL;
231                 /* Run the regex against the argument name. */
232                 if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name,
233                     arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
234             } else { /* Simple comparison. */
235                 if (strcasecmp(arg->name, var->param) == 0) match = 1;
236             }
237         }
238
239         /* If we had a match add this argument to the collection. */
240         if (match) {
241             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
242
243             rvar->value = arg->value;
244             rvar->value_len = arg->value_len;
245             rvar->name = apr_psprintf(mptmp, "ARGS_GET:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len));
246             apr_table_addn(vartab, rvar->name, (void *)rvar);
247
248             count++;
249         }
250     }
251
252     return count;
253 }
254
255 /* ARGS_GET_NAMES */
256
257 static int var_args_get_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
258     apr_table_t *vartab, apr_pool_t *mptmp)
259 {
260     const apr_array_header_t *arr = NULL;
261     const apr_table_entry_t *te = NULL;
262     int i, count = 0;
263
264     arr = apr_table_elts(msr->arguments);
265     te = (apr_table_entry_t *)arr->elts;
266     for (i = 0; i < arr->nelts; i++) {
267         msc_arg *arg = (msc_arg *)te[i].val;
268         int match = 0;
269
270         /* Only QUERY_STRING arguments */
271         if (strcmp("QUERY_STRING", arg->origin) != 0) continue;
272
273         /* Figure out if we want to include this variable. */
274         if (var->param == NULL) match = 1; /* Unconditional inclusion. */
275         else {
276             if (var->param_data != NULL) { /* Regex. */
277                 char *my_error_msg = NULL;
278                 if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name,
279                     arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
280             } else { /* Simple comparison. */
281                 if (strcasecmp(arg->name, var->param) == 0) match = 1;
282             }
283         }
284
285         /* If we had a match add this argument to the collection. */
286         if (match) {
287             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
288
289             rvar->value = arg->name;
290             rvar->value_len = arg->name_len;
291             rvar->name = apr_psprintf(mptmp, "ARGS_GET_NAMES:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len));
292             apr_table_addn(vartab, rvar->name, (void *)rvar);
293
294             count++;
295         }
296     }
297
298     return count;
299 }
300
301 /* ARGS_POST */
302
303 static int var_args_post_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
304     apr_table_t *vartab, apr_pool_t *mptmp)
305 {
306     const apr_array_header_t *arr = NULL;
307     const apr_table_entry_t *te = NULL;
308     int i, count = 0;
309
310     /* Loop through the arguments. */
311     arr = apr_table_elts(msr->arguments);
312     te = (apr_table_entry_t *)arr->elts;
313     for (i = 0; i < arr->nelts; i++) {
314         msc_arg *arg = (msc_arg *)te[i].val;
315         int match = 0;
316
317         /* Only BODY arguments */
318         if (strcmp("BODY", arg->origin) != 0) continue;
319
320         /* Figure out if we want to include this argument. */
321         if (var->param == NULL) match = 1; /* Unconditional inclusion. */
322         else {
323             if (var->param_data != NULL) { /* Regex. */
324                 char *my_error_msg = NULL;
325                 /* Run the regex against the argument name. */
326                 if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name,
327                     arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
328             } else { /* Simple comparison. */
329                 if (strcasecmp(arg->name, var->param) == 0) match = 1;
330             }
331         }
332
333         /* If we had a match add this argument to the collection. */
334         if (match) {
335             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
336
337             rvar->value = arg->value;
338             rvar->value_len = arg->value_len;
339             rvar->name = apr_psprintf(mptmp, "ARGS_POST:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len));
340             apr_table_addn(vartab, rvar->name, (void *)rvar);
341
342             count++;
343         }
344     }
345
346     return count;
347 }
348
349 /* ARGS_POST_NAMES */
350
351 static int var_args_post_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
352     apr_table_t *vartab, apr_pool_t *mptmp)
353 {
354     const apr_array_header_t *arr = NULL;
355     const apr_table_entry_t *te = NULL;
356     int i, count = 0;
357
358     arr = apr_table_elts(msr->arguments);
359     te = (apr_table_entry_t *)arr->elts;
360     for (i = 0; i < arr->nelts; i++) {
361         msc_arg *arg = (msc_arg *)te[i].val;
362         int match = 0;
363
364         /* Only BODY arguments */
365         if (strcmp("BODY", arg->origin) != 0) continue;
366
367         /* Figure out if we want to include this variable. */
368         if (var->param == NULL) match = 1; /* Unconditional inclusion. */
369         else {
370             if (var->param_data != NULL) { /* Regex. */
371                 char *my_error_msg = NULL;
372                 if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name,
373                     arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
374             } else { /* Simple comparison. */
375                 if (strcasecmp(arg->name, var->param) == 0) match = 1;
376             }
377         }
378
379         /* If we had a match add this argument to the collection. */
380         if (match) {
381             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
382
383             rvar->value = arg->name;
384             rvar->value_len = arg->name_len;
385             rvar->name = apr_psprintf(mptmp, "ARGS_POST_NAMES:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len));
386             apr_table_addn(vartab, rvar->name, (void *)rvar);
387
388             count++;
389         }
390     }
391
392     return count;
393 }
394
395 /* RULE */
396
397 static int var_rule_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
398     apr_table_t *vartab, apr_pool_t *mptmp)
399 {
400     msre_actionset *actionset = NULL;
401
402     if (rule == NULL) return 0;
403     actionset = rule->actionset;
404     if (rule->chain_starter != NULL) actionset = rule->chain_starter->actionset;
405
406     if ((strcasecmp(var->param, "id") == 0)&&(actionset->id != NULL)) {
407         return var_simple_generate(var, vartab, mptmp, actionset->id);
408     } else
409     if ((strcasecmp(var->param, "rev") == 0)&&(actionset->rev != NULL)) {
410         return var_simple_generate(var, vartab, mptmp, actionset->rev);
411     } else
412     if ((strcasecmp(var->param, "severity") == 0)&&(actionset->severity != -1)) {
413         char *value = apr_psprintf(mptmp, "%d", actionset->severity);
414         return var_simple_generate(var, vartab, mptmp, value);
415     } else
416     if ((strcasecmp(var->param, "msg") == 0)&&(actionset->msg != NULL)) {
417         return var_simple_generate(var, vartab, mptmp, actionset->msg);
418     } else
419     if ((strcasecmp(var->param, "logdata") == 0)&&(actionset->logdata != NULL)) {
420         return var_simple_generate(var, vartab, mptmp, actionset->logdata);
421     }
422
423     return 0;
424 }
425
426 /* ENV */
427
428 static char *var_env_validate(msre_ruleset *ruleset, msre_var *var) {
429     if (var->param == NULL) {
430         return apr_psprintf(ruleset->mp, "Parameter required for ENV.");
431     }
432     if ((strlen(var->param) > 2)&&(var->param[0] == '/')
433         &&(var->param[strlen(var->param) - 1] == '/'))
434     {
435         return apr_psprintf(ruleset->mp, "Regular expressions not supported in ENV.");
436     }
437     return NULL;
438 }
439
440 static int var_env_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
441     apr_table_t *vartab, apr_pool_t *mptmp)
442 {
443     char *value = get_env_var(msr->r, (char *)var->param);
444     if (value != NULL) {
445         return var_simple_generate(var, vartab, mptmp, value);
446     }
447     return 0;
448 }
449
450 /* REQUEST_URI_RAW */
451
452 static int var_request_uri_raw_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
453     apr_table_t *vartab, apr_pool_t *mptmp)
454 {
455     return var_simple_generate(var, vartab, mptmp, msr->r->unparsed_uri);
456 }
457
458 /* REQUEST_URI */
459
460 static int var_request_uri_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
461     apr_table_t *vartab, apr_pool_t *mptmp) /* dynamic */
462 {
463     char *value = NULL;
464
465     if (msr->r->parsed_uri.query == NULL) value = msr->r->parsed_uri.path;
466     else value = apr_pstrcat(mptmp,  msr->r->parsed_uri.path, "?", msr->r->parsed_uri.query, NULL);
467
468     return var_simple_generate(var, vartab, mptmp, value);
469 }
470
471 /* REQBODY_PROCESSOR */
472
473 static int var_reqbody_processor_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
474     apr_table_t *vartab, apr_pool_t *mptmp)
475 {
476     msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
477
478     if (msr->msc_reqbody_processor == NULL) {
479         rvar->value = apr_pstrdup(mptmp, "");
480         rvar->value_len = 0;
481     } else {
482         rvar->value = apr_pstrdup(mptmp, msr->msc_reqbody_processor);
483         rvar->value_len = strlen(rvar->value);
484     }
485
486     apr_table_addn(vartab, rvar->name, (void *)rvar);
487
488     return 1;
489 }
490
491 /* REQBODY_ERROR */
492
493 static int var_reqbody_processor_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
494     apr_table_t *vartab, apr_pool_t *mptmp)
495 {
496     msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
497
498     rvar->value = apr_psprintf(mptmp, "%d", msr->msc_reqbody_error);
499     rvar->value_len = strlen(rvar->value);
500     apr_table_addn(vartab, rvar->name, (void *)rvar);
501
502     return 1;
503 }
504
505 /* REQBODY_ERROR_MSG */
506
507 static int var_reqbody_processor_error_msg_generate(modsec_rec *msr, msre_var *var,
508     msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp)
509 {
510     msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
511
512     if (msr->msc_reqbody_error_msg == NULL) {
513         rvar->value = apr_pstrdup(mptmp, "");
514         rvar->value_len = 0;
515     } else {
516         rvar->value = apr_psprintf(mptmp, "%s", msr->msc_reqbody_error_msg);
517         rvar->value_len = strlen(rvar->value);
518     }
519
520     apr_table_addn(vartab, rvar->name, (void *)rvar);
521
522     return 1;
523 }
524
525 /* XML */
526
527 static char *var_xml_validate(msre_ruleset *ruleset, msre_var *var) {
528     /* It's OK if there's no parameter. */
529     if (var->param == NULL) return NULL;
530
531     /* ENH validate XPath expression in advance. */
532
533     return NULL;
534 }
535
536 static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
537     apr_table_t *vartab, apr_pool_t *mptmp)
538 {
539     const apr_array_header_t *tarr;
540     const apr_table_entry_t *telts;
541     xmlXPathContextPtr xpathCtx;
542     xmlXPathObjectPtr xpathObj;
543     xmlNodeSetPtr nodes;
544     const xmlChar* xpathExpr = NULL;
545     int i, count;
546
547     /* Is there an XML document tree at all? */
548     if ((msr->xml == NULL)||(msr->xml->doc == NULL)) {
549         /* Sorry, we've got nothing to give! */
550         return 0;
551     }
552
553     if (var->param == NULL) {
554         /* Invocation without an XPath expression makes sense
555          * with functions that manipulate the document tree.
556          */
557         msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
558
559         rvar->value = apr_pstrdup(mptmp, "[XML document tree]");
560         rvar->value_len = strlen(rvar->value);
561         apr_table_addn(vartab, rvar->name, (void *)rvar);
562
563         return 1;
564     }
565
566     /* Process the XPath expression. */
567
568     count = 0;
569     xpathExpr = (const xmlChar*)var->param;
570
571     xpathCtx = xmlXPathNewContext(msr->xml->doc);
572     if (xpathCtx == NULL) {
573         msr_log(msr, 1, "XML: Unable to create new XPath context.");
574         return -1;
575     }
576
577     /* Look through the actionset of the associated rule
578      * for the namespace information. Register them if any are found.
579      */
580     tarr = apr_table_elts(rule->actionset->actions);
581     telts = (const apr_table_entry_t*)tarr->elts;
582     for (i = 0; i < tarr->nelts; i++) {
583         msre_action *action = (msre_action *)telts[i].val;
584
585         if (strcasecmp(action->metadata->name, "xmlns") == 0) {
586             char *prefix, *href;
587
588             if (parse_name_eq_value(mptmp, action->param, &prefix, &href) < 0) return -1;
589             if ((prefix == NULL)||(href == NULL)) return -1;
590
591             if(xmlXPathRegisterNs(xpathCtx, (const xmlChar*)prefix, (const xmlChar*)href) != 0) {
592                 msr_log(msr, 1, "Failed to register XML namespace href \"%s\" prefix \"%s\".",
593                     log_escape(mptmp, prefix), log_escape(mptmp, href));
594                 return -1;
595             }
596
597             msr_log(msr, 4, "Registered XML namespace href \"%s\" prefix \"%s\".",
598                 log_escape(mptmp, prefix), log_escape(mptmp, href));
599         }
600     }
601
602     /* Initialise XPath expression. */
603     xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
604     if (xpathObj == NULL) {
605         msr_log(msr, 1, "XML: Unable to evaluate xpath expression.");
606         xmlXPathFreeContext(xpathCtx);
607         return -1;
608     }
609
610     /* Evaluate XPath expression. */
611     nodes = xpathObj->nodesetval;
612     if (nodes == NULL) {
613         xmlXPathFreeObject(xpathObj);
614         xmlXPathFreeContext(xpathCtx);
615         return 0;
616     }
617
618     /* Create one variable for each node in the result. */
619     for(i = 0; i < nodes->nodeNr; i++) {
620         msre_var *rvar = NULL;
621         char *content = NULL;
622
623         content = (char *)xmlNodeGetContent(nodes->nodeTab[i]);
624         if (content != NULL) {
625             rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
626             rvar->value = apr_pstrdup(mptmp, content);
627             xmlFree(content);
628             rvar->value_len = strlen(rvar->value);
629             apr_table_addn(vartab, rvar->name, (void *)rvar);
630
631             count++;
632          }
633     }
634
635     xmlXPathFreeObject(xpathObj);
636     xmlXPathFreeContext(xpathCtx);
637
638     return count;
639 }
640
641 /* WEBSERVER_ERROR_LOG */
642
643 static int var_webserver_error_log_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
644     apr_table_t *vartab, apr_pool_t *mptmp)
645 {
646     msre_var *rvar = NULL;
647     int i, count = 0;
648
649     for(i = 0; i < msr->error_messages->nelts; i++) {
650         error_message *em = (((error_message**)msr->error_messages->elts)[i]);
651         char *fem = NULL;
652
653         fem = format_error_log_message(mptmp, em);
654         if (fem != NULL) {
655             rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
656             rvar->value = apr_pstrdup(mptmp, fem);
657             rvar->value_len = strlen(rvar->value);
658             apr_table_addn(vartab, rvar->name, (void *)rvar);
659
660             count++;
661         }
662     }
663
664     return count;
665 }
666
667 /* REMOTE_ADDR */
668
669 static int var_remote_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
670     apr_table_t *vartab, apr_pool_t *mptmp)
671 {
672     return var_simple_generate(var, vartab, mptmp, msr->remote_addr);
673 }
674
675 /* REMOTE_HOST */
676
677 static int var_remote_host_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
678     apr_table_t *vartab, apr_pool_t *mptmp)
679 {
680     const char *value1 = ap_get_remote_host(msr->r->connection, msr->r->per_dir_config,
681         REMOTE_NAME, NULL);
682     return var_simple_generate(var, vartab, mptmp, value1);
683 }
684
685 /* REMOTE_PORT */
686
687 static int var_remote_port_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
688     apr_table_t *vartab, apr_pool_t *mptmp)
689 {
690     char *value = apr_psprintf(mptmp, "%u", msr->remote_port);
691     return var_simple_generate(var, vartab, mptmp, value);
692 }
693
694 /* REMOTE_USER */
695
696 static int var_remote_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
697     apr_table_t *vartab, apr_pool_t *mptmp)
698 {
699     return var_simple_generate(var, vartab, mptmp, msr->remote_user);
700 }
701
702 /* TX */
703
704 static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
705     apr_table_t *vartab, apr_pool_t *mptmp)
706 {
707     const apr_array_header_t *arr = NULL;
708     const apr_table_entry_t *te = NULL;
709     int i, count = 0;
710
711     arr = apr_table_elts(msr->tx_vars);
712     te = (apr_table_entry_t *)arr->elts;
713     for (i = 0; i < arr->nelts; i++) {
714         msc_string *str = (msc_string *)te[i].val;
715         int match;
716
717         /* Figure out if we want to include this variable. */
718         match = 0;
719         if (var->param == NULL) match = 1; /* Unconditional inclusion. */
720         else {
721             if (var->param_data != NULL) { /* Regex. */
722                 char *my_error_msg = NULL;
723                 if (!(msc_regexec((msc_regex_t *)var->param_data, str->name,
724                     str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
725             } else { /* Simple comparison. */
726                 if (strcasecmp(str->name, var->param) == 0) match = 1;
727             }
728         }
729
730         /* If we had a match add this argument to the collection. */
731         if (match) {
732             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
733
734             rvar->value = str->value;
735             rvar->value_len = str->value_len;
736             rvar->name = apr_psprintf(mptmp, "TX:%s", log_escape_nq_ex(mptmp, str->name, str->name_len));
737             apr_table_addn(vartab, rvar->name, (void *)rvar);
738
739             count++;
740         }
741     }
742
743     return count;
744 }
745
746 /* GEO */
747
748 static int var_geo_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
749     apr_table_t *vartab, apr_pool_t *mptmp)
750 {
751     const apr_array_header_t *arr = NULL;
752     const apr_table_entry_t *te = NULL;
753     int i, count = 0;
754
755     arr = apr_table_elts(msr->geo_vars);
756     te = (apr_table_entry_t *)arr->elts;
757     for (i = 0; i < arr->nelts; i++) {
758         msc_string *str = (msc_string *)te[i].val;
759         int match;
760
761         /* Figure out if we want to include this variable. */
762         match = 0;
763         if (var->param == NULL) match = 1; /* Unconditional inclusion. */
764         else {
765             if (var->param_data != NULL) { /* Regex. */
766                 char *my_error_msg = NULL;
767                 if (!(msc_regexec((msc_regex_t *)var->param_data, str->name,
768                     str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
769             } else { /* Simple comparison. */
770                 if (strcasecmp(str->name, var->param) == 0) match = 1;
771             }
772         }
773
774         /* If we had a match add this argument to the collection. */
775         if (match) {
776             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
777
778             rvar->value = str->value;
779             rvar->value_len = str->value_len;
780             rvar->name = apr_psprintf(mptmp, "GEO:%s", log_escape_nq_ex(mptmp, str->name, str->name_len));
781             apr_table_addn(vartab, rvar->name, (void *)rvar);
782
783             count++;
784         }
785     }
786
787     return count;
788 }
789
790 /* HIGHEST_SEVERITY */
791
792 static int var_highest_severity_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
793     apr_table_t *vartab, apr_pool_t *mptmp)
794 {
795     return var_simple_generate(var, vartab, mptmp,
796                                apr_psprintf(mptmp, "%d", msr->highest_severity));
797 }
798
799 /* IP */
800
801 static int var_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
802     apr_table_t *vartab, apr_pool_t *mptmp)
803 {
804     const apr_array_header_t *arr = NULL;
805     const apr_table_entry_t *te = NULL;
806     int i, count = 0;
807     apr_table_t *target_col = NULL;
808
809     target_col = (apr_table_t *)apr_table_get(msr->collections, "ip");
810     if (target_col == NULL) return 0;
811
812     arr = apr_table_elts(target_col);
813     te = (apr_table_entry_t *)arr->elts;
814     for (i = 0; i < arr->nelts; i++) {
815         msc_string *str = (msc_string *)te[i].val;
816         int match;
817
818         /* Figure out if we want to include this variable. */
819         match = 0;
820         if (var->param == NULL) match = 1; /* Unconditional inclusion. */
821         else {
822             if (var->param_data != NULL) { /* Regex. */
823                 char *my_error_msg = NULL;
824                 if (!(msc_regexec((msc_regex_t *)var->param_data, str->name,
825                     str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
826             } else { /* Simple comparison. */
827                 if (strcasecmp(str->name, var->param) == 0) match = 1;
828             }
829         }
830
831         /* If we had a match add this argument to the collection. */
832         if (match) {
833             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
834
835             rvar->value = str->value;
836             rvar->value_len = str->value_len;
837             rvar->name = apr_psprintf(mptmp, "IP:%s", log_escape_nq_ex(mptmp, str->name, str->name_len));
838             apr_table_addn(vartab, rvar->name, (void *)rvar);
839
840             count++;
841         }
842     }
843
844     return count;
845 }
846
847 /* MATCHED_VAR */
848
849 static int var_matched_var_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
850     apr_table_t *vartab, apr_pool_t *mptmp)
851 {
852     return var_simple_generate_ex(var, vartab, mptmp,
853                                   apr_pmemdup(mptmp,
854                                       msr->matched_var->value,
855                                       msr->matched_var->value_len),
856                                   msr->matched_var->value_len);
857 }
858
859 /* MATCHED_VAR_NAME */
860
861 static int var_matched_var_name_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
862     apr_table_t *vartab, apr_pool_t *mptmp)
863 {
864     return var_simple_generate_ex(var, vartab, mptmp,
865                                   apr_pmemdup(mptmp,
866                                       msr->matched_var->name,
867                                       msr->matched_var->name_len),
868                                   msr->matched_var->name_len);
869 }
870
871 /* SESSION */
872
873 static int var_session_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
874     apr_table_t *vartab, apr_pool_t *mptmp)
875 {
876     const apr_array_header_t *arr = NULL;
877     const apr_table_entry_t *te = NULL;
878     int i, count = 0;
879     apr_table_t *target_col = NULL;
880
881     target_col = (apr_table_t *)apr_table_get(msr->collections, "session");
882     if (target_col == NULL) return 0;
883
884     arr = apr_table_elts(target_col);
885     te = (apr_table_entry_t *)arr->elts;
886     for (i = 0; i < arr->nelts; i++) {
887         msc_string *str = (msc_string *)te[i].val;
888         int match;
889
890         /* Figure out if we want to include this variable. */
891         match = 0;
892         if (var->param == NULL) match = 1; /* Unconditional inclusion. */
893         else {
894             if (var->param_data != NULL) { /* Regex. */
895                 char *my_error_msg = NULL;
896                 if (!(msc_regexec((msc_regex_t *)var->param_data, str->name,
897                     str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
898             } else { /* Simple comparison. */
899                 if (strcasecmp(str->name, var->param) == 0) match = 1;
900             }
901         }
902
903         /* If we had a match add this argument to the collection. */
904         if (match) {
905             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
906
907             rvar->value = str->value;
908             rvar->value_len = str->value_len;
909             rvar->name = apr_psprintf(mptmp, "SESSION:%s", log_escape_nq_ex(mptmp, str->name, str->name_len));
910             apr_table_addn(vartab, rvar->name, (void *)rvar);
911
912             count++;
913         }
914     }
915
916     return count;
917 }
918
919 /* USER */
920
921 static int var_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
922     apr_table_t *vartab, apr_pool_t *mptmp)
923 {
924     const apr_array_header_t *arr = NULL;
925     const apr_table_entry_t *te = NULL;
926     int i, count = 0;
927     apr_table_t *target_col = NULL;
928
929     target_col = (apr_table_t *)apr_table_get(msr->collections, "user");
930     if (target_col == NULL) return 0;
931
932     arr = apr_table_elts(target_col);
933     te = (apr_table_entry_t *)arr->elts;
934     for (i = 0; i < arr->nelts; i++) {
935         msc_string *str = (msc_string *)te[i].val;
936         int match;
937
938         /* Figure out if we want to include this variable. */
939         match = 0;
940         if (var->param == NULL) match = 1; /* Unconditional match. */
941         else {
942             if (var->param_data != NULL) { /* Regex. */
943                 char *my_error_msg = NULL;
944                 if (!(msc_regexec((msc_regex_t *)var->param_data, str->name,
945                     str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
946             } else { /* Simple comparison. */
947                 if (strcasecmp(str->name, var->param) == 0) match = 1;
948             }
949         }
950
951         /* If we had a match add this argument to the collection. */
952         if (match) {
953             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
954
955             rvar->value = str->value;
956             rvar->value_len = str->value_len;
957             rvar->name = apr_psprintf(mptmp, "USER:%s", log_escape_nq_ex(mptmp, str->name, str->name_len));
958             apr_table_addn(vartab, rvar->name, (void *)rvar);
959
960             count++;
961         }
962     }
963
964     return count;
965 }
966
967 /* GLOBAL */
968
969 static int var_global_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
970     apr_table_t *vartab, apr_pool_t *mptmp)
971 {
972     const apr_array_header_t *arr = NULL;
973     const apr_table_entry_t *te = NULL;
974     int i, count = 0;
975     apr_table_t *target_col = NULL;
976
977     target_col = (apr_table_t *)apr_table_get(msr->collections, "global");
978     if (target_col == NULL) return 0;
979
980     arr = apr_table_elts(target_col);
981     te = (apr_table_entry_t *)arr->elts;
982     for (i = 0; i < arr->nelts; i++) {
983         msc_string *str = (msc_string *)te[i].val;
984         int match;
985
986         /* Figure out if we want to include this variable. */
987         match = 0;
988         if (var->param == NULL) match = 1; /* Unconditional match. */
989         else {
990             if (var->param_data != NULL) { /* Regex. */
991                 char *my_error_msg = NULL;
992                 if (!(msc_regexec((msc_regex_t *)var->param_data, str->name,
993                     str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
994             } else { /* Simple comparison. */
995                 if (strcasecmp(str->name, var->param) == 0) match = 1;
996             }
997         }
998
999         /* If we had a match add this argument to the collection. */
1000         if (match) {
1001             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1002
1003             rvar->value = str->value;
1004             rvar->value_len = str->value_len;
1005             rvar->name = apr_psprintf(mptmp, "GLOBAL:%s", log_escape_nq_ex(mptmp, str->name, str->name_len));
1006             apr_table_addn(vartab, rvar->name, (void *)rvar);
1007
1008             count++;
1009         }
1010     }
1011
1012     return count;
1013 }
1014
1015 /* RESOURCE */
1016
1017 static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1018     apr_table_t *vartab, apr_pool_t *mptmp)
1019 {
1020     const apr_array_header_t *arr = NULL;
1021     const apr_table_entry_t *te = NULL;
1022     int i, count = 0;
1023     apr_table_t *target_col = NULL;
1024
1025     target_col = (apr_table_t *)apr_table_get(msr->collections, "resource");
1026     if (target_col == NULL) return 0;
1027
1028     arr = apr_table_elts(target_col);
1029     te = (apr_table_entry_t *)arr->elts;
1030     for (i = 0; i < arr->nelts; i++) {
1031         msc_string *str = (msc_string *)te[i].val;
1032         int match;
1033
1034         /* Figure out if we want to include this variable. */
1035         match = 0;
1036         if (var->param == NULL) match = 1; /* Unconditional match. */
1037         else {
1038             if (var->param_data != NULL) { /* Regex. */
1039                 char *my_error_msg = NULL;
1040                 if (!(msc_regexec((msc_regex_t *)var->param_data, str->name,
1041                     str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
1042             } else { /* Simple comparison. */
1043                 if (strcasecmp(str->name, var->param) == 0) match = 1;
1044             }
1045         }
1046
1047         /* If we had a match add this argument to the collection. */
1048         if (match) {
1049             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1050
1051             rvar->value = str->value;
1052             rvar->value_len = str->value_len;
1053             rvar->name = apr_psprintf(mptmp, "RESOURCE:%s", log_escape_nq_ex(mptmp, str->name, str->name_len));
1054             apr_table_addn(vartab, rvar->name, (void *)rvar);
1055
1056             count++;
1057         }
1058     }
1059
1060     return count;
1061 }
1062
1063 /* FILES_TMPNAMES */
1064
1065 static int var_files_tmpnames_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1066     apr_table_t *vartab, apr_pool_t *mptmp)
1067 {
1068     multipart_part **parts = NULL;
1069     int i, count = 0;
1070
1071     if (msr->mpd == NULL) return 0;
1072
1073     parts = (multipart_part **)msr->mpd->parts->elts;
1074     for(i = 0; i < msr->mpd->parts->nelts; i++) {
1075         if ((parts[i]->type == MULTIPART_FILE)&&(parts[i]->tmp_file_name != NULL)) {
1076             int match = 0;
1077
1078             /* Figure out if we want to include this variable. */
1079             if (var->param == NULL) match = 1;
1080             else {
1081                 if (var->param_data != NULL) { /* Regex. */
1082                     char *my_error_msg = NULL;
1083                     if (!(msc_regexec((msc_regex_t *)var->param_data, parts[i]->name,
1084                         strlen(parts[i]->name), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
1085                 } else { /* Simple comparison. */
1086                     if (strcasecmp(parts[i]->name, var->param) == 0) match = 1;
1087                 }
1088             }
1089
1090             /* If we had a match add this argument to the collection. */
1091             if (match) {
1092                 msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1093
1094                 rvar->value = parts[i]->tmp_file_name;
1095                 rvar->value_len = strlen(rvar->value);
1096                 rvar->name = apr_psprintf(mptmp, "FILES_TMPNAMES:%s",
1097                     log_escape_nq(mptmp, parts[i]->name));
1098                 apr_table_addn(vartab, rvar->name, (void *)rvar);
1099
1100                 count++;
1101             }
1102         }
1103     }
1104
1105     return count;
1106 }
1107
1108 /* FILES */
1109
1110 static int var_files_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1111     apr_table_t *vartab, apr_pool_t *mptmp)
1112 {
1113     multipart_part **parts = NULL;
1114     int i, count = 0;
1115
1116     if (msr->mpd == NULL) return 0;
1117
1118     parts = (multipart_part **)msr->mpd->parts->elts;
1119     for(i = 0; i < msr->mpd->parts->nelts; i++) {
1120         if (parts[i]->type == MULTIPART_FILE) {
1121             int match = 0;
1122
1123             /* Figure out if we want to include this variable. */
1124             if (var->param == NULL) match = 1;
1125             else {
1126                 if (var->param_data != NULL) { /* Regex. */
1127                     char *my_error_msg = NULL;
1128                     if (!(msc_regexec((msc_regex_t *)var->param_data, parts[i]->name,
1129                         strlen(parts[i]->name), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
1130                 } else { /* Simple comparison. */
1131                     if (strcasecmp(parts[i]->name, var->param) == 0) match = 1;
1132                 }
1133             }
1134
1135             /* If we had a match add this argument to the collection. */
1136             if (match) {
1137                 msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1138
1139                 rvar->value = parts[i]->filename;
1140                 rvar->value_len = strlen(rvar->value);
1141                 rvar->name = apr_psprintf(mptmp, "FILES:%s",
1142                     log_escape_nq(mptmp, parts[i]->name));
1143                 apr_table_addn(vartab, rvar->name, (void *)rvar);
1144
1145                 count++;
1146             }
1147         }
1148     }
1149
1150     return count;
1151 }
1152
1153 /* FILES_SIZES */
1154
1155 static int var_files_sizes_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1156     apr_table_t *vartab, apr_pool_t *mptmp)
1157 {
1158     multipart_part **parts = NULL;
1159     int i, count = 0;
1160
1161     if (msr->mpd == NULL) return 0;
1162
1163     parts = (multipart_part **)msr->mpd->parts->elts;
1164     for(i = 0; i < msr->mpd->parts->nelts; i++) {
1165         if (parts[i]->type == MULTIPART_FILE) {
1166             int match = 0;
1167
1168             /* Figure out if we want to include this variable. */
1169             if (var->param == NULL) match = 1;
1170             else {
1171                 if (var->param_data != NULL) { /* Regex. */
1172                     char *my_error_msg = NULL;
1173                     if (!(msc_regexec((msc_regex_t *)var->param_data, parts[i]->name,
1174                         strlen(parts[i]->name), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
1175                 } else { /* Simple comparison. */
1176                     if (strcasecmp(parts[i]->name, var->param) == 0) match = 1;
1177                 }
1178             }
1179
1180             /* If we had a match add this argument to the collection. */
1181             if (match) {
1182                 msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1183
1184                 rvar->value = apr_psprintf(mptmp, "%u", parts[i]->tmp_file_size);
1185                 rvar->value_len = strlen(rvar->value);
1186                 rvar->name = apr_psprintf(mptmp, "FILES_SIZES:%s",
1187                     log_escape_nq(mptmp, parts[i]->name));
1188                 apr_table_addn(vartab, rvar->name, (void *)rvar);
1189
1190                 count++;
1191             }
1192         }
1193     }
1194
1195     return count;
1196 }
1197
1198 /* FILES_NAMES */
1199
1200 static int var_files_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1201     apr_table_t *vartab, apr_pool_t *mptmp)
1202 {
1203     multipart_part **parts = NULL;
1204     int i, count = 0;
1205
1206     if (msr->mpd == NULL) return 0;
1207
1208     parts = (multipart_part **)msr->mpd->parts->elts;
1209     for(i = 0; i < msr->mpd->parts->nelts; i++) {
1210         if (parts[i]->type == MULTIPART_FILE) {
1211             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1212
1213             rvar->value = parts[i]->name;
1214             rvar->value_len = strlen(rvar->value);
1215             rvar->name = apr_psprintf(mptmp, "FILES_NAMES:%s",
1216                 log_escape_nq_ex(mptmp, parts[i]->name, rvar->value_len));
1217             apr_table_addn(vartab, rvar->name, (void *)rvar);
1218
1219             count++;
1220         }
1221     }
1222
1223     return count;
1224 }
1225
1226 /* FILES_COMBINED_SIZE */
1227
1228 static int var_files_combined_size_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1229     apr_table_t *vartab, apr_pool_t *mptmp)
1230 {
1231     multipart_part **parts = NULL;
1232     msre_var *rvar = NULL;
1233     unsigned int combined_size = 0;
1234     int i;
1235
1236     if (msr->mpd != NULL) {
1237         parts = (multipart_part **)msr->mpd->parts->elts;
1238         for(i = 0; i < msr->mpd->parts->nelts; i++) {
1239             if (parts[i]->type == MULTIPART_FILE) {
1240                 combined_size += parts[i]->tmp_file_size;
1241             }
1242         }
1243     }
1244
1245     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1246     rvar->value = apr_psprintf(mptmp, "%u", combined_size);
1247     rvar->value_len = strlen(rvar->value);
1248     apr_table_addn(vartab, rvar->name, (void *)rvar);
1249
1250     return 1;
1251 }
1252
1253 /* MODSEC_BUILD */
1254
1255 static int var_modsec_build_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1256     apr_table_t *vartab, apr_pool_t *mptmp)
1257 {
1258     return var_simple_generate(var, vartab, mptmp, modsec_build(mptmp));
1259 }
1260
1261 /* MULTIPART_BOUNDARY_QUOTED */
1262
1263 static int var_multipart_boundary_quoted_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1264     apr_table_t *vartab, apr_pool_t *mptmp)
1265 {
1266     if ((msr->mpd != NULL)&&(msr->mpd->flag_boundary_quoted != 0)) {
1267         return var_simple_generate(var, vartab, mptmp, "1");
1268     } else {
1269         return var_simple_generate(var, vartab, mptmp, "0");
1270     }
1271 }
1272
1273 /* MULTIPART_BOUNDARY_WHITESPACE */
1274
1275 static int var_multipart_boundary_whitespace_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1276     apr_table_t *vartab, apr_pool_t *mptmp)
1277 {
1278     if ((msr->mpd != NULL)&&(msr->mpd->flag_boundary_whitespace != 0)) {
1279         return var_simple_generate(var, vartab, mptmp, "1");
1280     } else {
1281         return var_simple_generate(var, vartab, mptmp, "0");
1282     }
1283 }
1284
1285 /* MULTIPART_DATA_AFTER */
1286
1287 static int var_multipart_data_after_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1288     apr_table_t *vartab, apr_pool_t *mptmp)
1289 {
1290     if ((msr->mpd != NULL)&&(msr->mpd->flag_data_after != 0)) {
1291         return var_simple_generate(var, vartab, mptmp, "1");
1292     } else {
1293         return var_simple_generate(var, vartab, mptmp, "0");
1294     }
1295 }
1296
1297 /* MULTIPART_DATA_BEFORE */
1298
1299 static int var_multipart_data_before_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1300     apr_table_t *vartab, apr_pool_t *mptmp)
1301 {
1302     if ((msr->mpd != NULL)&&(msr->mpd->flag_data_before != 0)) {
1303         return var_simple_generate(var, vartab, mptmp, "1");
1304     } else {
1305         return var_simple_generate(var, vartab, mptmp, "0");
1306     }
1307 }
1308
1309 /* MULTIPART_HEADER_FOLDING */
1310
1311 static int var_multipart_header_folding_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1312     apr_table_t *vartab, apr_pool_t *mptmp)
1313 {
1314     if ((msr->mpd != NULL)&&(msr->mpd->flag_header_folding != 0)) {
1315         return var_simple_generate(var, vartab, mptmp, "1");
1316     } else {
1317         return var_simple_generate(var, vartab, mptmp, "0");
1318     }
1319 }
1320
1321 /* MULTIPART_CRLF_LINE */
1322
1323 static int var_multipart_crlf_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1324     apr_table_t *vartab, apr_pool_t *mptmp)
1325 {
1326     if ((msr->mpd != NULL)&&(msr->mpd->flag_crlf_line != 0)) {
1327         return var_simple_generate(var, vartab, mptmp, "1");
1328     } else {
1329         return var_simple_generate(var, vartab, mptmp, "0");
1330     }
1331 }
1332
1333 /* MULTIPART_CRLF_LF_LINES */
1334
1335 static int var_multipart_crlf_lf_lines_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1336     apr_table_t *vartab, apr_pool_t *mptmp)
1337 {
1338     if ((msr->mpd != NULL)&&(msr->mpd->flag_lf_line != 0)&&(msr->mpd->flag_crlf_line != 0)) {
1339         return var_simple_generate(var, vartab, mptmp, "1");
1340     } else {
1341         return var_simple_generate(var, vartab, mptmp, "0");
1342     }
1343 }
1344
1345 /* MULTIPART_LF_LINE */
1346
1347 static int var_multipart_lf_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1348     apr_table_t *vartab, apr_pool_t *mptmp)
1349 {
1350     if ((msr->mpd != NULL)&&(msr->mpd->flag_lf_line != 0)) {
1351         return var_simple_generate(var, vartab, mptmp, "1");
1352     } else {
1353         return var_simple_generate(var, vartab, mptmp, "0");
1354     }
1355 }
1356
1357 /* MULTIPART_MISSING_SEMICOLON */
1358
1359 static int var_multipart_missing_semicolon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1360     apr_table_t *vartab, apr_pool_t *mptmp)
1361 {
1362     if ((msr->mpd != NULL)&&(msr->mpd->flag_missing_semicolon != 0)) {
1363         return var_simple_generate(var, vartab, mptmp, "1");
1364     } else {
1365         return var_simple_generate(var, vartab, mptmp, "0");
1366     }
1367 }
1368
1369 /* MULTIPART_INVALID_QUOTING */
1370
1371 static int var_multipart_invalid_quoting_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1372     apr_table_t *vartab, apr_pool_t *mptmp)
1373 {
1374     if ((msr->mpd != NULL)&&(msr->mpd->flag_invalid_quoting != 0)) {
1375         return var_simple_generate(var, vartab, mptmp, "1");
1376     } else {
1377         return var_simple_generate(var, vartab, mptmp, "0");
1378     }
1379 }
1380
1381 /* MULTIPART_STRICT_ERROR */
1382
1383 static int var_multipart_strict_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1384     apr_table_t *vartab, apr_pool_t *mptmp)
1385 {
1386     if (msr->mpd != NULL) {
1387         /* Respond positive if at least one of the multipart flags is raised. */
1388         if (  (msr->mpd->flag_error)
1389             ||(msr->mpd->flag_boundary_quoted != 0)
1390             ||(msr->mpd->flag_boundary_whitespace != 0)
1391             ||(msr->mpd->flag_data_before != 0)
1392             ||(msr->mpd->flag_data_after != 0)
1393             ||(msr->mpd->flag_header_folding != 0)
1394             ||(msr->mpd->flag_lf_line != 0)
1395             ||(msr->mpd->flag_missing_semicolon != 0)
1396             ||(msr->mpd->flag_invalid_quoting != 0)
1397         ) {
1398             return var_simple_generate(var, vartab, mptmp, "1");
1399         }
1400     }
1401
1402     return var_simple_generate(var, vartab, mptmp, "0");
1403 }
1404
1405 /* MULTIPART_UNMATCHED_BOUNDARY */
1406
1407 static int var_multipart_unmatched_boundary_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1408     apr_table_t *vartab, apr_pool_t *mptmp)
1409 {
1410     if ((msr->mpd != NULL)&&(msr->mpd->flag_unmatched_boundary != 0)) {
1411         return var_simple_generate(var, vartab, mptmp, "1");
1412     } else {
1413         return var_simple_generate(var, vartab, mptmp, "0");
1414     }
1415 }
1416
1417 /* TIME */
1418
1419 static int var_time_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1420     apr_table_t *vartab, apr_pool_t *mptmp)
1421 {
1422     msre_var *rvar = NULL;
1423     struct tm *tm;
1424     time_t tc;
1425
1426     tc = time(NULL);
1427     tm = localtime(&tc);
1428     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1429     rvar->value = apr_psprintf(mptmp, "%02d%02d%02d%02d%02d%02d%02d",
1430         (tm->tm_year / 100) + 19, (tm->tm_year % 100),
1431          tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1432          tm->tm_sec);
1433     rvar->value_len = strlen(rvar->value);
1434     apr_table_addn(vartab, rvar->name, (void *)rvar);
1435
1436     return 1;
1437 }
1438
1439 /* TIME_YEAR */
1440
1441 static int var_time_year_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1442     apr_table_t *vartab, apr_pool_t *mptmp)
1443 {
1444     msre_var *rvar = NULL;
1445     struct tm *tm;
1446     time_t tc;
1447
1448     tc = time(NULL);
1449     tm = localtime(&tc);
1450     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1451     rvar->value = apr_psprintf(mptmp, "%02d%02d",
1452         (tm->tm_year / 100) + 19,
1453          tm->tm_year % 100);
1454     rvar->value_len = strlen(rvar->value);
1455     apr_table_addn(vartab, rvar->name, (void *)rvar);
1456
1457     return 1;
1458 }
1459
1460 /* TIME_WDAY */
1461
1462 static int var_time_wday_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1463     apr_table_t *vartab, apr_pool_t *mptmp)
1464 {
1465     msre_var *rvar = NULL;
1466     struct tm *tm;
1467     time_t tc;
1468
1469     tc = time(NULL);
1470     tm = localtime(&tc);
1471     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1472     rvar->value = apr_psprintf(mptmp, "%d", tm->tm_wday);
1473     rvar->value_len = strlen(rvar->value);
1474     apr_table_addn(vartab, rvar->name, (void *)rvar);
1475
1476     return 1;
1477 }
1478
1479 /* TIME_SEC */
1480
1481 static int var_time_sec_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1482     apr_table_t *vartab, apr_pool_t *mptmp)
1483 {
1484     msre_var *rvar = NULL;
1485     struct tm *tm;
1486     time_t tc;
1487
1488     tc = time(NULL);
1489     tm = localtime(&tc);
1490     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1491     rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_sec);
1492     rvar->value_len = strlen(rvar->value);
1493     apr_table_addn(vartab, rvar->name, (void *)rvar);
1494
1495     return 1;
1496 }
1497
1498 /* TIME_MIN */
1499
1500 static int var_time_min_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1501     apr_table_t *vartab, apr_pool_t *mptmp)
1502 {
1503     msre_var *rvar = NULL;
1504     struct tm *tm;
1505     time_t tc;
1506
1507     tc = time(NULL);
1508     tm = localtime(&tc);
1509     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1510     rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_min);
1511     rvar->value_len = strlen(rvar->value);
1512     apr_table_addn(vartab, rvar->name, (void *)rvar);
1513
1514     return 1;
1515 }
1516
1517 /* TIME_HOUR */
1518 static int var_time_hour_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1519     apr_table_t *vartab, apr_pool_t *mptmp)
1520 {
1521     msre_var *rvar = NULL;
1522     struct tm *tm;
1523     time_t tc;
1524
1525     tc = time(NULL);
1526     tm = localtime(&tc);
1527     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1528     rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_hour);
1529     rvar->value_len = strlen(rvar->value);
1530     apr_table_addn(vartab, rvar->name, (void *)rvar);
1531
1532     return 1;
1533 }
1534
1535 /* TIME_MON */
1536
1537 static int var_time_mon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1538     apr_table_t *vartab, apr_pool_t *mptmp)
1539 {
1540     msre_var *rvar = NULL;
1541     struct tm *tm;
1542     time_t tc;
1543
1544     tc = time(NULL);
1545     tm = localtime(&tc);
1546     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1547     rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_mon + 1);
1548     rvar->value_len = strlen(rvar->value);
1549     apr_table_addn(vartab, rvar->name, (void *)rvar);
1550
1551     return 1;
1552 }
1553
1554 /* TIME_DAY */
1555
1556 static int var_time_day_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1557     apr_table_t *vartab, apr_pool_t *mptmp)
1558 {
1559     msre_var *rvar = NULL;
1560     struct tm *tm;
1561     time_t tc;
1562
1563     tc = time(NULL);
1564     tm = localtime(&tc);
1565     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1566     rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_mday);
1567     rvar->value_len = strlen(rvar->value);
1568     apr_table_addn(vartab, rvar->name, (void *)rvar);
1569
1570     return 1;
1571 }
1572
1573 /* TIME_EPOCH */
1574
1575 static int var_time_epoch_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1576     apr_table_t *vartab, apr_pool_t *mptmp)
1577 {
1578     msre_var *rvar = NULL;
1579     struct tm *tm;
1580     time_t tc;
1581
1582     tc = time(NULL);
1583     tm = localtime(&tc);
1584     rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1585     rvar->value = apr_psprintf(mptmp, "%ld", (long)tc);
1586     rvar->value_len = strlen(rvar->value);
1587     apr_table_addn(vartab, rvar->name, (void *)rvar);
1588
1589     return 1;
1590 }
1591
1592 /* QUERY_STRING */
1593
1594 static int var_query_string_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1595     apr_table_t *vartab, apr_pool_t *mptmp)
1596 {
1597     return var_simple_generate(var, vartab, mptmp, msr->query_string);
1598 }
1599
1600 /* REQUEST_BASENAME */
1601
1602 static int var_request_basename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1603     apr_table_t *vartab, apr_pool_t *mptmp)
1604 {
1605     char *value = file_basename(mptmp, msr->r->parsed_uri.path);
1606     return var_simple_generate(var, vartab, mptmp, value);
1607 }
1608
1609 /* REQUEST_BODY */
1610
1611 static int var_request_body_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1612     apr_table_t *vartab, apr_pool_t *mptmp)
1613 {
1614     if (msr->msc_reqbody_buffer != NULL) {
1615         return var_simple_generate_ex(var, vartab, mptmp,
1616             msr->msc_reqbody_buffer, msr->msc_reqbody_length);
1617     }
1618     return 0;
1619 }
1620
1621 /* REQUEST_COOKIES */
1622
1623 static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1624     apr_table_t *vartab, apr_pool_t *mptmp)
1625 {
1626     const apr_array_header_t *arr = NULL;
1627     const apr_table_entry_t *te = NULL;
1628     int i, count = 0;
1629
1630     arr = apr_table_elts(msr->request_cookies);
1631     te = (apr_table_entry_t *)arr->elts;
1632     for (i = 0; i < arr->nelts; i++) {
1633         int match = 0;
1634
1635         /* Figure out if we want to include this variable. */
1636         if (var->param == NULL) match = 1;
1637         else {
1638             if (var->param_data != NULL) { /* Regex. */
1639                 char *my_error_msg = NULL;
1640                 if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key,
1641                     strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
1642             } else { /* Simple comparison. */
1643                 if (strcasecmp(te[i].key, var->param) == 0) match = 1;
1644             }
1645         }
1646
1647         /* If we had a match add this argument to the collection. */
1648         if (match) {
1649             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1650
1651             rvar->value = te[i].val;
1652             rvar->value_len = strlen(rvar->value);
1653             rvar->name = apr_psprintf(mptmp, "REQUEST_COOKIES:%s",
1654                 log_escape_nq(mptmp, te[i].key));
1655             apr_table_addn(vartab, rvar->name, (void *)rvar);
1656
1657             count++;
1658         }
1659     }
1660
1661     return count;
1662 }
1663
1664 /* REQUEST_COOKIES_NAMES */
1665
1666 static int var_request_cookies_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1667     apr_table_t *vartab, apr_pool_t *mptmp)
1668 {
1669     const apr_array_header_t *arr = NULL;
1670     const apr_table_entry_t *te = NULL;
1671     int i, count = 0;
1672
1673     arr = apr_table_elts(msr->request_cookies);
1674     te = (apr_table_entry_t *)arr->elts;
1675     for (i = 0; i < arr->nelts; i++) {
1676         int match = 0;
1677
1678         /* Figure out if we want to include this variable. */
1679         if (var->param == NULL) match = 1;
1680         else {
1681             if (var->param_data != NULL) { /* Regex. */
1682                 char *my_error_msg = NULL;
1683                 if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key,
1684                     strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
1685             } else { /* Simple comparison. */
1686                 if (strcasecmp(te[i].key, var->param) == 0) match = 1;
1687             }
1688         }
1689
1690         /* If we had a match add this argument to the collection. */
1691         if (match) {
1692             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1693
1694             rvar->value = te[i].key;
1695             rvar->value_len = strlen(rvar->value);
1696             rvar->name = apr_psprintf(mptmp, "REQUEST_COOKIES_NAMES:%s",
1697                 log_escape_nq(mptmp, te[i].key));
1698             apr_table_addn(vartab, rvar->name, (void *)rvar);
1699
1700             count++;
1701         }
1702     }
1703
1704     return count;
1705 }
1706
1707 /* REQUEST_HEADERS */
1708
1709 static int var_request_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1710     apr_table_t *vartab, apr_pool_t *mptmp)
1711 {
1712     const apr_array_header_t *arr = NULL;
1713     const apr_table_entry_t *te = NULL;
1714     int i, count = 0;
1715
1716     arr = apr_table_elts(msr->request_headers);
1717     te = (apr_table_entry_t *)arr->elts;
1718     for (i = 0; i < arr->nelts; i++) {
1719         int match = 0;
1720
1721         /* Figure out if we want to include this variable. */
1722         if (var->param == NULL) match = 1;
1723         else {
1724             if (var->param_data != NULL) { /* Regex. */
1725                 char *my_error_msg = NULL;
1726                 if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key,
1727                     strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
1728             } else { /* Simple comparison. */
1729                 if (strcasecmp(te[i].key, var->param) == 0) match = 1;
1730             }
1731         }
1732
1733         /* If we had a match add this argument to the collection. */
1734         if (match) {
1735             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1736
1737             rvar->value = te[i].val;
1738             rvar->value_len = strlen(rvar->value);
1739             rvar->name = apr_psprintf(mptmp, "REQUEST_HEADERS:%s",
1740                 log_escape_nq(mptmp, te[i].key));
1741             apr_table_addn(vartab, rvar->name, (void *)rvar);
1742
1743             count++;
1744         }
1745     }
1746
1747     return count;
1748 }
1749
1750 /* REQUEST_HEADERS_NAMES */
1751
1752 static int var_request_headers_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1753     apr_table_t *vartab, apr_pool_t *mptmp)
1754 {
1755     const apr_array_header_t *arr = NULL;
1756     const apr_table_entry_t *te = NULL;
1757     int i, count = 0;
1758
1759     arr = apr_table_elts(msr->request_headers);
1760     te = (apr_table_entry_t *)arr->elts;
1761     for (i = 0; i < arr->nelts; i++) {
1762         int match = 0;
1763
1764         /* Figure out if we want to include this variable. */
1765         if (var->param == NULL) match = 1;
1766         else {
1767             if (var->param_data != NULL) { /* Regex. */
1768                 char *my_error_msg = NULL;
1769                 if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key,
1770                     strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
1771             } else { /* Simple comparison. */
1772                 if (strcasecmp(te[i].key, var->param) == 0) match = 1;
1773             }
1774         }
1775
1776         /* If we had a match add this argument to the collection. */
1777         if (match) {
1778             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1779
1780             rvar->value = te[i].key;
1781             rvar->value_len = strlen(rvar->value);
1782             rvar->name = apr_psprintf(mptmp, "REQUEST_HEADERS_NAMES:%s",
1783                 log_escape_nq(mptmp, te[i].key));
1784             apr_table_addn(vartab, rvar->name, (void *)rvar);
1785
1786             count++;
1787         }
1788     }
1789
1790     return count;
1791 }
1792
1793 /* REQUEST_FILENAME */
1794
1795 static int var_request_filename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1796     apr_table_t *vartab, apr_pool_t *mptmp)
1797 {
1798     return var_simple_generate(var, vartab, mptmp, msr->r->parsed_uri.path);
1799 }
1800
1801 /* REQUEST_LINE */
1802
1803 static int var_request_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1804     apr_table_t *vartab, apr_pool_t *mptmp)
1805 {
1806     return var_simple_generate(var, vartab, mptmp, msr->request_line);
1807 }
1808
1809 /* REQUEST_METHOD */
1810
1811 static int var_request_method_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1812     apr_table_t *vartab, apr_pool_t *mptmp)
1813 {
1814     return var_simple_generate(var, vartab, mptmp, msr->request_method);
1815 }
1816
1817 /* REQUEST_PROTOCOL */
1818
1819 static int var_request_protocol_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1820     apr_table_t *vartab, apr_pool_t *mptmp)
1821 {
1822     return var_simple_generate(var, vartab, mptmp, msr->request_protocol);
1823 }
1824
1825 /* SERVER_ADDR */
1826
1827 static int var_server_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1828     apr_table_t *vartab, apr_pool_t *mptmp)
1829 {
1830     return var_simple_generate(var, vartab, mptmp, msr->local_addr);
1831 }
1832
1833 /* SERVER_NAME */
1834
1835 static int var_server_name_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1836     apr_table_t *vartab, apr_pool_t *mptmp)
1837 {
1838     return var_simple_generate(var, vartab, mptmp, msr->hostname);
1839 }
1840
1841 /* SERVER_PORT */
1842
1843 static int var_server_port_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1844     apr_table_t *vartab, apr_pool_t *mptmp)
1845 {
1846     char *value = apr_psprintf(mptmp, "%u", msr->local_port);
1847     return var_simple_generate(var, vartab, mptmp, value);
1848 }
1849
1850 /* SCRIPT_BASENAME */
1851
1852 static int var_script_basename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1853     apr_table_t *vartab, apr_pool_t *mptmp)
1854 {
1855     char *value = file_basename(mptmp, msr->r->filename);
1856     return var_simple_generate(var, vartab, mptmp, value);
1857 }
1858
1859 /* SCRIPT_FILENAME */
1860
1861 static int var_script_filename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1862     apr_table_t *vartab, apr_pool_t *mptmp)
1863 {
1864     char *value = msr->r->filename;
1865     return var_simple_generate(var, vartab, mptmp, value);
1866 }
1867
1868 /* SCRIPT_GID */
1869
1870 static int var_script_gid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1871     apr_table_t *vartab, apr_pool_t *mptmp)
1872 {
1873     char *value = apr_psprintf(mptmp, "%ld", (long)msr->r->finfo.group);
1874     return var_simple_generate(var, vartab, mptmp, value);
1875 }
1876
1877 /* SCRIPT_GROUPNAME */
1878
1879 static int var_script_groupname_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1880     apr_table_t *vartab, apr_pool_t *mptmp)
1881 {
1882     char *value = NULL;
1883     if (apr_gid_name_get(&value, msr->r->finfo.group, mptmp) == APR_SUCCESS) {
1884         return var_simple_generate(var, vartab, mptmp, value);
1885     }
1886     return 0;
1887 }
1888
1889 /* SCRIPT_MODE */
1890
1891 static int var_script_mode_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1892     apr_table_t *vartab, apr_pool_t *mptmp)
1893 {
1894     char *value = apr_psprintf(mptmp, "%04x", msr->r->finfo.protection);
1895     return var_simple_generate(var, vartab, mptmp, value);
1896 }
1897
1898 /* SCRIPT_UID */
1899
1900 static int var_script_uid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1901     apr_table_t *vartab, apr_pool_t *mptmp)
1902 {
1903     char *value = apr_psprintf(mptmp, "%ld", (long)msr->r->finfo.user);
1904     return var_simple_generate(var, vartab, mptmp, value);
1905 }
1906
1907 /* SCRIPT_USERNAME */
1908
1909 static int var_script_username_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1910     apr_table_t *vartab, apr_pool_t *mptmp)
1911 {
1912     char *value = NULL;
1913     if (apr_uid_name_get(&value, msr->r->finfo.user, mptmp) == APR_SUCCESS) {
1914         return var_simple_generate(var, vartab, mptmp, value);
1915     }
1916     return 0;
1917 }
1918
1919 /* AUTH_TYPE */
1920
1921 static int var_auth_type_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1922     apr_table_t *vartab, apr_pool_t *mptmp)
1923 {
1924     char *value = msr->r->ap_auth_type;
1925     return var_simple_generate(var, vartab, mptmp, value);
1926 }
1927
1928 /* PATH_INFO */
1929
1930 static int var_path_info_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1931     apr_table_t *vartab, apr_pool_t *mptmp)
1932 {
1933     const char *value = msr->r->path_info;
1934     return var_simple_generate(var, vartab, mptmp, value);
1935 }
1936
1937 /* RESPONSE_BODY */
1938
1939 static int var_response_body_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1940     apr_table_t *vartab, apr_pool_t *mptmp)
1941 {
1942     if (msr->resbody_data != NULL) {
1943         return var_simple_generate_ex(var, vartab, mptmp,
1944             msr->resbody_data, msr->resbody_length);
1945     }
1946
1947     return 0;
1948 }
1949
1950 /* RESPONSE_HEADERS */
1951
1952 static int var_response_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1953     apr_table_t *vartab, apr_pool_t *mptmp)
1954 {
1955     const apr_array_header_t *arr = NULL;
1956     const apr_table_entry_t *te = NULL;
1957     int i, count = 0;
1958
1959     if (msr->response_headers == NULL) return 0;
1960
1961     arr = apr_table_elts(msr->response_headers);
1962     te = (apr_table_entry_t *)arr->elts;
1963     for (i = 0; i < arr->nelts; i++) {
1964         int match = 0;
1965
1966         /* Figure out if we want to include this variable. */
1967         if (var->param == NULL) match = 1;
1968         else {
1969             if (var->param_data != NULL) { /* Regex. */
1970                 char *my_error_msg = NULL;
1971                 if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key,
1972                     strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
1973             } else { /* Simple comparison. */
1974                 if (strcasecmp(te[i].key, var->param) == 0) match = 1;
1975             }
1976         }
1977
1978         /* If we had a match add this argument to the collection. */
1979         if (match) {
1980             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
1981
1982             rvar->value = te[i].val;
1983             rvar->value_len = strlen(rvar->value);
1984             rvar->name = apr_psprintf(mptmp, "RESPONSE_HEADERS:%s",
1985                 log_escape_nq(mptmp, te[i].key));
1986             apr_table_addn(vartab, rvar->name, (void *)rvar);
1987
1988             count++;
1989         }
1990     }
1991
1992     return count;
1993 }
1994
1995 /* RESPONSE_HEADERS_NAMES */
1996
1997 static int var_response_headers_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
1998     apr_table_t *vartab, apr_pool_t *mptmp)
1999 {
2000     const apr_array_header_t *arr = NULL;
2001     const apr_table_entry_t *te = NULL;
2002     int i, count = 0;
2003
2004     arr = apr_table_elts(msr->response_headers);
2005     te = (apr_table_entry_t *)arr->elts;
2006     for (i = 0; i < arr->nelts; i++) {
2007         int match = 0;
2008
2009         /* Figure out if we want to include this variable. */
2010         if (var->param == NULL) match = 1;
2011         else {
2012             if (var->param_data != NULL) { /* Regex. */
2013                 char *my_error_msg = NULL;
2014                 if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key,
2015                     strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
2016             } else { /* Simple comparison. */
2017                 if (strcasecmp(te[i].key, var->param) == 0) match = 1;
2018             }
2019         }
2020
2021         /* If we had a match add this argument to the collection. */
2022         if (match) {
2023             msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
2024
2025             rvar->value = te[i].key;
2026             rvar->value_len = strlen(rvar->value);
2027             rvar->name = apr_psprintf(mptmp, "RESPONSE_HEADERS_NAMES:%s",
2028                 log_escape_nq(mptmp, te[i].key));
2029             apr_table_addn(vartab, rvar->name, (void *)rvar);
2030
2031             count++;
2032         }
2033     }
2034
2035     return count;
2036 }
2037
2038 /* STATUS_LINE */
2039
2040 static int var_status_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
2041     apr_table_t *vartab, apr_pool_t *mptmp)
2042 {
2043     const char *value = msr->status_line;
2044     return var_simple_generate(var, vartab, mptmp, value);
2045 }
2046
2047 /* RESPONSE_PROTOCOL */
2048
2049 static int var_response_protocol_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
2050     apr_table_t *vartab, apr_pool_t *mptmp)
2051 {
2052     const char *value = msr->response_protocol;
2053     return var_simple_generate(var, vartab, mptmp, value);
2054 }
2055
2056 /* RESPONSE_STATUS */
2057
2058 static int var_response_status_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
2059     apr_table_t *vartab, apr_pool_t *mptmp)
2060 {
2061     const char *value = apr_psprintf(mptmp, "%u", msr->response_status);
2062     return var_simple_generate(var, vartab, mptmp, value);
2063 }
2064
2065 /* RESPONSE_CONTENT_TYPE */
2066
2067 static int var_response_content_type(modsec_rec *msr, msre_var *var, msre_rule *rule,
2068     apr_table_t *vartab, apr_pool_t *mptmp)
2069 {
2070     return var_simple_generate(var, vartab, mptmp, msr->r->content_type);
2071 }
2072
2073 /* RESPONSE_CONTENT_LENGTH */
2074
2075 static int var_response_content_length(modsec_rec *msr, msre_var *var, msre_rule *rule,
2076     apr_table_t *vartab, apr_pool_t *mptmp)
2077 {
2078     const char *value = apr_psprintf(mptmp, "%" APR_OFF_T_FMT, msr->r->clength);
2079     return var_simple_generate(var, vartab, mptmp, value);
2080 }
2081
2082 /* USERID */
2083
2084 static int var_userid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
2085     apr_table_t *vartab, apr_pool_t *mptmp)
2086 {
2087     const char *value = msr->userid;
2088     return var_simple_generate(var, vartab, mptmp, value);
2089 }
2090
2091 /* SESSIONID */
2092
2093 static int var_sessionid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
2094     apr_table_t *vartab, apr_pool_t *mptmp)
2095 {
2096     const char *value = msr->sessionid;
2097     return var_simple_generate(var, vartab, mptmp, value);
2098 }
2099
2100 /* WEBAPPID */
2101
2102 static int var_webappid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
2103     apr_table_t *vartab, apr_pool_t *mptmp)
2104 {
2105     const char *value = msr->txcfg->webappid;
2106     return var_simple_generate(var, vartab, mptmp, value);
2107 }
2108
2109 /* ---------------------------------------------- */
2110
2111 /**
2112  *
2113  */
2114 void msre_engine_variable_register(msre_engine *engine, const char *name,
2115     unsigned int type, unsigned int argc_min, unsigned int argc_max,
2116     fn_var_validate_t validate, fn_var_generate_t generate,
2117     unsigned int is_cacheable, unsigned int availability)
2118 {
2119     msre_var_metadata *metadata = (msre_var_metadata *)apr_pcalloc(engine->mp,
2120         sizeof(msre_var_metadata));
2121     if (metadata == NULL) return;
2122
2123     metadata->name = name;
2124     metadata->type = type;
2125     metadata->argc_min = argc_min;
2126     metadata->argc_max = argc_max;
2127     metadata->validate = validate;
2128     metadata->generate = generate;
2129     metadata->is_cacheable = is_cacheable;
2130     metadata->availability = availability;
2131
2132     apr_table_setn(engine->variables, name, (void *)metadata);
2133 }
2134
2135 /**
2136  *
2137  */
2138 void msre_engine_register_default_variables(msre_engine *engine) {
2139
2140     /* ARGS */
2141     msre_engine_variable_register(engine,
2142         "ARGS",
2143         VAR_LIST,
2144         0, 1,
2145         var_generic_list_validate,
2146         var_args_generate,
2147         VAR_CACHE,
2148         PHASE_REQUEST_HEADERS
2149     );
2150
2151     /* ARGS_COMBINED_SIZE */
2152     msre_engine_variable_register(engine,
2153         "ARGS_COMBINED_SIZE",
2154         VAR_LIST,
2155         0, 0,
2156         NULL,
2157         var_args_combined_size_generate,
2158         VAR_DONT_CACHE, /* dynamic */
2159         PHASE_REQUEST_HEADERS
2160     );
2161
2162     /* ARGS_GET */
2163     msre_engine_variable_register(engine,
2164         "ARGS_GET",
2165         VAR_LIST,
2166         0, 1,
2167         var_generic_list_validate,
2168         var_args_get_generate,
2169         VAR_CACHE,
2170         PHASE_REQUEST_HEADERS
2171     );
2172
2173     /* ARGS_GET_NAMES */
2174     msre_engine_variable_register(engine,
2175         "ARGS_GET_NAMES",
2176         VAR_LIST,
2177         0, 1,
2178         var_generic_list_validate,
2179         var_args_get_names_generate,
2180         VAR_CACHE,
2181         PHASE_REQUEST_HEADERS
2182     );
2183
2184     /* ARGS_NAMES */
2185     msre_engine_variable_register(engine,
2186         "ARGS_NAMES",
2187         VAR_LIST,
2188         0, 1,
2189         var_generic_list_validate,
2190         var_args_names_generate,
2191         VAR_CACHE,
2192         PHASE_REQUEST_HEADERS
2193     );
2194
2195     /* ARGS_POST */
2196     msre_engine_variable_register(engine,
2197         "ARGS_POST",
2198         VAR_LIST,
2199         0, 1,
2200         var_generic_list_validate,
2201         var_args_post_generate,
2202         VAR_CACHE,
2203         PHASE_REQUEST_BODY
2204     );
2205
2206     /* ARGS_POST_NAMES */
2207     msre_engine_variable_register(engine,
2208         "ARGS_POST_NAMES",
2209         VAR_LIST,
2210         0, 1,
2211         var_generic_list_validate,
2212         var_args_post_names_generate,
2213         VAR_CACHE,
2214         PHASE_REQUEST_BODY
2215     );
2216
2217     /* AUTH_TYPE */
2218     msre_engine_variable_register(engine,
2219         "AUTH_TYPE",
2220         VAR_SIMPLE,
2221         0, 0,
2222         NULL,
2223         var_auth_type_generate,
2224         VAR_CACHE,
2225         PHASE_REQUEST_BODY
2226     );
2227
2228     /* ENV */
2229     msre_engine_variable_register(engine,
2230         "ENV",
2231         VAR_LIST,
2232         0, 1,
2233         var_env_validate,
2234         var_env_generate,
2235         VAR_DONT_CACHE,
2236         PHASE_REQUEST_HEADERS
2237     );
2238
2239     /* FILES */
2240     msre_engine_variable_register(engine,
2241         "FILES",
2242         VAR_LIST,
2243         0, 1,
2244         var_generic_list_validate,
2245         var_files_generate,
2246         VAR_CACHE,
2247         PHASE_REQUEST_BODY
2248     );
2249
2250     /* FILES_COMBINED_SIZE */
2251     msre_engine_variable_register(engine,
2252         "FILES_COMBINED_SIZE",
2253         VAR_LIST,
2254         0, 0,
2255         NULL,
2256         var_files_combined_size_generate,
2257         VAR_DONT_CACHE, /* temp copy */
2258         PHASE_REQUEST_BODY
2259     );
2260
2261     /* FILES_NAMES */
2262     msre_engine_variable_register(engine,
2263         "FILES_NAMES",
2264         VAR_LIST,
2265         0, 0,
2266         NULL,
2267         var_files_names_generate,
2268         VAR_CACHE,
2269         PHASE_REQUEST_BODY
2270     );
2271
2272     /* FILES_SIZES */
2273     msre_engine_variable_register(engine,
2274         "FILES_SIZES",
2275         VAR_LIST,
2276         0, 1,
2277         var_generic_list_validate,
2278         var_files_sizes_generate,
2279         VAR_DONT_CACHE, /* temp copy */
2280         PHASE_REQUEST_BODY
2281     );
2282
2283     /* FILES_TMPNAMES */
2284     msre_engine_variable_register(engine,
2285         "FILES_TMPNAMES",
2286         VAR_LIST,
2287         0, 1,
2288         var_generic_list_validate,
2289         var_files_tmpnames_generate,
2290         VAR_CACHE,
2291         PHASE_REQUEST_BODY
2292     );
2293
2294     /* GEO */
2295     msre_engine_variable_register(engine,
2296         "GEO",
2297         VAR_LIST,
2298         0, 1,
2299         var_generic_list_validate,
2300         var_geo_generate,
2301         VAR_DONT_CACHE, /* dynamic */
2302         PHASE_REQUEST_HEADERS
2303     );
2304
2305     /* GLOBAL */
2306     msre_engine_variable_register(engine,
2307         "GLOBAL",
2308         VAR_LIST,
2309         1, 1,
2310         var_generic_list_validate,
2311         var_global_generate,
2312         VAR_DONT_CACHE, /* dynamic */
2313         PHASE_REQUEST_HEADERS
2314     );
2315
2316     /* HIGHEST_SEVERITY */
2317     msre_engine_variable_register(engine,
2318         "HIGHEST_SEVERITY",
2319         VAR_SIMPLE,
2320         0, 0,
2321         NULL,
2322         var_highest_severity_generate,
2323         VAR_DONT_CACHE, /* dynamic */
2324         PHASE_REQUEST_HEADERS
2325     );
2326
2327     /* IP */
2328     msre_engine_variable_register(engine,
2329         "IP",
2330         VAR_LIST,
2331         1, 1,
2332         var_generic_list_validate,
2333         var_ip_generate,
2334         VAR_DONT_CACHE, /* dynamic */
2335         PHASE_REQUEST_HEADERS
2336     );
2337
2338     /* MATCHED_VAR */
2339     msre_engine_variable_register(engine,
2340         "MATCHED_VAR",
2341         VAR_SIMPLE,
2342         0, 0,
2343         NULL,
2344         var_matched_var_generate,
2345         VAR_DONT_CACHE, /* dynamic */
2346         PHASE_REQUEST_HEADERS
2347     );
2348
2349     /* MATCHED_VAR_NAME */
2350     msre_engine_variable_register(engine,
2351         "MATCHED_VAR_NAME",
2352         VAR_SIMPLE,
2353         0, 0,
2354         NULL,
2355         var_matched_var_name_generate,
2356         VAR_DONT_CACHE, /* dynamic */
2357         PHASE_REQUEST_HEADERS
2358     );
2359
2360     /* MODSEC_BUILD */
2361     msre_engine_variable_register(engine,
2362         "MODSEC_BUILD",
2363         VAR_SIMPLE,
2364         0, 0,
2365         NULL,
2366         var_modsec_build_generate,
2367         VAR_CACHE,
2368         PHASE_REQUEST_HEADERS
2369     );
2370
2371     /* MULTIPART_BOUNDARY_QUOTED */
2372     msre_engine_variable_register(engine,
2373         "MULTIPART_BOUNDARY_QUOTED",
2374         VAR_SIMPLE,
2375         0, 0,
2376         NULL,
2377         var_multipart_boundary_quoted_generate,
2378         VAR_DONT_CACHE, /* flag */
2379         PHASE_REQUEST_BODY
2380     );
2381
2382     /* MULTIPART_BOUNDARY_WHITESPACE */
2383     msre_engine_variable_register(engine,
2384         "MULTIPART_BOUNDARY_WHITESPACE",
2385         VAR_SIMPLE,
2386         0, 0,
2387         NULL,
2388         var_multipart_boundary_whitespace_generate,
2389         VAR_DONT_CACHE, /* flag */
2390         PHASE_REQUEST_BODY
2391     );
2392
2393     /* MULTIPART_DATA_AFTER */
2394     msre_engine_variable_register(engine,
2395         "MULTIPART_DATA_AFTER",
2396         VAR_SIMPLE,
2397         0, 0,
2398         NULL,
2399         var_multipart_data_after_generate,
2400         VAR_DONT_CACHE, /* flag */
2401         PHASE_REQUEST_BODY
2402     );
2403
2404     /* MULTIPART_DATA_BEFORE */
2405     msre_engine_variable_register(engine,
2406         "MULTIPART_DATA_BEFORE",
2407         VAR_SIMPLE,
2408         0, 0,
2409         NULL,
2410         var_multipart_data_before_generate,
2411         VAR_DONT_CACHE, /* flag */
2412         PHASE_REQUEST_BODY
2413     );
2414
2415     /* MULTIPART_HEADER_FOLDING */
2416     msre_engine_variable_register(engine,
2417         "MULTIPART_HEADER_FOLDING",
2418         VAR_SIMPLE,
2419         0, 0,
2420         NULL,
2421         var_multipart_header_folding_generate,
2422         VAR_DONT_CACHE, /* flag */
2423         PHASE_REQUEST_BODY
2424     );
2425
2426     /* MULTIPART_CRLF_LINE */
2427     msre_engine_variable_register(engine,
2428         "MULTIPART_CRLF_LINE",
2429         VAR_SIMPLE,
2430         0, 0,
2431         NULL,
2432         var_multipart_crlf_line_generate,
2433         VAR_DONT_CACHE, /* flag */
2434         PHASE_REQUEST_BODY
2435     );
2436
2437     /* MULTIPART_CRLF_LF_LINES */
2438     msre_engine_variable_register(engine,
2439         "MULTIPART_CRLF_LF_LINES",
2440         VAR_SIMPLE,
2441         0, 0,
2442         NULL,
2443         var_multipart_crlf_lf_lines_generate,
2444         VAR_DONT_CACHE, /* flag */
2445         PHASE_REQUEST_BODY
2446     );
2447
2448     /* MULTIPART_LF_LINE */
2449     msre_engine_variable_register(engine,
2450         "MULTIPART_LF_LINE",
2451         VAR_SIMPLE,
2452         0, 0,
2453         NULL,
2454         var_multipart_lf_line_generate,
2455         VAR_DONT_CACHE, /* flag */
2456         PHASE_REQUEST_BODY
2457     );
2458
2459     /* MULTIPART_MISSING_SEMICOLON */
2460     msre_engine_variable_register(engine,
2461         "MULTIPART_MISSING_SEMICOLON",
2462         VAR_SIMPLE,
2463         0, 0,
2464         NULL,
2465         var_multipart_missing_semicolon_generate,
2466         VAR_DONT_CACHE, /* flag */
2467         PHASE_REQUEST_BODY
2468     );
2469
2470     /* MULTIPART_INVALID_QUOTING */
2471     msre_engine_variable_register(engine,
2472         "MULTIPART_INVALID_QUOTING",
2473         VAR_SIMPLE,
2474         0, 0,
2475         NULL,
2476         var_multipart_invalid_quoting_generate,
2477         VAR_DONT_CACHE, /* flag */
2478         PHASE_REQUEST_BODY
2479     );
2480
2481     /* MULTIPART_STRICT_ERROR */
2482     msre_engine_variable_register(engine,
2483         "MULTIPART_STRICT_ERROR",
2484         VAR_SIMPLE,
2485         0, 0,
2486         NULL,
2487         var_multipart_strict_error_generate,
2488         VAR_DONT_CACHE, /* flag */
2489         PHASE_REQUEST_BODY
2490     );
2491
2492     /* MULTIPART_UNMATCHED_BOUNDARY */
2493     msre_engine_variable_register(engine,
2494         "MULTIPART_UNMATCHED_BOUNDARY",
2495         VAR_SIMPLE,
2496         0, 0,
2497         NULL,
2498         var_multipart_unmatched_boundary_generate,
2499         VAR_DONT_CACHE, /* flag */
2500         PHASE_REQUEST_BODY
2501     );
2502
2503     /* PATH_INFO */
2504     msre_engine_variable_register(engine,
2505         "PATH_INFO",
2506         VAR_SIMPLE,
2507         0, 0,
2508         NULL,
2509         var_path_info_generate,
2510         VAR_CACHE,
2511         PHASE_REQUEST_BODY
2512     );
2513
2514     /* QUERY_STRING */
2515     msre_engine_variable_register(engine,
2516         "QUERY_STRING",
2517         VAR_SIMPLE,
2518         0, 0,
2519         NULL,
2520         var_query_string_generate,
2521         VAR_CACHE,
2522         PHASE_REQUEST_HEADERS
2523     );
2524
2525     /* REMOTE_ADDR */
2526     msre_engine_variable_register(engine,
2527         "REMOTE_ADDR",
2528         VAR_SIMPLE,
2529         0, 0,
2530         NULL,
2531         var_remote_addr_generate,
2532         VAR_CACHE,
2533         PHASE_REQUEST_HEADERS
2534     );
2535
2536     /* REMOTE_HOST */
2537     msre_engine_variable_register(engine,
2538         "REMOTE_HOST",
2539         VAR_SIMPLE,
2540         0, 0,
2541         NULL,
2542         var_remote_host_generate,
2543         VAR_CACHE,
2544         PHASE_REQUEST_BODY
2545     );
2546
2547     /* REMOTE_PORT */
2548     msre_engine_variable_register(engine,
2549         "REMOTE_PORT",
2550         VAR_SIMPLE,
2551         0, 0,
2552         NULL,
2553         var_remote_port_generate,
2554         VAR_DONT_CACHE, /* temp copy */
2555         PHASE_REQUEST_BODY
2556     );
2557
2558     /* REMOTE_USER */
2559     msre_engine_variable_register(engine,
2560         "REMOTE_USER",
2561         VAR_SIMPLE,
2562         0, 0,
2563         NULL,
2564         var_remote_user_generate,
2565         VAR_CACHE,
2566         PHASE_REQUEST_BODY
2567     );
2568
2569     /* RESOURCE */
2570     msre_engine_variable_register(engine,
2571         "RESOURCE",
2572         VAR_LIST,
2573         1, 1,
2574         var_generic_list_validate,
2575         var_resource_generate,
2576         VAR_DONT_CACHE, /* dynamic */
2577         PHASE_REQUEST_HEADERS
2578     );
2579
2580     /* REQBODY_PROCESSOR */
2581     msre_engine_variable_register(engine,
2582         "REQBODY_PROCESSOR",
2583         VAR_SIMPLE,
2584         0, 0,
2585         NULL,
2586         var_reqbody_processor_generate,
2587         VAR_DONT_CACHE, /* temp copy */
2588         PHASE_REQUEST_HEADERS
2589     );
2590
2591     /* REQBODY_PROCESSOR_ERROR */
2592     msre_engine_variable_register(engine,
2593         "REQBODY_PROCESSOR_ERROR",
2594         VAR_SIMPLE,
2595         0, 0,
2596         NULL,
2597         var_reqbody_processor_error_generate,
2598         VAR_DONT_CACHE, /* dynamic */
2599         PHASE_REQUEST_BODY
2600     );
2601
2602     /* REQBODY_PROCESSOR_ERROR_MSG */
2603     msre_engine_variable_register(engine,
2604         "REQBODY_PROCESSOR_ERROR_MSG",
2605         VAR_SIMPLE,
2606         0, 0,
2607         NULL,
2608         var_reqbody_processor_error_msg_generate,
2609         VAR_DONT_CACHE, /* dynamic */
2610         PHASE_REQUEST_BODY
2611     );
2612
2613     /* REQUEST_BASENAME */
2614     msre_engine_variable_register(engine,
2615         "REQUEST_BASENAME",
2616         VAR_SIMPLE,
2617         0, 0,
2618         NULL,
2619         var_request_basename_generate,
2620         VAR_DONT_CACHE, /* temp copy */
2621         PHASE_REQUEST_HEADERS
2622     );
2623
2624     /* REQUEST_BODY */
2625     msre_engine_variable_register(engine,
2626         "REQUEST_BODY",
2627         VAR_SIMPLE,
2628         0, 0,
2629         NULL,
2630         var_request_body_generate,
2631         VAR_CACHE,
2632         PHASE_REQUEST_BODY
2633     );
2634
2635     /* REQUEST_COOKIES */
2636     msre_engine_variable_register(engine,
2637         "REQUEST_COOKIES",
2638         VAR_LIST,
2639         0, 1,
2640         var_generic_list_validate,
2641         var_request_cookies_generate,
2642         VAR_CACHE,
2643         PHASE_REQUEST_HEADERS
2644     );
2645
2646     /* REQUEST_COOKIES_NAMES */
2647     msre_engine_variable_register(engine,
2648         "REQUEST_COOKIES_NAMES",
2649         VAR_LIST,
2650         0, 1,
2651         var_generic_list_validate,
2652         var_request_cookies_names_generate,
2653         VAR_CACHE,
2654         PHASE_REQUEST_HEADERS
2655     );
2656
2657     /* REQUEST_FILENAME */
2658     msre_engine_variable_register(engine,
2659         "REQUEST_FILENAME",
2660         VAR_SIMPLE,
2661         0, 0,
2662         NULL,
2663         var_request_filename_generate,
2664         VAR_CACHE,
2665         PHASE_REQUEST_HEADERS
2666     );
2667
2668     /* REQUEST_HEADERS */
2669     msre_engine_variable_register(engine,
2670         "REQUEST_HEADERS",
2671         VAR_LIST,
2672         0, 1,
2673         var_generic_list_validate,
2674         var_request_headers_generate,
2675         VAR_CACHE,
2676         PHASE_REQUEST_HEADERS
2677     );
2678
2679     /* REQUEST_HEADERS_NAMES */
2680     msre_engine_variable_register(engine,
2681         "REQUEST_HEADERS_NAMES",
2682         VAR_LIST,
2683         0, 1,
2684         var_generic_list_validate,
2685         var_request_headers_names_generate,
2686         VAR_CACHE,
2687         PHASE_REQUEST_HEADERS
2688     );
2689
2690     /* REQUEST_LINE */
2691     msre_engine_variable_register(engine,
2692         "REQUEST_LINE",
2693         VAR_SIMPLE,
2694         0, 0,
2695         NULL,
2696         var_request_line_generate,
2697         VAR_CACHE,
2698         PHASE_REQUEST_HEADERS
2699     );
2700
2701     /* REQUEST_METHOD */
2702     msre_engine_variable_register(engine,
2703         "REQUEST_METHOD",
2704         VAR_SIMPLE,
2705         0, 0,
2706         NULL,
2707         var_request_method_generate,
2708         VAR_CACHE,
2709         PHASE_REQUEST_HEADERS
2710     );
2711
2712     /* REQUEST_PROTOCOL */
2713     msre_engine_variable_register(engine,
2714         "REQUEST_PROTOCOL",
2715         VAR_SIMPLE,
2716         0, 0,
2717         NULL,
2718         var_request_protocol_generate,
2719         VAR_CACHE,
2720         PHASE_REQUEST_HEADERS
2721     );
2722
2723     /* REQUEST_URI */
2724     msre_engine_variable_register(engine,
2725         "REQUEST_URI",
2726         VAR_SIMPLE,
2727         0, 0,
2728         NULL,
2729         var_request_uri_generate,
2730         VAR_DONT_CACHE, /* temp copy */
2731         PHASE_REQUEST_HEADERS
2732     );
2733
2734     /* REQUEST_URI_RAW */
2735     msre_engine_variable_register(engine,
2736         "REQUEST_URI_RAW",
2737         VAR_SIMPLE,
2738         0, 0,
2739         NULL,
2740         var_request_uri_raw_generate,
2741         VAR_CACHE,
2742         PHASE_REQUEST_HEADERS
2743     );
2744
2745     /* RESPONSE_BODY */
2746     msre_engine_variable_register(engine,
2747         "RESPONSE_BODY",
2748         VAR_SIMPLE,
2749         0, 0,
2750         NULL,
2751         var_response_body_generate,
2752         VAR_CACHE,
2753         PHASE_RESPONSE_BODY
2754     );
2755
2756     /* RESPONSE_CONTENT_LENGTH */
2757     msre_engine_variable_register(engine,
2758         "RESPONSE_CONTENT_LENGTH",
2759         VAR_SIMPLE,
2760         0, 0,
2761         NULL,
2762         var_response_content_length,
2763         VAR_DONT_CACHE, /* temp copy */
2764         PHASE_RESPONSE_HEADERS
2765     );
2766
2767     /* RESPONSE_CONTENT_TYPE */
2768     msre_engine_variable_register(engine,
2769         "RESPONSE_CONTENT_TYPE",
2770         VAR_SIMPLE,
2771         0, 0,
2772         NULL,
2773         var_response_content_type,
2774         VAR_CACHE,
2775         PHASE_RESPONSE_HEADERS
2776     );
2777
2778     /* RESPONSE_HEADERS */
2779     msre_engine_variable_register(engine,
2780         "RESPONSE_HEADERS",
2781         VAR_LIST,
2782         0, 1,
2783         var_generic_list_validate,
2784         var_response_headers_generate,
2785         VAR_CACHE,
2786         PHASE_RESPONSE_HEADERS
2787     );
2788
2789     /* RESPONSE_HEADERS_NAMES */
2790     msre_engine_variable_register(engine,
2791         "RESPONSE_HEADERS_NAMES",
2792         VAR_LIST,
2793         0, 1,
2794         var_generic_list_validate,
2795         var_response_headers_names_generate,
2796         VAR_CACHE,
2797         PHASE_RESPONSE_HEADERS
2798     );
2799
2800     /* RESPONSE_PROTOCOL */
2801     msre_engine_variable_register(engine,
2802         "RESPONSE_PROTOCOL",
2803         VAR_SIMPLE,
2804         0, 0,
2805         NULL,
2806         var_response_protocol_generate,
2807         VAR_CACHE,
2808         PHASE_RESPONSE_HEADERS
2809     );
2810
2811     /* RESPONSE_STATUS */
2812     msre_engine_variable_register(engine,
2813         "RESPONSE_STATUS",
2814         VAR_SIMPLE,
2815         0, 0,
2816         NULL,
2817         var_response_status_generate,
2818         VAR_DONT_CACHE, /* temp copy */
2819         PHASE_RESPONSE_HEADERS
2820     );
2821
2822     /* RULE */
2823     msre_engine_variable_register(engine,
2824         "RULE",
2825         VAR_LIST,
2826         1, 1,
2827         NULL,
2828         var_rule_generate,
2829         VAR_DONT_CACHE, /* dynamic */
2830         PHASE_RESPONSE_HEADERS
2831     );
2832
2833     /* SCRIPT_GID */
2834     msre_engine_variable_register(engine,
2835         "SCRIPT_GID",
2836         VAR_SIMPLE,
2837         0, 0,
2838         NULL,
2839         var_script_gid_generate,
2840         VAR_DONT_CACHE, /* temp copy */
2841         PHASE_REQUEST_BODY
2842     );
2843
2844     /* SCRIPT_BASENAME */
2845     msre_engine_variable_register(engine,
2846         "SCRIPT_BASENAME",
2847         VAR_SIMPLE,
2848         0, 0,
2849         NULL,
2850         var_script_basename_generate,
2851         VAR_DONT_CACHE, /* temp copy */
2852         PHASE_REQUEST_BODY
2853     );
2854
2855     /* SCRIPT_FILENAME */
2856     msre_engine_variable_register(engine,
2857         "SCRIPT_FILENAME",
2858         VAR_SIMPLE,
2859         0, 0,
2860         NULL,
2861         var_script_filename_generate,
2862         VAR_CACHE,
2863         PHASE_REQUEST_BODY
2864     );
2865
2866     /* SCRIPT_GROUPNAME */
2867     msre_engine_variable_register(engine,
2868         "SCRIPT_GROUPNAME",
2869         VAR_SIMPLE,
2870         0, 0,
2871         NULL,
2872         var_script_groupname_generate,
2873         VAR_DONT_CACHE, /* temp copy */
2874         PHASE_REQUEST_BODY
2875     );
2876
2877     /* SCRIPT_MODE */
2878     msre_engine_variable_register(engine,
2879         "SCRIPT_MODE",
2880         VAR_SIMPLE,
2881         0, 0,
2882         NULL,
2883         var_script_mode_generate,
2884         VAR_DONT_CACHE, /* temp copy */
2885         PHASE_REQUEST_BODY
2886     );
2887
2888     /* SCRIPT_UID */
2889     msre_engine_variable_register(engine,
2890         "SCRIPT_UID",
2891         VAR_SIMPLE,
2892         0, 0,
2893         NULL,
2894         var_script_uid_generate,
2895         VAR_DONT_CACHE, /* temp copy */
2896         PHASE_REQUEST_BODY
2897     );
2898
2899     /* SCRIPT_USERNAME */
2900     msre_engine_variable_register(engine,
2901         "SCRIPT_USERNAME",
2902         VAR_SIMPLE,
2903         0, 0,
2904         NULL,
2905         var_script_username_generate,
2906         VAR_DONT_CACHE, /* temp copy */
2907         PHASE_REQUEST_BODY
2908     );
2909
2910     /* SERVER_ADDR */
2911     msre_engine_variable_register(engine,
2912         "SERVER_ADDR",
2913         VAR_SIMPLE,
2914         0, 0,
2915         NULL,
2916         var_server_addr_generate,
2917         VAR_CACHE,
2918         PHASE_REQUEST_HEADERS
2919     );
2920
2921     /* SERVER_NAME */
2922     msre_engine_variable_register(engine,
2923         "SERVER_NAME",
2924         VAR_SIMPLE,
2925         0, 0,
2926         NULL,
2927         var_server_name_generate,
2928         VAR_CACHE,
2929         PHASE_REQUEST_HEADERS
2930     );
2931
2932     /* SERVER_PORT */
2933     msre_engine_variable_register(engine,
2934         "SERVER_PORT",
2935         VAR_SIMPLE,
2936         0, 0,
2937         NULL,
2938         var_server_port_generate,
2939         VAR_DONT_CACHE, /* temp copy */
2940         PHASE_REQUEST_HEADERS
2941     );
2942
2943     /* SESSION */
2944     msre_engine_variable_register(engine,
2945         "SESSION",
2946         VAR_LIST,
2947         1, 1,
2948         var_generic_list_validate,
2949         var_session_generate,
2950         VAR_DONT_CACHE, /* dynamic */
2951         PHASE_REQUEST_HEADERS
2952     );
2953
2954     /* SESSIONID */
2955     msre_engine_variable_register(engine,
2956         "SESSIONID",
2957         VAR_SIMPLE,
2958         0, 0,
2959         NULL,
2960         var_sessionid_generate,
2961         VAR_DONT_CACHE, /* dynamic */
2962         PHASE_RESPONSE_HEADERS
2963     );
2964
2965     /* STATUS_LINE */
2966     msre_engine_variable_register(engine,
2967         "STATUS_LINE",
2968         VAR_SIMPLE,
2969         0, 0,
2970         NULL,
2971         var_status_line_generate,
2972         VAR_CACHE,
2973         PHASE_RESPONSE_HEADERS
2974     );
2975
2976     /* USER */
2977     msre_engine_variable_register(engine,
2978         "USER",
2979         VAR_LIST,
2980         1, 1,
2981         var_generic_list_validate,
2982         var_user_generate,
2983         VAR_DONT_CACHE, /* dynamic */
2984         PHASE_REQUEST_HEADERS
2985     );
2986
2987     /* USERID */
2988     msre_engine_variable_register(engine,
2989         "USERID",
2990         VAR_SIMPLE,
2991         0, 0,
2992         NULL,
2993         var_userid_generate,
2994         VAR_DONT_CACHE, /* dynamic */
2995         PHASE_RESPONSE_HEADERS
2996     );
2997
2998     /* TIME */
2999     msre_engine_variable_register(engine,
3000         "TIME",
3001         VAR_SIMPLE,
3002         0, 0,
3003         NULL,
3004         var_time_generate,
3005         VAR_DONT_CACHE, /* dynamic */
3006         PHASE_REQUEST_HEADERS
3007     );
3008
3009     /* TIME_DAY */
3010     msre_engine_variable_register(engine,
3011         "TIME_DAY",
3012         VAR_SIMPLE,
3013         0, 0,
3014         NULL,
3015         var_time_day_generate,
3016         VAR_DONT_CACHE, /* dynamic */
3017         PHASE_REQUEST_HEADERS
3018     );
3019
3020     /* TIME_EPOCH */
3021     msre_engine_variable_register(engine,
3022         "TIME_EPOCH",
3023         VAR_SIMPLE,
3024         0, 0,
3025         NULL,
3026         var_time_epoch_generate,
3027         VAR_DONT_CACHE, /* dynamic */
3028         PHASE_REQUEST_HEADERS
3029     );
3030
3031     /* TIME_HOUR */
3032     msre_engine_variable_register(engine,
3033         "TIME_HOUR",
3034         VAR_SIMPLE,
3035         0, 0,
3036         NULL,
3037         var_time_hour_generate,
3038         VAR_DONT_CACHE, /* dynamic */
3039         PHASE_REQUEST_HEADERS
3040     );
3041
3042     /* TIME_MIN */
3043     msre_engine_variable_register(engine,
3044         "TIME_MIN",
3045         VAR_SIMPLE,
3046         0, 0,
3047         NULL,
3048         var_time_min_generate,
3049         VAR_DONT_CACHE, /* dynamic */
3050         PHASE_REQUEST_HEADERS
3051     );
3052
3053     /* TIME_MON */
3054     msre_engine_variable_register(engine,
3055         "TIME_MON",
3056         VAR_SIMPLE,
3057         0, 0,
3058         NULL,
3059         var_time_mon_generate,
3060         VAR_DONT_CACHE, /* dynamic */
3061         PHASE_REQUEST_HEADERS
3062     );
3063
3064     /* TIME_SEC */
3065     msre_engine_variable_register(engine,
3066         "TIME_SEC",
3067         VAR_SIMPLE,
3068         0, 0,
3069         NULL,
3070         var_time_sec_generate,
3071         VAR_DONT_CACHE, /* dynamic */
3072         PHASE_REQUEST_HEADERS
3073     );
3074
3075     /* TIME_WDAY */
3076     msre_engine_variable_register(engine,
3077         "TIME_WDAY",
3078         VAR_SIMPLE,
3079         0, 0,
3080         NULL,
3081         var_time_wday_generate,
3082         VAR_DONT_CACHE, /* dynamic */
3083         PHASE_REQUEST_HEADERS
3084     );
3085
3086     /* TIME_YEAR */
3087     msre_engine_variable_register(engine,
3088         "TIME_YEAR",
3089         VAR_SIMPLE,
3090         0, 0,
3091         NULL,
3092         var_time_year_generate,
3093         VAR_DONT_CACHE, /* dynamic */
3094         PHASE_REQUEST_HEADERS
3095     );
3096
3097     /* TX */
3098     msre_engine_variable_register(engine,
3099         "TX",
3100         VAR_LIST,
3101         1, 1,
3102         var_generic_list_validate,
3103         var_tx_generate,
3104         VAR_DONT_CACHE, /* dynamic */
3105         PHASE_REQUEST_HEADERS
3106     );
3107
3108     /* WEBAPPID */
3109     msre_engine_variable_register(engine,
3110         "WEBAPPID",
3111         VAR_SIMPLE,
3112         0, 0,
3113         NULL,
3114         var_webappid_generate,
3115         VAR_DONT_CACHE,
3116         PHASE_RESPONSE_HEADERS
3117     );
3118
3119     /* WEBSERVER_ERROR_LOG */
3120     msre_engine_variable_register(engine,
3121         "WEBSERVER_ERROR_LOG",
3122         VAR_LIST,
3123         0, 0,
3124         NULL,
3125         var_webserver_error_log_generate,
3126         VAR_DONT_CACHE, /* dynamic */
3127         PHASE_REQUEST_HEADERS
3128     );
3129
3130     /* XML */
3131     msre_engine_variable_register(engine,
3132         "XML",
3133         VAR_LIST,
3134         0, 1,
3135         var_xml_validate,
3136         var_xml_generate,
3137         VAR_DONT_CACHE, /* dynamic */
3138         PHASE_REQUEST_BODY
3139     );
3140 }