1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <getopt.h>
5 #include <errno.h>
6 #include <stdbool.h>
7 #include <fts.h>
8 #include <selinux/android.h>
9 #include <selinux/selinux.h>
10 #include <selinux/label.h>
11
usage(const char * progname)12 static __attribute__ ((__noreturn__)) void usage(const char *progname)
13 {
14 fprintf(stderr,
15 "usage: %s [-vr] [-f file] path\n\n"
16 "Where:\n\t"
17 "-v Validate file_contxts entries against loaded policy.\n\t"
18 "-r Recursively descend directories.\n\t"
19 "-f Optional file_contexts file (defaults to current policy).\n\t"
20 "path Path to check current SHA1 digest against file_contexts entries.\n\n"
21 "This will check the directory selinux.sehash SHA1 digest for "
22 "<path> against\na newly generated digest based on the "
23 "file_context entries for that node\n(using the regx, mode "
24 "and path entries).\n", progname);
25 exit(1);
26 }
27
main(int argc,char ** argv)28 int main(int argc, char **argv)
29 {
30 int opt, fts_flags;
31 size_t i, digest_len;
32 bool status, recurse = false;
33 FTS *fts;
34 FTSENT *ftsent;
35 char *validate = NULL, *file = NULL;
36 char *paths[2] = { NULL, NULL };
37 uint8_t *xattr_digest = NULL;
38 uint8_t *calculated_digest = NULL;
39 char *sha1_buf = NULL;
40
41 struct selabel_handle *hnd;
42 struct selinux_opt selabel_option[] = {
43 { SELABEL_OPT_PATH, file },
44 { SELABEL_OPT_VALIDATE, validate }
45 };
46
47 if (argc < 2)
48 usage(argv[0]);
49
50 while ((opt = getopt(argc, argv, "f:rv")) > 0) {
51 switch (opt) {
52 case 'f':
53 file = optarg;
54 break;
55 case 'r':
56 recurse = true;
57 break;
58 case 'v':
59 validate = (char *)1;
60 break;
61 default:
62 usage(argv[0]);
63 }
64 }
65
66 if (optind >= argc) {
67 fprintf(stderr, "No pathname specified\n");
68 exit(-1);
69 }
70
71 paths[0] = argv[optind];
72
73 #ifdef ANDROID
74 hnd = selinux_android_file_context_handle();
75 #else
76 selabel_option[0].value = file;
77 selabel_option[1].value = validate;
78
79 hnd = selabel_open(SELABEL_CTX_FILE, selabel_option, 2);
80 #endif
81 if (!hnd) {
82 fprintf(stderr, "ERROR: selabel_open - Could not obtain "
83 "handle: %s\n",
84 strerror(errno));
85 return -1;
86 }
87
88 fts_flags = FTS_PHYSICAL | FTS_NOCHDIR;
89 fts = fts_open(paths, fts_flags, NULL);
90 if (!fts) {
91 printf("fts error on %s: %s\n",
92 paths[0], strerror(errno));
93 return -1;
94 }
95
96 while ((ftsent = fts_read(fts)) != NULL) {
97 switch (ftsent->fts_info) {
98 case FTS_DP:
99 continue;
100 case FTS_D: {
101
102 xattr_digest = NULL;
103 calculated_digest = NULL;
104 digest_len = 0;
105
106 status = selabel_get_digests_all_partial_matches(hnd,
107 ftsent->fts_path,
108 &calculated_digest,
109 &xattr_digest,
110 &digest_len);
111
112 sha1_buf = calloc(1, digest_len * 2 + 1);
113 if (!sha1_buf) {
114 fprintf(stderr, "Could not calloc buffer ERROR: %s\n",
115 strerror(errno));
116 return -1;
117 }
118
119 if (status) { /* They match */
120 printf("xattr and file_contexts SHA1 digests match for: %s\n",
121 ftsent->fts_path);
122
123 if (calculated_digest) {
124 for (i = 0; i < digest_len; i++)
125 sprintf((&sha1_buf[i * 2]),
126 "%02x",
127 calculated_digest[i]);
128 printf("SHA1 digest: %s\n", sha1_buf);
129 }
130 } else {
131 if (!calculated_digest) {
132 printf("No SHA1 digest available for: %s\n",
133 ftsent->fts_path);
134 printf("as file_context entry is \"<<none>>\"\n");
135 goto cleanup;
136 }
137
138 printf("The file_context entries for: %s\n",
139 ftsent->fts_path);
140
141 for (i = 0; i < digest_len; i++)
142 sprintf((&sha1_buf[i * 2]), "%02x",
143 calculated_digest[i]);
144 printf("generated SHA1 digest: %s\n", sha1_buf);
145
146 if (!xattr_digest) {
147 printf("however there is no selinux.sehash xattr entry.\n");
148 } else {
149 printf("however it does NOT match the current entry of:\n");
150 for (i = 0; i < digest_len; i++)
151 sprintf((&sha1_buf[i * 2]),
152 "%02x",
153 xattr_digest[i]);
154 printf("%s\n", sha1_buf);
155 }
156 }
157 cleanup:
158 free(xattr_digest);
159 free(calculated_digest);
160 free(sha1_buf);
161 break;
162 }
163 default:
164 break;
165 }
166
167 if (!recurse)
168 break;
169 }
170
171 (void) fts_close(fts);
172 (void) selabel_close(hnd);
173 return 0;
174 }
175