#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <fts.h> #include <selinux/selinux.h> #include <selinux/label.h> #define FCPATH "/file_contexts" static struct selabel_handle *sehandle; static const char *progname; static int nochange; static int verbose; static void usage(void) { fprintf(stderr, "usage: %s [-f file_contexts] [-nrRv] pathname...\n", progname); exit(1); } static int restore(const char *pathname, const struct stat *sb) { char *oldcontext, *newcontext; if (lgetfilecon(pathname, &oldcontext) < 0) { fprintf(stderr, "Could not get context of %s: %s\n", pathname, strerror(errno)); return -1; } if (selabel_lookup(sehandle, &newcontext, pathname, sb->st_mode) < 0) { fprintf(stderr, "Could not lookup context for %s: %s\n", pathname, strerror(errno)); return -1; } if (strcmp(newcontext, "<<none>>") && strcmp(oldcontext, newcontext)) { if (verbose) printf("Relabeling %s from %s to %s.\n", pathname, oldcontext, newcontext); if (!nochange) { if (lsetfilecon(pathname, newcontext) < 0) { fprintf(stderr, "Could not label %s with %s: %s\n", pathname, newcontext, strerror(errno)); return -1; } } } freecon(oldcontext); freecon(newcontext); return 0; } int restorecon_main(int argc, char **argv) { struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, FCPATH } }; int ch, recurse = 0, ftsflags = FTS_PHYSICAL; progname = argv[0]; do { ch = getopt(argc, argv, "f:nrRv"); if (ch == EOF) break; switch (ch) { case 'f': seopts[0].value = optarg; break; case 'n': nochange = 1; break; case 'r': case 'R': recurse = 1; break; case 'v': verbose = 1; break; default: usage(); } } while (1); argc -= optind; argv += optind; if (!argc) usage(); sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); if (!sehandle) { fprintf(stderr, "Could not load file contexts from %s: %s\n", seopts[0].value, strerror(errno)); return -1; } if (recurse) { FTS *fts; FTSENT *ftsent; fts = fts_open(argv, ftsflags, NULL); if (!fts) { fprintf(stderr, "Could not traverse filesystems (first was %s): %s\n", argv[0], strerror(errno)); return -1; } while ((ftsent = fts_read(fts))) { switch (ftsent->fts_info) { case FTS_DP: break; case FTS_DNR: case FTS_ERR: case FTS_NS: fprintf(stderr, "Could not access %s: %s\n", ftsent->fts_path, strerror(errno)); fts_set(fts, ftsent, FTS_SKIP); break; default: if (restore(ftsent->fts_path, ftsent->fts_statp) < 0) fts_set(fts, ftsent, FTS_SKIP); break; } } } else { int i, rc; struct stat sb; for (i = 0; i < argc; i++) { rc = lstat(argv[i], &sb); if (rc < 0) { fprintf(stderr, "Could not stat %s: %s\n", argv[i], strerror(errno)); continue; } restore(argv[i], &sb); } } return 0; }