From 72eaa1034c4612f84cd4ffa39a8d1ddf63a5479f Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Mon, 3 Aug 2015 17:26:57 +0200 Subject: sync --- httpd/config.c | 4 ++-- httpd/httpd.conf.5 | 7 ++++-- httpd/httpd.h | 15 +++++++------ httpd/parse.y | 10 ++++++--- httpd/server.c | 39 +++++++++++----------------------- httpd/server_fcgi.c | 61 ++++++++++++++++++++++++++++++++++++++++------------- httpd/server_file.c | 13 +++++++++--- httpd/server_http.c | 31 ++++++++++++++++++--------- 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 @@ -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 .\" @@ -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 @@ -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 @@ -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 STRING %token 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 @@ -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 @@ -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, ¶m.buf, + if (bufferevent_write(clt->clt_srvbev, ¶m.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(¶m, "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, ¶m.buf, + if (bufferevent_write(clt->clt_srvbev, ¶m.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, ¶m.buf, - sizeof(struct fcgi_record_header)); + if (bufferevent_write(clt->clt_srvbev, ¶m.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 @@ -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 @@ -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); } -- cgit v1.2.3-54-g00ecf