dgaudet 98/02/03 01:53:51
Modified: src CHANGES http_protocol.c
Log:
Ed's patch has been running on one of my 1.2 servers w/name and ip vhosts
for 5 days now without a hassle.
Ed says:
> I posted a patch much like this some months ago, but Dean pointed out that
> it still had a few problems. So far as I can see, this covers all of
> those; check_fulluri and reduce_uri (in mod_rewrite) can mess with
> r->filename (removing http[s]://{hostname}[:{port}]), but they don't
> change r->server, which is where the security hole lies.
>
> It also fixes check_fulluri to work for virtual hosts w/ a wildcard port
> and/or multiple ports.
>
> It also fixes check_serverpath, which should make sure the server in
> question can possibly be listening for this request (note that one of
> either check_hostalias and check_serverpath will run).
>
> It's not needed for 1.3, since Dean's rewrite of the vhost code fixed it
> in that.
Submitted by: Ed Korthof <ed@organic.com>
Revision Changes Path
1.291 +7 -0 apache-1.2/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /export/home/cvs/apache-1.2/src/CHANGES,v
retrieving revision 1.290
retrieving revision 1.291
diff -u -r1.290 -r1.291
--- CHANGES 1998/02/01 02:47:37 1.290
+++ CHANGES 1998/02/03 09:53:48 1.291
@@ -1,4 +1,11 @@
Changes with Apache 1.2.6
+
+ *) SECURITY: When a client connects to a particular port/addr, and
+ gives a Host: header ensure that the virtual host requested can
+ actually be reached via that port/addr. [Ed Korthof <ed@organic.com>]
+
+ *) Support virtual hosts with wildcard port and/or multiple ports
+ properly. [Ed Korthof <ed@organic.com>]
*) Fixed some case-sensitivity issues according to RFC2068.
[Dean Gaudet]
1.131 +112 -31 apache-1.2/src/http_protocol.c
Index: http_protocol.c
===================================================================
RCS file: /export/home/cvs/apache-1.2/src/http_protocol.c,v
retrieving revision 1.130
retrieving revision 1.131
diff -u -r1.130 -r1.131
--- http_protocol.c 1998/02/01 02:47:39 1.130
+++ http_protocol.c 1998/02/03 09:53:49 1.131
@@ -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;
}
}
|