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 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 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 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 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 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 759 priv_getbyname(const char *name) 760 { 761 WITHPRIVLOCKED(int, -1, __priv_getbyname(GETPRIVDATA(), name)) 762 } 763 764 int 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 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 * 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 * 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 * 808 priv_getbynum(int num) 809 { 810 WITHPRIVLOCKED(const char *, NULL, __priv_getbynum(GETPRIVDATA(), num)) 811 } 812 813 const char * 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 * 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 * 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 * 845 priv_allocset(void) 846 { 847 return (__priv_allocset(GETPRIVDATA())); 848 } 849 850 void 851 priv_freeset(priv_set_t *p) 852 { 853 int er = errno; 854 855 libc_free(p); 856 errno = er; 857 } 858 859 void 860 __priv_emptyset(priv_data_t *d, priv_set_t *set) 861 { 862 (void) memset(set, 0, d->pd_setsize); 863 } 864 865 void 866 priv_emptyset(priv_set_t *set) 867 { 868 __priv_emptyset(GETPRIVDATA(), set); 869 } 870 871 void 872 priv_basicset(priv_set_t *set) 873 { 874 priv_copyset(priv_basic(), set); 875 } 876 877 void 878 __priv_fillset(priv_data_t *d, priv_set_t *set) 879 { 880 (void) memset(set, ~0, d->pd_setsize); 881 } 882 883 void 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 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 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 916 priv_isemptyset(const priv_set_t *set) 917 { 918 return (__priv_isemptyset(GETPRIVDATA(), set)); 919 } 920 921 boolean_t 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 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 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 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 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 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 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 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 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 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 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