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 }