diff options
author | Gilles Chehade <gilles@cvs.openbsd.org> | 2018-11-01 10:13:26 +0000 |
---|---|---|
committer | Gilles Chehade <gilles@cvs.openbsd.org> | 2018-11-01 10:13:26 +0000 |
commit | d997c59f310385d16d9f257bbcb311a26f51ccf2 (patch) | |
tree | 90a33525969cf0a42e346de904f3dc7489273c29 /usr.sbin/smtpd | |
parent | b470850cbf610d8e60b6d6326dd2d94a81b155c2 (diff) |
allow smtpd to fork processes at startup and maintain a socketpair with
them.
ok jung@, eric@
Diffstat (limited to 'usr.sbin/smtpd')
-rw-r--r-- | usr.sbin/smtpd/config.c | 6 | ||||
-rw-r--r-- | usr.sbin/smtpd/lka.c | 13 | ||||
-rw-r--r-- | usr.sbin/smtpd/lka_proc.c | 88 | ||||
-rw-r--r-- | usr.sbin/smtpd/parse.y | 63 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.c | 103 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 19 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd/Makefile | 3 |
7 files changed, 284 insertions, 11 deletions
diff --git a/usr.sbin/smtpd/config.c b/usr.sbin/smtpd/config.c index 88d78d30eeb..1d148f9c61b 100644 --- a/usr.sbin/smtpd/config.c +++ b/usr.sbin/smtpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.42 2018/07/03 01:34:43 mortimer Exp $ */ +/* $OpenBSD: config.c,v 1.43 2018/11/01 10:13:25 gilles Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -88,6 +88,7 @@ config_default(void) conf->sc_ssl_dict = calloc(1, sizeof(*conf->sc_ssl_dict)); conf->sc_limits_dict = calloc(1, sizeof(*conf->sc_limits_dict)); conf->sc_mda_wrappers = calloc(1, sizeof(*conf->sc_mda_wrappers)); + conf->sc_processors_dict = calloc(1, sizeof(*conf->sc_processors_dict)); conf->sc_dispatcher_bounce = calloc(1, sizeof(*conf->sc_dispatcher_bounce)); limits = calloc(1, sizeof(*limits)); @@ -100,6 +101,7 @@ config_default(void) conf->sc_ssl_dict == NULL || conf->sc_limits_dict == NULL || conf->sc_mda_wrappers == NULL || + conf->sc_processors_dict == NULL || conf->sc_dispatcher_bounce == NULL || limits == NULL) goto error; @@ -111,6 +113,7 @@ config_default(void) dict_init(conf->sc_ssl_dict); dict_init(conf->sc_tables_dict); dict_init(conf->sc_limits_dict); + dict_init(conf->sc_processors_dict); limit_mta_set_defaults(limits); @@ -149,6 +152,7 @@ error: free(conf->sc_ssl_dict); free(conf->sc_limits_dict); free(conf->sc_mda_wrappers); + free(conf->sc_processors_dict); free(conf->sc_dispatcher_bounce); free(limits); free(conf); diff --git a/usr.sbin/smtpd/lka.c b/usr.sbin/smtpd/lka.c index 8f67210f935..e763e16ac2f 100644 --- a/usr.sbin/smtpd/lka.c +++ b/usr.sbin/smtpd/lka.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lka.c,v 1.207 2018/07/25 16:00:48 eric Exp $ */ +/* $OpenBSD: lka.c,v 1.208 2018/11/01 10:13:25 gilles Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -79,7 +79,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) struct msg m; union lookup lk; char buf[LINE_MAX]; - const char *tablename, *username, *password, *label; + const char *tablename, *username, *password, *label, *procname; uint64_t reqid; int v; @@ -389,6 +389,15 @@ lka_imsg(struct mproc *p, struct imsg *imsg) (ret == 1) ? IMSG_CTL_OK : IMSG_CTL_FAIL, imsg->hdr.peerid, 0, -1, NULL, 0); return; + + case IMSG_LKA_PROCESSOR_FORK: + m_msg(&m, imsg); + m_get_string(&m, &procname); + m_end(&m); + + lka_proc_forked(procname, imsg->fd); + return; + } errx(1, "lka_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type)); diff --git a/usr.sbin/smtpd/lka_proc.c b/usr.sbin/smtpd/lka_proc.c new file mode 100644 index 00000000000..a18da64667d --- /dev/null +++ b/usr.sbin/smtpd/lka_proc.c @@ -0,0 +1,88 @@ +/* $OpenBSD: lka_proc.c,v 1.1 2018/11/01 10:13:25 gilles Exp $ */ + +/* + * Copyright (c) 2018 Gilles Chehade <gilles@poolp.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/tree.h> +#include <sys/socket.h> + +#include <netinet/in.h> + +#include <errno.h> +#include <event.h> +#include <imsg.h> +#include <inttypes.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "smtpd.h" +#include "log.h" + +static int inited = 0; +static struct dict processors; + + +struct processor_instance { + const char *name; + struct io *io; +}; + +static void processor_io(struct io *, int, void *); + +void +lka_proc_forked(const char *name, int fd) +{ + struct processor_instance *processor; + + if (!inited) { + dict_init(&processors); + inited = 1; + } + + processor = xcalloc(1, sizeof *processor); + processor->name = name; + processor->io = io_new(); + io_set_fd(processor->io, fd); + io_set_callback(processor->io, processor_io, processor); + dict_xset(&processors, name, processor); +} + + +static void +processor_io(struct io *io, int evt, void *arg) +{ + struct processor_instance *processor = arg; + char *line = NULL; + ssize_t len; + + log_trace(TRACE_IO, "processor: %p: %s %s", processor, io_strevent(evt), + io_strio(io)); + + switch (evt) { + case IO_DATAIN: + nextline: + line = io_getline(processor->io, &len); + /* No complete line received */ + if (line == NULL) + return; + + goto nextline; + } +} diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y index 366ff71d59a..a9c6855ad6e 100644 --- a/usr.sbin/smtpd/parse.y +++ b/usr.sbin/smtpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.223 2018/11/01 00:18:44 sashan Exp $ */ +/* $OpenBSD: parse.y,v 1.224 2018/11/01 10:13:25 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -105,7 +105,7 @@ static struct ca *sca; struct dispatcher *dispatcher; struct rule *rule; - +struct processor *processor; enum listen_options { LO_FAMILY = 0x000001, @@ -173,10 +173,11 @@ typedef struct { %token ACTION ALIAS ANY ARROW AUTH AUTH_OPTIONAL %token BACKUP BOUNCE -%token CA CERT CIPHERS COMPRESSION +%token CA CERT CHROOT CIPHERS COMPRESSION %token DHE DOMAIN %token ENCRYPTION ERROR EXPAND_ONLY %token FILTER FOR FORWARD_ONLY FROM +%token GROUP %token HELO HELO_SRC HOST HOSTNAME HOSTNAMES %token INCLUDE INET4 INET6 %token JUNK @@ -185,7 +186,7 @@ typedef struct { %token MAIL_FROM MAILDIR MASK_SRC MASQUERADE MATCH MAX_MESSAGE_SIZE MAX_DEFERRED MBOX MDA MTA MX %token NO_DSN NO_VERIFY %token ON -%token PKI PORT +%token PKI PORT PROC %token QUEUE %token RCPT_TO RECIPIENT RECEIVEDAUTH RELAY REJECT %token SCHEDULER SENDER SENDERS SMTP SMTPS SOCKET SRC SUB_ADDR_DELIM @@ -210,6 +211,7 @@ grammar : /* empty */ | grammar mda '\n' | grammar mta '\n' | grammar pki '\n' + | grammar proc '\n' | grammar queue '\n' | grammar scheduler '\n' | grammar smtp '\n' @@ -428,6 +430,56 @@ pki_params_opt pki_params ; + +proc: +PROC STRING STRING { + if (dict_get(conf->sc_processors_dict, $2)) { + yyerror("processor already exists with that name: %s", $2); + free($2); + free($3); + YYERROR; + } + processor = xcalloc(1, sizeof *processor); + processor->command = $3; +} proc_params { + dict_set(conf->sc_processors_dict, $2, processor); + processor = NULL; +} +; + +proc_params_opt: +USER STRING { + if (processor->user) { + yyerror("user already specified for this processor"); + free($2); + YYERROR; + } + processor->user = $2; +} +| GROUP STRING { + if (processor->group) { + yyerror("group already specified for this processor"); + free($2); + YYERROR; + } + processor->group = $2; +} +| CHROOT STRING { + if (processor->chroot) { + yyerror("chroot already specified for this processor"); + free($2); + YYERROR; + } + processor->chroot = $2; +} +; + +proc_params: +proc_params_opt proc_params +| /* empty */ +; + + queue: QUEUE COMPRESSION { conf->sc_queue_flags |= QUEUE_COMPRESSION; @@ -1607,6 +1659,7 @@ lookup(char *s) { "bounce", BOUNCE }, { "ca", CA }, { "cert", CERT }, + { "chroot", CHROOT }, { "ciphers", CIPHERS }, { "compression", COMPRESSION }, { "dhe", DHE }, @@ -1617,6 +1670,7 @@ lookup(char *s) { "for", FOR }, { "forward-only", FORWARD_ONLY }, { "from", FROM }, + { "group", GROUP }, { "helo", HELO }, { "helo-src", HELO_SRC }, { "host", HOST }, @@ -1647,6 +1701,7 @@ lookup(char *s) { "on", ON }, { "pki", PKI }, { "port", PORT }, + { "proc", PROC }, { "queue", QUEUE }, { "rcpt-to", RCPT_TO }, { "received-auth", RECEIVEDAUTH }, diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c index bc94e8ee55c..0ec428ced9b 100644 --- a/usr.sbin/smtpd/smtpd.c +++ b/usr.sbin/smtpd/smtpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.c,v 1.303 2018/09/04 13:04:42 gilles Exp $ */ +/* $OpenBSD: smtpd.c,v 1.304 2018/11/01 10:13:25 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -34,6 +34,7 @@ #include <event.h> #include <fcntl.h> #include <fts.h> +#include <grp.h> #include <imsg.h> #include <inttypes.h> #include <login_cap.h> @@ -89,9 +90,13 @@ static int parent_auth_user(const char *, const char *); static void load_pki_tree(void); static void load_pki_keys(void); +static void fork_processors(void); +static void fork_processor(const char *, const char *, const char *, const char *, const char *); + enum child_type { CHILD_DAEMON, CHILD_MDA, + CHILD_PROCESSOR, CHILD_ENQUEUE_OFFLINE, }; @@ -382,6 +387,14 @@ parent_sig_handler(int sig, short event, void *p) goto skip; switch (child->type) { + case CHILD_PROCESSOR: + if (fail) { + log_warnx("warn: lost processor: %s %s", + child->title, cause); + parent_shutdown(); + } + break; + case CHILD_DAEMON: if (fail) log_warnx("warn: lost child: %s %s", @@ -1053,6 +1066,8 @@ smtpd(void) { offline_timeout.tv_usec = 0; evtimer_add(&offline_ev, &offline_timeout); + fork_processors(); + purge_task(); if (pledge("stdio rpath wpath cpath fattr flock tmppath " @@ -1229,6 +1244,88 @@ purge_task(void) } static void +fork_processors(void) +{ + const char *name; + struct processor *processor; + void *iter; + + iter = NULL; + while (dict_iter(env->sc_processors_dict, &iter, &name, (void **)&processor)) + fork_processor(name, processor->command, processor->user, processor->group, processor->chroot); +} + +static void +fork_processor(const char *name, const char *command, const char *user, const char *group, const char *chroot_path) +{ + pid_t pid; + int sp[2]; + struct passwd *pw; + struct group *gr; + + log_debug("debug: smtpd: forking processor %s %s user=%s,group=%s", name, command, user, group); + + if (user == NULL) + user = SMTPD_USER; + if ((pw = getpwnam(user)) == NULL) + err(1, "getpwnam"); + + if (group) { + if ((gr = getgrnam(group)) == NULL) + err(1, "getgrnam"); + } + else { + if ((gr = getgrgid(pw->pw_gid)) == NULL) + err(1, "getgrgid"); + } + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) + err(1, "socketpair"); + + if ((pid = fork()) < 0) + err(1, "fork"); + + /* parent passes the child fd over to lka */ + if (pid > 0) { + child_add(pid, CHILD_PROCESSOR, name); + close(sp[0]); + m_create(p_lka, IMSG_LKA_PROCESSOR_FORK, 0, 0, sp[1]); + m_add_string(p_lka, name); + m_close(p_lka); + return; + } + + close(sp[1]); + dup2(sp[0], STDIN_FILENO); + dup2(sp[0], STDOUT_FILENO); + + if (chroot_path) { + if (chroot(chroot_path) != 0 || chdir("/") != 0) + err(1, "chroot: %s", chroot_path); + } + + if (setgroups(1, &gr->gr_gid) || + setresgid(gr->gr_gid, gr->gr_gid, gr->gr_gid) || + setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) + err(1, "fork_processor: cannot drop privileges"); + + if (closefrom(STDERR_FILENO + 1) < 0) + err(1, "closefrom"); + if (setsid() < 0) + err(1, "setsid"); + if (signal(SIGPIPE, SIG_DFL) == SIG_ERR || + signal(SIGINT, SIG_DFL) == SIG_ERR || + signal(SIGTERM, SIG_DFL) == SIG_ERR || + signal(SIGCHLD, SIG_DFL) == SIG_ERR || + signal(SIGHUP, SIG_DFL) == SIG_ERR) + err(1, "signal"); + + execle(command, name, (char *)NULL, NULL); + perror("execle"); + _exit(1); +} + +static void forkmda(struct mproc *p, uint64_t id, struct deliver *deliver) { char ebuf[128], sfn[32]; @@ -1725,6 +1822,8 @@ proc_title(enum smtp_proc_type proc) return "klondike"; case PROC_CLIENT: return "client"; + case PROC_PROCESSOR: + return "processor"; } return "unknown"; } @@ -1905,6 +2004,8 @@ imsg_to_str(int type) CASE(IMSG_SMTP_EVENT_ROLLBACK); CASE(IMSG_SMTP_EVENT_DISCONNECT); + CASE(IMSG_LKA_PROCESSOR_FORK); + CASE(IMSG_CA_PRIVENC); CASE(IMSG_CA_PRIVDEC); default: diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index 777bc11efda..1224ec712e7 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.563 2018/10/31 16:32:12 gilles Exp $ */ +/* $OpenBSD: smtpd.h,v 1.564 2018/11/01 10:13:25 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -302,6 +302,8 @@ enum imsg_type { IMSG_SMTP_EVENT_ROLLBACK, IMSG_SMTP_EVENT_DISCONNECT, + IMSG_LKA_PROCESSOR_FORK, + IMSG_CA_PRIVENC, IMSG_CA_PRIVDEC }; @@ -314,7 +316,7 @@ enum smtp_proc_type { PROC_SCHEDULER, PROC_PONY, PROC_CA, - + PROC_PROCESSOR, PROC_CLIENT, }; @@ -531,6 +533,8 @@ struct smtpd { size_t sc_scheduler_max_msg_batch_size; size_t sc_scheduler_max_schedule; + struct dict *sc_processors_dict; + int sc_ttl; #define MAX_BOUNCE_WARN 4 time_t sc_bounce_warn[MAX_BOUNCE_WARN]; @@ -976,6 +980,13 @@ enum lka_resp_status { LKA_PERMFAIL }; +struct processor { + const char *command; + const char *user; + const char *group; + const char *chroot; +}; + enum ca_resp_status { CA_OK, CA_FAIL @@ -1220,6 +1231,10 @@ int limit_mta_set(struct mta_limits *, const char*, int64_t); int lka(void); +/* lka_proc.c */ +void lka_proc_forked(const char *, int); + + /* lka_session.c */ void lka_session(uint64_t, struct envelope *); void lka_session_forward_reply(struct forward_req *, int); diff --git a/usr.sbin/smtpd/smtpd/Makefile b/usr.sbin/smtpd/smtpd/Makefile index 4beb5967af1..511128c5328 100644 --- a/usr.sbin/smtpd/smtpd/Makefile +++ b/usr.sbin/smtpd/smtpd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.93 2018/08/31 07:28:27 eric Exp $ +# $OpenBSD: Makefile,v 1.94 2018/11/01 10:13:25 gilles Exp $ .PATH: ${.CURDIR}/.. @@ -22,6 +22,7 @@ SRCS+= iobuf.c SRCS+= ioev.c SRCS+= limit.c SRCS+= lka.c +SRCS+= lka_proc.c SRCS+= lka_session.c SRCS+= log.c SRCS+= mailaddr.c |