1 /*	$OpenBSD: policy.c,v 1.32 2006/09/19 10:48:41 otto 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/stat.h>
35 #include <sys/tree.h>
36 #include <dirent.h>
37 #include <limits.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <grp.h>
42 #include <stdio.h>
43 #include <fcntl.h>
44 #include <ctype.h>
45 #include <err.h>
46 #include <libgen.h>
47 
48 #include "intercept.h"
49 #include "systrace.h"
50 
51 static int psccompare(struct policy_syscall *, struct policy_syscall *);
52 static int policycompare(struct policy *, struct policy *);
53 static int polnrcompare(struct policy *, struct policy *);
54 static char *systrace_policyfilename(char *, const char *);
55 static char *systrace_policyline(char *line);
56 static int systrace_policyprocess(struct policy *,
57     char *);
58 static int systrace_writepolicy(struct policy *);
59 
60 int systrace_templatedir(void);
61 
62 static int
psccompare(struct policy_syscall * a,struct policy_syscall * b)63 psccompare(struct policy_syscall *a, struct policy_syscall *b)
64 {
65 	int diff;
66 	diff = strcmp(a->emulation, b->emulation);
67 	if (diff)
68 		return (diff);
69 	return (strcmp(a->name, b->name));
70 }
71 
72 SPLAY_PROTOTYPE(syscalltree, policy_syscall, node, psccompare)
73 SPLAY_GENERATE(syscalltree, policy_syscall, node, psccompare)
74 
75 static SPLAY_HEAD(policytree, policy) policyroot;
76 static SPLAY_HEAD(polnrtree, policy) polnrroot;
77 
78 int
policycompare(struct policy * a,struct policy * b)79 policycompare(struct policy *a, struct policy *b)
80 {
81 	return (strcmp(a->name, b->name));
82 }
83 
84 int
polnrcompare(struct policy * a,struct policy * b)85 polnrcompare(struct policy *a, struct policy *b)
86 {
87 	int diff = a->policynr - b->policynr;
88 
89 	if (diff == 0)
90 		return (0);
91 	if (diff > 0 )
92 		return (1);
93 	return (-1);
94 }
95 
96 SPLAY_PROTOTYPE(policytree, policy, node, policycompare)
97 SPLAY_GENERATE(policytree, policy, node, policycompare)
98 
99 SPLAY_PROTOTYPE(polnrtree, policy, nrnode, polnrcompare)
100 SPLAY_GENERATE(polnrtree, policy, nrnode, polnrcompare)
101 
102 extern int userpolicy;
103 
104 static char policydir[MAXPATHLEN];
105 
106 struct tmplqueue templates;
107 
108 void
systrace_setupdir(char * path)109 systrace_setupdir(char *path)
110 {
111 	char *home;
112 	struct stat sb;
113 
114 	if (path == NULL) {
115 		home = getenv("HOME");
116 
117 		if (home == NULL)
118 			errx(1, "No HOME environment set");
119 
120 		if (strlcpy(policydir, home, sizeof(policydir)) >= sizeof(policydir))
121 			errx(1, "HOME too long");
122 
123 		if (strlcat(policydir, "/.etc/systrace", sizeof(policydir)) >= sizeof(policydir))
124 			errx(1, "HOME too long");
125 	} else if (strlcpy(policydir, path, sizeof(policydir)) >= sizeof(policydir))
126 		errx(1, "policy directory too long");
127 
128 
129 	if (stat(policydir, &sb) != -1) {
130 		if (!S_ISDIR(sb.st_mode))
131 			errx(1, "Not a directory: \"%s\"", policydir);
132 	} else if (mkdir(policydir, 0700) == -1)
133 		err(1, "mkdir(%s)", policydir);
134 }
135 
136 int
systrace_initpolicy(char * file,char * path)137 systrace_initpolicy(char *file, char *path)
138 {
139 	SPLAY_INIT(&policyroot);
140 	SPLAY_INIT(&polnrroot);
141 
142 	if (userpolicy) {
143 		systrace_setupdir(path);
144 		systrace_templatedir();
145 	}
146 
147 	if (file != NULL)
148 		return (systrace_readpolicy(file) != NULL ? 0 : -1);
149 
150 	return (0);
151 }
152 
153 struct policy *
systrace_findpolicy(const char * name)154 systrace_findpolicy(const char *name)
155 {
156 	struct policy tmp;
157 
158 	tmp.name = name;
159 
160 	return (SPLAY_FIND(policytree, &policyroot, &tmp));
161 }
162 
163 struct policy *
systrace_findpolicy_wildcard(const char * name)164 systrace_findpolicy_wildcard(const char *name)
165 {
166 	struct policy tmp, *res;
167 	static char path[MAXPATHLEN], lookup[MAXPATHLEN];
168 
169 	if (strlcpy(path, name, sizeof(path)) >= sizeof(path))
170 		errx(1, "%s: path name overflow", __func__);
171 
172 	strlcpy(lookup, "*/", sizeof(lookup));
173 	strlcat(lookup, basename(path), sizeof(lookup));
174 
175 	tmp.name = lookup;
176 	res = SPLAY_FIND(policytree, &policyroot, &tmp);
177 	if (res == NULL)
178 		return (NULL);
179 
180 	/* we found the wildcarded policy; now remove it and bind it */
181 	SPLAY_REMOVE(policytree, &policyroot, res);
182 
183 	free((char *)res->name);
184 	if ((res->name = strdup(name)) == NULL)
185 		err(1, "%s: strdup", __func__);
186 
187 	SPLAY_INSERT(policytree, &policyroot, res);
188 	return (res);
189 }
190 
191 struct policy *
systrace_findpolnr(int nr)192 systrace_findpolnr(int nr)
193 {
194 	struct policy tmp;
195 
196 	tmp.policynr = nr;
197 
198 	return (SPLAY_FIND(polnrtree, &polnrroot, &tmp));
199 }
200 
201 int
systrace_newpolicynr(int fd,struct policy * tmp)202 systrace_newpolicynr(int fd, struct policy *tmp)
203 {
204 	if (tmp->policynr != -1)
205 		return (-1);
206 
207 	if ((tmp->policynr = intercept_newpolicy(fd)) == -1) {
208 		/* XXX - maybe free policy structure here */
209 		return (-1);
210 	}
211 
212 	SPLAY_INSERT(polnrtree, &polnrroot, tmp);
213 
214 	return (tmp->policynr);
215 }
216 
217 struct policy *
systrace_newpolicy(const char * emulation,const char * name)218 systrace_newpolicy(const char *emulation, const char *name)
219 {
220 	int i;
221 	struct policy *tmp;
222 
223 	if ((tmp = systrace_findpolicy(name)) != NULL)
224 		return (tmp);
225 
226 	if ((tmp = systrace_findpolicy_wildcard(name)) != NULL)
227 		return (tmp);
228 
229 	tmp = calloc(1, sizeof(struct policy));
230 	if (tmp == NULL)
231 		return (NULL);
232 
233 	tmp->policynr = -1;
234 
235 	/* New policies requires initialization */
236 	if ((tmp->name = strdup(name)) == NULL)
237 		err(1, "%s:%d: strdup", __func__, __LINE__);
238 	strlcpy(tmp->emulation, emulation, sizeof(tmp->emulation));
239 
240 	SPLAY_INSERT(policytree, &policyroot, tmp);
241 	SPLAY_INIT(&tmp->pflqs);
242 	TAILQ_INIT(&tmp->filters);
243 	TAILQ_INIT(&tmp->prefilters);
244 
245 	/* Set the default policy to ask */
246 	for (i = 0; i < INTERCEPT_MAXSYSCALLNR; i++)
247 		tmp->kerneltable[i] = ICPOLICY_ASK;
248 
249 	return (tmp);
250 }
251 
252 void
systrace_cleanpolicy(struct policy * policy)253 systrace_cleanpolicy(struct policy *policy)
254 {
255 	struct filter *filter;
256 	struct policy_syscall *pflq;
257 	int i;
258 
259 	/* Set the default policy to ask */
260 	for (i = 0; i < INTERCEPT_MAXSYSCALLNR; i++)
261 		policy->kerneltable[i] = ICPOLICY_ASK;
262 
263 	while ((filter = TAILQ_FIRST(&policy->prefilters)) != NULL) {
264 		TAILQ_REMOVE(&policy->prefilters, filter, policy_next);
265 		filter_free(filter);
266 	}
267 
268 	while ((filter = TAILQ_FIRST(&policy->filters)) != NULL) {
269 		TAILQ_REMOVE(&policy->filters, filter, policy_next);
270 		filter_free(filter);
271 	}
272 
273 	while ((pflq = SPLAY_ROOT(&policy->pflqs)) != NULL) {
274 		SPLAY_REMOVE(syscalltree, &policy->pflqs, pflq);
275 
276 		while ((filter = TAILQ_FIRST(&pflq->flq)) != NULL) {
277 			TAILQ_REMOVE(&pflq->flq, filter, next);
278 			filter_free(filter);
279 		}
280 
281 		free(pflq);
282 	}
283 }
284 
285 void
systrace_freepolicy(struct policy * policy)286 systrace_freepolicy(struct policy *policy)
287 {
288 	if (policy->flags & POLICY_CHANGED) {
289 		if (systrace_writepolicy(policy) == -1)
290 			fprintf(stderr, "Failed to write policy for %s\n",
291 			    policy->name);
292 	}
293 
294 	systrace_cleanpolicy(policy);
295 
296 	SPLAY_REMOVE(policytree, &policyroot, policy);
297 	if (policy->policynr != -1)
298 		SPLAY_REMOVE(polnrtree, &polnrroot, policy);
299 
300 	free((char *)policy->name);
301 	free(policy);
302 }
303 
304 struct filterq *
systrace_policyflq(struct policy * policy,const char * emulation,const char * name)305 systrace_policyflq(struct policy *policy, const char *emulation,
306     const char *name)
307 {
308 	struct policy_syscall tmp2, *tmp;
309 
310 	strlcpy(tmp2.emulation, emulation, sizeof(tmp2.emulation));
311 	strlcpy(tmp2.name, name, sizeof(tmp2.name));
312 
313 	tmp = SPLAY_FIND(syscalltree, &policy->pflqs, &tmp2);
314 	if (tmp != NULL)
315 		return (&tmp->flq);
316 
317 	if ((tmp = calloc(1, sizeof(struct policy_syscall))) == NULL)
318 		err(1, "%s:%d: out of memory", __func__, __LINE__);
319 
320 	strlcpy(tmp->emulation, emulation, sizeof(tmp->emulation));
321 	strlcpy(tmp->name, name, sizeof(tmp->name));
322 	TAILQ_INIT(&tmp->flq);
323 
324 	SPLAY_INSERT(syscalltree, &policy->pflqs, tmp);
325 
326 	return (&tmp->flq);
327 }
328 
329 int
systrace_modifypolicy(int fd,int policynr,const char * name,short action)330 systrace_modifypolicy(int fd, int policynr, const char *name, short action)
331 {
332 	struct policy *policy;
333 	int res, nr;
334 
335 	if ((policy = systrace_findpolnr(policynr)) == NULL)
336 		return (-1);
337 
338 	res = intercept_modifypolicy(fd, policynr, policy->emulation,
339 	    name, action);
340 
341 	/* Remember the kernel policy */
342 	if (res != -1 &&
343 	    (nr = intercept_getsyscallnumber(policy->emulation, name)) != -1)
344 		policy->kerneltable[nr] = action;
345 
346 	return (res);
347 }
348 
349 char *
systrace_policyfilename(char * dirname,const char * name)350 systrace_policyfilename(char *dirname, const char *name)
351 {
352 	static char file[2*MAXPATHLEN];
353 	const char *p;
354 	int i, plen;
355 
356 	if (strlen(name) + strlen(dirname) + 1 >= sizeof(file))
357 		return (NULL);
358 
359 	strlcpy(file, dirname, sizeof(file));
360 	i = strlen(file);
361 	file[i++] = '/';
362 	plen = i;
363 
364 	p = name;
365 	while (*p) {
366 		if (!isalnum(*p)) {
367 			if (i != plen)
368 				file[i++] = '_';
369 		} else
370 			file[i++] = *p;
371 		p++;
372 	}
373 
374 	file[i] = '\0';
375 
376 	return (file);
377 }
378 
379 /*
380  * Converts a executeable name into the corresponding filename
381  * that contains the security policy.
382  */
383 
384 char *
systrace_getpolicyname(const char * name)385 systrace_getpolicyname(const char *name)
386 {
387 	char *file = NULL;
388 
389 	if (userpolicy) {
390 		file = systrace_policyfilename(policydir, name);
391 		/* Check if the user policy file exists */
392 		if (file != NULL && access(file, R_OK) == -1)
393 			file = NULL;
394 	}
395 
396 	/* Read global policy */
397 	if (file == NULL)
398 		file = systrace_policyfilename(POLICY_PATH, name);
399 
400 	return (file);
401 }
402 
403 int
systrace_addpolicy(const char * name)404 systrace_addpolicy(const char *name)
405 {
406 	char *file;
407 
408 	if ((file = systrace_getpolicyname(name)) == NULL)
409 		return (-1);
410 
411 	return (systrace_readpolicy(file) != NULL ? 0 : -1);
412 }
413 
414 /*
415  * Reads policy templates from the template directory.
416  * These policies can be inserted during interactive policy
417  * generation.
418  */
419 
420 int
systrace_templatedir(void)421 systrace_templatedir(void)
422 {
423 	char filename[MAXPATHLEN];
424 	DIR *dir = NULL;
425 	struct stat sb;
426 	struct dirent *dp;
427 	struct template *template;
428 	int off;
429 
430 	TAILQ_INIT(&templates);
431 
432 	if (userpolicy) {
433 		if (strlcpy(filename, policydir, sizeof(filename)) >=
434 		    sizeof(filename))
435 			goto error;
436 		if (strlcat(filename, "/templates", sizeof(filename)) >=
437 		    sizeof(filename))
438 			goto error;
439 
440 		/* Check if template directory exists */
441 		if (stat(filename, &sb) != -1 && S_ISDIR(sb.st_mode))
442 			dir = opendir(filename);
443 	}
444 
445 	/* Read global policy */
446 	if (dir == NULL) {
447 		strlcpy(filename, POLICY_PATH, sizeof(filename));
448 		strlcat(filename, "/templates", sizeof(filename));
449 		if (stat(filename, &sb) != -1 && S_ISDIR(sb.st_mode))
450 			dir = opendir(filename);
451 		if (dir == NULL)
452 			return (-1);
453 	}
454 
455 	if (strlcat(filename, "/", sizeof(filename)) >= sizeof(filename))
456 		goto error;
457 	off = strlen(filename);
458 
459 	while ((dp = readdir(dir)) != NULL) {
460 		filename[off] = '\0';
461 		if (strlcat(filename, dp->d_name, sizeof(filename)) >=
462 		    sizeof(filename))
463 			goto error;
464 
465 		if (stat(filename, &sb) == -1 || !S_ISREG(sb.st_mode))
466 			continue;
467 
468 		template = systrace_readtemplate(filename, NULL, NULL);
469 		if (template == NULL)
470 			continue;
471 
472 		TAILQ_INSERT_TAIL(&templates, template, next);
473 	}
474 	closedir(dir);
475 
476 	return (0);
477 
478  error:
479 	errx(1, "%s: template name too long", __func__);
480 
481 	/* NOTREACHED */
482 }
483 
484 struct template *
systrace_readtemplate(char * filename,struct policy * policy,struct template * template)485 systrace_readtemplate(char *filename, struct policy *policy,
486     struct template *template)
487 {
488 	FILE *fp;
489 	char line[_POSIX2_LINE_MAX], *p;
490 	char *emulation, *name, *description;
491 	int linenumber = 0;
492 
493 	if ((fp = fopen(filename, "r")) == NULL)
494 		return (NULL);
495 
496 	/* Set up pid with current information */
497 	while (fgets(line, sizeof(line), fp)) {
498 		linenumber++;
499 
500 		if ((p = systrace_policyline(line)) == NULL) {
501 			fprintf(stderr, "%s:%d: input line too long.\n",
502 			    filename, linenumber);
503 			template = NULL;
504 			goto out;
505 		}
506 
507 		if (strlen(p) == 0)
508 			continue;
509 
510 		if (!strncasecmp(p, "Template: ", 10)) {
511 			p += 10;
512 			name = strsep(&p, ",");
513 			if (p == NULL)
514 				goto error;
515 			if (strncasecmp(p, " Emulation: ", 12))
516 				goto error;
517 			p += 12;
518 			emulation = strsep(&p, ", ");
519 			if (p == NULL)
520 				goto error;
521 			if (strncasecmp(p, " Description: ", 14))
522 				goto error;
523 			p += 14;
524 			description = p;
525 
526 			if (template != NULL)
527 				continue;
528 
529 			template = calloc(1, sizeof(struct template));
530 			if (template == NULL)
531 				err(1, "calloc");
532 
533 			template->filename = strdup(filename);
534 			template->name = strdup(name);
535 			template->emulation = strdup(emulation);
536 			template->description = strdup(description);
537 
538 			if (template->filename == NULL ||
539 			    template->name == NULL ||
540 			    template->emulation == NULL ||
541 			    template->description == NULL)
542 				err(1, "strdup");
543 
544 			continue;
545 		}
546 
547 		if (policy == NULL)
548 			goto out;
549 
550 		if (systrace_policyprocess(policy, p) == -1)
551 			goto error;
552 	}
553 
554  out:
555 	fclose(fp);
556 	return (template);
557 
558  error:
559 	fprintf(stderr, "%s:%d: syntax error.\n", filename, linenumber);
560 	goto out;
561 }
562 
563 /*
564  * Removes trailing whitespace and comments from the input line
565  */
566 
567 static char *
systrace_policyline(char * line)568 systrace_policyline(char *line)
569 {
570 	char *p;
571 	int quoted = 0;
572 
573 	if ((p = strchr(line, '\n')) == NULL)
574 		return (NULL);
575 	*p = '\0';
576 
577 	/* Remove comments from the input line but ignore # that are part
578 	 * of the system call name or within quotes.
579 	 */
580 	for (p = line; *p; p++) {
581 		if (*p == '"')
582 			quoted = quoted ? 0 : 1;
583 		if (*p == '#') {
584 			if (quoted)
585 				continue;
586 			if (p != line && *(p-1) == '-')
587 				continue;
588 			*p = '\0';
589 			break;
590 		}
591 	}
592 
593 	/* Remove trailing white space */
594 	p = line + strlen(line) - 1;
595 	while (p > line) {
596 		if (!isspace(*p))
597 			break;
598 		*p-- = '\0';
599 	}
600 
601 	/* Ignore white space at start of line */
602 	p = line;
603 	p += strspn(p, " \t");
604 
605 	return (p);
606 }
607 
608 /*
609  * Parse a single line from a policy and convert it into a policy filter.
610  * Predicates are matched.
611  */
612 
613 static int
systrace_policyprocess(struct policy * policy,char * p)614 systrace_policyprocess(struct policy *policy, char *p)
615 {
616 	char line[_POSIX2_LINE_MAX];
617 	char *name, *emulation, *rule;
618 	struct filter *filter, *parsed;
619 	short action, future;
620 	int  resolved = 0, res, isvalid;
621 
622 	/* Delay predicate evaluation if we are root */
623 
624 	emulation = strsep(&p, "-");
625 	if (p == NULL || *p == '\0')
626 		return (-1);
627 
628 	if (strcmp(emulation, policy->emulation))
629 		return (-1);
630 
631 	name = strsep(&p, ":");
632 	if (p == NULL || *p != ' ')
633 		return (-1);
634 
635 	isvalid = intercept_isvalidsystemcall(emulation, name);
636 
637 	p++;
638 	rule = p;
639 
640 	if ((p = strrchr(p, ',')) != NULL && !strncasecmp(p, ", if", 4)) {
641 		*p = '\0';
642 		res = filter_parse_simple(rule, &action, &future);
643 		*p = ',';
644 		if (res == 0) {
645 			/* Need to make a real policy out of it */
646 			snprintf(line, sizeof(line), "true then %s", rule);
647 			rule = line;
648 		}
649 	} else if (filter_parse_simple(rule, &action, &future) == 0)
650 		resolved = 1;
651 
652 	/*
653 	 * For now, everything that does not seem to be a valid syscall
654 	 * does not get fast kernel policies even though the aliasing
655 	 * system supports it.
656 	 */
657 	if (resolved && !isvalid) {
658 		resolved = 0;
659 		snprintf(line, sizeof(line), "true then %s", rule);
660 		rule = line;
661 	}
662 
663 	/* If the simple parser did not match, try real parser */
664 	if (!resolved) {
665 		if (parse_filter(rule, &parsed) == -1)
666 			return (-1);
667 
668 		filter_free(parsed);
669 	}
670 
671 	filter = calloc(1, sizeof(struct filter));
672 	if (filter == NULL)
673 		err(1, "%s:%d: calloc", __func__, __LINE__);
674 
675 	filter->rule = strdup(rule);
676 	if (filter->rule == NULL)
677 		err(1, "%s:%d: strdup", __func__, __LINE__);
678 
679 	strlcpy(filter->name, name, sizeof(filter->name));
680 	strlcpy(filter->emulation,  emulation, sizeof(filter->emulation));
681 
682 	TAILQ_INSERT_TAIL(&policy->prefilters, filter, policy_next);
683 
684 	return (0);
685 }
686 
687 /*
688  * Reads security policy from specified file.
689  * If policy exists already, this function appends new statements from the
690  * file to the existing policy.
691  */
692 
693 struct policy *
systrace_readpolicy(const char * filename)694 systrace_readpolicy(const char *filename)
695 {
696 	FILE *fp;
697 	struct policy *policy;
698 	char line[_POSIX2_LINE_MAX], *p;
699 	char *emulation, *name;
700 	int linenumber = 0;
701 	int res = -1;
702 
703 	if ((fp = fopen(filename, "r")) == NULL)
704 		return (NULL);
705 
706 	policy = NULL;
707 	while (fgets(line, sizeof(line), fp)) {
708 		linenumber++;
709 
710 		if ((p = systrace_policyline(line)) == NULL) {
711 			fprintf(stderr, "%s:%d: input line too long.\n",
712 			    filename, linenumber);
713 			goto out;
714 		}
715 
716 		if (strlen(p) == 0)
717 			continue;
718 
719 		if (!strncasecmp(p, "Policy: ", 8)) {
720 			struct timeval now;
721 
722 			p += 8;
723 			name = strsep(&p, ",");
724 			if (p == NULL)
725 				goto error;
726 			if (strncasecmp(p, " Emulation: ", 12))
727 				goto error;
728 			p += 12;
729 			emulation = p;
730 
731 			policy = systrace_newpolicy(emulation, name);
732 			if (policy == NULL)
733 				goto error;
734 
735 			/* Update access time */
736 			gettimeofday(&now, NULL);
737 			TIMEVAL_TO_TIMESPEC(&now, &policy->ts_last);
738 			continue;
739 		}
740 
741 		if (policy == NULL)
742 			goto error;
743 
744 		if (!strncasecmp(p, "detached", 8)) {
745 			policy->flags |= POLICY_DETACHED;
746 			policy = NULL;
747 			continue;
748 		}
749 
750 		if (systrace_policyprocess(policy, p) == -1)
751 			goto error;
752 	}
753 	res = 0;
754 
755  out:
756 	fclose(fp);
757 	return (res == -1 ? NULL : policy);
758 
759  error:
760 	fprintf(stderr, "%s:%d: syntax error.\n", filename, linenumber);
761 	goto out;
762 }
763 
764 /*
765  * Appends new policy statements if the policy has been updated by
766  * another process.  Assumes that policies are append-only.
767  *
768  * Returns:
769  *	-1	if the policy could not be updated.
770  *	 0	if the policy has been updated.
771  */
772 
773 int
systrace_updatepolicy(int fd,struct policy * policy)774 systrace_updatepolicy(int fd, struct policy *policy)
775 {
776 	struct stat sb;
777 	struct timespec mtimespec;
778 	int i, policynr = policy->policynr;
779 	char *file;
780 
781 	if ((file = systrace_getpolicyname(policy->name)) == NULL)
782 		return (-1);
783 
784 	if (stat(file, &sb) == -1)
785 		return (-1);
786 
787 	mtimespec = sb.st_mtimespec;
788 
789 	/* Policy does not need updating */
790 	if (timespeccmp(&mtimespec, &policy->ts_last, <=))
791 		return (-1);
792 
793 	/* Reset the existing policy */
794 	for (i = 0; i < INTERCEPT_MAXSYSCALLNR; i++) {
795 		if (policy->kerneltable[i] == ICPOLICY_ASK)
796 			continue;
797 		if (intercept_modifypolicy_nr(fd, policynr, i,
798 		    ICPOLICY_ASK) == -1)
799 			errx(1, "%s: failed to modify policy for %d",
800 			    __func__, i);
801 	}
802 
803 	/* Now clean up all filter structures in this policy */
804 	systrace_cleanpolicy(policy);
805 
806 	/* XXX - This does not deal with Detached and Automatic */
807 	if (systrace_readpolicy(file) == NULL)
808 		return (-1);
809 
810 	/* Resets the changed flag */
811 	filter_prepolicy(fd, policy);
812 
813 	return (0);
814 }
815 
816 int
systrace_writepolicy(struct policy * policy)817 systrace_writepolicy(struct policy *policy)
818 {
819 	FILE *fp;
820 	int fd;
821 	char *p;
822 	char tmpname[2*MAXPATHLEN];
823 	char finalname[2*MAXPATHLEN];
824 	struct filter *filter;
825 	struct timeval now;
826 
827 	if ((p = systrace_policyfilename(policydir, policy->name)) == NULL)
828 		return (-1);
829 	strlcpy(finalname, p, sizeof(finalname));
830 	if ((p = systrace_policyfilename(policydir, "tmpXXXXXXXX")) == NULL)
831 		return (-1);
832 	strlcpy(tmpname, p, sizeof(tmpname));
833 	if ((fd = mkstemp(tmpname)) == -1 ||
834 	    (fp = fdopen(fd, "w+")) == NULL) {
835 		if (fd != -1) {
836 			unlink(tmpname);
837 			close(fd);
838 		}
839 		return (-1);
840 	}
841 
842 
843 	fprintf(fp, "Policy: %s, Emulation: %s\n",
844 	    policy->name, policy->emulation);
845 	if (policy->flags & POLICY_DETACHED) {
846 		fprintf(fp, "detached\n");
847 	} else {
848 		TAILQ_FOREACH(filter, &policy->prefilters, policy_next) {
849 			fprintf(fp, "\t%s-%s: %s\n",
850 			    filter->emulation, filter->name, filter->rule);
851 		}
852 		TAILQ_FOREACH(filter, &policy->filters, policy_next) {
853 			fprintf(fp, "\t%s-%s: %s\n",
854 			    filter->emulation, filter->name, filter->rule);
855 		}
856 	}
857 	fprintf(fp, "\n");
858 	fclose(fp);
859 
860 	if (rename(tmpname, finalname) == -1) {
861 		warn("rename(%s, %s)", tmpname, finalname);
862 		return (-1);
863 	}
864 
865 	/* Update access time */
866 	gettimeofday(&now, NULL);
867 	TIMEVAL_TO_TIMESPEC(&now, &policy->ts_last);
868 
869 	return (0);
870 }
871 
872 int
systrace_updatepolicies(int fd)873 systrace_updatepolicies(int fd)
874 {
875 	struct policy *policy;
876 
877 	SPLAY_FOREACH(policy, policytree, &policyroot) {
878 		/* Check if the policy has been updated */
879 		systrace_updatepolicy(fd, policy);
880 	}
881 
882 	return (0);
883 }
884 
885 /*
886  * Write policy to disk if it has been changed.  We need to
887  * call systrace_updatepolicies() before this, so that we
888  * don't clobber changes.
889  */
890 
891 int
systrace_dumppolicies(int fd)892 systrace_dumppolicies(int fd)
893 {
894 	struct policy *policy;
895 
896 	SPLAY_FOREACH(policy, policytree, &policyroot) {
897 		if (!(policy->flags & POLICY_CHANGED))
898 			continue;
899 
900 		if (systrace_writepolicy(policy) == -1)
901 			fprintf(stderr, "Failed to write policy for %s\n",
902 			    policy->name);
903 		else
904 			policy->flags &= ~POLICY_CHANGED;
905 	}
906 
907 	return (0);
908 }
909