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