libselinux: Add selabel partial and best match APIs

Add support for new API functions selabel_partial_match and
selabel_lookup_best_match ported from the Android libselinux
fork.

Add supporting man(3) pages and test utilities: selabel_lookup,
selabel_lookup_best_match and selabel_partial_match.

Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
This commit is contained in:
Richard Haines 2015-05-06 16:11:03 +01:00 committed by Stephen Smalley
parent 9ab426eea1
commit e7f970ffd1
11 changed files with 766 additions and 52 deletions

View File

@ -6,6 +6,7 @@
#ifndef _SELABEL_H_
#define _SELABEL_H_
#include <stdbool.h>
#include <sys/types.h>
#include <selinux/selinux.h>
@ -97,6 +98,13 @@ int selabel_lookup(struct selabel_handle *handle, char **con,
int selabel_lookup_raw(struct selabel_handle *handle, char **con,
const char *key, int type);
bool selabel_partial_match(struct selabel_handle *handle, const char *key);
int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
const char *key, const char **aliases, int type);
int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
const char *key, const char **aliases, int type);
/**
* selabel_stats - log labeling operation statistics.
* @handle: specifies backend instance to query

View File

@ -0,0 +1,100 @@
.TH "selabel_lookup_best_match" "3" "05 May 2015" "Security Enhanced Linux" "SELinux API documentation"
.SH "NAME"
selabel_lookup_best_match \- obtain a best match SELinux security
context \- Only supported on file backend.
.
.SH "SYNOPSIS"
.B #include <selinux/selinux.h>
.br
.B #include <selinux/label.h>
.sp
.BI "int selabel_lookup_best_match(struct selabel_handle *" hnd ,
.in +\w'int selabel_lookup_best_match('u
.BI "char **" context ,
.br
.BI "const char *" key ,
.br
.BI "const char **" links ,
.br
.BI "int " type ");"
.in
.sp
.BI "int selabel_lookup_best_match_raw(struct selabel_handle *" hnd ,
.in +\w'int selabel_lookup_best_match_raw('u
.BI "char **" context ,
.br
.BI "const char *" key ,
.br
.BI "const char **" links ,
.br
.BI "int " type ");"
.in
.
.SH "DESCRIPTION"
.BR selabel_lookup_best_match ()
performs a best match lookup operation on the handle
.IR hnd ,
returning the result in the memory pointed to by
.IR context ,
which must be freed by the caller using
.BR freecon (3).
The \fIkey\fR parameter is a file path to check for best match using zero or
more \fIlink\fR (aliases) parameters. The order of precedence for best match is:
.RS
.IP "1." 4
An exact match for the real path (\fIkey\fR) or
.IP "2." 4
An exact match for any of the \fIlink\fRs (aliases), or
.IP "3." 4
The longest fixed prefix match.
.RE
.sp
The \fItype\fR parameter is an optional file \fImode\fR argument that should
be set to the mode bits of the file, as determined by \fBlstat\fR(2).
\fImode\fR may be zero, however full matching may not occur.
.BR selabel_lookup_best_match_raw ()
behaves identically to
.BR selabel_lookup_best_match ()
but does not perform context translation.
.
.SH "RETURN VALUE"
On success, zero is returned. On error, \-1 is returned and
.I errno
is set appropriately.
.
.SH "ERRORS"
.TP
.B ENOENT
No context corresponding to the input
.I key
and
.I type
was found.
.TP
.B EINVAL
The
.I key
and/or
.I type
inputs are invalid, or the context being returned failed validation.
.TP
.B ENOMEM
An attempt to allocate memory failed.
.sp
.SH "NOTES"
Example usage - When a service creates a device node, it may also create one
or more symlinks to the device node. These symlinks may be the only stable
name for the device, e.g. if the partition is dynamically assigned.
The file label backend supports this by looking up the "best match"
for a device node based on its real path (\fIkey\fR) and any \fIlink\fRs to it
(aliases). The order of precedence for best match is described above.
.sp
.SH "SEE ALSO"
.BR selabel_open (3),
.BR selabel_stats (3),
.BR selinux_set_callback (3),
.BR selinux (8),
.BR lstat (2),
.BR selabel_file (5)

View File

@ -0,0 +1 @@
.so man3/selabel_lookup_best_match.3

View File

@ -0,0 +1,34 @@
.TH "selabel_partial_match" "3" "05 May 2015" "Security Enhanced Linux" "SELinux API documentation"
.SH "NAME"
selabel_partial_match \- determine whether a direct or partial match is
possible on a file path \- Only supported on file backend.
.
.SH "SYNOPSIS"
.B #include <stdbool.h>
.br
.B #include <selinux/selinux.h>
.br
.B #include <selinux/label.h>
.sp
.BI "bool selabel_partial_match(struct selabel_handle *" hnd ,
.in +\w'int selabel_partial_match('u
.BI "const char *" key ");"
.in
.
.SH "DESCRIPTION"
.BR selabel_partial_match ()
performs a partial match operation on the handle
.IR hnd ,
returning TRUE or FALSE.
The \fIkey\fR parameter is a file path to check for a direct or partial match.
.sp
.SH "RETURN VALUE"
TRUE is returned if a direct or partial match is found, FALSE if not.
.sp
.SH "SEE ALSO"
.BR selabel_open (3),
.BR selabel_stats (3),
.BR selinux_set_callback (3),
.BR selinux (8),
.BR selabel_file (5)

View File

@ -154,6 +154,98 @@ out:
return rc;
}
/* Public API helpers */
static char *selabel_sub_key(struct selabel_handle *rec, const char *key)
{
char *ptr = NULL;
char *dptr = NULL;
ptr = selabel_sub(rec->subs, key);
if (ptr) {
dptr = selabel_sub(rec->dist_subs, ptr);
if (dptr) {
free(ptr);
ptr = dptr;
}
} else {
ptr = selabel_sub(rec->dist_subs, key);
}
if (ptr)
return ptr;
return NULL;
}
static int selabel_fini(struct selabel_handle *rec,
struct selabel_lookup_rec *lr,
int translating)
{
if (compat_validate(rec, lr, rec->spec_file, 0))
return -1;
if (translating && !lr->ctx_trans &&
selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
return -1;
return 0;
}
static struct selabel_lookup_rec *
selabel_lookup_common(struct selabel_handle *rec, int translating,
const char *key, int type)
{
struct selabel_lookup_rec *lr;
char *ptr = NULL;
if (key == NULL) {
errno = EINVAL;
return NULL;
}
ptr = selabel_sub_key(rec, key);
if (ptr) {
lr = rec->func_lookup(rec, ptr, type);
free(ptr);
} else {
lr = rec->func_lookup(rec, key, type);
}
if (!lr)
return NULL;
if (selabel_fini(rec, lr, translating))
return NULL;
return lr;
}
static struct selabel_lookup_rec *
selabel_lookup_bm_common(struct selabel_handle *rec, int translating,
const char *key, int type, const char **aliases)
{
struct selabel_lookup_rec *lr;
char *ptr = NULL;
if (key == NULL) {
errno = EINVAL;
return NULL;
}
ptr = selabel_sub_key(rec, key);
if (ptr) {
lr = rec->func_lookup_best_match(rec, ptr, aliases, type);
free(ptr);
} else {
lr = rec->func_lookup_best_match(rec, key, aliases, type);
}
if (!lr)
return NULL;
if (selabel_fini(rec, lr, translating))
return NULL;
return lr;
}
/*
* Public API
*/
@ -188,48 +280,6 @@ out:
return rec;
}
static struct selabel_lookup_rec *
selabel_lookup_common(struct selabel_handle *rec, int translating,
const char *key, int type)
{
struct selabel_lookup_rec *lr;
char *ptr = NULL;
char *dptr = NULL;
if (key == NULL) {
errno = EINVAL;
return NULL;
}
ptr = selabel_sub(rec->subs, key);
if (ptr) {
dptr = selabel_sub(rec->dist_subs, ptr);
if (dptr) {
free(ptr);
ptr = dptr;
}
} else {
ptr = selabel_sub(rec->dist_subs, key);
}
if (ptr) {
lr = rec->func_lookup(rec, ptr, type);
free(ptr);
} else {
lr = rec->func_lookup(rec, key, type);
}
if (!lr)
return NULL;
if (compat_validate(rec, lr, rec->spec_file, 0))
return NULL;
if (translating && !lr->ctx_trans &&
selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
return NULL;
return lr;
}
int selabel_lookup(struct selabel_handle *rec, char **con,
const char *key, int type)
{
@ -256,6 +306,66 @@ int selabel_lookup_raw(struct selabel_handle *rec, char **con,
return *con ? 0 : -1;
}
bool selabel_partial_match(struct selabel_handle *rec, const char *key)
{
char *ptr;
bool ret;
if (!rec->func_partial_match) {
/*
* If the label backend does not support partial matching,
* then assume a match is possible.
*/
return true;
}
ptr = selabel_sub_key(rec, key);
if (ptr) {
ret = rec->func_partial_match(rec, ptr);
free(ptr);
} else {
ret = rec->func_partial_match(rec, key);
}
return ret;
}
int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
const char *key, const char **aliases, int type)
{
struct selabel_lookup_rec *lr;
if (!rec->func_lookup_best_match) {
errno = ENOTSUP;
return -1;
}
lr = selabel_lookup_bm_common(rec, 1, key, type, aliases);
if (!lr)
return -1;
*con = strdup(lr->ctx_trans);
return *con ? 0 : -1;
}
int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
const char *key, const char **aliases, int type)
{
struct selabel_lookup_rec *lr;
if (!rec->func_lookup_best_match) {
errno = ENOTSUP;
return -1;
}
lr = selabel_lookup_bm_common(rec, 0, key, type, aliases);
if (!lr)
return -1;
*con = strdup(lr->ctx_raw);
return *con ? 0 : -1;
}
void selabel_close(struct selabel_handle *rec)
{
selabel_subs_fini(rec->subs);

View File

@ -601,15 +601,17 @@ static void closef(struct selabel_handle *rec)
free(data);
}
static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
const char *key, int type)
static struct spec *lookup_common(struct selabel_handle *rec,
const char *key,
int type,
bool partial)
{
struct saved_data *data = (struct saved_data *)rec->data;
struct spec *spec_arr = data->spec_arr;
int i, rc, file_stem;
int i, rc, file_stem, pcre_options = 0;
mode_t mode = (mode_t)type;
const char *buf;
struct selabel_lookup_rec *ret = NULL;
struct spec *ret = NULL;
char *clean_key = NULL;
const char *prev_slash, *next_slash;
unsigned int sofar = 0;
@ -621,7 +623,7 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
/* Remove duplicate slashes */
if ((next_slash = strstr(key, "//"))) {
clean_key = malloc(strlen(key) + 1);
clean_key = (char *) malloc(strlen(key) + 1);
if (!clean_key)
goto finish;
prev_slash = key;
@ -639,6 +641,9 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
file_stem = find_stem_from_file(data, &buf);
mode &= S_IFMT;
if (partial)
pcre_options |= PCRE_PARTIAL_SOFT;
/*
* Check for matching specifications in reverse order, so that
* the last matching specification is used.
@ -654,14 +659,22 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
if (compile_regex(data, spec, NULL) < 0)
goto finish;
if (spec->stem_id == -1)
rc = pcre_exec(spec->regex, get_pcre_extra(spec), key, strlen(key), 0, 0, NULL, 0);
rc = pcre_exec(spec->regex,
get_pcre_extra(spec),
key, strlen(key), 0,
pcre_options, NULL, 0);
else
rc = pcre_exec(spec->regex, get_pcre_extra(spec), buf, strlen(buf), 0, 0, NULL, 0);
rc = pcre_exec(spec->regex,
get_pcre_extra(spec),
buf, strlen(buf), 0,
pcre_options, NULL, 0);
if (rc == 0) {
spec->matches++;
break;
} else if (rc == PCRE_ERROR_NOMATCH)
} else if (partial && rc == PCRE_ERROR_PARTIAL)
break;
if (rc == PCRE_ERROR_NOMATCH)
continue;
errno = ENOENT;
@ -677,13 +690,87 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
}
errno = 0;
ret = &spec_arr[i].lr;
ret = &spec_arr[i];
finish:
free(clean_key);
return ret;
}
static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
const char *key, int type)
{
struct spec *spec;
spec = lookup_common(rec, key, type, false);
if (spec)
return &spec->lr;
return NULL;
}
static bool partial_match(struct selabel_handle *rec, const char *key)
{
return lookup_common(rec, key, 0, true) ? true : false;
}
static struct selabel_lookup_rec *lookup_best_match(struct selabel_handle *rec,
const char *key,
const char **aliases,
int type)
{
size_t n, i;
int best = -1;
struct spec **specs;
size_t prefix_len = 0;
struct selabel_lookup_rec *lr = NULL;
if (!aliases || !aliases[0])
return lookup(rec, key, type);
for (n = 0; aliases[n]; n++)
;
specs = calloc(n+1, sizeof(struct spec *));
if (!specs)
return NULL;
specs[0] = lookup_common(rec, key, type, false);
if (specs[0]) {
if (!specs[0]->hasMetaChars) {
/* exact match on key */
lr = &specs[0]->lr;
goto out;
}
best = 0;
prefix_len = specs[0]->prefix_len;
}
for (i = 1; i <= n; i++) {
specs[i] = lookup_common(rec, aliases[i-1], type, false);
if (specs[i]) {
if (!specs[i]->hasMetaChars) {
/* exact match on alias */
lr = &specs[i]->lr;
goto out;
}
if (specs[i]->prefix_len > prefix_len) {
best = i;
prefix_len = specs[i]->prefix_len;
}
}
}
if (best >= 0) {
/* longest fixed prefix match on key or alias */
lr = &specs[best]->lr;
} else {
errno = ENOENT;
}
out:
free(specs);
return lr;
}
static void stats(struct selabel_handle *rec)
{
struct saved_data *data = (struct saved_data *)rec->data;
@ -722,6 +809,8 @@ int selabel_file_init(struct selabel_handle *rec, struct selinux_opt *opts,
rec->func_close = &closef;
rec->func_stats = &stats;
rec->func_lookup = &lookup;
rec->func_partial_match = &partial_match;
rec->func_lookup_best_match = &lookup_best_match;
return init(rec, opts, nopts);
}

View File

@ -31,6 +31,7 @@ struct spec {
char hasMetaChars; /* regular expression has meta-chars */
char regcomp; /* regex_str has been compiled to regex */
char from_mmap; /* this spec is from an mmap of the data */
size_t prefix_len; /* length of fixed path prefix */
};
/* A regular expression stem */

View File

@ -57,6 +57,12 @@ struct selabel_handle {
const char *key, int type);
void (*func_close) (struct selabel_handle *h);
void (*func_stats) (struct selabel_handle *h);
bool (*func_partial_match) (struct selabel_handle *h, const char *key);
struct selabel_lookup_rec *(*func_lookup_best_match)
(struct selabel_handle *h,
const char *key,
const char **aliases,
int type);
/* supports backend-specific state information */
void *data;

View File

@ -0,0 +1,126 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <selinux/selinux.h>
#include <selinux/label.h>
static void usage(const char *progname)
{
fprintf(stderr,
"usage: %s -b backend [-v] [-r] -k key [-t type] [-f file]\n\n"
"Where:\n\t"
"-b The backend - \"file\", \"media\", \"x\", \"db\" or "
"\"prop\"\n\t"
"-v Validate entries against loaded policy.\n\t"
"-r Use \"raw\" function.\n\t"
"-k Lookup key - Depends on backend.\n\t"
"-t Lookup type - Optional as depends on backend.\n\t"
"-f Optional file containing the specs (defaults to\n\t"
" those used by loaded policy).\n\n"
"Examples:\n\t"
"%s -v -b file -k /run -t 0\n\t"
" lookup with validation against the loaded policy, the\n\t"
" \"file\" backend for path \"/run\" with mode = 0\n\t"
"%s -r -b x -t 4 -k X11:ButtonPress\n\t"
" lookup_raw the \"X\" backend for type SELABEL_X_EVENT\n\t"
" using key \"X11:ButtonPress\"\n\n",
progname, progname, progname);
exit(1);
}
int main(int argc, char **argv)
{
int raw = 0, type = 0, backend = 0, rc, opt;
char *validate = NULL, *key = NULL, *context = NULL, *file = NULL;
struct selabel_handle *hnd;
struct selinux_opt selabel_option[] = {
{ SELABEL_OPT_PATH, file },
{ SELABEL_OPT_VALIDATE, validate }
};
if (argc < 3)
usage(argv[0]);
while ((opt = getopt(argc, argv, "b:f:vrk:t:")) > 0) {
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 'f':
file = optarg;
break;
case 'v':
validate = (char *)1;
break;
case 'r':
raw = 1;
break;
case 'k':
key = optarg;
break;
case 't':
type = atoi(optarg);
break;
default:
usage(argv[0]);
}
}
selabel_option[0].value = file;
selabel_option[1].value = validate;
hnd = selabel_open(backend, selabel_option, 2);
if (!hnd) {
fprintf(stderr, "ERROR: selabel_open - Could not obtain "
"handle.\n");
return -1;
}
switch (raw) {
case 1:
rc = selabel_lookup_raw(hnd, &context, key, type);
break;
default:
rc = selabel_lookup(hnd, &context, key, type);
}
selabel_close(hnd);
if (rc) {
switch (errno) {
case ENOENT:
fprintf(stderr, "ERROR: selabel_lookup failed to "
"find a valid context.\n");
break;
case EINVAL:
fprintf(stderr, "ERROR: selabel_lookup failed to "
"validate context, or key / type are "
"invalid.\n");
break;
default:
fprintf(stderr, "selabel_lookup ERROR: %s\n",
strerror(errno));
}
} else {
printf("Default context: %s\n", context);
freecon(context);
}
return rc;
}

View File

@ -0,0 +1,164 @@
#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 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_size;
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 != 0) {
links = malloc(sizeof(char *) * num_links);
if (links == NULL) {
fprintf(stderr, "ERROR: malloc failed.");
exit(1);
}
for (i = optind, num_links = 0; i < argc; i++, num_links++) {
string_size = strlen(argv[i]) + 1;
links[num_links] = malloc(string_size);
if (links[num_links] == NULL) {
fprintf(stderr, "ERROR: malloc failed.");
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;
}
switch (raw) {
case 1:
rc = selabel_lookup_best_match_raw(hnd, &context, path,
(const char **)links, mode);
break;
default:
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 (num_links != 0) {
for (i = 0; i < num_links; i++)
free(links[i]);
free(links);
}
return rc;
}

View File

@ -0,0 +1,75 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <stdbool.h>
#include <selinux/selinux.h>
#include <selinux/label.h>
static void usage(const char *progname)
{
fprintf(stderr,
"usage: %s [-v] -p <path> [-f file]\n\n"
"Where:\n\t"
"-v Validate file_contxts entries against loaded policy.\n\t"
"-p Path to check if a match or partial match is possible\n\t"
" against a regex entry in the file_contexts file.\n\t"
"-f Optional file_contexts file (defaults to current policy).\n\n"
"Example:\n\t"
"%s -p /sys/devices/system/cpu/online\n\t"
" Check if a match or partial match is possible against\n\t"
" the path \"/sys/devices/system/cpu/online\", returning\n\t"
" TRUE or FALSE.\n\n", progname, progname);
exit(1);
}
int main(int argc, char **argv)
{
int opt;
bool partial_match;
char *validate = NULL, *path = NULL, *file = 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:vp:")) > 0) {
switch (opt) {
case 'f':
file = optarg;
break;
case 'v':
validate = (char *)1;
break;
case 'p':
path = optarg;
break;
default:
usage(argv[0]);
}
}
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;
}
partial_match = selabel_partial_match(hnd, path);
printf("Match or Partial match: %s\n",
partial_match == 1 ? "TRUE" : "FALSE");
selabel_close(hnd);
return partial_match;
}