164 lines
3.7 KiB
C
164 lines
3.7 KiB
C
#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: %s\n",
|
|
strerror(errno));
|
|
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;
|
|
}
|