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