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