Imported Upstream version 2.5.11
[libapache-mod-security.git] / apache2 / msc_parsers.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 "msc_parsers.h"
20 #include <ctype.h>
21
22 /**
23  *
24  */
25 int parse_cookies_v0(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies) {
26     char *attr_name = NULL, *attr_value = NULL;
27     char *cookie_header;
28     char *saveptr = NULL;
29     int cookie_count = 0;
30     char *p = NULL;
31
32     if (_cookie_header == NULL) {
33         msr_log(msr, 1, "Cookie parser: Received null for argument.");
34         return -1;
35     }
36
37     cookie_header = strdup(_cookie_header);
38     if (cookie_header == NULL) return -1;
39
40     p = apr_strtok(cookie_header, ";", &saveptr);
41     while(p != NULL) {
42         attr_name = NULL;
43         attr_value = NULL;
44
45         /* ignore whitespace at the beginning of cookie name */
46         while(isspace(*p)) p++;
47         attr_name = p;
48
49         attr_value = strstr(p, "=");
50         if (attr_value != NULL) {
51             /* terminate cookie name */
52             *attr_value = 0;
53             /* move over to the beginning of the value */
54             attr_value++;
55         }
56
57         /* we ignore cookies with empty names */
58         if ((attr_name != NULL)&&(strlen(attr_name) != 0)) {
59             if (attr_value != NULL) {
60                 if (msr->txcfg->debuglog_level >= 5) {
61                     msr_log(msr, 5, "Adding request cookie: name \"%s\", value \"%s\"",
62                         log_escape(msr->mp, attr_name), log_escape(msr->mp, attr_value));
63                 }
64
65                 apr_table_add(cookies, attr_name, attr_value);
66             } else {
67                 if (msr->txcfg->debuglog_level >= 5) {
68                     msr_log(msr, 5, "Adding request cookie: name \"%s\", value empty",
69                         log_escape(msr->mp, attr_name));
70                 }
71
72                 apr_table_add(cookies, attr_name, "");
73             }
74
75             cookie_count++;
76         }
77
78         p = apr_strtok(NULL, ";", &saveptr);
79     }
80
81     free(cookie_header);
82     return cookie_count;
83 }
84
85 /**
86  *
87  */
88 int parse_cookies_v1(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies) {
89     char *attr_name = NULL, *attr_value = NULL, *p = NULL;
90     char *prev_attr_name = NULL;
91     char *cookie_header = NULL;
92     int cookie_count = 0;
93
94     if (_cookie_header == NULL) return -1;
95     cookie_header = strdup(_cookie_header);
96     if (cookie_header == NULL) return -1;
97
98     p = cookie_header;
99     while(*p != 0) {
100         attr_name = NULL;
101         attr_value = NULL;
102
103         /* attribute name */
104
105         /* remove space from the beginning */
106         while((isspace(*p))&&(*p != 0)) p++;
107         attr_name = p;
108         while((*p != 0)&&(*p != '=')&&(*p != ';')&&(*p != ',')) p++;
109
110         /* if we've reached the end of string */
111         if (*p == 0) goto add_cookie;
112
113         /* if there is no cookie value supplied */
114         if ((*p == ';')||(*p == ',')) {
115             *p++ = 0; /* terminate the name */
116             goto add_cookie;
117         }
118
119         /* terminate the attribute name,
120          * writing over the = character
121          */
122         *p++ = 0;
123
124         /* attribute value */
125
126         /* skip over the whitespace at the beginning */
127         while((isspace(*p))&&(*p != 0)) p++;
128
129         /* no value supplied */
130         if (*p == 0) goto add_cookie;
131
132         if (*p == '"') {
133             if (*++p == 0) goto add_cookie;
134             attr_value = p;
135             while((*p != 0)&&(*p != '"')) p++;
136             if (*p != 0) *p++ = 0;
137             else {
138                 /* Do nothing about this. */
139             }
140         } else {
141             attr_value = p;
142             while((*p != 0)&&(*p != ',')&&(*p != ';')) p++;
143             if (*p != 0) *p++ = 0;
144
145             /* remove the whitespace from the end of cookie value */
146             if (attr_value != NULL) {
147                 char *t = attr_value;
148                 int i = 0;
149
150                 while(*t != 0) {
151                     t++;
152                     i++;
153                 }
154
155                 while((i-- > 0)&&(isspace(*(--t)))) *t = 0;
156             }
157         }
158
159     add_cookie:
160
161         /* remove the whitespace from the end of cookie name */
162         if (attr_name != NULL) {
163             char *t = attr_name;
164             int i = 0;
165
166             while(*t != 0) {
167                 t++;
168                 i++;
169             }
170
171             while((i-- > 0)&&(isspace(*(--t)))) *t = 0;
172         }
173
174         /* add the cookie to the list now */
175         if ((attr_name != NULL)&&(strlen(attr_name) != 0)) {
176
177             /* handle special attribute names */
178             if (attr_name[0] == '$') {
179                 if (prev_attr_name != NULL) {
180                     /* cookie keyword, we change the name we use
181                      * so they can have a unique name in the cookie table
182                      */
183                     attr_name = apr_psprintf(msr->mp, "$%s_%s", prev_attr_name, attr_name + 1);
184                 }
185             }
186
187             if (attr_value != NULL) {
188                 if (msr->txcfg->debuglog_level >= 5) {
189                     msr_log(msr, 5, "Adding request cookie: name \"%s\", value \"%s\"",
190                         log_escape(msr->mp, attr_name), log_escape(msr->mp, attr_value));
191                 }
192
193                 apr_table_add(cookies, attr_name, attr_value);
194             } else {
195                 if (msr->txcfg->debuglog_level >= 5) {
196                     msr_log(msr, 5, "Adding request cookie: name \"%s\", value empty",
197                         log_escape(msr->mp, attr_name));
198                 }
199
200                 apr_table_add(cookies, attr_name, "");
201             }
202
203             cookie_count++;
204
205             /* only keep the cookie names for later */
206             if (attr_name[0] != '$') prev_attr_name = attr_name;
207         }
208
209         /* at this point the *p is either 0 (in which case we exit), or
210          * right after the current cookie ended - we need to look for
211          * the next cookie
212          */
213         while( (*p != 0)&&( (*p == ',')||(*p == ';')||(isspace(*p)) ) ) p++;
214     }
215
216     return cookie_count;
217 }
218
219 /**
220  *
221  */
222 int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength,
223     int argument_separator, const char *origin,
224     apr_table_t *arguments, int *invalid_count)
225 {
226     msc_arg *arg;
227     apr_size_t i, j;
228     char *value = NULL;
229     char *buf;
230     int status;
231     int changed;
232
233     if (s == NULL) return -1;
234     if (inputlength == 0) return 1;
235
236     /* Check that adding one will not overflow */
237     if (inputlength + 1 <= 0) return -1;
238
239     buf = (char *)malloc(inputlength + 1);
240     if (buf == NULL) return -1;
241
242     arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg));
243     arg->origin = origin;
244
245     i = 0;
246     j = 0;
247     status = 0;
248     *invalid_count = 0;
249     while (i < inputlength) {
250         if (status == 0) {
251             /* parameter name */
252             arg->name_origin_offset = i;
253             while ((s[i] != '=') && (s[i] != argument_separator) && (i < inputlength)) {
254                 buf[j] = s[i];
255                 j++;
256                 i++;
257             }
258             buf[j++] = '\0';
259             arg->name_origin_len = i - arg->name_origin_offset;
260         } else {
261             /* parameter value */
262             arg->value_origin_offset = i;
263             while ((s[i] != argument_separator) && (i < inputlength)) {
264                 buf[j] = s[i];
265                 j++;
266                 i++;
267             }
268             buf[j++] = '\0';
269             arg->value_origin_len = i - arg->value_origin_offset;
270         }
271
272         if (status == 0) {
273             arg->name_len = urldecode_nonstrict_inplace_ex((unsigned char *)buf, arg->name_origin_len, invalid_count, &changed);
274             arg->name = apr_pstrmemdup(msr->mp, buf, arg->name_len);
275
276             if (s[i] == argument_separator) {
277                 /* Empty parameter */
278                 arg->value_len = 0;
279                 arg->value = "";
280
281                 add_argument(msr, arguments, arg);
282
283                 arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg));
284                 arg->origin = origin;
285
286                 status = 0; /* unchanged */
287                 j = 0;
288             } else {
289                 status = 1;
290                 value = &buf[j];
291             }
292         }
293         else {
294             arg->value_len = urldecode_nonstrict_inplace_ex((unsigned char *)value, arg->value_origin_len, invalid_count, &changed);
295             arg->value = apr_pstrmemdup(msr->mp, value, arg->value_len);
296
297             add_argument(msr, arguments, arg);
298
299             arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg));
300             arg->origin = origin;
301
302             status = 0;
303             j = 0;
304         }
305
306         i++; /* skip over the separator */
307     }
308
309     /* the last parameter was empty */
310     if (status == 1) {
311         arg->value_len = 0;
312         arg->value = "";
313
314         add_argument(msr, arguments, arg);
315     }
316
317     free(buf);
318
319     return 1;
320 }
321
322 /**
323  *
324  */
325 void add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg) {
326     if (msr->txcfg->debuglog_level >= 5) {
327         msr_log(msr, 5, "Adding request argument (%s): name \"%s\", value \"%s\"",
328             arg->origin, log_escape_ex(msr->mp, arg->name, arg->name_len),
329             log_escape_ex(msr->mp, arg->value, arg->value_len));
330     }
331
332     apr_table_addn(arguments, log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *)arg);
333 }
334