From bf556abca3c60bf9ce432380412eca19c048e15a Mon Sep 17 00:00:00 2001 From: reyk Date: Tue, 22 Apr 2014 12:00:03 +0000 Subject: [PATCH] Update iked to use the same proc.c that relayd uses. Less differences, less code to audit. ok mikeb@ --- sbin/iked/ca.c | 27 +-- sbin/iked/config.c | 33 ++-- sbin/iked/control.c | 10 +- sbin/iked/iked.c | 12 +- sbin/iked/iked.h | 36 +++- sbin/iked/ikev1.c | 6 +- sbin/iked/ikev2_msg.c | 6 +- sbin/iked/ocsp.c | 16 +- sbin/iked/proc.c | 399 ++++++++++++++++++++++++++++++++---------- 9 files changed, 400 insertions(+), 145 deletions(-) diff --git a/sbin/iked/ca.c b/sbin/iked/ca.c index 3cc03d8583d..18be7e5be65 100644 --- a/sbin/iked/ca.c +++ b/sbin/iked/ca.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ca.c,v 1.26 2014/02/17 15:07:23 markus Exp $ */ +/* $OpenBSD: ca.c,v 1.27 2014/04/22 12:00:03 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -47,7 +47,7 @@ #include "iked.h" #include "ikev2.h" -void ca_reset(struct privsep *, void *); +void ca_reset(struct privsep *, struct privsep_proc *, void *); int ca_reload(struct iked *); int ca_getreq(struct iked *, struct imsg *); @@ -119,7 +119,7 @@ caproc(struct privsep *ps, struct privsep_proc *p) } void -ca_reset(struct privsep *ps, void *arg) +ca_reset(struct privsep *ps, struct privsep_proc *p, void *arg) { struct iked *env = ps->ps_env; struct ca_store *store = arg; @@ -160,7 +160,7 @@ ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) memcpy(&mode, imsg->data, sizeof(mode)); if (mode == RESET_ALL || mode == RESET_CA) { log_debug("%s: config reload", __func__); - ca_reset(&env->sc_ps, store); + ca_reset(&env->sc_ps, p, store); } break; case IMSG_OCSP_FD: @@ -241,7 +241,8 @@ ca_setcert(struct iked *env, struct iked_sahdr *sh, struct iked_id *id, iov[iovcnt].iov_len = len; iovcnt++; - if (proc_composev_imsg(env, procid, IMSG_CERT, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, procid, -1, + IMSG_CERT, -1, iov, iovcnt) == -1) return (-1); return (0); } @@ -282,7 +283,7 @@ ca_setreq(struct iked *env, struct iked_sahdr *sh, iov[iovcnt].iov_len = len; iovcnt++; - if (proc_composev_imsg(env, procid, + if (proc_composev_imsg(&env->sc_ps, procid, -1, IMSG_CERTREQ, -1, iov, iovcnt) == -1) goto done; @@ -319,7 +320,8 @@ ca_setauth(struct iked *env, struct iked_sa *sa, log_debug("%s: auth length %zu", __func__, ibuf_size(authmsg)); } - if (proc_composev_imsg(env, id, IMSG_AUTH, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, id, -1, + IMSG_AUTH, -1, iov, iovcnt) == -1) return (-1); return (0); } @@ -379,7 +381,8 @@ ca_getcert(struct iked *env, struct imsg *imsg) iov[1].iov_base = &type; iov[1].iov_len = sizeof(type); - if (proc_composev_imsg(env, PROC_IKEV2, cmd, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + cmd, -1, iov, iovcnt) == -1) return (-1); return (0); } @@ -623,8 +626,8 @@ ca_reload(struct iked *env) ibuf_length(env->sc_certreq) == SHA_DIGEST_LENGTH ? "" : "s"); - (void)proc_composev_imsg(env, PROC_IKEV2, IMSG_CERTREQ, -1, - iov, iovcnt); + (void)proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + IMSG_CERTREQ, -1, iov, iovcnt); } /* @@ -672,8 +675,8 @@ ca_reload(struct iked *env) iov[0].iov_base = &env->sc_certreqtype; iov[0].iov_len = sizeof(env->sc_certreqtype); - (void)proc_composev_imsg(env, PROC_IKEV2, IMSG_CERTREQ, -1, - iov, iovcnt); + (void)proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + IMSG_CERTREQ, -1, iov, iovcnt); return (0); } diff --git a/sbin/iked/config.c b/sbin/iked/config.c index 333b00581b4..987f5f24b2e 100644 --- a/sbin/iked/config.c +++ b/sbin/iked/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.26 2014/02/17 15:53:46 markus Exp $ */ +/* $OpenBSD: config.c,v 1.27 2014/04/22 12:00:03 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -391,8 +391,8 @@ config_setcoupled(struct iked *env, u_int couple) u_int type; type = couple ? IMSG_CTL_COUPLE : IMSG_CTL_DECOUPLE; - proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); - proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, type, -1, NULL, 0); return (0); } @@ -410,8 +410,8 @@ config_setmode(struct iked *env, u_int passive) u_int type; type = passive ? IMSG_CTL_PASSIVE : IMSG_CTL_ACTIVE; - proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); - proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, type, -1, NULL, 0); return (0); } @@ -437,7 +437,8 @@ config_getmode(struct iked *env, u_int type) int config_setreset(struct iked *env, u_int mode, enum privsep_procid id) { - proc_compose_imsg(env, id, IMSG_CTL_RESET, -1, &mode, sizeof(mode)); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_CTL_RESET, -1, &mode, sizeof(mode)); return (0); } @@ -491,8 +492,8 @@ config_setsocket(struct iked *env, struct sockaddr_storage *ss, if ((s = udp_bind((struct sockaddr *)ss, port)) == -1) return (-1); - proc_compose_imsg(env, id, IMSG_UDP_SOCKET, s, - ss, sizeof(*ss)); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_UDP_SOCKET, s, ss, sizeof(*ss)); return (0); } @@ -547,7 +548,8 @@ config_setpfkey(struct iked *env, enum privsep_procid id) if ((s = pfkey_socket()) == -1) return (-1); - proc_compose_imsg(env, id, IMSG_PFKEY_SOCKET, s, NULL, 0); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_PFKEY_SOCKET, s, NULL, 0); return (0); } @@ -567,7 +569,8 @@ config_setuser(struct iked *env, struct iked_user *usr, enum privsep_procid id) return (0); } - proc_compose_imsg(env, id, IMSG_CFG_USER, -1, usr, sizeof(*usr)); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_CFG_USER, -1, usr, sizeof(*usr)); return (0); } @@ -637,8 +640,8 @@ config_setpolicy(struct iked *env, struct iked_policy *pol, return (0); } - if (proc_composev_imsg(env, id, IMSG_CFG_POLICY, -1, - iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, id, -1, + IMSG_CFG_POLICY, -1, iov, iovcnt) == -1) return (-1); return (0); @@ -717,7 +720,8 @@ config_setcompile(struct iked *env, enum privsep_procid id) if (env->sc_opts & IKED_OPT_NOACTION) return (0); - proc_compose_imsg(env, id, IMSG_COMPILE, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_COMPILE, -1, NULL, 0); return (0); } @@ -739,7 +743,8 @@ config_setocsp(struct iked *env) { if (env->sc_opts & IKED_OPT_NOACTION) return (0); - proc_compose_imsg(env, PROC_CERT, IMSG_OCSP_URL, -1, env->sc_ocsp_url, + proc_compose_imsg(&env->sc_ps, PROC_CERT, -1, + IMSG_OCSP_URL, -1, env->sc_ocsp_url, env->sc_ocsp_url ? strlen(env->sc_ocsp_url) : 0); return (0); diff --git a/sbin/iked/control.c b/sbin/iked/control.c index ae63780994d..6bf3a862b32 100644 --- a/sbin/iked/control.c +++ b/sbin/iked/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.13 2013/11/15 12:30:19 mikeb Exp $ */ +/* $OpenBSD: control.c,v 1.14 2014/04/22 12:00:03 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -288,9 +288,9 @@ control_dispatch_imsg(int fd, short event, void *arg) memcpy(&v, imsg.data, sizeof(v)); log_verbose(v); - proc_forward_imsg(env, &imsg, PROC_PARENT); - proc_forward_imsg(env, &imsg, PROC_IKEV2); - proc_forward_imsg(env, &imsg, PROC_IKEV1); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV2, -1); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV1, -1); break; case IMSG_CTL_RELOAD: case IMSG_CTL_RESET: @@ -298,7 +298,7 @@ control_dispatch_imsg(int fd, short event, void *arg) case IMSG_CTL_DECOUPLE: case IMSG_CTL_ACTIVE: case IMSG_CTL_PASSIVE: - proc_forward_imsg(env, &imsg, PROC_PARENT); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); break; default: log_debug("%s: error handling imsg %d", diff --git a/sbin/iked/iked.c b/sbin/iked/iked.c index 3c5e2bdbc19..f139dbdc020 100644 --- a/sbin/iked/iked.c +++ b/sbin/iked/iked.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.c,v 1.19 2014/02/17 15:07:23 markus Exp $ */ +/* $OpenBSD: iked.c,v 1.20 2014/04/22 12:00:03 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -146,6 +146,8 @@ main(int argc, char *argv[]) err(1, "failed to daemonize"); group_init(); + + ps->ps_ninstances = 1; proc_init(ps, procs, nitems(procs)); setproctitle("parent"); @@ -164,7 +166,7 @@ main(int argc, char *argv[]) signal_add(&ps->ps_evsighup, NULL); signal_add(&ps->ps_evsigpipe, NULL); - proc_config(ps, procs, nitems(procs)); + proc_listen(ps, procs, nitems(procs)); if (parent_configure(env) == -1) fatalx("configuration failed"); @@ -361,8 +363,10 @@ parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) case IMSG_CTL_DECOUPLE: case IMSG_CTL_ACTIVE: case IMSG_CTL_PASSIVE: - proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); - proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, + type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, + type, -1, NULL, 0); break; case IMSG_CTL_RELOAD: if (IMSG_DATA_SIZE(imsg) > 0) diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index e7093c718fc..7ac47bf0392 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.71 2014/04/10 16:08:02 reyk Exp $ */ +/* $OpenBSD: iked.h,v 1.72 2014/04/22 12:00:03 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -50,6 +50,7 @@ struct imsgev { struct imsgbuf ibuf; void (*handler)(int, short, void *); struct event ev; + struct privsep_proc *proc; void *data; short events; const char *name; @@ -487,15 +488,26 @@ struct iked_user { }; RB_HEAD(iked_users, iked_user); +struct privsep_pipes { + int *pp_pipes[PROC_MAX]; +}; + struct privsep { - int ps_pipes[PROC_MAX][PROC_MAX]; - struct imsgev ps_ievs[PROC_MAX]; + struct privsep_pipes *ps_pipes[PROC_MAX]; + struct privsep_pipes *ps_pp; + + struct imsgev *ps_ievs[PROC_MAX]; const char *ps_title[PROC_MAX]; pid_t ps_pid[PROC_MAX]; struct passwd *ps_pw; + int ps_noaction; struct control_sock ps_csock; + u_int ps_instances[PROC_MAX]; + u_int ps_ninstances; + u_int ps_instance; + /* Event and signal handlers */ struct event ps_evsigint; struct event ps_evsigterm; @@ -516,6 +528,8 @@ struct privsep_proc { const char *p_chroot; struct privsep *p_ps; struct iked *p_env; + void (*p_shutdown)(void); + u_int p_instance; }; struct iked_ocsp_entry { @@ -825,22 +839,26 @@ void timer_del(struct iked *, struct iked_timer *); /* proc.c */ void proc_init(struct privsep *, struct privsep_proc *, u_int); void proc_kill(struct privsep *); -void proc_config(struct privsep *, struct privsep_proc *, u_int); +void proc_listen(struct privsep *, struct privsep_proc *, size_t); void proc_dispatch(int, short event, void *); pid_t proc_run(struct privsep *, struct privsep_proc *, struct privsep_proc *, u_int, - void (*)(struct privsep *, void *), void *); + void (*)(struct privsep *, struct privsep_proc *, void *), void *); void imsg_event_add(struct imsgev *); int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t, pid_t, int, void *, u_int16_t); int imsg_composev_event(struct imsgev *, u_int16_t, u_int32_t, pid_t, int, const struct iovec *, int); -int proc_compose_imsg(struct iked *, enum privsep_procid, +int proc_compose_imsg(struct privsep *, enum privsep_procid, int, u_int16_t, int, void *, u_int16_t); -int proc_composev_imsg(struct iked *, enum privsep_procid, +int proc_composev_imsg(struct privsep *, enum privsep_procid, int, u_int16_t, int, const struct iovec *, int); -int proc_forward_imsg(struct iked *, struct imsg *, - enum privsep_procid); +int proc_forward_imsg(struct privsep *, struct imsg *, + enum privsep_procid, int); +struct imsgbuf * + proc_ibuf(struct privsep *, enum privsep_procid, int); +struct imsgev * + proc_iev(struct privsep *, enum privsep_procid, int); /* util.c */ void socket_set_blockmode(int, enum blockmodes); diff --git a/sbin/iked/ikev1.c b/sbin/iked/ikev1.c index da152ccb33d..832dceff62a 100644 --- a/sbin/iked/ikev1.c +++ b/sbin/iked/ikev1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev1.c,v 1.14 2014/02/17 11:00:14 reyk Exp $ */ +/* $OpenBSD: ikev1.c,v 1.15 2014/04/22 12:00:03 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -158,8 +158,8 @@ ikev1_msg_cb(int fd, short event, void *arg) iov[1].iov_base = buf; iov[1].iov_len = len; - proc_composev_imsg(env, PROC_IKEV2, IMSG_IKE_MESSAGE, -1, - iov, 2); + proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + IMSG_IKE_MESSAGE, -1, iov, 2); goto done; } diff --git a/sbin/iked/ikev2_msg.c b/sbin/iked/ikev2_msg.c index 1ba719c2c15..96abaaca9d0 100644 --- a/sbin/iked/ikev2_msg.c +++ b/sbin/iked/ikev2_msg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_msg.c,v 1.30 2014/04/10 16:08:02 reyk Exp $ */ +/* $OpenBSD: ikev2_msg.c,v 1.31 2014/04/22 12:00:03 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -97,8 +97,8 @@ ikev2_msg_cb(int fd, short event, void *arg) iov[1].iov_base = buf; iov[1].iov_len = len; - proc_composev_imsg(env, PROC_IKEV1, IMSG_IKE_MESSAGE, -1, - iov, 2); + proc_composev_imsg(&env->sc_ps, PROC_IKEV1, -1, + IMSG_IKE_MESSAGE, -1, iov, 2); goto done; } TAILQ_INIT(&msg.msg_proposals); diff --git a/sbin/iked/ocsp.c b/sbin/iked/ocsp.c index f17c54d2639..80ce1b69230 100644 --- a/sbin/iked/ocsp.c +++ b/sbin/iked/ocsp.c @@ -184,11 +184,11 @@ ocsp_connect_finish(struct iked *env, int fd, struct ocsp_connect *oc) /* the imsg framework will close the FD after send */ iov[0].iov_base = oc->oc_path; iov[0].iov_len = strlen(oc->oc_path); - ret = proc_composev_imsg(env, PROC_CERT, IMSG_OCSP_FD, fd, - iov, iovcnt); + ret = proc_composev_imsg(&env->sc_ps, PROC_CERT, -1, + IMSG_OCSP_FD, fd, iov, iovcnt); } else { - ret = proc_compose_imsg(env, PROC_CERT, IMSG_OCSP_FD, -1, - NULL, 0); + ret = proc_compose_imsg(&env->sc_ps, PROC_CERT, -1, + IMSG_OCSP_FD, -1, NULL, 0); if (fd >= 0) close(fd); } @@ -242,7 +242,8 @@ ocsp_validate_cert(struct iked *env, struct iked_static_id *id, TAILQ_INSERT_TAIL(&env->sc_ocsp, ioe, ioe_entry); /* request connection to ocsp-responder */ - proc_compose_imsg(env, PROC_PARENT, IMSG_OCSP_FD, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_PARENT, -1, + IMSG_OCSP_FD, -1, NULL, 0); return (0); err: @@ -493,6 +494,7 @@ ocsp_parse_response(struct iked_ocsp *ocsp, OCSP_RESPONSE *resp) int ocsp_validate_finish(struct iked_ocsp *ocsp, int valid) { + struct iked *env = ocsp->ocsp_env; struct iovec iov[2]; int iovcnt = 2, ret, cmd; @@ -502,8 +504,8 @@ ocsp_validate_finish(struct iked_ocsp *ocsp, int valid) iov[1].iov_len = sizeof(ocsp->ocsp_type); cmd = valid ? IMSG_CERTVALID : IMSG_CERTINVALID; - ret = proc_composev_imsg(ocsp->ocsp_env, PROC_IKEV2, cmd, -1, iov, - iovcnt); + ret = proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + cmd, -1, iov, iovcnt); ocsp_free(ocsp); return (ret); diff --git a/sbin/iked/proc.c b/sbin/iked/proc.c index 57b619e7c12..d1be2c623c3 100644 --- a/sbin/iked/proc.c +++ b/sbin/iked/proc.c @@ -1,7 +1,7 @@ -/* $OpenBSD: proc.c,v 1.13 2014/04/18 21:29:20 tedu Exp $ */ +/* $OpenBSD: proc.c,v 1.14 2014/04/22 12:00:03 reyk Exp $ */ /* - * Copyright (c) 2010-2013 Reyk Floeter + * Copyright (c) 2010 - 2014 Reyk Floeter * Copyright (c) 2008 Pierre-Yves Ritschard * * Permission to use, copy, modify, and distribute this software for any @@ -19,9 +19,15 @@ #include #include -#include -#include #include +#include +#include + +#include +#include +#include +#include +#include #include #include @@ -33,32 +39,92 @@ #include #include +#include #include "iked.h" -void proc_setup(struct privsep *); +void proc_open(struct privsep *, struct privsep_proc *, + struct privsep_proc *, size_t); +void proc_close(struct privsep *); +int proc_ispeer(struct privsep_proc *, u_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_ispeer(struct privsep_proc *procs, u_int nproc, enum privsep_procid type) +{ + u_int i; + + for (i = 0; i < nproc; i++) + if (procs[i].p_id == type) + return (1); + return (0); +} void -proc_init(struct privsep *ps, struct privsep_proc *p, u_int nproc) +proc_init(struct privsep *ps, struct privsep_proc *procs, u_int nproc) { - u_int i; + u_int i, j, src, dst; + struct privsep_pipes *pp; /* - * Called from parent + * Allocate pipes for all process instances (incl. parent) + * + * - ps->ps_pipes: N:M mapping + * N source processes connected to M destination processes: + * [src][instances][dst][instances], for example + * [PROC_RELAY][3][PROC_CA][3] + * + * - ps->ps_pp: per-process 1:M part of ps->ps_pipes + * Each process instance has a destination array of socketpair fds: + * [dst][instances], for example + * [PROC_PARENT][0] + */ + for (src = 0; src < PROC_MAX; src++) { + /* Allocate destination array for each process */ + if ((ps->ps_pipes[src] = calloc(ps->ps_ninstances, + sizeof(struct privsep_pipes))) == NULL) + fatal("proc_init: calloc"); + + for (i = 0; i < ps->ps_ninstances; i++) { + pp = &ps->ps_pipes[src][i]; + + for (dst = 0; dst < PROC_MAX; dst++) { + /* Allocate maximum fd integers */ + if ((pp->pp_pipes[dst] = + calloc(ps->ps_ninstances, + sizeof(int))) == NULL) + fatal("proc_init: calloc"); + + /* Mark fd as unused */ + for (j = 0; j < ps->ps_ninstances; j++) + pp->pp_pipes[dst][j] = -1; + } + } + } + + /* + * Setup and run the parent and its children */ privsep_process = PROC_PARENT; + ps->ps_instances[PROC_PARENT] = 1; ps->ps_title[PROC_PARENT] = "parent"; ps->ps_pid[PROC_PARENT] = getpid(); + ps->ps_pp = &ps->ps_pipes[privsep_process][0]; - proc_setup(ps); + for (i = 0; i < nproc; i++) { + /* Default to 1 process instance */ + if (ps->ps_instances[procs[i].p_id] < 1) + ps->ps_instances[procs[i].p_id] = 1; + ps->ps_title[procs[i].p_id] = procs[i].p_title; + } + + proc_open(ps, NULL, procs, nproc); /* Engage! */ - for (i = 0; i < nproc; i++, p++) { - ps->ps_title[p->p_id] = p->p_title; - ps->ps_pid[p->p_id] = (*p->p_init)(ps, p); - } + for (i = 0; i < nproc; i++) + ps->ps_pid[procs[i].p_id] = (*procs[i].p_init)(ps, &procs[i]); } void @@ -73,83 +139,157 @@ proc_kill(struct privsep *ps) for (i = 0; i < PROC_MAX; i++) { if (ps->ps_pid[i] == 0) continue; - kill(ps->ps_pid[i], SIGTERM); + killpg(ps->ps_pid[i], SIGTERM); } do { pid = waitpid(WAIT_ANY, NULL, 0); } while (pid != -1 || (pid == -1 && errno == EINTR)); + + proc_close(ps); } void -proc_setup(struct privsep *ps) +proc_open(struct privsep *ps, struct privsep_proc *p, + struct privsep_proc *procs, size_t nproc) { - int i, j, sockpair[2]; - - for (i = 0; i < PROC_MAX; i++) - for (j = 0; j < PROC_MAX; j++) { - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, - sockpair) == -1) - fatal("sockpair"); - ps->ps_pipes[i][j] = sockpair[0]; - ps->ps_pipes[j][i] = sockpair[1]; - socket_set_blockmode(ps->ps_pipes[i][j], - BM_NONBLOCK); - socket_set_blockmode(ps->ps_pipes[j][i], - BM_NONBLOCK); + struct privsep_pipes *pa, *pb; + int fds[2]; + u_int i, j, src, proc; + + if (p == NULL) + src = privsep_process; /* parent */ + else + src = p->p_id; + + /* + * Open socket pairs for our peers + */ + for (proc = 0; proc < nproc; proc++) { + procs[proc].p_ps = ps; + procs[proc].p_env = ps->ps_env; + + for (i = 0; i < ps->ps_instances[src]; i++) { + for (j = 0; j < ps->ps_instances[procs[proc].p_id]; + j++) { + pa = &ps->ps_pipes[src][i]; + pb = &ps->ps_pipes[procs[proc].p_id][j]; + + /* Check if fds are already set by peer */ + if (pa->pp_pipes[procs[proc].p_id][j] != -1) + continue; + + if (socketpair(AF_UNIX, SOCK_STREAM, + 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]; + } } + } } void -proc_config(struct privsep *ps, struct privsep_proc *p, u_int nproc) +proc_listen(struct privsep *ps, struct privsep_proc *procs, size_t nproc) { - u_int src, dst, i, j, k, found; - - src = privsep_process; + u_int i, dst, src, n, m; + struct privsep_pipes *pp; /* - * close unused pipes + * Close unused pipes */ - for (i = 0; i < PROC_MAX; i++) { - if (i != privsep_process) { - for (j = 0; j < PROC_MAX; j++) { - close(ps->ps_pipes[i][j]); - ps->ps_pipes[i][j] = -1; - } - } else { - for (j = found = 0; j < PROC_MAX; j++, found = 0) { - for (k = 0; k < nproc; k++) { - if (p[k].p_id == j) - found++; - } - if (!found) { - close(ps->ps_pipes[i][j]); - ps->ps_pipes[i][j] = -1; + for (src = 0; src < PROC_MAX; src++) { + for (n = 0; n < ps->ps_instances[src]; n++) { + /* Ingore current process */ + if (src == (u_int)privsep_process && + n == ps->ps_instance) + continue; + + pp = &ps->ps_pipes[src][n]; + + for (dst = 0; dst < PROC_MAX; dst++) { + if (src == dst) + continue; + for (m = 0; m < ps->ps_instances[dst]; m++) { + if (pp->pp_pipes[dst][m] == -1) + continue; + + /* Close and invalidate fd */ + close(pp->pp_pipes[dst][m]); + pp->pp_pipes[dst][m] = -1; } } } } + src = privsep_process; + ps->ps_pp = pp = &ps->ps_pipes[src][ps->ps_instance]; + /* - * listen on appropriate pipes + * Listen on appropriate pipes */ - for (i = 0; i < nproc; i++, p++) { - dst = p->p_id; - p->p_ps = ps; - p->p_env = ps->ps_env; - - imsg_init(&ps->ps_ievs[dst].ibuf, - ps->ps_pipes[src][dst]); - ps->ps_ievs[dst].handler = proc_dispatch; - ps->ps_ievs[dst].events = EV_READ; - ps->ps_ievs[dst].data = p; - ps->ps_ievs[dst].name = p->p_title; - event_set(&ps->ps_ievs[dst].ev, - ps->ps_ievs[dst].ibuf.fd, - ps->ps_ievs[dst].events, - ps->ps_ievs[dst].handler, - ps->ps_ievs[dst].data); - event_add(&ps->ps_ievs[dst].ev, NULL); + for (i = 0; i < nproc; i++) { + dst = procs[i].p_id; + + if (src == dst) + fatal("proc_listen: cannot peer with oneself"); + + if ((ps->ps_ievs[dst] = calloc(ps->ps_instances[dst], + sizeof(struct imsgev))) == NULL) + fatal("proc_open"); + + for (n = 0; n < ps->ps_instances[dst]; n++) { + if (pp->pp_pipes[dst][n] == -1) + continue; + + imsg_init(&(ps->ps_ievs[dst][n].ibuf), + pp->pp_pipes[dst][n]); + ps->ps_ievs[dst][n].handler = proc_dispatch; + ps->ps_ievs[dst][n].events = EV_READ; + ps->ps_ievs[dst][n].proc = &procs[i]; + ps->ps_ievs[dst][n].data = &ps->ps_ievs[dst][n]; + procs[i].p_instance = n; + + event_set(&(ps->ps_ievs[dst][n].ev), + ps->ps_ievs[dst][n].ibuf.fd, + ps->ps_ievs[dst][n].events, + ps->ps_ievs[dst][n].handler, + ps->ps_ievs[dst][n].data); + event_add(&(ps->ps_ievs[dst][n].ev), NULL); + } + } +} + +void +proc_close(struct privsep *ps) +{ + u_int dst, n; + struct privsep_pipes *pp; + + if (ps == NULL) + return; + + pp = ps->ps_pp; + + for (dst = 0; dst < PROC_MAX; dst++) { + if (ps->ps_ievs[dst] == NULL) + continue; + + for (n = 0; n < ps->ps_instances[dst]; n++) { + if (pp->pp_pipes[dst][n] == -1) + continue; + + /* Cancel the fd, close and invalidate the fd */ + event_del(&(ps->ps_ievs[dst][n].ev)); + imsg_clear(&(ps->ps_ievs[dst][n].ibuf)); + close(pp->pp_pipes[dst][n]); + pp->pp_pipes[dst][n] = -1; + } + free(ps->ps_ievs[dst]); } } @@ -161,7 +301,13 @@ proc_shutdown(struct privsep_proc *p) if (p->p_id == PROC_CONTROL && ps) control_cleanup(&ps->ps_csock); - log_info("%s exiting", p->p_title); + if (p->p_shutdown != NULL) + (*p->p_shutdown)(); + + proc_close(ps); + + log_info("%s exiting, pid %d", p->p_title, getpid()); + _exit(0); } @@ -189,16 +335,25 @@ proc_sig_handler(int sig, short event, void *arg) pid_t proc_run(struct privsep *ps, struct privsep_proc *p, struct privsep_proc *procs, u_int nproc, - void (*init)(struct privsep *, void *), void *arg) + void (*init)(struct privsep *, struct privsep_proc *, void *), void *arg) { pid_t pid; struct passwd *pw; const char *root; + u_int n; + + if (ps->ps_noaction) + return (0); + proc_open(ps, p, procs, nproc); + + /* Fork child handlers */ switch (pid = fork()) { case -1: fatal("proc_run: cannot fork"); case 0: + /* Set the process group of the current process */ + setpgrp(0, getpid()); break; default: return (pid); @@ -206,7 +361,7 @@ proc_run(struct privsep *ps, struct privsep_proc *p, pw = ps->ps_pw; - if (p->p_id == PROC_CONTROL) { + if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { if (control_init(ps, &ps->ps_csock) == -1) fatalx(p->p_title); } @@ -243,6 +398,19 @@ proc_run(struct privsep *ps, struct privsep_proc *p, fatal("proc_run: cannot drop privileges"); #endif + /* Fork child handlers */ + for (n = 1; n < ps->ps_instances[p->p_id]; n++) { + if (fork() == 0) { + ps->ps_instance = p->p_instance = n; + break; + } + } + +#ifdef DEBUG + log_debug("%s: %s %d/%d, pid %d", __func__, p->p_title, + ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid()); +#endif + event_init(); signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p); @@ -257,16 +425,16 @@ proc_run(struct privsep *ps, struct privsep_proc *p, signal_add(&ps->ps_evsighup, NULL); signal_add(&ps->ps_evsigpipe, NULL); - proc_config(ps, procs, nproc); + proc_listen(ps, procs, nproc); - if (p->p_id == PROC_CONTROL) { + 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); } if (init != NULL) - init(ps, arg); + init(ps, p, arg); event_dispatch(); @@ -278,9 +446,9 @@ proc_run(struct privsep *ps, struct privsep_proc *p, void proc_dispatch(int fd, short event, void *arg) { - struct privsep_proc *p = (struct privsep_proc *)arg; + struct imsgev *iev = arg; + struct privsep_proc *p = iev->proc; struct privsep *ps = p->p_ps; - struct imsgev *iev; struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; @@ -288,7 +456,6 @@ proc_dispatch(int fd, short event, void *arg) const char *title; title = ps->ps_title[privsep_process]; - iev = &ps->ps_ievs[p->p_id]; ibuf = &iev->ibuf; if (event & EV_READ) { @@ -303,7 +470,7 @@ proc_dispatch(int fd, short event, void *arg) } if (event & EV_WRITE) { - if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) + if (msgbuf_write(&ibuf->w) == -1 && errno != EAGAIN) fatal(title); } @@ -313,6 +480,12 @@ proc_dispatch(int fd, short event, void *arg) if (n == 0) break; +#if DEBUG > 1 + log_debug("%s: %s %d got imsg %d from %s %d", + __func__, title, ps->ps_instance + 1, + imsg.hdr.type, p->p_title, p->p_instance); +#endif + /* * Check the message with the program callback */ @@ -328,13 +501,13 @@ proc_dispatch(int fd, short event, void *arg) switch (imsg.hdr.type) { case IMSG_CTL_VERBOSE: IMSG_SIZE_CHECK(&imsg, &verbose); - memcpy(&verbose, imsg.data, sizeof(verbose)); log_verbose(verbose); break; default: - log_warnx("%s: %s got imsg %d", __func__, p->p_title, - imsg.hdr.type); + log_warnx("%s: %s %d got invalid imsg %d from %s %d", + __func__, title, ps->ps_instance + 1, + imsg.hdr.type, p->p_title, p->p_instance); fatalx(title); } imsg_free(&imsg); @@ -342,6 +515,10 @@ proc_dispatch(int fd, short event, void *arg) imsg_event_add(iev); } +/* + * imsg helper functions + */ + void imsg_event_add(struct imsgev *iev) { @@ -385,26 +562,72 @@ imsg_composev_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, return (ret); } +void +proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m) +{ + if (*n == -1) { + /* Use a range of all target instances */ + *n = 0; + *m = ps->ps_instances[id]; + } else { + /* Use only a single slot of the specified peer process */ + *m = *n + 1; + } +} + int -proc_compose_imsg(struct iked *env, enum privsep_procid id, +proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n, u_int16_t type, int fd, void *data, u_int16_t datalen) { - return (imsg_compose_event(&env->sc_ps.ps_ievs[id], - type, -1, 0, fd, data, 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) + return (-1); + } + + return (0); } int -proc_composev_imsg(struct iked *env, enum privsep_procid id, +proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n, u_int16_t type, int fd, const struct iovec *iov, int iovcnt) { - return (imsg_composev_event(&env->sc_ps.ps_ievs[id], - type, -1, 0, fd, iov, 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) + return (-1); + + return (0); } int -proc_forward_imsg(struct iked *env, struct imsg *imsg, - enum privsep_procid id) +proc_forward_imsg(struct privsep *ps, struct imsg *imsg, + enum privsep_procid id, int n) { - return (proc_compose_imsg(env, id, imsg->hdr.type, + return (proc_compose_imsg(ps, id, n, imsg->hdr.type, imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); } + +struct imsgbuf * +proc_ibuf(struct privsep *ps, enum privsep_procid id, int n) +{ + int m; + + proc_range(ps, id, &n, &m); + return (&ps->ps_ievs[id][n].ibuf); +} + +struct imsgev * +proc_iev(struct privsep *ps, enum privsep_procid id, int n) +{ + int m; + + proc_range(ps, id, &n, &m); + return (&ps->ps_ievs[id][n]); +} -- 2.20.1