• 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 <selinux/selinux.h>
7 #include <selinux/label.h>
8 
9 static size_t digest_len;
10 
usage(const char * progname)11 static __attribute__ ((__noreturn__)) void usage(const char *progname)
12 {
13 	fprintf(stderr,
14 		"usage: %s -b backend [-d] [-v] [-B] [-i] [-f file]\n\n"
15 		"Where:\n\t"
16 		"-b  The backend - \"file\", \"media\", \"x\", \"db\" or "
17 			"\"prop\"\n\t"
18 		"-v  Run \"cat <specfile_list> | openssl dgst -sha1 -hex\"\n\t"
19 		"    on the list of specfiles to compare the SHA1 digests.\n\t"
20 		"-B  Use base specfiles only (valid for \"-b file\" only).\n\t"
21 		"-i  Do not request a digest.\n\t"
22 		"-f  Optional file containing the specs (defaults to\n\t"
23 		"    those used by loaded policy).\n\n",
24 		progname);
25 	exit(1);
26 }
27 
run_check_digest(char * cmd,char * selabel_digest)28 static int run_check_digest(char *cmd, char *selabel_digest)
29 {
30 	FILE *fp;
31 	char files_digest[128];
32 	char *files_ptr;
33 	int rc = 0;
34 
35 	fp = popen(cmd, "r");
36 	if (!fp) {
37 		printf("Failed to run command line\n");
38 		return -1;
39 	}
40 
41 	/* Only expect one line "(stdin)= x.." so read and find first space */
42 	while (fgets(files_digest, sizeof(files_digest) - 1, fp) != NULL)
43 		;
44 
45 	files_ptr = strstr(files_digest, " ");
46 
47 	rc = strncmp(selabel_digest, files_ptr + 1, digest_len * 2);
48 	if (rc) {
49 		printf("Failed validation:\n\tselabel_digest: %s\n\t"
50 				    "files_digest:   %s\n",
51 				    selabel_digest, files_ptr + 1);
52 	} else {
53 		printf("Passed validation - digest: %s\n", selabel_digest);
54 	}
55 
56 	pclose(fp);
57 	return rc;
58 }
59 
main(int argc,char ** argv)60 int main(int argc, char **argv)
61 {
62 	int backend = 0, rc, opt, validate = 0;
63 	char *baseonly = NULL, *file = NULL, *digest = (char *)1;
64 	char **specfiles = NULL;
65 	unsigned char *sha1_digest = NULL;
66 	size_t i, num_specfiles;
67 
68 	char cmd_buf[4096];
69 	char *cmd_ptr;
70 	char *sha1_buf;
71 
72 	struct selabel_handle *hnd;
73 	struct selinux_opt selabel_option[] = {
74 		{ SELABEL_OPT_PATH, file },
75 		{ SELABEL_OPT_BASEONLY, baseonly },
76 		{ SELABEL_OPT_DIGEST, digest }
77 	};
78 
79 	if (argc < 3)
80 		usage(argv[0]);
81 
82 	while ((opt = getopt(argc, argv, "ib:Bvf:")) > 0) {
83 		switch (opt) {
84 		case 'b':
85 			if (!strcasecmp(optarg, "file")) {
86 				backend = SELABEL_CTX_FILE;
87 			} else if (!strcmp(optarg, "media")) {
88 				backend = SELABEL_CTX_MEDIA;
89 			} else if (!strcmp(optarg, "x")) {
90 				backend = SELABEL_CTX_X;
91 			} else if (!strcmp(optarg, "db")) {
92 				backend = SELABEL_CTX_DB;
93 			} else if (!strcmp(optarg, "prop")) {
94 				backend = SELABEL_CTX_ANDROID_PROP;
95 			} else if (!strcmp(optarg, "service")) {
96 				backend = SELABEL_CTX_ANDROID_SERVICE;
97 			} else {
98 				fprintf(stderr, "Unknown backend: %s\n",
99 								    optarg);
100 				usage(argv[0]);
101 			}
102 			break;
103 		case 'B':
104 			baseonly = (char *)1;
105 			break;
106 		case 'v':
107 			validate = 1;
108 			break;
109 		case 'i':
110 			digest = NULL;
111 			break;
112 		case 'f':
113 			file = optarg;
114 			break;
115 		default:
116 			usage(argv[0]);
117 		}
118 	}
119 
120 	memset(cmd_buf, 0, sizeof(cmd_buf));
121 
122 	selabel_option[0].value = file;
123 	selabel_option[1].value = baseonly;
124 	selabel_option[2].value = digest;
125 
126 	hnd = selabel_open(backend, selabel_option, 3);
127 	if (!hnd) {
128 		switch (errno) {
129 		case EOVERFLOW:
130 			fprintf(stderr, "ERROR Number of specfiles or specfile"
131 					" buffer caused an overflow.\n");
132 			break;
133 		default:
134 			fprintf(stderr, "ERROR: selabel_open: %s\n",
135 						    strerror(errno));
136 		}
137 		return -1;
138 	}
139 
140 	rc = selabel_digest(hnd, &sha1_digest, &digest_len, &specfiles,
141 							    &num_specfiles);
142 
143 	if (rc) {
144 		switch (errno) {
145 		case EINVAL:
146 			fprintf(stderr, "No digest available.\n");
147 			break;
148 		default:
149 			fprintf(stderr, "selabel_digest ERROR: %s\n",
150 						    strerror(errno));
151 		}
152 		goto err;
153 	}
154 
155 	sha1_buf = malloc(digest_len * 2 + 1);
156 	if (!sha1_buf) {
157 		fprintf(stderr, "Could not malloc buffer ERROR: %s\n",
158 						    strerror(errno));
159 		rc = -1;
160 		goto err;
161 	}
162 
163 	printf("SHA1 digest: ");
164 	for (i = 0; i < digest_len; i++)
165 		sprintf(&(sha1_buf[i * 2]), "%02x", sha1_digest[i]);
166 
167 	printf("%s\n", sha1_buf);
168 	printf("calculated using the following specfile(s):\n");
169 
170 	if (specfiles) {
171 		cmd_ptr = &cmd_buf[0];
172 		sprintf(cmd_ptr, "/usr/bin/cat ");
173 		cmd_ptr = &cmd_buf[0] + strlen(cmd_buf);
174 
175 		for (i = 0; i < num_specfiles; i++) {
176 			sprintf(cmd_ptr, "%s ", specfiles[i]);
177 			cmd_ptr += strlen(specfiles[i]) + 1;
178 			printf("%s\n", specfiles[i]);
179 		}
180 		sprintf(cmd_ptr, "| /usr/bin/openssl dgst -sha1 -hex");
181 
182 		if (validate)
183 			rc = run_check_digest(cmd_buf, sha1_buf);
184 	}
185 
186 	free(sha1_buf);
187 err:
188 	selabel_close(hnd);
189 	return rc;
190 }
191