xref: /openbsd-src/usr.sbin/smtpd/control.c (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1 /*	$OpenBSD: control.c,v 1.38 2009/09/18 00:04:26 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 	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 		case IMSG_CONF_RELOAD: {
352 			struct reload r;
353 
354 			log_debug("received reload request");
355 
356 			if (euid)
357 				goto badcred;
358 
359 			if (env->sc_flags & SMTPD_CONFIGURING) {
360 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
361 					NULL, 0);
362 				break;
363 			}
364 			env->sc_flags |= SMTPD_CONFIGURING;
365 
366 			r.fd = fd;
367 			imsg_compose_event(env->sc_ievs[PROC_PARENT], IMSG_CONF_RELOAD, 0, 0, -1, &r, sizeof(r));
368 			break;
369 		}
370 		case IMSG_CTL_SHUTDOWN:
371 			/* NEEDS_FIX */
372 			log_debug("received shutdown request");
373 
374 			if (euid)
375 				goto badcred;
376 
377 			if (env->sc_flags & SMTPD_EXITING) {
378 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
379 					NULL, 0);
380 				break;
381 			}
382 			env->sc_flags |= SMTPD_EXITING;
383 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
384 			break;
385 		case IMSG_MDA_PAUSE:
386 			if (euid)
387 				goto badcred;
388 
389 			if (env->sc_flags & SMTPD_MDA_PAUSED) {
390 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
391 					NULL, 0);
392 				break;
393 			}
394 			env->sc_flags |= SMTPD_MDA_PAUSED;
395 			imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MDA_PAUSE,
396 			    0, 0, -1, NULL, 0);
397 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
398 			break;
399 		case IMSG_MTA_PAUSE:
400 			if (euid)
401 				goto badcred;
402 
403 			if (env->sc_flags & SMTPD_MTA_PAUSED) {
404 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
405 					NULL, 0);
406 				break;
407 			}
408 			env->sc_flags |= SMTPD_MTA_PAUSED;
409 			imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MTA_PAUSE,
410 			    0, 0, -1, NULL, 0);
411 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
412 			break;
413 		case IMSG_SMTP_PAUSE:
414 			if (euid)
415 				goto badcred;
416 
417 			if (env->sc_flags & SMTPD_SMTP_PAUSED) {
418 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
419 					NULL, 0);
420 				break;
421 			}
422 			env->sc_flags |= SMTPD_SMTP_PAUSED;
423 			imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_PAUSE,
424 			    0, 0, -1, NULL, 0);
425 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
426 			break;
427 		case IMSG_MDA_RESUME:
428 			if (euid)
429 				goto badcred;
430 
431 			if (! (env->sc_flags & SMTPD_MDA_PAUSED)) {
432 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
433 					NULL, 0);
434 				break;
435 			}
436 			env->sc_flags &= ~SMTPD_MDA_PAUSED;
437 			imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MTA_RESUME,
438 			    0, 0, -1, NULL, 0);
439 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
440 			break;
441 		case IMSG_MTA_RESUME:
442 			if (euid)
443 				goto badcred;
444 
445 			if (!(env->sc_flags & SMTPD_MTA_PAUSED)) {
446 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
447 					NULL, 0);
448 				break;
449 			}
450 			env->sc_flags &= ~SMTPD_MTA_PAUSED;
451 			imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MTA_RESUME,
452 			    0, 0, -1, NULL, 0);
453 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
454 			break;
455 		case IMSG_SMTP_RESUME:
456 			if (euid)
457 				goto badcred;
458 
459 			if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) {
460 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
461 					NULL, 0);
462 				break;
463 			}
464 			env->sc_flags &= ~SMTPD_SMTP_PAUSED;
465 			imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_RESUME,
466 			    0, 0, -1, NULL, 0);
467 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
468 			break;
469 		default:
470 			log_debug("control_dispatch_ext: "
471 			    "error handling imsg %d", imsg.hdr.type);
472 			break;
473 		}
474 		imsg_free(&imsg);
475 		continue;
476 
477 badcred:
478 		imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
479 		    NULL, 0);
480 	}
481 
482 	imsg_event_add(&c->iev);
483 }
484 
485 void
486 control_dispatch_parent(int sig, short event, void *p)
487 {
488 	struct smtpd		*env = p;
489 	struct imsgev		*iev;
490 	struct imsgbuf		*ibuf;
491 	struct imsg		 imsg;
492 	ssize_t			 n;
493 
494 	iev = env->sc_ievs[PROC_PARENT];
495 	ibuf = &iev->ibuf;
496 
497 	if (event & EV_READ) {
498 		if ((n = imsg_read(ibuf)) == -1)
499 			fatal("imsg_read_error");
500 		if (n == 0) {
501 			/* this pipe is dead, so remove the event handler */
502 			event_del(&iev->ev);
503 			event_loopexit(NULL);
504 			return;
505 		}
506 	}
507 
508 	if (event & EV_WRITE) {
509 		if (msgbuf_write(&ibuf->w) == -1)
510 			fatal("msgbuf_write");
511 	}
512 
513 	for (;;) {
514 		if ((n = imsg_get(ibuf, &imsg)) == -1)
515 			fatal("control_dispatch_parent: imsg_get error");
516 		if (n == 0)
517 			break;
518 
519 		switch (imsg.hdr.type) {
520 		case IMSG_CONF_RELOAD: {
521 			struct reload *r = imsg.data;
522 			struct ctl_conn	*c;
523 
524 			IMSG_SIZE_CHECK(r);
525 
526 			env->sc_flags &= ~SMTPD_CONFIGURING;
527 			if ((c = control_connbyfd(r->fd)) == NULL) {
528 				log_warn("control_dispatch_parent: fd %d not found", r->fd);
529 				return;
530 			}
531 
532 			if (r->ret)
533 				imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
534 			else
535 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
536 			break;
537 		}
538 		default:
539 			log_warnx("control_dispatch_parent: got imsg %d",
540 			    imsg.hdr.type);
541 			fatalx("control_dispatch_parent: unexpected imsg");
542 		}
543 		imsg_free(&imsg);
544 	}
545 	imsg_event_add(iev);
546 }
547 
548 void
549 control_dispatch_lka(int sig, short event, void *p)
550 {
551 	struct smtpd		*env = p;
552 	struct imsgev		*iev;
553 	struct imsgbuf		*ibuf;
554 	struct imsg		 imsg;
555 	ssize_t			 n;
556 
557 	iev = env->sc_ievs[PROC_LKA];
558 	ibuf = &iev->ibuf;
559 
560 	if (event & EV_READ) {
561 		if ((n = imsg_read(ibuf)) == -1)
562 			fatal("imsg_read_error");
563 		if (n == 0) {
564 			/* this pipe is dead, so remove the event handler */
565 			event_del(&iev->ev);
566 			event_loopexit(NULL);
567 			return;
568 		}
569 	}
570 
571 	if (event & EV_WRITE) {
572 		if (msgbuf_write(&ibuf->w) == -1)
573 			fatal("msgbuf_write");
574 	}
575 
576 	for (;;) {
577 		if ((n = imsg_get(ibuf, &imsg)) == -1)
578 			fatal("control_dispatch_lka: imsg_get error");
579 		if (n == 0)
580 			break;
581 
582 		switch (imsg.hdr.type) {
583 		default:
584 			log_warnx("control_dispatch_lka: got imsg %d",
585 			    imsg.hdr.type);
586 			fatalx("control_dispatch_lka: unexpected imsg");
587 		}
588 		imsg_free(&imsg);
589 	}
590 	imsg_event_add(iev);
591 }
592 
593 void
594 control_dispatch_mfa(int sig, short event, void *p)
595 {
596 	struct smtpd		*env = p;
597 	struct imsgev		*iev;
598 	struct imsgbuf		*ibuf;
599 	struct imsg		 imsg;
600 	ssize_t			 n;
601 
602 	iev = env->sc_ievs[PROC_MFA];
603 	ibuf = &iev->ibuf;
604 
605 	if (event & EV_READ) {
606 		if ((n = imsg_read(ibuf)) == -1)
607 			fatal("imsg_read_error");
608 		if (n == 0) {
609 			/* this pipe is dead, so remove the event handler */
610 			event_del(&iev->ev);
611 			event_loopexit(NULL);
612 			return;
613 		}
614 	}
615 
616 	if (event & EV_WRITE) {
617 		if (msgbuf_write(&ibuf->w) == -1)
618 			fatal("msgbuf_write");
619 	}
620 
621 	for (;;) {
622 		if ((n = imsg_get(ibuf, &imsg)) == -1)
623 			fatal("control_dispatch_mfa: imsg_get error");
624 		if (n == 0)
625 			break;
626 
627 		switch (imsg.hdr.type) {
628 		default:
629 			log_warnx("control_dispatch_mfa: got imsg %d",
630 			    imsg.hdr.type);
631 			fatalx("control_dispatch_mfa: unexpected imsg");
632 		}
633 		imsg_free(&imsg);
634 	}
635 	imsg_event_add(iev);
636 }
637 
638 void
639 control_dispatch_queue(int sig, short event, void *p)
640 {
641 	struct smtpd		*env = p;
642 	struct imsgev		*iev;
643 	struct imsgbuf		*ibuf;
644 	struct imsg		 imsg;
645 	ssize_t			 n;
646 
647 	iev = env->sc_ievs[PROC_QUEUE];
648 	ibuf = &iev->ibuf;
649 
650 	if (event & EV_READ) {
651 		if ((n = imsg_read(ibuf)) == -1)
652 			fatal("imsg_read_error");
653 		if (n == 0) {
654 			/* this pipe is dead, so remove the event handler */
655 			event_del(&iev->ev);
656 			event_loopexit(NULL);
657 			return;
658 		}
659 	}
660 
661 	if (event & EV_WRITE) {
662 		if (msgbuf_write(&ibuf->w) == -1)
663 			fatal("msgbuf_write");
664 	}
665 
666 	for (;;) {
667 		if ((n = imsg_get(ibuf, &imsg)) == -1)
668 			fatal("control_dispatch_queue: imsg_get error");
669 		if (n == 0)
670 			break;
671 
672 		switch (imsg.hdr.type) {
673 		default:
674 			log_warnx("control_dispatch_queue: got imsg %d",
675 			    imsg.hdr.type);
676 			fatalx("control_dispatch_queue: unexpected imsg");
677 		}
678 		imsg_free(&imsg);
679 	}
680 	imsg_event_add(iev);
681 }
682 
683 void
684 control_dispatch_runner(int sig, short event, void *p)
685 {
686 	struct smtpd		*env = p;
687 	struct imsgev		*iev;
688 	struct imsgbuf		*ibuf;
689 	struct imsg		 imsg;
690 	ssize_t			 n;
691 
692 	iev = env->sc_ievs[PROC_RUNNER];
693 	ibuf = &iev->ibuf;
694 
695 	if (event & EV_READ) {
696 		if ((n = imsg_read(ibuf)) == -1)
697 			fatal("imsg_read_error");
698 		if (n == 0) {
699 			/* this pipe is dead, so remove the event handler */
700 			event_del(&iev->ev);
701 			event_loopexit(NULL);
702 			return;
703 		}
704 	}
705 
706 	if (event & EV_WRITE) {
707 		if (msgbuf_write(&ibuf->w) == -1)
708 			fatal("msgbuf_write");
709 	}
710 
711 	for (;;) {
712 		if ((n = imsg_get(ibuf, &imsg)) == -1)
713 			fatal("control_dispatch_runner: imsg_get error");
714 		if (n == 0)
715 			break;
716 
717 		switch (imsg.hdr.type) {
718 		case IMSG_RUNNER_SCHEDULE: {
719 			struct sched	*s = imsg.data;
720 			struct ctl_conn	*c;
721 
722 			IMSG_SIZE_CHECK(s);
723 
724 			if ((c = control_connbyfd(s->fd)) == NULL) {
725 				log_warn("control_dispatch_runner: fd %d not found", s->fd);
726 				imsg_free(&imsg);
727 				return;
728 			}
729 
730 			if (s->ret)
731 				imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
732 			else
733 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
734 			break;
735 		}
736 		default:
737 			log_warnx("control_dispatch_runner: got imsg %d",
738 			    imsg.hdr.type);
739 			fatalx("control_dispatch_runner: unexpected imsg");
740 		}
741 		imsg_free(&imsg);
742 	}
743 	imsg_event_add(iev);
744 }
745 
746 void
747 control_dispatch_smtp(int sig, short event, void *p)
748 {
749 	struct smtpd		*env = p;
750 	struct imsgev		*iev;
751 	struct imsgbuf		*ibuf;
752 	struct imsg		 imsg;
753 	ssize_t			 n;
754 
755 	iev = env->sc_ievs[PROC_SMTP];
756 	ibuf = &iev->ibuf;
757 
758 	if (event & EV_READ) {
759 		if ((n = imsg_read(ibuf)) == -1)
760 			fatal("imsg_read_error");
761 		if (n == 0) {
762 			/* this pipe is dead, so remove the event handler */
763 			event_del(&iev->ev);
764 			event_loopexit(NULL);
765 			return;
766 		}
767 	}
768 
769 	if (event & EV_WRITE) {
770 		if (msgbuf_write(&ibuf->w) == -1)
771 			fatal("msgbuf_write");
772 	}
773 
774 	for (;;) {
775 		if ((n = imsg_get(ibuf, &imsg)) == -1)
776 			fatal("control_dispatch_smtp: imsg_get error");
777 		if (n == 0)
778 			break;
779 
780 		switch (imsg.hdr.type) {
781 		case IMSG_SMTP_ENQUEUE: {
782 			struct ctl_conn	*c;
783 			int		client_fd;
784 
785 			client_fd = imsg.hdr.peerid;
786 
787 			if ((c = control_connbyfd(client_fd)) == NULL) {
788 				log_warn("control_dispatch_smtp: fd %d not found", client_fd);
789 				imsg_free(&imsg);
790 				return;
791 			}
792 
793 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0,
794 			    imsg.fd, NULL, 0);
795 			break;
796 		}
797 		default:
798 			log_warnx("control_dispatch_smtp: got imsg %d",
799 			    imsg.hdr.type);
800 			fatalx("control_dispatch_smtp: unexpected imsg");
801 		}
802 		imsg_free(&imsg);
803 	}
804 	imsg_event_add(iev);
805 }
806 
807 void
808 session_socket_blockmode(int fd, enum blockmodes bm)
809 {
810 	int	flags;
811 
812 	if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
813 		fatal("fcntl F_GETFL");
814 
815 	if (bm == BM_NONBLOCK)
816 		flags |= O_NONBLOCK;
817 	else
818 		flags &= ~O_NONBLOCK;
819 
820 	if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
821 		fatal("fcntl F_SETFL");
822 }
823 
824 void
825 session_socket_no_linger(int fd)
826 {
827 	struct linger	 lng;
828 
829 	bzero(&lng, sizeof(lng));
830 	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng)) == -1)
831 		fatal("session_socket_no_linger");
832 }
833 
834 int
835 session_socket_error(int fd)
836 {
837 	int	 err, len;
838 
839 	len = sizeof(err);
840 	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) == -1)
841 		fatal("session_socket_error: getsockopt");
842 
843 	return (err);
844 }
845