1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <stdbool.h>
#include <fts.h>
#include <selinux/selinux.h>
#include <selinux/label.h>
#include "../src/label_file.h"
static __attribute__ ((__noreturn__)) void usage(const char *progname)
{
fprintf(stderr,
"usage: %s [-vr] [-f file] path\n\n"
"Where:\n\t"
"-v Validate file_contxts entries against loaded policy.\n\t"
"-r Recursively descend directories.\n\t"
"-f Optional file_contexts file (defaults to current policy).\n\t"
"path Path to check current SHA1 digest against file_contexts entries.\n\n"
"This will check the directory selinux.sehash SHA1 digest for "
"<path> against\na newly generated digest based on the "
"file_context entries for that node\n(using the regx, mode "
"and path entries).\n", progname);
exit(1);
}
int main(int argc, char **argv)
{
int opt, fts_flags;
size_t i, digest_len;
bool status, recurse = false;
FTS *fts;
FTSENT *ftsent;
char *validate = NULL, *file = NULL;
char *paths[2] = { NULL, NULL };
uint8_t *xattr_digest = NULL;
uint8_t *calculated_digest = NULL;
char *sha1_buf = NULL;
struct selabel_handle *hnd;
struct selinux_opt selabel_option[] = {
{ SELABEL_OPT_PATH, file },
{ SELABEL_OPT_VALIDATE, validate }
};
if (argc < 2)
usage(argv[0]);
while ((opt = getopt(argc, argv, "f:rv")) > 0) {
switch (opt) {
case 'f':
file = optarg;
break;
case 'r':
recurse = true;
break;
case 'v':
validate = (char *)1;
break;
default:
usage(argv[0]);
}
}
if (optind >= argc) {
fprintf(stderr, "No pathname specified\n");
exit(-1);
}
paths[0] = argv[optind];
selabel_option[0].value = file;
selabel_option[1].value = validate;
hnd = selabel_open(SELABEL_CTX_FILE, selabel_option, 2);
if (!hnd) {
fprintf(stderr, "ERROR: selabel_open - Could not obtain "
"handle.\n");
return -1;
}
fts_flags = FTS_PHYSICAL | FTS_NOCHDIR;
fts = fts_open(paths, fts_flags, NULL);
if (!fts) {
printf("fts error on %s: %s\n",
paths[0], strerror(errno));
return -1;
}
while ((ftsent = fts_read(fts)) != NULL) {
switch (ftsent->fts_info) {
case FTS_DP:
continue;
case FTS_D: {
xattr_digest = NULL;
calculated_digest = NULL;
digest_len = 0;
status = selabel_get_digests_all_partial_matches(hnd,
ftsent->fts_path,
&calculated_digest,
&xattr_digest,
&digest_len);
sha1_buf = calloc(1, digest_len * 2 + 1);
if (!sha1_buf) {
fprintf(stderr, "Could not calloc buffer ERROR: %s\n",
strerror(errno));
return -1;
}
if (status) { /* They match */
printf("xattr and file_contexts SHA1 digests match for: %s\n",
ftsent->fts_path);
if (calculated_digest) {
for (i = 0; i < digest_len; i++)
sprintf((&sha1_buf[i * 2]),
"%02x",
calculated_digest[i]);
printf("SHA1 digest: %s\n", sha1_buf);
}
} else {
if (!calculated_digest) {
printf("No SHA1 digest available for: %s\n",
ftsent->fts_path);
printf("as file_context entry is \"<<none>>\"\n");
break;
}
printf("The file_context entries for: %s\n",
ftsent->fts_path);
for (i = 0; i < digest_len; i++)
sprintf((&sha1_buf[i * 2]), "%02x",
calculated_digest[i]);
printf("generated SHA1 digest: %s\n", sha1_buf);
if (!xattr_digest) {
printf("however there is no selinux.sehash xattr entry.\n");
} else {
printf("however it does NOT match the current entry of:\n");
for (i = 0; i < digest_len; i++)
sprintf((&sha1_buf[i * 2]),
"%02x",
xattr_digest[i]);
printf("%s\n", sha1_buf);
}
free(xattr_digest);
free(calculated_digest);
free(sha1_buf);
}
break;
}
default:
break;
}
if (!recurse)
break;
}
(void) fts_close(fts);
(void) selabel_close(hnd);
return 0;
}
|