dispatcher.c revision 1.4
1/*	$OpenBSD: dispatcher.c,v 1.4 2021/05/26 18:08:55 eric Exp $	*/
2
3/*
4 * Copyright (c) 2014 Gilles Chehade <gilles@poolp.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/queue.h>
21#include <sys/tree.h>
22#include <sys/socket.h>
23
24#include <ctype.h>
25#include <errno.h>
26#include <event.h>
27#include <imsg.h>
28#include <inttypes.h>
29#include <pwd.h>
30#include <signal.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <time.h>
35#include <unistd.h>
36#include <limits.h>
37#include <grp.h>
38
39#include "smtpd.h"
40#include "log.h"
41
42void mda_imsg(struct mproc *, struct imsg *);
43void mta_imsg(struct mproc *, struct imsg *);
44void smtp_imsg(struct mproc *, struct imsg *);
45
46static void dispatcher_shutdown(void);
47
48void
49dispatcher_imsg(struct mproc *p, struct imsg *imsg)
50{
51	struct msg	m;
52	int		v;
53
54	if (imsg == NULL)
55		dispatcher_shutdown();
56
57	switch (imsg->hdr.type) {
58
59	case IMSG_GETADDRINFO:
60	case IMSG_GETADDRINFO_END:
61	case IMSG_GETNAMEINFO:
62	case IMSG_RES_QUERY:
63		resolver_dispatch_result(p, imsg);
64		return;
65
66	case IMSG_CONF_START:
67		return;
68	case IMSG_CONF_END:
69		smtp_configure();
70		return;
71	case IMSG_CTL_VERBOSE:
72		m_msg(&m, imsg);
73		m_get_int(&m, &v);
74		m_end(&m);
75		log_trace_verbose(v);
76		return;
77	case IMSG_CTL_PROFILE:
78		m_msg(&m, imsg);
79		m_get_int(&m, &v);
80		m_end(&m);
81		profiling = v;
82		return;
83
84	/* smtp imsg */
85	case IMSG_SMTP_CHECK_SENDER:
86	case IMSG_SMTP_EXPAND_RCPT:
87	case IMSG_SMTP_LOOKUP_HELO:
88	case IMSG_SMTP_AUTHENTICATE:
89	case IMSG_SMTP_MESSAGE_COMMIT:
90	case IMSG_SMTP_MESSAGE_CREATE:
91	case IMSG_SMTP_MESSAGE_OPEN:
92	case IMSG_FILTER_SMTP_PROTOCOL:
93	case IMSG_FILTER_SMTP_DATA_BEGIN:
94	case IMSG_QUEUE_ENVELOPE_SUBMIT:
95	case IMSG_QUEUE_ENVELOPE_COMMIT:
96	case IMSG_QUEUE_SMTP_SESSION:
97	case IMSG_CTL_SMTP_SESSION:
98	case IMSG_CTL_PAUSE_SMTP:
99	case IMSG_CTL_RESUME_SMTP:
100		smtp_imsg(p, imsg);
101		return;
102
103        /* mta imsg */
104	case IMSG_QUEUE_TRANSFER:
105	case IMSG_MTA_OPEN_MESSAGE:
106	case IMSG_MTA_LOOKUP_CREDENTIALS:
107	case IMSG_MTA_LOOKUP_SMARTHOST:
108	case IMSG_MTA_LOOKUP_SOURCE:
109	case IMSG_MTA_LOOKUP_HELO:
110	case IMSG_MTA_DNS_HOST:
111	case IMSG_MTA_DNS_HOST_END:
112	case IMSG_MTA_DNS_MX_PREFERENCE:
113	case IMSG_CTL_RESUME_ROUTE:
114	case IMSG_CTL_MTA_SHOW_HOSTS:
115	case IMSG_CTL_MTA_SHOW_RELAYS:
116	case IMSG_CTL_MTA_SHOW_ROUTES:
117	case IMSG_CTL_MTA_SHOW_HOSTSTATS:
118	case IMSG_CTL_MTA_BLOCK:
119	case IMSG_CTL_MTA_UNBLOCK:
120	case IMSG_CTL_MTA_SHOW_BLOCK:
121		mta_imsg(p, imsg);
122		return;
123
124        /* mda imsg */
125	case IMSG_MDA_LOOKUP_USERINFO:
126	case IMSG_QUEUE_DELIVER:
127	case IMSG_MDA_OPEN_MESSAGE:
128	case IMSG_MDA_FORK:
129	case IMSG_MDA_DONE:
130		mda_imsg(p, imsg);
131		return;
132	default:
133		break;
134	}
135
136	fatalx("session_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
137}
138
139static void
140dispatcher_shutdown(void)
141{
142	log_debug("debug: dispatcher agent exiting");
143	_exit(0);
144}
145
146int
147dispatcher(void)
148{
149	struct passwd	*pw;
150
151	ca_engine_init();
152
153	mda_postfork();
154	mta_postfork();
155	smtp_postfork();
156
157	/* do not purge listeners and pki, they are purged
158	 * in smtp_configure()
159	 */
160	purge_config(PURGE_TABLES|PURGE_RULES);
161
162	if ((pw = getpwnam(SMTPD_USER)) == NULL)
163		fatalx("unknown user " SMTPD_USER);
164
165	if (chroot(PATH_CHROOT) == -1)
166		fatal("dispatcher: chroot");
167	if (chdir("/") == -1)
168		fatal("dispatcher: chdir(\"/\")");
169
170	config_process(PROC_DISPATCHER);
171
172	if (setgroups(1, &pw->pw_gid) ||
173	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
174	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
175		fatal("dispatcher: cannot drop privileges");
176
177	imsg_callback = dispatcher_imsg;
178	event_init();
179
180	mda_postprivdrop();
181	mta_postprivdrop();
182	smtp_postprivdrop();
183
184	signal(SIGINT, SIG_IGN);
185	signal(SIGTERM, SIG_IGN);
186	signal(SIGPIPE, SIG_IGN);
187	signal(SIGHUP, SIG_IGN);
188
189	config_peer(PROC_PARENT);
190	config_peer(PROC_QUEUE);
191	config_peer(PROC_LKA);
192	config_peer(PROC_CONTROL);
193	config_peer(PROC_CA);
194
195	if (pledge("stdio inet unix recvfd sendfd", NULL) == -1)
196		fatal("pledge");
197
198	event_dispatch();
199	fatalx("exited event loop");
200
201	return (0);
202}
203