#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <sys/stat.h>
#include <selinux/selinux.h>
#include <selinux/label.h>
static __attribute__ ((__noreturn__)) void usage(const char *progname)
{
fprintf(stderr,
"usage: %s [-v] [-r] -p path [-m mode] [-f file] [link...]\n\n"
"Where:\n\t"
"-v Validate file_contxts entries against loaded policy.\n\t"
"-r Use \"raw\" function.\n\t"
"-p Path to check for best match using the link(s) provided.\n\t"
"-m Optional mode (b, c, d, p, l, s or f) Defaults to 0.\n\t"
"-f Optional file containing the specs (defaults to\n\t"
" those used by loaded policy).\n\t"
"link Zero or more links to check against, the order of\n\t"
" precedence for best match is:\n\t\t"
" 1) An exact match for the real path (if no links), or\n\t\t"
" 2) An exact match for any of the links (aliases), or\n\t\t"
" 3) The longest fixed prefix match.\n\n"
"Example:\n\t"
"%s -p /dev/initctl /run/systemd/initctl/fifo\n\t"
" Find best matching context for the specified path using one link.\n\n",
progname, progname);
exit(1);
}
static mode_t string_to_mode(char *s)
{
switch (s[0]) {
case 'b':
return S_IFBLK;
case 'c':
return S_IFCHR;
case 'd':
return S_IFDIR;
case 'p':
return S_IFIFO;
case 'l':
return S_IFLNK;
case 's':
return S_IFSOCK;
case 'f':
return S_IFREG;
};
return 0;
}
int main(int argc, char **argv)
{
int raw = 0, mode = 0, rc, opt, i, num_links, string_len;
char *validate = NULL, *path = NULL, *context = NULL, *file = NULL;
char **links = NULL;
struct selabel_handle *hnd;
struct selinux_opt options[] = {
{ SELABEL_OPT_PATH, file },
{ SELABEL_OPT_VALIDATE, validate }
};
if (argc < 3)
usage(argv[0]);
while ((opt = getopt(argc, argv, "f:vrp:m:")) > 0) {
switch (opt) {
case 'f':
file = optarg;
break;
case 'v':
validate = (char *)1;
break;
case 'r':
raw = 1;
break;
case 'p':
path = optarg;
break;
case 'm':
mode = string_to_mode(optarg);
break;
default:
usage(argv[0]);
}
}
/* Count links */
for (i = optind, num_links = 0; i < argc; i++, num_links++)
;
if (num_links) {
links = calloc(num_links + 1, sizeof(char *));
if (!links) {
fprintf(stderr, "ERROR: calloc failed.\n");
exit(1);
}
for (i = optind, num_links = 0; i < argc; i++, num_links++) {
string_len = strlen(argv[i]) + 1;
links[num_links] = malloc(string_len);
if (!links[num_links]) {
fprintf(stderr, "ERROR: malloc failed.\n");
exit(1);
}
strcpy(links[num_links], argv[i]);
}
}
options[0].value = file;
options[1].value = validate;
hnd = selabel_open(SELABEL_CTX_FILE, options, 2);
if (!hnd) {
fprintf(stderr, "ERROR: selabel_open - Could not obtain "
"handle.\n");
rc = -1;
goto out;
}
if (raw)
rc = selabel_lookup_best_match_raw(hnd, &context, path,
(const char **)links, mode);
else
rc = selabel_lookup_best_match(hnd, &context, path,
(const char **)links, mode);
selabel_close(hnd);
if (rc) {
switch (errno) {
case ENOENT:
fprintf(stderr, "ERROR: selabel_lookup_best_match "
"failed to find a valid context.\n");
break;
case EINVAL:
fprintf(stderr, "ERROR: selabel_lookup_best_match "
"failed to validate context, or path / mode "
"are invalid.\n");
break;
default:
fprintf(stderr, "selabel_lookup_best_match ERROR: "
"%s\n", strerror(errno));
}
} else {
printf("Best match context: %s\n", context);
freecon(context);
}
out:
if (links) {
for (i = 0; links[i]; i++)
free(links[i]);
free(links);
}
return rc;
}