diff --git a/apache2/msc_parsers.c b/apache2/msc_parsers.c index 7aa80ae0..86d2bf43 100644 --- a/apache2/msc_parsers.c +++ b/apache2/msc_parsers.c @@ -208,6 +208,7 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength, char *value = NULL; char *buf; int status; + int changed; if (s == NULL) return -1; if (inputlength == 0) return 1; @@ -249,7 +250,7 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength, } if (status == 0) { - arg->name_len = urldecode_nonstrict_inplace_ex((unsigned char *)buf, arg->name_origin_len, invalid_count); + arg->name_len = urldecode_nonstrict_inplace_ex((unsigned char *)buf, arg->name_origin_len, invalid_count, &changed); arg->name = apr_pstrmemdup(msr->mp, buf, arg->name_len); if (s[i] == argument_separator) { @@ -270,7 +271,7 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength, } } else { - arg->value_len = urldecode_nonstrict_inplace_ex((unsigned char *)value, arg->value_origin_len, invalid_count); + arg->value_len = urldecode_nonstrict_inplace_ex((unsigned char *)value, arg->value_origin_len, invalid_count, &changed); arg->value = apr_pstrmemdup(msr->mp, value, arg->value_len); add_argument(msr, arguments, arg); diff --git a/apache2/msc_util.c b/apache2/msc_util.c index a8695b8a..913e636e 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -74,10 +74,12 @@ int parse_name_eq_value(apr_pool_t *mp, const char *input, char **name, char **v * * IMP1 Assumes NUL-terminated */ -char *url_encode(apr_pool_t *mp, char *input, unsigned int input_len) { +char *url_encode(apr_pool_t *mp, char *input, unsigned int input_len, int *changed) { char *rval, *d; unsigned int i, len; + *changed = 0; + len = input_len * 3 + 1; d = rval = apr_palloc(mp, len); if (rval == NULL) return NULL; @@ -89,6 +91,7 @@ char *url_encode(apr_pool_t *mp, char *input, unsigned int input_len) { if (c == ' ') { *d++ = '+'; + *changed = 1; } else if ( (c == 42) || ((c >= 48)&&(c <= 57)) || ((c >= 65)&&(c <= 90)) || ((c >= 97)&&(c <= 122)) @@ -98,6 +101,7 @@ char *url_encode(apr_pool_t *mp, char *input, unsigned int input_len) { *d++ = '%'; c2x(c, (unsigned char *)d); d += 2; + *changed = 1; } } @@ -700,10 +704,12 @@ int js_decode_nonstrict_inplace(unsigned char *input, long int input_len) { * * IMP1 Assumes NUL-terminated */ -int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len) { +int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *changed) { unsigned char *d = input; long int i, count; + *changed = 0; + if (input == NULL) return -1; i = count = 0; @@ -732,6 +738,7 @@ int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len) d++; count++; i += 6; + *changed = 1; } else { /* Invalid data, skip %u. */ *d++ = input[i++]; @@ -761,6 +768,7 @@ int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len) *d++ = x2c(&input[i + 1]); count++; i += 3; + *changed = 1; } else { /* Not a valid encoding, skip this % */ *d++ = input[i++]; @@ -777,6 +785,7 @@ int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len) /* Character is not a percent sign. */ if (input[i] == '+') { *d++ = ' '; + *changed = 1; } else { *d++ = input[i]; } @@ -795,10 +804,12 @@ int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len) * * IMP1 Assumes NUL-terminated */ -int urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *invalid_count) { +int urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *invalid_count, int *changed) { unsigned char *d = (unsigned char *)input; long int i, count; + *changed = 0; + if (input == NULL) return -1; i = count = 0; @@ -816,6 +827,7 @@ int urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *d++ = x2c(&input[i + 1]); count++; i += 3; + *changed = 1; } else { /* Not a valid encoding, skip this % */ *d++ = input[i++]; @@ -832,6 +844,7 @@ int urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_len, int /* Character is not a percent sign. */ if (input[i] == '+') { *d++ = ' '; + *changed = 1; } else { *d++ = input[i]; } @@ -1071,16 +1084,21 @@ int ansi_c_sequences_decode_inplace(unsigned char *input, int input_len) { * * IMP1 Assumes NUL-terminated */ -int normalise_path_inplace(unsigned char *input, int input_len, int win) { +int normalise_path_inplace(unsigned char *input, int input_len, int win, int *changed) { unsigned char *d = input; int i, count; + *changed = 0; + i = count = 0; while ((i < input_len)&&(count < input_len)) { char c = input[i]; /* Convert backslash to forward slash on Windows only. */ - if ((win)&&(c == '\\')) c = '/'; + if ((win)&&(c == '\\')) { + c = '/'; + *changed = 1; + } if (c == '/') { /* Is there a directory back-reference? Yes, we @@ -1091,6 +1109,8 @@ int normalise_path_inplace(unsigned char *input, int input_len, int win) { unsigned char *cd = d - 4; int ccount = count - 4; + *changed = 1; + /* Go back until we reach the beginning or a forward slash. */ while ((ccount > 0)&&(*cd != '/')) { ccount--; @@ -1107,12 +1127,14 @@ int normalise_path_inplace(unsigned char *input, int input_len, int win) { /* Ignore the last two bytes. */ d -= 2; count -= 2; + *changed = 1; } else /* Or are there just multiple occurences of forward slash? */ if ((count >= 1)&&(*(d - 1) == '/')) { /* Ignore the last one byte. */ d--; count--; + *changed = 1; } } diff --git a/apache2/msc_util.h b/apache2/msc_util.h index ae531590..5e1431a2 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -13,13 +13,13 @@ #include "modsecurity.h" -int DSOLOCAL normalise_path_inplace(unsigned char *input, int len, int win); +int DSOLOCAL normalise_path_inplace(unsigned char *input, int len, int win, int *changed); int DSOLOCAL parse_boolean(const char *input); int DSOLOCAL parse_name_eq_value(apr_pool_t *mp, const char *input, char **name, char **value); -char DSOLOCAL *url_encode(apr_pool_t *mp, char *input, unsigned int input_len); +char DSOLOCAL *url_encode(apr_pool_t *mp, char *input, unsigned int input_len, int *changed); char DSOLOCAL *strnurlencat(char *destination, char *source, unsigned int maxlen); @@ -68,9 +68,9 @@ char DSOLOCAL *_log_escape(apr_pool_t *p, const unsigned char *input, int DSOLOCAL js_decode_nonstrict_inplace(unsigned char *input, long int input_len); -int DSOLOCAL urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_length); +int DSOLOCAL urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_length, int * changed); -int DSOLOCAL urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_length, int *invalid_count); +int DSOLOCAL urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_length, int *invalid_count, int *changed); int DSOLOCAL html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int len); diff --git a/apache2/re_tfns.c b/apache2/re_tfns.c index 03a66664..9fc8ad25 100644 --- a/apache2/re_tfns.c +++ b/apache2/re_tfns.c @@ -279,12 +279,13 @@ static int msre_fn_urlDecode_execute(apr_pool_t *mptmp, unsigned char *input, { long int length; int invalid_count; + int changed; - length = urldecode_nonstrict_inplace_ex(input, input_len, &invalid_count); + length = urldecode_nonstrict_inplace_ex(input, input_len, &invalid_count, &changed); *rval = (char *)input; *rval_len = length; - return (*rval_len == input_len ? 0 : 1); + return changed; } /* urlDecodeUni */ @@ -293,12 +294,13 @@ static int msre_fn_urlDecodeUni_execute(apr_pool_t *mptmp, unsigned char *input, long int input_len, char **rval, long int *rval_len) { long int length; + int changed; - length = urldecode_uni_nonstrict_inplace_ex(input, input_len); + length = urldecode_uni_nonstrict_inplace_ex(input, input_len, &changed); *rval = (char *)input; *rval_len = length; - return (*rval_len == input_len ? 0 : 1); + return changed; } /* urlEncode */ @@ -306,10 +308,12 @@ static int msre_fn_urlDecodeUni_execute(apr_pool_t *mptmp, unsigned char *input, static int msre_fn_urlEncode_execute(apr_pool_t *mptmp, unsigned char *input, long int input_len, char **rval, long int *rval_len) { - *rval = url_encode(mptmp, (char *)input, input_len); + int changed; + + *rval = url_encode(mptmp, (char *)input, input_len, &changed); *rval_len = strlen(*rval); - return (*rval_len == input_len ? 0 : 1); + return changed; } /* base64Encode */ @@ -430,10 +434,12 @@ static int msre_fn_escapeSeqDecode_execute(apr_pool_t *mptmp, unsigned char *inp static int msre_fn_normalisePath_execute(apr_pool_t *mptmp, unsigned char *input, long int input_len, char **rval, long int *rval_len) { - *rval_len = normalise_path_inplace(input, input_len, 0); + int changed; + + *rval_len = normalise_path_inplace(input, input_len, 0, &changed); *rval = (char *)input; - return (*rval_len == input_len ? 0 : 1); + return changed; } /* normalisePathWin */ @@ -441,10 +447,12 @@ static int msre_fn_normalisePath_execute(apr_pool_t *mptmp, unsigned char *input static int msre_fn_normalisePathWin_execute(apr_pool_t *mptmp, unsigned char *input, long int input_len, char **rval, long int *rval_len) { - *rval_len = normalise_path_inplace(input, input_len, 1); + int changed; + + *rval_len = normalise_path_inplace(input, input_len, 1, &changed); *rval = (char *)input; - return (*rval_len == input_len ? 0 : 1); + return changed; } /* ------------------------------------------------------------------------------ */