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 9static size_t digest_len; 10 11static 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 28static 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 60int main(int argc, char **argv) 61{ 62 int backend = 0, rc, opt, i, validate = 0; 63 char *baseonly = NULL, *file = NULL, *digest = (char *)1; 64 char **specfiles = NULL; 65 unsigned char *sha1_digest = NULL; 66 size_t 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 { 96 fprintf(stderr, "Unknown backend: %s\n", 97 optarg); 98 usage(argv[0]); 99 } 100 break; 101 case 'B': 102 baseonly = (char *)1; 103 break; 104 case 'v': 105 validate = 1; 106 break; 107 case 'i': 108 digest = NULL; 109 break; 110 case 'f': 111 file = optarg; 112 break; 113 default: 114 usage(argv[0]); 115 } 116 } 117 118 memset(cmd_buf, 0, sizeof(cmd_buf)); 119 120 selabel_option[0].value = file; 121 selabel_option[1].value = baseonly; 122 selabel_option[2].value = digest; 123 124 hnd = selabel_open(backend, selabel_option, 3); 125 if (!hnd) { 126 switch (errno) { 127 case EOVERFLOW: 128 fprintf(stderr, "ERROR Number of specfiles or specfile" 129 " buffer caused an overflow.\n"); 130 break; 131 default: 132 fprintf(stderr, "ERROR: selabel_open: %s\n", 133 strerror(errno)); 134 } 135 return -1; 136 } 137 138 rc = selabel_digest(hnd, &sha1_digest, &digest_len, &specfiles, 139 &num_specfiles); 140 141 if (rc) { 142 switch (errno) { 143 case EINVAL: 144 fprintf(stderr, "No digest available.\n"); 145 break; 146 default: 147 fprintf(stderr, "selabel_digest ERROR: %s\n", 148 strerror(errno)); 149 } 150 goto err; 151 } 152 153 sha1_buf = malloc(digest_len * 2 + 1); 154 if (!sha1_buf) { 155 fprintf(stderr, "Could not malloc buffer ERROR: %s\n", 156 strerror(errno)); 157 rc = -1; 158 goto err; 159 } 160 161 printf("SHA1 digest: "); 162 for (i = 0; i < digest_len; i++) 163 sprintf(&(sha1_buf[i * 2]), "%02x", sha1_digest[i]); 164 165 printf("%s\n", sha1_buf); 166 printf("calculated using the following specfile(s):\n"); 167 168 if (specfiles) { 169 cmd_ptr = &cmd_buf[0]; 170 sprintf(cmd_ptr, "/usr/bin/cat "); 171 cmd_ptr = &cmd_buf[0] + strlen(cmd_buf); 172 173 for (i = 0; i < num_specfiles; i++) { 174 sprintf(cmd_ptr, "%s ", specfiles[i]); 175 cmd_ptr += strlen(specfiles[i]) + 1; 176 printf("%s\n", specfiles[i]); 177 } 178 sprintf(cmd_ptr, "| /usr/bin/openssl dgst -sha1 -hex"); 179 180 if (validate) 181 rc = run_check_digest(cmd_buf, sha1_buf); 182 } 183 184 free(sha1_buf); 185err: 186 selabel_close(hnd); 187 return rc; 188} 189