Return-Path: Delivered-To: apache-cvs-archive@hyperreal.org Received: (qmail 6808 invoked by uid 6000); 3 Feb 1998 09:53:55 -0000 Received: (qmail 6792 invoked by alias); 3 Feb 1998 09:53:52 -0000 Delivered-To: apache-1.2-cvs@hyperreal.org Received: (qmail 6790 invoked by uid 143); 3 Feb 1998 09:53:51 -0000 Date: 3 Feb 1998 09:53:51 -0000 Message-ID: <19980203095351.6789.qmail@hyperreal.org> From: dgaudet@hyperreal.org To: apache-1.2-cvs@hyperreal.org Subject: cvs commit: apache-1.2/src CHANGES http_protocol.c Sender: apache-cvs-owner@apache.org Precedence: bulk Reply-To: new-httpd@apache.org 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 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 ] + + *) Support virtual hosts with wildcard port and/or multiple ports + properly. [Ed Korthof ] *) 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 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; } }