From 3136fbbe0327f4dade00903cdb65ca05b029dd32 Mon Sep 17 00:00:00 2001 From: Gilles Chehade Date: Mon, 15 May 2017 09:39:01 +0200 Subject: [PATCH 01/41] skeleton for smtpfd --- extras/filters/smtpfd/Makefile | 17 + extras/filters/smtpfd/control.c | 306 +++++++++ extras/filters/smtpfd/control.h | 35 + extras/filters/smtpfd/engine.c | 340 ++++++++++ extras/filters/smtpfd/engine.h | 20 + extras/filters/smtpfd/frontend.c | 324 +++++++++ extras/filters/smtpfd/frontend.h | 27 + extras/filters/smtpfd/log.c | 199 ++++++ extras/filters/smtpfd/log.h | 46 ++ extras/filters/smtpfd/parse.y | 765 ++++++++++++++++++++++ extras/filters/smtpfd/printconf.c | 64 ++ extras/filters/smtpfd/smtpfd.8 | 91 +++ extras/filters/smtpfd/smtpfd.c | 635 ++++++++++++++++++ extras/filters/smtpfd/smtpfd.conf.5 | 137 ++++ extras/filters/smtpfd/smtpfd.conf.example | 18 + extras/filters/smtpfd/smtpfd.h | 120 ++++ 16 files changed, 3144 insertions(+) create mode 100644 extras/filters/smtpfd/Makefile create mode 100644 extras/filters/smtpfd/control.c create mode 100644 extras/filters/smtpfd/control.h create mode 100644 extras/filters/smtpfd/engine.c create mode 100644 extras/filters/smtpfd/engine.h create mode 100644 extras/filters/smtpfd/frontend.c create mode 100644 extras/filters/smtpfd/frontend.h create mode 100644 extras/filters/smtpfd/log.c create mode 100644 extras/filters/smtpfd/log.h create mode 100644 extras/filters/smtpfd/parse.y create mode 100644 extras/filters/smtpfd/printconf.c create mode 100644 extras/filters/smtpfd/smtpfd.8 create mode 100644 extras/filters/smtpfd/smtpfd.c create mode 100644 extras/filters/smtpfd/smtpfd.conf.5 create mode 100644 extras/filters/smtpfd/smtpfd.conf.example create mode 100644 extras/filters/smtpfd/smtpfd.h diff --git a/extras/filters/smtpfd/Makefile b/extras/filters/smtpfd/Makefile new file mode 100644 index 0000000..61658fd --- /dev/null +++ b/extras/filters/smtpfd/Makefile @@ -0,0 +1,17 @@ +# $OpenBSD$ + +PROG= smtpfd +SRCS= control.c engine.c frontend.c log.c smtpfd.c parse.y printconf.c + +MAN= smtpfd.8 smtpfd.conf.5 + +CFLAGS+= -Wall -I${.CURDIR} +CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes +CFLAGS+= -Wmissing-declarations +CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual +CFLAGS+= -Wsign-compare +YFLAGS= +LDADD+= -levent -lutil +DPADD+= ${LIBEVENT} ${LIBUTIL} + +.include diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c new file mode 100644 index 0000000..cc49058 --- /dev/null +++ b/extras/filters/smtpfd/control.c @@ -0,0 +1,306 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * 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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "smtpfd.h" +#include "control.h" +#include "frontend.h" + +#define CONTROL_BACKLOG 5 + +struct ctl_conn *control_connbyfd(int); +struct ctl_conn *control_connbypid(pid_t); +void control_close(int); + +int +control_init(char *path) +{ + struct sockaddr_un sun; + int fd; + mode_t old_umask; + + if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + 0)) == -1) { + log_warn("%s: socket", __func__); + return (-1); + } + + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); + + if (unlink(path) == -1) + if (errno != ENOENT) { + log_warn("%s: unlink %s", __func__, path); + close(fd); + return (-1); + } + + old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); + if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { + log_warn("%s: bind: %s", __func__, path); + close(fd); + umask(old_umask); + return (-1); + } + umask(old_umask); + + if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { + log_warn("%s: chmod", __func__); + close(fd); + (void)unlink(path); + return (-1); + } + + control_state.fd = fd; + + return (0); +} + +int +control_listen(void) +{ + + if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { + log_warn("%s: listen", __func__); + return (-1); + } + + event_set(&control_state.ev, control_state.fd, EV_READ, + control_accept, NULL); + event_add(&control_state.ev, NULL); + evtimer_set(&control_state.evt, control_accept, NULL); + + return (0); +} + +void +control_cleanup(char *path) +{ + if (path == NULL) + return; + event_del(&control_state.ev); + event_del(&control_state.evt); + unlink(path); +} + +void +control_accept(int listenfd, short event, void *bula) +{ + int connfd; + socklen_t len; + struct sockaddr_un sun; + struct ctl_conn *c; + + event_add(&control_state.ev, NULL); + if ((event & EV_TIMEOUT)) + return; + + len = sizeof(sun); + if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len, + SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) { + /* + * Pause accept if we are out of file descriptors, or + * libevent will haunt us here too. + */ + if (errno == ENFILE || errno == EMFILE) { + struct timeval evtpause = { 1, 0 }; + + event_del(&control_state.ev); + evtimer_add(&control_state.evt, &evtpause); + } else if (errno != EWOULDBLOCK && errno != EINTR && + errno != ECONNABORTED) + log_warn("%s: accept4", __func__); + return; + } + + if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { + log_warn("%s: calloc", __func__); + close(connfd); + return; + } + + imsg_init(&c->iev.ibuf, connfd); + c->iev.handler = control_dispatch_imsg; + c->iev.events = EV_READ; + event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, + c->iev.handler, &c->iev); + event_add(&c->iev.ev, NULL); + + TAILQ_INSERT_TAIL(&ctl_conns, c, entry); +} + +struct ctl_conn * +control_connbyfd(int fd) +{ + struct ctl_conn *c; + + TAILQ_FOREACH(c, &ctl_conns, entry) { + if (c->iev.ibuf.fd == fd) + break; + } + + return (c); +} + +struct ctl_conn * +control_connbypid(pid_t pid) +{ + struct ctl_conn *c; + + TAILQ_FOREACH(c, &ctl_conns, entry) { + if (c->iev.ibuf.pid == pid) + break; + } + + return (c); +} + +void +control_close(int fd) +{ + struct ctl_conn *c; + + if ((c = control_connbyfd(fd)) == NULL) { + log_warnx("%s: fd %d: not found", __func__, fd); + return; + } + + msgbuf_clear(&c->iev.ibuf.w); + TAILQ_REMOVE(&ctl_conns, c, entry); + + event_del(&c->iev.ev); + close(c->iev.ibuf.fd); + + /* Some file descriptors are available again. */ + if (evtimer_pending(&control_state.evt, NULL)) { + evtimer_del(&control_state.evt); + event_add(&control_state.ev, NULL); + } + + free(c); +} + +void +control_dispatch_imsg(int fd, short event, void *bula) +{ + struct ctl_conn *c; + struct imsg imsg; + ssize_t n; + int verbose; + + if ((c = control_connbyfd(fd)) == NULL) { + log_warnx("%s: fd %d: not found", __func__, fd); + return; + } + + if (event & EV_READ) { + if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || + n == 0) { + control_close(fd); + return; + } + } + if (event & EV_WRITE) { + if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { + control_close(fd); + return; + } + } + + for (;;) { + if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { + control_close(fd); + return; + } + if (n == 0) + break; + + switch (imsg.hdr.type) { + case IMSG_CTL_RELOAD: + frontend_imsg_compose_main(imsg.hdr.type, 0, NULL, 0); + break; + case IMSG_CTL_LOG_VERBOSE: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(verbose)) + break; + + /* Forward to all other processes. */ + frontend_imsg_compose_main(imsg.hdr.type, imsg.hdr.pid, + imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); + frontend_imsg_compose_engine(imsg.hdr.type, 0, + imsg.hdr.pid, imsg.data, + imsg.hdr.len - IMSG_HEADER_SIZE); + + memcpy(&verbose, imsg.data, sizeof(verbose)); + log_setverbose(verbose); + break; + case IMSG_CTL_SHOW_MAIN_INFO: + c->iev.ibuf.pid = imsg.hdr.pid; + frontend_imsg_compose_main(imsg.hdr.type, imsg.hdr.pid, + imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); + break; + case IMSG_CTL_SHOW_FRONTEND_INFO: + frontend_showinfo_ctl(c); + imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, + NULL, 0); + break; + case IMSG_CTL_SHOW_ENGINE_INFO: + c->iev.ibuf.pid = imsg.hdr.pid; + frontend_imsg_compose_engine(imsg.hdr.type, 0, + imsg.hdr.pid, + imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); + break; + default: + log_debug("%s: error handling imsg %d", __func__, + imsg.hdr.type); + break; + } + imsg_free(&imsg); + } + + imsg_event_add(&c->iev); +} + +int +control_imsg_relay(struct imsg *imsg) +{ + struct ctl_conn *c; + + if ((c = control_connbypid(imsg->hdr.pid)) == NULL) + return (0); + + return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, + -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); +} diff --git a/extras/filters/smtpfd/control.h b/extras/filters/smtpfd/control.h new file mode 100644 index 0000000..33cf7cb --- /dev/null +++ b/extras/filters/smtpfd/control.h @@ -0,0 +1,35 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * 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. + */ + +struct { + struct event ev; + struct event evt; + int fd; +} control_state; + +struct ctl_conn { + TAILQ_ENTRY(ctl_conn) entry; + struct imsgev iev; +}; + +int control_init(char *); +int control_listen(void); +void control_accept(int, short, void *); +void control_dispatch_imsg(int, short, void *); +int control_imsg_relay(struct imsg *); +void control_cleanup(char *); diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c new file mode 100644 index 0000000..22b1fae --- /dev/null +++ b/extras/filters/smtpfd/engine.c @@ -0,0 +1,340 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2004, 2005 Claudio Jeker + * Copyright (c) 2004 Esben Norby + * Copyright (c) 2003, 2004 Henning Brauer + * + * 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 +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "smtpfd.h" +#include "engine.h" + +__dead void engine_shutdown(void); +void engine_sig_handler(int sig, short, void *); +void engine_dispatch_frontend(int, short, void *); +void engine_dispatch_main(int, short, void *); +void engine_showinfo_ctl(struct imsg *); + +struct newd_conf *engine_conf; +struct imsgev *iev_frontend; +struct imsgev *iev_main; + +void +engine_sig_handler(int sig, short event, void *arg) +{ + /* + * Normal signal handler rules don't apply because libevent + * decouples for us. + */ + + switch (sig) { + case SIGINT: + case SIGTERM: + engine_shutdown(); + default: + fatalx("unexpected signal"); + } +} + +void +engine(int debug, int verbose) +{ + struct event ev_sigint, ev_sigterm; + struct passwd *pw; + + engine_conf = config_new_empty(); + + log_init(debug, LOG_DAEMON); + log_setverbose(verbose); + + if ((pw = getpwnam(SMTPFD_USER)) == NULL) + fatal("getpwnam"); + + if (chroot(pw->pw_dir) == -1) + fatal("chroot"); + if (chdir("/") == -1) + fatal("chdir(\"/\")"); + + newd_process = PROC_ENGINE; + setproctitle(log_procnames[newd_process]); + log_procinit(log_procnames[newd_process]); + + 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("can't drop privileges"); + + if (pledge("stdio recvfd", NULL) == -1) + fatal("pledge"); + + event_init(); + + /* Setup signal handler(s). */ + signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL); + signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL); + signal_add(&ev_sigint, NULL); + signal_add(&ev_sigterm, NULL); + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, SIG_IGN); + + /* Setup pipe and event handler to the main process. */ + if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) + fatal(NULL); + + imsg_init(&iev_main->ibuf, 3); + iev_main->handler = engine_dispatch_main; + + /* Setup event handlers. */ + iev_main->events = EV_READ; + event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, + iev_main->handler, iev_main); + event_add(&iev_main->ev, NULL); + + event_dispatch(); + + engine_shutdown(); +} + +__dead void +engine_shutdown(void) +{ + /* Close pipes. */ + msgbuf_clear(&iev_frontend->ibuf.w); + close(iev_frontend->ibuf.fd); + msgbuf_clear(&iev_main->ibuf.w); + close(iev_main->ibuf.fd); + + config_clear(engine_conf); + + free(iev_frontend); + free(iev_main); + + log_info("engine exiting"); + exit(0); +} + +int +engine_imsg_compose_frontend(int type, pid_t pid, void *data, + uint16_t datalen) +{ + return (imsg_compose_event(iev_frontend, type, 0, pid, -1, + data, datalen)); +} + +void +engine_dispatch_frontend(int fd, short event, void *bula) +{ + struct imsgev *iev = bula; + struct imsgbuf *ibuf; + struct imsg imsg; + ssize_t n; + int shut = 0, verbose; + + ibuf = &iev->ibuf; + + if (event & EV_READ) { + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + if (event & EV_WRITE) { + if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) + fatal("msgbuf_write"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatal("%s: imsg_get error", __func__); + if (n == 0) /* No more messages. */ + break; + + switch (imsg.hdr.type) { + case IMSG_CTL_LOG_VERBOSE: + /* Already checked by frontend. */ + memcpy(&verbose, imsg.data, sizeof(verbose)); + log_setverbose(verbose); + break; + case IMSG_CTL_SHOW_ENGINE_INFO: + engine_showinfo_ctl(&imsg); + break; + default: + log_debug("%s: unexpected imsg %d", __func__, + imsg.hdr.type); + break; + } + imsg_free(&imsg); + } + if (!shut) + imsg_event_add(iev); + else { + /* This pipe is dead. Remove its event handler. */ + event_del(&iev->ev); + event_loopexit(NULL); + } +} + +void +engine_dispatch_main(int fd, short event, void *bula) +{ + static struct newd_conf *nconf; + struct imsg imsg; + struct group *g; + struct imsgev *iev = bula; + struct imsgbuf *ibuf; + ssize_t n; + int shut = 0; + + ibuf = &iev->ibuf; + + if (event & EV_READ) { + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + if (event & EV_WRITE) { + if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) + fatal("msgbuf_write"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatal("%s: imsg_get error", __func__); + if (n == 0) /* No more messages. */ + break; + + switch (imsg.hdr.type) { + case IMSG_SOCKET_IPC: + /* + * Setup pipe and event handler to the frontend + * process. + */ + if (iev_frontend) { + log_warnx("%s: received unexpected imsg fd " + "to engine", __func__); + break; + } + if ((fd = imsg.fd) == -1) { + log_warnx("%s: expected to receive imsg fd to " + "engine but didn't receive any", __func__); + break; + } + + iev_frontend = malloc(sizeof(struct imsgev)); + if (iev_frontend == NULL) + fatal(NULL); + + imsg_init(&iev_frontend->ibuf, fd); + iev_frontend->handler = engine_dispatch_frontend; + iev_frontend->events = EV_READ; + + event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, + iev_frontend->events, iev_frontend->handler, + iev_frontend); + event_add(&iev_frontend->ev, NULL); + break; + case IMSG_RECONF_CONF: + if ((nconf = malloc(sizeof(struct newd_conf))) == NULL) + fatal(NULL); + memcpy(nconf, imsg.data, sizeof(struct newd_conf)); + LIST_INIT(&nconf->group_list); + break; + case IMSG_RECONF_GROUP: + if ((g = malloc(sizeof(struct group))) == NULL) + fatal(NULL); + memcpy(g, imsg.data, sizeof(struct group)); + LIST_INSERT_HEAD(&nconf->group_list, g, entry); + break; + case IMSG_RECONF_END: + merge_config(engine_conf, nconf); + nconf = NULL; + break; + default: + log_debug("%s: unexpected imsg %d", __func__, + imsg.hdr.type); + break; + } + imsg_free(&imsg); + } + if (!shut) + imsg_event_add(iev); + else { + /* This pipe is dead. Remove its event handler. */ + event_del(&iev->ev); + event_loopexit(NULL); + } +} + +void +engine_showinfo_ctl(struct imsg *imsg) +{ + char filter[NEWD_MAXGROUPNAME]; + struct ctl_engine_info cei; + struct group *g; + + switch (imsg->hdr.type) { + case IMSG_CTL_SHOW_ENGINE_INFO: + memcpy(filter, imsg->data, sizeof(filter)); + LIST_FOREACH(g, &engine_conf->group_list, entry) { + if (filter[0] == '\0' || memcmp(filter, g->name, + sizeof(filter)) == 0) { + memcpy(cei.name, g->name, sizeof(cei.name)); + cei.yesno = g->yesno; + cei.integer = g->integer; + cei.group_v4_bits = g->group_v4_bits; + cei.group_v6_bits = g->group_v6_bits; + memcpy(&cei.group_v4address, + &g->group_v4address, + sizeof(cei.group_v4address)); + memcpy(&cei.group_v6address, + &g->group_v6address, + sizeof(cei.group_v6address)); + + engine_imsg_compose_frontend( + IMSG_CTL_SHOW_ENGINE_INFO, imsg->hdr.pid, + &cei, sizeof(cei)); + } + } + engine_imsg_compose_frontend(IMSG_CTL_END, imsg->hdr.pid, NULL, + 0); + break; + default: + log_debug("%s: error handling imsg", __func__); + break; + } +} diff --git a/extras/filters/smtpfd/engine.h b/extras/filters/smtpfd/engine.h new file mode 100644 index 0000000..be86f34 --- /dev/null +++ b/extras/filters/smtpfd/engine.h @@ -0,0 +1,20 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2004, 2005 Esben Norby + * + * 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. + */ + +void engine(int, int); +int engine_imsg_compose_frontend(int, pid_t, void *, uint16_t); diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c new file mode 100644 index 0000000..1498692 --- /dev/null +++ b/extras/filters/smtpfd/frontend.c @@ -0,0 +1,324 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2005 Claudio Jeker + * Copyright (c) 2004 Esben Norby + * Copyright (c) 2003, 2004 Henning Brauer + * + * 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 +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "smtpfd.h" +#include "frontend.h" +#include "control.h" + +__dead void frontend_shutdown(void); +void frontend_sig_handler(int, short, void *); + +struct newd_conf *frontend_conf; +struct imsgev *iev_main; +struct imsgev *iev_engine; + +void +frontend_sig_handler(int sig, short event, void *bula) +{ + /* + * Normal signal handler rules don't apply because libevent + * decouples for us. + */ + + switch (sig) { + case SIGINT: + case SIGTERM: + frontend_shutdown(); + default: + fatalx("unexpected signal"); + } +} + +void +frontend(int debug, int verbose, char *sockname) +{ + struct event ev_sigint, ev_sigterm; + struct passwd *pw; + + frontend_conf = config_new_empty(); + + log_init(debug, LOG_DAEMON); + log_setverbose(verbose); + + /* Create newd control socket outside chroot. */ + if (control_init(sockname) == -1) + fatalx("control socket setup failed"); + + if ((pw = getpwnam(SMTPFD_USER)) == NULL) + fatal("getpwnam"); + + if (chroot(pw->pw_dir) == -1) + fatal("chroot"); + if (chdir("/") == -1) + fatal("chdir(\"/\")"); + + newd_process = PROC_FRONTEND; + setproctitle(log_procnames[newd_process]); + log_procinit(log_procnames[newd_process]); + + 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("can't drop privileges"); + + if (pledge("stdio inet recvfd", NULL) == -1) + fatal("pledge"); + + event_init(); + + /* Setup signal handler. */ + signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL); + signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL); + signal_add(&ev_sigint, NULL); + signal_add(&ev_sigterm, NULL); + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, SIG_IGN); + + /* Setup pipe and event handler to the parent process. */ + if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) + fatal(NULL); + imsg_init(&iev_main->ibuf, 3); + iev_main->handler = frontend_dispatch_main; + iev_main->events = EV_READ; + event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, + iev_main->handler, iev_main); + event_add(&iev_main->ev, NULL); + + /* Listen on control socket. */ + TAILQ_INIT(&ctl_conns); + control_listen(); + + event_dispatch(); + + frontend_shutdown(); +} + +__dead void +frontend_shutdown(void) +{ + /* Close pipes. */ + msgbuf_write(&iev_engine->ibuf.w); + msgbuf_clear(&iev_engine->ibuf.w); + close(iev_engine->ibuf.fd); + msgbuf_write(&iev_main->ibuf.w); + msgbuf_clear(&iev_main->ibuf.w); + close(iev_main->ibuf.fd); + + config_clear(frontend_conf); + + free(iev_engine); + free(iev_main); + + log_info("frontend exiting"); + exit(0); +} + +int +frontend_imsg_compose_main(int type, pid_t pid, void *data, + uint16_t datalen) +{ + return (imsg_compose_event(iev_main, type, 0, pid, -1, data, + datalen)); +} + +int +frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, + void *data, uint16_t datalen) +{ + return (imsg_compose_event(iev_engine, type, peerid, pid, -1, + data, datalen)); +} + +void +frontend_dispatch_main(int fd, short event, void *bula) +{ + static struct newd_conf *nconf; + struct imsg imsg; + struct group *g; + struct imsgev *iev = bula; + struct imsgbuf *ibuf = &iev->ibuf; + int n, shut = 0; + + if (event & EV_READ) { + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + if (event & EV_WRITE) { + if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) + fatal("msgbuf_write"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatal("%s: imsg_get error", __func__); + if (n == 0) /* No more messages. */ + break; + + switch (imsg.hdr.type) { + case IMSG_SOCKET_IPC: + /* + * Setup pipe and event handler to the engine + * process. + */ + if (iev_engine) { + log_warnx("%s: received unexpected imsg fd " + "to frontend", __func__); + break; + } + if ((fd = imsg.fd) == -1) { + log_warnx("%s: expected to receive imsg fd to " + "frontend but didn't receive any", + __func__); + break; + } + + iev_engine = malloc(sizeof(struct imsgev)); + if (iev_engine == NULL) + fatal(NULL); + + imsg_init(&iev_engine->ibuf, fd); + iev_engine->handler = frontend_dispatch_engine; + iev_engine->events = EV_READ; + + event_set(&iev_engine->ev, iev_engine->ibuf.fd, + iev_engine->events, iev_engine->handler, iev_engine); + event_add(&iev_engine->ev, NULL); + break; + case IMSG_RECONF_CONF: + if ((nconf = malloc(sizeof(struct newd_conf))) == + NULL) + fatal(NULL); + memcpy(nconf, imsg.data, sizeof(struct newd_conf)); + LIST_INIT(&nconf->group_list); + break; + case IMSG_RECONF_GROUP: + if ((g = malloc(sizeof(struct group))) == NULL) + fatal(NULL); + memcpy(g, imsg.data, sizeof(struct group)); + LIST_INSERT_HEAD(&nconf->group_list, g, entry); + break; + case IMSG_RECONF_END: + merge_config(frontend_conf, nconf); + nconf = NULL; + break; + case IMSG_CTL_END: + case IMSG_CTL_SHOW_MAIN_INFO: + control_imsg_relay(&imsg); + break; + default: + log_debug("%s: error handling imsg %d", __func__, + imsg.hdr.type); + break; + } + imsg_free(&imsg); + } + if (!shut) + imsg_event_add(iev); + else { + /* This pipe is dead. Remove its event handler. */ + event_del(&iev->ev); + event_loopexit(NULL); + } +} + +void +frontend_dispatch_engine(int fd, short event, void *bula) +{ + struct imsgev *iev = bula; + struct imsgbuf *ibuf = &iev->ibuf; + struct imsg imsg; + int n, shut = 0; + + if (event & EV_READ) { + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + if (event & EV_WRITE) { + if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) + fatal("msgbuf_write"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatal("%s: imsg_get error", __func__); + if (n == 0) /* No more messages. */ + break; + + switch (imsg.hdr.type) { + case IMSG_CTL_END: + case IMSG_CTL_SHOW_ENGINE_INFO: + control_imsg_relay(&imsg); + break; + default: + log_debug("%s: error handling imsg %d", __func__, + imsg.hdr.type); + break; + } + imsg_free(&imsg); + } + if (!shut) + imsg_event_add(iev); + else { + /* This pipe is dead. Remove its event handler. */ + event_del(&iev->ev); + event_loopexit(NULL); + } +} + +void +frontend_showinfo_ctl(struct ctl_conn *c) +{ + static struct ctl_frontend_info cfi; + + cfi.yesno = frontend_conf->yesno; + cfi.integer = frontend_conf->integer; + + memcpy(cfi.global_text, frontend_conf->global_text, + sizeof(cfi.global_text)); + + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_FRONTEND_INFO, 0, 0, -1, + &cfi, sizeof(struct ctl_frontend_info)); +} diff --git a/extras/filters/smtpfd/frontend.h b/extras/filters/smtpfd/frontend.h new file mode 100644 index 0000000..3dcdf6e --- /dev/null +++ b/extras/filters/smtpfd/frontend.h @@ -0,0 +1,27 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2004, 2005 Esben Norby + * + * 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. + */ + +TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns; + +void frontend(int, int, char *); +void frontend_dispatch_main(int, short, void *); +void frontend_dispatch_engine(int, short, void *); +int frontend_imsg_compose_main(int, pid_t, void *, uint16_t); +int frontend_imsg_compose_engine(int, uint32_t, pid_t, void *, + uint16_t); +void frontend_showinfo_ctl(struct ctl_conn *); diff --git a/extras/filters/smtpfd/log.c b/extras/filters/smtpfd/log.c new file mode 100644 index 0000000..8956cd8 --- /dev/null +++ b/extras/filters/smtpfd/log.c @@ -0,0 +1,199 @@ +/* $OpenBSD: log.c,v 1.2 2017/03/21 12:06:55 bluhm Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "log.h" + +static int debug; +static int verbose; +static const char *log_procname; + +void +log_init(int n_debug, int facility) +{ + extern char *__progname; + + debug = n_debug; + verbose = n_debug; + log_procinit(__progname); + + if (!debug) + openlog(__progname, LOG_PID | LOG_NDELAY, facility); + + tzset(); +} + +void +log_procinit(const char *procname) +{ + if (procname != NULL) + log_procname = procname; +} + +void +log_setverbose(int v) +{ + verbose = v; +} + +int +log_getverbose(void) +{ + return (verbose); +} + +void +logit(int pri, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vlog(pri, fmt, ap); + va_end(ap); +} + +void +vlog(int pri, const char *fmt, va_list ap) +{ + char *nfmt; + int saved_errno = errno; + + if (debug) { + /* best effort in out of mem situations */ + if (asprintf(&nfmt, "%s\n", fmt) == -1) { + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } else { + vfprintf(stderr, nfmt, ap); + free(nfmt); + } + fflush(stderr); + } else + vsyslog(pri, fmt, ap); + + errno = saved_errno; +} + +void +log_warn(const char *emsg, ...) +{ + char *nfmt; + va_list ap; + int saved_errno = errno; + + /* best effort to even work in out of memory situations */ + if (emsg == NULL) + logit(LOG_ERR, "%s", strerror(saved_errno)); + else { + va_start(ap, emsg); + + if (asprintf(&nfmt, "%s: %s", emsg, + strerror(saved_errno)) == -1) { + /* we tried it... */ + vlog(LOG_ERR, emsg, ap); + logit(LOG_ERR, "%s", strerror(saved_errno)); + } else { + vlog(LOG_ERR, nfmt, ap); + free(nfmt); + } + va_end(ap); + } + + errno = saved_errno; +} + +void +log_warnx(const char *emsg, ...) +{ + va_list ap; + + va_start(ap, emsg); + vlog(LOG_ERR, emsg, ap); + va_end(ap); +} + +void +log_info(const char *emsg, ...) +{ + va_list ap; + + va_start(ap, emsg); + vlog(LOG_INFO, emsg, ap); + va_end(ap); +} + +void +log_debug(const char *emsg, ...) +{ + va_list ap; + + if (verbose) { + va_start(ap, emsg); + vlog(LOG_DEBUG, emsg, ap); + va_end(ap); + } +} + +static void +vfatalc(int code, const char *emsg, va_list ap) +{ + static char s[BUFSIZ]; + const char *sep; + + if (emsg != NULL) { + (void)vsnprintf(s, sizeof(s), emsg, ap); + sep = ": "; + } else { + s[0] = '\0'; + sep = ""; + } + if (code) + logit(LOG_CRIT, "fatal in %s: %s%s%s", + log_procname, s, sep, strerror(code)); + else + logit(LOG_CRIT, "fatal in %s%s%s", log_procname, sep, s); +} + +void +fatal(const char *emsg, ...) +{ + va_list ap; + + va_start(ap, emsg); + vfatalc(errno, emsg, ap); + va_end(ap); + exit(1); +} + +void +fatalx(const char *emsg, ...) +{ + va_list ap; + + va_start(ap, emsg); + vfatalc(0, emsg, ap); + va_end(ap); + exit(1); +} diff --git a/extras/filters/smtpfd/log.h b/extras/filters/smtpfd/log.h new file mode 100644 index 0000000..8bba629 --- /dev/null +++ b/extras/filters/smtpfd/log.h @@ -0,0 +1,46 @@ +/* $OpenBSD: log.h,v 1.10 2017/01/24 04:24:25 benno Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * 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. + */ + +#ifndef LOG_H +#define LOG_H + +#include +#include + +void log_init(int, int); +void log_procinit(const char *); +void log_setverbose(int); +int log_getverbose(void); +void log_warn(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_warnx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_info(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_debug(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void logit(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +void vlog(int, const char *, va_list) + __attribute__((__format__ (printf, 2, 0))); +__dead void fatal(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +__dead void fatalx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); + +#endif /* LOG_H */ diff --git a/extras/filters/smtpfd/parse.y b/extras/filters/smtpfd/parse.y new file mode 100644 index 0000000..38c0986 --- /dev/null +++ b/extras/filters/smtpfd/parse.y @@ -0,0 +1,765 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2004, 2005 Esben Norby + * Copyright (c) 2004 Ryan McBride + * Copyright (c) 2002, 2003, 2004 Henning Brauer + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. + * Copyright (c) 2001 Theo de Raadt. All rights reserved. + * + * 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 +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "smtpfd.h" +#include "frontend.h" + +TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); +static struct file { + TAILQ_ENTRY(file) entry; + FILE *stream; + char *name; + int lineno; + int errors; +} *file, *topfile; +struct file *pushfile(const char *, int); +int popfile(void); +int check_file_secrecy(int, const char *); +int yyparse(void); +int yylex(void); +int yyerror(const char *, ...) + __attribute__((__format__ (printf, 1, 2))) + __attribute__((__nonnull__ (1))); +int kw_cmp(const void *, const void *); +int lookup(char *); +int lgetc(int); +int lungetc(int); +int findeol(void); + +TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); +struct sym { + TAILQ_ENTRY(sym) entry; + int used; + int persist; + char *nam; + char *val; +}; + +int symset(const char *, const char *, int); +char *symget(const char *); + +void clear_config(struct newd_conf *xconf); + +static struct newd_conf *conf; +static int errors; + +static struct group *group; + +struct group *conf_get_group(char *); +void *conf_del_group(struct group *); + +typedef struct { + union { + int64_t number; + char *string; + } v; + int lineno; +} YYSTYPE; + +%} + +%token GROUP YES NO INCLUDE ERROR +%token YESNO INTEGER +%token GLOBAL_TEXT +%token GROUP_V4ADDRESS GROUP_V6ADDRESS + +%token STRING +%token NUMBER +%type yesno +%type string + +%% + +grammar : /* empty */ + | grammar include '\n' + | grammar '\n' + | grammar conf_main '\n' + | grammar varset '\n' + | grammar group '\n' + | grammar error '\n' { file->errors++; } + ; + +include : INCLUDE STRING { + struct file *nfile; + + if ((nfile = pushfile($2, 1)) == NULL) { + yyerror("failed to include file %s", $2); + free($2); + YYERROR; + } + free($2); + + file = nfile; + lungetc('\n'); + } + ; + +string : string STRING { + if (asprintf(&$$, "%s %s", $1, $2) == -1) { + free($1); + free($2); + yyerror("string: asprintf"); + YYERROR; + } + free($1); + free($2); + } + | STRING + ; + +yesno : YES { $$ = 1; } + | NO { $$ = 0; } + ; + +varset : STRING '=' string { + char *s = $1; + if (cmd_opts & OPT_VERBOSE) + printf("%s = \"%s\"\n", $1, $3); + while (*s++) { + if (isspace((unsigned char)*s)) { + yyerror("macro name cannot contain " + "whitespace"); + YYERROR; + } + } + if (symset($1, $3, 0) == -1) + fatal("cannot store variable"); + free($1); + free($3); + } + ; + +conf_main : YESNO yesno { + conf->yesno = $2; + } + | INTEGER NUMBER { + conf->integer = $2; + } + | GLOBAL_TEXT STRING { + size_t n; + memset(conf->global_text, 0, + sizeof(conf->global_text)); + n = strlcpy(conf->global_text, $2, + sizeof(conf->global_text)); + if (n >= sizeof(conf->global_text)) { + yyerror("error parsing global_text: too long"); + free($2); + YYERROR; + } + } + +optnl : '\n' optnl /* zero or more newlines */ + | /*empty*/ + ; + +nl : '\n' optnl /* one or more newlines */ + ; + +group : GROUP STRING { + group = conf_get_group($2); + } '{' optnl groupopts_l '}' { + group = NULL; + } + ; + +groupopts_l : groupopts_l groupoptsl nl + | groupoptsl optnl + ; + +groupoptsl : GROUP_V4ADDRESS STRING { + memset(&group->group_v4address, 0, + sizeof(group->group_v4address)); + group->group_v4_bits = inet_net_pton(AF_INET, $2, + &group->group_v4address, + sizeof(group->group_v4address)); + if (group->group_v4_bits == -1) { + yyerror("error parsing group_v4address"); + free($2); + YYERROR; + } + } + | GROUP_V6ADDRESS STRING { + memset(&group->group_v6address, 0, + sizeof(group->group_v6address)); + group->group_v6_bits = inet_net_pton(AF_INET6, $2, + &group->group_v6address, + sizeof(group->group_v6address)); + if (group->group_v6_bits == -1) { + yyerror("error parsing group_v6address"); + free($2); + YYERROR; + } + } + | YESNO yesno { + group->yesno = $2; + } + | INTEGER NUMBER { + group->integer = $2; + } + ; + +%% + +struct keywords { + const char *k_name; + int k_val; +}; + +int +yyerror(const char *fmt, ...) +{ + va_list ap; + char *msg; + + file->errors++; + va_start(ap, fmt); + if (vasprintf(&msg, fmt, ap) == -1) + fatalx("yyerror vasprintf"); + va_end(ap); + logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); + free(msg); + return (0); +} + +int +kw_cmp(const void *k, const void *e) +{ + return (strcmp(k, ((const struct keywords *)e)->k_name)); +} + +int +lookup(char *s) +{ + /* This has to be sorted always. */ + static const struct keywords keywords[] = { + {"global-text", GLOBAL_TEXT}, + {"group", GROUP}, + {"group-v4address", GROUP_V4ADDRESS}, + {"group-v6address", GROUP_V6ADDRESS}, + {"include", INCLUDE}, + {"integer", INTEGER}, + {"no", NO}, + {"yes", YES}, + {"yesno", YESNO} + }; + const struct keywords *p; + + p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), + sizeof(keywords[0]), kw_cmp); + + if (p) + return (p->k_val); + else + return (STRING); +} + +#define MAXPUSHBACK 128 + +unsigned char *parsebuf; +int parseindex; +unsigned char pushback_buffer[MAXPUSHBACK]; +int pushback_index = 0; + +int +lgetc(int quotec) +{ + int c, next; + + if (parsebuf) { + /* Read character from the parsebuffer instead of input. */ + if (parseindex >= 0) { + c = parsebuf[parseindex++]; + if (c != '\0') + return (c); + parsebuf = NULL; + } else + parseindex++; + } + + if (pushback_index) + return (pushback_buffer[--pushback_index]); + + if (quotec) { + if ((c = getc(file->stream)) == EOF) { + yyerror("reached end of file while parsing " + "quoted string"); + if (file == topfile || popfile() == EOF) + return (EOF); + return (quotec); + } + return (c); + } + + while ((c = getc(file->stream)) == '\\') { + next = getc(file->stream); + if (next != '\n') { + c = next; + break; + } + yylval.lineno = file->lineno; + file->lineno++; + } + + while (c == EOF) { + if (file == topfile || popfile() == EOF) + return (EOF); + c = getc(file->stream); + } + return (c); +} + +int +lungetc(int c) +{ + if (c == EOF) + return (EOF); + if (parsebuf) { + parseindex--; + if (parseindex >= 0) + return (c); + } + if (pushback_index < MAXPUSHBACK-1) + return (pushback_buffer[pushback_index++] = c); + else + return (EOF); +} + +int +findeol(void) +{ + int c; + + parsebuf = NULL; + + /* Skip to either EOF or the first real EOL. */ + while (1) { + if (pushback_index) + c = pushback_buffer[--pushback_index]; + else + c = lgetc(0); + if (c == '\n') { + file->lineno++; + break; + } + if (c == EOF) + break; + } + return (ERROR); +} + +int +yylex(void) +{ + unsigned char buf[8096]; + unsigned char *p, *val; + int quotec, next, c; + int token; + +top: + p = buf; + while ((c = lgetc(0)) == ' ' || c == '\t') + ; /* nothing */ + + yylval.lineno = file->lineno; + if (c == '#') + while ((c = lgetc(0)) != '\n' && c != EOF) + ; /* nothing */ + if (c == '$' && parsebuf == NULL) { + while (1) { + if ((c = lgetc(0)) == EOF) + return (0); + + if (p + 1 >= buf + sizeof(buf) - 1) { + yyerror("string too long"); + return (findeol()); + } + if (isalnum(c) || c == '_') { + *p++ = c; + continue; + } + *p = '\0'; + lungetc(c); + break; + } + val = symget(buf); + if (val == NULL) { + yyerror("macro '%s' not defined", buf); + return (findeol()); + } + parsebuf = val; + parseindex = 0; + goto top; + } + + switch (c) { + case '\'': + case '"': + quotec = c; + while (1) { + if ((c = lgetc(quotec)) == EOF) + return (0); + if (c == '\n') { + file->lineno++; + continue; + } else if (c == '\\') { + if ((next = lgetc(quotec)) == EOF) + return (0); + if (next == quotec || c == ' ' || c == '\t') + c = next; + else if (next == '\n') { + file->lineno++; + continue; + } else + lungetc(next); + } else if (c == quotec) { + *p = '\0'; + break; + } else if (c == '\0') { + yyerror("syntax error"); + return (findeol()); + } + if (p + 1 >= buf + sizeof(buf) - 1) { + yyerror("string too long"); + return (findeol()); + } + *p++ = c; + } + yylval.v.string = strdup(buf); + if (yylval.v.string == NULL) + err(1, "yylex: strdup"); + return (STRING); + } + +#define allowed_to_end_number(x) \ + (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') + + if (c == '-' || isdigit(c)) { + do { + *p++ = c; + if ((unsigned)(p-buf) >= sizeof(buf)) { + yyerror("string too long"); + return (findeol()); + } + } while ((c = lgetc(0)) != EOF && isdigit(c)); + lungetc(c); + if (p == buf + 1 && buf[0] == '-') + goto nodigits; + if (c == EOF || allowed_to_end_number(c)) { + const char *errstr = NULL; + + *p = '\0'; + yylval.v.number = strtonum(buf, LLONG_MIN, + LLONG_MAX, &errstr); + if (errstr) { + yyerror("\"%s\" invalid number: %s", + buf, errstr); + return (findeol()); + } + return (NUMBER); + } else { +nodigits: + while (p > buf + 1) + lungetc(*--p); + c = *--p; + if (c == '-') + return (c); + } + } + +#define allowed_in_string(x) \ + (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ + x != '{' && x != '}' && \ + x != '!' && x != '=' && x != '#' && \ + x != ',')) + + if (isalnum(c) || c == ':' || c == '_') { + do { + *p++ = c; + if ((unsigned)(p-buf) >= sizeof(buf)) { + yyerror("string too long"); + return (findeol()); + } + } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); + lungetc(c); + *p = '\0'; + if ((token = lookup(buf)) == STRING) + if ((yylval.v.string = strdup(buf)) == NULL) + err(1, "yylex: strdup"); + return (token); + } + if (c == '\n') { + yylval.lineno = file->lineno; + file->lineno++; + } + if (c == EOF) + return (0); + return (c); +} + +int +check_file_secrecy(int fd, const char *fname) +{ + struct stat st; + + if (fstat(fd, &st)) { + log_warn("cannot stat %s", fname); + return (-1); + } + if (st.st_uid != 0 && st.st_uid != getuid()) { + log_warnx("%s: owner not root or current user", fname); + return (-1); + } + if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { + log_warnx("%s: group writable or world read/writable", fname); + return (-1); + } + return (0); +} + +struct file * +pushfile(const char *name, int secret) +{ + struct file *nfile; + + if ((nfile = calloc(1, sizeof(struct file))) == NULL) { + log_warn("calloc"); + return (NULL); + } + if ((nfile->name = strdup(name)) == NULL) { + log_warn("strdup"); + free(nfile); + return (NULL); + } + if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { + log_warn("%s", nfile->name); + free(nfile->name); + free(nfile); + return (NULL); + } else if (secret && + check_file_secrecy(fileno(nfile->stream), nfile->name)) { + fclose(nfile->stream); + free(nfile->name); + free(nfile); + return (NULL); + } + nfile->lineno = 1; + TAILQ_INSERT_TAIL(&files, nfile, entry); + return (nfile); +} + +int +popfile(void) +{ + struct file *prev; + + if ((prev = TAILQ_PREV(file, files, entry)) != NULL) + prev->errors += file->errors; + + TAILQ_REMOVE(&files, file, entry); + fclose(file->stream); + free(file->name); + free(file); + file = prev; + return (file ? 0 : EOF); +} + +struct newd_conf * +parse_config(char *filename) +{ + struct sym *sym, *next; + + conf = config_new_empty(); + + file = pushfile(filename, !(cmd_opts & OPT_NOACTION)); + if (file == NULL) { + free(conf); + return (NULL); + } + topfile = file; + + LIST_INIT(&conf->group_list); + + yyparse(); + errors = file->errors; + popfile(); + + /* Free macros and check which have not been used. */ + TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { + if ((cmd_opts & OPT_VERBOSE2) && !sym->used) + fprintf(stderr, "warning: macro '%s' not used\n", + sym->nam); + if (!sym->persist) { + free(sym->nam); + free(sym->val); + TAILQ_REMOVE(&symhead, sym, entry); + free(sym); + } + } + + if (errors) { + clear_config(conf); + return (NULL); + } + + return (conf); +} + +int +symset(const char *nam, const char *val, int persist) +{ + struct sym *sym; + + TAILQ_FOREACH(sym, &symhead, entry) { + if (strcmp(nam, sym->nam) == 0) + break; + } + + if (sym != NULL) { + if (sym->persist == 1) + return (0); + else { + free(sym->nam); + free(sym->val); + TAILQ_REMOVE(&symhead, sym, entry); + free(sym); + } + } + if ((sym = calloc(1, sizeof(*sym))) == NULL) + return (-1); + + sym->nam = strdup(nam); + if (sym->nam == NULL) { + free(sym); + return (-1); + } + sym->val = strdup(val); + if (sym->val == NULL) { + free(sym->nam); + free(sym); + return (-1); + } + sym->used = 0; + sym->persist = persist; + TAILQ_INSERT_TAIL(&symhead, sym, entry); + return (0); +} + +int +cmdline_symset(char *s) +{ + char *sym, *val; + int ret; + size_t len; + + if ((val = strrchr(s, '=')) == NULL) + return (-1); + + len = strlen(s) - strlen(val) + 1; + if ((sym = malloc(len)) == NULL) + errx(1, "cmdline_symset: malloc"); + + strlcpy(sym, s, len); + + ret = symset(sym, val + 1, 1); + free(sym); + + return (ret); +} + +char * +symget(const char *nam) +{ + struct sym *sym; + + TAILQ_FOREACH(sym, &symhead, entry) { + if (strcmp(nam, sym->nam) == 0) { + sym->used = 1; + return (sym->val); + } + } + return (NULL); +} + +struct group * +conf_get_group(char *name) +{ + struct group *g; + size_t n; + + LIST_FOREACH(g, &conf->group_list, entry) { + if (strcmp(name, g->name) == 0) + return (g); + } + + g = calloc(1, sizeof(*g)); + if (g == NULL) + errx(1, "get_group: calloc"); + n = strlcpy(g->name, name, sizeof(g->name)); + if (n >= sizeof(g->name)) + errx(1, "get_group: name too long"); + + /* Inherit attributes set in global section. */ + g->yesno = conf->yesno; + g->integer = conf->integer; + + LIST_INSERT_HEAD(&conf->group_list, g, entry); + + return (g); +} + +void +clear_config(struct newd_conf *xconf) +{ + struct group *g; + + while ((g = LIST_FIRST(&xconf->group_list)) != NULL) { + LIST_REMOVE(g, entry); + free(g); + } + + free(xconf); +} diff --git a/extras/filters/smtpfd/printconf.c b/extras/filters/smtpfd/printconf.c new file mode 100644 index 0000000..edb9165 --- /dev/null +++ b/extras/filters/smtpfd/printconf.c @@ -0,0 +1,64 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2004, 2005 Esben Norby + * + * 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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "smtpfd.h" + +void +print_config(struct newd_conf *conf) +{ + struct group *g; + char buf[INET6_ADDRSTRLEN], *bufp; + + printf("yesno %s\n", conf->yesno ? "yes" : "no"); + printf("integer %d\n", conf->integer); + printf("\n"); + + printf("global_text \"%s\"\n", conf->global_text); + printf("\n"); + + + LIST_FOREACH(g, &conf->group_list, entry) { + printf("group %s {\n", g->name); + + printf("\tyesno %s\n", g->yesno ? "yes" : "no"); + printf("\tinteger %d\n", g->integer); + + bufp = inet_net_ntop(AF_INET, &g->group_v4address, + g->group_v4_bits, buf, sizeof(buf)); + printf("\tgroup-v4address %s\n", + bufp ? bufp : ""); + bufp = inet_net_ntop(AF_INET6, &g->group_v6address, + g->group_v6_bits, buf, sizeof(buf)); + printf("\tgroup-v6address %s\n", + bufp ? bufp : ""); + + printf("}\n"); + } +} diff --git a/extras/filters/smtpfd/smtpfd.8 b/extras/filters/smtpfd/smtpfd.8 new file mode 100644 index 0000000..5c8c1ed --- /dev/null +++ b/extras/filters/smtpfd/smtpfd.8 @@ -0,0 +1,91 @@ +.\" $OpenBSD$ +.\" +.\" Copyright (c) 2016 Kenneth R Westerback +.\" +.\" 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. +.\" +.Dd $Mdocdate: July 27 2015 $ +.Dt NEWD 8 +.Os +.Sh NAME +.Nm newd +.Nd sample daemon +.Sh SYNOPSIS +.Nm +.Op Fl dnv +.Op Fl f Ar file +.Op Fl s Ar socket +.Sh DESCRIPTION +.Nm +is an example daemon that does nothing but provide the framework for a +standard +.Ox +privilege separated daemon. +.Pp +.Nm +is usually started at boot time, and can be enabled by +setting the following in +.Pa /etc/rc.conf.local : +.Pp +.Dl newd_flags=\&"\&" +.Pp +See +.Xr rc 8 +and +.Xr rc.conf 8 +for more information on the boot process +and enabling daemons. +.Pp +A running +.Nm +can be controlled with the +.Xr newctl 8 +utility. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl d +Do not daemonize. +If this option is specified, +.Nm +will run in the foreground and log to +.Em stderr . +.It Fl f Ar file +Specify an alternative configuration file. +.It Fl n +Configtest mode. +Only check the configuration file for validity. +.It Fl s Ar socket +Use an alternate location for the default control socket. +.It Fl v +Produce more verbose output. +.El +.Sh FILES +.Bl -tag -width "/var/run/newd.sockXX" -compact +.It Pa /etc/newd.conf +Default +.Nm +configuration file. +.It Pa /var/run/newd.sock +.Ux Ns -domain +socket used for communication with +.Xr newctl 8 . +.El +.Sh SEE ALSO +.Xr newd.conf 5 , +.Xr newctl 8 +.Sh HISTORY +The +.Nm +program first appeared in +.Ox X.Y . diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c new file mode 100644 index 0000000..c5019cd --- /dev/null +++ b/extras/filters/smtpfd/smtpfd.c @@ -0,0 +1,635 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2005 Claudio Jeker + * Copyright (c) 2004 Esben Norby + * Copyright (c) 2003, 2004 Henning Brauer + * + * 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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "smtpfd.h" +#include "frontend.h" +#include "engine.h" +#include "control.h" + +__dead void usage(void); +__dead void main_shutdown(void); + +void main_sig_handler(int, short, void *); + +static pid_t start_child(int, char *, int, int, int, char *); + +void main_dispatch_frontend(int, short, void *); +void main_dispatch_engine(int, short, void *); + +static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); +static int main_imsg_send_config(struct newd_conf *); + +int main_reload(void); +int main_sendboth(enum imsg_type, void *, uint16_t); +void main_showinfo_ctl(struct imsg *); + +struct newd_conf *main_conf; +struct imsgev *iev_frontend; +struct imsgev *iev_engine; +char *conffile; +char *csock; + +pid_t frontend_pid; +pid_t engine_pid; + +uint32_t cmd_opts; + +void +main_sig_handler(int sig, short event, void *arg) +{ + /* + * Normal signal handler rules don't apply because libevent + * decouples for us. + */ + + switch (sig) { + case SIGTERM: + case SIGINT: + main_shutdown(); + case SIGHUP: + if (main_reload() == -1) + log_warnx("configuration reload failed"); + else + log_debug("configuration reloaded"); + break; + default: + fatalx("unexpected signal"); + } +} + +__dead void +usage(void) +{ + extern char *__progname; + + fprintf(stderr, "usage: %s [-dnv] [-f file] [-s socket]\n", + __progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + struct event ev_sigint, ev_sigterm, ev_sighup; + int ch; + int debug = 0, engine_flag = 0, frontend_flag = 0; + char *saved_argv0; + int pipe_main2frontend[2]; + int pipe_main2engine[2]; + + conffile = CONF_FILE; + csock = SMTPFD_SOCKET; + + log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ + log_setverbose(1); + + saved_argv0 = argv[0]; + if (saved_argv0 == NULL) + saved_argv0 = "newd"; + + while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) { + switch (ch) { + case 'd': + debug = 1; + break; + case 'E': + engine_flag = 1; + break; + case 'F': + frontend_flag = 1; + break; + case 'f': + conffile = optarg; + break; + case 'n': + cmd_opts |= OPT_NOACTION; + break; + case 's': + csock = optarg; + break; + case 'v': + if (cmd_opts & OPT_VERBOSE) + cmd_opts |= OPT_VERBOSE2; + cmd_opts |= OPT_VERBOSE; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc > 0 || (engine_flag && frontend_flag)) + usage(); + + if (engine_flag) + engine(debug, cmd_opts & OPT_VERBOSE); + else if (frontend_flag) + frontend(debug, cmd_opts & OPT_VERBOSE, csock); + + /* parse config file */ + if ((main_conf = parse_config(conffile)) == NULL) { + exit(1); + } + + if (cmd_opts & OPT_NOACTION) { + if (cmd_opts & OPT_VERBOSE) + print_config(main_conf); + else + fprintf(stderr, "configuration OK\n"); + exit(0); + } + + /* Check for root privileges. */ + if (geteuid()) + errx(1, "need root privileges"); + + /* Check for assigned daemon user */ + if (getpwnam(SMTPFD_USER) == NULL) + errx(1, "unknown user %s", SMTPFD_USER); + + log_init(debug, LOG_DAEMON); + log_setverbose(cmd_opts & OPT_VERBOSE); + + if (!debug) + daemon(1, 0); + + log_info("startup"); + + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + PF_UNSPEC, pipe_main2frontend) == -1) + fatal("main2frontend socketpair"); + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + PF_UNSPEC, pipe_main2engine) == -1) + fatal("main2engine socketpair"); + + /* Start children. */ + engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1], + debug, cmd_opts & OPT_VERBOSE, NULL); + frontend_pid = start_child(PROC_FRONTEND, saved_argv0, + pipe_main2frontend[1], debug, cmd_opts & OPT_VERBOSE, csock); + + newd_process = PROC_MAIN; + setproctitle(log_procnames[newd_process]); + log_procinit(log_procnames[newd_process]); + + event_init(); + + /* Setup signal handler. */ + signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); + signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); + signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); + signal_add(&ev_sigint, NULL); + signal_add(&ev_sigterm, NULL); + signal_add(&ev_sighup, NULL); + signal(SIGPIPE, SIG_IGN); + + /* Setup pipes to children. */ + + if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL || + (iev_engine = malloc(sizeof(struct imsgev))) == NULL) + fatal(NULL); + imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); + iev_frontend->handler = main_dispatch_frontend; + imsg_init(&iev_engine->ibuf, pipe_main2engine[0]); + iev_engine->handler = main_dispatch_engine; + + /* Setup event handlers for pipes to engine & frontend. */ + iev_frontend->events = EV_READ; + event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, + iev_frontend->events, iev_frontend->handler, iev_frontend); + event_add(&iev_frontend->ev, NULL); + + iev_engine->events = EV_READ; + event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events, + iev_engine->handler, iev_engine); + event_add(&iev_engine->ev, NULL); + + if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf)) + fatal("could not establish imsg links"); + main_imsg_send_config(main_conf); + + if (pledge("rpath stdio sendfd", NULL) == -1) + fatal("pledge"); + + event_dispatch(); + + main_shutdown(); + return (0); +} + +__dead void +main_shutdown(void) +{ + pid_t pid; + int status; + + /* Close pipes. */ + msgbuf_clear(&iev_frontend->ibuf.w); + close(iev_frontend->ibuf.fd); + msgbuf_clear(&iev_engine->ibuf.w); + close(iev_engine->ibuf.fd); + + config_clear(main_conf); + + log_debug("waiting for children to terminate"); + do { + pid = wait(&status); + if (pid == -1) { + if (errno != EINTR && errno != ECHILD) + fatal("wait"); + } else if (WIFSIGNALED(status)) + log_warnx("%s terminated; signal %d", + (pid == engine_pid) ? "engine" : + "frontend", WTERMSIG(status)); + } while (pid != -1 || (pid == -1 && errno == EINTR)); + + free(iev_frontend); + free(iev_engine); + + control_cleanup(csock); + + log_info("terminating"); + exit(0); +} + +static pid_t +start_child(int p, char *argv0, int fd, int debug, int verbose, char *sockname) +{ + char *argv[7]; + int argc = 0; + pid_t pid; + + switch (pid = fork()) { + case -1: + fatal("cannot fork"); + case 0: + break; + default: + close(fd); + return (pid); + } + + if (dup2(fd, 3) == -1) + fatal("cannot setup imsg fd"); + + argv[argc++] = argv0; + switch (p) { + case PROC_MAIN: + fatalx("Can not start main process"); + case PROC_ENGINE: + argv[argc++] = "-E"; + break; + case PROC_FRONTEND: + argv[argc++] = "-F"; + break; + } + if (debug) + argv[argc++] = "-d"; + if (verbose) + argv[argc++] = "-v"; + if (sockname) { + argv[argc++] = "-s"; + argv[argc++] = sockname; + } + argv[argc++] = NULL; + + execvp(argv0, argv); + fatal("execvp"); +} + +void +main_dispatch_frontend(int fd, short event, void *bula) +{ + struct imsgev *iev = bula; + struct imsgbuf *ibuf; + struct imsg imsg; + ssize_t n; + int shut = 0, verbose; + + ibuf = &iev->ibuf; + + if (event & EV_READ) { + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + if (event & EV_WRITE) { + if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) + fatal("msgbuf_write"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatal("imsg_get"); + if (n == 0) /* No more messages. */ + break; + + switch (imsg.hdr.type) { + case IMSG_CTL_RELOAD: + if (main_reload() == -1) + log_warnx("configuration reload failed"); + else + log_warnx("configuration reloaded"); + break; + case IMSG_CTL_LOG_VERBOSE: + /* Already checked by frontend. */ + memcpy(&verbose, imsg.data, sizeof(verbose)); + log_setverbose(verbose); + break; + case IMSG_CTL_SHOW_MAIN_INFO: + main_showinfo_ctl(&imsg); + break; + default: + log_debug("%s: error handling imsg %d", __func__, + imsg.hdr.type); + break; + } + imsg_free(&imsg); + } + if (!shut) + imsg_event_add(iev); + else { + /* This pipe is dead. Remove its event handler */ + event_del(&iev->ev); + event_loopexit(NULL); + } +} + +void +main_dispatch_engine(int fd, short event, void *bula) +{ + struct imsgev *iev = bula; + struct imsgbuf *ibuf; + struct imsg imsg; + ssize_t n; + int shut = 0; + + ibuf = &iev->ibuf; + + if (event & EV_READ) { + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + if (event & EV_WRITE) { + if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) + fatal("msgbuf_write"); + if (n == 0) /* Connection closed. */ + shut = 1; + } + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatal("imsg_get"); + if (n == 0) /* No more messages. */ + break; + + switch (imsg.hdr.type) { + default: + log_debug("%s: error handling imsg %d", __func__, + imsg.hdr.type); + break; + } + imsg_free(&imsg); + } + if (!shut) + imsg_event_add(iev); + else { + /* This pipe is dead. Remove its event handler. */ + event_del(&iev->ev); + event_loopexit(NULL); + } +} + +void +main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) +{ + if (iev_frontend) + imsg_compose_event(iev_frontend, type, 0, pid, -1, data, + datalen); +} + +void +main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) +{ + if (iev_engine) + imsg_compose_event(iev_engine, type, 0, pid, -1, data, + datalen); +} + +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); + event_add(&iev->ev, NULL); +} + +int +imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, + pid_t pid, int fd, void *data, uint16_t datalen) +{ + int ret; + + if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, + datalen)) != -1) + imsg_event_add(iev); + + return (ret); +} + +static int +main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, + struct imsgbuf *engine_buf) +{ + int pipe_frontend2engine[2]; + + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + PF_UNSPEC, pipe_frontend2engine) == -1) + return (-1); + + if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0, + pipe_frontend2engine[0], NULL, 0) == -1) + return (-1); + if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0, + pipe_frontend2engine[1], NULL, 0) == -1) + return (-1); + + return (0); +} + +int +main_reload(void) +{ + struct newd_conf *xconf; + + if ((xconf = parse_config(conffile)) == NULL) + return (-1); + + if (main_imsg_send_config(xconf) == -1) + return (-1); + + merge_config(main_conf, xconf); + + return (0); +} + +int +main_imsg_send_config(struct newd_conf *xconf) +{ + struct group *g; + + /* Send fixed part of config to children. */ + if (main_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) + return (-1); + + /* Send the group list to children. */ + LIST_FOREACH(g, &xconf->group_list, entry) { + if (main_sendboth(IMSG_RECONF_GROUP, g, sizeof(*g)) == -1) + return (-1); + } + + /* Tell children the revised config is now complete. */ + if (main_sendboth(IMSG_RECONF_END, NULL, 0) == -1) + return (-1); + + return (0); +} + +int +main_sendboth(enum imsg_type type, void *buf, uint16_t len) +{ + if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1) + return (-1); + if (imsg_compose_event(iev_engine, type, 0, 0, -1, buf, len) == -1) + return (-1); + return (0); +} + +void +main_showinfo_ctl(struct imsg *imsg) +{ + struct ctl_main_info cmi; + size_t n; + + switch (imsg->hdr.type) { + case IMSG_CTL_SHOW_MAIN_INFO: + memset(cmi.text, 0, sizeof(cmi.text)); + n = strlcpy(cmi.text, "I'm a little teapot.", + sizeof(cmi.text)); + if (n >= sizeof(cmi.text)) + log_debug("%s: I was cut off!", __func__); + main_imsg_compose_frontend(IMSG_CTL_SHOW_MAIN_INFO, + imsg->hdr.pid, &cmi, sizeof(cmi)); + memset(cmi.text, 0, sizeof(cmi.text)); + n = strlcpy(cmi.text, "Full of sencha.", + sizeof(cmi.text)); + if (n >= sizeof(cmi.text)) + log_debug("%s: I was cut off!", __func__); + main_imsg_compose_frontend(IMSG_CTL_SHOW_MAIN_INFO, + imsg->hdr.pid, &cmi, sizeof(cmi)); + main_imsg_compose_frontend(IMSG_CTL_END, imsg->hdr.pid, NULL, + 0); + break; + default: + log_debug("%s: error handling imsg", __func__); + break; + } +} + +void +merge_config(struct newd_conf *conf, struct newd_conf *xconf) +{ + struct group *g; + + conf->yesno = xconf->yesno; + conf->integer = xconf->integer; + memcpy(conf->global_text, xconf->global_text, + sizeof(conf->global_text)); + + /* Remove & discard existing groups. */ + while ((g = LIST_FIRST(&conf->group_list)) != NULL) { + LIST_REMOVE(g, entry); + free(g); + } + + /* Add new groups. */ + while ((g = LIST_FIRST(&xconf->group_list)) != NULL) { + LIST_REMOVE(g, entry); + LIST_INSERT_HEAD(&conf->group_list, g, entry); + } + + free(xconf); +} + +struct newd_conf * +config_new_empty(void) +{ + struct newd_conf *xconf; + + xconf = calloc(1, sizeof(*xconf)); + if (xconf == NULL) + fatal(NULL); + + LIST_INIT(&xconf->group_list); + + return (xconf); +} + +void +config_clear(struct newd_conf *conf) +{ + struct newd_conf *xconf; + + /* Merge current config with an empty config. */ + xconf = config_new_empty(); + merge_config(conf, xconf); + + free(conf); +} diff --git a/extras/filters/smtpfd/smtpfd.conf.5 b/extras/filters/smtpfd/smtpfd.conf.5 new file mode 100644 index 0000000..d88b230 --- /dev/null +++ b/extras/filters/smtpfd/smtpfd.conf.5 @@ -0,0 +1,137 @@ +.\" $OpenBSD$ +.\" +.\" Copyright (c) 2005 Esben Norby +.\" Copyright (c) 2004 Claudio Jeker +.\" Copyright (c) 2003, 2004 Henning Brauer +.\" Copyright (c) 2002 Daniel Hartmeier +.\" +.\" 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. +.\" +.Dd $Mdocdate: March 11 2015 $ +.Dt NEWD.CONF 5 +.Os +.Sh NAME +.Nm newd.conf +.Nd New Daemon configuration file +.Sh DESCRIPTION +The +.Xr newd 8 +daemon is a skeleton daemon implementing a privileged separated daemon +in accord with current +.Ox +practices. +.Sh SECTIONS +The +.Nm +config file is divided into three sections. +.Bl -tag -width xxxx +.It Sy Macros +User-defined variables may be defined and used later, simplifying the +configuration file. +.It Sy Global Configuration +Zero or more +.Xr newd 8 +attibutes. +.It Sy Groups +Named lists of +zero or more +.Xr newd 8 +attributes. +.El +.Pp +Additional configuration files can be included with the +.Ic include +keyword. +.Sh MACROS +Macros can be defined that will later be expanded in context. +Macro names must start with a letter, digit, or underscore, +and may contain any of those characters. +Macro names may not be reserved words (for example, +.Ic group ) +Macros are not expanded inside quotes. +.Sh GLOBAL CONFIGURATION +The global configuration section is a list of attribute specifications. +.Pp +Attributes with a +.Sq global- +prefix can be used +.Em only +in the global configuration section. These are +.Pp +.Bl -tag -width Ds -compact +.It Ic global-text Ar string +.El +.Sh GROUPS +A group is a named list of attributes, specified with +.Bl -tag -width group-name +.It Ic group Ar name { attribute list } +.El +.Pp +Attibutes with the +.Sq group- +prefix can be used only a group. These are +.Pp +.Bl -tag -width Ds -compact +.It Ic group-v4address Ar IPv4address +.Pp +.It Ic group-v6address Ar IPv6address +.El +.Sh COMMON ATTRIBUTES +Attributes with neither +.Sq global- +nor +.Sq group- +prefixes can be used in either or both global and group configuration +sections. +If used in only the global configuration section then the specification is +inherited by all groups. +If used in both the sections, the specification in the group will take +precedence in that group. +.Pp +These are +.Pp +.Bl -tag -width Ds -compact +.It Xo +.Ic yesno +.Pq Ic yes Ns | Ns Ic no +.Xc +.Pp +.It Ic integer Ar integer +.El +.Sh EXAMPLE +.Bd -literal -offset indent +include "/etc/newd.sub.conf" +hi="5" +integer=$hi +yesno no; +group Barrymore { + yesno yes; + integer 1; + group-v4address 1.2.3.4/32; +} +.Ed +.Sh FILES +.Bl -tag -width "/etc/newd.conf" -compact +.It Pa /etc/newd.conf +.Xr newd 8 +configuration file +.El +.Sh SEE ALSO +.Xr newd 8 , +.Xr newdfctl 8 , +.Xr rc.conf.local 8 +.Sh HISTORY +The +.Nm +file format first appeared in +.Ox X.Y . diff --git a/extras/filters/smtpfd/smtpfd.conf.example b/extras/filters/smtpfd/smtpfd.conf.example new file mode 100644 index 0000000..4207ef5 --- /dev/null +++ b/extras/filters/smtpfd/smtpfd.conf.example @@ -0,0 +1,18 @@ +global-text "Thanks for all the herring" + +yesno no +integer 24 + +group Starbucks { + group-v4address 1.2.3.4/32 + group-v6address 1::1 +} + +group Timmys { + yesno yes + integer 1 + + group-v4address 8.8.8.8/32 + group-v6address 8::8 + +} diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h new file mode 100644 index 0000000..cdc4268 --- /dev/null +++ b/extras/filters/smtpfd/smtpfd.h @@ -0,0 +1,120 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2004 Esben Norby + * Copyright (c) 2003, 2004 Henning Brauer + * + * 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. + */ + +#define CONF_FILE "/etc/smtpfd.conf" +#define SMTPFD_SOCKET "/var/run/smtpfd.sock" +#define SMTPFD_USER "_smtpfd" + +#define OPT_VERBOSE 0x00000001 +#define OPT_VERBOSE2 0x00000002 +#define OPT_NOACTION 0x00000004 + +#define NEWD_MAXTEXT 256 +#define NEWD_MAXGROUPNAME 16 + +static const char * const log_procnames[] = { + "main", + "frontend", + "engine" +}; + +struct imsgev { + struct imsgbuf ibuf; + void (*handler)(int, short, void *); + struct event ev; + short events; +}; + +enum imsg_type { + IMSG_NONE, + IMSG_CTL_LOG_VERBOSE, + IMSG_CTL_RELOAD, + IMSG_CTL_SHOW_ENGINE_INFO, + IMSG_CTL_SHOW_FRONTEND_INFO, + IMSG_CTL_SHOW_MAIN_INFO, + IMSG_CTL_END, + IMSG_RECONF_CONF, + IMSG_RECONF_GROUP, + IMSG_RECONF_END, + IMSG_SOCKET_IPC +}; + +enum { + PROC_MAIN, + PROC_ENGINE, + PROC_FRONTEND +} newd_process; + +struct group { + LIST_ENTRY(group) entry; + char name[NEWD_MAXGROUPNAME]; + int yesno; + int integer; + int group_v4_bits; + int group_v6_bits; + struct in_addr group_v4address; + struct in6_addr group_v6address; +}; + +struct newd_conf { + int yesno; + int integer; + char global_text[NEWD_MAXTEXT]; + LIST_HEAD(, group) group_list; +}; + +struct ctl_frontend_info { + int yesno; + int integer; + char global_text[NEWD_MAXTEXT]; +}; + +struct ctl_engine_info { + char name[NEWD_MAXGROUPNAME]; + int yesno; + int integer; + int group_v4_bits; + int group_v6_bits; + struct in_addr group_v4address; + struct in6_addr group_v6address; +}; + +struct ctl_main_info { + char text[NEWD_MAXTEXT]; +}; + +extern uint32_t cmd_opts; + +/* newd.c */ +void main_imsg_compose_frontend(int, pid_t, void *, uint16_t); +void main_imsg_compose_engine(int, pid_t, void *, uint16_t); +void merge_config(struct newd_conf *, struct newd_conf *); +void imsg_event_add(struct imsgev *); +int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t, + int, void *, uint16_t); + +struct newd_conf *config_new_empty(void); +void config_clear(struct newd_conf *); + +/* printconf.c */ +void print_config(struct newd_conf *); + +/* parse.y */ +struct newd_conf *parse_config(char *); +int cmdline_symset(char *); From 28203105c2366dc0b97c1018bc3efb815753d1b1 Mon Sep 17 00:00:00 2001 From: Sunil Nimmagadda Date: Sat, 20 May 2017 17:16:10 +0530 Subject: [PATCH 02/41] Let the default conf location be /etc/mail. --- extras/filters/smtpfd/smtpfd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index cdc4268..715e956 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -17,7 +17,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define CONF_FILE "/etc/smtpfd.conf" +#define CONF_FILE "/etc/mail/smtpfd.conf" #define SMTPFD_SOCKET "/var/run/smtpfd.sock" #define SMTPFD_USER "_smtpfd" From b290b1a77d10442d038ec05ac2f0bedb55a74b4c Mon Sep 17 00:00:00 2001 From: Sunil Nimmagadda Date: Sat, 20 May 2017 17:27:30 +0530 Subject: [PATCH 03/41] s/newd_conf/smtpfd_conf. --- extras/filters/smtpfd/engine.c | 20 ++++++++++---------- extras/filters/smtpfd/frontend.c | 18 +++++++++--------- extras/filters/smtpfd/parse.y | 8 ++++---- extras/filters/smtpfd/printconf.c | 2 +- extras/filters/smtpfd/smtpfd.c | 18 +++++++++--------- extras/filters/smtpfd/smtpfd.h | 12 ++++++------ 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 22b1fae..8e5a72d 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -45,7 +45,7 @@ void engine_dispatch_frontend(int, short, void *); void engine_dispatch_main(int, short, void *); void engine_showinfo_ctl(struct imsg *); -struct newd_conf *engine_conf; +struct smtpfd_conf *engine_conf; struct imsgev *iev_frontend; struct imsgev *iev_main; @@ -209,13 +209,13 @@ engine_dispatch_frontend(int fd, short event, void *bula) void engine_dispatch_main(int fd, short event, void *bula) { - static struct newd_conf *nconf; - struct imsg imsg; - struct group *g; - struct imsgev *iev = bula; - struct imsgbuf *ibuf; - ssize_t n; - int shut = 0; + static struct smtpfd_conf *nconf; + struct imsg imsg; + struct group *g; + struct imsgev *iev = bula; + struct imsgbuf *ibuf; + ssize_t n; + int shut = 0; ibuf = &iev->ibuf; @@ -269,9 +269,9 @@ engine_dispatch_main(int fd, short event, void *bula) event_add(&iev_frontend->ev, NULL); break; case IMSG_RECONF_CONF: - if ((nconf = malloc(sizeof(struct newd_conf))) == NULL) + if ((nconf = malloc(sizeof(struct smtpfd_conf))) == NULL) fatal(NULL); - memcpy(nconf, imsg.data, sizeof(struct newd_conf)); + memcpy(nconf, imsg.data, sizeof(struct smtpfd_conf)); LIST_INIT(&nconf->group_list); break; case IMSG_RECONF_GROUP: diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 1498692..1f06a02 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -43,7 +43,7 @@ __dead void frontend_shutdown(void); void frontend_sig_handler(int, short, void *); -struct newd_conf *frontend_conf; +struct smtpfd_conf *frontend_conf; struct imsgev *iev_main; struct imsgev *iev_engine; @@ -167,12 +167,12 @@ frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, void frontend_dispatch_main(int fd, short event, void *bula) { - static struct newd_conf *nconf; - struct imsg imsg; - struct group *g; - struct imsgev *iev = bula; - struct imsgbuf *ibuf = &iev->ibuf; - int n, shut = 0; + static struct smtpfd_conf *nconf; + struct imsg imsg; + struct group *g; + struct imsgev *iev = bula; + struct imsgbuf *ibuf = &iev->ibuf; + int n, shut = 0; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) @@ -224,10 +224,10 @@ frontend_dispatch_main(int fd, short event, void *bula) event_add(&iev_engine->ev, NULL); break; case IMSG_RECONF_CONF: - if ((nconf = malloc(sizeof(struct newd_conf))) == + if ((nconf = malloc(sizeof(struct smtpfd_conf))) == NULL) fatal(NULL); - memcpy(nconf, imsg.data, sizeof(struct newd_conf)); + memcpy(nconf, imsg.data, sizeof(struct smtpfd_conf)); LIST_INIT(&nconf->group_list); break; case IMSG_RECONF_GROUP: diff --git a/extras/filters/smtpfd/parse.y b/extras/filters/smtpfd/parse.y index 38c0986..73e0fc9 100644 --- a/extras/filters/smtpfd/parse.y +++ b/extras/filters/smtpfd/parse.y @@ -82,9 +82,9 @@ struct sym { int symset(const char *, const char *, int); char *symget(const char *); -void clear_config(struct newd_conf *xconf); +void clear_config(struct smtpfd_conf *xconf); -static struct newd_conf *conf; +static struct smtpfd_conf *conf; static int errors; static struct group *group; @@ -607,7 +607,7 @@ popfile(void) return (file ? 0 : EOF); } -struct newd_conf * +struct smtpfd_conf * parse_config(char *filename) { struct sym *sym, *next; @@ -752,7 +752,7 @@ conf_get_group(char *name) } void -clear_config(struct newd_conf *xconf) +clear_config(struct smtpfd_conf *xconf) { struct group *g; diff --git a/extras/filters/smtpfd/printconf.c b/extras/filters/smtpfd/printconf.c index edb9165..8fb9459 100644 --- a/extras/filters/smtpfd/printconf.c +++ b/extras/filters/smtpfd/printconf.c @@ -31,7 +31,7 @@ #include "smtpfd.h" void -print_config(struct newd_conf *conf) +print_config(struct smtpfd_conf *conf) { struct group *g; char buf[INET6_ADDRSTRLEN], *bufp; diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index c5019cd..d193967 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -54,13 +54,13 @@ void main_dispatch_frontend(int, short, void *); void main_dispatch_engine(int, short, void *); static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); -static int main_imsg_send_config(struct newd_conf *); +static int main_imsg_send_config(struct smtpfd_conf *); int main_reload(void); int main_sendboth(enum imsg_type, void *, uint16_t); void main_showinfo_ctl(struct imsg *); -struct newd_conf *main_conf; +struct smtpfd_conf *main_conf; struct imsgev *iev_frontend; struct imsgev *iev_engine; char *conffile; @@ -507,7 +507,7 @@ main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, int main_reload(void) { - struct newd_conf *xconf; + struct smtpfd_conf *xconf; if ((xconf = parse_config(conffile)) == NULL) return (-1); @@ -521,7 +521,7 @@ main_reload(void) } int -main_imsg_send_config(struct newd_conf *xconf) +main_imsg_send_config(struct smtpfd_conf *xconf) { struct group *g; @@ -584,7 +584,7 @@ main_showinfo_ctl(struct imsg *imsg) } void -merge_config(struct newd_conf *conf, struct newd_conf *xconf) +merge_config(struct smtpfd_conf *conf, struct smtpfd_conf *xconf) { struct group *g; @@ -608,10 +608,10 @@ merge_config(struct newd_conf *conf, struct newd_conf *xconf) free(xconf); } -struct newd_conf * +struct smtpfd_conf * config_new_empty(void) { - struct newd_conf *xconf; + struct smtpfd_conf *xconf; xconf = calloc(1, sizeof(*xconf)); if (xconf == NULL) @@ -623,9 +623,9 @@ config_new_empty(void) } void -config_clear(struct newd_conf *conf) +config_clear(struct smtpfd_conf *conf) { - struct newd_conf *xconf; + struct smtpfd_conf *xconf; /* Merge current config with an empty config. */ xconf = config_new_empty(); diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 715e956..4d42d4c 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -72,7 +72,7 @@ struct group { struct in6_addr group_v6address; }; -struct newd_conf { +struct smtpfd_conf { int yesno; int integer; char global_text[NEWD_MAXTEXT]; @@ -104,17 +104,17 @@ extern uint32_t cmd_opts; /* newd.c */ void main_imsg_compose_frontend(int, pid_t, void *, uint16_t); void main_imsg_compose_engine(int, pid_t, void *, uint16_t); -void merge_config(struct newd_conf *, struct newd_conf *); +void merge_config(struct smtpfd_conf *, struct smtpfd_conf *); void imsg_event_add(struct imsgev *); int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t, int, void *, uint16_t); -struct newd_conf *config_new_empty(void); -void config_clear(struct newd_conf *); +struct smtpfd_conf *config_new_empty(void); +void config_clear(struct smtpfd_conf *); /* printconf.c */ -void print_config(struct newd_conf *); +void print_config(struct smtpfd_conf *); /* parse.y */ -struct newd_conf *parse_config(char *); +struct smtpfd_conf *parse_config(char *); int cmdline_symset(char *); From e2c574db7d06193c4bb5ce517847c0e0c9fd0d15 Mon Sep 17 00:00:00 2001 From: Sunil Nimmagadda Date: Sat, 20 May 2017 17:30:31 +0530 Subject: [PATCH 04/41] s/newd_process/smtpfd_process. --- extras/filters/smtpfd/engine.c | 6 +++--- extras/filters/smtpfd/frontend.c | 6 +++--- extras/filters/smtpfd/smtpfd.c | 6 +++--- extras/filters/smtpfd/smtpfd.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 8e5a72d..cedba78 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -85,9 +85,9 @@ engine(int debug, int verbose) if (chdir("/") == -1) fatal("chdir(\"/\")"); - newd_process = PROC_ENGINE; - setproctitle(log_procnames[newd_process]); - log_procinit(log_procnames[newd_process]); + smtpfd_process = PROC_ENGINE; + setproctitle(log_procnames[smtpfd_process]); + log_procinit(log_procnames[smtpfd_process]); if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 1f06a02..2287629 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -87,9 +87,9 @@ frontend(int debug, int verbose, char *sockname) if (chdir("/") == -1) fatal("chdir(\"/\")"); - newd_process = PROC_FRONTEND; - setproctitle(log_procnames[newd_process]); - log_procinit(log_procnames[newd_process]); + smtpfd_process = PROC_FRONTEND; + setproctitle(log_procnames[smtpfd_process]); + log_procinit(log_procnames[smtpfd_process]); if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index d193967..7123724 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -206,9 +206,9 @@ main(int argc, char *argv[]) frontend_pid = start_child(PROC_FRONTEND, saved_argv0, pipe_main2frontend[1], debug, cmd_opts & OPT_VERBOSE, csock); - newd_process = PROC_MAIN; - setproctitle(log_procnames[newd_process]); - log_procinit(log_procnames[newd_process]); + smtpfd_process = PROC_MAIN; + setproctitle(log_procnames[smtpfd_process]); + log_procinit(log_procnames[smtpfd_process]); event_init(); diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 4d42d4c..d5cd519 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -59,7 +59,7 @@ enum { PROC_MAIN, PROC_ENGINE, PROC_FRONTEND -} newd_process; +} smtpfd_process; struct group { LIST_ENTRY(group) entry; From 29158c876a33db3408fcf64f552f324e415213c5 Mon Sep 17 00:00:00 2001 From: Sunil Nimmagadda Date: Sat, 20 May 2017 17:42:07 +0530 Subject: [PATCH 05/41] Replace remaining 'newd' with 'smtpfd'. --- extras/filters/smtpfd/engine.c | 2 +- extras/filters/smtpfd/frontend.c | 2 +- extras/filters/smtpfd/smtpfd.8 | 14 +++++++------- extras/filters/smtpfd/smtpfd.c | 2 +- extras/filters/smtpfd/smtpfd.conf.5 | 22 +++++++++++----------- extras/filters/smtpfd/smtpfd.h | 16 ++++++++-------- 6 files changed, 29 insertions(+), 29 deletions(-) diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index cedba78..940f536 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -303,7 +303,7 @@ engine_dispatch_main(int fd, short event, void *bula) void engine_showinfo_ctl(struct imsg *imsg) { - char filter[NEWD_MAXGROUPNAME]; + char filter[SMTPFD_MAXGROUPNAME]; struct ctl_engine_info cei; struct group *g; diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 2287629..6abe5e2 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -75,7 +75,7 @@ frontend(int debug, int verbose, char *sockname) log_init(debug, LOG_DAEMON); log_setverbose(verbose); - /* Create newd control socket outside chroot. */ + /* Create smtpfd control socket outside chroot. */ if (control_init(sockname) == -1) fatalx("control socket setup failed"); diff --git a/extras/filters/smtpfd/smtpfd.8 b/extras/filters/smtpfd/smtpfd.8 index 5c8c1ed..77ab9d8 100644 --- a/extras/filters/smtpfd/smtpfd.8 +++ b/extras/filters/smtpfd/smtpfd.8 @@ -15,10 +15,10 @@ .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate: July 27 2015 $ -.Dt NEWD 8 +.Dt SMTPFD 8 .Os .Sh NAME -.Nm newd +.Nm smtpfd .Nd sample daemon .Sh SYNOPSIS .Nm @@ -37,7 +37,7 @@ is usually started at boot time, and can be enabled by setting the following in .Pa /etc/rc.conf.local : .Pp -.Dl newd_flags=\&"\&" +.Dl smtpfd_flags=\&"\&" .Pp See .Xr rc 8 @@ -71,18 +71,18 @@ Use an alternate location for the default control socket. Produce more verbose output. .El .Sh FILES -.Bl -tag -width "/var/run/newd.sockXX" -compact -.It Pa /etc/newd.conf +.Bl -tag -width "/var/run/smtpfd.sockXX" -compact +.It Pa /etc/mail/smtpfd.conf Default .Nm configuration file. -.It Pa /var/run/newd.sock +.It Pa /var/run/smtpfd.sock .Ux Ns -domain socket used for communication with .Xr newctl 8 . .El .Sh SEE ALSO -.Xr newd.conf 5 , +.Xr smtpfd.conf 5 , .Xr newctl 8 .Sh HISTORY The diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 7123724..095c603 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -122,7 +122,7 @@ main(int argc, char *argv[]) saved_argv0 = argv[0]; if (saved_argv0 == NULL) - saved_argv0 = "newd"; + saved_argv0 = "smtpfd"; while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) { switch (ch) { diff --git a/extras/filters/smtpfd/smtpfd.conf.5 b/extras/filters/smtpfd/smtpfd.conf.5 index d88b230..cad6ffd 100644 --- a/extras/filters/smtpfd/smtpfd.conf.5 +++ b/extras/filters/smtpfd/smtpfd.conf.5 @@ -18,14 +18,14 @@ .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate: March 11 2015 $ -.Dt NEWD.CONF 5 +.Dt SMTPFD.CONF 5 .Os .Sh NAME -.Nm newd.conf +.Nm smtpfd.conf .Nd New Daemon configuration file .Sh DESCRIPTION The -.Xr newd 8 +.Xr smtpfd 8 daemon is a skeleton daemon implementing a privileged separated daemon in accord with current .Ox @@ -40,12 +40,12 @@ User-defined variables may be defined and used later, simplifying the configuration file. .It Sy Global Configuration Zero or more -.Xr newd 8 +.Xr smtpfd 8 attibutes. .It Sy Groups Named lists of zero or more -.Xr newd 8 +.Xr smtpfd 8 attributes. .El .Pp @@ -110,7 +110,7 @@ These are .El .Sh EXAMPLE .Bd -literal -offset indent -include "/etc/newd.sub.conf" +include "/etc/mail/smtpfd.sub.conf" hi="5" integer=$hi yesno no; @@ -121,14 +121,14 @@ group Barrymore { } .Ed .Sh FILES -.Bl -tag -width "/etc/newd.conf" -compact -.It Pa /etc/newd.conf -.Xr newd 8 +.Bl -tag -width "/etc/mail/smtpfd.conf" -compact +.It Pa /etc/mail/smtpfd.conf +.Xr smtpfd 8 configuration file .El .Sh SEE ALSO -.Xr newd 8 , -.Xr newdfctl 8 , +.Xr smtpfd 8 , +.Xr smtpfdfctl 8 , .Xr rc.conf.local 8 .Sh HISTORY The diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index d5cd519..dad5321 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -25,8 +25,8 @@ #define OPT_VERBOSE2 0x00000002 #define OPT_NOACTION 0x00000004 -#define NEWD_MAXTEXT 256 -#define NEWD_MAXGROUPNAME 16 +#define SMTPFD_MAXTEXT 256 +#define SMTPFD_MAXGROUPNAME 16 static const char * const log_procnames[] = { "main", @@ -63,7 +63,7 @@ enum { struct group { LIST_ENTRY(group) entry; - char name[NEWD_MAXGROUPNAME]; + char name[SMTPFD_MAXGROUPNAME]; int yesno; int integer; int group_v4_bits; @@ -75,18 +75,18 @@ struct group { struct smtpfd_conf { int yesno; int integer; - char global_text[NEWD_MAXTEXT]; + char global_text[SMTPFD_MAXTEXT]; LIST_HEAD(, group) group_list; }; struct ctl_frontend_info { int yesno; int integer; - char global_text[NEWD_MAXTEXT]; + char global_text[SMTPFD_MAXTEXT]; }; struct ctl_engine_info { - char name[NEWD_MAXGROUPNAME]; + char name[SMTPFD_MAXGROUPNAME]; int yesno; int integer; int group_v4_bits; @@ -96,12 +96,12 @@ struct ctl_engine_info { }; struct ctl_main_info { - char text[NEWD_MAXTEXT]; + char text[SMTPFD_MAXTEXT]; }; extern uint32_t cmd_opts; -/* newd.c */ +/* smtpfd.c */ void main_imsg_compose_frontend(int, pid_t, void *, uint16_t); void main_imsg_compose_engine(int, pid_t, void *, uint16_t); void merge_config(struct smtpfd_conf *, struct smtpfd_conf *); From ffb8bf44880f772dc8c614a563d6f4a5e3a35d8f Mon Sep 17 00:00:00 2001 From: Sunil Nimmagadda Date: Sat, 20 May 2017 17:49:20 +0530 Subject: [PATCH 06/41] Fix mandoc lint warnings. --- extras/filters/smtpfd/smtpfd.conf.5 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/extras/filters/smtpfd/smtpfd.conf.5 b/extras/filters/smtpfd/smtpfd.conf.5 index cad6ffd..0b006f5 100644 --- a/extras/filters/smtpfd/smtpfd.conf.5 +++ b/extras/filters/smtpfd/smtpfd.conf.5 @@ -66,7 +66,8 @@ Attributes with a .Sq global- prefix can be used .Em only -in the global configuration section. These are +in the global configuration section. +These are .Pp .Bl -tag -width Ds -compact .It Ic global-text Ar string @@ -79,7 +80,8 @@ A group is a named list of attributes, specified with .Pp Attibutes with the .Sq group- -prefix can be used only a group. These are +prefix can be used only a group. +These are .Pp .Bl -tag -width Ds -compact .It Ic group-v4address Ar IPv4address @@ -127,9 +129,9 @@ group Barrymore { configuration file .El .Sh SEE ALSO +.Xr rc.conf.local 8 , .Xr smtpfd 8 , -.Xr smtpfdfctl 8 , -.Xr rc.conf.local 8 +.Xr smtpfdfctl 8 .Sh HISTORY The .Nm From 715fb9012793766da860b428acab055337782c40 Mon Sep 17 00:00:00 2001 From: Sunil Nimmagadda Date: Sat, 20 May 2017 18:21:04 +0530 Subject: [PATCH 07/41] unlink(2) requires cpath in pledge. Fixes a crash on SIGINT. --- extras/filters/smtpfd/smtpfd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 095c603..7bf2da9 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -246,7 +246,7 @@ main(int argc, char *argv[]) fatal("could not establish imsg links"); main_imsg_send_config(main_conf); - if (pledge("rpath stdio sendfd", NULL) == -1) + if (pledge("rpath stdio sendfd cpath", NULL) == -1) fatal("pledge"); event_dispatch(); From 50e5fe7a4b3c541b947f18aba19cc42a8bb52f9d Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Tue, 23 May 2017 16:54:30 +0200 Subject: [PATCH 08/41] remove sample implementation for process info --- extras/filters/smtpfd/engine.c | 25 ------------------------- extras/filters/smtpfd/frontend.c | 8 +------- extras/filters/smtpfd/smtpfd.c | 17 ----------------- extras/filters/smtpfd/smtpfd.h | 11 ----------- 4 files changed, 1 insertion(+), 60 deletions(-) diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 940f536..153f838 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -303,33 +303,8 @@ engine_dispatch_main(int fd, short event, void *bula) void engine_showinfo_ctl(struct imsg *imsg) { - char filter[SMTPFD_MAXGROUPNAME]; - struct ctl_engine_info cei; - struct group *g; - switch (imsg->hdr.type) { case IMSG_CTL_SHOW_ENGINE_INFO: - memcpy(filter, imsg->data, sizeof(filter)); - LIST_FOREACH(g, &engine_conf->group_list, entry) { - if (filter[0] == '\0' || memcmp(filter, g->name, - sizeof(filter)) == 0) { - memcpy(cei.name, g->name, sizeof(cei.name)); - cei.yesno = g->yesno; - cei.integer = g->integer; - cei.group_v4_bits = g->group_v4_bits; - cei.group_v6_bits = g->group_v6_bits; - memcpy(&cei.group_v4address, - &g->group_v4address, - sizeof(cei.group_v4address)); - memcpy(&cei.group_v6address, - &g->group_v6address, - sizeof(cei.group_v6address)); - - engine_imsg_compose_frontend( - IMSG_CTL_SHOW_ENGINE_INFO, imsg->hdr.pid, - &cei, sizeof(cei)); - } - } engine_imsg_compose_frontend(IMSG_CTL_END, imsg->hdr.pid, NULL, 0); break; diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 6abe5e2..816e2fe 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -311,13 +311,7 @@ frontend_dispatch_engine(int fd, short event, void *bula) void frontend_showinfo_ctl(struct ctl_conn *c) { - static struct ctl_frontend_info cfi; - - cfi.yesno = frontend_conf->yesno; - cfi.integer = frontend_conf->integer; - - memcpy(cfi.global_text, frontend_conf->global_text, - sizeof(cfi.global_text)); + struct ctl_frontend_info cfi; imsg_compose_event(&c->iev, IMSG_CTL_SHOW_FRONTEND_INFO, 0, 0, -1, &cfi, sizeof(struct ctl_frontend_info)); diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 7bf2da9..b9e81d3 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -555,25 +555,8 @@ main_sendboth(enum imsg_type type, void *buf, uint16_t len) void main_showinfo_ctl(struct imsg *imsg) { - struct ctl_main_info cmi; - size_t n; - switch (imsg->hdr.type) { case IMSG_CTL_SHOW_MAIN_INFO: - memset(cmi.text, 0, sizeof(cmi.text)); - n = strlcpy(cmi.text, "I'm a little teapot.", - sizeof(cmi.text)); - if (n >= sizeof(cmi.text)) - log_debug("%s: I was cut off!", __func__); - main_imsg_compose_frontend(IMSG_CTL_SHOW_MAIN_INFO, - imsg->hdr.pid, &cmi, sizeof(cmi)); - memset(cmi.text, 0, sizeof(cmi.text)); - n = strlcpy(cmi.text, "Full of sencha.", - sizeof(cmi.text)); - if (n >= sizeof(cmi.text)) - log_debug("%s: I was cut off!", __func__); - main_imsg_compose_frontend(IMSG_CTL_SHOW_MAIN_INFO, - imsg->hdr.pid, &cmi, sizeof(cmi)); main_imsg_compose_frontend(IMSG_CTL_END, imsg->hdr.pid, NULL, 0); break; diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index dad5321..5f07a73 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -80,23 +80,12 @@ struct smtpfd_conf { }; struct ctl_frontend_info { - int yesno; - int integer; - char global_text[SMTPFD_MAXTEXT]; }; struct ctl_engine_info { - char name[SMTPFD_MAXGROUPNAME]; - int yesno; - int integer; - int group_v4_bits; - int group_v6_bits; - struct in_addr group_v4address; - struct in6_addr group_v6address; }; struct ctl_main_info { - char text[SMTPFD_MAXTEXT]; }; extern uint32_t cmd_opts; From b12ed3b521f37de481c94074d88a4e6263144ece Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Wed, 24 May 2017 18:56:49 +0200 Subject: [PATCH 09/41] introduce a helper layer for imsg process management. make the frontend process use it. --- extras/filters/smtpfd/Makefile | 1 + extras/filters/smtpfd/frontend.c | 221 ++++++++--------------- extras/filters/smtpfd/frontend.h | 6 +- extras/filters/smtpfd/proc.c | 296 +++++++++++++++++++++++++++++++ extras/filters/smtpfd/proc.h | 38 ++++ 5 files changed, 412 insertions(+), 150 deletions(-) create mode 100644 extras/filters/smtpfd/proc.c create mode 100644 extras/filters/smtpfd/proc.h diff --git a/extras/filters/smtpfd/Makefile b/extras/filters/smtpfd/Makefile index 61658fd..038b871 100644 --- a/extras/filters/smtpfd/Makefile +++ b/extras/filters/smtpfd/Makefile @@ -2,6 +2,7 @@ PROG= smtpfd SRCS= control.c engine.c frontend.c log.c smtpfd.c parse.y printconf.c +SRCS+= proc.c MAN= smtpfd.8 smtpfd.conf.5 diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 816e2fe..d295267 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -36,6 +36,7 @@ #include #include "log.h" +#include "proc.h" #include "smtpfd.h" #include "frontend.h" #include "control.h" @@ -44,8 +45,8 @@ __dead void frontend_shutdown(void); void frontend_sig_handler(int, short, void *); struct smtpfd_conf *frontend_conf; -struct imsgev *iev_main; -struct imsgev *iev_engine; +struct imsgproc *p_main; +struct imsgproc *p_engine; void frontend_sig_handler(int sig, short event, void *bula) @@ -110,14 +111,9 @@ frontend(int debug, int verbose, char *sockname) signal(SIGHUP, SIG_IGN); /* Setup pipe and event handler to the parent process. */ - if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) - fatal(NULL); - imsg_init(&iev_main->ibuf, 3); - iev_main->handler = frontend_dispatch_main; - iev_main->events = EV_READ; - event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, - iev_main->handler, iev_main); - event_add(&iev_main->ev, NULL); + p_main = proc_attach(PROC_MAIN, 3); + proc_setcallback(p_main, frontend_dispatch_main, NULL); + proc_enable(p_main); /* Listen on control socket. */ TAILQ_INIT(&ctl_conns); @@ -132,18 +128,11 @@ __dead void frontend_shutdown(void) { /* Close pipes. */ - msgbuf_write(&iev_engine->ibuf.w); - msgbuf_clear(&iev_engine->ibuf.w); - close(iev_engine->ibuf.fd); - msgbuf_write(&iev_main->ibuf.w); - msgbuf_clear(&iev_main->ibuf.w); - close(iev_main->ibuf.fd); + proc_free(p_engine); + proc_free(p_main); config_clear(frontend_conf); - free(iev_engine); - free(iev_main); - log_info("frontend exiting"); exit(0); } @@ -152,159 +141,95 @@ int frontend_imsg_compose_main(int type, pid_t pid, void *data, uint16_t datalen) { - return (imsg_compose_event(iev_main, type, 0, pid, -1, data, - datalen)); + return proc_compose(p_main, type, 0, pid, -1, data, datalen); } int frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, void *data, uint16_t datalen) { - return (imsg_compose_event(iev_engine, type, peerid, pid, -1, - data, datalen)); + return proc_compose(p_engine, type, peerid, pid, -1, data, datalen); } void -frontend_dispatch_main(int fd, short event, void *bula) +frontend_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *arg) { static struct smtpfd_conf *nconf; - struct imsg imsg; struct group *g; - struct imsgev *iev = bula; - struct imsgbuf *ibuf = &iev->ibuf; - int n, shut = 0; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* Connection closed. */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("msgbuf_write"); - if (n == 0) /* Connection closed. */ - shut = 1; - } + int fd; - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("%s: imsg_get error", __func__); - if (n == 0) /* No more messages. */ - break; + if (imsg == NULL) { + event_loopexit(NULL); + return; + } - switch (imsg.hdr.type) { - case IMSG_SOCKET_IPC: - /* - * Setup pipe and event handler to the engine - * process. - */ - if (iev_engine) { - log_warnx("%s: received unexpected imsg fd " - "to frontend", __func__); - break; - } - if ((fd = imsg.fd) == -1) { - log_warnx("%s: expected to receive imsg fd to " - "frontend but didn't receive any", - __func__); - break; - } - - iev_engine = malloc(sizeof(struct imsgev)); - if (iev_engine == NULL) - fatal(NULL); - - imsg_init(&iev_engine->ibuf, fd); - iev_engine->handler = frontend_dispatch_engine; - iev_engine->events = EV_READ; - - event_set(&iev_engine->ev, iev_engine->ibuf.fd, - iev_engine->events, iev_engine->handler, iev_engine); - event_add(&iev_engine->ev, NULL); - break; - case IMSG_RECONF_CONF: - if ((nconf = malloc(sizeof(struct smtpfd_conf))) == - NULL) - fatal(NULL); - memcpy(nconf, imsg.data, sizeof(struct smtpfd_conf)); - LIST_INIT(&nconf->group_list); + switch (imsg->hdr.type) { + case IMSG_SOCKET_IPC: + /* + * Setup pipe and event handler to the engine + * process. + */ + if (p_engine) { + log_warnx("%s: received unexpected imsg fd " + "to frontend", __func__); break; - case IMSG_RECONF_GROUP: - if ((g = malloc(sizeof(struct group))) == NULL) - fatal(NULL); - memcpy(g, imsg.data, sizeof(struct group)); - LIST_INSERT_HEAD(&nconf->group_list, g, entry); - break; - case IMSG_RECONF_END: - merge_config(frontend_conf, nconf); - nconf = NULL; - break; - case IMSG_CTL_END: - case IMSG_CTL_SHOW_MAIN_INFO: - control_imsg_relay(&imsg); - break; - default: - log_debug("%s: error handling imsg %d", __func__, - imsg.hdr.type); + } + if ((fd = imsg->fd) == -1) { + log_warnx("%s: expected to receive imsg fd to " + "frontend but didn't receive any", + __func__); break; } - imsg_free(&imsg); - } - if (!shut) - imsg_event_add(iev); - else { - /* This pipe is dead. Remove its event handler. */ - event_del(&iev->ev); - event_loopexit(NULL); + + p_engine = proc_attach(PROC_ENGINE, fd); + proc_setcallback(p_engine, frontend_dispatch_engine, NULL); + proc_enable(p_engine); + break; + case IMSG_RECONF_CONF: + if ((nconf = malloc(sizeof(struct smtpfd_conf))) == + NULL) + fatal(NULL); + memcpy(nconf, imsg->data, sizeof(struct smtpfd_conf)); + LIST_INIT(&nconf->group_list); + break; + case IMSG_RECONF_GROUP: + if ((g = malloc(sizeof(struct group))) == NULL) + fatal(NULL); + memcpy(g, imsg->data, sizeof(struct group)); + LIST_INSERT_HEAD(&nconf->group_list, g, entry); + break; + case IMSG_RECONF_END: + merge_config(frontend_conf, nconf); + nconf = NULL; + break; + case IMSG_CTL_END: + case IMSG_CTL_SHOW_MAIN_INFO: + control_imsg_relay(imsg); + break; + default: + log_debug("%s: error handling imsg %d", __func__, + imsg->hdr.type); + break; } } void -frontend_dispatch_engine(int fd, short event, void *bula) +frontend_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) { - struct imsgev *iev = bula; - struct imsgbuf *ibuf = &iev->ibuf; - struct imsg imsg; - int n, shut = 0; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* Connection closed. */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("msgbuf_write"); - if (n == 0) /* Connection closed. */ - shut = 1; + if (imsg == NULL) { + event_loopexit(NULL); + return; } - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("%s: imsg_get error", __func__); - if (n == 0) /* No more messages. */ - break; - - switch (imsg.hdr.type) { - case IMSG_CTL_END: - case IMSG_CTL_SHOW_ENGINE_INFO: - control_imsg_relay(&imsg); - break; - default: - log_debug("%s: error handling imsg %d", __func__, - imsg.hdr.type); - break; - } - imsg_free(&imsg); - } - if (!shut) - imsg_event_add(iev); - else { - /* This pipe is dead. Remove its event handler. */ - event_del(&iev->ev); - event_loopexit(NULL); + switch (imsg->hdr.type) { + case IMSG_CTL_END: + case IMSG_CTL_SHOW_ENGINE_INFO: + control_imsg_relay(imsg); + break; + default: + log_debug("%s: error handling imsg %d", __func__, + imsg->hdr.type); + break; } } diff --git a/extras/filters/smtpfd/frontend.h b/extras/filters/smtpfd/frontend.h index 3dcdf6e..370a686 100644 --- a/extras/filters/smtpfd/frontend.h +++ b/extras/filters/smtpfd/frontend.h @@ -18,9 +18,11 @@ TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns; +struct imsgproc; + void frontend(int, int, char *); -void frontend_dispatch_main(int, short, void *); -void frontend_dispatch_engine(int, short, void *); +void frontend_dispatch_main(struct imsgproc *, struct imsg *, void *); +void frontend_dispatch_engine(struct imsgproc *, struct imsg *, void *); int frontend_imsg_compose_main(int, pid_t, void *, uint16_t); int frontend_imsg_compose_engine(int, uint32_t, pid_t, void *, uint16_t); diff --git a/extras/filters/smtpfd/proc.c b/extras/filters/smtpfd/proc.c new file mode 100644 index 0000000..5203dc7 --- /dev/null +++ b/extras/filters/smtpfd/proc.c @@ -0,0 +1,296 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2016-2017 Eric Faurot + * + * 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 +#include + +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "proc.h" + +struct imsgproc { + TAILQ_ENTRY(imsgproc) tqe; + int type; + int instance; + char *title; + pid_t pid; + void *arg; + void (*cb)(struct imsgproc *, struct imsg *, void *); + struct imsgbuf imsgbuf; + short events; + struct event ev; +}; + +static struct imsgproc *proc_new(int); +static void proc_setsock(struct imsgproc *, int); +static void proc_callback(struct imsgproc *, struct imsg *); +static void proc_dispatch(int, short, void *); +static void proc_event_add(struct imsgproc *); + +static TAILQ_HEAD(, imsgproc) procs = TAILQ_HEAD_INITIALIZER(procs); + +pid_t +proc_getpid(struct imsgproc *p) +{ + return p->pid; +} + +int +proc_gettype(struct imsgproc *p) +{ + return p->type; +} + +int +proc_getinstance(struct imsgproc *p) +{ + return p->instance; +} + +const char * +proc_gettitle(struct imsgproc *p) +{ + return p->title; +} + +struct imsgproc * +proc_bypid(pid_t pid) +{ + struct imsgproc *p; + + TAILQ_FOREACH(p, &procs, tqe) + if (pid == p->pid) + return p; + + return NULL; +} + +struct imsgproc * +proc_exec(int type, char **argv) +{ + struct imsgproc *p; + int sp[2]; + pid_t pid; + + p = proc_new(type); + if (p == NULL) + fatal("proc_exec: calloc"); + + if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, PF_UNSPEC, sp) == -1) + fatal("proc_exec: socketpair"); + + switch (pid = fork()) { + case -1: + fatal("proc_exec: fork"); + case 0: + break; + default: + close(sp[0]); + p->pid = pid; + proc_setsock(p, sp[1]); + return p; + } + + if (dup2(sp[0], 3) == -1) + fatal("proc_exec: dup2"); + + if (closefrom(4) == -1) + fatal("proc_exec: closefrom"); + + execvp(argv[0], argv); + fatal("proc_exec: execvp: %s", argv[0]); +} + +struct imsgproc * +proc_attach(int type, int fd) +{ + struct imsgproc *p; + + p = proc_new(type); + if (p == NULL) + fatal("proc_exec: calloc"); + + proc_setsock(p, fd); + return p; +} + +void +proc_settitle(struct imsgproc *p, const char *title) +{ + free(p->title); + if (title) { + p->title = strdup(title); + if (p->title == NULL) + fatal("proc_title: strdup"); + } + else + p->title = NULL; +} + +void +proc_setcallback(struct imsgproc *p, + void(*cb)(struct imsgproc *, struct imsg *, void *), void *arg) +{ + p->cb = cb; + p->arg = arg; +} + +void +proc_enable(struct imsgproc *p) +{ + proc_event_add(p); +} + +void +proc_free(struct imsgproc *p) +{ + + if (p == NULL) + return; + + TAILQ_REMOVE(&procs, p, tqe); + + event_del(&p->ev); + close(p->imsgbuf.fd); + imsg_clear(&p->imsgbuf); + free(p->title); + free(p); +} + +static struct imsgproc * +proc_new(int type) +{ + struct imsgproc *p; + + p = calloc(1, sizeof(*p)); + if (p == NULL) + return NULL; + + p->type = type; + p->instance = -1; + p->pid = -1; + imsg_init(&p->imsgbuf, -1); + + TAILQ_INSERT_TAIL(&procs, p, tqe); + + return p; +} + +static void +proc_setsock(struct imsgproc *p, int sock) +{ + p->imsgbuf.fd = sock; + p->imsgbuf.w.fd = sock; +} + +static void +proc_event_add(struct imsgproc *p) +{ + short events; + + events = EV_READ; + if (p->imsgbuf.w.queued) + events |= EV_WRITE; + + if (p->events) + event_del(&p->ev); + + p->events = events; + if (events) { + event_set(&p->ev, p->imsgbuf.fd, events, proc_dispatch, p); + event_add(&p->ev, NULL); + } +} + +static void +proc_callback(struct imsgproc *p, struct imsg *imsg) +{ + p->cb(p, imsg, p->arg); +} + +static void +proc_dispatch(int fd, short event, void *arg) +{ + struct imsgproc *p = arg; + struct imsg imsg; + ssize_t n; + + p->events = 0; + + if (event & EV_READ) { + + n = imsg_read(&p->imsgbuf); + + switch (n) { + case -1: + if (errno == EAGAIN) + return; + fatal("proc_dispatch: imsg_read"); + /* NOTREACHED */ + case 0: + /* this pipe is dead, so remove the event handler */ + proc_callback(p, NULL); + return; + default: + break; + } + } + + if (event & EV_WRITE) { + n = msgbuf_write(&p->imsgbuf.w); + if (n == 0 || (n == -1 && errno != EAGAIN)) { + /* this pipe is dead, so remove the event handler */ + proc_callback(p, NULL); + return; + } + } + + for (;;) { + if ((n = imsg_get(&p->imsgbuf, &imsg)) == -1) { + log_warn("proc_dispatch: imsg_get"); + proc_callback(p, NULL); + return; + } + if (n == 0) + break; + + proc_callback(p, &imsg); + imsg_free(&imsg); + } + + proc_event_add(p); +} + +int +proc_compose(struct imsgproc *p, int type, uint32_t peerid, pid_t pid, int fd, + void *data, uint16_t datalen) +{ + int r; + + r = imsg_compose(&p->imsgbuf, type, peerid, pid, fd, data, datalen); + if (r != -1) + proc_event_add(p); + + return r; +} diff --git a/extras/filters/smtpfd/proc.h b/extras/filters/smtpfd/proc.h new file mode 100644 index 0000000..9f7dc1f --- /dev/null +++ b/extras/filters/smtpfd/proc.h @@ -0,0 +1,38 @@ +/* $OpenBSD: log.h,v 1.7 2017/01/09 14:49:22 reyk Exp $ */ + +/* + * Copyright (c) 2017 Eric Faurot + * + * 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 + +struct imsgproc; + +/* proc.c */ +struct imsgproc *proc_bypid(pid_t); +struct imsgproc *proc_exec(int, char **); +struct imsgproc *proc_attach(int, int); +void proc_enable(struct imsgproc *); +void proc_free(struct imsgproc *); +pid_t proc_getpid(struct imsgproc *); +int proc_gettype(struct imsgproc *); +int proc_getinstance(struct imsgproc *); +const char *proc_gettitle(struct imsgproc *); +void proc_settitle(struct imsgproc *, const char *); +void proc_setinstance(struct imsgproc *, int); +void proc_setcallback(struct imsgproc *, + void(*)(struct imsgproc *, struct imsg *, void *), void *); +int proc_compose(struct imsgproc *, int, uint32_t, pid_t, int, void *, + uint16_t); From 2eae71faa11e4c1f531bf5c2141d261ef403676e Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Wed, 24 May 2017 19:08:31 +0200 Subject: [PATCH 10/41] convert engine.c to use the procimsg abstraction --- extras/filters/smtpfd/engine.c | 234 +++++++++++---------------------- 1 file changed, 78 insertions(+), 156 deletions(-) diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 153f838..3abcd47 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -36,18 +36,19 @@ #include #include "log.h" +#include "proc.h" #include "smtpfd.h" #include "engine.h" __dead void engine_shutdown(void); void engine_sig_handler(int sig, short, void *); -void engine_dispatch_frontend(int, short, void *); -void engine_dispatch_main(int, short, void *); +void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *); +void engine_dispatch_main(struct imsgproc *, struct imsg *, void *); void engine_showinfo_ctl(struct imsg *); struct smtpfd_conf *engine_conf; -struct imsgev *iev_frontend; -struct imsgev *iev_main; +struct imsgproc *p_frontend; +struct imsgproc *p_main; void engine_sig_handler(int sig, short event, void *arg) @@ -108,17 +109,9 @@ engine(int debug, int verbose) signal(SIGHUP, SIG_IGN); /* Setup pipe and event handler to the main process. */ - if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) - fatal(NULL); - - imsg_init(&iev_main->ibuf, 3); - iev_main->handler = engine_dispatch_main; - - /* Setup event handlers. */ - iev_main->events = EV_READ; - event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, - iev_main->handler, iev_main); - event_add(&iev_main->ev, NULL); + p_main = proc_attach(PROC_MAIN, 3); + proc_setcallback(p_main, engine_dispatch_main, NULL); + proc_enable(p_main); event_dispatch(); @@ -129,16 +122,11 @@ __dead void engine_shutdown(void) { /* Close pipes. */ - msgbuf_clear(&iev_frontend->ibuf.w); - close(iev_frontend->ibuf.fd); - msgbuf_clear(&iev_main->ibuf.w); - close(iev_main->ibuf.fd); + proc_free(p_main); + proc_free(p_frontend); config_clear(engine_conf); - free(iev_frontend); - free(iev_main); - log_info("engine exiting"); exit(0); } @@ -147,156 +135,90 @@ int engine_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) { - return (imsg_compose_event(iev_frontend, type, 0, pid, -1, - data, datalen)); + return proc_compose(p_frontend, type, 0, pid, -1, data, datalen); } void -engine_dispatch_frontend(int fd, short event, void *bula) +engine_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *bula) { - struct imsgev *iev = bula; - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; - int shut = 0, verbose; - - ibuf = &iev->ibuf; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* Connection closed. */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("msgbuf_write"); - if (n == 0) /* Connection closed. */ - shut = 1; - } + int verbose; - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("%s: imsg_get error", __func__); - if (n == 0) /* No more messages. */ - break; - - switch (imsg.hdr.type) { - case IMSG_CTL_LOG_VERBOSE: - /* Already checked by frontend. */ - memcpy(&verbose, imsg.data, sizeof(verbose)); - log_setverbose(verbose); - break; - case IMSG_CTL_SHOW_ENGINE_INFO: - engine_showinfo_ctl(&imsg); - break; - default: - log_debug("%s: unexpected imsg %d", __func__, - imsg.hdr.type); - break; - } - imsg_free(&imsg); - } - if (!shut) - imsg_event_add(iev); - else { - /* This pipe is dead. Remove its event handler. */ - event_del(&iev->ev); + if (imsg == NULL) { event_loopexit(NULL); + return; + } + + switch (imsg->hdr.type) { + case IMSG_CTL_LOG_VERBOSE: + /* Already checked by frontend. */ + memcpy(&verbose, imsg->data, sizeof(verbose)); + log_setverbose(verbose); + break; + case IMSG_CTL_SHOW_ENGINE_INFO: + engine_showinfo_ctl(imsg); + break; + default: + log_debug("%s: unexpected imsg %d", __func__, + imsg->hdr.type); + break; } } void -engine_dispatch_main(int fd, short event, void *bula) +engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) { - static struct smtpfd_conf *nconf; - struct imsg imsg; - struct group *g; - struct imsgev *iev = bula; - struct imsgbuf *ibuf; - ssize_t n; - int shut = 0; - - ibuf = &iev->ibuf; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* Connection closed. */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("msgbuf_write"); - if (n == 0) /* Connection closed. */ - shut = 1; - } + static struct smtpfd_conf *nconf; + struct group *g; - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("%s: imsg_get error", __func__); - if (n == 0) /* No more messages. */ - break; + if (imsg == NULL) { + event_loopexit(NULL); + return; + } - switch (imsg.hdr.type) { - case IMSG_SOCKET_IPC: - /* - * Setup pipe and event handler to the frontend - * process. - */ - if (iev_frontend) { - log_warnx("%s: received unexpected imsg fd " - "to engine", __func__); - break; - } - if ((fd = imsg.fd) == -1) { - log_warnx("%s: expected to receive imsg fd to " - "engine but didn't receive any", __func__); - break; - } - - iev_frontend = malloc(sizeof(struct imsgev)); - if (iev_frontend == NULL) - fatal(NULL); - - imsg_init(&iev_frontend->ibuf, fd); - iev_frontend->handler = engine_dispatch_frontend; - iev_frontend->events = EV_READ; - - event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, - iev_frontend->events, iev_frontend->handler, - iev_frontend); - event_add(&iev_frontend->ev, NULL); - break; - case IMSG_RECONF_CONF: - if ((nconf = malloc(sizeof(struct smtpfd_conf))) == NULL) - fatal(NULL); - memcpy(nconf, imsg.data, sizeof(struct smtpfd_conf)); - LIST_INIT(&nconf->group_list); - break; - case IMSG_RECONF_GROUP: - if ((g = malloc(sizeof(struct group))) == NULL) - fatal(NULL); - memcpy(g, imsg.data, sizeof(struct group)); - LIST_INSERT_HEAD(&nconf->group_list, g, entry); - break; - case IMSG_RECONF_END: - merge_config(engine_conf, nconf); - nconf = NULL; + switch (imsg->hdr.type) { + case IMSG_SOCKET_IPC: + /* + * Setup pipe and event handler to the frontend + * process. + */ + if (p_frontend) { + log_warnx("%s: received unexpected imsg fd " + "to engine", __func__); break; - default: - log_debug("%s: unexpected imsg %d", __func__, - imsg.hdr.type); + } + if (imsg->fd == -1) { + log_warnx("%s: expected to receive imsg fd to " + "engine but didn't receive any", __func__); break; } - imsg_free(&imsg); - } - if (!shut) - imsg_event_add(iev); - else { - /* This pipe is dead. Remove its event handler. */ - event_del(&iev->ev); - event_loopexit(NULL); + + p_frontend = proc_attach(PROC_FRONTEND, imsg->fd); + if (p_frontend == NULL) + fatal(NULL); + + proc_setcallback(p_frontend, engine_dispatch_frontend, NULL); + proc_enable(p_frontend); + break; + case IMSG_RECONF_CONF: + if ((nconf = malloc(sizeof(struct smtpfd_conf))) == NULL) + fatal(NULL); + memcpy(nconf, imsg->data, sizeof(struct smtpfd_conf)); + LIST_INIT(&nconf->group_list); + break; + case IMSG_RECONF_GROUP: + if ((g = malloc(sizeof(struct group))) == NULL) + fatal(NULL); + memcpy(g, imsg->data, sizeof(struct group)); + LIST_INSERT_HEAD(&nconf->group_list, g, entry); + break; + case IMSG_RECONF_END: + merge_config(engine_conf, nconf); + nconf = NULL; + break; + default: + log_debug("%s: unexpected imsg %d", __func__, + imsg->hdr.type); + break; } } From ae02db525497265a592214d26a6d3ec7b0f589c5 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Wed, 24 May 2017 21:49:20 +0200 Subject: [PATCH 11/41] use imsgproc abstraction for main process. --- extras/filters/smtpfd/smtpfd.c | 301 +++++++++------------------------ 1 file changed, 81 insertions(+), 220 deletions(-) diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index b9e81d3..6b1a5db 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -38,6 +38,7 @@ #include #include "log.h" +#include "proc.h" #include "smtpfd.h" #include "frontend.h" #include "engine.h" @@ -48,12 +49,8 @@ __dead void main_shutdown(void); void main_sig_handler(int, short, void *); -static pid_t start_child(int, char *, int, int, int, char *); - -void main_dispatch_frontend(int, short, void *); -void main_dispatch_engine(int, short, void *); - -static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); +void main_dispatch_frontend(struct imsgproc *, struct imsg*, void *); +void main_dispatch_engine(struct imsgproc *, struct imsg*, void *); static int main_imsg_send_config(struct smtpfd_conf *); int main_reload(void); @@ -61,14 +58,11 @@ int main_sendboth(enum imsg_type, void *, uint16_t); void main_showinfo_ctl(struct imsg *); struct smtpfd_conf *main_conf; -struct imsgev *iev_frontend; -struct imsgev *iev_engine; +struct imsgproc *p_frontend; +struct imsgproc *p_engine; char *conffile; char *csock; -pid_t frontend_pid; -pid_t engine_pid; - uint32_t cmd_opts; void @@ -108,11 +102,10 @@ int main(int argc, char *argv[]) { struct event ev_sigint, ev_sigterm, ev_sighup; - int ch; + int ch, sp[2], rargc = 0; int debug = 0, engine_flag = 0, frontend_flag = 0; char *saved_argv0; - int pipe_main2frontend[2]; - int pipe_main2engine[2]; + char *rargv[7]; conffile = CONF_FILE; csock = SMTPFD_SOCKET; @@ -193,18 +186,21 @@ main(int argc, char *argv[]) log_info("startup"); - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - PF_UNSPEC, pipe_main2frontend) == -1) - fatal("main2frontend socketpair"); - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - PF_UNSPEC, pipe_main2engine) == -1) - fatal("main2engine socketpair"); - - /* Start children. */ - engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1], - debug, cmd_opts & OPT_VERBOSE, NULL); - frontend_pid = start_child(PROC_FRONTEND, saved_argv0, - pipe_main2frontend[1], debug, cmd_opts & OPT_VERBOSE, csock); + rargc = 0; + rargv[rargc++] = saved_argv0; + rargv[rargc++] = "-F"; + if (debug) + rargv[rargc++] = "-d"; + if (cmd_opts & OPT_VERBOSE) + rargv[rargc++] = "-v"; + rargv[rargc++] = "-s"; + rargv[rargc++] = csock; + rargv[rargc++] = NULL; + + p_frontend = proc_exec(PROC_FRONTEND, rargv); + rargv[1] = "-E"; + rargv[argc - 3] = NULL; + p_engine = proc_exec(PROC_ENGINE, rargv); smtpfd_process = PROC_MAIN; setproctitle(log_procnames[smtpfd_process]); @@ -221,29 +217,21 @@ main(int argc, char *argv[]) signal_add(&ev_sighup, NULL); signal(SIGPIPE, SIG_IGN); - /* Setup pipes to children. */ + /* Start children */ + proc_enable(p_frontend); + proc_enable(p_engine); + + /* Connect the two children */ + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + PF_UNSPEC, sp) == -1) + fatal("socketpair"); + if (proc_compose(p_frontend, IMSG_SOCKET_IPC, 0, 0, sp[0], NULL, 0) + == -1) + fatal("proc_compose"); + if (proc_compose(p_engine, IMSG_SOCKET_IPC, 0, 0, sp[1], NULL, 0) + == -1) + fatal("proc_compose"); - if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL || - (iev_engine = malloc(sizeof(struct imsgev))) == NULL) - fatal(NULL); - imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); - iev_frontend->handler = main_dispatch_frontend; - imsg_init(&iev_engine->ibuf, pipe_main2engine[0]); - iev_engine->handler = main_dispatch_engine; - - /* Setup event handlers for pipes to engine & frontend. */ - iev_frontend->events = EV_READ; - event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, - iev_frontend->events, iev_frontend->handler, iev_frontend); - event_add(&iev_frontend->ev, NULL); - - iev_engine->events = EV_READ; - event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events, - iev_engine->handler, iev_engine); - event_add(&iev_engine->ev, NULL); - - if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf)) - fatal("could not establish imsg links"); main_imsg_send_config(main_conf); if (pledge("rpath stdio sendfd cpath", NULL) == -1) @@ -259,13 +247,16 @@ __dead void main_shutdown(void) { pid_t pid; + pid_t frontend_pid; + pid_t engine_pid; int status; + frontend_pid = proc_getpid(p_frontend); + engine_pid = proc_getpid(p_frontend); + /* Close pipes. */ - msgbuf_clear(&iev_frontend->ibuf.w); - close(iev_frontend->ibuf.fd); - msgbuf_clear(&iev_engine->ibuf.w); - close(iev_engine->ibuf.fd); + proc_free(p_frontend); + proc_free(p_engine); config_clear(main_conf); @@ -281,182 +272,72 @@ main_shutdown(void) "frontend", WTERMSIG(status)); } while (pid != -1 || (pid == -1 && errno == EINTR)); - free(iev_frontend); - free(iev_engine); - control_cleanup(csock); log_info("terminating"); exit(0); } -static pid_t -start_child(int p, char *argv0, int fd, int debug, int verbose, char *sockname) +void +main_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *arg) { - char *argv[7]; - int argc = 0; - pid_t pid; + int verbose; - switch (pid = fork()) { - case -1: - fatal("cannot fork"); - case 0: - break; - default: - close(fd); - return (pid); + if (imsg == NULL) { + event_loopexit(NULL); + return; } - if (dup2(fd, 3) == -1) - fatal("cannot setup imsg fd"); - - argv[argc++] = argv0; - switch (p) { - case PROC_MAIN: - fatalx("Can not start main process"); - case PROC_ENGINE: - argv[argc++] = "-E"; + switch (imsg->hdr.type) { + case IMSG_CTL_RELOAD: + if (main_reload() == -1) + log_warnx("configuration reload failed"); + else + log_warnx("configuration reloaded"); break; - case PROC_FRONTEND: - argv[argc++] = "-F"; + case IMSG_CTL_LOG_VERBOSE: + /* Already checked by frontend. */ + memcpy(&verbose, imsg->data, sizeof(verbose)); + log_setverbose(verbose); + break; + case IMSG_CTL_SHOW_MAIN_INFO: + main_showinfo_ctl(imsg); + break; + default: + log_debug("%s: error handling imsg %d", __func__, + imsg->hdr.type); break; } - if (debug) - argv[argc++] = "-d"; - if (verbose) - argv[argc++] = "-v"; - if (sockname) { - argv[argc++] = "-s"; - argv[argc++] = sockname; - } - argv[argc++] = NULL; - - execvp(argv0, argv); - fatal("execvp"); } void -main_dispatch_frontend(int fd, short event, void *bula) +main_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) { - struct imsgev *iev = bula; - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; - int shut = 0, verbose; - - ibuf = &iev->ibuf; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* Connection closed. */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("msgbuf_write"); - if (n == 0) /* Connection closed. */ - shut = 1; - } - - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("imsg_get"); - if (n == 0) /* No more messages. */ - break; - - switch (imsg.hdr.type) { - case IMSG_CTL_RELOAD: - if (main_reload() == -1) - log_warnx("configuration reload failed"); - else - log_warnx("configuration reloaded"); - break; - case IMSG_CTL_LOG_VERBOSE: - /* Already checked by frontend. */ - memcpy(&verbose, imsg.data, sizeof(verbose)); - log_setverbose(verbose); - break; - case IMSG_CTL_SHOW_MAIN_INFO: - main_showinfo_ctl(&imsg); - break; - default: - log_debug("%s: error handling imsg %d", __func__, - imsg.hdr.type); - break; - } - imsg_free(&imsg); - } - if (!shut) - imsg_event_add(iev); - else { - /* This pipe is dead. Remove its event handler */ - event_del(&iev->ev); + if (imsg == NULL) { event_loopexit(NULL); - } -} - -void -main_dispatch_engine(int fd, short event, void *bula) -{ - struct imsgev *iev = bula; - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; - int shut = 0; - - ibuf = &iev->ibuf; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* Connection closed. */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("msgbuf_write"); - if (n == 0) /* Connection closed. */ - shut = 1; + return; } - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("imsg_get"); - if (n == 0) /* No more messages. */ - break; - - switch (imsg.hdr.type) { - default: - log_debug("%s: error handling imsg %d", __func__, - imsg.hdr.type); - break; - } - imsg_free(&imsg); - } - if (!shut) - imsg_event_add(iev); - else { - /* This pipe is dead. Remove its event handler. */ - event_del(&iev->ev); - event_loopexit(NULL); + switch (imsg->hdr.type) { + default: + log_debug("%s: error handling imsg %d", __func__, + imsg->hdr.type); + break; } } void main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) { - if (iev_frontend) - imsg_compose_event(iev_frontend, type, 0, pid, -1, data, - datalen); + if (p_frontend) + proc_compose(p_frontend, type, 0, pid, -1, data, datalen); } void main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) { - if (iev_engine) - imsg_compose_event(iev_engine, type, 0, pid, -1, data, - datalen); + if (p_engine) + proc_compose(p_engine, type, 0, pid, -1, data, datalen); } void @@ -475,7 +356,7 @@ int imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, pid_t pid, int fd, void *data, uint16_t datalen) { - int ret; + int ret; if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, datalen)) != -1) @@ -484,26 +365,6 @@ imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, return (ret); } -static int -main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, - struct imsgbuf *engine_buf) -{ - int pipe_frontend2engine[2]; - - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - PF_UNSPEC, pipe_frontend2engine) == -1) - return (-1); - - if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0, - pipe_frontend2engine[0], NULL, 0) == -1) - return (-1); - if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0, - pipe_frontend2engine[1], NULL, 0) == -1) - return (-1); - - return (0); -} - int main_reload(void) { @@ -545,9 +406,9 @@ main_imsg_send_config(struct smtpfd_conf *xconf) int main_sendboth(enum imsg_type type, void *buf, uint16_t len) { - if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1) + if (proc_compose(p_frontend, type, 0, 0, -1, buf, len) == -1) return (-1); - if (imsg_compose_event(iev_engine, type, 0, 0, -1, buf, len) == -1) + if (proc_compose(p_engine, type, 0, 0, -1, buf, len) == -1) return (-1); return (0); } From 410d86198e0b02ad166790fa41dcf1052fcf83d8 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Fri, 26 May 2017 11:30:40 +0200 Subject: [PATCH 12/41] use imsgproc abstraction for control clients --- extras/filters/smtpfd/control.c | 158 +++++++++++-------------------- extras/filters/smtpfd/control.h | 6 +- extras/filters/smtpfd/frontend.c | 2 +- extras/filters/smtpfd/proc.c | 12 +++ extras/filters/smtpfd/proc.h | 2 + extras/filters/smtpfd/smtpfd.h | 8 +- 6 files changed, 75 insertions(+), 113 deletions(-) diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c index cc49058..22ed824 100644 --- a/extras/filters/smtpfd/control.c +++ b/extras/filters/smtpfd/control.c @@ -33,15 +33,17 @@ #include #include "log.h" +#include "proc.h" #include "smtpfd.h" #include "control.h" #include "frontend.h" #define CONTROL_BACKLOG 5 -struct ctl_conn *control_connbyfd(int); -struct ctl_conn *control_connbypid(pid_t); -void control_close(int); +static struct ctl_conn *control_connbypid(pid_t); +static void control_accept(int, short, void *); +static void control_close(struct ctl_conn *); +static void control_dispatch_imsg(struct imsgproc *, struct imsg *, void *); int control_init(char *path) @@ -151,36 +153,20 @@ control_accept(int listenfd, short event, void *bula) return; } - imsg_init(&c->iev.ibuf, connfd); - c->iev.handler = control_dispatch_imsg; - c->iev.events = EV_READ; - event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, - c->iev.handler, &c->iev); - event_add(&c->iev.ev, NULL); + c->proc = proc_attach(PROC_CLIENT, connfd); + proc_setcallback(c->proc, control_dispatch_imsg, c); + proc_enable(c->proc); TAILQ_INSERT_TAIL(&ctl_conns, c, entry); } -struct ctl_conn * -control_connbyfd(int fd) -{ - struct ctl_conn *c; - - TAILQ_FOREACH(c, &ctl_conns, entry) { - if (c->iev.ibuf.fd == fd) - break; - } - - return (c); -} - struct ctl_conn * control_connbypid(pid_t pid) { struct ctl_conn *c; TAILQ_FOREACH(c, &ctl_conns, entry) { - if (c->iev.ibuf.pid == pid) + if (proc_getpid(c->proc) == pid) break; } @@ -188,20 +174,11 @@ control_connbypid(pid_t pid) } void -control_close(int fd) +control_close(struct ctl_conn *c) { - struct ctl_conn *c; - - if ((c = control_connbyfd(fd)) == NULL) { - log_warnx("%s: fd %d: not found", __func__, fd); - return; - } - - msgbuf_clear(&c->iev.ibuf.w); TAILQ_REMOVE(&ctl_conns, c, entry); - event_del(&c->iev.ev); - close(c->iev.ibuf.fd); + proc_free(c->proc); /* Some file descriptors are available again. */ if (evtimer_pending(&control_state.evt, NULL)) { @@ -213,84 +190,55 @@ control_close(int fd) } void -control_dispatch_imsg(int fd, short event, void *bula) +control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) { - struct ctl_conn *c; - struct imsg imsg; - ssize_t n; - int verbose; + struct ctl_conn *c = arg; + int verbose; - if ((c = control_connbyfd(fd)) == NULL) { - log_warnx("%s: fd %d: not found", __func__, fd); + if (imsg == NULL) { + control_close(c); return; } - if (event & EV_READ) { - if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || - n == 0) { - control_close(fd); - return; - } - } - if (event & EV_WRITE) { - if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { - control_close(fd); - return; - } - } - - for (;;) { - if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { - control_close(fd); - return; - } - if (n == 0) + switch (imsg->hdr.type) { + case IMSG_CTL_RELOAD: + frontend_imsg_compose_main(imsg->hdr.type, 0, NULL, 0); + break; + case IMSG_CTL_LOG_VERBOSE: + if (imsg->hdr.len != IMSG_HEADER_SIZE + + sizeof(verbose)) break; - switch (imsg.hdr.type) { - case IMSG_CTL_RELOAD: - frontend_imsg_compose_main(imsg.hdr.type, 0, NULL, 0); - break; - case IMSG_CTL_LOG_VERBOSE: - if (imsg.hdr.len != IMSG_HEADER_SIZE + - sizeof(verbose)) - break; - - /* Forward to all other processes. */ - frontend_imsg_compose_main(imsg.hdr.type, imsg.hdr.pid, - imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); - frontend_imsg_compose_engine(imsg.hdr.type, 0, - imsg.hdr.pid, imsg.data, - imsg.hdr.len - IMSG_HEADER_SIZE); - - memcpy(&verbose, imsg.data, sizeof(verbose)); - log_setverbose(verbose); - break; - case IMSG_CTL_SHOW_MAIN_INFO: - c->iev.ibuf.pid = imsg.hdr.pid; - frontend_imsg_compose_main(imsg.hdr.type, imsg.hdr.pid, - imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); - break; - case IMSG_CTL_SHOW_FRONTEND_INFO: - frontend_showinfo_ctl(c); - imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, - NULL, 0); - break; - case IMSG_CTL_SHOW_ENGINE_INFO: - c->iev.ibuf.pid = imsg.hdr.pid; - frontend_imsg_compose_engine(imsg.hdr.type, 0, - imsg.hdr.pid, - imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); - break; - default: - log_debug("%s: error handling imsg %d", __func__, - imsg.hdr.type); - break; - } - imsg_free(&imsg); + /* Forward to all other processes. */ + frontend_imsg_compose_main(imsg->hdr.type, imsg->hdr.pid, + imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); + frontend_imsg_compose_engine(imsg->hdr.type, 0, + imsg->hdr.pid, imsg->data, + imsg->hdr.len - IMSG_HEADER_SIZE); + + memcpy(&verbose, imsg->data, sizeof(verbose)); + log_setverbose(verbose); + break; + case IMSG_CTL_SHOW_MAIN_INFO: + proc_setpid(c->proc, imsg->hdr.pid); + frontend_imsg_compose_main(imsg->hdr.type, imsg->hdr.pid, + imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); + break; + case IMSG_CTL_SHOW_FRONTEND_INFO: + frontend_showinfo_ctl(c); + proc_compose(c->proc, IMSG_CTL_END, 0, 0, -1, NULL, 0); + break; + case IMSG_CTL_SHOW_ENGINE_INFO: + proc_setpid(c->proc, imsg->hdr.pid); + frontend_imsg_compose_engine(imsg->hdr.type, 0, + imsg->hdr.pid, + imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); + break; + default: + log_debug("%s: error handling imsg %d", __func__, + imsg->hdr.type); + break; } - - imsg_event_add(&c->iev); } int @@ -301,6 +249,6 @@ control_imsg_relay(struct imsg *imsg) if ((c = control_connbypid(imsg->hdr.pid)) == NULL) return (0); - return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, + return (proc_compose(c->proc, imsg->hdr.type, 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); } diff --git a/extras/filters/smtpfd/control.h b/extras/filters/smtpfd/control.h index 33cf7cb..9d40f8a 100644 --- a/extras/filters/smtpfd/control.h +++ b/extras/filters/smtpfd/control.h @@ -23,13 +23,11 @@ struct { } control_state; struct ctl_conn { - TAILQ_ENTRY(ctl_conn) entry; - struct imsgev iev; + TAILQ_ENTRY(ctl_conn) entry; + struct imsgproc *proc; }; int control_init(char *); int control_listen(void); -void control_accept(int, short, void *); -void control_dispatch_imsg(int, short, void *); int control_imsg_relay(struct imsg *); void control_cleanup(char *); diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index d295267..61b6479 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -238,6 +238,6 @@ frontend_showinfo_ctl(struct ctl_conn *c) { struct ctl_frontend_info cfi; - imsg_compose_event(&c->iev, IMSG_CTL_SHOW_FRONTEND_INFO, 0, 0, -1, + proc_compose(c->proc, IMSG_CTL_SHOW_FRONTEND_INFO, 0, 0, -1, &cfi, sizeof(struct ctl_frontend_info)); } diff --git a/extras/filters/smtpfd/proc.c b/extras/filters/smtpfd/proc.c index 5203dc7..2817df5 100644 --- a/extras/filters/smtpfd/proc.c +++ b/extras/filters/smtpfd/proc.c @@ -50,6 +50,12 @@ static void proc_event_add(struct imsgproc *); static TAILQ_HEAD(, imsgproc) procs = TAILQ_HEAD_INITIALIZER(procs); +int +proc_getfd(struct imsgproc *p) +{ + return p->imsgbuf.fd; +} + pid_t proc_getpid(struct imsgproc *p) { @@ -148,6 +154,12 @@ proc_settitle(struct imsgproc *p, const char *title) p->title = NULL; } +void +proc_setpid(struct imsgproc *p, pid_t pid) +{ + p->pid = pid; +} + void proc_setcallback(struct imsgproc *p, void(*cb)(struct imsgproc *, struct imsg *, void *), void *arg) diff --git a/extras/filters/smtpfd/proc.h b/extras/filters/smtpfd/proc.h index 9f7dc1f..c6a67f7 100644 --- a/extras/filters/smtpfd/proc.h +++ b/extras/filters/smtpfd/proc.h @@ -27,9 +27,11 @@ struct imsgproc *proc_attach(int, int); void proc_enable(struct imsgproc *); void proc_free(struct imsgproc *); pid_t proc_getpid(struct imsgproc *); +int proc_getfd(struct imsgproc *); int proc_gettype(struct imsgproc *); int proc_getinstance(struct imsgproc *); const char *proc_gettitle(struct imsgproc *); +void proc_setpid(struct imsgproc *, pid_t); void proc_settitle(struct imsgproc *, const char *); void proc_setinstance(struct imsgproc *, int); void proc_setcallback(struct imsgproc *, diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 5f07a73..cd072a1 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -19,7 +19,7 @@ #define CONF_FILE "/etc/mail/smtpfd.conf" #define SMTPFD_SOCKET "/var/run/smtpfd.sock" -#define SMTPFD_USER "_smtpfd" +#define SMTPFD_USER "_smtpd" #define OPT_VERBOSE 0x00000001 #define OPT_VERBOSE2 0x00000002 @@ -31,7 +31,8 @@ static const char * const log_procnames[] = { "main", "frontend", - "engine" + "engine", + "client" }; struct imsgev { @@ -58,7 +59,8 @@ enum imsg_type { enum { PROC_MAIN, PROC_ENGINE, - PROC_FRONTEND + PROC_FRONTEND, + PROC_CLIENT, } smtpfd_process; struct group { From 602e5ab77f2766ce73c667994dc3c6057446808b Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Fri, 26 May 2017 11:31:35 +0200 Subject: [PATCH 13/41] revert change that was not supposed to be commited --- extras/filters/smtpfd/smtpfd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index cd072a1..dfe0e07 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -19,7 +19,7 @@ #define CONF_FILE "/etc/mail/smtpfd.conf" #define SMTPFD_SOCKET "/var/run/smtpfd.sock" -#define SMTPFD_USER "_smtpd" +#define SMTPFD_USER "_smtpfd" #define OPT_VERBOSE 0x00000001 #define OPT_VERBOSE2 0x00000002 From 26d2baf21d17f14a214a046251a2d9c7ab884ad4 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Mon, 29 May 2017 18:28:27 +0200 Subject: [PATCH 14/41] remove unused imsgev-related code --- extras/filters/smtpfd/smtpfd.c | 25 ------------------------- extras/filters/smtpfd/smtpfd.h | 10 ---------- 2 files changed, 35 deletions(-) diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 6b1a5db..3e681a0 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -340,31 +340,6 @@ main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) proc_compose(p_engine, type, 0, pid, -1, data, datalen); } -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); - event_add(&iev->ev, NULL); -} - -int -imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, - pid_t pid, int fd, void *data, uint16_t datalen) -{ - int ret; - - if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, - datalen)) != -1) - imsg_event_add(iev); - - return (ret); -} - int main_reload(void) { diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index dfe0e07..3e1cf0a 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -35,13 +35,6 @@ static const char * const log_procnames[] = { "client" }; -struct imsgev { - struct imsgbuf ibuf; - void (*handler)(int, short, void *); - struct event ev; - short events; -}; - enum imsg_type { IMSG_NONE, IMSG_CTL_LOG_VERBOSE, @@ -96,9 +89,6 @@ extern uint32_t cmd_opts; void main_imsg_compose_frontend(int, pid_t, void *, uint16_t); void main_imsg_compose_engine(int, pid_t, void *, uint16_t); void merge_config(struct smtpfd_conf *, struct smtpfd_conf *); -void imsg_event_add(struct imsgev *); -int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t, - int, void *, uint16_t); struct smtpfd_conf *config_new_empty(void); void config_clear(struct smtpfd_conf *); From bbb466b6e2839b83aea0ed860b6cc28d8cbcb555 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Mon, 29 May 2017 21:43:53 +0200 Subject: [PATCH 15/41] replace config parser and get rid of config handling in the child processes for now. --- extras/filters/smtpfd/Makefile | 2 +- extras/filters/smtpfd/engine.c | 28 +---- extras/filters/smtpfd/frontend.c | 34 +----- extras/filters/smtpfd/parse.y | 179 +++++++++--------------------- extras/filters/smtpfd/printconf.c | 64 ----------- extras/filters/smtpfd/smtpfd.c | 84 ++++++-------- extras/filters/smtpfd/smtpfd.h | 35 ++---- 7 files changed, 106 insertions(+), 320 deletions(-) delete mode 100644 extras/filters/smtpfd/printconf.c diff --git a/extras/filters/smtpfd/Makefile b/extras/filters/smtpfd/Makefile index 038b871..b094c63 100644 --- a/extras/filters/smtpfd/Makefile +++ b/extras/filters/smtpfd/Makefile @@ -1,7 +1,7 @@ # $OpenBSD$ PROG= smtpfd -SRCS= control.c engine.c frontend.c log.c smtpfd.c parse.y printconf.c +SRCS= control.c engine.c frontend.c log.c smtpfd.c parse.y SRCS+= proc.c MAN= smtpfd.8 smtpfd.conf.5 diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 3abcd47..79f077c 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -46,9 +46,8 @@ void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *); void engine_dispatch_main(struct imsgproc *, struct imsg *, void *); void engine_showinfo_ctl(struct imsg *); -struct smtpfd_conf *engine_conf; -struct imsgproc *p_frontend; -struct imsgproc *p_main; +struct imsgproc *p_frontend; +struct imsgproc *p_main; void engine_sig_handler(int sig, short event, void *arg) @@ -73,8 +72,6 @@ engine(int debug, int verbose) struct event ev_sigint, ev_sigterm; struct passwd *pw; - engine_conf = config_new_empty(); - log_init(debug, LOG_DAEMON); log_setverbose(verbose); @@ -125,8 +122,6 @@ engine_shutdown(void) proc_free(p_main); proc_free(p_frontend); - config_clear(engine_conf); - log_info("engine exiting"); exit(0); } @@ -167,9 +162,6 @@ engine_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *bula) void engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) { - static struct smtpfd_conf *nconf; - struct group *g; - if (imsg == NULL) { event_loopexit(NULL); return; @@ -199,22 +191,6 @@ engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) proc_setcallback(p_frontend, engine_dispatch_frontend, NULL); proc_enable(p_frontend); break; - case IMSG_RECONF_CONF: - if ((nconf = malloc(sizeof(struct smtpfd_conf))) == NULL) - fatal(NULL); - memcpy(nconf, imsg->data, sizeof(struct smtpfd_conf)); - LIST_INIT(&nconf->group_list); - break; - case IMSG_RECONF_GROUP: - if ((g = malloc(sizeof(struct group))) == NULL) - fatal(NULL); - memcpy(g, imsg->data, sizeof(struct group)); - LIST_INSERT_HEAD(&nconf->group_list, g, entry); - break; - case IMSG_RECONF_END: - merge_config(engine_conf, nconf); - nconf = NULL; - break; default: log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 61b6479..debdd70 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -44,9 +44,8 @@ __dead void frontend_shutdown(void); void frontend_sig_handler(int, short, void *); -struct smtpfd_conf *frontend_conf; -struct imsgproc *p_main; -struct imsgproc *p_engine; +struct imsgproc *p_main; +struct imsgproc *p_engine; void frontend_sig_handler(int sig, short event, void *bula) @@ -71,8 +70,6 @@ frontend(int debug, int verbose, char *sockname) struct event ev_sigint, ev_sigterm; struct passwd *pw; - frontend_conf = config_new_empty(); - log_init(debug, LOG_DAEMON); log_setverbose(verbose); @@ -131,8 +128,6 @@ frontend_shutdown(void) proc_free(p_engine); proc_free(p_main); - config_clear(frontend_conf); - log_info("frontend exiting"); exit(0); } @@ -154,10 +149,6 @@ frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, void frontend_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *arg) { - static struct smtpfd_conf *nconf; - struct group *g; - int fd; - if (imsg == NULL) { event_loopexit(NULL); return; @@ -174,34 +165,17 @@ frontend_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *arg) "to frontend", __func__); break; } - if ((fd = imsg->fd) == -1) { + if (imsg->fd == -1) { log_warnx("%s: expected to receive imsg fd to " "frontend but didn't receive any", __func__); break; } - p_engine = proc_attach(PROC_ENGINE, fd); + p_engine = proc_attach(PROC_ENGINE, imsg->fd); proc_setcallback(p_engine, frontend_dispatch_engine, NULL); proc_enable(p_engine); break; - case IMSG_RECONF_CONF: - if ((nconf = malloc(sizeof(struct smtpfd_conf))) == - NULL) - fatal(NULL); - memcpy(nconf, imsg->data, sizeof(struct smtpfd_conf)); - LIST_INIT(&nconf->group_list); - break; - case IMSG_RECONF_GROUP: - if ((g = malloc(sizeof(struct group))) == NULL) - fatal(NULL); - memcpy(g, imsg->data, sizeof(struct group)); - LIST_INSERT_HEAD(&nconf->group_list, g, entry); - break; - case IMSG_RECONF_END: - merge_config(frontend_conf, nconf); - nconf = NULL; - break; case IMSG_CTL_END: case IMSG_CTL_SHOW_MAIN_INFO: control_imsg_relay(imsg); diff --git a/extras/filters/smtpfd/parse.y b/extras/filters/smtpfd/parse.y index 73e0fc9..5a03f93 100644 --- a/extras/filters/smtpfd/parse.y +++ b/extras/filters/smtpfd/parse.y @@ -82,15 +82,9 @@ struct sym { int symset(const char *, const char *, int); char *symget(const char *); -void clear_config(struct smtpfd_conf *xconf); - -static struct smtpfd_conf *conf; -static int errors; - -static struct group *group; - -struct group *conf_get_group(char *); -void *conf_del_group(struct group *); +static struct smtpfd_conf *conf; +static struct filter_conf *filter; +static int errors; typedef struct { union { @@ -102,24 +96,20 @@ typedef struct { %} -%token GROUP YES NO INCLUDE ERROR -%token YESNO INTEGER -%token GLOBAL_TEXT -%token GROUP_V4ADDRESS GROUP_V6ADDRESS +%token CHAIN ERROR FILTER INCLUDE %token STRING %token NUMBER -%type yesno %type string +%type filter_or_chain %% grammar : /* empty */ | grammar include '\n' | grammar '\n' - | grammar conf_main '\n' + | grammar filter '\n' | grammar varset '\n' - | grammar group '\n' | grammar error '\n' { file->errors++; } ; @@ -151,10 +141,6 @@ string : string STRING { | STRING ; -yesno : YES { $$ = 1; } - | NO { $$ = 0; } - ; - varset : STRING '=' string { char *s = $1; if (cmd_opts & OPT_VERBOSE) @@ -173,75 +159,60 @@ varset : STRING '=' string { } ; -conf_main : YESNO yesno { - conf->yesno = $2; - } - | INTEGER NUMBER { - conf->integer = $2; - } - | GLOBAL_TEXT STRING { - size_t n; - memset(conf->global_text, 0, - sizeof(conf->global_text)); - n = strlcpy(conf->global_text, $2, - sizeof(conf->global_text)); - if (n >= sizeof(conf->global_text)) { - yyerror("error parsing global_text: too long"); - free($2); +filter_args : STRING { + struct filter_conf *f; + + if (filter->argc == SMTPFD_MAXFILTERARG) { + yyerror("too many args for filter %s", + filter->name); YYERROR; } - } -optnl : '\n' optnl /* zero or more newlines */ - | /*empty*/ + if (filter->chain) { + TAILQ_FOREACH(f, &conf->filters, entry) + if (!strcmp(f->name, $1)) + break; + if (f == NULL) { + yyerror("unknown filter %s", $1); + YYERROR; + } + if (f == filter) { + yyerror("cannot chain %s with itself", + f->name); + YYERROR; + } + } + filter->argv[filter->argc++] = $1; + } filter_args + | /* empty */ ; -nl : '\n' optnl /* one or more newlines */ +filter_or_chain : FILTER { $$ = 0; } + | CHAIN { $$ = 1; } ; -group : GROUP STRING { - group = conf_get_group($2); - } '{' optnl groupopts_l '}' { - group = NULL; - } +filter : filter_or_chain STRING { + TAILQ_FOREACH(filter, &conf->filters, entry) + if (!strcmp(filter->name, $2)) { + yyerror("filter %s already defined", + filter->name); + YYERROR; + } + filter = calloc(1, sizeof(*filter)); + if (filter == NULL) + fatal("calloc"); + filter->chain = $1; + filter->name = $2; + TAILQ_INSERT_TAIL(&conf->filters, filter, entry); + } filter_args ; -groupopts_l : groupopts_l groupoptsl nl - | groupoptsl optnl +optnl : '\n' optnl /* zero or more newlines */ + | /*empty*/ ; -groupoptsl : GROUP_V4ADDRESS STRING { - memset(&group->group_v4address, 0, - sizeof(group->group_v4address)); - group->group_v4_bits = inet_net_pton(AF_INET, $2, - &group->group_v4address, - sizeof(group->group_v4address)); - if (group->group_v4_bits == -1) { - yyerror("error parsing group_v4address"); - free($2); - YYERROR; - } - } - | GROUP_V6ADDRESS STRING { - memset(&group->group_v6address, 0, - sizeof(group->group_v6address)); - group->group_v6_bits = inet_net_pton(AF_INET6, $2, - &group->group_v6address, - sizeof(group->group_v6address)); - if (group->group_v6_bits == -1) { - yyerror("error parsing group_v6address"); - free($2); - YYERROR; - } - } - | YESNO yesno { - group->yesno = $2; - } - | INTEGER NUMBER { - group->integer = $2; - } +nl : '\n' optnl /* one or more newlines */ ; - %% struct keywords { @@ -276,15 +247,9 @@ lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { - {"global-text", GLOBAL_TEXT}, - {"group", GROUP}, - {"group-v4address", GROUP_V4ADDRESS}, - {"group-v6address", GROUP_V6ADDRESS}, + {"chain", CHAIN}, + {"filter", FILTER}, {"include", INCLUDE}, - {"integer", INTEGER}, - {"no", NO}, - {"yes", YES}, - {"yesno", YESNO} }; const struct keywords *p; @@ -621,8 +586,6 @@ parse_config(char *filename) } topfile = file; - LIST_INIT(&conf->group_list); - yyparse(); errors = file->errors; popfile(); @@ -641,7 +604,7 @@ parse_config(char *filename) } if (errors) { - clear_config(conf); + config_clear(conf); return (NULL); } @@ -723,43 +686,3 @@ symget(const char *nam) } return (NULL); } - -struct group * -conf_get_group(char *name) -{ - struct group *g; - size_t n; - - LIST_FOREACH(g, &conf->group_list, entry) { - if (strcmp(name, g->name) == 0) - return (g); - } - - g = calloc(1, sizeof(*g)); - if (g == NULL) - errx(1, "get_group: calloc"); - n = strlcpy(g->name, name, sizeof(g->name)); - if (n >= sizeof(g->name)) - errx(1, "get_group: name too long"); - - /* Inherit attributes set in global section. */ - g->yesno = conf->yesno; - g->integer = conf->integer; - - LIST_INSERT_HEAD(&conf->group_list, g, entry); - - return (g); -} - -void -clear_config(struct smtpfd_conf *xconf) -{ - struct group *g; - - while ((g = LIST_FIRST(&xconf->group_list)) != NULL) { - LIST_REMOVE(g, entry); - free(g); - } - - free(xconf); -} diff --git a/extras/filters/smtpfd/printconf.c b/extras/filters/smtpfd/printconf.c deleted file mode 100644 index 8fb9459..0000000 --- a/extras/filters/smtpfd/printconf.c +++ /dev/null @@ -1,64 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2004, 2005 Esben Norby - * - * 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 -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "smtpfd.h" - -void -print_config(struct smtpfd_conf *conf) -{ - struct group *g; - char buf[INET6_ADDRSTRLEN], *bufp; - - printf("yesno %s\n", conf->yesno ? "yes" : "no"); - printf("integer %d\n", conf->integer); - printf("\n"); - - printf("global_text \"%s\"\n", conf->global_text); - printf("\n"); - - - LIST_FOREACH(g, &conf->group_list, entry) { - printf("group %s {\n", g->name); - - printf("\tyesno %s\n", g->yesno ? "yes" : "no"); - printf("\tinteger %d\n", g->integer); - - bufp = inet_net_ntop(AF_INET, &g->group_v4address, - g->group_v4_bits, buf, sizeof(buf)); - printf("\tgroup-v4address %s\n", - bufp ? bufp : ""); - bufp = inet_net_ntop(AF_INET6, &g->group_v6address, - g->group_v6_bits, buf, sizeof(buf)); - printf("\tgroup-v6address %s\n", - bufp ? bufp : ""); - - printf("}\n"); - } -} diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 3e681a0..95b9f54 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -53,9 +53,10 @@ void main_dispatch_frontend(struct imsgproc *, struct imsg*, void *); void main_dispatch_engine(struct imsgproc *, struct imsg*, void *); static int main_imsg_send_config(struct smtpfd_conf *); -int main_reload(void); -int main_sendboth(enum imsg_type, void *, uint16_t); -void main_showinfo_ctl(struct imsg *); +static int main_reload(void); +static int main_sendboth(enum imsg_type, void *, uint16_t); +static void main_showinfo_ctl(struct imsg *); +static void config_print(struct smtpfd_conf *); struct smtpfd_conf *main_conf; struct imsgproc *p_frontend; @@ -164,7 +165,7 @@ main(int argc, char *argv[]) if (cmd_opts & OPT_NOACTION) { if (cmd_opts & OPT_VERBOSE) - print_config(main_conf); + config_print(main_conf); else fprintf(stderr, "configuration OK\n"); exit(0); @@ -351,7 +352,8 @@ main_reload(void) if (main_imsg_send_config(xconf) == -1) return (-1); - merge_config(main_conf, xconf); + config_clear(main_conf); + main_conf = xconf; return (0); } @@ -359,18 +361,10 @@ main_reload(void) int main_imsg_send_config(struct smtpfd_conf *xconf) { - struct group *g; - /* Send fixed part of config to children. */ if (main_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) return (-1); - /* Send the group list to children. */ - LIST_FOREACH(g, &xconf->group_list, entry) { - if (main_sendboth(IMSG_RECONF_GROUP, g, sizeof(*g)) == -1) - return (-1); - } - /* Tell children the revised config is now complete. */ if (main_sendboth(IMSG_RECONF_END, NULL, 0) == -1) return (-1); @@ -402,53 +396,47 @@ main_showinfo_ctl(struct imsg *imsg) } } -void -merge_config(struct smtpfd_conf *conf, struct smtpfd_conf *xconf) -{ - struct group *g; - - conf->yesno = xconf->yesno; - conf->integer = xconf->integer; - memcpy(conf->global_text, xconf->global_text, - sizeof(conf->global_text)); - - /* Remove & discard existing groups. */ - while ((g = LIST_FIRST(&conf->group_list)) != NULL) { - LIST_REMOVE(g, entry); - free(g); - } - - /* Add new groups. */ - while ((g = LIST_FIRST(&xconf->group_list)) != NULL) { - LIST_REMOVE(g, entry); - LIST_INSERT_HEAD(&conf->group_list, g, entry); - } - - free(xconf); -} - struct smtpfd_conf * config_new_empty(void) { - struct smtpfd_conf *xconf; + struct smtpfd_conf *conf; - xconf = calloc(1, sizeof(*xconf)); - if (xconf == NULL) + conf = calloc(1, sizeof(*conf)); + if (conf == NULL) fatal(NULL); - LIST_INIT(&xconf->group_list); + TAILQ_INIT(&conf->filters); - return (xconf); + return (conf); } void config_clear(struct smtpfd_conf *conf) { - struct smtpfd_conf *xconf; - - /* Merge current config with an empty config. */ - xconf = config_new_empty(); - merge_config(conf, xconf); + struct filter_conf *f; + int i; + + while ((f = TAILQ_FIRST(&conf->filters))) { + TAILQ_REMOVE(&conf->filters, f, entry); + free(f->name); + for (i = 0; i < f->argc; i++) + free(f->argv[i]); + free(f); + } free(conf); } + +void +config_print(struct smtpfd_conf *conf) +{ + struct filter_conf *f; + int i; + + TAILQ_FOREACH(f, &conf->filters, entry) { + printf("%s %s", f->chain ? "chain":"filter", f->name); + for (i = 0; i < f->argc; i++) + printf(" %s", f->argv[i]); + printf("\n"); + } +} diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 3e1cf0a..597e98d 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -21,13 +21,12 @@ #define SMTPFD_SOCKET "/var/run/smtpfd.sock" #define SMTPFD_USER "_smtpfd" +#define SMTPFD_MAXFILTERARG 32 + #define OPT_VERBOSE 0x00000001 #define OPT_VERBOSE2 0x00000002 #define OPT_NOACTION 0x00000004 -#define SMTPFD_MAXTEXT 256 -#define SMTPFD_MAXGROUPNAME 16 - static const char * const log_procnames[] = { "main", "frontend", @@ -56,22 +55,17 @@ enum { PROC_CLIENT, } smtpfd_process; -struct group { - LIST_ENTRY(group) entry; - char name[SMTPFD_MAXGROUPNAME]; - int yesno; - int integer; - int group_v4_bits; - int group_v6_bits; - struct in_addr group_v4address; - struct in6_addr group_v6address; + +struct filter_conf { + TAILQ_ENTRY(filter_conf) entry; + char *name; + int chain; + int argc; + char *argv[SMTPFD_MAXFILTERARG + 1]; }; struct smtpfd_conf { - int yesno; - int integer; - char global_text[SMTPFD_MAXTEXT]; - LIST_HEAD(, group) group_list; + TAILQ_HEAD(, filter_conf) filters; }; struct ctl_frontend_info { @@ -88,13 +82,8 @@ extern uint32_t cmd_opts; /* smtpfd.c */ void main_imsg_compose_frontend(int, pid_t, void *, uint16_t); void main_imsg_compose_engine(int, pid_t, void *, uint16_t); -void merge_config(struct smtpfd_conf *, struct smtpfd_conf *); - -struct smtpfd_conf *config_new_empty(void); -void config_clear(struct smtpfd_conf *); - -/* printconf.c */ -void print_config(struct smtpfd_conf *); +struct smtpfd_conf *config_new_empty(void); +void config_clear(struct smtpfd_conf *); /* parse.y */ struct smtpfd_conf *parse_config(char *); From 3aa74a70a843bae2ec3b537e12cfed273dd8198e Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Mon, 29 May 2017 22:43:40 +0200 Subject: [PATCH 16/41] simplify engine and frontend code: - remove unncessary signal handlers - simpler exit path - use static functions where possible --- extras/filters/smtpfd/engine.c | 73 ++++++------------------------ extras/filters/smtpfd/frontend.c | 78 +++++++------------------------- extras/filters/smtpfd/frontend.h | 2 - 3 files changed, 30 insertions(+), 123 deletions(-) diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 79f077c..0d39fe8 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -40,36 +40,16 @@ #include "smtpfd.h" #include "engine.h" -__dead void engine_shutdown(void); -void engine_sig_handler(int sig, short, void *); -void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *); -void engine_dispatch_main(struct imsgproc *, struct imsg *, void *); -void engine_showinfo_ctl(struct imsg *); +static void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *); +static void engine_dispatch_main(struct imsgproc *, struct imsg *, void *); +static void engine_showinfo_ctl(struct imsg *); struct imsgproc *p_frontend; struct imsgproc *p_main; -void -engine_sig_handler(int sig, short event, void *arg) -{ - /* - * Normal signal handler rules don't apply because libevent - * decouples for us. - */ - - switch (sig) { - case SIGINT: - case SIGTERM: - engine_shutdown(); - default: - fatalx("unexpected signal"); - } -} - void engine(int debug, int verbose) { - struct event ev_sigint, ev_sigterm; struct passwd *pw; log_init(debug, LOG_DAEMON); @@ -97,14 +77,6 @@ engine(int debug, int verbose) event_init(); - /* Setup signal handler(s). */ - signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL); - signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL); - signal_add(&ev_sigint, NULL); - signal_add(&ev_sigterm, NULL); - signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, SIG_IGN); - /* Setup pipe and event handler to the main process. */ p_main = proc_attach(PROC_MAIN, 3); proc_setcallback(p_main, engine_dispatch_main, NULL); @@ -112,17 +84,6 @@ engine(int debug, int verbose) event_dispatch(); - engine_shutdown(); -} - -__dead void -engine_shutdown(void) -{ - /* Close pipes. */ - proc_free(p_main); - proc_free(p_frontend); - - log_info("engine exiting"); exit(0); } @@ -139,6 +100,7 @@ engine_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *bula) int verbose; if (imsg == NULL) { + log_debug("%s: imsg connection lost", __func__); event_loopexit(NULL); return; } @@ -153,8 +115,7 @@ engine_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *bula) engine_showinfo_ctl(imsg); break; default: - log_debug("%s: unexpected imsg %d", __func__, - imsg->hdr.type); + log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); break; } } @@ -163,6 +124,7 @@ void engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) { if (imsg == NULL) { + log_debug("%s: imsg connection lost", __func__); event_loopexit(NULL); return; } @@ -173,27 +135,20 @@ engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) * Setup pipe and event handler to the frontend * process. */ - if (p_frontend) { - log_warnx("%s: received unexpected imsg fd " - "to engine", __func__); - break; - } - if (imsg->fd == -1) { - log_warnx("%s: expected to receive imsg fd to " - "engine but didn't receive any", __func__); - break; - } + if (p_frontend) + fatalx("frontend process already set"); + + if (imsg->fd == -1) + fatalx("failed to receive frontend process fd"); p_frontend = proc_attach(PROC_FRONTEND, imsg->fd); if (p_frontend == NULL) - fatal(NULL); - + fatal("proc_attach"); proc_setcallback(p_frontend, engine_dispatch_frontend, NULL); proc_enable(p_frontend); break; default: - log_debug("%s: unexpected imsg %d", __func__, - imsg->hdr.type); + log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); break; } } @@ -207,7 +162,7 @@ engine_showinfo_ctl(struct imsg *imsg) 0); break; default: - log_debug("%s: error handling imsg", __func__); + log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); break; } } diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index debdd70..cc910db 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -41,33 +41,16 @@ #include "frontend.h" #include "control.h" -__dead void frontend_shutdown(void); -void frontend_sig_handler(int, short, void *); + +static void frontend_dispatch_main(struct imsgproc *, struct imsg *, void *); +static void frontend_dispatch_engine(struct imsgproc *, struct imsg *, void *); struct imsgproc *p_main; struct imsgproc *p_engine; -void -frontend_sig_handler(int sig, short event, void *bula) -{ - /* - * Normal signal handler rules don't apply because libevent - * decouples for us. - */ - - switch (sig) { - case SIGINT: - case SIGTERM: - frontend_shutdown(); - default: - fatalx("unexpected signal"); - } -} - void frontend(int debug, int verbose, char *sockname) { - struct event ev_sigint, ev_sigterm; struct passwd *pw; log_init(debug, LOG_DAEMON); @@ -99,14 +82,6 @@ frontend(int debug, int verbose, char *sockname) event_init(); - /* Setup signal handler. */ - signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL); - signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL); - signal_add(&ev_sigint, NULL); - signal_add(&ev_sigterm, NULL); - signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, SIG_IGN); - /* Setup pipe and event handler to the parent process. */ p_main = proc_attach(PROC_MAIN, 3); proc_setcallback(p_main, frontend_dispatch_main, NULL); @@ -118,17 +93,6 @@ frontend(int debug, int verbose, char *sockname) event_dispatch(); - frontend_shutdown(); -} - -__dead void -frontend_shutdown(void) -{ - /* Close pipes. */ - proc_free(p_engine); - proc_free(p_main); - - log_info("frontend exiting"); exit(0); } @@ -146,10 +110,11 @@ frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, return proc_compose(p_engine, type, peerid, pid, -1, data, datalen); } -void +static void frontend_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *arg) { if (imsg == NULL) { + log_debug("%s: imsg connection lost", __func__); event_loopexit(NULL); return; } @@ -160,50 +125,39 @@ frontend_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *arg) * Setup pipe and event handler to the engine * process. */ - if (p_engine) { - log_warnx("%s: received unexpected imsg fd " - "to frontend", __func__); - break; - } - if (imsg->fd == -1) { - log_warnx("%s: expected to receive imsg fd to " - "frontend but didn't receive any", - __func__); - break; - } + if (p_engine) + fatalx("engine process already set"); + + if (imsg->fd == -1) + fatalx("failed to receive engine process fd"); p_engine = proc_attach(PROC_ENGINE, imsg->fd); + if (p_engine == NULL) + fatal("proc_attach"); proc_setcallback(p_engine, frontend_dispatch_engine, NULL); proc_enable(p_engine); break; - case IMSG_CTL_END: - case IMSG_CTL_SHOW_MAIN_INFO: - control_imsg_relay(imsg); - break; default: - log_debug("%s: error handling imsg %d", __func__, - imsg->hdr.type); + log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); break; } } -void +static void frontend_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) { if (imsg == NULL) { + log_debug("%s: imsg connection lost", __func__); event_loopexit(NULL); return; } switch (imsg->hdr.type) { - case IMSG_CTL_END: case IMSG_CTL_SHOW_ENGINE_INFO: control_imsg_relay(imsg); break; default: - log_debug("%s: error handling imsg %d", __func__, - imsg->hdr.type); - break; + log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); } } diff --git a/extras/filters/smtpfd/frontend.h b/extras/filters/smtpfd/frontend.h index 370a686..5117e43 100644 --- a/extras/filters/smtpfd/frontend.h +++ b/extras/filters/smtpfd/frontend.h @@ -21,8 +21,6 @@ TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns; struct imsgproc; void frontend(int, int, char *); -void frontend_dispatch_main(struct imsgproc *, struct imsg *, void *); -void frontend_dispatch_engine(struct imsgproc *, struct imsg *, void *); int frontend_imsg_compose_main(int, pid_t, void *, uint16_t); int frontend_imsg_compose_engine(int, uint32_t, pid_t, void *, uint16_t); From 1121fc2c20aa86cae9a2e2d21daafca01cc9c61a Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Mon, 29 May 2017 22:59:59 +0200 Subject: [PATCH 17/41] set procname earlier and get rid of the log_procnames indirection --- extras/filters/smtpfd/engine.c | 6 ++---- extras/filters/smtpfd/frontend.c | 6 ++---- extras/filters/smtpfd/smtpfd.c | 6 ++---- extras/filters/smtpfd/smtpfd.h | 11 ++--------- 4 files changed, 8 insertions(+), 21 deletions(-) diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 0d39fe8..8bc154d 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -54,6 +54,8 @@ engine(int debug, int verbose) log_init(debug, LOG_DAEMON); log_setverbose(verbose); + log_procinit("engine"); + setproctitle("engine"); if ((pw = getpwnam(SMTPFD_USER)) == NULL) fatal("getpwnam"); @@ -63,10 +65,6 @@ engine(int debug, int verbose) if (chdir("/") == -1) fatal("chdir(\"/\")"); - smtpfd_process = PROC_ENGINE; - setproctitle(log_procnames[smtpfd_process]); - log_procinit(log_procnames[smtpfd_process]); - 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)) diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index cc910db..719d7ff 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -55,6 +55,8 @@ frontend(int debug, int verbose, char *sockname) log_init(debug, LOG_DAEMON); log_setverbose(verbose); + log_procinit("frontend"); + setproctitle("frontend"); /* Create smtpfd control socket outside chroot. */ if (control_init(sockname) == -1) @@ -68,10 +70,6 @@ frontend(int debug, int verbose, char *sockname) if (chdir("/") == -1) fatal("chdir(\"/\")"); - smtpfd_process = PROC_FRONTEND; - setproctitle(log_procnames[smtpfd_process]); - log_procinit(log_procnames[smtpfd_process]); - 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)) diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 95b9f54..f7b934f 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -181,6 +181,8 @@ main(int argc, char *argv[]) log_init(debug, LOG_DAEMON); log_setverbose(cmd_opts & OPT_VERBOSE); + log_procinit("main"); + setproctitle("main"); if (!debug) daemon(1, 0); @@ -203,10 +205,6 @@ main(int argc, char *argv[]) rargv[argc - 3] = NULL; p_engine = proc_exec(PROC_ENGINE, rargv); - smtpfd_process = PROC_MAIN; - setproctitle(log_procnames[smtpfd_process]); - log_procinit(log_procnames[smtpfd_process]); - event_init(); /* Setup signal handler. */ diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 597e98d..c1a6145 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -27,13 +27,6 @@ #define OPT_VERBOSE2 0x00000002 #define OPT_NOACTION 0x00000004 -static const char * const log_procnames[] = { - "main", - "frontend", - "engine", - "client" -}; - enum imsg_type { IMSG_NONE, IMSG_CTL_LOG_VERBOSE, @@ -48,12 +41,12 @@ enum imsg_type { IMSG_SOCKET_IPC }; -enum { +enum smtpfd_process { PROC_MAIN, PROC_ENGINE, PROC_FRONTEND, PROC_CLIENT, -} smtpfd_process; +}; struct filter_conf { From 112f687c41ea0e0f9920a1017003fff3e3dbbf8d Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Mon, 29 May 2017 23:10:23 +0200 Subject: [PATCH 18/41] declare p_* as external globals in smtpfd.h and put them in smtpfd.c --- extras/filters/smtpfd/engine.c | 2 -- extras/filters/smtpfd/frontend.c | 2 -- extras/filters/smtpfd/smtpfd.c | 2 ++ extras/filters/smtpfd/smtpfd.h | 3 +++ 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 8bc154d..65b97d4 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -44,8 +44,6 @@ static void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *); static void engine_dispatch_main(struct imsgproc *, struct imsg *, void *); static void engine_showinfo_ctl(struct imsg *); -struct imsgproc *p_frontend; -struct imsgproc *p_main; void engine(int debug, int verbose) diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 719d7ff..9136d8b 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -45,8 +45,6 @@ static void frontend_dispatch_main(struct imsgproc *, struct imsg *, void *); static void frontend_dispatch_engine(struct imsgproc *, struct imsg *, void *); -struct imsgproc *p_main; -struct imsgproc *p_engine; void frontend(int debug, int verbose, char *sockname) diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index f7b934f..9dd753a 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -61,6 +61,8 @@ static void config_print(struct smtpfd_conf *); struct smtpfd_conf *main_conf; struct imsgproc *p_frontend; struct imsgproc *p_engine; +struct imsgproc *p_main; + char *conffile; char *csock; diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index c1a6145..2c83068 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -71,6 +71,9 @@ struct ctl_main_info { }; extern uint32_t cmd_opts; +extern struct imsgproc *p_frontend; +extern struct imsgproc *p_engine; +extern struct imsgproc *p_main; /* smtpfd.c */ void main_imsg_compose_frontend(int, pid_t, void *, uint16_t); From e2c3f59df687db3753c8b85ac0d972c52f807a94 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Mon, 29 May 2017 23:27:10 +0200 Subject: [PATCH 19/41] use proc_compose() directly everywhere --- extras/filters/smtpfd/control.c | 18 ++++++++---------- extras/filters/smtpfd/engine.c | 11 ++--------- extras/filters/smtpfd/engine.h | 1 - extras/filters/smtpfd/frontend.c | 14 -------------- extras/filters/smtpfd/frontend.h | 3 --- extras/filters/smtpfd/smtpfd.c | 18 ++---------------- extras/filters/smtpfd/smtpfd.h | 2 -- 7 files changed, 12 insertions(+), 55 deletions(-) diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c index 22ed824..6fbc9e6 100644 --- a/extras/filters/smtpfd/control.c +++ b/extras/filters/smtpfd/control.c @@ -202,7 +202,7 @@ control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) switch (imsg->hdr.type) { case IMSG_CTL_RELOAD: - frontend_imsg_compose_main(imsg->hdr.type, 0, NULL, 0); + proc_compose(p_main, imsg->hdr.type, 0, 0, -1, NULL, 0); break; case IMSG_CTL_LOG_VERBOSE: if (imsg->hdr.len != IMSG_HEADER_SIZE + @@ -210,18 +210,17 @@ control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) break; /* Forward to all other processes. */ - frontend_imsg_compose_main(imsg->hdr.type, imsg->hdr.pid, + proc_compose(p_main, imsg->hdr.type, 0, imsg->hdr.pid, -1, + imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); + proc_compose(p_engine, imsg->hdr.type, 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); - frontend_imsg_compose_engine(imsg->hdr.type, 0, - imsg->hdr.pid, imsg->data, - imsg->hdr.len - IMSG_HEADER_SIZE); memcpy(&verbose, imsg->data, sizeof(verbose)); log_setverbose(verbose); break; case IMSG_CTL_SHOW_MAIN_INFO: proc_setpid(c->proc, imsg->hdr.pid); - frontend_imsg_compose_main(imsg->hdr.type, imsg->hdr.pid, + proc_compose(p_main, imsg->hdr.type, 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_FRONTEND_INFO: @@ -230,8 +229,7 @@ control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) break; case IMSG_CTL_SHOW_ENGINE_INFO: proc_setpid(c->proc, imsg->hdr.pid); - frontend_imsg_compose_engine(imsg->hdr.type, 0, - imsg->hdr.pid, + proc_compose(p_engine, imsg->hdr.type, 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); break; default: @@ -249,6 +247,6 @@ control_imsg_relay(struct imsg *imsg) if ((c = control_connbypid(imsg->hdr.pid)) == NULL) return (0); - return (proc_compose(c->proc, imsg->hdr.type, 0, imsg->hdr.pid, - -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); + return (proc_compose(c->proc, imsg->hdr.type, 0, imsg->hdr.pid, -1, + imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); } diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 65b97d4..9c4b939 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -83,13 +83,6 @@ engine(int debug, int verbose) exit(0); } -int -engine_imsg_compose_frontend(int type, pid_t pid, void *data, - uint16_t datalen) -{ - return proc_compose(p_frontend, type, 0, pid, -1, data, datalen); -} - void engine_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *bula) { @@ -154,8 +147,8 @@ engine_showinfo_ctl(struct imsg *imsg) { switch (imsg->hdr.type) { case IMSG_CTL_SHOW_ENGINE_INFO: - engine_imsg_compose_frontend(IMSG_CTL_END, imsg->hdr.pid, NULL, - 0); + proc_compose(p_frontend, IMSG_CTL_END, 0, imsg->hdr.pid, -1, + NULL, 0); break; default: log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); diff --git a/extras/filters/smtpfd/engine.h b/extras/filters/smtpfd/engine.h index be86f34..3ac771a 100644 --- a/extras/filters/smtpfd/engine.h +++ b/extras/filters/smtpfd/engine.h @@ -17,4 +17,3 @@ */ void engine(int, int); -int engine_imsg_compose_frontend(int, pid_t, void *, uint16_t); diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 9136d8b..c29a7ec 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -92,20 +92,6 @@ frontend(int debug, int verbose, char *sockname) exit(0); } -int -frontend_imsg_compose_main(int type, pid_t pid, void *data, - uint16_t datalen) -{ - return proc_compose(p_main, type, 0, pid, -1, data, datalen); -} - -int -frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, - void *data, uint16_t datalen) -{ - return proc_compose(p_engine, type, peerid, pid, -1, data, datalen); -} - static void frontend_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *arg) { diff --git a/extras/filters/smtpfd/frontend.h b/extras/filters/smtpfd/frontend.h index 5117e43..bf0d13e 100644 --- a/extras/filters/smtpfd/frontend.h +++ b/extras/filters/smtpfd/frontend.h @@ -21,7 +21,4 @@ TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns; struct imsgproc; void frontend(int, int, char *); -int frontend_imsg_compose_main(int, pid_t, void *, uint16_t); -int frontend_imsg_compose_engine(int, uint32_t, pid_t, void *, - uint16_t); void frontend_showinfo_ctl(struct ctl_conn *); diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 9dd753a..cd919b9 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -327,20 +327,6 @@ main_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) } } -void -main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) -{ - if (p_frontend) - proc_compose(p_frontend, type, 0, pid, -1, data, datalen); -} - -void -main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) -{ - if (p_engine) - proc_compose(p_engine, type, 0, pid, -1, data, datalen); -} - int main_reload(void) { @@ -387,8 +373,8 @@ main_showinfo_ctl(struct imsg *imsg) { switch (imsg->hdr.type) { case IMSG_CTL_SHOW_MAIN_INFO: - main_imsg_compose_frontend(IMSG_CTL_END, imsg->hdr.pid, NULL, - 0); + proc_compose(p_frontend, IMSG_CTL_END, 0, imsg->hdr.pid, -1, + NULL, 0); break; default: log_debug("%s: error handling imsg", __func__); diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 2c83068..6610138 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -76,8 +76,6 @@ extern struct imsgproc *p_engine; extern struct imsgproc *p_main; /* smtpfd.c */ -void main_imsg_compose_frontend(int, pid_t, void *, uint16_t); -void main_imsg_compose_engine(int, pid_t, void *, uint16_t); struct smtpfd_conf *config_new_empty(void); void config_clear(struct smtpfd_conf *); From 07834eebdf0d56f1c34398f47ab2fd4b2da568d7 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Mon, 29 May 2017 23:35:35 +0200 Subject: [PATCH 20/41] make ctl_conn and control_state internal to contol.c --- extras/filters/smtpfd/control.c | 18 +++++++++++++++++- extras/filters/smtpfd/control.h | 11 ----------- extras/filters/smtpfd/frontend.c | 5 ++--- extras/filters/smtpfd/frontend.h | 4 +--- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c index 6fbc9e6..d3a438f 100644 --- a/extras/filters/smtpfd/control.c +++ b/extras/filters/smtpfd/control.c @@ -40,11 +40,25 @@ #define CONTROL_BACKLOG 5 +struct ctl_conn { + TAILQ_ENTRY(ctl_conn) entry; + struct imsgproc *proc; +}; + static struct ctl_conn *control_connbypid(pid_t); static void control_accept(int, short, void *); static void control_close(struct ctl_conn *); static void control_dispatch_imsg(struct imsgproc *, struct imsg *, void *); +static struct { + struct event ev; + struct event evt; + int fd; +} control_state; + +static TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns; + + int control_init(char *path) { @@ -52,6 +66,8 @@ control_init(char *path) int fd; mode_t old_umask; + TAILQ_INIT(&ctl_conns); + if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) { log_warn("%s: socket", __func__); @@ -224,7 +240,7 @@ control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_FRONTEND_INFO: - frontend_showinfo_ctl(c); + frontend_showinfo_ctl(c->proc); proc_compose(c->proc, IMSG_CTL_END, 0, 0, -1, NULL, 0); break; case IMSG_CTL_SHOW_ENGINE_INFO: diff --git a/extras/filters/smtpfd/control.h b/extras/filters/smtpfd/control.h index 9d40f8a..89f150d 100644 --- a/extras/filters/smtpfd/control.h +++ b/extras/filters/smtpfd/control.h @@ -16,17 +16,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -struct { - struct event ev; - struct event evt; - int fd; -} control_state; - -struct ctl_conn { - TAILQ_ENTRY(ctl_conn) entry; - struct imsgproc *proc; -}; - int control_init(char *); int control_listen(void); int control_imsg_relay(struct imsg *); diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index c29a7ec..184d8cf 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -84,7 +84,6 @@ frontend(int debug, int verbose, char *sockname) proc_enable(p_main); /* Listen on control socket. */ - TAILQ_INIT(&ctl_conns); control_listen(); event_dispatch(); @@ -144,10 +143,10 @@ frontend_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) } void -frontend_showinfo_ctl(struct ctl_conn *c) +frontend_showinfo_ctl(struct imsgproc *proc) { struct ctl_frontend_info cfi; - proc_compose(c->proc, IMSG_CTL_SHOW_FRONTEND_INFO, 0, 0, -1, + proc_compose(proc, IMSG_CTL_SHOW_FRONTEND_INFO, 0, 0, -1, &cfi, sizeof(struct ctl_frontend_info)); } diff --git a/extras/filters/smtpfd/frontend.h b/extras/filters/smtpfd/frontend.h index bf0d13e..4add148 100644 --- a/extras/filters/smtpfd/frontend.h +++ b/extras/filters/smtpfd/frontend.h @@ -16,9 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns; - struct imsgproc; void frontend(int, int, char *); -void frontend_showinfo_ctl(struct ctl_conn *); +void frontend_showinfo_ctl(struct imsgproc *); From e5ad1bd8b83585dd83594d93057b1e6ad1adb100 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Mon, 29 May 2017 23:40:34 +0200 Subject: [PATCH 21/41] move mostly empty engine.h and frontend.h to smtpfd.h --- extras/filters/smtpfd/control.c | 1 - extras/filters/smtpfd/engine.c | 1 - extras/filters/smtpfd/engine.h | 19 ------------------- extras/filters/smtpfd/frontend.c | 1 - extras/filters/smtpfd/frontend.h | 22 ---------------------- extras/filters/smtpfd/parse.y | 1 - extras/filters/smtpfd/smtpfd.c | 2 -- extras/filters/smtpfd/smtpfd.h | 8 ++++++++ 8 files changed, 8 insertions(+), 47 deletions(-) delete mode 100644 extras/filters/smtpfd/engine.h delete mode 100644 extras/filters/smtpfd/frontend.h diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c index d3a438f..93395cd 100644 --- a/extras/filters/smtpfd/control.c +++ b/extras/filters/smtpfd/control.c @@ -36,7 +36,6 @@ #include "proc.h" #include "smtpfd.h" #include "control.h" -#include "frontend.h" #define CONTROL_BACKLOG 5 diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 9c4b939..a600a32 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -38,7 +38,6 @@ #include "log.h" #include "proc.h" #include "smtpfd.h" -#include "engine.h" static void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *); static void engine_dispatch_main(struct imsgproc *, struct imsg *, void *); diff --git a/extras/filters/smtpfd/engine.h b/extras/filters/smtpfd/engine.h deleted file mode 100644 index 3ac771a..0000000 --- a/extras/filters/smtpfd/engine.h +++ /dev/null @@ -1,19 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2004, 2005 Esben Norby - * - * 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. - */ - -void engine(int, int); diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 184d8cf..3e52528 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -38,7 +38,6 @@ #include "log.h" #include "proc.h" #include "smtpfd.h" -#include "frontend.h" #include "control.h" diff --git a/extras/filters/smtpfd/frontend.h b/extras/filters/smtpfd/frontend.h deleted file mode 100644 index 4add148..0000000 --- a/extras/filters/smtpfd/frontend.h +++ /dev/null @@ -1,22 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2004, 2005 Esben Norby - * - * 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. - */ - -struct imsgproc; - -void frontend(int, int, char *); -void frontend_showinfo_ctl(struct imsgproc *); diff --git a/extras/filters/smtpfd/parse.y b/extras/filters/smtpfd/parse.y index 5a03f93..28932cf 100644 --- a/extras/filters/smtpfd/parse.y +++ b/extras/filters/smtpfd/parse.y @@ -46,7 +46,6 @@ #include "log.h" #include "smtpfd.h" -#include "frontend.h" TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index cd919b9..dd9fbfc 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -40,8 +40,6 @@ #include "log.h" #include "proc.h" #include "smtpfd.h" -#include "frontend.h" -#include "engine.h" #include "control.h" __dead void usage(void); diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 6610138..361bc90 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -75,6 +75,14 @@ extern struct imsgproc *p_frontend; extern struct imsgproc *p_engine; extern struct imsgproc *p_main; + +/* engine.c */ +void engine(int, int); + +/* frontend.c */ +void frontend(int, int, char *); +void frontend_showinfo_ctl(struct imsgproc *); + /* smtpfd.c */ struct smtpfd_conf *config_new_empty(void); void config_clear(struct smtpfd_conf *); From f5ff470c5da7ea118c7a0978e057741da9d0305e Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Tue, 30 May 2017 08:42:29 +0200 Subject: [PATCH 22/41] implement the -D option and tweak manpage --- extras/filters/smtpfd/smtpfd.8 | 23 +++++++++++++++-------- extras/filters/smtpfd/smtpfd.c | 7 ++++++- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/extras/filters/smtpfd/smtpfd.8 b/extras/filters/smtpfd/smtpfd.8 index 77ab9d8..df783f4 100644 --- a/extras/filters/smtpfd/smtpfd.8 +++ b/extras/filters/smtpfd/smtpfd.8 @@ -19,18 +19,18 @@ .Os .Sh NAME .Nm smtpfd -.Nd sample daemon +.Nd SMTP filter daemon .Sh SYNOPSIS .Nm .Op Fl dnv .Op Fl f Ar file .Op Fl s Ar socket .Sh DESCRIPTION +The .Nm -is an example daemon that does nothing but provide the framework for a -standard -.Ox -privilege separated daemon. +daemon is an SMTP filter server. It is typically used by +.Xr smtpd 8 +to provide custom filtering on SMTP sessions. .Pp .Nm is usually started at boot time, and can be enabled by @@ -49,11 +49,17 @@ and enabling daemons. A running .Nm can be controlled with the -.Xr newctl 8 +.Xr smtpfctl 8 utility. .Pp The options are as follows: -.Bl -tag -width Ds +.Bl -tag -width Dssmacro=value +.It Fl D Ar macro Ns = Ns Ar value +Set a +.Ar macro +to a +.Ar value . +Macros can be referenced in the configuration files. .It Fl d Do not daemonize. If this option is specified, @@ -83,7 +89,8 @@ socket used for communication with .El .Sh SEE ALSO .Xr smtpfd.conf 5 , -.Xr newctl 8 +.Xr smtpfctl 8 , +.Xr smtpd 8 .Sh HISTORY The .Nm diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index dd9fbfc..39d6a7d 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -118,8 +118,13 @@ main(int argc, char *argv[]) if (saved_argv0 == NULL) saved_argv0 = "smtpfd"; - while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) { + while ((ch = getopt(argc, argv, "D:dEFf:ns:v")) != -1) { switch (ch) { + case 'D': + if (cmdline_symset(optarg) < 0) + log_warnx("could not parse macro definition %s", + optarg); + break; case 'd': debug = 1; break; From a64a73fbf0fe284d51725132dd261ffba48aeb28 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Tue, 30 May 2017 08:53:48 +0200 Subject: [PATCH 23/41] mark static funciotns as static --- extras/filters/smtpfd/engine.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index a600a32..8e6cc6f 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -82,7 +82,7 @@ engine(int debug, int verbose) exit(0); } -void +static void engine_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *bula) { int verbose; @@ -108,7 +108,7 @@ engine_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *bula) } } -void +static void engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) { if (imsg == NULL) { @@ -141,7 +141,7 @@ engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) } } -void +static void engine_showinfo_ctl(struct imsg *imsg) { switch (imsg->hdr.type) { From 96e5d22ac078962cb1e578402be90cb4b39682b0 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Tue, 30 May 2017 09:08:13 +0200 Subject: [PATCH 24/41] tweak includes --- extras/filters/smtpfd/control.c | 5 +---- extras/filters/smtpfd/engine.c | 8 +------- extras/filters/smtpfd/frontend.c | 9 +-------- extras/filters/smtpfd/parse.y | 10 ---------- extras/filters/smtpfd/proc.h | 2 -- extras/filters/smtpfd/smtpfd.c | 4 +--- 6 files changed, 4 insertions(+), 34 deletions(-) diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c index 93395cd..7a5d9a4 100644 --- a/extras/filters/smtpfd/control.c +++ b/extras/filters/smtpfd/control.c @@ -15,19 +15,16 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + #include #include #include #include -#include #include -#include - #include #include #include -#include #include #include #include diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 8e6cc6f..9254a5d 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -19,20 +19,14 @@ */ #include -#include #include #include -#include -#include - -#include #include #include -#include +#include #include #include -#include #include #include "log.h" diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 3e52528..f4bbbbb 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -17,22 +17,15 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + #include -#include #include #include -#include - -#include -#include #include #include #include -#include -#include #include -#include #include #include "log.h" diff --git a/extras/filters/smtpfd/parse.y b/extras/filters/smtpfd/parse.y index 28932cf..6c876a7 100644 --- a/extras/filters/smtpfd/parse.y +++ b/extras/filters/smtpfd/parse.y @@ -27,20 +27,10 @@ #include #include -#include - -#include - #include #include -#include -#include -#include -#include #include -#include #include -#include #include #include diff --git a/extras/filters/smtpfd/proc.h b/extras/filters/smtpfd/proc.h index c6a67f7..5cb436a 100644 --- a/extras/filters/smtpfd/proc.h +++ b/extras/filters/smtpfd/proc.h @@ -16,8 +16,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - struct imsgproc; /* proc.c */ diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 39d6a7d..522a20e 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -17,15 +17,13 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + #include #include #include #include -#include #include -#include - #include #include #include From e95fb1e8abf3df68432b5eff8dfe4ea685fa01f2 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Tue, 30 May 2017 13:28:21 +0200 Subject: [PATCH 25/41] use fatalx() instead of errx() --- extras/filters/smtpfd/smtpfd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 522a20e..d5c49b2 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -176,11 +175,11 @@ main(int argc, char *argv[]) /* Check for root privileges. */ if (geteuid()) - errx(1, "need root privileges"); + fatalx("need root privileges"); /* Check for assigned daemon user */ if (getpwnam(SMTPFD_USER) == NULL) - errx(1, "unknown user %s", SMTPFD_USER); + fatalx("unknown user %s", SMTPFD_USER); log_init(debug, LOG_DAEMON); log_setverbose(cmd_opts & OPT_VERBOSE); From d6d8f1e0dbfe9b535113a24ce282d8a607e44ff4 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Tue, 30 May 2017 13:36:12 +0200 Subject: [PATCH 26/41] get rid of ctl_conn structure and use imsgproc directly --- extras/filters/smtpfd/control.c | 73 +++++++++------------------------ 1 file changed, 19 insertions(+), 54 deletions(-) diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c index 7a5d9a4..5310d72 100644 --- a/extras/filters/smtpfd/control.c +++ b/extras/filters/smtpfd/control.c @@ -36,14 +36,8 @@ #define CONTROL_BACKLOG 5 -struct ctl_conn { - TAILQ_ENTRY(ctl_conn) entry; - struct imsgproc *proc; -}; - -static struct ctl_conn *control_connbypid(pid_t); static void control_accept(int, short, void *); -static void control_close(struct ctl_conn *); +static void control_close(struct imsgproc *); static void control_dispatch_imsg(struct imsgproc *, struct imsg *, void *); static struct { @@ -52,8 +46,6 @@ static struct { int fd; } control_state; -static TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns; - int control_init(char *path) @@ -62,8 +54,6 @@ control_init(char *path) int fd; mode_t old_umask; - TAILQ_INIT(&ctl_conns); - if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) { log_warn("%s: socket", __func__); @@ -129,13 +119,13 @@ control_cleanup(char *path) unlink(path); } -void +static void control_accept(int listenfd, short event, void *bula) { int connfd; socklen_t len; struct sockaddr_un sun; - struct ctl_conn *c; + struct imsgproc *p; event_add(&control_state.ev, NULL); if ((event & EV_TIMEOUT)) @@ -159,56 +149,30 @@ control_accept(int listenfd, short event, void *bula) return; } - if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { - log_warn("%s: calloc", __func__); - close(connfd); - return; - } - - c->proc = proc_attach(PROC_CLIENT, connfd); - proc_setcallback(c->proc, control_dispatch_imsg, c); - proc_enable(c->proc); - - TAILQ_INSERT_TAIL(&ctl_conns, c, entry); + p = proc_attach(PROC_CLIENT, connfd); + proc_setcallback(p, control_dispatch_imsg, NULL); + proc_enable(p); } -struct ctl_conn * -control_connbypid(pid_t pid) +static void +control_close(struct imsgproc *p) { - struct ctl_conn *c; - - TAILQ_FOREACH(c, &ctl_conns, entry) { - if (proc_getpid(c->proc) == pid) - break; - } - - return (c); -} - -void -control_close(struct ctl_conn *c) -{ - TAILQ_REMOVE(&ctl_conns, c, entry); - - proc_free(c->proc); + proc_free(p); /* Some file descriptors are available again. */ if (evtimer_pending(&control_state.evt, NULL)) { evtimer_del(&control_state.evt); event_add(&control_state.ev, NULL); } - - free(c); } -void +static void control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) { - struct ctl_conn *c = arg; int verbose; if (imsg == NULL) { - control_close(c); + control_close(p); return; } @@ -231,16 +195,16 @@ control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) log_setverbose(verbose); break; case IMSG_CTL_SHOW_MAIN_INFO: - proc_setpid(c->proc, imsg->hdr.pid); + proc_setpid(p, imsg->hdr.pid); proc_compose(p_main, imsg->hdr.type, 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_FRONTEND_INFO: - frontend_showinfo_ctl(c->proc); - proc_compose(c->proc, IMSG_CTL_END, 0, 0, -1, NULL, 0); + frontend_showinfo_ctl(p); + proc_compose(p, IMSG_CTL_END, 0, 0, -1, NULL, 0); break; case IMSG_CTL_SHOW_ENGINE_INFO: - proc_setpid(c->proc, imsg->hdr.pid); + proc_setpid(p, imsg->hdr.pid); proc_compose(p_engine, imsg->hdr.type, 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); break; @@ -254,11 +218,12 @@ control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) int control_imsg_relay(struct imsg *imsg) { - struct ctl_conn *c; + struct imsgproc *p; - if ((c = control_connbypid(imsg->hdr.pid)) == NULL) + if ((p = proc_bypid(imsg->hdr.pid)) == NULL || + proc_gettype(p) != PROC_CLIENT) return (0); - return (proc_compose(c->proc, imsg->hdr.type, 0, imsg->hdr.pid, -1, + return (proc_compose(p, imsg->hdr.type, 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); } From 3e3f65493fe8f956ebd1d442754f4991be55c43a Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Tue, 30 May 2017 13:58:13 +0200 Subject: [PATCH 27/41] - use static where appropriate - properly set up child imsgproc --- extras/filters/smtpfd/smtpfd.c | 47 +++++++++++++++++----------------- extras/filters/smtpfd/smtpfd.h | 2 +- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index d5c49b2..06eafe6 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -39,31 +39,28 @@ #include "smtpfd.h" #include "control.h" -__dead void usage(void); -__dead void main_shutdown(void); - -void main_sig_handler(int, short, void *); - -void main_dispatch_frontend(struct imsgproc *, struct imsg*, void *); -void main_dispatch_engine(struct imsgproc *, struct imsg*, void *); +__dead static void usage(void); +__dead static void main_shutdown(void); +static void main_sig_handler(int, short, void *); +static void main_dispatch_frontend(struct imsgproc *, struct imsg*, void *); +static void main_dispatch_engine(struct imsgproc *, struct imsg*, void *); static int main_imsg_send_config(struct smtpfd_conf *); - static int main_reload(void); static int main_sendboth(enum imsg_type, void *, uint16_t); static void main_showinfo_ctl(struct imsg *); static void config_print(struct smtpfd_conf *); -struct smtpfd_conf *main_conf; -struct imsgproc *p_frontend; -struct imsgproc *p_engine; -struct imsgproc *p_main; - -char *conffile; -char *csock; +static char *conffile; +static char *csock; +static struct smtpfd_conf *main_conf; +/* globals */ uint32_t cmd_opts; +struct imsgproc *p_frontend; +struct imsgproc *p_engine; +struct imsgproc *p_main; -void +static void main_sig_handler(int sig, short event, void *arg) { /* @@ -86,7 +83,7 @@ main_sig_handler(int sig, short event, void *arg) } } -__dead void +__dead static void usage(void) { extern char *__progname; @@ -203,9 +200,11 @@ main(int argc, char *argv[]) rargv[rargc++] = NULL; p_frontend = proc_exec(PROC_FRONTEND, rargv); + proc_setcallback(p_frontend, main_dispatch_frontend, NULL); rargv[1] = "-E"; rargv[argc - 3] = NULL; p_engine = proc_exec(PROC_ENGINE, rargv); + proc_setcallback(p_engine, main_dispatch_engine, NULL); event_init(); @@ -244,7 +243,7 @@ main(int argc, char *argv[]) return (0); } -__dead void +__dead static void main_shutdown(void) { pid_t pid; @@ -279,7 +278,7 @@ main_shutdown(void) exit(0); } -void +static void main_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *arg) { int verbose; @@ -311,7 +310,7 @@ main_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *arg) } } -void +static void main_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) { if (imsg == NULL) { @@ -327,7 +326,7 @@ main_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) } } -int +static int main_reload(void) { struct smtpfd_conf *xconf; @@ -344,7 +343,7 @@ main_reload(void) return (0); } -int +static int main_imsg_send_config(struct smtpfd_conf *xconf) { /* Send fixed part of config to children. */ @@ -358,7 +357,7 @@ main_imsg_send_config(struct smtpfd_conf *xconf) return (0); } -int +static int main_sendboth(enum imsg_type type, void *buf, uint16_t len) { if (proc_compose(p_frontend, type, 0, 0, -1, buf, len) == -1) @@ -368,7 +367,7 @@ main_sendboth(enum imsg_type type, void *buf, uint16_t len) return (0); } -void +static void main_showinfo_ctl(struct imsg *imsg) { switch (imsg->hdr.type) { diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 361bc90..097c00e 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -70,7 +70,7 @@ struct ctl_engine_info { struct ctl_main_info { }; -extern uint32_t cmd_opts; +extern uint32_t cmd_opts; extern struct imsgproc *p_frontend; extern struct imsgproc *p_engine; extern struct imsgproc *p_main; From b1e1128ab3c2875cab7a2804f52ba7875d21f01d Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Tue, 30 May 2017 19:20:26 +0200 Subject: [PATCH 28/41] tweak the condig parser a bit. make the main process fork external filters as found in the config file and pass the imsg handle to the engine. --- extras/filters/smtpfd/engine.c | 75 +++++++++++++++++++++------------- extras/filters/smtpfd/parse.y | 26 +++++++++--- extras/filters/smtpfd/smtpfd.c | 67 +++++++++++++++++++++++++++++- extras/filters/smtpfd/smtpfd.h | 4 +- 4 files changed, 136 insertions(+), 36 deletions(-) diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 9254a5d..2815087 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -35,7 +35,7 @@ static void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *); static void engine_dispatch_main(struct imsgproc *, struct imsg *, void *); -static void engine_showinfo_ctl(struct imsg *); +static void engine_dispatch_filter(struct imsgproc *, struct imsg *, void *); void @@ -76,32 +76,6 @@ engine(int debug, int verbose) exit(0); } -static void -engine_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *bula) -{ - int verbose; - - if (imsg == NULL) { - log_debug("%s: imsg connection lost", __func__); - event_loopexit(NULL); - return; - } - - switch (imsg->hdr.type) { - case IMSG_CTL_LOG_VERBOSE: - /* Already checked by frontend. */ - memcpy(&verbose, imsg->data, sizeof(verbose)); - log_setverbose(verbose); - break; - case IMSG_CTL_SHOW_ENGINE_INFO: - engine_showinfo_ctl(imsg); - break; - default: - log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); - break; - } -} - static void engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) { @@ -129,6 +103,19 @@ engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) proc_setcallback(p_frontend, engine_dispatch_frontend, NULL); proc_enable(p_frontend); break; + + case IMSG_RECONF_FILTER: + if (imsg->fd == -1) + fatalx("failed to receive filter process fd"); + + p = proc_attach(PROC_FILTER, imsg->fd); + if (p == NULL) + fatal("proc_attach"); + proc_settitle(p, imsg->data); + proc_setcallback(p, engine_dispatch_filter, NULL); + proc_enable(p); + break; + default: log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); break; @@ -136,9 +123,22 @@ engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) } static void -engine_showinfo_ctl(struct imsg *imsg) +engine_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *bula) { + int verbose; + + if (imsg == NULL) { + log_debug("%s: imsg connection lost", __func__); + event_loopexit(NULL); + return; + } + switch (imsg->hdr.type) { + case IMSG_CTL_LOG_VERBOSE: + /* Already checked by frontend. */ + memcpy(&verbose, imsg->data, sizeof(verbose)); + log_setverbose(verbose); + break; case IMSG_CTL_SHOW_ENGINE_INFO: proc_compose(p_frontend, IMSG_CTL_END, 0, imsg->hdr.pid, -1, NULL, 0); @@ -148,3 +148,22 @@ engine_showinfo_ctl(struct imsg *imsg) break; } } + +static void +engine_dispatch_filter(struct imsgproc *p, struct imsg *imsg, void *bula) +{ + if (imsg == NULL) { + log_debug("%s: imsg connection lost to filter %s", __func__, + proc_gettitle(p)); + event_loopexit(NULL); + return; + } + + switch (imsg->hdr.type) { + default: + log_debug("%s: unexpected imsg %d from filter %s", __func__, + imsg->hdr.type, proc_gettitle(p)); + proc_compose(p, 1, 0, 0, -1, NULL, 0); + break; + } +} diff --git a/extras/filters/smtpfd/parse.y b/extras/filters/smtpfd/parse.y index 6c876a7..6c336fa 100644 --- a/extras/filters/smtpfd/parse.y +++ b/extras/filters/smtpfd/parse.y @@ -90,7 +90,6 @@ typedef struct { %token STRING %token NUMBER %type string -%type filter_or_chain %% @@ -98,6 +97,7 @@ grammar : /* empty */ | grammar include '\n' | grammar '\n' | grammar filter '\n' + | grammar chain '\n' | grammar varset '\n' | grammar error '\n' { file->errors++; } ; @@ -176,11 +176,26 @@ filter_args : STRING { | /* empty */ ; -filter_or_chain : FILTER { $$ = 0; } - | CHAIN { $$ = 1; } +filter : FILTER STRING STRING { + TAILQ_FOREACH(filter, &conf->filters, entry) + if (!strcmp(filter->name, $2)) { + yyerror("filter %s already defined", + filter->name); + YYERROR; + } + filter = calloc(1, sizeof(*filter)); + if (filter == NULL) + fatal("calloc"); + filter->argv[filter->argc++] = $3; + filter->argv[filter->argc++] = $2; + filter->name = strdup($2); + if (filter->name == NULL) + fatal("strdup"); + TAILQ_INSERT_TAIL(&conf->filters, filter, entry); + } filter_args ; -filter : filter_or_chain STRING { +chain : CHAIN STRING { TAILQ_FOREACH(filter, &conf->filters, entry) if (!strcmp(filter->name, $2)) { yyerror("filter %s already defined", @@ -190,11 +205,10 @@ filter : filter_or_chain STRING { filter = calloc(1, sizeof(*filter)); if (filter == NULL) fatal("calloc"); - filter->chain = $1; + filter->chain = 1; filter->name = $2; TAILQ_INSERT_TAIL(&conf->filters, filter, entry); } filter_args - ; optnl : '\n' optnl /* zero or more newlines */ | /*empty*/ diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 06eafe6..54bbf8d 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -47,6 +47,7 @@ static void main_dispatch_engine(struct imsgproc *, struct imsg*, void *); static int main_imsg_send_config(struct smtpfd_conf *); static int main_reload(void); static int main_sendboth(enum imsg_type, void *, uint16_t); +static void main_runfilter(struct filter_conf *f); static void main_showinfo_ctl(struct imsg *); static void config_print(struct smtpfd_conf *); @@ -63,12 +64,34 @@ struct imsgproc *p_main; static void main_sig_handler(int sig, short event, void *arg) { + pid_t pid; + int status; + /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { + case SIGCHLD: + do { + pid = waitpid(-1, &status, WNOHANG); + if (pid <= 0) + continue; + if (WIFSIGNALED(status)) + log_warnx("process %d terminated by signal %d", + (int)pid, WTERMSIG(status)); + else if (WIFEXITED(status) && WEXITSTATUS(status)) + log_warnx("process %d exited with status %d", + (int)pid, WEXITSTATUS(status)); + else if (WIFEXITED(status)) + log_debug("debug: process %d exited normally", + (int)pid); + else + /* WIFSTOPPED or WIFCONTINUED */ + continue; + } while (pid > 0 || (pid == -1 && errno == EINTR)); + break; case SIGTERM: case SIGINT: main_shutdown(); @@ -96,7 +119,7 @@ usage(void) int main(int argc, char *argv[]) { - struct event ev_sigint, ev_sigterm, ev_sighup; + struct event ev_sigint, ev_sigterm, ev_sighup, ev_sigchld; int ch, sp[2], rargc = 0; int debug = 0, engine_flag = 0, frontend_flag = 0; char *saved_argv0; @@ -212,9 +235,11 @@ main(int argc, char *argv[]) signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); + signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, NULL); signal_add(&ev_sigint, NULL); signal_add(&ev_sigterm, NULL); signal_add(&ev_sighup, NULL); + signal_add(&ev_sigchld, NULL); signal(SIGPIPE, SIG_IGN); /* Start children */ @@ -346,10 +371,18 @@ main_reload(void) static int main_imsg_send_config(struct smtpfd_conf *xconf) { + struct filter_conf *f; + /* Send fixed part of config to children. */ if (main_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) return (-1); + TAILQ_FOREACH(f, &xconf->filters, entry) { + if (f->chain) + continue; + main_runfilter(f); + } + /* Tell children the revised config is now complete. */ if (main_sendboth(IMSG_RECONF_END, NULL, 0) == -1) return (-1); @@ -367,6 +400,38 @@ main_sendboth(enum imsg_type type, void *buf, uint16_t len) return (0); } +static void +main_runfilter(struct filter_conf *f) +{ + int sp[2]; + pid_t pid; + + if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, PF_UNSPEC, sp) == -1) + fatal("socketpair"); + + switch (pid = fork()) { + case -1: + fatal("fork"); + case 0: + break; + default: + close(sp[0]); + log_debug("forked filter %s as pid %d", f->name, (int)pid); + proc_compose(p_engine, IMSG_RECONF_FILTER, 0, pid, sp[1], + f->name, strlen(f->name) + 1); + return; + } + + if (dup2(sp[0], 3) == -1) + fatal("dup2"); + + if (closefrom(4) == -1) + fatal("closefrom"); + + execvp(f->argv[0], f->argv+1); + fatal("proc_exec: execvp: %s", f->argv[0]); +} + static void main_showinfo_ctl(struct imsg *imsg) { diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 097c00e..9eb7940 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -36,7 +36,8 @@ enum imsg_type { IMSG_CTL_SHOW_MAIN_INFO, IMSG_CTL_END, IMSG_RECONF_CONF, - IMSG_RECONF_GROUP, + IMSG_RECONF_FILTER, + IMSG_RECONF_CHAIN, IMSG_RECONF_END, IMSG_SOCKET_IPC }; @@ -45,6 +46,7 @@ enum smtpfd_process { PROC_MAIN, PROC_ENGINE, PROC_FRONTEND, + PROC_FILTER, PROC_CLIENT, }; From 23819696e89ad86af7cbc9ba49cafbe4705c58f9 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Tue, 30 May 2017 22:50:09 +0200 Subject: [PATCH 29/41] pass the filter processes and flattened chains to the engine --- extras/filters/smtpfd/engine.c | 91 +++++++++++++++++++++++++++++++--- extras/filters/smtpfd/smtpfd.c | 61 +++++++++++++++-------- extras/filters/smtpfd/smtpfd.h | 3 +- 3 files changed, 125 insertions(+), 30 deletions(-) diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 2815087..9cde802 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -33,15 +33,38 @@ #include "proc.h" #include "smtpfd.h" +struct filter_process { + TAILQ_ENTRY(filter_process) entry; + struct imsgproc *proc; +}; + +struct filter_node { + TAILQ_ENTRY(filter_node) entry; + struct filter_process *fproc; +}; + +struct filter { + char *name; + TAILQ_ENTRY(filter) entry; + TAILQ_HEAD(, filter_node) nodes; +}; + +struct engine_config { + TAILQ_HEAD(, filter_process) procs; + TAILQ_HEAD(, filter) filters; +}; + static void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *); static void engine_dispatch_main(struct imsgproc *, struct imsg *, void *); static void engine_dispatch_filter(struct imsgproc *, struct imsg *, void *); +static struct engine_config *conf; +static struct engine_config *tmpconf; void engine(int debug, int verbose) { - struct passwd *pw; + struct passwd *pw; log_init(debug, LOG_DAEMON); log_setverbose(verbose); @@ -79,6 +102,10 @@ engine(int debug, int verbose) static void engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) { + struct filter_process *fproc; + struct filter_node *fnode; + struct filter *f; + if (imsg == NULL) { log_debug("%s: imsg connection lost", __func__); event_loopexit(NULL); @@ -104,16 +131,66 @@ engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) proc_enable(p_frontend); break; - case IMSG_RECONF_FILTER: + case IMSG_RECONF_CONF: + if (tmpconf) + fatalx("already configuring"); + tmpconf = calloc(1, sizeof(*tmpconf)); + if (tmpconf == NULL) + fatal("calloc"); + TAILQ_INIT(&tmpconf->procs); + TAILQ_INIT(&tmpconf->filters); + break; + + case IMSG_RECONF_FILTER_PROC: if (imsg->fd == -1) fatalx("failed to receive filter process fd"); - p = proc_attach(PROC_FILTER, imsg->fd); - if (p == NULL) + fproc = calloc(1, sizeof(*fproc)); + if (fproc == NULL) + fatal("calloc"); + fproc->proc = proc_attach(PROC_FILTER, imsg->fd); + if (fproc->proc == NULL) fatal("proc_attach"); - proc_settitle(p, imsg->data); - proc_setcallback(p, engine_dispatch_filter, NULL); - proc_enable(p); + proc_settitle(fproc->proc, imsg->data); + proc_setcallback(fproc->proc, engine_dispatch_filter, fproc); + proc_enable(fproc->proc); + TAILQ_INSERT_TAIL(&tmpconf->procs, fproc, entry); + log_info("new filter process: %s", (char *)imsg->data); + break; + + case IMSG_RECONF_FILTER: + f = calloc(1, sizeof(*f)); + if (f == NULL) + fatal("calloc"); + f->name = strdup(imsg->data); + if (f->name == NULL) + fatal("strdup"); + TAILQ_INIT(&f->nodes); + TAILQ_INSERT_HEAD(&tmpconf->filters, f, entry); + log_info("new filter: %s", (char *)imsg->data); + break; + + case IMSG_RECONF_FILTER_NODE: + fnode = calloc(1, sizeof(*fnode)); + if (fnode == NULL) + fatal("calloc"); + TAILQ_FOREACH(fproc, &tmpconf->procs, entry) { + if (!strcmp(proc_gettitle(fproc->proc), imsg->data)) { + fnode->fproc = fproc; + break; + } + } + if (fnode->fproc == NULL) + fatalx("unknown filter process %s", (char *)imsg->data); + f = TAILQ_FIRST(&tmpconf->filters); + TAILQ_INSERT_TAIL(&f->nodes, fnode, entry); + log_info("new node filter on filter %s: %s", f->name, (char *)imsg->data); + break; + + case IMSG_RECONF_END: + /* XXX purge old config */ + conf = tmpconf; + tmpconf = NULL; break; default: diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 54bbf8d..28374a4 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -44,10 +44,10 @@ __dead static void main_shutdown(void); static void main_sig_handler(int, short, void *); static void main_dispatch_frontend(struct imsgproc *, struct imsg*, void *); static void main_dispatch_engine(struct imsgproc *, struct imsg*, void *); -static int main_imsg_send_config(struct smtpfd_conf *); static int main_reload(void); -static int main_sendboth(enum imsg_type, void *, uint16_t); -static void main_runfilter(struct filter_conf *f); +static int main_send_config(struct smtpfd_conf *); +static void main_send_filter_proc(struct filter_conf *); +static void main_send_filter_conf(struct smtpfd_conf *, struct filter_conf *); static void main_showinfo_ctl(struct imsg *); static void config_print(struct smtpfd_conf *); @@ -257,7 +257,7 @@ main(int argc, char *argv[]) == -1) fatal("proc_compose"); - main_imsg_send_config(main_conf); + main_send_config(main_conf); if (pledge("rpath stdio sendfd cpath", NULL) == -1) fatal("pledge"); @@ -359,7 +359,7 @@ main_reload(void) if ((xconf = parse_config(conffile)) == NULL) return (-1); - if (main_imsg_send_config(xconf) == -1) + if (main_send_config(xconf) == -1) return (-1); config_clear(main_conf); @@ -369,39 +369,35 @@ main_reload(void) } static int -main_imsg_send_config(struct smtpfd_conf *xconf) +main_send_config(struct smtpfd_conf *xconf) { struct filter_conf *f; - /* Send fixed part of config to children. */ - if (main_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) + /* Send fixed part of config to engine. */ + if (proc_compose(p_engine, IMSG_RECONF_CONF, 0, 0, -1, NULL, 0) == -1) return (-1); TAILQ_FOREACH(f, &xconf->filters, entry) { if (f->chain) continue; - main_runfilter(f); + main_send_filter_proc(f); + } + + TAILQ_FOREACH(f, &xconf->filters, entry) { + proc_compose(p_engine, IMSG_RECONF_FILTER, 0, 0, -1, f->name, + strlen(f->name) + 1); + main_send_filter_conf(xconf, f); } /* Tell children the revised config is now complete. */ - if (main_sendboth(IMSG_RECONF_END, NULL, 0) == -1) + if (proc_compose(p_engine, IMSG_RECONF_END, 0, 0, -1, NULL, 0) == -1) return (-1); return (0); } -static int -main_sendboth(enum imsg_type type, void *buf, uint16_t len) -{ - if (proc_compose(p_frontend, type, 0, 0, -1, buf, len) == -1) - return (-1); - if (proc_compose(p_engine, type, 0, 0, -1, buf, len) == -1) - return (-1); - return (0); -} - static void -main_runfilter(struct filter_conf *f) +main_send_filter_proc(struct filter_conf *f) { int sp[2]; pid_t pid; @@ -417,7 +413,7 @@ main_runfilter(struct filter_conf *f) default: close(sp[0]); log_debug("forked filter %s as pid %d", f->name, (int)pid); - proc_compose(p_engine, IMSG_RECONF_FILTER, 0, pid, sp[1], + proc_compose(p_engine, IMSG_RECONF_FILTER_PROC, 0, pid, sp[1], f->name, strlen(f->name) + 1); return; } @@ -432,6 +428,27 @@ main_runfilter(struct filter_conf *f) fatal("proc_exec: execvp: %s", f->argv[0]); } +static void +main_send_filter_conf(struct smtpfd_conf *conf, struct filter_conf *f) +{ + struct filter_conf *tmp; + int i; + + if (f->chain) { + for (i = 0; i < f->argc; i++) { + TAILQ_FOREACH(tmp, &conf->filters, entry) + if (!strcmp(f->argv[i], tmp->name)) { + main_send_filter_conf(conf, tmp); + break; + } + } + } + else { + proc_compose(p_engine, IMSG_RECONF_FILTER_NODE, 0, 0, -1, + f->name, strlen(f->name) + 1); + } +} + static void main_showinfo_ctl(struct imsg *imsg) { diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 9eb7940..8eaa867 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -36,8 +36,9 @@ enum imsg_type { IMSG_CTL_SHOW_MAIN_INFO, IMSG_CTL_END, IMSG_RECONF_CONF, + IMSG_RECONF_FILTER_PROC, IMSG_RECONF_FILTER, - IMSG_RECONF_CHAIN, + IMSG_RECONF_FILTER_NODE, IMSG_RECONF_END, IMSG_SOCKET_IPC }; From 6823d6c6d9144cf4966bc785d34e3ebe658fe47e Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Wed, 31 May 2017 08:23:49 +0200 Subject: [PATCH 30/41] remove unused showinfo code --- extras/filters/smtpfd/control.c | 1 - extras/filters/smtpfd/frontend.c | 14 ++++---------- extras/filters/smtpfd/smtpfd.c | 17 +---------------- extras/filters/smtpfd/smtpfd.h | 10 ---------- 4 files changed, 5 insertions(+), 37 deletions(-) diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c index 5310d72..f278348 100644 --- a/extras/filters/smtpfd/control.c +++ b/extras/filters/smtpfd/control.c @@ -200,7 +200,6 @@ control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_FRONTEND_INFO: - frontend_showinfo_ctl(p); proc_compose(p, IMSG_CTL_END, 0, 0, -1, NULL, 0); break; case IMSG_CTL_SHOW_ENGINE_INFO: diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index f4bbbbb..faf1ead 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -93,6 +93,9 @@ frontend_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *arg) } switch (imsg->hdr.type) { + case IMSG_CTL_END: + control_imsg_relay(imsg); + break; case IMSG_SOCKET_IPC: /* * Setup pipe and event handler to the engine @@ -126,19 +129,10 @@ frontend_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) } switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_ENGINE_INFO: + case IMSG_CTL_END: control_imsg_relay(imsg); break; default: log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); } } - -void -frontend_showinfo_ctl(struct imsgproc *proc) -{ - struct ctl_frontend_info cfi; - - proc_compose(proc, IMSG_CTL_SHOW_FRONTEND_INFO, 0, 0, -1, - &cfi, sizeof(struct ctl_frontend_info)); -} diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 28374a4..391ff0d 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -48,7 +48,6 @@ static int main_reload(void); static int main_send_config(struct smtpfd_conf *); static void main_send_filter_proc(struct filter_conf *); static void main_send_filter_conf(struct smtpfd_conf *, struct filter_conf *); -static void main_showinfo_ctl(struct imsg *); static void config_print(struct smtpfd_conf *); static char *conffile; @@ -326,7 +325,7 @@ main_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *arg) log_setverbose(verbose); break; case IMSG_CTL_SHOW_MAIN_INFO: - main_showinfo_ctl(imsg); + proc_compose(p, IMSG_CTL_END, 0, imsg->hdr.pid, -1, NULL, 0); break; default: log_debug("%s: error handling imsg %d", __func__, @@ -449,20 +448,6 @@ main_send_filter_conf(struct smtpfd_conf *conf, struct filter_conf *f) } } -static void -main_showinfo_ctl(struct imsg *imsg) -{ - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_MAIN_INFO: - proc_compose(p_frontend, IMSG_CTL_END, 0, imsg->hdr.pid, -1, - NULL, 0); - break; - default: - log_debug("%s: error handling imsg", __func__); - break; - } -} - struct smtpfd_conf * config_new_empty(void) { diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 8eaa867..feef9b2 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -64,15 +64,6 @@ struct smtpfd_conf { TAILQ_HEAD(, filter_conf) filters; }; -struct ctl_frontend_info { -}; - -struct ctl_engine_info { -}; - -struct ctl_main_info { -}; - extern uint32_t cmd_opts; extern struct imsgproc *p_frontend; extern struct imsgproc *p_engine; @@ -84,7 +75,6 @@ void engine(int, int); /* frontend.c */ void frontend(int, int, char *); -void frontend_showinfo_ctl(struct imsgproc *); /* smtpfd.c */ struct smtpfd_conf *config_new_empty(void); From 1d8035ddbf332ae02611b1c621aaa60240392cdb Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Wed, 31 May 2017 08:28:46 +0200 Subject: [PATCH 31/41] missing semicolon --- extras/filters/smtpfd/parse.y | 1 + 1 file changed, 1 insertion(+) diff --git a/extras/filters/smtpfd/parse.y b/extras/filters/smtpfd/parse.y index 6c336fa..7e28948 100644 --- a/extras/filters/smtpfd/parse.y +++ b/extras/filters/smtpfd/parse.y @@ -209,6 +209,7 @@ chain : CHAIN STRING { filter->name = $2; TAILQ_INSERT_TAIL(&conf->filters, filter, entry); } filter_args + ; optnl : '\n' optnl /* zero or more newlines */ | /*empty*/ From 5808452958f38d18e79c729d6ac78616be2974b5 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Mon, 10 Jul 2017 20:00:01 +0200 Subject: [PATCH 32/41] display __func__ in log message where appropriate --- extras/filters/smtpfd/proc.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/extras/filters/smtpfd/proc.c b/extras/filters/smtpfd/proc.c index 2817df5..0a8dcf2 100644 --- a/extras/filters/smtpfd/proc.c +++ b/extras/filters/smtpfd/proc.c @@ -101,14 +101,14 @@ proc_exec(int type, char **argv) p = proc_new(type); if (p == NULL) - fatal("proc_exec: calloc"); + fatal("%s: proc_new", __func__); if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, PF_UNSPEC, sp) == -1) - fatal("proc_exec: socketpair"); + fatal("%s: socketpair", __func__); switch (pid = fork()) { case -1: - fatal("proc_exec: fork"); + fatal("%s: fork", __func__); case 0: break; default: @@ -119,13 +119,13 @@ proc_exec(int type, char **argv) } if (dup2(sp[0], 3) == -1) - fatal("proc_exec: dup2"); + fatal("%s: dup2", __func__); if (closefrom(4) == -1) - fatal("proc_exec: closefrom"); + fatal("%s: closefrom", __func__); execvp(argv[0], argv); - fatal("proc_exec: execvp: %s", argv[0]); + fatal("%s: execvp: %s", __func__, argv[0]); } struct imsgproc * @@ -135,7 +135,7 @@ proc_attach(int type, int fd) p = proc_new(type); if (p == NULL) - fatal("proc_exec: calloc"); + fatal("%s: proc_new", __func__); proc_setsock(p, fd); return p; @@ -148,7 +148,7 @@ proc_settitle(struct imsgproc *p, const char *title) if (title) { p->title = strdup(title); if (p->title == NULL) - fatal("proc_title: strdup"); + fatal("%s: strdup", __func__); } else p->title = NULL; @@ -258,7 +258,7 @@ proc_dispatch(int fd, short event, void *arg) case -1: if (errno == EAGAIN) return; - fatal("proc_dispatch: imsg_read"); + fatal("%s: imsg_read", __func__); /* NOTREACHED */ case 0: /* this pipe is dead, so remove the event handler */ @@ -272,7 +272,7 @@ proc_dispatch(int fd, short event, void *arg) if (event & EV_WRITE) { n = msgbuf_write(&p->imsgbuf.w); if (n == 0 || (n == -1 && errno != EAGAIN)) { - /* this pipe is dead, so remove the event handler */ + /* This pipe is dead. */ proc_callback(p, NULL); return; } @@ -280,7 +280,7 @@ proc_dispatch(int fd, short event, void *arg) for (;;) { if ((n = imsg_get(&p->imsgbuf, &imsg)) == -1) { - log_warn("proc_dispatch: imsg_get"); + log_warn("%s: imsg_get", __func__); proc_callback(p, NULL); return; } From 7c419232cbd74b7b985a25fd62779e8c6e93117c Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Sat, 15 Jul 2017 12:23:00 +0200 Subject: [PATCH 33/41] tweak proc.c --- extras/filters/smtpfd/proc.c | 31 ++++++++++++++++--------------- extras/filters/smtpfd/proc.h | 2 -- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/extras/filters/smtpfd/proc.c b/extras/filters/smtpfd/proc.c index 0a8dcf2..0facfb5 100644 --- a/extras/filters/smtpfd/proc.c +++ b/extras/filters/smtpfd/proc.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2016-2017 Eric Faurot + * Copyright (c) 2017 Eric Faurot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -50,12 +50,6 @@ static void proc_event_add(struct imsgproc *); static TAILQ_HEAD(, imsgproc) procs = TAILQ_HEAD_INITIALIZER(procs); -int -proc_getfd(struct imsgproc *p) -{ - return p->imsgbuf.fd; -} - pid_t proc_getpid(struct imsgproc *p) { @@ -177,7 +171,6 @@ proc_enable(struct imsgproc *p) void proc_free(struct imsgproc *p) { - if (p == NULL) return; @@ -251,17 +244,16 @@ proc_dispatch(int fd, short event, void *arg) p->events = 0; if (event & EV_READ) { - n = imsg_read(&p->imsgbuf); - switch (n) { case -1: if (errno == EAGAIN) - return; - fatal("%s: imsg_read", __func__); - /* NOTREACHED */ + break; + log_warn("%s: imsg_read", __func__); + proc_callback(p, NULL); + return; case 0: - /* this pipe is dead, so remove the event handler */ + /* This pipe is dead. */ proc_callback(p, NULL); return; default: @@ -271,10 +263,19 @@ proc_dispatch(int fd, short event, void *arg) if (event & EV_WRITE) { n = msgbuf_write(&p->imsgbuf.w); - if (n == 0 || (n == -1 && errno != EAGAIN)) { + switch (n) { + case -1: + if (errno == EAGAIN) + break; + log_warn("%s: msgbuf_write", __func__); + proc_callback(p, NULL); + return; + case 0: /* This pipe is dead. */ proc_callback(p, NULL); return; + default: + break; } } diff --git a/extras/filters/smtpfd/proc.h b/extras/filters/smtpfd/proc.h index 5cb436a..362a822 100644 --- a/extras/filters/smtpfd/proc.h +++ b/extras/filters/smtpfd/proc.h @@ -18,14 +18,12 @@ struct imsgproc; -/* proc.c */ struct imsgproc *proc_bypid(pid_t); struct imsgproc *proc_exec(int, char **); struct imsgproc *proc_attach(int, int); void proc_enable(struct imsgproc *); void proc_free(struct imsgproc *); pid_t proc_getpid(struct imsgproc *); -int proc_getfd(struct imsgproc *); int proc_gettype(struct imsgproc *); int proc_getinstance(struct imsgproc *); const char *proc_gettitle(struct imsgproc *); From 8970ebb31fd74e58bac5f01954bd87e88f2d7dd1 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Sat, 15 Jul 2017 15:30:09 +0200 Subject: [PATCH 34/41] main -> priv --- extras/filters/smtpfd/control.c | 6 +-- extras/filters/smtpfd/engine.c | 12 ++--- extras/filters/smtpfd/frontend.c | 12 ++--- extras/filters/smtpfd/smtpfd.c | 78 ++++++++++++++++---------------- extras/filters/smtpfd/smtpfd.h | 12 ++--- 5 files changed, 60 insertions(+), 60 deletions(-) diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c index f278348..ea538d1 100644 --- a/extras/filters/smtpfd/control.c +++ b/extras/filters/smtpfd/control.c @@ -178,7 +178,7 @@ control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) switch (imsg->hdr.type) { case IMSG_CTL_RELOAD: - proc_compose(p_main, imsg->hdr.type, 0, 0, -1, NULL, 0); + proc_compose(p_priv, imsg->hdr.type, 0, 0, -1, NULL, 0); break; case IMSG_CTL_LOG_VERBOSE: if (imsg->hdr.len != IMSG_HEADER_SIZE + @@ -186,7 +186,7 @@ control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) break; /* Forward to all other processes. */ - proc_compose(p_main, imsg->hdr.type, 0, imsg->hdr.pid, -1, + proc_compose(p_priv, imsg->hdr.type, 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); proc_compose(p_engine, imsg->hdr.type, 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); @@ -196,7 +196,7 @@ control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) break; case IMSG_CTL_SHOW_MAIN_INFO: proc_setpid(p, imsg->hdr.pid); - proc_compose(p_main, imsg->hdr.type, 0, imsg->hdr.pid, -1, + proc_compose(p_priv, imsg->hdr.type, 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_FRONTEND_INFO: diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 9cde802..7b139db 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -55,7 +55,7 @@ struct engine_config { }; static void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *); -static void engine_dispatch_main(struct imsgproc *, struct imsg *, void *); +static void engine_dispatch_priv(struct imsgproc *, struct imsg *, void *); static void engine_dispatch_filter(struct imsgproc *, struct imsg *, void *); static struct engine_config *conf; @@ -89,10 +89,10 @@ engine(int debug, int verbose) event_init(); - /* Setup pipe and event handler to the main process. */ - p_main = proc_attach(PROC_MAIN, 3); - proc_setcallback(p_main, engine_dispatch_main, NULL); - proc_enable(p_main); + /* Setup imsg socket with parent. */ + p_priv = proc_attach(PROC_PRIV, 3); + proc_setcallback(p_priv, engine_dispatch_priv, NULL); + proc_enable(p_priv); event_dispatch(); @@ -100,7 +100,7 @@ engine(int debug, int verbose) } static void -engine_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *bula) +engine_dispatch_priv(struct imsgproc *p, struct imsg *imsg, void *bula) { struct filter_process *fproc; struct filter_node *fnode; diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index faf1ead..1fb2611 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -34,7 +34,7 @@ #include "control.h" -static void frontend_dispatch_main(struct imsgproc *, struct imsg *, void *); +static void frontend_dispatch_priv(struct imsgproc *, struct imsg *, void *); static void frontend_dispatch_engine(struct imsgproc *, struct imsg *, void *); @@ -70,10 +70,10 @@ frontend(int debug, int verbose, char *sockname) event_init(); - /* Setup pipe and event handler to the parent process. */ - p_main = proc_attach(PROC_MAIN, 3); - proc_setcallback(p_main, frontend_dispatch_main, NULL); - proc_enable(p_main); + /* Setup imsg socket with parent. */ + p_priv = proc_attach(PROC_PRIV, 3); + proc_setcallback(p_priv, frontend_dispatch_priv, NULL); + proc_enable(p_priv); /* Listen on control socket. */ control_listen(); @@ -84,7 +84,7 @@ frontend(int debug, int verbose, char *sockname) } static void -frontend_dispatch_main(struct imsgproc *p, struct imsg *imsg, void *arg) +frontend_dispatch_priv(struct imsgproc *p, struct imsg *imsg, void *arg) { if (imsg == NULL) { log_debug("%s: imsg connection lost", __func__); diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index 391ff0d..be5e962 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -40,28 +40,28 @@ #include "control.h" __dead static void usage(void); -__dead static void main_shutdown(void); -static void main_sig_handler(int, short, void *); -static void main_dispatch_frontend(struct imsgproc *, struct imsg*, void *); -static void main_dispatch_engine(struct imsgproc *, struct imsg*, void *); -static int main_reload(void); -static int main_send_config(struct smtpfd_conf *); -static void main_send_filter_proc(struct filter_conf *); -static void main_send_filter_conf(struct smtpfd_conf *, struct filter_conf *); +__dead static void priv_shutdown(void); +static void priv_sig_handler(int, short, void *); +static void priv_dispatch_frontend(struct imsgproc *, struct imsg*, void *); +static void priv_dispatch_engine(struct imsgproc *, struct imsg*, void *); +static int priv_reload(void); +static int priv_send_config(struct smtpfd_conf *); +static void priv_send_filter_proc(struct filter_conf *); +static void priv_send_filter_conf(struct smtpfd_conf *, struct filter_conf *); static void config_print(struct smtpfd_conf *); static char *conffile; static char *csock; -static struct smtpfd_conf *main_conf; +static struct smtpfd_conf *env; /* globals */ uint32_t cmd_opts; -struct imsgproc *p_frontend; struct imsgproc *p_engine; -struct imsgproc *p_main; +struct imsgproc *p_frontend; +struct imsgproc *p_priv; static void -main_sig_handler(int sig, short event, void *arg) +priv_sig_handler(int sig, short event, void *arg) { pid_t pid; int status; @@ -93,9 +93,9 @@ main_sig_handler(int sig, short event, void *arg) break; case SIGTERM: case SIGINT: - main_shutdown(); + priv_shutdown(); case SIGHUP: - if (main_reload() == -1) + if (priv_reload() == -1) log_warnx("configuration reload failed"); else log_debug("configuration reloaded"); @@ -180,13 +180,13 @@ main(int argc, char *argv[]) frontend(debug, cmd_opts & OPT_VERBOSE, csock); /* parse config file */ - if ((main_conf = parse_config(conffile)) == NULL) { + if ((env = parse_config(conffile)) == NULL) { exit(1); } if (cmd_opts & OPT_NOACTION) { if (cmd_opts & OPT_VERBOSE) - config_print(main_conf); + config_print(env); else fprintf(stderr, "configuration OK\n"); exit(0); @@ -222,19 +222,19 @@ main(int argc, char *argv[]) rargv[rargc++] = NULL; p_frontend = proc_exec(PROC_FRONTEND, rargv); - proc_setcallback(p_frontend, main_dispatch_frontend, NULL); + proc_setcallback(p_frontend, priv_dispatch_frontend, NULL); rargv[1] = "-E"; rargv[argc - 3] = NULL; p_engine = proc_exec(PROC_ENGINE, rargv); - proc_setcallback(p_engine, main_dispatch_engine, NULL); + proc_setcallback(p_engine, priv_dispatch_engine, NULL); event_init(); /* Setup signal handler. */ - signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); - signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); - signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); - signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, NULL); + signal_set(&ev_sigint, SIGINT, priv_sig_handler, NULL); + signal_set(&ev_sigterm, SIGTERM, priv_sig_handler, NULL); + signal_set(&ev_sighup, SIGHUP, priv_sig_handler, NULL); + signal_set(&ev_sigchld, SIGCHLD, priv_sig_handler, NULL); signal_add(&ev_sigint, NULL); signal_add(&ev_sigterm, NULL); signal_add(&ev_sighup, NULL); @@ -256,19 +256,19 @@ main(int argc, char *argv[]) == -1) fatal("proc_compose"); - main_send_config(main_conf); + priv_send_config(env); if (pledge("rpath stdio sendfd cpath", NULL) == -1) fatal("pledge"); event_dispatch(); - main_shutdown(); + priv_shutdown(); return (0); } __dead static void -main_shutdown(void) +priv_shutdown(void) { pid_t pid; pid_t frontend_pid; @@ -282,7 +282,7 @@ main_shutdown(void) proc_free(p_frontend); proc_free(p_engine); - config_clear(main_conf); + config_clear(env); log_debug("waiting for children to terminate"); do { @@ -303,7 +303,7 @@ main_shutdown(void) } static void -main_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *arg) +priv_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *arg) { int verbose; @@ -314,7 +314,7 @@ main_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *arg) switch (imsg->hdr.type) { case IMSG_CTL_RELOAD: - if (main_reload() == -1) + if (priv_reload() == -1) log_warnx("configuration reload failed"); else log_warnx("configuration reloaded"); @@ -335,7 +335,7 @@ main_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *arg) } static void -main_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) +priv_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) { if (imsg == NULL) { event_loopexit(NULL); @@ -351,24 +351,24 @@ main_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) } static int -main_reload(void) +priv_reload(void) { struct smtpfd_conf *xconf; if ((xconf = parse_config(conffile)) == NULL) return (-1); - if (main_send_config(xconf) == -1) + if (priv_send_config(xconf) == -1) return (-1); - config_clear(main_conf); - main_conf = xconf; + config_clear(env); + env = xconf; return (0); } static int -main_send_config(struct smtpfd_conf *xconf) +priv_send_config(struct smtpfd_conf *xconf) { struct filter_conf *f; @@ -379,13 +379,13 @@ main_send_config(struct smtpfd_conf *xconf) TAILQ_FOREACH(f, &xconf->filters, entry) { if (f->chain) continue; - main_send_filter_proc(f); + priv_send_filter_proc(f); } TAILQ_FOREACH(f, &xconf->filters, entry) { proc_compose(p_engine, IMSG_RECONF_FILTER, 0, 0, -1, f->name, strlen(f->name) + 1); - main_send_filter_conf(xconf, f); + priv_send_filter_conf(xconf, f); } /* Tell children the revised config is now complete. */ @@ -396,7 +396,7 @@ main_send_config(struct smtpfd_conf *xconf) } static void -main_send_filter_proc(struct filter_conf *f) +priv_send_filter_proc(struct filter_conf *f) { int sp[2]; pid_t pid; @@ -428,7 +428,7 @@ main_send_filter_proc(struct filter_conf *f) } static void -main_send_filter_conf(struct smtpfd_conf *conf, struct filter_conf *f) +priv_send_filter_conf(struct smtpfd_conf *conf, struct filter_conf *f) { struct filter_conf *tmp; int i; @@ -437,7 +437,7 @@ main_send_filter_conf(struct smtpfd_conf *conf, struct filter_conf *f) for (i = 0; i < f->argc; i++) { TAILQ_FOREACH(tmp, &conf->filters, entry) if (!strcmp(f->argv[i], tmp->name)) { - main_send_filter_conf(conf, tmp); + priv_send_filter_conf(conf, tmp); break; } } diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index feef9b2..5ab0888 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -44,14 +44,14 @@ enum imsg_type { }; enum smtpfd_process { - PROC_MAIN, + PROC_CLIENT, + PROC_CONTROL, PROC_ENGINE, - PROC_FRONTEND, PROC_FILTER, - PROC_CLIENT, + PROC_FRONTEND, + PROC_PRIV }; - struct filter_conf { TAILQ_ENTRY(filter_conf) entry; char *name; @@ -65,9 +65,9 @@ struct smtpfd_conf { }; extern uint32_t cmd_opts; -extern struct imsgproc *p_frontend; extern struct imsgproc *p_engine; -extern struct imsgproc *p_main; +extern struct imsgproc *p_frontend; +extern struct imsgproc *p_priv; /* engine.c */ From 4ca7e6a4befe974e694d3bad6455498a19a3c3d9 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Tue, 18 Jul 2017 21:17:40 +0200 Subject: [PATCH 35/41] move forward --- extras/filters/smtpfd/Makefile | 13 +- extras/filters/smtpfd/control.c | 142 ++-- extras/filters/smtpfd/control.h | 22 - extras/filters/smtpfd/engine.c | 168 ++-- extras/filters/smtpfd/frontend.c | 250 ++++-- extras/filters/smtpfd/io.c | 1227 ++++++++++++++++++++++++++++++ extras/filters/smtpfd/io.h | 87 +++ extras/filters/smtpfd/iobuf.c | 467 ++++++++++++ extras/filters/smtpfd/iobuf.h | 68 ++ extras/filters/smtpfd/log.c | 43 +- extras/filters/smtpfd/log.h | 12 +- extras/filters/smtpfd/logmsg.c | 149 ++++ extras/filters/smtpfd/parse.y | 518 ++++++++++--- extras/filters/smtpfd/proc.c | 203 ++++- extras/filters/smtpfd/proc.h | 25 +- extras/filters/smtpfd/resolver.c | 351 +++++++++ extras/filters/smtpfd/smtpfd.c | 573 +++++++------- extras/filters/smtpfd/smtpfd.h | 114 ++- 18 files changed, 3732 insertions(+), 700 deletions(-) delete mode 100644 extras/filters/smtpfd/control.h create mode 100644 extras/filters/smtpfd/io.c create mode 100644 extras/filters/smtpfd/io.h create mode 100644 extras/filters/smtpfd/iobuf.c create mode 100644 extras/filters/smtpfd/iobuf.h create mode 100644 extras/filters/smtpfd/logmsg.c create mode 100644 extras/filters/smtpfd/resolver.c diff --git a/extras/filters/smtpfd/Makefile b/extras/filters/smtpfd/Makefile index b094c63..eb407d7 100644 --- a/extras/filters/smtpfd/Makefile +++ b/extras/filters/smtpfd/Makefile @@ -1,8 +1,19 @@ # $OpenBSD$ PROG= smtpfd -SRCS= control.c engine.c frontend.c log.c smtpfd.c parse.y + +SRCS+= control.c +SRCS+= engine.c +SRCS+= frontend.c +SRCS+= frontend_smtpf.c +SRCS+= io.c +SRCS+= iobuf.c +SRCS+= log.c +SRCS+= logmsg.c +SRCS+= parse.y SRCS+= proc.c +SRCS+= resolver.c +SRCS+= smtpfd.c MAN= smtpfd.8 smtpfd.conf.5 diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c index ea538d1..181524f 100644 --- a/extras/filters/smtpfd/control.c +++ b/extras/filters/smtpfd/control.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2003, 2004 Henning Brauer + * Copyright (c) 2017 Eric Faurot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,20 +25,25 @@ #include #include #include +#include +#include #include #include #include +#include "smtpfd.h" + #include "log.h" #include "proc.h" -#include "smtpfd.h" -#include "control.h" #define CONTROL_BACKLOG 5 +static int control_init(const char *); +static int control_listen(void); static void control_accept(int, short, void *); static void control_close(struct imsgproc *); -static void control_dispatch_imsg(struct imsgproc *, struct imsg *, void *); +static void control_dispatch_priv(struct imsgproc *, struct imsg *, void *); +static void control_dispatch_client(struct imsgproc *, struct imsg *, void *); static struct { struct event ev; @@ -46,9 +51,50 @@ static struct { int fd; } control_state; +void +control(int debug, int verbose) +{ + struct passwd *pw; + + /* Early initialisation */ + log_init(debug, LOG_DAEMON); + log_setverbose(verbose); + log_procinit("control"); + setproctitle("control"); + + control_init(SMTPFD_SOCKET); + + /* Drop priviledges */ + if ((pw = getpwnam(SMTPFD_USER)) == NULL) + fatalx("unknown user " SMTPFD_USER); + + 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("cannot drop privileges"); + + if (chroot(pw->pw_dir) == 1) + fatal("chroot"); + + if (pledge("stdio unix recvfd sendfd", NULL) == -1) + fatal("pledge"); -int -control_init(char *path) + event_init(); + + signal(SIGPIPE, SIG_IGN); + + /* Setup imsg socket with parent */ + p_priv = proc_attach(PROC_PRIV, 3); + proc_setcallback(p_priv, control_dispatch_priv, NULL); + proc_enable(p_priv); + + event_dispatch(); + + exit(0); +} + +static int +control_init(const char *path) { struct sockaddr_un sun; int fd; @@ -62,7 +108,7 @@ control_init(char *path) memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; - strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); + strlcpy(sun.sun_path, SMTPFD_SOCKET, sizeof(sun.sun_path)); if (unlink(path) == -1) if (errno != ENOENT) { @@ -92,7 +138,7 @@ control_init(char *path) return (0); } -int +static int control_listen(void) { @@ -109,16 +155,6 @@ control_listen(void) return (0); } -void -control_cleanup(char *path) -{ - if (path == NULL) - return; - event_del(&control_state.ev); - event_del(&control_state.evt); - unlink(path); -} - static void control_accept(int listenfd, short event, void *bula) { @@ -150,7 +186,7 @@ control_accept(int listenfd, short event, void *bula) } p = proc_attach(PROC_CLIENT, connfd); - proc_setcallback(p, control_dispatch_imsg, NULL); + proc_setcallback(p, control_dispatch_client, NULL); proc_enable(p); } @@ -167,62 +203,42 @@ control_close(struct imsgproc *p) } static void -control_dispatch_imsg(struct imsgproc *p, struct imsg *imsg, void *arg) +control_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg) { - int verbose; - if (imsg == NULL) { - control_close(p); + log_debug("%s: imsg connection lost", __func__); + event_loopexit(NULL); return; } switch (imsg->hdr.type) { - case IMSG_CTL_RELOAD: - proc_compose(p_priv, imsg->hdr.type, 0, 0, -1, NULL, 0); - break; - case IMSG_CTL_LOG_VERBOSE: - if (imsg->hdr.len != IMSG_HEADER_SIZE + - sizeof(verbose)) - break; - - /* Forward to all other processes. */ - proc_compose(p_priv, imsg->hdr.type, 0, imsg->hdr.pid, -1, - imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); - proc_compose(p_engine, imsg->hdr.type, 0, imsg->hdr.pid, -1, - imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); - - memcpy(&verbose, imsg->data, sizeof(verbose)); - log_setverbose(verbose); + case IMSG_CONF_START: + m_end(proc); break; - case IMSG_CTL_SHOW_MAIN_INFO: - proc_setpid(p, imsg->hdr.pid); - proc_compose(p_priv, imsg->hdr.type, 0, imsg->hdr.pid, -1, - imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); - break; - case IMSG_CTL_SHOW_FRONTEND_INFO: - proc_compose(p, IMSG_CTL_END, 0, 0, -1, NULL, 0); - break; - case IMSG_CTL_SHOW_ENGINE_INFO: - proc_setpid(p, imsg->hdr.pid); - proc_compose(p_engine, imsg->hdr.type, 0, imsg->hdr.pid, -1, - imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); + + case IMSG_CONF_END: + m_end(proc); + control_listen(); break; + default: - log_debug("%s: error handling imsg %d", __func__, - imsg->hdr.type); - break; + fatalx("%s: unexpected imsg %s", __func__, + log_fmt_imsgtype(imsg->hdr.type)); } } -int -control_imsg_relay(struct imsg *imsg) +static void +control_dispatch_client(struct imsgproc *p, struct imsg *imsg, void *arg) { - struct imsgproc *p; - - if ((p = proc_bypid(imsg->hdr.pid)) == NULL || - proc_gettype(p) != PROC_CLIENT) - return (0); + if (imsg == NULL) { + control_close(p); + return; + } - return (proc_compose(p, imsg->hdr.type, 0, imsg->hdr.pid, -1, - imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); + switch (imsg->hdr.type) { + default: + log_debug("%s: error handling imsg %d", __func__, + imsg->hdr.type); + break; + } } diff --git a/extras/filters/smtpfd/control.h b/extras/filters/smtpfd/control.h deleted file mode 100644 index 89f150d..0000000 --- a/extras/filters/smtpfd/control.h +++ /dev/null @@ -1,22 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2003, 2004 Henning Brauer - * - * 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. - */ - -int control_init(char *); -int control_listen(void); -int control_imsg_relay(struct imsg *); -void control_cleanup(char *); diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 7b139db..f8d2fa6 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -1,9 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2004, 2005 Claudio Jeker - * Copyright (c) 2004 Esben Norby - * Copyright (c) 2003, 2004 Henning Brauer + * Copyright (c) 2017 Eric Faurot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,29 +16,27 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include -#include +#include -#include -#include +#include #include #include -#include +#include #include +#include "smtpfd.h" + #include "log.h" #include "proc.h" -#include "smtpfd.h" -struct filter_process { - TAILQ_ENTRY(filter_process) entry; +struct filter_proc { + TAILQ_ENTRY(filter_proc) entry; struct imsgproc *proc; }; struct filter_node { TAILQ_ENTRY(filter_node) entry; - struct filter_process *fproc; + struct filter_proc *proc; }; struct filter { @@ -50,45 +46,44 @@ struct filter { }; struct engine_config { - TAILQ_HEAD(, filter_process) procs; + TAILQ_HEAD(, filter_proc) procs; TAILQ_HEAD(, filter) filters; }; -static void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *); +static void engine_shutdown(void); static void engine_dispatch_priv(struct imsgproc *, struct imsg *, void *); static void engine_dispatch_filter(struct imsgproc *, struct imsg *, void *); +static void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *); -static struct engine_config *conf; -static struct engine_config *tmpconf; +static struct engine_config *tmpconf, *conf; void engine(int debug, int verbose) { struct passwd *pw; + /* Early initialisation. */ log_init(debug, LOG_DAEMON); log_setverbose(verbose); log_procinit("engine"); setproctitle("engine"); + /* Drop priviledges. */ if ((pw = getpwnam(SMTPFD_USER)) == NULL) - fatal("getpwnam"); - - if (chroot(pw->pw_dir) == -1) - fatal("chroot"); - if (chdir("/") == -1) - fatal("chdir(\"/\")"); + fatal("%s: getpwnam: %s", __func__, SMTPFD_USER); 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("can't drop privileges"); + fatal("%s: cannot drop privileges", __func__); - if (pledge("stdio recvfd", NULL) == -1) - fatal("pledge"); + if (pledge("stdio rpath wpath cpath dns sendfd recvfd", NULL) == -1) + fatal("%s: pledge", __func__); event_init(); + signal(SIGPIPE, SIG_IGN); + /* Setup imsg socket with parent. */ p_priv = proc_attach(PROC_PRIV, 3); proc_setcallback(p_priv, engine_dispatch_priv, NULL); @@ -96,15 +91,21 @@ engine(int debug, int verbose) event_dispatch(); + engine_shutdown(); +} + +static void +engine_shutdown() +{ + log_debug("exiting"); + exit(0); } static void -engine_dispatch_priv(struct imsgproc *p, struct imsg *imsg, void *bula) +engine_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg) { - struct filter_process *fproc; - struct filter_node *fnode; - struct filter *f; + struct filter_proc *fproc; if (imsg == NULL) { log_debug("%s: imsg connection lost", __func__); @@ -112,45 +113,37 @@ engine_dispatch_priv(struct imsgproc *p, struct imsg *imsg, void *bula) return; } + log_imsg(proc, imsg); + switch (imsg->hdr.type) { - case IMSG_SOCKET_IPC: - /* - * Setup pipe and event handler to the frontend - * process. - */ - if (p_frontend) - fatalx("frontend process already set"); + case IMSG_SOCK_FRONTEND: + m_end(proc); if (imsg->fd == -1) - fatalx("failed to receive frontend process fd"); - + fatalx("failed to receive frontend socket"); p_frontend = proc_attach(PROC_FRONTEND, imsg->fd); - if (p_frontend == NULL) - fatal("proc_attach"); proc_setcallback(p_frontend, engine_dispatch_frontend, NULL); proc_enable(p_frontend); break; - case IMSG_RECONF_CONF: - if (tmpconf) - fatalx("already configuring"); + case IMSG_CONF_START: + m_end(proc); tmpconf = calloc(1, sizeof(*tmpconf)); if (tmpconf == NULL) - fatal("calloc"); + fatal("%s: calloc", __func__); TAILQ_INIT(&tmpconf->procs); TAILQ_INIT(&tmpconf->filters); break; - case IMSG_RECONF_FILTER_PROC: + case IMSG_CONF_FILTER_PROC: if (imsg->fd == -1) - fatalx("failed to receive filter process fd"); - + fatalx("%s: filter process fd not received", __func__); fproc = calloc(1, sizeof(*fproc)); if (fproc == NULL) - fatal("calloc"); + fatal("%s: calloc", __func__); fproc->proc = proc_attach(PROC_FILTER, imsg->fd); if (fproc->proc == NULL) - fatal("proc_attach"); + fatal("%s: proc_attach", __func__); proc_settitle(fproc->proc, imsg->data); proc_setcallback(fproc->proc, engine_dispatch_filter, fproc); proc_enable(fproc->proc); @@ -158,89 +151,56 @@ engine_dispatch_priv(struct imsgproc *p, struct imsg *imsg, void *bula) log_info("new filter process: %s", (char *)imsg->data); break; - case IMSG_RECONF_FILTER: - f = calloc(1, sizeof(*f)); - if (f == NULL) - fatal("calloc"); - f->name = strdup(imsg->data); - if (f->name == NULL) - fatal("strdup"); - TAILQ_INIT(&f->nodes); - TAILQ_INSERT_HEAD(&tmpconf->filters, f, entry); - log_info("new filter: %s", (char *)imsg->data); - break; - - case IMSG_RECONF_FILTER_NODE: - fnode = calloc(1, sizeof(*fnode)); - if (fnode == NULL) - fatal("calloc"); - TAILQ_FOREACH(fproc, &tmpconf->procs, entry) { - if (!strcmp(proc_gettitle(fproc->proc), imsg->data)) { - fnode->fproc = fproc; - break; - } - } - if (fnode->fproc == NULL) - fatalx("unknown filter process %s", (char *)imsg->data); - f = TAILQ_FIRST(&tmpconf->filters); - TAILQ_INSERT_TAIL(&f->nodes, fnode, entry); - log_info("new node filter on filter %s: %s", f->name, (char *)imsg->data); - break; - - case IMSG_RECONF_END: - /* XXX purge old config */ + case IMSG_CONF_END: + m_end(proc); conf = tmpconf; - tmpconf = NULL; break; default: - log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); - break; + fatalx("%s: unexpected imsg %s", __func__, + log_fmt_imsgtype(imsg->hdr.type)); } } static void -engine_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *bula) +engine_dispatch_frontend(struct imsgproc *proc, struct imsg *imsg, void *arg) { - int verbose; - if (imsg == NULL) { log_debug("%s: imsg connection lost", __func__); event_loopexit(NULL); return; } + log_imsg(proc, imsg); + switch (imsg->hdr.type) { - case IMSG_CTL_LOG_VERBOSE: - /* Already checked by frontend. */ - memcpy(&verbose, imsg->data, sizeof(verbose)); - log_setverbose(verbose); - break; - case IMSG_CTL_SHOW_ENGINE_INFO: - proc_compose(p_frontend, IMSG_CTL_END, 0, imsg->hdr.pid, -1, - NULL, 0); + case IMSG_RES_GETADDRINFO: + case IMSG_RES_GETNAMEINFO: + resolver_dispatch_request(proc, imsg); break; + default: - log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); - break; + fatalx("%s: unexpected imsg %s", __func__, + log_fmt_imsgtype(imsg->hdr.type)); } } static void -engine_dispatch_filter(struct imsgproc *p, struct imsg *imsg, void *bula) +engine_dispatch_filter(struct imsgproc *proc, struct imsg *imsg, void *arg) { if (imsg == NULL) { - log_debug("%s: imsg connection lost to filter %s", __func__, - proc_gettitle(p)); + log_debug("%s: imsg connection lost", __func__); event_loopexit(NULL); return; } + log_imsg(proc, imsg); + + return; + switch (imsg->hdr.type) { default: - log_debug("%s: unexpected imsg %d from filter %s", __func__, - imsg->hdr.type, proc_gettitle(p)); - proc_compose(p, 1, 0, 0, -1, NULL, 0); - break; + fatalx("%s: unexpected imsg %s", __func__, + log_fmt_imsgtype(imsg->hdr.type)); } } diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 1fb2611..447e718 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -1,9 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2005 Claudio Jeker - * Copyright (c) 2004 Esben Norby - * Copyright (c) 2003, 2004 Henning Brauer + * Copyright (c) 2017 Eric Faurot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,109 +16,259 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include -#include +#include -#include -#include +#include +#include #include +#include #include #include -#include "log.h" -#include "proc.h" #include "smtpfd.h" -#include "control.h" +#include "log.h" +#include "proc.h" +static void frontend_shutdown(void); +static void frontend_listen(struct listener *); +static void frontend_accept(int, short, void *); +static void frontend_resume(int, short, void *); static void frontend_dispatch_priv(struct imsgproc *, struct imsg *, void *); static void frontend_dispatch_engine(struct imsgproc *, struct imsg *, void *); +struct conn { + SPLAY_ENTRY(conn) entry; + struct listener *listener; + uint32_t id; + struct sockaddr_storage ss; +}; + +static int conn_cmp(struct conn *, struct conn *); + +SPLAY_HEAD(conntree, conn); +SPLAY_PROTOTYPE(conntree, conn, entry, conn_cmp); + +static struct conntree conns; +static struct smtpfd_conf *tmpconf; + +static int +conn_cmp(struct conn *a, struct conn *b) +{ + if (a->id < b->id) + return (-1); + if (a->id > b->id) + return (1); + return (0); +} + +SPLAY_GENERATE(conntree, conn, entry, conn_cmp); void -frontend(int debug, int verbose, char *sockname) +frontend(int debug, int verbose) { - struct passwd *pw; + struct passwd *pw; + /* Early initialisation. */ log_init(debug, LOG_DAEMON); log_setverbose(verbose); log_procinit("frontend"); setproctitle("frontend"); - /* Create smtpfd control socket outside chroot. */ - if (control_init(sockname) == -1) - fatalx("control socket setup failed"); + SPLAY_INIT(&conns); + frontend_smtpf_init(); + /* Drop priviledges. */ if ((pw = getpwnam(SMTPFD_USER)) == NULL) - fatal("getpwnam"); + fatal("%s: getpwnam: %s", __func__, SMTPFD_USER); - if (chroot(pw->pw_dir) == -1) - fatal("chroot"); + if (chroot(_PATH_VAREMPTY) == -1) + fatal("%s: chroot", __func__); if (chdir("/") == -1) - fatal("chdir(\"/\")"); + fatal("%s: chdir", __func__); 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("can't drop privileges"); + fatal("%s: cannot drop privileges", __func__); - if (pledge("stdio inet recvfd", NULL) == -1) - fatal("pledge"); + if (pledge("stdio unix inet recvfd sendfd", NULL) == -1) + fatal("%s: pledge", __func__); event_init(); + signal(SIGPIPE, SIG_IGN); + /* Setup imsg socket with parent. */ p_priv = proc_attach(PROC_PRIV, 3); proc_setcallback(p_priv, frontend_dispatch_priv, NULL); proc_enable(p_priv); - /* Listen on control socket. */ - control_listen(); - event_dispatch(); + frontend_shutdown(); +} + +void +frontend_conn_closed(uint32_t connid) +{ + struct conn key, *conn; + + key.id = connid; + conn = SPLAY_FIND(conntree, &conns, &key); + if (conn) { + SPLAY_REMOVE(conntree, &conns, conn); + free(conn); + } +} + +static void +frontend_shutdown() +{ + struct listener *l; + + TAILQ_FOREACH(l, &env->listeners, entry) + close(l->sock); + + log_debug("exiting"); + exit(0); } static void -frontend_dispatch_priv(struct imsgproc *p, struct imsg *imsg, void *arg) +frontend_listen(struct listener *l) +{ + log_debug("conn listen proto=%s sockaddr=%s", log_fmt_proto(l->proto), + log_fmt_sockaddr((struct sockaddr*)&l->ss)); + + if (listen(l->sock, 5) == -1) + fatal("%s: listen", __func__); + + event_set(&l->ev, l->sock, EV_READ|EV_PERSIST, frontend_accept, l); + event_add(&l->ev, NULL); +} + +static void +frontend_accept(int sock, short ev, void *arg) { + struct listener *l = arg; + struct sockaddr_storage ss; + struct sockaddr *sa; + struct timeval tv; + struct conn *conn; + socklen_t len; + + conn = calloc(1, sizeof(*conn)); + if (conn == NULL) { + log_warn("%s: calloc", __func__); + sa = NULL; + len = 0; + } + else { + sa = (struct sockaddr *)&ss; + len = sizeof(conn->ss); + } + + sock = accept4(sock, sa, &len, SOCK_NONBLOCK); + if (sock == -1) { + log_warn("%s: accept4", __func__); + if (errno == ENFILE || errno == EMFILE) { + /* Stop listening for a while. */ + tv.tv_sec = 2; + tv.tv_usec = 0; + event_del(&l->ev); + evtimer_set(&l->ev, frontend_resume, l); + evtimer_add(&l->ev, &tv); + } + free(conn); + return; + } + + if (conn == NULL) { + close(sock); + return; + } + + while (conn->id == 0 || SPLAY_FIND(conntree, &conns, conn)) + conn->id = arc4random(); + SPLAY_INSERT(conntree, &conns, conn); + conn->listener = l; + + switch (l->proto) { + case PROTO_SMTPF: + frontend_smtpf_conn(conn->id, l, sock, sa); + break; + default: + fatalx("%s: unexpected protocol %d", __func__, l->proto); + } +} + +static void +frontend_resume(int sock, short ev, void *arg) +{ + struct listener *l = arg; + + event_set(&l->ev, l->sock, EV_READ|EV_PERSIST, frontend_accept, l); + event_add(&l->ev, NULL); +} + +static void +frontend_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg) +{ + struct listener *l; + if (imsg == NULL) { log_debug("%s: imsg connection lost", __func__); event_loopexit(NULL); return; } - switch (imsg->hdr.type) { - case IMSG_CTL_END: - control_imsg_relay(imsg); - break; - case IMSG_SOCKET_IPC: - /* - * Setup pipe and event handler to the engine - * process. - */ - if (p_engine) - fatalx("engine process already set"); + log_imsg(proc, imsg); + switch (imsg->hdr.type) { + case IMSG_SOCK_ENGINE: if (imsg->fd == -1) - fatalx("failed to receive engine process fd"); - + fatalx("%s: engine socket not received", __func__); + m_end(proc); p_engine = proc_attach(PROC_ENGINE, imsg->fd); - if (p_engine == NULL) - fatal("proc_attach"); proc_setcallback(p_engine, frontend_dispatch_engine, NULL); proc_enable(p_engine); break; - default: - log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); + + case IMSG_CONF_START: + m_end(proc); + if ((tmpconf = calloc(1, sizeof(*tmpconf))) == NULL) + fatal("%s: calloc", __func__); + TAILQ_INIT(&tmpconf->listeners); break; + + case IMSG_CONF_LISTENER: + if (imsg->fd == -1) + fatalx("%s: listener socket not received", __func__); + if ((l = calloc(1, sizeof(*l))) == NULL) + fatal("%s: calloc", __func__); + m_get_int(proc, &l->proto); + m_get_sockaddr(proc, (struct sockaddr *)(&l->ss)); + m_end(proc); + l->sock = imsg->fd; + TAILQ_INSERT_TAIL(&tmpconf->listeners, l, entry); + break; + + case IMSG_CONF_END: + m_end(proc); + TAILQ_FOREACH(l, &tmpconf->listeners, entry) + frontend_listen(l); + env = tmpconf; + break; + + default: + fatalx("%s: unexpected imsg %s", __func__, + log_fmt_imsgtype(imsg->hdr.type)); } } static void -frontend_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) +frontend_dispatch_engine(struct imsgproc *proc, struct imsg *imsg, void *arg) { if (imsg == NULL) { log_debug("%s: imsg connection lost", __func__); @@ -128,11 +276,17 @@ frontend_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) return; } + log_imsg(proc, imsg); + switch (imsg->hdr.type) { - case IMSG_CTL_END: - control_imsg_relay(imsg); + case IMSG_RES_GETADDRINFO: + case IMSG_RES_GETADDRINFO_END: + case IMSG_RES_GETNAMEINFO: + resolver_dispatch_result(proc, imsg); break; + default: - log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); + fatalx("%s: unexpected imsg %s", __func__, + log_fmt_imsgtype(imsg->hdr.type)); } } diff --git a/extras/filters/smtpfd/io.c b/extras/filters/smtpfd/io.c new file mode 100644 index 0000000..4fb886f --- /dev/null +++ b/extras/filters/smtpfd/io.c @@ -0,0 +1,1227 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2012 Eric Faurot + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "io.h" +#include "iobuf.h" +#include "log.h" + +#ifdef IO_SSL +#include +#include +#endif + +enum { + IO_STATE_DOWN, + IO_STATE_UP, + IO_STATE_RESOLVE, + IO_STATE_CONNECT, + IO_STATE_CONNECT_TLS, + IO_STATE_ACCEPT_TLS +}; + +#define IO_PAUSE_IN IO_IN +#define IO_PAUSE_OUT IO_OUT + +#define IO_READ 0x0100 +#define IO_WRITE 0x0200 +#define IO_RW (IO_READ | IO_WRITE) +#define IO_RESET 0x1000 +#define IO_HELD 0x2000 + +struct io { + int sock; + void *arg; + void (*cb)(struct io*, int, void *); + struct iobuf iobuf; + size_t lowat; + int timeout; + int flags; + int state; + struct event ev; + void *tls; + const char *error; /* only valid immediately on callback */ + struct sockaddr *bind; + struct addrinfo *ai; /* for connecting */ + struct event_asr *eva; +}; + +static void fd_set_nonblocking(int); +static void fd_set_nolinger(int); + +static const char* io_strflags(int); +static const char* io_strevents(short); + +static void io_reload(struct io *); +static void io_reset(struct io *, short, void (*)(int, short, void*)); +static void io_frame_enter(const char *, struct io *, int); +static void io_frame_leave(struct io *); +static void io_hold(struct io *); +static void io_release(struct io *); +static void io_callback(struct io*, int); +static void io_dispatch(int, short, void *); +static void io_dispatch_getaddrinfo(struct asr_result *, void *); +static void io_dispatch_connect(int, short, void *); +static int io_connect_next(struct io *); + +#ifdef IO_SSL +void ssl_error(const char *); /* XXX external */ +static const char* io_ssl_error(void); +static void io_dispatch_accept_tls(int, short, void *); +static void io_dispatch_connect_tls(int, short, void *); +static void io_dispatch_read_tls(int, short, void *); +static void io_dispatch_write_tls(int, short, void *); +static void io_reload_tls(struct io *io); +#endif + +static struct io *current = NULL; +static long long unsigned frame = 0; +static int _io_trace = 0; + +static const char *states[] = { + "DOWN", + "UP", + "RESOLVE", + "CONNECT", + "CONNECT_TLS", + "ACCEPT_TLS" +}; + +#define io_debug(args...) do { if (_io_trace) log_debug(args); } while(0) +#define IO_READING(io) (((io)->flags & IO_RW) != IO_WRITE) +#define IO_WRITING(io) (((io)->flags & IO_RW) != IO_READ) + +void +io_trace(int on) +{ + _io_trace = on; +} + +const char* +io_strio(struct io *io) +{ + static char buf[128]; + char ssl[128]; + + ssl[0] = '\0'; +#ifdef IO_SSL + if (io->tls) { + (void)snprintf(ssl, sizeof ssl, " ssl=%s:%s:%d", + SSL_get_version(io->tls), + SSL_get_cipher_name(io->tls), + SSL_get_cipher_bits(io->tls, NULL)); + } +#endif + (void)snprintf(buf, sizeof buf, + "", + io, states[io->state], io->sock, io->timeout, + io_strflags(io->flags), ssl, io_datalen(io), io_queued(io)); + + return buf; +} + +const char* +io_strevent(int evt) +{ + static char buf[32]; + + switch (evt) { + case IO_CONNECTED: + return "IO_CONNECTED"; + case IO_TLSREADY: + return "IO_TLSREADY"; + case IO_DATAIN: + return "IO_DATAIN"; + case IO_LOWAT: + return "IO_LOWAT"; + case IO_CLOSED: + return "IO_CLOSED"; + case IO_DISCONNECTED: + return "IO_DISCONNECTED"; + case IO_TIMEOUT: + return "IO_TIMEOUT"; + case IO_ERROR: + return "IO_ERROR"; + case IO_TLSERROR: + return "IO_TLSERROR"; + default: + (void)snprintf(buf, sizeof(buf), "IO_? %d", evt); + return buf; + } +} + +struct io * +io_new(void) +{ + struct io *io; + + io = calloc(1, sizeof(*io)); + if (io == NULL) + return NULL; + + iobuf_init(&io->iobuf, 0, 0); + io->sock = -1; + io->timeout = -1; + + return io; +} + +void +io_free(struct io *io) +{ + io_debug("io_free(%p)", io); + + /* the current io is virtually dead */ + if (io == current) + current = NULL; + +#ifdef IO_SSL + if (io->tls) { + SSL_free(io->tls); + io->tls = NULL; + } +#endif + + if (io->eva) + event_asr_abort(io->eva); + if (io->ai) + freeaddrinfo(io->ai); + if (event_initialized(&io->ev)) + event_del(&io->ev); + if (io->sock != -1) { + (void)close(io->sock); + io->sock = -1; + } + + iobuf_clear(&io->iobuf); + free(io->bind); + free(io); +} + +int +io_set_callback(struct io *io, void(*cb)(struct io *, int, void *), void *arg) +{ + io->cb = cb; + io->arg = arg; + + return 0; +} + +int +io_set_bindaddr(struct io *io, const struct sockaddr *sa) +{ + struct sockaddr *t; + + if (io->state != IO_STATE_DOWN) { + errno = EISCONN; + return -1; + } + + t = malloc(sa->sa_len); + if (t == NULL) + return -1; + memmove(t, sa, sa->sa_len); + + free(io->bind); + io->bind = t; + + return 0; +} + +int +io_set_bufsize(struct io *io, size_t sz) +{ + errno = ENOSYS; + return -1; +} + +void +io_set_timeout(struct io *io, int msec) +{ + io_debug("io_set_timeout(%p, %d)", io, msec); + + io->timeout = msec; +} + +void +io_set_lowat(struct io *io, size_t lowat) +{ + io_debug("io_set_lowat(%p, %zu)", io, lowat); + + io->lowat = lowat; +} + +const char * +io_error(struct io *io) +{ + const char *e; + + e = io->error; + io->error = NULL; + return e; +} + +int +io_fileno(struct io *io) +{ + return io->sock; +} + +int +io_attach(struct io *io, int sock) +{ + if (io->state != IO_STATE_DOWN) { + errno = EISCONN; + return -1; + } + + io->state = IO_STATE_UP; + io->sock = sock; + io_reload(io); + return 0; +} + +int +io_detach(struct io *io) +{ + errno = ENOSYS; + return -1; +} + +int +io_close(struct io *io) +{ + errno = ENOSYS; + return -1; +} + +int +io_connect(struct io *io, const char *host, const char *port, + const struct addrinfo *hints) +{ + struct addrinfo hints2; + struct asr_query *as; + + if (io->state != IO_STATE_DOWN) { + errno = EISCONN; + return -1; + } + + if (hints) { + hints2 = *hints; + } + else { + memset(&hints2, 0, sizeof(hints2)); + hints2.ai_flags = AI_ADDRCONFIG; + } + + if (hints2.ai_socktype == 0) + hints2.ai_socktype = SOCK_STREAM; + if (hints2.ai_socktype != SOCK_STREAM) { + errno = ESOCKTNOSUPPORT; + return -1; + } + + as = getaddrinfo_async(host, port, &hints2, NULL); + if (as == NULL) + return -1; + + io->eva = event_asr_run(as, io_dispatch_getaddrinfo, io); + if (io->eva == NULL) { + asr_abort(as); + return -1; + } + + io->state = IO_STATE_RESOLVE; + return 0; +} + +int +io_connect_addrinfo(struct io *io, struct addrinfo *ai) +{ + if (ai == NULL) { + errno = EINVAL; + return -1; + } + + if (io->state != IO_STATE_DOWN) { + freeaddrinfo(ai); + errno = EISCONN; + return -1; + } + + io->ai = ai; + return io_connect_next(io); +} + +int +io_disconnect(struct io *io) +{ + errno = ENOSYS; + return -1; +} + +int +io_starttls(struct io *io, void *ssl) +{ +#ifdef IO_SSL + int mode; + + mode = io->flags & IO_RW; + if (mode == 0 || mode == IO_RW) + fatalx("io_starttls: full-duplex or unset"); + + if (io->tls) + fatalx("io_starttls: SSL already started"); + io->tls = ssl; + + if (SSL_set_fd(io->tls, io->sock) == 0) { + ssl_error("io_start_tls:SSL_set_fd"); + return -1; + } + + if (mode == IO_WRITE) { + io->state = IO_STATE_CONNECT_TLS; + SSL_set_connect_state(io->tls); + io_reset(io, EV_WRITE, io_dispatch_connect_tls); + } else { + io->state = IO_STATE_ACCEPT_TLS; + SSL_set_accept_state(io->tls); + io_reset(io, EV_READ, io_dispatch_accept_tls); + } + + return 0; +#else + errno = ENOSYS; + return -1; +#endif +} + +void +io_pause(struct io *io, int dir) +{ + io_debug("io_pause(%p, %x)", io, dir); + + io->flags |= dir & (IO_IN | IO_OUT); + io_reload(io); +} + +void +io_resume(struct io *io, int dir) +{ + io_debug("io_resume(%p, %x)", io, dir); + + io->flags &= ~(dir & (IO_IN | IO_OUT)); + io_reload(io); +} + +void +io_set_read(struct io *io) +{ + int mode; + + io_debug("io_set_read(%p)", io); + + mode = io->flags & IO_RW; + if (!(mode == 0 || mode == IO_WRITE)) + fatalx("io_set_read: full-duplex or reading"); + + io->flags &= ~IO_RW; + io->flags |= IO_READ; + io_reload(io); +} + +void +io_set_write(struct io *io) +{ + int mode; + + io_debug("io_set_write(%p)", io); + + mode = io->flags & IO_RW; + if (!(mode == 0 || mode == IO_READ)) + fatalx("io_set_write: full-duplex or writing"); + + io->flags &= ~IO_RW; + io->flags |= IO_WRITE; + io_reload(io); +} + +int +io_write(struct io *io, const void *buf, size_t len) +{ + int r; + + r = iobuf_queue(&io->iobuf, buf, len); + + io_reload(io); + + return r; +} + +int +io_writev(struct io *io, const struct iovec *iov, int iovcount) +{ + int r; + + r = iobuf_queuev(&io->iobuf, iov, iovcount); + + io_reload(io); + + return r; +} + +int +io_print(struct io *io, const char *s) +{ + return io_write(io, s, strlen(s)); +} + +int +io_printf(struct io *io, const char *fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = io_vprintf(io, fmt, ap); + va_end(ap); + + return r; +} + +int +io_vprintf(struct io *io, const char *fmt, va_list ap) +{ + + char *buf; + int len; + + len = vasprintf(&buf, fmt, ap); + if (len == -1) + return -1; + + len = io_write(io, buf, len); + free(buf); + + return len; +} + +size_t +io_queued(struct io *io) +{ + return iobuf_queued(&io->iobuf); +} + +void * +io_data(struct io *io) +{ + return iobuf_data(&io->iobuf); +} + +size_t +io_datalen(struct io *io) +{ + return iobuf_len(&io->iobuf); +} + +char * +io_getline(struct io *io, size_t *sz) +{ + return iobuf_getline(&io->iobuf, sz); +} + +void +io_drop(struct io *io, size_t sz) +{ + return iobuf_drop(&io->iobuf, sz); +} + +static void +fd_set_nonblocking(int sock) +{ + int flags; + + if ((flags = fcntl(sock, F_GETFL)) == -1) + fatal("fd_set_blocking: fcntl(F_GETFL)"); + + flags |= O_NONBLOCK; + + if (fcntl(sock, F_SETFL, flags) == -1) + fatal("fd_set_blocking: fcntl(F_SETFL)"); +} + +static void +fd_set_nolinger(int sock) +{ + struct linger l; + + memset(&l, 0, sizeof(l)); + if (setsockopt(sock, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1) + fatal("fd_set_linger: setsockopt"); +} + +const char* +io_strflags(int flags) +{ + static char buf[64]; + + buf[0] = '\0'; + + switch (flags & IO_RW) { + case 0: + (void)strlcat(buf, "rw", sizeof buf); + break; + case IO_READ: + (void)strlcat(buf, "R", sizeof buf); + break; + case IO_WRITE: + (void)strlcat(buf, "W", sizeof buf); + break; + case IO_RW: + (void)strlcat(buf, "RW", sizeof buf); + break; + } + + if (flags & IO_PAUSE_IN) + (void)strlcat(buf, ",F_PI", sizeof buf); + if (flags & IO_PAUSE_OUT) + (void)strlcat(buf, ",F_PO", sizeof buf); + + return buf; +} + +const char* +io_strevents(short ev) +{ + static char buf[64]; + char buf2[16]; + int n; + + n = 0; + buf[0] = '\0'; + + if (ev == 0) { + (void)strlcat(buf, "", sizeof(buf)); + return buf; + } + + if (ev & EV_TIMEOUT) { + (void)strlcat(buf, "EV_TIMEOUT", sizeof(buf)); + ev &= ~EV_TIMEOUT; + n++; + } + + if (ev & EV_READ) { + if (n) + (void)strlcat(buf, "|", sizeof(buf)); + (void)strlcat(buf, "EV_READ", sizeof(buf)); + ev &= ~EV_READ; + n++; + } + + if (ev & EV_WRITE) { + if (n) + (void)strlcat(buf, "|", sizeof(buf)); + (void)strlcat(buf, "EV_WRITE", sizeof(buf)); + ev &= ~EV_WRITE; + n++; + } + + if (ev & EV_SIGNAL) { + if (n) + (void)strlcat(buf, "|", sizeof(buf)); + (void)strlcat(buf, "EV_SIGNAL", sizeof(buf)); + ev &= ~EV_SIGNAL; + n++; + } + + if (ev) { + if (n) + (void)strlcat(buf, "|", sizeof(buf)); + (void)strlcat(buf, "EV_?=0x", sizeof(buf)); + (void)snprintf(buf2, sizeof(buf2), "%hx", ev); + (void)strlcat(buf, buf2, sizeof(buf)); + } + + return buf; +} + +/* + * Setup the necessary events as required by the current io state, + * honouring duplex mode and i/o pause. + */ +static void +io_reload(struct io *io) +{ + short events; + + /* The io will be reloaded at release time. */ + if (io->flags & IO_HELD) + return; + + /* Do nothing if no socket. */ + if (io->sock == -1) + return; + +#ifdef IO_SSL + if (io->tls) { + io_reload_tls(io); + return; + } +#endif + + io_debug("io_reload(%p)", io); + + events = 0; + if (IO_READING(io) && !(io->flags & IO_PAUSE_IN)) + events = EV_READ; + if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && io_queued(io)) + events |= EV_WRITE; + + io_reset(io, events, io_dispatch); +} + +static void +io_reset(struct io *io, short events, void (*dispatch)(int, short, void*)) +{ + struct timeval tv, *ptv; + + io_debug("io_reset(%p, %s, %p) -> %s", + io, io_strevents(events), dispatch, io_strio(io)); + + /* + * Indicate that the event has already been reset so that reload + * is not called on frame_leave. + */ + io->flags |= IO_RESET; + + if (event_initialized(&io->ev)) + event_del(&io->ev); + + /* + * The io is paused by the user, so we don't want the timeout to be + * effective. + */ + if (events == 0) + return; + + event_set(&io->ev, io->sock, events, dispatch, io); + if (io->timeout >= 0) { + tv.tv_sec = io->timeout / 1000; + tv.tv_usec = (io->timeout % 1000) * 1000; + ptv = &tv; + } else + ptv = NULL; + + event_add(&io->ev, ptv); +} + +static void +io_frame_enter(const char *where, struct io *io, int ev) +{ + io_debug("io: BEGIN %llu", frame); + io_debug("io_frame_enter(%s, %s, %s)", + where, io_strevents(ev), io_strio(io)); + + if (current) + fatalx("io_frame_enter: interleaved frames"); + + current = io; + + io_hold(io); +} + +static void +io_frame_leave(struct io *io) +{ + io_debug("io_frame_leave(%llu)", frame); + + if (current && current != io) + fatalx("io_frame_leave: io mismatch"); + + /* The io has been cleared. */ + if (current == NULL) + goto done; + + /* + * TODO: There is a possible optimization there: + * In a typical half-duplex request/response scenario, + * the io is waiting to read a request, and when done, it queues + * the response in the output buffer and goes to write mode. + * There, the write event is set and will be triggered in the next + * event frame. In most case, the write call could be done + * immediately as part of the last read frame, thus avoiding to go + * through the event loop machinery. So, as an optimisation, we + * could detect that case here and force an event dispatching. + */ + + /* Reload the io if it has not been reset already. */ + io_release(io); + current = NULL; + done: + io_debug("io: END %llu", frame); + + frame += 1; +} + +static void +io_hold(struct io *io) +{ + io_debug("io_hold(%p)", io); + + if (io->flags & IO_HELD) + fatalx("io_hold: already held"); + + io->flags &= ~IO_RESET; + io->flags |= IO_HELD; +} + +static void +io_release(struct io *io) +{ + io_debug("io_release(%p)", io); + + if (!(io->flags & IO_HELD)) + fatalx("io_release: not held"); + + io->flags &= ~IO_HELD; + if (!(io->flags & IO_RESET)) + io_reload(io); +} + +static void +io_callback(struct io *io, int evt) +{ + io_debug("io_callback(%s, %s)", io_strio(io), io_strevent(evt)); + + io->cb(io, evt, io->arg); +} + +static void +io_dispatch(int fd, short ev, void *arg) +{ + struct io *io = arg; + size_t w; + ssize_t n; + int saved_errno; + + io_frame_enter("io_dispatch", io, ev); + + if (ev == EV_TIMEOUT) { + io_callback(io, IO_TIMEOUT); + goto leave; + } + + if (ev & EV_WRITE && (w = io_queued(io))) { + if ((n = iobuf_write(&io->iobuf, io->sock)) < 0) { + if (n == IOBUF_WANT_WRITE) /* kqueue bug? */ + goto read; + if (n == IOBUF_CLOSED) + io_callback(io, IO_DISCONNECTED); + else { + saved_errno = errno; + io->error = strerror(errno); + errno = saved_errno; + io_callback(io, IO_ERROR); + } + goto leave; + } + if (w > io->lowat && w - n <= io->lowat) + io_callback(io, IO_LOWAT); + } + read: + + if (ev & EV_READ) { + iobuf_normalize(&io->iobuf); + if ((n = iobuf_read(&io->iobuf, io->sock)) < 0) { + if (n == IOBUF_CLOSED) + io_callback(io, IO_DISCONNECTED); + else { + saved_errno = errno; + io->error = strerror(errno); + errno = saved_errno; + io_callback(io, IO_ERROR); + } + goto leave; + } + if (n) + io_callback(io, IO_DATAIN); + } + +leave: + io_frame_leave(io); +} + +static void +io_dispatch_connect(int fd, short ev, void *arg) +{ + struct io *io = arg; + socklen_t sl; + int r, e; + + io_frame_enter("io_dispatch_connect", io, ev); + + if (ev == EV_TIMEOUT) + e = ETIMEDOUT; + else { + sl = sizeof(e); + r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &e, &sl); + if (r == -1) { + log_warn("io_dispatch_connect: getsockopt"); + e = errno; + } + } + + if (e == 0) { + io->state = IO_STATE_UP; + io_callback(io, IO_CONNECTED); + goto done; + } + + if (io->ai) { + r = io_connect_next(io); + if (r == 0) + goto done; + e = errno; + } + + (void)close(fd); + io->sock = -1; + io->error = strerror(e); + io->state = IO_STATE_DOWN; + io_callback(io, e == ETIMEDOUT ? IO_TIMEOUT : IO_ERROR); + done: + io_frame_leave(io); +} + +static void +io_dispatch_getaddrinfo(struct asr_result *ar, void *arg) +{ + struct io *io = arg; + + io_frame_enter("io_dispatch_getaddrinfo", io, 0); + + io->eva = NULL; + + if (ar->ar_gai_errno) { + io->error = gai_strerror(ar->ar_gai_errno); + io->state = IO_STATE_DOWN; + io_callback(io, IO_ERROR); + } + else { + io->ai = ar->ar_addrinfo; + io->state = IO_STATE_CONNECT; + if (io_connect_next(io) == -1) { + io->state = IO_STATE_DOWN; + io_callback(io, IO_ERROR); + } + } + + io_frame_leave(io); +} + +static int +io_connect_next(struct io *io) +{ + struct addrinfo *ai; + int errno_save; + + while ((ai = io->ai)) { + io->ai = ai->ai_next; + ai->ai_next = NULL; + if (ai->ai_socktype == SOCK_STREAM) + break; + freeaddrinfo(ai); + } + + if (ai == NULL) { + errno = ESOCKTNOSUPPORT; + return -1; + } + + if ((io->sock = socket(ai->ai_family, ai->ai_socktype, 0)) == -1) + goto fail; + + fd_set_nonblocking(io->sock); + fd_set_nolinger(io->sock); + + if (io->bind && bind(io->sock, io->bind, io->bind->sa_len) == -1) + goto fail; + + if (connect(io->sock, ai->ai_addr, ai->ai_addr->sa_len) == -1) + if (errno != EINPROGRESS) + goto fail; + + freeaddrinfo(ai); + io->state = IO_STATE_CONNECT; + io_reset(io, EV_WRITE, io_dispatch_connect); + return 0; + + fail: + if (io->sock != -1) { + errno_save = errno; + close(io->sock); + errno = errno_save; + io->error = strerror(errno); + io->sock = -1; + } + freeaddrinfo(ai); + if (io->ai) { + freeaddrinfo(io->ai); + io->ai = NULL; + } + return -1; +} + +#ifdef IO_SSL + +static const char* +io_ssl_error(void) +{ + static char buf[128]; + unsigned long e; + + e = ERR_peek_last_error(); + if (e) { + ERR_error_string(e, buf); + return buf; + } + + return "No SSL error"; +} + +static void +io_dispatch_accept_tls(int fd, short event, void *arg) +{ + struct io *io = arg; + int e, ret; + + io_frame_enter("io_dispatch_accept_tls", io, event); + + if (event == EV_TIMEOUT) { + io_callback(io, IO_TIMEOUT); + goto leave; + } + + if ((ret = SSL_accept(io->tls)) > 0) { + io->state = IO_STATE_UP; + io_callback(io, IO_TLSREADY); + goto leave; + } + + switch ((e = SSL_get_error(io->tls, ret))) { + case SSL_ERROR_WANT_READ: + io_reset(io, EV_READ, io_dispatch_accept_tls); + break; + case SSL_ERROR_WANT_WRITE: + io_reset(io, EV_WRITE, io_dispatch_accept_tls); + break; + default: + io->error = io_ssl_error(); + ssl_error("io_dispatch_accept_tls:SSL_accept"); + io_callback(io, IO_ERROR); + break; + } + + leave: + io_frame_leave(io); +} + +static void +io_dispatch_connect_tls(int fd, short event, void *arg) +{ + struct io *io = arg; + int e, ret; + + io_frame_enter("io_dispatch_connect_tls", io, event); + + if (event == EV_TIMEOUT) { + io_callback(io, IO_TIMEOUT); + goto leave; + } + + if ((ret = SSL_connect(io->tls)) > 0) { + io->state = IO_STATE_UP; + io_callback(io, IO_TLSREADY); + goto leave; + } + + switch ((e = SSL_get_error(io->tls, ret))) { + case SSL_ERROR_WANT_READ: + io_reset(io, EV_READ, io_dispatch_connect_tls); + break; + case SSL_ERROR_WANT_WRITE: + io_reset(io, EV_WRITE, io_dispatch_connect_tls); + break; + default: + io->error = io_ssl_error(); + ssl_error("io_dispatch_connect_tls:SSL_connect"); + io_callback(io, IO_TLSERROR); + break; + } + + leave: + io_frame_leave(io); +} + +static void +io_dispatch_read_tls(int fd, short event, void *arg) +{ + struct io *io = arg; + int n, saved_errno; + + io_frame_enter("io_dispatch_read_tls", io, event); + + if (event == EV_TIMEOUT) { + io_callback(io, IO_TIMEOUT); + goto leave; + } + +again: + iobuf_normalize(&io->iobuf); + switch ((n = iobuf_read_ssl(&io->iobuf, (SSL*)io->tls))) { + case IOBUF_WANT_READ: + io_reset(io, EV_READ, io_dispatch_read_tls); + break; + case IOBUF_WANT_WRITE: + io_reset(io, EV_WRITE, io_dispatch_read_tls); + break; + case IOBUF_CLOSED: + io_callback(io, IO_DISCONNECTED); + break; + case IOBUF_ERROR: + saved_errno = errno; + io->error = strerror(errno); + errno = saved_errno; + io_callback(io, IO_ERROR); + break; + case IOBUF_SSLERROR: + io->error = io_ssl_error(); + ssl_error("io_dispatch_read_tls:SSL_read"); + io_callback(io, IO_ERROR); + break; + default: + io_debug("io_dispatch_read_tls(...) -> r=%d", n); + io_callback(io, IO_DATAIN); + if (current == io && IO_READING(io) && SSL_pending(io->tls)) + goto again; + } + + leave: + io_frame_leave(io); +} + +static void +io_dispatch_write_tls(int fd, short event, void *arg) +{ + struct io *io = arg; + size_t w2, w; + int n, saved_errno; + + io_frame_enter("io_dispatch_write_tls", io, event); + + if (event == EV_TIMEOUT) { + io_callback(io, IO_TIMEOUT); + goto leave; + } + + w = io_queued(io); + switch ((n = iobuf_write_ssl(&io->iobuf, (SSL*)io->tls))) { + case IOBUF_WANT_READ: + io_reset(io, EV_READ, io_dispatch_write_tls); + break; + case IOBUF_WANT_WRITE: + io_reset(io, EV_WRITE, io_dispatch_write_tls); + break; + case IOBUF_CLOSED: + io_callback(io, IO_DISCONNECTED); + break; + case IOBUF_ERROR: + saved_errno = errno; + io->error = strerror(errno); + errno = saved_errno; + io_callback(io, IO_ERROR); + break; + case IOBUF_SSLERROR: + io->error = io_ssl_error(); + ssl_error("io_dispatch_write_tls:SSL_write"); + io_callback(io, IO_ERROR); + break; + default: + io_debug("io_dispatch_write_tls(...) -> w=%d", n); + w2 = io_queued(io); + if (w > io->lowat && w2 <= io->lowat) + io_callback(io, IO_LOWAT); + break; + } + + leave: + io_frame_leave(io); +} + +static void +io_reload_tls(struct io *io) +{ + short ev = 0; + void (*dispatch)(int, short, void*) = NULL; + + switch (io->state) { + case IO_STATE_CONNECT_TLS: + ev = EV_WRITE; + dispatch = io_dispatch_connect_tls; + break; + case IO_STATE_ACCEPT_TLS: + ev = EV_READ; + dispatch = io_dispatch_accept_tls; + break; + case IO_STATE_UP: + ev = 0; + if (IO_READING(io) && !(io->flags & IO_PAUSE_IN)) { + ev = EV_READ; + dispatch = io_dispatch_read_tls; + } + else if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && + io_queued(io)) { + ev = EV_WRITE; + dispatch = io_dispatch_write_tls; + } + if (!ev) + return; /* paused */ + break; + default: + fatalx("io_reload_tls: state %d", io->state); + } + + io_reset(io, ev, dispatch); +} + +#endif /* IO_SSL */ diff --git a/extras/filters/smtpfd/io.h b/extras/filters/smtpfd/io.h new file mode 100644 index 0000000..b4ce4cc --- /dev/null +++ b/extras/filters/smtpfd/io.h @@ -0,0 +1,87 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2017 Eric Faurot + * + * 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 + +enum { + IO_CONNECTED = 0, /* connection successful */ + IO_TLSREADY, /* TLS started successfully */ + IO_DATAIN, /* new data in input buffer */ + IO_LOWAT, /* output queue running low */ + IO_CLOSED, /* normally terminated */ + IO_DISCONNECTED, /* error? */ + IO_TIMEOUT, /* error? */ + IO_ERROR, /* details? */ + IO_TLSERROR, /* XXX - needs more work */ +}; + +#define IO_IN 0x1 +#define IO_OUT 0x2 + +struct io; + +void io_trace(int); +const char* io_strio(struct io *); +const char* io_strevent(int); + +/* IO management */ +struct io *io_new(void); +void io_free(struct io *); + +/* IO setup */ +int io_set_callback(struct io *, void(*)(struct io *, int, void *), void *); +int io_set_bindaddr(struct io *, const struct sockaddr *); +int io_set_bufsize(struct io *, size_t); +void io_set_timeout(struct io *, int); +void io_set_lowat(struct io *, size_t); + +/* State retreival */ +const char *io_error(struct io *); +int io_fileno(struct io *); + +/* Connection management */ +int io_attach(struct io *io, int); +int io_detach(struct io *io); +int io_close(struct io *io); +int io_connect(struct io *, const char *, const char *, + const struct addrinfo *); +int io_connect_addrinfo(struct io *, struct addrinfo *); +int io_disconnect(struct io *io); +int io_starttls(struct io *, void *); + +/* Flow control */ +void io_pause(struct io *, int); +void io_resume(struct io *, int); + +/* IO direction */ +void io_set_read(struct io *); +void io_set_write(struct io *); + +/* Output buffering */ +int io_write(struct io *, const void *, size_t); +int io_writev(struct io *, const struct iovec *, int); +int io_print(struct io *, const char *); +int io_printf(struct io *, const char *, ...); +int io_vprintf(struct io *, const char *, va_list); +size_t io_queued(struct io *); + +/* Buffered input */ +void * io_data(struct io *); +size_t io_datalen(struct io *); +char * io_getline(struct io *, size_t *); +void io_drop(struct io *, size_t); diff --git a/extras/filters/smtpfd/iobuf.c b/extras/filters/smtpfd/iobuf.c new file mode 100644 index 0000000..8706793 --- /dev/null +++ b/extras/filters/smtpfd/iobuf.c @@ -0,0 +1,467 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2012 Eric Faurot + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef IO_SSL +#include +#include +#endif + +#include "iobuf.h" + +#define IOBUF_MAX 65536 +#define IOBUFQ_MIN 4096 + +struct ioqbuf *ioqbuf_alloc(struct iobuf *, size_t); +void iobuf_drain(struct iobuf *, size_t); + +int +iobuf_init(struct iobuf *io, size_t size, size_t max) +{ + memset(io, 0, sizeof *io); + + if (max == 0) + max = IOBUF_MAX; + + if (size == 0) + size = max; + + if (size > max) + return (-1); + + if ((io->buf = calloc(size, 1)) == NULL) + return (-1); + + io->size = size; + io->max = max; + + return (0); +} + +void +iobuf_clear(struct iobuf *io) +{ + struct ioqbuf *q; + + free(io->buf); + + while ((q = io->outq)) { + io->outq = q->next; + free(q); + } + + memset(io, 0, sizeof (*io)); +} + +void +iobuf_drain(struct iobuf *io, size_t n) +{ + struct ioqbuf *q; + size_t left = n; + + while ((q = io->outq) && left) { + if ((q->wpos - q->rpos) > left) { + q->rpos += left; + left = 0; + } else { + left -= q->wpos - q->rpos; + io->outq = q->next; + free(q); + } + } + + io->queued -= (n - left); + if (io->outq == NULL) + io->outqlast = NULL; +} + +int +iobuf_extend(struct iobuf *io, size_t n) +{ + char *t; + + if (n > io->max) + return (-1); + + if (io->max - io->size < n) + return (-1); + + t = recallocarray(io->buf, io->size, io->size + n, 1); + if (t == NULL) + return (-1); + + io->size += n; + io->buf = t; + + return (0); +} + +size_t +iobuf_left(struct iobuf *io) +{ + return io->size - io->wpos; +} + +size_t +iobuf_space(struct iobuf *io) +{ + return io->size - (io->wpos - io->rpos); +} + +size_t +iobuf_len(struct iobuf *io) +{ + return io->wpos - io->rpos; +} + +char * +iobuf_data(struct iobuf *io) +{ + return io->buf + io->rpos; +} + +void +iobuf_drop(struct iobuf *io, size_t n) +{ + if (n >= iobuf_len(io)) { + io->rpos = io->wpos = 0; + return; + } + + io->rpos += n; +} + +char * +iobuf_getline(struct iobuf *iobuf, size_t *rlen) +{ + char *buf; + size_t len, i; + + buf = iobuf_data(iobuf); + len = iobuf_len(iobuf); + + for (i = 0; i + 1 <= len; i++) + if (buf[i] == '\n') { + /* Note: the returned address points into the iobuf + * buffer. We NUL-end it for convenience, and discard + * the data from the iobuf, so that the caller doesn't + * have to do it. The data remains "valid" as long + * as the iobuf does not overwrite it, that is until + * the next call to iobuf_normalize() or iobuf_extend(). + */ + iobuf_drop(iobuf, i + 1); + len = (i && buf[i - 1] == '\r') ? i - 1 : i; + buf[len] = '\0'; + if (rlen) + *rlen = len; + return (buf); + } + + return (NULL); +} + +void +iobuf_normalize(struct iobuf *io) +{ + if (io->rpos == 0) + return; + + if (io->rpos == io->wpos) { + io->rpos = io->wpos = 0; + return; + } + + memmove(io->buf, io->buf + io->rpos, io->wpos - io->rpos); + io->wpos -= io->rpos; + io->rpos = 0; +} + +ssize_t +iobuf_read(struct iobuf *io, int fd) +{ + ssize_t n; + + n = read(fd, io->buf + io->wpos, iobuf_left(io)); + if (n == -1) { + /* XXX is this really what we want? */ + if (errno == EAGAIN || errno == EINTR) + return (IOBUF_WANT_READ); + return (IOBUF_ERROR); + } + if (n == 0) + return (IOBUF_CLOSED); + + io->wpos += n; + + return (n); +} + +struct ioqbuf * +ioqbuf_alloc(struct iobuf *io, size_t len) +{ + struct ioqbuf *q; + + if (len < IOBUFQ_MIN) + len = IOBUFQ_MIN; + + if ((q = malloc(sizeof(*q) + len)) == NULL) + return (NULL); + + q->rpos = 0; + q->wpos = 0; + q->size = len; + q->next = NULL; + q->buf = (char *)(q) + sizeof(*q); + + if (io->outqlast == NULL) + io->outq = q; + else + io->outqlast->next = q; + io->outqlast = q; + + return (q); +} + +size_t +iobuf_queued(struct iobuf *io) +{ + return io->queued; +} + +void * +iobuf_reserve(struct iobuf *io, size_t len) +{ + struct ioqbuf *q; + void *r; + + if (len == 0) + return (NULL); + + if (((q = io->outqlast) == NULL) || q->size - q->wpos <= len) { + if ((q = ioqbuf_alloc(io, len)) == NULL) + return (NULL); + } + + r = q->buf + q->wpos; + q->wpos += len; + io->queued += len; + + return (r); +} + +int +iobuf_queue(struct iobuf *io, const void *data, size_t len) +{ + void *buf; + + if (len == 0) + return (0); + + if ((buf = iobuf_reserve(io, len)) == NULL) + return (-1); + + memmove(buf, data, len); + + return (len); +} + +int +iobuf_queuev(struct iobuf *io, const struct iovec *iov, int iovcnt) +{ + int i; + size_t len = 0; + char *buf; + + for (i = 0; i < iovcnt; i++) + len += iov[i].iov_len; + + if ((buf = iobuf_reserve(io, len)) == NULL) + return (-1); + + for (i = 0; i < iovcnt; i++) { + if (iov[i].iov_len == 0) + continue; + memmove(buf, iov[i].iov_base, iov[i].iov_len); + buf += iov[i].iov_len; + } + + return (0); + +} + +int +iobuf_fqueue(struct iobuf *io, const char *fmt, ...) +{ + va_list ap; + int len; + + va_start(ap, fmt); + len = iobuf_vfqueue(io, fmt, ap); + va_end(ap); + + return (len); +} + +int +iobuf_vfqueue(struct iobuf *io, const char *fmt, va_list ap) +{ + char *buf; + int len; + + len = vasprintf(&buf, fmt, ap); + + if (len == -1) + return (-1); + + len = iobuf_queue(io, buf, len); + free(buf); + + return (len); +} + +ssize_t +iobuf_write(struct iobuf *io, int fd) +{ + struct iovec iov[IOV_MAX]; + struct ioqbuf *q; + int i; + ssize_t n; + + i = 0; + for (q = io->outq; q ; q = q->next) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = q->buf + q->rpos; + iov[i].iov_len = q->wpos - q->rpos; + i++; + } + + n = writev(fd, iov, i); + if (n == -1) { + if (errno == EAGAIN || errno == EINTR) + return (IOBUF_WANT_WRITE); + if (errno == EPIPE) + return (IOBUF_CLOSED); + return (IOBUF_ERROR); + } + + iobuf_drain(io, n); + + return (n); +} + +int +iobuf_flush(struct iobuf *io, int fd) +{ + ssize_t s; + + while (io->queued) + if ((s = iobuf_write(io, fd)) < 0) + return (s); + + return (0); +} + +#ifdef IO_SSL + +int +iobuf_flush_ssl(struct iobuf *io, void *ssl) +{ + ssize_t s; + + while (io->queued) + if ((s = iobuf_write_ssl(io, ssl)) < 0) + return (s); + + return (0); +} + +ssize_t +iobuf_write_ssl(struct iobuf *io, void *ssl) +{ + struct ioqbuf *q; + int r; + ssize_t n; + + q = io->outq; + n = SSL_write(ssl, q->buf + q->rpos, q->wpos - q->rpos); + if (n <= 0) { + switch ((r = SSL_get_error(ssl, n))) { + case SSL_ERROR_WANT_READ: + return (IOBUF_WANT_READ); + case SSL_ERROR_WANT_WRITE: + return (IOBUF_WANT_WRITE); + case SSL_ERROR_ZERO_RETURN: /* connection closed */ + return (IOBUF_CLOSED); + case SSL_ERROR_SYSCALL: + if (ERR_peek_last_error()) + return (IOBUF_SSLERROR); + if (r == 0) + errno = EPIPE; + return (IOBUF_ERROR); + default: + return (IOBUF_SSLERROR); + } + } + iobuf_drain(io, n); + + return (n); +} + +ssize_t +iobuf_read_ssl(struct iobuf *io, void *ssl) +{ + ssize_t n; + int r; + + n = SSL_read(ssl, io->buf + io->wpos, iobuf_left(io)); + if (n < 0) { + switch ((r = SSL_get_error(ssl, n))) { + case SSL_ERROR_WANT_READ: + return (IOBUF_WANT_READ); + case SSL_ERROR_WANT_WRITE: + return (IOBUF_WANT_WRITE); + case SSL_ERROR_SYSCALL: + if (ERR_peek_last_error()) + return (IOBUF_SSLERROR); + if (r == 0) + errno = EPIPE; + return (IOBUF_ERROR); + default: + return (IOBUF_SSLERROR); + } + } else if (n == 0) + return (IOBUF_CLOSED); + + io->wpos += n; + + return (n); +} + +#endif /* IO_SSL */ diff --git a/extras/filters/smtpfd/iobuf.h b/extras/filters/smtpfd/iobuf.h new file mode 100644 index 0000000..f1385a2 --- /dev/null +++ b/extras/filters/smtpfd/iobuf.h @@ -0,0 +1,68 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2017 Eric Faurot + * + * 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. + */ + +struct ioqbuf { + struct ioqbuf *next; + char *buf; + size_t size; + size_t wpos; + size_t rpos; +}; + +struct iobuf { + char *buf; + size_t max; + size_t size; + size_t wpos; + size_t rpos; + + size_t queued; + struct ioqbuf *outq; + struct ioqbuf *outqlast; +}; + +#define IOBUF_WANT_READ -1 +#define IOBUF_WANT_WRITE -2 +#define IOBUF_CLOSED -3 +#define IOBUF_ERROR -4 +#define IOBUF_SSLERROR -5 + +int iobuf_init(struct iobuf *, size_t, size_t); +void iobuf_clear(struct iobuf *); + +int iobuf_extend(struct iobuf *, size_t); +void iobuf_normalize(struct iobuf *); +void iobuf_drop(struct iobuf *, size_t); +size_t iobuf_space(struct iobuf *); +size_t iobuf_len(struct iobuf *); +size_t iobuf_left(struct iobuf *); +char *iobuf_data(struct iobuf *); +char *iobuf_getline(struct iobuf *, size_t *); +ssize_t iobuf_read(struct iobuf *, int); +ssize_t iobuf_read_ssl(struct iobuf *, void *); + +size_t iobuf_queued(struct iobuf *); +void* iobuf_reserve(struct iobuf *, size_t); +int iobuf_queue(struct iobuf *, const void*, size_t); +int iobuf_queuev(struct iobuf *, const struct iovec *, int); +int iobuf_fqueue(struct iobuf *, const char *, ...); +int iobuf_vfqueue(struct iobuf *, const char *, va_list); +int iobuf_flush(struct iobuf *, int); +int iobuf_flush_ssl(struct iobuf *, void *); +ssize_t iobuf_write(struct iobuf *, int); +ssize_t iobuf_write_ssl(struct iobuf *, void *); diff --git a/extras/filters/smtpfd/log.c b/extras/filters/smtpfd/log.c index 8956cd8..b42a45d 100644 --- a/extras/filters/smtpfd/log.c +++ b/extras/filters/smtpfd/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.2 2017/03/21 12:06:55 bluhm Exp $ */ +/* $OpenBSD: log.c,v 1.20 2017/03/21 12:06:56 bluhm Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -23,12 +23,32 @@ #include #include #include - -#include "log.h" - -static int debug; -static int verbose; -static const char *log_procname; +#include + +static int debug; +static int verbose; +const char *log_procname; + +void log_init(int, int); +void log_procinit(const char *); +void log_setverbose(int); +int log_getverbose(void); +void log_warn(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_warnx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_info(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_debug(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void logit(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +void vlog(int, const char *, va_list) + __attribute__((__format__ (printf, 2, 0))); +__dead void fatal(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +__dead void fatalx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); void log_init(int n_debug, int facility) @@ -82,7 +102,8 @@ vlog(int pri, const char *fmt, va_list ap) if (debug) { /* best effort in out of mem situations */ - if (asprintf(&nfmt, "%s\n", fmt) == -1) { + if (asprintf(&nfmt, "[%s(%d)] %s\n", log_procname, + (int)getpid(), fmt) == -1) { vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); } else { @@ -149,7 +170,7 @@ log_debug(const char *emsg, ...) { va_list ap; - if (verbose) { + if (verbose > 1) { va_start(ap, emsg); vlog(LOG_DEBUG, emsg, ap); va_end(ap); @@ -170,10 +191,10 @@ vfatalc(int code, const char *emsg, va_list ap) sep = ""; } if (code) - logit(LOG_CRIT, "fatal in %s: %s%s%s", + logit(LOG_CRIT, "%s: %s%s%s", log_procname, s, sep, strerror(code)); else - logit(LOG_CRIT, "fatal in %s%s%s", log_procname, sep, s); + logit(LOG_CRIT, "%s%s%s", log_procname, sep, s); } void diff --git a/extras/filters/smtpfd/log.h b/extras/filters/smtpfd/log.h index 8bba629..d680e86 100644 --- a/extras/filters/smtpfd/log.h +++ b/extras/filters/smtpfd/log.h @@ -1,7 +1,7 @@ -/* $OpenBSD: log.h,v 1.10 2017/01/24 04:24:25 benno Exp $ */ +/* $OpenBSD: log.h,v 1.7 2017/01/09 14:49:22 reyk Exp $ */ /* - * Copyright (c) 2003, 2004 Henning Brauer + * Copyright (c) 2010 Gilles Chehade * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,12 +16,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef LOG_H -#define LOG_H - #include -#include +#include +/* log.c */ void log_init(int, int); void log_procinit(const char *); void log_setverbose(int); @@ -42,5 +40,3 @@ __dead void fatal(const char *, ...) __attribute__((__format__ (printf, 1, 2))); __dead void fatalx(const char *, ...) __attribute__((__format__ (printf, 1, 2))); - -#endif /* LOG_H */ diff --git a/extras/filters/smtpfd/logmsg.c b/extras/filters/smtpfd/logmsg.c new file mode 100644 index 0000000..d3bf3f8 --- /dev/null +++ b/extras/filters/smtpfd/logmsg.c @@ -0,0 +1,149 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2017 Eric Faurot + * + * 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 + +#include +#include +#include + +#include "smtpfd.h" + +#include "io.h" +#include "log.h" +#include "proc.h" + +const char * +log_fmt_proto(int p) +{ + switch (p) { + case PROTO_SMTPF: + return "smtpf"; + default: + return NULL; + } +}; + +const char * +log_fmt_imsgtype(int type) +{ + static char buf[16]; + + switch (type) { + case IMSG_NONE: + return "IMSG_NONE"; + case IMSG_SOCK_ENGINE: + return "IMSG_SOCK_ENGINE"; + case IMSG_SOCK_FRONTEND: + return "IMSG_SOCK_FRONTEND"; + case IMSG_CONF_START: + return "IMSG_CONF_START"; + case IMSG_CONF_FILTER_PROC: + return "IMSG_CONF_FILTER_PROC"; + case IMSG_CONF_LISTENER: + return "IMSG_CONF_LISTENER"; + case IMSG_CONF_END: + return "IMSG_CONF_END"; + case IMSG_RES_GETADDRINFO: + return "IMSG_RES_GETADDRINFO"; + case IMSG_RES_GETADDRINFO_END: + return "IMSG_RES_GETADDRINFO_END"; + case IMSG_RES_GETNAMEINFO: + return "IMSG_RES_GETNAMEINFO"; + default: + snprintf(buf, sizeof(buf), "?%d", type); + return buf; + } +} + +const char * +log_fmt_proctype(int proctype) +{ + switch (proctype) { + case PROC_CLIENT: + return "client"; + case PROC_CONTROL: + return "control"; + case PROC_ENGINE: + return "engine"; + case PROC_FILTER: + return "filter"; + case PROC_FRONTEND: + return "frontend"; + case PROC_PRIV: + return "priv"; + default: + return NULL; + } +}; + +const char * +log_fmt_sockaddr(const struct sockaddr *sa) +{ + static char buf[PATH_MAX]; + char host[NI_MAXHOST], serv[NI_MAXSERV]; + + switch (sa->sa_family) { + case AF_LOCAL: + (void)strlcpy(buf, ((const struct sockaddr_un*)sa)->sun_path, + sizeof(buf)); + return buf; + + case AF_INET: + case AF_INET6: + if (getnameinfo(sa, sa->sa_len, host, sizeof(host), + serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV)) { + log_warnx("%s: getnameinfo", __func__); + return NULL; + } + if (sa->sa_family == AF_INET6) + snprintf(buf, sizeof(buf), "[%s]:%s", host, serv); + else + snprintf(buf, sizeof(buf), "%s:%s", host, serv); + return buf; + + default: + return NULL; + } +} + +void +log_imsg(struct imsgproc *proc, struct imsg *imsg) +{ + if (log_getverbose() < 3) + return; + + if (imsg == NULL) + log_debug("imsg from=%s closed", + log_fmt_proctype(proc_gettype(proc))); + else + log_debug("imsg from=%s imsg=%s len=%d fd=%d", + log_fmt_proctype(proc_gettype(proc)), + log_fmt_imsgtype(imsg->hdr.type), + imsg->hdr.len, imsg->fd); +} + +void +log_io(const char *name, struct io *io, int ev) +{ + if (log_getverbose() < 4) + return; + + log_debug("io %s event=%s io=%s", name, io_strevent(ev), + io_strio(io)); +} diff --git a/extras/filters/smtpfd/parse.y b/extras/filters/smtpfd/parse.y index 7e28948..acfcc58 100644 --- a/extras/filters/smtpfd/parse.y +++ b/extras/filters/smtpfd/parse.y @@ -1,8 +1,8 @@ -/* $OpenBSD$ */ +/* $OpenBSD: parse.y,v 1.183 2016/02/22 16:19:05 gilles Exp $ */ /* - * Copyright (c) 2004, 2005 Esben Norby - * Copyright (c) 2004 Ryan McBride + * Copyright (c) 2008 Gilles Chehade + * Copyright (c) 2008 Pierre-Yves Ritschard * Copyright (c) 2002, 2003, 2004 Henning Brauer * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. @@ -23,20 +23,29 @@ %{ #include -#include #include #include +#include +#include + +#include +#include +#include #include #include +#include +#include +#include #include #include -#include +#include #include -#include "log.h" #include "smtpfd.h" +#include "log.h" + TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; @@ -50,14 +59,14 @@ int popfile(void); int check_file_secrecy(int, const char *); int yyparse(void); int yylex(void); -int yyerror(const char *, ...) - __attribute__((__format__ (printf, 1, 2))) - __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); int lungetc(int); int findeol(void); +int yyerror(const char *, ...) + __attribute__((__format__ (printf, 1, 2))) + __attribute__((__nonnull__ (1))); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { @@ -67,45 +76,69 @@ struct sym { char *nam; char *val; }; +int symset(const char *, const char *, int); +char *symget(const char *); + +static int errors = 0; + +struct smtpfd_conf *conf = NULL; +static struct filter_conf *filter; -int symset(const char *, const char *, int); -char *symget(const char *); +enum listen_options { + LO_FAMILY = 0x000001, + LO_PORT = 0x000002, +}; -static struct smtpfd_conf *conf; -static struct filter_conf *filter; -static int errors; +static struct listen_opts { + char *ifx; + int family; + int proto; + in_port_t port; + uint32_t options; +} listen_opts; + +static void config_free(struct smtpfd_conf *); +static void create_listeners(struct listen_opts *); +static void config_listener(struct listener *, struct listen_opts *); +static int local(struct listen_opts *); +static int host_v4(struct listen_opts *); +static int host_v6(struct listen_opts *); +static int host_dns(struct listen_opts *); +static int interface(struct listen_opts *); +static int is_if_in_group(const char *, const char *); typedef struct { union { int64_t number; char *string; + struct host *host; } v; int lineno; } YYSTYPE; %} -%token CHAIN ERROR FILTER INCLUDE - +%token ERROR ARROW INCLUDE +%token LISTEN ON PORT INET4 INET6 LOCAL SOCKET +%token CHAIN FILTER %token STRING -%token NUMBER -%type string +%token NUMBER +%type family_inet portno %% grammar : /* empty */ - | grammar include '\n' | grammar '\n' - | grammar filter '\n' - | grammar chain '\n' + | grammar include '\n' | grammar varset '\n' + | grammar main '\n' | grammar error '\n' { file->errors++; } ; include : INCLUDE STRING { struct file *nfile; - if ((nfile = pushfile($2, 1)) == NULL) { + if ((nfile = pushfile($2, 0)) == NULL) { yyerror("failed to include file %s", $2); free($2); YYERROR; @@ -117,34 +150,59 @@ include : INCLUDE STRING { } ; -string : string STRING { - if (asprintf(&$$, "%s %s", $1, $2) == -1) { +varset : STRING '=' STRING { + if (symset($1, $3, 0) == -1) + fatal("cannot store variable"); + free($1); + free($3); + } + ; + +portno : STRING { + struct servent *servent; + servent = getservbyname($1, "tcp"); + if (servent == NULL) { + yyerror("invalid port: %s", $1); free($1); - free($2); - yyerror("string: asprintf"); YYERROR; } free($1); - free($2); + $$ = ntohs(servent->s_port); + } + | NUMBER { + if ($1 <= 0 || $1 >= (int)USHRT_MAX) { + yyerror("invalid port: %" PRId64, $1); + YYERROR; + } + $$ = $1; } - | STRING ; -varset : STRING '=' string { - char *s = $1; - if (cmd_opts & OPT_VERBOSE) - printf("%s = \"%s\"\n", $1, $3); - while (*s++) { - if (isspace((unsigned char)*s)) { - yyerror("macro name cannot contain " - "whitespace"); - YYERROR; - } +family_inet : INET4 { $$ = AF_INET; } + | INET6 { $$ = AF_INET6; } + ; + +opt_listen : family_inet { + if (listen_opts.options & LO_FAMILY) { + yyerror("address family already specified"); + YYERROR; } - if (symset($1, $3, 0) == -1) - fatal("cannot store variable"); - free($1); - free($3); + listen_opts.options |= LO_FAMILY; + listen_opts.family = $1; + } + | PORT portno { + if (listen_opts.options & LO_PORT) { + yyerror("port already specified"); + YYERROR; + } + listen_opts.options |= LO_PORT; + listen_opts.port = htons($2); + } + ; + +listener : opt_listen listener + | /* empty */ { + create_listeners(&listen_opts); } ; @@ -211,11 +269,15 @@ chain : CHAIN STRING { } filter_args ; -optnl : '\n' optnl /* zero or more newlines */ - | /*empty*/ - ; - -nl : '\n' optnl /* one or more newlines */ +main : LISTEN ON STRING { + memset(&listen_opts, 0, sizeof listen_opts); + listen_opts.ifx = $3; + listen_opts.family = AF_UNSPEC; + listen_opts.proto = PROTO_SMTPF; + listen_opts.port = htons(PORT_SMTPF); + } listener + | filter + | chain ; %% @@ -235,7 +297,7 @@ yyerror(const char *fmt, ...) if (vasprintf(&msg, fmt, ap) == -1) fatalx("yyerror vasprintf"); va_end(ap); - logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); + log_warnx("%s:%d: %s", file->name, yylval.lineno, msg); free(msg); return (0); } @@ -249,11 +311,17 @@ kw_cmp(const void *k, const void *e) int lookup(char *s) { - /* This has to be sorted always. */ + /* this has to be sorted always */ static const struct keywords keywords[] = { - {"chain", CHAIN}, - {"filter", FILTER}, - {"include", INCLUDE}, + { "chain", CHAIN }, + { "filter", FILTER }, + { "include", INCLUDE }, + { "inet4", INET4 }, + { "inet6", INET6 }, + { "listen", LISTEN }, + { "on", ON }, + { "port", PORT }, + { "socket", SOCKET }, }; const struct keywords *p; @@ -343,13 +411,11 @@ findeol(void) int c; parsebuf = NULL; + pushback_index = 0; - /* Skip to either EOF or the first real EOL. */ + /* skip to either EOF or the first real EOL */ while (1) { - if (pushback_index) - c = pushback_buffer[--pushback_index]; - else - c = lgetc(0); + c = lgetc(0); if (c == '\n') { file->lineno++; break; @@ -479,9 +545,16 @@ nodigits: } } + if (c == '=') { + if ((c = lgetc(0)) != EOF && c == '>') + return (ARROW); + lungetc(c); + c = '='; + } + #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ - x != '{' && x != '}' && \ + x != '{' && x != '}' && x != '<' && x != '>' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) @@ -515,15 +588,15 @@ check_file_secrecy(int fd, const char *fname) struct stat st; if (fstat(fd, &st)) { - log_warn("cannot stat %s", fname); + log_warn("warn: cannot stat %s", fname); return (-1); } if (st.st_uid != 0 && st.st_uid != getuid()) { - log_warnx("%s: owner not root or current user", fname); + log_warnx("warn: %s: owner not root or current user", fname); return (-1); } if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { - log_warnx("%s: group writable or world read/writable", fname); + log_warnx("warn: %s: group/world readable/writeable", fname); return (-1); } return (0); @@ -535,16 +608,16 @@ pushfile(const char *name, int secret) struct file *nfile; if ((nfile = calloc(1, sizeof(struct file))) == NULL) { - log_warn("calloc"); + log_warn("warn: malloc"); return (NULL); } if ((nfile->name = strdup(name)) == NULL) { - log_warn("strdup"); + log_warn("warn: malloc"); free(nfile); return (NULL); } if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { - log_warn("%s", nfile->name); + log_warn("warn: %s", nfile->name); free(nfile->name); free(nfile); return (NULL); @@ -577,28 +650,38 @@ popfile(void) } struct smtpfd_conf * -parse_config(char *filename) +parse_config(const char *filename, int verbose) { - struct sym *sym, *next; + struct sym *sym, *next; - conf = config_new_empty(); + conf = calloc(1, sizeof(*conf)); + if (conf == NULL) + return NULL; + TAILQ_INIT(&conf->listeners); + TAILQ_INIT(&conf->filters); - file = pushfile(filename, !(cmd_opts & OPT_NOACTION)); - if (file == NULL) { - free(conf); - return (NULL); + errors = 0; + + if ((file = pushfile(filename, 0)) == NULL) { + config_free(conf); + return NULL; } topfile = file; + /* + * parse configuration + */ + setservent(1); yyparse(); errors = file->errors; popfile(); + endservent(); /* Free macros and check which have not been used. */ - TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { - if ((cmd_opts & OPT_VERBOSE2) && !sym->used) - fprintf(stderr, "warning: macro '%s' not used\n", - sym->nam); + for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { + next = TAILQ_NEXT(sym, entry); + if ((verbose) && !sym->used) + log_warnx("warning: macro '%s' not used\n", sym->nam); if (!sym->persist) { free(sym->nam); free(sym->val); @@ -608,11 +691,11 @@ parse_config(char *filename) } if (errors) { - config_clear(conf); - return (NULL); + config_free(conf); + return NULL; } - return (conf); + return conf; } int @@ -620,10 +703,9 @@ symset(const char *nam, const char *val, int persist) { struct sym *sym; - TAILQ_FOREACH(sym, &symhead, entry) { - if (strcmp(nam, sym->nam) == 0) - break; - } + for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); + sym = TAILQ_NEXT(sym, entry)) + ; /* nothing */ if (sym != NULL) { if (sym->persist == 1) @@ -669,7 +751,7 @@ cmdline_symset(char *s) if ((sym = malloc(len)) == NULL) errx(1, "cmdline_symset: malloc"); - strlcpy(sym, s, len); + (void)strlcpy(sym, s, len); ret = symset(sym, val + 1, 1); free(sym); @@ -682,11 +764,277 @@ symget(const char *nam) { struct sym *sym; - TAILQ_FOREACH(sym, &symhead, entry) { + TAILQ_FOREACH(sym, &symhead, entry) if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } - } return (NULL); } + +static void +config_free(struct smtpfd_conf *c) +{ + struct listener *l; + struct filter_conf *f; + + while ((l = TAILQ_FIRST(&c->listeners))) { + TAILQ_REMOVE(&c->listeners, l, entry); + free(l); + } + while ((f = TAILQ_FIRST(&c->filters))) { + TAILQ_REMOVE(&c->filters, f, entry); + free(f->name); + free(f); + } + + free(c); +} + +static void +create_listeners(struct listen_opts *lo) +{ + if (local(lo)) + return; + if (interface(lo)) + return; + if (host_v4(lo)) + return; + if (host_v6(lo)) + return; + if (host_dns(lo)) + return; + + errx(1, "invalid virtual ip or interface: %s", lo->ifx); +} + +static void +config_listener(struct listener *l, struct listen_opts *lo) +{ + l->sock = -1; + l->proto = lo->proto; + + TAILQ_INSERT_TAIL(&conf->listeners, l, entry); +} + +static int +local(struct listen_opts *lo) +{ + struct sockaddr_un *sun; + struct listener *h; + + if (lo->family != AF_UNSPEC && lo->family != AF_LOCAL) + return 0; + + if (lo->ifx[0] != '/') + return 0; + + h = calloc(1, sizeof(*h)); + sun = (struct sockaddr_un *)&h->ss; + sun->sun_len = sizeof(*sun); + sun->sun_family = AF_LOCAL; + if (strlcpy(sun->sun_path, lo->ifx, sizeof(sun->sun_path)) + >= sizeof(sun->sun_path)) + fatalx("path too long"); + + config_listener(h, lo); + + return (1); +} + +static int +host_v4(struct listen_opts *lo) +{ + struct in_addr ina; + struct sockaddr_in *sain; + struct listener *h; + + if (lo->family != AF_UNSPEC && lo->family != AF_INET) + return (0); + + memset(&ina, 0, sizeof(ina)); + if (inet_pton(AF_INET, lo->ifx, &ina) != 1) + return (0); + + h = calloc(1, sizeof(*h)); + sain = (struct sockaddr_in *)&h->ss; + sain->sin_len = sizeof(struct sockaddr_in); + sain->sin_family = AF_INET; + sain->sin_addr.s_addr = ina.s_addr; + sain->sin_port = lo->port; + + config_listener(h, lo); + + return (1); +} + +static int +host_v6(struct listen_opts *lo) +{ + struct in6_addr ina6; + struct sockaddr_in6 *sin6; + struct listener *h; + + if (lo->family != AF_UNSPEC && lo->family != AF_INET6) + return (0); + + memset(&ina6, 0, sizeof(ina6)); + if (inet_pton(AF_INET6, lo->ifx, &ina6) != 1) + return (0); + + h = calloc(1, sizeof(*h)); + sin6 = (struct sockaddr_in6 *)&h->ss; + sin6->sin6_len = sizeof(struct sockaddr_in6); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = lo->port; + memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6)); + + config_listener(h, lo); + + return (1); +} + +static int +host_dns(struct listen_opts *lo) +{ + struct addrinfo hints, *res0, *res; + int error, cnt = 0; + struct sockaddr_in *sain; + struct sockaddr_in6 *sin6; + struct listener *h; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = lo->family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; + error = getaddrinfo(lo->ifx, NULL, &hints, &res0); + if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME) + return (0); + if (error) { + log_warnx("warn: host_dns: could not parse \"%s\": %s", lo->ifx, + gai_strerror(error)); + return (-1); + } + + for (res = res0; res; res = res->ai_next) { + if (res->ai_family != AF_INET && + res->ai_family != AF_INET6) + continue; + h = calloc(1, sizeof(*h)); + h->ss.ss_family = res->ai_family; + if (res->ai_family == AF_INET) { + sain = (struct sockaddr_in *)&h->ss; + sain->sin_len = sizeof(struct sockaddr_in); + sain->sin_addr.s_addr = ((struct sockaddr_in *) + res->ai_addr)->sin_addr.s_addr; + sain->sin_port = lo->port; + } else { + sin6 = (struct sockaddr_in6 *)&h->ss; + sin6->sin6_len = sizeof(struct sockaddr_in6); + memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *) + res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); + sin6->sin6_port = lo->port; + } + + config_listener(h, lo); + + cnt++; + } + + freeaddrinfo(res0); + return (cnt); +} + +static int +interface(struct listen_opts *lo) +{ + struct ifaddrs *ifap, *p; + struct sockaddr_in *sain; + struct sockaddr_in6 *sin6; + struct listener *h; + int ret = 0; + + if (getifaddrs(&ifap) == -1) + fatal("getifaddrs"); + + for (p = ifap; p != NULL; p = p->ifa_next) { + if (p->ifa_addr == NULL) + continue; + if (strcmp(p->ifa_name, lo->ifx) != 0 && + !is_if_in_group(p->ifa_name, lo->ifx)) + continue; + if (lo->family != AF_UNSPEC && lo->family != p->ifa_addr->sa_family) + continue; + + h = calloc(1, sizeof(*h)); + + switch (p->ifa_addr->sa_family) { + case AF_INET: + sain = (struct sockaddr_in *)&h->ss; + *sain = *(struct sockaddr_in *)p->ifa_addr; + sain->sin_len = sizeof(struct sockaddr_in); + sain->sin_port = lo->port; + break; + + case AF_INET6: + sin6 = (struct sockaddr_in6 *)&h->ss; + *sin6 = *(struct sockaddr_in6 *)p->ifa_addr; + sin6->sin6_len = sizeof(struct sockaddr_in6); + sin6->sin6_port = lo->port; + break; + + default: + free(h); + continue; + } + + config_listener(h, lo); + ret = 1; + } + + freeifaddrs(ifap); + return ret; +} + +static int +is_if_in_group(const char *ifname, const char *groupname) +{ + unsigned int len; + struct ifgroupreq ifgr; + struct ifg_req *ifg; + int s; + int ret = 0; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + + memset(&ifgr, 0, sizeof(ifgr)); + if (strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ) >= IFNAMSIZ) + errx(1, "interface name too large"); + + if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) { + if (errno == EINVAL || errno == ENOTTY) + goto end; + err(1, "SIOCGIFGROUP"); + } + + len = ifgr.ifgr_len; + ifgr.ifgr_groups = calloc(len/sizeof(struct ifg_req), + sizeof(struct ifg_req)); + if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) + err(1, "SIOCGIFGROUP"); + + ifg = ifgr.ifgr_groups; + for (; ifg && len >= sizeof(struct ifg_req); ifg++) { + len -= sizeof(struct ifg_req); + if (strcmp(ifg->ifgrq_group, groupname) == 0) { + ret = 1; + break; + } + } + free(ifgr.ifgr_groups); + +end: + close(s); + return ret; +} diff --git a/extras/filters/smtpfd/proc.c b/extras/filters/smtpfd/proc.c index 0facfb5..3784a9a 100644 --- a/extras/filters/smtpfd/proc.c +++ b/extras/filters/smtpfd/proc.c @@ -40,6 +40,21 @@ struct imsgproc { struct imsgbuf imsgbuf; short events; struct event ev; + + struct { + const uint8_t *pos; + const uint8_t *end; + } m_in; + + struct m_out { + char *buf; + size_t alloc; + size_t pos; + uint32_t type; + uint32_t peerid; + pid_t pid; + int fd; + } m_out; }; static struct imsgproc *proc_new(int); @@ -231,6 +246,15 @@ proc_event_add(struct imsgproc *p) static void proc_callback(struct imsgproc *p, struct imsg *imsg) { + if (imsg != NULL) { + p->m_in.pos = imsg->data; + p->m_in.end = p->m_in.pos + (imsg->hdr.len - sizeof(imsg->hdr)); + } + else { + p->m_in.pos = NULL; + p->m_in.end = NULL; + } + p->cb(p, imsg, p->arg); } @@ -295,15 +319,180 @@ proc_dispatch(int fd, short event, void *arg) proc_event_add(p); } +void +m_compose(struct imsgproc *p, uint32_t type, uint32_t peerid, pid_t pid, int fd, + const void *data, size_t len) +{ + if (imsg_compose(&p->imsgbuf, type, peerid, pid, fd, data, len) == -1) + fatal("%s: imsg_compose", __func__); + + proc_event_add(p); +} + +void +m_create(struct imsgproc *p, uint32_t type, uint32_t peerid, pid_t pid, int fd) +{ + p->m_out.pos = 0; + p->m_out.type = type; + p->m_out.peerid = peerid; + p->m_out.pid = pid; + p->m_out.fd = fd; +} + +void +m_close(struct imsgproc *p) +{ + if (imsg_compose(&p->imsgbuf, p->m_out.type, p->m_out.peerid, + p->m_out.pid, p->m_out.fd, p->m_out.buf, p->m_out.pos) == -1) + fatal("%s: imsg_compose", __func__); + + proc_event_add(p); +} + +void +m_add(struct imsgproc *p, const void *data, size_t len) +{ + size_t alloc; + void *tmp; + + if (p->m_out.pos + len + IMSG_HEADER_SIZE > MAX_IMSGSIZE) + fatalx("%s: message too large", __func__); + + alloc = p->m_out.alloc ? p->m_out.alloc : 128; + while (p->m_out.pos + len > alloc) + alloc *= 2; + if (alloc != p->m_out.alloc) { + tmp = recallocarray(p->m_out.buf, p->m_out.alloc, alloc, 1); + if (tmp == NULL) + fatal("%s: reallocarray", __func__); + p->m_out.alloc = alloc; + p->m_out.buf = tmp; + } + + memmove(p->m_out.buf + p->m_out.pos, data, len); + p->m_out.pos += len; +} + +void +m_add_int(struct imsgproc *p, int v) +{ + m_add(p, &v, sizeof(v)); +}; + +void +m_add_u32(struct imsgproc *p, uint32_t v) +{ + m_add(p, &v, sizeof(v)); +}; + +void +m_add_u64(struct imsgproc *p, uint64_t v) +{ + m_add(p, &v, sizeof(v)); +} + +void +m_add_size(struct imsgproc *p, size_t v) +{ + m_add(p, &v, sizeof(v)); +} + +void +m_add_time(struct imsgproc *p, time_t v) +{ + m_add(p, &v, sizeof(v)); +} + +void +m_add_string(struct imsgproc *p, const char *str) +{ + m_add(p, str, strlen(str) + 1); +} + +void +m_add_sockaddr(struct imsgproc *p, const struct sockaddr *sa) +{ + m_add_size(p, sa->sa_len); + m_add(p, sa, sa->sa_len); +} + +void +m_end(struct imsgproc *p) +{ + if (p->m_in.pos != p->m_in.end) + fatal("%s: %zi bytes left", __func__, + p->m_in.end - p->m_in.pos); +} + int -proc_compose(struct imsgproc *p, int type, uint32_t peerid, pid_t pid, int fd, - void *data, uint16_t datalen) +m_is_eom(struct imsgproc *p) +{ + return (p->m_in.pos == p->m_in.end); +} + +void +m_get(struct imsgproc *p, void *dst, size_t sz) +{ + if (sz > MAX_IMSGSIZE || + p->m_in.end - p->m_in.pos < (ssize_t)sz ) + fatalx("%s: %zu bytes requested, %zi left", __func__, sz, + p->m_in.end - p->m_in.pos); + + memmove(dst, p->m_in.pos, sz); + p->m_in.pos += sz; +} + +void +m_get_int(struct imsgproc *p, int *dst) +{ + m_get(p, dst, sizeof(*dst)); +} + +void +m_get_u32(struct imsgproc *p, uint32_t *dst) +{ + m_get(p, dst, sizeof(*dst)); +} + +void +m_get_u64(struct imsgproc *p, uint64_t *dst) +{ + m_get(p, dst, sizeof(*dst)); +} + +void +m_get_size(struct imsgproc *p, size_t *dst) { - int r; + m_get(p, dst, sizeof(*dst)); +} - r = imsg_compose(&p->imsgbuf, type, peerid, pid, fd, data, datalen); - if (r != -1) - proc_event_add(p); +void +m_get_time(struct imsgproc *p, time_t *dst) +{ + m_get(p, dst, sizeof(*dst)); +} + +void +m_get_string(struct imsgproc *p, const char **dst) +{ + char *end; + + if (p->m_in.pos >= p->m_in.end) + fatalx("%s: no data left", __func__); + + end = memchr(p->m_in.pos, 0, p->m_in.end - p->m_in.pos); + if (end == NULL) + fatalx("%s: unterminated string", __func__); + + *dst = p->m_in.pos; + p->m_in.pos = end + 1; +} + +void +m_get_sockaddr(struct imsgproc *p, struct sockaddr *dst) +{ + size_t len; - return r; + m_get_size(p, &len); + m_get(p, dst, len); } diff --git a/extras/filters/smtpfd/proc.h b/extras/filters/smtpfd/proc.h index 362a822..bf0f19d 100644 --- a/extras/filters/smtpfd/proc.h +++ b/extras/filters/smtpfd/proc.h @@ -32,5 +32,26 @@ void proc_settitle(struct imsgproc *, const char *); void proc_setinstance(struct imsgproc *, int); void proc_setcallback(struct imsgproc *, void(*)(struct imsgproc *, struct imsg *, void *), void *); -int proc_compose(struct imsgproc *, int, uint32_t, pid_t, int, void *, - uint16_t); + +void m_compose(struct imsgproc *, uint32_t, uint32_t, pid_t, int, const void *, + size_t); +void m_create(struct imsgproc *, uint32_t, uint32_t, pid_t, int); +void m_close(struct imsgproc *); +void m_add(struct imsgproc *, const void *, size_t); +void m_add_int(struct imsgproc *, int); +void m_add_u32(struct imsgproc *, uint32_t); +void m_add_u64(struct imsgproc *, uint64_t); +void m_add_size(struct imsgproc *, size_t); +void m_add_time(struct imsgproc *, time_t); +void m_add_string(struct imsgproc *, const char *); +void m_add_sockaddr(struct imsgproc *, const struct sockaddr *); +void m_end(struct imsgproc *); +int m_is_eom(struct imsgproc *); +void m_get(struct imsgproc *, void *, size_t); +void m_get_int(struct imsgproc *, int *); +void m_get_u32(struct imsgproc *, uint32_t *); +void m_get_u64(struct imsgproc *, uint64_t *); +void m_get_size(struct imsgproc *, size_t *); +void m_get_time(struct imsgproc *, time_t *); +void m_get_string(struct imsgproc *, const char **); +void m_get_sockaddr(struct imsgproc *, struct sockaddr *); diff --git a/extras/filters/smtpfd/resolver.c b/extras/filters/smtpfd/resolver.c new file mode 100644 index 0000000..db675e2 --- /dev/null +++ b/extras/filters/smtpfd/resolver.c @@ -0,0 +1,351 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2017 Eric Faurot + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "smtpfd.h" + +#include "log.h" +#include "proc.h" + +struct request { + SPLAY_ENTRY(request) entry; + uint32_t id; + void (*cb_ai)(void *, int, struct addrinfo *); + void (*cb_ni)(void *, int, const char *, const char *); + void *arg; + struct addrinfo *ai; +}; + +struct session { + uint32_t reqid; + struct imsgproc *proc; + char *host; + char *serv; +}; + +SPLAY_HEAD(reqtree, request); + +static void resolver_init(void); +static void resolver_getaddrinfo_cb(struct asr_result *, void *); +static void resolver_getnameinfo_cb(struct asr_result *, void *); + +static int request_cmp(struct request *, struct request *); +SPLAY_PROTOTYPE(reqtree, request, entry, request_cmp); + +static struct reqtree reqs; + +void +resolver_getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, void (*cb)(void *, int, struct addrinfo *), + void *arg) +{ + struct request *req; + + resolver_init(); + + req = calloc(1, sizeof(*req)); + if (req == NULL) { + cb(arg, EAI_MEMORY, NULL); + return; + } + + while (req->id == 0 || SPLAY_FIND(reqtree, &reqs, req)) + req->id = arc4random(); + req->cb_ai = cb; + req->arg = arg; + + m_create(p_engine, IMSG_RES_GETADDRINFO, req->id, 0, -1); + m_add_int(p_engine, hints ? hints->ai_flags : 0); + m_add_int(p_engine, hints ? hints->ai_family : 0); + m_add_int(p_engine, hints ? hints->ai_socktype : 0); + m_add_int(p_engine, hints ? hints->ai_protocol : 0); + m_add_string(p_engine, hostname); + m_add_string(p_engine, servname ? servname : ""); + m_close(p_engine); +} + +void +resolver_getnameinfo(const struct sockaddr *sa, int flags, + void(*cb)(void *, int, const char *, const char *), void *arg) +{ + struct request *req; + + resolver_init(); + + req = calloc(1, sizeof(*req)); + if (req == NULL) { + cb(arg, EAI_MEMORY, NULL, NULL); + return; + } + + while (req->id == 0 || SPLAY_FIND(reqtree, &reqs, req)) + req->id = arc4random(); + req->cb_ni = cb; + req->arg = arg; + + m_create(p_engine, IMSG_RES_GETNAMEINFO, req->id, 0, -1); + m_add_sockaddr(p_engine, sa); + m_add_int(p_engine, flags); + m_close(p_engine); +} + +void +resolver_dispatch_request(struct imsgproc *proc, struct imsg *imsg) +{ + const char *hostname, *servname; + struct session *s; + struct asr_query *q; + struct addrinfo hints; + struct sockaddr_storage ss; + struct sockaddr *sa; + uint32_t reqid; + int flags, save_errno; + + reqid = imsg->hdr.peerid; + + switch (imsg->hdr.type) { + + case IMSG_RES_GETADDRINFO: + servname = NULL; + memset(&hints, 0 , sizeof(hints)); + m_get_int(proc, &hints.ai_flags); + m_get_int(proc, &hints.ai_family); + m_get_int(proc, &hints.ai_socktype); + m_get_int(proc, &hints.ai_protocol); + m_get_string(proc, &hostname); + if (!m_is_eom(proc)) + m_get_string(proc, &servname); + m_end(proc); + + s = NULL; + q = NULL; + if ((s = calloc(1, sizeof(*s))) && + (q = getaddrinfo_async(hostname, servname, &hints, NULL)) && + (event_asr_run(q, resolver_getaddrinfo_cb, s))) { + s->reqid = reqid; + s->proc = proc; + break; + } + save_errno = errno; + + if (q) + asr_abort(q); + if (s) + free(s); + + m_create(proc, IMSG_RES_GETADDRINFO_END, reqid, 0, -1); + m_add_int(proc, EAI_SYSTEM); + m_add_int(proc, save_errno); + m_close(proc); + break; + + case IMSG_RES_GETNAMEINFO: + sa = (struct sockaddr*)&ss; + m_get_sockaddr(proc, sa); + m_get_int(proc, &flags); + m_end(proc); + + s = NULL; + q = NULL; + if ((s = calloc(1, sizeof(*s))) && + (s->host = malloc(NI_MAXHOST)) && + (s->serv = malloc(NI_MAXSERV)) && + (q = getnameinfo_async(sa, sa->sa_len, s->host, NI_MAXHOST, + s->serv, NI_MAXSERV, flags, NULL)) && + (event_asr_run(q, resolver_getnameinfo_cb, s))) { + s->reqid = reqid; + s->proc = proc; + break; + } + save_errno = errno; + + if (q) + asr_abort(q); + if (s) { + free(s->host); + free(s->serv); + free(s); + } + + m_create(proc, IMSG_RES_GETNAMEINFO, reqid, 0, -1); + m_add_int(proc, EAI_SYSTEM); + m_add_int(proc, save_errno); + m_add_string(proc, ""); + m_add_string(proc, ""); + m_close(proc); + break; + + default: + fatalx("%s: %s", __func__, log_fmt_imsgtype(imsg->hdr.type)); + } +} + +void +resolver_dispatch_result(struct imsgproc *proc, struct imsg *imsg) +{ + struct request key, *req; + struct sockaddr_storage ss; + struct addrinfo *ai; + const char *cname, *host, *serv; + int gai_errno; + + key.id = imsg->hdr.peerid; + req = SPLAY_FIND(reqtree, &reqs, &key); + + switch (imsg->hdr.type) { + + case IMSG_RES_GETADDRINFO: + ai = calloc(1, sizeof(*ai)); + if (ai == NULL) { + log_warn("%s: calloc", __func__); + break; + } + m_get_int(proc, &ai->ai_flags); + m_get_int(proc, &ai->ai_family); + m_get_int(proc, &ai->ai_socktype); + m_get_int(proc, &ai->ai_protocol); + m_get_sockaddr(proc, (struct sockaddr *)&ss); + m_get_string(proc, &cname); + m_end(proc); + + ai->ai_addr = malloc(ss.ss_len); + if (ai->ai_addr == NULL) { + log_warn("%s: malloc", __func__); + free(ai); + break; + } + + memmove(ai->ai_addr, &ss, ss.ss_len); + + if (cname[0]) { + ai->ai_canonname = strdup(cname); + if (ai->ai_canonname == NULL) { + log_warn("%s: strdup", __func__); + free(ai->ai_addr); + free(ai); + break; + } + } + + ai->ai_next = req->ai; + req->ai = ai; + break; + + case IMSG_RES_GETADDRINFO_END: + m_get_int(proc, &gai_errno); + m_get_int(proc, &errno); + m_end(proc); + + SPLAY_REMOVE(reqtree, &reqs, req); + req->cb_ai(req->arg, gai_errno, req->ai); + free(req); + break; + + case IMSG_RES_GETNAMEINFO: + m_get_int(proc, &gai_errno); + m_get_int(proc, &errno); + m_get_string(proc, &host); + m_get_string(proc, &serv); + m_end(proc); + + SPLAY_REMOVE(reqtree, &reqs, req); + req->cb_ni(req->arg, gai_errno, host[0] ? host : NULL, + serv[0] ? serv : NULL); + free(req); + break; + } +} + +static void +resolver_init(void) +{ + static int init = 0; + + if (init == 0) { + SPLAY_INIT(&reqs); + init = 1; + } +} + +static void +resolver_getaddrinfo_cb(struct asr_result *ar, void *arg) +{ + struct session *s = arg; + struct addrinfo *ai; + + for (ai = ar->ar_addrinfo; ai; ai = ai->ai_next) { + m_create(s->proc, IMSG_RES_GETADDRINFO, s->reqid, 0, -1); + m_add_int(s->proc, ai->ai_flags); + m_add_int(s->proc, ai->ai_family); + m_add_int(s->proc, ai->ai_socktype); + m_add_int(s->proc, ai->ai_protocol); + m_add_sockaddr(s->proc, ai->ai_addr); + m_add_string(s->proc, ai->ai_canonname ? + ai->ai_canonname : ""); + m_close(s->proc); + } + + m_create(s->proc, IMSG_RES_GETADDRINFO_END, s->reqid, 0, -1); + m_add_int(s->proc, ar->ar_gai_errno); + m_add_int(s->proc, ar->ar_errno); + m_close(s->proc); + + freeaddrinfo(ar->ar_addrinfo); + free(s); +} + +static void +resolver_getnameinfo_cb(struct asr_result *ar, void *arg) +{ + struct session *s = arg; + + m_create(s->proc, IMSG_RES_GETNAMEINFO, s->reqid, 0, -1); + m_add_int(s->proc, ar->ar_gai_errno); + m_add_int(s->proc, ar->ar_errno); + m_add_string(s->proc, s->host ? s->host : ""); + m_add_string(s->proc, s->serv ? s->serv : ""); + m_close(s->proc); + + free(s->host); + free(s->serv); + free(s); +} + +static int +request_cmp(struct request *a, struct request *b) +{ + if (a->id < b->id) + return (-1); + if (a->id > b->id) + return (1); + return (0); +} + +SPLAY_GENERATE(reqtree, request, entry, request_cmp); diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index be5e962..baf741d 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -1,9 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2005 Claudio Jeker - * Copyright (c) 2004 Esben Norby - * Copyright (c) 2003, 2004 Henning Brauer + * Copyright (c) 2017 Eric Faurot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,122 +17,68 @@ */ #include -#include -#include -#include +#include +#include #include #include -#include -#include +#include #include -#include #include -#include +#include #include +#include #include +#include "smtpfd.h" + #include "log.h" #include "proc.h" -#include "smtpfd.h" -#include "control.h" - -__dead static void usage(void); -__dead static void priv_shutdown(void); -static void priv_sig_handler(int, short, void *); -static void priv_dispatch_frontend(struct imsgproc *, struct imsg*, void *); -static void priv_dispatch_engine(struct imsgproc *, struct imsg*, void *); -static int priv_reload(void); -static int priv_send_config(struct smtpfd_conf *); -static void priv_send_filter_proc(struct filter_conf *); -static void priv_send_filter_conf(struct smtpfd_conf *, struct filter_conf *); -static void config_print(struct smtpfd_conf *); - -static char *conffile; -static char *csock; -static struct smtpfd_conf *env; - -/* globals */ -uint32_t cmd_opts; + +struct smtpfd_conf *env; +struct imsgproc *p_control; struct imsgproc *p_engine; struct imsgproc *p_frontend; struct imsgproc *p_priv; -static void -priv_sig_handler(int sig, short event, void *arg) -{ - pid_t pid; - int status; - - /* - * Normal signal handler rules don't apply because libevent - * decouples for us. - */ +static void priv_dispatch_control(struct imsgproc *, struct imsg *, void *); +static void priv_dispatch_engine(struct imsgproc *, struct imsg *, void *); +static void priv_dispatch_frontend(struct imsgproc *, struct imsg *, void *); +static void priv_open_listener(struct listener *); +static void priv_open_filter(struct filter_conf *); +static void priv_send_config(void); +static void priv_sighandler(int, short, void *); +static void priv_shutdown(void); - switch (sig) { - case SIGCHLD: - do { - pid = waitpid(-1, &status, WNOHANG); - if (pid <= 0) - continue; - if (WIFSIGNALED(status)) - log_warnx("process %d terminated by signal %d", - (int)pid, WTERMSIG(status)); - else if (WIFEXITED(status) && WEXITSTATUS(status)) - log_warnx("process %d exited with status %d", - (int)pid, WEXITSTATUS(status)); - else if (WIFEXITED(status)) - log_debug("debug: process %d exited normally", - (int)pid); - else - /* WIFSTOPPED or WIFCONTINUED */ - continue; - } while (pid > 0 || (pid == -1 && errno == EINTR)); - break; - case SIGTERM: - case SIGINT: - priv_shutdown(); - case SIGHUP: - if (priv_reload() == -1) - log_warnx("configuration reload failed"); - else - log_debug("configuration reloaded"); - break; - default: - fatalx("unexpected signal"); - } -} +static char **saved_argv; +static int saved_argc; -__dead static void +static void usage(void) { extern char *__progname; - fprintf(stderr, "usage: %s [-dnv] [-f file] [-s socket]\n", + fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", __progname); exit(1); } int -main(int argc, char *argv[]) +main(int argc, char **argv) { - struct event ev_sigint, ev_sigterm, ev_sighup, ev_sigchld; - int ch, sp[2], rargc = 0; - int debug = 0, engine_flag = 0, frontend_flag = 0; - char *saved_argv0; - char *rargv[7]; + struct listener *l; + struct filter_conf *f; + struct event evt_sigchld, evt_sigint, evt_sigterm, evt_sighup; + const char *conffile = SMTPFD_CONFIG, *reexec = NULL; + int sp[2], ch, debug = 0, nflag = 0, verbose = 0; - conffile = CONF_FILE; - csock = SMTPFD_SOCKET; + saved_argv = argv; + saved_argc = argc; - log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ + log_init(1, LOG_LPR); log_setverbose(1); - saved_argv0 = argv[0]; - if (saved_argv0 == NULL) - saved_argv0 = "smtpfd"; - - while ((ch = getopt(argc, argv, "D:dEFf:ns:v")) != -1) { + while ((ch = getopt(argc, argv, "D:df:nvX:")) != -1) { switch (ch) { case 'D': if (cmdline_symset(optarg) < 0) @@ -144,51 +88,46 @@ main(int argc, char *argv[]) case 'd': debug = 1; break; - case 'E': - engine_flag = 1; - break; - case 'F': - frontend_flag = 1; - break; case 'f': conffile = optarg; break; case 'n': - cmd_opts |= OPT_NOACTION; - break; - case 's': - csock = optarg; + nflag = 1; break; case 'v': - if (cmd_opts & OPT_VERBOSE) - cmd_opts |= OPT_VERBOSE2; - cmd_opts |= OPT_VERBOSE; + verbose++; + break; + case 'X': + reexec = optarg; break; default: usage(); } } - argc -= optind; argv += optind; - if (argc > 0 || (engine_flag && frontend_flag)) + argc -= optind; + + if (argc || *argv) usage(); - if (engine_flag) - engine(debug, cmd_opts & OPT_VERBOSE); - else if (frontend_flag) - frontend(debug, cmd_opts & OPT_VERBOSE, csock); + if (reexec) { + if (!strcmp(reexec, "control")) + control(debug, verbose); + if (!strcmp(reexec, "engine")) + engine(debug, verbose); + if (!strcmp(reexec, "frontend")) + frontend(debug, verbose); + fatalx("unknown process %s", reexec); + } - /* parse config file */ - if ((env = parse_config(conffile)) == NULL) { + /* Parse config file. */ + env = parse_config(conffile, verbose); + if (env == NULL) exit(1); - } - if (cmd_opts & OPT_NOACTION) { - if (cmd_opts & OPT_VERBOSE) - config_print(env); - else - fprintf(stderr, "configuration OK\n"); + if (nflag) { + fprintf(stderr, "configuration OK\n"); exit(0); } @@ -196,299 +135,295 @@ main(int argc, char *argv[]) if (geteuid()) fatalx("need root privileges"); - /* Check for assigned daemon user */ + /* Check for assigned daemon user. */ if (getpwnam(SMTPFD_USER) == NULL) fatalx("unknown user %s", SMTPFD_USER); log_init(debug, LOG_DAEMON); - log_setverbose(cmd_opts & OPT_VERBOSE); - log_procinit("main"); - setproctitle("main"); + log_setverbose(verbose); + log_procinit("priv"); + setproctitle("priv"); if (!debug) - daemon(1, 0); - - log_info("startup"); - - rargc = 0; - rargv[rargc++] = saved_argv0; - rargv[rargc++] = "-F"; - if (debug) - rargv[rargc++] = "-d"; - if (cmd_opts & OPT_VERBOSE) - rargv[rargc++] = "-v"; - rargv[rargc++] = "-s"; - rargv[rargc++] = csock; - rargv[rargc++] = NULL; - - p_frontend = proc_exec(PROC_FRONTEND, rargv); - proc_setcallback(p_frontend, priv_dispatch_frontend, NULL); - rargv[1] = "-E"; - rargv[argc - 3] = NULL; - p_engine = proc_exec(PROC_ENGINE, rargv); - proc_setcallback(p_engine, priv_dispatch_engine, NULL); + if (daemon(1, 0) == -1) + fatal("daemon"); + + log_info("startup"); + + TAILQ_FOREACH(l, &env->listeners, entry) + priv_open_listener(l); + TAILQ_FOREACH(f, &env->filters, entry) + priv_open_filter(f); event_init(); - /* Setup signal handler. */ - signal_set(&ev_sigint, SIGINT, priv_sig_handler, NULL); - signal_set(&ev_sigterm, SIGTERM, priv_sig_handler, NULL); - signal_set(&ev_sighup, SIGHUP, priv_sig_handler, NULL); - signal_set(&ev_sigchld, SIGCHLD, priv_sig_handler, NULL); - signal_add(&ev_sigint, NULL); - signal_add(&ev_sigterm, NULL); - signal_add(&ev_sighup, NULL); - signal_add(&ev_sigchld, NULL); + signal_set(&evt_sigint, SIGINT, priv_sighandler, NULL); + signal_add(&evt_sigint, NULL); + signal_set(&evt_sigterm, SIGTERM, priv_sighandler, NULL); + signal_add(&evt_sigterm, NULL); + signal_set(&evt_sigchld, SIGCHLD, priv_sighandler, NULL); + signal_add(&evt_sigchld, NULL); + signal_set(&evt_sighup, SIGHUP, priv_sighandler, NULL); + signal_add(&evt_sighup, NULL); signal(SIGPIPE, SIG_IGN); - /* Start children */ - proc_enable(p_frontend); + /* Fork and exec unpriviledged processes. */ + argv = calloc(saved_argc + 3, sizeof(*argv)); + if (argv == NULL) + fatal("calloc"); + for (argc = 0; argc < saved_argc; argc++) + argv[argc] = saved_argv[argc]; + argv[argc++] = "-X"; + argv[argc++] = ""; + argv[argc++] = NULL; + + argv[argc - 2] = "control"; + p_control = proc_exec(PROC_CONTROL, argv); + proc_setcallback(p_control, priv_dispatch_control, NULL); + proc_enable(p_control); + + argv[argc - 2] = "engine"; + p_engine = proc_exec(PROC_ENGINE, argv); + proc_setcallback(p_engine, priv_dispatch_engine, NULL); proc_enable(p_engine); - /* Connect the two children */ - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - PF_UNSPEC, sp) == -1) + argv[argc - 2] = "frontend"; + p_frontend = proc_exec(PROC_FRONTEND, argv); + proc_setcallback(p_frontend, priv_dispatch_frontend, NULL); + proc_enable(p_frontend); + + /* Connect processes. */ + if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, PF_UNSPEC, sp) == -1) fatal("socketpair"); - if (proc_compose(p_frontend, IMSG_SOCKET_IPC, 0, 0, sp[0], NULL, 0) - == -1) - fatal("proc_compose"); - if (proc_compose(p_engine, IMSG_SOCKET_IPC, 0, 0, sp[1], NULL, 0) - == -1) - fatal("proc_compose"); + m_compose(p_engine, IMSG_SOCK_FRONTEND, 0, 0, sp[1], NULL, 0); + m_compose(p_frontend, IMSG_SOCK_ENGINE, 0, 0, sp[0], NULL, 0); - priv_send_config(env); + priv_send_config(); - if (pledge("rpath stdio sendfd cpath", NULL) == -1) + if (pledge("stdio sendfd proc", NULL) == -1) fatal("pledge"); event_dispatch(); priv_shutdown(); - return (0); -} -__dead static void -priv_shutdown(void) -{ - pid_t pid; - pid_t frontend_pid; - pid_t engine_pid; - int status; - - frontend_pid = proc_getpid(p_frontend); - engine_pid = proc_getpid(p_frontend); - - /* Close pipes. */ - proc_free(p_frontend); - proc_free(p_engine); - - config_clear(env); - - log_debug("waiting for children to terminate"); - do { - pid = wait(&status); - if (pid == -1) { - if (errno != EINTR && errno != ECHILD) - fatal("wait"); - } else if (WIFSIGNALED(status)) - log_warnx("%s terminated; signal %d", - (pid == engine_pid) ? "engine" : - "frontend", WTERMSIG(status)); - } while (pid != -1 || (pid == -1 && errno == EINTR)); - - control_cleanup(csock); - - log_info("terminating"); - exit(0); + return (0); } static void -priv_dispatch_frontend(struct imsgproc *p, struct imsg *imsg, void *arg) +priv_sighandler(int sig, short ev, void *arg) { - int verbose; - - if (imsg == NULL) { - event_loopexit(NULL); - return; - } + pid_t pid; + int status; - switch (imsg->hdr.type) { - case IMSG_CTL_RELOAD: - if (priv_reload() == -1) - log_warnx("configuration reload failed"); - else - log_warnx("configuration reloaded"); - break; - case IMSG_CTL_LOG_VERBOSE: - /* Already checked by frontend. */ - memcpy(&verbose, imsg->data, sizeof(verbose)); - log_setverbose(verbose); + switch (sig) { + case SIGTERM: + case SIGINT: + event_loopbreak(); break; - case IMSG_CTL_SHOW_MAIN_INFO: - proc_compose(p, IMSG_CTL_END, 0, imsg->hdr.pid, -1, NULL, 0); + case SIGCHLD: + do { + pid = waitpid(-1, &status, WNOHANG); + if (pid <= 0) + continue; + if (WIFSIGNALED(status)) + log_warnx("process %d terminated by signal %d", + (int)pid, WTERMSIG(status)); + else if (WIFEXITED(status) && WEXITSTATUS(status)) + log_warnx("process %d exited with status %d", + (int)pid, WEXITSTATUS(status)); + else if (WIFEXITED(status)) + log_debug("process %d exited normally", + (int)pid); + else + /* WIFSTOPPED or WIFCONTINUED */ + continue; + } while (pid > 0 || (pid == -1 && errno == EINTR)); break; default: - log_debug("%s: error handling imsg %d", __func__, - imsg->hdr.type); - break; + fatalx("signal %d", sig); } } static void -priv_dispatch_engine(struct imsgproc *p, struct imsg *imsg, void *arg) +priv_shutdown(void) { - if (imsg == NULL) { - event_loopexit(NULL); - return; - } + pid_t pid; - switch (imsg->hdr.type) { - default: - log_debug("%s: error handling imsg %d", __func__, - imsg->hdr.type); - break; - } + proc_free(p_control); + proc_free(p_engine); + proc_free(p_frontend); + + do { + pid = waitpid(WAIT_MYPGRP, NULL, 0); + } while (pid != -1 || (pid == -1 && errno == EINTR)); + + log_info("exiting"); + + exit(0); } -static int -priv_reload(void) +static void +priv_open_listener(struct listener *l) { - struct smtpfd_conf *xconf; - - if ((xconf = parse_config(conffile)) == NULL) - return (-1); + struct sockaddr_un *su; + struct sockaddr *sa; + const char *path; + mode_t old_umask; + int opt, sock, r; + + sa = (struct sockaddr *)&l->ss; + + sock = socket(sa->sa_family, SOCK_STREAM | SOCK_NONBLOCK, 0); + if (sock == -1) { + if (errno == EAFNOSUPPORT) { + log_warn("%s: socket", __func__); + return; + } + fatal("%s: socket", __func__); + } - if (priv_send_config(xconf) == -1) - return (-1); + switch (sa->sa_family) { + case AF_LOCAL: + su = (struct sockaddr_un *)sa; + path = su->sun_path; + if (connect(sock, sa, sa->sa_len) == 0) + fatalx("%s already in use", path); - config_clear(env); - env = xconf; + if (unlink(path) == -1) + if (errno != ENOENT) + fatal("unlink: %s", path); - return (0); -} + old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); + r = bind(sock, sa, sizeof(*su)); + (void)umask(old_umask); -static int -priv_send_config(struct smtpfd_conf *xconf) -{ - struct filter_conf *f; + if (r == -1) + fatal("bind: %s", path); + break; - /* Send fixed part of config to engine. */ - if (proc_compose(p_engine, IMSG_RECONF_CONF, 0, 0, -1, NULL, 0) == -1) - return (-1); + case AF_INET: + case AF_INET6: + opt = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, + sizeof(opt)) < 0) + fatal("setsockopt: %s", log_fmt_sockaddr(sa)); - TAILQ_FOREACH(f, &xconf->filters, entry) { - if (f->chain) - continue; - priv_send_filter_proc(f); - } + if (bind(sock, sa, sa->sa_len) == -1) + fatal("bind: %s", log_fmt_sockaddr(sa)); + break; - TAILQ_FOREACH(f, &xconf->filters, entry) { - proc_compose(p_engine, IMSG_RECONF_FILTER, 0, 0, -1, f->name, - strlen(f->name) + 1); - priv_send_filter_conf(xconf, f); + default: + fatalx("bad address family %d", sa->sa_family); } - /* Tell children the revised config is now complete. */ - if (proc_compose(p_engine, IMSG_RECONF_END, 0, 0, -1, NULL, 0) == -1) - return (-1); - - return (0); + l->sock = sock; } static void -priv_send_filter_proc(struct filter_conf *f) +priv_open_filter(struct filter_conf *f) { int sp[2]; pid_t pid; + if (f->chain) + return; + if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, PF_UNSPEC, sp) == -1) - fatal("socketpair"); + fatal("%s: socketpair", __func__); switch (pid = fork()) { case -1: - fatal("fork"); + fatal("%s: fork", __func__); case 0: break; default: close(sp[0]); log_debug("forked filter %s as pid %d", f->name, (int)pid); - proc_compose(p_engine, IMSG_RECONF_FILTER_PROC, 0, pid, sp[1], - f->name, strlen(f->name) + 1); + f->pid = pid; + f->sock = sp[1]; return; } if (dup2(sp[0], 3) == -1) - fatal("dup2"); + fatal("%s: dup2", __func__); if (closefrom(4) == -1) - fatal("closefrom"); + fatal("%s: closefrom", __func__); execvp(f->argv[0], f->argv+1); - fatal("proc_exec: execvp: %s", f->argv[0]); + fatal("%s: execvp: %s", __func__, f->argv[0]); } static void -priv_send_filter_conf(struct smtpfd_conf *conf, struct filter_conf *f) +priv_send_config(void) { - struct filter_conf *tmp; - int i; - - if (f->chain) { - for (i = 0; i < f->argc; i++) { - TAILQ_FOREACH(tmp, &conf->filters, entry) - if (!strcmp(f->argv[i], tmp->name)) { - priv_send_filter_conf(conf, tmp); - break; - } - } - } - else { - proc_compose(p_engine, IMSG_RECONF_FILTER_NODE, 0, 0, -1, + struct listener *l; + struct filter_conf *f; + + m_compose(p_control, IMSG_CONF_START, 0, 0, -1, NULL, 0); + m_compose(p_control, IMSG_CONF_END, 0, 0, -1, NULL, 0); + + m_compose(p_engine, IMSG_CONF_START, 0, 0, -1, NULL, 0); + TAILQ_FOREACH(f, &env->filters, entry) { + if (f->chain) + continue; + m_compose(p_engine, IMSG_CONF_FILTER_PROC, 0, f->pid, f->sock, f->name, strlen(f->name) + 1); } + m_compose(p_engine, IMSG_CONF_END, 0, 0, -1, NULL, 0); + + m_compose(p_frontend, IMSG_CONF_START, 0, 0, -1, NULL, 0); + TAILQ_FOREACH(l, &env->listeners, entry) { + m_create(p_frontend, IMSG_CONF_LISTENER, 0, 0, l->sock); + m_add_int(p_frontend, l->proto); + m_add_sockaddr(p_frontend, (struct sockaddr *)(&l->ss)); + m_close(p_frontend); + } + m_compose(p_frontend, IMSG_CONF_END, 0, 0, -1, NULL, 0); } -struct smtpfd_conf * -config_new_empty(void) +static void +priv_dispatch_control(struct imsgproc *proc, struct imsg *imsg, void *arg) { - struct smtpfd_conf *conf; - - conf = calloc(1, sizeof(*conf)); - if (conf == NULL) - fatal(NULL); + if (imsg == NULL) + fatalx("%s: imsg connection lost", __func__); - TAILQ_INIT(&conf->filters); + log_imsg(proc, imsg); - return (conf); + switch (imsg->hdr.type) { + default: + fatalx("%s: unexpected imsg %s", __func__, + log_fmt_imsgtype(imsg->hdr.type)); + } } -void -config_clear(struct smtpfd_conf *conf) +static void +priv_dispatch_engine(struct imsgproc *proc, struct imsg *imsg, void *arg) { - struct filter_conf *f; - int i; - - while ((f = TAILQ_FIRST(&conf->filters))) { - TAILQ_REMOVE(&conf->filters, f, entry); - free(f->name); - for (i = 0; i < f->argc; i++) - free(f->argv[i]); - free(f); - } + if (imsg == NULL) + fatalx("%s: imsg connection lost", __func__); + + log_imsg(proc, imsg); - free(conf); + switch (imsg->hdr.type) { + default: + fatalx("%s: unexpected imsg %s", __func__, + log_fmt_imsgtype(imsg->hdr.type)); + } } -void -config_print(struct smtpfd_conf *conf) +static void +priv_dispatch_frontend(struct imsgproc *proc, struct imsg *imsg, void *arg) { - struct filter_conf *f; - int i; + if (imsg == NULL) + fatalx("%s: imsg connection lost", __func__); + + log_imsg(proc, imsg); - TAILQ_FOREACH(f, &conf->filters, entry) { - printf("%s %s", f->chain ? "chain":"filter", f->name); - for (i = 0; i < f->argc; i++) - printf(" %s", f->argv[i]); - printf("\n"); + switch (imsg->hdr.type) { + default: + fatalx("%s: unexpected imsg %s", __func__, + log_fmt_imsgtype(imsg->hdr.type)); } } diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 5ab0888..3125f63 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -1,8 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2004 Esben Norby - * Copyright (c) 2003, 2004 Henning Brauer + * Copyright (c) 2017 Eric Faurot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,33 +16,43 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define CONF_FILE "/etc/mail/smtpfd.conf" -#define SMTPFD_SOCKET "/var/run/smtpfd.sock" -#define SMTPFD_USER "_smtpfd" +#include +#include +#include +#include +#include + +#include +#include +#include +#include -#define SMTPFD_MAXFILTERARG 32 +#define PORT_SMTPF 2626 -#define OPT_VERBOSE 0x00000001 -#define OPT_VERBOSE2 0x00000002 -#define OPT_NOACTION 0x00000004 +#define SMTPFD_CONFIG "/etc/mail/smtpfd.conf" +#define SMTPFD_SOCKET "/var/run/smtpfd.sock" +#define SMTPFD_CHROOT "/var/empty" +#define SMTPFD_USER "_smtpfd" -enum imsg_type { +#define SMTPFD_MAXFILTERARG 32 + +enum { IMSG_NONE, - IMSG_CTL_LOG_VERBOSE, - IMSG_CTL_RELOAD, - IMSG_CTL_SHOW_ENGINE_INFO, - IMSG_CTL_SHOW_FRONTEND_INFO, - IMSG_CTL_SHOW_MAIN_INFO, - IMSG_CTL_END, - IMSG_RECONF_CONF, - IMSG_RECONF_FILTER_PROC, - IMSG_RECONF_FILTER, - IMSG_RECONF_FILTER_NODE, - IMSG_RECONF_END, - IMSG_SOCKET_IPC + + IMSG_SOCK_ENGINE, + IMSG_SOCK_FRONTEND, + + IMSG_CONF_START, + IMSG_CONF_FILTER_PROC, + IMSG_CONF_LISTENER, + IMSG_CONF_END, + + IMSG_RES_GETADDRINFO, + IMSG_RES_GETADDRINFO_END, + IMSG_RES_GETNAMEINFO }; -enum smtpfd_process { +enum { PROC_CLIENT, PROC_CONTROL, PROC_ENGINE, @@ -52,34 +61,79 @@ enum smtpfd_process { PROC_PRIV }; +enum { + PROTO_NONE = 0, + PROTO_SMTPF +}; + +struct listener { + int sock; + int proto; + struct sockaddr_storage ss; + struct timeval timeout; + struct event ev; + TAILQ_ENTRY(listener) entry; +}; + struct filter_conf { TAILQ_ENTRY(filter_conf) entry; char *name; int chain; int argc; char *argv[SMTPFD_MAXFILTERARG + 1]; + pid_t pid; + int sock; }; struct smtpfd_conf { - TAILQ_HEAD(, filter_conf) filters; + TAILQ_HEAD(, listener) listeners; + TAILQ_HEAD(, filter_conf) filters; }; -extern uint32_t cmd_opts; +struct io; +struct imsgproc; + +extern struct smtpfd_conf *env; +extern struct imsgproc *p_control; extern struct imsgproc *p_engine; extern struct imsgproc *p_frontend; extern struct imsgproc *p_priv; +/* control.c */ +void control(int, int); /* engine.c */ void engine(int, int); /* frontend.c */ -void frontend(int, int, char *); +void frontend(int, int); +void frontend_conn_closed(uint32_t); + +/* frontend_smtpf.c */ +void frontend_smtpf_init(void); +void frontend_smtpf_conn(uint32_t, struct listener *, int, + const struct sockaddr *); + +/* logmsg.c */ +const char *log_fmt_proto(int); +const char *log_fmt_imsgtype(int); +const char *log_fmt_proctype(int); +const char *log_fmt_sockaddr(const struct sockaddr *); +void log_imsg(struct imsgproc *, struct imsg *); +void log_io(const char *, struct io *, int); + +/* parse.y */ +struct smtpfd_conf *parse_config(const char *, int); +int cmdline_symset(char *); + +/* resolver.c */ +void resolver_getaddrinfo(const char *, const char *, const struct addrinfo *, + void(*)(void *, int, struct addrinfo*), void *); +void resolver_getnameinfo(const struct sockaddr *, int, + void(*)(void *, int, const char *, const char *), void *); +void resolver_dispatch_request(struct imsgproc *, struct imsg *); +void resolver_dispatch_result(struct imsgproc *, struct imsg *); /* smtpfd.c */ struct smtpfd_conf *config_new_empty(void); void config_clear(struct smtpfd_conf *); - -/* parse.y */ -struct smtpfd_conf *parse_config(char *); -int cmdline_symset(char *); From d4aaaf1ad0326edf055e8053dd89fb90b5c35103 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Wed, 19 Jul 2017 22:25:19 +0200 Subject: [PATCH 36/41] more work on smtpfd --- extras/filters/smtpfd/control.c | 22 +- extras/filters/smtpfd/engine.c | 9 +- extras/filters/smtpfd/frontend.c | 35 ++- extras/filters/smtpfd/frontend_smtpf.c | 281 +++++++++++++++++++++++++ extras/filters/smtpfd/io.c | 220 +++++++------------ extras/filters/smtpfd/io.h | 4 +- extras/filters/smtpfd/logmsg.c | 12 +- extras/filters/smtpfd/smtpfd.c | 13 +- extras/filters/smtpfd/smtpfd.h | 6 +- 9 files changed, 413 insertions(+), 189 deletions(-) create mode 100644 extras/filters/smtpfd/frontend_smtpf.c diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c index 181524f..9e11210 100644 --- a/extras/filters/smtpfd/control.c +++ b/extras/filters/smtpfd/control.c @@ -161,7 +161,7 @@ control_accept(int listenfd, short event, void *bula) int connfd; socklen_t len; struct sockaddr_un sun; - struct imsgproc *p; + struct imsgproc *proc; event_add(&control_state.ev, NULL); if ((event & EV_TIMEOUT)) @@ -185,15 +185,15 @@ control_accept(int listenfd, short event, void *bula) return; } - p = proc_attach(PROC_CLIENT, connfd); - proc_setcallback(p, control_dispatch_client, NULL); - proc_enable(p); + proc = proc_attach(PROC_CLIENT, connfd); + proc_setcallback(proc, control_dispatch_client, NULL); + proc_enable(proc); } static void -control_close(struct imsgproc *p) +control_close(struct imsgproc *proc) { - proc_free(p); + proc_free(proc); /* Some file descriptors are available again. */ if (evtimer_pending(&control_state.evt, NULL)) { @@ -211,6 +211,9 @@ control_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg) return; } + if (log_getverbose() > LOGLEVEL_IMSG) + log_imsg(proc, imsg); + switch (imsg->hdr.type) { case IMSG_CONF_START: m_end(proc); @@ -228,13 +231,16 @@ control_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg) } static void -control_dispatch_client(struct imsgproc *p, struct imsg *imsg, void *arg) +control_dispatch_client(struct imsgproc *proc, struct imsg *imsg, void *arg) { if (imsg == NULL) { - control_close(p); + control_close(proc); return; } + if (log_getverbose() > LOGLEVEL_IMSG) + log_imsg(proc, imsg); + switch (imsg->hdr.type) { default: log_debug("%s: error handling imsg %d", __func__, diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index f8d2fa6..0f17683 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -113,7 +113,8 @@ engine_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg) return; } - log_imsg(proc, imsg); + if (log_getverbose() > LOGLEVEL_IMSG) + log_imsg(proc, imsg); switch (imsg->hdr.type) { case IMSG_SOCK_FRONTEND: @@ -171,7 +172,8 @@ engine_dispatch_frontend(struct imsgproc *proc, struct imsg *imsg, void *arg) return; } - log_imsg(proc, imsg); + if (log_getverbose() > LOGLEVEL_IMSG) + log_imsg(proc, imsg); switch (imsg->hdr.type) { case IMSG_RES_GETADDRINFO: @@ -194,7 +196,8 @@ engine_dispatch_filter(struct imsgproc *proc, struct imsg *imsg, void *arg) return; } - log_imsg(proc, imsg); + if (log_getverbose() > LOGLEVEL_IMSG) + log_imsg(proc, imsg); return; diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 447e718..7e75ce8 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -116,10 +116,16 @@ frontend_conn_closed(uint32_t connid) key.id = connid; conn = SPLAY_FIND(conntree, &conns, &key); - if (conn) { - SPLAY_REMOVE(conntree, &conns, conn); - free(conn); - } + if (conn == NULL) + fatalx("%s: %08x unknown connid", __func__, connid); + + if (log_getverbose() > LOGLEVEL_CONN) + log_debug("%08x close %s %s", conn->id, + log_fmt_proto(conn->listener->proto), + log_fmt_sockaddr((struct sockaddr*)&conn->ss)); + + SPLAY_REMOVE(conntree, &conns, conn); + free(conn); } static void @@ -138,8 +144,9 @@ frontend_shutdown() static void frontend_listen(struct listener *l) { - log_debug("conn listen proto=%s sockaddr=%s", log_fmt_proto(l->proto), - log_fmt_sockaddr((struct sockaddr*)&l->ss)); + if (log_getverbose() > LOGLEVEL_CONN) + log_debug("listen %s %s", log_fmt_proto(l->proto), + log_fmt_sockaddr((struct sockaddr*)&l->ss)); if (listen(l->sock, 5) == -1) fatal("%s: listen", __func__); @@ -152,7 +159,6 @@ static void frontend_accept(int sock, short ev, void *arg) { struct listener *l = arg; - struct sockaddr_storage ss; struct sockaddr *sa; struct timeval tv; struct conn *conn; @@ -165,7 +171,7 @@ frontend_accept(int sock, short ev, void *arg) len = 0; } else { - sa = (struct sockaddr *)&ss; + sa = (struct sockaddr *)&conn->ss; len = sizeof(conn->ss); } @@ -194,6 +200,11 @@ frontend_accept(int sock, short ev, void *arg) SPLAY_INSERT(conntree, &conns, conn); conn->listener = l; + if (log_getverbose() > LOGLEVEL_CONN) + log_debug("%08x accept %s %s", conn->id, + log_fmt_proto(conn->listener->proto), + log_fmt_sockaddr((struct sockaddr*)&conn->ss)); + switch (l->proto) { case PROTO_SMTPF: frontend_smtpf_conn(conn->id, l, sock, sa); @@ -223,7 +234,8 @@ frontend_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg) return; } - log_imsg(proc, imsg); + if (log_getverbose() > LOGLEVEL_IMSG) + log_imsg(proc, imsg); switch (imsg->hdr.type) { case IMSG_SOCK_ENGINE: @@ -248,7 +260,7 @@ frontend_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg) if ((l = calloc(1, sizeof(*l))) == NULL) fatal("%s: calloc", __func__); m_get_int(proc, &l->proto); - m_get_sockaddr(proc, (struct sockaddr *)(&l->ss)); + m_get_sockaddr(proc, (struct sockaddr *)&l->ss); m_end(proc); l->sock = imsg->fd; TAILQ_INSERT_TAIL(&tmpconf->listeners, l, entry); @@ -276,7 +288,8 @@ frontend_dispatch_engine(struct imsgproc *proc, struct imsg *imsg, void *arg) return; } - log_imsg(proc, imsg); + if (log_getverbose() > LOGLEVEL_IMSG) + log_imsg(proc, imsg); switch (imsg->hdr.type) { case IMSG_RES_GETADDRINFO: diff --git a/extras/filters/smtpfd/frontend_smtpf.c b/extras/filters/smtpfd/frontend_smtpf.c new file mode 100644 index 0000000..1b9a68b --- /dev/null +++ b/extras/filters/smtpfd/frontend_smtpf.c @@ -0,0 +1,281 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2017 Eric Faurot + * + * 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 +#include +#include + +#include "smtpfd.h" + +#include "io.h" +#include "log.h" + +#define SMTPF_LINEMAX 4096 +#define SMTPF_MAXSESSIONNAME 32 + +struct smtpf_session { + SPLAY_ENTRY(smtpf_session) entry; + char name[SMTPF_MAXSESSIONNAME]; +}; + +SPLAY_HEAD(sessiontree, smtpf_session); + +struct smtpf_client { + uint32_t id; + struct io *io; + struct sessiontree sessions; + struct smtpf_session *last; +}; + +static void smtpf_close(struct smtpf_client *); +static void smtpf_dispatch_io(struct io *, int, void *); +static void smtpf_process_line(struct smtpf_client *, char *); +static void smtpf_session_open(struct smtpf_client *, const char *); +static void smtpf_session_close(struct smtpf_client *, const char *); +static void smtpf_session_line(struct smtpf_client *, const char *, const char *); +static struct smtpf_session *smtpf_session_find(struct smtpf_client *, const char *); +static int smtpf_session_cmp(struct smtpf_session *, struct smtpf_session *); +SPLAY_PROTOTYPE(sessiontree, smtpf_session, entry, smtpf_session_cmp); + +void +frontend_smtpf_init(void) +{ +} + +void +frontend_smtpf_conn(uint32_t connid, struct listener *l, int sock, + const struct sockaddr *sa) +{ + struct smtpf_client *clt; + + if ((clt = calloc(1, sizeof(*clt))) == NULL) { + log_warn("%s: calloc", __func__); + close(sock); + frontend_conn_closed(connid); + return; + } + clt->id = connid; + clt->io = io_new(); + if (clt->io == NULL) { + close(sock); + free(clt); + frontend_conn_closed(connid); + return; + } + io_set_callback(clt->io, smtpf_dispatch_io, clt); + io_attach(clt->io, sock); +} + +static void +smtpf_close(struct smtpf_client *clt) +{ + struct smtpf_session *s; + uint32_t connid; + + while ((s = SPLAY_ROOT(&clt->sessions))) { + SPLAY_REMOVE(sessiontree, &clt->sessions, s); + free(s); + } + + connid = clt->id; + io_free(clt->io); + free(clt); + + frontend_conn_closed(connid); +} + +static void +smtpf_dispatch_io(struct io *io, int evt, void *arg) +{ + struct smtpf_client *clt = arg; + char *line; + + switch (evt) { + case IO_CONNECTED: + case IO_TLSREADY: + case IO_TLSERROR: + break; + + case IO_DATAIN: + while ((line = io_getline(clt->io, NULL))) + smtpf_process_line(clt, line); + + if (io_datalen(clt->io) > SMTPF_LINEMAX) { + log_warnx("%s: line too long", __func__); + break; + } + return; + + case IO_LOWAT: + return; + + case IO_DISCONNECTED: + log_debug("%08x disconnected", clt->id); + break; + + case IO_TIMEOUT: + log_debug("%08x timeout", clt->id); + break; + + case IO_ERROR: + log_warnx("%08x io error: %s", clt->id, io_error(io)); + break; + + default: + fatalx("%s: unexpected event %d", __func__, evt); + } + + smtpf_close(clt); +} + +static void +smtpf_process_line(struct smtpf_client *clt, char *line) +{ + #define MAXARGS 8 + char *cmd, *name, *data, *last, *args[MAXARGS], *p; + int i = 0; + + if ((name = strchr(line, ':')) == NULL) { + log_warnx("%s: invalid line \"%s\"", __func__, line); + return; + } + if ((data = strchr(name + 1, ':')) == NULL) { + log_warnx("%s: invalid session name \"%s\"", __func__, name+1); + return; + } + cmd = line; + *name++ = '\0'; + *data++ = '\0'; + + if (!strcmp(cmd, "SMTP")) { + smtpf_session_line(clt, name, data); + } + else if (!strcmp(cmd, "SMTPF")) { + for (p = strtok_r(data, " ", &last); p; p = strtok_r(NULL, " ", &last)) { + if (i >= MAXARGS) { + log_warnx("%s: too many args", __func__); + return; + } + args[i++] = p; + } + args[i] = NULL; + + if (i != 1) { + log_warnx("%s: no command (%d)", __func__, i); + return; + } + + if (!strcmp(args[0], "OPEN")) + smtpf_session_open(clt, name); + else if (!strcmp(args[0], "CLOSE")) + smtpf_session_close(clt, name); + } + else + log_warn("%s: invalid command \"%s\"", __func__, line); +} + +static struct smtpf_session * +smtpf_session_find(struct smtpf_client *clt, const char *name) +{ + struct smtpf_session key, *s; + + if (clt->last && !(strcmp(name, clt->last->name))) + return clt->last; + + if (strlcpy(key.name, name, sizeof(key.name)) >= sizeof(key.name)) { + log_warnx("%s: name too long", __func__); + return NULL; + } + + s = SPLAY_FIND(sessiontree, &clt->sessions, &key); + if (s == NULL) + return NULL; + + clt->last = s; + return clt->last; + +} + +static void +smtpf_session_open(struct smtpf_client *clt, const char *name) +{ + struct smtpf_session *s; + + s = calloc(1, sizeof(*s)); + if (s == NULL) { + log_warn("%s: calloc", __func__); + goto fail; + } + + if (strlcpy(s->name, name, sizeof(s->name)) >= sizeof(s->name)) { + log_warnx("%s: name too long", __func__); + free(s); + goto fail; + } + + if (smtpf_session_find(clt, name)) { + log_warnx("%s: duplicate token", __func__); + free(s); + goto fail; + } + + SPLAY_INSERT(sessiontree, &clt->sessions, s); + clt->last = s; + io_printf(clt->io, "SMTPF:%s:OPEN OK\n", name); + return; + fail: + io_printf(clt->io, "SMTPF:%s:OPEN FAILED\n", name); +} + +static void +smtpf_session_close(struct smtpf_client *clt, const char *name) +{ + struct smtpf_session *s; + + s = smtpf_session_find(clt, name); + if (s == NULL) { + log_warnx("%s: session not found", __func__); + return; + } + + SPLAY_REMOVE(sessiontree, &clt->sessions, s); + clt->last = NULL; + free(s); +} + +static void +smtpf_session_line(struct smtpf_client *clt, const char *name, const char *line) +{ + struct smtpf_session *s; + + s = smtpf_session_find(clt, name); + if (s == NULL) { + log_warnx("%s: session not found", __func__); + return; + } + + io_printf(clt->io, "SMTP:%s:%s\n", name, line); +} + +static int +smtpf_session_cmp(struct smtpf_session *a, struct smtpf_session *b) +{ + return strcmp(a->name, b->name); +} + +SPLAY_GENERATE(sessiontree, smtpf_session, entry, smtpf_session_cmp); diff --git a/extras/filters/smtpfd/io.c b/extras/filters/smtpfd/io.c index 4fb886f..1f4f16f 100644 --- a/extras/filters/smtpfd/io.c +++ b/extras/filters/smtpfd/io.c @@ -20,11 +20,10 @@ #include #include -#include -#include #include #include #include +#include #include #include #include @@ -42,7 +41,6 @@ enum { IO_STATE_DOWN, IO_STATE_UP, - IO_STATE_RESOLVE, IO_STATE_CONNECT, IO_STATE_CONNECT_TLS, IO_STATE_ACCEPT_TLS @@ -71,12 +69,8 @@ struct io { const char *error; /* only valid immediately on callback */ struct sockaddr *bind; struct addrinfo *ai; /* for connecting */ - struct event_asr *eva; }; -static void fd_set_nonblocking(int); -static void fd_set_nolinger(int); - static const char* io_strflags(int); static const char* io_strevents(short); @@ -88,7 +82,6 @@ static void io_hold(struct io *); static void io_release(struct io *); static void io_callback(struct io*, int); static void io_dispatch(int, short, void *); -static void io_dispatch_getaddrinfo(struct asr_result *, void *); static void io_dispatch_connect(int, short, void *); static int io_connect_next(struct io *); @@ -109,7 +102,6 @@ static int _io_trace = 0; static const char *states[] = { "DOWN", "UP", - "RESOLVE", "CONNECT", "CONNECT_TLS", "ACCEPT_TLS" @@ -197,7 +189,7 @@ io_new(void) void io_free(struct io *io) { - io_debug("io_free(%p)", io); + io_debug("%s(%p)", __func__, io); /* the current io is virtually dead */ if (io == current) @@ -210,8 +202,6 @@ io_free(struct io *io) } #endif - if (io->eva) - event_asr_abort(io->eva); if (io->ai) freeaddrinfo(io->ai); if (event_initialized(&io->ev)) @@ -266,7 +256,7 @@ io_set_bufsize(struct io *io, size_t sz) void io_set_timeout(struct io *io, int msec) { - io_debug("io_set_timeout(%p, %d)", io, msec); + io_debug("%s(%p, %d)", __func__, io, msec); io->timeout = msec; } @@ -274,7 +264,7 @@ io_set_timeout(struct io *io, int msec) void io_set_lowat(struct io *io, size_t lowat) { - io_debug("io_set_lowat(%p, %zu)", io, lowat); + io_debug("%s(%p, %zu)", __func__, io, lowat); io->lowat = lowat; } @@ -324,57 +314,18 @@ io_close(struct io *io) } int -io_connect(struct io *io, const char *host, const char *port, - const struct addrinfo *hints) -{ - struct addrinfo hints2; - struct asr_query *as; - - if (io->state != IO_STATE_DOWN) { - errno = EISCONN; - return -1; - } - - if (hints) { - hints2 = *hints; - } - else { - memset(&hints2, 0, sizeof(hints2)); - hints2.ai_flags = AI_ADDRCONFIG; - } - - if (hints2.ai_socktype == 0) - hints2.ai_socktype = SOCK_STREAM; - if (hints2.ai_socktype != SOCK_STREAM) { - errno = ESOCKTNOSUPPORT; - return -1; - } - - as = getaddrinfo_async(host, port, &hints2, NULL); - if (as == NULL) - return -1; - - io->eva = event_asr_run(as, io_dispatch_getaddrinfo, io); - if (io->eva == NULL) { - asr_abort(as); - return -1; - } - - io->state = IO_STATE_RESOLVE; - return 0; -} - -int -io_connect_addrinfo(struct io *io, struct addrinfo *ai) +io_connect(struct io *io, struct addrinfo *ai) { if (ai == NULL) { errno = EINVAL; + fatal("%s", __func__); return -1; } if (io->state != IO_STATE_DOWN) { freeaddrinfo(ai); errno = EISCONN; + fatal("%s", __func__); return -1; } @@ -386,6 +337,7 @@ int io_disconnect(struct io *io) { errno = ENOSYS; + fatal("%s", __func__); return -1; } @@ -397,10 +349,10 @@ io_starttls(struct io *io, void *ssl) mode = io->flags & IO_RW; if (mode == 0 || mode == IO_RW) - fatalx("io_starttls: full-duplex or unset"); + fatalx("%s: full-duplex or unset", __func__); if (io->tls) - fatalx("io_starttls: SSL already started"); + fatalx("%s: SSL already started", __func__); io->tls = ssl; if (SSL_set_fd(io->tls, io->sock) == 0) { @@ -428,7 +380,7 @@ io_starttls(struct io *io, void *ssl) void io_pause(struct io *io, int dir) { - io_debug("io_pause(%p, %x)", io, dir); + io_debug("%s(%p, %x)", __func__, io, dir); io->flags |= dir & (IO_IN | IO_OUT); io_reload(io); @@ -437,7 +389,7 @@ io_pause(struct io *io, int dir) void io_resume(struct io *io, int dir) { - io_debug("io_resume(%p, %x)", io, dir); + io_debug("%s(%p, %x)", __func__, io, dir); io->flags &= ~(dir & (IO_IN | IO_OUT)); io_reload(io); @@ -448,11 +400,11 @@ io_set_read(struct io *io) { int mode; - io_debug("io_set_read(%p)", io); + io_debug("%s(%p)", __func__, io); mode = io->flags & IO_RW; if (!(mode == 0 || mode == IO_WRITE)) - fatalx("io_set_read: full-duplex or reading"); + fatalx("%s: full-duplex or reading", __func__); io->flags &= ~IO_RW; io->flags |= IO_READ; @@ -464,11 +416,11 @@ io_set_write(struct io *io) { int mode; - io_debug("io_set_write(%p)", io); + io_debug("%s(%p)", __func__, io); mode = io->flags & IO_RW; if (!(mode == 0 || mode == IO_READ)) - fatalx("io_set_write: full-duplex or writing"); + fatalx("%s: full-duplex or writing", __func__); io->flags &= ~IO_RW; io->flags |= IO_WRITE; @@ -565,30 +517,6 @@ io_drop(struct io *io, size_t sz) return iobuf_drop(&io->iobuf, sz); } -static void -fd_set_nonblocking(int sock) -{ - int flags; - - if ((flags = fcntl(sock, F_GETFL)) == -1) - fatal("fd_set_blocking: fcntl(F_GETFL)"); - - flags |= O_NONBLOCK; - - if (fcntl(sock, F_SETFL, flags) == -1) - fatal("fd_set_blocking: fcntl(F_SETFL)"); -} - -static void -fd_set_nolinger(int sock) -{ - struct linger l; - - memset(&l, 0, sizeof(l)); - if (setsockopt(sock, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1) - fatal("fd_set_linger: setsockopt"); -} - const char* io_strflags(int flags) { @@ -699,7 +627,7 @@ io_reload(struct io *io) } #endif - io_debug("io_reload(%p)", io); + io_debug("%s(%p)", __func__, io); events = 0; if (IO_READING(io) && !(io->flags & IO_PAUSE_IN)) @@ -715,8 +643,8 @@ io_reset(struct io *io, short events, void (*dispatch)(int, short, void*)) { struct timeval tv, *ptv; - io_debug("io_reset(%p, %s, %p) -> %s", - io, io_strevents(events), dispatch, io_strio(io)); + io_debug("%s(%p, %s, %p) -> %s", __func__, io, + io_strevents(events), dispatch, io_strio(io)); /* * Indicate that the event has already been reset so that reload @@ -749,11 +677,11 @@ static void io_frame_enter(const char *where, struct io *io, int ev) { io_debug("io: BEGIN %llu", frame); - io_debug("io_frame_enter(%s, %s, %s)", - where, io_strevents(ev), io_strio(io)); + io_debug("%s(%s, %s, %s)", __func__, where, io_strevents(ev), + io_strio(io)); if (current) - fatalx("io_frame_enter: interleaved frames"); + fatalx("%s: interleaved frames", __func__); current = io; @@ -763,10 +691,10 @@ io_frame_enter(const char *where, struct io *io, int ev) static void io_frame_leave(struct io *io) { - io_debug("io_frame_leave(%llu)", frame); + io_debug("%s(%llu)", __func__, frame); if (current && current != io) - fatalx("io_frame_leave: io mismatch"); + fatalx("%s: io mismatch", __func__); /* The io has been cleared. */ if (current == NULL) @@ -796,10 +724,10 @@ io_frame_leave(struct io *io) static void io_hold(struct io *io) { - io_debug("io_hold(%p)", io); + io_debug("%s(%p)", __func__, io); if (io->flags & IO_HELD) - fatalx("io_hold: already held"); + fatalx("%s: already held", __func__); io->flags &= ~IO_RESET; io->flags |= IO_HELD; @@ -808,10 +736,10 @@ io_hold(struct io *io) static void io_release(struct io *io) { - io_debug("io_release(%p)", io); + io_debug("%s(%p)", __func__, io); if (!(io->flags & IO_HELD)) - fatalx("io_release: not held"); + fatalx("%s: not held", __func__); io->flags &= ~IO_HELD; if (!(io->flags & IO_RESET)) @@ -821,7 +749,7 @@ io_release(struct io *io) static void io_callback(struct io *io, int evt) { - io_debug("io_callback(%s, %s)", io_strio(io), io_strevent(evt)); + io_debug("%s(%s, %s)", __func__, io_strio(io), io_strevent(evt)); io->cb(io, evt, io->arg); } @@ -834,7 +762,7 @@ io_dispatch(int fd, short ev, void *arg) ssize_t n; int saved_errno; - io_frame_enter("io_dispatch", io, ev); + io_frame_enter(__func__, io, ev); if (ev == EV_TIMEOUT) { io_callback(io, IO_TIMEOUT); @@ -848,6 +776,7 @@ io_dispatch(int fd, short ev, void *arg) if (n == IOBUF_CLOSED) io_callback(io, IO_DISCONNECTED); else { + log_warn("%s: iobuf_write", __func__); saved_errno = errno; io->error = strerror(errno); errno = saved_errno; @@ -866,6 +795,7 @@ io_dispatch(int fd, short ev, void *arg) if (n == IOBUF_CLOSED) io_callback(io, IO_DISCONNECTED); else { + log_warn("%s: iobuf_read", __func__); saved_errno = errno; io->error = strerror(errno); errno = saved_errno; @@ -888,7 +818,7 @@ io_dispatch_connect(int fd, short ev, void *arg) socklen_t sl; int r, e; - io_frame_enter("io_dispatch_connect", io, ev); + io_frame_enter(__func__, io, ev); if (ev == EV_TIMEOUT) e = ETIMEDOUT; @@ -896,9 +826,13 @@ io_dispatch_connect(int fd, short ev, void *arg) sl = sizeof(e); r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &e, &sl); if (r == -1) { - log_warn("io_dispatch_connect: getsockopt"); + log_warn("%s: getsockopt", __func__); e = errno; } + else if (e) { + errno = e; + log_warn("%s: (connect)", __func__); + } } if (e == 0) { @@ -907,7 +841,7 @@ io_dispatch_connect(int fd, short ev, void *arg) goto done; } - if (io->ai) { + while (io->ai) { r = io_connect_next(io); if (r == 0) goto done; @@ -923,37 +857,12 @@ io_dispatch_connect(int fd, short ev, void *arg) io_frame_leave(io); } -static void -io_dispatch_getaddrinfo(struct asr_result *ar, void *arg) -{ - struct io *io = arg; - - io_frame_enter("io_dispatch_getaddrinfo", io, 0); - - io->eva = NULL; - - if (ar->ar_gai_errno) { - io->error = gai_strerror(ar->ar_gai_errno); - io->state = IO_STATE_DOWN; - io_callback(io, IO_ERROR); - } - else { - io->ai = ar->ar_addrinfo; - io->state = IO_STATE_CONNECT; - if (io_connect_next(io) == -1) { - io->state = IO_STATE_DOWN; - io_callback(io, IO_ERROR); - } - } - - io_frame_leave(io); -} - static int io_connect_next(struct io *io) { struct addrinfo *ai; - int errno_save; + struct linger l; + int saved_errno; while ((ai = io->ai)) { io->ai = ai->ai_next; @@ -965,21 +874,32 @@ io_connect_next(struct io *io) if (ai == NULL) { errno = ESOCKTNOSUPPORT; + log_warn("%s", __func__); return -1; } - if ((io->sock = socket(ai->ai_family, ai->ai_socktype, 0)) == -1) + if ((io->sock = socket(ai->ai_family, ai->ai_socktype | SOCK_NONBLOCK, + 0)) == -1) { + log_warn("%s: socket", __func__); goto fail; + } - fd_set_nonblocking(io->sock); - fd_set_nolinger(io->sock); + memset(&l, 0, sizeof(l)); + if (setsockopt(io->sock, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1) { + log_warn("%s: setsockopt", __func__); + goto fail; + } - if (io->bind && bind(io->sock, io->bind, io->bind->sa_len) == -1) + if (io->bind && bind(io->sock, io->bind, io->bind->sa_len) == -1) { + log_warn("%s: bind", __func__); goto fail; + } if (connect(io->sock, ai->ai_addr, ai->ai_addr->sa_len) == -1) - if (errno != EINPROGRESS) + if (errno != EINPROGRESS) { + log_warn("%s: connect", __func__); goto fail; + } freeaddrinfo(ai); io->state = IO_STATE_CONNECT; @@ -988,9 +908,9 @@ io_connect_next(struct io *io) fail: if (io->sock != -1) { - errno_save = errno; + saved_errno = errno; close(io->sock); - errno = errno_save; + errno = saved_errno; io->error = strerror(errno); io->sock = -1; } @@ -1025,7 +945,7 @@ io_dispatch_accept_tls(int fd, short event, void *arg) struct io *io = arg; int e, ret; - io_frame_enter("io_dispatch_accept_tls", io, event); + io_frame_enter(__func__, io, event); if (event == EV_TIMEOUT) { io_callback(io, IO_TIMEOUT); @@ -1048,7 +968,7 @@ io_dispatch_accept_tls(int fd, short event, void *arg) default: io->error = io_ssl_error(); ssl_error("io_dispatch_accept_tls:SSL_accept"); - io_callback(io, IO_ERROR); + io_callback(io, IO_TLSERROR); break; } @@ -1062,7 +982,7 @@ io_dispatch_connect_tls(int fd, short event, void *arg) struct io *io = arg; int e, ret; - io_frame_enter("io_dispatch_connect_tls", io, event); + io_frame_enter(__func__, io, event); if (event == EV_TIMEOUT) { io_callback(io, IO_TIMEOUT); @@ -1099,7 +1019,7 @@ io_dispatch_read_tls(int fd, short event, void *arg) struct io *io = arg; int n, saved_errno; - io_frame_enter("io_dispatch_read_tls", io, event); + io_frame_enter(__func__, io, event); if (event == EV_TIMEOUT) { io_callback(io, IO_TIMEOUT); @@ -1122,15 +1042,16 @@ io_dispatch_read_tls(int fd, short event, void *arg) saved_errno = errno; io->error = strerror(errno); errno = saved_errno; + log_warn("%s: iobuf_read_ssl", __func__); io_callback(io, IO_ERROR); break; case IOBUF_SSLERROR: io->error = io_ssl_error(); ssl_error("io_dispatch_read_tls:SSL_read"); - io_callback(io, IO_ERROR); + io_callback(io, IO_TLSERROR); break; default: - io_debug("io_dispatch_read_tls(...) -> r=%d", n); + io_debug("%s(...) -> r=%d", __func__, n); io_callback(io, IO_DATAIN); if (current == io && IO_READING(io) && SSL_pending(io->tls)) goto again; @@ -1147,7 +1068,7 @@ io_dispatch_write_tls(int fd, short event, void *arg) size_t w2, w; int n, saved_errno; - io_frame_enter("io_dispatch_write_tls", io, event); + io_frame_enter(__func__, io, event); if (event == EV_TIMEOUT) { io_callback(io, IO_TIMEOUT); @@ -1169,15 +1090,16 @@ io_dispatch_write_tls(int fd, short event, void *arg) saved_errno = errno; io->error = strerror(errno); errno = saved_errno; + log_warn("%s: iobuf_write_ssl", __func__); io_callback(io, IO_ERROR); break; case IOBUF_SSLERROR: io->error = io_ssl_error(); ssl_error("io_dispatch_write_tls:SSL_write"); - io_callback(io, IO_ERROR); + io_callback(io, IO_TLSERROR); break; default: - io_debug("io_dispatch_write_tls(...) -> w=%d", n); + io_debug("%s(...) -> w=%d", __func__, n); w2 = io_queued(io); if (w > io->lowat && w2 <= io->lowat) io_callback(io, IO_LOWAT); @@ -1218,7 +1140,7 @@ io_reload_tls(struct io *io) return; /* paused */ break; default: - fatalx("io_reload_tls: state %d", io->state); + fatalx("%s: unexpected state %d", __func__, io->state); } io_reset(io, ev, dispatch); diff --git a/extras/filters/smtpfd/io.h b/extras/filters/smtpfd/io.h index b4ce4cc..59f7939 100644 --- a/extras/filters/smtpfd/io.h +++ b/extras/filters/smtpfd/io.h @@ -58,9 +58,7 @@ int io_fileno(struct io *); int io_attach(struct io *io, int); int io_detach(struct io *io); int io_close(struct io *io); -int io_connect(struct io *, const char *, const char *, - const struct addrinfo *); -int io_connect_addrinfo(struct io *, struct addrinfo *); +int io_connect(struct io *, struct addrinfo *); int io_disconnect(struct io *io); int io_starttls(struct io *, void *); diff --git a/extras/filters/smtpfd/logmsg.c b/extras/filters/smtpfd/logmsg.c index d3bf3f8..6b3d2db 100644 --- a/extras/filters/smtpfd/logmsg.c +++ b/extras/filters/smtpfd/logmsg.c @@ -125,14 +125,11 @@ log_fmt_sockaddr(const struct sockaddr *sa) void log_imsg(struct imsgproc *proc, struct imsg *imsg) { - if (log_getverbose() < 3) - return; - if (imsg == NULL) - log_debug("imsg from=%s closed", + log_debug("imsg src=%s closed", log_fmt_proctype(proc_gettype(proc))); else - log_debug("imsg from=%s imsg=%s len=%d fd=%d", + log_debug("imsg src=%s type=%s len=%d fd=%d", log_fmt_proctype(proc_gettype(proc)), log_fmt_imsgtype(imsg->hdr.type), imsg->hdr.len, imsg->fd); @@ -141,9 +138,6 @@ log_imsg(struct imsgproc *proc, struct imsg *imsg) void log_io(const char *name, struct io *io, int ev) { - if (log_getverbose() < 4) - return; - - log_debug("io %s event=%s io=%s", name, io_strevent(ev), + log_debug("io %s evt=%s io=%s", name, io_strevent(ev), io_strio(io)); } diff --git a/extras/filters/smtpfd/smtpfd.c b/extras/filters/smtpfd/smtpfd.c index baf741d..03a89fe 100644 --- a/extras/filters/smtpfd/smtpfd.c +++ b/extras/filters/smtpfd/smtpfd.c @@ -70,13 +70,13 @@ main(int argc, char **argv) struct filter_conf *f; struct event evt_sigchld, evt_sigint, evt_sigterm, evt_sighup; const char *conffile = SMTPFD_CONFIG, *reexec = NULL; - int sp[2], ch, debug = 0, nflag = 0, verbose = 0; + int sp[2], ch, debug = 0, nflag = 0, verbose = 1; saved_argv = argv; saved_argc = argc; log_init(1, LOG_LPR); - log_setverbose(1); + log_setverbose(0); while ((ch = getopt(argc, argv, "D:df:nvX:")) != -1) { switch (ch) { @@ -389,7 +389,8 @@ priv_dispatch_control(struct imsgproc *proc, struct imsg *imsg, void *arg) if (imsg == NULL) fatalx("%s: imsg connection lost", __func__); - log_imsg(proc, imsg); + if (log_getverbose() > LOGLEVEL_IMSG) + log_imsg(proc, imsg); switch (imsg->hdr.type) { default: @@ -404,7 +405,8 @@ priv_dispatch_engine(struct imsgproc *proc, struct imsg *imsg, void *arg) if (imsg == NULL) fatalx("%s: imsg connection lost", __func__); - log_imsg(proc, imsg); + if (log_getverbose() > LOGLEVEL_IMSG) + log_imsg(proc, imsg); switch (imsg->hdr.type) { default: @@ -419,7 +421,8 @@ priv_dispatch_frontend(struct imsgproc *proc, struct imsg *imsg, void *arg) if (imsg == NULL) fatalx("%s: imsg connection lost", __func__); - log_imsg(proc, imsg); + if (log_getverbose() > LOGLEVEL_IMSG) + log_imsg(proc, imsg); switch (imsg->hdr.type) { default: diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 3125f63..0b594ce 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -27,7 +27,7 @@ #include #include -#define PORT_SMTPF 2626 +#define PORT_SMTPF 2626 #define SMTPFD_CONFIG "/etc/mail/smtpfd.conf" #define SMTPFD_SOCKET "/var/run/smtpfd.sock" @@ -36,6 +36,10 @@ #define SMTPFD_MAXFILTERARG 32 +#define LOGLEVEL_CONN 2 +#define LOGLEVEL_IMSG 3 +#define LOGLEVEL_IO 4 + enum { IMSG_NONE, From 8d3417bfbae2277b1efccde952bea8469dedad43 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Sat, 22 Jul 2017 23:05:17 +0200 Subject: [PATCH 37/41] tweaks --- extras/filters/smtpfd/control.c | 154 +++++++++++++++---------------- extras/filters/smtpfd/engine.c | 2 + extras/filters/smtpfd/frontend.c | 70 +++++++++----- extras/filters/smtpfd/proc.c | 26 ++++-- extras/filters/smtpfd/resolver.c | 4 + extras/filters/smtpfd/smtpfd.h | 3 +- 6 files changed, 151 insertions(+), 108 deletions(-) diff --git a/extras/filters/smtpfd/control.c b/extras/filters/smtpfd/control.c index 9e11210..f322507 100644 --- a/extras/filters/smtpfd/control.c +++ b/extras/filters/smtpfd/control.c @@ -38,25 +38,27 @@ #define CONTROL_BACKLOG 5 -static int control_init(const char *); -static int control_listen(void); +static void control_init(const char *); +static void control_listen(void); +static void control_pause(void); +static void control_resume(void); static void control_accept(int, short, void *); static void control_close(struct imsgproc *); static void control_dispatch_priv(struct imsgproc *, struct imsg *, void *); static void control_dispatch_client(struct imsgproc *, struct imsg *, void *); static struct { - struct event ev; struct event evt; int fd; -} control_state; + int pause; +} ctl; void control(int debug, int verbose) { struct passwd *pw; - /* Early initialisation */ + /* Early initialisation. */ log_init(debug, LOG_DAEMON); log_setverbose(verbose); log_procinit("control"); @@ -64,7 +66,7 @@ control(int debug, int verbose) control_init(SMTPFD_SOCKET); - /* Drop priviledges */ + /* Drop priviledges. */ if ((pw = getpwnam(SMTPFD_USER)) == NULL) fatalx("unknown user " SMTPFD_USER); @@ -74,17 +76,19 @@ control(int debug, int verbose) fatal("cannot drop privileges"); if (chroot(pw->pw_dir) == 1) - fatal("chroot"); + fatal("%s: chroot", __func__); if (pledge("stdio unix recvfd sendfd", NULL) == -1) - fatal("pledge"); + fatal("%s: pledge", __func__); event_init(); signal(SIGPIPE, SIG_IGN); - /* Setup imsg socket with parent */ + /* Setup imsg socket with parent. */ p_priv = proc_attach(PROC_PRIV, 3); + if (p_priv == NULL) + fatal("%s: proc_attach", __func__); proc_setcallback(p_priv, control_dispatch_priv, NULL); proc_enable(p_priv); @@ -93,99 +97,99 @@ control(int debug, int verbose) exit(0); } -static int +static void control_init(const char *path) { - struct sockaddr_un sun; - int fd; - mode_t old_umask; - - if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - 0)) == -1) { - log_warn("%s: socket", __func__); - return (-1); - } + struct sockaddr_un sun; + mode_t old_umask; + int fd; + + fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + if (fd == -1) + fatal("%s: socket", __func__); memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; strlcpy(sun.sun_path, SMTPFD_SOCKET, sizeof(sun.sun_path)); - if (unlink(path) == -1) - if (errno != ENOENT) { - log_warn("%s: unlink %s", __func__, path); - close(fd); - return (-1); - } + if ((unlink(path) == -1) && (errno != ENOENT)) + fatal("%s: unlink: %s", __func__, path); old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); - if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { - log_warn("%s: bind: %s", __func__, path); - close(fd); - umask(old_umask); - return (-1); - } + if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) + fatal("%s: bind: %s", __func__, path); umask(old_umask); - if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { - log_warn("%s: chmod", __func__); - close(fd); - (void)unlink(path); - return (-1); - } - - control_state.fd = fd; + if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) + fatal("%s: chmod: %s", __func__, path); - return (0); + ctl.fd = fd; } -static int +static void control_listen(void) { + if (listen(ctl.fd, CONTROL_BACKLOG) == -1) + fatal("%s: listen", __func__); - if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { - log_warn("%s: listen", __func__); - return (-1); - } + ctl.pause = 0; + control_resume(); +} + +static void +control_pause(void) +{ + struct timeval tv; - event_set(&control_state.ev, control_state.fd, EV_READ, - control_accept, NULL); - event_add(&control_state.ev, NULL); - evtimer_set(&control_state.evt, control_accept, NULL); + event_del(&ctl.evt); - return (0); + tv.tv_sec = 1; + tv.tv_usec = 0; + + evtimer_set(&ctl.evt, control_accept, NULL); + evtimer_add(&ctl.evt, &tv); + ctl.pause = 1; +} + +static void +control_resume(void) +{ + if (ctl.pause) { + evtimer_del(&ctl.evt); + ctl.pause = 0; + } + event_set(&ctl.evt, ctl.fd, EV_READ | EV_PERSIST, control_accept, NULL); + event_add(&ctl.evt, NULL); } static void -control_accept(int listenfd, short event, void *bula) +control_accept(int fd, short event, void *arg) { - int connfd; - socklen_t len; - struct sockaddr_un sun; - struct imsgproc *proc; + struct imsgproc *proc; + int sock; - event_add(&control_state.ev, NULL); - if ((event & EV_TIMEOUT)) + if (ctl.pause) { + ctl.pause = 0; + control_resume(); return; + } - len = sizeof(sun); - if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len, - SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) { - /* - * Pause accept if we are out of file descriptors, or - * libevent will haunt us here too. - */ - if (errno == ENFILE || errno == EMFILE) { - struct timeval evtpause = { 1, 0 }; - - event_del(&control_state.ev); - evtimer_add(&control_state.evt, &evtpause); - } else if (errno != EWOULDBLOCK && errno != EINTR && + sock = accept4(ctl.fd, NULL, NULL, SOCK_CLOEXEC | SOCK_NONBLOCK); + if (sock == -1) { + if (errno == ENFILE || errno == EMFILE) + control_pause(); + else if (errno != EWOULDBLOCK && errno != EINTR && errno != ECONNABORTED) log_warn("%s: accept4", __func__); return; } - proc = proc_attach(PROC_CLIENT, connfd); + proc = proc_attach(PROC_CLIENT, sock); + if (proc == NULL) { + log_warn("%s: proc_attach", __func__); + close(sock); + return; + } proc_setcallback(proc, control_dispatch_client, NULL); proc_enable(proc); } @@ -195,11 +199,8 @@ control_close(struct imsgproc *proc) { proc_free(proc); - /* Some file descriptors are available again. */ - if (evtimer_pending(&control_state.evt, NULL)) { - evtimer_del(&control_state.evt); - event_add(&control_state.ev, NULL); - } + if (ctl.pause) + control_resume(); } static void @@ -245,6 +246,5 @@ control_dispatch_client(struct imsgproc *proc, struct imsg *imsg, void *arg) default: log_debug("%s: error handling imsg %d", __func__, imsg->hdr.type); - break; } } diff --git a/extras/filters/smtpfd/engine.c b/extras/filters/smtpfd/engine.c index 0f17683..9682ef3 100644 --- a/extras/filters/smtpfd/engine.c +++ b/extras/filters/smtpfd/engine.c @@ -86,6 +86,8 @@ engine(int debug, int verbose) /* Setup imsg socket with parent. */ p_priv = proc_attach(PROC_PRIV, 3); + if (p_priv == NULL) + fatal("%s: proc_attach", __func__); proc_setcallback(p_priv, engine_dispatch_priv, NULL); proc_enable(p_priv); diff --git a/extras/filters/smtpfd/frontend.c b/extras/filters/smtpfd/frontend.c index 7e75ce8..d7b5e60 100644 --- a/extras/filters/smtpfd/frontend.c +++ b/extras/filters/smtpfd/frontend.c @@ -32,8 +32,9 @@ static void frontend_shutdown(void); static void frontend_listen(struct listener *); +static void frontend_pause(struct listener *); +static void frontend_resume(struct listener *); static void frontend_accept(int, short, void *); -static void frontend_resume(int, short, void *); static void frontend_dispatch_priv(struct imsgproc *, struct imsg *, void *); static void frontend_dispatch_engine(struct imsgproc *, struct imsg *, void *); @@ -101,6 +102,8 @@ frontend(int debug, int verbose) /* Setup imsg socket with parent. */ p_priv = proc_attach(PROC_PRIV, 3); + if (p_priv == NULL) + fatal("%s: proc_attach", __func__); proc_setcallback(p_priv, frontend_dispatch_priv, NULL); proc_enable(p_priv); @@ -112,6 +115,7 @@ frontend(int debug, int verbose) void frontend_conn_closed(uint32_t connid) { + struct listener *l; struct conn key, *conn; key.id = connid; @@ -119,13 +123,18 @@ frontend_conn_closed(uint32_t connid) if (conn == NULL) fatalx("%s: %08x unknown connid", __func__, connid); + l = conn->listener; + if (log_getverbose() > LOGLEVEL_CONN) log_debug("%08x close %s %s", conn->id, - log_fmt_proto(conn->listener->proto), + log_fmt_proto(l->proto), log_fmt_sockaddr((struct sockaddr*)&conn->ss)); SPLAY_REMOVE(conntree, &conns, conn); free(conn); + + if (l->pause) + frontend_resume(l); } static void @@ -151,7 +160,32 @@ frontend_listen(struct listener *l) if (listen(l->sock, 5) == -1) fatal("%s: listen", __func__); - event_set(&l->ev, l->sock, EV_READ|EV_PERSIST, frontend_accept, l); + frontend_resume(l); +} + +static void +frontend_pause(struct listener *l) +{ + struct timeval tv; + + event_del(&l->ev); + + tv.tv_sec = 2; + tv.tv_usec = 0; + + evtimer_set(&l->ev, frontend_accept, l); + evtimer_add(&l->ev, &tv); + l->pause = 1; +} + +static void +frontend_resume(struct listener *l) +{ + if (l->pause) { + evtimer_del(&l->ev); + l->pause = 0; + } + event_set(&l->ev, l->sock, EV_READ | EV_PERSIST, frontend_accept, l); event_add(&l->ev, NULL); } @@ -160,10 +194,15 @@ frontend_accept(int sock, short ev, void *arg) { struct listener *l = arg; struct sockaddr *sa; - struct timeval tv; struct conn *conn; socklen_t len; + if (l->pause) { + l->pause = 0; + frontend_resume(l); + return; + } + conn = calloc(1, sizeof(*conn)); if (conn == NULL) { log_warn("%s: calloc", __func__); @@ -177,15 +216,11 @@ frontend_accept(int sock, short ev, void *arg) sock = accept4(sock, sa, &len, SOCK_NONBLOCK); if (sock == -1) { - log_warn("%s: accept4", __func__); - if (errno == ENFILE || errno == EMFILE) { - /* Stop listening for a while. */ - tv.tv_sec = 2; - tv.tv_usec = 0; - event_del(&l->ev); - evtimer_set(&l->ev, frontend_resume, l); - evtimer_add(&l->ev, &tv); - } + if (errno == ENFILE || errno == EMFILE) + frontend_pause(l); + else if (errno != EWOULDBLOCK && errno != EINTR && + errno != ECONNABORTED) + log_warn("%s: accept4", __func__); free(conn); return; } @@ -214,15 +249,6 @@ frontend_accept(int sock, short ev, void *arg) } } -static void -frontend_resume(int sock, short ev, void *arg) -{ - struct listener *l = arg; - - event_set(&l->ev, l->sock, EV_READ|EV_PERSIST, frontend_accept, l); - event_add(&l->ev, NULL); -} - static void frontend_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg) { diff --git a/extras/filters/smtpfd/proc.c b/extras/filters/smtpfd/proc.c index 3784a9a..3c1bfbe 100644 --- a/extras/filters/smtpfd/proc.c +++ b/extras/filters/smtpfd/proc.c @@ -109,15 +109,24 @@ proc_exec(int type, char **argv) pid_t pid; p = proc_new(type); - if (p == NULL) - fatal("%s: proc_new", __func__); + if (p == NULL) { + log_warn("%s: proc_new", __func__); + return NULL; + } - if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, PF_UNSPEC, sp) == -1) - fatal("%s: socketpair", __func__); + if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, PF_UNSPEC, sp) == -1) { + log_warn("%s: socketpair", __func__); + proc_free(p); + return NULL; + } switch (pid = fork()) { case -1: - fatal("%s: fork", __func__); + log_warn("%s: fork", __func__); + close(sp[0]); + close(sp[1]); + proc_free(p); + return NULL; case 0: break; default: @@ -144,7 +153,7 @@ proc_attach(int type, int fd) p = proc_new(type); if (p == NULL) - fatal("%s: proc_new", __func__); + return NULL; proc_setsock(p, fd); return p; @@ -157,7 +166,7 @@ proc_settitle(struct imsgproc *p, const char *title) if (title) { p->title = strdup(title); if (p->title == NULL) - fatal("%s: strdup", __func__); + log_warn("%s: strdup", __func__); } else p->title = NULL; @@ -191,7 +200,8 @@ proc_free(struct imsgproc *p) TAILQ_REMOVE(&procs, p, tqe); - event_del(&p->ev); + if (event_initialized(&p->ev)) + event_del(&p->ev); close(p->imsgbuf.fd); imsg_clear(&p->imsgbuf); free(p->title); diff --git a/extras/filters/smtpfd/resolver.c b/extras/filters/smtpfd/resolver.c index db675e2..c09ce8e 100644 --- a/extras/filters/smtpfd/resolver.c +++ b/extras/filters/smtpfd/resolver.c @@ -81,6 +81,8 @@ resolver_getaddrinfo(const char *hostname, const char *servname, req->cb_ai = cb; req->arg = arg; + SPLAY_INSERT(reqtree, &reqs, req); + m_create(p_engine, IMSG_RES_GETADDRINFO, req->id, 0, -1); m_add_int(p_engine, hints ? hints->ai_flags : 0); m_add_int(p_engine, hints ? hints->ai_family : 0); @@ -218,6 +220,8 @@ resolver_dispatch_result(struct imsgproc *proc, struct imsg *imsg) key.id = imsg->hdr.peerid; req = SPLAY_FIND(reqtree, &reqs, &key); + if (req == NULL) + fatalx("%s: unknown request %08x", __func__, imsg->hdr.peerid); switch (imsg->hdr.type) { diff --git a/extras/filters/smtpfd/smtpfd.h b/extras/filters/smtpfd/smtpfd.h index 0b594ce..3e4afaf 100644 --- a/extras/filters/smtpfd/smtpfd.h +++ b/extras/filters/smtpfd/smtpfd.h @@ -71,12 +71,13 @@ enum { }; struct listener { + TAILQ_ENTRY(listener) entry; int sock; int proto; struct sockaddr_storage ss; struct timeval timeout; struct event ev; - TAILQ_ENTRY(listener) entry; + int pause; }; struct filter_conf { From 85c98eb5c610b6af7b4922b6badb612f1b48402b Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Thu, 27 Jul 2017 18:44:31 +0200 Subject: [PATCH 38/41] consider that a smtpf session has two ends A and B, and simply relay smtp lines between them for now. --- extras/filters/smtpfd/frontend_smtpf.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/extras/filters/smtpfd/frontend_smtpf.c b/extras/filters/smtpfd/frontend_smtpf.c index 1b9a68b..3cbc50c 100644 --- a/extras/filters/smtpfd/frontend_smtpf.c +++ b/extras/filters/smtpfd/frontend_smtpf.c @@ -47,7 +47,7 @@ static void smtpf_dispatch_io(struct io *, int, void *); static void smtpf_process_line(struct smtpf_client *, char *); static void smtpf_session_open(struct smtpf_client *, const char *); static void smtpf_session_close(struct smtpf_client *, const char *); -static void smtpf_session_line(struct smtpf_client *, const char *, const char *); +static void smtpf_session_line(struct smtpf_client *, int, const char *, const char *); static struct smtpf_session *smtpf_session_find(struct smtpf_client *, const char *); static int smtpf_session_cmp(struct smtpf_session *, struct smtpf_session *); SPLAY_PROTOTYPE(sessiontree, smtpf_session, entry, smtpf_session_cmp); @@ -162,8 +162,11 @@ smtpf_process_line(struct smtpf_client *clt, char *line) *name++ = '\0'; *data++ = '\0'; - if (!strcmp(cmd, "SMTP")) { - smtpf_session_line(clt, name, data); + if (!strcmp(cmd, "A")) { + smtpf_session_line(clt, 0, name, data); + } + if (!strcmp(cmd, "B")) { + smtpf_session_line(clt, 1, name, data); } else if (!strcmp(cmd, "SMTPF")) { for (p = strtok_r(data, " ", &last); p; p = strtok_r(NULL, " ", &last)) { @@ -259,7 +262,8 @@ smtpf_session_close(struct smtpf_client *clt, const char *name) } static void -smtpf_session_line(struct smtpf_client *clt, const char *name, const char *line) +smtpf_session_line(struct smtpf_client *clt, int srv, const char *name, + const char *line) { struct smtpf_session *s; @@ -269,7 +273,8 @@ smtpf_session_line(struct smtpf_client *clt, const char *name, const char *line) return; } - io_printf(clt->io, "SMTP:%s:%s\n", name, line); + /* relay between the two ends of the session */ + io_printf(clt->io, "%c:%s:%s\n", srv ? 'A' : 'B', name, line); } static int From 003f0c9d3aa22fe35feb8a91bc6e021403d7e6f0 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Thu, 27 Jul 2017 18:59:00 +0200 Subject: [PATCH 39/41] missing else --- extras/filters/smtpfd/frontend_smtpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/filters/smtpfd/frontend_smtpf.c b/extras/filters/smtpfd/frontend_smtpf.c index 3cbc50c..80d3b30 100644 --- a/extras/filters/smtpfd/frontend_smtpf.c +++ b/extras/filters/smtpfd/frontend_smtpf.c @@ -165,7 +165,7 @@ smtpf_process_line(struct smtpf_client *clt, char *line) if (!strcmp(cmd, "A")) { smtpf_session_line(clt, 0, name, data); } - if (!strcmp(cmd, "B")) { + else if (!strcmp(cmd, "B")) { smtpf_session_line(clt, 1, name, data); } else if (!strcmp(cmd, "SMTPF")) { From 90dd9fa694100b75a11ebae46fe95cda4f1f88c8 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Thu, 27 Jul 2017 22:25:35 +0200 Subject: [PATCH 40/41] add an example of smtpf handling a command directly, instead of forwarding to the server. --- extras/filters/smtpfd/frontend_smtpf.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/extras/filters/smtpfd/frontend_smtpf.c b/extras/filters/smtpfd/frontend_smtpf.c index 80d3b30..9051b5e 100644 --- a/extras/filters/smtpfd/frontend_smtpf.c +++ b/extras/filters/smtpfd/frontend_smtpf.c @@ -273,8 +273,11 @@ smtpf_session_line(struct smtpf_client *clt, int srv, const char *name, return; } - /* relay between the two ends of the session */ - io_printf(clt->io, "%c:%s:%s\n", srv ? 'A' : 'B', name, line); + if (!srv && !strcmp(line, "HAHA")) + io_printf(clt->io, "A:%s:200 Funny!\n", name); + else + /* relay between the two ends of the session */ + io_printf(clt->io, "%c:%s:%s\n", srv ? 'A' : 'B', name, line); } static int From 778dbaab5b6d19aae1132ac2322d742d4bcae985 Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Mon, 9 Jul 2018 15:46:09 +0200 Subject: [PATCH 41/41] Add traces and a simple filtering PoC. --- extras/filters/smtpfd/frontend_smtpf.c | 48 ++++++++++++++++++-------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/extras/filters/smtpfd/frontend_smtpf.c b/extras/filters/smtpfd/frontend_smtpf.c index 9051b5e..aeddf63 100644 --- a/extras/filters/smtpfd/frontend_smtpf.c +++ b/extras/filters/smtpfd/frontend_smtpf.c @@ -45,8 +45,8 @@ struct smtpf_client { static void smtpf_close(struct smtpf_client *); static void smtpf_dispatch_io(struct io *, int, void *); static void smtpf_process_line(struct smtpf_client *, char *); -static void smtpf_session_open(struct smtpf_client *, const char *); -static void smtpf_session_close(struct smtpf_client *, const char *); +static void smtpf_session_open(struct smtpf_client *, const char *, int, char **); +static void smtpf_session_close(struct smtpf_client *, const char *, int, char **); static void smtpf_session_line(struct smtpf_client *, int, const char *, const char *); static struct smtpf_session *smtpf_session_find(struct smtpf_client *, const char *); static int smtpf_session_cmp(struct smtpf_session *, struct smtpf_session *); @@ -79,6 +79,8 @@ frontend_smtpf_conn(uint32_t connid, struct listener *l, int sock, } io_set_callback(clt->io, smtpf_dispatch_io, clt); io_attach(clt->io, sock); + + log_debug("%08x:newconn", clt->id); } static void @@ -87,6 +89,8 @@ smtpf_close(struct smtpf_client *clt) struct smtpf_session *s; uint32_t connid; + log_debug("%08x:close", clt->id); + while ((s = SPLAY_ROOT(&clt->sessions))) { SPLAY_REMOVE(sessiontree, &clt->sessions, s); free(s); @@ -150,6 +154,8 @@ smtpf_process_line(struct smtpf_client *clt, char *line) char *cmd, *name, *data, *last, *args[MAXARGS], *p; int i = 0; + log_debug("%08x >>> %s", clt->id, line); + if ((name = strchr(line, ':')) == NULL) { log_warnx("%s: invalid line \"%s\"", __func__, line); return; @@ -178,15 +184,10 @@ smtpf_process_line(struct smtpf_client *clt, char *line) } args[i] = NULL; - if (i != 1) { - log_warnx("%s: no command (%d)", __func__, i); - return; - } - if (!strcmp(args[0], "OPEN")) - smtpf_session_open(clt, name); + smtpf_session_open(clt, name, i - 1, &args[1]); else if (!strcmp(args[0], "CLOSE")) - smtpf_session_close(clt, name); + smtpf_session_close(clt, name, i - 1, &args[1]); } else log_warn("%s: invalid command \"%s\"", __func__, line); @@ -215,7 +216,7 @@ smtpf_session_find(struct smtpf_client *clt, const char *name) } static void -smtpf_session_open(struct smtpf_client *clt, const char *name) +smtpf_session_open(struct smtpf_client *clt, const char *name, int argc, char **argv) { struct smtpf_session *s; @@ -240,22 +241,29 @@ smtpf_session_open(struct smtpf_client *clt, const char *name) SPLAY_INSERT(sessiontree, &clt->sessions, s); clt->last = s; io_printf(clt->io, "SMTPF:%s:OPEN OK\n", name); + log_debug("%08x <<< SMTPF:%s:OPEN OK", clt->id, name); return; fail: io_printf(clt->io, "SMTPF:%s:OPEN FAILED\n", name); + log_debug("%08x <<< SMTPF:%s:OPEN FAILED", clt->id, name); } static void -smtpf_session_close(struct smtpf_client *clt, const char *name) +smtpf_session_close(struct smtpf_client *clt, const char *name, int argc, char **argv) { struct smtpf_session *s; s = smtpf_session_find(clt, name); if (s == NULL) { log_warnx("%s: session not found", __func__); + io_printf(clt->io, "SMTPF:%s:CLOSE NOT_FOUND\n", name); + log_debug("%08x <<< SMTPF:%s:CLOSE NOT_FOUND", clt->id, name); return; } + io_printf(clt->io, "SMTPF:%s:CLOSE OK\n", name); + log_debug("%08x <<< SMTPF:%s:CLOSE OK", clt->id, name); + SPLAY_REMOVE(sessiontree, &clt->sessions, s); clt->last = NULL; free(s); @@ -266,6 +274,7 @@ smtpf_session_line(struct smtpf_client *clt, int srv, const char *name, const char *line) { struct smtpf_session *s; + char *buf, *p; s = smtpf_session_find(clt, name); if (s == NULL) { @@ -273,11 +282,20 @@ smtpf_session_line(struct smtpf_client *clt, int srv, const char *name, return; } - if (!srv && !strcmp(line, "HAHA")) - io_printf(clt->io, "A:%s:200 Funny!\n", name); - else + if (!srv && !strcmp(line, "HAHA")) { + io_printf(clt->io, "A:%s:200 (from smtpfd) %s\n", name, line + 2); + log_debug("%08x <<< A:%s:200 (from smtpfd) %s", clt->id, name, line + 2); + } + else { /* relay between the two ends of the session */ - io_printf(clt->io, "%c:%s:%s\n", srv ? 'A' : 'B', name, line); + buf = strdup(line); + for (p = buf; *p; p++) + if (*p == 'z') + *p = 'x'; + io_printf(clt->io, "%c:%s:%s\n", srv ? 'A' : 'B', name, buf); + log_debug("%08x <<< %c:%s:%s", clt->id, srv ? 'A' : 'B', name, buf); + free(buf); + } } static int