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