xref: /openbsd-src/usr.sbin/smtpd/control.c (revision 5054e3e78af0749a9bb00ba9a024b3ee2d90290f)
1 /*	$OpenBSD: control.c,v 1.39 2009/10/25 19:46:31 gilles 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 	smtpd_process = PROC_CONTROL;
148 	setproctitle("%s", env->sc_title[smtpd_process]);
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, nitems(peers));
169 	config_peers(env, peers, nitems(peers));
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->iev.ibuf, connfd);
232 	c->iev.handler = control_dispatch_ext;
233 	c->iev.events = EV_READ;
234 	c->iev.data = env;
235 	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
236 	    c->iev.handler, env);
237 	event_add(&c->iev.ev, NULL);
238 
239 	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
240 }
241 
242 struct ctl_conn *
243 control_connbyfd(int fd)
244 {
245 	struct ctl_conn	*c;
246 
247 	for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd;
248 	    c = TAILQ_NEXT(c, entry))
249 		;	/* nothing */
250 
251 	return (c);
252 }
253 
254 void
255 control_close(int fd)
256 {
257 	struct ctl_conn	*c;
258 
259 	if ((c = control_connbyfd(fd)) == NULL) {
260 		log_warn("control_close: fd %d: not found", fd);
261 		return;
262 	}
263 
264 	msgbuf_clear(&c->iev.ibuf.w);
265 	TAILQ_REMOVE(&ctl_conns, c, entry);
266 
267 	event_del(&c->iev.ev);
268 	close(c->iev.ibuf.fd);
269 	free(c);
270 }
271 
272 /* ARGSUSED */
273 void
274 control_dispatch_ext(int fd, short event, void *arg)
275 {
276 	struct ctl_conn		*c;
277 	struct smtpd		*env = arg;
278 	struct imsg		 imsg;
279 	int			 n;
280 	uid_t			 euid;
281 	gid_t			 egid;
282 
283 	if (getpeereid(fd, &euid, &egid) == -1)
284 		fatal("getpeereid");
285 
286 	if ((c = control_connbyfd(fd)) == NULL) {
287 		log_warn("control_dispatch_ext: fd %d: not found", fd);
288 		return;
289 	}
290 
291 	if (event & EV_READ) {
292 		if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) {
293 			control_close(fd);
294 			return;
295 		}
296 	}
297 
298 	if (event & EV_WRITE) {
299 		if (msgbuf_write(&c->iev.ibuf.w) < 0) {
300 			control_close(fd);
301 			return;
302 		}
303 	}
304 
305 	for (;;) {
306 		if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
307 			control_close(fd);
308 			return;
309 		}
310 
311 		if (n == 0)
312 			break;
313 
314 		switch (imsg.hdr.type) {
315 		case IMSG_SMTP_ENQUEUE:
316 			if (env->sc_flags & (SMTPD_SMTP_PAUSED |
317 			    SMTPD_CONFIGURING | SMTPD_EXITING)) {
318 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
319 					NULL, 0);
320 				break;
321 			}
322 			imsg_compose_event(env->sc_ievs[PROC_SMTP],
323 			    IMSG_SMTP_ENQUEUE, fd, 0, -1, &euid, sizeof(euid));
324 			break;
325 		case IMSG_STATS:
326 			if (euid)
327 				goto badcred;
328 			imsg_compose_event(&c->iev, IMSG_STATS, 0, 0, -1,
329 			    env->stats, sizeof(struct stats));
330 			break;
331 		case IMSG_RUNNER_SCHEDULE: {
332 			struct sched *s = imsg.data;
333 
334 			if (euid)
335 				goto badcred;
336 
337 			if (IMSG_DATA_SIZE(&imsg) != sizeof(*s))
338 				goto badcred;
339 
340 			s->fd = fd;
341 
342 			if (! valid_message_id(s->mid) && ! valid_message_uid(s->mid)) {
343 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
344 				    NULL, 0);
345 				break;
346 			}
347 
348 			imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_RUNNER_SCHEDULE, 0, 0, -1, s, sizeof(*s));
349 			break;
350 		}
351 /*
352 		case IMSG_CONF_RELOAD: {
353 			struct reload r;
354 
355 			log_debug("received reload request");
356 
357 			if (euid)
358 				goto badcred;
359 
360 			if (env->sc_flags & SMTPD_CONFIGURING) {
361 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
362 					NULL, 0);
363 				break;
364 			}
365 			env->sc_flags |= SMTPD_CONFIGURING;
366 
367 			r.fd = fd;
368 			imsg_compose_event(env->sc_ievs[PROC_PARENT], IMSG_CONF_RELOAD, 0, 0, -1, &r, sizeof(r));
369 			break;
370 		}
371 */
372 		case IMSG_CTL_SHUTDOWN:
373 			/* NEEDS_FIX */
374 			log_debug("received shutdown request");
375 
376 			if (euid)
377 				goto badcred;
378 
379 			if (env->sc_flags & SMTPD_EXITING) {
380 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
381 					NULL, 0);
382 				break;
383 			}
384 			env->sc_flags |= SMTPD_EXITING;
385 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
386 			break;
387 		case IMSG_MDA_PAUSE:
388 			if (euid)
389 				goto badcred;
390 
391 			if (env->sc_flags & SMTPD_MDA_PAUSED) {
392 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
393 					NULL, 0);
394 				break;
395 			}
396 			env->sc_flags |= SMTPD_MDA_PAUSED;
397 			imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MDA_PAUSE,
398 			    0, 0, -1, NULL, 0);
399 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
400 			break;
401 		case IMSG_MTA_PAUSE:
402 			if (euid)
403 				goto badcred;
404 
405 			if (env->sc_flags & SMTPD_MTA_PAUSED) {
406 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
407 					NULL, 0);
408 				break;
409 			}
410 			env->sc_flags |= SMTPD_MTA_PAUSED;
411 			imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MTA_PAUSE,
412 			    0, 0, -1, NULL, 0);
413 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
414 			break;
415 		case IMSG_SMTP_PAUSE:
416 			if (euid)
417 				goto badcred;
418 
419 			if (env->sc_flags & SMTPD_SMTP_PAUSED) {
420 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
421 					NULL, 0);
422 				break;
423 			}
424 			env->sc_flags |= SMTPD_SMTP_PAUSED;
425 			imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_PAUSE,
426 			    0, 0, -1, NULL, 0);
427 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
428 			break;
429 		case IMSG_MDA_RESUME:
430 			if (euid)
431 				goto badcred;
432 
433 			if (! (env->sc_flags & SMTPD_MDA_PAUSED)) {
434 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
435 					NULL, 0);
436 				break;
437 			}
438 			env->sc_flags &= ~SMTPD_MDA_PAUSED;
439 			imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MTA_RESUME,
440 			    0, 0, -1, NULL, 0);
441 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
442 			break;
443 		case IMSG_MTA_RESUME:
444 			if (euid)
445 				goto badcred;
446 
447 			if (!(env->sc_flags & SMTPD_MTA_PAUSED)) {
448 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
449 					NULL, 0);
450 				break;
451 			}
452 			env->sc_flags &= ~SMTPD_MTA_PAUSED;
453 			imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MTA_RESUME,
454 			    0, 0, -1, NULL, 0);
455 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
456 			break;
457 		case IMSG_SMTP_RESUME:
458 			if (euid)
459 				goto badcred;
460 
461 			if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) {
462 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
463 					NULL, 0);
464 				break;
465 			}
466 			env->sc_flags &= ~SMTPD_SMTP_PAUSED;
467 			imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_RESUME,
468 			    0, 0, -1, NULL, 0);
469 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
470 			break;
471 		default:
472 			log_debug("control_dispatch_ext: "
473 			    "error handling imsg %d", imsg.hdr.type);
474 			break;
475 		}
476 		imsg_free(&imsg);
477 		continue;
478 
479 badcred:
480 		imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
481 		    NULL, 0);
482 	}
483 
484 	imsg_event_add(&c->iev);
485 }
486 
487 void
488 control_dispatch_parent(int sig, short event, void *p)
489 {
490 	struct smtpd		*env = p;
491 	struct imsgev		*iev;
492 	struct imsgbuf		*ibuf;
493 	struct imsg		 imsg;
494 	ssize_t			 n;
495 
496 	iev = env->sc_ievs[PROC_PARENT];
497 	ibuf = &iev->ibuf;
498 
499 	if (event & EV_READ) {
500 		if ((n = imsg_read(ibuf)) == -1)
501 			fatal("imsg_read_error");
502 		if (n == 0) {
503 			/* this pipe is dead, so remove the event handler */
504 			event_del(&iev->ev);
505 			event_loopexit(NULL);
506 			return;
507 		}
508 	}
509 
510 	if (event & EV_WRITE) {
511 		if (msgbuf_write(&ibuf->w) == -1)
512 			fatal("msgbuf_write");
513 	}
514 
515 	for (;;) {
516 		if ((n = imsg_get(ibuf, &imsg)) == -1)
517 			fatal("control_dispatch_parent: imsg_get error");
518 		if (n == 0)
519 			break;
520 
521 		switch (imsg.hdr.type) {
522 		case IMSG_CONF_RELOAD: {
523 			struct reload *r = imsg.data;
524 			struct ctl_conn	*c;
525 
526 			IMSG_SIZE_CHECK(r);
527 
528 			env->sc_flags &= ~SMTPD_CONFIGURING;
529 			if ((c = control_connbyfd(r->fd)) == NULL) {
530 				log_warn("control_dispatch_parent: fd %d not found", r->fd);
531 				return;
532 			}
533 
534 			if (r->ret)
535 				imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
536 			else
537 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
538 			break;
539 		}
540 		default:
541 			log_warnx("control_dispatch_parent: got imsg %d",
542 			    imsg.hdr.type);
543 			fatalx("control_dispatch_parent: unexpected imsg");
544 		}
545 		imsg_free(&imsg);
546 	}
547 	imsg_event_add(iev);
548 }
549 
550 void
551 control_dispatch_lka(int sig, short event, void *p)
552 {
553 	struct smtpd		*env = p;
554 	struct imsgev		*iev;
555 	struct imsgbuf		*ibuf;
556 	struct imsg		 imsg;
557 	ssize_t			 n;
558 
559 	iev = env->sc_ievs[PROC_LKA];
560 	ibuf = &iev->ibuf;
561 
562 	if (event & EV_READ) {
563 		if ((n = imsg_read(ibuf)) == -1)
564 			fatal("imsg_read_error");
565 		if (n == 0) {
566 			/* this pipe is dead, so remove the event handler */
567 			event_del(&iev->ev);
568 			event_loopexit(NULL);
569 			return;
570 		}
571 	}
572 
573 	if (event & EV_WRITE) {
574 		if (msgbuf_write(&ibuf->w) == -1)
575 			fatal("msgbuf_write");
576 	}
577 
578 	for (;;) {
579 		if ((n = imsg_get(ibuf, &imsg)) == -1)
580 			fatal("control_dispatch_lka: imsg_get error");
581 		if (n == 0)
582 			break;
583 
584 		switch (imsg.hdr.type) {
585 		default:
586 			log_warnx("control_dispatch_lka: got imsg %d",
587 			    imsg.hdr.type);
588 			fatalx("control_dispatch_lka: unexpected imsg");
589 		}
590 		imsg_free(&imsg);
591 	}
592 	imsg_event_add(iev);
593 }
594 
595 void
596 control_dispatch_mfa(int sig, short event, void *p)
597 {
598 	struct smtpd		*env = p;
599 	struct imsgev		*iev;
600 	struct imsgbuf		*ibuf;
601 	struct imsg		 imsg;
602 	ssize_t			 n;
603 
604 	iev = env->sc_ievs[PROC_MFA];
605 	ibuf = &iev->ibuf;
606 
607 	if (event & EV_READ) {
608 		if ((n = imsg_read(ibuf)) == -1)
609 			fatal("imsg_read_error");
610 		if (n == 0) {
611 			/* this pipe is dead, so remove the event handler */
612 			event_del(&iev->ev);
613 			event_loopexit(NULL);
614 			return;
615 		}
616 	}
617 
618 	if (event & EV_WRITE) {
619 		if (msgbuf_write(&ibuf->w) == -1)
620 			fatal("msgbuf_write");
621 	}
622 
623 	for (;;) {
624 		if ((n = imsg_get(ibuf, &imsg)) == -1)
625 			fatal("control_dispatch_mfa: imsg_get error");
626 		if (n == 0)
627 			break;
628 
629 		switch (imsg.hdr.type) {
630 		default:
631 			log_warnx("control_dispatch_mfa: got imsg %d",
632 			    imsg.hdr.type);
633 			fatalx("control_dispatch_mfa: unexpected imsg");
634 		}
635 		imsg_free(&imsg);
636 	}
637 	imsg_event_add(iev);
638 }
639 
640 void
641 control_dispatch_queue(int sig, short event, void *p)
642 {
643 	struct smtpd		*env = p;
644 	struct imsgev		*iev;
645 	struct imsgbuf		*ibuf;
646 	struct imsg		 imsg;
647 	ssize_t			 n;
648 
649 	iev = env->sc_ievs[PROC_QUEUE];
650 	ibuf = &iev->ibuf;
651 
652 	if (event & EV_READ) {
653 		if ((n = imsg_read(ibuf)) == -1)
654 			fatal("imsg_read_error");
655 		if (n == 0) {
656 			/* this pipe is dead, so remove the event handler */
657 			event_del(&iev->ev);
658 			event_loopexit(NULL);
659 			return;
660 		}
661 	}
662 
663 	if (event & EV_WRITE) {
664 		if (msgbuf_write(&ibuf->w) == -1)
665 			fatal("msgbuf_write");
666 	}
667 
668 	for (;;) {
669 		if ((n = imsg_get(ibuf, &imsg)) == -1)
670 			fatal("control_dispatch_queue: imsg_get error");
671 		if (n == 0)
672 			break;
673 
674 		switch (imsg.hdr.type) {
675 		default:
676 			log_warnx("control_dispatch_queue: got imsg %d",
677 			    imsg.hdr.type);
678 			fatalx("control_dispatch_queue: unexpected imsg");
679 		}
680 		imsg_free(&imsg);
681 	}
682 	imsg_event_add(iev);
683 }
684 
685 void
686 control_dispatch_runner(int sig, short event, void *p)
687 {
688 	struct smtpd		*env = p;
689 	struct imsgev		*iev;
690 	struct imsgbuf		*ibuf;
691 	struct imsg		 imsg;
692 	ssize_t			 n;
693 
694 	iev = env->sc_ievs[PROC_RUNNER];
695 	ibuf = &iev->ibuf;
696 
697 	if (event & EV_READ) {
698 		if ((n = imsg_read(ibuf)) == -1)
699 			fatal("imsg_read_error");
700 		if (n == 0) {
701 			/* this pipe is dead, so remove the event handler */
702 			event_del(&iev->ev);
703 			event_loopexit(NULL);
704 			return;
705 		}
706 	}
707 
708 	if (event & EV_WRITE) {
709 		if (msgbuf_write(&ibuf->w) == -1)
710 			fatal("msgbuf_write");
711 	}
712 
713 	for (;;) {
714 		if ((n = imsg_get(ibuf, &imsg)) == -1)
715 			fatal("control_dispatch_runner: imsg_get error");
716 		if (n == 0)
717 			break;
718 
719 		switch (imsg.hdr.type) {
720 		case IMSG_RUNNER_SCHEDULE: {
721 			struct sched	*s = imsg.data;
722 			struct ctl_conn	*c;
723 
724 			IMSG_SIZE_CHECK(s);
725 
726 			if ((c = control_connbyfd(s->fd)) == NULL) {
727 				log_warn("control_dispatch_runner: fd %d not found", s->fd);
728 				imsg_free(&imsg);
729 				return;
730 			}
731 
732 			if (s->ret)
733 				imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
734 			else
735 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
736 			break;
737 		}
738 		default:
739 			log_warnx("control_dispatch_runner: got imsg %d",
740 			    imsg.hdr.type);
741 			fatalx("control_dispatch_runner: unexpected imsg");
742 		}
743 		imsg_free(&imsg);
744 	}
745 	imsg_event_add(iev);
746 }
747 
748 void
749 control_dispatch_smtp(int sig, short event, void *p)
750 {
751 	struct smtpd		*env = p;
752 	struct imsgev		*iev;
753 	struct imsgbuf		*ibuf;
754 	struct imsg		 imsg;
755 	ssize_t			 n;
756 
757 	iev = env->sc_ievs[PROC_SMTP];
758 	ibuf = &iev->ibuf;
759 
760 	if (event & EV_READ) {
761 		if ((n = imsg_read(ibuf)) == -1)
762 			fatal("imsg_read_error");
763 		if (n == 0) {
764 			/* this pipe is dead, so remove the event handler */
765 			event_del(&iev->ev);
766 			event_loopexit(NULL);
767 			return;
768 		}
769 	}
770 
771 	if (event & EV_WRITE) {
772 		if (msgbuf_write(&ibuf->w) == -1)
773 			fatal("msgbuf_write");
774 	}
775 
776 	for (;;) {
777 		if ((n = imsg_get(ibuf, &imsg)) == -1)
778 			fatal("control_dispatch_smtp: imsg_get error");
779 		if (n == 0)
780 			break;
781 
782 		switch (imsg.hdr.type) {
783 		case IMSG_SMTP_ENQUEUE: {
784 			struct ctl_conn	*c;
785 			int		client_fd;
786 
787 			client_fd = imsg.hdr.peerid;
788 
789 			if ((c = control_connbyfd(client_fd)) == NULL) {
790 				log_warn("control_dispatch_smtp: fd %d not found", client_fd);
791 				imsg_free(&imsg);
792 				return;
793 			}
794 
795 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0,
796 			    imsg.fd, NULL, 0);
797 			break;
798 		}
799 		default:
800 			log_warnx("control_dispatch_smtp: got imsg %d",
801 			    imsg.hdr.type);
802 			fatalx("control_dispatch_smtp: unexpected imsg");
803 		}
804 		imsg_free(&imsg);
805 	}
806 	imsg_event_add(iev);
807 }
808 
809 void
810 session_socket_blockmode(int fd, enum blockmodes bm)
811 {
812 	int	flags;
813 
814 	if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
815 		fatal("fcntl F_GETFL");
816 
817 	if (bm == BM_NONBLOCK)
818 		flags |= O_NONBLOCK;
819 	else
820 		flags &= ~O_NONBLOCK;
821 
822 	if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
823 		fatal("fcntl F_SETFL");
824 }
825 
826 void
827 session_socket_no_linger(int fd)
828 {
829 	struct linger	 lng;
830 
831 	bzero(&lng, sizeof(lng));
832 	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng)) == -1)
833 		fatal("session_socket_no_linger");
834 }
835 
836 int
837 session_socket_error(int fd)
838 {
839 	int	 err, len;
840 
841 	len = sizeof(err);
842 	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) == -1)
843 		fatal("session_socket_error: getsockopt");
844 
845 	return (err);
846 }
847