Imported Upstream version 2.5.11
[libapache-mod-security.git] / apache2 / api / mod_op_strstr.c
1
2 #include "httpd.h"
3 #include "http_core.h"
4 #include "http_config.h"
5 #include "http_log.h"
6 #include "http_protocol.h"
7 #include "ap_config.h"
8 #include "apr_optional.h"
9
10 #include "modsecurity.h"
11
12 #define ALPHABET_SIZE       256
13 #define MAX_PATTERN_SIZE    64
14
15 static void initBoyerMooreHorspool(const char *pattern, int patlength,
16     int *bm_badcharacter_array);
17
18 static int BoyerMooreHorspool(const char *pattern, int patlength,
19     const char *text, int textlen, int *bm_badcharacter_array);
20
21 /**
22  * Operator parameter initialisation entry point.
23  */
24 static int op_strstr_init(msre_rule *rule, char **error_msg) {
25     /* Operator initialisation function will be called once per
26      * statement where operator is used. It is meant to be used
27      * to check the parameters to see whether they are present
28      * and if they are in the correct format.
29      */
30
31     /* In this example we just look for a simple non-empty parameter. */
32     if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) {
33         *error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'strstr'.");
34         return 0; /* ERROR */
35     }
36
37     /* If you need to transform the data in the parameter into something
38      * else you should do that here. Simply create a new structure to hold
39      * the transformed data and place the pointer to it into rule->op_param_data.
40      * You will have access to this pointer later on.
41      */
42     rule->op_param_data = apr_pcalloc(rule->ruleset->mp, ALPHABET_SIZE * sizeof(int));
43     initBoyerMooreHorspool(rule->op_param, strlen(rule->op_param), (int *)rule->op_param_data);
44
45     /* OK */
46     return 1;
47 }
48
49 /**
50  * Operator execution entry point.
51  */
52 static int op_strstr_exec(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
53     /* Here we need to inspect the contents of the supplied variable. */
54
55     /* In a general case it is possible for the value
56      * to be NULL. What you need to do in this case
57      * depends on your operator. In this example we return
58      * a "no match" response.
59      */
60     if (var->value == NULL) return 0; /* No match. */
61
62     /* Another thing to note is that variables are not C strings,
63      * meaning the NULL byte is not used to determine the end
64      * of the string. Variable length var->value_len should be
65      * used for this purpose.
66      */
67
68     if (BoyerMooreHorspool(rule->op_param, strlen(rule->op_param),
69         var->value, var->value_len, (int *)rule->op_param_data) >= 0)
70     {
71         return 1; /* Match. */
72     }
73     
74     return 0; /* No match. */
75 }
76
77 static int hook_pre_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_temp) {
78     void (*fn)(const char *name, void *fn_init, void *fn_exec);
79
80     /* Look for the registration function
81      * exported by ModSecurity.
82      */
83     fn = APR_RETRIEVE_OPTIONAL_FN(modsec_register_operator);
84     if (fn) {
85         /* Use it to register our new
86          * transformation function under the
87          * name "reverse".
88          */
89         fn("strstr", (void *)op_strstr_init, (void *)op_strstr_exec);
90     }
91
92     return OK;
93 }
94
95 static void register_hooks(apr_pool_t *p) {
96     ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_LAST);
97 }
98
99 /* Dispatch list for API hooks */
100 module AP_MODULE_DECLARE_DATA op_strstr_module = {
101     STANDARD20_MODULE_STUFF, 
102     NULL,                  /* create per-dir    config structures */
103     NULL,                  /* merge  per-dir    config structures */
104     NULL,                  /* create per-server config structures */
105     NULL,                  /* merge  per-server config structures */
106     NULL,                  /* table of config file commands       */
107     register_hooks         /* register hooks                      */
108 };
109
110 /*
111
112 This example uses an implementation Boyer-Moore-Horspool
113 matching algorithm as implemented in Streamline (http://ffpf.sourceforge.net).
114
115 Copyright (c) 2004-2006, Vrije Universiteit Amsterdam
116 All rights reserved.
117
118 Redistribution and use in source and binary forms, with or without modification, 
119 are permitted provided that the following conditions are met:
120
121 Redistributions of source code must retain the above copyright notice, 
122 this list of conditions and the following disclaimer.
123
124 Redistributions in binary form must reproduce the above copyright notice, 
125 this list of conditions and the following disclaimer in the documentation 
126 and/or other materials provided with the distribution.
127
128 Neither the name of the Vrije Universiteit nor the names of its contributors 
129 may be used to endorse or promote products derived from this software without 
130 specific prior written permission.
131
132 */
133
134 static void precompute_badcharacter(const char *pattern, int patlength,
135     int bm_badcharacter_array[])
136 {
137     int i;
138  
139     for (i = 0; i < ALPHABET_SIZE; ++i) {
140         bm_badcharacter_array[i] = patlength;
141     }
142
143     for (i = 0; i < patlength - 1; ++i){
144         bm_badcharacter_array[(uint8_t)pattern[i]] = patlength - i - 1;
145         }
146 }
147
148 static void initBoyerMooreHorspool(const char *pattern, int patlength,
149     int *bm_badcharacter_array)
150 {
151     precompute_badcharacter(pattern,
152         (patlength < MAX_PATTERN_SIZE ? patlength : MAX_PATTERN_SIZE), bm_badcharacter_array);
153 }
154
155 static int BoyerMooreHorspool(const char *pattern, int patlength,
156     const char *text, int textlen, int *bm_badcharacter_array)
157 {
158     int j;
159     char c;
160
161     j = 0;
162     while (j <= textlen - patlength) {
163         c = text[j + patlength - 1];
164         if (pattern[patlength - 1] == c && memcmp(pattern, text + j, patlength - 1) == 0) {
165             return j;
166         }
167         j += bm_badcharacter_array[(uint8_t)c];
168     }
169
170     return -1;
171 }