1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2015 Gary Mills
24 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25 */
26
27 #pragma weak _getprivimplinfo = getprivimplinfo
28 #pragma weak _priv_addset = priv_addset
29 #pragma weak _priv_allocset = priv_allocset
30 #pragma weak _priv_copyset = priv_copyset
31 #pragma weak _priv_delset = priv_delset
32 #pragma weak _priv_emptyset = priv_emptyset
33 #pragma weak _priv_basicset = priv_basicset
34 #pragma weak _priv_fillset = priv_fillset
35 #pragma weak _priv_freeset = priv_freeset
36 #pragma weak _priv_getbyname = priv_getbyname
37 #pragma weak _priv_getbynum = priv_getbynum
38 #pragma weak _priv_getsetbyname = priv_getsetbyname
39 #pragma weak _priv_getsetbynum = priv_getsetbynum
40 #pragma weak _priv_ineffect = priv_ineffect
41 #pragma weak _priv_intersect = priv_intersect
42 #pragma weak _priv_inverse = priv_inverse
43 #pragma weak _priv_isemptyset = priv_isemptyset
44 #pragma weak _priv_isequalset = priv_isequalset
45 #pragma weak _priv_isfullset = priv_isfullset
46 #pragma weak _priv_ismember = priv_ismember
47 #pragma weak _priv_issubset = priv_issubset
48 #pragma weak _priv_set = priv_set
49 #pragma weak _priv_union = priv_union
50
51 #include "lint.h"
52
53 #define _STRUCTURED_PROC 1
54
55 #include "priv_private.h"
56 #include "mtlib.h"
57 #include "libc.h"
58 #include <errno.h>
59 #include <stdarg.h>
60 #include <stdlib.h>
61 #include <unistd.h>
62 #include <strings.h>
63 #include <synch.h>
64 #include <alloca.h>
65 #include <atomic.h>
66 #include <sys/ucred.h>
67 #include <sys/procfs.h>
68 #include <sys/param.h>
69 #include <sys/corectl.h>
70 #include <priv_utils.h>
71 #include <zone.h>
72
73 /* Include each string only once - until the compiler/linker are fixed */
74 static const char *permitted = PRIV_PERMITTED;
75 static const char *effective = PRIV_EFFECTIVE;
76 static const char *limit = PRIV_LIMIT;
77 static const char *inheritable = PRIV_INHERITABLE;
78 /*
79 * Data independent privilege set operations.
80 *
81 * Only a few functions are provided that do not default to
82 * the system implementation of privileges. A limited set of
83 * interfaces is provided that accepts a priv_data_t *
84 * argument; this set of interfaces is a private interface between libc
85 * and libproc. It is delivered in order to interpret privilege sets
86 * in debuggers in a implementation independent way. As such, we
87 * don't need to provide the bulk of the interfaces, only a few
88 * boolean tests (isfull, isempty) the name<->num mappings and
89 * set pretty print functions. The boolean tests are only needed for
90 * the latter, so those aren't provided externally.
91 *
92 * Additionally, we provide the function that maps the kernel implementation
93 * structure into a libc private data structure.
94 */
95
96 priv_data_t *privdata;
97
98 static mutex_t pd_lock = DEFAULTMUTEX;
99
100 static int
101 parseninfo(priv_info_names_t *na, char ***buf, int *cp)
102 {
103 char *q;
104 int i;
105
106 *buf = libc_malloc(sizeof (char *) * na->cnt);
107
108 if (*buf == NULL)
109 return (-1);
110
111 q = na->names;
112
113 for (i = 0; i < na->cnt; i++) {
114 int l = strlen(q);
115
116 (*buf)[i] = q;
117 q += l + 1;
118 }
119 *cp = na->cnt;
120 return (0);
121 }
122
123 struct strint {
124 char *name;
125 int rank;
126 };
127
128 static int
129 strintcmp(const void *a, const void *b)
130 {
131 const struct strint *ap = a;
132 const struct strint *bp = b;
133
134 return (strcasecmp(ap->name, bp->name));
135 }
136
137 priv_data_t *
138 __priv_parse_info(priv_impl_info_t *ip)
139 {
140 priv_data_t *tmp;
141 char *x;
142 size_t size = PRIV_IMPL_INFO_SIZE(ip);
143 int i;
144
145 tmp = libc_malloc(sizeof (*tmp));
146
147 if (tmp == NULL)
148 return (NULL);
149
150 (void) memset(tmp, 0, sizeof (*tmp));
151
152 tmp->pd_pinfo = ip;
153 tmp->pd_setsize = sizeof (priv_chunk_t) * ip->priv_setsize;
154 tmp->pd_ucredsize = UCRED_SIZE(ip);
155
156 x = (char *)ip;
157 x += ip->priv_headersize;
158
159 while (x < ((char *)ip) + size) {
160 /* LINTED: alignment */
161 priv_info_names_t *na = (priv_info_names_t *)x;
162 /* LINTED: alignment */
163 priv_info_set_t *st = (priv_info_set_t *)x;
164 struct strint *tmparr;
165
166 switch (na->info.priv_info_type) {
167 case PRIV_INFO_SETNAMES:
168 if (parseninfo(na, &tmp->pd_setnames, &tmp->pd_nsets))
169 goto out;
170 break;
171 case PRIV_INFO_PRIVNAMES:
172 if (parseninfo(na, &tmp->pd_privnames, &tmp->pd_nprivs))
173 goto out;
174 /*
175 * We compute a sorted index which allows us
176 * to present a sorted list of privileges
177 * without actually having to sort it each time.
178 */
179 tmp->pd_setsort = libc_malloc(tmp->pd_nprivs *
180 sizeof (int));
181 if (tmp->pd_setsort == NULL)
182 goto out;
183
184 tmparr = libc_malloc(tmp->pd_nprivs *
185 sizeof (struct strint));
186
187 if (tmparr == NULL)
188 goto out;
189
190 for (i = 0; i < tmp->pd_nprivs; i++) {
191 tmparr[i].rank = i;
192 tmparr[i].name = tmp->pd_privnames[i];
193 }
194 qsort(tmparr, tmp->pd_nprivs, sizeof (struct strint),
195 strintcmp);
196 for (i = 0; i < tmp->pd_nprivs; i++)
197 tmp->pd_setsort[i] = tmparr[i].rank;
198 libc_free(tmparr);
199 break;
200 case PRIV_INFO_BASICPRIVS:
201 tmp->pd_basicset = (priv_set_t *)&st->set[0];
202 break;
203 case PRIV_INFO_DEFAULTPRIVS:
204 tmp->pd_defaultset = (priv_set_t *)&st->set[0];
205 break;
206 default:
207 /* unknown, ignore */
208 break;
209 }
210 x += na->info.priv_info_size;
211 }
212 return (tmp);
213 out:
214 libc_free(tmp->pd_setnames);
215 libc_free(tmp->pd_privnames);
216 libc_free(tmp->pd_setsort);
217 libc_free(tmp);
218 return (NULL);
219 }
220
221 /*
222 * Caller must have allocated d->pd_pinfo and should free it,
223 * if necessary.
224 */
225 void
226 __priv_free_info(priv_data_t *d)
227 {
228 libc_free(d->pd_setnames);
229 libc_free(d->pd_privnames);
230 libc_free(d->pd_setsort);
231 libc_free(d);
232 }
233
234 /*
235 * Return with the pd_lock held and data loaded or indicate failure.
236 */
237 int
238 lock_data(void)
239 {
240 if (__priv_getdata() == NULL)
241 return (-1);
242
243 lmutex_lock(&pd_lock);
244 return (0);
245 }
246
247 boolean_t
248 refresh_data(void)
249 {
250 priv_impl_info_t *ip, ii;
251 priv_data_t *tmp;
252 char *p0, *q0;
253 int oldn, newn;
254 int i;
255
256 if (getprivinfo(&ii, sizeof (ii)) != 0 ||
257 ii.priv_max == privdata->pd_nprivs)
258 return (B_FALSE);
259
260 ip = alloca(PRIV_IMPL_INFO_SIZE(&ii));
261
262 (void) getprivinfo(ip, PRIV_IMPL_INFO_SIZE(&ii));
263
264 /* Parse the info; then copy the additional bits */
265 tmp = __priv_parse_info(ip);
266 if (tmp == NULL)
267 return (B_FALSE);
268
269 oldn = privdata->pd_nprivs;
270 p0 = privdata->pd_privnames[0];
271
272 newn = tmp->pd_nprivs;
273 q0 = tmp->pd_privnames[0];
274
275 /* copy the extra information to the old datastructure */
276 (void) memcpy((char *)privdata->pd_pinfo + sizeof (priv_impl_info_t),
277 (char *)ip + sizeof (priv_impl_info_t),
278 PRIV_IMPL_INFO_SIZE(ip) - sizeof (priv_impl_info_t));
279
280 /* Copy the first oldn pointers */
281 (void) memcpy(tmp->pd_privnames, privdata->pd_privnames,
282 oldn * sizeof (char *));
283
284 /* Adjust the rest */
285 for (i = oldn; i < newn; i++)
286 tmp->pd_privnames[i] += p0 - q0;
287
288 /* Install the larger arrays */
289 libc_free(privdata->pd_privnames);
290 privdata->pd_privnames = tmp->pd_privnames;
291 tmp->pd_privnames = NULL;
292
293 libc_free(privdata->pd_setsort);
294 privdata->pd_setsort = tmp->pd_setsort;
295 tmp->pd_setsort = NULL;
296
297 /* Copy the rest of the data */
298 *privdata->pd_pinfo = *ip;
299
300 privdata->pd_nprivs = newn;
301
302 __priv_free_info(tmp);
303 return (B_TRUE);
304 }
305
306 void
307 unlock_data(void)
308 {
309 lmutex_unlock(&pd_lock);
310 }
311
312 static priv_set_t *__priv_allocset(priv_data_t *);
313
314 priv_data_t *
315 __priv_getdata(void)
316 {
317 if (privdata == NULL) {
318 lmutex_lock(&pd_lock);
319 if (privdata == NULL) {
320 priv_data_t *tmp;
321 priv_impl_info_t *ip;
322 size_t size = sizeof (priv_impl_info_t) + 2048;
323 size_t realsize;
324 priv_impl_info_t *aip = alloca(size);
325
326 if (getprivinfo(aip, size) != 0)
327 goto out;
328
329 realsize = PRIV_IMPL_INFO_SIZE(aip);
330
331 ip = libc_malloc(realsize);
332
333 if (ip == NULL)
334 goto out;
335
336 if (realsize <= size) {
337 (void) memcpy(ip, aip, realsize);
338 } else if (getprivinfo(ip, realsize) != 0) {
339 libc_free(ip);
340 goto out;
341 }
342
343 if ((tmp = __priv_parse_info(ip)) == NULL) {
344 libc_free(ip);
345 goto out;
346 }
347
348 /* Allocate the zoneset just once, here */
349 tmp->pd_zoneset = __priv_allocset(tmp);
350 if (tmp->pd_zoneset == NULL)
351 goto clean;
352
353 if (zone_getattr(getzoneid(), ZONE_ATTR_PRIVSET,
354 tmp->pd_zoneset, tmp->pd_setsize)
355 == tmp->pd_setsize) {
356 membar_producer();
357 privdata = tmp;
358 goto out;
359 }
360
361 priv_freeset(tmp->pd_zoneset);
362 clean:
363 __priv_free_info(tmp);
364 libc_free(ip);
365 }
366 out:
367 lmutex_unlock(&pd_lock);
368 }
369 membar_consumer();
370 return (privdata);
371 }
372
373 const priv_impl_info_t *
374 getprivimplinfo(void)
375 {
376 priv_data_t *d;
377
378 LOADPRIVDATA(d);
379
380 return (d->pd_pinfo);
381 }
382
383 static priv_set_t *
384 priv_vlist(va_list ap)
385 {
386 priv_set_t *pset = priv_allocset();
387 const char *priv;
388
389 if (pset == NULL)
390 return (NULL);
391
392 priv_emptyset(pset);
393
394 while ((priv = va_arg(ap, const char *)) != NULL) {
395 if (priv_addset(pset, priv) < 0) {
396 priv_freeset(pset);
397 return (NULL);
398 }
399 }
400 return (pset);
401 }
402
403 /*
404 * priv_set(op, set, priv_id1, priv_id2, ..., NULL)
405 *
406 * Library routine to enable a user process to set a specific
407 * privilege set appropriately using a single call. User is
408 * required to terminate the list of privileges with NULL.
409 */
410 int
411 priv_set(priv_op_t op, priv_ptype_t setname, ...)
412 {
413 va_list ap;
414 priv_set_t *pset;
415 int ret;
416
417 va_start(ap, setname);
418
419 pset = priv_vlist(ap);
420
421 va_end(ap);
422
423 if (pset == NULL)
424 return (-1);
425
426 /* All sets */
427 if (setname == NULL) {
428 priv_data_t *d;
429 int set;
430
431 LOADPRIVDATA(d);
432
433 for (set = 0; set < d->pd_nsets; set++)
434 if ((ret = syscall(SYS_privsys, PRIVSYS_SETPPRIV, op,
435 set, (void *)pset, d->pd_setsize)) != 0)
436 break;
437 } else {
438 ret = setppriv(op, setname, pset);
439 }
440
441 priv_freeset(pset);
442 return (ret);
443 }
444
445 /*
446 * priv_ineffect(privilege).
447 * tests the existence of a privilege against the effective set.
448 */
449 boolean_t
450 priv_ineffect(const char *priv)
451 {
452 priv_set_t *curset;
453 boolean_t res;
454
455 curset = priv_allocset();
456
457 if (curset == NULL)
458 return (B_FALSE);
459
460 if (getppriv(effective, curset) != 0 ||
461 !priv_ismember(curset, priv))
462 res = B_FALSE;
463 else
464 res = B_TRUE;
465
466 priv_freeset(curset);
467
468 return (res);
469 }
470
471 /*
472 * The routine __init_daemon_priv() is private to Solaris and is
473 * used by daemons to limit the privileges they can use and
474 * to set the uid they run under.
475 */
476
477 static const char root_cp[] = "/core.%f.%t";
478 static const char daemon_cp[] = "/var/tmp/core.%f.%t";
479
480 int
481 __init_daemon_priv(int flags, uid_t uid, gid_t gid, ...)
482 {
483 priv_set_t *nset;
484 priv_set_t *perm = NULL;
485 va_list pa;
486 priv_data_t *d;
487 int ret = -1;
488 char buf[1024];
489
490 LOADPRIVDATA(d);
491
492 va_start(pa, gid);
493
494 nset = priv_vlist(pa);
495
496 va_end(pa);
497
498 if (nset == NULL)
499 return (-1);
500
501 /* Always add the basic set */
502 /* XXX: Always add the _default_ set? */
503 if (d->pd_basicset != NULL)
504 priv_union(d->pd_basicset, nset);
505
506 /*
507 * This is not a significant failure: it allows us to start programs
508 * with sufficient privileges and with the proper uid. We don't
509 * care enough about the extra groups in that case.
510 */
511 if (flags & PU_RESETGROUPS)
512 (void) setgroups(0, NULL);
513
514 if (gid != (gid_t)-1 && setgid(gid) != 0)
515 goto end;
516
517 perm = priv_allocset();
518 if (perm == NULL)
519 goto end;
520
521 /* E = P */
522 (void) getppriv(permitted, perm);
523 (void) setppriv(PRIV_SET, effective, perm);
524
525 /* Now reset suid and euid */
526 if (uid != (uid_t)-1 && setreuid(uid, uid) != 0)
527 goto end;
528
529 /* Check for the limit privs */
530 if ((flags & PU_LIMITPRIVS) &&
531 setppriv(PRIV_SET, limit, nset) != 0)
532 goto end;
533
534 if (flags & PU_CLEARLIMITSET) {
535 priv_emptyset(perm);
536 if (setppriv(PRIV_SET, limit, perm) != 0)
537 goto end;
538 }
539
540 /* Remove the privileges from all the other sets */
541 if (setppriv(PRIV_SET, permitted, nset) != 0)
542 goto end;
543
544 if (!(flags & PU_INHERITPRIVS))
545 priv_emptyset(nset);
546
547 ret = setppriv(PRIV_SET, inheritable, nset);
548 end:
549 priv_freeset(nset);
550 priv_freeset(perm);
551
552 if (core_get_process_path(buf, sizeof (buf), getpid()) == 0 &&
553 strcmp(buf, "core") == 0) {
554
555 if ((uid == (uid_t)-1 ? geteuid() : uid) == 0) {
556 (void) core_set_process_path(root_cp, sizeof (root_cp),
557 getpid());
558 } else {
559 (void) core_set_process_path(daemon_cp,
560 sizeof (daemon_cp), getpid());
561 }
562 }
563 (void) setpflags(__PROC_PROTECT, 0);
564
565 return (ret);
566 }
567
568 /*
569 * The routine __fini_daemon_priv() is private to Solaris and is
570 * used by daemons to clear remaining unwanted privileges and
571 * reenable core dumps.
572 */
573 void
574 __fini_daemon_priv(const char *priv, ...)
575 {
576 priv_set_t *nset;
577 va_list pa;
578
579 if (priv != NULL) {
580
581 va_start(pa, priv);
582 nset = priv_vlist(pa);
583 va_end(pa);
584
585 if (nset == NULL)
586 return;
587
588 (void) priv_addset(nset, priv);
589 (void) setppriv(PRIV_OFF, permitted, nset);
590 priv_freeset(nset);
591 }
592
593 (void) setpflags(__PROC_PROTECT, 0);
594 }
595
596 /*
597 * The routine __init_suid_priv() is private to Solaris and is
598 * used by set-uid root programs to limit the privileges acquired
599 * to those actually needed.
600 */
601
602 static priv_set_t *bracketpriv;
603
604 int
605 __init_suid_priv(int flags, ...)
606 {
607 priv_set_t *nset = NULL;
608 priv_set_t *tmpset = NULL;
609 va_list pa;
610 int r = -1;
611 uid_t ruid, euid;
612
613 euid = geteuid();
614
615 /* If we're not set-uid root, don't reset the uid */
616 if (euid == 0) {
617 ruid = getuid();
618 /* If we're running as root, keep everything */
619 if (ruid == 0)
620 return (0);
621 }
622
623 /* Can call this only once */
624 if (bracketpriv != NULL)
625 return (-1);
626
627 va_start(pa, flags);
628
629 nset = priv_vlist(pa);
630
631 va_end(pa);
632
633 if (nset == NULL)
634 goto end;
635
636 tmpset = priv_allocset();
637
638 if (tmpset == NULL)
639 goto end;
640
641 /* We cannot grow our privileges beyond P, so start there */
642 (void) getppriv(permitted, tmpset);
643
644 /* Is the privilege we need even in P? */
645 if (!priv_issubset(nset, tmpset))
646 goto end;
647
648 bracketpriv = priv_allocset();
649 if (bracketpriv == NULL)
650 goto end;
651
652 priv_copyset(nset, bracketpriv);
653
654 /* Always add the basic set */
655 /* XXX: Always add the default set? */
656 priv_union(priv_basic(), nset);
657
658 /* But don't add what we don't have */
659 priv_intersect(tmpset, nset);
660
661 (void) getppriv(inheritable, tmpset);
662
663 /* And stir in the inheritable privileges */
664 priv_union(tmpset, nset);
665
666 if ((r = setppriv(PRIV_SET, effective, tmpset)) != 0)
667 goto end;
668
669 if ((r = setppriv(PRIV_SET, permitted, nset)) != 0)
670 goto end;
671
672 if (flags & PU_CLEARLIMITSET)
673 priv_emptyset(nset);
674
675 if ((flags & (PU_LIMITPRIVS|PU_CLEARLIMITSET)) != 0 &&
676 (r = setppriv(PRIV_SET, limit, nset)) != 0)
677 goto end;
678
679 if (euid == 0)
680 r = setreuid(ruid, ruid);
681
682 end:
683 priv_freeset(tmpset);
684 priv_freeset(nset);
685 if (r != 0) {
686 /* Fail without leaving uid 0 around */
687 if (euid == 0)
688 (void) setreuid(ruid, ruid);
689 priv_freeset(bracketpriv);
690 bracketpriv = NULL;
691 }
692
693 return (r);
694 }
695
696 /*
697 * Toggle privileges on/off in the effective set.
698 */
699 int
700 __priv_bracket(priv_op_t op)
701 {
702 /* We're running fully privileged or didn't check errors first time */
703 if (bracketpriv == NULL)
704 return (0);
705
706 /* Only PRIV_ON and PRIV_OFF are valid */
707 if (op == PRIV_SET)
708 return (-1);
709
710 return (setppriv(op, effective, bracketpriv));
711 }
712
713 /*
714 * Remove privileges from E & P.
715 */
716 void
717 __priv_relinquish(void)
718 {
719 if (bracketpriv != NULL) {
720 (void) setppriv(PRIV_OFF, permitted, bracketpriv);
721 priv_freeset(bracketpriv);
722 bracketpriv = NULL;
723 }
724 }
725
726 /*
727 * Use binary search on the ordered list.
728 */
729 int
730 __priv_getbyname(const priv_data_t *d, const char *name)
731 {
732 char *const *list;
733 const int *order;
734 int lo = 0;
735 int hi;
736
737 if (d == NULL)
738 return (-1);
739
740 list = d->pd_privnames;
741 order = d->pd_setsort;
742 hi = d->pd_nprivs - 1;
743
744 if (strncasecmp(name, "priv_", 5) == 0)
745 name += 5;
746
747 do {
748 int mid = (lo + hi) / 2;
749 int res = strcasecmp(name, list[order[mid]]);
750
751 if (res == 0)
752 return (order[mid]);
753 else if (res < 0)
754 hi = mid - 1;
755 else
756 lo = mid + 1;
757 } while (lo <= hi);
758
759 errno = EINVAL;
760 return (-1);
761 }
762
763 int
764 priv_getbyname(const char *name)
765 {
766 WITHPRIVLOCKED(int, -1, __priv_getbyname(GETPRIVDATA(), name))
767 }
768
769 int
770 __priv_getsetbyname(const priv_data_t *d, const char *name)
771 {
772 int i;
773 int n = d->pd_nsets;
774 char *const *list = d->pd_setnames;
775
776 if (strncasecmp(name, "priv_", 5) == 0)
777 name += 5;
778
779 for (i = 0; i < n; i++) {
780 if (strcasecmp(list[i], name) == 0)
781 return (i);
782 }
783
784 errno = EINVAL;
785 return (-1);
786 }
787
788 int
789 priv_getsetbyname(const char *name)
790 {
791 /* Not locked: sets don't change */
792 return (__priv_getsetbyname(GETPRIVDATA(), name));
793 }
794
795 static const char *
796 priv_bynum(int i, int n, char **list)
797 {
798 if (i < 0 || i >= n)
799 return (NULL);
800
801 return (list[i]);
802 }
803
804 const char *
805 __priv_getbynum(const priv_data_t *d, int num)
806 {
807 if (d == NULL)
808 return (NULL);
809 return (priv_bynum(num, d->pd_nprivs, d->pd_privnames));
810 }
811
812 const char *
813 priv_getbynum(int num)
814 {
815 WITHPRIVLOCKED(const char *, NULL, __priv_getbynum(GETPRIVDATA(), num))
816 }
817
818 const char *
819 __priv_getsetbynum(const priv_data_t *d, int num)
820 {
821 if (d == NULL)
822 return (NULL);
823 return (priv_bynum(num, d->pd_nsets, d->pd_setnames));
824 }
825
826 const char *
827 priv_getsetbynum(int num)
828 {
829 return (__priv_getsetbynum(GETPRIVDATA(), num));
830 }
831
832
833 /*
834 * Privilege manipulation functions
835 *
836 * Without knowing the details of the privilege set implementation,
837 * opaque pointers can be used to manipulate sets at will.
838 */
839
840 static priv_set_t *
841 __priv_allocset(priv_data_t *d)
842 {
843 if (d == NULL)
844 return (NULL);
845
846 return (libc_malloc(d->pd_setsize));
847 }
848
849 priv_set_t *
850 priv_allocset(void)
851 {
852 return (__priv_allocset(GETPRIVDATA()));
853 }
854
855 void
856 priv_freeset(priv_set_t *p)
857 {
858 int er = errno;
859
860 libc_free(p);
861 errno = er;
862 }
863
864 void
865 __priv_emptyset(priv_data_t *d, priv_set_t *set)
866 {
867 (void) memset(set, 0, d->pd_setsize);
868 }
869
870 void
871 priv_emptyset(priv_set_t *set)
872 {
873 __priv_emptyset(GETPRIVDATA(), set);
874 }
875
876 void
877 priv_basicset(priv_set_t *set)
878 {
879 priv_copyset(priv_basic(), set);
880 }
881
882 void
883 priv_defaultset(priv_set_t *set)
884 {
885 priv_copyset(priv_default(), set);
886 }
887
888 void
889 __priv_fillset(priv_data_t *d, priv_set_t *set)
890 {
891 (void) memset(set, ~0, d->pd_setsize);
892 }
893
894 void
895 priv_fillset(priv_set_t *set)
896 {
897 __priv_fillset(GETPRIVDATA(), set);
898 }
899
900
901 #define PRIV_TEST_BODY_D(d, test) \
902 int i; \
903 \
904 for (i = d->pd_pinfo->priv_setsize; i-- > 0; ) \
905 if (!(test)) \
906 return (B_FALSE); \
907 \
908 return (B_TRUE)
909
910 boolean_t
911 priv_isequalset(const priv_set_t *a, const priv_set_t *b)
912 {
913 priv_data_t *d;
914
915 LOADPRIVDATA(d);
916
917 return ((boolean_t)(memcmp(a, b, d->pd_setsize) == 0));
918 }
919
920 boolean_t
921 __priv_isemptyset(priv_data_t *d, const priv_set_t *set)
922 {
923 PRIV_TEST_BODY_D(d, ((priv_chunk_t *)set)[i] == 0);
924 }
925
926 boolean_t
927 priv_isemptyset(const priv_set_t *set)
928 {
929 return (__priv_isemptyset(GETPRIVDATA(), set));
930 }
931
932 boolean_t
933 __priv_isfullset(priv_data_t *d, const priv_set_t *set)
934 {
935 PRIV_TEST_BODY_D(d, ((priv_chunk_t *)set)[i] == ~(priv_chunk_t)0);
936 }
937
938 boolean_t
939 priv_isfullset(const priv_set_t *set)
940 {
941 return (__priv_isfullset(GETPRIVDATA(), set));
942 }
943
944 /*
945 * Return true if a is a subset of b
946 */
947 boolean_t
948 __priv_issubset(priv_data_t *d, const priv_set_t *a, const priv_set_t *b)
949 {
950 PRIV_TEST_BODY_D(d, (((priv_chunk_t *)a)[i] | ((priv_chunk_t *)b)[i]) ==
951 ((priv_chunk_t *)b)[i]);
952 }
953
954 boolean_t
955 priv_issubset(const priv_set_t *a, const priv_set_t *b)
956 {
957 return (__priv_issubset(GETPRIVDATA(), a, b));
958 }
959
960 #define PRIV_CHANGE_BODY(a, op, b) \
961 int i; \
962 priv_data_t *d; \
963 \
964 LOADPRIVDATA(d); \
965 \
966 for (i = 0; i < d->pd_pinfo->priv_setsize; i++) \
967 ((priv_chunk_t *)a)[i] op \
968 ((priv_chunk_t *)b)[i]
969
970 /* B = A ^ B */
971 void
972 priv_intersect(const priv_set_t *a, priv_set_t *b)
973 {
974 /* CSTYLED */
975 PRIV_CHANGE_BODY(b, &=, a);
976 }
977
978 /* B = A */
979 void
980 priv_copyset(const priv_set_t *a, priv_set_t *b)
981 {
982 /* CSTYLED */
983 PRIV_CHANGE_BODY(b, =, a);
984 }
985
986 /* B = A v B */
987 void
988 priv_union(const priv_set_t *a, priv_set_t *b)
989 {
990 /* CSTYLED */
991 PRIV_CHANGE_BODY(b, |=, a);
992 }
993
994 /* A = ! A */
995 void
996 priv_inverse(priv_set_t *a)
997 {
998 PRIV_CHANGE_BODY(a, = ~, a);
999 }
1000
1001 /*
1002 * Manipulating single privileges.
1003 */
1004
1005 int
1006 priv_addset(priv_set_t *a, const char *p)
1007 {
1008 int priv = priv_getbyname(p);
1009
1010 if (priv < 0)
1011 return (-1);
1012
1013 PRIV_ADDSET(a, priv);
1014
1015 return (0);
1016 }
1017
1018 int
1019 priv_delset(priv_set_t *a, const char *p)
1020 {
1021 int priv = priv_getbyname(p);
1022
1023 if (priv < 0)
1024 return (-1);
1025
1026 PRIV_DELSET(a, priv);
1027 return (0);
1028 }
1029
1030 boolean_t
1031 priv_ismember(const priv_set_t *a, const char *p)
1032 {
1033 int priv = priv_getbyname(p);
1034
1035 if (priv < 0)
1036 return (B_FALSE);
1037
1038 return ((boolean_t)PRIV_ISMEMBER(a, priv));
1039 }