1 /*	$OpenBSD: systrace.c,v 1.54 2006/07/02 12:34:15 sturm Exp $	*/
2 /*
3  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Niels Provos.
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/wait.h>
35 #include <sys/tree.h>
36 #include <sys/socket.h>
37 #include <sys/stat.h>
38 #include <limits.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <stdio.h>
42 #include <stdarg.h>
43 #include <fcntl.h>
44 #include <signal.h>
45 #include <syslog.h>
46 #include <string.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <grp.h>
50 #include <pwd.h>
51 #include <event.h>
52 
53 #include "intercept.h"
54 #include "systrace.h"
55 #include "util.h"
56 
57 #define CRADLE_SERVER "cradle_server"
58 #define CRADLE_UI     "cradle_ui"
59 
60 #define VERSION "1.6d (OpenBSD)"
61 
62 pid_t trpid;
63 int trfd;
64 int connected = 0;		/* Connected to GUI */
65 int inherit = 0;		/* Inherit policy to childs */
66 int automatic = 0;		/* Do not run interactively */
67 int allow = 0;			/* Allow all and generate */
68 int userpolicy = 1;		/* Permit user defined policies */
69 int noalias = 0;		/* Do not do system call aliasing */
70 int iamroot = 0;		/* Set if we are running as root */
71 int cradle = 0;			/* Set if we are running in cradle mode */
72 int logtofile = 0;		/* Log to file instead of syslog */
73 FILE *logfile;			/* default logfile to send to if enabled */
74 char cwd[MAXPATHLEN];		/* Current working directory */
75 char home[MAXPATHLEN];		/* Home directory of user */
76 char username[LOGIN_NAME_MAX];	/* Username: predicate match and expansion */
77 char *guipath = _PATH_XSYSTRACE; /* Path to GUI executable */
78 char dirpath[MAXPATHLEN];
79 
80 static struct event ev_read;
81 static struct event ev_timeout;
82 
83 static void child_handler(int);
84 static void log_msg(int, const char *, ...);
85 static void systrace_read(int, short, void *);
86 static void systrace_timeout(int, short, void *);
87 static void usage(void);
88 
89 void
systrace_parameters(void)90 systrace_parameters(void)
91 {
92 	struct passwd *pw;
93 	char *normcwd;
94 	uid_t uid = getuid();
95 
96 	iamroot = getuid() == 0;
97 
98 	/* Find out current username. */
99 	if ((pw = getpwuid(uid)) == NULL) {
100 		snprintf(username, sizeof(username), "uid %u", uid);
101 	} else {
102 		strlcpy(username, pw->pw_name, sizeof(username));
103 		strlcpy(home, pw->pw_dir, sizeof(home));
104 	}
105 
106 	/* Determine current working directory for filtering */
107 	if (getcwd(cwd, sizeof(cwd)) == NULL)
108 		err(1, "getcwd");
109 	if ((normcwd = normalize_filename(-1, 0, cwd, ICLINK_ALL)) == NULL)
110 		errx(1, "normalize_filename");
111 	if (strlcpy(cwd, normcwd, sizeof(cwd)) >= sizeof(cwd))
112 		errx(1, "cwd too long");
113 }
114 
115 /*
116  * Generate human readable output and setup replacements if available.
117  */
118 
119 void
make_output(char * output,size_t outlen,const char * binname,pid_t pid,pid_t ppid,int policynr,const char * policy,int nfilters,const char * emulation,const char * name,int code,struct intercept_tlq * tls,struct intercept_replace * repl)120 make_output(char *output, size_t outlen, const char *binname,
121     pid_t pid, pid_t ppid,
122     int policynr, const char *policy, int nfilters, const char *emulation,
123     const char *name, int code, struct intercept_tlq *tls,
124     struct intercept_replace *repl)
125 {
126 	struct intercept_translate *tl;
127 	char *p, *line;
128 	int size;
129 
130 	snprintf(output, outlen,
131 	    "%s, pid: %d(%d)[%d], policy: %s, filters: %d, syscall: %s-%s(%d)",
132 	    binname, pid, policynr, ppid, policy, nfilters,
133 	    emulation, name, code);
134 
135 	p = output + strlen(output);
136 	size = outlen - strlen(output);
137 
138 	if (tls == NULL)
139 		return;
140 
141 	TAILQ_FOREACH(tl, tls, next) {
142 		if (!tl->trans_valid)
143 			continue;
144 		line = intercept_translate_print(tl);
145 		if (line == NULL)
146 			continue;
147 
148 		snprintf(p, size, ", %s: %s", tl->name, strescape(line));
149 		p = output + strlen(output);
150 		size = outlen - strlen(output);
151 
152 		if (repl != NULL && tl->trans_size)
153 			intercept_replace_add(repl, tl->off,
154 			    tl->trans_data, tl->trans_size,
155 			    tl->trans_flags);
156 	}
157 }
158 
159 short
trans_cb(int fd,pid_t pid,int policynr,const char * name,int code,const char * emulation,void * args,int argsize,struct intercept_replace * repl,struct intercept_tlq * tls,void * cbarg)160 trans_cb(int fd, pid_t pid, int policynr,
161     const char *name, int code, const char *emulation,
162     void *args, int argsize,
163     struct intercept_replace *repl,
164     struct intercept_tlq *tls, void *cbarg)
165 {
166 	short action, future;
167 	struct policy *policy;
168 	struct intercept_pid *ipid;
169 	struct intercept_tlq alitls;
170 	struct intercept_translate alitl[SYSTRACE_MAXALIAS];
171 	struct systrace_alias *alias = NULL;
172 	struct filterq *pflq = NULL;
173 	const char *binname = NULL;
174 	char output[_POSIX2_LINE_MAX];
175 	pid_t ppid;
176 	int done = 0, dolog = 0;
177 
178 	action = ICPOLICY_PERMIT;
179 
180 	if (policynr == -1)
181 		goto out;
182 
183 	if ((policy = systrace_findpolnr(policynr)) == NULL)
184 		errx(1, "%s:%d: find %d", __func__, __LINE__,
185 		    policynr);
186 
187 	ipid = intercept_getpid(pid);
188 	ipid->uflags = 0;
189 	binname = ipid->name != NULL ? ipid->name : policy->name;
190 	ppid = ipid->ppid;
191 
192 	/* Required to set up replacements */
193 	do {
194 		make_output(output, sizeof(output), binname, pid, ppid,
195 		    policynr, policy->name, policy->nfilters,
196 		    emulation, name, code, tls, repl);
197 
198 		/* Fast-path checking */
199 		if ((action = policy->kerneltable[code]) != ICPOLICY_ASK)
200 			goto out;
201 
202 		pflq = systrace_policyflq(policy, emulation, name);
203 		if (pflq == NULL)
204 			errx(1, "%s:%d: no filter queue", __func__, __LINE__);
205 
206 		action = filter_evaluate(tls, pflq, ipid);
207 		if (action != ICPOLICY_ASK)
208 			goto done;
209 
210 		/* Do aliasing here */
211 		if (!noalias)
212 			alias = systrace_find_alias(emulation, name);
213 		if (alias != NULL) {
214 			int i;
215 
216 			/* Set up variables for further filter actions */
217 			tls = &alitls;
218 			emulation = alias->aemul;
219 			name = alias->aname;
220 
221 			/* Create an aliased list for filter_evaluate */
222 			TAILQ_INIT(tls);
223 			for (i = 0; i < alias->nargs; i++) {
224 				memcpy(&alitl[i], alias->arguments[i],
225 				    sizeof(struct intercept_translate));
226 				TAILQ_INSERT_TAIL(tls, &alitl[i], next);
227 			}
228 
229 			if ((pflq = systrace_policyflq(policy,
230 			    alias->aemul, alias->aname)) == NULL)
231 				errx(1, "%s:%d: no filter queue",
232 				    __func__, __LINE__);
233 
234 			action = filter_evaluate(tls, pflq, ipid);
235 			if (action != ICPOLICY_ASK)
236 				goto done;
237 
238 			make_output(output, sizeof(output), binname, pid, ppid,
239 			    policynr, policy->name, policy->nfilters,
240 			    alias->aemul, alias->aname, code, tls, NULL);
241 		}
242 
243 		/*
244 		 * At this point, we have to ask the user, but we may check
245 		 * if the policy has been updated in the meanwhile.
246 		 */
247 		if (systrace_updatepolicy(fd, policy) == -1)
248 			done = 1;
249 	} while (!done);
250 
251 	if (policy->flags & POLICY_UNSUPERVISED) {
252 		action = ICPOLICY_NEVER;
253 		dolog = 1;
254 		goto out;
255 	}
256 
257 	action = filter_ask(fd, tls, pflq, policynr, emulation, name,
258 	    output, &future, ipid);
259 	if (future != ICPOLICY_ASK)
260 		filter_modifypolicy(fd, policynr, emulation, name, future);
261 
262 	if (policy->flags & POLICY_DETACHED) {
263 		if (intercept_detach(fd, pid) == -1)
264 			err(1, "intercept_detach");
265 		return (action);
266 	} else if (action == ICPOLICY_KILL) {
267 		kill(pid, SIGKILL);
268 		return (ICPOLICY_NEVER);
269 	}
270  done:
271 	if (ipid->uflags & SYSCALL_LOG)
272 		dolog = 1;
273 
274  out:
275 	if (dolog)
276 		log_msg(LOG_WARNING, "%s user: %s, prog: %s",
277 		    action < ICPOLICY_NEVER ? "permit" : "deny",
278 		    ipid->username, output);
279 
280  	/* Argument replacement in intercept might still fail */
281 
282 	return (action);
283 }
284 
285 short
gen_cb(int fd,pid_t pid,int policynr,const char * name,int code,const char * emulation,void * args,int argsize,void * cbarg)286 gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
287     const char *emulation, void *args, int argsize, void *cbarg)
288 {
289 	char output[_POSIX2_LINE_MAX];
290 	struct policy *policy;
291 	struct intercept_pid *ipid;
292 	struct filterq *pflq = NULL;
293 	short action = ICPOLICY_PERMIT;
294 	short future;
295 	int off, done = 0, dolog = 0;
296 	size_t len;
297 
298 	if (policynr == -1)
299 		goto out;
300 
301 	if ((policy = systrace_findpolnr(policynr)) == NULL)
302 		errx(1, "%s:%d: find %d", __func__, __LINE__,
303 		    policynr);
304 
305 	ipid = intercept_getpid(pid);
306 	ipid->uflags = 0;
307 
308 	make_output(output, sizeof(output),
309 	    ipid->name != NULL ? ipid->name : policy->name,
310 	    pid, ipid->ppid, policynr,
311 	    policy->name, policy->nfilters, emulation, name, code,
312 	    NULL, NULL);
313 
314 	off = strlen(output);
315 	len = sizeof(output) - off;
316 	if (len > 0)
317 		snprintf(output + off, len, ", args: %d", argsize);
318 
319 	if ((pflq = systrace_policyflq(policy, emulation, name)) == NULL)
320 		errx(1, "%s:%d: no filter queue", __func__, __LINE__);
321 
322 	do {
323 		/* Fast-path checking */
324 		if ((action = policy->kerneltable[code]) != ICPOLICY_ASK)
325 			goto out;
326 
327 		action = filter_evaluate(NULL, pflq, ipid);
328 
329 		if (action != ICPOLICY_ASK)
330 			goto haveresult;
331 		/*
332 		 * At this point, we have to ask the user, but we may check
333 		 * if the policy has been updated in the meanwhile.
334 		 */
335 		if (systrace_updatepolicy(fd, policy) == -1)
336 			done = 1;
337 	} while (!done);
338 
339 	if (policy->flags & POLICY_UNSUPERVISED) {
340 		action = ICPOLICY_NEVER;
341 		dolog = 1;
342 		goto haveresult;
343 	}
344 
345 	action = filter_ask(fd, NULL, pflq, policynr, emulation, name,
346 	    output, &future, ipid);
347 	if (future != ICPOLICY_ASK)
348 		systrace_modifypolicy(fd, policynr, name, future);
349 
350 	if (policy->flags & POLICY_DETACHED) {
351 		if (intercept_detach(fd, pid) == -1)
352 			err(1, "intercept_detach");
353 	} else if (action == ICPOLICY_KILL) {
354 		kill(pid, SIGKILL);
355 		return (ICPOLICY_NEVER);
356 	}
357 
358  haveresult:
359 	if (ipid->uflags & SYSCALL_LOG)
360 		dolog = 1;
361 	if (dolog)
362 		log_msg(LOG_WARNING, "%s user: %s, prog: %s",
363 		    action < ICPOLICY_NEVER ? "permit" : "deny",
364 		    ipid->username, output);
365  out:
366 	return (action);
367 }
368 
369 void
execres_cb(int fd,pid_t pid,int policynr,const char * emulation,const char * name,void * arg)370 execres_cb(int fd, pid_t pid, int policynr, const char *emulation,
371     const char *name, void *arg)
372 {
373 	struct policy *policy;
374 
375 	if (policynr != -1) {
376 		struct intercept_pid *ipid;
377 
378 		ipid = intercept_getpid(pid);
379 		if (ipid->uflags & PROCESS_DETACH) {
380 			if (intercept_detach(fd, pid) == -1)
381 				err(1, "%s: intercept_detach", __func__);
382 			return;
383 		}
384 		if (inherit)
385 			return;
386 
387 		if (ipid->uflags & PROCESS_INHERIT_POLICY)
388 			return;
389 	}
390 	if ((policy = systrace_newpolicy(emulation, name)) == NULL)
391 		goto error;
392 
393 	/* See if this policies runs without interactive feedback */
394 	if (automatic)
395 		policy->flags |= POLICY_UNSUPERVISED;
396 
397 	policynr = policy->policynr;
398 
399 	/* Try to find existing policy in file system */
400 	if (policynr == -1 && TAILQ_FIRST(&policy->prefilters) == NULL)
401 		systrace_addpolicy(name);
402 
403 	if (policy->flags & POLICY_DETACHED) {
404 		if (intercept_detach(fd, pid) == -1)
405 			err(1, "intercept_detach");
406 		return;
407 	}
408 
409 	if (policynr == -1) {
410 		policynr = systrace_newpolicynr(fd, policy);
411 		if (policynr == -1)
412 			goto error;
413 	}
414 
415 	if (intercept_assignpolicy(fd, pid, policynr) == -1)
416 		goto error;
417 
418 	if (TAILQ_FIRST(&policy->prefilters) != NULL)
419 		filter_prepolicy(fd, policy);
420 
421 	return;
422 
423  error:
424 	kill(pid, SIGKILL);
425 	fprintf(stderr, "Terminating %d: %s\n", pid, name);
426 }
427 
428 void
policyfree_cb(int policynr,void * arg)429 policyfree_cb(int policynr, void *arg)
430 {
431 	struct policy *policy;
432 
433 	if ((policy = systrace_findpolnr(policynr)) == NULL)
434 		errx(1, "%s:%d: find %d", __func__, __LINE__,
435 		    policynr);
436 
437 	systrace_freepolicy(policy);
438 }
439 
440 /* ARGSUSED */
441 static void
child_handler(int sig)442 child_handler(int sig)
443 {
444 	int s = errno, status;
445 
446 	if (signal(SIGCHLD, child_handler) == SIG_ERR) {
447 		close(trfd);
448 	}
449 
450 	while (wait4(-1, &status, WNOHANG, NULL) > 0)
451 		;
452 
453 	errno = s;
454 }
455 
456 static void
log_msg(int priority,const char * fmt,...)457 log_msg(int priority, const char *fmt, ...)
458 {
459 	char buf[_POSIX2_LINE_MAX];
460 	extern char *__progname;
461 	va_list ap;
462 
463 	va_start(ap, fmt);
464 
465 	if (logtofile) {
466 		vsnprintf(buf, sizeof(buf), fmt, ap);
467 		fprintf(logfile, "%s: %s\n", __progname, buf);
468 	} else
469 		vsyslog(priority, fmt, ap);
470 
471 	va_end(ap);
472 }
473 
474 static void
usage(void)475 usage(void)
476 {
477 	fprintf(stderr,
478 	    "Usage: systrace [-AaCeitUuV] [-c user:group] [-d policydir] [-E logfile]\n"
479 	    "\t [-f file] [-g gui] [-p pid] command ...\n");
480 	exit(1);
481 }
482 
483 int
requestor_start(char * path,int docradle)484 requestor_start(char *path, int docradle)
485 {
486 	char *argv[3];
487 	int pair[2];
488 	pid_t pid;
489 
490 	argv[0] = path;
491 	argv[1] = docradle ? "-C" : NULL;
492 	argv[2] = NULL;
493 
494 	if (!docradle && socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
495 		err(1, "socketpair");
496 
497 	pid = fork();
498 	if (pid == -1)
499 		err(1, "fork");
500 	if (pid == 0) {
501 		if (!docradle) {
502 			close(pair[0]);
503 			if (dup2(pair[1], fileno(stdin)) == -1)
504 				err(1, "dup2");
505 			if (dup2(pair[1], fileno(stdout)) == -1)
506 				err(1, "dup2");
507 			setlinebuf(stdout);
508 
509 			close(pair[1]);
510 		}
511 
512 		execvp(path, argv);
513 
514 		err(1, "execvp: %s", path);
515 
516 	}
517 
518 	if (!docradle) {
519 		close(pair[1]);
520 		if (dup2(pair[0], fileno(stdin)) == -1)
521 			err(1, "dup2");
522 
523 		if (dup2(pair[0], fileno(stdout)) == -1)
524 			err(1, "dup2");
525 
526 		close(pair[0]);
527 
528 		setlinebuf(stdout);
529 
530 		connected = 1;
531 	}
532 
533 	return (0);
534 }
535 
536 
537 static void
cradle_setup(char * pathtogui)538 cradle_setup(char *pathtogui)
539 {
540 	struct stat sb;
541 	char cradlepath[MAXPATHLEN], cradleuipath[MAXPATHLEN];
542 
543 	snprintf(dirpath, sizeof(dirpath), "/tmp/systrace-%d", getuid());
544 
545 	if (stat(dirpath, &sb) == -1) {
546 		if (errno != ENOENT)
547 			err(1, "stat()");
548 		if (mkdir(dirpath, S_IRUSR | S_IWUSR | S_IXUSR) == -1)
549 			err(1, "mkdir()");
550 	} else {
551 		if (sb.st_uid != getuid())
552 			errx(1, "Wrong owner on directory %s", dirpath);
553 		if (sb.st_mode != (S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR))
554 			errx(1, "Wrong permissions on directory %s", dirpath);
555 	}
556 
557 	strlcpy(cradlepath, dirpath, sizeof (cradlepath));
558 	strlcat(cradlepath, "/" CRADLE_SERVER, sizeof (cradlepath));
559 
560 	strlcpy(cradleuipath, dirpath, sizeof (cradleuipath));
561 	strlcat(cradleuipath, "/" CRADLE_UI, sizeof (cradleuipath));
562 
563 	cradle_start(cradlepath, cradleuipath, pathtogui);
564 }
565 
566 static int
get_uid_gid(const char * argument,uid_t * uid,gid_t * gid)567 get_uid_gid(const char *argument, uid_t *uid, gid_t *gid)
568 {
569 	struct group *gp;
570 	struct passwd *pw;
571 	unsigned long ulval;
572 	char uid_gid_str[128];
573 	char *endp, *g, *u;
574 
575 	strlcpy(uid_gid_str, argument, sizeof(uid_gid_str));
576 	g = uid_gid_str;
577 	u = strsep(&g, ":");
578 
579 	if ((pw = getpwnam(u)) != NULL) {
580 		memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
581 		*uid = pw->pw_uid;
582 		*gid = pw->pw_gid;
583 		/* Ok if group not specified. */
584 		if (g == NULL)
585 			return (0);
586 	} else {
587 		errno = 0;
588 		ulval = strtoul(u, &endp, 10);
589 		if (u[0] == '\0' || *endp != '\0')
590 			errx(1, "no such user '%s'", u);
591 		if (errno == ERANGE && ulval == ULONG_MAX)
592 			errx(1, "invalid uid %s", u);
593 		*uid = (uid_t)ulval;
594 	}
595 
596 	if (g == NULL)
597 		return (-1);
598 
599 	if ((gp = getgrnam(g)) != NULL)
600 		*gid = gp->gr_gid;
601 	else {
602 		errno = 0;
603 		ulval = strtoul(g, &endp, 10);
604 		if (g[0] == '\0' || *endp != '\0')
605 			errx(1, "no such group '%s'", g);
606 		if (errno == ERANGE && ulval == ULONG_MAX)
607 			errx(1, "invalid gid %s", g);
608 		*gid = (gid_t)ulval;
609 	}
610 
611 	return (0);
612 }
613 
614 static void
systrace_timeout(int fd,short what,void * arg)615 systrace_timeout(int fd, short what, void *arg)
616 {
617 	struct timeval tv;
618 
619 	/* Reschedule timeout */
620 	timerclear(&tv);
621 	tv.tv_sec = SYSTRACE_UPDATETIME;
622 	evtimer_add(&ev_timeout, &tv);
623 
624 	systrace_updatepolicies(trfd);
625 	if (userpolicy)
626 		systrace_dumppolicies(trfd);
627 }
628 
629 /*
630  * Read from the kernel if something happened.
631  */
632 
633 static void
systrace_read(int fd,short what,void * arg)634 systrace_read(int fd, short what, void *arg)
635 {
636 	intercept_read(fd);
637 
638 	if (!intercept_existpids()) {
639 		event_del(&ev_read);
640 		event_del(&ev_timeout);
641 	}
642 }
643 
644 int
main(int argc,char ** argv)645 main(int argc, char **argv)
646 {
647 	int i, c;
648 	char **args;
649 	char *filename = NULL;
650 	char *policypath = NULL;
651 	struct timeval tv;
652 	pid_t pidattach = 0;
653 	int usex11 = 1;
654 	int background;
655 	int setcredentials = 0;
656 	uid_t cr_uid;
657 	gid_t cr_gid;
658 
659 	while ((c = getopt(argc, argv, "Vc:aAeE:ituUCd:g:f:p:")) != -1) {
660 		switch (c) {
661 		case 'V':
662 			fprintf(stderr, "%s V%s\n", argv[0], VERSION);
663 			exit(0);
664 		case 'c':
665 			setcredentials = 1;
666 			if (get_uid_gid(optarg, &cr_uid, &cr_gid) == -1)
667 				usage();
668 			break;
669 		case 'a':
670 			if (allow)
671 				usage();
672 			automatic = 1;
673 			break;
674 		case 'd':
675 			policypath = optarg;
676 			break;
677 		case 'e':
678 			logtofile = 1;
679 			logfile = stderr;
680 			break;
681 		case 'E':
682 			logtofile = 1;
683 			logfile = fopen(optarg, "a");
684 			if (logfile == NULL)
685 				err(1, "Cannot open \"%s\" for writing",
686 				    optarg);
687 			break;
688 		case 'A':
689 			if (automatic)
690 				usage();
691 			allow = 1;
692 			break;
693 		case 'u':
694 			noalias = 1;
695 			break;
696 		case 'i':
697 			inherit = 1;
698 			break;
699 		case 'g':
700 			guipath = optarg;
701 			break;
702 		case 'C':
703 			cradle = 1;
704 			break;
705 		case 'f':
706 			filename = optarg;
707 			break;
708 		case 'p':
709 			if (setcredentials)
710 				usage();
711 			if ((pidattach = atoi(optarg)) == 0) {
712 				warnx("bad pid: %s", optarg);
713 				usage();
714 			}
715 			break;
716 		case 't':
717 			usex11 = 0;
718 			break;
719 		case 'U':
720 			userpolicy = 0;
721 			break;
722 		default:
723 			usage();
724 			break;
725 		}
726 	}
727 	argc -= optind;
728 	argv += optind;
729 
730 	if (argc == 0 || (pidattach && *argv[0] != '/'))
731 		usage();
732 
733 	systrace_parameters();
734 
735 	if (setcredentials && !iamroot) {
736 		fprintf(stderr, "Need to be root to change credentials.\n");
737 		usage();
738 	}
739 
740 	/* Initalize libevent but without kqueue because of systrace fd */
741 	setenv("EVENT_NOKQUEUE", "yes", 0);
742 	event_init();
743 
744 	/* Local initialization */
745 	systrace_initalias();
746 	systrace_initpolicy(filename, policypath);
747 	systrace_initcb();
748 
749 	if ((trfd = intercept_open()) == -1)
750 		exit(1);
751 
752 	/* See if we can run the systrace process in the background */
753 	background = usex11 || automatic || allow;
754 
755 	if (pidattach == 0) {
756 		/* Run a command and attach to it */
757 		if ((args = malloc((argc + 1) * sizeof(char *))) == NULL)
758 			err(1, "malloc");
759 
760 		for (i = 0; i < argc; i++)
761 			args[i] = argv[i];
762 		args[i] = NULL;
763 
764 		if (setcredentials)
765 			trpid = intercept_run(background, trfd,
766 			    cr_uid, cr_gid, args[0], args);
767 		else
768 			trpid = intercept_run(background, trfd, 0, 0,
769 			    args[0], args);
770 		if (trpid == -1)
771 			err(1, "fork");
772 
773 		if (intercept_attach(trfd, trpid) == -1)
774 			err(1, "attach");
775 
776 		if (kill(trpid, SIGUSR1) == -1)
777 			err(1, "kill");
778 	} else {
779 		/* Attach to a running command */
780 		if (intercept_attachpid(trfd, pidattach, argv[0]) == -1)
781 			err(1, "attachpid");
782 
783 		if (background) {
784 			if (daemon(1, 1) == -1)
785 				err(1, "daemon");
786 		}
787 	}
788 
789 	if (signal(SIGCHLD, child_handler) == SIG_ERR)
790 		err(1, "signal");
791 
792 	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
793 		err(1, "signal");
794 
795 	/* Start the policy GUI or cradle if necessary */
796 	if (usex11 && (!automatic && !allow)) {
797 		if (cradle)
798 			cradle_setup(guipath);
799 		else
800 			requestor_start(guipath, 0);
801 
802 	}
803 
804 	/* Register read events */
805 	event_set(&ev_read, trfd, EV_READ|EV_PERSIST, systrace_read, NULL);
806 	event_add(&ev_read, NULL);
807 
808 	if (userpolicy || automatic) {
809 		evtimer_set(&ev_timeout, systrace_timeout, &ev_timeout);
810 		timerclear(&tv);
811 		tv.tv_sec = SYSTRACE_UPDATETIME;
812 		evtimer_add(&ev_timeout, &tv);
813 	}
814 
815 	/* Wait for events */
816 	event_dispatch();
817 
818 	if (userpolicy)
819 		systrace_dumppolicies(trfd);
820 
821 	close(trfd);
822 
823 	exit(0);
824 }
825