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