From f6babe9f2d05966903998909432e8b873b69192f Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Mon, 15 Aug 2016 20:54:53 +0200 Subject: sync --- httpd/config.c | 87 ++++++++++++-------------- httpd/control.c | 31 ++-------- httpd/http.h | 3 +- httpd/httpd.8 | 6 +- httpd/httpd.c | 152 ++++++++++++++++++++++++++++++++++------------ httpd/httpd.conf.5 | 76 +++++++++++++++++++++-- httpd/httpd.h | 61 ++++++++++--------- httpd/log.c | 171 ++++++++++++++++++++-------------------------------- httpd/logger.c | 9 ++- httpd/parse.y | 95 +++++++++++++++++------------ httpd/patterns.c | 5 +- httpd/patterns.h | 3 +- httpd/proc.c | 77 +++++++++++++++-------- httpd/server.c | 160 +++++++++++++++++++++++++++++++----------------- httpd/server_fcgi.c | 17 ++++-- httpd/server_file.c | 12 +++- httpd/server_http.c | 60 +++++++++--------- 17 files changed, 607 insertions(+), 418 deletions(-) diff --git a/httpd/config.c b/httpd/config.c index 8536028..4f8ef4c 100644 --- a/httpd/config.c +++ b/httpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.43 2015/08/20 13:00:23 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.47 2016/08/15 14:14:55 jsing Exp $ */ /* * Copyright (c) 2011 - 2015 Reyk Floeter @@ -113,7 +113,7 @@ config_setreset(struct httpd *env, unsigned int reset) if ((reset & ps->ps_what[id]) == 0 || id == privsep_process) continue; - proc_compose_imsg(ps, id, -1, IMSG_CTL_RESET, -1, + proc_compose(ps, id, IMSG_CTL_RESET, &reset, sizeof(reset)); } @@ -151,8 +151,8 @@ config_getcfg(struct httpd *env, struct imsg *imsg) what = ps->ps_what[privsep_process]; if (privsep_process != PROC_PARENT) - proc_compose_imsg(env->sc_ps, PROC_PARENT, -1, - IMSG_CFG_DONE, -1, NULL, 0); + proc_compose(env->sc_ps, PROC_PARENT, + IMSG_CFG_DONE, NULL, 0); return (0); } @@ -205,7 +205,7 @@ config_setserver(struct httpd *env, struct server *srv) else if ((fd = dup(srv->srv_s)) == -1) return (-1); if (proc_composev_imsg(ps, id, n, - IMSG_CFG_SERVER, fd, iov, c) != 0) { + IMSG_CFG_SERVER, -1, fd, iov, c) != 0) { log_warn("%s: failed to compose " "IMSG_CFG_SERVER imsg for `%s'", __func__, srv->srv_conf.name); @@ -216,7 +216,7 @@ config_setserver(struct httpd *env, struct server *srv) /* Configure TLS if necessary. */ config_settls(env, srv); } else { - if (proc_composev_imsg(ps, id, -1, IMSG_CFG_SERVER, -1, + if (proc_composev(ps, id, IMSG_CFG_SERVER, iov, c) != 0) { log_warn("%s: failed to compose " "IMSG_CFG_SERVER imsg for `%s'", @@ -233,61 +233,56 @@ int config_settls(struct httpd *env, struct server *srv) { struct privsep *ps = env->sc_ps; + struct server_config *srv_conf = &srv->srv_conf; struct tls_config tls; struct iovec iov[2]; size_t c; - if ((srv->srv_conf.flags & SRVFLAG_TLS) == 0) + if ((srv_conf->flags & SRVFLAG_TLS) == 0) return (0); - log_debug("%s: configuring TLS for %s", __func__, srv->srv_conf.name); + log_debug("%s: configuring tls for %s", __func__, srv_conf->name); - if (srv->srv_conf.tls_cert_len != 0) { - DPRINTF("%s: sending TLS cert \"%s[%u]\" to %s fd %d", __func__, - srv->srv_conf.name, srv->srv_conf.id, - ps->ps_title[PROC_SERVER], srv->srv_s); + if (srv_conf->tls_cert_len != 0) { + DPRINTF("%s: sending tls cert \"%s[%u]\" to %s fd %d", __func__, + srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER], + srv->srv_s); memset(&tls, 0, sizeof(tls)); - tls.id = srv->srv_conf.id; - tls.port = srv->srv_conf.port; - memcpy(&tls.ss, &srv->srv_conf.ss, sizeof(tls.ss)); - tls.tls_cert_len = srv->srv_conf.tls_cert_len; + tls.id = srv_conf->id; + tls.tls_cert_len = srv_conf->tls_cert_len; c = 0; iov[c].iov_base = &tls; iov[c++].iov_len = sizeof(tls); - iov[c].iov_base = srv->srv_conf.tls_cert; - iov[c++].iov_len = srv->srv_conf.tls_cert_len; + iov[c].iov_base = srv_conf->tls_cert; + iov[c++].iov_len = srv_conf->tls_cert_len; - if (proc_composev_imsg(ps, PROC_SERVER, -1, IMSG_CFG_TLS, -1, - iov, c) != 0) { + if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) { log_warn("%s: failed to compose IMSG_CFG_TLS imsg for " - "`%s'", __func__, srv->srv_conf.name); + "`%s'", __func__, srv_conf->name); return (-1); } } - if (srv->srv_conf.tls_key_len != 0) { - DPRINTF("%s: sending TLS key \"%s[%u]\" to %s fd %d", __func__, - srv->srv_conf.name, srv->srv_conf.id, - ps->ps_title[PROC_SERVER], srv->srv_s); + if (srv_conf->tls_key_len != 0) { + DPRINTF("%s: sending tls key \"%s[%u]\" to %s fd %d", __func__, + srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER], + srv->srv_s); memset(&tls, 0, sizeof(tls)); - tls.id = srv->srv_conf.id; - tls.port = srv->srv_conf.port; - memcpy(&tls.ss, &srv->srv_conf.ss, sizeof(tls.ss)); - tls.tls_key_len = srv->srv_conf.tls_key_len; + tls.id = srv_conf->id; + tls.tls_key_len = srv_conf->tls_key_len; c = 0; iov[c].iov_base = &tls; iov[c++].iov_len = sizeof(tls); - iov[c].iov_base = srv->srv_conf.tls_key; - iov[c++].iov_len = srv->srv_conf.tls_key_len; + iov[c].iov_base = srv_conf->tls_key; + iov[c++].iov_len = srv_conf->tls_key_len; - if (proc_composev_imsg(ps, PROC_SERVER, -1, IMSG_CFG_TLS, -1, - iov, c) != 0) { + if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) { log_warn("%s: failed to compose IMSG_CFG_TLS imsg for " - "`%s'", __func__, srv->srv_conf.name); + "`%s'", __func__, srv_conf->name); return (-1); } } @@ -565,7 +560,7 @@ config_gettls(struct httpd *env, struct imsg *imsg) #ifdef DEBUG struct privsep *ps = env->sc_ps; #endif - struct server *srv = NULL; + struct server_config *srv_conf = NULL; struct tls_config tls_conf; uint8_t *p = imsg->data; size_t s; @@ -580,27 +575,25 @@ config_gettls(struct httpd *env, struct imsg *imsg) goto fail; } - /* Find server with matching listening socket. */ - if ((srv = server_byaddr((struct sockaddr *) - &tls_conf.ss, tls_conf.port)) == NULL) { + if ((srv_conf = serverconfig_byid(tls_conf.id)) == NULL) { log_debug("%s: server not found", __func__); goto fail; } - DPRINTF("%s: %s %d TLS configuration \"%s[%u]\"", __func__, + DPRINTF("%s: %s %d tls configuration \"%s[%u]\"", __func__, ps->ps_title[privsep_process], ps->ps_instance, - srv->srv_conf.name, srv->srv_conf.id); + srv_conf->name, srv_conf->id); if (tls_conf.tls_cert_len != 0) { - srv->srv_conf.tls_cert_len = tls_conf.tls_cert_len; - if ((srv->srv_conf.tls_cert = get_data(p + s, + srv_conf->tls_cert_len = tls_conf.tls_cert_len; + if ((srv_conf->tls_cert = get_data(p + s, tls_conf.tls_cert_len)) == NULL) goto fail; s += tls_conf.tls_cert_len; } if (tls_conf.tls_key_len != 0) { - srv->srv_conf.tls_key_len = tls_conf.tls_key_len; - if ((srv->srv_conf.tls_key = get_data(p + s, + srv_conf->tls_key_len = tls_conf.tls_key_len; + if ((srv_conf->tls_key = get_data(p + s, tls_conf.tls_key_len)) == NULL) goto fail; s += tls_conf.tls_key_len; @@ -628,8 +621,7 @@ config_setmedia(struct httpd *env, struct media_type *media) DPRINTF("%s: sending media \"%s\" to %s", __func__, media->media_name, ps->ps_title[id]); - proc_compose_imsg(ps, id, -1, IMSG_CFG_MEDIA, -1, - media, sizeof(*media)); + proc_compose(ps, id, IMSG_CFG_MEDIA, media, sizeof(*media)); } return (0); @@ -676,8 +668,7 @@ config_setauth(struct httpd *env, struct auth *auth) DPRINTF("%s: sending auth \"%s[%u]\" to %s", __func__, auth->auth_htpasswd, auth->auth_id, ps->ps_title[id]); - proc_compose_imsg(ps, id, -1, IMSG_CFG_AUTH, -1, - auth, sizeof(*auth)); + proc_compose(ps, id, IMSG_CFG_AUTH, auth, sizeof(*auth)); } return (0); diff --git a/httpd/control.c b/httpd/control.c index 5c71545..c29cd5b 100644 --- a/httpd/control.c +++ b/httpd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.7 2015/05/28 17:08:08 florian Exp $ */ +/* $OpenBSD: control.c,v 1.9 2015/12/05 13:15:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -50,7 +50,7 @@ control_init(struct privsep *ps, struct control_sock *cs) if (cs->cs_name == NULL) return (0); - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) { log_warn("%s: socket", __func__); return (-1); } @@ -93,7 +93,6 @@ control_init(struct privsep *ps, struct control_sock *cs) return (-1); } - socket_set_blockmode(fd, BM_NONBLOCK); cs->cs_fd = fd; cs->cs_env = env; @@ -143,8 +142,8 @@ control_accept(int listenfd, short event, void *arg) return; len = sizeof(sun); - if ((connfd = accept(listenfd, - (struct sockaddr *)&sun, &len)) == -1) { + if ((connfd = accept4(listenfd, + (struct sockaddr *)&sun, &len, SOCK_NONBLOCK)) == -1) { /* * Pause accept if we are out of file descriptors, or * libevent will haunt us here too. @@ -160,8 +159,6 @@ control_accept(int listenfd, short event, void *arg) return; } - socket_set_blockmode(connfd, BM_NONBLOCK); - if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { close(connfd); log_warn("%s: calloc", __func__); @@ -233,7 +230,8 @@ control_dispatch_imsg(int fd, short event, void *arg) } if (event & EV_READ) { - if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { + if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || + n == 0) { control_close(fd, cs); return; } @@ -314,20 +312,3 @@ control_imsg_forward(struct imsg *imsg) 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); } - -void -socket_set_blockmode(int fd, enum blockmodes bm) -{ - int flags; - - if ((flags = fcntl(fd, F_GETFL, 0)) == -1) - fatal("fcntl F_GETFL"); - - if (bm == BM_NONBLOCK) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - - if ((flags = fcntl(fd, F_SETFL, flags)) == -1) - fatal("fcntl F_SETFL"); -} diff --git a/httpd/http.h b/httpd/http.h index 9042342..410704f 100644 --- a/httpd/http.h +++ b/httpd/http.h @@ -1,4 +1,4 @@ -/* $OpenBSD: http.h,v 1.13 2015/06/11 18:49:09 reyk Exp $ */ +/* $OpenBSD: http.h,v 1.14 2016/08/01 21:15:30 benno Exp $ */ /* * Copyright (c) 2012 - 2015 Reyk Floeter @@ -241,6 +241,7 @@ struct http_descriptor { enum httpmethod http_method; int http_chunked; char *http_version; + unsigned int http_status; /* Rewritten path remains NULL if not used */ char *http_path_alias; diff --git a/httpd/httpd.8 b/httpd/httpd.8 index fcb3e42..7084120 100644 --- a/httpd/httpd.8 +++ b/httpd/httpd.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: httpd.8,v 1.51 2015/03/26 19:16:57 jmc Exp $ +.\" $OpenBSD: httpd.8,v 1.52 2016/06/10 18:32:40 jmc Exp $ .\" .\" Copyright (c) 2014 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: March 26 2015 $ +.Dd $Mdocdate: June 10 2016 $ .Dt HTTPD 8 .Os .Sh NAME @@ -65,7 +65,7 @@ Check that the configuration is valid, but don't start any servers. Verbose mode. Multiple .Fl v -options increases the verbosity. +options increase the verbosity. .El .Sh FILES .Bl -tag -width "/etc/ssl/private/server.key" -compact diff --git a/httpd/httpd.c b/httpd/httpd.c index f6decea..fae7c53 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.c,v 1.39 2015/08/20 13:00:23 reyk Exp $ */ +/* $OpenBSD: httpd.c,v 1.56 2016/06/10 12:09:48 florian Exp $ */ /* * Copyright (c) 2014 Reyk Floeter @@ -33,10 +33,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -189,7 +191,8 @@ main(int argc, char *argv[]) } } - log_init(debug ? debug : 1); /* log to stderr until daemonized */ + /* log to stderr until daemonized */ + log_init(debug ? debug : 1, LOG_DAEMON); argc -= optind; if (argc > 0) @@ -218,7 +221,7 @@ main(int argc, char *argv[]) /* Configure the control socket */ ps->ps_csock.cs_name = NULL; - log_init(debug); + log_init(debug, LOG_DAEMON); log_verbose(verbose); if (!debug && daemon(1, 0) == -1) @@ -244,8 +247,11 @@ main(int argc, char *argv[]) } proc_init(ps, procs, nitems(procs)); + log_procinit("parent"); - setproctitle("parent"); + if (pledge("stdio rpath wpath cpath inet dns proc ioctl sendfd", + NULL) == -1) + fatal("pledge"); event_init(); @@ -331,8 +337,7 @@ parent_configure(struct httpd *env) cf.cf_opts = env->sc_opts; cf.cf_flags = env->sc_flags; - proc_compose_imsg(env->sc_ps, id, -1, IMSG_CFG_DONE, -1, - &cf, sizeof(cf)); + proc_compose(env->sc_ps, id, IMSG_CFG_DONE, &cf, sizeof(cf)); } ret = 0; @@ -377,8 +382,7 @@ parent_reload(struct httpd *env, unsigned int reset, const char *filename) void parent_reopen(struct httpd *env) { - proc_compose_imsg(env->sc_ps, PROC_LOGGER, -1, IMSG_CTL_REOPEN, - -1, NULL, 0); + proc_compose(env->sc_ps, PROC_LOGGER, IMSG_CTL_REOPEN, NULL, 0); } void @@ -397,8 +401,7 @@ parent_configure_done(struct httpd *env) if (id == privsep_process) continue; - proc_compose_imsg(env->sc_ps, id, -1, IMSG_CTL_START, - -1, NULL, 0); + proc_compose(env->sc_ps, id, IMSG_CTL_START, NULL, 0); } } } @@ -454,8 +457,7 @@ parent_dispatch_logger(int fd, struct privsep_proc *p, struct imsg *imsg) if (IMSG_DATA_SIZE(imsg) > 0) str = get_string(imsg->data, IMSG_DATA_SIZE(imsg)); parent_reload(env, CONFIG_RELOAD, str); - if (str != NULL) - free(str); + free(str); break; case IMSG_CTL_SHUTDOWN: parent_shutdown(env); @@ -565,7 +567,7 @@ canonicalize_host(const char *host, char *name, size_t len) for (i = j = 0; i < plen; i++) { if (j >= (len - 1)) goto fail; - c = tolower(host[i]); + c = tolower((unsigned char)host[i]); if ((c == '.') && (j == 0 || name[j - 1] == '.')) continue; name[j++] = c; @@ -602,7 +604,8 @@ url_decode(char *url) switch (*p) { case '%': /* Encoding character is followed by two hex chars */ - if (!(isxdigit(p[1]) && isxdigit(p[2]))) + if (!(isxdigit((unsigned char)p[1]) && + isxdigit((unsigned char)p[2]))) return (NULL); hex[0] = p[1]; @@ -741,7 +744,7 @@ escape_html(const char* src) { char *dp, *dst; - /* We need 5 times the memory if every letter is "<" or ">". */ + /* We need 5 times the memory if every letter is "&" */ if ((dst = calloc(5, strlen(src) + 1)) == NULL) return NULL; @@ -827,17 +830,13 @@ char * get_string(uint8_t *ptr, size_t len) { size_t i; - char *str; for (i = 0; i < len; i++) - if (!(isprint(ptr[i]) || isspace(ptr[i]))) + if (!(isprint((unsigned char)ptr[i]) || + isspace((unsigned char)ptr[i]))) break; - if ((str = calloc(1, i + 1)) == NULL) - return (NULL); - memcpy(str, ptr, i); - - return (str); + return strndup(ptr, i); } void * @@ -845,7 +844,7 @@ get_data(uint8_t *ptr, size_t len) { uint8_t *data; - if ((data = calloc(1, len)) == NULL) + if ((data = malloc(len)) == NULL) return (NULL); memcpy(data, ptr, len); @@ -959,7 +958,7 @@ accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen, return (-1); } - if ((ret = accept(sockfd, addr, addrlen)) > -1) { + if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK)) > -1) { (*counter)++; DPRINTF("%s: inflight incremented, now %d",__func__, *counter); } @@ -1001,11 +1000,13 @@ kv_set(struct kv *kv, char *fmt, ...) va_list ap; char *value = NULL; struct kv *ckv; + int ret; va_start(ap, fmt); - if (vasprintf(&value, fmt, ap) == -1) - return (-1); + ret = vasprintf(&value, fmt, ap); va_end(ap); + if (ret == -1) + return (-1); /* Remove all children */ while ((ckv = TAILQ_FIRST(&kv->kv_children)) != NULL) { @@ -1015,8 +1016,7 @@ kv_set(struct kv *kv, char *fmt, ...) } /* Set the new value */ - if (kv->kv_value != NULL) - free(kv->kv_value); + free(kv->kv_value); kv->kv_value = value; return (0); @@ -1027,14 +1027,15 @@ kv_setkey(struct kv *kv, char *fmt, ...) { va_list ap; char *key = NULL; + int ret; va_start(ap, fmt); - if (vasprintf(&key, fmt, ap) == -1) - return (-1); + ret = vasprintf(&key, fmt, ap); va_end(ap); + if (ret == -1) + return (-1); - if (kv->kv_key != NULL) - free(kv->kv_key); + free(kv->kv_key); kv->kv_key = key; return (0); @@ -1089,13 +1090,9 @@ kv_purge(struct kvtree *keys) void kv_free(struct kv *kv) { - if (kv->kv_key != NULL) { - free(kv->kv_key); - } + free(kv->kv_key); kv->kv_key = NULL; - if (kv->kv_value != NULL) { - free(kv->kv_value); - } + free(kv->kv_value); kv->kv_value = NULL; memset(kv, 0, sizeof(*kv)); } @@ -1202,8 +1199,8 @@ void media_delete(struct mediatypes *types, struct media_type *media) { RB_REMOVE(mediatypes, types, media); - if (media->media_encoding != NULL) - free(media->media_encoding); + + free(media->media_encoding); free(media); } @@ -1302,3 +1299,78 @@ auth_free(struct serverauth *serverauth, struct auth *auth) { TAILQ_REMOVE(serverauth, auth, auth_entry); } + + +const char * +print_host(struct sockaddr_storage *ss, char *buf, size_t len) +{ + if (getnameinfo((struct sockaddr *)ss, ss->ss_len, + buf, len, NULL, 0, NI_NUMERICHOST) != 0) { + buf[0] = '\0'; + return (NULL); + } + return (buf); +} + +const char * +print_time(struct timeval *a, struct timeval *b, char *buf, size_t len) +{ + struct timeval tv; + unsigned long h, sec, min; + + timerclear(&tv); + timersub(a, b, &tv); + sec = tv.tv_sec % 60; + min = tv.tv_sec / 60 % 60; + h = tv.tv_sec / 60 / 60; + + snprintf(buf, len, "%.2lu:%.2lu:%.2lu", h, min, sec); + return (buf); +} + +const char * +printb_flags(const uint32_t v, const char *bits) +{ + static char buf[2][BUFSIZ]; + static int idx = 0; + int i, any = 0; + char c, *p, *r; + + p = r = buf[++idx % 2]; + memset(p, 0, BUFSIZ); + + if (bits) { + bits++; + while ((i = *bits++)) { + if (v & (1 << (i - 1))) { + if (any) { + *p++ = ','; + *p++ = ' '; + } + any = 1; + for (; (c = *bits) > 32; bits++) { + if (c == '_') + *p++ = ' '; + else + *p++ = + tolower((unsigned char)c); + } + } else + for (; *bits > 32; bits++) + ; + } + } + + return (r); +} + +void +getmonotime(struct timeval *tv) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + fatal("clock_gettime"); + + TIMESPEC_TO_TIMEVAL(tv, &ts); +} diff --git a/httpd/httpd.conf.5 b/httpd/httpd.conf.5 index 785f726..2bd3ec7 100644 --- a/httpd/httpd.conf.5 +++ b/httpd/httpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: httpd.conf.5,v 1.68 2015/07/19 05:17:27 reyk Exp $ +.\" $OpenBSD: httpd.conf.5,v 1.73 2016/05/09 19:36:54 tj 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 19 2015 $ +.Dd $Mdocdate: May 9 2016 $ .Dt HTTPD.CONF 5 .Os .Sh NAME @@ -274,6 +274,67 @@ root directory of .Xr httpd 8 and defaults to .Pa /run/slowcgi.sock . +.Pp +The FastCGI handler will be given the following variables: +.Pp +.Bl -tag -width GATEWAY_INTERFACE -offset indent -compact +.It Ic DOCUMENT_ROOT +The document root in which the script is located as configured by the +.Ic root +option for the server or location that matches the request. +.It Ic GATEWAY_INTERFACE +The revision of the CGI specification used. +.It Ic HTTP_* +Additional HTTP headers the connected client sent in the request, if +any. +.It Ic HTTPS +A variable that is set to +.Qq on +when the server has been configured to use TLS. +This variable is omitted otherwise. +.It Ic REQUEST_URI +The path and optional query string as requested by the connected client. +.It Ic DOCUMENT_URI +The canonicalized request path, possibly with a slash or +directory index file name appended. +This is the same as +.Ic PATH_INFO +appended to +.Ic SCRIPT_NAME . +.It Ic SCRIPT_NAME +The virtual URI path to the script. +.It Ic PATH_INFO +The optional path appended after the script name in the request path. +This variable is an empty string if no path is appended after the +script name. +.It Ic SCRIPT_FILENAME +The absolute, physical path to the script within the +.Xr chroot 2 +directory. +.It Ic QUERY_STRING +The optional query string of the request. +This variable is an empty +string if there is no query string in the request. +.It Ic REMOTE_ADDR +The IP address of the connected client. +.It Ic REMOTE_PORT +The TCP source port of the connected client. +.It Ic REMOTE_USER +The remote user when using HTTP authentication. +.It Ic REQUEST_METHOD +The HTTP method the connected client used when making the request. +.It Ic SERVER_ADDR +The configured IP address of the server. +.It Ic SERVER_NAME +The name of the server. +.It Ic SERVER_PORT +The configured TCP server port of the server. +.It Ic SERVER_PROTOCOL +The revision of the HTTP specification used. +.It Ic SERVER_SOFTWARE +The server software name of +.Xr httpd 8 . +.El .It Ic hsts Oo Ar option Oc Enable HTTP Strict Transport Security. Valid options are: @@ -299,11 +360,14 @@ The argument will be matched against the request path with shell globbing rules. A location section may include most of the server configuration rules except +.Ic alias , .Ic connection , +.Ic hsts , .Ic listen on , -.Ic location +.Ic location , +.Ic tcp and -.Ic tcp . +.Ic tls . .It Ic location match Ar path Brq ... Like the .Ic location @@ -530,7 +594,7 @@ server "default" { types { text/css css text/html html htm - text/txt txt + text/plain txt image/gif gif image/jpeg jpeg jpg image/png png @@ -584,7 +648,7 @@ directive: .Bd -literal -offset indent server "example.com" { listen on 10.0.0.1 port 80 - block return 301 "http://www.example.com/" + block return 301 "http://www.example.com$REQUEST_URI" } server "www.example.com" { diff --git a/httpd/httpd.h b/httpd/httpd.h index f1c6090..595cce9 100644 --- a/httpd/httpd.h +++ b/httpd/httpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.h,v 1.97 2015/08/20 13:00:23 reyk Exp $ */ +/* $OpenBSD: httpd.h,v 1.106 2016/08/15 16:12:34 jsing Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter @@ -52,7 +52,7 @@ #define HTTPD_LOGVIS VIS_NL|VIS_TAB|VIS_CSTYLE #define HTTPD_TLS_CERT "/etc/ssl/server.crt" #define HTTPD_TLS_KEY "/etc/ssl/private/server.key" -#define HTTPD_TLS_CIPHERS "HIGH:!aNULL" +#define HTTPD_TLS_CIPHERS "compat" #define HTTPD_TLS_DHE_PARAMS "none" #define HTTPD_TLS_ECDHE_CURVE "auto" #define FD_RESERVE 5 @@ -164,11 +164,6 @@ struct { int fd; } control_state; -enum blockmodes { - BM_NORMAL, - BM_NONBLOCK -}; - struct imsgev { struct imsgbuf ibuf; void (*handler)(int, short, void *); @@ -454,7 +449,7 @@ struct server_config { char auth_realm[NAME_MAX]; uint32_t auth_id; - struct auth *auth; + const struct auth *auth; int return_code; char *return_uri; @@ -470,9 +465,6 @@ TAILQ_HEAD(serverhosts, server_config); struct tls_config { uint32_t id; - in_port_t port; - struct sockaddr_storage ss; - size_t tls_cert_len; size_t tls_key_len; }; @@ -524,7 +516,6 @@ void control_dispatch_imsg(int, short, void *); void control_imsg_forward(struct imsg *); struct ctl_conn * control_connbyfd(int); -void socket_set_blockmode(int, enum blockmodes); extern struct ctl_connlist ctl_conns; @@ -535,6 +526,7 @@ int cmdline_symset(char *); /* server.c */ pid_t server(struct privsep *, struct privsep_proc *); +int server_tls_cmp(struct server *, struct server *); int server_tls_load_keypair(struct server *); int server_privinit(struct server *); void server_purge(struct server *); @@ -569,6 +561,8 @@ struct server_config * serverconfig_byid(uint32_t); int server_foreach(int (*)(struct server *, struct server_config *, void *), void *); +struct server * + server_match(struct server *, int); SPLAY_PROTOTYPE(client_tree, client, clt_nodes, server_client_cmp); @@ -664,22 +658,31 @@ RB_PROTOTYPE(mediatypes, media_type, media_entry, media_cmp); struct auth *auth_add(struct serverauth *, struct auth *); struct auth *auth_byid(struct serverauth *, uint32_t); void auth_free(struct serverauth *, struct auth *); +const char *print_host(struct sockaddr_storage *, char *, size_t); +const char *print_time(struct timeval *, struct timeval *, char *, size_t); +const char *printb_flags(const uint32_t, const char *); +void getmonotime(struct timeval *); /* log.c */ -void log_init(int); +void log_init(int, int); +void log_procinit(const char *); void log_verbose(int); -void log_warn(const char *, ...) __attribute__((__format__ (printf, 1, 2))); -void log_warnx(const char *, ...) __attribute__((__format__ (printf, 1, 2))); -void log_info(const char *, ...) __attribute__((__format__ (printf, 1, 2))); -void log_debug(const char *, ...) __attribute__((__format__ (printf, 1, 2))); -void logit(int, const char *, ...) __attribute__((__format__ (printf, 2, 3))); -void vlog(int, const char *, va_list) __attribute__((__format__ (printf, 2, 0))); -__dead void fatal(const char *); -__dead void fatalx(const char *); -const char *print_host(struct sockaddr_storage *, char *, size_t); -const char *print_time(struct timeval *, struct timeval *, char *, size_t); -const char *printb_flags(const uint32_t, const char *); -void getmonotime(struct timeval *); +void log_warn(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_warnx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_info(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_debug(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void logit(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +void vlog(int, const char *, va_list) + __attribute__((__format__ (printf, 2, 0))); +__dead void fatal(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +__dead void fatalx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); /* proc.c */ void proc_init(struct privsep *, struct privsep_proc *, unsigned int); @@ -691,9 +694,13 @@ pid_t proc_run(struct privsep *, struct privsep_proc *, void (*)(struct privsep *, struct privsep_proc *, void *), void *); void proc_range(struct privsep *, enum privsep_procid, int *, int *); int proc_compose_imsg(struct privsep *, enum privsep_procid, int, - uint16_t, int, void *, uint16_t); + u_int16_t, u_int32_t, int, void *, u_int16_t); +int proc_compose(struct privsep *, enum privsep_procid, + uint16_t, void *, uint16_t); int proc_composev_imsg(struct privsep *, enum privsep_procid, int, - uint16_t, int, const struct iovec *, int); + u_int16_t, u_int32_t, int, const struct iovec *, int); +int proc_composev(struct privsep *, enum privsep_procid, + uint16_t, const struct iovec *, int); int proc_forward_imsg(struct privsep *, struct imsg *, enum privsep_procid, int); struct imsgbuf * diff --git a/httpd/log.c b/httpd/log.c index 16e57d0..1f6ff49 100644 --- a/httpd/log.c +++ b/httpd/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.6 2015/08/20 13:00:23 reyk Exp $ */ +/* $OpenBSD: log.c,v 1.10 2015/12/07 12:13:51 reyk Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -11,49 +11,65 @@ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include -#include - -#include -#include #include #include +#include #include #include +#include #include -#include -#include - -#include "httpd.h" -int debug; -int verbose; - -void vlog(int, const char *, va_list) - __attribute__((__format__ (printf, 2, 0))); -void logit(int, const char *, ...) +int debug; +int verbose; +const char *log_procname; + +void log_init(int, int); +void log_procinit(const char *); +void log_verbose(int); +void log_warn(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_warnx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_info(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_debug(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void logit(int, const char *, ...) __attribute__((__format__ (printf, 2, 3))); +void vlog(int, const char *, va_list) + __attribute__((__format__ (printf, 2, 0))); +__dead void fatal(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +__dead void fatalx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); void -log_init(int n_debug) +log_init(int n_debug, int facility) { extern char *__progname; debug = n_debug; verbose = n_debug; + log_procinit(__progname); if (!debug) - openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); + openlog(__progname, LOG_PID | LOG_NDELAY, facility); tzset(); } +void +log_procinit(const char *procname) +{ + if (procname != NULL) + log_procname = procname; +} + void log_verbose(int v) { @@ -146,98 +162,45 @@ log_debug(const char *emsg, ...) } } -void -fatal(const char *emsg) +static void +vfatal(const char *emsg, va_list ap) { - if (emsg == NULL) - logit(LOG_CRIT, "fatal: %s", strerror(errno)); + static char s[BUFSIZ]; + const char *sep; + + if (emsg != NULL) { + (void)vsnprintf(s, sizeof(s), emsg, ap); + sep = ": "; + } else { + s[0] = '\0'; + sep = ""; + } + if (errno) + logit(LOG_CRIT, "%s: %s%s%s", + log_procname, s, sep, strerror(errno)); else - if (errno) - logit(LOG_CRIT, "fatal: %s: %s", - emsg, strerror(errno)); - else - logit(LOG_CRIT, "fatal: %s", emsg); - - exit(1); + logit(LOG_CRIT, "%s%s%s", log_procname, sep, s); } void -fatalx(const char *emsg) -{ - errno = 0; - fatal(emsg); -} - -const char * -print_host(struct sockaddr_storage *ss, char *buf, size_t len) +fatal(const char *emsg, ...) { - if (getnameinfo((struct sockaddr *)ss, ss->ss_len, - buf, len, NULL, 0, NI_NUMERICHOST) != 0) { - buf[0] = '\0'; - return (NULL); - } - return (buf); -} - -const char * -print_time(struct timeval *a, struct timeval *b, char *buf, size_t len) -{ - struct timeval tv; - unsigned long h, sec, min; - - timerclear(&tv); - timersub(a, b, &tv); - sec = tv.tv_sec % 60; - min = tv.tv_sec / 60 % 60; - h = tv.tv_sec / 60 / 60; - - snprintf(buf, len, "%.2lu:%.2lu:%.2lu", h, min, sec); - return (buf); -} - -const char * -printb_flags(const uint32_t v, const char *bits) -{ - static char buf[2][BUFSIZ]; - static int idx = 0; - int i, any = 0; - char c, *p, *r; - - p = r = buf[++idx % 2]; - memset(p, 0, BUFSIZ); - - if (bits) { - bits++; - while ((i = *bits++)) { - if (v & (1 << (i - 1))) { - if (any) { - *p++ = ','; - *p++ = ' '; - } - any = 1; - for (; (c = *bits) > 32; bits++) { - if (c == '_') - *p++ = ' '; - else - *p++ = - tolower((unsigned char)c); - } - } else - for (; *bits > 32; bits++) - ; - } - } + va_list ap; - return (r); + va_start(ap, emsg); + vfatal(emsg, ap); + va_end(ap); + exit(1); } void -getmonotime(struct timeval *tv) +fatalx(const char *emsg, ...) { - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts)) - fatal("clock_gettime"); + va_list ap; - TIMESPEC_TO_TIMEVAL(tv, &ts); + errno = 0; + va_start(ap, emsg); + vfatal(emsg, ap); + va_end(ap); + exit(1); } diff --git a/httpd/logger.c b/httpd/logger.c index 4d3b741..a212fb1 100644 --- a/httpd/logger.c +++ b/httpd/logger.c @@ -1,4 +1,4 @@ -/* $OpenBSD: logger.c,v 1.13 2015/08/20 13:00:23 reyk Exp $ */ +/* $OpenBSD: logger.c,v 1.15 2015/12/02 15:13:00 reyk Exp $ */ /* * Copyright (c) 2014 Reyk Floeter @@ -70,6 +70,9 @@ logger_shutdown(void) void logger_init(struct privsep *ps, struct privsep_proc *p, void *arg) { + if (pledge("stdio recvfd", NULL) == -1) + fatal("pledge"); + if (config_init(ps->ps_env) == -1) fatal("failed to initialize configuration"); @@ -118,7 +121,7 @@ logger_open_file(const char *name) iov[1].iov_base = log->log_name; iov[1].iov_len = strlen(log->log_name) + 1; - if (proc_composev_imsg(env->sc_ps, PROC_PARENT, -1, IMSG_LOG_OPEN, -1, + if (proc_composev(env->sc_ps, PROC_PARENT, IMSG_LOG_OPEN, iov, 2) != 0) { log_warn("%s: failed to compose IMSG_LOG_OPEN imsg", __func__); goto err; @@ -188,7 +191,7 @@ logger_open_priv(struct imsg *imsg) return (-1); } - proc_compose_imsg(env->sc_ps, PROC_LOGGER, -1, IMSG_LOG_OPEN, fd, + proc_compose_imsg(env->sc_ps, PROC_LOGGER, -1, IMSG_LOG_OPEN, -1, fd, &id, sizeof(id)); DPRINTF("%s: opened log file %s, fd %d", __func__, path, fd); diff --git a/httpd/parse.y b/httpd/parse.y index 8622d84..6900bc6 100644 --- a/httpd/parse.y +++ b/httpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.76 2015/08/20 22:39:29 deraadt Exp $ */ +/* $OpenBSD: parse.y,v 1.80 2016/08/15 16:12:34 jsing Exp $ */ /* * Copyright (c) 2007 - 2015 Reyk Floeter @@ -171,6 +171,14 @@ include : INCLUDE STRING { ; varset : STRING '=' STRING { + char *s = $1; + while (*s++) { + if (isspace((unsigned char)*s)) { + yyerror("macro name cannot contain " + "whitespace"); + YYERROR; + } + } if (symset($1, $3, 0) == -1) fatal("cannot store variable"); free($1); @@ -275,24 +283,13 @@ server : SERVER optmatch STRING { TAILQ_INSERT_TAIL(&srv->srv_hosts, srv_conf, entry); } '{' optnl serveropts_l '}' { - struct server *s = NULL, *sn; + struct server *s, *sn; struct server_config *a, *b; srv_conf = &srv->srv_conf; - TAILQ_FOREACH(s, conf->sc_servers, srv_entry) { - if ((s->srv_conf.flags & - SRVFLAG_LOCATION) == 0 && - strcmp(s->srv_conf.name, - srv->srv_conf.name) == 0 && - s->srv_conf.port == srv->srv_conf.port && - sockaddr_cmp( - (struct sockaddr *)&s->srv_conf.ss, - (struct sockaddr *)&srv->srv_conf.ss, - s->srv_conf.prefixlen) == 0) - break; - } - if (s != NULL) { + /* Check if the new server already exists. */ + if (server_match(srv, 1) != NULL) { yyerror("server \"%s\" defined twice", srv->srv_conf.name); serverconfig_free(srv_conf); @@ -307,16 +304,39 @@ server : SERVER optmatch STRING { YYERROR; } + if ((s = server_match(srv, 0)) != NULL) { + if ((s->srv_conf.flags & SRVFLAG_TLS) != + (srv->srv_conf.flags & SRVFLAG_TLS)) { + yyerror("server \"%s\": tls and " + "non-tls on same address/port", + srv->srv_conf.name); + serverconfig_free(srv_conf); + free(srv); + YYERROR; + } + if (server_tls_cmp(s, srv) != 0) { + yyerror("server \"%s\": tls " + "configuration mismatch on same " + "address/port", + srv->srv_conf.name); + serverconfig_free(srv_conf); + free(srv); + YYERROR; + } + } + if ((srv->srv_conf.flags & SRVFLAG_TLS) && srv->srv_conf.tls_protocols == 0) { - yyerror("no TLS protocols"); + yyerror("server \"%s\": no tls protocols", + srv->srv_conf.name); + serverconfig_free(srv_conf); free(srv); YYERROR; } if (server_tls_load_keypair(srv) == -1) { - yyerror("failed to load public/private keys " - "for server %s", srv->srv_conf.name); + yyerror("server \"%s\": failed to load " + "public/private keys", srv->srv_conf.name); serverconfig_free(srv_conf); free(srv); YYERROR; @@ -390,7 +410,7 @@ serveroptsl : LISTEN ON STRING opttls port { sizeof(*alias))) == NULL) fatal("out of memory"); - /* Add as an alias */ + /* Add as an IP-based alias. */ s_conf = alias; } else s_conf = &srv->srv_conf; @@ -408,9 +428,8 @@ serveroptsl : LISTEN ON STRING opttls port { s_conf->prefixlen = h->prefixlen; host_free(&al); - if ($4) { + if ($4) s_conf->flags |= SRVFLAG_TLS; - } if (alias != NULL) { /* IP-based; use name match flags from parent */ @@ -460,10 +479,22 @@ serveroptsl : LISTEN ON STRING opttls port { } } | tls { + struct server_config *sc; + int tls_flag = 0; + if (parentsrv != NULL) { yyerror("tls configuration inside location"); YYERROR; } + + /* Ensure that at least one server has TLS enabled. */ + TAILQ_FOREACH(sc, &srv->srv_hosts, entry) { + tls_flag |= (sc->flags & SRVFLAG_TLS); + } + if (tls_flag == 0) { + yyerror("tls options without tls listener"); + YYERROR; + } } | root | directory @@ -708,7 +739,7 @@ tlsopts : CERTIFICATE STRING { | PROTOCOLS STRING { if (tls_config_parse_protocols( &srv_conf->tls_protocols, $2) != 0) { - yyerror("invalid TLS protocols"); + yyerror("invalid tls protocols"); free($2); YYERROR; } @@ -1723,7 +1754,7 @@ host_v4(const char *s) return (NULL); if ((h = calloc(1, sizeof(*h))) == NULL) - fatal(NULL); + fatal(__func__); sain = (struct sockaddr_in *)&h->ss; sain->sin_len = sizeof(struct sockaddr_in); sain->sin_family = AF_INET; @@ -1748,7 +1779,7 @@ host_v6(const char *s) hints.ai_flags = AI_NUMERICHOST; if (getaddrinfo(s, "0", &hints, &res) == 0) { if ((h = calloc(1, sizeof(*h))) == NULL) - fatal(NULL); + fatal(__func__); sa_in6 = (struct sockaddr_in6 *)&h->ss; sa_in6->sin6_len = sizeof(struct sockaddr_in6); sa_in6->sin6_family = AF_INET6; @@ -1799,7 +1830,7 @@ host_dns(const char *s, struct addresslist *al, int max, res->ai_family != AF_INET6) continue; if ((h = calloc(1, sizeof(*h))) == NULL) - fatal(NULL); + fatal(__func__); if (port != NULL) memcpy(&h->port, port, sizeof(h->port)); @@ -2020,19 +2051,7 @@ server_inherit(struct server *src, struct server_config *alias, } /* Check if the new server already exists */ - TAILQ_FOREACH(s, conf->sc_servers, srv_entry) { - if ((s->srv_conf.flags & - SRVFLAG_LOCATION) == 0 && - strcmp(s->srv_conf.name, - dst->srv_conf.name) == 0 && - s->srv_conf.port == dst->srv_conf.port && - sockaddr_cmp( - (struct sockaddr *)&s->srv_conf.ss, - (struct sockaddr *)&dst->srv_conf.ss, - s->srv_conf.prefixlen) == 0) - break; - } - if (s != NULL) { + if (server_match(dst, 1) != NULL) { yyerror("server \"%s\" defined twice", dst->srv_conf.name); serverconfig_free(&dst->srv_conf); diff --git a/httpd/patterns.c b/httpd/patterns.c index 42e4b25..c691078 100644 --- a/httpd/patterns.c +++ b/httpd/patterns.c @@ -1,4 +1,4 @@ -/* $OpenBSD: patterns.c,v 1.4 2015/08/18 08:26:39 reyk Exp $ */ +/* $OpenBSD: patterns.c,v 1.5 2016/02/14 18:20:59 semarie Exp $ */ /* * Copyright (c) 2015 Reyk Floeter @@ -26,7 +26,7 @@ /* * Derived from Lua 5.3.1: - * $Id: patterns.c,v 1.4 2015/08/18 08:26:39 reyk Exp $ + * $Id: patterns.c,v 1.5 2016/02/14 18:20:59 semarie Exp $ * Standard library for string operations and pattern-matching */ @@ -708,5 +708,6 @@ str_match_free(struct str_match *m) for (i = 0; i < m->sm_nmatch; i++) free(m->sm_match[i]); free(m->sm_match); + m->sm_match = NULL; m->sm_nmatch = 0; } diff --git a/httpd/patterns.h b/httpd/patterns.h index 74790b5..6dccd7b 100644 --- a/httpd/patterns.h +++ b/httpd/patterns.h @@ -1,4 +1,4 @@ -/* $OpenBSD: patterns.h,v 1.2 2015/06/26 17:26:29 semarie Exp $ */ +/* $OpenBSD: patterns.h,v 1.3 2015/12/12 19:59:43 mmcc Exp $ */ /* * Copyright (c) 2015 Reyk Floeter @@ -20,7 +20,6 @@ #define PATTERNS_H #include -#include #define MAXCAPTURES 32 /* Max no. of allowed captures in pattern */ #define MAXCCALLS 200 /* Max recusion depth in pattern matching */ diff --git a/httpd/proc.c b/httpd/proc.c index 9ba7bbe..7a6124a 100644 --- a/httpd/proc.c +++ b/httpd/proc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.c,v 1.9 2015/08/20 13:00:23 reyk Exp $ */ +/* $OpenBSD: proc.c,v 1.15 2015/12/07 16:05:56 reyk Exp $ */ /* * Copyright (c) 2010 - 2014 Reyk Floeter @@ -41,6 +41,7 @@ int proc_ispeer(struct privsep_proc *, unsigned int, enum privsep_procid); void proc_shutdown(struct privsep_proc *); void proc_sig_handler(int, short, void *); void proc_range(struct privsep *, enum privsep_procid, int *, int *); +int proc_dispatch_null(int, struct privsep_proc *, struct imsg *); int proc_ispeer(struct privsep_proc *procs, unsigned int nproc, @@ -160,6 +161,8 @@ proc_open(struct privsep *ps, struct privsep_proc *p, for (proc = 0; proc < nproc; proc++) { procs[proc].p_ps = ps; procs[proc].p_env = ps->ps_env; + if (procs[proc].p_cb == NULL) + procs[proc].p_cb = proc_dispatch_null; for (i = 0; i < ps->ps_instances[src]; i++) { for (j = 0; j < ps->ps_instances[procs[proc].p_id]; @@ -171,13 +174,11 @@ proc_open(struct privsep *ps, struct privsep_proc *p, if (pa->pp_pipes[procs[proc].p_id][j] != -1) continue; - if (socketpair(AF_UNIX, SOCK_STREAM, + if (socketpair(AF_UNIX, + SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC, fds) == -1) fatal("socketpair"); - socket_set_blockmode(fds[0], BM_NONBLOCK); - socket_set_blockmode(fds[1], BM_NONBLOCK); - pa->pp_pipes[procs[proc].p_id][j] = fds[0]; pb->pp_pipes[src][i] = fds[1]; } @@ -328,7 +329,7 @@ proc_sig_handler(int sig, short event, void *arg) pid_t proc_run(struct privsep *ps, struct privsep_proc *p, struct privsep_proc *procs, unsigned int nproc, - void (*init)(struct privsep *, struct privsep_proc *, void *), void *arg) + void (*run)(struct privsep *, struct privsep_proc *, void *), void *arg) { pid_t pid; struct passwd *pw; @@ -346,6 +347,8 @@ proc_run(struct privsep *ps, struct privsep_proc *p, case -1: fatal("proc_run: cannot fork"); case 0: + log_procinit(p->p_title); + /* Set the process group of the current process */ setpgid(0, 0); break; @@ -357,10 +360,10 @@ proc_run(struct privsep *ps, struct privsep_proc *p, if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { if (control_init(ps, &ps->ps_csock) == -1) - fatalx(p->p_title); + fatalx(__func__); TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) if (control_init(ps, rcs) == -1) - fatalx(p->p_title); + fatalx(__func__); } /* Change root directory */ @@ -417,14 +420,14 @@ proc_run(struct privsep *ps, struct privsep_proc *p, if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { TAILQ_INIT(&ctl_conns); if (control_listen(&ps->ps_csock) == -1) - fatalx(p->p_title); + fatalx(__func__); TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) if (control_listen(rcs) == -1) - fatalx(p->p_title); + fatalx(__func__); } - if (init != NULL) - init(ps, p, arg); + if (run != NULL) + run(ps, p, arg); event_dispatch(); @@ -449,8 +452,8 @@ proc_dispatch(int fd, short event, void *arg) ibuf = &iev->ibuf; if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1) - fatal(title); + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal(__func__); if (n == 0) { /* this pipe is dead, so remove the event handler */ event_del(&iev->ev); @@ -461,19 +464,19 @@ proc_dispatch(int fd, short event, void *arg) if (event & EV_WRITE) { if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) - fatal(title); + fatal(__func__); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal(title); + fatal(__func__); if (n == 0) break; #if DEBUG > 1 - log_debug("%s: %s %d got imsg %d from %s %d", + log_debug("%s: %s %d got imsg %d peerid %d from %s %d", __func__, title, ps->ps_instance + 1, - imsg.hdr.type, p->p_title, p->p_instance); + imsg.hdr.type, imsg.hdr.peerid, p->p_title, p->p_instance); #endif /* @@ -495,16 +498,24 @@ proc_dispatch(int fd, short event, void *arg) log_verbose(verbose); break; default: - log_warnx("%s: %s %d got invalid imsg %d from %s %d", + log_warnx("%s: %s %d got invalid imsg %d peerid %d " + "from %s %d", __func__, title, ps->ps_instance + 1, - imsg.hdr.type, p->p_title, p->p_instance); - fatalx(title); + imsg.hdr.type, imsg.hdr.peerid, + p->p_title, p->p_instance); + fatalx(__func__); } imsg_free(&imsg); } imsg_event_add(iev); } +int +proc_dispatch_null(int fd, struct privsep_proc *p, struct imsg *imsg) +{ + return (-1); +} + /* * imsg helper functions */ @@ -567,41 +578,55 @@ proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m) int proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n, - uint16_t type, int fd, void *data, uint16_t datalen) + uint16_t type, uint32_t peerid, int fd, void *data, uint16_t datalen) { int m; proc_range(ps, id, &n, &m); for (; n < m; n++) { if (imsg_compose_event(&ps->ps_ievs[id][n], - type, -1, 0, fd, data, datalen) == -1) + type, peerid, 0, fd, data, datalen) == -1) return (-1); } return (0); } +int +proc_compose(struct privsep *ps, enum privsep_procid id, + uint16_t type, void *data, uint16_t datalen) +{ + return (proc_compose_imsg(ps, id, -1, type, -1, -1, data, datalen)); +} + int proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n, - uint16_t type, int fd, const struct iovec *iov, int iovcnt) + uint16_t type, uint32_t peerid, int fd, const struct iovec *iov, int iovcnt) { int m; proc_range(ps, id, &n, &m); for (; n < m; n++) if (imsg_composev_event(&ps->ps_ievs[id][n], - type, -1, 0, fd, iov, iovcnt) == -1) + type, peerid, 0, fd, iov, iovcnt) == -1) return (-1); return (0); } +int +proc_composev(struct privsep *ps, enum privsep_procid id, + uint16_t type, const struct iovec *iov, int iovcnt) +{ + return (proc_composev_imsg(ps, id, -1, type, -1, -1, iov, iovcnt)); +} + int proc_forward_imsg(struct privsep *ps, struct imsg *imsg, enum privsep_procid id, int n) { return (proc_compose_imsg(ps, id, n, imsg->hdr.type, - imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); + imsg->hdr.peerid, imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); } struct imsgbuf * diff --git a/httpd/server.c b/httpd/server.c index 21593bf..849b92a 100644 --- a/httpd/server.c +++ b/httpd/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.75 2015/08/20 13:00:23 reyk Exp $ */ +/* $OpenBSD: server.c,v 1.88 2016/08/15 16:12:34 jsing Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter @@ -65,7 +65,7 @@ void server_tls_readcb(int, short, void *); void server_tls_writecb(int, short, void *); void server_accept(int, short, void *); -void server_accept_tls(int, short, void *); +void server_handshake_tls(int, short, void *); void server_input(struct client *); void server_inflight_dec(struct client *, const char *); @@ -132,6 +132,30 @@ server_privinit(struct server *srv) return (0); } +int +server_tls_cmp(struct server *s1, struct server *s2) +{ + struct server_config *sc1, *sc2; + + sc1 = &s1->srv_conf; + sc2 = &s2->srv_conf; + + if (sc1->tls_protocols != sc2->tls_protocols) + return (-1); + if (strcmp(sc1->tls_cert_file, sc2->tls_cert_file) != 0) + return (-1); + if (strcmp(sc1->tls_key_file, sc2->tls_key_file) != 0) + return (-1); + if (strcmp(sc1->tls_ciphers, sc2->tls_ciphers) != 0) + return (-1); + if (strcmp(sc1->tls_dhe_params, sc2->tls_dhe_params) != 0) + return (-1); + if (strcmp(sc1->tls_ecdhe_curve, sc2->tls_ecdhe_curve) != 0) + return (-1); + + return (0); +} + int server_tls_load_keypair(struct server *srv) { @@ -162,18 +186,18 @@ server_tls_init(struct server *srv) if ((srv->srv_conf.flags & SRVFLAG_TLS) == 0) return (0); - log_debug("%s: setting up TLS for %s", __func__, srv->srv_conf.name); + log_debug("%s: setting up tls for %s", __func__, srv->srv_conf.name); if (tls_init() != 0) { - log_warn("%s: failed to initialise tls", __func__); + log_warnx("%s: failed to initialise tls", __func__); return (-1); } if ((srv->srv_tls_config = tls_config_new()) == NULL) { - log_warn("%s: failed to get tls config", __func__); + log_warnx("%s: failed to get tls config", __func__); return (-1); } if ((srv->srv_tls_ctx = tls_server()) == NULL) { - log_warn("%s: failed to get tls server", __func__); + log_warnx("%s: failed to get tls server", __func__); return (-1); } @@ -182,33 +206,33 @@ server_tls_init(struct server *srv) if (tls_config_set_ciphers(srv->srv_tls_config, srv->srv_conf.tls_ciphers) != 0) { - log_warn("%s: failed to set tls ciphers", __func__); + log_warnx("%s: failed to set tls ciphers: %s", + __func__, tls_config_error(srv->srv_tls_config)); return (-1); } if (tls_config_set_dheparams(srv->srv_tls_config, srv->srv_conf.tls_dhe_params) != 0) { - log_warn("%s: failed to set tls dhe params", __func__); + log_warnx("%s: failed to set tls dhe params: %s", + __func__, tls_config_error(srv->srv_tls_config)); return (-1); } if (tls_config_set_ecdhecurve(srv->srv_tls_config, srv->srv_conf.tls_ecdhe_curve) != 0) { - log_warn("%s: failed to set tls ecdhe curve", __func__); + log_warnx("%s: failed to set tls ecdhe curve: %s", + __func__, tls_config_error(srv->srv_tls_config)); return (-1); } - if (tls_config_set_cert_mem(srv->srv_tls_config, - srv->srv_conf.tls_cert, srv->srv_conf.tls_cert_len) != 0) { - log_warn("%s: failed to set tls cert", __func__); - return (-1); - } - if (tls_config_set_key_mem(srv->srv_tls_config, + if (tls_config_set_keypair_mem(srv->srv_tls_config, + srv->srv_conf.tls_cert, srv->srv_conf.tls_cert_len, srv->srv_conf.tls_key, srv->srv_conf.tls_key_len) != 0) { - log_warn("%s: failed to set tls key", __func__); + log_warnx("%s: failed to set tls certificate/key: %s", + __func__, tls_config_error(srv->srv_tls_config)); return (-1); } if (tls_configure(srv->srv_tls_ctx, srv->srv_tls_config) != 0) { - log_warn("%s: failed to configure TLS - %s", __func__, + log_warnx("%s: failed to configure tls - %s", __func__, tls_error(srv->srv_tls_ctx)); return (-1); } @@ -244,6 +268,9 @@ server_init(struct privsep *ps, struct privsep_proc *p, void *arg) /* Unlimited file descriptors (use system limits) */ socket_rlimit(-1); + if (pledge("stdio rpath inet unix recvfd", NULL) == -1) + fatal("pledge"); + #if 0 /* Schedule statistics timer */ evtimer_set(&env->sc_statev, server_statistics, NULL); @@ -313,7 +340,6 @@ server_purge(struct server *srv) void serverconfig_free(struct server_config *srv_conf) { - free(srv_conf->auth); free(srv_conf->return_uri); free(srv_conf->tls_cert_file); free(srv_conf->tls_key_file); @@ -392,6 +418,33 @@ server_foreach(int (*srv_cb)(struct server *, return (0); } +struct server * +server_match(struct server *s2, int match_name) +{ + struct server *s1; + + /* Attempt to find matching server. */ + TAILQ_FOREACH(s1, env->sc_servers, srv_entry) { + if ((s1->srv_conf.flags & SRVFLAG_LOCATION) != 0) + continue; + if (match_name) { + if (strcmp(s1->srv_conf.name, s2->srv_conf.name) != 0) + continue; + } + if (s1->srv_conf.port != s2->srv_conf.port) + continue; + if (sockaddr_cmp( + (struct sockaddr *)&s1->srv_conf.ss, + (struct sockaddr *)&s2->srv_conf.ss, + s1->srv_conf.prefixlen) != 0) + continue; + + return (s1); + } + + return (NULL); +} + int server_socket_af(struct sockaddr_storage *ss, in_port_t port) { @@ -439,7 +492,8 @@ server_socket(struct sockaddr_storage *ss, in_port_t port, if (server_socket_af(ss, port) == -1) goto bad; - s = fd == -1 ? socket(ss->ss_family, SOCK_STREAM, IPPROTO_TCP) : fd; + s = fd == -1 ? socket(ss->ss_family, SOCK_STREAM | SOCK_NONBLOCK, + IPPROTO_TCP) : fd; if (s == -1) goto bad; @@ -455,8 +509,6 @@ server_socket(struct sockaddr_storage *ss, in_port_t port, sizeof(int)) == -1) goto bad; } - if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) - goto bad; if (srv_conf->tcpflags & TCPFLAG_BUFSIZ) { val = srv_conf->tcpbufsiz; if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, @@ -564,7 +616,7 @@ server_tls_readcb(int fd, short event, void *arg) char rbuf[IBUF_READ_SIZE]; int what = EVBUFFER_READ; int howmuch = IBUF_READ_SIZE; - int ret; + ssize_t ret; size_t len; if (event == EV_TIMEOUT) { @@ -575,13 +627,14 @@ server_tls_readcb(int fd, short event, void *arg) if (bufev->wm_read.high != 0) howmuch = MINIMUM(sizeof(rbuf), bufev->wm_read.high); - ret = tls_read(clt->clt_tls_ctx, rbuf, howmuch, &len); - if (ret == TLS_READ_AGAIN || ret == TLS_WRITE_AGAIN) { + ret = tls_read(clt->clt_tls_ctx, rbuf, howmuch); + if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) { goto retry; - } else if (ret != 0) { + } else if (ret < 0) { what |= EVBUFFER_ERROR; goto err; } + len = ret; if (len == 0) { what |= EVBUFFER_EOF; @@ -622,7 +675,7 @@ server_tls_writecb(int fd, short event, void *arg) { struct bufferevent *bufev = arg; struct client *clt = bufev->cbarg; - int ret; + ssize_t ret; short what = EVBUFFER_WRITE; size_t len; @@ -634,13 +687,14 @@ server_tls_writecb(int fd, short event, void *arg) if (EVBUFFER_LENGTH(bufev->output)) { 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) { + EVBUFFER_LENGTH(bufev->output)); + if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) { goto retry; - } else if (ret != 0) { + } else if (ret < 0) { what |= EVBUFFER_ERROR; goto err; } + len = ret; evbuffer_drain(bufev->output, len); } @@ -742,8 +796,6 @@ server_write(struct bufferevent *bev, void *arg) void server_dump(struct client *clt, const void *buf, size_t len) { - size_t outlen; - if (!len) return; @@ -754,7 +806,7 @@ server_dump(struct client *clt, const void *buf, size_t len) * error message before gracefully closing the client. */ if (clt->clt_tls_ctx != NULL) - (void)tls_write(clt->clt_tls_ctx, buf, len, &outlen); + (void)tls_write(clt->clt_tls_ctx, buf, len); else (void)write(clt->clt_s, buf, len); } @@ -857,9 +909,6 @@ server_accept(int fd, short event, void *arg) if (server_clients >= SERVER_MAX_CLIENTS) goto err; - if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) - goto err; - if ((clt = calloc(1, sizeof(*clt))) == NULL) goto err; @@ -916,8 +965,13 @@ server_accept(int fd, short event, void *arg) } if (srv->srv_conf.flags & SRVFLAG_TLS) { + if (tls_accept_socket(srv->srv_tls_ctx, &clt->clt_tls_ctx, + clt->clt_s) != 0) { + server_close(clt, "failed to setup tls context"); + return; + } event_again(&clt->clt_ev, clt->clt_s, EV_TIMEOUT|EV_READ, - server_accept_tls, &clt->clt_tv_start, + server_handshake_tls, &clt->clt_tv_start, &srv->srv_conf.timeout, clt); return; } @@ -938,39 +992,36 @@ server_accept(int fd, short event, void *arg) } void -server_accept_tls(int fd, short event, void *arg) +server_handshake_tls(int fd, short event, void *arg) { struct client *clt = (struct client *)arg; struct server *srv = (struct server *)clt->clt_srv; int ret; if (event == EV_TIMEOUT) { - server_close(clt, "TLS accept timeout"); + server_close(clt, "tls handshake timeout"); return; } - if (srv->srv_tls_ctx == NULL) + if (srv->srv_tls_ctx == NULL || clt->clt_tls_ctx == NULL) fatalx("NULL tls context"); - ret = tls_accept_socket(srv->srv_tls_ctx, &clt->clt_tls_ctx, - clt->clt_s); - if (ret == TLS_READ_AGAIN) { + ret = tls_handshake(clt->clt_tls_ctx); + if (ret == 0) { + server_input(clt); + } else if (ret == TLS_WANT_POLLIN) { event_again(&clt->clt_ev, clt->clt_s, EV_TIMEOUT|EV_READ, - server_accept_tls, &clt->clt_tv_start, + server_handshake_tls, &clt->clt_tv_start, &srv->srv_conf.timeout, clt); - } else if (ret == TLS_WRITE_AGAIN) { + } else if (ret == TLS_WANT_POLLOUT) { event_again(&clt->clt_ev, clt->clt_s, EV_TIMEOUT|EV_WRITE, - server_accept_tls, &clt->clt_tv_start, + server_handshake_tls, &clt->clt_tv_start, &srv->srv_conf.timeout, clt); - } else if (ret != 0) { - log_warnx("%s: TLS accept failed - %s", __func__, - tls_error(srv->srv_tls_ctx)); - server_close(clt, "TLS accept failed"); - return; + } else { + log_warnx("%s: tls handshake failed - %s", __func__, + tls_error(clt->clt_tls_ctx)); + server_close(clt, "tls handshake failed"); } - - server_input(clt); - return; } void @@ -1020,8 +1071,7 @@ server_sendlog(struct server_config *srv_conf, int cmd, const char *emsg, ...) iov[1].iov_base = msg; iov[1].iov_len = strlen(msg) + 1; - if (proc_composev_imsg(env->sc_ps, PROC_LOGGER, -1, cmd, -1, iov, - 2) != 0) { + if (proc_composev(env->sc_ps, PROC_LOGGER, cmd, iov, 2) != 0) { log_warn("%s: failed to compose imsg", __func__); return; } diff --git a/httpd/server_fcgi.c b/httpd/server_fcgi.c index e7d9747..21ebeed 100644 --- a/httpd/server_fcgi.c +++ b/httpd/server_fcgi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_fcgi.c,v 1.64 2015/08/20 13:00:23 reyk Exp $ */ +/* $OpenBSD: server_fcgi.c,v 1.68 2016/04/24 20:09:45 chrisz Exp $ */ /* * Copyright (c) 2014 Florian Obser @@ -122,7 +122,8 @@ server_fcgi(struct httpd *env, struct client *clt) struct sockaddr_un sun; size_t len; - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + if ((fd = socket(AF_UNIX, + SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) goto fail; memset(&sun, 0, sizeof(sun)); @@ -130,7 +131,7 @@ server_fcgi(struct httpd *env, struct client *clt) len = strlcpy(sun.sun_path, srv_conf->socket, sizeof(sun.sun_path)); if (len >= sizeof(sun.sun_path)) { - errstr = "socket path to long"; + errstr = "socket path too long"; goto fail; } sun.sun_len = len; @@ -139,8 +140,6 @@ server_fcgi(struct httpd *env, struct client *clt) goto fail; } - socket_set_blockmode(fd, BM_NONBLOCK); - memset(hbuf, 0, sizeof(hbuf)); clt->clt_fcgi_state = FCGI_READ_HEADER; clt->clt_fcgi_toread = sizeof(struct fcgi_record_header); @@ -243,12 +242,16 @@ server_fcgi(struct httpd *env, struct client *clt) goto fail; } - if (desc->http_query) + if (desc->http_query) { if (fcgi_add_param(¶m, "QUERY_STRING", desc->http_query, clt) == -1) { errstr = "failed to encode param"; goto fail; } + } else if (fcgi_add_param(¶m, "QUERY_STRING", "", clt) == -1) { + errstr = "failed to encode param"; + goto fail; + } if (fcgi_add_param(¶m, "DOCUMENT_ROOT", srv_conf->root, clt) == -1) { @@ -399,6 +402,8 @@ server_fcgi(struct httpd *env, struct client *clt) free(script); if (errstr == NULL) errstr = strerror(errno); + if (fd != -1 && clt->clt_fd != fd) + close(fd); server_abort_http(clt, 500, errstr); return (-1); } diff --git a/httpd/server_file.c b/httpd/server_file.c index e060124..48ecbb5 100644 --- a/httpd/server_file.c +++ b/httpd/server_file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_file.c,v 1.60 2015/08/03 11:45:17 florian Exp $ */ +/* $OpenBSD: server_file.c,v 1.62 2016/05/17 03:12:39 deraadt Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter @@ -287,6 +287,8 @@ server_file_request(struct httpd *env, struct client *clt, char *path, bufferevent_free(clt->clt_bev); clt->clt_bev = NULL; abort: + if (fd != -1) + close(fd); if (errstr == NULL) errstr = strerror(errno); server_abort_http(clt, code, errstr); @@ -387,6 +389,9 @@ server_partial_file_request(struct httpd *env, struct client *clt, char *path, media = &multipart_media; } + close(fd); + fd = -1; + ret = server_response_http(clt, 206, media, content_length, MINIMUM(time(NULL), st->st_mtim.tv_sec)); switch (ret) { @@ -394,7 +399,6 @@ server_partial_file_request(struct httpd *env, struct client *clt, char *path, goto fail; case 0: /* Connection is already finished */ - close(fd); evbuffer_free(evb); evb = NULL; goto done; @@ -423,6 +427,8 @@ server_partial_file_request(struct httpd *env, struct client *clt, char *path, bufferevent_free(clt->clt_bev); clt->clt_bev = NULL; abort: + if (fd != -1) + close(fd); if (errstr == NULL) errstr = strerror(errno); server_abort_http(clt, code, errstr); @@ -484,6 +490,8 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st) "\n" "\n" "\n" + "\n" "Index of %s\n" "\n" "\n" diff --git a/httpd/server_http.c b/httpd/server_http.c index 8ed98b5..b69805a 100644 --- a/httpd/server_http.c +++ b/httpd/server_http.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_http.c,v 1.98 2015/08/21 07:30:50 reyk Exp $ */ +/* $OpenBSD: server_http.c,v 1.109 2016/07/27 11:02:41 reyk Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter @@ -102,26 +102,18 @@ server_httpdesc_free(struct http_descriptor *desc) { if (desc == NULL) return; - if (desc->http_path != NULL) { - free(desc->http_path); - desc->http_path = NULL; - } - if (desc->http_path_alias != NULL) { - free(desc->http_path_alias); - desc->http_path_alias = NULL; - } - if (desc->http_query != NULL) { - free(desc->http_query); - desc->http_query = NULL; - } - if (desc->http_version != NULL) { - free(desc->http_version); - desc->http_version = NULL; - } - if (desc->http_host != NULL) { - free(desc->http_host); - desc->http_host = NULL; - } + + free(desc->http_path); + desc->http_path = NULL; + free(desc->http_path_alias); + desc->http_path_alias = NULL; + free(desc->http_query); + desc->http_query = NULL; + free(desc->http_version); + desc->http_version = NULL; + free(desc->http_host); + desc->http_host = NULL; + kv_purge(&desc->http_headers); desc->http_lastheader = NULL; desc->http_method = 0; @@ -134,7 +126,7 @@ server_http_authenticate(struct server_config *srv_conf, struct client *clt) char decoded[1024]; FILE *fp = NULL; struct http_descriptor *desc = clt->clt_descreq; - struct auth *auth = srv_conf->auth; + const struct auth *auth = srv_conf->auth; struct kv *ba, key; size_t linesize = 0; ssize_t linelen; @@ -195,6 +187,7 @@ server_http_authenticate(struct server_config *srv_conf, struct client *clt) } } done: + free(line); if (fp != NULL) fclose(fp); @@ -303,8 +296,10 @@ server_read_http(struct bufferevent *bev, void *arg) goto fail; desc->http_version = strchr(desc->http_path, ' '); - if (desc->http_version == NULL) - goto fail; + if (desc->http_version == NULL) { + server_abort_http(clt, 400, "malformed"); + goto abort; + } *desc->http_version++ = '\0'; desc->http_query = strchr(desc->http_path, '?'); @@ -385,12 +380,12 @@ server_read_http(struct bufferevent *bev, void *arg) case HTTP_METHOD_DELETE: case HTTP_METHOD_GET: case HTTP_METHOD_HEAD: - case HTTP_METHOD_OPTIONS: /* WebDAV methods */ case HTTP_METHOD_COPY: case HTTP_METHOD_MOVE: clt->clt_toread = 0; break; + case HTTP_METHOD_OPTIONS: case HTTP_METHOD_POST: case HTTP_METHOD_PUT: case HTTP_METHOD_RESPONSE: @@ -597,8 +592,7 @@ server_read_httpchunks(struct bufferevent *bev, void *arg) case 0: /* Chunk is terminated by an empty newline */ line = evbuffer_readln(src, NULL, EVBUFFER_EOL_CRLF_STRICT); - if (line != NULL) - free(line); + free(line); if (server_bufferevent_print(clt, "\r\n") == -1) goto fail; clt->clt_toread = TOREAD_HTTP_CHUNK_LENGTH; @@ -824,6 +818,8 @@ server_abort_http(struct client *clt, unsigned int code, const char *msg) "\n" "\n" "\n" + "\n" "%03d %s\n" "\n" "\n" @@ -832,8 +828,10 @@ server_abort_http(struct client *clt, unsigned int code, const char *msg) "
\n
%s
\n" "\n" "\n", - code, httperr, style, code, httperr, HTTPD_SERVERNAME)) == -1) + code, httperr, style, code, httperr, HTTPD_SERVERNAME)) == -1) { + body = NULL; goto done; + } if (srv_conf->flags & SRVFLAG_SERVER_HSTS) { if (asprintf(&hstsheader, "Strict-Transport-Security: " @@ -841,8 +839,10 @@ server_abort_http(struct client *clt, unsigned int code, const char *msg) srv_conf->hsts_flags & HSTSFLAG_SUBDOMAINS ? "; includeSubDomains" : "", srv_conf->hsts_flags & HSTSFLAG_PRELOAD ? - "; preload" : "") == -1) + "; preload" : "") == -1) { + hstsheader = NULL; goto done; + } } /* Add basic HTTP headers */ @@ -918,7 +918,7 @@ server_expand_http(struct client *clt, const char *val, char *buf, /* Find previously matched substrings by index */ for (p = val; clt->clt_srv_match.sm_nmatch && (p = strstr(p, "%")) != NULL; p++) { - if (!isdigit(*(p + 1))) + if (!isdigit((unsigned char)*(p + 1))) continue; /* Copy number, leading '%' char and add trailing \0 */ -- cgit v1.2.3-54-g00ecf