Apache has several bugs in mod_rewrite and mod_vhost_alias that could
cause arbirtary files on the server to be exposed under certain configurations.
if you are using theses modules.
Apply by doing:
cd /usr/src
patch -p0 < 031_httpd_patch
cd usr.sbin/httpd
make -f Makefile.bsd-wrapper obj
make -f Makefile.bsd-wrapper depend
make -f Makefile.bsd-wrapper
make -f Makefile.bsd-wrapper install
/*
* Apply the patterns
@@ -2194,7 +2107,7 @@
}
}
else if (strcmp(p->pattern, "-l") == 0) {
-#if !defined(OS2) && !defined(WIN32)
+#if !defined(OS2) && !defined(WIN32) && !defined(NETWARE)
if (lstat(input, &sb) == 0) {
if (S_ISLNK(sb.st_mode)) {
rc = 1;
@@ -2211,12 +2124,7 @@
}
else if (strcmp(p->pattern, "-U") == 0) {
/* avoid infinite subrequest recursion */
- if (strlen(input) > 0 /* nonempty path, and */
- && ( r->main == NULL /* - either not in a subrequest */
- || ( r->main->uri != NULL /* - or in a subrequest... */
- && r->uri != NULL /* ...and URIs aren't NULL... */
- /* ...and sub/main URIs differ */
- && strcmp(r->main->uri, r->uri) != 0) ) ) {
+ if (strlen(input) > 0 && subreq_ok(r)) {
/* run a URI-based subrequest */
rsub = ap_sub_req_lookup_uri(input, r);
@@ -2235,12 +2143,7 @@
}
else if (strcmp(p->pattern, "-F") == 0) {
/* avoid infinite subrequest recursion */
- if (strlen(input) > 0 /* nonempty path, and */
- && ( r->main == NULL /* - either not in a subrequest */
- || ( r->main->uri != NULL /* - or in a subrequest... */
- && r->uri != NULL /* ...and URIs aren't NULL... */
- /* ...and sub/main URIs differ */
- && strcmp(r->main->uri, r->uri) != 0) ) ) {
+ if (strlen(input) > 0 && subreq_ok(r)) {
/* process a file-based subrequest:
* this differs from -U in that no path translation is done.
@@ -2314,8 +2217,161 @@
** +-------------------------------------------------------+
*/
+
/*
**
+** 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 = find_closing_bracket(inp+2, '{', '}');
+ if (endp == NULL) {
+ goto skip;
+ }
+ *endp = '\0';
+ if (inp[0] == '$') {
+ /* ${...} map lookup expansion */
+ /*
+ * To make rewrite maps useful the lookup key and
+ * default values must be expanded, so we make
+ * recursive calls to do the work. For security
+ * reasons we must never expand a string that includes
+ * verbatim data from the network. The recursion here
+ * isn't a problem because the result of expansion is
+ * only passed to lookup_map() so it cannot be
+ * re-expanded, only re-looked-up. Another way of
+ * looking at it is that the recursion is entirely
+ * driven by the syntax of the nested curly brackets.
+ */
+ char *key, *dflt, *result;
+ char xkey[MAX_STRING_LEN];
+ char xdflt[MAX_STRING_LEN];
+ char *empty = "";
+ key = strchr(inp, ':');
+ if (key == NULL) {
+ goto skip;
+ }
+ *key++ = '\0';
+ dflt = strchr(key, '|');
+ if (dflt == NULL) {
+ dflt = empty;
+ }
+ else {
+ *dflt++ = '\0';
+ }
+ 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 = ap_cpystrn(outp, result, space) - outp;
+ key[-1] = ':';
+ if (dflt != empty) {
+ 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
** the current URI string
**
@@ -2442,20 +2498,12 @@
static void fully_qualify_uri(request_rec *r)
{
- int i;
char buf[32];
const char *thisserver;
char *thisport;
int port;
- i = strlen(r->filename);
- if (!( (i > 7 && strncasecmp(r->filename, "http://", 7) == 0)
- || (i > 8 && strncasecmp(r->filename, "https://", 8) == 0)
- || (i > 9 && strncasecmp(r->filename, "gopher://", 9) == 0)
- || (i > 6 && strncasecmp(r->filename, "ftp://", 6) == 0)
- || (i > 5 && strncasecmp(r->filename, "ldap:", 5) == 0)
- || (i > 5 && strncasecmp(r->filename, "news:", 5) == 0)
- || (i > 7 && strncasecmp(r->filename, "mailto:", 7) == 0))) {
+ if (!is_absolute_uri(r->filename)) {
thisserver = ap_get_server_name(r);
port = ap_get_server_port(r);
@@ -2484,45 +2532,24 @@
/*
**
-** Expand the %0-%9 or $0-$9 regex backreferences
+** return non-zero if the URI is absolute (includes a scheme etc.)
**
*/
-static void expand_backref_inbuffer(pool *p, char *buf, int nbuf,
- backrefinfo *bri, char c)
+static int is_absolute_uri(char *uri)
{
- 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 */
- }
+ int i = strlen(uri);
+ if ( (i > 7 && strncasecmp(uri, "http://", 7) == 0)
+ || (i > 8 && strncasecmp(uri, "https://", 8) == 0)
+ || (i > 9 && strncasecmp(uri, "gopher://", 9) == 0)
+ || (i > 6 && strncasecmp(uri, "ftp://", 6) == 0)
+ || (i > 5 && strncasecmp(uri, "ldap:", 5) == 0)
+ || (i > 5 && strncasecmp(uri, "news:", 5) == 0)
+ || (i > 7 && strncasecmp(uri, "mailto:", 7) == 0) ) {
+ return 1;
}
-
- /* 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] = '$';
- }
+ else {
+ return 0;
}
}
@@ -2571,121 +2598,8 @@
}
#endif
-/*
-**
-** mapfile expansion support
-** i.e. expansion of MAP lookup directives
-** ${<mapname>:<key>} in RewriteRule rhs
-**
-*/