Commit a81e4fae authored by Tony Finch's avatar Tony Finch
Browse files

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
parent 06862f97
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
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 <alexeyt@wam.umd.edu>]

+51 −25
Original line number Diff line number Diff line
@@ -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;
		}
		result = lookup_map(r, map, xkey);
		if (result) {
		    span = apr_cpystrn(outp, result, space) - outp;
		key[-1] = ':';
		if (dflt != empty) {
		    dflt[-1] = '|';
		} 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[]) 
{
+2 −1
Original line number Diff line number Diff line
@@ -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 */