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