summaryrefslogtreecommitdiff
path: root/sbin/iked/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/iked/proc.c')
-rw-r--r--sbin/iked/proc.c332
1 files changed, 332 insertions, 0 deletions
diff --git a/sbin/iked/proc.c b/sbin/iked/proc.c
new file mode 100644
index 00000000000..05213b1e083
--- /dev/null
+++ b/sbin/iked/proc.c
@@ -0,0 +1,332 @@
+/* $OpenBSD: proc.c,v 1.1 2010/06/03 16:41:12 reyk Exp $ */
+/* $vantronix: proc.c,v 1.11 2010/06/01 16:45:56 jsg Exp $ */
+
+/*
+ * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net>
+ * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * 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 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 <sys/types.h>
+#include <sys/queue.h>
+#include <sys/tree.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <pwd.h>
+#include <event.h>
+
+#include <openssl/rand.h>
+
+#include "iked.h"
+
+void proc_shutdown(struct iked_proc *);
+void proc_sig_handler(int, short, void *);
+
+void
+init_procs(struct iked *env, struct iked_proc *p, u_int nproc)
+{
+ u_int i;
+
+ iked_process = PROC_PARENT;
+ init_pipes(env);
+
+ for (i = 0; i < nproc; i++, p++) {
+ env->sc_title[p->id] = p->title;
+ env->sc_pid[p->id] = (*p->init)(env, p);
+ }
+}
+
+void
+kill_procs(struct iked *env)
+{
+ u_int i;
+
+ if (iked_process != PROC_PARENT)
+ return;
+
+ for (i = 0; i < PROC_MAX; i++) {
+ if (env->sc_pid[i] == 0)
+ continue;
+ kill(env->sc_pid[i], SIGTERM);
+ }
+}
+
+void
+init_pipes(struct iked *env)
+{
+ int i, j, fds[2];
+
+ for (i = 0; i < PROC_MAX; i++)
+ for (j = 0; j < PROC_MAX; j++) {
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
+ fds) == -1)
+ fatal("socketpair");
+ env->sc_pipes[i][j] = fds[0];
+ env->sc_pipes[j][i] = fds[1];
+ socket_set_blockmode(env->sc_pipes[i][j],
+ BM_NONBLOCK);
+ socket_set_blockmode(env->sc_pipes[j][i],
+ BM_NONBLOCK);
+ }
+}
+
+void
+config_pipes(struct iked *env, struct iked_proc *p, u_int nproc)
+{
+ u_int i, j, k, found;
+
+ for (i = 0; i < PROC_MAX; i++) {
+ if (i != iked_process) {
+ for (j = 0; j < PROC_MAX; j++) {
+ close(env->sc_pipes[i][j]);
+ env->sc_pipes[i][j] = -1;
+ }
+ } else {
+ for (j = found = 0; j < PROC_MAX; j++, found = 0) {
+ for (k = 0; k < nproc; k++) {
+ if (p[k].id == j)
+ found++;
+ }
+ if (!found) {
+ close(env->sc_pipes[i][j]);
+ env->sc_pipes[i][j] = -1;
+ }
+ }
+ }
+ }
+}
+
+void
+config_procs(struct iked *env, struct iked_proc *p, u_int nproc)
+{
+ u_int src, dst, i;
+
+ /*
+ * listen on appropriate pipes
+ */
+ for (i = 0; i < nproc; i++, p++) {
+ src = iked_process;
+ dst = p->id;
+ p->env = env;
+
+ imsg_init(&env->sc_ievs[dst].ibuf,
+ env->sc_pipes[src][dst]);
+ env->sc_ievs[dst].handler = dispatch_proc;
+ env->sc_ievs[dst].events = EV_READ;
+ env->sc_ievs[dst].data = p;
+ env->sc_ievs[dst].name = p->title;
+ event_set(&env->sc_ievs[dst].ev,
+ env->sc_ievs[dst].ibuf.fd,
+ env->sc_ievs[dst].events,
+ env->sc_ievs[dst].handler,
+ env->sc_ievs[dst].data);
+ event_add(&env->sc_ievs[dst].ev, NULL);
+ }
+}
+
+void
+proc_shutdown(struct iked_proc *p)
+{
+ struct iked *env = p->env;
+
+ if (p->id == PROC_CONTROL)
+ control_cleanup(&env->sc_csock);
+
+ log_info("%s exiting", p->title);
+ _exit(0);
+}
+
+void
+proc_sig_handler(int sig, short event, void *arg)
+{
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ proc_shutdown((struct iked_proc *)arg);
+ break;
+ case SIGCHLD:
+ case SIGHUP:
+ case SIGPIPE:
+ /* ignore */
+ break;
+ default:
+ fatalx("proc_sig_handler: unexpected signal");
+ /* NOTREACHED */
+ }
+}
+
+pid_t
+run_proc(struct iked *env, struct iked_proc *p,
+ struct iked_proc *procs, u_int nproc,
+ void (*init)(struct iked *, void *), void *arg)
+{
+ pid_t pid;
+ struct passwd *pw;
+ const char *root;
+ u_int32_t seed[256];
+
+ switch (pid = fork()) {
+ case -1:
+ fatal("run_proc: cannot fork");
+ case 0:
+ break;
+ default:
+ return (pid);
+ }
+
+ pw = env->sc_pw;
+
+ if (p->id == PROC_CONTROL) {
+ if (control_init(env, &env->sc_csock) == -1)
+ fatalx(p->title);
+ }
+
+ /* Change root directory */
+ if (p->chroot != NULL)
+ root = p->chroot;
+ else
+ root = pw->pw_dir;
+
+#ifndef DEBUG
+ if (chroot(root) == -1)
+ fatal("run_proc: chroot");
+ if (chdir("/") == -1)
+ fatal("run_proc: chdir(\"/\")");
+#else
+#warning disabling privilege revocation and chroot in DEBUG MODE
+ if (p->chroot != NULL) {
+ if (chroot(root) == -1)
+ fatal("run_proc: chroot");
+ if (chdir("/") == -1)
+ fatal("run_proc: chdir(\"/\")");
+ }
+#endif
+
+ iked_process = p->id;
+ setproctitle("%s", p->title);
+
+#ifndef DEBUG
+ if (setgroups(1, &pw->pw_gid) ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+ fatal("run_proc: cannot drop privileges");
+#endif
+
+ event_init();
+
+ signal_set(&env->sc_evsigint, SIGINT, proc_sig_handler, env);
+ signal_set(&env->sc_evsigterm, SIGTERM, proc_sig_handler, env);
+ signal_set(&env->sc_evsigchld, SIGCHLD, proc_sig_handler, env);
+ signal_set(&env->sc_evsighup, SIGHUP, proc_sig_handler, env);
+ signal_set(&env->sc_evsigpipe, SIGPIPE, proc_sig_handler, env);
+
+ signal_add(&env->sc_evsigint, NULL);
+ signal_add(&env->sc_evsigterm, NULL);
+ signal_add(&env->sc_evsigchld, NULL);
+ signal_add(&env->sc_evsighup, NULL);
+ signal_add(&env->sc_evsigpipe, NULL);
+
+ config_pipes(env, procs, nproc);
+ config_procs(env, procs, nproc);
+
+ arc4random_buf(seed, sizeof(seed));
+ RAND_seed(seed, sizeof(seed));
+
+ if (p->id == PROC_CONTROL) {
+ TAILQ_INIT(&ctl_conns);
+ if (control_listen(&env->sc_csock) == -1)
+ fatalx(p->title);
+ }
+
+ if (init != NULL)
+ init(env, arg);
+
+ event_dispatch();
+
+ proc_shutdown(p);
+
+ return (0);
+}
+
+void
+dispatch_proc(int fd, short event, void *arg)
+{
+ struct iked_proc *p = (struct iked_proc *)arg;
+ struct iked *env = p->env;
+ struct imsgev *iev;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ ssize_t n;
+ int verbose;
+
+ iev = &env->sc_ievs[p->id];
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsg_read(ibuf)) == -1)
+ fatal(p->title);
+ if (n == 0) {
+ /* this pipe is dead, so remove the event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ return;
+ }
+ }
+
+ if (event & EV_WRITE) {
+ if (msgbuf_write(&ibuf->w) == -1)
+ fatal(p->title);
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal(p->title);
+ if (n == 0)
+ break;
+
+ /*
+ * Check the message with the program callback
+ */
+ if ((p->cb)(fd, p, &imsg) == 0) {
+ /* Message was handled by the callback, continue */
+ imsg_free(&imsg);
+ continue;
+ }
+
+ /*
+ * Generic message handling
+ */
+ 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->title,
+ imsg.hdr.type);
+ fatalx(p->title);
+ }
+ imsg_free(&imsg);
+ }
+ imsg_event_add(iev);
+}