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