aboutsummaryrefslogtreecommitdiff
path: root/httpd/httpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'httpd/httpd.c')
-rw-r--r--httpd/httpd.c150
1 files changed, 82 insertions, 68 deletions
diff --git a/httpd/httpd.c b/httpd/httpd.c
index fae7c53..6d1d1ff 100644
--- a/httpd/httpd.c
+++ b/httpd/httpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: httpd.c,v 1.56 2016/06/10 12:09:48 florian Exp $ */
+/* $OpenBSD: httpd.c,v 1.67 2017/05/28 10:37:26 benno Exp $ */
/*
* Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
@@ -16,12 +16,10 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <sys/param.h> /* nitems */
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/stat.h>
-#include <sys/wait.h>
#include <sys/resource.h>
#include <netinet/in.h>
@@ -59,6 +57,8 @@ int parent_dispatch_server(int, struct privsep_proc *,
struct imsg *);
int parent_dispatch_logger(int, struct privsep_proc *,
struct imsg *);
+void parent_tls_ticket_rekey_start(struct server *);
+void parent_tls_ticket_rekey(int, short, void *);
struct httpd *httpd_env;
@@ -71,56 +71,11 @@ void
parent_sig_handler(int sig, short event, void *arg)
{
struct privsep *ps = arg;
- int die = 0, status, fail, id;
- pid_t pid;
- char *cause;
switch (sig) {
case SIGTERM:
case SIGINT:
- die = 1;
- /* FALLTHROUGH */
- case SIGCHLD:
- do {
- int len;
-
- pid = waitpid(WAIT_ANY, &status, WNOHANG);
- if (pid <= 0)
- continue;
-
- fail = 0;
- if (WIFSIGNALED(status)) {
- fail = 1;
- len = asprintf(&cause, "terminated; signal %d",
- WTERMSIG(status));
- } else if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) != 0) {
- fail = 1;
- len = asprintf(&cause,
- "exited abnormally");
- } else
- len = asprintf(&cause, "exited okay");
- } else
- fatalx("unexpected cause of SIGCHLD");
-
- if (len == -1)
- fatal("asprintf");
-
- die = 1;
-
- for (id = 0; id < PROC_MAX; id++)
- if (pid == ps->ps_pid[id]) {
- if (fail)
- log_warnx("lost child: %s %s",
- ps->ps_title[id], cause);
- break;
- }
-
- free(cause);
- } while (pid > 0 || (pid == -1 && errno == EINTR));
-
- if (die)
- parent_shutdown(ps->ps_env);
+ parent_shutdown(ps->ps_env);
break;
case SIGHUP:
log_info("%s: reload requested with SIGHUP", __func__);
@@ -164,8 +119,12 @@ main(int argc, char *argv[])
struct httpd *env;
struct privsep *ps;
const char *conffile = CONF_FILE;
+ enum privsep_procid proc_id = PROC_PARENT;
+ int proc_instance = 0;
+ const char *errp, *title = NULL;
+ int argc0 = argc;
- while ((c = getopt(argc, argv, "dD:nf:v")) != -1) {
+ while ((c = getopt(argc, argv, "dD:nf:I:P:v")) != -1) {
switch (c) {
case 'd':
debug = 2;
@@ -186,6 +145,18 @@ main(int argc, char *argv[])
verbose++;
opts |= HTTPD_OPT_VERBOSE;
break;
+ case 'P':
+ title = optarg;
+ proc_id = proc_getid(procs, nitems(procs), title);
+ if (proc_id == PROC_MAX)
+ fatalx("invalid process name");
+ break;
+ case 'I':
+ proc_instance = strtonum(optarg, 0,
+ PROC_MAX_INSTANCES, &errp);
+ if (errp)
+ fatalx("invalid process instance");
+ break;
default:
usage();
}
@@ -222,18 +193,15 @@ main(int argc, char *argv[])
ps->ps_csock.cs_name = NULL;
log_init(debug, LOG_DAEMON);
- log_verbose(verbose);
-
- if (!debug && daemon(1, 0) == -1)
- err(1, "failed to daemonize");
+ log_setverbose(verbose);
if (env->sc_opts & HTTPD_OPT_NOACTION)
ps->ps_noaction = 1;
- else
- log_info("startup");
ps->ps_instances[PROC_SERVER] = env->sc_prefork_server;
- ps->ps_ninstances = env->sc_prefork_server;
+ ps->ps_instance = proc_instance;
+ if (title != NULL)
+ ps->ps_title[proc_id] = title;
if (env->sc_chroot == NULL)
env->sc_chroot = ps->ps_pw->pw_dir;
@@ -246,30 +214,34 @@ main(int argc, char *argv[])
errx(1, "malloc failed");
}
- proc_init(ps, procs, nitems(procs));
+ /* only the parent returns */
+ proc_init(ps, procs, nitems(procs), argc0, argv, proc_id);
+
log_procinit("parent");
+ if (!debug && daemon(1, 0) == -1)
+ err(1, "failed to daemonize");
- if (pledge("stdio rpath wpath cpath inet dns proc ioctl sendfd",
- NULL) == -1)
+ if (ps->ps_noaction == 0)
+ log_info("startup");
+
+ if (pledge("stdio rpath wpath cpath inet dns sendfd", NULL) == -1)
fatal("pledge");
event_init();
signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps);
signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps);
- signal_set(&ps->ps_evsigchld, SIGCHLD, parent_sig_handler, ps);
signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps);
signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps);
signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps);
signal_add(&ps->ps_evsigint, NULL);
signal_add(&ps->ps_evsigterm, NULL);
- signal_add(&ps->ps_evsigchld, NULL);
signal_add(&ps->ps_evsighup, NULL);
signal_add(&ps->ps_evsigpipe, NULL);
signal_add(&ps->ps_evsigusr1, NULL);
- proc_listen(ps, procs, nitems(procs));
+ proc_connect(ps);
if (load_config(env->sc_conffile, env) == -1) {
proc_kill(env->sc_ps);
@@ -282,6 +254,9 @@ main(int argc, char *argv[])
exit(0);
}
+ /* initialize the TLS session id to a random key for all procs */
+ arc4random_buf(env->sc_tls_sid, sizeof(env->sc_tls_sid));
+
if (parent_configure(env) == -1)
fatalx("configuration failed");
@@ -317,6 +292,10 @@ parent_configure(struct httpd *env)
TAILQ_FOREACH(srv, env->sc_servers, srv_entry) {
if (srv->srv_conf.flags & SRVFLAG_LOCATION)
continue;
+ /* start the rekey of the tls ticket keys */
+ if (srv->srv_conf.flags & SRVFLAG_TLS &&
+ srv->srv_conf.tls_ticket_lifetime)
+ parent_tls_ticket_rekey_start(srv);
if (config_setserver(env, srv) == -1)
fatal("send server");
}
@@ -336,13 +315,14 @@ parent_configure(struct httpd *env)
continue;
cf.cf_opts = env->sc_opts;
cf.cf_flags = env->sc_flags;
+ memcpy(cf.cf_tls_sid, env->sc_tls_sid, sizeof(cf.cf_tls_sid));
proc_compose(env->sc_ps, id, IMSG_CFG_DONE, &cf, sizeof(cf));
}
ret = 0;
- config_purge(env, CONFIG_ALL);
+ config_purge(env, CONFIG_ALL & ~CONFIG_SERVERS);
return (ret);
}
@@ -427,7 +407,8 @@ parent_shutdown(struct httpd *env)
int
parent_dispatch_server(int fd, struct privsep_proc *p, struct imsg *imsg)
{
- struct httpd *env = p->p_env;
+ struct privsep *ps = p->p_ps;
+ struct httpd *env = ps->ps_env;
switch (imsg->hdr.type) {
case IMSG_CFG_DONE:
@@ -443,7 +424,8 @@ parent_dispatch_server(int fd, struct privsep_proc *p, struct imsg *imsg)
int
parent_dispatch_logger(int fd, struct privsep_proc *p, struct imsg *imsg)
{
- struct httpd *env = p->p_env;
+ struct privsep *ps = p->p_ps;
+ struct httpd *env = ps->ps_env;
unsigned int v;
char *str = NULL;
@@ -479,6 +461,38 @@ parent_dispatch_logger(int fd, struct privsep_proc *p, struct imsg *imsg)
return (0);
}
+void
+parent_tls_ticket_rekey_start(struct server *srv)
+{
+ struct timeval tv;
+
+ server_generate_ticket_key(&srv->srv_conf);
+
+ evtimer_set(&srv->srv_evt, parent_tls_ticket_rekey, srv);
+ timerclear(&tv);
+ tv.tv_sec = srv->srv_conf.tls_ticket_lifetime / 4;
+ evtimer_add(&srv->srv_evt, &tv);
+}
+
+void
+parent_tls_ticket_rekey(int fd, short events, void *arg)
+{
+ struct server *srv = arg;
+ struct timeval tv;
+
+ server_generate_ticket_key(&srv->srv_conf);
+ proc_compose_imsg(httpd_env->sc_ps, PROC_SERVER, -1,
+ IMSG_TLSTICKET_REKEY, -1, -1, &srv->srv_conf.tls_ticket_key,
+ sizeof(srv->srv_conf.tls_ticket_key));
+ explicit_bzero(&srv->srv_conf.tls_ticket_key,
+ sizeof(srv->srv_conf.tls_ticket_key));
+
+ evtimer_set(&srv->srv_evt, parent_tls_ticket_rekey, srv);
+ timerclear(&tv);
+ tv.tv_sec = srv->srv_conf.tls_ticket_lifetime / 4;
+ evtimer_add(&srv->srv_evt, &tv);
+}
+
/*
* Utility functions
*/
@@ -777,7 +791,7 @@ socket_rlimit(int maxfd)
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
- fatal("socket_rlimit: failed to get resource limit");
+ fatal("%s: failed to get resource limit", __func__);
log_debug("%s: max open files %llu", __func__, rl.rlim_max);
/*
@@ -789,7 +803,7 @@ socket_rlimit(int maxfd)
else
rl.rlim_cur = MAXIMUM(rl.rlim_max, (rlim_t)maxfd);
if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
- fatal("socket_rlimit: failed to set resource limit");
+ fatal("%s: failed to set resource limit", __func__);
}
char *