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