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