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