• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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