blob: ac11b3759cee1059416816c5d4bdcaab8e1f97b4 [file] [log] [blame]
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001/*
2 * File contexts backend for labeling system
3 *
4 * Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
5 * Author : Stephen Smalley <sds@tycho.nsa.gov>
6 *
7 * This library derived in part from setfiles and the setfiles.pl script
8 * developed by Secure Computing Corporation.
9 */
10
11#include <fcntl.h>
12#include <stdarg.h>
13#include <string.h>
14#include <stdio.h>
15#include <stdio_ext.h>
16#include <ctype.h>
17#include <errno.h>
18#include <limits.h>
19#include <regex.h>
Stephen Smalley070505f2010-02-16 09:29:31 -050020#include <sys/types.h>
21#include <sys/stat.h>
22#include <unistd.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -040023#include "callbacks.h"
24#include "label_internal.h"
25
26/*
27 * Internals, mostly moved over from matchpathcon.c
28 */
29
30/* A file security context specification. */
31typedef struct spec {
32 struct selabel_lookup_rec lr; /* holds contexts for lookup result */
33 char *regex_str; /* regular expession string for diagnostics */
34 char *type_str; /* type string for diagnostic messages */
35 regex_t regex; /* compiled regular expression */
36 char regcomp; /* regex_str has been compiled to regex */
37 mode_t mode; /* mode format value */
38 int matches; /* number of matching pathnames */
39 int hasMetaChars; /* regular expression has meta-chars */
40 int stem_id; /* indicates which stem-compression item */
41} spec_t;
42
43/* A regular expression stem */
44typedef struct stem {
45 char *buf;
46 int len;
47} stem_t;
48
49/* Our stored configuration */
50struct saved_data {
51 /*
52 * The array of specifications, initially in the same order as in
53 * the specification file. Sorting occurs based on hasMetaChars.
54 */
55 spec_t *spec_arr;
56 unsigned int nspec;
57 unsigned int ncomp;
58
59 /*
60 * The array of regular expression stems.
61 */
62 stem_t *stem_arr;
63 int num_stems;
64 int alloc_stems;
65};
66
67/* Return the length of the text that can be considered the stem, returns 0
68 * if there is no identifiable stem */
69static int get_stem_from_spec(const char *const buf)
70{
71 const char *tmp = strchr(buf + 1, '/');
72 const char *ind;
73
74 if (!tmp)
75 return 0;
76
77 for (ind = buf; ind < tmp; ind++) {
78 if (strchr(".^$?*+|[({", (int)*ind))
79 return 0;
80 }
81 return tmp - buf;
82}
83
84/* return the length of the text that is the stem of a file name */
85static int get_stem_from_file_name(const char *const buf)
86{
87 const char *tmp = strchr(buf + 1, '/');
88
89 if (!tmp)
90 return 0;
91 return tmp - buf;
92}
93
94/* find the stem of a file spec, returns the index into stem_arr for a new
95 * or existing stem, (or -1 if there is no possible stem - IE for a file in
96 * the root directory or a regex that is too complex for us). */
97static int find_stem_from_spec(struct saved_data *data, const char *buf)
98{
99 int i, num = data->num_stems;
100 int stem_len = get_stem_from_spec(buf);
101
102 if (!stem_len)
103 return -1;
104 for (i = 0; i < num; i++) {
105 if (stem_len == data->stem_arr[i].len
106 && !strncmp(buf, data->stem_arr[i].buf, stem_len))
107 return i;
108 }
109 if (data->alloc_stems == num) {
110 stem_t *tmp_arr;
111 data->alloc_stems = data->alloc_stems * 2 + 16;
112 tmp_arr = realloc(data->stem_arr,
113 sizeof(stem_t) * data->alloc_stems);
114 if (!tmp_arr)
115 return -1;
116 data->stem_arr = tmp_arr;
117 }
118 data->stem_arr[num].len = stem_len;
119 data->stem_arr[num].buf = malloc(stem_len + 1);
120 if (!data->stem_arr[num].buf)
121 return -1;
122 memcpy(data->stem_arr[num].buf, buf, stem_len);
123 data->stem_arr[num].buf[stem_len] = '\0';
124 data->num_stems++;
125 buf += stem_len;
126 return num;
127}
128
129/* find the stem of a file name, returns the index into stem_arr (or -1 if
130 * there is no match - IE for a file in the root directory or a regex that is
131 * too complex for us). Makes buf point to the text AFTER the stem. */
132static int find_stem_from_file(struct saved_data *data, const char **buf)
133{
134 int i;
135 int stem_len = get_stem_from_file_name(*buf);
136
137 if (!stem_len)
138 return -1;
139 for (i = 0; i < data->num_stems; i++) {
140 if (stem_len == data->stem_arr[i].len
141 && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) {
142 *buf += stem_len;
143 return i;
144 }
145 }
146 return -1;
147}
148
149/*
150 * Warn about duplicate specifications.
151 */
152static int nodups_specs(struct saved_data *data, const char *path)
153{
154 int rc = 0;
155 unsigned int ii, jj;
156 struct spec *curr_spec, *spec_arr = data->spec_arr;
157
158 for (ii = 0; ii < data->nspec; ii++) {
159 curr_spec = &spec_arr[ii];
160 for (jj = ii + 1; jj < data->nspec; jj++) {
Eric Parisd4a39ca2011-09-29 17:07:54 -0400161 if ((!strcmp(spec_arr[jj].regex_str, curr_spec->regex_str))
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400162 && (!spec_arr[jj].mode || !curr_spec->mode
163 || spec_arr[jj].mode == curr_spec->mode)) {
164 rc = -1;
165 errno = EINVAL;
Eric Parisd4a39ca2011-09-29 17:07:54 -0400166 if (strcmp(spec_arr[jj].lr.ctx_raw, curr_spec->lr.ctx_raw)) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400167 COMPAT_LOG
168 (SELINUX_ERROR,
169 "%s: Multiple different specifications for %s (%s and %s).\n",
170 path, curr_spec->regex_str,
171 spec_arr[jj].lr.ctx_raw,
172 curr_spec->lr.ctx_raw);
173 } else {
174 COMPAT_LOG
175 (SELINUX_ERROR,
176 "%s: Multiple same specifications for %s.\n",
177 path, curr_spec->regex_str);
178 }
179 }
180 }
181 }
182 return rc;
183}
184
185/* Determine if the regular expression specification has any meta characters. */
186static void spec_hasMetaChars(struct spec *spec)
187{
188 char *c;
189 int len;
190 char *end;
191
192 c = spec->regex_str;
193 len = strlen(spec->regex_str);
194 end = c + len;
195
196 spec->hasMetaChars = 0;
197
198 /* Look at each character in the RE specification string for a
199 * meta character. Return when any meta character reached. */
200 while (c != end) {
201 switch (*c) {
202 case '.':
203 case '^':
204 case '$':
205 case '?':
206 case '*':
207 case '+':
208 case '|':
209 case '[':
210 case '(':
211 case '{':
212 spec->hasMetaChars = 1;
213 return;
214 case '\\': /* skip the next character */
215 c++;
216 break;
217 default:
218 break;
219
220 }
221 c++;
222 }
223 return;
224}
225
226static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf)
227{
228 char *reg_buf, *anchored_regex, *cp;
229 stem_t *stem_arr = data->stem_arr;
230 size_t len;
231 int regerr;
232
233 if (spec->regcomp)
234 return 0; /* already done */
235
236 data->ncomp++; /* how many compiled regexes required */
237
238 /* Skip the fixed stem. */
239 reg_buf = spec->regex_str;
240 if (spec->stem_id >= 0)
241 reg_buf += stem_arr[spec->stem_id].len;
242
243 /* Anchor the regular expression. */
244 len = strlen(reg_buf);
245 cp = anchored_regex = malloc(len + 3);
246 if (!anchored_regex)
247 return -1;
248 /* Create ^...$ regexp. */
249 *cp++ = '^';
250 cp = mempcpy(cp, reg_buf, len);
251 *cp++ = '$';
252 *cp = '\0';
253
254 /* Compile the regular expression. */
255 regerr = regcomp(&spec->regex, anchored_regex,
256 REG_EXTENDED | REG_NOSUB);
257 if (regerr != 0) {
258 size_t errsz = 0;
259 errsz = regerror(regerr, &spec->regex, NULL, 0);
260 if (errsz && errbuf)
261 *errbuf = malloc(errsz);
262 if (errbuf && *errbuf)
263 (void)regerror(regerr, &spec->regex,
264 *errbuf, errsz);
265
266 free(anchored_regex);
267 return -1;
268 }
269 free(anchored_regex);
270
271 /* Done. */
272 spec->regcomp = 1;
273
274 return 0;
275}
276
277
278static int process_line(struct selabel_handle *rec,
279 const char *path, const char *prefix,
280 char *line_buf, int pass, unsigned lineno)
281{
282 int items, len;
283 char *buf_p, *regex, *type, *context;
284 struct saved_data *data = (struct saved_data *)rec->data;
285 spec_t *spec_arr = data->spec_arr;
286 unsigned int nspec = data->nspec;
287
288 len = strlen(line_buf);
289 if (line_buf[len - 1] == '\n')
290 line_buf[len - 1] = 0;
291 buf_p = line_buf;
292 while (isspace(*buf_p))
293 buf_p++;
294 /* Skip comment lines and empty lines. */
295 if (*buf_p == '#' || *buf_p == 0)
296 return 0;
297 items = sscanf(line_buf, "%as %as %as", &regex, &type, &context);
298 if (items < 2) {
299 COMPAT_LOG(SELINUX_WARNING,
300 "%s: line %d is missing fields, skipping\n", path,
301 lineno);
Hiroshi Shinjia4af8472009-04-11 14:41:51 -0400302 if (items == 1)
303 free(regex);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400304 return 0;
305 } else if (items == 2) {
306 /* The type field is optional. */
307 free(context);
308 context = type;
309 type = 0;
310 }
311
312 len = get_stem_from_spec(regex);
313 if (len && prefix && strncmp(prefix, regex, len)) {
314 /* Stem of regex does not match requested prefix, discard. */
315 free(regex);
316 free(type);
317 free(context);
318 return 0;
319 }
320
321 if (pass == 1) {
322 /* On the second pass, process and store the specification in spec. */
323 char *errbuf = NULL;
324 spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
325 spec_arr[nspec].regex_str = regex;
326 if (rec->validating && compile_regex(data, &spec_arr[nspec], &errbuf)) {
327 COMPAT_LOG(SELINUX_WARNING,
328 "%s: line %d has invalid regex %s: %s\n",
329 path, lineno, regex,
330 (errbuf ? errbuf : "out of memory"));
331 }
332
333 /* Convert the type string to a mode format */
334 spec_arr[nspec].type_str = type;
335 spec_arr[nspec].mode = 0;
336 if (!type)
337 goto skip_type;
338 len = strlen(type);
339 if (type[0] != '-' || len != 2) {
340 COMPAT_LOG(SELINUX_WARNING,
341 "%s: line %d has invalid file type %s\n",
342 path, lineno, type);
343 return 0;
344 }
345 switch (type[1]) {
346 case 'b':
347 spec_arr[nspec].mode = S_IFBLK;
348 break;
349 case 'c':
350 spec_arr[nspec].mode = S_IFCHR;
351 break;
352 case 'd':
353 spec_arr[nspec].mode = S_IFDIR;
354 break;
355 case 'p':
356 spec_arr[nspec].mode = S_IFIFO;
357 break;
358 case 'l':
359 spec_arr[nspec].mode = S_IFLNK;
360 break;
361 case 's':
362 spec_arr[nspec].mode = S_IFSOCK;
363 break;
364 case '-':
365 spec_arr[nspec].mode = S_IFREG;
366 break;
367 default:
368 COMPAT_LOG(SELINUX_WARNING,
369 "%s: line %d has invalid file type %s\n",
370 path, lineno, type);
371 return 0;
372 }
373
374 skip_type:
375 spec_arr[nspec].lr.ctx_raw = context;
376
377 /* Determine if specification has
378 * any meta characters in the RE */
379 spec_hasMetaChars(&spec_arr[nspec]);
380
381 if (strcmp(context, "<<none>>") && rec->validating)
382 compat_validate(rec, &spec_arr[nspec].lr, path, lineno);
383 }
384
385 data->nspec = ++nspec;
386 if (pass == 0) {
387 free(regex);
388 if (type)
389 free(type);
390 free(context);
391 }
392 return 0;
393}
394
395static int init(struct selabel_handle *rec, struct selinux_opt *opts,
396 unsigned n)
397{
398 struct saved_data *data = (struct saved_data *)rec->data;
399 const char *path = NULL;
400 const char *prefix = NULL;
401 FILE *fp;
402 FILE *localfp = NULL;
403 FILE *homedirfp = NULL;
404 char local_path[PATH_MAX + 1];
405 char homedir_path[PATH_MAX + 1];
Richard Haines441cf2e2011-04-18 16:41:40 +0100406 char subs_file[PATH_MAX + 1];
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400407 char *line_buf = NULL;
408 size_t line_len = 0;
409 unsigned int lineno, pass, i, j, maxnspec;
410 spec_t *spec_copy = NULL;
411 int status = -1, baseonly = 0;
412 struct stat sb;
413
414 /* Process arguments */
415 while (n--)
416 switch(opts[n].type) {
417 case SELABEL_OPT_PATH:
418 path = opts[n].value;
419 break;
420 case SELABEL_OPT_SUBSET:
421 prefix = opts[n].value;
422 break;
423 case SELABEL_OPT_BASEONLY:
424 baseonly = !!opts[n].value;
425 break;
426 }
427
Richard Haines441cf2e2011-04-18 16:41:40 +0100428 /* Process local and distribution substitution files */
429 if (!path) {
430 rec->subs = selabel_subs_init(selinux_file_context_subs_dist_path(), rec->subs);
431 rec->subs = selabel_subs_init(selinux_file_context_subs_path(), rec->subs);
432 } else {
433 snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", path);
434 rec->subs = selabel_subs_init(subs_file, rec->subs);
435 snprintf(subs_file, sizeof(subs_file), "%s.subs", path);
436 rec->subs = selabel_subs_init(subs_file, rec->subs);
437 }
438
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400439 /* Open the specification file. */
440 if (!path)
441 path = selinux_file_context_path();
442 if ((fp = fopen(path, "r")) == NULL)
443 return -1;
444 __fsetlocking(fp, FSETLOCKING_BYCALLER);
445
446 if (fstat(fileno(fp), &sb) < 0)
447 return -1;
448 if (!S_ISREG(sb.st_mode)) {
449 errno = EINVAL;
450 return -1;
451 }
452
453 if (!baseonly) {
454 snprintf(homedir_path, sizeof(homedir_path), "%s.homedirs",
455 path);
456 homedirfp = fopen(homedir_path, "r");
457 if (homedirfp != NULL)
458 __fsetlocking(homedirfp, FSETLOCKING_BYCALLER);
459
460 snprintf(local_path, sizeof(local_path), "%s.local", path);
461 localfp = fopen(local_path, "r");
462 if (localfp != NULL)
463 __fsetlocking(localfp, FSETLOCKING_BYCALLER);
464 }
465
466 /*
467 * Perform two passes over the specification file.
468 * The first pass counts the number of specifications and
469 * performs simple validation of the input. At the end
470 * of the first pass, the spec array is allocated.
471 * The second pass performs detailed validation of the input
472 * and fills in the spec array.
473 */
474 maxnspec = UINT_MAX / sizeof(spec_t);
475 for (pass = 0; pass < 2; pass++) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400476 data->nspec = 0;
477 data->ncomp = 0;
Eric Parisd4a39ca2011-09-29 17:07:54 -0400478
479 lineno = 0;
480 while (getline(&line_buf, &line_len, fp) > 0) {
481 if (data->nspec >= maxnspec)
482 break;
483 status = process_line(rec, path, prefix, line_buf, pass, ++lineno);
484 if (status)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400485 goto finish;
486 }
Eric Parisd4a39ca2011-09-29 17:07:54 -0400487
Eric Paris4f621a12011-06-28 21:37:38 -0400488 if (pass == 1 && rec->validating) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400489 status = nodups_specs(data, path);
490 if (status)
491 goto finish;
492 }
Eric Parisd4a39ca2011-09-29 17:07:54 -0400493
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400494 lineno = 0;
495 if (homedirfp)
Eric Parisd4a39ca2011-09-29 17:07:54 -0400496 while (getline(&line_buf, &line_len, homedirfp) > 0) {
497 if (data->nspec >= maxnspec)
498 break;
499 status = process_line(rec, homedir_path, prefix, line_buf, pass, ++lineno);
500 if (status)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400501 goto finish;
502 }
503
504 lineno = 0;
505 if (localfp)
Eric Parisd4a39ca2011-09-29 17:07:54 -0400506 while (getline(&line_buf, &line_len, localfp) > 0) {
507 if (data->nspec >= maxnspec)
508 break;
509 status = process_line(rec, local_path, prefix, line_buf, pass, ++lineno);
510 if (status)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400511 goto finish;
512 }
513
514 if (pass == 0) {
515 if (data->nspec == 0) {
516 status = 0;
517 goto finish;
518 }
Eric Parisd4a39ca2011-09-29 17:07:54 -0400519 data->spec_arr = calloc(data->nspec, sizeof(spec_t));
520 if (!data->spec_arr)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400521 goto finish;
Eric Parisd4a39ca2011-09-29 17:07:54 -0400522
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400523 maxnspec = data->nspec;
524 rewind(fp);
525 if (homedirfp)
526 rewind(homedirfp);
527 if (localfp)
528 rewind(localfp);
529 }
530 }
531 free(line_buf);
532
533 /* Move exact pathname specifications to the end. */
534 spec_copy = malloc(sizeof(spec_t) * data->nspec);
535 if (!spec_copy)
536 goto finish;
537 j = 0;
538 for (i = 0; i < data->nspec; i++)
539 if (data->spec_arr[i].hasMetaChars)
540 memcpy(&spec_copy[j++],
541 &data->spec_arr[i], sizeof(spec_t));
542 for (i = 0; i < data->nspec; i++)
543 if (!data->spec_arr[i].hasMetaChars)
544 memcpy(&spec_copy[j++],
545 &data->spec_arr[i], sizeof(spec_t));
546 free(data->spec_arr);
547 data->spec_arr = spec_copy;
548
549 status = 0;
550finish:
551 fclose(fp);
552 if (data->spec_arr != spec_copy)
553 free(data->spec_arr);
554 if (homedirfp)
555 fclose(homedirfp);
556 if (localfp)
557 fclose(localfp);
558 return status;
559}
560
561/*
562 * Backend interface routines
563 */
Stephen Smalley070505f2010-02-16 09:29:31 -0500564static void closef(struct selabel_handle *rec)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400565{
566 struct saved_data *data = (struct saved_data *)rec->data;
567 struct spec *spec;
568 struct stem *stem;
569 unsigned int i;
570
571 for (i = 0; i < data->nspec; i++) {
572 spec = &data->spec_arr[i];
573 free(spec->regex_str);
574 free(spec->type_str);
575 free(spec->lr.ctx_raw);
576 free(spec->lr.ctx_trans);
577 regfree(&spec->regex);
578 }
579
580 for (i = 0; i < (unsigned int)data->num_stems; i++) {
581 stem = &data->stem_arr[i];
582 free(stem->buf);
583 }
584
585 if (data->spec_arr)
586 free(data->spec_arr);
587 if (data->stem_arr)
588 free(data->stem_arr);
589
590 free(data);
591}
592
593static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
594 const char *key, int type)
595{
596 struct saved_data *data = (struct saved_data *)rec->data;
597 spec_t *spec_arr = data->spec_arr;
598 int i, rc, file_stem;
599 mode_t mode = (mode_t)type;
Chad Sellers8f007922010-06-02 14:39:36 -0400600 const char *buf;
601 struct selabel_lookup_rec *ret = NULL;
602 char *clean_key = NULL;
603 const char *prev_slash, *next_slash;
604 unsigned int sofar = 0;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400605
606 if (!data->nspec) {
607 errno = ENOENT;
Chad Sellers8f007922010-06-02 14:39:36 -0400608 goto finish;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400609 }
610
Chad Sellers8f007922010-06-02 14:39:36 -0400611 /* Remove duplicate slashes */
612 if ((next_slash = strstr(key, "//"))) {
613 clean_key = malloc(strlen(key) + 1);
614 if (!clean_key)
615 goto finish;
616 prev_slash = key;
617 while (next_slash) {
618 memcpy(clean_key + sofar, prev_slash, next_slash - prev_slash);
619 sofar += next_slash - prev_slash;
620 prev_slash = next_slash + 1;
621 next_slash = strstr(prev_slash, "//");
622 }
623 strcpy(clean_key + sofar, prev_slash);
624 key = clean_key;
625 }
626
627 buf = key;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400628 file_stem = find_stem_from_file(data, &buf);
629 mode &= S_IFMT;
630
631 /*
632 * Check for matching specifications in reverse order, so that
633 * the last matching specification is used.
634 */
635 for (i = data->nspec - 1; i >= 0; i--) {
636 /* if the spec in question matches no stem or has the same
637 * stem as the file AND if the spec in question has no mode
638 * specified or if the mode matches the file mode then we do
639 * a regex check */
640 if ((spec_arr[i].stem_id == -1
641 || spec_arr[i].stem_id == file_stem)
642 && (!mode || !spec_arr[i].mode
643 || mode == spec_arr[i].mode)) {
644 if (compile_regex(data, &spec_arr[i], NULL) < 0)
Chad Sellers8f007922010-06-02 14:39:36 -0400645 goto finish;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400646 if (spec_arr[i].stem_id == -1)
647 rc = regexec(&spec_arr[i].regex, key, 0, 0, 0);
648 else
649 rc = regexec(&spec_arr[i].regex, buf, 0, 0, 0);
650
651 if (rc == 0) {
652 spec_arr[i].matches++;
653 break;
654 }
655 if (rc == REG_NOMATCH)
656 continue;
657 /* else it's an error */
Chad Sellers8f007922010-06-02 14:39:36 -0400658 goto finish;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400659 }
660 }
661
662 if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
663 /* No matching specification. */
664 errno = ENOENT;
Chad Sellers8f007922010-06-02 14:39:36 -0400665 goto finish;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400666 }
667
Chad Sellers8f007922010-06-02 14:39:36 -0400668 ret = &spec_arr[i].lr;
669
670finish:
671 free(clean_key);
672 return ret;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400673}
674
675static void stats(struct selabel_handle *rec)
676{
677 struct saved_data *data = (struct saved_data *)rec->data;
678 unsigned int i, nspec = data->nspec;
679 spec_t *spec_arr = data->spec_arr;
680
681 for (i = 0; i < nspec; i++) {
682 if (spec_arr[i].matches == 0) {
683 if (spec_arr[i].type_str) {
684 COMPAT_LOG(SELINUX_WARNING,
685 "Warning! No matches for (%s, %s, %s)\n",
686 spec_arr[i].regex_str,
687 spec_arr[i].type_str,
688 spec_arr[i].lr.ctx_raw);
689 } else {
690 COMPAT_LOG(SELINUX_WARNING,
691 "Warning! No matches for (%s, %s)\n",
692 spec_arr[i].regex_str,
693 spec_arr[i].lr.ctx_raw);
694 }
695 }
696 }
697}
698
699int selabel_file_init(struct selabel_handle *rec, struct selinux_opt *opts,
700 unsigned nopts)
701{
702 struct saved_data *data;
703
704 data = (struct saved_data *)malloc(sizeof(*data));
705 if (!data)
706 return -1;
707 memset(data, 0, sizeof(*data));
708
709 rec->data = data;
Stephen Smalley070505f2010-02-16 09:29:31 -0500710 rec->func_close = &closef;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400711 rec->func_stats = &stats;
712 rec->func_lookup = &lookup;
713
714 return init(rec, opts, nopts);
715}