1 /* $OpenBSD: filter.c,v 1.33 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/param.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35 #include <sys/tree.h>
36 #include <limits.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <stdio.h>
41 #include <fcntl.h>
42 #include <regex.h>
43 #include <errno.h>
44 #include <fnmatch.h>
45 #include <err.h>
46
47 #include "intercept.h"
48 #include "systrace.h"
49 #include "filter.h"
50 #include "util.h"
51
52 extern int allow;
53 extern int noalias;
54 extern int connected;
55 extern int cradle;
56 extern char cwd[];
57 extern char home[];
58 extern char username[];
59 extern char *guipath;
60
61 int requestor_restart = 0;
62
63 static void logic_free(struct logic *);
64 static int filter_match(struct intercept_pid *, struct intercept_tlq *,
65 struct logic *);
66 static void filter_review(struct filterq *);
67 static void filter_templates(const char *);
68 static int filter_template(int, struct policy *, int);
69 static int filter_quickpredicate(struct filter *);
70 static void filter_policyrecord(struct policy *, struct filter *, const char *,
71 const char *, char *);
72 static void filter_replace(char *, size_t, char *, char *);
73
74 static int
filter_match(struct intercept_pid * icpid,struct intercept_tlq * tls,struct logic * logic)75 filter_match(struct intercept_pid *icpid, struct intercept_tlq *tls,
76 struct logic *logic)
77 {
78 struct intercept_translate *tl;
79 int off = 0, res;
80
81 switch (logic->op) {
82 case LOGIC_NOT:
83 return (!filter_match(icpid, tls, logic->left));
84 case LOGIC_OR:
85 if (filter_match(icpid, tls, logic->left))
86 return (1);
87 return (filter_match(icpid, tls, logic->right));
88 case LOGIC_AND:
89 if (!filter_match(icpid, tls, logic->left))
90 return (0);
91 return (filter_match(icpid, tls, logic->right));
92 default:
93 break;
94 }
95
96 /* Now we just have a logic single */
97 if (logic->type == NULL)
98 goto match;
99
100 if (tls == NULL)
101 errx(1, "filter_match has no translators");
102
103 TAILQ_FOREACH(tl, tls, next) {
104 if (!tl->trans_valid)
105 continue;
106
107 if (strcasecmp(tl->name, logic->type))
108 continue;
109
110 if (logic->typeoff == -1 || logic->typeoff == off)
111 break;
112
113 off++;
114 }
115
116 if (tl == NULL)
117 return (0);
118
119 match:
120 /* We need to do dynamic expansion on the data */
121 if (logic->filterdata && (logic->flags & LOGIC_NEEDEXPAND)) {
122 char *old = logic->filterdata;
123 size_t oldlen = logic->filterlen;
124
125 logic->filterdata = filter_dynamicexpand(icpid, old);
126 logic->filterlen = strlen(logic->filterdata) + 1;
127
128 res = logic->filter_match(tl, logic);
129
130 logic->filterdata = old;
131 logic->filterlen = oldlen;
132 } else
133 res = logic->filter_match(tl, logic);
134
135 return (res);
136 }
137
138 /* Evaluate filter predicate */
139
140 int
filter_predicate(struct intercept_pid * icpid,struct predicate * pdc)141 filter_predicate(struct intercept_pid *icpid, struct predicate *pdc)
142 {
143 id_t pidnr, pdcnr;
144 int res = 0;
145
146 if (!pdc->p_flags)
147 return (1);
148
149 if (pdc->p_flags & PREDIC_UID) {
150 pidnr = icpid->uid;
151 pdcnr = pdc->p_uid;
152 } else {
153 pidnr = icpid->gid;
154 pdcnr = pdc->p_gid;
155 }
156
157 switch (pdc->p_flags & PREDIC_MASK) {
158 case PREDIC_NEGATIVE:
159 res = pidnr != pdcnr;
160 break;
161 case PREDIC_LESSER:
162 res = pidnr < pdcnr;
163 break;
164 case PREDIC_GREATER:
165 res = pidnr > pdcnr;
166 break;
167 default:
168 res = pidnr == pdcnr;
169 break;
170 }
171
172 return (res);
173 }
174
175 short
filter_evaluate(struct intercept_tlq * tls,struct filterq * fls,struct intercept_pid * icpid)176 filter_evaluate(struct intercept_tlq *tls, struct filterq *fls,
177 struct intercept_pid *icpid)
178 {
179 struct filter *filter, *last = NULL;
180 short action;
181
182 TAILQ_FOREACH(filter, fls, next) {
183 action = filter->match_action;
184
185 if (filter_predicate(icpid, &filter->match_predicate) &&
186 filter_match(icpid, tls, filter->logicroot)) {
187 /* Profile feedback optimization */
188 filter->match_count++;
189 if (last != NULL && last->match_action == action &&
190 last->match_flags == filter->match_flags &&
191 filter->match_count > last->match_count) {
192 TAILQ_REMOVE(fls, last, next);
193 TAILQ_INSERT_AFTER(fls, filter, last, next);
194 }
195
196 if (action == ICPOLICY_NEVER)
197 action = filter->match_error;
198 icpid->uflags = filter->match_flags;
199
200 /* Policy requests privilege elevation */
201 if (filter->elevate.e_flags)
202 icpid->elevate = &filter->elevate;
203 return (action);
204 }
205
206 /* Keep track of last processed filtered in a group */
207 last = filter;
208 }
209
210 return (ICPOLICY_ASK);
211 }
212
213 static void
logic_free(struct logic * logic)214 logic_free(struct logic *logic)
215 {
216 if (logic->left)
217 logic_free(logic->left);
218 if (logic->right)
219 logic_free(logic->right);
220 if (logic->type)
221 free(logic->type);
222 if (logic->filterdata)
223 free(logic->filterdata);
224 free(logic);
225 }
226
227 void
filter_free(struct filter * filter)228 filter_free(struct filter *filter)
229 {
230 if (filter->logicroot)
231 logic_free(filter->logicroot);
232 if (filter->rule)
233 free(filter->rule);
234 free(filter);
235 }
236
237 static void
filter_review(struct filterq * fls)238 filter_review(struct filterq *fls)
239 {
240 struct filter *filter;
241 int i = 0;
242
243 printf("Filter review:\n");
244
245 TAILQ_FOREACH(filter, fls, next) {
246 i++;
247 printf("%d. %s\n", i, filter->rule);
248 }
249 }
250
251 static void
filter_templates(const char * emulation)252 filter_templates(const char *emulation)
253 {
254 extern struct tmplqueue templates;
255 struct template *template;
256 int i = 0;
257
258 printf("Available Templates:\n");
259
260 TAILQ_FOREACH(template, &templates, next) {
261 if (strcmp(template->emulation, emulation))
262 continue;
263
264 i++;
265 printf("%d. %s - %s\n", i,
266 template->name, template->description);
267 }
268 }
269
270 /* Inserts a policy from a template */
271
272 static int
filter_template(int fd,struct policy * policy,int count)273 filter_template(int fd, struct policy *policy, int count)
274 {
275 extern struct tmplqueue templates;
276 struct template *template;
277 int i = 0;
278
279 TAILQ_FOREACH(template, &templates, next) {
280 if (strcmp(template->emulation, policy->emulation))
281 continue;
282
283 i++;
284 if (i == count)
285 break;
286 }
287
288 if (i != count)
289 return (-1);
290
291 template = systrace_readtemplate(template->filename, policy, template);
292 if (template == NULL)
293 return (-1);
294
295 if (filter_prepolicy(fd, policy) == -1)
296 return (-1);
297
298 /* We inserted new statements into the policy */
299 policy->flags |= POLICY_CHANGED;
300
301 return (0);
302 }
303
304 static void
filter_policyrecord(struct policy * policy,struct filter * filter,const char * emulation,const char * name,char * rule)305 filter_policyrecord(struct policy *policy, struct filter *filter,
306 const char *emulation, const char *name, char *rule)
307 {
308 /* Record the filter in the policy */
309 filter = calloc(1, sizeof(struct filter));
310 if (filter == NULL)
311 err(1, "%s:%d: calloc", __func__, __LINE__);
312 if ((filter->rule = strdup(rule)) == NULL)
313 err(1, "%s:%d: strdup", __func__, __LINE__);
314
315 strlcpy(filter->name, name, sizeof(filter->name));
316 strlcpy(filter->emulation, emulation, sizeof(filter->emulation));
317
318 TAILQ_INSERT_TAIL(&policy->filters, filter, policy_next);
319 policy->nfilters++;
320
321 policy->flags |= POLICY_CHANGED;
322 }
323
324 int
filter_parse(char * line,struct filter ** pfilter)325 filter_parse(char *line, struct filter **pfilter)
326 {
327 char *rule;
328
329 if (parse_filter(line, pfilter) == -1)
330 return (-1);
331
332 if ((rule = strdup(line)) == NULL)
333 err(1, "%s:%d: strdup", __func__, __LINE__);
334
335 (*pfilter)->rule = rule;
336
337 return (0);
338 }
339
340 /* Translate a simple action like "permit" or "deny[einval]" to numbers */
341
342 int
filter_parse_simple(char * rule,short * paction,short * pfuture)343 filter_parse_simple(char *rule, short *paction, short *pfuture)
344 {
345 char buf[_POSIX2_LINE_MAX];
346 int isfuture = 1;
347 char *line, *p;
348
349 if (strlcpy(buf, rule, sizeof(buf)) >= sizeof(buf))
350 return (-1);
351
352 line = buf;
353
354 if (!strcmp("permit", line)) {
355 *paction = *pfuture = ICPOLICY_PERMIT;
356 return (0);
357 } else if (!strcmp("permit-now", line)) {
358 *paction = ICPOLICY_PERMIT;
359 return (0);
360 } else if (strncmp("deny", line, 4))
361 return (-1);
362
363 line +=4 ;
364 if (!strncmp("-now", line, 4)) {
365 line += 4;
366 isfuture = 0;
367 }
368
369 *paction = ICPOLICY_NEVER;
370
371 switch (line[0]) {
372 case '\0':
373 break;
374 case '[':
375 line++;
376 p = strsep(&line, "]");
377 if (line == NULL || *line != '\0')
378 return (-1);
379
380 *paction = systrace_error_translate(p);
381 if (*paction == -1)
382 return (-1);
383 break;
384 default:
385 return (-1);
386 }
387
388 if (isfuture)
389 *pfuture = *paction;
390
391 return (0);
392 }
393
394 void
filter_modifypolicy(int fd,int policynr,const char * emulation,const char * name,short future)395 filter_modifypolicy(int fd, int policynr, const char *emulation,
396 const char *name, short future)
397 {
398 struct systrace_revalias *reverse = NULL;
399
400 /*
401 * Check if we are dealing with a system call that really
402 * is an alias for something else.
403 */
404 if (!noalias)
405 reverse = systrace_find_reverse(emulation, name);
406 if (reverse == NULL) {
407 if (systrace_modifypolicy(fd, policynr, name, future) == -1)
408 errx(1, "%s:%d: modify policy for %s-%s",
409 __func__, __LINE__, emulation, name);
410 } else {
411 struct systrace_alias *alias;
412
413 /* For every system call associated with this alias
414 * set the permanent in-kernel policy.
415 */
416 TAILQ_FOREACH(alias, &reverse->revl, next) {
417 if(systrace_modifypolicy(fd, policynr,
418 alias->name, future) == -1)
419 errx(1, "%s:%d: modify policy for %s-%s",
420 __func__, __LINE__,
421 emulation, alias->name);
422 }
423 }
424 }
425
426 /* In non-root case, evaluate predicates early */
427
428 static int
filter_quickpredicate(struct filter * filter)429 filter_quickpredicate(struct filter *filter)
430 {
431 struct predicate *pdc;
432 struct intercept_pid icpid;
433
434 pdc = &filter->match_predicate;
435 if (!pdc->p_flags)
436 return (1);
437
438 intercept_setpid(&icpid, getuid(), getgid());
439
440 if (!filter_predicate(&icpid, pdc))
441 return (0);
442
443 memset(pdc, 0, sizeof(filter->match_predicate));
444
445 return (1);
446 }
447
448 /*
449 * Processes the filters for a policy that have not been applied yet.
450 * Pre-filters get installed when reading a policy. This function
451 * installs a fast-path in the kernel.
452 */
453
454 int
filter_prepolicy(int fd,struct policy * policy)455 filter_prepolicy(int fd, struct policy *policy)
456 {
457 int res;
458 struct filter *filter, *parsed;
459 struct filterq *fls;
460 short action, future;
461 extern int iamroot;
462
463 /* Commit all matching pre-filters */
464 for (filter = TAILQ_FIRST(&policy->prefilters);
465 filter; filter = TAILQ_FIRST(&policy->prefilters)) {
466 future = ICPOLICY_ASK;
467
468 TAILQ_REMOVE(&policy->prefilters, filter, policy_next);
469
470 res = 0;
471 parsed = NULL;
472 /* Special rules that are not real filters */
473 if (filter_parse_simple(filter->rule, &action, &future) == -1)
474 res = filter_parse(filter->rule, &parsed);
475 if (res == -1)
476 errx(1, "%s:%d: can not parse \"%s\"",
477 __func__, __LINE__, filter->rule);
478
479 if (future == ICPOLICY_ASK) {
480 if (iamroot || filter_quickpredicate(parsed)) {
481 fls = systrace_policyflq(policy,
482 policy->emulation, filter->name);
483 TAILQ_INSERT_TAIL(fls, parsed, next);
484 }
485 } else {
486 filter_modifypolicy(fd, policy->policynr,
487 policy->emulation, filter->name, future);
488 }
489 filter_policyrecord(policy, parsed, policy->emulation,
490 filter->name, filter->rule);
491
492 filter_free(filter);
493 }
494
495 /* Existing policy applied undo changed flag */
496 policy->flags &= ~POLICY_CHANGED;
497
498 return (0);
499 }
500
501 short
filter_ask(int fd,struct intercept_tlq * tls,struct filterq * fls,int policynr,const char * emulation,const char * name,char * output,short * pfuture,struct intercept_pid * icpid)502 filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls,
503 int policynr, const char *emulation, const char *name,
504 char *output, short *pfuture, struct intercept_pid *icpid)
505 {
506 char line[2*MAXPATHLEN], *p;
507 char compose[2*MAXPATHLEN];
508 struct filter *filter;
509 struct policy *policy;
510 short action;
511 int first = 1, isalias, isprompt = 0;
512
513 *pfuture = ICPOLICY_ASK;
514
515 isalias = systrace_find_reverse(emulation, name) != NULL;
516
517 if ((policy = systrace_findpolnr(policynr)) == NULL)
518 errx(1, "%s:%d: no policy %d", __func__, __LINE__, policynr);
519
520 if (!allow)
521 printf("%s\n", output);
522 else {
523 /* Automatically allow */
524 if (tls != NULL) {
525 struct intercept_translate *tl;
526 char *l, *lst = NULL;
527 int set = 0;
528
529 /* Explicitly match every component */
530 line[0] = '\0';
531 TAILQ_FOREACH(tl, tls, next) {
532 if (!tl->trans_valid)
533 continue;
534 l = intercept_translate_print(tl);
535 if (l == NULL)
536 continue;
537
538 snprintf(compose, sizeof(compose),
539 "%s%s eq \"%s\"",
540 tl->name,
541 lst && !strcmp(tl->name, lst) ? "[1]" : "",
542 strescape(l));
543
544 lst = tl->name;
545
546 if (set)
547 strlcat(line, " and ",
548 sizeof(line));
549 else
550 set = 1;
551 strlcat(line, compose, sizeof(line));
552 }
553 if (!set)
554 strlcpy(line, "true", sizeof(line));
555 strlcat(line, " then permit", sizeof(line));
556 } else
557 strlcpy(line, "permit", sizeof(line));
558 }
559
560 while (1) {
561 /* Special policy active that allows only yes or no */
562 if (icpid->uflags & PROCESS_PROMPT)
563 isprompt = 1;
564 filter = NULL;
565
566 if (!allow) {
567 /* Ask for a policy */
568 if (!connected)
569 printf("Answer: ");
570 else {
571 /* Do not prompt the first time */
572 if (!first) {
573 printf("WRONG\n");
574 }
575 }
576
577 if (fgets(line, sizeof(line), stdin) == NULL) {
578 if (connected && !cradle && errno == EPIPE &&
579 !requestor_restart) {
580 requestor_start(guipath, 0);
581 clearerr(stdin);
582 clearerr(stdout);
583 requestor_restart = 1;
584 printf("%s\n", output);
585 continue;
586 }
587 err(1, "EOF on policy input request");
588 }
589 p = line;
590 strsep(&p, "\n");
591 } else if (!first) {
592 /* Error with filter */
593 errx(1, "Filter generation error: %s", line);
594 }
595 first = 0;
596 requestor_restart = 0;
597
598 /* Simple keywords */
599 if (!strcasecmp(line, "detach")) {
600 if (policy->nfilters) {
601 policy->flags |= POLICY_UNSUPERVISED;
602 action = ICPOLICY_NEVER;
603 } else {
604 policy->flags |= POLICY_DETACHED;
605 policy->flags |= POLICY_CHANGED;
606 action = ICPOLICY_PERMIT;
607 }
608 goto out;
609 } else if (!strcasecmp(line, "kill")) {
610 action = ICPOLICY_KILL;
611 goto out;
612 } else if (!strcasecmp(line, "review") && fls != NULL) {
613 filter_review(fls);
614 continue;
615 } else if (!strcasecmp(line, "templates")) {
616 filter_templates(emulation);
617 continue;
618 } else if (!strncasecmp(line, "template ", 9)) {
619 int count = atoi(line + 9);
620
621 if (count == 0 ||
622 filter_template(fd, policy, count) == -1) {
623 printf("Syntax error.\n");
624 continue;
625 }
626
627 if (fls != NULL)
628 action = filter_evaluate(tls, fls, icpid);
629 else
630 action = ICPOLICY_PERMIT;
631 if (action == ICPOLICY_ASK) {
632 printf("Filter unmatched.\n");
633 continue;
634 }
635
636 goto out;
637 }
638
639 if (filter_parse_simple(line, &action, pfuture) != -1) {
640 /* Yes or no, no in-kernel policy allowed */
641 if (isprompt)
642 *pfuture = ICPOLICY_ASK;
643 if (*pfuture == ICPOLICY_ASK)
644 goto out;
645 /* We have a policy decision */
646 if (!isalias)
647 break;
648
649 /* No in-kernel policy for aliases */
650 strlcpy(compose, line, sizeof(compose));
651
652 /* Change into userland rule */
653 snprintf(line, sizeof(line), "true then %s", compose);
654 }
655
656 if (isprompt) {
657 printf("Answer only \"permit\" or \"deny\". "
658 "This is a prompt.\n");
659 continue;
660 }
661
662 if (fls == NULL) {
663 printf("Syntax error.\n");
664 continue;
665 }
666
667 if (filter_parse(line, &filter) == -1) {
668 printf("Parse error.\n");
669 continue;
670 }
671
672 TAILQ_INSERT_TAIL(fls, filter, next);
673 action = filter_evaluate(tls, fls, icpid);
674
675 /* If we get a prompt flag here, we ask again */
676 if (icpid->uflags & PROCESS_PROMPT) {
677 filter_policyrecord(policy, filter, emulation, name, line);
678 printf("Answer only \"permit\" or \"deny\". "
679 "This is a prompt.\n");
680 continue;
681 }
682 if (action == ICPOLICY_ASK) {
683 TAILQ_REMOVE(fls, filter, next);
684 printf("Filter unmatched. Freeing it\n");
685 filter_free(filter);
686 continue;
687 }
688
689 break;
690 }
691
692 filter_policyrecord(policy, filter, emulation, name, line);
693
694 out:
695 if (connected)
696 printf("OKAY\n");
697 return (action);
698
699 }
700
701 static void
filter_replace(char * buf,size_t buflen,char * match,char * repl)702 filter_replace(char *buf, size_t buflen, char *match, char *repl)
703 {
704 while (strrpl(buf, buflen, match, repl) != NULL)
705 ;
706 }
707
708 char *
filter_expand(char * data)709 filter_expand(char *data)
710 {
711 static char expand[2*MAXPATHLEN];
712
713 strlcpy(expand, data, sizeof(expand));
714
715 filter_replace(expand, sizeof(expand), "$HOME", home);
716 filter_replace(expand, sizeof(expand), "$USER", username);
717 filter_replace(expand, sizeof(expand), "$CWD", cwd);
718
719 return (expand);
720 }
721
722 char *
filter_dynamicexpand(struct intercept_pid * icpid,char * data)723 filter_dynamicexpand(struct intercept_pid *icpid, char *data)
724 {
725 extern char cwd[];
726 static char expand[2*MAXPATHLEN];
727
728 strlcpy(expand, data, sizeof(expand));
729
730 filter_replace(expand, sizeof(expand), "$HOME", icpid->home);
731 filter_replace(expand, sizeof(expand), "$USER", icpid->username);
732 filter_replace(expand, sizeof(expand), "$CWD", cwd);
733
734 return (expand);
735 }
736
737 /* Checks if the string needs expansion */
738
739 int
filter_needexpand(char * data)740 filter_needexpand(char *data)
741 {
742 if (strstr(data, "$HOME") != NULL)
743 return (1);
744 if (strstr(data, "$USER") != NULL)
745 return (1);
746 if (strstr(data, "$CWD") != NULL)
747 return (1);
748
749 return (0);
750 }
751
752 int
filter_fnmatch(struct intercept_translate * tl,struct logic * logic)753 filter_fnmatch(struct intercept_translate *tl, struct logic *logic)
754 {
755 int res;
756 char *line;
757
758 if ((line = intercept_translate_print(tl)) == NULL)
759 return (0);
760 res = fnmatch(logic->filterdata, line, FNM_PATHNAME | FNM_LEADING_DIR);
761
762 return (res == 0);
763 }
764
765 int
filter_substrmatch(struct intercept_translate * tl,struct logic * logic)766 filter_substrmatch(struct intercept_translate *tl, struct logic *logic)
767 {
768 char *line;
769
770 if ((line = intercept_translate_print(tl)) == NULL)
771 return (0);
772
773 return (strstr(line, logic->filterdata) != NULL);
774 }
775
776 int
filter_negsubstrmatch(struct intercept_translate * tl,struct logic * logic)777 filter_negsubstrmatch(struct intercept_translate *tl, struct logic *logic)
778 {
779 char *line;
780
781 if ((line = intercept_translate_print(tl)) == NULL)
782 return (0);
783
784 return (strstr(line, logic->filterdata) == NULL);
785 }
786
787 int
filter_stringmatch(struct intercept_translate * tl,struct logic * logic)788 filter_stringmatch(struct intercept_translate *tl, struct logic *logic)
789 {
790 char *line;
791
792 if ((line = intercept_translate_print(tl)) == NULL)
793 return (0);
794
795 return (!strcasecmp(line, logic->filterdata));
796 }
797
798 int
filter_negstringmatch(struct intercept_translate * tl,struct logic * logic)799 filter_negstringmatch(struct intercept_translate *tl, struct logic *logic)
800 {
801 char *line;
802
803 if ((line = intercept_translate_print(tl)) == NULL)
804 return (1);
805
806 return (strcasecmp(line, logic->filterdata) != 0);
807 }
808
809 int
filter_inpath(struct intercept_translate * tl,struct logic * logic)810 filter_inpath(struct intercept_translate *tl, struct logic *logic)
811 {
812 char *line, c;
813 int len;
814
815 if ((line = intercept_translate_print(tl)) == NULL)
816 return (0);
817
818 len = strlen(line);
819 if (len == 0 || len > strlen(logic->filterdata))
820 return (0);
821
822 /* Root is always in path */
823 if (len == 1)
824 return (line[0] == '/');
825
826 /* Complete filename needs to fit */
827 if (strncmp(line, logic->filterdata, len))
828 return (0);
829
830 /* Termination has to be \0 or / */
831 c = ((char *)logic->filterdata)[len];
832 if (c != '/' && c != '\0')
833 return (0);
834
835 return (1);
836 }
837
838 int
filter_regex(struct intercept_translate * tl,struct logic * logic)839 filter_regex(struct intercept_translate *tl, struct logic *logic)
840 {
841 regex_t tmpre, *re;
842 char *line;
843 int res;
844
845 if ((line = intercept_translate_print(tl)) == NULL)
846 return (0);
847
848 re = logic->filterarg;
849 if (re == NULL) {
850 /* If regex does not compute, we just do not match */
851 if (regcomp(&tmpre, logic->filterdata,
852 REG_EXTENDED | REG_NOSUB) != 0)
853 return (0);
854 re = &tmpre;
855 }
856
857 res = regexec(re, line, 0, NULL, 0);
858
859 /* Clean up temporary memory associated with regex */
860 if (re == &tmpre)
861 regfree(re);
862
863 return (res == 0);
864 }
865
866 /* ARGSUSED */
867 int
filter_true(struct intercept_translate * tl,struct logic * logic)868 filter_true(struct intercept_translate *tl, struct logic *logic)
869 {
870 return (1);
871 }
872