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