xref: /openbsd/usr.sbin/smtpd/smtp.c (revision cca36db2)
1 /*	$OpenBSD: smtp.c,v 1.101 2012/01/31 21:05:26 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 <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 			env->sc_flags &= ~SMTPD_CONFIGURING;
236 			return;
237 
238 		case IMSG_PARENT_AUTHENTICATE:
239 			auth = imsg->data;
240 			s = session_lookup(auth->id);
241 			if (s == NULL)
242 				return;
243 			if (auth->success) {
244 				s->s_flags |= F_AUTHENTICATED;
245 				s->s_msg.flags |= DF_AUTHENTICATED;
246 			} else {
247 				s->s_flags &= ~F_AUTHENTICATED;
248 				s->s_msg.flags &= ~DF_AUTHENTICATED;
249 			}
250 			session_pickup(s, NULL);
251 			return;
252 
253 		case IMSG_CTL_VERBOSE:
254 			log_verbose(*(int *)imsg->data);
255 			return;
256 		}
257 	}
258 
259 	if (iev->proc == PROC_CONTROL) {
260 		switch (imsg->hdr.type) {
261 		case IMSG_SMTP_ENQUEUE:
262 			imsg_compose_event(iev, IMSG_SMTP_ENQUEUE,
263 			    imsg->hdr.peerid, 0, smtp_enqueue(imsg->data),
264 			    NULL, 0);
265 			return;
266 
267 		case IMSG_SMTP_PAUSE:
268 			smtp_pause();
269 			return;
270 
271 		case IMSG_SMTP_RESUME:
272 			smtp_resume();
273 			return;
274 		}
275 	}
276 
277 	errx(1, "smtp_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
278 }
279 
280 static void
281 smtp_sig_handler(int sig, short event, void *p)
282 {
283 	switch (sig) {
284 	case SIGINT:
285 	case SIGTERM:
286 		smtp_shutdown();
287 		break;
288 	default:
289 		fatalx("smtp_sig_handler: unexpected signal");
290 	}
291 }
292 
293 static void
294 smtp_shutdown(void)
295 {
296 	log_info("smtp server exiting");
297 	_exit(0);
298 }
299 
300 pid_t
301 smtp(void)
302 {
303 	pid_t		 pid;
304 	struct passwd	*pw;
305 
306 	struct event	 ev_sigint;
307 	struct event	 ev_sigterm;
308 
309 	struct peer peers[] = {
310 		{ PROC_PARENT,	imsg_dispatch },
311 		{ PROC_MFA,	imsg_dispatch },
312 		{ PROC_QUEUE,	imsg_dispatch },
313 		{ PROC_LKA,	imsg_dispatch },
314 		{ PROC_CONTROL,	imsg_dispatch }
315 	};
316 
317 	switch (pid = fork()) {
318 	case -1:
319 		fatal("smtp: cannot fork");
320 	case 0:
321 		break;
322 	default:
323 		return (pid);
324 	}
325 
326 	ssl_init();
327 	purge_config(PURGE_EVERYTHING);
328 
329 	pw = env->sc_pw;
330 
331 	if (chroot(pw->pw_dir) == -1)
332 		fatal("smtp: chroot");
333 	if (chdir("/") == -1)
334 		fatal("smtp: chdir(\"/\")");
335 
336 	smtpd_process = PROC_SMTP;
337 	setproctitle("%s", env->sc_title[smtpd_process]);
338 
339 	if (setgroups(1, &pw->pw_gid) ||
340 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
341 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
342 		fatal("smtp: cannot drop privileges");
343 
344 	imsg_callback = smtp_imsg;
345 	event_init();
346 
347 	signal_set(&ev_sigint, SIGINT, smtp_sig_handler, NULL);
348 	signal_set(&ev_sigterm, SIGTERM, smtp_sig_handler, NULL);
349 	signal_add(&ev_sigint, NULL);
350 	signal_add(&ev_sigterm, NULL);
351 	signal(SIGPIPE, SIG_IGN);
352 	signal(SIGHUP, SIG_IGN);
353 
354 	/* Initial limit for use by IMSG_SMTP_ENQUEUE, will be tuned later once
355 	 * the listening sockets arrive. */
356 	env->sc_maxconn = availdesc() / 2;
357 
358 	config_pipes(peers, nitems(peers));
359 	config_peers(peers, nitems(peers));
360 
361 	if (event_dispatch() < 0)
362 		fatal("event_dispatch");
363 	smtp_shutdown();
364 
365 	return (0);
366 }
367 
368 static void
369 smtp_setup_events(void)
370 {
371 	struct listener *l;
372 	int avail = availdesc();
373 
374 	TAILQ_FOREACH(l, env->sc_listeners, entry) {
375 		log_debug("smtp: listen on %s port %d flags 0x%01x"
376 		    " cert \"%s\"", ss_to_text(&l->ss), ntohs(l->port),
377 		    l->flags, l->ssl_cert_name);
378 
379 		session_socket_blockmode(l->fd, BM_NONBLOCK);
380 		if (listen(l->fd, SMTPD_BACKLOG) == -1)
381 			fatal("listen");
382 		event_set(&l->ev, l->fd, EV_READ|EV_PERSIST, smtp_accept, l);
383 		event_add(&l->ev, NULL);
384 		ssl_setup(l);
385 		avail--;
386 	}
387 
388 	/* guarantee 2 fds to each accepted client */
389 	if ((env->sc_maxconn = avail / 2) < 1)
390 		fatalx("smtp_setup_events: fd starvation");
391 
392 	log_debug("smtp: will accept at most %d clients", env->sc_maxconn);
393 }
394 
395 static void
396 smtp_pause(void)
397 {
398 	struct listener *l;
399 
400 	log_debug("smtp: pausing listening sockets");
401 	env->sc_flags |= SMTPD_SMTP_PAUSED;
402 
403 	TAILQ_FOREACH(l, env->sc_listeners, entry)
404 		event_del(&l->ev);
405 }
406 
407 void
408 smtp_resume(void)
409 {
410 	struct listener *l;
411 
412 	log_debug("smtp: resuming listening sockets");
413 	env->sc_flags &= ~SMTPD_SMTP_PAUSED;
414 
415 	TAILQ_FOREACH(l, env->sc_listeners, entry)
416 		event_add(&l->ev, NULL);
417 }
418 
419 static int
420 smtp_enqueue(uid_t *euid)
421 {
422 	static struct listener		 local, *l;
423 	static struct sockaddr_storage	 sa;
424 	struct session			*s;
425 	int				 fd[2];
426 
427 	if (l == NULL) {
428 		struct addrinfo hints, *res;
429 
430 		l = &local;
431 		strlcpy(l->tag, "local", sizeof(l->tag));
432 
433 		bzero(&hints, sizeof(hints));
434 		hints.ai_family = PF_UNSPEC;
435 		hints.ai_flags = AI_NUMERICHOST;
436 
437 		if (getaddrinfo("::1", NULL, &hints, &res))
438 			fatal("getaddrinfo");
439 		memcpy(&sa, res->ai_addr, res->ai_addrlen);
440 		freeaddrinfo(res);
441 	}
442 
443 	/*
444 	 * Some enqueue requests buffered in IMSG may still arrive even after
445 	 * call to smtp_pause() because enqueue listener is not a real socket
446 	 * and thus cannot be paused properly.
447 	 */
448 	if (env->sc_flags & SMTPD_SMTP_PAUSED)
449 		return (-1);
450 
451 	if ((s = smtp_new(l)) == NULL)
452 		return (-1);
453 
454 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd))
455 		fatal("socketpair");
456 
457 	s->s_io.sock = fd[0];
458 	s->s_ss = sa;
459 	s->s_msg.flags |= DF_ENQUEUED;
460 
461 	if (euid)
462 		bsnprintf(s->s_hostname, sizeof(s->s_hostname), "%d@localhost",
463 		    *euid);
464 	else {
465 		strlcpy(s->s_hostname, "localhost", sizeof(s->s_hostname));
466 		s->s_msg.flags |= DF_BOUNCE;
467 	}
468 
469 	strlcpy(s->s_msg.hostname, s->s_hostname,
470 	    sizeof(s->s_msg.hostname));
471 
472 	session_pickup(s, NULL);
473 
474 	return (fd[1]);
475 }
476 
477 static void
478 smtp_accept(int fd, short event, void *p)
479 {
480 	struct listener		*l = p;
481 	struct session		*s;
482 	socklen_t		 len;
483 
484 	if ((s = smtp_new(l)) == NULL)
485 		return;
486 
487 	len = sizeof(s->s_ss);
488 	if ((s->s_io.sock = accept(fd, (struct sockaddr *)&s->s_ss, &len)) == -1) {
489 		if (errno == EINTR || errno == ECONNABORTED)
490 			return;
491 		fatal("smtp_accept");
492 	}
493 
494 	io_set_timeout(&s->s_io, SMTPD_SESSION_TIMEOUT * 1000);
495 	io_set_write(&s->s_io);
496 	dns_query_ptr(&s->s_ss, s->s_id);
497 }
498 
499 
500 static struct session *
501 smtp_new(struct listener *l)
502 {
503 	struct session	*s;
504 
505 	log_debug("smtp: new client on listener: %p", l);
506 
507 	if (env->sc_flags & SMTPD_SMTP_PAUSED)
508 		fatalx("smtp_new: unexpected client");
509 
510 	if ((s = calloc(1, sizeof(*s))) == NULL)
511 		fatal(NULL);
512 	s->s_id = generate_uid();
513 	s->s_l = l;
514 	strlcpy(s->s_msg.tag, l->tag, sizeof(s->s_msg.tag));
515 	SPLAY_INSERT(sessiontree, &env->sc_sessions, s);
516 
517 	if (stat_increment(STATS_SMTP_SESSION) >= env->sc_maxconn) {
518 		log_warnx("client limit hit, disabling incoming connections");
519 		smtp_pause();
520 	}
521 
522 	if (s->s_l->ss.ss_family == AF_INET)
523 		stat_increment(STATS_SMTP_SESSION_INET4);
524 	if (s->s_l->ss.ss_family == AF_INET6)
525 		stat_increment(STATS_SMTP_SESSION_INET6);
526 
527 	iobuf_init(&s->s_iobuf, MAX_LINE_SIZE, MAX_LINE_SIZE);
528 	io_init(&s->s_io, -1, s, session_io, &s->s_iobuf);
529 	s->s_state = S_CONNECTED;
530 
531 	return (s);
532 }
533 
534 /*
535  * Helper function for handling IMSG replies.
536  */
537 static struct session *
538 session_lookup(u_int64_t id)
539 {
540 	struct session	 key;
541 	struct session	*s;
542 
543 	key.s_id = id;
544 	s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key);
545 	if (s == NULL)
546 		fatalx("session_lookup: session is gone");
547 
548 	if (s->s_flags & F_ZOMBIE) {
549 		session_destroy(s, "(finalizing)");
550 		s = NULL;
551 	}
552 
553 	return (s);
554 }
555