xref: /openbsd-src/sbin/iked/proc.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: proc.c,v 1.7 2011/05/09 11:27:08 reyk Exp $	*/
2 
3 /*
4  * Copyright (c) 2010,2011 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/tree.h>
23 #include <sys/param.h>
24 #include <sys/wait.h>
25 #include <sys/socket.h>
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <signal.h>
33 #include <pwd.h>
34 #include <event.h>
35 
36 #include <openssl/rand.h>
37 
38 #include "iked.h"
39 
40 void	 proc_setup(struct privsep *);
41 void	 proc_shutdown(struct privsep_proc *);
42 void	 proc_sig_handler(int, short, void *);
43 
44 void
45 proc_init(struct privsep *ps, struct privsep_proc *p, u_int nproc)
46 {
47 	u_int	 i;
48 
49 	/*
50 	 * Called from parent
51 	 */
52 	privsep_process = PROC_PARENT;
53 	ps->ps_title[PROC_PARENT] = "parent";
54 	ps->ps_pid[PROC_PARENT] = getpid();
55 
56 	proc_setup(ps);
57 
58 	/* Engage! */
59 	for (i = 0; i < nproc; i++, p++) {
60 		ps->ps_title[p->p_id] = p->p_title;
61 		ps->ps_pid[p->p_id] = (*p->p_init)(ps, p);
62 	}
63 }
64 
65 void
66 proc_kill(struct privsep *ps)
67 {
68 	pid_t		 pid;
69 	u_int		 i;
70 
71 	if (privsep_process != PROC_PARENT)
72 		return;
73 
74 	for (i = 0; i < PROC_MAX; i++) {
75 		if (ps->ps_pid[i] == 0)
76 			continue;
77 		kill(ps->ps_pid[i], SIGTERM);
78 	}
79 
80 	do {
81 		pid = waitpid(WAIT_ANY, NULL, 0);
82 	} while (pid != -1 || (pid == -1 && errno == EINTR));
83 }
84 
85 void
86 proc_setup(struct privsep *ps)
87 {
88 	int	 i, j, sockpair[2];
89 
90 	for (i = 0; i < PROC_MAX; i++)
91 		for (j = 0; j < PROC_MAX; j++) {
92 			if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
93 			    sockpair) == -1)
94 				fatal("sockpair");
95 			ps->ps_pipes[i][j] = sockpair[0];
96 			ps->ps_pipes[j][i] = sockpair[1];
97 			socket_set_blockmode(ps->ps_pipes[i][j],
98 			    BM_NONBLOCK);
99 			socket_set_blockmode(ps->ps_pipes[j][i],
100 			    BM_NONBLOCK);
101 		}
102 }
103 
104 void
105 proc_config(struct privsep *ps, struct privsep_proc *p, u_int nproc)
106 {
107 	u_int	 src, dst, i, j, k, found;
108 
109 	src = privsep_process;
110 
111 	/*
112 	 * close unused pipes
113 	 */
114 	for (i = 0; i < PROC_MAX; i++) {
115 		if (i != privsep_process) {
116 			for (j = 0; j < PROC_MAX; j++) {
117 				close(ps->ps_pipes[i][j]);
118 				ps->ps_pipes[i][j] = -1;
119 			}
120 		} else {
121 			for (j = found = 0; j < PROC_MAX; j++, found = 0) {
122 				for (k = 0; k < nproc; k++) {
123 					if (p[k].p_id == j)
124 						found++;
125 				}
126 				if (!found) {
127 					close(ps->ps_pipes[i][j]);
128 					ps->ps_pipes[i][j] = -1;
129 				}
130 			}
131 		}
132 	}
133 
134 	/*
135 	 * listen on appropriate pipes
136 	 */
137 	for (i = 0; i < nproc; i++, p++) {
138 		dst = p->p_id;
139 		p->p_ps = ps;
140 		p->p_env = ps->ps_env;
141 
142 		imsg_init(&ps->ps_ievs[dst].ibuf,
143 		    ps->ps_pipes[src][dst]);
144 		ps->ps_ievs[dst].handler = proc_dispatch;
145 		ps->ps_ievs[dst].events = EV_READ;
146 		ps->ps_ievs[dst].data = p;
147 		ps->ps_ievs[dst].name = p->p_title;
148 		event_set(&ps->ps_ievs[dst].ev,
149 		    ps->ps_ievs[dst].ibuf.fd,
150 		    ps->ps_ievs[dst].events,
151 		    ps->ps_ievs[dst].handler,
152 		    ps->ps_ievs[dst].data);
153 		event_add(&ps->ps_ievs[dst].ev, NULL);
154 	}
155 }
156 
157 void
158 proc_shutdown(struct privsep_proc *p)
159 {
160 	struct privsep	*ps = p->p_ps;
161 
162 	if (p->p_id == PROC_CONTROL && ps)
163 		control_cleanup(&ps->ps_csock);
164 
165 	log_info("%s exiting", p->p_title);
166 	_exit(0);
167 }
168 
169 void
170 proc_sig_handler(int sig, short event, void *arg)
171 {
172 	struct privsep_proc	*p = arg;
173 
174 	switch (sig) {
175 	case SIGINT:
176 	case SIGTERM:
177 		proc_shutdown(p);
178 		break;
179 	case SIGCHLD:
180 	case SIGHUP:
181 	case SIGPIPE:
182 		/* ignore */
183 		break;
184 	default:
185 		fatalx("proc_sig_handler: unexpected signal");
186 		/* NOTREACHED */
187 	}
188 }
189 
190 pid_t
191 proc_run(struct privsep *ps, struct privsep_proc *p,
192     struct privsep_proc *procs, u_int nproc,
193     void (*init)(struct privsep *, void *), void *arg)
194 {
195 	pid_t		 pid;
196 	struct passwd	*pw;
197 	const char	*root;
198 	u_int32_t	 seed[256];
199 
200 	switch (pid = fork()) {
201 	case -1:
202 		fatal("proc_run: cannot fork");
203 	case 0:
204 		break;
205 	default:
206 		return (pid);
207 	}
208 
209 	pw = ps->ps_pw;
210 
211 	if (p->p_id == PROC_CONTROL) {
212 		if (control_init(ps, &ps->ps_csock) == -1)
213 			fatalx(p->p_title);
214 	}
215 
216 	/* Change root directory */
217 	if (p->p_chroot != NULL)
218 		root = p->p_chroot;
219 	else
220 		root = pw->pw_dir;
221 
222 #ifndef DEBUG
223 	if (chroot(root) == -1)
224 		fatal("proc_run: chroot");
225 	if (chdir("/") == -1)
226 		fatal("proc_run: chdir(\"/\")");
227 #else
228 #warning disabling privilege revocation and chroot in DEBUG MODE
229 	if (p->p_chroot != NULL) {
230 		if (chroot(root) == -1)
231 			fatal("proc_run: chroot");
232 		if (chdir("/") == -1)
233 			fatal("proc_run: chdir(\"/\")");
234 	}
235 #endif
236 
237 	privsep_process = p->p_id;
238 
239 	setproctitle("%s", p->p_title);
240 
241 #ifndef DEBUG
242 	if (setgroups(1, &pw->pw_gid) ||
243 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
244 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
245 		fatal("proc_run: cannot drop privileges");
246 #endif
247 
248 	event_init();
249 
250 	signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p);
251 	signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p);
252 	signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p);
253 	signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p);
254 	signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p);
255 
256 	signal_add(&ps->ps_evsigint, NULL);
257 	signal_add(&ps->ps_evsigterm, NULL);
258 	signal_add(&ps->ps_evsigchld, NULL);
259 	signal_add(&ps->ps_evsighup, NULL);
260 	signal_add(&ps->ps_evsigpipe, NULL);
261 
262 	proc_config(ps, procs, nproc);
263 
264 	arc4random_buf(seed, sizeof(seed));
265 	RAND_seed(seed, sizeof(seed));
266 
267 	if (p->p_id == PROC_CONTROL) {
268 		TAILQ_INIT(&ctl_conns);
269 		if (control_listen(&ps->ps_csock) == -1)
270 			fatalx(p->p_title);
271 	}
272 
273 	if (init != NULL)
274 		init(ps, arg);
275 
276 	event_dispatch();
277 
278 	proc_shutdown(p);
279 
280 	return (0);
281 }
282 
283 void
284 proc_dispatch(int fd, short event, void *arg)
285 {
286 	struct privsep_proc	*p = (struct privsep_proc *)arg;
287 	struct privsep		*ps = p->p_ps;
288 	struct imsgev		*iev;
289 	struct imsgbuf		*ibuf;
290 	struct imsg		 imsg;
291 	ssize_t			 n;
292 	int			 verbose;
293 	const char		*title;
294 
295 	title = ps->ps_title[privsep_process];
296 	iev = &ps->ps_ievs[p->p_id];
297 	ibuf = &iev->ibuf;
298 
299 	if (event & EV_READ) {
300 		if ((n = imsg_read(ibuf)) == -1)
301 			fatal(title);
302 		if (n == 0) {
303 			/* this pipe is dead, so remove the event handler */
304 			event_del(&iev->ev);
305 			event_loopexit(NULL);
306 			return;
307 		}
308 	}
309 
310 	if (event & EV_WRITE) {
311 		if (msgbuf_write(&ibuf->w) == -1)
312 			fatal(title);
313 	}
314 
315 	for (;;) {
316 		if ((n = imsg_get(ibuf, &imsg)) == -1)
317 			fatal(title);
318 		if (n == 0)
319 			break;
320 
321 		/*
322 		 * Check the message with the program callback
323 		 */
324 		if ((p->p_cb)(fd, p, &imsg) == 0) {
325 			/* Message was handled by the callback, continue */
326 			imsg_free(&imsg);
327 			continue;
328 		}
329 
330 		/*
331 		 * Generic message handling
332 		 */
333 		switch (imsg.hdr.type) {
334 		case IMSG_CTL_VERBOSE:
335 			IMSG_SIZE_CHECK(&imsg, &verbose);
336 
337 			memcpy(&verbose, imsg.data, sizeof(verbose));
338 			log_verbose(verbose);
339 			break;
340 		default:
341 			log_warnx("%s: %s got imsg %d", __func__, p->p_title,
342 			    imsg.hdr.type);
343 			fatalx(title);
344 		}
345 		imsg_free(&imsg);
346 	}
347 	imsg_event_add(iev);
348 }
349 
350 void
351 imsg_event_add(struct imsgev *iev)
352 {
353 	if (iev->handler == NULL) {
354 		imsg_flush(&iev->ibuf);
355 		return;
356 	}
357 
358 	iev->events = EV_READ;
359 	if (iev->ibuf.w.queued)
360 		iev->events |= EV_WRITE;
361 
362 	event_del(&iev->ev);
363 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
364 	event_add(&iev->ev, NULL);
365 }
366 
367 int
368 imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid,
369     pid_t pid, int fd, void *data, u_int16_t datalen)
370 {
371 	int	ret;
372 
373 	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
374 	    pid, fd, data, datalen)) == -1)
375 		return (ret);
376 	imsg_event_add(iev);
377 	return (ret);
378 }
379 
380 int
381 imsg_composev_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid,
382     pid_t pid, int fd, const struct iovec *iov, int iovcnt)
383 {
384 	int	ret;
385 
386 	if ((ret = imsg_composev(&iev->ibuf, type, peerid,
387 	    pid, fd, iov, iovcnt)) == -1)
388 		return (ret);
389 	imsg_event_add(iev);
390 	return (ret);
391 }
392 
393 int
394 proc_compose_imsg(struct iked *env, enum privsep_procid id,
395     u_int16_t type, int fd, void *data, u_int16_t datalen)
396 {
397 	return (imsg_compose_event(&env->sc_ps.ps_ievs[id],
398 	    type, -1, 0, fd, data, datalen));
399 }
400 
401 int
402 proc_composev_imsg(struct iked *env, enum privsep_procid id,
403     u_int16_t type, int fd, const struct iovec *iov, int iovcnt)
404 {
405 	return (imsg_composev_event(&env->sc_ps.ps_ievs[id],
406 	    type, -1, 0, fd, iov, iovcnt));
407 }
408 
409 int
410 proc_forward_imsg(struct iked *env, struct imsg *imsg,
411     enum privsep_procid id)
412 {
413 	return (proc_compose_imsg(env, id, imsg->hdr.type,
414 	    imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg)));
415 }
416 
417 void
418 proc_flush_imsg(struct iked *env, enum privsep_procid id)
419 {
420 	imsg_flush(&env->sc_ps.ps_ievs[id].ibuf);
421 }
422