xref: /openbsd-src/usr.sbin/smtpd/smtp.c (revision 5054e3e78af0749a9bb00ba9a024b3ee2d90290f)
1 /*	$OpenBSD: smtp.c,v 1.64 2009/11/08 21:40:05 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 <ctype.h>
28 #include <event.h>
29 #include <netdb.h>
30 #include <pwd.h>
31 #include <signal.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37 
38 #include "smtpd.h"
39 
40 __dead void	smtp_shutdown(void);
41 void		smtp_sig_handler(int, short, void *);
42 void		smtp_dispatch_parent(int, short, void *);
43 void		smtp_dispatch_mfa(int, short, void *);
44 void		smtp_dispatch_lka(int, short, void *);
45 void		smtp_dispatch_queue(int, short, void *);
46 void		smtp_dispatch_control(int, short, void *);
47 void		smtp_dispatch_runner(int, short, void *);
48 void		smtp_setup_events(struct smtpd *);
49 void		smtp_disable_events(struct smtpd *);
50 void		smtp_pause(struct smtpd *);
51 void		smtp_resume(struct smtpd *);
52 void		smtp_accept(int, short, void *);
53 void		session_auth_pickup(struct session *, char *, size_t);
54 struct session *session_lookup(struct smtpd *, u_int64_t);
55 
56 void
57 smtp_sig_handler(int sig, short event, void *p)
58 {
59 	switch (sig) {
60 	case SIGINT:
61 	case SIGTERM:
62 		smtp_shutdown();
63 		break;
64 	default:
65 		fatalx("smtp_sig_handler: unexpected signal");
66 	}
67 }
68 
69 void
70 smtp_dispatch_parent(int sig, short event, void *p)
71 {
72 	struct smtpd		*env = p;
73 	struct imsgev		*iev;
74 	struct imsgbuf		*ibuf;
75 	struct imsg		 imsg;
76 	ssize_t			 n;
77 
78 	iev = env->sc_ievs[PROC_PARENT];
79 	ibuf = &iev->ibuf;
80 
81 
82 	if (event & EV_READ) {
83 		if ((n = imsg_read(ibuf)) == -1)
84 			fatal("imsg_read_error");
85 		if (n == 0) {
86 			/* this pipe is dead, so remove the event handler */
87 			event_del(&iev->ev);
88 			event_loopexit(NULL);
89 			return;
90 		}
91 	}
92 
93 	if (event & EV_WRITE) {
94 		if (msgbuf_write(&ibuf->w) == -1)
95 			fatal("msgbuf_write");
96 	}
97 
98 	for (;;) {
99 		if ((n = imsg_get(ibuf, &imsg)) == -1)
100 			fatal("smtp_dispatch_parent: imsg_get error");
101 		if (n == 0)
102 			break;
103 
104 		switch (imsg.hdr.type) {
105 		case IMSG_CONF_RELOAD: {
106 			struct session *s;
107 
108 			/* reloading may invalidate various pointers our
109 			 * sessions rely upon, we better tell clients we
110 			 * want them to retry.
111 			 */
112 			SPLAY_FOREACH(s, sessiontree, &env->sc_sessions) {
113 				s->s_l = NULL;
114 				s->s_msg.status |= S_MESSAGE_TEMPFAILURE;
115 			}
116 			if (env->sc_listeners)
117 				smtp_disable_events(env);
118 			imsg_compose_event(iev, IMSG_PARENT_SEND_CONFIG, 0, 0, -1,
119 			    NULL, 0);
120 			break;
121 		}
122 		case IMSG_CONF_START:
123 			if (env->sc_flags & SMTPD_CONFIGURING)
124 				break;
125 			env->sc_flags |= SMTPD_CONFIGURING;
126 
127 			if ((env->sc_listeners = calloc(1, sizeof(*env->sc_listeners))) == NULL)
128 				fatal("smtp_dispatch_parent: calloc");
129 			if ((env->sc_ssl = calloc(1, sizeof(*env->sc_ssl))) == NULL)
130 				fatal("smtp_dispatch_parent: calloc");
131 			TAILQ_INIT(env->sc_listeners);
132 			break;
133 		case IMSG_CONF_SSL: {
134 			struct ssl	*s;
135 			struct ssl	*x_ssl;
136 
137 			if (!(env->sc_flags & SMTPD_CONFIGURING))
138 				break;
139 
140 			if ((s = calloc(1, sizeof(*s))) == NULL)
141 				fatal(NULL);
142 			x_ssl = imsg.data;
143 			(void)strlcpy(s->ssl_name, x_ssl->ssl_name,
144 			    sizeof(s->ssl_name));
145 			s->ssl_cert_len = x_ssl->ssl_cert_len;
146 			if ((s->ssl_cert =
147 			    strdup((char *)imsg.data + sizeof(*s))) == NULL)
148 				fatal(NULL);
149 			s->ssl_key_len = x_ssl->ssl_key_len;
150 			if ((s->ssl_key = strdup((char *)imsg.data +
151 			    (sizeof(*s) + s->ssl_cert_len))) == NULL)
152 				fatal(NULL);
153 
154 			SPLAY_INSERT(ssltree, env->sc_ssl, s);
155 			break;
156 		}
157 		case IMSG_CONF_LISTENER: {
158 			struct listener	*l;
159 			struct ssl	 key;
160 
161 			if (!(env->sc_flags & SMTPD_CONFIGURING))
162 				break;
163 
164 			if ((l = calloc(1, sizeof(*l))) == NULL)
165 				fatal(NULL);
166 			memcpy(l, imsg.data, sizeof(*l));
167 
168 			if ((l->fd = imsg.fd) == -1)
169 				fatal("cannot get fd");
170 
171 			(void)strlcpy(key.ssl_name, l->ssl_cert_name,
172 			    sizeof(key.ssl_name));
173 
174 			if (l->flags & F_SSL)
175 				if ((l->ssl = SPLAY_FIND(ssltree,
176 				    env->sc_ssl, &key)) == NULL)
177 					fatal("parent and smtp desynchronized");
178 
179 			TAILQ_INSERT_TAIL(env->sc_listeners, l, entry);
180 			break;
181 		}
182 		case IMSG_CONF_END:
183 			if (!(env->sc_flags & SMTPD_CONFIGURING))
184 				break;
185 			smtp_setup_events(env);
186 			env->sc_flags &= ~SMTPD_CONFIGURING;
187 			break;
188 		case IMSG_PARENT_AUTHENTICATE: {
189 			struct auth	*reply = imsg.data;
190 			struct session	*s;
191 
192 			log_debug("smtp_dispatch_parent: got auth reply");
193 
194 			IMSG_SIZE_CHECK(reply);
195 
196 			if ((s = session_lookup(env, reply->id)) == NULL)
197 				break;
198 
199 			if (reply->success) {
200 				s->s_flags |= F_AUTHENTICATED;
201 				s->s_msg.flags |= F_MESSAGE_AUTHENTICATED;
202 			} else {
203 				s->s_flags &= ~F_AUTHENTICATED;
204 				s->s_msg.flags &= ~F_MESSAGE_AUTHENTICATED;
205 			}
206 
207 			session_pickup(s, NULL);
208 			break;
209 		}
210 		default:
211 			log_warnx("smtp_dispatch_parent: got imsg %d",
212 			    imsg.hdr.type);
213 			fatalx("smtp_dispatch_parent: unexpected imsg");
214 		}
215 		imsg_free(&imsg);
216 	}
217 	imsg_event_add(iev);
218 }
219 
220 void
221 smtp_dispatch_mfa(int sig, short event, void *p)
222 {
223 	struct smtpd		*env = p;
224 	struct imsgev		*iev;
225 	struct imsgbuf		*ibuf;
226 	struct imsg		 imsg;
227 	ssize_t			 n;
228 
229 	iev = env->sc_ievs[PROC_MFA];
230 	ibuf = &iev->ibuf;
231 
232 	if (event & EV_READ) {
233 		if ((n = imsg_read(ibuf)) == -1)
234 			fatal("imsg_read_error");
235 		if (n == 0) {
236 			/* this pipe is dead, so remove the event handler */
237 			event_del(&iev->ev);
238 			event_loopexit(NULL);
239 			return;
240 		}
241 	}
242 
243 	if (event & EV_WRITE) {
244 		if (msgbuf_write(&ibuf->w) == -1)
245 			fatal("msgbuf_write");
246 	}
247 
248 	for (;;) {
249 		if ((n = imsg_get(ibuf, &imsg)) == -1)
250 			fatal("smtp_dispatch_mfa: imsg_get error");
251 		if (n == 0)
252 			break;
253 
254 		switch (imsg.hdr.type) {
255 		case IMSG_MFA_MAIL:
256 		case IMSG_MFA_RCPT: {
257 			struct submit_status	*ss = imsg.data;
258 			struct session		*s;
259 
260 			log_debug("smtp_dispatch_mfa: mfa handled return path");
261 
262 			IMSG_SIZE_CHECK(ss);
263 
264 			if ((s = session_lookup(env, ss->id)) == NULL)
265 				break;
266 
267 			session_pickup(s, ss);
268 			break;
269 		}
270 		default:
271 			log_warnx("smtp_dispatch_mfa: got imsg %d",
272 			    imsg.hdr.type);
273 			fatalx("smtp_dispatch_mfa: unexpected imsg");
274 		}
275 		imsg_free(&imsg);
276 	}
277 	imsg_event_add(iev);
278 }
279 
280 void
281 smtp_dispatch_lka(int sig, short event, void *p)
282 {
283 	struct smtpd		*env = p;
284 	struct imsgev		*iev;
285 	struct imsgbuf		*ibuf;
286 	struct imsg		 imsg;
287 	ssize_t			 n;
288 
289 	iev = env->sc_ievs[PROC_LKA];
290 	ibuf = &iev->ibuf;
291 
292 	if (event & EV_READ) {
293 		if ((n = imsg_read(ibuf)) == -1)
294 			fatal("imsg_read_error");
295 		if (n == 0) {
296 			/* this pipe is dead, so remove the event handler */
297 			event_del(&iev->ev);
298 			event_loopexit(NULL);
299 			return;
300 		}
301 	}
302 
303 	if (event & EV_WRITE) {
304 		if (msgbuf_write(&ibuf->w) == -1)
305 			fatal("msgbuf_write");
306 	}
307 
308 	for (;;) {
309 		if ((n = imsg_get(ibuf, &imsg)) == -1)
310 			fatal("smtp_dispatch_lka: imsg_get error");
311 		if (n == 0)
312 			break;
313 
314 		switch (imsg.hdr.type) {
315 		case IMSG_DNS_PTR: {
316 			struct dns		*reply = imsg.data;
317 			struct session		*s;
318 			struct session		 key;
319 
320 			IMSG_SIZE_CHECK(reply);
321 
322 			key.s_id = reply->id;
323 
324 			s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key);
325 			if (s == NULL)
326 				fatal("smtp_dispatch_lka: session is gone");
327 
328 			strlcpy(s->s_hostname,
329 			    reply->error ? "<unknown>" : reply->host,
330 			    sizeof(s->s_hostname));
331 
332 			strlcpy(s->s_msg.session_hostname, s->s_hostname,
333 			    sizeof(s->s_msg.session_hostname));
334 
335 			session_init(s->s_l, s);
336 
337 			break;
338 		}
339 		default:
340 			log_warnx("smtp_dispatch_lka: got imsg %d",
341 			    imsg.hdr.type);
342 			fatalx("smtp_dispatch_lka: unexpected imsg");
343 		}
344 		imsg_free(&imsg);
345 	}
346 	imsg_event_add(iev);
347 }
348 
349 void
350 smtp_dispatch_queue(int sig, short event, void *p)
351 {
352 	struct smtpd		*env = p;
353 	struct imsgev		*iev;
354 	struct imsgbuf		*ibuf;
355 	struct imsg		 imsg;
356 	ssize_t			 n;
357 
358 	iev = env->sc_ievs[PROC_QUEUE];
359 	ibuf = &iev->ibuf;
360 
361 	if (event & EV_READ) {
362 		if ((n = imsg_read(ibuf)) == -1)
363 			fatal("imsg_read_error");
364 		if (n == 0) {
365 			/* this pipe is dead, so remove the event handler */
366 			event_del(&iev->ev);
367 			event_loopexit(NULL);
368 			return;
369 		}
370 	}
371 
372 	if (event & EV_WRITE) {
373 		if (msgbuf_write(&ibuf->w) == -1)
374 			fatal("msgbuf_write");
375 	}
376 
377 	for (;;) {
378 		if ((n = imsg_get(ibuf, &imsg)) == -1)
379 			fatal("smtp_dispatch_queue: imsg_get error");
380 		if (n == 0)
381 			break;
382 
383 		switch (imsg.hdr.type) {
384 		case IMSG_QUEUE_CREATE_MESSAGE: {
385 			struct submit_status	*ss = imsg.data;
386 			struct session		*s;
387 
388 			log_debug("smtp_dispatch_queue: queue handled message creation");
389 
390 			IMSG_SIZE_CHECK(ss);
391 
392 			if ((s = session_lookup(env, ss->id)) == NULL)
393 				break;
394 
395 			(void)strlcpy(s->s_msg.message_id, ss->u.msgid,
396 			    sizeof(s->s_msg.message_id));
397 			session_pickup(s, ss);
398 			break;
399 		}
400 		case IMSG_QUEUE_MESSAGE_FILE: {
401 			struct submit_status	*ss = imsg.data;
402 			struct session		*s;
403 			int			 fd;
404 
405 			log_debug("smtp_dispatch_queue: queue handled message creation");
406 
407 			IMSG_SIZE_CHECK(ss);
408 
409 			fd = imsg.fd;
410 
411 			if ((s = session_lookup(env, ss->id)) == NULL) {
412 				close(fd);
413 				break;
414 			}
415 
416 			if ((s->datafp = fdopen(fd, "w")) == NULL) {
417 				/* queue may have experienced tempfail. */
418 				if (ss->code != 421)
419 					fatal("smtp_dispatch_queue: fdopen");
420 				close(fd);
421 			}
422 
423 			session_pickup(s, ss);
424 			break;
425 		}
426 		case IMSG_QUEUE_TEMPFAIL: {
427 			struct submit_status	*ss = imsg.data;
428 			struct session		*s;
429 			struct session		 key;
430 
431 			log_debug("smtp_dispatch_queue: tempfail in queue");
432 
433 			IMSG_SIZE_CHECK(ss);
434 
435 			key.s_id = ss->id;
436 			s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key);
437 			if (s == NULL)
438 				fatalx("smtp_dispatch_queue: session is gone");
439 
440 			if (s->s_flags & F_WRITEONLY) {
441 				/*
442 				 * Session is write-only, can't destroy it.
443 				 */
444 				s->s_msg.status |= S_MESSAGE_TEMPFAILURE;
445 			} else
446 				fatalx("smtp_dispatch_queue: corrupt session");
447 			break;
448 		}
449 
450 		case IMSG_QUEUE_COMMIT_ENVELOPES:
451 		case IMSG_QUEUE_COMMIT_MESSAGE: {
452 			struct submit_status	*ss = imsg.data;
453 			struct session		*s;
454 
455 			log_debug("smtp_dispatch_queue: queue acknowledged message submission");
456 
457 			IMSG_SIZE_CHECK(ss);
458 
459 			if ((s = session_lookup(env, ss->id)) == NULL)
460 				break;
461 
462 			session_pickup(s, ss);
463 			break;
464 		}
465 		default:
466 			log_warnx("smtp_dispatch_queue: got imsg %d",
467 			    imsg.hdr.type);
468 			fatalx("smtp_dispatch_queue: unexpected imsg");
469 		}
470 		imsg_free(&imsg);
471 	}
472 	imsg_event_add(iev);
473 }
474 
475 void
476 smtp_dispatch_control(int sig, short event, void *p)
477 {
478 	struct smtpd		*env = p;
479 	struct imsgev		*iev;
480 	struct imsgbuf		*ibuf;
481 	struct imsg		 imsg;
482 	ssize_t			 n;
483 
484 	iev = env->sc_ievs[PROC_CONTROL];
485 	ibuf = &iev->ibuf;
486 
487 	if (event & EV_READ) {
488 		if ((n = imsg_read(ibuf)) == -1)
489 			fatal("imsg_read_error");
490 		if (n == 0) {
491 			/* this pipe is dead, so remove the event handler */
492 			event_del(&iev->ev);
493 			event_loopexit(NULL);
494 			return;
495 		}
496 	}
497 
498 	if (event & EV_WRITE) {
499 		if (msgbuf_write(&ibuf->w) == -1)
500 			fatal("msgbuf_write");
501 	}
502 
503 	for (;;) {
504 		if ((n = imsg_get(ibuf, &imsg)) == -1)
505 			fatal("smtp_dispatch_control: imsg_get error");
506 		if (n == 0)
507 			break;
508 
509 		switch (imsg.hdr.type) {
510 		case IMSG_SMTP_ENQUEUE: {
511 			static struct listener	 l;
512 			struct addrinfo		 hints, *res;
513 			struct session		*s;
514 			uid_t			 euid;
515 			int			 fd[2];
516 
517 			bzero(&l, sizeof(l));
518 			l.env = env;
519 
520 			memcpy(&euid, imsg.data, sizeof(euid));
521 
522 			if (env->stats->smtp.sessions_active >=
523 			    env->sc_maxconn) {
524 				log_warnx("denying local connection, too many"
525 				    " sessions active");
526 				imsg_compose_event(iev, IMSG_SMTP_ENQUEUE,
527 				    imsg.hdr.peerid, 0, -1, NULL, 0);
528 				break;
529 			}
530 
531 			if (socketpair(
532 			    AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd) == -1)
533 				fatal("socketpair");
534 
535 			if ((s = calloc(1, sizeof(*s))) == NULL)
536 				fatal(NULL);
537 
538 			s->s_id = generate_uid();
539 			s->s_fd = fd[0];
540 			s->s_env = env;
541 			s->s_l = &l;
542 			s->s_msg.flags |= F_MESSAGE_ENQUEUED;
543 			(void)strlcpy(s->s_msg.tag, s->s_l->tag, sizeof(s->s_msg.tag));
544 
545 			bzero(&hints, sizeof(hints));
546 			hints.ai_family = PF_UNSPEC;
547 			hints.ai_flags = AI_NUMERICHOST;
548 
549 			if (getaddrinfo("::1", NULL, &hints, &res) != 0)
550 				fatal("getaddrinfo");
551 
552 			memcpy(&s->s_ss, res->ai_addr, res->ai_addrlen);
553 
554 			env->stats->smtp.sessions++;
555 			env->stats->smtp.sessions_active++;
556 
557 			bsnprintf(s->s_hostname, sizeof(s->s_hostname),
558 			    "%d@localhost", euid);
559 			strlcpy(s->s_msg.session_hostname, s->s_hostname,
560 			    sizeof(s->s_msg.session_hostname));
561 
562 			SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s);
563 
564 			session_init(s->s_l, s);
565 
566 			imsg_compose_event(iev, IMSG_SMTP_ENQUEUE,
567 			    imsg.hdr.peerid, 0, fd[1], NULL, 0);
568 			break;
569 		}
570 		case IMSG_SMTP_PAUSE:
571 			smtp_pause(env);
572 			break;
573 		case IMSG_SMTP_RESUME:
574 			smtp_resume(env);
575 			break;
576 		default:
577 			log_warnx("smtp_dispatch_control: got imsg %d",
578 			    imsg.hdr.type);
579 			fatalx("smtp_dispatch_control: unexpected imsg");
580 		}
581 		imsg_free(&imsg);
582 	}
583 	imsg_event_add(iev);
584 }
585 
586 void
587 smtp_dispatch_runner(int sig, short event, void *p)
588 {
589 	struct smtpd		*env = p;
590 	struct imsgev		*iev;
591 	struct imsgbuf		*ibuf;
592 	struct imsg		 imsg;
593 	ssize_t			 n;
594 
595 	iev = env->sc_ievs[PROC_RUNNER];
596 	ibuf = &iev->ibuf;
597 
598 	if (event & EV_READ) {
599 		if ((n = imsg_read(ibuf)) == -1)
600 			fatal("imsg_read_error");
601 		if (n == 0) {
602 			/* this pipe is dead, so remove the event handler */
603 			event_del(&iev->ev);
604 			event_loopexit(NULL);
605 			return;
606 		}
607 	}
608 
609 	if (event & EV_WRITE) {
610 		if (msgbuf_write(&ibuf->w) == -1)
611 			fatal("msgbuf_write");
612 	}
613 
614 	for (;;) {
615 		if ((n = imsg_get(ibuf, &imsg)) == -1)
616 			fatal("smtp_dispatch_runner: imsg_get error");
617 		if (n == 0)
618 			break;
619 
620 		switch (imsg.hdr.type) {
621 		case IMSG_SMTP_ENQUEUE: {
622 			static struct listener	 l;
623 			struct addrinfo		 hints, *res;
624 			struct session		*s;
625 			int			 fd[2];
626 
627 			bzero(&l, sizeof(l));
628 			l.env = env;
629 
630 			if (env->stats->smtp.sessions_active >=
631 			    env->sc_maxconn) {
632 				log_warnx("denying internal connection, too many"
633 				    " sessions active");
634 				imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 0, 0, -1,
635 				    imsg.data, sizeof(struct message));
636 				break;
637 			}
638 
639 			if (socketpair(
640 			    AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd) == -1)
641 				fatal("socketpair");
642 
643 			if ((s = calloc(1, sizeof(*s))) == NULL)
644 				fatal(NULL);
645 
646 			s->s_id = generate_uid();
647 			s->s_fd = fd[0];
648 			s->s_env = env;
649 			s->s_l = &l;
650 			s->s_msg.flags |= F_MESSAGE_ENQUEUED|F_MESSAGE_BOUNCE;
651 
652 			bzero(&hints, sizeof(hints));
653 			hints.ai_family = PF_UNSPEC;
654 			hints.ai_flags = AI_NUMERICHOST;
655 
656 			if (getaddrinfo("::1", NULL, &hints, &res) != 0)
657 				fatal("getaddrinfo");
658 
659 			memcpy(&s->s_ss, res->ai_addr, res->ai_addrlen);
660 
661 			env->stats->smtp.sessions++;
662 			env->stats->smtp.sessions_active++;
663 
664 			strlcpy(s->s_hostname, "localhost",
665 			    sizeof(s->s_hostname));
666 			strlcpy(s->s_msg.session_hostname, s->s_hostname,
667 			    sizeof(s->s_msg.session_hostname));
668 
669 			SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s);
670 
671 			session_init(s->s_l, s);
672 
673 			imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 0, 0, fd[1],
674 			    imsg.data, sizeof(struct message));
675 			break;
676 		}
677 		default:
678 			log_warnx("smtp_dispatch_runner: got imsg %d",
679 			    imsg.hdr.type);
680 			fatalx("smtp_dispatch_runner: unexpected imsg");
681 		}
682 		imsg_free(&imsg);
683 	}
684 	imsg_event_add(iev);
685 }
686 
687 void
688 smtp_shutdown(void)
689 {
690 	log_info("smtp server exiting");
691 	_exit(0);
692 }
693 
694 pid_t
695 smtp(struct smtpd *env)
696 {
697 	pid_t		 pid;
698 	struct passwd	*pw;
699 
700 	struct event	 ev_sigint;
701 	struct event	 ev_sigterm;
702 
703 	struct peer peers[] = {
704 		{ PROC_PARENT,	smtp_dispatch_parent },
705 		{ PROC_MFA,	smtp_dispatch_mfa },
706 		{ PROC_QUEUE,	smtp_dispatch_queue },
707 		{ PROC_LKA,	smtp_dispatch_lka },
708 		{ PROC_CONTROL,	smtp_dispatch_control },
709 		{ PROC_RUNNER,	smtp_dispatch_runner }
710 	};
711 
712 	switch (pid = fork()) {
713 	case -1:
714 		fatal("smtp: cannot fork");
715 	case 0:
716 		break;
717 	default:
718 		return (pid);
719 	}
720 
721 	ssl_init();
722 	purge_config(env, PURGE_EVERYTHING);
723 
724 	pw = env->sc_pw;
725 
726 #ifndef DEBUG
727 	if (chroot(pw->pw_dir) == -1)
728 		fatal("smtp: chroot");
729 	if (chdir("/") == -1)
730 		fatal("smtp: chdir(\"/\")");
731 #else
732 #warning disabling privilege revocation and chroot in DEBUG MODE
733 #endif
734 
735 	smtpd_process = PROC_SMTP;
736 	setproctitle("%s", env->sc_title[smtpd_process]);
737 
738 #ifndef DEBUG
739 	if (setgroups(1, &pw->pw_gid) ||
740 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
741 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
742 		fatal("smtp: cannot drop privileges");
743 #endif
744 
745 	event_init();
746 
747 	signal_set(&ev_sigint, SIGINT, smtp_sig_handler, env);
748 	signal_set(&ev_sigterm, SIGTERM, smtp_sig_handler, env);
749 	signal_add(&ev_sigint, NULL);
750 	signal_add(&ev_sigterm, NULL);
751 	signal(SIGPIPE, SIG_IGN);
752 	signal(SIGHUP, SIG_IGN);
753 
754 	config_pipes(env, peers, nitems(peers));
755 	config_peers(env, peers, nitems(peers));
756 
757 	event_dispatch();
758 	smtp_shutdown();
759 
760 	return (0);
761 }
762 
763 void
764 smtp_setup_events(struct smtpd *env)
765 {
766 	struct listener *l;
767 
768 	TAILQ_FOREACH(l, env->sc_listeners, entry) {
769 		log_debug("smtp_setup_events: listen on %s port %d flags 0x%01x"
770 		    " cert \"%s\"", ss_to_text(&l->ss), ntohs(l->port),
771 		    l->flags, l->ssl_cert_name);
772 
773 		session_socket_blockmode(l->fd, BM_NONBLOCK);
774 		if (listen(l->fd, SMTPD_BACKLOG) == -1)
775 			fatal("listen");
776 		l->env = env;
777 		event_set(&l->ev, l->fd, EV_READ, smtp_accept, l);
778 		event_add(&l->ev, NULL);
779 		ssl_setup(env, l);
780 	}
781 }
782 
783 void
784 smtp_disable_events(struct smtpd *env)
785 {
786 	struct listener	*l;
787 
788 	log_debug("smtp_disable_events: closing listening sockets");
789 	while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) {
790 		TAILQ_REMOVE(env->sc_listeners, l, entry);
791 		event_del(&l->ev);
792 		close(l->fd);
793 		free(l);
794 	}
795 	free(env->sc_listeners);
796 	env->sc_listeners = NULL;
797 }
798 
799 void
800 smtp_pause(struct smtpd *env)
801 {
802 	struct listener *l;
803 
804 	log_debug("smtp_pause: pausing listening sockets");
805 	env->sc_opts |= SMTPD_SMTP_PAUSED;
806 
807 	TAILQ_FOREACH(l, env->sc_listeners, entry)
808 		event_del(&l->ev);
809 }
810 
811 void
812 smtp_resume(struct smtpd *env)
813 {
814 	struct listener *l;
815 
816 	log_debug("smtp_resume: resuming listening sockets");
817 	env->sc_opts &= ~SMTPD_SMTP_PAUSED;
818 
819 	TAILQ_FOREACH(l, env->sc_listeners, entry)
820 		event_add(&l->ev, NULL);
821 }
822 
823 void
824 smtp_accept(int fd, short event, void *p)
825 {
826 	int			 s_fd;
827 	struct sockaddr_storage	 ss;
828 	struct listener		*l = p;
829 	struct session		*s;
830 	socklen_t		 len;
831 
832 	log_debug("smtp_accept: incoming client on listener: %p", l);
833 	len = sizeof(struct sockaddr_storage);
834 	if ((s_fd = accept(l->fd, (struct sockaddr *)&ss, &len)) == -1) {
835 		event_del(&l->ev);
836 		return;
837 	}
838 
839 	log_debug("smtp_accept: accepted client on listener: %p", l);
840 	if ((s = calloc(1, sizeof(*s))) == NULL)
841 		fatal(NULL);
842 	len = sizeof(s->s_ss);
843 
844 	s->s_id = generate_uid();
845 	s->s_fd = s_fd;
846 	s->s_env = l->env;
847 	s->s_l = l;
848 
849 	(void)memcpy(&s->s_ss, &ss, sizeof(s->s_ss));
850 
851 	event_add(&l->ev, NULL);
852 
853 	s->s_env->stats->smtp.sessions++;
854 	s->s_env->stats->smtp.sessions_active++;
855 
856 	if (s->s_env->stats->smtp.sessions_active == s->s_env->sc_maxconn)
857 		event_del(&l->ev);
858 
859 	dns_query_ptr(l->env, &s->s_ss, s->s_id);
860 
861 	SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s);
862 }
863 
864 /*
865  * Helper function for handling IMSG replies.
866  */
867 struct session *
868 session_lookup(struct smtpd *env, u_int64_t id)
869 {
870 	struct session	 key;
871 	struct session	*s;
872 
873 	key.s_id = id;
874 	s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key);
875 	if (s == NULL)
876 		fatalx("session_lookup: session is gone");
877 
878 	if (!(s->s_flags & F_WRITEONLY))
879 		fatalx("session_lookup: corrupt session");
880 	s->s_flags &= ~F_WRITEONLY;
881 
882 	if (s->s_flags & F_QUIT) {
883 		session_destroy(s);
884 		s = NULL;
885 	}
886 
887 	return (s);
888 }
889