summaryrefslogtreecommitdiff
path: root/usr.sbin/smtpd/smtpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/smtpd/smtpd.c')
-rw-r--r--usr.sbin/smtpd/smtpd.c103
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: