• 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/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