~vcs-imports/busybox/trunk

« back to all changes in this revision

Viewing changes to selinux/setfiles.c

  • Committer: Eric Andersen
  • Date: 1999-11-24 09:04:33 UTC
  • Revision ID: git-v1:b99df0fd65abe3245fa2d04115326100847f865e
First draft

Show diffs side-by-side

added added

removed removed

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