xref: /openbsd/usr.sbin/snmpd/proc.c (revision 5f2be52b)
1 /*	$OpenBSD: proc.c,v 1.11 2014/08/18 13:13:42 reyk Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 - 2014 Reyk Floeter <reyk@openbsd.org>
5  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@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/socket.h>
23 #include <sys/wait.h>
24 #include <sys/tree.h>
25 
26 #include <net/if.h>
27 #include <netinet/in_systm.h>
28 #include <netinet/in.h>
29 #include <netinet/ip.h>
30 #include <arpa/inet.h>
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <signal.h>
38 #include <pwd.h>
39 #include <event.h>
40 
41 #include "snmpd.h"
42 
43 void	 proc_open(struct privsep *, struct privsep_proc *,
44 	    struct privsep_proc *, size_t);
45 void	 proc_close(struct privsep *);
46 int	 proc_ispeer(struct privsep_proc *, u_int, enum privsep_procid);
47 void	 proc_shutdown(struct privsep_proc *);
48 void	 proc_sig_handler(int, short, void *);
49 void	 proc_range(struct privsep *, enum privsep_procid, int *, int *);
50 
51 int
52 proc_ispeer(struct privsep_proc *procs, u_int nproc, enum privsep_procid type)
53 {
54 	u_int	i;
55 
56 	for (i = 0; i < nproc; i++)
57 		if (procs[i].p_id == type)
58 			return (1);
59 	return (0);
60 }
61 
62 void
63 proc_init(struct privsep *ps, struct privsep_proc *procs, u_int nproc)
64 {
65 	u_int			 i, j, src, dst;
66 	struct privsep_pipes	*pp;
67 
68 	/*
69 	 * Allocate pipes for all process instances (incl. parent)
70 	 *
71 	 * - ps->ps_pipes: N:M mapping
72 	 * N source processes connected to M destination processes:
73 	 * [src][instances][dst][instances], for example
74 	 * [PROC_RELAY][3][PROC_CA][3]
75 	 *
76 	 * - ps->ps_pp: per-process 1:M part of ps->ps_pipes
77 	 * Each process instance has a destination array of socketpair fds:
78 	 * [dst][instances], for example
79 	 * [PROC_PARENT][0]
80 	 */
81 	for (src = 0; src < PROC_MAX; src++) {
82 		/* Allocate destination array for each process */
83 		if ((ps->ps_pipes[src] = calloc(ps->ps_ninstances,
84 		    sizeof(struct privsep_pipes))) == NULL)
85 			fatal("proc_init: calloc");
86 
87 		for (i = 0; i < ps->ps_ninstances; i++) {
88 			pp = &ps->ps_pipes[src][i];
89 
90 			for (dst = 0; dst < PROC_MAX; dst++) {
91 				/* Allocate maximum fd integers */
92 				if ((pp->pp_pipes[dst] =
93 				    calloc(ps->ps_ninstances,
94 				    sizeof(int))) == NULL)
95 					fatal("proc_init: calloc");
96 
97 				/* Mark fd as unused */
98 				for (j = 0; j < ps->ps_ninstances; j++)
99 					pp->pp_pipes[dst][j] = -1;
100 			}
101 		}
102 	}
103 
104 	/*
105 	 * Setup and run the parent and its children
106 	 */
107 	privsep_process = PROC_PARENT;
108 	ps->ps_instances[PROC_PARENT] = 1;
109 	ps->ps_title[PROC_PARENT] = "parent";
110 	ps->ps_pid[PROC_PARENT] = getpid();
111 	ps->ps_pp = &ps->ps_pipes[privsep_process][0];
112 
113 	for (i = 0; i < nproc; i++) {
114 		/* Default to 1 process instance */
115 		if (ps->ps_instances[procs[i].p_id] < 1)
116 			ps->ps_instances[procs[i].p_id] = 1;
117 		ps->ps_title[procs[i].p_id] = procs[i].p_title;
118 	}
119 
120 	proc_open(ps, NULL, procs, nproc);
121 
122 	/* Engage! */
123 	for (i = 0; i < nproc; i++)
124 		ps->ps_pid[procs[i].p_id] = (*procs[i].p_init)(ps, &procs[i]);
125 }
126 
127 void
128 proc_kill(struct privsep *ps)
129 {
130 	pid_t		 pid;
131 	u_int		 i;
132 
133 	if (privsep_process != PROC_PARENT)
134 		return;
135 
136 	for (i = 0; i < PROC_MAX; i++) {
137 		if (ps->ps_pid[i] == 0)
138 			continue;
139 		killpg(ps->ps_pid[i], SIGTERM);
140 	}
141 
142 	do {
143 		pid = waitpid(WAIT_ANY, NULL, 0);
144 	} while (pid != -1 || (pid == -1 && errno == EINTR));
145 
146 	proc_close(ps);
147 }
148 
149 void
150 proc_open(struct privsep *ps, struct privsep_proc *p,
151     struct privsep_proc *procs, size_t nproc)
152 {
153 	struct privsep_pipes	*pa, *pb;
154 	int			 fds[2];
155 	u_int			 i, j, src, proc;
156 
157 	if (p == NULL)
158 		src = privsep_process; /* parent */
159 	else
160 		src = p->p_id;
161 
162 	/*
163 	 * Open socket pairs for our peers
164 	 */
165 	for (proc = 0; proc < nproc; proc++) {
166 		procs[proc].p_ps = ps;
167 		procs[proc].p_env = ps->ps_env;
168 
169 		for (i = 0; i < ps->ps_instances[src]; i++) {
170 			for (j = 0; j < ps->ps_instances[procs[proc].p_id];
171 			    j++) {
172 				pa = &ps->ps_pipes[src][i];
173 				pb = &ps->ps_pipes[procs[proc].p_id][j];
174 
175 				/* Check if fds are already set by peer */
176 				if (pa->pp_pipes[procs[proc].p_id][j] != -1)
177 					continue;
178 
179 				if (socketpair(AF_UNIX, SOCK_STREAM,
180 				    PF_UNSPEC, fds) == -1)
181 					fatal("socketpair");
182 
183 				socket_set_blockmode(fds[0], BM_NONBLOCK);
184 				socket_set_blockmode(fds[1], BM_NONBLOCK);
185 
186 				pa->pp_pipes[procs[proc].p_id][j] = fds[0];
187 				pb->pp_pipes[src][i] = fds[1];
188 			}
189 		}
190 	}
191 }
192 
193 void
194 proc_listen(struct privsep *ps, struct privsep_proc *procs, size_t nproc)
195 {
196 	u_int			 i, dst, src, n, m;
197 	struct privsep_pipes	*pp;
198 
199 	/*
200 	 * Close unused pipes
201 	 */
202 	for (src = 0; src < PROC_MAX; src++) {
203 		for (n = 0; n < ps->ps_instances[src]; n++) {
204 			/* Ingore current process */
205 			if (src == (u_int)privsep_process &&
206 			    n == ps->ps_instance)
207 				continue;
208 
209 			pp = &ps->ps_pipes[src][n];
210 
211 			for (dst = 0; dst < PROC_MAX; dst++) {
212 				if (src == dst)
213 					continue;
214 				for (m = 0; m < ps->ps_instances[dst]; m++) {
215 					if (pp->pp_pipes[dst][m] == -1)
216 						continue;
217 
218 					/* Close and invalidate fd */
219 					close(pp->pp_pipes[dst][m]);
220 					pp->pp_pipes[dst][m] = -1;
221 				}
222 			}
223 		}
224 	}
225 
226 	src = privsep_process;
227 	ps->ps_pp = pp = &ps->ps_pipes[src][ps->ps_instance];
228 
229 	/*
230 	 * Listen on appropriate pipes
231 	 */
232 	for (i = 0; i < nproc; i++) {
233 		dst = procs[i].p_id;
234 
235 		if (src == dst)
236 			fatal("proc_listen: cannot peer with oneself");
237 
238 		if ((ps->ps_ievs[dst] = calloc(ps->ps_instances[dst],
239 		    sizeof(struct imsgev))) == NULL)
240 			fatal("proc_open");
241 
242 		for (n = 0; n < ps->ps_instances[dst]; n++) {
243 			if (pp->pp_pipes[dst][n] == -1)
244 				continue;
245 
246 			imsg_init(&(ps->ps_ievs[dst][n].ibuf),
247 			    pp->pp_pipes[dst][n]);
248 			ps->ps_ievs[dst][n].handler = proc_dispatch;
249 			ps->ps_ievs[dst][n].events = EV_READ;
250 			ps->ps_ievs[dst][n].proc = &procs[i];
251 			ps->ps_ievs[dst][n].data = &ps->ps_ievs[dst][n];
252 			procs[i].p_instance = n;
253 
254 			event_set(&(ps->ps_ievs[dst][n].ev),
255 			    ps->ps_ievs[dst][n].ibuf.fd,
256 			    ps->ps_ievs[dst][n].events,
257 			    ps->ps_ievs[dst][n].handler,
258 			    ps->ps_ievs[dst][n].data);
259 			event_add(&(ps->ps_ievs[dst][n].ev), NULL);
260 		}
261 	}
262 }
263 
264 void
265 proc_close(struct privsep *ps)
266 {
267 	u_int			 dst, n;
268 	struct privsep_pipes	*pp;
269 
270 	if (ps == NULL)
271 		return;
272 
273 	pp = ps->ps_pp;
274 
275 	for (dst = 0; dst < PROC_MAX; dst++) {
276 		if (ps->ps_ievs[dst] == NULL)
277 			continue;
278 
279 		for (n = 0; n < ps->ps_instances[dst]; n++) {
280 			if (pp->pp_pipes[dst][n] == -1)
281 				continue;
282 
283 			/* Cancel the fd, close and invalidate the fd */
284 			event_del(&(ps->ps_ievs[dst][n].ev));
285 			imsg_clear(&(ps->ps_ievs[dst][n].ibuf));
286 			close(pp->pp_pipes[dst][n]);
287 			pp->pp_pipes[dst][n] = -1;
288 		}
289 		free(ps->ps_ievs[dst]);
290 	}
291 }
292 
293 void
294 proc_shutdown(struct privsep_proc *p)
295 {
296 	struct privsep	*ps = p->p_ps;
297 
298 	if (p->p_id == PROC_CONTROL && ps)
299 		control_cleanup(&ps->ps_csock);
300 
301 	if (p->p_shutdown != NULL)
302 		(*p->p_shutdown)();
303 
304 	proc_close(ps);
305 
306 	log_info("%s exiting, pid %d", p->p_title, getpid());
307 
308 	_exit(0);
309 }
310 
311 void
312 proc_sig_handler(int sig, short event, void *arg)
313 {
314 	struct privsep_proc	*p = arg;
315 
316 	switch (sig) {
317 	case SIGINT:
318 	case SIGTERM:
319 		proc_shutdown(p);
320 		break;
321 	case SIGCHLD:
322 	case SIGHUP:
323 	case SIGPIPE:
324 	case SIGUSR1:
325 		/* ignore */
326 		break;
327 	default:
328 		fatalx("proc_sig_handler: unexpected signal");
329 		/* NOTREACHED */
330 	}
331 }
332 
333 pid_t
334 proc_run(struct privsep *ps, struct privsep_proc *p,
335     struct privsep_proc *procs, u_int nproc,
336     void (*init)(struct privsep *, struct privsep_proc *, void *), void *arg)
337 {
338 	pid_t			 pid;
339 	struct passwd		*pw;
340 	const char		*root;
341 	struct control_sock	*rcs;
342 	u_int			 n;
343 
344 	if (ps->ps_noaction)
345 		return (0);
346 
347 	proc_open(ps, p, procs, nproc);
348 
349 	/* Fork child handlers */
350 	switch (pid = fork()) {
351 	case -1:
352 		fatal("proc_run: cannot fork");
353 	case 0:
354 		/* Set the process group of the current process */
355 		setpgrp(0, getpid());
356 		break;
357 	default:
358 		return (pid);
359 	}
360 
361 	pw = ps->ps_pw;
362 
363 	if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) {
364 		if (control_init(ps, &ps->ps_csock) == -1)
365 			fatalx(p->p_title);
366 		TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
367 			if (control_init(ps, rcs) == -1)
368 				fatalx(p->p_title);
369 	}
370 
371 	/* Change root directory */
372 	if (p->p_chroot != NULL)
373 		root = p->p_chroot;
374 	else
375 		root = pw->pw_dir;
376 
377 	if (chroot(root) == -1)
378 		fatal("proc_run: chroot");
379 	if (chdir("/") == -1)
380 		fatal("proc_run: chdir(\"/\")");
381 
382 	privsep_process = p->p_id;
383 
384 	setproctitle("%s", p->p_title);
385 
386 	if (setgroups(1, &pw->pw_gid) ||
387 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
388 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
389 		fatal("proc_run: cannot drop privileges");
390 
391 	/* Fork child handlers */
392 	for (n = 1; n < ps->ps_instances[p->p_id]; n++) {
393 		if (fork() == 0) {
394 			ps->ps_instance = p->p_instance = n;
395 			break;
396 		}
397 	}
398 
399 #ifdef DEBUG
400 	log_debug("%s: %s %d/%d, pid %d", __func__, p->p_title,
401 	    ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid());
402 #endif
403 
404 	event_init();
405 
406 	signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p);
407 	signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p);
408 	signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p);
409 	signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p);
410 	signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p);
411 	signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p);
412 
413 	signal_add(&ps->ps_evsigint, NULL);
414 	signal_add(&ps->ps_evsigterm, NULL);
415 	signal_add(&ps->ps_evsigchld, NULL);
416 	signal_add(&ps->ps_evsighup, NULL);
417 	signal_add(&ps->ps_evsigpipe, NULL);
418 	signal_add(&ps->ps_evsigusr1, NULL);
419 
420 	proc_listen(ps, procs, nproc);
421 
422 	if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) {
423 		TAILQ_INIT(&ctl_conns);
424 		if (control_listen(&ps->ps_csock) == -1)
425 			fatalx(p->p_title);
426 		TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
427 			if (control_listen(rcs) == -1)
428 				fatalx(p->p_title);
429 	}
430 
431 	if (init != NULL)
432 		init(ps, p, arg);
433 
434 	event_dispatch();
435 
436 	proc_shutdown(p);
437 
438 	return (0);
439 }
440 
441 void
442 proc_dispatch(int fd, short event, void *arg)
443 {
444 	struct imsgev		*iev = arg;
445 	struct privsep_proc	*p = iev->proc;
446 	struct privsep		*ps = p->p_ps;
447 	struct imsgbuf		*ibuf;
448 	struct imsg		 imsg;
449 	ssize_t			 n;
450 	int			 verbose;
451 	const char		*title;
452 
453 	title = ps->ps_title[privsep_process];
454 	ibuf = &iev->ibuf;
455 
456 	if (event & EV_READ) {
457 		if ((n = imsg_read(ibuf)) == -1)
458 			fatal(title);
459 		if (n == 0) {
460 			/* this pipe is dead, so remove the event handler */
461 			event_del(&iev->ev);
462 			event_loopexit(NULL);
463 			return;
464 		}
465 	}
466 
467 	if (event & EV_WRITE) {
468 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
469 			fatal(title);
470 	}
471 
472 	for (;;) {
473 		if ((n = imsg_get(ibuf, &imsg)) == -1)
474 			fatal(title);
475 		if (n == 0)
476 			break;
477 
478 #if DEBUG > 1
479 		log_debug("%s: %s %d got imsg %d from %s %d",
480 		    __func__, title, ps->ps_instance + 1,
481 		    imsg.hdr.type, p->p_title, p->p_instance);
482 #endif
483 
484 		/*
485 		 * Check the message with the program callback
486 		 */
487 		if ((p->p_cb)(fd, p, &imsg) == 0) {
488 			/* Message was handled by the callback, continue */
489 			imsg_free(&imsg);
490 			continue;
491 		}
492 
493 		/*
494 		 * Generic message handling
495 		 */
496 		switch (imsg.hdr.type) {
497 		case IMSG_CTL_VERBOSE:
498 			IMSG_SIZE_CHECK(&imsg, &verbose);
499 			memcpy(&verbose, imsg.data, sizeof(verbose));
500 			log_verbose(verbose);
501 			break;
502 		default:
503 			log_warnx("%s: %s %d got invalid imsg %d from %s %d",
504 			    __func__, title, ps->ps_instance + 1,
505 			    imsg.hdr.type, p->p_title, p->p_instance);
506 			fatalx(title);
507 		}
508 		imsg_free(&imsg);
509 	}
510 	imsg_event_add(iev);
511 }
512 
513 /*
514  * imsg helper functions
515  */
516 
517 void
518 imsg_event_add(struct imsgev *iev)
519 {
520 	if (iev->handler == NULL) {
521 		imsg_flush(&iev->ibuf);
522 		return;
523 	}
524 
525 	iev->events = EV_READ;
526 	if (iev->ibuf.w.queued)
527 		iev->events |= EV_WRITE;
528 
529 	event_del(&iev->ev);
530 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
531 	event_add(&iev->ev, NULL);
532 }
533 
534 int
535 imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid,
536     pid_t pid, int fd, void *data, u_int16_t datalen)
537 {
538 	int	ret;
539 
540 	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
541 	    pid, fd, data, datalen)) == -1)
542 		return (ret);
543 	imsg_event_add(iev);
544 	return (ret);
545 }
546 
547 int
548 imsg_composev_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid,
549     pid_t pid, int fd, const struct iovec *iov, int iovcnt)
550 {
551 	int	ret;
552 
553 	if ((ret = imsg_composev(&iev->ibuf, type, peerid,
554 	    pid, fd, iov, iovcnt)) == -1)
555 		return (ret);
556 	imsg_event_add(iev);
557 	return (ret);
558 }
559 
560 void
561 proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m)
562 {
563 	if (*n == -1) {
564 		/* Use a range of all target instances */
565 		*n = 0;
566 		*m = ps->ps_instances[id];
567 	} else {
568 		/* Use only a single slot of the specified peer process */
569 		*m = *n + 1;
570 	}
571 }
572 
573 int
574 proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n,
575     u_int16_t type, int fd, void *data, u_int16_t datalen)
576 {
577 	int	 m;
578 
579 	proc_range(ps, id, &n, &m);
580 	for (; n < m; n++) {
581 		if (imsg_compose_event(&ps->ps_ievs[id][n],
582 		    type, -1, 0, fd, data, datalen) == -1)
583 			return (-1);
584 	}
585 
586 	return (0);
587 }
588 
589 int
590 proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n,
591     u_int16_t type, int fd, const struct iovec *iov, int iovcnt)
592 {
593 	int	 m;
594 
595 	proc_range(ps, id, &n, &m);
596 	for (; n < m; n++)
597 		if (imsg_composev_event(&ps->ps_ievs[id][n],
598 		    type, -1, 0, fd, iov, iovcnt) == -1)
599 			return (-1);
600 
601 	return (0);
602 }
603 
604 int
605 proc_forward_imsg(struct privsep *ps, struct imsg *imsg,
606     enum privsep_procid id, int n)
607 {
608 	return (proc_compose_imsg(ps, id, n, imsg->hdr.type,
609 	    imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg)));
610 }
611 
612 struct imsgbuf *
613 proc_ibuf(struct privsep *ps, enum privsep_procid id, int n)
614 {
615 	int	 m;
616 
617 	proc_range(ps, id, &n, &m);
618 	return (&ps->ps_ievs[id][n].ibuf);
619 }
620 
621 struct imsgev *
622 proc_iev(struct privsep *ps, enum privsep_procid id, int n)
623 {
624 	int	 m;
625 
626 	proc_range(ps, id, &n, &m);
627 	return (&ps->ps_ievs[id][n]);
628 }
629