PageRenderTime 150ms CodeModel.GetById 20ms app.highlight 104ms RepoModel.GetById 17ms app.codeStats 0ms

/apache2/re_tfns.c

https://github.com/peterwillcn/ModSecurity
C | 1051 lines | 1016 code | 7 blank | 28 comment | 3 complexity | 2fc58dd9d141c7eefe55e15f3e8f8336 MD5 | raw file
   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 <ctype.h>
  16
  17#include "apr_md5.h"
  18#include "apr_sha1.h"
  19#include "apr_base64.h"
  20
  21#include "msc_unicode.h"
  22#include "re.h"
  23#include "msc_util.h"
  24
  25/* cmdline */
  26
  27/**
  28* \brief cmdline transformation function
  29*
  30* \param mptmp Pointer to resource pool
  31* \param input Pointer to input data
  32* \param input_len Input data length
  33* \param rval Pointer to decoded buffer
  34* \param rval_len Decoded buffer length
  35*
  36* \retval 0 On failure
  37* \retval 1 On Success
  38*/
  39static int msre_fn_cmdline_execute(apr_pool_t *mptmp, unsigned char *input,
  40        long int input_len, char **rval, long int *rval_len)
  41{
  42    int space = 0;
  43    unsigned char *s = input;
  44
  45    if (rval == NULL) return -1;
  46
  47    *rval = (char *)input;
  48    /* Check characters */
  49    for ( ; *input; input++ ) {
  50        switch(*input) {
  51            /* remove some characters */
  52            case '"':
  53            case '\'':
  54            case '\\':
  55            case '^':
  56                continue;
  57                /* replace some characters to space (only one) */
  58            case ' ':
  59            case ',':
  60            case ';':
  61            case '\t':
  62            case '\r':
  63            case '\n':
  64                if (!space) {
  65                    *s++ = ' ';
  66                    space++;
  67                }
  68                break;
  69            case '/':
  70            case '(':
  71                /* remove space before / or ( */
  72                if (space) s--;
  73                space = 0;
  74                *s++ = *input;
  75                break;
  76                /* copy normal characters */
  77            default :
  78                *s++ = tolower(*input);
  79                space = 0;
  80        }
  81    }
  82
  83    *s = 0;
  84    *rval_len = strlen(*rval);
  85    return 1;
  86}
  87
  88/* lowercase */
  89
  90static int msre_fn_lowercase_execute(apr_pool_t *mptmp, unsigned char *input,
  91    long int input_len, char **rval, long int *rval_len)
  92{
  93    long int i;
  94    int changed = 0;
  95
  96    if (rval == NULL) return -1;
  97    *rval = NULL;
  98
  99    i = 0;
 100    while(i < input_len) {
 101        int x = input[i];
 102        input[i] = tolower(x);
 103        if (x != input[i]) changed = 1;
 104        i++;
 105    }
 106
 107    *rval = (char *)input;
 108    *rval_len = input_len;
 109
 110    return changed;
 111}
 112
 113/* trimLeft */
 114
 115static int msre_fn_trimLeft_execute(apr_pool_t *mptmp, unsigned char *input,
 116    long int input_len, char **rval, long int *rval_len)
 117{
 118    long int i;
 119
 120    *rval = (char *)input;
 121    for (i = 0; i < input_len; i++) {
 122        if (isspace(**rval) == 0) {
 123            break;
 124        }
 125        (*rval)++;
 126    }
 127
 128    *rval_len = input_len - i;
 129
 130    return (*rval_len == input_len ? 0 : 1);
 131}
 132
 133/* trimRight */
 134
 135static int msre_fn_trimRight_execute(apr_pool_t *mptmp, unsigned char *input,
 136    long int input_len, char **rval, long int *rval_len)
 137{
 138    long int i;
 139
 140    *rval = (char *)input;
 141    for (i = input_len - 1; i >= 0; i--) {
 142        if (isspace((*rval)[i]) == 0) {
 143            break;
 144        }
 145        (*rval)[i] = '\0';
 146    }
 147
 148    *rval_len = i + 1;
 149
 150    return (*rval_len == input_len ? 0 : 1);
 151}
 152
 153/* trim */
 154
 155static int msre_fn_trim_execute(apr_pool_t *mptmp, unsigned char *input,
 156    long int input_len, char **rval, long int *rval_len)
 157{
 158    int rc = 0;
 159
 160    rc = msre_fn_trimLeft_execute(mptmp, input, input_len, rval, rval_len);
 161    if (rc == 1) {
 162        rc = msre_fn_trimRight_execute(mptmp, (unsigned char *)*rval, *rval_len, rval, rval_len);
 163    }
 164    else {
 165        rc = msre_fn_trimRight_execute(mptmp, input, input_len, rval, rval_len);
 166    }
 167
 168    return (*rval_len == input_len ? 0 : 1);
 169}
 170
 171/* removeNulls */
 172
 173static int msre_fn_removeNulls_execute(apr_pool_t *mptmp, unsigned char *input,
 174    long int input_len, char **rval, long int *rval_len)
 175{
 176    long int i, j;
 177    int changed = 0;
 178
 179    i = j = 0;
 180    while(i < input_len) {
 181        if (input[i] == '\0') {
 182            changed = 1;
 183        } else {
 184            input[j] = input[i];
 185            j++;
 186        }
 187        i++;
 188    }
 189
 190    *rval = (char *)input;
 191    *rval_len = j;
 192
 193    return changed;
 194}
 195
 196/* replaceNulls */
 197
 198static int msre_fn_replaceNulls_execute(apr_pool_t *mptmp, unsigned char *input,
 199    long int input_len, char **rval, long int *rval_len)
 200{
 201    long int i;
 202    int changed = 0;
 203
 204    if (rval == NULL) return -1;
 205    *rval = NULL;
 206
 207    i = 0;
 208    while(i < input_len) {
 209        if (input[i] == '\0') {
 210            changed = 1;
 211            input[i] = ' ';
 212        }
 213        i++;
 214    }
 215
 216    *rval = (char *)input;
 217    *rval_len = input_len;
 218
 219    return changed;
 220}
 221
 222/* compressWhitespace */
 223
 224static int msre_fn_compressWhitespace_execute(apr_pool_t *mptmp, unsigned char *input,
 225    long int input_len, char **rval, long int *rval_len)
 226{
 227    long int i, j, count;
 228    int changed = 0;
 229    int inwhitespace = 0;
 230
 231    i = j = count = 0;
 232    while(i < input_len) {
 233        if (isspace(input[i])||(input[i] == NBSP)) {
 234            if (inwhitespace) changed = 1;
 235            inwhitespace = 1;
 236            count++;
 237        } else {
 238            inwhitespace = 0;
 239            if (count) {
 240                input[j] = ' ';
 241                count = 0;
 242                j++;
 243            }
 244            input[j] = input[i];
 245            j++;
 246        }
 247        i++;
 248    }
 249
 250    if (count) {
 251        input[j] = ' ';
 252        j++;
 253    }
 254
 255    *rval = (char *)input;
 256    *rval_len = j;
 257
 258    return changed;
 259}
 260
 261/* cssDecode */
 262
 263static int msre_fn_cssDecode_execute(apr_pool_t *mptmp, unsigned char *input,
 264    long int input_len, char **rval, long int *rval_len)
 265{
 266    long int length;
 267
 268    length = css_decode_inplace(input, input_len);
 269    *rval = (char *)input;
 270    *rval_len = length;
 271
 272    return (*rval_len == input_len ? 0 : 1);
 273}
 274
 275/* removeWhitespace */
 276
 277static int msre_fn_removeWhitespace_execute(apr_pool_t *mptmp, unsigned char *input,
 278    long int input_len, char **rval, long int *rval_len)
 279{
 280    long int i, j;
 281    int changed = 0;
 282
 283    i = j = 0;
 284    while(i < input_len) {
 285        if (isspace(input[i])||(input[i] == NBSP)) {
 286            /* do nothing */
 287            changed = 1;
 288        } else {
 289            input[j] = input[i];
 290            j++;
 291        }
 292        i++;
 293    }
 294
 295    *rval = (char *)input;
 296    *rval_len = j;
 297
 298    return changed;
 299}
 300
 301/* removeCommentsChar */
 302
 303static int msre_fn_removeCommentsChar_execute(apr_pool_t *mptmp, unsigned char *input,
 304        long int input_len, char **rval, long int *rval_len)
 305{
 306    long int i, j;
 307    int changed = 0;
 308
 309    i = j = 0;
 310    while(i < input_len) {
 311        if ((input[i] == '/')&&(i + 1 < input_len)&&(input[i + 1] == '*')) {
 312            changed = 1;
 313            i += 2;
 314        } else if ((input[i] == '*')&&(i + 1 < input_len)&&(input[i + 1] == '/')) {
 315            changed = 1;
 316            i += 2;
 317        } else if ((input[i] == '<')&&(i + 1 < input_len)&&(input[i + 1] == '!')&&
 318                    (i + 2 < input_len)&&(input[i+2] == '-')&&(i + 3 < input_len)&&
 319                    (input[i + 3] == '-')) {
 320            changed = 1;
 321            i += 4;
 322        } else if ((input[i] == '-')&&(i + 1 < input_len)&&(input[i + 1] == '-')&&
 323                    (i + 2 < input_len)&&(input[i+2] == '>'))   {
 324            changed = 1;
 325            i += 3;
 326        } else if ((input[i] == '-')&&(i + 1 < input_len)&&(input[i + 1] == '-')) {
 327            changed = 1;
 328            i += 2;
 329        } else if (input[i] == '#') {
 330            changed = 1;
 331            i++;
 332        } else {
 333            input[j] = input[i];
 334            i++;
 335            j++;
 336        }
 337    }
 338    input[j] = '\0';
 339
 340    *rval = (char *)input;
 341    *rval_len = j;
 342
 343    return changed;
 344}
 345
 346/* removeComments */
 347
 348static int msre_fn_removeComments_execute(apr_pool_t *mptmp, unsigned char *input,
 349        long int input_len, char **rval, long int *rval_len)
 350{
 351    long int i, j, incomment;
 352    int changed = 0;
 353
 354    i = j = incomment = 0;
 355    while(i < input_len) {
 356        if (incomment == 0) {
 357            if ((input[i] == '/')&&(i + 1 < input_len)&&(input[i + 1] == '*')) {
 358                changed = 1;
 359                incomment = 1;
 360                i += 2;
 361            } else if ((input[i] == '<')&&(i + 1 < input_len)&&(input[i + 1] == '!')&&
 362                    (i + 2 < input_len)&&(input[i+2] == '-')&&(i + 3 < input_len)&&
 363                    (input[i + 3] == '-') && (incomment == 0)) {
 364                incomment = 1;
 365                changed = 1;
 366                i += 4;
 367            } else if ((input[i] == '-')&&(i + 1 < input_len)&&(input[i + 1] == '-')
 368                        && (incomment == 0)) {
 369                changed = 1;
 370                input[i] = ' ';
 371                break;
 372            } else if (input[i] == '#' && (incomment == 0)) {
 373                changed = 1;
 374                input[i] = ' ';
 375               break;
 376            } else {
 377                input[j] = input[i];
 378                i++;
 379                j++;
 380            }
 381        } else {
 382            if ((input[i] == '*')&&(i + 1 < input_len)&&(input[i + 1] == '/')) {
 383                incomment = 0;
 384                i += 2;
 385                input[j] = input[i];
 386                i++;
 387                j++;
 388            } else if ((input[i] == '-')&&(i + 1 < input_len)&&(input[i + 1] == '-')&&
 389                    (i + 2 < input_len)&&(input[i+2] == '>'))   {
 390                incomment = 0;
 391                i += 3;
 392                input[j] = input[i];
 393                i++;
 394                j++;
 395            } else {
 396                i++;
 397            }
 398        }
 399    }
 400
 401    if (incomment) {
 402        input[j++] = ' ';
 403    }
 404
 405    *rval = (char *)input;
 406    *rval_len = j;
 407
 408    return changed;
 409}
 410
 411/* replaceComments */
 412
 413static int msre_fn_replaceComments_execute(apr_pool_t *mptmp, unsigned char *input,
 414    long int input_len, char **rval, long int *rval_len)
 415{
 416    long int i, j, incomment;
 417    int changed = 0;
 418
 419    i = j = incomment = 0;
 420    while(i < input_len) {
 421        if (incomment == 0) {
 422            if ((input[i] == '/')&&(i + 1 < input_len)&&(input[i + 1] == '*')) {
 423                changed = 1;
 424                incomment = 1;
 425                i += 2;
 426            } else {
 427                input[j] = input[i];
 428                i++;
 429                j++;
 430            }
 431        } else {
 432            if ((input[i] == '*')&&(i + 1 < input_len)&&(input[i + 1] == '/')) {
 433                incomment = 0;
 434                i += 2;
 435                input[j] = ' ';
 436                j++;
 437            } else {
 438                i++;
 439            }
 440        }
 441    }
 442
 443    if (incomment) {
 444        input[j++] = ' ';
 445    }
 446
 447    *rval = (char *)input;
 448    *rval_len = j;
 449
 450    return changed;
 451}
 452
 453/* jsDecode */
 454
 455static int msre_fn_jsDecode_execute(apr_pool_t *mptmp, unsigned char *input,
 456    long int input_len, char **rval, long int *rval_len)
 457{
 458    long int length;
 459
 460    length = js_decode_nonstrict_inplace(input, input_len);
 461    *rval = (char *)input;
 462    *rval_len = length;
 463
 464    return (*rval_len == input_len ? 0 : 1);
 465}
 466
 467/* urlDecode */
 468
 469static int msre_fn_urlDecode_execute(apr_pool_t *mptmp, unsigned char *input,
 470    long int input_len, char **rval, long int *rval_len)
 471{
 472    long int length;
 473    int invalid_count;
 474    int changed;
 475
 476    length = urldecode_nonstrict_inplace_ex(input, input_len, &invalid_count, &changed);
 477    *rval = (char *)input;
 478    *rval_len = length;
 479
 480    return changed;
 481}
 482
 483/* urlDecodeUni */
 484
 485static int msre_fn_urlDecodeUni_execute(apr_pool_t *mptmp, unsigned char *input,
 486    long int input_len, char **rval, long int *rval_len)
 487{
 488    long int length;
 489    int changed;
 490
 491    length = urldecode_uni_nonstrict_inplace_ex(input, input_len, &changed);
 492    *rval = (char *)input;
 493    *rval_len = length;
 494
 495    return changed;
 496}
 497
 498static int msre_fn_utf8Unicode_execute(apr_pool_t *mptmp, unsigned char *input,
 499    long int input_len, char **rval, long int *rval_len)
 500{
 501    int changed = 0;
 502
 503    *rval = (char *)utf8_unicode_inplace_ex(mptmp, input, input_len, &changed);
 504    *rval_len = strlen(*rval);
 505
 506    return changed;
 507}
 508
 509
 510/* urlEncode */
 511
 512static int msre_fn_urlEncode_execute(apr_pool_t *mptmp, unsigned char *input,
 513    long int input_len, char **rval, long int *rval_len)
 514{
 515    int changed;
 516
 517    *rval = url_encode(mptmp, (char *)input, input_len, &changed);
 518    *rval_len = strlen(*rval);
 519
 520    return changed;
 521}
 522
 523/* base64Encode */
 524
 525static int msre_fn_base64Encode_execute(apr_pool_t *mptmp, unsigned char *input,
 526    long int input_len, char **rval, long int *rval_len)
 527{
 528    *rval_len = apr_base64_encode_len(input_len); /* returns len with NULL byte included */
 529    *rval = apr_palloc(mptmp, *rval_len);
 530    apr_base64_encode(*rval, (const char *)input, input_len);
 531    (*rval_len)--;
 532
 533    return *rval_len ? 1 : 0;
 534}
 535
 536/* base64Decode */
 537
 538static int msre_fn_base64Decode_execute(apr_pool_t *mptmp, unsigned char *input,
 539    long int input_len, char **rval, long int *rval_len)
 540{
 541    *rval_len = apr_base64_decode_len((const char *)input); /* returns len with NULL byte included */
 542    *rval = apr_palloc(mptmp, *rval_len);
 543    *rval_len = apr_base64_decode(*rval, (const char *)input);
 544
 545    return *rval_len ? 1 : 0;
 546}
 547
 548/* length */
 549
 550static int msre_fn_length_execute(apr_pool_t *mptmp, unsigned char *input,
 551    long int input_len, char **rval, long int *rval_len)
 552{
 553    *rval = apr_psprintf(mptmp, "%ld", input_len);
 554    *rval_len = strlen(*rval);
 555
 556    return 1;
 557}
 558
 559/* md5 */
 560
 561static int msre_fn_md5_execute(apr_pool_t *mptmp, unsigned char *input,
 562    long int input_len, char **rval, long int *rval_len)
 563{
 564    unsigned char digest[APR_MD5_DIGESTSIZE];
 565
 566    apr_md5(digest, input, input_len);
 567
 568    *rval_len = APR_MD5_DIGESTSIZE;
 569    *rval = apr_pstrmemdup(mptmp, (const char *)digest, APR_MD5_DIGESTSIZE);
 570
 571    return 1;
 572}
 573
 574/* sha1 */
 575
 576static int msre_fn_sha1_execute(apr_pool_t *mptmp, unsigned char *input,
 577    long int input_len, char **rval, long int *rval_len)
 578{
 579    unsigned char digest[APR_SHA1_DIGESTSIZE];
 580    apr_sha1_ctx_t context;
 581
 582    apr_sha1_init(&context);
 583    apr_sha1_update(&context, (const char *)input, input_len);
 584    apr_sha1_final(digest, &context);
 585
 586    *rval_len = APR_SHA1_DIGESTSIZE;
 587    *rval = apr_pstrmemdup(mptmp, (const char *)digest, APR_SHA1_DIGESTSIZE);
 588
 589    return 1;
 590}
 591
 592/**
 593* \brief SqlHexDecode transformation function. Transform xNN data.
 594*
 595* \param mptmp Pointer to resource pool
 596* \param input Pointer to input data
 597* \param input_len Input data length
 598* \param rval Pointer to decoded buffer
 599* \param rval_len Decoded buffer length
 600*
 601* \retval 0 On failure
 602* \retval 1 On Success
 603*/
 604static int msre_fn_sqlHexDecode_execute(apr_pool_t *mptmp, unsigned char *input,
 605    long int input_len, char **rval, long int *rval_len)
 606{
 607    *rval_len = sql_hex2bytes_inplace(input, input_len);
 608    *rval = (char *)input;
 609
 610    return 1;
 611}
 612
 613/* hexDecode */
 614
 615static int msre_fn_hexDecode_execute(apr_pool_t *mptmp, unsigned char *input,
 616    long int input_len, char **rval, long int *rval_len)
 617{
 618    *rval_len = hex2bytes_inplace(input, input_len);
 619    *rval = (char *)input;
 620
 621    return 1;
 622}
 623
 624/* hexEncode */
 625
 626static int msre_fn_hexEncode_execute(apr_pool_t *mptmp, unsigned char *input,
 627    long int input_len, char **rval, long int *rval_len)
 628{
 629    *rval = bytes2hex(mptmp, input, input_len);
 630    *rval_len = strlen(*rval);
 631
 632    return 1;
 633}
 634
 635/* htmlEntityDecode */
 636
 637static int msre_fn_htmlEntityDecode_execute(apr_pool_t *mptmp, unsigned char *input,
 638    long int input_len, char **rval, long int *rval_len)
 639{
 640    *rval_len = html_entities_decode_inplace(mptmp, input, input_len);
 641    *rval = (char *)input;
 642
 643    return (*rval_len == input_len ? 0 : 1);
 644}
 645
 646/* escapeSeqDecode */
 647
 648static int msre_fn_escapeSeqDecode_execute(apr_pool_t *mptmp, unsigned char *input,
 649    long int input_len, char **rval, long int *rval_len)
 650{
 651    *rval_len = ansi_c_sequences_decode_inplace(input, input_len);
 652    *rval = (char *)input;
 653
 654    return (*rval_len == input_len ? 0 : 1);
 655}
 656
 657/* normalizePath */
 658
 659static int msre_fn_normalizePath_execute(apr_pool_t *mptmp, unsigned char *input,
 660    long int input_len, char **rval, long int *rval_len)
 661{
 662    int changed;
 663
 664    *rval_len = normalize_path_inplace(input, input_len, 0, &changed);
 665    *rval = (char *)input;
 666
 667    return changed;
 668}
 669
 670/* normalizePathWin */
 671
 672static int msre_fn_normalizePathWin_execute(apr_pool_t *mptmp, unsigned char *input,
 673    long int input_len, char **rval, long int *rval_len)
 674{
 675    int changed;
 676
 677    *rval_len = normalize_path_inplace(input, input_len, 1, &changed);
 678    *rval = (char *)input;
 679
 680    return changed;
 681}
 682
 683/* parityEven7bit */
 684
 685static int msre_fn_parityEven7bit_execute(apr_pool_t *mptmp, unsigned char *input,
 686    long int input_len, char **rval, long int *rval_len)
 687{
 688    long int i;
 689    int changed = 0;
 690
 691    if (rval == NULL) return -1;
 692    *rval = NULL;
 693
 694    i = 0;
 695    while(i < input_len) {
 696        unsigned int x = input[i];
 697
 698        input[i] ^= input[i] >> 4;
 699        input[i] &= 0xf;
 700
 701        if ((0x6996 >> input[i]) & 1) {
 702            input[i] = x | 0x80;
 703        }
 704        else {
 705            input[i] = x & 0x7f;
 706        }
 707
 708        if (x != input[i]) changed = 1;
 709        i++;
 710    }
 711
 712    *rval = (char *)input;
 713    *rval_len = input_len;
 714
 715    return changed;
 716}
 717
 718/* parityZero7bit */
 719
 720static int msre_fn_parityZero7bit_execute(apr_pool_t *mptmp, unsigned char *input,
 721    long int input_len, char **rval, long int *rval_len)
 722{
 723    long int i;
 724    int changed = 0;
 725
 726    if (rval == NULL) return -1;
 727    *rval = NULL;
 728
 729    i = 0;
 730    while(i < input_len) {
 731        unsigned char c = input[i];
 732        input[i] &= 0x7f;
 733        if (c != input[i]) changed = 1;
 734        i++;
 735    }
 736
 737    *rval = (char *)input;
 738    *rval_len = input_len;
 739
 740    return changed;
 741}
 742
 743/* parityOdd7bit */
 744
 745static int msre_fn_parityOdd7bit_execute(apr_pool_t *mptmp, unsigned char *input,
 746    long int input_len, char **rval, long int *rval_len)
 747{
 748    long int i;
 749    int changed = 0;
 750
 751    if (rval == NULL) return -1;
 752    *rval = NULL;
 753
 754    i = 0;
 755    while(i < input_len) {
 756        unsigned int x = input[i];
 757
 758        input[i] ^= input[i] >> 4;
 759        input[i] &= 0xf;
 760
 761        if ((0x6996 >> input[i]) & 1) {
 762            input[i] = x & 0x7f;
 763        }
 764        else {
 765            input[i] = x | 0x80;
 766        }
 767
 768        if (x != input[i]) changed = 1;
 769        i++;
 770    }
 771
 772    *rval = (char *)input;
 773    *rval_len = input_len;
 774
 775    return changed;
 776}
 777
 778/**
 779* \brief Base64 transformation function based on RFC2045
 780*
 781* \param mptmp Pointer to resource pool
 782* \param input Pointer to input data
 783* \param input_len Input data length
 784* \param rval Pointer to decoded buffer
 785* \param rval_len Decoded buffer length
 786*
 787* \retval 0 On failure
 788* \retval 1 On Success
 789*/
 790static int msre_fn_base64DecodeExt_execute(apr_pool_t *mptmp, unsigned char *input, long int input_len, char **rval, long int *rval_len)
 791{
 792    *rval_len = input_len;
 793    *rval = apr_palloc(mptmp, *rval_len);
 794    *rval_len = decode_base64_ext(*rval, (const unsigned char *)input, input_len);
 795
 796    return *rval_len ? 1 : 0;
 797}
 798
 799
 800/* ------------------------------------------------------------------------------ */
 801
 802/**
 803 * Registers one transformation function with the engine.
 804 */
 805void msre_engine_tfn_register(msre_engine *engine, const char *name,
 806    fn_tfn_execute_t execute)
 807{
 808    msre_tfn_metadata *metadata = (msre_tfn_metadata *)apr_pcalloc(engine->mp,
 809        sizeof(msre_tfn_metadata));
 810    if (metadata == NULL) return;
 811
 812    metadata->name = name;
 813    metadata->execute = execute;
 814
 815    apr_table_setn(engine->tfns, name, (void *)metadata);
 816}
 817
 818/**
 819 * Returns transformation function metadata given a name.
 820 */
 821msre_tfn_metadata *msre_engine_tfn_resolve(msre_engine *engine, const char *name) {
 822    return (msre_tfn_metadata *)apr_table_get(engine->tfns, name);
 823}
 824
 825/**
 826 * Register the default transformation functions.
 827 */
 828void msre_engine_register_default_tfns(msre_engine *engine) {
 829
 830    /* none */
 831    msre_engine_tfn_register(engine,
 832        "none",
 833        NULL
 834    );
 835
 836    /* base64Decode */
 837    msre_engine_tfn_register(engine,
 838        "base64Decode",
 839        msre_fn_base64Decode_execute
 840    );
 841
 842    /* base64Encode */
 843    msre_engine_tfn_register(engine,
 844        "base64Encode",
 845        msre_fn_base64Encode_execute
 846    );
 847
 848    /* compressWhitespace */
 849    msre_engine_tfn_register(engine,
 850        "compressWhitespace",
 851        msre_fn_compressWhitespace_execute
 852    );
 853
 854    /* cssDecode */
 855    msre_engine_tfn_register(engine,
 856        "cssDecode",
 857        msre_fn_cssDecode_execute
 858    );
 859
 860    /* escapeSeqDecode */
 861    msre_engine_tfn_register(engine,
 862        "escapeSeqDecode",
 863        msre_fn_escapeSeqDecode_execute
 864    );
 865
 866    /* sqlHexDecode */
 867    msre_engine_tfn_register(engine,
 868        "sqlHexDecode",
 869        msre_fn_sqlHexDecode_execute
 870    );
 871
 872    /* hexDecode */
 873    msre_engine_tfn_register(engine,
 874        "hexDecode",
 875        msre_fn_hexDecode_execute
 876    );
 877
 878    /* hexEncode */
 879    msre_engine_tfn_register(engine,
 880        "hexEncode",
 881        msre_fn_hexEncode_execute
 882    );
 883
 884    /* htmlEntityDecode */
 885    msre_engine_tfn_register(engine,
 886        "htmlEntityDecode",
 887        msre_fn_htmlEntityDecode_execute
 888    );
 889
 890    /* jsDecode */
 891    msre_engine_tfn_register(engine,
 892        "jsDecode",
 893        msre_fn_jsDecode_execute
 894    );
 895
 896    /* length */
 897    msre_engine_tfn_register(engine,
 898        "length",
 899        msre_fn_length_execute
 900    );
 901
 902    /* lowercase */
 903    msre_engine_tfn_register(engine,
 904        "lowercase",
 905        msre_fn_lowercase_execute
 906    );
 907
 908    /* md5 */
 909    msre_engine_tfn_register(engine,
 910        "md5",
 911        msre_fn_md5_execute
 912    );
 913
 914    /* normalisePath */
 915    msre_engine_tfn_register(engine,
 916        "normalisePath",
 917        msre_fn_normalizePath_execute
 918    );
 919    
 920    /* normalizePath */
 921    msre_engine_tfn_register(engine,
 922        "normalizePath",
 923        msre_fn_normalizePath_execute
 924    );
 925
 926    /* normalisePathWin */
 927    msre_engine_tfn_register(engine,
 928        "normalisePathWin",
 929        msre_fn_normalizePathWin_execute
 930    );
 931    
 932    /* normalizePathWin */
 933    msre_engine_tfn_register(engine,
 934        "normalizePathWin",
 935        msre_fn_normalizePathWin_execute
 936    );
 937
 938    /* parityEven7bit */
 939    msre_engine_tfn_register(engine,
 940        "parityEven7bit",
 941        msre_fn_parityEven7bit_execute
 942    );
 943
 944    /* parityZero7bit */
 945    msre_engine_tfn_register(engine,
 946        "parityZero7bit",
 947        msre_fn_parityZero7bit_execute
 948    );
 949
 950    /* parityOdd7bit */
 951    msre_engine_tfn_register(engine,
 952        "parityOdd7bit",
 953        msre_fn_parityOdd7bit_execute
 954    );
 955
 956    /* removeWhitespace */
 957    msre_engine_tfn_register(engine,
 958        "removeWhitespace",
 959        msre_fn_removeWhitespace_execute
 960    );
 961
 962    /* removeNulls */
 963    msre_engine_tfn_register(engine,
 964        "removeNulls",
 965        msre_fn_removeNulls_execute
 966    );
 967
 968    /* replaceNulls */
 969    msre_engine_tfn_register(engine,
 970        "replaceNulls",
 971        msre_fn_replaceNulls_execute
 972    );
 973
 974    /* removeComments */
 975    msre_engine_tfn_register(engine,
 976        "removeComments",
 977        msre_fn_removeComments_execute
 978    );
 979
 980    /* removeCommentsChar */
 981    msre_engine_tfn_register(engine,
 982        "removeCommentsChar",
 983        msre_fn_removeCommentsChar_execute
 984    );
 985
 986    /* replaceComments */
 987    msre_engine_tfn_register(engine,
 988        "replaceComments",
 989        msre_fn_replaceComments_execute
 990    );
 991
 992    /* sha1 */
 993    msre_engine_tfn_register(engine,
 994        "sha1",
 995        msre_fn_sha1_execute
 996    );
 997
 998    /* trim */
 999    msre_engine_tfn_register(engine,
1000        "trim",
1001        msre_fn_trim_execute
1002    );
1003
1004    /* trimLeft */
1005    msre_engine_tfn_register(engine,
1006        "trimLeft",
1007        msre_fn_trimLeft_execute
1008    );
1009
1010    msre_engine_tfn_register(engine,
1011        "cmdline",
1012        msre_fn_cmdline_execute
1013    );
1014
1015    /* trimRight */
1016    msre_engine_tfn_register(engine,
1017        "trimRight",
1018        msre_fn_trimRight_execute
1019    );
1020
1021    /* urlDecode */
1022    msre_engine_tfn_register(engine,
1023        "urlDecode",
1024        msre_fn_urlDecode_execute
1025    );
1026
1027    /* urlDecodeUni */
1028    msre_engine_tfn_register(engine,
1029        "urlDecodeUni",
1030        msre_fn_urlDecodeUni_execute
1031    );
1032
1033    /* Utf8Unicode */
1034    msre_engine_tfn_register(engine,
1035        "Utf8toUnicode",
1036        msre_fn_utf8Unicode_execute
1037    );
1038
1039    /* urlEncode */
1040    msre_engine_tfn_register(engine,
1041        "urlEncode",
1042        msre_fn_urlEncode_execute
1043    );
1044
1045    /* base64DecodeExt */
1046    msre_engine_tfn_register(engine,
1047        "base64DecodeExt",
1048        msre_fn_base64DecodeExt_execute
1049    );
1050
1051}