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 "modsecurity.h"
16 #include <ctype.h>
17 #include <fcntl.h>
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21
22 #include "msc_release.h"
23 #include "msc_util.h"
24
25 #include <apr.h>
26 #if APR_HAVE_ARPA_INET_H
27 #include <arpa/inet.h>
28 #endif
29 #include <apr_lib.h>
30 #include <apr_sha1.h>
31 #include "modsecurity_config.h"
32
33 #include "msc_remote_rules.h"
34
35 #ifdef WITH_CURL
36 #include "curl/curl.h"
37 #endif
38
39 /**
40 * NOTE: Be careful as these can ONLY be used on static values for X.
41 * (i.e. VALID_HEX(c++) will NOT work)
42 */
43 #define VALID_HEX(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F')))
44 #define ISODIGIT(X) ((X >= '0')&&(X <= '7'))
45
46 #if (defined(WIN32) || defined(NETWARE))
47 /** Windows does not define all the octal modes */
48 #define S_IXOTH 00001
49 #define S_IWOTH 00002
50 #define S_IROTH 00004
51 #define S_IXGRP 00010
52 #define S_IWGRP 00020
53 #define S_IRGRP 00040
54 #define S_IXUSR 00100
55 #define S_IWUSR 00200
56 #define S_IRUSR 00400
57 #define S_ISVTX 01000
58 #define S_ISGID 02000
59 #define S_ISUID 04000
60 #endif /* defined(WIN32 || NETWARE) */
61
62 /* Base64 tables used in decodeBase64Ext */
63 static const char b64_pad = '=';
64
65 static const short b64_reverse_t[256] = {
66 -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -2, -1, -2, -2,
67 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
68 -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63,
69 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2,
70 -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
71 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2,
72 -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
73 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
74 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
75 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
76 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
77 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
78 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
79 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
80 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
81 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
82 };
83
84 static unsigned char *c2x(unsigned what, unsigned char *where);
85 static unsigned char x2c(unsigned char *what);
86 static unsigned char xsingle2c(unsigned char *what);
87
88 #ifdef LINUX_S390
swap_int32(int x)89 int swap_int32(int x) {
90 int swap = ((x>>24)&0xff) | ((x<<8)&0xff0000) |
91 ((x>>8)&0xff00) | ((x<<24)&0xff000000);
92 return swap;
93 }
94 #endif
95
96
97 /** \brief Decode utf-8 to unicode format.
98 *
99 * \param mp Pointer to memory pool
100 * \param input Pointer to input data
101 * \param input_len Input data length
102 * \param changed Set if data is changed
103 *
104 * \retval rval On Success
105 */
utf8_unicode_inplace_ex(apr_pool_t * mp,unsigned char * input,long int input_len,int * changed)106 char *utf8_unicode_inplace_ex(apr_pool_t *mp, unsigned char *input, long int input_len, int *changed) {
107 int unicode_len = 0, length = 0;
108 unsigned int d = 0, count = 0;
109 unsigned char c, *utf;
110 char *rval, *data;
111 unsigned int i, len, j;
112 unsigned int bytes_left = input_len;
113 unsigned char *unicode = NULL;
114
115 *changed = 0;
116 /* RFC3629 states that UTF-8 are encoded using sequences of 1 to 4 octets. */
117 /* Max size per character should fit in 4 bytes */
118 len = input_len * 4 + 1;
119 data = rval = apr_palloc(mp, len);
120 if (rval == NULL) return NULL;
121
122
123 if (input == NULL) return NULL;
124
125 for(i = 0; i < bytes_left;) {
126 unicode_len = 0; d = 0;
127 utf = (unsigned char *)&input[i];
128
129 c = *utf;
130
131 /* If first byte begins with binary 0 it is single byte encoding */
132 if ((c & 0x80) == 0) {
133 /* single byte unicode (7 bit ASCII equivilent) has no validation */
134 count++;
135 if(count <= len) {
136 if(c == 0)
137 *data = x2c(&c);
138 else
139 *data++ = c;
140 }
141
142 }
143 /* If first byte begins with binary 110 it is two byte encoding*/
144 else if ((c & 0xE0) == 0xC0) {
145 /* check we have at least two bytes */
146 if (bytes_left < 2) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING;
147 /* check second byte starts with binary 10 */
148 else if (((*(utf + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
149 else {
150 unicode_len = 2;
151 count+=6;
152 if(count <= len) {
153 /* compute character number */
154 d = ((c & 0x1F) << 6) | (*(utf + 1) & 0x3F);
155 *data++ = '%';
156 *data++ = 'u';
157 unicode = apr_psprintf(mp, "%x", d);
158 length = strlen(unicode);
159
160 switch(length) {
161 case 1:
162 *data++ = '0';
163 *data++ = '0';
164 *data++ = '0';
165 break;
166 case 2:
167 *data++ = '0';
168 *data++ = '0';
169 break;
170 case 3:
171 *data++ = '0';
172 break;
173 case 4:
174 case 5:
175 break;
176 }
177
178 for(j=0; j<length; j++) {
179 *data++ = unicode[j];
180 }
181
182 *changed = 1;
183 }
184 }
185 }
186 /* If first byte begins with binary 1110 it is three byte encoding */
187 else if ((c & 0xF0) == 0xE0) {
188 /* check we have at least three bytes */
189 if (bytes_left < 3) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING;
190 /* check second byte starts with binary 10 */
191 else if (((*(utf + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
192 /* check third byte starts with binary 10 */
193 else if (((*(utf + 2)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
194 else {
195 unicode_len = 3;
196 count+=6;
197 if(count <= len) {
198 /* compute character number */
199 d = ((c & 0x0F) << 12) | ((*(utf + 1) & 0x3F) << 6) | (*(utf + 2) & 0x3F);
200 *data++ = '%';
201 *data++ = 'u';
202 unicode = apr_psprintf(mp, "%x", d);
203 length = strlen(unicode);
204
205 switch(length) {
206 case 1:
207 *data++ = '0';
208 *data++ = '0';
209 *data++ = '0';
210 break;
211 case 2:
212 *data++ = '0';
213 *data++ = '0';
214 break;
215 case 3:
216 *data++ = '0';
217 break;
218 case 4:
219 case 5:
220 break;
221 }
222
223 for(j=0; j<length; j++) {
224 *data++ = unicode[j];
225 }
226
227 *changed = 1;
228
229 }
230 }
231 }
232 /* If first byte begins with binary 11110 it is four byte encoding */
233 else if ((c & 0xF8) == 0xF0) {
234 /* restrict characters to UTF-8 range (U+0000 - U+10FFFF)*/
235 if (c >= 0xF5) {
236 *data++ = c;
237 }
238 /* check we have at least four bytes */
239 if (bytes_left < 4) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING;
240 /* check second byte starts with binary 10 */
241 else if (((*(utf + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
242 /* check third byte starts with binary 10 */
243 else if (((*(utf + 2)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
244 /* check forth byte starts with binary 10 */
245 else if (((*(utf + 3)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
246 else {
247 unicode_len = 4;
248 count+=7;
249 if(count <= len) {
250 /* compute character number */
251 d = ((c & 0x07) << 18) | ((*(utf + 1) & 0x3F) << 12) | ((*(utf + 2) & 0x3F) << 6) | (*(utf + 3) & 0x3F);
252 *data++ = '%';
253 *data++ = 'u';
254 unicode = apr_psprintf(mp, "%x", d);
255 length = strlen(unicode);
256
257 switch(length) {
258 case 1:
259 *data++ = '0';
260 *data++ = '0';
261 *data++ = '0';
262 break;
263 case 2:
264 *data++ = '0';
265 *data++ = '0';
266 break;
267 case 3:
268 *data++ = '0';
269 break;
270 case 4:
271 case 5:
272 break;
273 }
274
275 for(j=0; j<length; j++) {
276 *data++ = unicode[j];
277 }
278
279 *changed = 1;
280
281 }
282 }
283 }
284 /* any other first byte is invalid (RFC 3629) */
285 else {
286 count++;
287 if(count <= len)
288 *data++ = c;
289 }
290
291 /* invalid UTF-8 character number range (RFC 3629) */
292 if ((d >= 0xD800) && (d <= 0xDFFF)) {
293 count++;
294 if(count <= len)
295 *data++ = c;
296 }
297
298 /* check for overlong */
299 if ((unicode_len == 4) && (d < 0x010000)) {
300 /* four byte could be represented with less bytes */
301 count++;
302 if(count <= len)
303 *data++ = c;
304 }
305 else if ((unicode_len == 3) && (d < 0x0800)) {
306 /* three byte could be represented with less bytes */
307 count++;
308 if(count <= len)
309 *data++ = c;
310 }
311 else if ((unicode_len == 2) && (d < 0x80)) {
312 /* two byte could be represented with less bytes */
313 count++;
314 if(count <= len)
315 *data++ = c;
316 }
317
318 if(unicode_len > 0) {
319 i += unicode_len;
320 } else {
321 i++;
322 }
323 }
324
325 *data ='\0';
326
327 return rval;
328 }
329
330 /** \brief Validate IPv4 Netmask
331 *
332 * \param ip_strv6 Pointer to ipv6 address
333 *
334 * \retval netmask_v4 On Success
335 */
is_netmask_v4(char * ip_strv4)336 unsigned char is_netmask_v4(char *ip_strv4) {
337 unsigned char netmask_v4 = 32;
338 char *mask_str = NULL;
339 int cidr;
340
341 if(ip_strv4 == NULL)
342 return netmask_v4;
343
344 if ((mask_str = strchr(ip_strv4, '/'))) {
345 *(mask_str++) = '\0';
346
347 if (strchr(mask_str, '.') != NULL) {
348 return 0;
349 }
350
351 cidr = atoi(mask_str);
352 if ((cidr < 0) || (cidr > 32)) {
353 return 0;
354 }
355
356 netmask_v4 = (unsigned char)cidr;
357 }
358
359 return netmask_v4;
360 }
361
362 /** \brief Validate IPv6 Netmask
363 *
364 * \param ip_strv6 Pointer to ipv6 address
365 *
366 * \retval netmask_v6 On Success
367 */
is_netmask_v6(char * ip_strv6)368 unsigned char is_netmask_v6(char *ip_strv6) {
369 unsigned char netmask_v6 = 128;
370 char *mask_str = NULL;
371 int cidr;
372
373 if(ip_strv6 == NULL)
374 return netmask_v6;
375
376 if ((mask_str = strchr(ip_strv6, '/'))) {
377 *(mask_str++) = '\0';
378
379 if (strchr(mask_str, ':') != NULL) {
380 return 0;
381 }
382
383 cidr = atoi(mask_str);
384 if ((cidr < 0) || (cidr > 128)) {
385 return 0;
386 }
387 netmask_v6 = (unsigned char)cidr;
388 }
389
390 return netmask_v6;
391 }
392
393 /** \brief Interpret |HEX| syntax
394 *
395 * \param op_parm Pointer to operator input
396 * \param op_len Operator input lenght
397 * \param rule Pointer to rule struct
398 * \param error_msg Pointer to error message
399 *
400 * \retval string On Success
401 */
parse_pm_content(const char * op_parm,unsigned short int op_len,msre_rule * rule,char ** error_msg)402 char *parse_pm_content(const char *op_parm, unsigned short int op_len, msre_rule *rule, char **error_msg) {
403 char *parm = NULL;
404 char *content = NULL;
405 unsigned short int offset = 0;
406 char converted = 0;
407 int i, x;
408 unsigned char bin = 0, esc = 0, bin_offset = 0;
409 unsigned char c = 0;
410 unsigned char bin_parm[3] = { 0 };
411 char *processed = NULL;
412
413 content = apr_pstrdup(rule->ruleset->mp, op_parm);
414
415 if (content == NULL) {
416 *error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
417 return NULL;
418 }
419
420 while (offset < op_len && apr_isspace(content[offset])) {
421 offset++;
422 };
423
424 op_len = strlen(content);
425
426 if (content[offset] == '\"' && content[op_len-1] == '\"') {
427 parm = apr_pstrdup(rule->ruleset->mp, content + offset + 1);
428 if (parm == NULL) {
429 *error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
430 return NULL;
431 }
432 parm[op_len - offset - 2] = '\0';
433 } else {
434 parm = apr_pstrdup(rule->ruleset->mp, content + offset);
435 if (parm == NULL) {
436 *error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
437 return NULL;
438 }
439 }
440
441 op_len = strlen(parm);
442
443 if (op_len == 0) {
444 *error_msg = apr_psprintf(rule->ruleset->mp, "Content length is 0.");
445 return NULL;
446 }
447
448
449 for (i = 0, x = 0; i < op_len; i++) {
450 if (parm[i] == '|') {
451 if (bin) {
452 bin = 0;
453 } else {
454 bin = 1;
455 }
456 } else if(!esc && parm[i] == '\\') {
457 esc = 1;
458 } else {
459 if (bin) {
460 if (apr_isdigit(parm[i]) ||
461 parm[i] == 'A' || parm[i] == 'a' ||
462 parm[i] == 'B' || parm[i] == 'b' ||
463 parm[i] == 'C' || parm[i] == 'c' ||
464 parm[i] == 'D' || parm[i] == 'd' ||
465 parm[i] == 'E' || parm[i] == 'e' ||
466 parm[i] == 'F' || parm[i] == 'f')
467 {
468 bin_parm[bin_offset] = (char)parm[i];
469 bin_offset++;
470 if (bin_offset == 2) {
471 c = strtol((char *)bin_parm, (char **) NULL, 16) & 0xFF;
472 bin_offset = 0;
473 parm[x] = c;
474 x++;
475 converted = 1;
476 }
477 } else if (parm[i] == ' ') {
478 }
479 } else if (esc) {
480 if (parm[i] == ':' ||
481 parm[i] == ';' ||
482 parm[i] == '\\' ||
483 parm[i] == '\"')
484 {
485 parm[x] = parm[i];
486 x++;
487 } else {
488 *error_msg = apr_psprintf(rule->ruleset->mp, "Unsupported escape sequence.");
489 return NULL;
490 }
491 esc = 0;
492 converted = 1;
493 } else {
494 parm[x] = parm[i];
495 x++;
496 }
497 }
498 }
499
500 if (converted) {
501 op_len = x;
502 }
503
504 processed = apr_pstrmemdup(rule->ruleset->mp, parm, op_len);
505
506 if (processed == NULL) {
507 *error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
508 return NULL;
509 }
510
511 return processed;
512 }
513
514
515 /** \brief Remove quotes
516 *
517 * \param mptmp Pointer to the pool
518 * \param input Pointer to input string
519 * \param input_len Input data length
520 *
521 * \retval string On Success
522 */
remove_quotes(apr_pool_t * mptmp,const char * input,int input_len)523 char *remove_quotes(apr_pool_t *mptmp, const char *input, int input_len) {
524 char *parm = apr_palloc(mptmp, input_len);
525 char *ret = parm;
526 int len = input_len;
527
528 for(; *input !='\0' && len >=0; input++, len--) {
529 if(*input != '\'' && *input != '\"') {
530 *parm++ = *input;
531 }
532 }
533
534 *parm = '\0';
535 return ret;
536 }
537
538 /** \brief Remove escape char
539 *
540 * \param mptmp Pointer to the pool
541 * \param input Pointer to input string
542 * \param input_len Input data length
543 *
544 * \retval string On Success
545 */
remove_escape(apr_pool_t * mptmp,const char * input,int input_len)546 char *remove_escape(apr_pool_t *mptmp, const char *input, int input_len) {
547 char *parm = apr_palloc(mptmp, input_len);
548 char *ret = parm;
549 int len = input_len;
550
551 for(; *input !='\0' && len >=0; input++, len--) {
552 if(*input != '\\') {
553 *parm++ = *input;
554 }
555 }
556
557 *parm = '\0';
558 return ret;
559 }
560
561 /**
562 *
563 */
parse_boolean(const char * input)564 int parse_boolean(const char *input) {
565 if (input == NULL) return -1;
566 if (strcasecmp(input, "on") == 0) return 1;
567 if (strcasecmp(input, "true") == 0) return 1;
568 if (strcasecmp(input, "1") == 0) return 1;
569 if (strcasecmp(input, "off") == 0) return 0;
570 if (strcasecmp(input, "false") == 0) return 0;
571 if (strcasecmp(input, "0") == 0) return 0;
572
573 return -1;
574 }
575
576 /** \brief Decode Base64 data with special chars
577 *
578 * \param plain_text Pointer to plain text data
579 * \param input Pointer to input data
580 * \param input_len Input data length
581 *
582 * \retval 0 On failure
583 * \retval string length On Success
584 */
decode_base64_ext(char * plain_text,const unsigned char * input,int input_len)585 int decode_base64_ext(char *plain_text, const unsigned char *input, int input_len) {
586 const unsigned char *encoded = input;
587 int i = 0, j = 0, k = 0;
588 int ch = 0;
589
590 while ((ch = *encoded++) != '\0' && input_len-- > 0) {
591 if (ch == b64_pad) {
592 if (*encoded != '=' && (i % 4) == 1) {
593 return 0;
594 }
595 continue;
596 }
597
598 ch = b64_reverse_t[ch];
599 if (ch < 0 || ch == -1) {
600 continue;
601 } else if (ch == -2) {
602 return 0;
603 }
604 switch(i % 4) {
605 case 0:
606 plain_text[j] = ch << 2;
607 break;
608 case 1:
609 plain_text[j++] |= ch >> 4;
610 plain_text[j] = (ch & 0x0f) << 4;
611 break;
612 case 2:
613 plain_text[j++] |= ch >>2;
614 plain_text[j] = (ch & 0x03) << 6;
615 break;
616 case 3:
617 plain_text[j++] |= ch;
618 break;
619 }
620 i++;
621 }
622
623 k = j;
624 if (ch == b64_pad) {
625 switch(i % 4) {
626 case 1:
627 return 0;
628 case 2:
629 k++;
630 case 3:
631 plain_text[k] = 0;
632 }
633 }
634
635 plain_text[j] = '\0';
636
637 return j;
638 }
639
640 /** \brief Convert const char to int
641 *
642 * \param c number string
643 *
644 * \retval n The converted number
645 */
convert_to_int(const char c)646 int convert_to_int(const char c)
647 {
648 int n;
649 if ((c>='0') && (c<='9'))
650 n = c - '0';
651 else if ((c>='A') && (c<='F'))
652 n = c - 'A' + 10;
653 else if ((c>='a') && (c<='f'))
654 n = c - 'a' + 10;
655 else
656 n = 0;
657 return n;
658 }
659
660 /** \brief Set a match to tx.N
661 *
662 * \param msr Pointer to modsec resource
663 * \param capture If ON match will be saved
664 * \param match Pointer to captured string
665 *\parm tx_n The tx number to save the data
666 *
667 * \retval 0 On Sucess|Fail
668 */
set_match_to_tx(modsec_rec * msr,int capture,const char * match,int tx_n)669 int set_match_to_tx(modsec_rec *msr, int capture, const char *match, int tx_n) {
670
671 if (capture) {
672 msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
673
674 if (s == NULL) return -1;
675
676 s->name = apr_psprintf(msr->mp,"%d", tx_n);
677 s->name_len = strlen(s->name);
678 s->value = apr_pstrdup(msr->mp, match);
679 if (s->value == NULL) return -1;
680 s->value_len = strlen(s->value);
681 apr_table_setn(msr->tx_vars, s->name, (void *)s);
682
683 if (msr->txcfg->debuglog_level >= 9) {
684 msr_log(msr, 9, "Added phrase match to TX.%d: %s",
685 tx_n, log_escape_nq_ex(msr->mp, s->value, s->value_len));
686 }
687
688 }
689
690 return 0;
691 }
692
693
694 /**
695 * Parses a string that contains a name-value pair in the form "name=value".
696 * IMP1 It does not check for whitespace between tokens.
697 */
parse_name_eq_value(apr_pool_t * mp,const char * input,char ** name,char ** value)698 int parse_name_eq_value(apr_pool_t *mp, const char *input, char **name, char **value) {
699 char *p = NULL;
700
701 if ((name == NULL)||(value == NULL)) return -1;
702 if (input == NULL) return 0;
703
704 *name = NULL;
705 *value = NULL;
706 p = (char *)input;
707
708 while((*p != '=')&&(*p != '\0')) p++;
709 if (*p == '\0') {
710 *name = (char *)input;
711 return 1;
712 }
713
714 *name = apr_pstrmemdup(mp, input, p - input);
715 if (*name == NULL) return -1;
716 p++;
717
718 *value = apr_pstrdup(mp, p);
719 if (*value == NULL) return -1;
720
721 return 1;
722 }
723
724 /**
725 *
726 * IMP1 Assumes NUL-terminated
727 */
url_encode(apr_pool_t * mp,char * input,unsigned int input_len,int * changed)728 char *url_encode(apr_pool_t *mp, char *input, unsigned int input_len, int *changed) {
729 char *rval, *d;
730 unsigned int i, len;
731
732 *changed = 0;
733
734 len = input_len * 3 + 1;
735 d = rval = apr_palloc(mp, len);
736 if (rval == NULL) return NULL;
737
738 /* ENH Only encode the characters that really need to be encoded. */
739
740 for(i = 0; i < input_len; i++) {
741 unsigned char c = input[i];
742
743 if (c == ' ') {
744 *d++ = '+';
745 *changed = 1;
746 } else
747 if ( (c == 42) || ((c >= 48)&&(c <= 57)) || ((c >= 65)&&(c <= 90))
748 || ((c >= 97)&&(c <= 122))
749 ) {
750 *d++ = c;
751 } else {
752 *d++ = '%';
753 c2x(c, (unsigned char *)d);
754 d += 2;
755 *changed = 1;
756 }
757 }
758
759 *d = '\0';
760
761 return rval;
762 }
763
764 /**
765 * Appends an URL-encoded version of the source string to the
766 * destination string, but makes sure that no more than "maxlen"
767 * bytes are added.
768 */
strnurlencat(char * destination,char * source,unsigned int maxlen)769 char *strnurlencat(char *destination, char *source, unsigned int maxlen) {
770 char *s = source;
771 char *d = destination;
772
773 /* ENH Only encode the characters that really need to be encoded. */
774
775 /* Advance to the end of destination string. */
776 while(*d != '\0') d++;
777
778 /* Loop while there's bytes in the source string or
779 * until we reach the output limit.
780 */
781 while((*s != '\0')&&(maxlen > 0)) {
782 unsigned char c = *s;
783
784 if (c == ' ') {
785 *d++ = '+';
786 maxlen--;
787 } else
788 if ( (c == 42) || ((c >= 48)&&(c <= 57)) || ((c >= 65)&&(c <= 90))
789 || ((c >= 97)&&(c <= 122))
790 ) {
791 *d++ = c;
792 maxlen--;
793 } else {
794 if (maxlen >= 3) {
795 *d++ = '%';
796 c2x(c, (unsigned char *)d);
797 d += 2;
798 maxlen -= 3;
799 } else {
800 /* If there's not enough room for the encoded
801 * byte we ignore it.
802 */
803 maxlen = 0;
804 }
805 }
806
807 s++;
808 }
809
810 *d++ = '\0';
811
812 return destination;
813 }
814
815 /**
816 *
817 */
file_basename(apr_pool_t * mp,const char * filename)818 char *file_basename(apr_pool_t *mp, const char *filename) {
819 char *d, *p;
820
821 if (filename == NULL) return NULL;
822 d = apr_pstrdup(mp, filename);
823 if (d == NULL) return NULL;
824
825 p = strrchr(d, '/');
826 if (p != NULL) d = p + 1;
827 p = strrchr(d, '\\');
828 if (p != NULL) d = p + 1;
829
830 return d;
831 }
832
m_strcasestr(const char * haystack,const char * needle)833 char *m_strcasestr(const char *haystack, const char *needle) {
834 char aux, lower_aux;
835 int length;
836
837 if ((aux = *needle++) != 0) {
838 aux = (char)tolower((unsigned char)aux);
839 length = strlen(needle);
840 do {
841 do {
842 if ((lower_aux = *haystack++) == 0)
843 return NULL;
844 } while ((char)tolower((unsigned char)lower_aux) != aux);
845 } while (strncasecmp(haystack, needle, length) != 0);
846 haystack--;
847 }
848 return ((char *)haystack);
849 }
850
851 #ifdef WIN32
852 #if !(NTDDI_VERSION >= NTDDI_VISTA)
inet_pton(int family,const char * src,void * dst)853 int inet_pton(int family, const char *src, void *dst) {
854 struct addrinfo addr;
855 struct sockaddr_in *in = NULL;
856 #if APR_HAVE_IPV6
857 struct sockaddr_in6 *in6 = NULL;
858 #endif
859 struct addrinfo *addr_info = NULL;
860
861 memset(&addr, 0, sizeof(struct addrinfo));
862 addr.ai_family = family;
863
864 if (getaddrinfo(src, NULL, &addr, &addr_info) != 0)
865 return -1;
866
867 if (addr_info) {
868 if (addr_info->ai_family == AF_INET) {
869 in = (struct sockaddr_in*)addr_info->ai_addr;
870 if(in != NULL)
871 memcpy(dst, &in->sin_addr, 4);
872 }
873 #if APR_HAVE_IPV6
874 else if (addr_info->ai_family == AF_INET6) {
875 in6 = (struct sockaddr_in6*)addr_info->ai_addr;
876 if(in6 != NULL)
877 memcpy(dst, &in6->sin6_addr, 16);
878 }
879 #endif
880 else {
881 freeaddrinfo(addr_info);
882 return -1;
883 }
884
885 freeaddrinfo(addr_info);
886 return 1;
887 }
888
889 return -1;
890 }
891 #endif
892 #endif
893
894 /**
895 *
896 */
897 #ifdef WIN32
file_dirname(apr_pool_t * p,const char * filename)898 char *file_dirname(apr_pool_t *p, const char *filename) {
899 char *b, *c, *d;
900
901 if (filename == NULL) return NULL;
902 b = apr_pstrdup(p, filename);
903 if (b == NULL) return NULL;
904
905 c = strrchr(b, '/');
906 if (c != NULL) {
907 d = strrchr(c, '\\');
908 if (d != NULL) *d = '\0';
909 else *c = '\0';
910 } else {
911 d = strrchr(b, '\\');
912 if (d != NULL) *d = '\0';
913 }
914
915 return b;
916 }
917 #else
file_dirname(apr_pool_t * p,const char * filename)918 char *file_dirname(apr_pool_t *p, const char *filename) {
919 char *b, *c;
920
921 if (filename == NULL) return NULL;
922 b = apr_pstrdup(p, filename);
923 if (b == NULL) return NULL;
924
925 c = strrchr(b, '/');
926 if (c != NULL) *c = '\0';
927
928 return b;
929 }
930 #endif
931
932
933 /**
934 *
935 */
sql_hex2bytes_inplace(unsigned char * data,int len)936 int sql_hex2bytes_inplace(unsigned char *data, int len) {
937 unsigned char *d, *begin = data;
938
939 if ((data == NULL)||(len == 0)) return 0;
940
941 for( d = data; *data; *d++ = *data++) {
942 if ( *data != '0' ) continue;
943 if ( tolower(*++data) != 'x' ) {
944 data--;
945 continue;
946 }
947
948 data++;
949
950 // Do we need to keep "0x" if no hexa after?
951 if ( !VALID_HEX(data[0]) || !VALID_HEX(data[1]) ) {
952 data-=2;
953 continue;
954 }
955
956 while ( VALID_HEX(data[0]) && VALID_HEX(data[1]) ) {
957 *d++ = x2c(data);
958 data += 2;
959 }
960 }
961
962 *d = '\0';
963 return strlen((char *)begin);
964 }
965
966 /**
967 *
968 *
969 */
hex2bytes_inplace(unsigned char * data,int len)970 int hex2bytes_inplace(unsigned char *data, int len) {
971 unsigned char *d = data;
972 int i, count = 0;
973
974 if ((data == NULL)||(len == 0)) return 0;
975
976 for(i = 0; i <= len - 2; i += 2) {
977 *d++ = x2c(&data[i]);
978 count++;
979 }
980 *d = '\0';
981
982 return count;
983 }
984
985 /**
986 * Converts a series of bytes into its hexadecimal
987 * representation.
988 */
bytes2hex(apr_pool_t * pool,unsigned char * data,int len)989 char *bytes2hex(apr_pool_t *pool, unsigned char *data, int len) {
990 static const unsigned char b2hex[] = "0123456789abcdef";
991 char *hex = NULL;
992 int i, j;
993
994 hex = apr_palloc(pool, (len * 2) + 1);
995 if (hex == NULL) return NULL;
996
997 j = 0;
998 for(i = 0; i < len; i++) {
999 hex[j++] = b2hex[data[i] >> 4];
1000 hex[j++] = b2hex[data[i] & 0x0f];
1001 }
1002 hex[j] = 0;
1003
1004 return hex;
1005 }
1006
1007 /**
1008 *
1009 */
is_token_char(unsigned char c)1010 int is_token_char(unsigned char c) {
1011 /* ENH Is the performance important at all? We could use a table instead. */
1012
1013 /* CTLs not allowed */
1014 if ((c <= 32)||(c >= 127)) return 0;
1015
1016 switch(c) {
1017 case '(' :
1018 case ')' :
1019 case '<' :
1020 case '>' :
1021 case '@' :
1022 case ',' :
1023 case ';' :
1024 case ':' :
1025 case '\\' :
1026 case '"' :
1027 case '/' :
1028 case '[' :
1029 case ']' :
1030 case '?' :
1031 case '=' :
1032 return 0;
1033 }
1034
1035 return 1;
1036 }
1037
1038 /**
1039 *
1040 */
remove_lf_crlf_inplace(char * text)1041 int remove_lf_crlf_inplace(char *text) {
1042 char *p = text;
1043 int count = 0;
1044
1045 if (text == NULL) return -1;
1046
1047 while(*p != '\0') {
1048 count++;
1049 p++;
1050 }
1051
1052 if (count > 0) {
1053 if (*(p - 1) == '\n') {
1054 *(p - 1) = '\0';
1055 if (count > 1) {
1056 if (*(p - 2) == '\r') {
1057 *(p - 2) = '\0';
1058 }
1059 }
1060 }
1061 }
1062
1063 return 1;
1064 }
1065
1066 /**
1067 * Converts a byte given as its hexadecimal representation
1068 * into a proper byte. Handles uppercase and lowercase letters
1069 * but does not check for overflows.
1070 */
x2c(unsigned char * what)1071 static unsigned char x2c(unsigned char *what) {
1072 register unsigned char digit;
1073
1074 digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
1075 digit *= 16;
1076 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
1077
1078 return digit;
1079 }
1080
1081 /**
1082 * Converts a single hexadecimal digit into a decimal value.
1083 */
xsingle2c(unsigned char * what)1084 static unsigned char xsingle2c(unsigned char *what) {
1085 register unsigned char digit;
1086
1087 digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
1088
1089 return digit;
1090 }
1091
1092 /**
1093 *
1094 */
guess_tmp_dir(apr_pool_t * p)1095 char *guess_tmp_dir(apr_pool_t *p) {
1096 char *filename = NULL;
1097
1098 /* ENH Use apr_temp_dir_get instead. */
1099
1100 #ifdef WIN32
1101 filename = apr_pcalloc(p, 256);
1102 if (filename == NULL) return "";
1103 if (GetTempPath(255, filename) != 0) return filename;
1104 #endif
1105
1106 filename = getenv("TMPDIR");
1107 if (filename != NULL) return filename;
1108
1109 filename = getenv("TEMP");
1110 if (filename != NULL) return filename;
1111
1112 filename = getenv("TMP");
1113 if (filename != NULL) return filename;
1114
1115 #if defined NETWARE
1116 return("sys:/tmp/");
1117 #elif defined WIN32
1118 return("");
1119 #else
1120 return("/tmp/");
1121 #endif
1122 }
1123
1124 /**
1125 *
1126 */
current_logtime(apr_pool_t * mp)1127 char *current_logtime(apr_pool_t *mp) {
1128 apr_time_exp_t t;
1129 char tstr[100];
1130 apr_size_t len;
1131
1132 apr_time_exp_lt(&t, apr_time_now());
1133
1134 apr_strftime(tstr, &len, 80, "%d/%b/%Y:%H:%M:%S ", &t);
1135 apr_snprintf(tstr + strlen(tstr), 80 - strlen(tstr), "%c%.2d%.2d",
1136 t.tm_gmtoff < 0 ? '-' : '+',
1137 t.tm_gmtoff / (60 * 60), (t.tm_gmtoff / 60) % 60);
1138 return apr_pstrdup(mp, tstr);
1139 }
1140
1141 /**
1142 *
1143 */
current_filetime(apr_pool_t * mp)1144 char *current_filetime(apr_pool_t *mp) {
1145 apr_time_exp_t t;
1146 char tstr[100];
1147 apr_size_t len;
1148
1149 apr_time_exp_lt(&t, apr_time_now());
1150
1151 apr_strftime(tstr, &len, 80, "%Y%m%d-%H%M%S", &t);
1152 return apr_pstrdup(mp, tstr);
1153 }
1154
1155 /**
1156 *
1157 */
msc_mkstemp_ex(char * templat,int mode)1158 int msc_mkstemp_ex(char *templat, int mode) {
1159 int fd = -1;
1160
1161 /* ENH Use apr_file_mktemp instead. */
1162
1163 #if !(defined(WIN32)||defined(NETWARE))
1164 fd = mkstemp(templat);
1165 #ifdef HAVE_FCHMOD
1166 if ((fd != -1) && (mode != 0)) {
1167 if (fchmod(fd, mode) == -1) {
1168 return -1;
1169 }
1170 }
1171 #endif /* HAVE_FCHMOD */
1172 #else
1173 if (mktemp(templat) == NULL) return -1;
1174 fd = open(templat, O_WRONLY | O_APPEND | O_CREAT | O_BINARY, mode);
1175 #endif /* !(defined(WIN32)||defined(NETWARE)) */
1176
1177 return fd;
1178 }
1179
1180 /**
1181 *
1182 */
msc_mkstemp(char * templat)1183 int msc_mkstemp(char *templat) {
1184 return msc_mkstemp_ex(templat, CREATEMODE_UNISTD);
1185 }
1186
1187 /**
1188 * Converts the input string to lowercase (in-place).
1189 */
strtolower_inplace(unsigned char * str)1190 char *strtolower_inplace(unsigned char *str) {
1191 unsigned char *c = str;
1192
1193 if (str == NULL) return NULL;
1194
1195 while(*c != 0) {
1196 *c = tolower(*c);
1197 c++;
1198 }
1199
1200 return (char *)str;
1201 }
1202
1203 /**
1204 * Converts a single byte into its hexadecimal representation.
1205 * Will overwrite two bytes at the destination.
1206 */
c2x(unsigned what,unsigned char * where)1207 static unsigned char *c2x(unsigned what, unsigned char *where) {
1208 static const char c2x_table[] = "0123456789abcdef";
1209
1210 what = what & 0xff;
1211 *where++ = c2x_table[what >> 4];
1212 *where++ = c2x_table[what & 0x0f];
1213
1214 return where;
1215 }
1216
1217 static char *_log_escape(apr_pool_t *p, const unsigned char *input,
1218 unsigned long int input_length, int escape_quotes, int escape_colon, int escape_re);
1219
log_escape_re(apr_pool_t * mp,const char * text)1220 char *log_escape_re(apr_pool_t *mp, const char *text) {
1221 return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 1, 1, 1);
1222 }
1223
log_escape(apr_pool_t * mp,const char * text)1224 char *log_escape(apr_pool_t *mp, const char *text) {
1225 return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 1, 0, 0);
1226 }
1227
log_escape_nq(apr_pool_t * mp,const char * text)1228 char *log_escape_nq(apr_pool_t *mp, const char *text) {
1229 #ifdef VERSION_IIS
1230 int l = 0;
1231
1232 // this is a workaround for unknown bug that causes 'text' sometimes to lack zero-termination
1233 //
1234 __try
1235 {
1236 l = text ? strlen(text) : 0;
1237 }
1238 __except(EXCEPTION_EXECUTE_HANDLER)
1239 {
1240 l = -1;
1241 }
1242 if(l < 0)
1243 return _log_escape(mp, "BUG: see log_escape_nq()", 24, 0, 0, 0);
1244
1245 return _log_escape(mp, (const unsigned char *)text, l, 0, 0, 0);
1246 #else
1247 return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 0, 0, 0);
1248 #endif
1249 }
1250
log_escape_ex(apr_pool_t * mp,const char * text,unsigned long int text_length)1251 char *log_escape_ex(apr_pool_t *mp, const char *text, unsigned long int text_length) {
1252 return _log_escape(mp, (const unsigned char *)text, text_length, 1, 0, 0);
1253 }
1254
log_escape_nq_ex(apr_pool_t * mp,const char * text,unsigned long int text_length)1255 char *log_escape_nq_ex(apr_pool_t *mp, const char *text, unsigned long int text_length) {
1256 return _log_escape(mp, (const unsigned char *)text, text_length, 0, 0, 0);
1257 }
1258
log_escape_raw(apr_pool_t * mp,const unsigned char * text,unsigned long int text_length)1259 char *log_escape_raw(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length) {
1260 unsigned char *ret = apr_palloc(mp, text_length * 4 + 1);
1261 unsigned long int i, j;
1262
1263 for (i = 0, j = 0; i < text_length; i++, j += 4) {
1264 ret[j] = '\\';
1265 ret[j+1] = 'x';
1266 c2x(text[i], ret+j+2);
1267 }
1268 ret[text_length * 4] = '\0';
1269
1270 return (char *)ret;
1271 }
1272
log_escape_nul(apr_pool_t * mp,const unsigned char * text,unsigned long int text_length)1273 char *log_escape_nul(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length) {
1274 unsigned char *ret = apr_palloc(mp, text_length * 4 + 1);
1275 unsigned long int i, j;
1276
1277 for (i = 0, j = 0; i < text_length; i++) {
1278 if (text[i] == '\0') {
1279 ret[j] = '\\';
1280 ret[j+1] = 'x';
1281 c2x(text[i], ret+j+2);
1282 j += 4;
1283 }
1284 else {
1285 ret[j] = text[i];
1286 j++;
1287 }
1288 }
1289 ret[j] = '\0';
1290
1291 return (char *)ret;
1292 }
1293
1294 /**
1295 * Transform text to ASCII printable or hex escaped
1296 */
log_escape_hex(apr_pool_t * mp,const unsigned char * text,unsigned long int text_length)1297 char *log_escape_hex(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length) {
1298 unsigned char *ret = apr_palloc(mp, text_length * 4 + 1);
1299 unsigned long int i, j;
1300
1301 for (i = 0, j = 0; i < text_length; i++) {
1302 if ( (text[i] == '"')
1303 ||(text[i] == '\\')
1304 ||(text[i] <= 0x1f)
1305 ||(text[i] >= 0x7f))
1306 {
1307 ret[j] = '\\';
1308 ret[j+1] = 'x';
1309 c2x(text[i], ret+j+2);
1310 j += 4;
1311 }
1312 else {
1313 ret[j] = text[i];
1314 j ++;
1315 }
1316 }
1317 ret[j] = '\0';
1318
1319 return (char *)ret;
1320 }
1321
1322 /**
1323 * Transform input into a form safe for logging.
1324 */
_log_escape(apr_pool_t * mp,const unsigned char * input,unsigned long int input_len,int escape_quotes,int escape_colon,int escape_re)1325 static char *_log_escape(apr_pool_t *mp, const unsigned char *input, unsigned long int input_len,
1326 int escape_quotes, int escape_colon, int escape_re)
1327 {
1328 unsigned char *d = NULL;
1329 char *ret = NULL;
1330 unsigned long int i;
1331
1332 if (input == NULL) return NULL;
1333
1334 ret = apr_palloc(mp, input_len * 4 + 1);
1335 if (ret == NULL) return NULL;
1336 d = (unsigned char *)ret;
1337
1338 i = 0;
1339 while(i < input_len) {
1340 switch(input[i]) {
1341 case ':' :
1342 if (escape_colon) {
1343 *d++ = '\\';
1344 *d++ = ':';
1345 } else {
1346 *d++ = input[i];
1347 }
1348 break;
1349 case '"' :
1350 if (escape_quotes) {
1351 *d++ = '\\';
1352 *d++ = '"';
1353 } else {
1354 *d++ = input[i];
1355 }
1356 break;
1357 case '+' :
1358 if (escape_re) {
1359 *d++ = '\\';
1360 *d++ = '+';
1361 } else {
1362 *d++ = input[i];
1363 }
1364 break;
1365 case '.' :
1366 if (escape_re) {
1367 *d++ = '\\';
1368 *d++ = '.';
1369 } else {
1370 *d++ = input[i];
1371 }
1372 break;
1373 case ']' :
1374 if (escape_re) {
1375 *d++ = '\\';
1376 *d++ = ']';
1377 } else {
1378 *d++ = input[i];
1379 }
1380 break;
1381 case '[' :
1382 if (escape_re) {
1383 *d++ = '\\';
1384 *d++ = '[';
1385 } else {
1386 *d++ = input[i];
1387 }
1388 break;
1389 case '(' :
1390 if (escape_re) {
1391 *d++ = '\\';
1392 *d++ = '(';
1393 } else {
1394 *d++ = input[i];
1395 }
1396 break;
1397 case ')' :
1398 if (escape_re) {
1399 *d++ = '\\';
1400 *d++ = ')';
1401 } else {
1402 *d++ = input[i];
1403 }
1404 break;
1405 case '?' :
1406 if (escape_re) {
1407 *d++ = '\\';
1408 *d++ = '?';
1409 } else {
1410 *d++ = input[i];
1411 }
1412 break;
1413 case '/' :
1414 if (escape_re) {
1415 *d++ = '\\';
1416 *d++ = '/';
1417 } else {
1418 *d++ = input[i];
1419 }
1420 break;
1421 case '\b' :
1422 *d++ = '\\';
1423 *d++ = 'b';
1424 break;
1425 case '\n' :
1426 *d++ = '\\';
1427 *d++ = 'n';
1428 break;
1429 case '\r' :
1430 *d++ = '\\';
1431 *d++ = 'r';
1432 break;
1433 case '\t' :
1434 *d++ = '\\';
1435 *d++ = 't';
1436 break;
1437 case '\v' :
1438 *d++ = '\\';
1439 *d++ = 'v';
1440 break;
1441 case '\\' :
1442 *d++ = '\\';
1443 *d++ = '\\';
1444 break;
1445 default :
1446 if ((input[i] <= 0x1f)||(input[i] >= 0x7f)) {
1447 *d++ = '\\';
1448 *d++ = 'x';
1449 c2x(input[i], d);
1450 d += 2;
1451 } else {
1452 *d++ = input[i];
1453 }
1454 break;
1455 }
1456
1457 i++;
1458 }
1459
1460 *d = 0;
1461
1462 return ret;
1463 }
1464
1465 /**
1466 * JavaScript decoding.
1467 * IMP1 Assumes NUL-terminated
1468 */
1469
js_decode_nonstrict_inplace(unsigned char * input,long int input_len)1470 int js_decode_nonstrict_inplace(unsigned char *input, long int input_len) {
1471 unsigned char *d = (unsigned char *)input;
1472 long int i, count;
1473
1474 if (input == NULL) return -1;
1475
1476 i = count = 0;
1477 while (i < input_len) {
1478 if (input[i] == '\\') {
1479 /* Character is an escape. */
1480
1481 if ( (i + 5 < input_len) && (input[i + 1] == 'u')
1482 && (VALID_HEX(input[i + 2])) && (VALID_HEX(input[i + 3]))
1483 && (VALID_HEX(input[i + 4])) && (VALID_HEX(input[i + 5])) )
1484 {
1485 /* \uHHHH */
1486
1487 /* Use only the lower byte. */
1488 *d = x2c(&input[i + 4]);
1489
1490 /* Full width ASCII (ff01 - ff5e) needs 0x20 added */
1491 if ( (*d > 0x00) && (*d < 0x5f)
1492 && ((input[i + 2] == 'f') || (input[i + 2] == 'F'))
1493 && ((input[i + 3] == 'f') || (input[i + 3] == 'F')))
1494 {
1495 (*d) += 0x20;
1496 }
1497
1498 d++;
1499 count++;
1500 i += 6;
1501 }
1502 else if ( (i + 3 < input_len) && (input[i + 1] == 'x')
1503 && VALID_HEX(input[i + 2]) && VALID_HEX(input[i + 3])) {
1504 /* \xHH */
1505 *d++ = x2c(&input[i + 2]);
1506 count++;
1507 i += 4;
1508 }
1509 else if ((i + 1 < input_len) && ISODIGIT(input[i + 1])) {
1510 /* \OOO (only one byte, \000 - \377) */
1511 char buf[4];
1512 int j = 0;
1513
1514 while((i + 1 + j < input_len)&&(j < 3)) {
1515 buf[j] = input[i + 1 + j];
1516 j++;
1517 if (!ISODIGIT(input[i + 1 + j])) break;
1518 }
1519 buf[j] = '\0';
1520
1521 if (j > 0) {
1522 /* Do not use 3 characters if we will be > 1 byte */
1523 if ((j == 3) && (buf[0] > '3')) {
1524 j = 2;
1525 buf[j] = '\0';
1526 }
1527 *d++ = (unsigned char)strtol(buf, NULL, 8);
1528 i += 1 + j;
1529 count++;
1530 }
1531 }
1532 else if (i + 1 < input_len) {
1533 /* \C */
1534 unsigned char c = input[i + 1];
1535 switch(input[i + 1]) {
1536 case 'a' :
1537 c = '\a';
1538 break;
1539 case 'b' :
1540 c = '\b';
1541 break;
1542 case 'f' :
1543 c = '\f';
1544 break;
1545 case 'n' :
1546 c = '\n';
1547 break;
1548 case 'r' :
1549 c = '\r';
1550 break;
1551 case 't' :
1552 c = '\t';
1553 break;
1554 case 'v' :
1555 c = '\v';
1556 break;
1557 /* The remaining (\?,\\,\',\") are just a removal
1558 * of the escape char which is default.
1559 */
1560 }
1561
1562 *d++ = c;
1563 i += 2;
1564 count++;
1565 }
1566 else {
1567 /* Not enough bytes */
1568 while(i < input_len) {
1569 *d++ = input[i++];
1570 count++;
1571 }
1572 }
1573 }
1574 else {
1575 *d++ = input[i++];
1576 count++;
1577 }
1578 }
1579
1580 *d = '\0';
1581
1582 return count;
1583 }
1584
1585 /**
1586 *
1587 * IMP1 Assumes NUL-terminated
1588 */
urldecode_uni_nonstrict_inplace_ex(unsigned char * input,long int input_len,int * changed)1589 int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *changed) {
1590 unsigned char *d = input;
1591 long int i, count, fact, j, xv;
1592 int Code, hmap = -1;
1593
1594 *changed = 0;
1595
1596 if (input == NULL) return -1;
1597
1598 i = count = 0;
1599 while (i < input_len) {
1600 if (input[i] == '%') {
1601 /* Character is a percent sign. */
1602
1603 if ((i + 1 < input_len)&&( (input[i + 1] == 'u')||(input[i + 1] == 'U') )) {
1604 /* IIS-specific %u encoding. */
1605 if (i + 5 < input_len) {
1606 /* We have at least 4 data bytes. */
1607 if ( (VALID_HEX(input[i + 2]))&&(VALID_HEX(input[i + 3]))
1608 &&(VALID_HEX(input[i + 4]))&&(VALID_HEX(input[i + 5])) )
1609 {
1610
1611 Code = 0;
1612 fact = 1;
1613
1614 if (unicode_map_table != NULL && unicode_codepage > 0) {
1615
1616 for(j=5; j>=2; j--) {
1617 if (isxdigit((input[i+j]))) {
1618 if ((input[i+j])>=97) {
1619 xv = ( (input[i+j]) - 97) + 10;
1620 } else if ( (input[i+j]) >= 65) {
1621 xv = ((input[i+j]) - 65) + 10;
1622 } else {
1623 xv = (input[i+j]) - 48;
1624 }
1625 Code += (xv * fact);
1626 fact *= 16;
1627 }
1628 }
1629
1630 if(Code >= 0 && Code <= 65535) {
1631 hmap = unicode_map_table[Code];
1632 }
1633 }
1634
1635 if(hmap != -1) {
1636 *d = hmap;
1637 } else {
1638 /* We first make use of the lower byte here, ignoring the higher byte. */
1639 *d = x2c(&input[i + 4]);
1640
1641 /* Full width ASCII (ff01 - ff5e) needs 0x20 added */
1642 if ( (*d > 0x00) && (*d < 0x5f)
1643 && ((input[i + 2] == 'f') || (input[i + 2] == 'F'))
1644 && ((input[i + 3] == 'f') || (input[i + 3] == 'F')))
1645 {
1646 (*d) += 0x20;
1647 }
1648 }
1649 d++;
1650 count++;
1651 i += 6;
1652 *changed = 1;
1653 } else {
1654 /* Invalid data, skip %u. */
1655 *d++ = input[i++];
1656 *d++ = input[i++];
1657 count += 2;
1658 }
1659 } else {
1660 /* Not enough bytes (4 data bytes), skip %u. */
1661 *d++ = input[i++];
1662 *d++ = input[i++];
1663 count += 2;
1664 }
1665 }
1666 else {
1667 /* Standard URL encoding. */
1668
1669 /* Are there enough bytes available? */
1670 if (i + 2 < input_len) {
1671 /* Yes. */
1672
1673 /* Decode a %xx combo only if it is valid.
1674 */
1675 char c1 = input[i + 1];
1676 char c2 = input[i + 2];
1677
1678 if (VALID_HEX(c1) && VALID_HEX(c2)) {
1679 *d++ = x2c(&input[i + 1]);
1680 count++;
1681 i += 3;
1682 *changed = 1;
1683 } else {
1684 /* Not a valid encoding, skip this % */
1685 *d++ = input[i++];
1686 count++;
1687 }
1688 } else {
1689 /* Not enough bytes available, skip this % */
1690 *d++ = input[i++];
1691 count++;
1692 }
1693 }
1694 }
1695 else {
1696 /* Character is not a percent sign. */
1697 if (input[i] == '+') {
1698 *d++ = ' ';
1699 *changed = 1;
1700 } else {
1701 *d++ = input[i];
1702 }
1703
1704 count++;
1705 i++;
1706 }
1707 }
1708
1709 *d = '\0';
1710
1711 return count;
1712 }
1713
1714 /**
1715 *
1716 * IMP1 Assumes NUL-terminated
1717 */
urldecode_nonstrict_inplace_ex(unsigned char * input,long int input_len,int * invalid_count,int * changed)1718 int urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *invalid_count, int *changed) {
1719 unsigned char *d = (unsigned char *)input;
1720 long int i, count;
1721
1722 *changed = 0;
1723
1724 if (input == NULL) return -1;
1725
1726 i = count = 0;
1727 while (i < input_len) {
1728 if (input[i] == '%') {
1729 /* Character is a percent sign. */
1730
1731 /* Are there enough bytes available? */
1732 if (i + 2 < input_len) {
1733 char c1 = input[i + 1];
1734 char c2 = input[i + 2];
1735
1736 if (VALID_HEX(c1) && VALID_HEX(c2)) {
1737 /* Valid encoding - decode it. */
1738 *d++ = x2c(&input[i + 1]);
1739 count++;
1740 i += 3;
1741 *changed = 1;
1742 } else {
1743 /* Not a valid encoding, skip this % */
1744 *d++ = input[i++];
1745 count ++;
1746 (*invalid_count)++;
1747 }
1748 } else {
1749 /* Not enough bytes available, copy the raw bytes. */
1750 *d++ = input[i++];
1751 count ++;
1752 (*invalid_count)++;
1753 }
1754 } else {
1755 /* Character is not a percent sign. */
1756 if (input[i] == '+') {
1757 *d++ = ' ';
1758 *changed = 1;
1759 } else {
1760 *d++ = input[i];
1761 }
1762 count++;
1763 i++;
1764 }
1765 }
1766
1767 *d = '\0';
1768
1769 return count;
1770 }
1771
1772 /**
1773 *
1774 * IMP1 Assumes NUL-terminated
1775 */
html_entities_decode_inplace(apr_pool_t * mp,unsigned char * input,int input_len)1776 int html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int input_len) {
1777 unsigned char *d = input;
1778 int i, count;
1779
1780 if ((input == NULL)||(input_len <= 0)) return 0;
1781
1782 i = count = 0;
1783 while((i < input_len)&&(count < input_len)) {
1784 int z, copy = 1;
1785
1786 /* Require an ampersand and at least one character to
1787 * start looking into the entity.
1788 */
1789 if ((input[i] == '&')&&(i + 1 < input_len)) {
1790 int k, j = i + 1;
1791
1792 if (input[j] == '#') {
1793 /* Numerical entity. */
1794 copy++;
1795
1796 if (!(j + 1 < input_len)) goto HTML_ENT_OUT; /* Not enough bytes. */
1797 j++;
1798
1799 if ((input[j] == 'x')||(input[j] == 'X')) {
1800 /* Hexadecimal entity. */
1801 copy++;
1802
1803 if (!(j + 1 < input_len)) goto HTML_ENT_OUT; /* Not enough bytes. */
1804 j++; /* j is the position of the first digit now. */
1805
1806 k = j;
1807 while((j < input_len)&&(isxdigit(input[j]))) j++;
1808 if (j > k) { /* Do we have at least one digit? */
1809 /* Decode the entity. */
1810 char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k);
1811 *d++ = (unsigned char)strtol(x, NULL, 16);
1812 count++;
1813
1814 /* Skip over the semicolon if it's there. */
1815 if ((j < input_len)&&(input[j] == ';')) i = j + 1;
1816 else i = j;
1817
1818 continue;
1819 } else {
1820 goto HTML_ENT_OUT;
1821 }
1822 } else {
1823 /* Decimal entity. */
1824 k = j;
1825 while((j < input_len)&&(isdigit(input[j]))) j++;
1826 if (j > k) { /* Do we have at least one digit? */
1827 /* Decode the entity. */
1828 char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k);
1829 *d++ = (unsigned char)strtol(x, NULL, 10);
1830 count++;
1831
1832 /* Skip over the semicolon if it's there. */
1833 if ((j < input_len)&&(input[j] == ';')) i = j + 1;
1834 else i = j;
1835
1836 continue;
1837 } else {
1838 goto HTML_ENT_OUT;
1839 }
1840 }
1841 } else {
1842 /* Text entity. */
1843
1844 k = j;
1845 while((j < input_len)&&(isalnum(input[j]))) j++;
1846 if (j > k) { /* Do we have at least one digit? */
1847 char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k);
1848
1849 /* Decode the entity. */
1850 /* ENH What about others? */
1851 if (strcasecmp(x, "quot") == 0) *d++ = '"';
1852 else
1853 if (strcasecmp(x, "amp") == 0) *d++ = '&';
1854 else
1855 if (strcasecmp(x, "lt") == 0) *d++ = '<';
1856 else
1857 if (strcasecmp(x, "gt") == 0) *d++ = '>';
1858 else
1859 if (strcasecmp(x, "nbsp") == 0) *d++ = NBSP;
1860 else {
1861 /* We do no want to convert this entity, copy the raw data over. */
1862 copy = j - k + 1;
1863 goto HTML_ENT_OUT;
1864 }
1865
1866 count++;
1867
1868 /* Skip over the semicolon if it's there. */
1869 if ((j < input_len)&&(input[j] == ';')) i = j + 1;
1870 else i = j;
1871
1872 continue;
1873 }
1874 }
1875 }
1876
1877 HTML_ENT_OUT:
1878
1879 for(z = 0; ((z < copy) && (count < input_len)); z++) {
1880 *d++ = input[i++];
1881 count++;
1882 }
1883 }
1884
1885 *d = '\0';
1886
1887 return count;
1888 }
1889
1890 /**
1891 *
1892 * IMP1 Assumes NUL-terminated
1893 */
ansi_c_sequences_decode_inplace(unsigned char * input,int input_len)1894 int ansi_c_sequences_decode_inplace(unsigned char *input, int input_len) {
1895 unsigned char *d = input;
1896 int i, count;
1897
1898 i = count = 0;
1899 while(i < input_len) {
1900 if ((input[i] == '\\')&&(i + 1 < input_len)) {
1901 int c = -1;
1902
1903 switch(input[i + 1]) {
1904 case 'a' :
1905 c = '\a';
1906 break;
1907 case 'b' :
1908 c = '\b';
1909 break;
1910 case 'f' :
1911 c = '\f';
1912 break;
1913 case 'n' :
1914 c = '\n';
1915 break;
1916 case 'r' :
1917 c = '\r';
1918 break;
1919 case 't' :
1920 c = '\t';
1921 break;
1922 case 'v' :
1923 c = '\v';
1924 break;
1925 case '\\' :
1926 c = '\\';
1927 break;
1928 case '?' :
1929 c = '?';
1930 break;
1931 case '\'' :
1932 c = '\'';
1933 break;
1934 case '"' :
1935 c = '"';
1936 break;
1937 }
1938
1939 if (c != -1) i += 2;
1940
1941 /* Hexadecimal or octal? */
1942 if (c == -1) {
1943 if ((input[i + 1] == 'x')||(input[i + 1] == 'X')) {
1944 /* Hexadecimal. */
1945 if ((i + 3 < input_len)&&(isxdigit(input[i + 2]))&&(isxdigit(input[i + 3]))) {
1946 /* Two digits. */
1947 c = x2c(&input[i + 2]);
1948 i += 4;
1949 } else {
1950 /* Invalid encoding, do nothing. */
1951 }
1952 }
1953 else
1954 if (ISODIGIT(input[i + 1])) { /* Octal. */
1955 char buf[4];
1956 int j = 0;
1957
1958 while((i + 1 + j < input_len)&&(j < 3)) {
1959 buf[j] = input[i + 1 + j];
1960 j++;
1961 if (!ISODIGIT(input[i + 1 + j])) break;
1962 }
1963 buf[j] = '\0';
1964
1965 if (j > 0) {
1966 c = strtol(buf, NULL, 8);
1967 i += 1 + j;
1968 }
1969 }
1970 }
1971
1972 if (c == -1) {
1973 /* Didn't recognise encoding, copy raw bytes. */
1974 *d++ = input[i + 1];
1975 count++;
1976 i += 2;
1977 } else {
1978 /* Converted the encoding. */
1979 *d++ = c;
1980 count++;
1981 }
1982 } else {
1983 /* Input character not a backslash, copy it. */
1984 *d++ = input[i++];
1985 count++;
1986 }
1987 }
1988
1989 *d = '\0';
1990
1991 return count;
1992 }
1993
1994 /**
1995 *
1996 * IMP1 Assumes NUL-terminated
1997 */
normalize_path_inplace(unsigned char * input,int input_len,int win,int * changed)1998 int normalize_path_inplace(unsigned char *input, int input_len, int win, int *changed) {
1999 unsigned char *src;
2000 unsigned char *dst;
2001 unsigned char *end;
2002 int ldst = 0;
2003 int hitroot = 0;
2004 int done = 0;
2005 int relative;
2006 int trailing;
2007
2008 *changed = 0;
2009
2010 /* Need at least one byte to normalize */
2011 if (input_len <= 0) return 0;
2012
2013 /*
2014 * ENH: Deal with UNC and drive letters?
2015 */
2016
2017 src = dst = input;
2018 end = input + (input_len - 1);
2019 ldst = 1;
2020
2021 relative = ((*input == '/') || (win && (*input == '\\'))) ? 0 : 1;
2022 trailing = ((*end == '/') || (win && (*end == '\\'))) ? 1 : 0;
2023
2024
2025 while (!done && (src <= end) && (dst <= end)) {
2026 /* Convert backslash to forward slash on Windows only. */
2027 if (win) {
2028 if (*src == '\\') {
2029 *src = '/';
2030 *changed = 1;
2031 }
2032 if ((src < end) && (*(src + 1) == '\\')) {
2033 *(src + 1) = '/';
2034 *changed = 1;
2035 }
2036 }
2037
2038 /* Always normalize at the end of the input. */
2039 if (src == end) {
2040 done = 1;
2041 }
2042
2043 /* Skip normalization if this is NOT the end of the path segment. */
2044 else if (*(src + 1) != '/') {
2045 goto copy; /* Skip normalization. */
2046 }
2047
2048 /*** Normalize the path segment. ***/
2049
2050 /* Could it be an empty path segment? */
2051 if ((src != end) && *src == '/') {
2052 /* Ignore */
2053 *changed = 1;
2054 goto copy; /* Copy will take care of this. */
2055 }
2056
2057 /* Could it be a back or self reference? */
2058 else if (*src == '.') {
2059
2060 /* Back-reference? */
2061 if ((dst > input) && (*(dst - 1) == '.')) {
2062 /* If a relative path and either our normalization has
2063 * already hit the rootdir, or this is a backref with no
2064 * previous path segment, then mark that the rootdir was hit
2065 * and just copy the backref as no normilization is possible.
2066 */
2067 if (relative && (hitroot || ((dst - 2) <= input))) {
2068 hitroot = 1;
2069
2070 goto copy; /* Skip normalization. */
2071 }
2072
2073 /* Remove backreference and the previous path segment. */
2074 dst -= 3;
2075 while ((dst > input) && (*dst != '/')) {
2076 dst--;
2077 }
2078
2079 /* But do not allow going above rootdir. */
2080 if (dst <= input) {
2081 hitroot = 1;
2082 dst = input;
2083
2084 /* Need to leave the root slash if this
2085 * is not a relative path and the end was reached
2086 * on a backreference.
2087 */
2088 if (!relative && (src == end)) {
2089 dst++;
2090 }
2091 }
2092
2093 if (done) goto length; /* Skip the copy. */
2094 src++;
2095
2096 *changed = 1;
2097 }
2098
2099 /* Relative Self-reference? */
2100 else if (dst == input) {
2101 *changed = 1;
2102
2103 /* Ignore. */
2104
2105 if (done) goto length; /* Skip the copy. */
2106 src++;
2107 }
2108
2109 /* Self-reference? */
2110 else if (*(dst - 1) == '/') {
2111 *changed = 1;
2112
2113 /* Ignore. */
2114
2115 if (done) goto length; /* Skip the copy. */
2116 dst--;
2117 src++;
2118 }
2119 }
2120
2121 /* Found a regular path segment. */
2122 else if (dst > input) {
2123 hitroot = 0;
2124 }
2125
2126 copy:
2127 /*** Copy the byte if required. ***/
2128
2129 /* Skip to the last forward slash when multiple are used. */
2130 if (*src == '/') {
2131 unsigned char *oldsrc = src;
2132
2133 while ( (src < end)
2134 && ((*(src + 1) == '/') || (win && (*(src + 1) == '\\'))) )
2135 {
2136 src++;
2137 }
2138 if (oldsrc != src) *changed = 1;
2139
2140 /* Do not copy the forward slash to the root
2141 * if it is not a relative path. Instead
2142 * move over the slash to the next segment.
2143 */
2144 if (relative && (dst == input)) {
2145 src++;
2146 goto length; /* Skip the copy */
2147 }
2148 }
2149
2150 *(dst++) = *(src++);
2151
2152 length:
2153 ldst = (dst - input);
2154 }
2155
2156 /* Make sure that there is not a trailing slash in the
2157 * normalized form if there was not one in the original form.
2158 */
2159 if (!trailing && (dst > input) && *(dst - 1) == '/') {
2160 ldst--;
2161 dst--;
2162 }
2163
2164 /* Always NUL terminate */
2165 *dst = '\0';
2166
2167 return ldst;
2168 }
2169
modsec_build(apr_pool_t * mp)2170 char *modsec_build(apr_pool_t *mp) {
2171 return apr_psprintf(mp, "%02i%02i%02i%1i%02i",
2172 atoi(MODSEC_VERSION_MAJOR),
2173 atoi(MODSEC_VERSION_MINOR),
2174 atoi(MODSEC_VERSION_MAINT),
2175 get_modsec_build_type(NULL),
2176 atoi(MODSEC_VERSION_RELEASE));
2177 }
2178
is_empty_string(const char * string)2179 int is_empty_string(const char *string) {
2180 unsigned int i;
2181
2182 if (string == NULL) return 1;
2183
2184 for(i = 0; string[i] != '\0'; i++) {
2185 if (!isspace(string[i])) {
2186 return 0;
2187 }
2188 }
2189
2190 return 1;
2191 }
2192
resolve_relative_path(apr_pool_t * pool,const char * parent_filename,const char * filename)2193 char *resolve_relative_path(apr_pool_t *pool, const char *parent_filename, const char *filename) {
2194 if (filename == NULL) return NULL;
2195 // TODO Support paths on operating systems other than Unix.
2196 if (filename[0] == '/') return (char *)filename;
2197
2198 return apr_pstrcat(pool, apr_pstrndup(pool, parent_filename,
2199 strlen(parent_filename) - strlen(apr_filepath_name_get(parent_filename))),
2200 filename, NULL);
2201 }
2202
2203 /**
2204 * Decode a string that contains CSS-escaped characters.
2205 *
2206 * References:
2207 * http://www.w3.org/TR/REC-CSS2/syndata.html#q4
2208 * http://www.unicode.org/roadmaps/
2209 */
css_decode_inplace(unsigned char * input,long int input_len)2210 int css_decode_inplace(unsigned char *input, long int input_len) {
2211 unsigned char *d = (unsigned char *)input;
2212 long int i, j, count;
2213
2214 if (input == NULL) return -1;
2215
2216 i = count = 0;
2217 while (i < input_len) {
2218
2219 /* Is the character a backslash? */
2220 if (input[i] == '\\') {
2221
2222 /* Is there at least one more byte? */
2223 if (i + 1 < input_len) {
2224 i++; /* We are not going to need the backslash. */
2225
2226 /* Check for 1-6 hex characters following the backslash */
2227 j = 0;
2228 while ( (j < 6)
2229 && (i + j < input_len)
2230 && (VALID_HEX(input[i + j])))
2231 {
2232 j++;
2233 }
2234
2235 if (j > 0) { /* We have at least one valid hexadecimal character. */
2236 int fullcheck = 0;
2237
2238 /* For now just use the last two bytes. */
2239 switch (j) {
2240 /* Number of hex characters */
2241 case 1:
2242 *d++ = xsingle2c(&input[i]);
2243 break;
2244
2245 case 2:
2246 case 3:
2247 /* Use the last two from the end. */
2248 *d++ = x2c(&input[i + j - 2]);
2249 break;
2250
2251 case 4:
2252 /* Use the last two from the end, but request
2253 * a full width check.
2254 */
2255 *d = x2c(&input[i + j - 2]);
2256 fullcheck = 1;
2257 break;
2258
2259 case 5:
2260 /* Use the last two from the end, but request
2261 * a full width check if the number is greater
2262 * or equal to 0xFFFF.
2263 */
2264 *d = x2c(&input[i + j - 2]);
2265
2266 /* Do full check if first byte is 0 */
2267 if (input[i] == '0') {
2268 fullcheck = 1;
2269 }
2270 else {
2271 d++;
2272 }
2273 break;
2274
2275 case 6:
2276 /* Use the last two from the end, but request
2277 * a full width check if the number is greater
2278 * or equal to 0xFFFF.
2279 */
2280 *d = x2c(&input[i + j - 2]);
2281
2282 /* Do full check if first/second bytes are 0 */
2283 if ( (input[i] == '0')
2284 && (input[i + 1] == '0')
2285 ) {
2286 fullcheck = 1;
2287 }
2288 else {
2289 d++;
2290 }
2291 break;
2292 }
2293
2294 /* Full width ASCII (0xff01 - 0xff5e) needs 0x20 added */
2295 if (fullcheck) {
2296 if ( (*d > 0x00) && (*d < 0x5f)
2297 && ((input[i + j - 3] == 'f') ||
2298 (input[i + j - 3] == 'F'))
2299 && ((input[i + j - 4] == 'f') ||
2300 (input[i + j - 4] == 'F')))
2301 {
2302 (*d) += 0x20;
2303 }
2304
2305 d++;
2306 }
2307
2308 /* We must ignore a single whitespace after a hex escape */
2309 if ((i + j < input_len) && isspace(input[i + j])) {
2310 j++;
2311 }
2312
2313 /* Move over. */
2314 count++;
2315 i += j;
2316 }
2317
2318 /* No hexadecimal digits after backslash */
2319 else if (input[i] == '\n') {
2320 /* A newline character following backslash is ignored. */
2321 i++;
2322 }
2323
2324 /* The character after backslash is not a hexadecimal digit, nor a newline. */
2325 else {
2326 /* Use one character after backslash as is. */
2327 *d++ = input[i++];
2328 count++;
2329 }
2330 }
2331
2332 /* No characters after backslash. */
2333 else {
2334 /* Do not include backslash in output (continuation to nothing) */
2335 i++;
2336 }
2337 }
2338
2339 /* Character is not a backslash. */
2340 else {
2341 /* Copy one normal character to output. */
2342 *d++ = input[i++];
2343 count++;
2344 }
2345 }
2346
2347 /* Terminate output string. */
2348 *d = '\0';
2349
2350 return count;
2351 }
2352
2353 /**
2354 * Translate UNIX octal umask/mode to APR apr_fileperms_t
2355 */
mode2fileperms(int mode)2356 apr_fileperms_t mode2fileperms(int mode) {
2357 apr_fileperms_t perms = 0;
2358
2359 if (mode & S_IXOTH) perms |= APR_WEXECUTE;
2360 if (mode & S_IWOTH) perms |= APR_WWRITE;
2361 if (mode & S_IROTH) perms |= APR_WREAD;
2362 if (mode & S_IXGRP) perms |= APR_GEXECUTE;
2363 if (mode & S_IWGRP) perms |= APR_GWRITE;
2364 if (mode & S_IRGRP) perms |= APR_GREAD;
2365 if (mode & S_IXUSR) perms |= APR_UEXECUTE;
2366 if (mode & S_IWUSR) perms |= APR_UWRITE;
2367 if (mode & S_IRUSR) perms |= APR_UREAD;
2368 if (mode & S_ISVTX) perms |= APR_WSTICKY;
2369 if (mode & S_ISGID) perms |= APR_GSETID;
2370 if (mode & S_ISUID) perms |= APR_USETID;
2371
2372 return perms;
2373 }
2374
2375 /**
2376 * Generate a single variable.
2377 */
construct_single_var(modsec_rec * msr,char * name)2378 char *construct_single_var(modsec_rec *msr, char *name) {
2379 char *varname = NULL;
2380 char *param = NULL;
2381 msre_var *var = NULL;
2382 msre_var *vx = NULL;
2383 char *my_error_msg = NULL;
2384
2385 /* Extract variable name and its parameter from the script. */
2386 varname = apr_pstrdup(msr->mp, name);
2387 param = strchr(varname, '.');
2388 if (param != NULL) {
2389 *param = '\0';
2390 param++;
2391 }
2392
2393 /* Resolve variable. */
2394 var = msre_create_var_ex(msr->mp, msr->modsecurity->msre,
2395 varname, param, msr, &my_error_msg);
2396 if (var == NULL) return NULL;
2397
2398 /* Generate variable. */
2399 vx = generate_single_var(msr, var, NULL, NULL, msr->msc_rule_mptmp);
2400 if (vx == NULL) return NULL;
2401
2402 return (char *)vx->value;
2403 }
2404
2405 /**
2406 * @brief Transforms an apr_array_header_t to a text buffer
2407 *
2408 * Converts an apr_array_header_t into a plain/text buffer in a Key: Pair
2409 * format. The generated buffer is not null terminated.
2410 *
2411 * If called with `buffer_length` set to 0 or with `buffer` set to NULL,
2412 * it will _not_ fill any buffer, instead, it will return the length, that
2413 * will be needed to save the entire content of `arr` into a buffer.
2414 *
2415 * @warning return is not NULL-terminated.
2416 * @note memory management is in the responsibility of the caller.
2417 *
2418 * @param arr apr_array_header_t to be iterated.
2419 * @param buffer pointer to the destination buffer.
2420 * @param buffer_length length that will fully fill the buffer.
2421 * @retval -1 Something went wrong in the process. Do not trust in
2422 * buffer content.
2423 * @retval n>0 size of the [needed|] buffer.
2424 *
2425 */
msc_headers_to_buffer(const apr_array_header_t * arr,char * buffer,int buffer_length)2426 int msc_headers_to_buffer(const apr_array_header_t *arr, char *buffer,
2427 int buffer_length)
2428 {
2429 int headers_length = 0;
2430 int write_to_buffer = 0;
2431 int i = 0;
2432 const apr_table_entry_t *te = NULL;
2433
2434 if (buffer != NULL && buffer_length > 0) {
2435 write_to_buffer = 1;
2436 }
2437
2438 te = (apr_table_entry_t *)arr->elts;
2439 for (i = 0; i < arr->nelts; i++) {
2440 char *value = te[i].val;
2441 char *key = te[i].key;
2442 headers_length = headers_length + strlen(value) + strlen(key) + /* \n: */ 1 +
2443 /* colum */ 1 + /* space: */ 1 ;
2444
2445 if (write_to_buffer == 1) {
2446 if (buffer_length < headers_length) {
2447 headers_length = -1;
2448 goto not_enough_memory;
2449 }
2450
2451 sprintf(buffer, "%s%s: %s\n", buffer, key, value);
2452 }
2453 }
2454
2455 headers_length++; /* Save space for an extra '\n' between the hedaers and the request body */
2456 if (write_to_buffer) {
2457 if (buffer_length < headers_length) {
2458 headers_length = -1;
2459 goto not_enough_memory;
2460 }
2461
2462 buffer[headers_length-1] = '\n';
2463 }
2464
2465 not_enough_memory:
2466 return headers_length;
2467 }
2468
read_line(char * buf,int len,FILE * fp)2469 int read_line(char *buf, int len, FILE *fp)
2470 {
2471 char *tmp;
2472
2473 if (buf == NULL)
2474 {
2475 return -1;
2476 }
2477
2478 memset(buf, '\0', len*sizeof(char));
2479
2480 if (fgets(buf, len, fp) == NULL)
2481 {
2482 *buf = '\0';
2483 return 0;
2484 }
2485 else
2486 {
2487 if ((tmp = strrchr(buf, '\n')) != NULL)
2488 {
2489 *tmp = '\0';
2490 }
2491 }
2492
2493 return 1;
2494 }
2495
create_radix_tree(apr_pool_t * mp,TreeRoot ** rtree,char ** error_msg)2496 int create_radix_tree(apr_pool_t *mp, TreeRoot **rtree, char **error_msg)
2497 {
2498 *rtree = apr_palloc(mp, sizeof(TreeRoot));
2499 if (*rtree == NULL)
2500 {
2501 *error_msg = apr_psprintf(mp, "Failed allocating " \
2502 "memory to TreeRoot.");
2503 goto root_node_failed;
2504 }
2505 memset(*rtree, 0, sizeof(TreeRoot));
2506
2507 (*rtree)->ipv4_tree = CPTCreateRadixTree(mp);
2508 if ((*rtree)->ipv4_tree == NULL)
2509 {
2510 *error_msg = apr_psprintf(mp, "IPmatch: Tree initialization " \
2511 "failed.");
2512 goto ipv4_tree_failed;
2513 }
2514
2515 (*rtree)->ipv6_tree = CPTCreateRadixTree(mp);
2516 if ((*rtree)->ipv6_tree == NULL)
2517 {
2518 *error_msg = apr_psprintf(mp, "IPmatch: Tree initialization " \
2519 "failed.");
2520 goto ipv6_tree_failed;
2521 }
2522
2523 return 0;
2524
2525 ipv6_tree_failed:
2526 ipv4_tree_failed:
2527 root_node_failed:
2528 return -1;
2529 }
2530
2531
ip_tree_from_file(TreeRoot ** rtree,char * uri,apr_pool_t * mp,char ** error_msg)2532 int ip_tree_from_file(TreeRoot **rtree, char *uri,
2533 apr_pool_t *mp, char **error_msg)
2534 {
2535 TreeNode *tnode = NULL;
2536 apr_status_t rc;
2537 int line = 0;
2538 apr_file_t *fd;
2539 char *start;
2540 char *end;
2541 char buf[HUGE_STRING_LEN + 1]; // FIXME: 2013-10-29 zimmerle: dynamic?
2542 char errstr[1024]; //
2543
2544 if (create_radix_tree(mp, rtree, error_msg))
2545 {
2546 return -1;
2547 }
2548
2549 rc = apr_file_open(&fd, uri, APR_READ | APR_BUFFERED | APR_FILE_NOCLEANUP,
2550 0, mp);
2551
2552 if (rc != APR_SUCCESS)
2553 {
2554 *error_msg = apr_psprintf(mp, "Could not open ipmatch file \"%s\": %s",
2555 uri, apr_strerror(rc, errstr, 1024));
2556 return -1;
2557 }
2558
2559 while ((rc = apr_file_gets(buf, HUGE_STRING_LEN, fd)) != APR_EOF)
2560 {
2561 line++;
2562 if (rc != APR_SUCCESS)
2563 {
2564 *error_msg = apr_psprintf(mp, "Could not read \"%s\" line %d: %s",
2565 uri, line, apr_strerror(rc, errstr, 1024));
2566 return -1;
2567 }
2568
2569 start = buf;
2570
2571 while ((apr_isspace(*start) != 0) && (*start != '\0'))
2572 {
2573 start++;
2574 }
2575
2576 for (end = start; end != NULL || *end != '\0' || *end != '\n'; end++)
2577 {
2578 if (apr_isxdigit(*end) || *end == '.' || *end == '/' || *end == ':')
2579 {
2580 continue;
2581 }
2582
2583 if (*end != '\n')
2584 {
2585 *error_msg = apr_psprintf(mp, "Invalid char \"%c\" in line %d " \
2586 "of file %s", *end, line, uri);
2587 }
2588
2589 break;
2590 }
2591
2592 *end = '\0';
2593
2594 if ((start == end) || (*start == '#'))
2595 {
2596 continue;
2597 }
2598
2599 if (strchr(start, ':') == NULL)
2600 {
2601 tnode = TreeAddIP(start, (*rtree)->ipv4_tree, IPV4_TREE);
2602 }
2603 #if APR_HAVE_IPV6
2604 else
2605 {
2606 tnode = TreeAddIP(start, (*rtree)->ipv6_tree, IPV6_TREE);
2607 }
2608 #endif
2609
2610 if (tnode == NULL)
2611 {
2612 *error_msg = apr_psprintf(mp, "Could not add entry " \
2613 "\"%s\" in line %d of file %s to IP list", start, line, uri);
2614 return -1;
2615 }
2616 }
2617
2618 if (fd != NULL)
2619 {
2620 apr_file_close(fd);
2621 }
2622
2623 return 0;
2624 }
2625
2626 #ifdef WITH_CURL
ip_tree_from_uri(TreeRoot ** rtree,char * uri,apr_pool_t * mp,char ** error_msg)2627 int ip_tree_from_uri(TreeRoot **rtree, char *uri,
2628 apr_pool_t *mp, char **error_msg)
2629 {
2630 TreeNode *tnode = NULL;
2631 apr_status_t rc;
2632 int line = 0;
2633 apr_file_t *fd;
2634 char *start;
2635 int res;
2636
2637 struct msc_curl_memory_buffer_t chunk;
2638 char *word = NULL;
2639 char *brkt = NULL;
2640 char *sep = "\n";
2641
2642 if (create_radix_tree(mp, rtree, error_msg))
2643 {
2644 return -1;
2645 }
2646
2647 res = msc_remote_download_content(mp, uri, NULL, &chunk, error_msg);
2648 if (res)
2649 {
2650 return res;
2651 }
2652
2653 for (word = strtok_r(chunk.memory, sep, &brkt);
2654 word;
2655 word = strtok_r(NULL, sep, &brkt))
2656 {
2657 int i = 0;
2658 line++;
2659
2660 /* Ignore empty lines and comments */
2661 if (*word == '#') continue;
2662
2663 for (i = 0; i < strlen(word); i++)
2664 {
2665 if (apr_isxdigit(word[i]) || word[i] == '.' || word[i] == '/' || word[i] == ':' || word[i] == '\n')
2666 {
2667 continue;
2668 }
2669
2670 *error_msg = apr_psprintf(mp, "Invalid char \"%c\" in line %d " \
2671 "of uri %s", word[i], line, uri);
2672 return -1;
2673 }
2674
2675 if (strchr(word, ':') == NULL)
2676 {
2677 tnode = TreeAddIP(word, (*rtree)->ipv4_tree, IPV4_TREE);
2678 }
2679 #if APR_HAVE_IPV6
2680 else
2681 {
2682 tnode = TreeAddIP(word, (*rtree)->ipv6_tree, IPV6_TREE);
2683 }
2684 #endif
2685
2686 if (tnode == NULL)
2687 {
2688 *error_msg = apr_psprintf(mp, "Could not add entry " \
2689 "\"%s\" in line %d of file %s to IP list", word, line, uri);
2690 return -1;
2691 }
2692
2693 }
2694
2695 msc_remote_clean_chunk(&chunk);
2696
2697 return 0;
2698 }
2699 #endif
2700
tree_contains_ip(apr_pool_t * mp,TreeRoot * rtree,const char * value,modsec_rec * msr,char ** error_msg)2701 int tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree,
2702 const char *value, modsec_rec *msr, char **error_msg)
2703 {
2704 struct in_addr in;
2705 #if APR_HAVE_IPV6
2706 struct in6_addr in6;
2707 #endif
2708
2709 if (rtree == NULL)
2710 {
2711 return 0;
2712 }
2713
2714 if (strchr(value, ':') == NULL) {
2715 if (inet_pton(AF_INET, value, &in) <= 0) {
2716 *error_msg = apr_psprintf(mp, "IPmatch: bad IPv4 " \
2717 "specification \"%s\".", value);
2718 return -1;
2719 }
2720
2721 if (CPTIpMatch(msr, (unsigned char *)&in.s_addr, rtree->ipv4_tree,
2722 IPV4_TREE) != NULL) {
2723 return 1;
2724 }
2725 }
2726 #if APR_HAVE_IPV6
2727 else {
2728 if (inet_pton(AF_INET6, value, &in6) <= 0) {
2729 *error_msg = apr_psprintf(mp, "IPmatch: bad IPv6 " \
2730 "specification \"%s\".", value);
2731 return -1;
2732 }
2733
2734 if (CPTIpMatch(msr, (unsigned char *)&in6.s6_addr, rtree->ipv6_tree,
2735 IPV6_TREE) != NULL) {
2736 return 1;
2737 }
2738 }
2739 #endif
2740
2741 return 0;
2742 }
2743
ip_tree_from_param(apr_pool_t * mp,char * param,TreeRoot ** rtree,char ** error_msg)2744 int ip_tree_from_param(apr_pool_t *mp,
2745 char *param, TreeRoot **rtree, char **error_msg)
2746 {
2747 char *saved = NULL;
2748 char *str = NULL;
2749 TreeNode *tnode = NULL;
2750
2751 if (create_radix_tree(mp, rtree, error_msg))
2752 {
2753 return -1;
2754 }
2755
2756 str = apr_strtok(param, ",", &saved);
2757 while (str != NULL)
2758 {
2759 if (strchr(str, ':') == NULL)
2760 {
2761 tnode = TreeAddIP(str, (*rtree)->ipv4_tree, IPV4_TREE);
2762 }
2763 #if APR_HAVE_IPV6
2764 else
2765 {
2766 tnode = TreeAddIP(str, (*rtree)->ipv6_tree, IPV6_TREE);
2767 }
2768 #endif
2769 if (tnode == NULL)
2770 {
2771 *error_msg = apr_psprintf(mp, "Could not add entry " \
2772 "\"%s\" from: %s.", str, param);
2773 return -1;
2774 }
2775
2776 str = apr_strtok(NULL, ",", &saved);
2777 }
2778
2779 return 0;
2780 }
2781
2782 #ifdef WITH_CURL
msc_curl_write_memory_cb(apr_pool_t * mp,void * contents,size_t size,size_t nmemb,void * userp,char ** error_msg)2783 size_t msc_curl_write_memory_cb(apr_pool_t *mp, void *contents, size_t size,
2784 size_t nmemb, void *userp, char **error_msg)
2785 {
2786 size_t realsize = size * nmemb;
2787 struct msc_curl_memory_buffer_t *mem = (struct msc_curl_memory_buffer_t *)userp;
2788
2789 if (mem->size == 0)
2790 {
2791 mem->memory = malloc(realsize + 1);
2792 if (mem->memory == NULL) {
2793 *error_msg = apr_psprintf(mp, "Unable to allocate buffer for mem->memory");
2794 return 0;
2795 }
2796 memset(mem->memory, '\0', sizeof(realsize + 1));
2797 }
2798 else
2799 {
2800 void *tmp;
2801 tmp = mem->memory;
2802 tmp = realloc(mem->memory, mem->size + realsize + 1);
2803 if (tmp != NULL) {
2804 mem->memory = tmp;
2805 }
2806 memset(mem->memory + mem->size, '\0', sizeof(realsize + 1));
2807 }
2808
2809 if (mem->memory == NULL) {
2810 /* out of memory! */
2811 return 0;
2812 }
2813
2814 memcpy(&(mem->memory[mem->size]), contents, realsize);
2815 mem->size += realsize;
2816 mem->memory[mem->size] = 0;
2817
2818 return realsize;
2819 }
2820 #endif
2821
2822 #ifdef WIN32
strtok_r(char * str,const char * delim,char ** nextp)2823 char* strtok_r(
2824 char *str,
2825 const char *delim,
2826 char **nextp)
2827 {
2828 char *ret;
2829
2830 if (str == NULL)
2831 {
2832 str = *nextp;
2833 }
2834 str += strspn(str, delim);
2835 if (*str == '\0')
2836 {
2837 return NULL;
2838 }
2839 ret = str;
2840 str += strcspn(str, delim);
2841 if (*str)
2842 {
2843 *str++ = '\0';
2844 }
2845 *nextp = str;
2846 return ret;
2847 }
2848 #endif
2849
2850