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