diff options
Diffstat (limited to 'usr.sbin/smtpd/smtpd.c')
-rw-r--r-- | usr.sbin/smtpd/smtpd.c | 103 |
1 files changed, 102 insertions, 1 deletions
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: |