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