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