2 * Copyright (c) 2000 Robert N. M. Watson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * TrustedBSD Project - support for POSIX.1e process capabilities
32 #include <sys/types.h>
33 #include <sys/capability.h>
34 #include <sys/errno.h>
40 static const size_t CAP_MAX_BUF_LEN = 1024;
41 static const size_t CAP_MAX_SMALL_BUF_LEN = 64;
43 static const char *CAP_FLAGS[8] = {
54 static const char *CAP_SEP = ": \t";
55 static const char *CAP_OPERATION = "=-+";
62 static const struct cap_info cap_info_array[] = {
63 {"CAP_CHOWN", CAP_CHOWN},
64 {"CAP_DAC_EXECUTE", CAP_DAC_EXECUTE},
65 {"CAP_DAC_WRITE", CAP_DAC_WRITE},
66 {"CAP_DAC_READ_SEARCH", CAP_DAC_READ_SEARCH},
67 {"CAP_FOWNER", CAP_FOWNER},
68 {"CAP_FSETID", CAP_FSETID},
69 {"CAP_KILL", CAP_KILL},
70 {"CAP_LINK_DIR", CAP_LINK_DIR},
71 {"CAP_SETFCAP", CAP_SETFCAP},
72 {"CAP_SETGID", CAP_SETGID},
73 {"CAP_SETUID", CAP_SETUID},
74 {"CAP_MAC_DOWNGRADE", CAP_MAC_DOWNGRADE},
75 {"CAP_MAC_READ", CAP_MAC_READ},
76 {"CAP_MAC_RELABEL_SUBJ", CAP_MAC_RELABEL_SUBJ},
77 {"CAP_MAC_UPGRADE", CAP_MAC_UPGRADE},
78 {"CAP_MAC_WRITE", CAP_MAC_WRITE},
79 {"CAP_INF_NOFLOAT_OBJ", CAP_INF_NOFLOAT_OBJ},
80 {"CAP_INF_NOFLOAT_SUBJ", CAP_INF_NOFLOAT_SUBJ},
81 {"CAP_INF_RELABEL_OBJ", CAP_INF_RELABEL_OBJ},
82 {"CAP_INF_RELABEL_SUBJ", CAP_INF_RELABEL_SUBJ},
83 {"CAP_AUDIT_CONTROL", CAP_AUDIT_CONTROL},
84 {"CAP_AUDIT_WRITE", CAP_AUDIT_WRITE},
85 {"CAP_SETPCAP", CAP_SETPCAP},
86 {"CAP_SYS_SETFFLAG", CAP_SYS_SETFFLAG},
87 {"CAP_LINUX_IMMUTABLE", CAP_SYS_SETFFLAG},
88 {"CAP_NET_BIND_SERVICE", CAP_NET_BIND_SERVICE},
89 {"CAP_NET_BROADCAST", CAP_NET_BROADCAST},
90 {"CAP_NET_ADMIN", CAP_NET_ADMIN},
91 {"CAP_NET_RAW", CAP_NET_RAW},
92 {"CAP_IPC_LOCK", CAP_IPC_LOCK},
93 {"CAP_IPC_OWNER", CAP_IPC_OWNER},
94 {"CAP_SYS_MODULE", CAP_SYS_MODULE},
95 {"CAP_SYS_RAWIO", CAP_SYS_RAWIO},
96 {"CAP_SYS_CHROOT", CAP_SYS_CHROOT},
97 {"CAP_SYS_PTRACE", CAP_SYS_PTRACE},
98 {"CAP_SYS_PACCT", CAP_SYS_PACCT},
99 {"CAP_SYS_ADMIN", CAP_SYS_ADMIN},
100 {"CAP_SYS_BOOT", CAP_SYS_BOOT},
101 {"CAP_SYS_NICE", CAP_SYS_NICE},
102 {"CAP_SYS_RESOURCE", CAP_SYS_RESOURCE},
103 {"CAP_SYS_TIME", CAP_SYS_TIME},
104 {"CAP_SYS_TTY_CONFIG", CAP_SYS_TTY_CONFIG},
105 {"CAP_MKNOD", CAP_MKNOD},
110 static const int cap_info_array_len = sizeof(cap_info_array) /
111 sizeof(cap_info_array[0]);
113 static const cap_value_t cap_list[] = {
127 CAP_MAC_RELABEL_SUBJ,
131 CAP_INF_NOFLOAT_SUBJ,
133 CAP_INF_RELABEL_SUBJ,
138 CAP_NET_BIND_SERVICE,
158 static const int cap_list_len = sizeof(cap_list) / sizeof(cap_list[0]);
161 cap_set(cap_t cap_p, cap_flag_t flags, cap_flag_value_t fvalue,
162 cap_value_t cap_value)
165 if (flags & CAP_EFFECTIVE) {
166 if (fvalue == CAP_SET)
167 cap_p->c_effective |= cap_value;
169 cap_p->c_effective &= ~cap_value;
171 if (flags & CAP_INHERITABLE) {
172 if (fvalue == CAP_SET)
173 cap_p->c_inheritable |= cap_value;
175 cap_p->c_inheritable &= ~cap_value;
177 if (flags & CAP_PERMITTED) {
178 if (fvalue == CAP_SET)
179 cap_p->c_permitted |= cap_value;
181 cap_p->c_permitted &= ~cap_value;
186 cap_is_set(cap_t cap_p, cap_flag_t cap_flag, cap_value_t cap_value)
190 if (cap_flag & CAP_EFFECTIVE)
191 seen |= (cap_p->c_effective & cap_value);
192 if (cap_flag & CAP_INHERITABLE)
193 seen |= (cap_p->c_inheritable & cap_value);
194 if (cap_flag & CAP_PERMITTED)
195 seen |= (cap_p->c_permitted & cap_value);
200 static cap_flag_value_t
201 cap_value_to_flags(cap_t cap_p, cap_value_t cap_value)
203 cap_flag_t flags = 0;
205 if (cap_p->c_effective & cap_value)
206 flags |= CAP_EFFECTIVE;
207 if (cap_p->c_inheritable & cap_value)
208 flags |= CAP_INHERITABLE;
209 if (cap_p->c_permitted & cap_value)
210 flags |= CAP_PERMITTED;
216 cap_flags_to_string(cap_flag_t flags)
219 return (CAP_FLAGS[flags]);
223 cap_string_to_flags(const char *string, cap_flag_t *flags)
225 const char *c = string;
231 *flags |= CAP_EFFECTIVE;
234 *flags |= CAP_INHERITABLE;
237 *flags |= CAP_PERMITTED;
249 cap_to_string(cap_value_t cap)
253 for (i = 0; i < cap_info_array_len; i++) {
254 if (cap_info_array[i].ci_cap == cap)
255 return (cap_info_array[i].ci_name);
262 cap_from_string(const char *string, cap_value_t *cap)
266 for (i = 0; i < cap_info_array_len; i++) {
267 if (!strcasecmp(cap_info_array[i].ci_name, string)) {
268 *cap = cap_info_array[i].ci_cap;
277 cap_to_text(cap_t cap_p, ssize_t *len_p)
279 cap_value_t cap_value;
280 cap_flag_t cap_flag, most_flag;
281 const char *flag_s, *value_s, *prefix_s;
282 char *buf, minibuf[CAP_MAX_SMALL_BUF_LEN], operation;
284 int num_effective, num_inheritable, num_permitted;
285 int most_effective, most_inheritable, most_permitted;
286 int count, any_so_far;
288 buf = (char *)malloc(CAP_MAX_BUF_LEN);
296 * For the sake of prettiness, first walk each flag to see if it's
297 * set for cap_list_len/2 or more. If so, list it as a plus, and
298 * do the remainder as negative, as needed. This will tend to
299 * collapse a lot of the common all= cases.
301 num_effective = num_inheritable = num_permitted = 0;
302 for (count = 0; count < cap_list_len; count++) {
303 cap_value = cap_list[count];
304 if (cap_is_set(cap_p, CAP_EFFECTIVE, cap_value))
306 if (cap_is_set(cap_p, CAP_INHERITABLE, cap_value))
308 if (cap_is_set(cap_p, CAP_PERMITTED, cap_value))
312 most_effective = (num_effective > cap_list_len / 2);
313 most_inheritable = (num_inheritable > cap_list_len / 2);
314 most_permitted = (num_permitted > cap_list_len / 2);
318 most_flag |= CAP_EFFECTIVE;
319 if (most_inheritable)
320 most_flag |= CAP_INHERITABLE;
322 most_flag |= CAP_PERMITTED;
325 if (most_flag != 0) {
326 if ((strlcat(buf, "all=", CAP_MAX_BUF_LEN) >=
328 (strlcat(buf, CAP_FLAGS[most_flag],
329 CAP_MAX_BUF_LEN) >= CAP_MAX_BUF_LEN)) {
338 * For each capability value, determine how that value relates
339 * to the most common case, and (depending on CAP_PRINT_RELATIVE)
340 * either print out the value's flag set relative to the most
341 * common, or its absolute flag set.
343 for (count = 0; count < cap_list_len; count++) {
344 cap_value = cap_list[count];
345 cap_flag = cap_value_to_flags(cap_p, cap_value);
347 * Determine which, if any, flags need to be printed
348 * for this capability. First, if the flags on the
349 * capability are equal to the "most" flags, just skip
352 if (cap_flag == most_flag)
355 #if CAP_PRINT_RELATIVE
357 * If the flags are a strict superset of the "most"
358 * flags, print it as a "+" case. If they're a
359 * strict subset, print as a "-" case. Otherwise,
360 * specify as an "=" case.
362 if ((cap_flag | most_flag) == cap_flag) {
363 /* Strict superset, use "+". */
365 cap_flag = cap_flag & ~most_flag;
366 flag_s = cap_flags_to_string(cap_flag);
367 } else if ((cap_flag | most_flag) == most_flag) {
368 /* Strict subset, use "-". */
370 cap_flag = most_flag & ~cap_flag;
371 flag_s = cap_flags_to_string(cap_flag);
374 /* Mixed, use an "=" case */
376 flag_s = cap_flags_to_string(cap_flag);
377 #if CAP_PRINT_RELATIVE
381 * Now assemble clause, and append to the string being
388 value_s = cap_to_string(cap_value);
389 if ((snprintf(minibuf, sizeof(minibuf), "%s%s%c%s", prefix_s,
390 value_s, operation, flag_s) >= sizeof(minibuf)) ||
391 (strlcat(buf, minibuf, CAP_MAX_BUF_LEN) >=
400 *len_p = strlen(buf);
405 cap_from_text(const char *buf_p)
407 cap_value_t cap_value_v, cap_value_set_v;
408 cap_flag_t cap_action_v;
411 char *clause_s, *cap_value_s, *cap_value_list_s;
412 char *cap_action_list_s, *cap_action_s;
413 char *next_operation_p, operation, next_operation;
417 return ((cap_t)NULL);
419 mybuf = strdup(buf_p);
426 * clase [SEP clause [SEP clause ...]]
427 * Split into "clauses", which are seperated by a : or whitespace.
429 * clause = [caplist]actionlist
430 * caplist = capabilityname[,capabilityname[, ...]]
431 * actionlist = op[flags][op[flags]]
432 * Split clauses into a (possibly null) capability name list, and a
433 * set of one or more {op,flags} pairs.
435 * Each assignment is then applied to a running "state" to
436 * produce an end-result in the internal representation.
437 * Parsing failure at any time releases resources and results
441 while ((clause_s = strsep(&cur, CAP_SEP)) != NULL) {
443 * Identify and NULL the first operation so that we
444 * can parse the capability name list, but save
445 * for later when we iterate over the operation list.
447 cap_action_list_s = clause_s;
448 next_operation_p = strpbrk(cap_action_list_s, CAP_OPERATION);
449 if (next_operation_p == NULL)
451 operation = *next_operation_p;
452 cap_value_list_s = strsep(&cap_action_list_s, CAP_OPERATION);
453 if (cap_value_list_s == NULL || cap_action_list_s == NULL)
456 * cap_value_list_s now points at the NULL-terminated list
457 * of capability values, if any.
458 * cap_action_list_s now points to the NULL-terminated list
461 * First, parse the value list to generate a value set
462 * refering to the combined contents of the value list.
465 while ((cap_value_s = strsep(&cap_value_list_s, ",")) != NULL) {
467 * Convert value string into internal representation.
468 * Reject if not a valid capability identifier.
470 if (cap_from_string(cap_value_s, &cap_value_v))
472 cap_value_set_v |= cap_value_v;
476 * While the current operation is non-0, parse its flags,
477 * apply the actions, and then repeat. The first set
478 * is assured above when the capability list is split off.
480 while (operation != 0) {
482 * Identify and save the next operation, then NULL
483 * it to find the end of the current flags.
485 next_operation_p = strpbrk(cap_action_list_s,
487 if (next_operation_p)
488 next_operation = *next_operation_p;
491 cap_action_s = strsep(&cap_action_list_s,
494 * Convert string form of flags to internal
495 * representation, reject if not possible.
497 if (cap_string_to_flags(cap_action_s, &cap_action_v))
501 * Now, based on operation apply actionlist flags
502 * to the capability value set built earlier from
503 * the capability list.
508 * Remove current flags for the value set,
509 * replace with new flags.
511 * Spec requires that an "=" operation with
512 * no value set be treated as an "=" operation
513 * with a value set equivilent to "all".
515 if (cap_value_set_v == CAP_ALL_OFF) {
516 cap_set(cap, CAP_EFFECTIVE|
517 CAP_INHERITABLE|CAP_PERMITTED,
518 CAP_CLEAR, CAP_ALL_ON);
519 cap_set(cap, cap_action_v, CAP_SET,
522 cap_set(cap, CAP_EFFECTIVE|
523 CAP_INHERITABLE|CAP_PERMITTED,
524 CAP_CLEAR, cap_value_set_v);
525 cap_set(cap, cap_action_v, CAP_SET,
531 * Add current flags to value set.
533 * Spec requires that a "+" operation with
534 * no value set be rejected.
536 if (cap_value_set_v == CAP_ALL_OFF)
538 cap_set(cap, cap_action_v, CAP_SET,
543 * Subtract current flags from value set.
545 * Spec requires that a "-" operation with
546 * no value set be treated as a "-" operation
547 * with a value set equivilent to "all".
549 if (cap_value_set_v == CAP_ALL_OFF)
550 cap_set(cap, cap_action_v, CAP_CLEAR,
553 cap_set(cap, cap_action_v, CAP_CLEAR,
559 operation = next_operation;
569 return ((cap_t)NULL);