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