Imported Upstream version 2.5.11
[libapache-mod-security.git] / apache2 / re_tfns.c
1 /*
2  * ModSecurity for Apache 2.x, http://www.modsecurity.org/
3  * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/)
4  *
5  * This product is released under the terms of the General Public Licence,
6  * version 2 (GPLv2). Please refer to the file LICENSE (included with this
7  * distribution) which contains the complete text of the licence.
8  *
9  * There are special exceptions to the terms and conditions of the GPL
10  * as it is applied to this software. View the full text of the exception in
11  * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software
12  * distribution.
13  *
14  * If any of the files related to licensing are missing or if you have any
15  * other questions related to licensing please contact Breach Security, Inc.
16  * directly using the email address support@breach.com.
17  *
18  */
19 #include <ctype.h>
20
21 #include "apr_md5.h"
22 #include "apr_sha1.h"
23 #include "apr_base64.h"
24
25 #include "re.h"
26 #include "msc_util.h"
27
28 /* lowercase */
29
30 static int msre_fn_lowercase_execute(apr_pool_t *mptmp, unsigned char *input,
31     long int input_len, char **rval, long int *rval_len)
32 {
33     long int i;
34     int changed = 0;
35
36     if (rval == NULL) return -1;
37     *rval = NULL;
38
39     i = 0;
40     while(i < input_len) {
41         int x = input[i];
42         input[i] = tolower(x);
43         if (x != input[i]) changed = 1;
44         i++;
45     }
46
47     *rval = (char *)input;
48     *rval_len = input_len;
49
50     return changed;
51 }
52
53 /* trimLeft */
54
55 static int msre_fn_trimLeft_execute(apr_pool_t *mptmp, unsigned char *input,
56     long int input_len, char **rval, long int *rval_len)
57 {
58     long int i;
59
60     *rval = (char *)input;
61     for (i = 0; i < input_len; i++) {
62         if (isspace(**rval) == 0) {
63             break;
64         }
65         (*rval)++;
66     }
67
68     *rval_len = input_len - i;
69
70     return (*rval_len == input_len ? 0 : 1);
71 }
72
73 /* trimRight */
74
75 static int msre_fn_trimRight_execute(apr_pool_t *mptmp, unsigned char *input,
76     long int input_len, char **rval, long int *rval_len)
77 {
78     long int i;
79
80     *rval = (char *)input;
81     for (i = input_len - 1; i >= 0; i--) {
82         if (isspace((*rval)[i]) == 0) {
83             break;
84         }
85         (*rval)[i] = '\0';
86     }
87
88     *rval_len = i + 1;
89
90     return (*rval_len == input_len ? 0 : 1);
91 }
92
93 /* trim */
94
95 static int msre_fn_trim_execute(apr_pool_t *mptmp, unsigned char *input,
96     long int input_len, char **rval, long int *rval_len)
97 {
98     int rc = 0;
99
100     rc = msre_fn_trimLeft_execute(mptmp, input, input_len, rval, rval_len);
101     if (rc == 1) {
102         rc = msre_fn_trimRight_execute(mptmp, (unsigned char *)*rval, *rval_len, rval, rval_len);
103     }
104     else {
105         rc = msre_fn_trimRight_execute(mptmp, input, input_len, rval, rval_len);
106     }
107
108     return (*rval_len == input_len ? 0 : 1);
109 }
110
111 /* removeNulls */
112
113 static int msre_fn_removeNulls_execute(apr_pool_t *mptmp, unsigned char *input,
114     long int input_len, char **rval, long int *rval_len)
115 {
116     long int i, j;
117     int changed = 0;
118
119     i = j = 0;
120     while(i < input_len) {
121         if (input[i] == '\0') {
122             changed = 1;
123         } else {
124             input[j] = input[i];
125             j++;
126         }
127         i++;
128     }
129
130     *rval = (char *)input;
131     *rval_len = j;
132
133     return changed;
134 }
135
136 /* replaceNulls */
137
138 static int msre_fn_replaceNulls_execute(apr_pool_t *mptmp, unsigned char *input,
139     long int input_len, char **rval, long int *rval_len)
140 {
141     long int i;
142     int changed = 0;
143
144     if (rval == NULL) return -1;
145     *rval = NULL;
146
147     i = 0;
148     while(i < input_len) {
149         if (input[i] == '\0') {
150             changed = 1;
151             input[i] = ' ';
152         }
153         i++;
154     }
155
156     *rval = (char *)input;
157     *rval_len = input_len;
158
159     return changed;
160 }
161
162 /* compressWhitespace */
163
164 static int msre_fn_compressWhitespace_execute(apr_pool_t *mptmp, unsigned char *input,
165     long int input_len, char **rval, long int *rval_len)
166 {
167     long int i, j, count;
168     int changed = 0;
169     int inwhitespace = 0;
170
171     i = j = count = 0;
172     while(i < input_len) {
173         if (isspace(input[i])||(input[i] == NBSP)) {
174             if (inwhitespace) changed = 1;
175             inwhitespace = 1;
176             count++;
177         } else {
178             inwhitespace = 0;
179             if (count) {
180                 input[j] = ' ';
181                 count = 0;
182                 j++;
183             }
184             input[j] = input[i];
185             j++;
186         }
187         i++;
188     }
189
190     if (count) {
191         input[j] = ' ';
192         j++;
193     }
194
195     *rval = (char *)input;
196     *rval_len = j;
197
198     return changed;
199 }
200
201 /* cssDecode */
202
203 static int msre_fn_cssDecode_execute(apr_pool_t *mptmp, unsigned char *input,
204     long int input_len, char **rval, long int *rval_len)
205 {
206     long int length;
207
208     length = css_decode_inplace(input, input_len);
209     *rval = (char *)input;
210     *rval_len = length;
211
212     return (*rval_len == input_len ? 0 : 1);
213 }
214
215 /* removeWhitespace */
216
217 static int msre_fn_removeWhitespace_execute(apr_pool_t *mptmp, unsigned char *input,
218     long int input_len, char **rval, long int *rval_len)
219 {
220     long int i, j;
221     int changed = 0;
222
223     i = j = 0;
224     while(i < input_len) {
225         if (isspace(input[i])||(input[i] == NBSP)) {
226             /* do nothing */
227             changed = 1;
228         } else {
229             input[j] = input[i];
230             j++;
231         }
232         i++;
233     }
234
235     *rval = (char *)input;
236     *rval_len = j;
237
238     return changed;
239 }
240
241 /* replaceComments */
242
243 static int msre_fn_replaceComments_execute(apr_pool_t *mptmp, unsigned char *input,
244     long int input_len, char **rval, long int *rval_len)
245 {
246     long int i, j, incomment;
247     int changed = 0;
248
249     i = j = incomment = 0;
250     while(i < input_len) {
251         if (incomment == 0) {
252             if ((input[i] == '/')&&(i + 1 < input_len)&&(input[i + 1] == '*')) {
253                 changed = 1;
254                 incomment = 1;
255                 i += 2;
256             } else {
257                 input[j] = input[i];
258                 i++;
259                 j++;
260             }
261         } else {
262             if ((input[i] == '*')&&(i + 1 < input_len)&&(input[i + 1] == '/')) {
263                 incomment = 0;
264                 i += 2;
265                 input[j] = ' ';
266                 j++;
267             } else {
268                 i++;
269             }
270         }
271     }
272
273     if (incomment) {
274         input[j++] = ' ';
275     }
276
277     *rval = (char *)input;
278     *rval_len = j;
279
280     return changed;
281 }
282
283 /* jsDecode */
284
285 static int msre_fn_jsDecode_execute(apr_pool_t *mptmp, unsigned char *input,
286     long int input_len, char **rval, long int *rval_len)
287 {
288     long int length;
289
290     length = js_decode_nonstrict_inplace(input, input_len);
291     *rval = (char *)input;
292     *rval_len = length;
293
294     return (*rval_len == input_len ? 0 : 1);
295 }
296
297 /* urlDecode */
298
299 static int msre_fn_urlDecode_execute(apr_pool_t *mptmp, unsigned char *input,
300     long int input_len, char **rval, long int *rval_len)
301 {
302     long int length;
303     int invalid_count;
304     int changed;
305
306     length = urldecode_nonstrict_inplace_ex(input, input_len, &invalid_count, &changed);
307     *rval = (char *)input;
308     *rval_len = length;
309
310     return changed;
311 }
312
313 /* urlDecodeUni */
314
315 static int msre_fn_urlDecodeUni_execute(apr_pool_t *mptmp, unsigned char *input,
316     long int input_len, char **rval, long int *rval_len)
317 {
318     long int length;
319     int changed;
320
321     length = urldecode_uni_nonstrict_inplace_ex(input, input_len, &changed);
322     *rval = (char *)input;
323     *rval_len = length;
324
325     return changed;
326 }
327
328 /* urlEncode */
329
330 static int msre_fn_urlEncode_execute(apr_pool_t *mptmp, unsigned char *input,
331     long int input_len, char **rval, long int *rval_len)
332 {
333     int changed;
334
335     *rval = url_encode(mptmp, (char *)input, input_len, &changed);
336     *rval_len = strlen(*rval);
337
338     return changed;
339 }
340
341 /* base64Encode */
342
343 static int msre_fn_base64Encode_execute(apr_pool_t *mptmp, unsigned char *input,
344     long int input_len, char **rval, long int *rval_len)
345 {
346     *rval_len = apr_base64_encode_len(input_len); /* returns len with NULL byte included */
347     *rval = apr_palloc(mptmp, *rval_len);
348     apr_base64_encode(*rval, (const char *)input, input_len);
349     (*rval_len)--;
350
351     return *rval_len ? 1 : 0;
352 }
353
354 /* base64Decode */
355
356 static int msre_fn_base64Decode_execute(apr_pool_t *mptmp, unsigned char *input,
357     long int input_len, char **rval, long int *rval_len)
358 {
359     *rval_len = apr_base64_decode_len((const char *)input); /* returns len with NULL byte included */
360     *rval = apr_palloc(mptmp, *rval_len);
361     *rval_len = apr_base64_decode(*rval, (const char *)input);
362
363     return *rval_len ? 1 : 0;
364 }
365
366 /* length */
367
368 static int msre_fn_length_execute(apr_pool_t *mptmp, unsigned char *input,
369     long int input_len, char **rval, long int *rval_len)
370 {
371     *rval = apr_psprintf(mptmp, "%ld", input_len);
372     *rval_len = strlen(*rval);
373
374     return 1;
375 }
376
377 /* md5 */
378
379 static int msre_fn_md5_execute(apr_pool_t *mptmp, unsigned char *input,
380     long int input_len, char **rval, long int *rval_len)
381 {
382     unsigned char digest[APR_MD5_DIGESTSIZE];
383
384     apr_md5(digest, input, input_len);
385
386     *rval_len = APR_MD5_DIGESTSIZE;
387     *rval = apr_pstrmemdup(mptmp, (const char *)digest, APR_MD5_DIGESTSIZE);
388
389     return 1;
390 }
391
392 /* sha1 */
393
394 static int msre_fn_sha1_execute(apr_pool_t *mptmp, unsigned char *input,
395     long int input_len, char **rval, long int *rval_len)
396 {
397     unsigned char digest[APR_SHA1_DIGESTSIZE];
398     apr_sha1_ctx_t context;
399
400     apr_sha1_init(&context);
401     apr_sha1_update(&context, (const char *)input, input_len);
402     apr_sha1_final(digest, &context);
403
404     *rval_len = APR_SHA1_DIGESTSIZE;
405     *rval = apr_pstrmemdup(mptmp, (const char *)digest, APR_SHA1_DIGESTSIZE);
406
407     return 1;
408 }
409
410 /* hexDecode */
411
412 static int msre_fn_hexDecode_execute(apr_pool_t *mptmp, unsigned char *input,
413     long int input_len, char **rval, long int *rval_len)
414 {
415     *rval_len = hex2bytes_inplace(input, input_len);
416     *rval = (char *)input;
417
418     return 1;
419 }
420
421 /* hexEncode */
422
423 static int msre_fn_hexEncode_execute(apr_pool_t *mptmp, unsigned char *input,
424     long int input_len, char **rval, long int *rval_len)
425 {
426     *rval = bytes2hex(mptmp, input, input_len);
427     *rval_len = strlen(*rval);
428
429     return 1;
430 }
431
432 /* htmlEntityDecode */
433
434 static int msre_fn_htmlEntityDecode_execute(apr_pool_t *mptmp, unsigned char *input,
435     long int input_len, char **rval, long int *rval_len)
436 {
437     *rval_len = html_entities_decode_inplace(mptmp, input, input_len);
438     *rval = (char *)input;
439
440     return (*rval_len == input_len ? 0 : 1);
441 }
442
443 /* escapeSeqDecode */
444
445 static int msre_fn_escapeSeqDecode_execute(apr_pool_t *mptmp, unsigned char *input,
446     long int input_len, char **rval, long int *rval_len)
447 {
448     *rval_len = ansi_c_sequences_decode_inplace(input, input_len);
449     *rval = (char *)input;
450
451     return (*rval_len == input_len ? 0 : 1);
452 }
453
454 /* normalisePath */
455
456 static int msre_fn_normalisePath_execute(apr_pool_t *mptmp, unsigned char *input,
457     long int input_len, char **rval, long int *rval_len)
458 {
459     int changed;
460
461     *rval_len = normalise_path_inplace(input, input_len, 0, &changed);
462     *rval = (char *)input;
463
464     return changed;
465 }
466
467 /* normalisePathWin */
468
469 static int msre_fn_normalisePathWin_execute(apr_pool_t *mptmp, unsigned char *input,
470     long int input_len, char **rval, long int *rval_len)
471 {
472     int changed;
473
474     *rval_len = normalise_path_inplace(input, input_len, 1, &changed);
475     *rval = (char *)input;
476
477     return changed;
478 }
479
480 /* parityEven7bit */
481
482 static int msre_fn_parityEven7bit_execute(apr_pool_t *mptmp, unsigned char *input,
483     long int input_len, char **rval, long int *rval_len)
484 {
485     long int i;
486     int changed = 0;
487
488     if (rval == NULL) return -1;
489     *rval = NULL;
490
491     i = 0;
492     while(i < input_len) {
493         unsigned int x = input[i];
494
495         input[i] ^= input[i] >> 4;
496         input[i] &= 0xf;
497
498         if ((0x6996 >> input[i]) & 1) {
499             input[i] = x | 0x80;
500         }
501         else {
502             input[i] = x & 0x7f;
503         }
504
505         if (x != input[i]) changed = 1;
506         i++;
507     }
508
509     *rval = (char *)input;
510     *rval_len = input_len;
511
512     return changed;
513 }
514
515 /* parityZero7bit */
516
517 static int msre_fn_parityZero7bit_execute(apr_pool_t *mptmp, unsigned char *input,
518     long int input_len, char **rval, long int *rval_len)
519 {
520     long int i;
521     int changed = 0;
522
523     if (rval == NULL) return -1;
524     *rval = NULL;
525
526     i = 0;
527     while(i < input_len) {
528         unsigned char c = input[i];
529         input[i] &= 0x7f;
530         if (c != input[i]) changed = 1;
531         i++;
532     }
533
534     *rval = (char *)input;
535     *rval_len = input_len;
536
537     return changed;
538 }
539
540 /* parityOdd7bit */
541
542 static int msre_fn_parityOdd7bit_execute(apr_pool_t *mptmp, unsigned char *input,
543     long int input_len, char **rval, long int *rval_len)
544 {
545     long int i;
546     int changed = 0;
547
548     if (rval == NULL) return -1;
549     *rval = NULL;
550
551     i = 0;
552     while(i < input_len) {
553         unsigned int x = input[i];
554
555         input[i] ^= input[i] >> 4;
556         input[i] &= 0xf;
557
558         if ((0x6996 >> input[i]) & 1) {
559             input[i] = x & 0x7f;
560         }
561         else {
562             input[i] = x | 0x80;
563         }
564
565         if (x != input[i]) changed = 1;
566         i++;
567     }
568
569     *rval = (char *)input;
570     *rval_len = input_len;
571
572     return changed;
573 }
574
575 /* ------------------------------------------------------------------------------ */
576
577 /**
578  * Registers one transformation function with the engine.
579  */
580 void msre_engine_tfn_register(msre_engine *engine, const char *name,
581     fn_tfn_execute_t execute)
582 {
583     msre_tfn_metadata *metadata = (msre_tfn_metadata *)apr_pcalloc(engine->mp,
584         sizeof(msre_tfn_metadata));
585     if (metadata == NULL) return;
586
587     metadata->name = name;
588     metadata->execute = execute;
589
590     apr_table_setn(engine->tfns, name, (void *)metadata);
591 }
592
593 /**
594  * Returns transformation function metadata given a name.
595  */
596 msre_tfn_metadata *msre_engine_tfn_resolve(msre_engine *engine, const char *name) {
597     return (msre_tfn_metadata *)apr_table_get(engine->tfns, name);
598 }
599
600 /**
601  * Register the default transformation functions.
602  */
603 void msre_engine_register_default_tfns(msre_engine *engine) {
604
605     /* none */
606     msre_engine_tfn_register(engine,
607         "none",
608         NULL
609     );
610
611     /* base64Decode */
612     msre_engine_tfn_register(engine,
613         "base64Decode",
614         msre_fn_base64Decode_execute
615     );
616
617     /* base64Encode */
618     msre_engine_tfn_register(engine,
619         "base64Encode",
620         msre_fn_base64Encode_execute
621     );
622
623     /* compressWhitespace */
624     msre_engine_tfn_register(engine,
625         "compressWhitespace",
626         msre_fn_compressWhitespace_execute
627     );
628
629     /* cssDecode */
630     msre_engine_tfn_register(engine,
631         "cssDecode",
632         msre_fn_cssDecode_execute
633     );
634
635     /* escapeSeqDecode */
636     msre_engine_tfn_register(engine,
637         "escapeSeqDecode",
638         msre_fn_escapeSeqDecode_execute
639     );
640
641     /* hexDecode */
642     msre_engine_tfn_register(engine,
643         "hexDecode",
644         msre_fn_hexDecode_execute
645     );
646
647     /* hexEncode */
648     msre_engine_tfn_register(engine,
649         "hexEncode",
650         msre_fn_hexEncode_execute
651     );
652
653     /* htmlEntityDecode */
654     msre_engine_tfn_register(engine,
655         "htmlEntityDecode",
656         msre_fn_htmlEntityDecode_execute
657     );
658
659     /* jsDecode */
660     msre_engine_tfn_register(engine,
661         "jsDecode",
662         msre_fn_jsDecode_execute
663     );
664
665     /* length */
666     msre_engine_tfn_register(engine,
667         "length",
668         msre_fn_length_execute
669     );
670
671     /* lowercase */
672     msre_engine_tfn_register(engine,
673         "lowercase",
674         msre_fn_lowercase_execute
675     );
676
677     /* md5 */
678     msre_engine_tfn_register(engine,
679         "md5",
680         msre_fn_md5_execute
681     );
682
683     /* normalisePath */
684     msre_engine_tfn_register(engine,
685         "normalisePath",
686         msre_fn_normalisePath_execute
687     );
688
689     /* normalisePathWin */
690     msre_engine_tfn_register(engine,
691         "normalisePathWin",
692         msre_fn_normalisePathWin_execute
693     );
694
695     /* parityEven7bit */
696     msre_engine_tfn_register(engine,
697         "parityEven7bit",
698         msre_fn_parityEven7bit_execute
699     );
700
701     /* parityZero7bit */
702     msre_engine_tfn_register(engine,
703         "parityZero7bit",
704         msre_fn_parityZero7bit_execute
705     );
706
707     /* parityOdd7bit */
708     msre_engine_tfn_register(engine,
709         "parityOdd7bit",
710         msre_fn_parityOdd7bit_execute
711     );
712
713     /* removeWhitespace */
714     msre_engine_tfn_register(engine,
715         "removeWhitespace",
716         msre_fn_removeWhitespace_execute
717     );
718
719     /* removeNulls */
720     msre_engine_tfn_register(engine,
721         "removeNulls",
722         msre_fn_removeNulls_execute
723     );
724
725     /* replaceNulls */
726     msre_engine_tfn_register(engine,
727         "replaceNulls",
728         msre_fn_replaceNulls_execute
729     );
730
731     /* replaceComments */
732     msre_engine_tfn_register(engine,
733         "replaceComments",
734         msre_fn_replaceComments_execute
735     );
736
737     /* sha1 */
738     msre_engine_tfn_register(engine,
739         "sha1",
740         msre_fn_sha1_execute
741     );
742
743     /* trim */
744     msre_engine_tfn_register(engine,
745         "trim",
746         msre_fn_trim_execute
747     );
748
749     /* trimLeft */
750     msre_engine_tfn_register(engine,
751         "trimLeft",
752         msre_fn_trimLeft_execute
753     );
754
755     /* trimRight */
756     msre_engine_tfn_register(engine,
757         "trimRight",
758         msre_fn_trimRight_execute
759     );
760
761     /* urlDecode */
762     msre_engine_tfn_register(engine,
763         "urlDecode",
764         msre_fn_urlDecode_execute
765     );
766
767     /* urlDecodeUni */
768     msre_engine_tfn_register(engine,
769         "urlDecodeUni",
770         msre_fn_urlDecodeUni_execute
771     );
772
773     /* urlEncode */
774     msre_engine_tfn_register(engine,
775         "urlEncode",
776         msre_fn_urlEncode_execute
777     );
778 }