xref: /openbsd/usr.sbin/smtpd/smtp.c (revision 91f110e0)
1 /*	$OpenBSD: smtp.c,v 1.133 2014/02/04 13:44:41 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
5  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
6  * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/queue.h>
23 #include <sys/tree.h>
24 #include <sys/socket.h>
25 
26 #include <err.h>
27 #include <errno.h>
28 #include <event.h>
29 #include <imsg.h>
30 #include <netdb.h>
31 #include <pwd.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include <openssl/ssl.h>
39 
40 #include "smtpd.h"
41 #include "log.h"
42 #include "ssl.h"
43 
44 static void smtp_imsg(struct mproc *, struct imsg *);
45 static void smtp_shutdown(void);
46 static void smtp_sig_handler(int, short, void *);
47 static void smtp_setup_events(void);
48 static void smtp_pause(void);
49 static void smtp_resume(void);
50 static void smtp_accept(int, short, void *);
51 static int smtp_enqueue(uid_t *);
52 static int smtp_can_accept(void);
53 static void smtp_setup_listeners(void);
54 
55 #define	SMTP_FD_RESERVE	5
56 static size_t	sessions;
57 
58 static void
59 smtp_imsg(struct mproc *p, struct imsg *imsg)
60 {
61 	struct msg	 m;
62 	int		 v;
63 
64 	if (p->proc == PROC_LKA) {
65 		switch (imsg->hdr.type) {
66 		case IMSG_DNS_PTR:
67 		case IMSG_LKA_EXPAND_RCPT:
68 		case IMSG_LKA_HELO:
69 		case IMSG_LKA_AUTHENTICATE:
70 		case IMSG_LKA_SSL_INIT:
71 		case IMSG_LKA_SSL_VERIFY:
72 			smtp_session_imsg(p, imsg);
73 			return;
74 		}
75 	}
76 
77 	if (p->proc == PROC_MFA) {
78 		switch (imsg->hdr.type) {
79 		case IMSG_MFA_SMTP_RESPONSE:
80 			smtp_session_imsg(p, imsg);
81 			return;
82 		}
83 	}
84 
85 	if (p->proc == PROC_QUEUE) {
86 		switch (imsg->hdr.type) {
87 		case IMSG_QUEUE_CREATE_MESSAGE:
88 		case IMSG_QUEUE_MESSAGE_FILE:
89 		case IMSG_QUEUE_SUBMIT_ENVELOPE:
90 		case IMSG_QUEUE_COMMIT_ENVELOPES:
91 		case IMSG_QUEUE_COMMIT_MESSAGE:
92 			smtp_session_imsg(p, imsg);
93 			return;
94 
95 		case IMSG_SMTP_ENQUEUE_FD:
96 			m_compose(p, IMSG_SMTP_ENQUEUE_FD, 0, 0,
97 			    smtp_enqueue(NULL), imsg->data,
98 			    imsg->hdr.len - sizeof imsg->hdr);
99 			return;
100 		}
101 	}
102 
103 	if (p->proc == PROC_PARENT) {
104 		switch (imsg->hdr.type) {
105 
106 		case IMSG_CONF_START:
107 			return;
108 
109 		case IMSG_CONF_END:
110 			smtp_setup_events();
111 			return;
112 
113 		case IMSG_CTL_VERBOSE:
114 			m_msg(&m, imsg);
115 			m_get_int(&m, &v);
116 			m_end(&m);
117 			log_verbose(v);
118 			return;
119 
120 		case IMSG_CTL_PROFILE:
121 			m_msg(&m, imsg);
122 			m_get_int(&m, &v);
123 			m_end(&m);
124 			profiling = v;
125 			return;
126 		}
127 	}
128 
129 	if (p->proc == PROC_CONTROL) {
130 		switch (imsg->hdr.type) {
131 		case IMSG_SMTP_ENQUEUE_FD:
132 			m_compose(p, IMSG_SMTP_ENQUEUE_FD, imsg->hdr.peerid, 0,
133 			    smtp_enqueue(imsg->data), NULL, 0);
134 			return;
135 
136 		case IMSG_CTL_PAUSE_SMTP:
137 			log_debug("debug: smtp: pausing listening sockets");
138 			smtp_pause();
139 			env->sc_flags |= SMTPD_SMTP_PAUSED;
140 			return;
141 
142 		case IMSG_CTL_RESUME_SMTP:
143 			log_debug("debug: smtp: resuming listening sockets");
144 			env->sc_flags &= ~SMTPD_SMTP_PAUSED;
145 			smtp_resume();
146 			return;
147 		}
148 	}
149 
150 	errx(1, "smtp_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
151 }
152 
153 static void
154 smtp_sig_handler(int sig, short event, void *p)
155 {
156 	switch (sig) {
157 	case SIGINT:
158 	case SIGTERM:
159 		smtp_shutdown();
160 		break;
161 	default:
162 		fatalx("smtp_sig_handler: unexpected signal");
163 	}
164 }
165 
166 static void
167 smtp_shutdown(void)
168 {
169 	log_info("info: smtp server exiting");
170 	_exit(0);
171 }
172 
173 pid_t
174 smtp(void)
175 {
176 	pid_t		 pid;
177 	struct passwd	*pw;
178 	struct event	 ev_sigint;
179 	struct event	 ev_sigterm;
180 
181 	switch (pid = fork()) {
182 	case -1:
183 		fatal("smtp: cannot fork");
184 	case 0:
185 		post_fork(PROC_SMTP);
186 		break;
187 	default:
188 		return (pid);
189 	}
190 
191 	smtp_setup_listeners();
192 
193 	/* SSL will be purged later */
194 	purge_config(PURGE_TABLES|PURGE_RULES);
195 
196 	if ((pw = getpwnam(SMTPD_USER)) == NULL)
197 		fatalx("unknown user " SMTPD_USER);
198 
199 	if (chroot(PATH_CHROOT) == -1)
200 		fatal("smtp: chroot");
201 	if (chdir("/") == -1)
202 		fatal("smtp: chdir(\"/\")");
203 
204 	config_process(PROC_SMTP);
205 
206 	if (setgroups(1, &pw->pw_gid) ||
207 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
208 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
209 		fatal("smtp: cannot drop privileges");
210 
211 	imsg_callback = smtp_imsg;
212 	event_init();
213 
214 	signal_set(&ev_sigint, SIGINT, smtp_sig_handler, NULL);
215 	signal_set(&ev_sigterm, SIGTERM, smtp_sig_handler, NULL);
216 	signal_add(&ev_sigint, NULL);
217 	signal_add(&ev_sigterm, NULL);
218 	signal(SIGPIPE, SIG_IGN);
219 	signal(SIGHUP, SIG_IGN);
220 
221 	config_peer(PROC_CONTROL);
222 	config_peer(PROC_PARENT);
223 	config_peer(PROC_LKA);
224 	config_peer(PROC_MFA);
225 	config_peer(PROC_QUEUE);
226 	config_done();
227 
228 	if (event_dispatch() < 0)
229 		fatal("event_dispatch");
230 	smtp_shutdown();
231 
232 	return (0);
233 }
234 
235 static void
236 smtp_setup_listeners(void)
237 {
238 	struct listener	       *l;
239 	int			opt;
240 
241 	TAILQ_FOREACH(l, env->sc_listeners, entry) {
242 		if ((l->fd = socket(l->ss.ss_family, SOCK_STREAM, 0)) == -1) {
243 			if (errno == EAFNOSUPPORT) {
244 				log_warn("smtpd: socket");
245 				continue;
246 			}
247 			fatal("smtpd: socket");
248 		}
249 		opt = 1;
250 		if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt,
251 			sizeof(opt)) < 0)
252 			fatal("smtpd: setsockopt");
253 		if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) == -1)
254 			fatal("smtpd: bind");
255 	}
256 }
257 
258 static void
259 smtp_setup_events(void)
260 {
261 	struct listener *l;
262 	struct pki	*pki;
263 	SSL_CTX		*ssl_ctx;
264 	void		*iter;
265 	const char	*k;
266 
267 	TAILQ_FOREACH(l, env->sc_listeners, entry) {
268 		log_debug("debug: smtp: listen on %s port %d flags 0x%01x"
269 		    " pki \"%s\"", ss_to_text(&l->ss), ntohs(l->port),
270 		    l->flags, l->pki_name);
271 
272 		session_socket_blockmode(l->fd, BM_NONBLOCK);
273 		if (listen(l->fd, SMTPD_BACKLOG) == -1)
274 			fatal("listen");
275 		event_set(&l->ev, l->fd, EV_READ|EV_PERSIST, smtp_accept, l);
276 
277 		if (!(env->sc_flags & SMTPD_SMTP_PAUSED))
278 			event_add(&l->ev, NULL);
279 	}
280 
281 	iter = NULL;
282 	while (dict_iter(env->sc_pki_dict, &iter, &k, (void **)&pki)) {
283 		if (! ssl_setup((SSL_CTX **)&ssl_ctx, pki))
284 			fatal("smtp_setup_events: ssl_setup failure");
285 		dict_xset(env->sc_ssl_dict, k, ssl_ctx);
286 	}
287 
288 	purge_config(PURGE_PKI);
289 
290 	log_debug("debug: smtp: will accept at most %d clients",
291 	    (getdtablesize() - getdtablecount())/2 - SMTP_FD_RESERVE);
292 }
293 
294 static void
295 smtp_pause(void)
296 {
297 	struct listener *l;
298 
299 	if (env->sc_flags & (SMTPD_SMTP_DISABLED|SMTPD_SMTP_PAUSED))
300 		return;
301 
302 	TAILQ_FOREACH(l, env->sc_listeners, entry)
303 		event_del(&l->ev);
304 }
305 
306 static void
307 smtp_resume(void)
308 {
309 	struct listener *l;
310 
311 	if (env->sc_flags & (SMTPD_SMTP_DISABLED|SMTPD_SMTP_PAUSED))
312 		return;
313 
314 	TAILQ_FOREACH(l, env->sc_listeners, entry)
315 		event_add(&l->ev, NULL);
316 }
317 
318 static int
319 smtp_enqueue(uid_t *euid)
320 {
321 	static struct listener	 local, *listener = NULL;
322 	char			 buf[SMTPD_MAXHOSTNAMELEN], *hostname;
323 	int			 fd[2];
324 
325 	if (listener == NULL) {
326 		listener = &local;
327 		strlcpy(listener->tag, "local", sizeof(listener->tag));
328 		listener->ss.ss_family = AF_LOCAL;
329 		listener->ss.ss_len = sizeof(struct sockaddr *);
330 		strlcpy(listener->hostname, "localhost",
331 		    sizeof(listener->hostname));
332 	}
333 
334 	/*
335 	 * Some enqueue requests buffered in IMSG may still arrive even after
336 	 * call to smtp_pause() because enqueue listener is not a real socket
337 	 * and thus cannot be paused properly.
338 	 */
339 	if (env->sc_flags & SMTPD_SMTP_PAUSED)
340 		return (-1);
341 
342 	/* XXX dont' fatal here */
343 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd))
344 		fatal("socketpair");
345 
346 	hostname = "localhost";
347 	if (euid) {
348 		snprintf(buf, sizeof(buf), "%d@localhost", *euid);
349 		hostname = buf;
350 	}
351 
352 	if ((smtp_session(listener, fd[0], &listener->ss, hostname)) == -1) {
353 		close(fd[0]);
354 		close(fd[1]);
355 		return (-1);
356 	}
357 
358 	sessions++;
359 	stat_increment("smtp.session", 1);
360 	stat_increment("smtp.session.local", 1);
361 
362 	return (fd[1]);
363 }
364 
365 static void
366 smtp_accept(int fd, short event, void *p)
367 {
368 	struct listener		*listener = p;
369 	struct sockaddr_storage	 ss;
370 	socklen_t		 len;
371 	int			 sock;
372 
373 	if (env->sc_flags & SMTPD_SMTP_PAUSED)
374 		fatalx("smtp_session: unexpected client");
375 
376 	if (! smtp_can_accept()) {
377 		log_warnx("warn: Disabling incoming SMTP connections: "
378 		    "Client limit reached");
379 		goto pause;
380 	}
381 
382 	len = sizeof(ss);
383 	if ((sock = accept(fd, (struct sockaddr *)&ss, &len)) == -1) {
384 		if (errno == ENFILE || errno == EMFILE) {
385 			log_warn("warn: Disabling incoming SMTP connections");
386 			goto pause;
387 		}
388 		if (errno == EINTR || errno == EWOULDBLOCK ||
389 		    errno == ECONNABORTED)
390 			return;
391 		fatal("smtp_accept");
392 	}
393 
394 	if (smtp_session(listener, sock, &ss, NULL) == -1) {
395 		log_warn("warn: Failed to create SMTP session");
396 		close(sock);
397 		return;
398 	}
399 	io_set_blocking(sock, 0);
400 
401 	sessions++;
402 	stat_increment("smtp.session", 1);
403 	if (listener->ss.ss_family == AF_LOCAL)
404 		stat_increment("smtp.session.local", 1);
405 	if (listener->ss.ss_family == AF_INET)
406 		stat_increment("smtp.session.inet4", 1);
407 	if (listener->ss.ss_family == AF_INET6)
408 		stat_increment("smtp.session.inet6", 1);
409 	return;
410 
411 pause:
412 	smtp_pause();
413 	env->sc_flags |= SMTPD_SMTP_DISABLED;
414 	return;
415 }
416 
417 static int
418 smtp_can_accept(void)
419 {
420 	size_t max;
421 
422 	max = (getdtablesize() - getdtablecount()) / 2 - SMTP_FD_RESERVE;
423 
424 	return (sessions < max);
425 }
426 
427 void
428 smtp_collect(void)
429 {
430 	sessions--;
431 	stat_decrement("smtp.session", 1);
432 
433 	if (!smtp_can_accept())
434 		return;
435 
436 	if (env->sc_flags & SMTPD_SMTP_DISABLED) {
437 		log_warnx("warn: smtp: "
438 		    "fd exaustion over, re-enabling incoming connections");
439 		env->sc_flags &= ~SMTPD_SMTP_DISABLED;
440 		smtp_resume();
441 	}
442 }
443