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