From: Tony Finch Date: Thu, 18 Jan 2001 22:36:58 +0000 (+0000) Subject: Bring forward from 1.3: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a81e4faefeeb5eb35e335297e9ea9592723f4409;p=apache Bring forward from 1.3: I broke mod_rewrite by modifying strings in place when expanding them, because variable lookups can cause subrequests which cause mod_rewrite to do its stuff again including an expansion on the same string, which is then syntactically invalid. So copy the lookup keys somewhere else before using them in such a way that may cause recursion. In addition to this, my parser could also be confused by complicated nested rewrite map expansions like ${map1:${map2:key|dflt}|dflt} so fix that too by keeping track of {} when looking for |. PR: 7087 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@87723 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 55e99d4855..aa880bb1c5 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ Changes with Apache 2.0b1 + *) Fix the handling of variable expansion look-ahead in mod_rewrite, + i.e. syntax like %{LA-U:REMOTE_USER}, and also fix the parsing of + more complicated nested RewriteMap lookups. PR#7087 [Tony Finch] + *) Fix the RFC number mentioned when complaining about a missing Host: header. PR#7079 [Alexey Toptygin ] diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index f1a014f690..f7d17504ab 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -2288,7 +2288,13 @@ static void do_expand(request_rec *r, char *input, char *buffer, int nbuf, if (endp == NULL) { goto skip; } - *endp = '\0'; + /* + * These lookups may be recursive in a very convoluted + * fashion -- see the LA-U and LA-F variable expansion + * prefixes -- so we copy lookup keys to a separate buffer + * rather than adding zero bytes in order to use them in + * place. + */ if (inp[0] == '$') { /* ${...} map lookup expansion */ /* @@ -2303,43 +2309,39 @@ static void do_expand(request_rec *r, char *input, char *buffer, int nbuf, * looking at it is that the recursion is entirely * driven by the syntax of the nested curly brackets. */ - char *key, *dflt, *result; + char *map, *key, *dflt, *result; char xkey[MAX_STRING_LEN]; char xdflt[MAX_STRING_LEN]; - char *empty = ""; - key = strchr(inp, ':'); - if (key == NULL) { - *endp = '}'; + key = find_char_in_brackets(inp, ':', '{', '}'); + if (key == NULL) goto skip; - } - *key++ = '\0'; - dflt = strchr(key, '|'); + map = apr_pstrndup(r->pool, inp+2, key-inp-2); + dflt = find_char_in_brackets(inp, '|', '{', '}'); if (dflt == NULL) { - dflt = empty; - } - else { - *dflt++ = '\0'; + key = apr_pstrndup(r->pool, key+1, endp-key-1); + dflt = ""; + } else { + key = apr_pstrndup(r->pool, key+1, dflt-key-1); + dflt = apr_pstrndup(r->pool, dflt+1, endp-dflt-1); } do_expand(r, key, xkey, sizeof(xkey), briRR, briRC); - do_expand(r, dflt, xdflt, sizeof(xdflt), briRR, briRC); - result = lookup_map(r, inp+2, xkey); - if (result == NULL) { - result = xdflt; - } - span = apr_cpystrn(outp, result, space) - outp; - key[-1] = ':'; - if (dflt != empty) { - dflt[-1] = '|'; + result = lookup_map(r, map, xkey); + if (result) { + span = apr_cpystrn(outp, result, space) - outp; + } else { + do_expand(r, dflt, xdflt, sizeof(xdflt), briRR, briRC); + span = apr_cpystrn(outp, xdflt, space) - outp; } } else if (inp[0] == '%') { /* %{...} variable lookup expansion */ - span = apr_cpystrn(outp, lookup_variable(r, inp+2), space) - outp; + char *var; + var = apr_pstrndup(r->pool, inp+2, endp-inp-2); + span = apr_cpystrn(outp, lookup_variable(r, var), space) - outp; } else { span = 0; } - *endp = '}'; inp = endp+1; outp += span; space -= span; @@ -4073,7 +4075,7 @@ static int compare_lexicography(char *cpNum1, char *cpNum2) /* ** -** Find end of bracketed expression +** Bracketed expression handling ** s points after the opening bracket ** */ @@ -4093,6 +4095,30 @@ static char *find_closing_bracket(char *s, int left, int right) return NULL; } +static char *find_char_in_brackets(char *s, int c, int left, int right) +{ + int depth; + + for (depth = 1; *s; ++s) { + if (*s == c && depth == 1) { + return s; + } + else if (*s == right && --depth == 0) { + return NULL; + } + else if (*s == left) { + ++depth; + } + } + return NULL; +} + +/* +** +** Module paraphernalia +** +*/ + #ifdef NETWARE int main(int argc, char *argv[]) { diff --git a/modules/mappers/mod_rewrite.h b/modules/mappers/mod_rewrite.h index d70f32fdc9..9ed59ce5f3 100644 --- a/modules/mappers/mod_rewrite.h +++ b/modules/mappers/mod_rewrite.h @@ -469,8 +469,9 @@ static int subreq_ok(request_rec *r); /* Lexicographic Comparison */ static int compare_lexicography(char *cpNum1, char *cpNum2); - /* Find end of bracketed expression */ + /* Bracketed expression handling */ static char *find_closing_bracket(char *s, int left, int right); +static char *find_char_in_brackets(char *s, int c, int left, int right); #endif /* _MOD_REWRITE_H */