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