selinux/libselinux/utils/selabel_lookup_best_match.c
Christian Göttsche 0c407c3f1d libselinux/utils: print errno on failure
Print error description on failure after functions known to set errno.

Also mention the library function name in getenforce, policyvers and
setenforce instead of the program name twice.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
2022-05-16 10:31:15 -04:00

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;
}