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.\n");
81 return -1;
82 }
83
84 fts_flags = FTS_PHYSICAL | FTS_NOCHDIR;
85 fts = fts_open(paths, fts_flags, NULL);
86 if (!fts) {
87 printf("fts error on %s: %s\n",
88 paths[0], strerror(errno));
89 return -1;
90 }
91
92 while ((ftsent = fts_read(fts)) != NULL) {
93 switch (ftsent->fts_info) {
94 case FTS_DP:
95 continue;
96 case FTS_D: {
97
98 xattr_digest = NULL;
99 calculated_digest = NULL;
100 digest_len = 0;
101
102 status = selabel_get_digests_all_partial_matches(hnd,
103 ftsent->fts_path,
104 &calculated_digest,
105 &xattr_digest,
106 &digest_len);
107
108 sha1_buf = calloc(1, digest_len * 2 + 1);
109 if (!sha1_buf) {
110 fprintf(stderr, "Could not calloc buffer ERROR: %s\n",
111 strerror(errno));
112 return -1;
113 }
114
115 if (status) { /* They match */
116 printf("xattr and file_contexts SHA1 digests match for: %s\n",
117 ftsent->fts_path);
118
119 if (calculated_digest) {
120 for (i = 0; i < digest_len; i++)
121 sprintf((&sha1_buf[i * 2]),
122 "%02x",
123 calculated_digest[i]);
124 printf("SHA1 digest: %s\n", sha1_buf);
125 }
126 } else {
127 if (!calculated_digest) {
128 printf("No SHA1 digest available for: %s\n",
129 ftsent->fts_path);
130 printf("as file_context entry is \"<<none>>\"\n");
131 goto cleanup;
132 }
133
134 printf("The file_context entries for: %s\n",
135 ftsent->fts_path);
136
137 for (i = 0; i < digest_len; i++)
138 sprintf((&sha1_buf[i * 2]), "%02x",
139 calculated_digest[i]);
140 printf("generated SHA1 digest: %s\n", sha1_buf);
141
142 if (!xattr_digest) {
143 printf("however there is no selinux.sehash xattr entry.\n");
144 } else {
145 printf("however it does NOT match the current entry of:\n");
146 for (i = 0; i < digest_len; i++)
147 sprintf((&sha1_buf[i * 2]),
148 "%02x",
149 xattr_digest[i]);
150 printf("%s\n", sha1_buf);
151 }
152 }
153 cleanup:
154 free(xattr_digest);
155 free(calculated_digest);
156 free(sha1_buf);
157 break;
158 }
159 default:
160 break;
161 }
162
163 if (!recurse)
164 break;
165 }
166
167 (void) fts_close(fts);
168 (void) selabel_close(hnd);
169 return 0;
170 }
171