blob: 9fa5d3f3093a049da7f808bbd5223751f8067e9d
1 | /* |
2 | setfiles: based on policycoreutils 2.0.19 |
3 | policycoreutils was released under GPL 2. |
4 | Port to BusyBox (c) 2007 by Yuichi Nakamura <ynakam@hitachisoft.jp> |
5 | */ |
6 | //config:config SETFILES |
7 | //config: bool "setfiles" |
8 | //config: default n |
9 | //config: depends on SELINUX |
10 | //config: help |
11 | //config: Enable support to modify to relabel files. |
12 | //config: Notice: If you built libselinux with -D_FILE_OFFSET_BITS=64, |
13 | //config: (It is default in libselinux's Makefile), you _must_ enable |
14 | //config: CONFIG_LFS. |
15 | //config: |
16 | //config:config FEATURE_SETFILES_CHECK_OPTION |
17 | //config: bool "Enable check option" |
18 | //config: default n |
19 | //config: depends on SETFILES |
20 | //config: help |
21 | //config: Support "-c" option (check the validity of the contexts against |
22 | //config: the specified binary policy) for setfiles. Requires libsepol. |
23 | //config: |
24 | //config:config RESTORECON |
25 | //config: bool "restorecon" |
26 | //config: default n |
27 | //config: depends on SELINUX |
28 | //config: help |
29 | //config: Enable support to relabel files. The feature is almost |
30 | //config: the same as setfiles, but usage is a little different. |
31 | |
32 | //applet:IF_SETFILES(APPLET(setfiles, BB_DIR_SBIN, BB_SUID_DROP)) |
33 | //applet:IF_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, BB_DIR_SBIN, BB_SUID_DROP, restorecon)) |
34 | |
35 | //kbuild:lib-$(CONFIG_SETFILES) += setfiles.o |
36 | //kbuild:lib-$(CONFIG_RESTORECON) += setfiles.o |
37 | |
38 | //usage:#define setfiles_trivial_usage |
39 | //usage: "[-dnpqsvW] [-e DIR]... [-o FILE] [-r alt_root_path]" |
40 | //usage: IF_FEATURE_SETFILES_CHECK_OPTION( |
41 | //usage: " [-c policyfile] spec_file" |
42 | //usage: ) |
43 | //usage: " pathname" |
44 | //usage:#define setfiles_full_usage "\n\n" |
45 | //usage: "Reset file contexts under pathname according to spec_file\n" |
46 | //usage: IF_FEATURE_SETFILES_CHECK_OPTION( |
47 | //usage: "\n -c FILE Check the validity of the contexts against the specified binary policy" |
48 | //usage: ) |
49 | //usage: "\n -d Show which specification matched each file" |
50 | //usage: "\n -l Log changes in file labels to syslog" |
51 | //TODO: log to syslog is not yet implemented, it goes to stdout only now |
52 | //usage: "\n -n Don't change any file labels" |
53 | //usage: "\n -q Suppress warnings" |
54 | //usage: "\n -r DIR Use an alternate root path" |
55 | //usage: "\n -e DIR Exclude DIR" |
56 | //usage: "\n -F Force reset of context to match file_context for customizable files" |
57 | //usage: "\n -o FILE Save list of files with incorrect context" |
58 | //usage: "\n -s Take a list of files from stdin (instead of command line)" |
59 | //usage: "\n -v Show changes in file labels, if type or role are changing" |
60 | //usage: "\n -vv Show changes in file labels, if type, role, or user are changing" |
61 | //usage: "\n -W Display warnings about entries that had no matching files" |
62 | //usage: |
63 | //usage:#define restorecon_trivial_usage |
64 | //usage: "[-iFnRv] [-e EXCLUDEDIR]... [-o FILE] [-f FILE]" |
65 | //usage:#define restorecon_full_usage "\n\n" |
66 | //usage: "Reset security contexts of files in pathname\n" |
67 | //usage: "\n -i Ignore files that don't exist" |
68 | //usage: "\n -f FILE File with list of files to process" |
69 | //usage: "\n -e DIR Directory to exclude" |
70 | //usage: "\n -R,-r Recurse" |
71 | //usage: "\n -n Don't change any file labels" |
72 | //usage: "\n -o FILE Save list of files with incorrect context" |
73 | //usage: "\n -v Verbose" |
74 | //usage: "\n -vv Show changed labels" |
75 | //usage: "\n -F Force reset of context to match file_context" |
76 | //usage: "\n for customizable files, or the user section," |
77 | //usage: "\n if it has changed" |
78 | |
79 | #include "libbb.h" |
80 | #include "common_bufsiz.h" |
81 | #if ENABLE_FEATURE_SETFILES_CHECK_OPTION |
82 | #include <sepol/sepol.h> |
83 | #endif |
84 | |
85 | #define MAX_EXCLUDES 50 |
86 | |
87 | struct edir { |
88 | char *directory; |
89 | size_t size; |
90 | }; |
91 | |
92 | struct globals { |
93 | FILE *outfile; |
94 | char *policyfile; |
95 | char *rootpath; |
96 | int rootpathlen; |
97 | unsigned count; |
98 | int excludeCtr; |
99 | int errors; |
100 | int verbose; /* getopt32 uses it, has to be int */ |
101 | smallint recurse; /* Recursive descent */ |
102 | smallint follow_mounts; |
103 | /* Behavior flags determined based on setfiles vs. restorecon */ |
104 | smallint expand_realpath; /* Expand paths via realpath */ |
105 | smallint abort_on_error; /* Abort the file tree walk upon an error */ |
106 | int add_assoc; /* Track inode associations for conflict detection */ |
107 | int matchpathcon_flags; /* Flags to matchpathcon */ |
108 | dev_t dev_id; /* Device id where target file exists */ |
109 | int nerr; |
110 | struct edir excludeArray[MAX_EXCLUDES]; |
111 | } FIX_ALIASING; |
112 | #define G (*(struct globals*)bb_common_bufsiz1) |
113 | void BUG_setfiles_globals_too_big(void); |
114 | #define INIT_G() do { \ |
115 | setup_common_bufsiz(); \ |
116 | if (sizeof(G) > COMMON_BUFSIZE) \ |
117 | BUG_setfiles_globals_too_big(); \ |
118 | /* memset(&G, 0, sizeof(G)); - already is */ \ |
119 | } while (0) |
120 | #define outfile (G.outfile ) |
121 | #define policyfile (G.policyfile ) |
122 | #define rootpath (G.rootpath ) |
123 | #define rootpathlen (G.rootpathlen ) |
124 | #define count (G.count ) |
125 | #define excludeCtr (G.excludeCtr ) |
126 | #define errors (G.errors ) |
127 | #define verbose (G.verbose ) |
128 | #define recurse (G.recurse ) |
129 | #define follow_mounts (G.follow_mounts ) |
130 | #define expand_realpath (G.expand_realpath ) |
131 | #define abort_on_error (G.abort_on_error ) |
132 | #define add_assoc (G.add_assoc ) |
133 | #define matchpathcon_flags (G.matchpathcon_flags) |
134 | #define dev_id (G.dev_id ) |
135 | #define nerr (G.nerr ) |
136 | #define excludeArray (G.excludeArray ) |
137 | |
138 | /* Must match getopt32 string! */ |
139 | enum { |
140 | OPT_d = (1 << 0), |
141 | OPT_e = (1 << 1), |
142 | OPT_f = (1 << 2), |
143 | OPT_i = (1 << 3), |
144 | OPT_l = (1 << 4), |
145 | OPT_n = (1 << 5), |
146 | OPT_p = (1 << 6), |
147 | OPT_q = (1 << 7), |
148 | OPT_r = (1 << 8), |
149 | OPT_s = (1 << 9), |
150 | OPT_v = (1 << 10), |
151 | OPT_o = (1 << 11), |
152 | OPT_F = (1 << 12), |
153 | OPT_W = (1 << 13), |
154 | OPT_c = (1 << 14), /* c only for setfiles */ |
155 | OPT_R = (1 << 14), /* R only for restorecon */ |
156 | }; |
157 | #define FLAG_d_debug (option_mask32 & OPT_d) |
158 | #define FLAG_e (option_mask32 & OPT_e) |
159 | #define FLAG_f (option_mask32 & OPT_f) |
160 | #define FLAG_i_ignore_enoent (option_mask32 & OPT_i) |
161 | #define FLAG_l_take_log (option_mask32 & OPT_l) |
162 | #define FLAG_n_dry_run (option_mask32 & OPT_n) |
163 | #define FLAG_p_progress (option_mask32 & OPT_p) |
164 | #define FLAG_q_quiet (option_mask32 & OPT_q) |
165 | #define FLAG_r (option_mask32 & OPT_r) |
166 | #define FLAG_s (option_mask32 & OPT_s) |
167 | #define FLAG_v (option_mask32 & OPT_v) |
168 | #define FLAG_o (option_mask32 & OPT_o) |
169 | #define FLAG_F_force (option_mask32 & OPT_F) |
170 | #define FLAG_W_warn_no_match (option_mask32 & OPT_W) |
171 | #define FLAG_c (option_mask32 & OPT_c) |
172 | #define FLAG_R (option_mask32 & OPT_R) |
173 | |
174 | |
175 | static void qprintf(const char *fmt UNUSED_PARAM, ...) |
176 | { |
177 | /* quiet, do nothing */ |
178 | } |
179 | |
180 | static void inc_err(void) |
181 | { |
182 | nerr++; |
183 | if (nerr > 9 && !FLAG_d_debug) { |
184 | bb_error_msg_and_die("exiting after 10 errors"); |
185 | } |
186 | } |
187 | |
188 | static void add_exclude(const char *directory) |
189 | { |
190 | struct stat sb; |
191 | size_t len; |
192 | |
193 | if (directory == NULL || directory[0] != '/') { |
194 | bb_error_msg_and_die("full path required for exclude: %s", directory); |
195 | } |
196 | if (lstat(directory, &sb)) { |
197 | bb_error_msg("directory \"%s\" not found, ignoring", directory); |
198 | return; |
199 | } |
200 | if ((sb.st_mode & S_IFDIR) == 0) { |
201 | bb_error_msg("\"%s\" is not a directory: mode %o, ignoring", |
202 | directory, sb.st_mode); |
203 | return; |
204 | } |
205 | if (excludeCtr == MAX_EXCLUDES) { |
206 | bb_error_msg_and_die("maximum excludes %d exceeded", MAX_EXCLUDES); |
207 | } |
208 | |
209 | len = strlen(directory); |
210 | while (len > 1 && directory[len - 1] == '/') { |
211 | len--; |
212 | } |
213 | excludeArray[excludeCtr].directory = xstrndup(directory, len); |
214 | excludeArray[excludeCtr++].size = len; |
215 | } |
216 | |
217 | static bool exclude(const char *file) |
218 | { |
219 | int i = 0; |
220 | for (i = 0; i < excludeCtr; i++) { |
221 | if (strncmp(file, excludeArray[i].directory, |
222 | excludeArray[i].size) == 0) { |
223 | if (file[excludeArray[i].size] == '\0' |
224 | || file[excludeArray[i].size] == '/') { |
225 | return 1; |
226 | } |
227 | } |
228 | } |
229 | return 0; |
230 | } |
231 | |
232 | static int match(const char *name, struct stat *sb, char **con) |
233 | { |
234 | int ret; |
235 | char path[PATH_MAX + 1]; |
236 | char *tmp_path = xstrdup(name); |
237 | |
238 | if (excludeCtr > 0 && exclude(name)) { |
239 | goto err; |
240 | } |
241 | ret = lstat(name, sb); |
242 | if (ret) { |
243 | if (FLAG_i_ignore_enoent && errno == ENOENT) { |
244 | free(tmp_path); |
245 | return 0; |
246 | } |
247 | bb_error_msg("stat(%s)", name); |
248 | goto err; |
249 | } |
250 | |
251 | if (expand_realpath) { |
252 | if (S_ISLNK(sb->st_mode)) { |
253 | char *p = NULL; |
254 | char *file_sep; |
255 | |
256 | size_t len = 0; |
257 | |
258 | if (verbose > 1) |
259 | bb_error_msg("warning! %s refers to a symbolic link, not following last component", name); |
260 | |
261 | file_sep = strrchr(tmp_path, '/'); |
262 | if (file_sep == tmp_path) { |
263 | file_sep++; |
264 | path[0] = '\0'; |
265 | p = path; |
266 | } else if (file_sep) { |
267 | *file_sep++ = '\0'; |
268 | p = realpath(tmp_path, path); |
269 | } else { |
270 | file_sep = tmp_path; |
271 | p = realpath("./", path); |
272 | } |
273 | if (p) |
274 | len = strlen(p); |
275 | if (!p || len + strlen(file_sep) + 2 > PATH_MAX) { |
276 | bb_perror_msg("realpath(%s) failed", name); |
277 | goto err; |
278 | } |
279 | p += len; |
280 | /* ensure trailing slash of directory name */ |
281 | if (len == 0 || p[-1] != '/') { |
282 | *p++ = '/'; |
283 | } |
284 | strcpy(p, file_sep); |
285 | name = path; |
286 | if (excludeCtr > 0 && exclude(name)) |
287 | goto err; |
288 | } else { |
289 | char *p; |
290 | p = realpath(name, path); |
291 | if (!p) { |
292 | bb_perror_msg("realpath(%s)", name); |
293 | goto err; |
294 | } |
295 | name = p; |
296 | if (excludeCtr > 0 && exclude(name)) |
297 | goto err; |
298 | } |
299 | } |
300 | |
301 | /* name will be what is matched in the policy */ |
302 | if (NULL != rootpath) { |
303 | if (0 != strncmp(rootpath, name, rootpathlen)) { |
304 | bb_error_msg("%s is not located in %s", |
305 | name, rootpath); |
306 | goto err; |
307 | } |
308 | name += rootpathlen; |
309 | } |
310 | |
311 | free(tmp_path); |
312 | if (rootpath != NULL && name[0] == '\0') |
313 | /* this is actually the root dir of the alt root */ |
314 | return matchpathcon_index("/", sb->st_mode, con); |
315 | return matchpathcon_index(name, sb->st_mode, con); |
316 | err: |
317 | free(tmp_path); |
318 | return -1; |
319 | } |
320 | |
321 | /* Compare two contexts to see if their differences are "significant", |
322 | * or whether the only difference is in the user. */ |
323 | static bool only_changed_user(const char *a, const char *b) |
324 | { |
325 | if (FLAG_F_force) |
326 | return 0; |
327 | if (!a || !b) |
328 | return 0; |
329 | a = strchr(a, ':'); /* Rest of the context after the user */ |
330 | b = strchr(b, ':'); |
331 | if (!a || !b) |
332 | return 0; |
333 | return (strcmp(a, b) == 0); |
334 | } |
335 | |
336 | static int restore(const char *file) |
337 | { |
338 | char *my_file; |
339 | struct stat my_sb; |
340 | int i, j, ret; |
341 | char *context = NULL; |
342 | char *newcon = NULL; |
343 | bool user_only_changed = 0; |
344 | int retval = 0; |
345 | |
346 | my_file = bb_simplify_path(file); |
347 | |
348 | i = match(my_file, &my_sb, &newcon); |
349 | |
350 | if (i < 0) /* No matching specification. */ |
351 | goto out; |
352 | |
353 | if (FLAG_p_progress) { |
354 | count++; |
355 | if (count % 0x400 == 0) { /* every 1024 times */ |
356 | count = (count % (80*0x400)); |
357 | if (count == 0) |
358 | bb_putchar('\n'); |
359 | bb_putchar('*'); |
360 | fflush_all(); |
361 | } |
362 | } |
363 | |
364 | /* |
365 | * Try to add an association between this inode and |
366 | * this specification. If there is already an association |
367 | * for this inode and it conflicts with this specification, |
368 | * then use the last matching specification. |
369 | */ |
370 | if (add_assoc) { |
371 | j = matchpathcon_filespec_add(my_sb.st_ino, i, my_file); |
372 | if (j < 0) |
373 | goto err; |
374 | |
375 | if (j != i) { |
376 | /* There was already an association and it took precedence. */ |
377 | goto out; |
378 | } |
379 | } |
380 | |
381 | if (FLAG_d_debug) |
382 | printf("%s: %s matched by %s\n", applet_name, my_file, newcon); |
383 | |
384 | /* Get the current context of the file. */ |
385 | ret = lgetfilecon_raw(my_file, &context); |
386 | if (ret < 0) { |
387 | if (errno == ENODATA) { |
388 | context = NULL; /* paranoia */ |
389 | } else { |
390 | bb_perror_msg("lgetfilecon_raw on %s", my_file); |
391 | goto err; |
392 | } |
393 | user_only_changed = 0; |
394 | } else |
395 | user_only_changed = only_changed_user(context, newcon); |
396 | |
397 | /* |
398 | * Do not relabel the file if the matching specification is |
399 | * <<none>> or the file is already labeled according to the |
400 | * specification. |
401 | */ |
402 | if ((strcmp(newcon, "<<none>>") == 0) |
403 | || (context && (strcmp(context, newcon) == 0) && !FLAG_F_force)) { |
404 | goto out; |
405 | } |
406 | |
407 | if (!FLAG_F_force && context && (is_context_customizable(context) > 0)) { |
408 | if (verbose > 1) { |
409 | bb_error_msg("skipping %s. %s is customizable_types", |
410 | my_file, context); |
411 | } |
412 | goto out; |
413 | } |
414 | |
415 | if (verbose) { |
416 | /* If we're just doing "-v", trim out any relabels where |
417 | * the user has changed but the role and type are the |
418 | * same. For "-vv", emit everything. */ |
419 | if (verbose > 1 || !user_only_changed) { |
420 | printf("%s: reset %s context %s->%s\n", |
421 | applet_name, my_file, context ? context : "", newcon); |
422 | } |
423 | } |
424 | |
425 | if (FLAG_l_take_log && !user_only_changed) { |
426 | if (context) |
427 | printf("relabeling %s from %s to %s\n", my_file, context, newcon); |
428 | else |
429 | printf("labeling %s to %s\n", my_file, newcon); |
430 | } |
431 | |
432 | if (outfile && !user_only_changed) |
433 | fprintf(outfile, "%s\n", my_file); |
434 | |
435 | /* |
436 | * Do not relabel the file if -n was used. |
437 | */ |
438 | if (FLAG_n_dry_run || user_only_changed) |
439 | goto out; |
440 | |
441 | /* |
442 | * Relabel the file to the specified context. |
443 | */ |
444 | ret = lsetfilecon(my_file, newcon); |
445 | if (ret) { |
446 | bb_perror_msg("lsetfileconon(%s,%s)", my_file, newcon); |
447 | goto err; |
448 | } |
449 | |
450 | out: |
451 | freecon(context); |
452 | freecon(newcon); |
453 | free(my_file); |
454 | return retval; |
455 | err: |
456 | retval--; /* -1 */ |
457 | goto out; |
458 | } |
459 | |
460 | /* |
461 | * Apply the last matching specification to a file. |
462 | * This function is called by recursive_action on each file during |
463 | * the directory traversal. |
464 | */ |
465 | static int FAST_FUNC apply_spec( |
466 | const char *file, |
467 | struct stat *sb, |
468 | void *userData UNUSED_PARAM, |
469 | int depth UNUSED_PARAM) |
470 | { |
471 | if (!follow_mounts) { |
472 | /* setfiles does not process across different mount points */ |
473 | if (sb->st_dev != dev_id) { |
474 | return SKIP; |
475 | } |
476 | } |
477 | errors |= restore(file); |
478 | if (abort_on_error && errors) |
479 | return FALSE; |
480 | return TRUE; |
481 | } |
482 | |
483 | |
484 | static int canoncon(const char *path, unsigned lineno, char **contextp) |
485 | { |
486 | static const char err_msg[] ALIGN1 = "%s: line %u has invalid context %s"; |
487 | |
488 | char *tmpcon; |
489 | char *context = *contextp; |
490 | int invalid = 0; |
491 | |
492 | #if ENABLE_FEATURE_SETFILES_CHECK_OPTION |
493 | if (policyfile) { |
494 | if (sepol_check_context(context) >= 0) |
495 | return 0; |
496 | /* Exit immediately if we're in checking mode. */ |
497 | bb_error_msg_and_die(err_msg, path, lineno, context); |
498 | } |
499 | #endif |
500 | |
501 | if (security_canonicalize_context_raw(context, &tmpcon) < 0) { |
502 | if (errno != ENOENT) { |
503 | invalid = 1; |
504 | inc_err(); |
505 | } |
506 | } else { |
507 | free(context); |
508 | *contextp = tmpcon; |
509 | } |
510 | |
511 | if (invalid) { |
512 | bb_error_msg(err_msg, path, lineno, context); |
513 | } |
514 | |
515 | return invalid; |
516 | } |
517 | |
518 | static int process_one(char *name) |
519 | { |
520 | struct stat sb; |
521 | int rc; |
522 | |
523 | rc = lstat(name, &sb); |
524 | if (rc < 0) { |
525 | if (FLAG_i_ignore_enoent && errno == ENOENT) |
526 | return 0; |
527 | bb_perror_msg("stat(%s)", name); |
528 | goto err; |
529 | } |
530 | dev_id = sb.st_dev; |
531 | |
532 | if (S_ISDIR(sb.st_mode) && recurse) { |
533 | if (recursive_action(name, |
534 | ACTION_RECURSE, |
535 | apply_spec, |
536 | apply_spec, |
537 | NULL, 0) != TRUE |
538 | ) { |
539 | bb_error_msg("error while labeling %s", name); |
540 | goto err; |
541 | } |
542 | } else { |
543 | rc = restore(name); |
544 | if (rc) |
545 | goto err; |
546 | } |
547 | |
548 | out: |
549 | if (add_assoc) { |
550 | if (FLAG_q_quiet) |
551 | set_matchpathcon_printf(&qprintf); |
552 | matchpathcon_filespec_eval(); |
553 | set_matchpathcon_printf(NULL); |
554 | matchpathcon_filespec_destroy(); |
555 | } |
556 | |
557 | return rc; |
558 | |
559 | err: |
560 | rc = -1; |
561 | goto out; |
562 | } |
563 | |
564 | int setfiles_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
565 | int setfiles_main(int argc UNUSED_PARAM, char **argv) |
566 | { |
567 | struct stat sb; |
568 | int rc, i = 0; |
569 | const char *input_filename = NULL; |
570 | char *buf = NULL; |
571 | size_t buf_len; |
572 | int flags; |
573 | llist_t *exclude_dir = NULL; |
574 | char *out_filename = NULL; |
575 | |
576 | INIT_G(); |
577 | |
578 | if (applet_name[0] == 's') { /* "setfiles" */ |
579 | /* |
580 | * setfiles: |
581 | * Recursive descent, |
582 | * Does not expand paths via realpath, |
583 | * Aborts on errors during the file tree walk, |
584 | * Try to track inode associations for conflict detection, |
585 | * Does not follow mounts, |
586 | * Validates all file contexts at init time. |
587 | */ |
588 | recurse = 1; |
589 | abort_on_error = 1; |
590 | add_assoc = 1; |
591 | /* follow_mounts = 0; - already is */ |
592 | matchpathcon_flags = MATCHPATHCON_VALIDATE | MATCHPATHCON_NOTRANS; |
593 | } else { |
594 | /* |
595 | * restorecon: |
596 | * No recursive descent unless -r/-R, |
597 | * Expands paths via realpath, |
598 | * Do not abort on errors during the file tree walk, |
599 | * Do not try to track inode associations for conflict detection, |
600 | * Follows mounts, |
601 | * Does lazy validation of contexts upon use. |
602 | */ |
603 | expand_realpath = 1; |
604 | follow_mounts = 1; |
605 | matchpathcon_flags = MATCHPATHCON_NOTRANS; |
606 | /* restorecon only */ |
607 | selinux_or_die(); |
608 | } |
609 | |
610 | set_matchpathcon_flags(matchpathcon_flags); |
611 | |
612 | opt_complementary = "vv:v--p:p--v:v--q:q--v"; |
613 | /* Option order must match OPT_x definitions! */ |
614 | if (applet_name[0] == 'r') { /* restorecon */ |
615 | flags = getopt32(argv, "de:*f:ilnpqrsvo:FWR", |
616 | &exclude_dir, &input_filename, &out_filename, &verbose); |
617 | } else { /* setfiles */ |
618 | flags = getopt32(argv, "de:*f:ilnpqr:svo:FW" |
619 | IF_FEATURE_SETFILES_CHECK_OPTION("c:"), |
620 | &exclude_dir, &input_filename, &rootpath, &out_filename, |
621 | IF_FEATURE_SETFILES_CHECK_OPTION(&policyfile,) |
622 | &verbose); |
623 | } |
624 | argv += optind; |
625 | |
626 | #if ENABLE_FEATURE_SETFILES_CHECK_OPTION |
627 | if ((applet_name[0] == 's') && (flags & OPT_c)) { |
628 | FILE *policystream; |
629 | |
630 | policystream = xfopen_for_read(policyfile); |
631 | if (sepol_set_policydb_from_file(policystream) < 0) { |
632 | bb_error_msg_and_die("sepol_set_policydb_from_file on %s", policyfile); |
633 | } |
634 | fclose(policystream); |
635 | |
636 | /* Only process the specified file_contexts file, not |
637 | * any .homedirs or .local files, and do not perform |
638 | * context translations. */ |
639 | set_matchpathcon_flags(MATCHPATHCON_BASEONLY | |
640 | MATCHPATHCON_NOTRANS | |
641 | MATCHPATHCON_VALIDATE); |
642 | } |
643 | #endif |
644 | |
645 | while (exclude_dir) |
646 | add_exclude(llist_pop(&exclude_dir)); |
647 | |
648 | if (flags & OPT_o) { |
649 | outfile = stdout; |
650 | if (NOT_LONE_CHAR(out_filename, '-')) { |
651 | outfile = xfopen_for_write(out_filename); |
652 | } |
653 | } |
654 | if (applet_name[0] == 'r') { /* restorecon */ |
655 | if (flags & (OPT_r | OPT_R)) |
656 | recurse = 1; |
657 | } else { /* setfiles */ |
658 | if (flags & OPT_r) |
659 | rootpathlen = strlen(rootpath); |
660 | } |
661 | if (flags & OPT_s) { |
662 | input_filename = "-"; |
663 | add_assoc = 0; |
664 | } |
665 | |
666 | if (applet_name[0] == 's') { /* setfiles */ |
667 | /* Use our own invalid context checking function so that |
668 | * we can support either checking against the active policy or |
669 | * checking against a binary policy file. */ |
670 | set_matchpathcon_canoncon(&canoncon); |
671 | if (!argv[0]) |
672 | bb_show_usage(); |
673 | xstat(argv[0], &sb); |
674 | if (!S_ISREG(sb.st_mode)) { |
675 | bb_error_msg_and_die("spec file %s is not a regular file", argv[0]); |
676 | } |
677 | /* Load the file contexts configuration and check it. */ |
678 | rc = matchpathcon_init(argv[0]); |
679 | if (rc < 0) { |
680 | bb_simple_perror_msg_and_die(argv[0]); |
681 | } |
682 | if (nerr) |
683 | exit(EXIT_FAILURE); |
684 | argv++; |
685 | } |
686 | |
687 | if (input_filename) { |
688 | ssize_t len; |
689 | FILE *f = stdin; |
690 | |
691 | if (NOT_LONE_CHAR(input_filename, '-')) |
692 | f = xfopen_for_read(input_filename); |
693 | while ((len = getline(&buf, &buf_len, f)) > 0) { |
694 | buf[len - 1] = '\0'; |
695 | errors |= process_one(buf); |
696 | } |
697 | if (ENABLE_FEATURE_CLEAN_UP) |
698 | fclose_if_not_stdin(f); |
699 | } else { |
700 | if (!argv[0]) |
701 | bb_show_usage(); |
702 | for (i = 0; argv[i]; i++) { |
703 | errors |= process_one(argv[i]); |
704 | } |
705 | } |
706 | |
707 | if (FLAG_W_warn_no_match) |
708 | matchpathcon_checkmatches(argv[0]); |
709 | |
710 | if (ENABLE_FEATURE_CLEAN_UP && outfile) |
711 | fclose(outfile); |
712 | |
713 | return errors; |
714 | } |
715 |