I'm filing this bug here, so that it might get noticed before the next release
cycle and cause no more noise on tech@. Plus, the last diff I sent to tech@ was
the wrong one anyway. Whoops.
In server_http.c, the wrong server config struct is checked in the queue for
maxrequestbody. The code is only comparing to the first entry in the queue.
Attached is the diff I'm using on current. Original notice:
https://marc.info/?l=openbsd-tech&m=153255699713565&w=2
Hopefully, someone can decide the best way to progress.
Thanks and have a good day.
Tracey
Index: src/usr.sbin/httpd/httpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v
retrieving revision 1.142
diff -u -p -u -r1.142 httpd.h
--- src/usr.sbin/httpd/httpd.h 11 Oct 2018 09:52:22 -0000 1.142
+++ src/usr.sbin/httpd/httpd.h 29 Oct 2018 17:11:55 -0000
@@ -691,6 +691,8 @@ const char *
char *server_http_parsehost(char *, char *, size_t, int *);
ssize_t server_http_time(time_t, char *, size_t);
int server_log_http(struct client *, unsigned int, size_t);
+int server_check_config(struct server_config *, struct client *,
+ struct kv *, char *);
/* server_file.c */
int server_file(struct httpd *, struct client *);
Index: src/usr.sbin/httpd/server_http.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/server_http.c,v
retrieving revision 1.126
diff -u -p -u -r1.126 server_http.c
--- src/usr.sbin/httpd/server_http.c 15 Oct 2018 08:16:17 -0000 1.126
+++ src/usr.sbin/httpd/server_http.c 29 Oct 2018 17:11:55 -0000
@@ -197,6 +197,7 @@ done:
void
server_read_http(struct bufferevent *bev, void *arg)
{
+ char hostname[HOST_NAME_MAX+1];
struct client *clt = arg;
struct server_config *srv_conf = clt->clt_srv_conf;
struct http_descriptor *desc = clt->clt_descreq;
@@ -204,7 +205,7 @@ server_read_http(struct bufferevent *bev
char *line = NULL, *key, *value;
const char *errstr;
size_t size, linelen;
- struct kv *hdr = NULL;
+ struct kv *hdr = NULL, kv_key, *host;
getmonotime(&clt->clt_tv_last);
@@ -344,6 +345,15 @@ server_read_http(struct bufferevent *bev
goto abort;
}
+ kv_key.kv_key = "Host";
+ if ((host = kv_find(&desc->http_headers, &kv_key)) !=
+ NULL && host->kv_value == NULL)
+ host = NULL;
+
+ if (server_check_config(srv_conf, clt, host,
+ hostname))
+ goto fail;
+
/*
* Need to read data from the client after the
* HTTP header.
@@ -1183,10 +1193,7 @@ server_response(struct httpd *httpd, str
struct server *srv = clt->clt_srv;
struct server_config *srv_conf = &srv->srv_conf;
struct kv *kv, key, *host;
- struct str_find sm;
- int portval = -1, ret;
- char *hostval, *query;
- const char *errstr = NULL;
+ char *query;
/* Decode the URL */
if (desc->http_path == NULL ||
@@ -1234,58 +1241,8 @@ server_response(struct httpd *httpd, str
if (clt->clt_pipelining && clt->clt_toread > 0)
clt->clt_persist = 0;
- /*
- * Do we have a Host header and matching configuration?
- * XXX the Host can also appear in the URL path.
- */
- if (host != NULL) {
- if ((hostval = server_http_parsehost(host->kv_value,
- hostname, sizeof(hostname), &portval)) == NULL)
- goto fail;
-
- TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
-#ifdef DEBUG
- if ((srv_conf->flags & SRVFLAG_LOCATION) == 0) {
- DPRINTF("%s: virtual host \"%s:%u\""
- " host \"%s\" (\"%s\")",
- __func__, srv_conf->name,
- ntohs(srv_conf->port), host->kv_value,
- hostname);
- }
-#endif
- if (srv_conf->flags & SRVFLAG_LOCATION)
- continue;
- else if (srv_conf->flags & SRVFLAG_SERVER_MATCH) {
- str_find(hostname, srv_conf->name,
- &sm, 1, &errstr);
- ret = errstr == NULL ? 0 : -1;
- } else {
- ret = fnmatch(srv_conf->name,
- hostname, FNM_CASEFOLD);
- }
- if (ret == 0 &&
- (portval == -1 ||
- (portval != -1 && portval == srv_conf->port))) {
- /* Replace host configuration */
- clt->clt_srv_conf = srv_conf;
- srv_conf = NULL;
- break;
- }
- }
- }
-
- if (srv_conf != NULL) {
- /* Use the actual server IP address */
- if (server_http_host(&clt->clt_srv_ss, hostname,
- sizeof(hostname)) == NULL)
- goto fail;
- } else {
- /* Host header was valid and found */
- if (strlcpy(hostname, host->kv_value, sizeof(hostname)) >=
- sizeof(hostname))
- goto fail;
- srv_conf = clt->clt_srv_conf;
- }
+ if (server_check_config(srv_conf, clt, host, hostname))
+ goto fail;
if ((desc->http_host = strdup(hostname)) == NULL)
goto fail;
@@ -1764,4 +1721,69 @@ done:
free(agent_v);
return (ret);
+}
+
+int
+server_check_config(struct server_config *srv_conf, struct client *clt,
+ struct kv *host, char *hostname)
+{
+ struct server *srv = clt->clt_srv;
+ struct str_find sm;
+ size_t len = HOST_NAME_MAX+1;
+ int portval = -1, ret;
+ char *hostval;
+ const char *errstr = NULL;
+
+ /*
+ * Do we have a Host header and matching configuration?
+ * XXX the Host can also appear in the URL path.
+ */
+ if (host != NULL) {
+ if ((hostval = server_http_parsehost(host->kv_value,
+ hostname, len, &portval)) == NULL)
+ return(-1);
+
+ TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
+#ifdef DEBUG
+ if ((srv_conf->flags & SRVFLAG_LOCATION) == 0) {
+ DPRINTF("%s: virtual host \"%s:%u\""
+ " host \"%s\" (\"%s\")",
+ __func__, srv_conf->name,
+ ntohs(srv_conf->port), host->kv_value,
+ hostname);
+ }
+#endif
+ if (srv_conf->flags & SRVFLAG_LOCATION)
+ continue;
+ else if (srv_conf->flags & SRVFLAG_SERVER_MATCH) {
+ str_find(hostname, srv_conf->name,
+ &sm, 1, &errstr);
+ ret = errstr == NULL ? 0 : -1;
+ } else {
+ ret = fnmatch(srv_conf->name,
+ hostname, FNM_CASEFOLD);
+ }
+ if (ret == 0 &&
+ (portval == -1 ||
+ (portval != -1 && portval == srv_conf->port))) {
+ /* Replace host configuration */
+ clt->clt_srv_conf = srv_conf;
+ srv_conf = NULL;
+ break;
+ }
+ }
+ }
+
+ if (srv_conf != NULL) {
+ /* Use the actual server IP address */
+ if (server_http_host(&clt->clt_srv_ss, hostname,
+ len) == NULL)
+ return(-1);
+ } else {
+ /* Host header was valid and found */
+ if (strlcpy(hostname, host->kv_value, len) >= len)
+ return(-1);
+ srv_conf = clt->clt_srv_conf;
+ }
+ return(0);
}