xref: /openbsd-src/usr.sbin/smtpd/control.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: control.c,v 1.21 2009/03/29 14:18:20 jacekm Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5  * Copyright (c) 2003, 2004 Henning Brauer <henning@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/stat.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 
28 #include <errno.h>
29 #include <event.h>
30 #include <fcntl.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 
40 #define CONTROL_BACKLOG 5
41 
42 /* control specific headers */
43 struct {
44 	struct event		 ev;
45 	int			 fd;
46 } control_state;
47 
48 __dead void	 control_shutdown(void);
49 int		 control_init(void);
50 int		 control_listen(struct smtpd *);
51 void		 control_cleanup(void);
52 void		 control_accept(int, short, void *);
53 struct ctl_conn	*control_connbyfd(int);
54 void		 control_close(int);
55 void		 control_sig_handler(int, short, void *);
56 void		 control_dispatch_ext(int, short, void *);
57 void		 control_dispatch_lka(int, short, void *);
58 void		 control_dispatch_mfa(int, short, void *);
59 void		 control_dispatch_queue(int, short, void *);
60 void		 control_dispatch_runner(int, short, void *);
61 void		 control_dispatch_smtp(int, short, void *);
62 void		 control_dispatch_parent(int, short, void *);
63 
64 struct ctl_connlist	ctl_conns;
65 
66 void
67 control_sig_handler(int sig, short event, void *p)
68 {
69 	switch (sig) {
70 	case SIGINT:
71 	case SIGTERM:
72 		control_shutdown();
73 		break;
74 	default:
75 		fatalx("control_sig_handler: unexpected signal");
76 	}
77 }
78 
79 
80 pid_t
81 control(struct smtpd *env)
82 {
83 	struct sockaddr_un	 sun;
84 	int			 fd;
85 	mode_t			 old_umask;
86 	pid_t			 pid;
87 	struct passwd		*pw;
88 	struct event		 ev_sigint;
89 	struct event		 ev_sigterm;
90 	struct peer		 peers [] = {
91 		{ PROC_QUEUE,	 control_dispatch_queue },
92 		{ PROC_RUNNER,	 control_dispatch_runner },
93 		{ PROC_SMTP,	 control_dispatch_smtp },
94 		{ PROC_MFA,	 control_dispatch_mfa },
95 		{ PROC_PARENT,	 control_dispatch_parent },
96 	};
97 
98 	switch (pid = fork()) {
99 	case -1:
100 		fatal("control: cannot fork");
101 	case 0:
102 		break;
103 	default:
104 		return (pid);
105 	}
106 
107 	purge_config(env, PURGE_EVERYTHING);
108 
109 	pw = env->sc_pw;
110 
111 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
112 		fatal("control: socket");
113 
114 	sun.sun_family = AF_UNIX;
115 	if (strlcpy(sun.sun_path, SMTPD_SOCKET,
116 	    sizeof(sun.sun_path)) >= sizeof(sun.sun_path))
117 		fatal("control: socket name too long");
118 
119 	if (unlink(SMTPD_SOCKET) == -1)
120 		if (errno != ENOENT)
121 			fatal("control: cannot unlink socket");
122 
123 	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
124 	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
125 		(void)umask(old_umask);
126 		fatal("control: bind");
127 	}
128 	(void)umask(old_umask);
129 
130 	if (chmod(SMTPD_SOCKET, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) {
131 		(void)unlink(SMTPD_SOCKET);
132 		fatal("control: chmod");
133 	}
134 
135 	session_socket_blockmode(fd, BM_NONBLOCK);
136 	control_state.fd = fd;
137 
138 #ifndef DEBUG
139 	if (chroot(pw->pw_dir) == -1)
140 		fatal("control: chroot");
141 	if (chdir("/") == -1)
142 		fatal("control: chdir(\"/\")");
143 #else
144 #warning disabling privilege revocation and chroot in DEBUG MODE
145 #endif
146 
147 	setproctitle("control process");
148 	smtpd_process = PROC_CONTROL;
149 
150 #ifndef DEBUG
151 	if (setgroups(1, &pw->pw_gid) ||
152 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
153 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
154 		fatal("control: cannot drop privileges");
155 #endif
156 
157 	event_init();
158 
159 	signal_set(&ev_sigint, SIGINT, control_sig_handler, env);
160 	signal_set(&ev_sigterm, SIGTERM, control_sig_handler, env);
161 	signal_add(&ev_sigint, NULL);
162 	signal_add(&ev_sigterm, NULL);
163 	signal(SIGPIPE, SIG_IGN);
164 	signal(SIGHUP, SIG_IGN);
165 
166 	TAILQ_INIT(&ctl_conns);
167 
168 	config_pipes(env, peers, 5);
169 	config_peers(env, peers, 5);
170 	control_listen(env);
171 	event_dispatch();
172 	control_shutdown();
173 
174 	return (0);
175 }
176 
177 void
178 control_shutdown(void)
179 {
180 	log_info("control process exiting");
181 	_exit(0);
182 }
183 
184 int
185 control_listen(struct smtpd *env)
186 {
187 	if (listen(control_state.fd, CONTROL_BACKLOG) == -1) {
188 		log_warn("control_listen: listen");
189 		return (-1);
190 	}
191 
192 	event_set(&control_state.ev, control_state.fd, EV_READ | EV_PERSIST,
193 	    control_accept, env);
194 	event_add(&control_state.ev, NULL);
195 
196 	return (0);
197 }
198 
199 void
200 control_cleanup(void)
201 {
202 	(void)unlink(SMTPD_SOCKET);
203 }
204 
205 /* ARGSUSED */
206 void
207 control_accept(int listenfd, short event, void *arg)
208 {
209 	int			 connfd;
210 	socklen_t		 len;
211 	struct sockaddr_un	 sun;
212 	struct ctl_conn		*c;
213 	struct smtpd		*env = arg;
214 
215 	len = sizeof(sun);
216 	if ((connfd = accept(listenfd,
217 	    (struct sockaddr *)&sun, &len)) == -1) {
218 		if (errno != EWOULDBLOCK && errno != EINTR)
219 			log_warn("control_accept");
220 		return;
221 	}
222 
223 	session_socket_blockmode(connfd, BM_NONBLOCK);
224 
225 	if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
226 		close(connfd);
227 		log_warn("control_accept");
228 		return;
229 	}
230 
231 	imsg_init(&c->ibuf, connfd, control_dispatch_ext);
232 	c->ibuf.events = EV_READ;
233 	c->ibuf.data = env;
234 	event_set(&c->ibuf.ev, c->ibuf.fd, c->ibuf.events,
235 	    c->ibuf.handler, env);
236 	event_add(&c->ibuf.ev, NULL);
237 
238 	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
239 }
240 
241 struct ctl_conn *
242 control_connbyfd(int fd)
243 {
244 	struct ctl_conn	*c;
245 
246 	for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->ibuf.fd != fd;
247 	    c = TAILQ_NEXT(c, entry))
248 		;	/* nothing */
249 
250 	return (c);
251 }
252 
253 void
254 control_close(int fd)
255 {
256 	struct ctl_conn	*c;
257 
258 	if ((c = control_connbyfd(fd)) == NULL) {
259 		log_warn("control_close: fd %d: not found", fd);
260 		return;
261 	}
262 
263 	msgbuf_clear(&c->ibuf.w);
264 	TAILQ_REMOVE(&ctl_conns, c, entry);
265 
266 	event_del(&c->ibuf.ev);
267 	close(c->ibuf.fd);
268 	free(c);
269 }
270 
271 /* ARGSUSED */
272 void
273 control_dispatch_ext(int fd, short event, void *arg)
274 {
275 	struct ctl_conn		*c;
276 	struct smtpd		*env = arg;
277 	struct imsg		 imsg;
278 	int			 n;
279 	uid_t			 euid;
280 	gid_t			 egid;
281 
282 	if (getpeereid(fd, &euid, &egid) == -1)
283 		fatal("getpeereid");
284 
285 	if ((c = control_connbyfd(fd)) == NULL) {
286 		log_warn("control_dispatch_ext: fd %d: not found", fd);
287 		return;
288 	}
289 
290 	switch (event) {
291 	case EV_READ:
292 		if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) {
293 			control_close(fd);
294 			return;
295 		}
296 		break;
297 	case EV_WRITE:
298 		if (msgbuf_write(&c->ibuf.w) < 0) {
299 			control_close(fd);
300 			return;
301 		}
302 		imsg_event_add(&c->ibuf);
303 		return;
304 	default:
305 		fatalx("unknown event");
306 	}
307 
308 	for (;;) {
309 		if ((n = imsg_get(&c->ibuf, &imsg)) == -1) {
310 			control_close(fd);
311 			return;
312 		}
313 
314 		if (n == 0)
315 			break;
316 
317 		switch (imsg.hdr.type) {
318 		case IMSG_MFA_RCPT: {
319 			struct message_recipient *mr;
320 
321 			if (c->state != CS_INIT && c->state != CS_RCPT)
322 				goto badstate;
323 
324 			mr = imsg.data;
325 			imsg_compose(env->sc_ibufs[PROC_MFA], IMSG_MFA_RCPT, 0, 0, -1,
326 			    mr, sizeof(*mr));
327 			event_del(&c->ibuf.ev);
328 			break;
329 		}
330 		case IMSG_QUEUE_CREATE_MESSAGE: {
331 			struct message *messagep;
332 
333 			if (c->state != CS_NONE && c->state != CS_DONE)
334 				goto badstate;
335 
336 			messagep = imsg.data;
337 			messagep->session_id = fd;
338 			imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1,
339 			    messagep, sizeof(*messagep));
340 			event_del(&c->ibuf.ev);
341 			break;
342 		}
343 		case IMSG_QUEUE_MESSAGE_FILE: {
344 			struct message *messagep;
345 
346 			if (c->state != CS_RCPT)
347 				goto badstate;
348 
349 			messagep = imsg.data;
350 			messagep->session_id = fd;
351 			imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_QUEUE_MESSAGE_FILE, 0, 0, -1,
352 			    messagep, sizeof(*messagep));
353 			event_del(&c->ibuf.ev);
354 			break;
355 		}
356 		case IMSG_QUEUE_COMMIT_MESSAGE: {
357 			struct message *messagep;
358 
359 			if (c->state != CS_FD)
360 				goto badstate;
361 
362 			messagep = imsg.data;
363 			messagep->session_id = fd;
364 			imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1,
365 			    messagep, sizeof(*messagep));
366 			event_del(&c->ibuf.ev);
367 			break;
368 		}
369 		case IMSG_STATS: {
370 			struct stats	s;
371 
372 			if (euid)
373 				goto badcred;
374 
375 			s.fd = fd;
376 			imsg_compose(env->sc_ibufs[PROC_PARENT], IMSG_STATS, 0, 0, -1, &s, sizeof(s));
377 			imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_STATS, 0, 0, -1, &s, sizeof(s));
378 			imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_STATS, 0, 0, -1, &s, sizeof(s));
379 			imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_STATS, 0, 0, -1, &s, sizeof(s));
380 			break;
381 		}
382 		case IMSG_RUNNER_SCHEDULE: {
383 			struct sched s;
384 
385 			if (euid)
386 				goto badcred;
387 
388 			s = *(struct sched *)imsg.data;
389 			s.fd = fd;
390 
391 			if (! valid_message_id(s.mid) && ! valid_message_uid(s.mid)) {
392 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
393 				    NULL, 0);
394 				break;
395 			}
396 
397 			imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_RUNNER_SCHEDULE, 0, 0, -1, &s, sizeof(s));
398 			break;
399 		}
400 		case IMSG_CTL_SHUTDOWN:
401 			/* NEEDS_FIX */
402 			log_debug("received shutdown request");
403 
404 			if (euid)
405 				goto badcred;
406 
407 			if (env->sc_flags & SMTPD_EXITING) {
408 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
409 					NULL, 0);
410 				break;
411 			}
412 			env->sc_flags |= SMTPD_EXITING;
413 			imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
414 			break;
415 		case IMSG_MDA_PAUSE:
416 			if (euid)
417 				goto badcred;
418 
419 			if (env->sc_flags & SMTPD_MDA_PAUSED) {
420 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
421 					NULL, 0);
422 				break;
423 			}
424 			env->sc_flags |= SMTPD_MDA_PAUSED;
425 			imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_MDA_PAUSE,
426 			    0, 0, -1, NULL, 0);
427 			imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
428 			break;
429 		case IMSG_MTA_PAUSE:
430 			if (euid)
431 				goto badcred;
432 
433 			if (env->sc_flags & SMTPD_MTA_PAUSED) {
434 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
435 					NULL, 0);
436 				break;
437 			}
438 			env->sc_flags |= SMTPD_MTA_PAUSED;
439 			imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_MTA_PAUSE,
440 			    0, 0, -1, NULL, 0);
441 			imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
442 			break;
443 		case IMSG_SMTP_PAUSE:
444 			if (euid)
445 				goto badcred;
446 
447 			if (env->sc_flags & SMTPD_SMTP_PAUSED) {
448 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
449 					NULL, 0);
450 				break;
451 			}
452 			env->sc_flags |= SMTPD_SMTP_PAUSED;
453 			imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_SMTP_PAUSE,
454 			    0, 0, -1, NULL, 0);
455 			imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
456 			break;
457 		case IMSG_MDA_RESUME:
458 			if (euid)
459 				goto badcred;
460 
461 			if (! (env->sc_flags & SMTPD_MDA_PAUSED)) {
462 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
463 					NULL, 0);
464 				break;
465 			}
466 			env->sc_flags &= ~SMTPD_MDA_PAUSED;
467 			imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_MTA_RESUME,
468 			    0, 0, -1, NULL, 0);
469 			imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
470 			break;
471 		case IMSG_MTA_RESUME:
472 			if (euid)
473 				goto badcred;
474 
475 			if (!(env->sc_flags & SMTPD_MTA_PAUSED)) {
476 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
477 					NULL, 0);
478 				break;
479 			}
480 			env->sc_flags &= ~SMTPD_MTA_PAUSED;
481 			imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_MTA_RESUME,
482 			    0, 0, -1, NULL, 0);
483 			imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
484 			break;
485 		case IMSG_SMTP_RESUME:
486 			if (euid)
487 				goto badcred;
488 
489 			if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) {
490 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
491 					NULL, 0);
492 				break;
493 			}
494 			env->sc_flags &= ~SMTPD_SMTP_PAUSED;
495 			imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_SMTP_RESUME,
496 			    0, 0, -1, NULL, 0);
497 			imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
498 			break;
499 		default:
500 			log_debug("control_dispatch_ext: "
501 			    "error handling imsg %d", imsg.hdr.type);
502 			break;
503 		}
504 		imsg_free(&imsg);
505 		continue;
506 
507 badstate:
508 badcred:
509 		imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
510 		    NULL, 0);
511 	}
512 
513 	imsg_event_add(&c->ibuf);
514 }
515 
516 void
517 control_dispatch_parent(int sig, short event, void *p)
518 {
519 	struct smtpd		*env = p;
520 	struct imsgbuf		*ibuf;
521 	struct imsg		 imsg;
522 	ssize_t			 n;
523 
524 	ibuf = env->sc_ibufs[PROC_PARENT];
525 	switch (event) {
526 	case EV_READ:
527 		if ((n = imsg_read(ibuf)) == -1)
528 			fatal("imsg_read_error");
529 		if (n == 0) {
530 			/* this pipe is dead, so remove the event handler */
531 			event_del(&ibuf->ev);
532 			event_loopexit(NULL);
533 			return;
534 		}
535 		break;
536 	case EV_WRITE:
537 		if (msgbuf_write(&ibuf->w) == -1)
538 			fatal("msgbuf_write");
539 		imsg_event_add(ibuf);
540 		return;
541 	default:
542 		fatalx("unknown event");
543 	}
544 
545 	for (;;) {
546 		if ((n = imsg_get(ibuf, &imsg)) == -1)
547 			fatal("control_dispatch_parent: imsg_read error");
548 		if (n == 0)
549 			break;
550 
551 		switch (imsg.hdr.type) {
552 		case IMSG_STATS: {
553 			struct stats	*s;
554 			struct ctl_conn	*c;
555 
556 			s = imsg.data;
557 			if ((c = control_connbyfd(s->fd)) == NULL) {
558 				log_warn("control_dispatch_parent: fd %d not found", s->fd);
559 				return;
560 			}
561 
562 			imsg_compose(&c->ibuf, IMSG_PARENT_STATS, 0, 0, -1,
563 			    &s->u.parent, sizeof(s->u.parent));
564 
565 			break;
566 		}
567 		default:
568 			log_warnx("control_dispatch_parent: got imsg %d",
569 			    imsg.hdr.type);
570 			fatalx("control_dispatch_parent: unexpected imsg");
571 		}
572 		imsg_free(&imsg);
573 	}
574 	imsg_event_add(ibuf);
575 }
576 
577 void
578 control_dispatch_lka(int sig, short event, void *p)
579 {
580 	struct smtpd		*env = p;
581 	struct imsgbuf		*ibuf;
582 	struct imsg		 imsg;
583 	ssize_t			 n;
584 
585 	ibuf = env->sc_ibufs[PROC_LKA];
586 	switch (event) {
587 	case EV_READ:
588 		if ((n = imsg_read(ibuf)) == -1)
589 			fatal("imsg_read_error");
590 		if (n == 0) {
591 			/* this pipe is dead, so remove the event handler */
592 			event_del(&ibuf->ev);
593 			event_loopexit(NULL);
594 			return;
595 		}
596 		break;
597 	case EV_WRITE:
598 		if (msgbuf_write(&ibuf->w) == -1)
599 			fatal("msgbuf_write");
600 		imsg_event_add(ibuf);
601 		return;
602 	default:
603 		fatalx("unknown event");
604 	}
605 
606 	for (;;) {
607 		if ((n = imsg_get(ibuf, &imsg)) == -1)
608 			fatal("control_dispatch_lka: imsg_read error");
609 		if (n == 0)
610 			break;
611 
612 		switch (imsg.hdr.type) {
613 		case IMSG_QUEUE_TEMPFAIL: {
614 			struct submit_status	 *ss;
615 
616 			log_debug("GOT LFA REPLY");
617 			ss = imsg.data;
618 			if (ss->code != 250)
619 				log_debug("LKA FAILED WITH TEMPORARY ERROR");
620 
621 			break;
622 		}
623 		default:
624 			log_warnx("control_dispatch_lka: got imsg %d",
625 			    imsg.hdr.type);
626 			fatalx("control_dispatch_lka: unexpected imsg");
627 		}
628 		imsg_free(&imsg);
629 	}
630 	imsg_event_add(ibuf);
631 }
632 
633 void
634 control_dispatch_mfa(int sig, short event, void *p)
635 {
636 	struct smtpd		*env = p;
637 	struct imsgbuf		*ibuf;
638 	struct imsg		 imsg;
639 	ssize_t			 n;
640 
641 	ibuf = env->sc_ibufs[PROC_MFA];
642 	switch (event) {
643 	case EV_READ:
644 		if ((n = imsg_read(ibuf)) == -1)
645 			fatal("imsg_read_error");
646 		if (n == 0) {
647 			/* this pipe is dead, so remove the event handler */
648 			event_del(&ibuf->ev);
649 			event_loopexit(NULL);
650 			return;
651 		}
652 		break;
653 	case EV_WRITE:
654 		if (msgbuf_write(&ibuf->w) == -1)
655 			fatal("msgbuf_write");
656 		imsg_event_add(ibuf);
657 		return;
658 	default:
659 		fatalx("unknown event");
660 	}
661 
662 	for (;;) {
663 		if ((n = imsg_get(ibuf, &imsg)) == -1)
664 			fatal("control_dispatch_mfa: imsg_read error");
665 		if (n == 0)
666 			break;
667 
668 		switch (imsg.hdr.type) {
669 		case IMSG_MFA_RCPT: {
670 			struct submit_status	 *ss;
671 			struct ctl_conn		*c;
672 
673 			ss = imsg.data;
674 			if ((c = control_connbyfd(ss->id)) == NULL) {
675 				log_warn("control_dispatch_queue: fd %lld: not found", ss->id);
676 				return;
677 			}
678 
679 			event_add(&c->ibuf.ev, NULL);
680 			if (ss->code == 250) {
681 				c->state = CS_RCPT;
682 				break;
683 			}
684 
685 			imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
686 
687 			break;
688 		}
689 		default:
690 			log_warnx("control_dispatch_mfa: got imsg %d",
691 			    imsg.hdr.type);
692 			fatalx("control_dispatch_mfa: unexpected imsg");
693 		}
694 		imsg_free(&imsg);
695 	}
696 	imsg_event_add(ibuf);
697 }
698 
699 void
700 control_dispatch_queue(int sig, short event, void *p)
701 {
702 	struct smtpd		*env = p;
703 	struct imsgbuf		*ibuf;
704 	struct imsg		 imsg;
705 	ssize_t			 n;
706 
707 	ibuf = env->sc_ibufs[PROC_QUEUE];
708 	switch (event) {
709 	case EV_READ:
710 		if ((n = imsg_read(ibuf)) == -1)
711 			fatal("imsg_read_error");
712 		if (n == 0) {
713 			/* this pipe is dead, so remove the event handler */
714 			event_del(&ibuf->ev);
715 			event_loopexit(NULL);
716 			return;
717 		}
718 		break;
719 	case EV_WRITE:
720 		if (msgbuf_write(&ibuf->w) == -1)
721 			fatal("msgbuf_write");
722 		imsg_event_add(ibuf);
723 		return;
724 	default:
725 		fatalx("unknown event");
726 	}
727 
728 	for (;;) {
729 		if ((n = imsg_get(ibuf, &imsg)) == -1)
730 			fatal("control_dispatch_queue: imsg_read error");
731 		if (n == 0)
732 			break;
733 
734 		switch (imsg.hdr.type) {
735 		case IMSG_QUEUE_CREATE_MESSAGE: {
736 			struct submit_status	 *ss;
737 			struct ctl_conn		*c;
738 
739 			ss = imsg.data;
740 			if ((c = control_connbyfd(ss->id)) == NULL) {
741 				log_warn("control_dispatch_queue: fd %lld: not found", ss->id);
742 				return;
743 			}
744 			event_add(&c->ibuf.ev, NULL);
745 
746 			if (ss->code != 250) {
747 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
748 				    NULL, 0);
749 			}
750 			else {
751 				c->state = CS_INIT;
752 				ss->msg.session_id = ss->id;
753 				strlcpy(ss->msg.message_id, ss->u.msgid,
754 				    sizeof(ss->msg.message_id));
755 				imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1,
756 				    &ss->msg, sizeof(struct message));
757 			}
758 
759 			break;
760 		}
761 		case IMSG_QUEUE_COMMIT_ENVELOPES: {
762 			struct submit_status	 *ss;
763 			struct ctl_conn		*c;
764 
765 			ss = imsg.data;
766 			if ((c = control_connbyfd(ss->id)) == NULL) {
767 				log_warn("control_dispatch_queue: fd %lld: not found", ss->id);
768 				return;
769 			}
770 			event_add(&c->ibuf.ev, NULL);
771 			c->state = CS_RCPT;
772 			imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1,
773 			    NULL, 0);
774 
775 			break;
776 		}
777 		case IMSG_QUEUE_MESSAGE_FILE: {
778 			struct submit_status	 *ss;
779 			struct ctl_conn *c;
780 			int fd;
781 
782 			ss = imsg.data;
783 			if ((c = control_connbyfd(ss->id)) == NULL) {
784 				log_warn("control_dispatch_queue: fd %lld: not found",
785 				    ss->id);
786 				return;
787 			}
788 			event_add(&c->ibuf.ev, NULL);
789 
790 			fd = imsg_get_fd(ibuf, &imsg);
791 			if (ss->code == 250) {
792 				c->state = CS_FD;
793 				imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, fd,
794 				    &ss->msg, sizeof(struct message));
795 			}
796 			else
797 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
798 				    &ss->msg, sizeof(struct message));
799 			break;
800 		}
801 		case IMSG_QUEUE_COMMIT_MESSAGE: {
802 			struct submit_status	 *ss;
803 			struct ctl_conn *c;
804 
805 			ss = imsg.data;
806 			if ((c = control_connbyfd(ss->id)) == NULL) {
807 				log_warn("control_dispatch_queue: fd %lld: not found",
808 				    ss->id);
809 				return;
810 			}
811 			event_add(&c->ibuf.ev, NULL);
812 
813 			if (ss->code == 250) {
814 				c->state = CS_DONE;
815 				imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1,
816 				    &ss->msg, sizeof(struct message));
817 			}
818 			else
819 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
820 				    &ss->msg, sizeof(struct message));
821 			break;
822 		}
823 		case IMSG_STATS: {
824 			struct stats	*s;
825 			struct ctl_conn	*c;
826 
827 			s = imsg.data;
828 			if ((c = control_connbyfd(s->fd)) == NULL) {
829 				log_warn("control_dispatch_queue: fd %d not found", s->fd);
830 				return;
831 			}
832 
833 			imsg_compose(&c->ibuf, IMSG_QUEUE_STATS, 0, 0, -1,
834 			    &s->u.queue, sizeof(s->u.queue));
835 
836 			break;
837 		}
838 		default:
839 			log_warnx("control_dispatch_queue: got imsg %d",
840 			    imsg.hdr.type);
841 			fatalx("control_dispatch_queue: unexpected imsg");
842 		}
843 		imsg_free(&imsg);
844 	}
845 	imsg_event_add(ibuf);
846 }
847 
848 void
849 control_dispatch_runner(int sig, short event, void *p)
850 {
851 	struct smtpd		*env = p;
852 	struct imsgbuf		*ibuf;
853 	struct imsg		 imsg;
854 	ssize_t			 n;
855 
856 	ibuf = env->sc_ibufs[PROC_RUNNER];
857 	switch (event) {
858 	case EV_READ:
859 		if ((n = imsg_read(ibuf)) == -1)
860 			fatal("imsg_read_error");
861 		if (n == 0) {
862 			/* this pipe is dead, so remove the event handler */
863 			event_del(&ibuf->ev);
864 			event_loopexit(NULL);
865 			return;
866 		}
867 		break;
868 	case EV_WRITE:
869 		if (msgbuf_write(&ibuf->w) == -1)
870 			fatal("msgbuf_write");
871 		imsg_event_add(ibuf);
872 		return;
873 	default:
874 		fatalx("unknown event");
875 	}
876 
877 	for (;;) {
878 		if ((n = imsg_get(ibuf, &imsg)) == -1)
879 			fatal("control_dispatch_runner: imsg_read error");
880 		if (n == 0)
881 			break;
882 
883 		switch (imsg.hdr.type) {
884 		case IMSG_STATS: {
885 			struct stats	*s;
886 			struct ctl_conn	*c;
887 
888 			s = imsg.data;
889 			if ((c = control_connbyfd(s->fd)) == NULL) {
890 				log_warn("control_dispatch_runner: fd %d not found", s->fd);
891 				return;
892 			}
893 
894 			imsg_compose(&c->ibuf, IMSG_RUNNER_STATS, 0, 0, -1,
895 			    &s->u.runner, sizeof(s->u.runner));
896 
897 			break;
898 		}
899 		case IMSG_RUNNER_SCHEDULE: {
900 			struct sched	*s;
901 			struct ctl_conn	*c;
902 
903 			s = imsg.data;
904 			if ((c = control_connbyfd(s->fd)) == NULL) {
905 				log_warn("control_dispatch_runner: fd %d not found", s->fd);
906 				return;
907 			}
908 
909 			if (s->ret)
910 				imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
911 			else
912 				imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
913 			break;
914 		}
915 		default:
916 			log_warnx("control_dispatch_runner: got imsg %d",
917 			    imsg.hdr.type);
918 			fatalx("control_dispatch_runner: unexpected imsg");
919 		}
920 		imsg_free(&imsg);
921 	}
922 	imsg_event_add(ibuf);
923 }
924 
925 void
926 control_dispatch_smtp(int sig, short event, void *p)
927 {
928 	struct smtpd		*env = p;
929 	struct imsgbuf		*ibuf;
930 	struct imsg		 imsg;
931 	ssize_t			 n;
932 
933 	ibuf = env->sc_ibufs[PROC_SMTP];
934 	switch (event) {
935 	case EV_READ:
936 		if ((n = imsg_read(ibuf)) == -1)
937 			fatal("imsg_read_error");
938 		if (n == 0) {
939 			/* this pipe is dead, so remove the event handler */
940 			event_del(&ibuf->ev);
941 			event_loopexit(NULL);
942 			return;
943 		}
944 		break;
945 	case EV_WRITE:
946 		if (msgbuf_write(&ibuf->w) == -1)
947 			fatal("msgbuf_write");
948 		imsg_event_add(ibuf);
949 		return;
950 	default:
951 		fatalx("unknown event");
952 	}
953 
954 	for (;;) {
955 		if ((n = imsg_get(ibuf, &imsg)) == -1)
956 			fatal("control_dispatch_smtp: imsg_read error");
957 		if (n == 0)
958 			break;
959 
960 		switch (imsg.hdr.type) {
961 		case IMSG_STATS: {
962 			struct stats	*s;
963 			struct ctl_conn	*c;
964 
965 			s = imsg.data;
966 			if ((c = control_connbyfd(s->fd)) == NULL) {
967 				log_warn("control_dispatch_queue: fd %d not found", s->fd);
968 				return;
969 			}
970 
971 			imsg_compose(&c->ibuf, IMSG_SMTP_STATS, 0, 0, -1,
972 			    &s->u.smtp, sizeof(s->u.smtp));
973 
974 			break;
975 		}
976 		default:
977 			log_warnx("control_dispatch_smtp: got imsg %d",
978 			    imsg.hdr.type);
979 			fatalx("control_dispatch_smtp: unexpected imsg");
980 		}
981 		imsg_free(&imsg);
982 	}
983 	imsg_event_add(ibuf);
984 }
985 
986 void
987 session_socket_blockmode(int fd, enum blockmodes bm)
988 {
989 	int	flags;
990 
991 	if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
992 		fatal("fcntl F_GETFL");
993 
994 	if (bm == BM_NONBLOCK)
995 		flags |= O_NONBLOCK;
996 	else
997 		flags &= ~O_NONBLOCK;
998 
999 	if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
1000 		fatal("fcntl F_SETFL");
1001 }
1002