xref: /openbsd-src/usr.sbin/smtpd/control.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: control.c,v 1.60 2011/09/01 19:56:49 eric 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 <imsg.h>
32 #include <pwd.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 
39 #include "smtpd.h"
40 #include "log.h"
41 
42 #define CONTROL_BACKLOG 5
43 
44 /* control specific headers */
45 struct {
46 	struct event		 ev;
47 	int			 fd;
48 } control_state;
49 
50 void		 control_imsg(struct imsgev *, struct imsg *);
51 __dead void	 control_shutdown(void);
52 int		 control_init(void);
53 void		 control_listen(void);
54 void		 control_cleanup(void);
55 void		 control_accept(int, short, void *);
56 struct ctl_conn	*control_connbyfd(int);
57 void		 control_close(int);
58 void		 control_sig_handler(int, short, void *);
59 void		 control_dispatch_ext(int, short, void *);
60 
61 struct ctl_connlist	ctl_conns;
62 
63 void
64 control_imsg(struct imsgev *iev, struct imsg *imsg)
65 {
66 	struct ctl_conn	*c;
67 	struct reload	*reload;
68 
69 	if (iev->proc == PROC_SMTP) {
70 		switch (imsg->hdr.type) {
71 		case IMSG_SMTP_ENQUEUE:
72 			c = control_connbyfd(imsg->hdr.peerid);
73 			if (c == NULL)
74 				return;
75 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0,
76 			    imsg->fd, NULL, 0);
77 			return;
78 		}
79 	}
80 
81 	if (iev->proc == PROC_PARENT) {
82 		switch (imsg->hdr.type) {
83 		case IMSG_CONF_RELOAD:
84 			env->sc_flags &= ~SMTPD_CONFIGURING;
85 			reload = imsg->data;
86 			c = control_connbyfd(reload->fd);
87 			if (c == NULL)
88 				return;
89 			imsg_compose_event(&c->iev,
90 			    reload->ret ? IMSG_CTL_OK : IMSG_CTL_FAIL, 0, 0,
91 			    -1, NULL, 0);
92 			return;
93 		}
94 	}
95 
96 	fatalx("control_imsg: unexpected imsg");
97 }
98 
99 void
100 control_sig_handler(int sig, short event, void *p)
101 {
102 	switch (sig) {
103 	case SIGINT:
104 	case SIGTERM:
105 		control_shutdown();
106 		break;
107 	default:
108 		fatalx("control_sig_handler: unexpected signal");
109 	}
110 }
111 
112 
113 pid_t
114 control(void)
115 {
116 	struct sockaddr_un	 sun;
117 	int			 fd;
118 	mode_t			 old_umask;
119 	pid_t			 pid;
120 	struct passwd		*pw;
121 	struct event		 ev_sigint;
122 	struct event		 ev_sigterm;
123 	struct peer		 peers [] = {
124 		{ PROC_RUNNER,	 imsg_dispatch },
125 		{ PROC_QUEUE,	 imsg_dispatch },
126 		{ PROC_SMTP,	 imsg_dispatch },
127 		{ PROC_MFA,	 imsg_dispatch },
128 		{ PROC_PARENT,	 imsg_dispatch },
129 	};
130 
131 	switch (pid = fork()) {
132 	case -1:
133 		fatal("control: cannot fork");
134 	case 0:
135 		break;
136 	default:
137 		return (pid);
138 	}
139 
140 	purge_config(PURGE_EVERYTHING);
141 
142 	pw = env->sc_pw;
143 
144 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
145 		fatal("control: socket");
146 
147 	bzero(&sun, sizeof(sun));
148 	sun.sun_family = AF_UNIX;
149 	if (strlcpy(sun.sun_path, SMTPD_SOCKET,
150 	    sizeof(sun.sun_path)) >= sizeof(sun.sun_path))
151 		fatal("control: socket name too long");
152 
153 	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == 0)
154 		fatalx("control socket already listening");
155 
156 	if (unlink(SMTPD_SOCKET) == -1)
157 		if (errno != ENOENT)
158 			fatal("control: cannot unlink socket");
159 
160 	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
161 	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
162 		(void)umask(old_umask);
163 		fatal("control: bind");
164 	}
165 	(void)umask(old_umask);
166 
167 	if (chmod(SMTPD_SOCKET, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) {
168 		(void)unlink(SMTPD_SOCKET);
169 		fatal("control: chmod");
170 	}
171 
172 	session_socket_blockmode(fd, BM_NONBLOCK);
173 	control_state.fd = fd;
174 
175 	if (chroot(pw->pw_dir) == -1)
176 		fatal("control: chroot");
177 	if (chdir("/") == -1)
178 		fatal("control: chdir(\"/\")");
179 
180 	smtpd_process = PROC_CONTROL;
181 	setproctitle("%s", env->sc_title[smtpd_process]);
182 
183 	if (setgroups(1, &pw->pw_gid) ||
184 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
185 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
186 		fatal("control: cannot drop privileges");
187 
188 	imsg_callback = control_imsg;
189 	event_init();
190 
191 	signal_set(&ev_sigint, SIGINT, control_sig_handler, NULL);
192 	signal_set(&ev_sigterm, SIGTERM, control_sig_handler, NULL);
193 	signal_add(&ev_sigint, NULL);
194 	signal_add(&ev_sigterm, NULL);
195 	signal(SIGPIPE, SIG_IGN);
196 	signal(SIGHUP, SIG_IGN);
197 
198 	TAILQ_INIT(&ctl_conns);
199 
200 	config_pipes(peers, nitems(peers));
201 	config_peers(peers, nitems(peers));
202 	control_listen();
203 
204 	if (event_dispatch() < 0)
205 		fatal("event_dispatch");
206 	control_shutdown();
207 
208 	return (0);
209 }
210 
211 void
212 control_shutdown(void)
213 {
214 	log_info("control process exiting");
215 	_exit(0);
216 }
217 
218 void
219 control_listen(void)
220 {
221 	int avail = availdesc();
222 
223 	if (listen(control_state.fd, CONTROL_BACKLOG) == -1)
224 		fatal("control_listen");
225 	avail--;
226 
227 	event_set(&control_state.ev, control_state.fd, EV_READ|EV_PERSIST,
228 	    control_accept, NULL);
229 	event_add(&control_state.ev, NULL);
230 
231 	/* guarantee 2 fds to each accepted client */
232 	if ((env->sc_maxconn = avail / 2) < 1)
233 		fatalx("control_listen: fd starvation");
234 }
235 
236 void
237 control_cleanup(void)
238 {
239 	(void)unlink(SMTPD_SOCKET);
240 }
241 
242 /* ARGSUSED */
243 void
244 control_accept(int listenfd, short event, void *arg)
245 {
246 	int			 connfd;
247 	socklen_t		 len;
248 	struct sockaddr_un	 sun;
249 	struct ctl_conn		*c;
250 
251 	len = sizeof(sun);
252 	if ((connfd = accept(listenfd, (struct sockaddr *)&sun, &len)) == -1) {
253 		if (errno == EINTR || errno == ECONNABORTED)
254 			return;
255 		fatal("control_accept: accept");
256 	}
257 
258 	session_socket_blockmode(connfd, BM_NONBLOCK);
259 
260 	if ((c = calloc(1, sizeof(*c))) == NULL)
261 		fatal(NULL);
262 	imsg_init(&c->iev.ibuf, connfd);
263 	c->iev.handler = control_dispatch_ext;
264 	c->iev.events = EV_READ;
265 	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
266 	    c->iev.handler, NULL);
267 	event_add(&c->iev.ev, NULL);
268 	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
269 
270 	if (stat_increment(STATS_CONTROL_SESSION) >= env->sc_maxconn) {
271 		log_warnx("ctl client limit hit, disabling new connections");
272 		event_del(&control_state.ev);
273 	}
274 }
275 
276 struct ctl_conn *
277 control_connbyfd(int fd)
278 {
279 	struct ctl_conn	*c;
280 
281 	for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd;
282 	    c = TAILQ_NEXT(c, entry))
283 		;	/* nothing */
284 
285 	return (c);
286 }
287 
288 void
289 control_close(int fd)
290 {
291 	struct ctl_conn	*c;
292 
293 	if ((c = control_connbyfd(fd)) == NULL) {
294 		log_warn("control_close: fd %d: not found", fd);
295 		return;
296 	}
297 	TAILQ_REMOVE(&ctl_conns, c, entry);
298 	event_del(&c->iev.ev);
299 	imsg_clear(&c->iev.ibuf);
300 	close(fd);
301 	free(c);
302 
303 	if (stat_decrement(STATS_CONTROL_SESSION) < env->sc_maxconn &&
304 	    !event_pending(&control_state.ev, EV_READ, NULL)) {
305 		log_warnx("re-enabling ctl connections");
306 		event_add(&control_state.ev, NULL);
307 	}
308 }
309 
310 /* ARGSUSED */
311 void
312 control_dispatch_ext(int fd, short event, void *arg)
313 {
314 	struct ctl_conn		*c;
315 	struct imsg		 imsg;
316 	int			 n;
317 	uid_t			 euid;
318 	gid_t			 egid;
319 
320 	if (getpeereid(fd, &euid, &egid) == -1)
321 		fatal("getpeereid");
322 
323 	if ((c = control_connbyfd(fd)) == NULL) {
324 		log_warn("control_dispatch_ext: fd %d: not found", fd);
325 		return;
326 	}
327 
328 	if (event & EV_READ) {
329 		if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) {
330 			control_close(fd);
331 			return;
332 		}
333 	}
334 
335 	if (event & EV_WRITE) {
336 		if (msgbuf_write(&c->iev.ibuf.w) < 0) {
337 			control_close(fd);
338 			return;
339 		}
340 	}
341 
342 	for (;;) {
343 		if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
344 			control_close(fd);
345 			return;
346 		}
347 
348 		if (n == 0)
349 			break;
350 
351 		switch (imsg.hdr.type) {
352 		case IMSG_SMTP_ENQUEUE:
353 			if (env->sc_flags & (SMTPD_SMTP_PAUSED |
354 			    SMTPD_CONFIGURING | SMTPD_EXITING)) {
355 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
356 					NULL, 0);
357 				break;
358 			}
359 			imsg_compose_event(env->sc_ievs[PROC_SMTP],
360 			    IMSG_SMTP_ENQUEUE, fd, 0, -1, &euid, sizeof(euid));
361 			break;
362 		case IMSG_STATS:
363 			if (euid)
364 				goto badcred;
365 			imsg_compose_event(&c->iev, IMSG_STATS, 0, 0, -1,
366 			    env->stats, sizeof(struct stats));
367 			break;
368 		case IMSG_CTL_SHUTDOWN:
369 			/* NEEDS_FIX */
370 			log_debug("received shutdown request");
371 
372 			if (euid)
373 				goto badcred;
374 
375 			if (env->sc_flags & SMTPD_EXITING) {
376 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
377 					NULL, 0);
378 				break;
379 			}
380 			env->sc_flags |= SMTPD_EXITING;
381 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
382 			break;
383 		case IMSG_CTL_VERBOSE: {
384 			int verbose;
385 
386 			if (euid)
387 				goto badcred;
388 
389 			if (IMSG_DATA_SIZE(&imsg) != sizeof(verbose))
390 				goto badcred;
391 
392 			memcpy(&verbose, imsg.data, sizeof(verbose));
393 			log_verbose(verbose);
394 			imsg_compose_event(env->sc_ievs[PROC_PARENT], IMSG_CTL_VERBOSE,
395 			    0, 0, -1, &verbose, sizeof(verbose));
396 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
397 			break;
398 		}
399 		case IMSG_QUEUE_PAUSE_LOCAL:
400 			if (euid)
401 				goto badcred;
402 
403 			if (env->sc_flags & SMTPD_MDA_PAUSED) {
404 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
405 					NULL, 0);
406 				break;
407 			}
408 			env->sc_flags |= SMTPD_MDA_PAUSED;
409 			imsg_compose_event(env->sc_ievs[PROC_QUEUE],
410 			    IMSG_QUEUE_PAUSE_LOCAL, 0, 0, -1, NULL, 0);
411 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
412 			break;
413 		case IMSG_QUEUE_PAUSE_OUTGOING:
414 			if (euid)
415 				goto badcred;
416 
417 			if (env->sc_flags & SMTPD_MTA_PAUSED) {
418 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
419 					NULL, 0);
420 				break;
421 			}
422 			env->sc_flags |= SMTPD_MTA_PAUSED;
423 			imsg_compose_event(env->sc_ievs[PROC_QUEUE],
424 			    IMSG_QUEUE_PAUSE_OUTGOING, 0, 0, -1, NULL, 0);
425 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
426 			break;
427 		case IMSG_SMTP_PAUSE:
428 			if (euid)
429 				goto badcred;
430 
431 			if (env->sc_flags & SMTPD_SMTP_PAUSED) {
432 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
433 					NULL, 0);
434 				break;
435 			}
436 			env->sc_flags |= SMTPD_SMTP_PAUSED;
437 			imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_PAUSE,
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_QUEUE_RESUME_LOCAL:
442 			if (euid)
443 				goto badcred;
444 
445 			if (! (env->sc_flags & SMTPD_MDA_PAUSED)) {
446 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
447 					NULL, 0);
448 				break;
449 			}
450 			env->sc_flags &= ~SMTPD_MDA_PAUSED;
451 			imsg_compose_event(env->sc_ievs[PROC_QUEUE],
452 			    IMSG_QUEUE_RESUME_LOCAL, 0, 0, -1, NULL, 0);
453 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
454 			break;
455 		case IMSG_QUEUE_RESUME_OUTGOING:
456 			if (euid)
457 				goto badcred;
458 
459 			if (!(env->sc_flags & SMTPD_MTA_PAUSED)) {
460 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
461 					NULL, 0);
462 				break;
463 			}
464 			env->sc_flags &= ~SMTPD_MTA_PAUSED;
465 			imsg_compose_event(env->sc_ievs[PROC_QUEUE],
466 			    IMSG_QUEUE_RESUME_OUTGOING, 0, 0, -1, NULL, 0);
467 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
468 			break;
469 
470 		case IMSG_SMTP_RESUME:
471 			if (euid)
472 				goto badcred;
473 
474 			if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) {
475 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
476 					NULL, 0);
477 				break;
478 			}
479 			env->sc_flags &= ~SMTPD_SMTP_PAUSED;
480 			imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_RESUME,
481 			    0, 0, -1, NULL, 0);
482 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
483 			break;
484 
485 		case IMSG_RUNNER_SCHEDULE: {
486 			u_int64_t ullval;
487 
488 			if (euid)
489 				goto badcred;
490 
491 			ullval = *(u_int64_t *)imsg.data;
492 
493 			imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_RUNNER_SCHEDULE,
494 			    0, 0, -1, &ullval, sizeof(ullval));
495 
496 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
497 			break;
498 		}
499 
500 		case IMSG_RUNNER_REMOVE: {
501 			u_int64_t ullval;
502 
503 			if (euid)
504 				goto badcred;
505 
506 			ullval = *(u_int64_t *)imsg.data;
507 
508 			imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_RUNNER_REMOVE,
509 			    0, 0, -1, &ullval, sizeof(ullval));
510 
511 			imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
512 			break;
513 		}
514 		default:
515 			log_debug("control_dispatch_ext: "
516 			    "error handling imsg %d", imsg.hdr.type);
517 			break;
518 		}
519 		imsg_free(&imsg);
520 		continue;
521 
522 badcred:
523 		imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1,
524 		    NULL, 0);
525 	}
526 
527 	imsg_event_add(&c->iev);
528 }
529