aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@esdenera.com>2015-08-03 17:26:57 +0200
committerReyk Floeter <reyk@esdenera.com>2015-08-03 17:26:57 +0200
commit72eaa1034c4612f84cd4ffa39a8d1ddf63a5479f (patch)
treedf4fcdd89abdf900b51471a8388a363577979bc4
parentc9b8164b7e7a829fc6e80c5879a5ba7e7448a3fb (diff)
downloadhttpd-72eaa1034c4612f84cd4ffa39a8d1ddf63a5479f.tar.gz
httpd-72eaa1034c4612f84cd4ffa39a8d1ddf63a5479f.zip
sync
-rw-r--r--httpd/config.c4
-rw-r--r--httpd/httpd.conf.57
-rw-r--r--httpd/httpd.h15
-rw-r--r--httpd/parse.y10
-rw-r--r--httpd/server.c39
-rw-r--r--httpd/server_fcgi.c61
-rw-r--r--httpd/server_file.c13
-rw-r--r--httpd/server_http.c31
8 files changed, 112 insertions, 68 deletions
diff --git a/httpd/config.c b/httpd/config.c
index 2829bed..15560ed 100644
--- a/httpd/config.c
+++ b/httpd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.41 2015/07/18 06:00:43 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.42 2015/07/19 05:17:27 reyk Exp $ */
/*
* Copyright (c) 2011 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -446,7 +446,7 @@ config_getserver_config(struct httpd *env, struct server *srv,
f = SRVFLAG_SERVER_HSTS;
srv_conf->flags |= parent->flags & f;
srv_conf->hsts_max_age = parent->hsts_max_age;
- srv_conf->hsts_subdomains = parent->hsts_subdomains;
+ srv_conf->hsts_flags = parent->hsts_flags;
memcpy(&srv_conf->timeout, &parent->timeout,
sizeof(srv_conf->timeout));
diff --git a/httpd/httpd.conf.5 b/httpd/httpd.conf.5
index 11dc3cd..785f726 100644
--- a/httpd/httpd.conf.5
+++ b/httpd/httpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: httpd.conf.5,v 1.67 2015/07/18 09:29:47 jmc Exp $
+.\" $OpenBSD: httpd.conf.5,v 1.68 2015/07/19 05:17:27 reyk Exp $
.\"
.\" Copyright (c) 2014, 2015 Reyk Floeter <reyk@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 18 2015 $
+.Dd $Mdocdate: July 19 2015 $
.Dt HTTPD.CONF 5
.Os
.Sh NAME
@@ -282,6 +282,9 @@ Valid options are:
Set the maximum time in seconds a receiving user agent should regard
this host as an HSTS host.
The default is one year.
+.It Ic preload
+Confirm and authenticate that the site is permitted to be included in
+a browser's preload list.
.It Ic subdomains
Signal to the receiving user agent that this host and all sub domains
of the host's domain should be considered HSTS hosts.
diff --git a/httpd/httpd.h b/httpd/httpd.h
index bbf02aa..9086baf 100644
--- a/httpd/httpd.h
+++ b/httpd/httpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: httpd.h,v 1.90 2015/07/18 06:00:43 reyk Exp $ */
+/* $OpenBSD: httpd.h,v 1.96 2015/08/03 11:45:17 florian Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -293,8 +293,6 @@ struct client {
in_port_t clt_port;
struct sockaddr_storage clt_ss;
struct bufferevent *clt_bev;
- char *clt_buf;
- size_t clt_buflen;
struct evbuffer *clt_output;
struct event clt_ev;
void *clt_descreq;
@@ -304,6 +302,7 @@ struct client {
int clt_fd;
struct tls *clt_tls_ctx;
struct bufferevent *clt_srvbev;
+ int clt_srvbev_throttled;
off_t clt_toread;
size_t clt_headerlen;
@@ -377,6 +376,10 @@ SPLAY_HEAD(client_tree, client);
"\10\01NODELAY\02NO_NODELAY\03SACK\04NO_SACK" \
"\05SOCKET_BUFFER_SIZE\06IP_TTL\07IP_MINTTL\10NO_SPLICE"
+#define HSTSFLAG_SUBDOMAINS 0x01
+#define HSTSFLAG_PRELOAD 0x02
+#define HSTSFLAG_BITS "\10\01SUBDOMAINS\02PRELOAD"
+
enum log_format {
LOG_FORMAT_COMMON,
LOG_FORMAT_COMBINED,
@@ -458,7 +461,7 @@ struct server_config {
off_t return_uri_len;
int hsts_max_age;
- int hsts_subdomains;
+ u_int8_t hsts_flags;
TAILQ_ENTRY(server_config) entry;
};
@@ -633,8 +636,8 @@ u_int32_t prefixlen2mask(u_int8_t);
int accept_reserve(int, struct sockaddr *, socklen_t *, int,
volatile int *);
struct kv *kv_add(struct kvtree *, char *, char *);
-int kv_set(struct kv *, char *, ...);
-int kv_setkey(struct kv *, char *, ...);
+int kv_set(struct kv *, char *, ...) __attribute__((__format__ (printf, 2, 3)));
+int kv_setkey(struct kv *, char *, ...) __attribute__((__format__ (printf, 2, 3)));
void kv_delete(struct kvtree *, struct kv *);
struct kv *kv_extend(struct kvtree *, struct kv *, char *);
void kv_purge(struct kvtree *);
diff --git a/httpd/parse.y b/httpd/parse.y
index 7b8da0e..cbb1374 100644
--- a/httpd/parse.y
+++ b/httpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.72 2015/07/18 06:00:43 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.73 2015/07/19 05:17:27 reyk Exp $ */
/*
* Copyright (c) 2007 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -133,7 +133,7 @@ typedef struct {
%token COMBINED CONNECTION DHE DIRECTORY ECDHE ERR FCGI INDEX IP KEY LISTEN
%token LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY ON PORT PREFORK PROTOCOLS
%token REQUEST REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TIMEOUT
-%token TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT
+%token TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD
%token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS
%token <v.string> STRING
%token <v.number> NUMBER
@@ -593,7 +593,10 @@ hstsflags : MAXAGE NUMBER {
srv_conf->hsts_max_age = $2;
}
| SUBDOMAINS {
- srv->srv_conf.hsts_subdomains = 1;
+ srv->srv_conf.hsts_flags |= HSTSFLAG_SUBDOMAINS;
+ }
+ | PRELOAD {
+ srv->srv_conf.hsts_flags |= HSTSFLAG_PRELOAD;
}
;
@@ -1176,6 +1179,7 @@ lookup(char *s)
{ "pass", PASS },
{ "port", PORT },
{ "prefork", PREFORK },
+ { "preload", PRELOAD },
{ "protocols", PROTOCOLS },
{ "request", REQUEST },
{ "requests", REQUESTS },
diff --git a/httpd/server.c b/httpd/server.c
index 86d0dca..ffd6d30 100644
--- a/httpd/server.c
+++ b/httpd/server.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server.c,v 1.70 2015/07/16 16:29:25 florian Exp $ */
+/* $OpenBSD: server.c,v 1.74 2015/08/03 11:45:17 florian Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -632,17 +632,9 @@ server_tls_writecb(int fd, short event, void *arg)
}
if (EVBUFFER_LENGTH(bufev->output)) {
- if (clt->clt_buf == NULL) {
- clt->clt_buflen = EVBUFFER_LENGTH(bufev->output);
- if ((clt->clt_buf = malloc(clt->clt_buflen)) == NULL) {
- what |= EVBUFFER_ERROR;
- goto err;
- }
- bcopy(EVBUFFER_DATA(bufev->output),
- clt->clt_buf, clt->clt_buflen);
- }
- ret = tls_write(clt->clt_tls_ctx, clt->clt_buf,
- clt->clt_buflen, &len);
+ ret = tls_write(clt->clt_tls_ctx,
+ EVBUFFER_DATA(bufev->output),
+ EVBUFFER_LENGTH(bufev->output), &len);
if (ret == TLS_READ_AGAIN || ret == TLS_WRITE_AGAIN) {
goto retry;
} else if (ret != 0) {
@@ -651,11 +643,6 @@ server_tls_writecb(int fd, short event, void *arg)
}
evbuffer_drain(bufev->output, len);
}
- if (clt->clt_buf != NULL) {
- free(clt->clt_buf);
- clt->clt_buf = NULL;
- clt->clt_buflen = 0;
- }
if (EVBUFFER_LENGTH(bufev->output) != 0)
server_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
@@ -666,16 +653,10 @@ server_tls_writecb(int fd, short event, void *arg)
return;
retry:
- if (clt->clt_buflen != 0)
- server_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+ server_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
return;
err:
- if (clt->clt_buf != NULL) {
- free(clt->clt_buf);
- clt->clt_buf = NULL;
- clt->clt_buflen = 0;
- }
(*bufev->errorcb)(bufev, what, bufev->cbarg);
}
@@ -747,8 +728,10 @@ server_write(struct bufferevent *bev, void *arg)
bufferevent_enable(bev, EV_READ);
- if (clt->clt_srvbev && !(clt->clt_srvbev->enabled & EV_READ))
+ if (clt->clt_srvbev && clt->clt_srvbev_throttled) {
bufferevent_enable(clt->clt_srvbev, EV_READ);
+ clt->clt_srvbev_throttled = 0;
+ }
return;
done:
@@ -792,8 +775,10 @@ server_read(struct bufferevent *bev, void *arg)
goto done;
if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(clt->clt_bev)) > (size_t)
- SERVER_MAX_PREFETCH * clt->clt_sndbufsiz)
- bufferevent_disable(bev, EV_READ);
+ SERVER_MAX_PREFETCH * clt->clt_sndbufsiz) {
+ bufferevent_disable(clt->clt_srvbev, EV_READ);
+ clt->clt_srvbev_throttled = 1;
+ }
return;
done:
diff --git a/httpd/server_fcgi.c b/httpd/server_fcgi.c
index 50a9d68..a5c96b1 100644
--- a/httpd/server_fcgi.c
+++ b/httpd/server_fcgi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server_fcgi.c,v 1.55 2015/07/17 20:44:57 reyk Exp $ */
+/* $OpenBSD: server_fcgi.c,v 1.63 2015/08/03 11:45:17 florian Exp $ */
/*
* Copyright (c) 2014 Florian Obser <florian@openbsd.org>
@@ -160,6 +160,7 @@ server_fcgi(struct httpd *env, struct client *clt)
if (clt->clt_srvbev != NULL)
bufferevent_free(clt->clt_srvbev);
+ clt->clt_srvbev_throttled = 0;
clt->clt_srvbev = bufferevent_new(fd, server_fcgi_read,
NULL, server_file_error, clt);
if (clt->clt_srvbev == NULL) {
@@ -180,9 +181,12 @@ server_fcgi(struct httpd *env, struct client *clt)
fcgi_record_header)];
begin->role = htons(FCGI_RESPONDER);
- bufferevent_write(clt->clt_srvbev, &param.buf,
+ if (bufferevent_write(clt->clt_srvbev, &param.buf,
sizeof(struct fcgi_record_header) +
- sizeof(struct fcgi_begin_request_body));
+ sizeof(struct fcgi_begin_request_body)) == -1) {
+ errstr = "failed to write to evbuffer";
+ goto fail;
+ }
h->type = FCGI_PARAMS;
h->content_len = param.total_len = 0;
@@ -306,8 +310,12 @@ server_fcgi(struct httpd *env, struct client *clt)
errstr = "failed to encode param";
goto fail;
}
- } else if (asprintf(&str, "%s?%s", desc->http_path,
- desc->http_query) != -1) {
+ } else {
+ if (asprintf(&str, "%s?%s", desc->http_path,
+ desc->http_query) == -1) {
+ errstr = "failed to encode param";
+ goto fail;
+ }
ret = fcgi_add_param(&param, "REQUEST_URI", str, clt);
free(str);
if (ret == -1) {
@@ -348,15 +356,21 @@ server_fcgi(struct httpd *env, struct client *clt)
}
if (param.total_len != 0) { /* send last params record */
- bufferevent_write(clt->clt_srvbev, &param.buf,
+ if (bufferevent_write(clt->clt_srvbev, &param.buf,
sizeof(struct fcgi_record_header) +
- ntohs(h->content_len));
+ ntohs(h->content_len)) == -1) {
+ errstr = "failed to write to client evbuffer";
+ goto fail;
+ }
}
/* send "no more params" message */
h->content_len = 0;
- bufferevent_write(clt->clt_srvbev, &param.buf,
- sizeof(struct fcgi_record_header));
+ if (bufferevent_write(clt->clt_srvbev, &param.buf,
+ sizeof(struct fcgi_record_header)) == -1) {
+ errstr = "failed to write to client evbuffer";
+ goto fail;
+ }
bufferevent_settimeout(clt->clt_srvbev,
srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec);
@@ -435,8 +449,9 @@ fcgi_add_param(struct server_fcgi_param *p, const char *key,
return (-1);
if (p->total_len + len > FCGI_CONTENT_SIZE) {
- bufferevent_write(clt->clt_srvbev, p->buf,
- sizeof(struct fcgi_record_header) + p->total_len);
+ if (bufferevent_write(clt->clt_srvbev, p->buf,
+ sizeof(struct fcgi_record_header) + p->total_len) == -1)
+ return (-1);
p->total_len = 0;
}
@@ -480,8 +495,10 @@ server_fcgi_read(struct bufferevent *bev, void *arg)
do {
len = bufferevent_read(bev, buf, clt->clt_fcgi_toread);
- /* XXX error handling */
- evbuffer_add(clt->clt_srvevb, buf, len);
+ if (evbuffer_add(clt->clt_srvevb, buf, len) == -1) {
+ server_abort_http(clt, 500, "short write");
+ return;
+ }
clt->clt_fcgi_toread -= len;
DPRINTF("%s: len: %lu toread: %d state: %d type: %d",
__func__, len, clt->clt_fcgi_toread,
@@ -573,11 +590,12 @@ server_fcgi_read(struct bufferevent *bev, void *arg)
int
server_fcgi_header(struct client *clt, u_int code)
{
+ struct server_config *srv_conf = clt->clt_srv_conf;
struct http_descriptor *desc = clt->clt_descreq;
struct http_descriptor *resp = clt->clt_descresp;
const char *error;
char tmbuf[32];
- struct kv *kv, key;
+ struct kv *kv, *cl, key;
if (desc == NULL || (error = server_httperror_byid(code)) == NULL)
return (-1);
@@ -586,7 +604,7 @@ server_fcgi_header(struct client *clt, u_int code)
return (-1);
/* Add error codes */
- if (kv_setkey(&resp->http_pathquery, "%lu", code) == -1 ||
+ if (kv_setkey(&resp->http_pathquery, "%u", code) == -1 ||
kv_set(&resp->http_pathquery, "%s", error) == -1)
return (-1);
@@ -618,6 +636,19 @@ server_fcgi_header(struct client *clt, u_int code)
} else if (kv_add(&resp->http_headers, "Connection", "close") == NULL)
return (-1);
+ /* HSTS header */
+ if (srv_conf->flags & SRVFLAG_SERVER_HSTS) {
+ if ((cl =
+ kv_add(&resp->http_headers, "Strict-Transport-Security",
+ NULL)) == NULL ||
+ kv_set(cl, "max-age=%d%s%s", srv_conf->hsts_max_age,
+ srv_conf->hsts_flags & HSTSFLAG_SUBDOMAINS ?
+ "; includeSubDomains" : "",
+ srv_conf->hsts_flags & HSTSFLAG_PRELOAD ?
+ "; preload" : "") == -1)
+ return (-1);
+ }
+
/* Date header is mandatory and should be added as late as possible */
if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0 ||
kv_add(&resp->http_headers, "Date", tmbuf) == NULL)
diff --git a/httpd/server_file.c b/httpd/server_file.c
index 9fd9ef2..e060124 100644
--- a/httpd/server_file.c
+++ b/httpd/server_file.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server_file.c,v 1.58 2015/07/18 14:36:24 kili Exp $ */
+/* $OpenBSD: server_file.c,v 1.60 2015/08/03 11:45:17 florian Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -66,7 +66,7 @@ server_file_access(struct httpd *env, struct client *clt,
struct server_config *srv_conf = clt->clt_srv_conf;
struct stat st;
struct kv *r, key;
- char *newpath;
+ char *newpath, *encodedpath;
int ret;
errno = 0;
@@ -90,10 +90,16 @@ server_file_access(struct httpd *env, struct client *clt,
/* Redirect to path with trailing "/" */
if (path[strlen(path) - 1] != '/') {
+ if ((encodedpath = url_encode(desc->http_path)) == NULL)
+ return (500);
if (asprintf(&newpath, "http%s://%s%s/",
srv_conf->flags & SRVFLAG_TLS ? "s" : "",
- desc->http_host, desc->http_path) == -1)
+ desc->http_host, encodedpath) == -1) {
+ free(encodedpath);
return (500);
+ }
+ free(encodedpath);
+
/* Path alias will be used for the redirection */
desc->http_path_alias = newpath;
@@ -256,6 +262,7 @@ server_file_request(struct httpd *env, struct client *clt, char *path,
if (clt->clt_srvbev != NULL)
bufferevent_free(clt->clt_srvbev);
+ clt->clt_srvbev_throttled = 0;
clt->clt_srvbev = bufferevent_new(clt->clt_fd, server_read,
server_write, server_file_error, clt);
if (clt->clt_srvbev == NULL) {
diff --git a/httpd/server_http.c b/httpd/server_http.c
index d51359f..bb29358 100644
--- a/httpd/server_http.c
+++ b/httpd/server_http.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server_http.c,v 1.91 2015/07/18 06:00:43 reyk Exp $ */
+/* $OpenBSD: server_http.c,v 1.96 2015/07/31 00:10:51 benno Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -742,6 +742,7 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
char *httpmsg, *body = NULL, *extraheader = NULL;
char tmbuf[32], hbuf[128], *hstsheader = NULL;
char buf[IBUF_READ_SIZE];
+ char *escapedmsg = NULL;
int bodylen;
if (code == 0) {
@@ -782,8 +783,12 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
msg = buf;
break;
case 401:
- if (asprintf(&extraheader,
- "WWW-Authenticate: Basic realm=\"%s\"\r\n", msg) == -1) {
+ if (stravis(&escapedmsg, msg, VIS_DQ) == -1) {
+ code = 500;
+ extraheader = NULL;
+ } else if (asprintf(&extraheader,
+ "WWW-Authenticate: Basic realm=\"%s\"\r\n", escapedmsg)
+ == -1) {
code = 500;
extraheader = NULL;
}
@@ -806,6 +811,8 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
break;
}
+ free(escapedmsg);
+
/* A CSS stylesheet allows minimal customization by the user */
style = "body { background-color: white; color: black; font-family: "
"'Comic Sans MS', 'Chalkboard SE', 'Comic Neue', sans-serif; }\n"
@@ -829,9 +836,11 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
if (srv_conf->flags & SRVFLAG_SERVER_HSTS) {
if (asprintf(&hstsheader, "Strict-Transport-Security: "
- "max-age=%d%s\r\n", srv_conf->hsts_max_age,
- srv_conf->hsts_subdomains == 0 ? "" :
- " ; includeSubDomains") == -1)
+ "max-age=%d%s%s\r\n", srv_conf->hsts_max_age,
+ srv_conf->hsts_flags & HSTSFLAG_SUBDOMAINS ?
+ "; includeSubDomains" : "",
+ srv_conf->hsts_flags & HSTSFLAG_PRELOAD ?
+ "; preload" : "") == -1)
goto done;
}
@@ -1235,7 +1244,7 @@ server_response_http(struct client *clt, u_int code,
return (-1);
/* Add error codes */
- if (kv_setkey(&resp->http_pathquery, "%lu", code) == -1 ||
+ if (kv_setkey(&resp->http_pathquery, "%u", code) == -1 ||
kv_set(&resp->http_pathquery, "%s", error) == -1)
return (-1);
@@ -1272,9 +1281,11 @@ server_response_http(struct client *clt, u_int code,
if ((cl =
kv_add(&resp->http_headers, "Strict-Transport-Security",
NULL)) == NULL ||
- kv_set(cl, "max-age=%d%s", srv_conf->hsts_max_age,
- srv_conf->hsts_subdomains == 0 ? "" :
- " ; includeSubDomains") == -1)
+ kv_set(cl, "max-age=%d%s%s", srv_conf->hsts_max_age,
+ srv_conf->hsts_flags & HSTSFLAG_SUBDOMAINS ?
+ "; includeSubDomains" : "",
+ srv_conf->hsts_flags & HSTSFLAG_PRELOAD ?
+ "; preload" : "") == -1)
return (-1);
}