restorecon.c revision 8290d1083ec7eee3f32265012f5d6be2774c4afc
18290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley#include <unistd.h>
28290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley#include <stdio.h>
38290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley#include <stdlib.h>
48290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley#include <errno.h>
58290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley#include <sys/types.h>
68290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley#include <sys/stat.h>
78290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley#include <fts.h>
88290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley#include <selinux/selinux.h>
98290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley#include <selinux/label.h>
108290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
118290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley#define FCPATH "/file_contexts"
128290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
138290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalleystatic struct selabel_handle *sehandle;
148290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalleystatic const char *progname;
158290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalleystatic int nochange;
168290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalleystatic int verbose;
178290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
188290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalleystatic void usage(void)
198290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley{
208290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    fprintf(stderr, "usage:  %s [-f file_contexts] [-nrRv] pathname...\n", progname);
218290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    exit(1);
228290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley}
238290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
248290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalleystatic int restore(const char *pathname, const struct stat *sb)
258290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley{
268290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    char *oldcontext, *newcontext;
278290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
288290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    if (lgetfilecon(pathname, &oldcontext) < 0) {
298290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        fprintf(stderr, "Could not get context of %s:  %s\n",
308290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                pathname, strerror(errno));
318290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        return -1;
328290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    }
338290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    if (selabel_lookup(sehandle, &newcontext, pathname, sb->st_mode) < 0) {
348290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        fprintf(stderr, "Could not lookup context for %s:  %s\n", pathname,
358290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                strerror(errno));
368290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        return -1;
378290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    }
388290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    if (strcmp(newcontext, "<<none>>") &&
398290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        strcmp(oldcontext, newcontext)) {
408290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        if (verbose)
418290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            printf("Relabeling %s from %s to %s.\n", pathname, oldcontext, newcontext);
428290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        if (!nochange) {
438290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            if (lsetfilecon(pathname, newcontext) < 0) {
448290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                fprintf(stderr, "Could not label %s with %s:  %s\n",
458290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                        pathname, newcontext, strerror(errno));
468290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                return -1;
478290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            }
488290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        }
498290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    }
508290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    freecon(oldcontext);
518290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    freecon(newcontext);
528290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    return 0;
538290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley}
548290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
558290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalleyint restorecon_main(int argc, char **argv)
568290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley{
578290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    struct selinux_opt seopts[] = {
588290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        { SELABEL_OPT_PATH, FCPATH }
598290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    };
608290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    int ch, recurse = 0, ftsflags = FTS_PHYSICAL;
618290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
628290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    progname = argv[0];
638290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
648290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    do {
658290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        ch = getopt(argc, argv, "f:nrRv");
668290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        if (ch == EOF)
678290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            break;
688290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        switch (ch) {
698290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        case 'f':
708290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            seopts[0].value = optarg;
718290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            break;
728290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        case 'n':
738290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            nochange = 1;
748290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            break;
758290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        case 'r':
768290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        case 'R':
778290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            recurse = 1;
788290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            break;
798290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        case 'v':
808290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            verbose = 1;
818290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            break;
828290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        default:
838290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            usage();
848290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        }
858290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    } while (1);
868290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
878290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    argc -= optind;
888290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    argv += optind;
898290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    if (!argc)
908290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        usage();
918290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
928290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
938290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    if (!sehandle) {
948290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        fprintf(stderr, "Could not load file contexts from %s:  %s\n", seopts[0].value,
958290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                strerror(errno));
968290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        return -1;
978290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    }
988290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
998290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    if (recurse) {
1008290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        FTS *fts;
1018290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        FTSENT *ftsent;
1028290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        fts = fts_open(argv, ftsflags, NULL);
1038290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        if (!fts) {
1048290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            fprintf(stderr, "Could not traverse filesystems (first was %s):  %s\n",
1058290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                    argv[0], strerror(errno));
1068290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            return -1;
1078290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        }
1088290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        while ((ftsent = fts_read(fts))) {
1098290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            switch (ftsent->fts_info) {
1108290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            case FTS_DP:
1118290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                break;
1128290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            case FTS_DNR:
1138290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            case FTS_ERR:
1148290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            case FTS_NS:
1158290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                fprintf(stderr, "Could not access %s:  %s\n", ftsent->fts_path,
1168290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                        strerror(errno));
1178290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                fts_set(fts, ftsent, FTS_SKIP);
1188290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                break;
1198290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            default:
1208290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                if (restore(ftsent->fts_path, ftsent->fts_statp) < 0)
1218290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                    fts_set(fts, ftsent, FTS_SKIP);
1228290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                break;
1238290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            }
1248290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        }
1258290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    } else {
1268290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        int i, rc;
1278290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        struct stat sb;
1288290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
1298290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        for (i = 0; i < argc; i++) {
1308290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            rc = lstat(argv[i], &sb);
1318290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            if (rc < 0) {
1328290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                fprintf(stderr, "Could not stat %s:  %s\n", argv[i],
1338290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                        strerror(errno));
1348290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley                continue;
1358290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            }
1368290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley            restore(argv[i], &sb);
1378290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley        }
1388290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    }
1398290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley
1408290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley    return 0;
1418290d1083ec7eee3f32265012f5d6be2774c4afcStephen Smalley}
142