From: André Malo Date: Wed, 19 Mar 2003 14:01:08 +0000 (+0000) Subject: backport from 2.x: X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=13da0890e8c4d65446aaaa1c4025464a2b2c525d;p=thirdparty%2Fapache%2Fhttpd.git backport from 2.x: Prevent endless loops of internal redirects in mod_rewrite by aborting after exceeding a limit of internal redirects. The limit defaults to 10 and can be changed using the RewriteOptions directive with the new MaxRedirects=n argument. (The latter required some restructuring of the RewriteOptions evaluation code). PR: 17462 Reviewed by: Will Rowe, Ian Holsman git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x@99022 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/CHANGES b/src/CHANGES index 1b026646060..a6b9ee40d54 100644 --- a/src/CHANGES +++ b/src/CHANGES @@ -1,5 +1,10 @@ Changes with Apache 1.3.28 + *) backport from 2.x series: Prevent endless loops of internal redirects + in mod_rewrite by aborting after exceeding a limit of internal redirects. + The limit defaults to 10 and can be changed using the RewriteOptions + directive. PR 17462. [André Malo] + *) Use the correct locations of srm.conf and access.conf when tailoring the httpd.conf during the install process. PR 9446. [Stanislav Brabec ] diff --git a/src/modules/standard/mod_rewrite.c b/src/modules/standard/mod_rewrite.c index fdac21eae3a..9a905e8474f 100644 --- a/src/modules/standard/mod_rewrite.c +++ b/src/modules/standard/mod_rewrite.c @@ -252,6 +252,7 @@ static void *config_server_create(pool *p, server_rec *s) a->rewriteconds = ap_make_array(p, 2, sizeof(rewritecond_entry)); a->rewriterules = ap_make_array(p, 2, sizeof(rewriterule_entry)); a->server = s; + a->redirect_limit = 0; /* unset (use default) */ return (void *)a; } @@ -267,6 +268,9 @@ static void *config_server_merge(pool *p, void *basev, void *overridesv) a->state = overrides->state; a->options = overrides->options; a->server = overrides->server; + a->redirect_limit = overrides->redirect_limit + ? overrides->redirect_limit + : base->redirect_limit; if (a->options & OPTION_INHERIT) { /* @@ -323,6 +327,7 @@ static void *config_perdir_create(pool *p, char *path) a->baseurl = NULL; a->rewriteconds = ap_make_array(p, 2, sizeof(rewritecond_entry)); a->rewriterules = ap_make_array(p, 2, sizeof(rewriterule_entry)); + a->redirect_limit = 0; /* unset (use server config) */ if (path == NULL) { a->directory = NULL; @@ -353,6 +358,9 @@ static void *config_perdir_merge(pool *p, void *basev, void *overridesv) a->options = overrides->options; a->directory = overrides->directory; a->baseurl = overrides->baseurl; + a->redirect_limit = overrides->redirect_limit + ? overrides->redirect_limit + : base->redirect_limit; if (a->options & OPTION_INHERIT) { a->rewriteconds = ap_append_arrays(p, overrides->rewriteconds, @@ -395,36 +403,50 @@ static const char *cmd_rewriteengine(cmd_parms *cmd, } static const char *cmd_rewriteoptions(cmd_parms *cmd, - rewrite_perdir_conf *dconf, char *option) + void *in_dconf, const char *option) { - rewrite_server_conf *sconf; - const char *err; + int options = 0, limit = 0; + char *w; - sconf = (rewrite_server_conf *) - ap_get_module_config(cmd->server->module_config, &rewrite_module); + while (*option) { + w = ap_getword_conf(cmd->pool, &option); - if (cmd->path == NULL) { /* is server command */ - err = cmd_rewriteoptions_setoption(cmd->pool, - &(sconf->options), option); - } - else { /* is per-directory command */ - err = cmd_rewriteoptions_setoption(cmd->pool, - &(dconf->options), option); + if (!strcasecmp(w, "inherit")) { + options |= OPTION_INHERIT; + } + else if (!strncasecmp(w, "MaxRedirects=", 13)) { + limit = atoi(&w[13]); + if (limit <= 0) { + return "RewriteOptions: MaxRedirects takes a number greater " + "than zero."; + } + } + else if (!strcasecmp(w, "MaxRedirects")) { /* be nice */ + return "RewriteOptions: MaxRedirects has the format MaxRedirects" + "=n."; + } + else { + return ap_pstrcat(cmd->pool, "RewriteOptions: unknown option '", + w, "'", NULL); + } } - return err; -} + /* put it into the appropriate config */ + if (cmd->path == NULL) { /* is server command */ + rewrite_server_conf *conf = + ap_get_module_config(cmd->server->module_config, + &rewrite_module); -static const char *cmd_rewriteoptions_setoption(pool *p, int *options, - char *name) -{ - if (strcasecmp(name, "inherit") == 0) { - *options |= OPTION_INHERIT; + conf->options |= options; + conf->redirect_limit = limit; } - else { - return ap_pstrcat(p, "RewriteOptions: unknown option '", - name, "'\n", NULL); + else { /* is per-directory command */ + rewrite_perdir_conf *conf = in_dconf; + + conf->options |= options; + conf->redirect_limit = limit; } + return NULL; } @@ -1598,6 +1620,15 @@ static int handler_redirect(request_rec *r) return DECLINED; } + if (is_redirect_limit_exceeded(r)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r, + "mod_rewrite: maximum number of internal redirects " + "reached. Assuming configuration error. Use " + "'RewriteOptions MaxRedirects' to increase the limit " + "if neccessary."); + return HTTP_INTERNAL_SERVER_ERROR; + } + /* now do the internal redirect */ ap_internal_redirect(ap_pstrcat(r->pool, r->filename+9, r->args ? "?" : NULL, r->args, NULL), r); @@ -1606,6 +1637,60 @@ static int handler_redirect(request_rec *r) return OK; } +/* + * check whether redirect limit is reached + */ +static int is_redirect_limit_exceeded(request_rec *r) +{ + request_rec *top = r; + rewrite_request_conf *reqc; + rewrite_perdir_conf *dconf; + + /* we store it in the top request */ + while (top->main) { + top = top->main; + } + while (top->prev) { + top = top->prev; + } + + /* fetch our config */ + reqc = (rewrite_request_conf *) ap_get_module_config(top->request_config, + &rewrite_module); + + /* no config there? create one. */ + if (!reqc) { + rewrite_server_conf *sconf; + + reqc = ap_palloc(top->pool, sizeof(rewrite_request_conf)); + sconf = ap_get_module_config(r->server->module_config, &rewrite_module); + + reqc->redirects = 0; + reqc->redirect_limit = sconf->redirect_limit + ? sconf->redirect_limit + : REWRITE_REDIRECT_LIMIT; + + /* associate it with this request */ + ap_set_module_config(top->request_config, &rewrite_module, reqc); + } + + /* allow to change the limit during redirects. */ + dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config, + &rewrite_module); + + /* 0 == unset; take server conf ... */ + if (dconf->redirect_limit) { + reqc->redirect_limit = dconf->redirect_limit; + } + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r, + "mod_rewrite's internal redirect status: %d/%d.", + reqc->redirects, reqc->redirect_limit); + + /* and now give the caller a hint */ + return (reqc->redirects++ >= reqc->redirect_limit); +} + /* ** +-------------------------------------------------------+ diff --git a/src/modules/standard/mod_rewrite.h b/src/modules/standard/mod_rewrite.h index 27806b1335c..47f43917f5a 100644 --- a/src/modules/standard/mod_rewrite.h +++ b/src/modules/standard/mod_rewrite.h @@ -255,6 +255,9 @@ #define MAX_NMATCH 10 +/* default maximum number of internal redirects */ +#define REWRITE_REDIRECT_LIMIT 10 + /* ** ** our private data structures we handle with @@ -309,6 +312,7 @@ typedef struct { array_header *rewriteconds; /* the RewriteCond entries (temporary) */ array_header *rewriterules; /* the RewriteRule entries */ server_rec *server; /* the corresponding server indicator */ + int redirect_limit; /* maximum number of internal redirects */ } rewrite_server_conf; @@ -322,8 +326,16 @@ typedef struct { array_header *rewriterules; /* the RewriteRule entries */ char *directory; /* the directory where it applies */ char *baseurl; /* the base-URL where it applies */ + int redirect_limit; /* maximum number of internal redirects */ } rewrite_perdir_conf; + /* the per-request configuration + */ +typedef struct { + int redirects; /* current number of redirects */ + int redirect_limit; /* maximum number of redirects */ +} rewrite_request_conf; + /* the cache structures, * a 4-way hash table with LRU functionality @@ -376,10 +388,8 @@ static void *config_perdir_merge (pool *p, void *basev, void *overridesv); static const char *cmd_rewriteengine(cmd_parms *cmd, rewrite_perdir_conf *dconf, int flag); static const char *cmd_rewriteoptions(cmd_parms *cmd, - rewrite_perdir_conf *dconf, - char *option); -static const char *cmd_rewriteoptions_setoption(pool *p, int *options, - char *name); + void *in_dconf, + const char *option); static const char *cmd_rewritelog (cmd_parms *cmd, void *dconf, char *a1); static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, char *a1); static const char *cmd_rewritemap (cmd_parms *cmd, void *dconf, char *a1, @@ -489,6 +499,7 @@ static int parseargline(char *str, char **a1, char **a2, char **a3); static int prefix_stat(const char *path, struct stat *sb); static void add_env_variable(request_rec *r, char *s); static int subreq_ok(request_rec *r); +static int is_redirect_limit_exceeded(request_rec *r); /* File locking */ static void fd_lock(request_rec *r, int fd);