diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2013-10-17 08:42:45 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2013-10-17 08:42:45 +0000 |
commit | e113d10070344c2a43cad66b9440395e7b3267db (patch) | |
tree | 03e01ae4527811a56a5c2204b8b8e97f6f2ff33d /usr.sbin | |
parent | f2d6fc8fc8eab2639590bae761a2dbbb921cfb4f (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/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/snmpd/control.c | 98 | ||||
-rw-r--r-- | usr.sbin/snmpd/log.c | 39 | ||||
-rw-r--r-- | usr.sbin/snmpd/parse.y | 12 | ||||
-rw-r--r-- | usr.sbin/snmpd/proc.c | 443 | ||||
-rw-r--r-- | usr.sbin/snmpd/snmpd.c | 211 | ||||
-rw-r--r-- | usr.sbin/snmpd/snmpd.h | 121 | ||||
-rw-r--r-- | usr.sbin/snmpd/snmpe.c | 176 |
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 |