]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libposix1e/cap_text.c
This commit was generated by cvs2svn to compensate for changes in r68349,
[FreeBSD/FreeBSD.git] / lib / libposix1e / cap_text.c
1 /*-
2  * Copyright (c) 2000 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 /*
29  * TrustedBSD Project - support for POSIX.1e process capabilities
30  */
31
32 #include <sys/types.h>
33 #include <sys/capability.h>
34 #include <sys/errno.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 static const size_t CAP_MAX_BUF_LEN = 1024;
41 static const size_t CAP_MAX_SMALL_BUF_LEN = 64;
42
43 static const char *CAP_FLAGS[8] = {
44         "",     /* 000 */
45         "e",    /* 001 */
46         "i",    /* 010 */
47         "ei",   /* 011 */
48         "p",    /* 100 */
49         "ep",   /* 101 */
50         "ip",   /* 110 */
51         "eip",  /* 111 */
52 };
53
54 static const char *CAP_SEP = ": \t";
55 static const char *CAP_OPERATION = "=-+";
56
57 struct cap_info {
58         char    *ci_name;
59         cap_value_t     ci_cap;
60 };
61
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},
106 {"", CAP_ALL_OFF},
107 {"all", CAP_ALL_ON},
108 };
109
110 static const int cap_info_array_len = sizeof(cap_info_array) /
111     sizeof(cap_info_array[0]);
112
113 static const cap_value_t cap_list[] = {
114 CAP_CHOWN,
115 CAP_DAC_EXECUTE,
116 CAP_DAC_WRITE,
117 CAP_DAC_READ_SEARCH,
118 CAP_FOWNER,
119 CAP_FSETID,
120 CAP_KILL,
121 CAP_LINK_DIR,
122 CAP_SETFCAP,
123 CAP_SETGID,
124 CAP_SETUID,
125 CAP_MAC_DOWNGRADE,
126 CAP_MAC_READ,
127 CAP_MAC_RELABEL_SUBJ,
128 CAP_MAC_UPGRADE,
129 CAP_MAC_WRITE,
130 CAP_INF_NOFLOAT_OBJ,
131 CAP_INF_NOFLOAT_SUBJ,
132 CAP_INF_RELABEL_OBJ,
133 CAP_INF_RELABEL_SUBJ,
134 CAP_AUDIT_CONTROL,
135 CAP_AUDIT_WRITE,
136 CAP_SETPCAP,
137 CAP_SYS_SETFFLAG,
138 CAP_NET_BIND_SERVICE,
139 CAP_NET_BROADCAST,
140 CAP_NET_ADMIN,
141 CAP_NET_RAW,
142 CAP_IPC_LOCK,
143 CAP_IPC_OWNER,
144 CAP_SYS_MODULE,
145 CAP_SYS_RAWIO,
146 CAP_SYS_CHROOT,
147 CAP_SYS_PTRACE,
148 CAP_SYS_PACCT,
149 CAP_SYS_ADMIN,
150 CAP_SYS_BOOT,
151 CAP_SYS_NICE,
152 CAP_SYS_RESOURCE,
153 CAP_SYS_TIME,
154 CAP_SYS_TTY_CONFIG,
155 CAP_MKNOD,
156 };
157
158 static const int cap_list_len = sizeof(cap_list) / sizeof(cap_list[0]);
159
160 static void
161 cap_set(cap_t cap_p, cap_flag_t flags, cap_flag_value_t fvalue,
162     cap_value_t cap_value)
163 {
164
165         if (flags & CAP_EFFECTIVE) {
166                 if (fvalue == CAP_SET)
167                         cap_p->c_effective |= cap_value;
168                 else
169                         cap_p->c_effective &= ~cap_value;
170         }
171         if (flags & CAP_INHERITABLE) {
172                 if (fvalue == CAP_SET)
173                         cap_p->c_inheritable |= cap_value;
174                 else
175                         cap_p->c_inheritable &= ~cap_value;
176         }
177         if (flags & CAP_PERMITTED) {
178                 if (fvalue == CAP_SET)
179                         cap_p->c_permitted |= cap_value;
180                 else
181                         cap_p->c_permitted &= ~cap_value;
182         }
183 }
184
185 static int
186 cap_is_set(cap_t cap_p, cap_flag_t cap_flag, cap_value_t cap_value)
187 {
188         int     seen = 0;
189
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);
196
197         return (seen);
198 }
199
200 static cap_flag_value_t
201 cap_value_to_flags(cap_t cap_p, cap_value_t cap_value)
202 {
203         cap_flag_t      flags = 0;
204
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;
211
212         return (flags);
213 }
214
215 static const char *
216 cap_flags_to_string(cap_flag_t flags)
217 {
218
219         return (CAP_FLAGS[flags]);
220 }
221
222 static int
223 cap_string_to_flags(const char *string, cap_flag_t *flags)
224 {
225         const char      *c = string;
226
227         *flags = 0;
228         while (*c != '\0') {
229                 switch (*c) {
230                 case 'e':
231                         *flags |= CAP_EFFECTIVE;
232                         break;
233                 case 'i':
234                         *flags |= CAP_INHERITABLE;
235                         break;
236                 case 'p':
237                         *flags |= CAP_PERMITTED;
238                         break;
239                 default:
240                         return (EINVAL);
241                 }
242                 c++;
243         }
244
245         return (0);
246 }
247
248 static const char *
249 cap_to_string(cap_value_t cap)
250 {
251         int     i;
252
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);
256         }
257
258         return (NULL);
259 }
260
261 static int
262 cap_from_string(const char *string, cap_value_t *cap)
263 {
264         int     i;
265
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;
269                         return (0);
270                 }
271         }
272
273         return (EINVAL);
274 }
275
276 char *
277 cap_to_text(cap_t cap_p, ssize_t *len_p)
278 {
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;
283
284         int     num_effective, num_inheritable, num_permitted;
285         int     most_effective, most_inheritable, most_permitted;
286         int     count, any_so_far;
287
288         buf = (char *)malloc(CAP_MAX_BUF_LEN);
289         if (buf == NULL) {
290                 errno = ENOMEM;
291                 return (NULL);
292         }
293         buf[0] = '\0';
294
295         /*
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.
300          */
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))
305                         num_effective++;
306                 if (cap_is_set(cap_p, CAP_INHERITABLE, cap_value))
307                         num_inheritable++;
308                 if (cap_is_set(cap_p, CAP_PERMITTED, cap_value))
309                         num_permitted++;
310         }
311
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);
315
316         most_flag = 0;
317         if (most_effective)
318                 most_flag |= CAP_EFFECTIVE;
319         if (most_inheritable)
320                 most_flag |= CAP_INHERITABLE;
321         if (most_permitted)
322                 most_flag |= CAP_PERMITTED;
323
324         any_so_far = 0;
325         if (most_flag != 0) {
326                 if ((strlcat(buf, "all=", CAP_MAX_BUF_LEN) >=
327                     CAP_MAX_BUF_LEN) ||
328                     (strlcat(buf, CAP_FLAGS[most_flag],
329                     CAP_MAX_BUF_LEN) >= CAP_MAX_BUF_LEN)) {
330                         free(buf);
331                         errno = ENOMEM;
332                         return (NULL);
333                 }
334                 any_so_far = 1;
335         }
336
337         /*
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.
342          */
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);
346                 /*
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
350                  * it.
351                  */
352                 if (cap_flag == most_flag)
353                         continue;
354
355 #if CAP_PRINT_RELATIVE
356                 /*
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.
361                  */
362                 if ((cap_flag | most_flag) == cap_flag) {
363                         /* Strict superset, use "+". */
364                         operation = '+';
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 "-". */
369                         operation = '-';
370                         cap_flag = most_flag & ~cap_flag;
371                         flag_s = cap_flags_to_string(cap_flag);
372                 } else {
373 #endif
374                         /* Mixed, use an "=" case */
375                         operation = '=';
376                         flag_s = cap_flags_to_string(cap_flag);
377 #if CAP_PRINT_RELATIVE
378                 }
379 #endif
380                 /*
381                  * Now assemble clause, and append to the string being
382                  * built.
383                  */
384                 if (any_so_far)
385                         prefix_s = ":";
386                 else
387                         prefix_s = "";
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) >=
392                     CAP_MAX_BUF_LEN)) {
393                         free(buf);
394                         errno = ENOMEM;
395                         return (NULL);
396                 }
397         }
398
399         if (len_p)
400                 *len_p = strlen(buf);
401         return (buf);
402 }
403
404 cap_t
405 cap_from_text(const char *buf_p)
406 {
407         cap_value_t     cap_value_v, cap_value_set_v;
408         cap_flag_t      cap_action_v;
409         cap_t   cap;
410         char    *mybuf, *cur;
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;
414
415         cap = cap_init();
416         if (cap == NULL)
417                 return ((cap_t)NULL);
418
419         mybuf = strdup(buf_p);
420         if (mybuf == NULL) {
421                 errno = ENOMEM;
422                 goto err1;
423         }
424
425         /*
426          * clase [SEP clause [SEP clause ...]]
427          * Split into "clauses", which are seperated by a : or whitespace.
428          *
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.
434          *
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
438          * in EINVAL.
439          */
440         cur = mybuf;
441         while ((clause_s = strsep(&cur, CAP_SEP)) != NULL) {
442                 /*
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.
446                  */
447                 cap_action_list_s = clause_s;
448                 next_operation_p = strpbrk(cap_action_list_s, CAP_OPERATION);
449                 if (next_operation_p == NULL)
450                         goto err2;
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)
454                         goto err2;
455                 /*
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
459                  * of actions.
460                  *
461                  * First, parse the value list to generate a value set
462                  * refering to the combined contents of the value list.
463                  */
464                 cap_value_set_v = 0;
465                 while ((cap_value_s = strsep(&cap_value_list_s, ",")) != NULL) {
466                         /*
467                          * Convert value string into internal representation.
468                          * Reject if not a valid capability identifier.
469                          */
470                         if (cap_from_string(cap_value_s, &cap_value_v))
471                                 goto err2;
472                         cap_value_set_v |= cap_value_v;
473                 }
474
475                 /*
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.
479                  */
480                 while (operation != 0) {
481                         /*
482                          * Identify and save the next operation, then NULL
483                          * it to find the end of the current flags.
484                          */
485                         next_operation_p = strpbrk(cap_action_list_s,
486                             CAP_OPERATION);
487                         if (next_operation_p)
488                                 next_operation = *next_operation_p;
489                         else
490                                 next_operation = 0;
491                         cap_action_s = strsep(&cap_action_list_s,
492                             CAP_OPERATION);
493                         /*
494                          * Convert string form of flags to internal
495                          * representation, reject if not possible.
496                          */
497                         if (cap_string_to_flags(cap_action_s, &cap_action_v))
498                                 goto err2;
499
500                         /*
501                          * Now, based on operation apply actionlist flags
502                          * to the capability value set built earlier from
503                          * the capability list.
504                          */
505                         switch (operation) {
506                         case '=':
507                                 /*
508                                  * Remove current flags for the value set,
509                                  * replace with new flags.
510                                  *
511                                  * Spec requires that an "=" operation with
512                                  * no value set be treated as an "=" operation
513                                  * with a value set equivilent to "all".
514                                  */
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,
520                                             CAP_ALL_ON);
521                                 } else {
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,
526                                             cap_value_set_v);
527                                 }
528                                 break;
529                         case '+':
530                                 /*
531                                  * Add current flags to value set.
532                                  *
533                                  * Spec requires that a "+" operation with
534                                  * no value set be rejected.
535                                  */
536                                 if (cap_value_set_v == CAP_ALL_OFF)
537                                         goto err2;
538                                 cap_set(cap, cap_action_v, CAP_SET,
539                                     cap_value_set_v);
540                                 break;
541                         case '-':
542                                 /*
543                                  * Subtract current flags from value set.
544                                  *
545                                  * Spec requires that a "-" operation with
546                                  * no value set be treated as a "-" operation
547                                  * with a value set equivilent to "all".
548                                  */
549                                 if (cap_value_set_v == CAP_ALL_OFF)
550                                         cap_set(cap, cap_action_v, CAP_CLEAR,
551                                             CAP_ALL_ON);
552                                 else
553                                         cap_set(cap, cap_action_v, CAP_CLEAR,
554                                             cap_value_set_v);
555                                 break;
556                         default:
557                                 goto err2;
558                         }
559                         operation = next_operation;
560                 }
561         }
562
563         return (cap);
564  err2:
565         errno = EINVAL;
566         free(mybuf);
567  err1:
568         cap_free(cap);
569         return ((cap_t)NULL);
570 }
571