xref: /openbsd-src/usr.sbin/smtpd/smtp.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: smtp.c,v 1.91 2011/09/01 20:17:47 gilles Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.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/param.h>
25 #include <sys/socket.h>
26 
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 "smtpd.h"
39 #include "log.h"
40 
41 static void smtp_imsg(struct imsgev *, struct imsg *);
42 static void smtp_shutdown(void);
43 static void smtp_sig_handler(int, short, void *);
44 static void smtp_setup_events(void);
45 static void smtp_disable_events(void);
46 static void smtp_pause(void);
47 static int smtp_enqueue(uid_t *);
48 static void smtp_accept(int, short, void *);
49 static struct session *smtp_new(struct listener *);
50 static struct session *session_lookup(u_int64_t);
51 
52 
53 static void
54 smtp_imsg(struct imsgev *iev, struct imsg *imsg)
55 {
56 	struct session		 skey;
57 	struct submit_status	*ss;
58 	struct listener		*l;
59 	struct session		*s;
60 	struct auth		*auth;
61 	struct ssl		*ssl;
62 	struct dns		*dns;
63 
64 	if (iev->proc == PROC_LKA) {
65 		switch (imsg->hdr.type) {
66 		case IMSG_DNS_PTR:
67 			dns = imsg->data;
68 			s = session_lookup(dns->id);
69 			if (s == NULL)
70 				fatalx("smtp: impossible quit");
71 			strlcpy(s->s_hostname,
72 			    dns->error ? "<unknown>" : dns->host,
73 			    sizeof s->s_hostname);
74 			strlcpy(s->s_msg.delivery.hostname, s->s_hostname,
75 			    sizeof s->s_msg.delivery.hostname);
76 			session_init(s->s_l, s);
77 			return;
78 		}
79 	}
80 
81 	if (iev->proc == PROC_MFA) {
82 		switch (imsg->hdr.type) {
83 		case IMSG_MFA_HELO:
84 		case IMSG_MFA_MAIL:
85 		case IMSG_MFA_RCPT:
86 			log_debug("smtp: got imsg_mfa_helo/mail/rcpt");
87 		case IMSG_MFA_DATALINE:
88 			ss = imsg->data;
89 			s = session_lookup(ss->id);
90 			if (s == NULL)
91 				return;
92 			session_pickup(s, ss);
93 			return;
94 		}
95 	}
96 
97 	if (iev->proc == PROC_QUEUE) {
98 		ss = imsg->data;
99 
100 		switch (imsg->hdr.type) {
101 		case IMSG_QUEUE_CREATE_MESSAGE:
102 			log_debug("smtp: imsg_queue_create_message returned");
103 			s = session_lookup(ss->id);
104 			if (s == NULL)
105 				return;
106 			s->s_msg.delivery.id = (u_int64_t)ss->u.msgid << 32;
107 			session_pickup(s, ss);
108 			return;
109 
110 		case IMSG_QUEUE_MESSAGE_FILE:
111 			log_debug("smtp: imsg_queue_message_file returned");
112 			s = session_lookup(ss->id);
113 			if (s == NULL) {
114 				close(imsg->fd);
115 				return;
116 			}
117 			s->datafp = fdopen(imsg->fd, "w");
118 			if (s->datafp == NULL) {
119 				/* queue may have experienced tempfail. */
120 				if (ss->code != 421)
121 					fatalx("smtp: fdopen");
122 				close(imsg->fd);
123 			}
124 			session_pickup(s, ss);
125 			return;
126 
127 		case IMSG_QUEUE_TEMPFAIL:
128 			log_debug("smtp: got imsg_queue_tempfail");
129 			skey.s_id = ss->id;
130 			s = SPLAY_FIND(sessiontree, &env->sc_sessions, &skey);
131 			if (s == NULL)
132 				fatalx("smtp: session is gone");
133 			if (s->s_flags & F_WRITEONLY)
134 				/* session is write-only, must not destroy it. */
135 				s->s_msg.delivery.status |= DS_TEMPFAILURE;
136 			else
137 				fatalx("smtp: corrupt session");
138 			return;
139 
140 		case IMSG_QUEUE_COMMIT_ENVELOPES:
141 			log_debug("smtp: got imsg_queue_commit_envelopes");
142 			s = session_lookup(ss->id);
143 			if (s == NULL)
144 				return;
145 			session_pickup(s, ss);
146 			return;
147 
148 		case IMSG_QUEUE_COMMIT_MESSAGE:
149 			log_debug("smtp: got imsg_queue_commit_message");
150 			s = session_lookup(ss->id);
151 			if (s == NULL)
152 				return;
153 			session_pickup(s, ss);
154 			return;
155 
156 		case IMSG_SMTP_ENQUEUE:
157 			imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 0, 0,
158 			    smtp_enqueue(NULL), imsg->data,
159 			    sizeof(struct envelope));
160 			return;
161 		}
162 	}
163 
164 	if (iev->proc == PROC_PARENT) {
165 		switch (imsg->hdr.type) {
166 		case IMSG_CONF_RELOAD:
167 			/*
168 			 * Reloading may invalidate various pointers our
169 			 * sessions rely upon, we better tell clients we
170 			 * want them to retry.
171 			 */
172 			SPLAY_FOREACH(s, sessiontree, &env->sc_sessions) {
173 				s->s_l = NULL;
174 				s->s_msg.delivery.status |= DS_TEMPFAILURE;
175 			}
176 			if (env->sc_listeners)
177 				smtp_disable_events();
178 			imsg_compose_event(iev, IMSG_PARENT_SEND_CONFIG, 0, 0, -1,
179 			    NULL, 0);
180 			return;
181 
182 		case IMSG_CONF_START:
183 			if (env->sc_flags & SMTPD_CONFIGURING)
184 				return;
185 			env->sc_flags |= SMTPD_CONFIGURING;
186 			env->sc_listeners = calloc(1, sizeof *env->sc_listeners);
187 			env->sc_ssl = calloc(1, sizeof *env->sc_ssl);
188 			if (env->sc_listeners == NULL || env->sc_ssl == NULL)
189 				fatal(NULL);
190 			TAILQ_INIT(env->sc_listeners);
191 			return;
192 
193 		case IMSG_CONF_SSL:
194 			if (!(env->sc_flags & SMTPD_CONFIGURING))
195 				return;
196 			ssl = calloc(1, sizeof *ssl);
197 			if (ssl == NULL)
198 				fatal(NULL);
199 			*ssl = *(struct ssl *)imsg->data;
200 			ssl->ssl_cert = strdup((char *)imsg->data +
201 			    sizeof *ssl);
202 			if (ssl->ssl_cert == NULL)
203 				fatal(NULL);
204 			ssl->ssl_key = strdup((char *)imsg->data + sizeof *ssl +
205 			    ssl->ssl_cert_len);
206 			if (ssl->ssl_key == NULL)
207 				fatal(NULL);
208 			if (ssl->ssl_dhparams_len) {
209 				ssl->ssl_dhparams = strdup((char *)imsg->data
210 				    + sizeof *ssl + ssl->ssl_cert_len +
211 				    ssl->ssl_key_len);
212 				if (ssl->ssl_dhparams == NULL)
213 					fatal(NULL);
214 			}
215 			SPLAY_INSERT(ssltree, env->sc_ssl, ssl);
216 			return;
217 
218 		case IMSG_CONF_LISTENER:
219 			if (!(env->sc_flags & SMTPD_CONFIGURING))
220 				return;
221 			l = calloc(1, sizeof *l);
222 			if (l == NULL)
223 				fatal(NULL);
224 			*l = *(struct listener *)imsg->data;
225 			l->fd = imsg->fd;
226 			if (l->fd < 0)
227 				fatalx("smtp: listener pass failed");
228 			if (l->flags & F_SSL) {
229 				struct ssl key;
230 
231 				strlcpy(key.ssl_name, l->ssl_cert_name,
232 				    sizeof key.ssl_name);
233 				l->ssl = SPLAY_FIND(ssltree, env->sc_ssl, &key);
234 				if (l->ssl == NULL)
235 					fatalx("smtp: ssltree out of sync");
236 			}
237 			TAILQ_INSERT_TAIL(env->sc_listeners, l, entry);
238 			return;
239 
240 		case IMSG_CONF_END:
241 			if (!(env->sc_flags & SMTPD_CONFIGURING))
242 				return;
243 			smtp_setup_events();
244 			env->sc_flags &= ~SMTPD_CONFIGURING;
245 			return;
246 
247 		case IMSG_PARENT_AUTHENTICATE:
248 			auth = imsg->data;
249 			s = session_lookup(auth->id);
250 			if (s == NULL)
251 				return;
252 			if (auth->success) {
253 				s->s_flags |= F_AUTHENTICATED;
254 				s->s_msg.delivery.flags |= DF_AUTHENTICATED;
255 			} else {
256 				s->s_flags &= ~F_AUTHENTICATED;
257 				s->s_msg.delivery.flags &= ~DF_AUTHENTICATED;
258 			}
259 			session_pickup(s, NULL);
260 			return;
261 
262 		case IMSG_CTL_VERBOSE:
263 			log_verbose(*(int *)imsg->data);
264 			return;
265 		}
266 	}
267 
268 	if (iev->proc == PROC_CONTROL) {
269 		switch (imsg->hdr.type) {
270 		case IMSG_SMTP_ENQUEUE:
271 			imsg_compose_event(iev, IMSG_SMTP_ENQUEUE,
272 			    imsg->hdr.peerid, 0, smtp_enqueue(imsg->data),
273 			    NULL, 0);
274 			return;
275 
276 		case IMSG_SMTP_PAUSE:
277 			smtp_pause();
278 			return;
279 
280 		case IMSG_SMTP_RESUME:
281 			smtp_resume();
282 			return;
283 		}
284 	}
285 
286 	fatalx("smtp_imsg: unexpected imsg");
287 }
288 
289 static void
290 smtp_sig_handler(int sig, short event, void *p)
291 {
292 	switch (sig) {
293 	case SIGINT:
294 	case SIGTERM:
295 		smtp_shutdown();
296 		break;
297 	default:
298 		fatalx("smtp_sig_handler: unexpected signal");
299 	}
300 }
301 
302 static void
303 smtp_shutdown(void)
304 {
305 	log_info("smtp server exiting");
306 	_exit(0);
307 }
308 
309 pid_t
310 smtp(void)
311 {
312 	pid_t		 pid;
313 	struct passwd	*pw;
314 
315 	struct event	 ev_sigint;
316 	struct event	 ev_sigterm;
317 
318 	struct peer peers[] = {
319 		{ PROC_PARENT,	imsg_dispatch },
320 		{ PROC_MFA,	imsg_dispatch },
321 		{ PROC_QUEUE,	imsg_dispatch },
322 		{ PROC_LKA,	imsg_dispatch },
323 		{ PROC_CONTROL,	imsg_dispatch }
324 	};
325 
326 	switch (pid = fork()) {
327 	case -1:
328 		fatal("smtp: cannot fork");
329 	case 0:
330 		break;
331 	default:
332 		return (pid);
333 	}
334 
335 	ssl_init();
336 	purge_config(PURGE_EVERYTHING);
337 
338 	pw = env->sc_pw;
339 
340 	if (chroot(pw->pw_dir) == -1)
341 		fatal("smtp: chroot");
342 	if (chdir("/") == -1)
343 		fatal("smtp: chdir(\"/\")");
344 
345 	smtpd_process = PROC_SMTP;
346 	setproctitle("%s", env->sc_title[smtpd_process]);
347 
348 	if (setgroups(1, &pw->pw_gid) ||
349 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
350 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
351 		fatal("smtp: cannot drop privileges");
352 
353 	imsg_callback = smtp_imsg;
354 	event_init();
355 
356 	signal_set(&ev_sigint, SIGINT, smtp_sig_handler, NULL);
357 	signal_set(&ev_sigterm, SIGTERM, smtp_sig_handler, NULL);
358 	signal_add(&ev_sigint, NULL);
359 	signal_add(&ev_sigterm, NULL);
360 	signal(SIGPIPE, SIG_IGN);
361 	signal(SIGHUP, SIG_IGN);
362 
363 	/* Initial limit for use by IMSG_SMTP_ENQUEUE, will be tuned later once
364 	 * the listening sockets arrive. */
365 	env->sc_maxconn = availdesc() / 2;
366 
367 	config_pipes(peers, nitems(peers));
368 	config_peers(peers, nitems(peers));
369 
370 	if (event_dispatch() < 0)
371 		fatal("event_dispatch");
372 	smtp_shutdown();
373 
374 	return (0);
375 }
376 
377 static void
378 smtp_setup_events(void)
379 {
380 	struct listener *l;
381 	int avail = availdesc();
382 
383 	TAILQ_FOREACH(l, env->sc_listeners, entry) {
384 		log_debug("smtp_setup_events: listen on %s port %d flags 0x%01x"
385 		    " cert \"%s\"", ss_to_text(&l->ss), ntohs(l->port),
386 		    l->flags, l->ssl_cert_name);
387 
388 		session_socket_blockmode(l->fd, BM_NONBLOCK);
389 		if (listen(l->fd, SMTPD_BACKLOG) == -1)
390 			fatal("listen");
391 		event_set(&l->ev, l->fd, EV_READ|EV_PERSIST, smtp_accept, l);
392 		event_add(&l->ev, NULL);
393 		ssl_setup(l);
394 		avail--;
395 	}
396 
397 	/* guarantee 2 fds to each accepted client */
398 	if ((env->sc_maxconn = avail / 2) < 1)
399 		fatalx("smtp_setup_events: fd starvation");
400 
401 	log_debug("smtp: will accept at most %d clients", env->sc_maxconn);
402 }
403 
404 static void
405 smtp_disable_events(void)
406 {
407 	struct listener	*l;
408 
409 	log_debug("smtp_disable_events: closing listening sockets");
410 	while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) {
411 		TAILQ_REMOVE(env->sc_listeners, l, entry);
412 		event_del(&l->ev);
413 		close(l->fd);
414 		free(l);
415 	}
416 	free(env->sc_listeners);
417 	env->sc_listeners = NULL;
418 	env->sc_maxconn = 0;
419 }
420 
421 static void
422 smtp_pause(void)
423 {
424 	struct listener *l;
425 
426 	log_debug("smtp_pause: pausing listening sockets");
427 	env->sc_opts |= SMTPD_SMTP_PAUSED;
428 
429 	TAILQ_FOREACH(l, env->sc_listeners, entry)
430 		event_del(&l->ev);
431 }
432 
433 void
434 smtp_resume(void)
435 {
436 	struct listener *l;
437 
438 	log_debug("smtp_resume: resuming listening sockets");
439 	env->sc_opts &= ~SMTPD_SMTP_PAUSED;
440 
441 	TAILQ_FOREACH(l, env->sc_listeners, entry)
442 		event_add(&l->ev, NULL);
443 }
444 
445 static int
446 smtp_enqueue(uid_t *euid)
447 {
448 	static struct listener		 local, *l;
449 	static struct sockaddr_storage	 sa;
450 	struct session			*s;
451 	int				 fd[2];
452 
453 	if (l == NULL) {
454 		struct addrinfo hints, *res;
455 
456 		l = &local;
457 		strlcpy(l->tag, "local", sizeof(l->tag));
458 
459 		bzero(&hints, sizeof(hints));
460 		hints.ai_family = PF_UNSPEC;
461 		hints.ai_flags = AI_NUMERICHOST;
462 
463 		if (getaddrinfo("::1", NULL, &hints, &res))
464 			fatal("getaddrinfo");
465 		memcpy(&sa, res->ai_addr, res->ai_addrlen);
466 		freeaddrinfo(res);
467 	}
468 
469 	/*
470 	 * Some enqueue requests buffered in IMSG may still arrive even after
471 	 * call to smtp_pause() because enqueue listener is not a real socket
472 	 * and thus cannot be paused properly.
473 	 */
474 	if (env->sc_opts & SMTPD_SMTP_PAUSED)
475 		return (-1);
476 
477 	if ((s = smtp_new(l)) == NULL)
478 		return (-1);
479 
480 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd))
481 		fatal("socketpair");
482 
483 	s->s_fd = fd[0];
484 	s->s_ss = sa;
485 	s->s_msg.delivery.flags |= DF_ENQUEUED;
486 
487 	if (euid)
488 		bsnprintf(s->s_hostname, sizeof(s->s_hostname), "%d@localhost",
489 		    *euid);
490 	else {
491 		strlcpy(s->s_hostname, "localhost", sizeof(s->s_hostname));
492 		s->s_msg.delivery.flags |= DF_BOUNCE;
493 	}
494 
495 	strlcpy(s->s_msg.delivery.hostname, s->s_hostname,
496 	    sizeof(s->s_msg.delivery.hostname));
497 
498 	session_init(l, s);
499 
500 	return (fd[1]);
501 }
502 
503 static void
504 smtp_accept(int fd, short event, void *p)
505 {
506 	struct listener		*l = p;
507 	struct session		*s;
508 	socklen_t		 len;
509 
510 	if ((s = smtp_new(l)) == NULL)
511 		return;
512 
513 	len = sizeof(s->s_ss);
514 	if ((s->s_fd = accept(fd, (struct sockaddr *)&s->s_ss, &len)) == -1) {
515 		if (errno == EINTR || errno == ECONNABORTED)
516 			return;
517 		fatal("smtp_accept");
518 	}
519 
520 
521 	s->s_flags |= F_WRITEONLY;
522 	dns_query_ptr(&s->s_ss, s->s_id);
523 }
524 
525 
526 static struct session *
527 smtp_new(struct listener *l)
528 {
529 	struct session	*s;
530 
531 	log_debug("smtp_new: incoming client on listener: %p", l);
532 
533 	if (env->sc_opts & SMTPD_SMTP_PAUSED)
534 		fatalx("smtp_new: unexpected client");
535 
536 	if ((s = calloc(1, sizeof(*s))) == NULL)
537 		fatal(NULL);
538 	s->s_id = generate_uid();
539 	s->s_l = l;
540 	strlcpy(s->s_msg.tag, l->tag, sizeof(s->s_msg.tag));
541 	SPLAY_INSERT(sessiontree, &env->sc_sessions, s);
542 
543 	if (stat_increment(STATS_SMTP_SESSION) >= env->sc_maxconn) {
544 		log_warnx("client limit hit, disabling incoming connections");
545 		smtp_pause();
546 	}
547 
548 	if (s->s_l->ss.ss_family == AF_INET)
549 		stat_increment(STATS_SMTP_SESSION_INET4);
550 	if (s->s_l->ss.ss_family == AF_INET6)
551 		stat_increment(STATS_SMTP_SESSION_INET6);
552 
553 	return (s);
554 }
555 
556 /*
557  * Helper function for handling IMSG replies.
558  */
559 static struct session *
560 session_lookup(u_int64_t id)
561 {
562 	struct session	 key;
563 	struct session	*s;
564 
565 	key.s_id = id;
566 	s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key);
567 	if (s == NULL)
568 		fatalx("session_lookup: session is gone");
569 
570 	if (!(s->s_flags & F_WRITEONLY))
571 		fatalx("session_lookup: corrupt session");
572 	s->s_flags &= ~F_WRITEONLY;
573 
574 	if (s->s_flags & F_QUIT) {
575 		session_destroy(s);
576 		s = NULL;
577 	}
578 
579 	return (s);
580 }
581