summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2013-10-17 08:42:45 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2013-10-17 08:42:45 +0000
commite113d10070344c2a43cad66b9440395e7b3267db (patch)
tree03e01ae4527811a56a5c2204b8b8e97f6f2ff33d /usr.sbin
parentf2d6fc8fc8eab2639590bae761a2dbbb921cfb4f (diff)
Update snmpd(8) to use the proc.c privsep style from iked and relayd.
ok sthen@ deraadt@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/snmpd/Makefile4
-rw-r--r--usr.sbin/snmpd/control.c98
-rw-r--r--usr.sbin/snmpd/log.c39
-rw-r--r--usr.sbin/snmpd/parse.y12
-rw-r--r--usr.sbin/snmpd/proc.c443
-rw-r--r--usr.sbin/snmpd/snmpd.c211
-rw-r--r--usr.sbin/snmpd/snmpd.h121
-rw-r--r--usr.sbin/snmpd/snmpe.c176
8 files changed, 740 insertions, 364 deletions
diff --git a/usr.sbin/snmpd/Makefile b/usr.sbin/snmpd/Makefile
index 9746eda9a87..3d407804c12 100644
--- a/usr.sbin/snmpd/Makefile
+++ b/usr.sbin/snmpd/Makefile
@@ -1,10 +1,10 @@
-# $OpenBSD: Makefile,v 1.9 2012/09/17 16:30:34 reyk Exp $
+# $OpenBSD: Makefile,v 1.10 2013/10/17 08:42:43 reyk Exp $
PROG= snmpd
MAN= snmpd.8 snmpd.conf.5
SRCS= parse.y ber.c log.c control.c snmpe.c \
mps.c trap.c mib.c smi.c kroute.c snmpd.c timer.c \
- pf.c usm.c
+ pf.c proc.c usm.c
LDADD= -levent -lutil -lkvm -lcrypto
DPADD= ${LIBEVENT} ${LIBUTIL}
diff --git a/usr.sbin/snmpd/control.c b/usr.sbin/snmpd/control.c
index f508d6bf56b..f463185fea8 100644
--- a/usr.sbin/snmpd/control.c
+++ b/usr.sbin/snmpd/control.c
@@ -1,6 +1,7 @@
-/* $OpenBSD: control.c,v 1.18 2013/03/11 17:40:11 deraadt Exp $ */
+/* $OpenBSD: control.c,v 1.19 2013/10/17 08:42:44 reyk Exp $ */
/*
+ * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -18,7 +19,6 @@
#include <sys/queue.h>
#include <sys/param.h>
-#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -40,12 +40,17 @@
struct ctl_connlist ctl_conns;
-struct ctl_conn *control_connbyfd(int);
-void control_close(int, struct control_sock *);
+void control_accept(int, short, void *);
+struct ctl_conn
+ *control_connbyfd(int);
+void control_close(int, struct control_sock *);
+void control_dispatch_imsg(int, short, void *);
+void control_imsg_forward(struct imsg *);
int
-control_init(struct control_sock *cs)
+control_init(struct privsep *ps, struct control_sock *cs)
{
+ struct snmpd *env = ps->ps_env;
struct sockaddr_un sun;
int fd;
mode_t old_umask, mode;
@@ -54,21 +59,21 @@ control_init(struct control_sock *cs)
return (0);
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
- log_warn("control_init: socket");
+ log_warn("%s: socket", __func__);
return (-1);
}
sun.sun_family = AF_UNIX;
if (strlcpy(sun.sun_path, cs->cs_name,
sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) {
- log_warn("control_init: %s name too long", cs->cs_name);
+ log_warn("%s: %s name too long", __func__, cs->cs_name);
close(fd);
return (-1);
}
if (unlink(cs->cs_name) == -1)
if (errno != ENOENT) {
- log_warn("control_init: unlink %s", cs->cs_name);
+ log_warn("%s: unlink %s", __func__, cs->cs_name);
close(fd);
return (-1);
}
@@ -82,7 +87,7 @@ control_init(struct control_sock *cs)
}
if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
- log_warn("control_init: bind: %s", cs->cs_name);
+ log_warn("%s: bind: %s", __func__, cs->cs_name);
close(fd);
(void)umask(old_umask);
return (-1);
@@ -90,14 +95,15 @@ control_init(struct control_sock *cs)
(void)umask(old_umask);
if (chmod(cs->cs_name, mode) == -1) {
- log_warn("control_init: chmod");
+ log_warn("%s: chmod", __func__);
close(fd);
(void)unlink(cs->cs_name);
return (-1);
}
- session_socket_blockmode(fd, BM_NONBLOCK);
+ socket_set_blockmode(fd, BM_NONBLOCK);
cs->cs_fd = fd;
+ cs->cs_env = env;
return (0);
}
@@ -109,7 +115,7 @@ control_listen(struct control_sock *cs)
return (0);
if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1) {
- log_warn("control_listen: listen");
+ log_warn("%s: listen", __func__);
return (-1);
}
@@ -135,7 +141,7 @@ control_cleanup(struct control_sock *cs)
void
control_accept(int listenfd, short event, void *arg)
{
- struct control_sock *cs = (struct control_sock *)arg;
+ struct control_sock *cs = arg;
int connfd;
socklen_t len;
struct sockaddr_un sun;
@@ -159,14 +165,14 @@ control_accept(int listenfd, short event, void *arg)
evtimer_add(&cs->cs_evt, &evtpause);
} else if (errno != EWOULDBLOCK && errno != EINTR &&
errno != ECONNABORTED)
- log_warn("control_accept: accept");
+ log_warn("%s: accept", __func__);
return;
}
- session_socket_blockmode(connfd, BM_NONBLOCK);
+ socket_set_blockmode(connfd, BM_NONBLOCK);
if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
- log_warn("control_accept");
+ log_warn("%s", __func__);
close(connfd);
return;
}
@@ -176,7 +182,7 @@ control_accept(int listenfd, short event, void *arg)
c->iev.events = EV_READ;
c->iev.data = cs;
event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
- c->iev.handler, cs);
+ c->iev.handler, c->iev.data);
event_add(&c->iev.ev, NULL);
TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
@@ -200,7 +206,7 @@ control_close(int fd, struct control_sock *cs)
struct ctl_conn *c;
if ((c = control_connbyfd(fd)) == NULL) {
- log_warn("control_close: fd %d: not found", fd);
+ log_warn("%s: fd %d: not found", __func__, fd);
return;
}
@@ -223,13 +229,14 @@ control_close(int fd, struct control_sock *cs)
void
control_dispatch_imsg(int fd, short event, void *arg)
{
- struct control_sock *cs = (struct control_sock *)arg;
+ struct control_sock *cs = arg;
+ struct snmpd *env = cs->cs_env;
struct ctl_conn *c;
struct imsg imsg;
- int n;
+ int n, v, i;
if ((c = control_connbyfd(fd)) == NULL) {
- log_warn("control_dispatch_imsg: fd %d: not found", fd);
+ log_warn("%s: fd %d: not found", __func__, fd);
return;
}
@@ -276,12 +283,15 @@ control_dispatch_imsg(int fd, short event, void *arg)
}
}
+ control_imsg_forward(&imsg);
+
switch (imsg.hdr.type) {
case IMSG_CTL_NOTIFY:
if (c->flags & CTL_CONN_NOTIFY) {
- log_debug("control_dispatch_imsg: "
- "client requested notify more than once");
- imsg_compose(&c->iev.ibuf, IMSG_CTL_FAIL,
+ log_debug("%s: "
+ "client requested notify more than once",
+ __func__);
+ imsg_compose_event(&c->iev, IMSG_CTL_FAIL,
0, 0, -1, NULL, 0);
break;
}
@@ -301,9 +311,24 @@ control_dispatch_imsg(int fd, short event, void *arg)
return;
}
break;
+ case IMSG_CTL_VERBOSE:
+ IMSG_SIZE_CHECK(&imsg, &v);
+
+ memcpy(&v, imsg.data, sizeof(v));
+ log_verbose(v);
+
+ for (i = 0; i < PROC_MAX; i++) {
+ if (privsep_process == PROC_CONTROL)
+ continue;
+ proc_forward_imsg(&env->sc_ps, &imsg, i);
+ }
+ break;
+ case IMSG_CTL_RELOAD:
+ proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT);
+ break;
default:
- log_debug("control_dispatch_imsg: "
- "error handling imsg %d", imsg.hdr.type);
+ log_debug("%s: error handling imsg %d",
+ __func__, imsg.hdr.type);
break;
}
imsg_free(&imsg);
@@ -319,24 +344,7 @@ control_imsg_forward(struct imsg *imsg)
TAILQ_FOREACH(c, &ctl_conns, entry)
if (c->flags & CTL_CONN_NOTIFY)
- imsg_compose(&c->iev.ibuf, imsg->hdr.type, 0,
- imsg->hdr.pid, -1, imsg->data,
+ imsg_compose(&c->iev.ibuf, imsg->hdr.type,
+ 0, imsg->hdr.pid, -1, imsg->data,
imsg->hdr.len - IMSG_HEADER_SIZE);
}
-
-void
-session_socket_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/usr.sbin/snmpd/log.c b/usr.sbin/snmpd/log.c
index 4ee13da9dc0..dde2a54f026 100644
--- a/usr.sbin/snmpd/log.c
+++ b/usr.sbin/snmpd/log.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: log.c,v 1.3 2010/03/29 14:52:49 claudio Exp $ */
+/* $OpenBSD: log.c,v 1.4 2013/10/17 08:42:44 reyk Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -43,6 +43,7 @@
#include "snmpd.h"
int debug;
+int verbose;
void vlog(int, const char *, va_list);
void logit(int, const char *, ...);
@@ -53,6 +54,7 @@ log_init(int n_debug)
extern char *__progname;
debug = n_debug;
+ verbose = n_debug;
if (!debug)
openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
@@ -61,6 +63,12 @@ log_init(int n_debug)
}
void
+log_verbose(int v)
+{
+ verbose = v;
+}
+
+void
logit(int pri, const char *fmt, ...)
{
va_list ap;
@@ -139,7 +147,7 @@ log_debug(const char *emsg, ...)
{
va_list ap;
- if (debug) {
+ if (verbose > 1) {
va_start(ap, emsg);
vlog(LOG_DEBUG, emsg, ap);
va_end(ap);
@@ -147,16 +155,41 @@ log_debug(const char *emsg, ...)
}
void
+print_debug(const char *emsg, ...)
+{
+ va_list ap;
+
+ if (debug && verbose > 2) {
+ va_start(ap, emsg);
+ vfprintf(stderr, emsg, ap);
+ va_end(ap);
+ }
+}
+
+void
+print_verbose(const char *emsg, ...)
+{
+ va_list ap;
+
+ if (verbose) {
+ va_start(ap, emsg);
+ vfprintf(stderr, emsg, ap);
+ va_end(ap);
+ }
+}
+
+void
fatal(const char *emsg)
{
if (emsg == NULL)
logit(LOG_CRIT, "fatal: %s", strerror(errno));
- else
+ else {
if (errno)
logit(LOG_CRIT, "fatal: %s: %s",
emsg, strerror(errno));
else
logit(LOG_CRIT, "fatal: %s", emsg);
+ }
exit(1);
}
diff --git a/usr.sbin/snmpd/parse.y b/usr.sbin/snmpd/parse.y
index 98b62993d5a..508afdbda32 100644
--- a/usr.sbin/snmpd/parse.y
+++ b/usr.sbin/snmpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.26 2013/10/16 16:05:02 blambert Exp $ */
+/* $OpenBSD: parse.y,v 1.27 2013/10/17 08:42:44 reyk Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -277,15 +277,15 @@ main : LISTEN ON STRING {
}
rcsock->cs_name = $2;
rcsock->cs_restricted = 1;
- TAILQ_INSERT_TAIL(&conf->sc_rcsocks, rcsock,
- cs_entry);
+ TAILQ_INSERT_TAIL(&conf->sc_ps.ps_rcsocks,
+ rcsock, cs_entry);
} else {
if (++nctlsocks > 1) {
yyerror("multiple control "
"sockets specified");
YYERROR;
}
- conf->sc_csock.cs_name = $2;
+ conf->sc_ps.ps_csock.cs_name = $2;
}
}
;
@@ -881,8 +881,8 @@ parse_config(const char *filename, u_int flags)
conf->sc_confpath = filename;
conf->sc_address.ss.ss_family = AF_INET;
conf->sc_address.port = SNMPD_PORT;
- conf->sc_csock.cs_name = SNMPD_SOCKET;
- TAILQ_INIT(&conf->sc_rcsocks);
+ conf->sc_ps.ps_csock.cs_name = SNMPD_SOCKET;
+ TAILQ_INIT(&conf->sc_ps.ps_rcsocks);
strlcpy(conf->sc_rdcommunity, "public", SNMPD_MAXCOMMUNITYLEN);
strlcpy(conf->sc_rwcommunity, "private", SNMPD_MAXCOMMUNITYLEN);
strlcpy(conf->sc_trcommunity, "public", SNMPD_MAXCOMMUNITYLEN);
diff --git a/usr.sbin/snmpd/proc.c b/usr.sbin/snmpd/proc.c
new file mode 100644
index 00000000000..6d29913fc44
--- /dev/null
+++ b/usr.sbin/snmpd/proc.c
@@ -0,0 +1,443 @@
+/* $OpenBSD: proc.c,v 1.1 2013/10/17 08:42:44 reyk Exp $ */
+
+/*
+ * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
+ * 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/socket.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/tree.h>
+
+#include <net/if.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <signal.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include <openssl/rand.h>
+
+#include "snmpd.h"
+
+void proc_setup(struct privsep *);
+void proc_shutdown(struct privsep_proc *);
+void proc_sig_handler(int, short, void *);
+
+void
+proc_init(struct privsep *ps, struct privsep_proc *p, u_int nproc)
+{
+ u_int i;
+
+ /*
+ * Called from parent
+ */
+ privsep_process = PROC_PARENT;
+ ps->ps_title[PROC_PARENT] = "parent";
+ ps->ps_pid[PROC_PARENT] = getpid();
+
+ proc_setup(ps);
+
+ /* 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);
+ }
+}
+
+void
+proc_kill(struct privsep *ps)
+{
+ pid_t pid;
+ u_int i;
+
+ if (privsep_process != PROC_PARENT)
+ return;
+
+ for (i = 0; i < PROC_MAX; i++) {
+ if (ps->ps_pid[i] == 0)
+ continue;
+ kill(ps->ps_pid[i], SIGTERM);
+ }
+
+ do {
+ pid = waitpid(WAIT_ANY, NULL, 0);
+ } while (pid != -1 || (pid == -1 && errno == EINTR));
+}
+
+void
+proc_setup(struct privsep *ps)
+{
+ 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);
+ }
+}
+
+void
+proc_config(struct privsep *ps, struct privsep_proc *p, u_int nproc)
+{
+ u_int src, dst, i, j, k, found;
+
+ src = privsep_process;
+
+ /*
+ * 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;
+ }
+ }
+ }
+ }
+
+ /*
+ * 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);
+ }
+}
+
+void
+proc_shutdown(struct privsep_proc *p)
+{
+ struct privsep *ps = p->p_ps;
+ struct control_sock *rcs;
+
+ if (p->p_shutdown != NULL)
+ (p->p_shutdown)(ps, p);
+
+ if (p->p_id == PROC_CONTROL && ps) {
+ control_cleanup(&ps->ps_csock);
+ while ((rcs = TAILQ_FIRST(&ps->ps_rcsocks)) != NULL) {
+ TAILQ_REMOVE(&ps->ps_rcsocks, rcs, cs_entry);
+ control_cleanup(rcs);
+ free(rcs);
+ }
+ }
+
+ log_info("%s exiting", p->p_title);
+ _exit(0);
+}
+
+void
+proc_sig_handler(int sig, short event, void *arg)
+{
+ struct privsep_proc *p = arg;
+
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ proc_shutdown(p);
+ break;
+ case SIGCHLD:
+ case SIGHUP:
+ case SIGPIPE:
+ /* ignore */
+ break;
+ default:
+ fatalx("proc_sig_handler: unexpected signal");
+ /* NOTREACHED */
+ }
+}
+
+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)
+{
+ pid_t pid;
+ struct passwd *pw;
+ const char *root;
+ u_int32_t seed[256];
+ struct control_sock *rcs;
+
+ switch (pid = fork()) {
+ case -1:
+ fatal("proc_run: cannot fork");
+ case 0:
+ break;
+ default:
+ return (pid);
+ }
+
+ pw = ps->ps_pw;
+
+ if (p->p_id == PROC_CONTROL) {
+ if (control_init(ps, &ps->ps_csock) == -1)
+ fatalx(p->p_title);
+ TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
+ if (control_init(ps, rcs) == -1)
+ fatalx(p->p_title);
+ }
+
+ /* Change root directory */
+ if (p->p_chroot != NULL)
+ root = p->p_chroot;
+ else
+ root = pw->pw_dir;
+
+#ifndef DEBUG
+ if (chroot(root) == -1)
+ fatal("proc_run: chroot");
+ if (chdir("/") == -1)
+ fatal("proc_run: chdir(\"/\")");
+#else
+#warning disabling privilege revocation and chroot in DEBUG MODE
+ if (p->p_chroot != NULL) {
+ if (chroot(root) == -1)
+ fatal("proc_run: chroot");
+ if (chdir("/") == -1)
+ fatal("proc_run: chdir(\"/\")");
+ }
+#endif
+
+ privsep_process = p->p_id;
+
+ setproctitle("%s", p->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("proc_run: cannot drop privileges");
+#endif
+
+ event_init();
+
+ signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p);
+ signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p);
+ signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p);
+ signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p);
+ signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p);
+
+ 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);
+
+ proc_config(ps, procs, nproc);
+
+ arc4random_buf(seed, sizeof(seed));
+ RAND_seed(seed, sizeof(seed));
+
+ if (p->p_id == PROC_CONTROL) {
+ TAILQ_INIT(&ctl_conns);
+ if (control_listen(&ps->ps_csock) == -1)
+ fatalx(p->p_title);
+ TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
+ if (control_listen(rcs) == -1)
+ fatalx(p->p_title);
+
+ }
+
+ if (init != NULL)
+ init(ps, arg);
+
+ event_dispatch();
+
+ proc_shutdown(p);
+
+ return (0);
+}
+
+void
+proc_dispatch(int fd, short event, void *arg)
+{
+ struct privsep_proc *p = (struct privsep_proc *)arg;
+ struct privsep *ps = p->p_ps;
+ struct imsgev *iev;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ ssize_t n;
+ int verbose;
+ const char *title;
+
+ title = ps->ps_title[privsep_process];
+ iev = &ps->ps_ievs[p->p_id];
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsg_read(ibuf)) == -1)
+ fatal(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(title);
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal(title);
+ if (n == 0)
+ break;
+
+ /*
+ * Check the message with the program callback
+ */
+ if ((p->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->p_title,
+ imsg.hdr.type);
+ fatalx(title);
+ }
+ imsg_free(&imsg);
+ }
+ imsg_event_add(iev);
+}
+
+void
+imsg_event_add(struct imsgev *iev)
+{
+ if (iev->handler == NULL) {
+ imsg_flush(&iev->ibuf);
+ return;
+ }
+
+ iev->events = EV_READ;
+ if (iev->ibuf.w.queued)
+ iev->events |= EV_WRITE;
+
+ event_del(&iev->ev);
+ event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
+ event_add(&iev->ev, NULL);
+}
+
+int
+imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid,
+ pid_t pid, int fd, void *data, u_int16_t datalen)
+{
+ int ret;
+
+ if ((ret = imsg_compose(&iev->ibuf, type, peerid,
+ pid, fd, data, datalen)) == -1)
+ return (ret);
+ imsg_event_add(iev);
+ return (ret);
+}
+
+int
+imsg_composev_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid,
+ pid_t pid, int fd, const struct iovec *iov, int iovcnt)
+{
+ int ret;
+
+ if ((ret = imsg_composev(&iev->ibuf, type, peerid,
+ pid, fd, iov, iovcnt)) == -1)
+ return (ret);
+ imsg_event_add(iev);
+ return (ret);
+}
+
+int
+proc_compose_imsg(struct privsep *ps, enum privsep_procid id,
+ u_int16_t type, int fd, void *data, u_int16_t datalen)
+{
+ return (imsg_compose_event(&ps->ps_ievs[id],
+ type, -1, 0, fd, data, datalen));
+}
+
+int
+proc_composev_imsg(struct privsep *ps, enum privsep_procid id,
+ u_int16_t type, int fd, const struct iovec *iov, int iovcnt)
+{
+ return (imsg_composev_event(&ps->ps_ievs[id],
+ type, -1, 0, fd, iov, iovcnt));
+}
+
+int
+proc_forward_imsg(struct privsep *ps, struct imsg *imsg,
+ enum privsep_procid id)
+{
+ return (proc_compose_imsg(ps, id, imsg->hdr.type,
+ imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg)));
+}
+
+void
+proc_flush_imsg(struct privsep *ps, enum privsep_procid id)
+{
+ imsg_flush(&ps->ps_ievs[id].ibuf);
+}
diff --git a/usr.sbin/snmpd/snmpd.c b/usr.sbin/snmpd/snmpd.c
index 2392ea67b0e..07a116a76bd 100644
--- a/usr.sbin/snmpd/snmpd.c
+++ b/usr.sbin/snmpd/snmpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmpd.c,v 1.17 2013/10/16 21:15:33 jmc Exp $ */
+/* $OpenBSD: snmpd.c,v 1.18 2013/10/17 08:42:44 reyk Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -34,6 +34,7 @@
#include <event.h>
#include <signal.h>
#include <unistd.h>
+#include <fcntl.h>
#include <pwd.h>
#include "snmpd.h"
@@ -41,23 +42,24 @@
__dead void usage(void);
-void snmpd_sig_handler(int, short, void *);
-void snmpd_shutdown(struct snmpd *);
-void snmpd_dispatch_snmpe(int, short, void *);
-int check_child(pid_t, const char *);
-void snmpd_generate_engineid(struct snmpd *);
+void snmpd_shutdown(struct snmpd *);
+void snmpd_sig_handler(int, short, void *);
+int snmpd_dispatch_snmpe(int, struct privsep_proc *, struct imsg *);
+void snmpd_generate_engineid(struct snmpd *);
+int check_child(pid_t, const char *);
struct snmpd *snmpd_env;
-int pipe_parent2snmpe[2];
-struct imsgev *iev_snmpe;
-pid_t snmpe_pid = 0;
+static struct privsep_proc procs[] = {
+ { "snmpe", PROC_SNMPE, snmpd_dispatch_snmpe, snmpe, snmpe_shutdown }
+};
void
snmpd_sig_handler(int sig, short event, void *arg)
{
- struct snmpd *env = arg;
- int die = 0;
+ struct privsep *ps = arg;
+ struct snmpd *env = ps->ps_env;
+ int die = 0, id;
switch (sig) {
case SIGTERM:
@@ -65,9 +67,10 @@ snmpd_sig_handler(int sig, short event, void *arg)
die = 1;
/* FALLTHROUGH */
case SIGCHLD:
- if (check_child(snmpe_pid, "snmp engine")) {
- snmpe_pid = 0;
- die = 1;
+ for (id = 0; id < PROC_MAX; id++) {
+ if (check_child(ps->ps_pid[id],
+ ps->ps_title[id]))
+ die = 1;
}
if (die)
snmpd_shutdown(env);
@@ -94,25 +97,21 @@ usage(void)
int
main(int argc, char *argv[])
{
- int c;
- struct snmpd *env;
- struct event ev_sigint;
- struct event ev_sigterm;
- struct event ev_sigchld;
- struct event ev_sighup;
- int debug = 0;
- u_int flags = 0;
- int noaction = 0;
- const char *conffile = CONF_FILE;
+ int c;
+ struct snmpd *env;
+ int debug = 0, verbose = 0;
+ u_int flags = 0;
+ int noaction = 0;
+ const char *conffile = CONF_FILE;
+ struct privsep *ps;
smi_init();
-
log_init(1); /* log to stderr until daemonized */
while ((c = getopt(argc, argv, "dD:nNf:v")) != -1) {
switch (c) {
case 'd':
- debug = 1;
+ debug++;
break;
case 'D':
if (cmdline_symset(optarg) < 0)
@@ -129,6 +128,7 @@ main(int argc, char *argv[])
conffile = optarg;
break;
case 'v':
+ verbose++;
flags |= SNMPD_F_VERBOSE;
break;
default:
@@ -143,6 +143,9 @@ main(int argc, char *argv[])
if ((env = parse_config(conffile, flags)) == NULL)
exit(1);
+
+ ps = &env->sc_ps;
+ ps->ps_env = env;
snmpd_env = env;
if (noaction) {
@@ -153,87 +156,56 @@ main(int argc, char *argv[])
if (geteuid())
errx(1, "need root privileges");
- if (getpwnam(SNMPD_USER) == NULL)
+ if ((ps->ps_pw = getpwnam(SNMPD_USER)) == NULL)
errx(1, "unknown user %s", SNMPD_USER);
log_init(debug);
+ log_verbose(verbose);
- if (!debug) {
- if (daemon(1, 0) == -1)
- err(1, "failed to daemonize");
- }
+ if (!debug && daemon(0, 0) == -1)
+ err(1, "failed to daemonize");
gettimeofday(&env->sc_starttime, NULL);
env->sc_engine_boots = 0;
- log_info("startup");
-
pf_init();
-
- if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
- pipe_parent2snmpe) == -1)
- fatal("socketpair");
-
- session_socket_blockmode(pipe_parent2snmpe[0], BM_NONBLOCK);
- session_socket_blockmode(pipe_parent2snmpe[1], BM_NONBLOCK);
-
snmpd_generate_engineid(env);
- snmpe_pid = snmpe(env, pipe_parent2snmpe);
+ proc_init(ps, procs, nitems(procs));
+
setproctitle("parent");
+ log_info("startup");
event_init();
- signal_set(&ev_sigint, SIGINT, snmpd_sig_handler, env);
- signal_set(&ev_sigterm, SIGTERM, snmpd_sig_handler, env);
- signal_set(&ev_sigchld, SIGCHLD, snmpd_sig_handler, env);
- signal_set(&ev_sighup, SIGHUP, snmpd_sig_handler, env);
- signal_add(&ev_sigint, NULL);
- signal_add(&ev_sigterm, NULL);
- signal_add(&ev_sigchld, NULL);
- signal_add(&ev_sighup, NULL);
- signal(SIGPIPE, SIG_IGN);
+ signal_set(&ps->ps_evsigint, SIGINT, snmpd_sig_handler, ps);
+ signal_set(&ps->ps_evsigterm, SIGTERM, snmpd_sig_handler, ps);
+ signal_set(&ps->ps_evsigchld, SIGCHLD, snmpd_sig_handler, ps);
+ signal_set(&ps->ps_evsighup, SIGHUP, snmpd_sig_handler, ps);
+ signal_set(&ps->ps_evsigpipe, SIGPIPE, snmpd_sig_handler, ps);
- close(pipe_parent2snmpe[1]);
+ 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);
- if ((iev_snmpe = calloc(1, sizeof(struct imsgev))) == NULL)
- fatal(NULL);
-
- imsg_init(&iev_snmpe->ibuf, pipe_parent2snmpe[0]);
- iev_snmpe->handler = snmpd_dispatch_snmpe;
- iev_snmpe->data = iev_snmpe;
-
- iev_snmpe->events = EV_READ;
- event_set(&iev_snmpe->ev, iev_snmpe->ibuf.fd, iev_snmpe->events,
- iev_snmpe->handler, iev_snmpe);
- event_add(&iev_snmpe->ev, NULL);
+ proc_config(ps, procs, nitems(procs));
event_dispatch();
+ log_debug("%d parent exiting", getpid());
+
return (0);
}
void
snmpd_shutdown(struct snmpd *env)
{
- struct control_sock *rcs;
- pid_t pid;
-
- if (snmpe_pid)
- kill(snmpe_pid, SIGTERM);
-
- do {
- if ((pid = wait(NULL)) == -1 &&
- errno != EINTR && errno != ECHILD)
- fatal("wait");
- } while (pid != -1 || (pid == -1 && errno == EINTR));
-
- control_cleanup(&env->sc_csock);
- while ((rcs = TAILQ_FIRST(&env->sc_rcsocks)) != NULL) {
- TAILQ_REMOVE(&env->sc_rcsocks, rcs, cs_entry);
- control_cleanup(rcs);
- free(rcs);
- }
+ proc_kill(&env->sc_ps);
+
+ free(env);
+
log_info("terminating");
exit(0);
}
@@ -258,63 +230,17 @@ check_child(pid_t pid, const char *pname)
return (0);
}
-void
-imsg_event_add(struct imsgev *iev)
-{
- iev->events = EV_READ;
- if (iev->ibuf.w.queued)
- iev->events |= EV_WRITE;
-
- event_del(&iev->ev);
- event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
- event_add(&iev->ev, NULL);
-}
-
-void
-snmpd_dispatch_snmpe(int fd, short event, void * ptr)
+int
+snmpd_dispatch_snmpe(int fd, struct privsep_proc *p, struct imsg *imsg)
{
- struct imsgev *iev;
- struct imsgbuf *ibuf;
- struct imsg imsg;
- ssize_t n;
-
- iev = ptr;
- ibuf = &iev->ibuf;
- switch (event) {
- case EV_READ:
- if ((n = imsg_read(ibuf)) == -1)
- fatal("imsg_read error");
- if (n == 0) {
- /* this pipe is dead, so remove the event handler */
- event_del(&iev->ev);
- event_loopexit(NULL);
- return;
- }
- break;
- case EV_WRITE:
- if (msgbuf_write(&ibuf->w) == -1)
- fatal("msgbuf_write");
- imsg_event_add(iev);
- return;
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_RELOAD:
+ /* XXX notyet */
default:
- fatalx("unknown event");
+ break;
}
- for (;;) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- fatal("snmpd_dispatch_relay: imsg_read error");
- if (n == 0)
- break;
-
- switch (imsg.hdr.type) {
- default:
- log_debug("snmpd_dispatch_relay: unexpected imsg %d",
- imsg.hdr.type);
- break;
- }
- imsg_free(&imsg);
- }
- imsg_event_add(iev);
+ return (-1);
}
int
@@ -396,3 +322,20 @@ tohexstr(u_int8_t *str, int len)
*r = '\0';
return hstr;
}
+
+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/usr.sbin/snmpd/snmpd.h b/usr.sbin/snmpd/snmpd.h
index e598ed0d268..6a84df3bd06 100644
--- a/usr.sbin/snmpd/snmpd.h
+++ b/usr.sbin/snmpd/snmpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmpd.h,v 1.46 2013/10/16 16:05:03 blambert Exp $ */
+/* $OpenBSD: snmpd.h,v 1.47 2013/10/17 08:42:44 reyk Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -73,13 +73,25 @@ enum imsg_type {
IMSG_CTL_OK, /* answer to snmpctl requests */
IMSG_CTL_FAIL,
IMSG_CTL_END,
- IMSG_CTL_NOTIFY
+ IMSG_CTL_NOTIFY,
+ IMSG_CTL_VERBOSE,
+ IMSG_CTL_RELOAD
};
-enum {
- PROC_PARENT, /* Parent process and application interface */
- PROC_SNMPE /* SNMP engine */
-} snmpd_process;
+struct imsgev {
+ struct imsgbuf ibuf;
+ void (*handler)(int, short, void *);
+ struct event ev;
+ void *data;
+ short events;
+ const char *name;
+};
+
+#define IMSG_SIZE_CHECK(imsg, p) do { \
+ if (IMSG_DATA_SIZE(imsg) < sizeof(*p)) \
+ fatalx("bad length imsg received"); \
+} while (0)
+#define IMSG_DATA_SIZE(imsg) ((imsg)->hdr.len - IMSG_HEADER_SIZE)
/* initially control.h */
struct control_sock {
@@ -88,24 +100,62 @@ struct control_sock {
struct event cs_evt;
int cs_fd;
int cs_restricted;
+ void *cs_env;
TAILQ_ENTRY(control_sock) cs_entry;
};
TAILQ_HEAD(control_socks, control_sock);
+enum privsep_procid {
+ PROC_PARENT, /* Parent process and application interface */
+ PROC_SNMPE, /* SNMP engine */
+ PROC_MAX
+};
+
+enum privsep_procid privsep_process;
+
+/* Attach the control socket to the following process */
+#define PROC_CONTROL PROC_SNMPE
+
+struct privsep {
+ int ps_pipes[PROC_MAX][PROC_MAX];
+ struct imsgev ps_ievs[PROC_MAX];
+ const char *ps_title[PROC_MAX];
+ pid_t ps_pid[PROC_MAX];
+ struct passwd *ps_pw;
+
+ struct control_sock ps_csock;
+ struct control_socks ps_rcsocks;
+
+ /* Event and signal handlers */
+ struct event ps_evsigint;
+ struct event ps_evsigterm;
+ struct event ps_evsigchld;
+ struct event ps_evsighup;
+ struct event ps_evsigpipe;
+
+ void *ps_env;
+};
+
+struct privsep_proc {
+ const char *p_title;
+ enum privsep_procid p_id;
+ int (*p_cb)(int, struct privsep_proc *,
+ struct imsg *);
+ pid_t (*p_init)(struct privsep *,
+ struct privsep_proc *);
+ void (*p_shutdown)(struct privsep *,
+ struct privsep_proc *);
+ const char *p_chroot;
+ struct privsep *p_ps;
+ void *p_env;
+};
+
enum blockmodes {
BM_NORMAL,
BM_NONBLOCK
};
-struct imsgev {
- struct imsgbuf ibuf;
- void (*handler)(int, short, void *);
- struct event ev;
- void *data;
- short events;
-};
-
struct ctl_conn {
TAILQ_ENTRY(ctl_conn) entry;
u_int8_t flags;
@@ -406,9 +456,6 @@ struct snmpd {
struct timeval sc_starttime;
u_int32_t sc_engine_boots;
- struct control_sock sc_csock;
- struct control_socks sc_rcsocks;
-
char sc_rdcommunity[SNMPD_MAXCOMMUNITYLEN];
char sc_rwcommunity[SNMPD_MAXCOMMUNITYLEN];
char sc_trcommunity[SNMPD_MAXCOMMUNITYLEN];
@@ -426,17 +473,16 @@ struct snmpd {
int sc_min_seclevel;
int sc_readonly;
+
+ struct privsep sc_ps;
};
/* control.c */
-int control_init(struct control_sock *);
+int control_init(struct privsep *, struct control_sock *);
int control_listen(struct control_sock *);
-void control_accept(int, short, void *);
-void control_dispatch_imsg(int, short, void *);
-void control_imsg_forward(struct imsg *);
void control_cleanup(struct control_sock *);
-void session_socket_blockmode(int, enum blockmodes);
+void socket_set_blockmode(int, enum blockmodes);
/* parse.y */
struct snmpd *parse_config(const char *, u_int);
@@ -444,20 +490,19 @@ int cmdline_symset(char *);
/* log.c */
void log_init(int);
+void log_verbose(int);
void log_warn(const char *, ...);
void log_warnx(const char *, ...);
void log_info(const char *, ...);
void log_debug(const char *, ...);
+void print_debug(const char *, ...);
+void print_verbose(const char *, ...);
__dead void fatal(const char *);
__dead void fatalx(const char *);
void vlog(int, const char *, va_list);
const char *log_in6addr(const struct in6_addr *);
const char *print_host(struct sockaddr_storage *, char *, size_t);
-void imsg_event_add(struct imsgev *);
-int imsg_compose_event(struct imsgev *, enum imsg_type, u_int32_t,
- pid_t, int, void *, u_int16_t);
-
/* kroute.c */
void kr_init(void);
void kr_shutdown(void);
@@ -476,7 +521,8 @@ struct kroute *kroute_first(void);
struct kroute *kroute_getaddr(in_addr_t, u_int8_t, u_int8_t, int);
/* snmpe.c */
-pid_t snmpe(struct snmpd *, int [2]);
+pid_t snmpe(struct privsep *, struct privsep_proc *);
+void snmpe_shutdown(struct privsep *, struct privsep_proc *);
/* trap.c */
void trap_init(void);
@@ -564,4 +610,25 @@ struct ber_element *usm_encode(struct snmp_message *, struct ber_element *);
struct ber_element *usm_encrypt(struct snmp_message *, struct ber_element *);
void usm_finalize_digest(struct snmp_message *, char *, ssize_t);
void usm_make_report(struct snmp_message *);
+
+/* 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_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 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 privsep *, enum privsep_procid,
+ u_int16_t, int, void *, u_int16_t);
+int proc_composev_imsg(struct privsep *, enum privsep_procid,
+ u_int16_t, int, const struct iovec *, int);
+int proc_forward_imsg(struct privsep *, struct imsg *,
+ enum privsep_procid);
+void proc_flush_imsg(struct privsep *, enum privsep_procid);
#endif /* _SNMPD_H */
diff --git a/usr.sbin/snmpd/snmpe.c b/usr.sbin/snmpd/snmpe.c
index 81395d4c7e6..ba6e22dcca7 100644
--- a/usr.sbin/snmpd/snmpe.c
+++ b/usr.sbin/snmpd/snmpe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmpe.c,v 1.36 2013/10/16 16:05:03 blambert Exp $ */
+/* $OpenBSD: snmpe.c,v 1.37 2013/10/17 08:42:44 reyk Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -40,13 +40,13 @@
#include "snmpd.h"
#include "mib.h"
+void snmpe_init(struct privsep *, void *);
int snmpe_parse(struct sockaddr_storage *,
struct ber_element *, struct snmp_message *);
unsigned long
snmpe_application(struct ber_element *);
void snmpe_sig_handler(int sig, short, void *);
-void snmpe_shutdown(void);
-void snmpe_dispatch_parent(int, short, void *);
+int snmpe_dispatch_parent(int, struct privsep_proc *, struct imsg *);
int snmpe_bind(struct address *);
void snmpe_recvmsg(int fd, short, void *);
int snmpe_encode(struct snmp_message *);
@@ -55,182 +55,64 @@ struct snmpd *env = NULL;
struct imsgev *iev_parent;
-void
-snmpe_sig_handler(int sig, short event, void *arg)
-{
- switch (sig) {
- case SIGINT:
- case SIGTERM:
- snmpe_shutdown();
- break;
- default:
- fatalx("snmpe_sig_handler: unexpected signal");
- }
-}
+static struct privsep_proc procs[] = {
+ { "parent", PROC_PARENT, snmpe_dispatch_parent }
+};
pid_t
-snmpe(struct snmpd *x_env, int pipe_parent2snmpe[2])
+snmpe(struct privsep *ps, struct privsep_proc *p)
{
- pid_t pid;
- struct passwd *pw;
- struct event ev_sigint;
- struct event ev_sigterm;
- struct control_sock *rcs;
#ifdef DEBUG
+ char buf[BUFSIZ];
struct oid *oid;
#endif
- switch (pid = fork()) {
- case -1:
- fatal("snmpe: cannot fork");
- case 0:
- break;
- default:
- return (pid);
- }
-
- env = x_env;
-
- if (control_init(&env->sc_csock) == -1)
- fatalx("snmpe: control socket setup failed");
- TAILQ_FOREACH(rcs, &env->sc_rcsocks, cs_entry)
- if (control_init(rcs) == -1)
- fatalx("snmpe: restricted control socket setup failed");
-
- if ((env->sc_sock = snmpe_bind(&env->sc_address)) == -1)
- fatalx("snmpe: failed to bind SNMP UDP socket");
-
- if ((pw = getpwnam(SNMPD_USER)) == NULL)
- fatal("snmpe: getpwnam");
-
-#ifndef DEBUG
- if (chroot(pw->pw_dir) == -1)
- fatal("snmpe: chroot");
- if (chdir("/") == -1)
- fatal("snmpe: chdir(\"/\")");
-#else
-#warning disabling privilege revocation and chroot in DEBUG mode
-#endif
-
- setproctitle("snmp engine");
- snmpd_process = PROC_SNMPE;
-
-#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("snmpe: cannot drop privileges");
-#endif
+ env = ps->ps_env;
#ifdef DEBUG
for (oid = NULL; (oid = smi_foreach(oid, 0)) != NULL;) {
- char buf[BUFSIZ];
smi_oid2string(&oid->o_id, buf, sizeof(buf), 0);
log_debug("oid %s", buf);
}
#endif
- event_init();
-
- signal_set(&ev_sigint, SIGINT, snmpe_sig_handler, NULL);
- signal_set(&ev_sigterm, SIGTERM, snmpe_sig_handler, NULL);
- signal_add(&ev_sigint, NULL);
- signal_add(&ev_sigterm, NULL);
- signal(SIGPIPE, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
-
- close(pipe_parent2snmpe[0]);
-
- if ((iev_parent = calloc(1, sizeof(struct imsgev))) == NULL)
- fatal("snmpe");
-
- imsg_init(&iev_parent->ibuf, pipe_parent2snmpe[1]);
- iev_parent->handler = snmpe_dispatch_parent;
- iev_parent->data = iev_parent;
-
- iev_parent->events = EV_READ;
- event_set(&iev_parent->ev, iev_parent->ibuf.fd, iev_parent->events,
- iev_parent->handler, iev_parent);
- event_add(&iev_parent->ev, NULL);
-
- TAILQ_INIT(&ctl_conns);
-
- if (control_listen(&env->sc_csock) == -1)
- fatalx("snmpe: control socket listen failed");
- TAILQ_FOREACH(rcs, &env->sc_rcsocks, cs_entry)
- if (control_listen(rcs) == -1)
- fatalx("snmpe: restricted control socket listen failed");
+ /* bind SNMP UDP socket */
+ if ((env->sc_sock = snmpe_bind(&env->sc_address)) == -1)
+ fatalx("snmpe: failed to bind SNMP UDP socket");
- event_set(&env->sc_ev, env->sc_sock, EV_READ|EV_PERSIST,
- snmpe_recvmsg, env);
- event_add(&env->sc_ev, NULL);
+ return (proc_run(ps, p, procs, nitems(procs), snmpe_init, NULL));
+}
+/* ARGSUSED */
+void
+snmpe_init(struct privsep *p, void *arg)
+{
kr_init();
trap_init();
timer_init();
-
usm_generate_keys();
- event_dispatch();
-
- snmpe_shutdown();
- kr_shutdown();
-
- return (0);
+ /* listen for incoming SNMP UDP messages */
+ event_set(&env->sc_ev, env->sc_sock, EV_READ|EV_PERSIST,
+ snmpe_recvmsg, env);
+ event_add(&env->sc_ev, NULL);
}
void
-snmpe_shutdown(void)
+snmpe_shutdown(struct privsep *ps, struct privsep_proc *p)
{
- log_info("snmp engine exiting");
- _exit(0);
+ kr_shutdown();
}
-void
-snmpe_dispatch_parent(int fd, short event, void * ptr)
+int
+snmpe_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
{
- struct imsgev *iev;
- struct imsgbuf *ibuf;
- struct imsg imsg;
- ssize_t n;
-
- iev = ptr;
- ibuf = &iev->ibuf;
- switch (event) {
- case EV_READ:
- if ((n = imsg_read(ibuf)) == -1)
- fatal("imsg_read error");
- if (n == 0) {
- /* this pipe is dead, so remove the event handler */
- event_del(&iev->ev);
- event_loopexit(NULL);
- return;
- }
- break;
- case EV_WRITE:
- if (msgbuf_write(&ibuf->w) == -1)
- fatal("msgbuf_write");
- imsg_event_add(iev);
- return;
+ switch (imsg->hdr.type) {
default:
- fatalx("snmpe_dispatch_parent: unknown event");
+ break;
}
- for (;;) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- fatal("snmpe_dispatch_parent: imsg_read error");
- if (n == 0)
- break;
-
- switch (imsg.hdr.type) {
- default:
- log_debug("snmpe_dispatch_parent: unexpected imsg %d",
- imsg.hdr.type);
- break;
- }
- imsg_free(&imsg);
- }
- imsg_event_add(iev);
+ return (-1);
}
int