16cd6a6acSopenharmony_ci#include <stdio.h> 26cd6a6acSopenharmony_ci#include <stdlib.h> 36cd6a6acSopenharmony_ci#include <string.h> 46cd6a6acSopenharmony_ci#include <getopt.h> 56cd6a6acSopenharmony_ci#include <errno.h> 66cd6a6acSopenharmony_ci#include <selinux/selinux.h> 76cd6a6acSopenharmony_ci#include <selinux/label.h> 86cd6a6acSopenharmony_ci 96cd6a6acSopenharmony_cistatic size_t digest_len; 106cd6a6acSopenharmony_ci 116cd6a6acSopenharmony_cistatic __attribute__ ((__noreturn__)) void usage(const char *progname) 126cd6a6acSopenharmony_ci{ 136cd6a6acSopenharmony_ci fprintf(stderr, 146cd6a6acSopenharmony_ci "usage: %s -b backend [-d] [-v] [-B] [-i] [-f file]\n\n" 156cd6a6acSopenharmony_ci "Where:\n\t" 166cd6a6acSopenharmony_ci "-b The backend - \"file\", \"media\", \"x\", \"db\" or " 176cd6a6acSopenharmony_ci "\"prop\"\n\t" 186cd6a6acSopenharmony_ci "-v Run \"cat <specfile_list> | openssl dgst -sha1 -hex\"\n\t" 196cd6a6acSopenharmony_ci " on the list of specfiles to compare the SHA1 digests.\n\t" 206cd6a6acSopenharmony_ci "-B Use base specfiles only (valid for \"-b file\" only).\n\t" 216cd6a6acSopenharmony_ci "-i Do not request a digest.\n\t" 226cd6a6acSopenharmony_ci "-f Optional file containing the specs (defaults to\n\t" 236cd6a6acSopenharmony_ci " those used by loaded policy).\n\n", 246cd6a6acSopenharmony_ci progname); 256cd6a6acSopenharmony_ci exit(1); 266cd6a6acSopenharmony_ci} 276cd6a6acSopenharmony_ci 286cd6a6acSopenharmony_cistatic int run_check_digest(char *cmd, char *selabel_digest) 296cd6a6acSopenharmony_ci{ 306cd6a6acSopenharmony_ci FILE *fp; 316cd6a6acSopenharmony_ci char files_digest[128]; 326cd6a6acSopenharmony_ci char *files_ptr; 336cd6a6acSopenharmony_ci int rc = 0; 346cd6a6acSopenharmony_ci 356cd6a6acSopenharmony_ci fp = popen(cmd, "r"); 366cd6a6acSopenharmony_ci if (!fp) { 376cd6a6acSopenharmony_ci fprintf(stderr, "Failed to run command '%s': %s\n", cmd, strerror(errno)); 386cd6a6acSopenharmony_ci return -1; 396cd6a6acSopenharmony_ci } 406cd6a6acSopenharmony_ci 416cd6a6acSopenharmony_ci /* Only expect one line "(stdin)= x.." so read and find first space */ 426cd6a6acSopenharmony_ci while (fgets(files_digest, sizeof(files_digest) - 1, fp) != NULL) 436cd6a6acSopenharmony_ci ; 446cd6a6acSopenharmony_ci 456cd6a6acSopenharmony_ci files_ptr = strstr(files_digest, " "); 466cd6a6acSopenharmony_ci 476cd6a6acSopenharmony_ci rc = strncmp(selabel_digest, files_ptr + 1, digest_len * 2); 486cd6a6acSopenharmony_ci if (rc) { 496cd6a6acSopenharmony_ci printf("Failed validation:\n\tselabel_digest: %s\n\t" 506cd6a6acSopenharmony_ci "files_digest: %s\n", 516cd6a6acSopenharmony_ci selabel_digest, files_ptr + 1); 526cd6a6acSopenharmony_ci } else { 536cd6a6acSopenharmony_ci printf("Passed validation - digest: %s\n", selabel_digest); 546cd6a6acSopenharmony_ci } 556cd6a6acSopenharmony_ci 566cd6a6acSopenharmony_ci pclose(fp); 576cd6a6acSopenharmony_ci return rc; 586cd6a6acSopenharmony_ci} 596cd6a6acSopenharmony_ci 606cd6a6acSopenharmony_ciint main(int argc, char **argv) 616cd6a6acSopenharmony_ci{ 626cd6a6acSopenharmony_ci int backend = 0, rc, opt, validate = 0; 636cd6a6acSopenharmony_ci char *baseonly = NULL, *file = NULL, *digest = (char *)1; 646cd6a6acSopenharmony_ci char **specfiles = NULL; 656cd6a6acSopenharmony_ci unsigned char *sha1_digest = NULL; 666cd6a6acSopenharmony_ci size_t i, num_specfiles; 676cd6a6acSopenharmony_ci 686cd6a6acSopenharmony_ci char cmd_buf[4096]; 696cd6a6acSopenharmony_ci char *cmd_ptr; 706cd6a6acSopenharmony_ci char *sha1_buf; 716cd6a6acSopenharmony_ci 726cd6a6acSopenharmony_ci struct selabel_handle *hnd; 736cd6a6acSopenharmony_ci struct selinux_opt selabel_option[] = { 746cd6a6acSopenharmony_ci { SELABEL_OPT_PATH, file }, 756cd6a6acSopenharmony_ci { SELABEL_OPT_BASEONLY, baseonly }, 766cd6a6acSopenharmony_ci { SELABEL_OPT_DIGEST, digest } 776cd6a6acSopenharmony_ci }; 786cd6a6acSopenharmony_ci 796cd6a6acSopenharmony_ci if (argc < 3) 806cd6a6acSopenharmony_ci usage(argv[0]); 816cd6a6acSopenharmony_ci 826cd6a6acSopenharmony_ci while ((opt = getopt(argc, argv, "ib:Bvf:")) > 0) { 836cd6a6acSopenharmony_ci switch (opt) { 846cd6a6acSopenharmony_ci case 'b': 856cd6a6acSopenharmony_ci if (!strcasecmp(optarg, "file")) { 866cd6a6acSopenharmony_ci backend = SELABEL_CTX_FILE; 876cd6a6acSopenharmony_ci } else if (!strcmp(optarg, "media")) { 886cd6a6acSopenharmony_ci backend = SELABEL_CTX_MEDIA; 896cd6a6acSopenharmony_ci } else if (!strcmp(optarg, "x")) { 906cd6a6acSopenharmony_ci backend = SELABEL_CTX_X; 916cd6a6acSopenharmony_ci } else if (!strcmp(optarg, "db")) { 926cd6a6acSopenharmony_ci backend = SELABEL_CTX_DB; 936cd6a6acSopenharmony_ci } else if (!strcmp(optarg, "prop")) { 946cd6a6acSopenharmony_ci backend = SELABEL_CTX_ANDROID_PROP; 956cd6a6acSopenharmony_ci } else if (!strcmp(optarg, "service")) { 966cd6a6acSopenharmony_ci backend = SELABEL_CTX_ANDROID_SERVICE; 976cd6a6acSopenharmony_ci } else { 986cd6a6acSopenharmony_ci fprintf(stderr, "Unknown backend: %s\n", 996cd6a6acSopenharmony_ci optarg); 1006cd6a6acSopenharmony_ci usage(argv[0]); 1016cd6a6acSopenharmony_ci } 1026cd6a6acSopenharmony_ci break; 1036cd6a6acSopenharmony_ci case 'B': 1046cd6a6acSopenharmony_ci baseonly = (char *)1; 1056cd6a6acSopenharmony_ci break; 1066cd6a6acSopenharmony_ci case 'v': 1076cd6a6acSopenharmony_ci validate = 1; 1086cd6a6acSopenharmony_ci break; 1096cd6a6acSopenharmony_ci case 'i': 1106cd6a6acSopenharmony_ci digest = NULL; 1116cd6a6acSopenharmony_ci break; 1126cd6a6acSopenharmony_ci case 'f': 1136cd6a6acSopenharmony_ci file = optarg; 1146cd6a6acSopenharmony_ci break; 1156cd6a6acSopenharmony_ci default: 1166cd6a6acSopenharmony_ci usage(argv[0]); 1176cd6a6acSopenharmony_ci } 1186cd6a6acSopenharmony_ci } 1196cd6a6acSopenharmony_ci 1206cd6a6acSopenharmony_ci memset(cmd_buf, 0, sizeof(cmd_buf)); 1216cd6a6acSopenharmony_ci 1226cd6a6acSopenharmony_ci selabel_option[0].value = file; 1236cd6a6acSopenharmony_ci selabel_option[1].value = baseonly; 1246cd6a6acSopenharmony_ci selabel_option[2].value = digest; 1256cd6a6acSopenharmony_ci 1266cd6a6acSopenharmony_ci hnd = selabel_open(backend, selabel_option, 3); 1276cd6a6acSopenharmony_ci if (!hnd) { 1286cd6a6acSopenharmony_ci switch (errno) { 1296cd6a6acSopenharmony_ci case EOVERFLOW: 1306cd6a6acSopenharmony_ci fprintf(stderr, "ERROR Number of specfiles or specfile" 1316cd6a6acSopenharmony_ci " buffer caused an overflow.\n"); 1326cd6a6acSopenharmony_ci break; 1336cd6a6acSopenharmony_ci default: 1346cd6a6acSopenharmony_ci fprintf(stderr, "ERROR: selabel_open: %s\n", 1356cd6a6acSopenharmony_ci strerror(errno)); 1366cd6a6acSopenharmony_ci } 1376cd6a6acSopenharmony_ci return -1; 1386cd6a6acSopenharmony_ci } 1396cd6a6acSopenharmony_ci 1406cd6a6acSopenharmony_ci rc = selabel_digest(hnd, &sha1_digest, &digest_len, &specfiles, 1416cd6a6acSopenharmony_ci &num_specfiles); 1426cd6a6acSopenharmony_ci 1436cd6a6acSopenharmony_ci if (rc) { 1446cd6a6acSopenharmony_ci switch (errno) { 1456cd6a6acSopenharmony_ci case EINVAL: 1466cd6a6acSopenharmony_ci fprintf(stderr, "No digest available.\n"); 1476cd6a6acSopenharmony_ci break; 1486cd6a6acSopenharmony_ci default: 1496cd6a6acSopenharmony_ci fprintf(stderr, "selabel_digest ERROR: %s\n", 1506cd6a6acSopenharmony_ci strerror(errno)); 1516cd6a6acSopenharmony_ci } 1526cd6a6acSopenharmony_ci goto err; 1536cd6a6acSopenharmony_ci } 1546cd6a6acSopenharmony_ci 1556cd6a6acSopenharmony_ci sha1_buf = malloc(digest_len * 2 + 1); 1566cd6a6acSopenharmony_ci if (!sha1_buf) { 1576cd6a6acSopenharmony_ci fprintf(stderr, "Could not malloc buffer ERROR: %s\n", 1586cd6a6acSopenharmony_ci strerror(errno)); 1596cd6a6acSopenharmony_ci rc = -1; 1606cd6a6acSopenharmony_ci goto err; 1616cd6a6acSopenharmony_ci } 1626cd6a6acSopenharmony_ci 1636cd6a6acSopenharmony_ci printf("SHA1 digest: "); 1646cd6a6acSopenharmony_ci for (i = 0; i < digest_len; i++) 1656cd6a6acSopenharmony_ci sprintf(&(sha1_buf[i * 2]), "%02x", sha1_digest[i]); 1666cd6a6acSopenharmony_ci 1676cd6a6acSopenharmony_ci printf("%s\n", sha1_buf); 1686cd6a6acSopenharmony_ci printf("calculated using the following specfile(s):\n"); 1696cd6a6acSopenharmony_ci 1706cd6a6acSopenharmony_ci if (specfiles) { 1716cd6a6acSopenharmony_ci cmd_ptr = &cmd_buf[0]; 1726cd6a6acSopenharmony_ci sprintf(cmd_ptr, "/usr/bin/cat "); 1736cd6a6acSopenharmony_ci cmd_ptr = &cmd_buf[0] + strlen(cmd_buf); 1746cd6a6acSopenharmony_ci 1756cd6a6acSopenharmony_ci for (i = 0; i < num_specfiles; i++) { 1766cd6a6acSopenharmony_ci sprintf(cmd_ptr, "%s ", specfiles[i]); 1776cd6a6acSopenharmony_ci cmd_ptr += strlen(specfiles[i]) + 1; 1786cd6a6acSopenharmony_ci printf("%s\n", specfiles[i]); 1796cd6a6acSopenharmony_ci } 1806cd6a6acSopenharmony_ci sprintf(cmd_ptr, "| /usr/bin/openssl dgst -sha1 -hex"); 1816cd6a6acSopenharmony_ci 1826cd6a6acSopenharmony_ci if (validate) 1836cd6a6acSopenharmony_ci rc = run_check_digest(cmd_buf, sha1_buf); 1846cd6a6acSopenharmony_ci } 1856cd6a6acSopenharmony_ci 1866cd6a6acSopenharmony_ci free(sha1_buf); 1876cd6a6acSopenharmony_cierr: 1886cd6a6acSopenharmony_ci selabel_close(hnd); 1896cd6a6acSopenharmony_ci return rc; 1906cd6a6acSopenharmony_ci} 191