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 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Privilege implementation.
  28  *
  29  * This file provides the infrastructure for privilege sets and limits
  30  * the number of files that requires to include <sys/cred_impl.h> and/or
  31  * <sys/priv_impl.h>.
  32  *
  33  * The Solaris privilege mechanism has been designed in a
  34  * future proof manner.  While the kernel may use fixed size arrays
  35  * and fixed bitmasks and bit values, the representation of those
  36  * is kernel private.  All external interfaces as well as K-to-K interfaces
  37  * have been constructed in a manner to provide the maximum flexibility.
  38  *
  39  * There can be X privilege sets each containing Y 32 bit words.
  40  * <X, Y> are constant for a kernel invocation.
  41  *
  42  * As a consequence, all privilege set manipulation happens in functions
  43  * below.
  44  *
  45  */
  46 
  47 #include <sys/systm.h>
  48 #include <sys/ddi.h>
  49 #include <sys/kmem.h>
  50 #include <sys/sunddi.h>
  51 #include <sys/errno.h>
  52 #include <sys/debug.h>
  53 #include <sys/priv_impl.h>
  54 #include <sys/procfs.h>
  55 #include <sys/policy.h>
  56 #include <sys/cred_impl.h>
  57 #include <sys/devpolicy.h>
  58 #include <sys/atomic.h>
  59 
  60 /*
  61  * Privilege name to number mapping table consists in the generated
  62  * priv_const.c file.  This lock protects against updates of the privilege
  63  * names and counts; all other priv_info fields are read-only.
  64  * The actual protected values are:
  65  *      global variable nprivs
  66  *      the priv_max field
  67  *      the priv_names field
  68  *      the priv names info item (cnt/strings)
  69  */
  70 krwlock_t privinfo_lock;
  71 
  72 static boolean_t priv_valid(const cred_t *);
  73 
  74 priv_set_t priv_fullset;        /* set of all privileges */
  75 priv_set_t priv_unsafe; /* unsafe to exec set-uid root if these are not in L */
  76 
  77 /*
  78  * Privilege initialization functions.
  79  * Called from common/os/cred.c when cred_init is called.
  80  */
  81 
  82 void
  83 priv_init(void)
  84 {
  85 #ifdef DEBUG
  86         int alloc_test_priv = 1;
  87 #else
  88         int alloc_test_priv = priv_debug;
  89 #endif
  90         rw_init(&privinfo_lock, NULL, RW_DRIVER, NULL);
  91 
  92         PRIV_BASIC_ASSERT(priv_basic);
  93         PRIV_UNSAFE_ASSERT(&priv_unsafe);
  94         priv_fillset(&priv_fullset);
  95 
  96         /*
  97          * When booting with priv_debug set or in a DEBUG kernel, then we'll
  98          * add an additional basic privilege and we verify that it is always
  99          * present in E.
 100          */
 101         if (alloc_test_priv != 0 &&
 102             (priv_basic_test = priv_getbyname("basic_test", PRIV_ALLOC)) >= 0) {
 103                 priv_addset(priv_basic, priv_basic_test);
 104         }
 105 
 106         devpolicy_init();
 107 }
 108 
 109 /* Utility functions: privilege sets as opaque data types */
 110 
 111 /*
 112  * Guts of prgetprivsize.
 113  */
 114 int
 115 priv_prgetprivsize(prpriv_t *tmpl)
 116 {
 117         return (sizeof (prpriv_t) +
 118             PRIV_SETBYTES - sizeof (priv_chunk_t) +
 119             (tmpl ? tmpl->pr_infosize : priv_info->priv_infosize));
 120 }
 121 
 122 /*
 123  * Guts of prgetpriv.
 124  */
 125 void
 126 cred2prpriv(const cred_t *cp, prpriv_t *pr)
 127 {
 128         priv_set_t *psa;
 129         int i;
 130 
 131         pr->pr_nsets = PRIV_NSET;
 132         pr->pr_setsize = PRIV_SETSIZE;
 133         pr->pr_infosize = priv_info->priv_infosize;
 134 
 135         psa = (priv_set_t *)pr->pr_sets;
 136 
 137         for (i = 0; i < PRIV_NSET; i++)
 138                 psa[i] = *priv_getset(cp, i);
 139 
 140         priv_getinfo(cp, (char *)pr + PRIV_PRPRIV_INFO_OFFSET(pr));
 141 }
 142 
 143 /*
 144  * Guts of pr_spriv:
 145  *
 146  * Set the privileges of a process.
 147  *
 148  * In order to set the privileges, the setting process will need to
 149  * have those privileges in its effective set in order to prevent
 150  * specially privileged processes to easily gain additional privileges.
 151  * Pre-existing privileges can be retained.  To change any privileges,
 152  * PRIV_PROC_OWNER needs to be asserted.
 153  *
 154  * In formula:
 155  *
 156  *      S' <= S || S' <= S + Ea
 157  *
 158  * the new set must either be subset of the old set or a subset of
 159  * the oldset merged with the effective set of the acting process; or just:
 160  *
 161  *      S' <= S + Ea
 162  *
 163  * It's not legal to grow the limit set this way.
 164  *
 165  */
 166 int
 167 priv_pr_spriv(proc_t *p, prpriv_t *prpriv, const cred_t *cr)
 168 {
 169         cred_t *oldcred;
 170         cred_t *newcred;
 171         int i;
 172         int err = EPERM;
 173         cred_priv_t *cp, *ocp;
 174         priv_set_t eset;
 175 
 176         ASSERT(MUTEX_HELD(&p->p_lock));
 177 
 178         /*
 179          * Set must have proper dimension; infosize must be absent
 180          * or properly sized.
 181          */
 182         if (prpriv->pr_nsets != PRIV_NSET ||
 183             prpriv->pr_setsize != PRIV_SETSIZE ||
 184             (prpriv->pr_infosize & (sizeof (uint32_t) - 1)) != 0 ||
 185             prpriv->pr_infosize > priv_info->priv_infosize)
 186                 return (EINVAL);
 187 
 188         mutex_exit(&p->p_lock);
 189 
 190         if (priv_proc_cred_perm(cr, p, &oldcred, VWRITE) != 0) {
 191                 mutex_enter(&p->p_lock);
 192                 return (EPERM);
 193         }
 194 
 195         newcred = crdup(oldcred);
 196 
 197         /* Copy the privilege sets from prpriv to newcred */
 198         bcopy(prpriv->pr_sets, CR_PRIVSETS(newcred), PRIV_SETBYTES);
 199 
 200         cp = &newcred->cr_priv;
 201         ocp = &oldcred->cr_priv;
 202         eset = CR_OEPRIV(cr);
 203 
 204         priv_intersect(&CR_LPRIV(oldcred), &eset);
 205 
 206         /*
 207          * Verify the constraints laid out:
 208          * for the limit set, we require that the new set is a subset
 209          * of the old limit set.
 210          * for all other sets, we require that the new set is either a
 211          * subset of the old set or a subset of the intersection of
 212          * the old limit set and the effective set of the acting process.
 213          */
 214         for (i = 0; i < PRIV_NSET; i++)
 215                 if (!priv_issubset(&cp->crprivs[i], &ocp->crprivs[i]) &&
 216                     (i == PRIV_LIMIT || !priv_issubset(&cp->crprivs[i], &eset)))
 217                         break;
 218 
 219         crfree(oldcred);
 220 
 221         if (i < PRIV_NSET || !priv_valid(newcred))
 222                 goto err;
 223 
 224         /* Load the settable privilege information */
 225         if (prpriv->pr_infosize > 0) {
 226                 char *x = (char *)prpriv + PRIV_PRPRIV_INFO_OFFSET(prpriv);
 227                 char *lastx = x + prpriv->pr_infosize;
 228 
 229                 while (x < lastx) {
 230                         priv_info_t *pi = (priv_info_t *)x;
 231                         priv_info_uint_t *pii;
 232 
 233                         switch (pi->priv_info_type) {
 234                         case PRIV_INFO_FLAGS:
 235                                 pii = (priv_info_uint_t *)x;
 236                                 if (pii->info.priv_info_size != sizeof (*pii)) {
 237                                         err = EINVAL;
 238                                         goto err;
 239                                 }
 240                                 CR_FLAGS(newcred) &= ~PRIV_USER;
 241                                 CR_FLAGS(newcred) |= (pii->val & PRIV_USER);
 242                                 break;
 243                         default:
 244                                 err = EINVAL;
 245                                 goto err;
 246                         }
 247                         /* Guarantee alignment and forward progress */
 248                         if ((pi->priv_info_size & (sizeof (uint32_t) - 1)) ||
 249                             pi->priv_info_size < sizeof (*pi) ||
 250                             lastx - x > pi->priv_info_size) {
 251                                 err = EINVAL;
 252                                 goto err;
 253                         }
 254 
 255                         x += pi->priv_info_size;
 256                 }
 257         }
 258 
 259         /*
 260          * We'll try to copy the privilege aware flag; but since the
 261          * privileges sets are all individually set, they are set
 262          * as if we're privilege aware.  If PRIV_AWARE wasn't set
 263          * or was explicitely unset, we need to set the flag and then
 264          * try to get rid of it.
 265          */
 266         if ((CR_FLAGS(newcred) & PRIV_AWARE) == 0) {
 267                 CR_FLAGS(newcred) |= PRIV_AWARE;
 268                 priv_adjust_PA(newcred);
 269         }
 270 
 271         mutex_enter(&p->p_crlock);
 272         oldcred = p->p_cred;
 273         p->p_cred = newcred;
 274         mutex_exit(&p->p_crlock);
 275         crfree(oldcred);
 276 
 277         mutex_enter(&p->p_lock);
 278         return (0);
 279 
 280 err:
 281         crfree(newcred);
 282         mutex_enter(&p->p_lock);
 283         return (err);
 284 }
 285 
 286 priv_impl_info_t
 287 *priv_hold_implinfo(void)
 288 {
 289         rw_enter(&privinfo_lock, RW_READER);
 290         return (priv_info);
 291 }
 292 
 293 void
 294 priv_release_implinfo(void)
 295 {
 296         rw_exit(&privinfo_lock);
 297 }
 298 
 299 size_t
 300 priv_get_implinfo_size(void)
 301 {
 302         return (privinfosize);
 303 }
 304 
 305 
 306 /*
 307  * Return the nth privilege set
 308  */
 309 const priv_set_t *
 310 priv_getset(const cred_t *cr, int set)
 311 {
 312         ASSERT(PRIV_VALIDSET(set));
 313 
 314         if ((CR_FLAGS(cr) & PRIV_AWARE) == 0)
 315                 switch (set) {
 316                 case PRIV_EFFECTIVE:
 317                         return (&CR_OEPRIV(cr));
 318                 case PRIV_PERMITTED:
 319                         return (&CR_OPPRIV(cr));
 320                 }
 321         return (&CR_PRIVS(cr)->crprivs[set]);
 322 }
 323 
 324 /*
 325  * Buf must be allocated by caller and contain sufficient space to
 326  * contain all additional info structures using priv_info.priv_infosize.
 327  * The buffer must be properly aligned.
 328  */
 329 /*ARGSUSED*/
 330 void
 331 priv_getinfo(const cred_t *cr, void *buf)
 332 {
 333         struct priv_info_uint *ii;
 334 
 335         ii = buf;
 336         ii->val = CR_FLAGS(cr);
 337         ii->info.priv_info_size = (uint32_t)sizeof (*ii);
 338         ii->info.priv_info_type = PRIV_INFO_FLAGS;
 339 }
 340 
 341 int
 342 priv_getbyname(const char *name, uint_t flag)
 343 {
 344         int i;
 345         int wheld = 0;
 346         int len;
 347         char *p;
 348 
 349         if (flag != 0 && flag != PRIV_ALLOC)
 350                 return (-EINVAL);
 351 
 352         if (strncasecmp(name, "priv_", 5) == 0)
 353                 name += 5;
 354 
 355         rw_enter(&privinfo_lock, RW_READER);
 356 rescan:
 357         for (i = 0; i < nprivs; i++)
 358                 if (strcasecmp(priv_names[i], name) == 0) {
 359                         rw_exit(&privinfo_lock);
 360                         return (i);
 361                 }
 362 
 363 
 364         if (!wheld) {
 365                 if (!(flag & PRIV_ALLOC)) {
 366                         rw_exit(&privinfo_lock);
 367                         return (-EINVAL);
 368                 }
 369 
 370                 /* check length, validity and available space */
 371                 len = strlen(name) + 1;
 372 
 373                 if (len > PRIVNAME_MAX) {
 374                         rw_exit(&privinfo_lock);
 375                         return (-ENAMETOOLONG);
 376                 }
 377 
 378                 for (p = (char *)name; *p != '\0'; p++) {
 379                         char c = *p;
 380 
 381                         if (!((c >= 'A' && c <= 'Z') ||
 382                             (c >= 'a' && c <= 'z') ||
 383                             (c >= '0' && c <= '9') ||
 384                             c == '_')) {
 385                                 rw_exit(&privinfo_lock);
 386                                 return (-EINVAL);
 387                         }
 388                 }
 389 
 390                 if (!rw_tryupgrade(&privinfo_lock)) {
 391                         rw_exit(&privinfo_lock);
 392                         rw_enter(&privinfo_lock, RW_WRITER);
 393                         wheld = 1;
 394                         /* Someone may have added our privilege */
 395                         goto rescan;
 396                 }
 397         }
 398 
 399         if (nprivs == MAX_PRIVILEGE || len + privbytes > maxprivbytes) {
 400                 rw_exit(&privinfo_lock);
 401                 return (-ENOMEM);
 402         }
 403 
 404         priv_names[i] = p = priv_str + privbytes;
 405 
 406         bcopy(name, p, len);
 407 
 408         /* make the priv_names[i] and privilege name globally visible */
 409         membar_producer();
 410 
 411         /* adjust priv count and bytes count */
 412         priv_ninfo->cnt = priv_info->priv_max = ++nprivs;
 413         privbytes += len;
 414 
 415         rw_exit(&privinfo_lock);
 416         return (i);
 417 }
 418 
 419 /*
 420  * We can't afford locking the privileges here because of the locations
 421  * we call this from; so we make sure that the privileges table
 422  * is visible to us; it is made visible before the value of nprivs is
 423  * updated.
 424  */
 425 const char *
 426 priv_getbynum(int priv)
 427 {
 428         int maxpriv = nprivs;
 429 
 430         membar_consumer();
 431 
 432         if (priv >= 0 && priv < maxpriv)
 433                 return (priv_names[priv]);
 434 
 435         return (NULL);
 436 }
 437 
 438 const char *
 439 priv_getsetbynum(int setno)
 440 {
 441         if (!PRIV_VALIDSET(setno))
 442                 return (NULL);
 443 
 444         return (priv_setnames[setno]);
 445 }
 446 
 447 /*
 448  * Privilege sanity checking when setting: E <= P.
 449  */
 450 static boolean_t
 451 priv_valid(const cred_t *cr)
 452 {
 453         return (priv_issubset(&CR_EPRIV(cr), &CR_PPRIV(cr)));
 454 }
 455 
 456 /*
 457  * Privilege manipulation functions
 458  *
 459  * Without knowing the details of the privilege set implementation,
 460  * opaque pointers can be used to manipulate sets at will.
 461  */
 462 void
 463 priv_emptyset(priv_set_t *set)
 464 {
 465         bzero(set, sizeof (*set));
 466 }
 467 
 468 void
 469 priv_fillset(priv_set_t *set)
 470 {
 471         int i;
 472 
 473         /* memset? */
 474         for (i = 0; i < PRIV_SETSIZE; i++)
 475                 set->pbits[i] = ~(priv_chunk_t)0;
 476 }
 477 
 478 void
 479 priv_addset(priv_set_t *set, int priv)
 480 {
 481         ASSERT(priv >= 0 && priv < MAX_PRIVILEGE);
 482         __PRIV_ASSERT(set, priv);
 483 }
 484 
 485 void
 486 priv_delset(priv_set_t *set, int priv)
 487 {
 488         ASSERT(priv >= 0 && priv < MAX_PRIVILEGE);
 489         __PRIV_CLEAR(set, priv);
 490 }
 491 
 492 boolean_t
 493 priv_ismember(const priv_set_t *set, int priv)
 494 {
 495         ASSERT(priv >= 0 && priv < MAX_PRIVILEGE);
 496         return (__PRIV_ISASSERT(set, priv) ? B_TRUE : B_FALSE);
 497 }
 498 
 499 #define PRIV_TEST_BODY(test) \
 500         int i; \
 501 \
 502         for (i = 0; i < PRIV_SETSIZE; i++) \
 503                 if (!(test)) \
 504                         return (B_FALSE); \
 505 \
 506         return (B_TRUE)
 507 
 508 boolean_t
 509 priv_isequalset(const priv_set_t *a, const priv_set_t *b)
 510 {
 511         return ((boolean_t)(bcmp(a, b, sizeof (*a)) == 0));
 512 }
 513 
 514 boolean_t
 515 priv_isemptyset(const priv_set_t *set)
 516 {
 517         PRIV_TEST_BODY(set->pbits[i] == 0);
 518 }
 519 
 520 boolean_t
 521 priv_isfullset(const priv_set_t *set)
 522 {
 523         PRIV_TEST_BODY(set->pbits[i] == ~(priv_chunk_t)0);
 524 }
 525 
 526 /*
 527  * Return true if a is a subset of b
 528  */
 529 boolean_t
 530 priv_issubset(const priv_set_t *a, const priv_set_t *b)
 531 {
 532         PRIV_TEST_BODY((a->pbits[i] | b->pbits[i]) == b->pbits[i]);
 533 }
 534 
 535 #define PRIV_CHANGE_BODY(a, op, b) \
 536         int i; \
 537 \
 538         for (i = 0; i < PRIV_SETSIZE; i++) \
 539                 a->pbits[i] op b->pbits[i]
 540 
 541 /* B = A ^ B */
 542 void
 543 priv_intersect(const priv_set_t *a, priv_set_t *b)
 544 {
 545         /* CSTYLED */
 546         PRIV_CHANGE_BODY(b, &=, a);
 547 }
 548 
 549 /* B = A v B */
 550 void
 551 priv_union(const priv_set_t *a, priv_set_t *b)
 552 {
 553         /* CSTYLED */
 554         PRIV_CHANGE_BODY(b, |=, a);
 555 }
 556 
 557 /* A = ! A */
 558 void
 559 priv_inverse(priv_set_t *a)
 560 {
 561         PRIV_CHANGE_BODY(a, = ~, a);
 562 }
 563 
 564 /*
 565  * Can the source cred act on the target credential?
 566  *
 567  * We will you allow to gain uids this way but not privileges.
 568  */
 569 int
 570 priv_proc_cred_perm(const cred_t *scr, proc_t *tp, cred_t **pcr, int mode)
 571 {
 572         const priv_set_t *eset;
 573         int idsmatch;
 574         cred_t *tcr;
 575         int res = 0;
 576 
 577         /* prevent the cred from going away */
 578         mutex_enter(&tp->p_crlock);
 579         crhold(tcr = tp->p_cred);
 580         mutex_exit(&tp->p_crlock);
 581 
 582         if (scr == tcr && !(tp->p_flag & SNOCD))
 583                 goto out;
 584 
 585         idsmatch = (scr->cr_uid == tcr->cr_uid &&
 586             scr->cr_uid == tcr->cr_ruid &&
 587             scr->cr_uid == tcr->cr_suid &&
 588             scr->cr_gid == tcr->cr_gid &&
 589             scr->cr_gid == tcr->cr_rgid &&
 590             scr->cr_gid == tcr->cr_sgid &&
 591             !(tp->p_flag & SNOCD));
 592 
 593         /*
 594          * Source credential must have the proc_zone privilege if referencing
 595          * a process in another zone.
 596          */
 597         if (scr->cr_zone != tcr->cr_zone && secpolicy_proc_zone(scr) != 0) {
 598                 res = EACCES;
 599                 goto out;
 600         }
 601 
 602         if (!(mode & VWRITE)) {
 603                 if (!idsmatch && secpolicy_proc_owner(scr, tcr, 0) != 0)
 604                         res = EACCES;
 605                 goto out;
 606         }
 607 
 608         /*
 609          * For writing, the effective set of scr must dominate all sets of tcr,
 610          * We test Pt <= Es (Et <= Pt so no need to test) and It <= Es
 611          * The Limit set of scr must be a superset of the limitset of
 612          * tcr.
 613          */
 614         eset = &CR_OEPRIV(scr);
 615 
 616         if (!priv_issubset(&CR_IPRIV(tcr), eset) ||
 617             !priv_issubset(&CR_OPPRIV(tcr), eset) ||
 618             !priv_issubset(&CR_LPRIV(tcr), &CR_LPRIV(scr)) ||
 619             !idsmatch && secpolicy_proc_owner(scr, tcr, mode) != 0)
 620                 res = EACCES;
 621 
 622 out:
 623         if (res == 0 && pcr != NULL)
 624                 *pcr = tcr;
 625         else
 626                 crfree(tcr);
 627         return (res);
 628 }
 629 
 630 /*
 631  * Set the privilege aware bit, adding L to E/P if necessary.
 632  * Each time we set it, we also clear PRIV_AWARE_RESET.
 633  */
 634 void
 635 priv_set_PA(cred_t *cr)
 636 {
 637         ASSERT(cr->cr_ref <= 2);
 638 
 639         if ((CR_FLAGS(cr) & (PRIV_AWARE|PRIV_AWARE_RESET)) == PRIV_AWARE)
 640                 return;
 641 
 642         CR_FLAGS(cr) |= PRIV_AWARE;
 643         CR_FLAGS(cr) &= ~PRIV_AWARE_RESET;
 644 
 645         if (cr->cr_uid == 0)
 646                 priv_union(&CR_LPRIV(cr), &CR_EPRIV(cr));
 647 
 648         if (cr->cr_uid == 0 || cr->cr_suid == 0 || cr->cr_ruid == 0)
 649                 priv_union(&CR_LPRIV(cr), &CR_PPRIV(cr));
 650 }
 651 
 652 boolean_t
 653 priv_can_clear_PA(const cred_t *cr)
 654 {
 655         /*
 656          * We can clear PA in the following cases:
 657          *
 658          * None of the uids are 0.
 659          * Any uid == 0 and P == L and (Euid != 0 or E == L)
 660          */
 661         return ((cr->cr_suid != 0 && cr->cr_ruid != 0 && cr->cr_uid != 0) ||
 662             priv_isequalset(&CR_PPRIV(cr), &CR_LPRIV(cr)) &&
 663             (cr->cr_uid != 0 || priv_isequalset(&CR_EPRIV(cr), &CR_LPRIV(cr))));
 664 }
 665 
 666 /*
 667  * Clear privilege aware bit if it is an idempotent operation and by
 668  * clearing it the process cannot get to uid 0 and all privileges.
 669  *
 670  * This function should be called with caution as it may cause "E" to be
 671  * lost once a processes assumes euid 0 again.
 672  */
 673 void
 674 priv_adjust_PA(cred_t *cr)
 675 {
 676         ASSERT(cr->cr_ref <= 2);
 677 
 678         if (!(CR_FLAGS(cr) & PRIV_AWARE) ||
 679             !priv_can_clear_PA(cr)) {
 680                 CR_FLAGS(cr) &= ~PRIV_AWARE_RESET;
 681                 return;
 682         }
 683 
 684         if (CR_FLAGS(cr) & PRIV_AWARE_INHERIT)
 685                 return;
 686 
 687         /*
 688          * We now need to adjust P/E in those cases when uids
 689          * are zero; the rules are P' = I & L, E' = I & L;
 690          * but since P = L and E = L, we can use P &= I, E &= I,
 691          * depending on which uids are 0.
 692          */
 693         if (cr->cr_suid == 0 || cr->cr_ruid == 0 || cr->cr_uid == 0) {
 694                 if (cr->cr_uid == 0)
 695                         priv_intersect(&CR_IPRIV(cr), &CR_EPRIV(cr));
 696                 priv_intersect(&CR_IPRIV(cr), &CR_PPRIV(cr));
 697         }
 698 
 699         CR_FLAGS(cr) &= ~(PRIV_AWARE|PRIV_AWARE_RESET);
 700 }
 701 
 702 /*
 703  * Reset privilege aware bit if so requested by setting the PRIV_AWARE_RESET
 704  * flag.
 705  */
 706 void
 707 priv_reset_PA(cred_t *cr, boolean_t finalize)
 708 {
 709         ASSERT(cr->cr_ref <= 2);
 710 
 711         if ((CR_FLAGS(cr) & (PRIV_AWARE|PRIV_AWARE_RESET)) !=
 712             (PRIV_AWARE|PRIV_AWARE_RESET)) {
 713                 CR_FLAGS(cr) &= ~PRIV_AWARE_RESET;
 714                 return;
 715         }
 716 
 717         /*
 718          * When PRIV_AWARE_RESET is enabled, any change of uids causes
 719          * a change to the P and E sets.  Bracketing with
 720          * seteuid(0) ... seteuid(uid)/setreuid(-1, 0) .. setreuid(-1, uid)
 721          * will cause the privilege sets "do the right thing.".
 722          * When the change of the uid is "final", e.g., by using setuid(uid),
 723          * or setreuid(uid, uid) or when the last set*uid() call causes all
 724          * uids to be the same, we set P and E to I & L, like when you exec.
 725          * We make an exception when all the uids are 0; this is required
 726          * when we login as root as in that particular case we cannot
 727          * make a distinction between seteuid(0) and seteuid(uid).
 728          * We rely on seteuid/setreuid/setuid to tell us with the
 729          * "finalize" argument that we no longer expect new uid changes,
 730          * cf. setreuid(uid, uid) and setuid(uid).
 731          */
 732         if (cr->cr_suid == cr->cr_ruid && cr->cr_suid == cr->cr_uid) {
 733                 if (finalize || cr->cr_uid != 0) {
 734                         CR_EPRIV(cr) = CR_IPRIV(cr);
 735                         priv_intersect(&CR_LPRIV(cr), &CR_EPRIV(cr));
 736                         CR_PPRIV(cr) = CR_EPRIV(cr);
 737                         CR_FLAGS(cr) &= ~(PRIV_AWARE|PRIV_AWARE_RESET);
 738                 } else {
 739                         CR_EPRIV(cr) = CR_PPRIV(cr);
 740                 }
 741         } else if (cr->cr_uid != 0 && (cr->cr_ruid == 0 || cr->cr_suid == 0)) {
 742                 CR_EPRIV(cr) = CR_IPRIV(cr);
 743                 priv_intersect(&CR_LPRIV(cr), &CR_EPRIV(cr));
 744         }
 745 }