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