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