httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject Re: [PATCH] Apache 1.2.5 -- security fix for name-based vhosts
Date Fri, 30 Jan 1998 10:02:30 GMT
Here's a slightly modified version of Ed's patch... I think I made only
strcmp/strcasecmp switches.  I've got this running on a 1.2 server which
has both name and ip vhosts, no problems yet.  I'll commit in a few days
unless something comes up. 

Dean

Index: http_protocol.c
===================================================================
RCS file: /export/home/cvs/apache-1.2/src/http_protocol.c,v
retrieving revision 1.127
diff -u -r1.127 http_protocol.c
--- http_protocol.c	1998/01/30 09:13:56	1.127
+++ http_protocol.c	1998/01/30 09:38:32
@@ -548,13 +548,15 @@
     }
 }
 
-const char *check_fulluri (request_rec *r, const char *uri) {
+const char *check_fulluri (request_rec *r, const char *uri)
+{
   char *name, *host;
   int i;
   unsigned port;
+  server_addr_rec * sar;
 
   /* This routine parses full URLs, if they match the server */
-  if (strncmp(uri, "http://", 7)) return uri;
+  if (strncasecmp(uri, "http://", 7)) return uri;
   name = pstrdup(r->pool, uri + 7);
   
   /* Find the hostname, assuming a valid request */
@@ -567,7 +569,13 @@
   else port = 80;
 
   /* Make sure ports patch */
-  if (port != r->server->port) return uri;
+  if (port != r->server->port) {
+    for (sar = r->server->addrs; sar; sar = sar->next) {
+      if( (sar->host_port == 0) || (port == sar->host_port) )
+        break;
+    }
+    if (!sar) return uri;
+  }
 
   /* Save it for later use */
   r->hostname = pstrdup(r->pool, host);
@@ -678,15 +686,29 @@
     }
 }
 
-static void check_hostalias (request_rec *r) {
+#define ADDR_MATCHES(addr1,addr2) \
+   (addr1.s_addr == addr2.s_addr) || (addr1.s_addr == htonl(INADDR_ANY)) \
+        || (addr1.s_addr == DEFAULT_VHOST_ADDR)
+
+static void check_hostalias (request_rec *r)
+{
   const char *hostname=r->hostname;
   char *host = getword(r->pool, &hostname, ':');	/* Get rid of port */
   unsigned port = (*hostname) ? atoi(hostname) : 80;
-  server_rec *s;
+  server_rec *s = r->server;
+  server_addr_rec * sar;
   int l;
 
-  if (port && (port != r->server->port))
-    return;
+/* make sure the client can't spoof the port;
+ * have to check all possiblities to see if the server
+ * should be listening. */
+  if (port != r->server->port) {
+    for (sar = s->addrs; sar; sar = sar->next) {
+      if ( (port == sar->host_port) || (sar->host_port == 0) )
+        break;
+    }
+    if (!sar) return;
+  }
 
   l = strlen(host)-1;
   if ((host[l]) == '.') {
@@ -704,37 +726,68 @@
 	    configuration */
 	continue;
     }
-
-    if ((!strcasecmp(host, s->server_hostname)) && (port == s->port)) {
-      r->server = r->connection->server = s;
-      if (r->hostlen && !strncmp(r->uri, "http://", 7)) {
-	r->uri += r->hostlen;
-	parse_uri(r, r->uri);
+/* ok, now there are several possibilities, and we're matching the
+ * hostname, the port, and r->connection->local_addr.  The last is
+ * required so as to only respond on an address to which this vhost
+ * should actually be listening.
+ *
+ * Either we can match s->server_name and s->port while matching
+ * against the ip address in a record in the s->addrs list *or* we
+ * can match s->server_name and a complete record in the s->addrs
+ * list *or* we can match the virtual host name and the address and
+ * the port of a record in the s->addrs list.
+ */
+    if (!strcasecmp(host,s->server_hostname)) {   /* ServerName matches hostname */
+      if (port == s->port) {                  /* possibly configured by Port */
+        for (sar = s->addrs; sar; sar = sar->next) {
+          if (ADDR_MATCHES(sar->host_addr,r->connection->local_addr.sin_addr))
+            break; /* SN matches, Port matches, and one IP addr matches */
+        }
+      } else {                             /* check to see if an addr matches */
+        for (sar = s->addrs; sar; sar = sar->next) {
+          if (((port == sar->host_port) || (sar->host_port == 0))
+              && (ADDR_MATCHES(sar->host_addr,
+                               r->connection->local_addr.sin_addr)))
+            break; /* SN matches, and a addr matches IP & port */
+        }
       }
-    }
+      if (sar) { /* we got a match */
+        r->server = r->connection->server = s;
+        if (r->hostlen && !strncasecmp(r->uri, "http://", 7)) {
+          r->uri += r->hostlen;
+          parse_uri(r, r->uri);
+          /* we still might want to do something below (ie. set r->proxyreq) */
+        }
+      }
+    } /* ServerName doesn't match */
 
-    /* search all the names from <VirtualHost> directive */
-    for( sar = s->addrs; sar; sar = sar->next ) {
-      if( !strcasecmp( sar->virthost, host ) &&
-       ( (sar->host_port == 0) || (port == sar->host_port) )) {
-	r->server = r->connection->server = s;
-	if( r->hostlen && !strncmp( r->uri, "http://", 7) ) {
-	  r->uri += r->hostlen;
-	  r->proxyreq = 0;
-	}
+    /* now s->addrs list, include the names, from the VirtualHost directive */
+    for (sar = s->addrs; sar; sar = sar->next) {
+      if (((sar->host_port==0) || (port==sar->host_port))
+          && (ADDR_MATCHES(sar->host_addr,r->connection->local_addr.sin_addr))
+          && !strcasecmp(host,sar->virthost)) {
+        /* ok, an element in the addrs list matched all three items */
+        r->server = r->connection->server = s;
+        if (r->hostlen && !strncasecmp(r->uri, "http://", 7)) {
+          r->uri += r->hostlen;
+          r->proxyreq = 0;
+        }
       }
     }
 
-    /* search all the aliases from ServerAlias directive */
+    /* search all the aliases from ServerAlias directive
+     * ServerAlias acts like a wildcard, so as to help deal with the
+     * transition when the DNS for a given host changes.
+     */
     names = s->names;
-    if( names ) {
+    if (names) {
       while (*names) {
 	char *name = getword_conf (r->pool, &names);
 
 	if ((is_matchexp(name) && !strcasecmp_match(host, name)) ||
 	    (!strcasecmp(host, name))) {
 	  r->server = r->connection->server = s;
-	  if (r->hostlen && !strncmp(r->uri, "http://", 7)) {
+	  if (r->hostlen && !strncasecmp(r->uri, "http://", 7)) {
 	    r->uri += r->hostlen;
 	    r->proxyreq = 0;
 	  }
@@ -744,8 +797,11 @@
   }
 }
 
-void check_serverpath (request_rec *r) {
+void check_serverpath (request_rec *r)
+{
   server_rec *s;
+  server_addr_rec * sar = NULL;
+  int port = r->connection->local_addr.sin_port;
 
   /* This is in conjunction with the ServerPath code in
    * http_core, so we get the right host attached to a non-
@@ -753,10 +809,35 @@
    */
 
   for (s = r->server->next; s; s = s->next) {
-    if (s->addrs && s->path && !strncmp(r->uri, s->path, s->pathlen)
&&
-	(s->path[s->pathlen - 1] == '/' ||
-	 r->uri[s->pathlen] == '/' ||
-	 r->uri[s->pathlen] == '\0'))
+    /* we should check to make sure that this server should be listening
+     * at all.
+     *
+     * this code is duplicated in check_hostalias, but only one of these
+     * two functions runs for a given request.
+     */
+    if (!s->addrs) continue;
+
+    if( (port == s->port) ) {
+        for(sar = s->addrs; sar; sar = sar->next) {
+          if(ADDR_MATCHES(sar->host_addr, r->connection->local_addr.sin_addr))
+            break;
+        }
+    }
+    else {
+        for(sar = s->addrs; sar; sar = sar->next) {
+          if( ( (port == sar->host_port) || (sar->host_port == 0) )
+              && ( ADDR_MATCHES(sar->host_addr,
+                                r->connection->local_addr.sin_addr) ) )
+            break;
+        }
+    }
+
+    if (!sar) continue; /* no match */
+
+    if (s->path && !strncmp(r->uri, s->path, s->pathlen)
+	&& (s->path[s->pathlen - 1] == '/'
+	    || r->uri[s->pathlen] == '/'
+	    || r->uri[s->pathlen] == '\0'))
       r->server = r->connection->server = s;
   }
 }

Mime
  • Unnamed multipart/mixed (inline, None, 0 bytes)
View raw message