--- /dev/null
+diff -uNr apache_1.3.11.orig/src/modules/standard/mod_rewrite.c apache_1.3.11/src/modules/standard/mod_rewrite.c
+--- apache_1.3.11.orig/src/modules/standard/mod_rewrite.c Sun Jan 16 19:06:30 2000
++++ apache_1.3.11/src/modules/standard/mod_rewrite.c Thu Oct 5 14:50:43 2000
+@@ -1745,7 +1745,6 @@
+ char *output;
+ const char *vary;
+ char newuri[MAX_STRING_LEN];
+- char env[MAX_STRING_LEN];
+ regex_t *regexp;
+ regmatch_t regmatch[MAX_NMATCH];
+ backrefinfo *briRR = NULL;
+@@ -1913,20 +1912,7 @@
+ * (`RewriteRule <pat> - [E=...]')
+ */
+ if (strcmp(output, "-") == 0) {
+- for (i = 0; p->env[i] != NULL; i++) {
+- /* 1. take the string */
+- ap_cpystrn(env, p->env[i], sizeof(env));
+- /* 2. expand $N (i.e. backrefs to RewriteRule pattern) */
+- expand_backref_inbuffer(r->pool, env, sizeof(env), briRR, '$');
+- /* 3. expand %N (i.e. backrefs to latest RewriteCond pattern) */
+- expand_backref_inbuffer(r->pool, env, sizeof(env), briRC, '%');
+- /* 4. expand %{...} (i.e. variables) */
+- expand_variables_inbuffer(r, env, sizeof(env));
+- /* 5. expand ${...} (RewriteMap lookups) */
+- expand_map_lookups(r, env, sizeof(env));
+- /* and add the variable to Apache's structures */
+- add_env_variable(r, env);
+- }
++ do_expand_env(r, p->env, briRR, briRC);
+ if (p->forced_mimetype != NULL) {
+ if (perdir == NULL) {
+ /* In the per-server context we can force the MIME-type
+@@ -1961,17 +1947,7 @@
+ * that there is something to replace, so we create the
+ * substitution URL string in `newuri'.
+ */
+- /* 1. take the output string */
+- ap_cpystrn(newuri, output, sizeof(newuri));
+- /* 2. expand $N (i.e. backrefs to RewriteRule pattern) */
+- expand_backref_inbuffer(r->pool, newuri, sizeof(newuri), briRR, '$');
+- /* 3. expand %N (i.e. backrefs to latest RewriteCond pattern) */
+- expand_backref_inbuffer(r->pool, newuri, sizeof(newuri), briRC, '%');
+- /* 4. expand %{...} (i.e. variables) */
+- expand_variables_inbuffer(r, newuri, sizeof(newuri));
+- /* 5. expand ${...} (RewriteMap lookups) */
+- expand_map_lookups(r, newuri, sizeof(newuri));
+- /* and log the result... */
++ do_expand(r, output, newuri, sizeof(newuri), briRR, briRC);
+ if (perdir == NULL) {
+ rewritelog(r, 2, "rewrite %s -> %s", uri, newuri);
+ }
+@@ -1983,20 +1959,7 @@
+ * Additionally do expansion for the environment variable
+ * strings (`RewriteRule .. .. [E=<string>]').
+ */
+- for (i = 0; p->env[i] != NULL; i++) {
+- /* 1. take the string */
+- ap_cpystrn(env, p->env[i], sizeof(env));
+- /* 2. expand $N (i.e. backrefs to RewriteRule pattern) */
+- expand_backref_inbuffer(r->pool, env, sizeof(env), briRR, '$');
+- /* 3. expand %N (i.e. backrefs to latest RewriteCond pattern) */
+- expand_backref_inbuffer(r->pool, env, sizeof(env), briRC, '%');
+- /* 4. expand %{...} (i.e. variables) */
+- expand_variables_inbuffer(r, env, sizeof(env));
+- /* 5. expand ${...} (RewriteMap lookups) */
+- expand_map_lookups(r, env, sizeof(env));
+- /* and add the variable to Apache's structures */
+- add_env_variable(r, env);
+- }
++ do_expand_env(r, p->env, briRR, briRC);
+
+ /*
+ * Now replace API's knowledge of the current URI:
+@@ -2163,16 +2126,7 @@
+ * Construct the string we match against
+ */
+
+- /* 1. take the string */
+- ap_cpystrn(input, p->input, sizeof(input));
+- /* 2. expand $N (i.e. backrefs to RewriteRule pattern) */
+- expand_backref_inbuffer(r->pool, input, sizeof(input), briRR, '$');
+- /* 3. expand %N (i.e. backrefs to latest RewriteCond pattern) */
+- expand_backref_inbuffer(r->pool, input, sizeof(input), briRC, '%');
+- /* 4. expand %{...} (i.e. variables) */
+- expand_variables_inbuffer(r, input, sizeof(input));
+- /* 5. expand ${...} (RewriteMap lookups) */
+- expand_map_lookups(r, input, sizeof(input));
++ do_expand(r, p->input, input, sizeof(input), briRR, briRC);
+
+ /*
+ * Apply the patterns
+@@ -2314,6 +2268,139 @@
+ ** +-------------------------------------------------------+
+ */
+
++
++/*
++**
++** perform all the expansions on the input string
++** leaving the result in the supplied buffer
++**
++*/
++
++static void do_expand(request_rec *r, char *input, char *buffer, int nbuf,
++ backrefinfo *briRR, backrefinfo *briRC)
++{
++ char *inp, *outp;
++ size_t span, space;
++
++ /*
++ * for security reasons this expansion must be perfomed in a
++ * single pass, otherwise an attacker can arrange for the result
++ * of an earlier expansion to include expansion specifiers that
++ * are interpreted by a later expansion, producing results that
++ * were not intended by the administrator.
++ */
++
++ inp = input;
++ outp = buffer;
++ space = nbuf - 1; /* room for '\0' */
++
++ for (;;) {
++ span = strcspn(inp, "$%");
++ if (span > space) {
++ span = space;
++ }
++ memcpy(outp, inp, span);
++ inp += span;
++ outp += span;
++ space -= span;
++ if (space == 0 || *inp == '\0') {
++ break;
++ }
++ /* now we have a '$' or a '%' */
++ if (inp[1] == '{') {
++ char *endp;
++ endp = strchr(inp, '}');
++ if (endp == NULL) {
++ goto skip;
++ }
++ *endp = '\0';
++ if (inp[0] == '$') {
++ /* ${...} map lookup expansion */
++ char *key, *dflt, *result;
++ key = strchr(inp, ':');
++ if (key == NULL) {
++ goto skip;
++ }
++ *key++ = '\0';
++ dflt = strchr(key, '|');
++ if (dflt) {
++ *dflt++ = '\0';
++ }
++ result = lookup_map(r, inp+2, key);
++ if (result == NULL) {
++ result = dflt ? dflt : "";
++ }
++ span = ap_cpystrn(outp, result, space) - outp;
++ key[-1] = ':';
++ if (dflt) {
++ dflt[-1] = '|';
++ }
++ }
++ else if (inp[0] == '%') {
++ /* %{...} variable lookup expansion */
++ span = ap_cpystrn(outp, lookup_variable(r, inp+2), space) - outp;
++ }
++ else {
++ span = 0;
++ }
++ *endp = '}';
++ inp = endp+1;
++ outp += span;
++ space -= span;
++ continue;
++ }
++ else if (ap_isdigit(inp[1])) {
++ int n = inp[1] - '0';
++ backrefinfo *bri = NULL;
++ if (inp[0] == '$') {
++ /* $N RewriteRule regexp backref expansion */
++ bri = briRR;
++ }
++ else if (inp[0] == '%') {
++ /* %N RewriteCond regexp backref expansion */
++ bri = briRC;
++ }
++ /* see ap_pregsub() in src/main/util.c */
++ if (bri && n <= bri->nsub &&
++ bri->regmatch[n].rm_eo > bri->regmatch[n].rm_so) {
++ span = bri->regmatch[n].rm_eo - bri->regmatch[n].rm_so;
++ if (span > space) {
++ span = space;
++ }
++ memcpy(outp, bri->source + bri->regmatch[n].rm_so, span);
++ outp += span;
++ space -= span;
++ }
++ inp += 2;
++ continue;
++ }
++ skip:
++ *outp++ = *inp++;
++ space--;
++ }
++ *outp++ = '\0';
++}
++
++
++/*
++**
++** perform all the expansions on the environment variables
++**
++*/
++
++static void do_expand_env(request_rec *r, char *env[],
++ backrefinfo *briRR, backrefinfo *briRC)
++{
++ int i;
++ char buf[MAX_STRING_LEN];
++
++ for (i = 0; env[i] != NULL; i++) {
++ do_expand(r, env[i], buf, sizeof(buf), briRR, briRC);
++ add_env_variable(r, buf);
++ }
++}
++
++
+ /*
+ **
+ ** split out a QUERY_STRING part from
+@@ -2484,51 +2571,6 @@
+
+ /*
+ **
+-** Expand the %0-%9 or $0-$9 regex backreferences
+-**
+-*/
+-
+-static void expand_backref_inbuffer(pool *p, char *buf, int nbuf,
+- backrefinfo *bri, char c)
+-{
+- register int i;
+-
+- /* protect existing $N and & backrefs and replace <c>N with $N backrefs */
+- for (i = 0; buf[i] != '\0' && i < nbuf; i++) {
+- if (buf[i] == '\\' && (buf[i+1] != '\0' && i < (nbuf-1))) {
+- i++; /* protect next */
+- }
+- else if (buf[i] == '&') {
+- buf[i] = '\001';
+- }
+- else if (c != '$' && buf[i] == '$' && (buf[i+1] >= '0' && buf[i+1] <= '9')) {
+- buf[i] = '\002';
+- i++; /* speedup */
+- }
+- else if (buf[i] == c && (buf[i+1] >= '0' && buf[i+1] <= '9')) {
+- buf[i] = '$';
+- i++; /* speedup */
+- }
+- }
+-
+- /* now apply the standard regex substitution function */
+- ap_cpystrn(buf, ap_pregsub(p, buf, bri->source,
+- bri->nsub+1, bri->regmatch), nbuf);
+-
+- /* restore the original $N and & backrefs */
+- for (i = 0; buf[i] != '\0' && i < nbuf; i++) {
+- if (buf[i] == '\001') {
+- buf[i] = '&';
+- }
+- else if (buf[i] == '\002') {
+- buf[i] = '$';
+- }
+- }
+-}
+-
+-
+-/*
+-**
+ ** Expand tilde-paths (/~user) through
+ ** Unix /etc/passwd database information
+ **
+@@ -2571,120 +2613,6 @@
+ }
+ #endif
+
+-/*
+-**
+-** mapfile expansion support
+-** i.e. expansion of MAP lookup directives
+-** ${<mapname>:<key>} in RewriteRule rhs
+-**
+-*/
+-
+-#define limit_length(n) (n > LONG_STRING_LEN-1 ? LONG_STRING_LEN-1 : n)
+-
+-static void expand_map_lookups(request_rec *r, char *uri, int uri_len)
+-{
+- char newuri[MAX_STRING_LEN];
+- char *cpI;
+- char *cpIE;
+- char *cpO;
+- char *cpT;
+- char *cpT2;
+- char mapname[LONG_STRING_LEN];
+- char mapkey[LONG_STRING_LEN];
+- char defaultvalue[LONG_STRING_LEN];
+- int n;
+-
+- cpI = uri;
+- cpIE = cpI+strlen(cpI);
+- cpO = newuri;
+- while (cpI < cpIE) {
+- if (cpI+6 < cpIE && strncmp(cpI, "${", 2) == 0) {
+- /* missing delimiter -> take it as plain text */
+- if ( strchr(cpI+2, ':') == NULL
+- || strchr(cpI+2, '}') == NULL) {
+- memcpy(cpO, cpI, 2);
+- cpO += 2;
+- cpI += 2;
+- continue;
+- }
+- cpI += 2;
+-
+- cpT = strchr(cpI, ':');
+- n = cpT-cpI;
+- memcpy(mapname, cpI, limit_length(n));
+- mapname[limit_length(n)] = '\0';
+- cpI += n+1;
+-
+- cpT2 = strchr(cpI, '|');
+- cpT = strchr(cpI, '}');
+- if (cpT2 != NULL && cpT2 < cpT) {
+- n = cpT2-cpI;
+- memcpy(mapkey, cpI, limit_length(n));
+- mapkey[limit_length(n)] = '\0';
+- cpI += n+1;
+-
+- n = cpT-cpI;
+- memcpy(defaultvalue, cpI, limit_length(n));
+- defaultvalue[limit_length(n)] = '\0';
+- cpI += n+1;
+- }
+- else {
+- n = cpT-cpI;
+- memcpy(mapkey, cpI, limit_length(n));
+- mapkey[limit_length(n)] = '\0';
+- cpI += n+1;
+-
+- defaultvalue[0] = '\0';
+- }
+-
+- cpT = lookup_map(r, mapname, mapkey);
+- if (cpT != NULL) {
+- n = strlen(cpT);
+- if (cpO + n >= newuri + sizeof(newuri)) {
+- ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
+- r, "insufficient space in "
+- "expand_map_lookups, aborting");
+- return;
+- }
+- memcpy(cpO, cpT, n);
+- cpO += n;
+- }
+- else {
+- n = strlen(defaultvalue);
+- if (cpO + n >= newuri + sizeof(newuri)) {
+- ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
+- r, "insufficient space in "
+- "expand_map_lookups, aborting");
+- return;
+- }
+- memcpy(cpO, defaultvalue, n);
+- cpO += n;
+- }
+- }
+- else {
+- cpT = strstr(cpI, "${");
+- if (cpT == NULL)
+- cpT = cpI+strlen(cpI);
+- n = cpT-cpI;
+- if (cpO + n >= newuri + sizeof(newuri)) {
+- ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
+- r, "insufficient space in "
+- "expand_map_lookups, aborting");
+- return;
+- }
+- memcpy(cpO, cpI, n);
+- cpO += n;
+- cpI += n;
+- }
+- }
+- *cpO = '\0';
+- ap_cpystrn(uri, newuri, uri_len);
+- return;
+-}
+-
+-#undef limit_length
+-
+-
+
+ /*
+ ** +-------------------------------------------------------+
+@@ -3483,53 +3411,6 @@
+ */
+
+
+-static void expand_variables_inbuffer(request_rec *r, char *buf, int buf_len)
+-{
+- char *newbuf;
+- newbuf = expand_variables(r, buf);
+- if (strcmp(newbuf, buf) != 0) {
+- ap_cpystrn(buf, newbuf, buf_len);
+- }
+- return;
+-}
+-
+-static char *expand_variables(request_rec *r, char *str)
+-{
+- char output[MAX_STRING_LEN];
+- char input[MAX_STRING_LEN];
+- char *cp;
+- char *cp2;
+- char *cp3;
+- int expanded;
+- char *outp;
+- char *endp;
+-
+- ap_cpystrn(input, str, sizeof(input));
+- output[0] = '\0';
+- outp = output;
+- endp = output + sizeof(output);
+- expanded = 0;
+- for (cp = input; cp < input+MAX_STRING_LEN; ) {
+- if ((cp2 = strstr(cp, "%{")) != NULL) {
+- if ((cp3 = strstr(cp2, "}")) != NULL) {
+- *cp2 = '\0';
+- outp = ap_cpystrn(outp, cp, endp - outp);
+-
+- cp2 += 2;
+- *cp3 = '\0';
+- outp = ap_cpystrn(outp, lookup_variable(r, cp2), endp - outp);
+-
+- cp = cp3+1;
+- expanded = 1;
+- continue;
+- }
+- }
+- outp = ap_cpystrn(outp, cp, endp - outp);
+- break;
+- }
+- return expanded ? ap_pstrdup(r->pool, output) : str;
+-}
+-
+ static char *lookup_variable(request_rec *r, char *var)
+ {
+ const char *result;
+diff -uNr apache_1.3.11.orig/src/modules/standard/mod_rewrite.h apache_1.3.11/src/modules/standard/mod_rewrite.h
+--- apache_1.3.11.orig/src/modules/standard/mod_rewrite.h Thu Oct 21 22:45:38 1999
++++ apache_1.3.11/src/modules/standard/mod_rewrite.h Thu Oct 5 14:48:43 2000
+@@ -420,14 +420,16 @@
+ char *perdir, backrefinfo *briRR,
+ backrefinfo *briRC);
+
++static void do_expand(request_rec *r, char *input, char *buffer, int nbuf,
++ backrefinfo *briRR, backrefinfo *briRC);
++static void do_expand_env(request_rec *r, char *env[],
++ backrefinfo *briRR, backrefinfo *briRC);
++
+ /* URI transformation function */
+ static void splitout_queryargs(request_rec *r, int qsappend);
+ static void fully_qualify_uri(request_rec *r);
+ static void reduce_uri(request_rec *r);
+-static void expand_backref_inbuffer(pool *p, char *buf, int nbuf,
+- backrefinfo *bri, char c);
+ static char *expand_tildepaths(request_rec *r, char *uri);
+-static void expand_map_lookups(request_rec *r, char *uri, int uri_len);
+
+ /* rewrite map support functions */
+ static char *lookup_map(request_rec *r, char *name, char *key);
+@@ -466,8 +468,6 @@
+ static int rewritemap_program_child(void *cmd, child_info *pinfo);
+
+ /* env variable support */
+-static void expand_variables_inbuffer(request_rec *r, char *buf, int buf_len);
+-static char *expand_variables(request_rec *r, char *str);
+ static char *lookup_variable(request_rec *r, char *var);
+ static char *lookup_header(request_rec *r, const char *name);
+