o Introduce cap_from_text() and cap_to_text() implementations.
Reviewed by: green Obtained from: TrustedBSD Project Security audited by: imp, green
This commit is contained in:
parent
d1ce910572
commit
36fa62c01b
@ -24,7 +24,8 @@ SRCS+= acl_delete.c \
|
||||
cap_set_fd.c \
|
||||
cap_set_file.c \
|
||||
cap_set_flag.c \
|
||||
cap_set_proc.c
|
||||
cap_set_proc.c \
|
||||
cap_text.c
|
||||
|
||||
|
||||
MAN3= acl.3 \
|
||||
|
571
lib/libc/posix1e/cap_text.c
Normal file
571
lib/libc/posix1e/cap_text.c
Normal file
@ -0,0 +1,571 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Robert N. M. Watson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
/*
|
||||
* TrustedBSD Project - support for POSIX.1e process capabilities
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/capability.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const size_t CAP_MAX_BUF_LEN = 1024;
|
||||
static const size_t CAP_MAX_SMALL_BUF_LEN = 64;
|
||||
|
||||
static const char *CAP_FLAGS[8] = {
|
||||
"", /* 000 */
|
||||
"e", /* 001 */
|
||||
"i", /* 010 */
|
||||
"ei", /* 011 */
|
||||
"p", /* 100 */
|
||||
"ep", /* 101 */
|
||||
"ip", /* 110 */
|
||||
"eip", /* 111 */
|
||||
};
|
||||
|
||||
static const char *CAP_SEP = ": \t";
|
||||
static const char *CAP_OPERATION = "=-+";
|
||||
|
||||
struct cap_info {
|
||||
char *ci_name;
|
||||
cap_value_t ci_cap;
|
||||
};
|
||||
|
||||
static const struct cap_info cap_info_array[] = {
|
||||
{"CAP_CHOWN", CAP_CHOWN},
|
||||
{"CAP_DAC_EXECUTE", CAP_DAC_EXECUTE},
|
||||
{"CAP_DAC_WRITE", CAP_DAC_WRITE},
|
||||
{"CAP_DAC_READ_SEARCH", CAP_DAC_READ_SEARCH},
|
||||
{"CAP_FOWNER", CAP_FOWNER},
|
||||
{"CAP_FSETID", CAP_FSETID},
|
||||
{"CAP_KILL", CAP_KILL},
|
||||
{"CAP_LINK_DIR", CAP_LINK_DIR},
|
||||
{"CAP_SETFCAP", CAP_SETFCAP},
|
||||
{"CAP_SETGID", CAP_SETGID},
|
||||
{"CAP_SETUID", CAP_SETUID},
|
||||
{"CAP_MAC_DOWNGRADE", CAP_MAC_DOWNGRADE},
|
||||
{"CAP_MAC_READ", CAP_MAC_READ},
|
||||
{"CAP_MAC_RELABEL_SUBJ", CAP_MAC_RELABEL_SUBJ},
|
||||
{"CAP_MAC_UPGRADE", CAP_MAC_UPGRADE},
|
||||
{"CAP_MAC_WRITE", CAP_MAC_WRITE},
|
||||
{"CAP_INF_NOFLOAT_OBJ", CAP_INF_NOFLOAT_OBJ},
|
||||
{"CAP_INF_NOFLOAT_SUBJ", CAP_INF_NOFLOAT_SUBJ},
|
||||
{"CAP_INF_RELABEL_OBJ", CAP_INF_RELABEL_OBJ},
|
||||
{"CAP_INF_RELABEL_SUBJ", CAP_INF_RELABEL_SUBJ},
|
||||
{"CAP_AUDIT_CONTROL", CAP_AUDIT_CONTROL},
|
||||
{"CAP_AUDIT_WRITE", CAP_AUDIT_WRITE},
|
||||
{"CAP_SETPCAP", CAP_SETPCAP},
|
||||
{"CAP_SYS_SETFFLAG", CAP_SYS_SETFFLAG},
|
||||
{"CAP_LINUX_IMMUTABLE", CAP_SYS_SETFFLAG},
|
||||
{"CAP_NET_BIND_SERVICE", CAP_NET_BIND_SERVICE},
|
||||
{"CAP_NET_BROADCAST", CAP_NET_BROADCAST},
|
||||
{"CAP_NET_ADMIN", CAP_NET_ADMIN},
|
||||
{"CAP_NET_RAW", CAP_NET_RAW},
|
||||
{"CAP_IPC_LOCK", CAP_IPC_LOCK},
|
||||
{"CAP_IPC_OWNER", CAP_IPC_OWNER},
|
||||
{"CAP_SYS_MODULE", CAP_SYS_MODULE},
|
||||
{"CAP_SYS_RAWIO", CAP_SYS_RAWIO},
|
||||
{"CAP_SYS_CHROOT", CAP_SYS_CHROOT},
|
||||
{"CAP_SYS_PTRACE", CAP_SYS_PTRACE},
|
||||
{"CAP_SYS_PACCT", CAP_SYS_PACCT},
|
||||
{"CAP_SYS_ADMIN", CAP_SYS_ADMIN},
|
||||
{"CAP_SYS_BOOT", CAP_SYS_BOOT},
|
||||
{"CAP_SYS_NICE", CAP_SYS_NICE},
|
||||
{"CAP_SYS_RESOURCE", CAP_SYS_RESOURCE},
|
||||
{"CAP_SYS_TIME", CAP_SYS_TIME},
|
||||
{"CAP_SYS_TTY_CONFIG", CAP_SYS_TTY_CONFIG},
|
||||
{"CAP_MKNOD", CAP_MKNOD},
|
||||
{"", CAP_ALL_OFF},
|
||||
{"all", CAP_ALL_ON},
|
||||
};
|
||||
|
||||
static const int cap_info_array_len = sizeof(cap_info_array) /
|
||||
sizeof(cap_info_array[0]);
|
||||
|
||||
static const cap_value_t cap_list[] = {
|
||||
CAP_CHOWN,
|
||||
CAP_DAC_EXECUTE,
|
||||
CAP_DAC_WRITE,
|
||||
CAP_DAC_READ_SEARCH,
|
||||
CAP_FOWNER,
|
||||
CAP_FSETID,
|
||||
CAP_KILL,
|
||||
CAP_LINK_DIR,
|
||||
CAP_SETFCAP,
|
||||
CAP_SETGID,
|
||||
CAP_SETUID,
|
||||
CAP_MAC_DOWNGRADE,
|
||||
CAP_MAC_READ,
|
||||
CAP_MAC_RELABEL_SUBJ,
|
||||
CAP_MAC_UPGRADE,
|
||||
CAP_MAC_WRITE,
|
||||
CAP_INF_NOFLOAT_OBJ,
|
||||
CAP_INF_NOFLOAT_SUBJ,
|
||||
CAP_INF_RELABEL_OBJ,
|
||||
CAP_INF_RELABEL_SUBJ,
|
||||
CAP_AUDIT_CONTROL,
|
||||
CAP_AUDIT_WRITE,
|
||||
CAP_SETPCAP,
|
||||
CAP_SYS_SETFFLAG,
|
||||
CAP_NET_BIND_SERVICE,
|
||||
CAP_NET_BROADCAST,
|
||||
CAP_NET_ADMIN,
|
||||
CAP_NET_RAW,
|
||||
CAP_IPC_LOCK,
|
||||
CAP_IPC_OWNER,
|
||||
CAP_SYS_MODULE,
|
||||
CAP_SYS_RAWIO,
|
||||
CAP_SYS_CHROOT,
|
||||
CAP_SYS_PTRACE,
|
||||
CAP_SYS_PACCT,
|
||||
CAP_SYS_ADMIN,
|
||||
CAP_SYS_BOOT,
|
||||
CAP_SYS_NICE,
|
||||
CAP_SYS_RESOURCE,
|
||||
CAP_SYS_TIME,
|
||||
CAP_SYS_TTY_CONFIG,
|
||||
CAP_MKNOD,
|
||||
};
|
||||
|
||||
static const int cap_list_len = sizeof(cap_list) / sizeof(cap_list[0]);
|
||||
|
||||
static void
|
||||
cap_set(cap_t cap_p, cap_flag_t flags, cap_flag_value_t fvalue,
|
||||
cap_value_t cap_value)
|
||||
{
|
||||
|
||||
if (flags & CAP_EFFECTIVE) {
|
||||
if (fvalue == CAP_SET)
|
||||
cap_p->c_effective |= cap_value;
|
||||
else
|
||||
cap_p->c_effective &= ~cap_value;
|
||||
}
|
||||
if (flags & CAP_INHERITABLE) {
|
||||
if (fvalue == CAP_SET)
|
||||
cap_p->c_inheritable |= cap_value;
|
||||
else
|
||||
cap_p->c_inheritable &= ~cap_value;
|
||||
}
|
||||
if (flags & CAP_PERMITTED) {
|
||||
if (fvalue == CAP_SET)
|
||||
cap_p->c_permitted |= cap_value;
|
||||
else
|
||||
cap_p->c_permitted &= ~cap_value;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cap_is_set(cap_t cap_p, cap_flag_t cap_flag, cap_value_t cap_value)
|
||||
{
|
||||
int seen = 0;
|
||||
|
||||
if (cap_flag & CAP_EFFECTIVE)
|
||||
seen |= (cap_p->c_effective & cap_value);
|
||||
if (cap_flag & CAP_INHERITABLE)
|
||||
seen |= (cap_p->c_inheritable & cap_value);
|
||||
if (cap_flag & CAP_PERMITTED)
|
||||
seen |= (cap_p->c_permitted & cap_value);
|
||||
|
||||
return (seen);
|
||||
}
|
||||
|
||||
static cap_flag_value_t
|
||||
cap_value_to_flags(cap_t cap_p, cap_value_t cap_value)
|
||||
{
|
||||
cap_flag_t flags = 0;
|
||||
|
||||
if (cap_p->c_effective & cap_value)
|
||||
flags |= CAP_EFFECTIVE;
|
||||
if (cap_p->c_inheritable & cap_value)
|
||||
flags |= CAP_INHERITABLE;
|
||||
if (cap_p->c_permitted & cap_value)
|
||||
flags |= CAP_PERMITTED;
|
||||
|
||||
return (flags);
|
||||
}
|
||||
|
||||
static const char *
|
||||
cap_flags_to_string(cap_flag_t flags)
|
||||
{
|
||||
|
||||
return (CAP_FLAGS[flags]);
|
||||
}
|
||||
|
||||
static int
|
||||
cap_string_to_flags(const char *string, cap_flag_t *flags)
|
||||
{
|
||||
const char *c = string;
|
||||
|
||||
*flags = 0;
|
||||
while (*c != '\0') {
|
||||
switch (*c) {
|
||||
case 'e':
|
||||
*flags |= CAP_EFFECTIVE;
|
||||
break;
|
||||
case 'i':
|
||||
*flags |= CAP_INHERITABLE;
|
||||
break;
|
||||
case 'p':
|
||||
*flags |= CAP_PERMITTED;
|
||||
break;
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
c++;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static const char *
|
||||
cap_to_string(cap_value_t cap)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cap_info_array_len; i++) {
|
||||
if (cap_info_array[i].ci_cap == cap)
|
||||
return (cap_info_array[i].ci_name);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
cap_from_string(const char *string, cap_value_t *cap)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cap_info_array_len; i++) {
|
||||
if (!strcasecmp(cap_info_array[i].ci_name, string)) {
|
||||
*cap = cap_info_array[i].ci_cap;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
char *
|
||||
cap_to_text(cap_t cap_p, ssize_t *len_p)
|
||||
{
|
||||
cap_value_t cap_value;
|
||||
cap_flag_t cap_flag, most_flag;
|
||||
const char *flag_s, *value_s, *prefix_s;
|
||||
char *buf, minibuf[CAP_MAX_SMALL_BUF_LEN], operation;
|
||||
|
||||
int num_effective, num_inheritable, num_permitted;
|
||||
int most_effective, most_inheritable, most_permitted;
|
||||
int count, any_so_far;
|
||||
|
||||
buf = (char *)malloc(CAP_MAX_BUF_LEN);
|
||||
if (buf == NULL) {
|
||||
errno = ENOMEM;
|
||||
return (NULL);
|
||||
}
|
||||
buf[0] = '\0';
|
||||
|
||||
/*
|
||||
* For the sake of prettiness, first walk each flag to see if it's
|
||||
* set for cap_list_len/2 or more. If so, list it as a plus, and
|
||||
* do the remainder as negative, as needed. This will tend to
|
||||
* collapse a lot of the common all= cases.
|
||||
*/
|
||||
num_effective = num_inheritable = num_permitted = 0;
|
||||
for (count = 0; count < cap_list_len; count++) {
|
||||
cap_value = cap_list[count];
|
||||
if (cap_is_set(cap_p, CAP_EFFECTIVE, cap_value))
|
||||
num_effective++;
|
||||
if (cap_is_set(cap_p, CAP_INHERITABLE, cap_value))
|
||||
num_inheritable++;
|
||||
if (cap_is_set(cap_p, CAP_PERMITTED, cap_value))
|
||||
num_permitted++;
|
||||
}
|
||||
|
||||
most_effective = (num_effective > cap_list_len / 2);
|
||||
most_inheritable = (num_inheritable > cap_list_len / 2);
|
||||
most_permitted = (num_permitted > cap_list_len / 2);
|
||||
|
||||
most_flag = 0;
|
||||
if (most_effective)
|
||||
most_flag |= CAP_EFFECTIVE;
|
||||
if (most_inheritable)
|
||||
most_flag |= CAP_INHERITABLE;
|
||||
if (most_permitted)
|
||||
most_flag |= CAP_PERMITTED;
|
||||
|
||||
any_so_far = 0;
|
||||
if (most_flag != 0) {
|
||||
if ((strlcat(buf, "all=", CAP_MAX_BUF_LEN) >=
|
||||
CAP_MAX_BUF_LEN) ||
|
||||
(strlcat(buf, CAP_FLAGS[most_flag],
|
||||
CAP_MAX_BUF_LEN) >= CAP_MAX_BUF_LEN)) {
|
||||
free(buf);
|
||||
errno = ENOMEM;
|
||||
return (NULL);
|
||||
}
|
||||
any_so_far = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each capability value, determine how that value relates
|
||||
* to the most common case, and (depending on CAP_PRINT_RELATIVE)
|
||||
* either print out the value's flag set relative to the most
|
||||
* common, or its absolute flag set.
|
||||
*/
|
||||
for (count = 0; count < cap_list_len; count++) {
|
||||
cap_value = cap_list[count];
|
||||
cap_flag = cap_value_to_flags(cap_p, cap_value);
|
||||
/*
|
||||
* Determine which, if any, flags need to be printed
|
||||
* for this capability. First, if the flags on the
|
||||
* capability are equal to the "most" flags, just skip
|
||||
* it.
|
||||
*/
|
||||
if (cap_flag == most_flag)
|
||||
continue;
|
||||
|
||||
#if CAP_PRINT_RELATIVE
|
||||
/*
|
||||
* If the flags are a strict superset of the "most"
|
||||
* flags, print it as a "+" case. If they're a
|
||||
* strict subset, print as a "-" case. Otherwise,
|
||||
* specify as an "=" case.
|
||||
*/
|
||||
if ((cap_flag | most_flag) == cap_flag) {
|
||||
/* Strict superset, use "+". */
|
||||
operation = '+';
|
||||
cap_flag = cap_flag & ~most_flag;
|
||||
flag_s = cap_flags_to_string(cap_flag);
|
||||
} else if ((cap_flag | most_flag) == most_flag) {
|
||||
/* Strict subset, use "-". */
|
||||
operation = '-';
|
||||
cap_flag = most_flag & ~cap_flag;
|
||||
flag_s = cap_flags_to_string(cap_flag);
|
||||
} else {
|
||||
#endif
|
||||
/* Mixed, use an "=" case */
|
||||
operation = '=';
|
||||
flag_s = cap_flags_to_string(cap_flag);
|
||||
#if CAP_PRINT_RELATIVE
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Now assemble clause, and append to the string being
|
||||
* built.
|
||||
*/
|
||||
if (any_so_far)
|
||||
prefix_s = ":";
|
||||
else
|
||||
prefix_s = "";
|
||||
value_s = cap_to_string(cap_value);
|
||||
if ((snprintf(minibuf, sizeof(minibuf), "%s%s%c%s", prefix_s,
|
||||
value_s, operation, flag_s) >= sizeof(minibuf)) ||
|
||||
(strlcat(buf, minibuf, CAP_MAX_BUF_LEN) >=
|
||||
CAP_MAX_BUF_LEN)) {
|
||||
free(buf);
|
||||
errno = ENOMEM;
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (len_p)
|
||||
*len_p = strlen(buf);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
cap_t
|
||||
cap_from_text(const char *buf_p)
|
||||
{
|
||||
cap_value_t cap_value_v, cap_value_set_v;
|
||||
cap_flag_t cap_action_v;
|
||||
cap_t cap;
|
||||
char *mybuf, *cur;
|
||||
char *clause_s, *cap_value_s, *cap_value_list_s;
|
||||
char *cap_action_list_s, *cap_action_s;
|
||||
char *next_operation_p, operation, next_operation;
|
||||
|
||||
cap = cap_init();
|
||||
if (cap == NULL)
|
||||
return ((cap_t)NULL);
|
||||
|
||||
mybuf = strdup(buf_p);
|
||||
if (mybuf == NULL) {
|
||||
errno = ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/*
|
||||
* clase [SEP clause [SEP clause ...]]
|
||||
* Split into "clauses", which are seperated by a : or whitespace.
|
||||
*
|
||||
* clause = [caplist]actionlist
|
||||
* caplist = capabilityname[,capabilityname[, ...]]
|
||||
* actionlist = op[flags][op[flags]]
|
||||
* Split clauses into a (possibly null) capability name list, and a
|
||||
* set of one or more {op,flags} pairs.
|
||||
*
|
||||
* Each assignment is then applied to a running "state" to
|
||||
* produce an end-result in the internal representation.
|
||||
* Parsing failure at any time releases resources and results
|
||||
* in EINVAL.
|
||||
*/
|
||||
cur = mybuf;
|
||||
while ((clause_s = strsep(&cur, CAP_SEP)) != NULL) {
|
||||
/*
|
||||
* Identify and NULL the first operation so that we
|
||||
* can parse the capability name list, but save
|
||||
* for later when we iterate over the operation list.
|
||||
*/
|
||||
cap_action_list_s = clause_s;
|
||||
next_operation_p = strpbrk(cap_action_list_s, CAP_OPERATION);
|
||||
if (next_operation_p == NULL)
|
||||
goto err2;
|
||||
operation = *next_operation_p;
|
||||
cap_value_list_s = strsep(&cap_action_list_s, CAP_OPERATION);
|
||||
if (cap_value_list_s == NULL || cap_action_list_s == NULL)
|
||||
goto err2;
|
||||
/*
|
||||
* cap_value_list_s now points at the NULL-terminated list
|
||||
* of capability values, if any.
|
||||
* cap_action_list_s now points to the NULL-terminated list
|
||||
* of actions.
|
||||
*
|
||||
* First, parse the value list to generate a value set
|
||||
* refering to the combined contents of the value list.
|
||||
*/
|
||||
cap_value_set_v = 0;
|
||||
while ((cap_value_s = strsep(&cap_value_list_s, ",")) != NULL) {
|
||||
/*
|
||||
* Convert value string into internal representation.
|
||||
* Reject if not a valid capability identifier.
|
||||
*/
|
||||
if (cap_from_string(cap_value_s, &cap_value_v))
|
||||
goto err2;
|
||||
cap_value_set_v |= cap_value_v;
|
||||
}
|
||||
|
||||
/*
|
||||
* While the current operation is non-0, parse its flags,
|
||||
* apply the actions, and then repeat. The first set
|
||||
* is assured above when the capability list is split off.
|
||||
*/
|
||||
while (operation != 0) {
|
||||
/*
|
||||
* Identify and save the next operation, then NULL
|
||||
* it to find the end of the current flags.
|
||||
*/
|
||||
next_operation_p = strpbrk(cap_action_list_s,
|
||||
CAP_OPERATION);
|
||||
if (next_operation_p)
|
||||
next_operation = *next_operation_p;
|
||||
else
|
||||
next_operation = 0;
|
||||
cap_action_s = strsep(&cap_action_list_s,
|
||||
CAP_OPERATION);
|
||||
/*
|
||||
* Convert string form of flags to internal
|
||||
* representation, reject if not possible.
|
||||
*/
|
||||
if (cap_string_to_flags(cap_action_s, &cap_action_v))
|
||||
goto err2;
|
||||
|
||||
/*
|
||||
* Now, based on operation apply actionlist flags
|
||||
* to the capability value set built earlier from
|
||||
* the capability list.
|
||||
*/
|
||||
switch (operation) {
|
||||
case '=':
|
||||
/*
|
||||
* Remove current flags for the value set,
|
||||
* replace with new flags.
|
||||
*
|
||||
* Spec requires that an "=" operation with
|
||||
* no value set be treated as an "=" operation
|
||||
* with a value set equivilent to "all".
|
||||
*/
|
||||
if (cap_value_set_v == CAP_ALL_OFF) {
|
||||
cap_set(cap, CAP_EFFECTIVE|
|
||||
CAP_INHERITABLE|CAP_PERMITTED,
|
||||
CAP_CLEAR, CAP_ALL_ON);
|
||||
cap_set(cap, cap_action_v, CAP_SET,
|
||||
CAP_ALL_ON);
|
||||
} else {
|
||||
cap_set(cap, CAP_EFFECTIVE|
|
||||
CAP_INHERITABLE|CAP_PERMITTED,
|
||||
CAP_CLEAR, cap_value_set_v);
|
||||
cap_set(cap, cap_action_v, CAP_SET,
|
||||
cap_value_set_v);
|
||||
}
|
||||
break;
|
||||
case '+':
|
||||
/*
|
||||
* Add current flags to value set.
|
||||
*
|
||||
* Spec requires that a "+" operation with
|
||||
* no value set be rejected.
|
||||
*/
|
||||
if (cap_value_set_v == CAP_ALL_OFF)
|
||||
goto err2;
|
||||
cap_set(cap, cap_action_v, CAP_SET,
|
||||
cap_value_set_v);
|
||||
break;
|
||||
case '-':
|
||||
/*
|
||||
* Subtract current flags from value set.
|
||||
*
|
||||
* Spec requires that a "-" operation with
|
||||
* no value set be treated as a "-" operation
|
||||
* with a value set equivilent to "all".
|
||||
*/
|
||||
if (cap_value_set_v == CAP_ALL_OFF)
|
||||
cap_set(cap, cap_action_v, CAP_CLEAR,
|
||||
CAP_ALL_ON);
|
||||
else
|
||||
cap_set(cap, cap_action_v, CAP_CLEAR,
|
||||
cap_value_set_v);
|
||||
break;
|
||||
default:
|
||||
goto err2;
|
||||
}
|
||||
operation = next_operation;
|
||||
}
|
||||
}
|
||||
|
||||
return (cap);
|
||||
err2:
|
||||
errno = EINVAL;
|
||||
free(mybuf);
|
||||
err1:
|
||||
cap_free(cap);
|
||||
return ((cap_t)NULL);
|
||||
}
|
||||
|
@ -24,7 +24,8 @@ SRCS+= acl_delete.c \
|
||||
cap_set_fd.c \
|
||||
cap_set_file.c \
|
||||
cap_set_flag.c \
|
||||
cap_set_proc.c
|
||||
cap_set_proc.c \
|
||||
cap_text.c
|
||||
|
||||
|
||||
MAN3= acl.3 \
|
||||
|
571
lib/libposix1e/cap_text.c
Normal file
571
lib/libposix1e/cap_text.c
Normal file
@ -0,0 +1,571 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Robert N. M. Watson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
/*
|
||||
* TrustedBSD Project - support for POSIX.1e process capabilities
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/capability.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const size_t CAP_MAX_BUF_LEN = 1024;
|
||||
static const size_t CAP_MAX_SMALL_BUF_LEN = 64;
|
||||
|
||||
static const char *CAP_FLAGS[8] = {
|
||||
"", /* 000 */
|
||||
"e", /* 001 */
|
||||
"i", /* 010 */
|
||||
"ei", /* 011 */
|
||||
"p", /* 100 */
|
||||
"ep", /* 101 */
|
||||
"ip", /* 110 */
|
||||
"eip", /* 111 */
|
||||
};
|
||||
|
||||
static const char *CAP_SEP = ": \t";
|
||||
static const char *CAP_OPERATION = "=-+";
|
||||
|
||||
struct cap_info {
|
||||
char *ci_name;
|
||||
cap_value_t ci_cap;
|
||||
};
|
||||
|
||||
static const struct cap_info cap_info_array[] = {
|
||||
{"CAP_CHOWN", CAP_CHOWN},
|
||||
{"CAP_DAC_EXECUTE", CAP_DAC_EXECUTE},
|
||||
{"CAP_DAC_WRITE", CAP_DAC_WRITE},
|
||||
{"CAP_DAC_READ_SEARCH", CAP_DAC_READ_SEARCH},
|
||||
{"CAP_FOWNER", CAP_FOWNER},
|
||||
{"CAP_FSETID", CAP_FSETID},
|
||||
{"CAP_KILL", CAP_KILL},
|
||||
{"CAP_LINK_DIR", CAP_LINK_DIR},
|
||||
{"CAP_SETFCAP", CAP_SETFCAP},
|
||||
{"CAP_SETGID", CAP_SETGID},
|
||||
{"CAP_SETUID", CAP_SETUID},
|
||||
{"CAP_MAC_DOWNGRADE", CAP_MAC_DOWNGRADE},
|
||||
{"CAP_MAC_READ", CAP_MAC_READ},
|
||||
{"CAP_MAC_RELABEL_SUBJ", CAP_MAC_RELABEL_SUBJ},
|
||||
{"CAP_MAC_UPGRADE", CAP_MAC_UPGRADE},
|
||||
{"CAP_MAC_WRITE", CAP_MAC_WRITE},
|
||||
{"CAP_INF_NOFLOAT_OBJ", CAP_INF_NOFLOAT_OBJ},
|
||||
{"CAP_INF_NOFLOAT_SUBJ", CAP_INF_NOFLOAT_SUBJ},
|
||||
{"CAP_INF_RELABEL_OBJ", CAP_INF_RELABEL_OBJ},
|
||||
{"CAP_INF_RELABEL_SUBJ", CAP_INF_RELABEL_SUBJ},
|
||||
{"CAP_AUDIT_CONTROL", CAP_AUDIT_CONTROL},
|
||||
{"CAP_AUDIT_WRITE", CAP_AUDIT_WRITE},
|
||||
{"CAP_SETPCAP", CAP_SETPCAP},
|
||||
{"CAP_SYS_SETFFLAG", CAP_SYS_SETFFLAG},
|
||||
{"CAP_LINUX_IMMUTABLE", CAP_SYS_SETFFLAG},
|
||||
{"CAP_NET_BIND_SERVICE", CAP_NET_BIND_SERVICE},
|
||||
{"CAP_NET_BROADCAST", CAP_NET_BROADCAST},
|
||||
{"CAP_NET_ADMIN", CAP_NET_ADMIN},
|
||||
{"CAP_NET_RAW", CAP_NET_RAW},
|
||||
{"CAP_IPC_LOCK", CAP_IPC_LOCK},
|
||||
{"CAP_IPC_OWNER", CAP_IPC_OWNER},
|
||||
{"CAP_SYS_MODULE", CAP_SYS_MODULE},
|
||||
{"CAP_SYS_RAWIO", CAP_SYS_RAWIO},
|
||||
{"CAP_SYS_CHROOT", CAP_SYS_CHROOT},
|
||||
{"CAP_SYS_PTRACE", CAP_SYS_PTRACE},
|
||||
{"CAP_SYS_PACCT", CAP_SYS_PACCT},
|
||||
{"CAP_SYS_ADMIN", CAP_SYS_ADMIN},
|
||||
{"CAP_SYS_BOOT", CAP_SYS_BOOT},
|
||||
{"CAP_SYS_NICE", CAP_SYS_NICE},
|
||||
{"CAP_SYS_RESOURCE", CAP_SYS_RESOURCE},
|
||||
{"CAP_SYS_TIME", CAP_SYS_TIME},
|
||||
{"CAP_SYS_TTY_CONFIG", CAP_SYS_TTY_CONFIG},
|
||||
{"CAP_MKNOD", CAP_MKNOD},
|
||||
{"", CAP_ALL_OFF},
|
||||
{"all", CAP_ALL_ON},
|
||||
};
|
||||
|
||||
static const int cap_info_array_len = sizeof(cap_info_array) /
|
||||
sizeof(cap_info_array[0]);
|
||||
|
||||
static const cap_value_t cap_list[] = {
|
||||
CAP_CHOWN,
|
||||
CAP_DAC_EXECUTE,
|
||||
CAP_DAC_WRITE,
|
||||
CAP_DAC_READ_SEARCH,
|
||||
CAP_FOWNER,
|
||||
CAP_FSETID,
|
||||
CAP_KILL,
|
||||
CAP_LINK_DIR,
|
||||
CAP_SETFCAP,
|
||||
CAP_SETGID,
|
||||
CAP_SETUID,
|
||||
CAP_MAC_DOWNGRADE,
|
||||
CAP_MAC_READ,
|
||||
CAP_MAC_RELABEL_SUBJ,
|
||||
CAP_MAC_UPGRADE,
|
||||
CAP_MAC_WRITE,
|
||||
CAP_INF_NOFLOAT_OBJ,
|
||||
CAP_INF_NOFLOAT_SUBJ,
|
||||
CAP_INF_RELABEL_OBJ,
|
||||
CAP_INF_RELABEL_SUBJ,
|
||||
CAP_AUDIT_CONTROL,
|
||||
CAP_AUDIT_WRITE,
|
||||
CAP_SETPCAP,
|
||||
CAP_SYS_SETFFLAG,
|
||||
CAP_NET_BIND_SERVICE,
|
||||
CAP_NET_BROADCAST,
|
||||
CAP_NET_ADMIN,
|
||||
CAP_NET_RAW,
|
||||
CAP_IPC_LOCK,
|
||||
CAP_IPC_OWNER,
|
||||
CAP_SYS_MODULE,
|
||||
CAP_SYS_RAWIO,
|
||||
CAP_SYS_CHROOT,
|
||||
CAP_SYS_PTRACE,
|
||||
CAP_SYS_PACCT,
|
||||
CAP_SYS_ADMIN,
|
||||
CAP_SYS_BOOT,
|
||||
CAP_SYS_NICE,
|
||||
CAP_SYS_RESOURCE,
|
||||
CAP_SYS_TIME,
|
||||
CAP_SYS_TTY_CONFIG,
|
||||
CAP_MKNOD,
|
||||
};
|
||||
|
||||
static const int cap_list_len = sizeof(cap_list) / sizeof(cap_list[0]);
|
||||
|
||||
static void
|
||||
cap_set(cap_t cap_p, cap_flag_t flags, cap_flag_value_t fvalue,
|
||||
cap_value_t cap_value)
|
||||
{
|
||||
|
||||
if (flags & CAP_EFFECTIVE) {
|
||||
if (fvalue == CAP_SET)
|
||||
cap_p->c_effective |= cap_value;
|
||||
else
|
||||
cap_p->c_effective &= ~cap_value;
|
||||
}
|
||||
if (flags & CAP_INHERITABLE) {
|
||||
if (fvalue == CAP_SET)
|
||||
cap_p->c_inheritable |= cap_value;
|
||||
else
|
||||
cap_p->c_inheritable &= ~cap_value;
|
||||
}
|
||||
if (flags & CAP_PERMITTED) {
|
||||
if (fvalue == CAP_SET)
|
||||
cap_p->c_permitted |= cap_value;
|
||||
else
|
||||
cap_p->c_permitted &= ~cap_value;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cap_is_set(cap_t cap_p, cap_flag_t cap_flag, cap_value_t cap_value)
|
||||
{
|
||||
int seen = 0;
|
||||
|
||||
if (cap_flag & CAP_EFFECTIVE)
|
||||
seen |= (cap_p->c_effective & cap_value);
|
||||
if (cap_flag & CAP_INHERITABLE)
|
||||
seen |= (cap_p->c_inheritable & cap_value);
|
||||
if (cap_flag & CAP_PERMITTED)
|
||||
seen |= (cap_p->c_permitted & cap_value);
|
||||
|
||||
return (seen);
|
||||
}
|
||||
|
||||
static cap_flag_value_t
|
||||
cap_value_to_flags(cap_t cap_p, cap_value_t cap_value)
|
||||
{
|
||||
cap_flag_t flags = 0;
|
||||
|
||||
if (cap_p->c_effective & cap_value)
|
||||
flags |= CAP_EFFECTIVE;
|
||||
if (cap_p->c_inheritable & cap_value)
|
||||
flags |= CAP_INHERITABLE;
|
||||
if (cap_p->c_permitted & cap_value)
|
||||
flags |= CAP_PERMITTED;
|
||||
|
||||
return (flags);
|
||||
}
|
||||
|
||||
static const char *
|
||||
cap_flags_to_string(cap_flag_t flags)
|
||||
{
|
||||
|
||||
return (CAP_FLAGS[flags]);
|
||||
}
|
||||
|
||||
static int
|
||||
cap_string_to_flags(const char *string, cap_flag_t *flags)
|
||||
{
|
||||
const char *c = string;
|
||||
|
||||
*flags = 0;
|
||||
while (*c != '\0') {
|
||||
switch (*c) {
|
||||
case 'e':
|
||||
*flags |= CAP_EFFECTIVE;
|
||||
break;
|
||||
case 'i':
|
||||
*flags |= CAP_INHERITABLE;
|
||||
break;
|
||||
case 'p':
|
||||
*flags |= CAP_PERMITTED;
|
||||
break;
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
c++;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static const char *
|
||||
cap_to_string(cap_value_t cap)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cap_info_array_len; i++) {
|
||||
if (cap_info_array[i].ci_cap == cap)
|
||||
return (cap_info_array[i].ci_name);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
cap_from_string(const char *string, cap_value_t *cap)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cap_info_array_len; i++) {
|
||||
if (!strcasecmp(cap_info_array[i].ci_name, string)) {
|
||||
*cap = cap_info_array[i].ci_cap;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
char *
|
||||
cap_to_text(cap_t cap_p, ssize_t *len_p)
|
||||
{
|
||||
cap_value_t cap_value;
|
||||
cap_flag_t cap_flag, most_flag;
|
||||
const char *flag_s, *value_s, *prefix_s;
|
||||
char *buf, minibuf[CAP_MAX_SMALL_BUF_LEN], operation;
|
||||
|
||||
int num_effective, num_inheritable, num_permitted;
|
||||
int most_effective, most_inheritable, most_permitted;
|
||||
int count, any_so_far;
|
||||
|
||||
buf = (char *)malloc(CAP_MAX_BUF_LEN);
|
||||
if (buf == NULL) {
|
||||
errno = ENOMEM;
|
||||
return (NULL);
|
||||
}
|
||||
buf[0] = '\0';
|
||||
|
||||
/*
|
||||
* For the sake of prettiness, first walk each flag to see if it's
|
||||
* set for cap_list_len/2 or more. If so, list it as a plus, and
|
||||
* do the remainder as negative, as needed. This will tend to
|
||||
* collapse a lot of the common all= cases.
|
||||
*/
|
||||
num_effective = num_inheritable = num_permitted = 0;
|
||||
for (count = 0; count < cap_list_len; count++) {
|
||||
cap_value = cap_list[count];
|
||||
if (cap_is_set(cap_p, CAP_EFFECTIVE, cap_value))
|
||||
num_effective++;
|
||||
if (cap_is_set(cap_p, CAP_INHERITABLE, cap_value))
|
||||
num_inheritable++;
|
||||
if (cap_is_set(cap_p, CAP_PERMITTED, cap_value))
|
||||
num_permitted++;
|
||||
}
|
||||
|
||||
most_effective = (num_effective > cap_list_len / 2);
|
||||
most_inheritable = (num_inheritable > cap_list_len / 2);
|
||||
most_permitted = (num_permitted > cap_list_len / 2);
|
||||
|
||||
most_flag = 0;
|
||||
if (most_effective)
|
||||
most_flag |= CAP_EFFECTIVE;
|
||||
if (most_inheritable)
|
||||
most_flag |= CAP_INHERITABLE;
|
||||
if (most_permitted)
|
||||
most_flag |= CAP_PERMITTED;
|
||||
|
||||
any_so_far = 0;
|
||||
if (most_flag != 0) {
|
||||
if ((strlcat(buf, "all=", CAP_MAX_BUF_LEN) >=
|
||||
CAP_MAX_BUF_LEN) ||
|
||||
(strlcat(buf, CAP_FLAGS[most_flag],
|
||||
CAP_MAX_BUF_LEN) >= CAP_MAX_BUF_LEN)) {
|
||||
free(buf);
|
||||
errno = ENOMEM;
|
||||
return (NULL);
|
||||
}
|
||||
any_so_far = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each capability value, determine how that value relates
|
||||
* to the most common case, and (depending on CAP_PRINT_RELATIVE)
|
||||
* either print out the value's flag set relative to the most
|
||||
* common, or its absolute flag set.
|
||||
*/
|
||||
for (count = 0; count < cap_list_len; count++) {
|
||||
cap_value = cap_list[count];
|
||||
cap_flag = cap_value_to_flags(cap_p, cap_value);
|
||||
/*
|
||||
* Determine which, if any, flags need to be printed
|
||||
* for this capability. First, if the flags on the
|
||||
* capability are equal to the "most" flags, just skip
|
||||
* it.
|
||||
*/
|
||||
if (cap_flag == most_flag)
|
||||
continue;
|
||||
|
||||
#if CAP_PRINT_RELATIVE
|
||||
/*
|
||||
* If the flags are a strict superset of the "most"
|
||||
* flags, print it as a "+" case. If they're a
|
||||
* strict subset, print as a "-" case. Otherwise,
|
||||
* specify as an "=" case.
|
||||
*/
|
||||
if ((cap_flag | most_flag) == cap_flag) {
|
||||
/* Strict superset, use "+". */
|
||||
operation = '+';
|
||||
cap_flag = cap_flag & ~most_flag;
|
||||
flag_s = cap_flags_to_string(cap_flag);
|
||||
} else if ((cap_flag | most_flag) == most_flag) {
|
||||
/* Strict subset, use "-". */
|
||||
operation = '-';
|
||||
cap_flag = most_flag & ~cap_flag;
|
||||
flag_s = cap_flags_to_string(cap_flag);
|
||||
} else {
|
||||
#endif
|
||||
/* Mixed, use an "=" case */
|
||||
operation = '=';
|
||||
flag_s = cap_flags_to_string(cap_flag);
|
||||
#if CAP_PRINT_RELATIVE
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Now assemble clause, and append to the string being
|
||||
* built.
|
||||
*/
|
||||
if (any_so_far)
|
||||
prefix_s = ":";
|
||||
else
|
||||
prefix_s = "";
|
||||
value_s = cap_to_string(cap_value);
|
||||
if ((snprintf(minibuf, sizeof(minibuf), "%s%s%c%s", prefix_s,
|
||||
value_s, operation, flag_s) >= sizeof(minibuf)) ||
|
||||
(strlcat(buf, minibuf, CAP_MAX_BUF_LEN) >=
|
||||
CAP_MAX_BUF_LEN)) {
|
||||
free(buf);
|
||||
errno = ENOMEM;
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (len_p)
|
||||
*len_p = strlen(buf);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
cap_t
|
||||
cap_from_text(const char *buf_p)
|
||||
{
|
||||
cap_value_t cap_value_v, cap_value_set_v;
|
||||
cap_flag_t cap_action_v;
|
||||
cap_t cap;
|
||||
char *mybuf, *cur;
|
||||
char *clause_s, *cap_value_s, *cap_value_list_s;
|
||||
char *cap_action_list_s, *cap_action_s;
|
||||
char *next_operation_p, operation, next_operation;
|
||||
|
||||
cap = cap_init();
|
||||
if (cap == NULL)
|
||||
return ((cap_t)NULL);
|
||||
|
||||
mybuf = strdup(buf_p);
|
||||
if (mybuf == NULL) {
|
||||
errno = ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/*
|
||||
* clase [SEP clause [SEP clause ...]]
|
||||
* Split into "clauses", which are seperated by a : or whitespace.
|
||||
*
|
||||
* clause = [caplist]actionlist
|
||||
* caplist = capabilityname[,capabilityname[, ...]]
|
||||
* actionlist = op[flags][op[flags]]
|
||||
* Split clauses into a (possibly null) capability name list, and a
|
||||
* set of one or more {op,flags} pairs.
|
||||
*
|
||||
* Each assignment is then applied to a running "state" to
|
||||
* produce an end-result in the internal representation.
|
||||
* Parsing failure at any time releases resources and results
|
||||
* in EINVAL.
|
||||
*/
|
||||
cur = mybuf;
|
||||
while ((clause_s = strsep(&cur, CAP_SEP)) != NULL) {
|
||||
/*
|
||||
* Identify and NULL the first operation so that we
|
||||
* can parse the capability name list, but save
|
||||
* for later when we iterate over the operation list.
|
||||
*/
|
||||
cap_action_list_s = clause_s;
|
||||
next_operation_p = strpbrk(cap_action_list_s, CAP_OPERATION);
|
||||
if (next_operation_p == NULL)
|
||||
goto err2;
|
||||
operation = *next_operation_p;
|
||||
cap_value_list_s = strsep(&cap_action_list_s, CAP_OPERATION);
|
||||
if (cap_value_list_s == NULL || cap_action_list_s == NULL)
|
||||
goto err2;
|
||||
/*
|
||||
* cap_value_list_s now points at the NULL-terminated list
|
||||
* of capability values, if any.
|
||||
* cap_action_list_s now points to the NULL-terminated list
|
||||
* of actions.
|
||||
*
|
||||
* First, parse the value list to generate a value set
|
||||
* refering to the combined contents of the value list.
|
||||
*/
|
||||
cap_value_set_v = 0;
|
||||
while ((cap_value_s = strsep(&cap_value_list_s, ",")) != NULL) {
|
||||
/*
|
||||
* Convert value string into internal representation.
|
||||
* Reject if not a valid capability identifier.
|
||||
*/
|
||||
if (cap_from_string(cap_value_s, &cap_value_v))
|
||||
goto err2;
|
||||
cap_value_set_v |= cap_value_v;
|
||||
}
|
||||
|
||||
/*
|
||||
* While the current operation is non-0, parse its flags,
|
||||
* apply the actions, and then repeat. The first set
|
||||
* is assured above when the capability list is split off.
|
||||
*/
|
||||
while (operation != 0) {
|
||||
/*
|
||||
* Identify and save the next operation, then NULL
|
||||
* it to find the end of the current flags.
|
||||
*/
|
||||
next_operation_p = strpbrk(cap_action_list_s,
|
||||
CAP_OPERATION);
|
||||
if (next_operation_p)
|
||||
next_operation = *next_operation_p;
|
||||
else
|
||||
next_operation = 0;
|
||||
cap_action_s = strsep(&cap_action_list_s,
|
||||
CAP_OPERATION);
|
||||
/*
|
||||
* Convert string form of flags to internal
|
||||
* representation, reject if not possible.
|
||||
*/
|
||||
if (cap_string_to_flags(cap_action_s, &cap_action_v))
|
||||
goto err2;
|
||||
|
||||
/*
|
||||
* Now, based on operation apply actionlist flags
|
||||
* to the capability value set built earlier from
|
||||
* the capability list.
|
||||
*/
|
||||
switch (operation) {
|
||||
case '=':
|
||||
/*
|
||||
* Remove current flags for the value set,
|
||||
* replace with new flags.
|
||||
*
|
||||
* Spec requires that an "=" operation with
|
||||
* no value set be treated as an "=" operation
|
||||
* with a value set equivilent to "all".
|
||||
*/
|
||||
if (cap_value_set_v == CAP_ALL_OFF) {
|
||||
cap_set(cap, CAP_EFFECTIVE|
|
||||
CAP_INHERITABLE|CAP_PERMITTED,
|
||||
CAP_CLEAR, CAP_ALL_ON);
|
||||
cap_set(cap, cap_action_v, CAP_SET,
|
||||
CAP_ALL_ON);
|
||||
} else {
|
||||
cap_set(cap, CAP_EFFECTIVE|
|
||||
CAP_INHERITABLE|CAP_PERMITTED,
|
||||
CAP_CLEAR, cap_value_set_v);
|
||||
cap_set(cap, cap_action_v, CAP_SET,
|
||||
cap_value_set_v);
|
||||
}
|
||||
break;
|
||||
case '+':
|
||||
/*
|
||||
* Add current flags to value set.
|
||||
*
|
||||
* Spec requires that a "+" operation with
|
||||
* no value set be rejected.
|
||||
*/
|
||||
if (cap_value_set_v == CAP_ALL_OFF)
|
||||
goto err2;
|
||||
cap_set(cap, cap_action_v, CAP_SET,
|
||||
cap_value_set_v);
|
||||
break;
|
||||
case '-':
|
||||
/*
|
||||
* Subtract current flags from value set.
|
||||
*
|
||||
* Spec requires that a "-" operation with
|
||||
* no value set be treated as a "-" operation
|
||||
* with a value set equivilent to "all".
|
||||
*/
|
||||
if (cap_value_set_v == CAP_ALL_OFF)
|
||||
cap_set(cap, cap_action_v, CAP_CLEAR,
|
||||
CAP_ALL_ON);
|
||||
else
|
||||
cap_set(cap, cap_action_v, CAP_CLEAR,
|
||||
cap_value_set_v);
|
||||
break;
|
||||
default:
|
||||
goto err2;
|
||||
}
|
||||
operation = next_operation;
|
||||
}
|
||||
}
|
||||
|
||||
return (cap);
|
||||
err2:
|
||||
errno = EINVAL;
|
||||
free(mybuf);
|
||||
err1:
|
||||
cap_free(cap);
|
||||
return ((cap_t)NULL);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user