xref: /openbsd-src/usr.sbin/smtpd/smtp.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: smtp.c,v 1.41 2009/04/28 22:38:22 jacekm Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
5  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/queue.h>
22 #include <sys/tree.h>
23 #include <sys/param.h>
24 #include <sys/socket.h>
25 
26 #include <ctype.h>
27 #include <event.h>
28 #include <netdb.h>
29 #include <pwd.h>
30 #include <signal.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 #include <unistd.h>
36 
37 #include "smtpd.h"
38 
39 __dead void	smtp_shutdown(void);
40 void		smtp_sig_handler(int, short, void *);
41 void		smtp_dispatch_parent(int, short, void *);
42 void		smtp_dispatch_mfa(int, short, void *);
43 void		smtp_dispatch_lka(int, short, void *);
44 void		smtp_dispatch_queue(int, short, void *);
45 void		smtp_dispatch_control(int, short, void *);
46 void		smtp_setup_events(struct smtpd *);
47 void		smtp_disable_events(struct smtpd *);
48 void		smtp_pause(struct smtpd *);
49 void		smtp_resume(struct smtpd *);
50 void		smtp_accept(int, short, void *);
51 void		session_auth_pickup(struct session *, char *, size_t);
52 struct session *session_lookup(struct smtpd *, u_int64_t);
53 
54 struct s_session	s_smtp;
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 imsgbuf		*ibuf;
74 	struct imsg		 imsg;
75 	ssize_t			 n;
76 
77 	ibuf = env->sc_ibufs[PROC_PARENT];
78 	switch (event) {
79 	case EV_READ:
80 		if ((n = imsg_read(ibuf)) == -1)
81 			fatal("imsg_read_error");
82 		if (n == 0) {
83 			/* this pipe is dead, so remove the event handler */
84 			event_del(&ibuf->ev);
85 			event_loopexit(NULL);
86 			return;
87 		}
88 		break;
89 	case EV_WRITE:
90 		if (msgbuf_write(&ibuf->w) == -1)
91 			fatal("msgbuf_write");
92 		imsg_event_add(ibuf);
93 		return;
94 	default:
95 		fatalx("unknown event");
96 	}
97 
98 	for (;;) {
99 		if ((n = imsg_get(ibuf, &imsg)) == -1)
100 			fatalx("smtp_dispatch_parent: imsg_get error");
101 		if (n == 0)
102 			break;
103 
104 		switch (imsg.hdr.type) {
105 		case IMSG_CONF_START:
106 			if (env->sc_flags & SMTPD_CONFIGURING)
107 				break;
108 			env->sc_flags |= SMTPD_CONFIGURING;
109 			smtp_disable_events(env);
110 			break;
111 		case IMSG_CONF_SSL: {
112 			struct ssl	*s;
113 			struct ssl	*x_ssl;
114 
115 			if (!(env->sc_flags & SMTPD_CONFIGURING))
116 				break;
117 
118 			if ((s = calloc(1, sizeof(*s))) == NULL)
119 				fatal(NULL);
120 			x_ssl = imsg.data;
121 			(void)strlcpy(s->ssl_name, x_ssl->ssl_name,
122 			    sizeof(s->ssl_name));
123 			s->ssl_cert_len = x_ssl->ssl_cert_len;
124 			if ((s->ssl_cert =
125 			    strdup((char *)imsg.data + sizeof(*s))) == NULL)
126 				fatal(NULL);
127 			s->ssl_key_len = x_ssl->ssl_key_len;
128 			if ((s->ssl_key = strdup((char *)imsg.data +
129 			    (sizeof(*s) + s->ssl_cert_len))) == NULL)
130 				fatal(NULL);
131 
132 			SPLAY_INSERT(ssltree, &env->sc_ssl, s);
133 			break;
134 		}
135 		case IMSG_CONF_LISTENER: {
136 			struct listener	*l;
137 			struct ssl	 key;
138 
139 			if (!(env->sc_flags & SMTPD_CONFIGURING))
140 				break;
141 
142 			if ((l = calloc(1, sizeof(*l))) == NULL)
143 				fatal(NULL);
144 			memcpy(l, imsg.data, sizeof(*l));
145 			if ((l->fd = imsg_get_fd(ibuf, &imsg)) == -1)
146 				fatal("cannot get fd");
147 
148 			(void)strlcpy(key.ssl_name, l->ssl_cert_name,
149 			    sizeof(key.ssl_name));
150 
151 			if (l->flags & F_SSL)
152 				if ((l->ssl = SPLAY_FIND(ssltree,
153 				    &env->sc_ssl, &key)) == NULL)
154 					fatal("parent and smtp desynchronized");
155 
156 			TAILQ_INSERT_TAIL(&env->sc_listeners, l, entry);
157 			break;
158 		}
159 		case IMSG_CONF_END:
160 			if (!(env->sc_flags & SMTPD_CONFIGURING))
161 				break;
162 			smtp_setup_events(env);
163 			env->sc_flags &= ~SMTPD_CONFIGURING;
164 			break;
165 		case IMSG_PARENT_AUTHENTICATE: {
166 			struct session			*s;
167 			struct session_auth_reply	*reply = imsg.data;
168 
169 			log_debug("smtp_dispatch_parent: parent handled authentication");
170 
171 			if ((s = session_lookup(env, reply->session_id)) == NULL)
172 				break;
173 
174 			if (reply->value)
175 				s->s_flags |= F_AUTHENTICATED;
176 
177 			session_auth_pickup(s, NULL, 0);
178 
179 			break;
180 		}
181 		default:
182 			log_warnx("smtp_dispatch_parent: got imsg %d",
183 			    imsg.hdr.type);
184 			fatalx("smtp_dispatch_parent: unexpected imsg");
185 		}
186 		imsg_free(&imsg);
187 	}
188 	imsg_event_add(ibuf);
189 }
190 
191 void
192 smtp_dispatch_mfa(int sig, short event, void *p)
193 {
194 	struct smtpd		*env = p;
195 	struct imsgbuf		*ibuf;
196 	struct imsg		 imsg;
197 	ssize_t			 n;
198 
199 	ibuf = env->sc_ibufs[PROC_MFA];
200 	switch (event) {
201 	case EV_READ:
202 		if ((n = imsg_read(ibuf)) == -1)
203 			fatal("imsg_read_error");
204 		if (n == 0) {
205 			/* this pipe is dead, so remove the event handler */
206 			event_del(&ibuf->ev);
207 			event_loopexit(NULL);
208 			return;
209 		}
210 		break;
211 	case EV_WRITE:
212 		if (msgbuf_write(&ibuf->w) == -1)
213 			fatal("msgbuf_write");
214 		imsg_event_add(ibuf);
215 		return;
216 	default:
217 		fatalx("unknown event");
218 	}
219 
220 	for (;;) {
221 		if ((n = imsg_get(ibuf, &imsg)) == -1)
222 			fatalx("smtp_dispatch_mfa: imsg_get error");
223 		if (n == 0)
224 			break;
225 
226 		switch (imsg.hdr.type) {
227 		case IMSG_MFA_MAIL:
228 		case IMSG_MFA_RCPT: {
229 			struct submit_status	*ss = imsg.data;
230 			struct session		*s;
231 
232 			log_debug("smtp_dispatch_mfa: mfa handled return path");
233 
234 			if ((s = session_lookup(env, ss->id)) == NULL)
235 				break;
236 
237 			session_pickup(s, ss);
238 			break;
239 		}
240 		default:
241 			log_warnx("smtp_dispatch_mfa: got imsg %d",
242 			    imsg.hdr.type);
243 			fatalx("smtp_dispatch_mfa: unexpected imsg");
244 		}
245 		imsg_free(&imsg);
246 	}
247 	imsg_event_add(ibuf);
248 }
249 
250 void
251 smtp_dispatch_lka(int sig, short event, void *p)
252 {
253 	struct smtpd		*env = p;
254 	struct imsgbuf		*ibuf;
255 	struct imsg		 imsg;
256 	ssize_t			 n;
257 
258 	ibuf = env->sc_ibufs[PROC_LKA];
259 	switch (event) {
260 	case EV_READ:
261 		if ((n = imsg_read(ibuf)) == -1)
262 			fatal("imsg_read_error");
263 		if (n == 0) {
264 			/* this pipe is dead, so remove the event handler */
265 			event_del(&ibuf->ev);
266 			event_loopexit(NULL);
267 			return;
268 		}
269 		break;
270 	case EV_WRITE:
271 		if (msgbuf_write(&ibuf->w) == -1)
272 			fatal("msgbuf_write");
273 		imsg_event_add(ibuf);
274 		return;
275 	default:
276 		fatalx("unknown event");
277 	}
278 
279 	for (;;) {
280 		if ((n = imsg_get(ibuf, &imsg)) == -1)
281 			fatalx("smtp_dispatch_lka: imsg_get error");
282 		if (n == 0)
283 			break;
284 
285 		switch (imsg.hdr.type) {
286 		case IMSG_LKA_HOST: {
287 			struct session		 key;
288 			struct session		*s;
289 			struct session		*ss;
290 
291 			ss = imsg.data;
292 			key.s_id = ss->s_id;
293 
294 			s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key);
295 			if (s == NULL)
296 				fatal("smtp_dispatch_lka: session is gone");
297 
298 			strlcpy(s->s_hostname, ss->s_hostname,
299 			    sizeof(s->s_hostname));
300 			strlcpy(s->s_msg.session_hostname, ss->s_hostname,
301 			    sizeof(s->s_msg.session_hostname));
302 
303 			session_init(s->s_l, s);
304 
305 			break;
306 		}
307 		default:
308 			log_warnx("smtp_dispatch_lka: got imsg %d",
309 			    imsg.hdr.type);
310 			fatalx("smtp_dispatch_lka: unexpected imsg");
311 		}
312 		imsg_free(&imsg);
313 	}
314 	imsg_event_add(ibuf);
315 }
316 
317 void
318 smtp_dispatch_queue(int sig, short event, void *p)
319 {
320 	struct smtpd		*env = p;
321 	struct imsgbuf		*ibuf;
322 	struct imsg		 imsg;
323 	ssize_t			 n;
324 
325 	ibuf = env->sc_ibufs[PROC_QUEUE];
326 	switch (event) {
327 	case EV_READ:
328 		if ((n = imsg_read(ibuf)) == -1)
329 			fatal("imsg_read_error");
330 		if (n == 0) {
331 			/* this pipe is dead, so remove the event handler */
332 			event_del(&ibuf->ev);
333 			event_loopexit(NULL);
334 			return;
335 		}
336 		break;
337 	case EV_WRITE:
338 		if (msgbuf_write(&ibuf->w) == -1)
339 			fatal("msgbuf_write");
340 		imsg_event_add(ibuf);
341 		return;
342 	default:
343 		fatalx("unknown event");
344 	}
345 
346 	for (;;) {
347 		if ((n = imsg_get(ibuf, &imsg)) == -1)
348 			fatalx("smtp_dispatch_queue: imsg_get error");
349 		if (n == 0)
350 			break;
351 
352 		switch (imsg.hdr.type) {
353 		case IMSG_QUEUE_CREATE_MESSAGE: {
354 			struct submit_status	*ss = imsg.data;
355 			struct session		*s;
356 
357 			log_debug("smtp_dispatch_queue: queue handled message creation");
358 
359 			if ((s = session_lookup(env, ss->id)) == NULL)
360 				break;
361 
362 			(void)strlcpy(s->s_msg.message_id, ss->u.msgid,
363 			    sizeof(s->s_msg.message_id));
364 			session_pickup(s, ss);
365 			break;
366 		}
367 		case IMSG_QUEUE_MESSAGE_FILE: {
368 			struct submit_status	*ss = imsg.data;
369 			struct session		*s;
370 			int			 fd;
371 
372 			log_debug("smtp_dispatch_queue: queue handled message creation");
373 
374 			fd = imsg_get_fd(ibuf, &imsg);
375 
376 			if ((s = session_lookup(env, ss->id)) == NULL) {
377 				close(fd);
378 				break;
379 			}
380 
381 			if ((s->datafp = fdopen(fd, "w")) == NULL) {
382 				/* queue may have experienced tempfail. */
383 				if (ss->code != 421)
384 					fatal("smtp_dispatch_queue: fdopen");
385 				close(fd);
386 			}
387 
388 			session_pickup(s, ss);
389 			break;
390 		}
391 		case IMSG_QUEUE_TEMPFAIL: {
392 			struct submit_status	*ss = imsg.data;
393 			struct session		*s;
394 			struct session		 key;
395 
396 			log_debug("smtp_dispatch_queue: tempfail in queue");
397 
398 			/*
399 			 * IMSG_QUEUE_TEMPFAIL is not the final reply to
400 			 * IMSG_MFA_RCPT - IMSG_QUEUE_COMMIT_ENVELOPES is.
401 			 * Therefore, nothing more but updating the flags
402 			 * is allowed here. If session_lookup were to be
403 			 * called, then subsequent session_lookup in the
404 			 * IMSG_QUEUE_COMMIT_ENVELOPES handler would fatal for
405 			 * either of two reasons: missing session, or missing
406 			 * EVLOCKED flag.
407 			 */
408 			key.s_id = ss->id;
409 			s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key);
410 			if (s == NULL)
411 				fatalx("smtp_dispatch_queue: session is gone");
412 
413 			s->s_msg.status |= S_MESSAGE_TEMPFAILURE;
414 			break;
415 		}
416 
417 		case IMSG_QUEUE_COMMIT_ENVELOPES:
418 		case IMSG_QUEUE_COMMIT_MESSAGE: {
419 			struct submit_status	*ss = imsg.data;
420 			struct session		*s;
421 
422 			log_debug("smtp_dispatch_queue: queue acknowledged message submission");
423 
424 			if ((s = session_lookup(env, ss->id)) == NULL)
425 				break;
426 
427 			session_pickup(s, ss);
428 			break;
429 		}
430 		default:
431 			log_warnx("smtp_dispatch_queue: got imsg %d",
432 			    imsg.hdr.type);
433 			fatalx("smtp_dispatch_queue: unexpected imsg");
434 		}
435 		imsg_free(&imsg);
436 	}
437 	imsg_event_add(ibuf);
438 }
439 
440 void
441 smtp_dispatch_control(int sig, short event, void *p)
442 {
443 	struct smtpd		*env = p;
444 	struct imsgbuf		*ibuf;
445 	struct imsg		 imsg;
446 	ssize_t			 n;
447 
448 	ibuf = env->sc_ibufs[PROC_CONTROL];
449 	switch (event) {
450 	case EV_READ:
451 		if ((n = imsg_read(ibuf)) == -1)
452 			fatal("imsg_read_error");
453 		if (n == 0) {
454 			/* this pipe is dead, so remove the event handler */
455 			event_del(&ibuf->ev);
456 			event_loopexit(NULL);
457 			return;
458 		}
459 		break;
460 	case EV_WRITE:
461 		if (msgbuf_write(&ibuf->w) == -1)
462 			fatal("msgbuf_write");
463 		imsg_event_add(ibuf);
464 		return;
465 	default:
466 		fatalx("unknown event");
467 	}
468 
469 	for (;;) {
470 		if ((n = imsg_get(ibuf, &imsg)) == -1)
471 			fatalx("smtp_dispatch_control: imsg_get error");
472 		if (n == 0)
473 			break;
474 
475 		switch (imsg.hdr.type) {
476 		case IMSG_SMTP_ENQUEUE: {
477 			static struct listener	 l;
478 			struct addrinfo		 hints, *res;
479 			struct session		*s;
480 			int			 fd[2];
481 
482 			bzero(&l, sizeof(l));
483 			l.env = env;
484 
485 			if (s_smtp.sessions_active >= env->sc_maxconn) {
486 				log_warnx("denying local connection, too many"
487 				    " sessions active");
488 				imsg_compose(ibuf, IMSG_SMTP_ENQUEUE, 0, 0, -1,
489 				    imsg.data, sizeof(int));
490 				break;
491 			}
492 
493 			if (socketpair(
494 			    AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd) == -1)
495 				fatal("socketpair");
496 
497 			if ((s = calloc(1, sizeof(*s))) == NULL)
498 				fatal(NULL);
499 
500 			s->s_id = queue_generate_id();
501 			s->s_fd = fd[0];
502 			s->s_env = env;
503 			s->s_l = &l;
504 			s->s_msg.flags |= F_MESSAGE_ENQUEUED;
505 
506 			bzero(&hints, sizeof(hints));
507 			hints.ai_family = PF_UNSPEC;
508 			hints.ai_flags = AI_NUMERICHOST;
509 
510 			if (getaddrinfo("::1", NULL, &hints, &res) != 0)
511 				fatal("getaddrinfo");
512 
513 			memcpy(&s->s_ss, res->ai_addr, res->ai_addrlen);
514 
515 			s_smtp.sessions++;
516 			s_smtp.sessions_active++;
517 
518 			strlcpy(s->s_hostname, "localhost",
519 			    sizeof(s->s_hostname));
520 			strlcpy(s->s_msg.session_hostname, s->s_hostname,
521 			    sizeof(s->s_msg.session_hostname));
522 
523 			SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s);
524 
525 			session_init(s->s_l, s);
526 
527 			imsg_compose(ibuf, IMSG_SMTP_ENQUEUE, 0, 0, fd[1],
528 			    imsg.data, sizeof(int));
529 			break;
530 		}
531 		case IMSG_SMTP_PAUSE:
532 			smtp_pause(env);
533 			break;
534 		case IMSG_SMTP_RESUME:
535 			smtp_resume(env);
536 			break;
537 		case IMSG_STATS: {
538 			struct stats *s;
539 
540 			s = imsg.data;
541 			s->u.smtp = s_smtp;
542 			imsg_compose(ibuf, IMSG_STATS, 0, 0, -1, s, sizeof(*s));
543 			break;
544 		}
545 		default:
546 			log_warnx("smtp_dispatch_control: got imsg %d",
547 			    imsg.hdr.type);
548 			fatalx("smtp_dispatch_control: unexpected imsg");
549 		}
550 		imsg_free(&imsg);
551 	}
552 	imsg_event_add(ibuf);
553 }
554 
555 void
556 smtp_shutdown(void)
557 {
558 	log_info("smtp server exiting");
559 	_exit(0);
560 }
561 
562 pid_t
563 smtp(struct smtpd *env)
564 {
565 	pid_t		 pid;
566 	struct passwd	*pw;
567 
568 	struct event	 ev_sigint;
569 	struct event	 ev_sigterm;
570 
571 	struct peer peers[] = {
572 		{ PROC_PARENT,	smtp_dispatch_parent },
573 		{ PROC_MFA,	smtp_dispatch_mfa },
574 		{ PROC_QUEUE,	smtp_dispatch_queue },
575 		{ PROC_LKA,	smtp_dispatch_lka },
576 		{ PROC_CONTROL,	smtp_dispatch_control }
577 	};
578 
579 	switch (pid = fork()) {
580 	case -1:
581 		fatal("smtp: cannot fork");
582 	case 0:
583 		break;
584 	default:
585 		return (pid);
586 	}
587 
588 	ssl_init();
589 	purge_config(env, PURGE_EVERYTHING);
590 
591 	pw = env->sc_pw;
592 
593 #ifndef DEBUG
594 	if (chroot(pw->pw_dir) == -1)
595 		fatal("smtp: chroot");
596 	if (chdir("/") == -1)
597 		fatal("smtp: chdir(\"/\")");
598 #else
599 #warning disabling privilege revocation and chroot in DEBUG MODE
600 #endif
601 
602 	setproctitle("smtp server");
603 	smtpd_process = PROC_SMTP;
604 
605 #ifndef DEBUG
606 	if (setgroups(1, &pw->pw_gid) ||
607 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
608 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
609 		fatal("smtp: cannot drop privileges");
610 #endif
611 
612 	event_init();
613 
614 	signal_set(&ev_sigint, SIGINT, smtp_sig_handler, env);
615 	signal_set(&ev_sigterm, SIGTERM, smtp_sig_handler, env);
616 	signal_add(&ev_sigint, NULL);
617 	signal_add(&ev_sigterm, NULL);
618 	signal(SIGPIPE, SIG_IGN);
619 	signal(SIGHUP, SIG_IGN);
620 
621 	config_pipes(env, peers, 5);
622 	config_peers(env, peers, 5);
623 
624 	smtp_setup_events(env);
625 	event_dispatch();
626 	smtp_shutdown();
627 
628 	return (0);
629 }
630 
631 void
632 smtp_setup_events(struct smtpd *env)
633 {
634 	struct listener *l;
635 
636 	TAILQ_FOREACH(l, &env->sc_listeners, entry) {
637 		log_debug("smtp_setup_events: listen on %s port %d flags 0x%01x"
638 		    " cert \"%s\"", ss_to_text(&l->ss), ntohs(l->port),
639 		    l->flags, l->ssl_cert_name);
640 
641 		session_socket_blockmode(l->fd, BM_NONBLOCK);
642 		if (listen(l->fd, SMTPD_BACKLOG) == -1)
643 			fatal("listen");
644 		l->env = env;
645 		event_set(&l->ev, l->fd, EV_READ, smtp_accept, l);
646 		event_add(&l->ev, NULL);
647 		ssl_setup(env, l);
648 	}
649 }
650 
651 void
652 smtp_disable_events(struct smtpd *env)
653 {
654 	struct listener	*l;
655 
656 	log_debug("smtp_disable_events: closing listening sockets");
657 	while ((l = TAILQ_FIRST(&env->sc_listeners)) != NULL) {
658 		TAILQ_REMOVE(&env->sc_listeners, l, entry);
659 		event_del(&l->ev);
660 		close(l->fd);
661 		free(l);
662 	}
663 	TAILQ_INIT(&env->sc_listeners);
664 }
665 
666 void
667 smtp_pause(struct smtpd *env)
668 {
669 	log_debug("smtp_pause_listeners: pausing listening sockets");
670 	smtp_disable_events(env);
671 	env->sc_opts |= SMTPD_SMTP_PAUSED;
672 }
673 
674 void
675 smtp_resume(struct smtpd *env)
676 {
677 	log_debug("smtp_pause_listeners: resuming listening sockets");
678 	imsg_compose(env->sc_ibufs[PROC_PARENT], IMSG_PARENT_SEND_CONFIG,
679 	    0, 0, -1, NULL, 0);
680 	env->sc_opts &= ~SMTPD_SMTP_PAUSED;
681 }
682 
683 void
684 smtp_accept(int fd, short event, void *p)
685 {
686 	int			 s_fd;
687 	struct sockaddr_storage	 ss;
688 	struct listener		*l = p;
689 	struct session		*s;
690 	socklen_t		 len;
691 
692 	log_debug("smtp_accept: incoming client on listener: %p", l);
693 	len = sizeof(struct sockaddr_storage);
694 	if ((s_fd = accept(l->fd, (struct sockaddr *)&ss, &len)) == -1) {
695 		event_del(&l->ev);
696 		return;
697 	}
698 
699 	log_debug("smtp_accept: accepted client on listener: %p", l);
700 	if ((s = calloc(1, sizeof(*s))) == NULL)
701 		fatal(NULL);
702 	len = sizeof(s->s_ss);
703 
704 	s->s_id = queue_generate_id();
705 	s->s_fd = s_fd;
706 	s->s_env = l->env;
707 	s->s_l = l;
708 
709 	(void)memcpy(&s->s_ss, &ss, sizeof(s->s_ss));
710 
711 	event_add(&l->ev, NULL);
712 
713 	s_smtp.sessions++;
714 	s_smtp.sessions_active++;
715 
716 	if (s_smtp.sessions_active == s->s_env->sc_maxconn)
717 		event_del(&l->ev);
718 
719 	imsg_compose(s->s_env->sc_ibufs[PROC_LKA], IMSG_LKA_HOST, 0, 0, -1, s,
720 	    sizeof(struct session));
721 
722 	SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s);
723 }
724 
725 void
726 smtp_listener_setup(struct smtpd *env, struct listener *l)
727 {
728 	int opt;
729 
730 	if ((l->fd = socket(l->ss.ss_family, SOCK_STREAM, 0)) == -1)
731 		fatal("socket");
732 
733 	opt = 1;
734 	setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
735 
736 	if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) == -1)
737 		fatal("bind");
738 }
739 
740 /*
741  * Helper function for handling IMSG replies.
742  */
743 struct session *
744 session_lookup(struct smtpd *env, u_int64_t id)
745 {
746 	struct session	 key;
747 	struct session	*s;
748 
749 	key.s_id = id;
750 	s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key);
751 	if (s == NULL)
752 		fatalx("session_lookup: session is gone");
753 
754 	if (!(s->s_flags & F_EVLOCKED))
755 		fatalx("session_lookup: corrupt session");
756 	s->s_flags &= ~F_EVLOCKED;
757 
758 	if (s->s_flags & F_QUIT) {
759 		session_destroy(s);
760 		s = NULL;
761 	}
762 
763 	return (s);
764 }
765