2015-09-30 17:29:20 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <selinux/selinux.h>
|
|
|
|
#include <selinux/label.h>
|
|
|
|
|
|
|
|
static size_t digest_len;
|
|
|
|
|
|
|
|
static void usage(const char *progname)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
2015-10-15 17:29:54 +02:00
|
|
|
"usage: %s -b backend [-d] [-v] [-B] [-i] [-f file]\n\n"
|
2015-09-30 17:29:20 +02:00
|
|
|
"Where:\n\t"
|
|
|
|
"-b The backend - \"file\", \"media\", \"x\", \"db\" or "
|
|
|
|
"\"prop\"\n\t"
|
|
|
|
"-v Run \"cat <specfile_list> | openssl dgst -sha1 -hex\"\n\t"
|
|
|
|
" on the list of specfiles to compare the SHA1 digests.\n\t"
|
|
|
|
"-B Use base specfiles only (valid for \"-b file\" only).\n\t"
|
2015-10-15 17:29:54 +02:00
|
|
|
"-i Do not request a digest.\n\t"
|
2015-09-30 17:29:20 +02:00
|
|
|
"-f Optional file containing the specs (defaults to\n\t"
|
|
|
|
" those used by loaded policy).\n\n",
|
|
|
|
progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int run_check_digest(char *cmd, char *selabel_digest)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
char files_digest[128];
|
|
|
|
char *files_ptr;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
fp = popen(cmd, "r");
|
|
|
|
if (!fp) {
|
|
|
|
printf("Failed to run command line\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Only expect one line "(stdin)= x.." so read and find first space */
|
|
|
|
while (fgets(files_digest, sizeof(files_digest) - 1, fp) != NULL)
|
|
|
|
;
|
|
|
|
|
|
|
|
files_ptr = strstr(files_digest, " ");
|
|
|
|
|
|
|
|
rc = strncmp(selabel_digest, files_ptr + 1, digest_len * 2);
|
|
|
|
if (rc) {
|
|
|
|
printf("Failed validation:\n\tselabel_digest: %s\n\t"
|
|
|
|
"files_digest: %s\n",
|
|
|
|
selabel_digest, files_ptr + 1);
|
|
|
|
} else {
|
|
|
|
printf("Passed validation - digest: %s\n", selabel_digest);
|
|
|
|
}
|
|
|
|
|
|
|
|
pclose(fp);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2016-09-25 14:16:07 +02:00
|
|
|
int backend = 0, rc, opt, validate = 0;
|
2015-10-15 17:29:54 +02:00
|
|
|
char *baseonly = NULL, *file = NULL, *digest = (char *)1;
|
2015-09-30 17:29:20 +02:00
|
|
|
char **specfiles = NULL;
|
|
|
|
unsigned char *sha1_digest = NULL;
|
2016-09-25 14:16:07 +02:00
|
|
|
size_t i, num_specfiles;
|
2015-09-30 17:29:20 +02:00
|
|
|
|
|
|
|
char cmd_buf[4096];
|
|
|
|
char *cmd_ptr;
|
|
|
|
char *sha1_buf;
|
|
|
|
|
|
|
|
struct selabel_handle *hnd;
|
|
|
|
struct selinux_opt selabel_option[] = {
|
|
|
|
{ SELABEL_OPT_PATH, file },
|
|
|
|
{ SELABEL_OPT_BASEONLY, baseonly },
|
2015-10-15 17:29:54 +02:00
|
|
|
{ SELABEL_OPT_DIGEST, digest }
|
2015-09-30 17:29:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
if (argc < 3)
|
|
|
|
usage(argv[0]);
|
|
|
|
|
2015-10-15 17:29:54 +02:00
|
|
|
while ((opt = getopt(argc, argv, "ib:Bvf:")) > 0) {
|
2015-09-30 17:29:20 +02:00
|
|
|
switch (opt) {
|
|
|
|
case 'b':
|
|
|
|
if (!strcasecmp(optarg, "file")) {
|
|
|
|
backend = SELABEL_CTX_FILE;
|
|
|
|
} else if (!strcmp(optarg, "media")) {
|
|
|
|
backend = SELABEL_CTX_MEDIA;
|
|
|
|
} else if (!strcmp(optarg, "x")) {
|
|
|
|
backend = SELABEL_CTX_X;
|
|
|
|
} else if (!strcmp(optarg, "db")) {
|
|
|
|
backend = SELABEL_CTX_DB;
|
|
|
|
} else if (!strcmp(optarg, "prop")) {
|
|
|
|
backend = SELABEL_CTX_ANDROID_PROP;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Unknown backend: %s\n",
|
|
|
|
optarg);
|
|
|
|
usage(argv[0]);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'B':
|
|
|
|
baseonly = (char *)1;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
validate = 1;
|
|
|
|
break;
|
2015-10-15 17:29:54 +02:00
|
|
|
case 'i':
|
|
|
|
digest = NULL;
|
|
|
|
break;
|
2015-09-30 17:29:20 +02:00
|
|
|
case 'f':
|
|
|
|
file = optarg;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage(argv[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(cmd_buf, 0, sizeof(cmd_buf));
|
|
|
|
|
|
|
|
selabel_option[0].value = file;
|
|
|
|
selabel_option[1].value = baseonly;
|
2015-10-15 17:29:54 +02:00
|
|
|
selabel_option[2].value = digest;
|
2015-09-30 17:29:20 +02:00
|
|
|
|
|
|
|
hnd = selabel_open(backend, selabel_option, 3);
|
|
|
|
if (!hnd) {
|
|
|
|
switch (errno) {
|
|
|
|
case EOVERFLOW:
|
|
|
|
fprintf(stderr, "ERROR Number of specfiles or specfile"
|
|
|
|
" buffer caused an overflow.\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "ERROR: selabel_open: %s\n",
|
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = selabel_digest(hnd, &sha1_digest, &digest_len, &specfiles,
|
|
|
|
&num_specfiles);
|
|
|
|
|
|
|
|
if (rc) {
|
|
|
|
switch (errno) {
|
|
|
|
case EINVAL:
|
|
|
|
fprintf(stderr, "No digest available.\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "selabel_digest ERROR: %s\n",
|
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
sha1_buf = malloc(digest_len * 2 + 1);
|
|
|
|
if (!sha1_buf) {
|
|
|
|
fprintf(stderr, "Could not malloc buffer ERROR: %s\n",
|
|
|
|
strerror(errno));
|
|
|
|
rc = -1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("SHA1 digest: ");
|
|
|
|
for (i = 0; i < digest_len; i++)
|
|
|
|
sprintf(&(sha1_buf[i * 2]), "%02x", sha1_digest[i]);
|
|
|
|
|
|
|
|
printf("%s\n", sha1_buf);
|
|
|
|
printf("calculated using the following specfile(s):\n");
|
|
|
|
|
|
|
|
if (specfiles) {
|
|
|
|
cmd_ptr = &cmd_buf[0];
|
|
|
|
sprintf(cmd_ptr, "/usr/bin/cat ");
|
|
|
|
cmd_ptr = &cmd_buf[0] + strlen(cmd_buf);
|
|
|
|
|
|
|
|
for (i = 0; i < num_specfiles; i++) {
|
|
|
|
sprintf(cmd_ptr, "%s ", specfiles[i]);
|
|
|
|
cmd_ptr += strlen(specfiles[i]) + 1;
|
|
|
|
printf("%s\n", specfiles[i]);
|
|
|
|
}
|
|
|
|
sprintf(cmd_ptr, "| /usr/bin/openssl dgst -sha1 -hex");
|
|
|
|
|
|
|
|
if (validate)
|
|
|
|
rc = run_check_digest(cmd_buf, sha1_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(sha1_buf);
|
|
|
|
err:
|
|
|
|
selabel_close(hnd);
|
|
|
|
return rc;
|
|
|
|
}
|