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             prpriv->pr_infosize < 0)
 187                 return (EINVAL);
 188 
 189         mutex_exit(&p->p_lock);
 190 
 191         if (priv_proc_cred_perm(cr, p, &oldcred, VWRITE) != 0) {
 192                 mutex_enter(&p->p_lock);
 193                 return (EPERM);
 194         }
 195 
 196         newcred = crdup(oldcred);
 197 
 198         /* Copy the privilege sets from prpriv to newcred */
 199         bcopy(prpriv->pr_sets, CR_PRIVSETS(newcred), PRIV_SETBYTES);
 200 
 201         cp = &newcred->cr_priv;
 202         ocp = &oldcred->cr_priv;
 203         eset = CR_OEPRIV(cr);
 204 
 205         priv_intersect(&CR_LPRIV(oldcred), &eset);
 206 
 207         /*
 208          * Verify the constraints laid out:
 209          * for the limit set, we require that the new set is a subset
 210          * of the old limit set.
 211          * for all other sets, we require that the new set is either a
 212          * subset of the old set or a subset of the intersection of
 213          * the old limit set and the effective set of the acting process.
 214          */
 215         for (i = 0; i < PRIV_NSET; i++)
 216                 if (!priv_issubset(&cp->crprivs[i], &ocp->crprivs[i]) &&
 217                     (i == PRIV_LIMIT || !priv_issubset(&cp->crprivs[i], &eset)))
 218                         break;
 219 
 220         crfree(oldcred);
 221 
 222         if (i < PRIV_NSET || !priv_valid(newcred))
 223                 goto err;
 224 
 225         /* Load the settable privilege information */
 226         if (prpriv->pr_infosize > 0) {
 227                 char *x = (char *)prpriv + PRIV_PRPRIV_INFO_OFFSET(prpriv);
 228                 char *lastx = x + prpriv->pr_infosize;
 229 
 230                 while (x < lastx) {
 231                         priv_info_t *pi = (priv_info_t *)x;
 232                         priv_info_uint_t *pii;
 233 
 234                         switch (pi->priv_info_type) {
 235                         case PRIV_INFO_FLAGS:
 236                                 pii = (priv_info_uint_t *)x;
 237                                 if (pii->info.priv_info_size != sizeof (*pii)) {
 238                                         err = EINVAL;
 239                                         goto err;
 240                                 }
 241                                 CR_FLAGS(newcred) &= ~PRIV_USER;
 242                                 CR_FLAGS(newcred) |= (pii->val & PRIV_USER);
 243                                 break;
 244                         default:
 245                                 err = EINVAL;
 246                                 goto err;
 247                         }
 248                         /* Guarantee alignment and forward progress */
 249                         if ((pi->priv_info_size & (sizeof (uint32_t) - 1)) ||
 250                             pi->priv_info_size < sizeof (*pi) ||
 251                             lastx - x > pi->priv_info_size) {
 252                                 err = EINVAL;
 253                                 goto err;
 254                         }
 255 
 256                         x += pi->priv_info_size;
 257                 }
 258         }
 259 
 260         /*
 261          * We'll try to copy the privilege aware flag; but since the
 262          * privileges sets are all individually set, they are set
 263          * as if we're privilege aware.  If PRIV_AWARE wasn't set
 264          * or was explicitely unset, we need to set the flag and then
 265          * try to get rid of it.
 266          */
 267         if ((CR_FLAGS(newcred) & PRIV_AWARE) == 0) {
 268                 CR_FLAGS(newcred) |= PRIV_AWARE;
 269                 priv_adjust_PA(newcred);
 270         }
 271 
 272         mutex_enter(&p->p_crlock);
 273         oldcred = p->p_cred;
 274         p->p_cred = newcred;
 275         mutex_exit(&p->p_crlock);
 276         crfree(oldcred);
 277 
 278         mutex_enter(&p->p_lock);
 279         return (0);
 280 
 281 err:
 282         crfree(newcred);
 283         mutex_enter(&p->p_lock);
 284         return (err);
 285 }
 286 
 287 priv_impl_info_t
 288 *priv_hold_implinfo(void)
 289 {
 290         rw_enter(&privinfo_lock, RW_READER);
 291         return (priv_info);
 292 }
 293 
 294 void
 295 priv_release_implinfo(void)
 296 {
 297         rw_exit(&privinfo_lock);
 298 }
 299 
 300 size_t
 301 priv_get_implinfo_size(void)
 302 {
 303         return (privinfosize);
 304 }
 305 
 306 
 307 /*
 308  * Return the nth privilege set
 309  */
 310 const priv_set_t *
 311 priv_getset(const cred_t *cr, int set)
 312 {
 313         ASSERT(PRIV_VALIDSET(set));
 314 
 315         if ((CR_FLAGS(cr) & PRIV_AWARE) == 0)
 316                 switch (set) {
 317                 case PRIV_EFFECTIVE:
 318                         return (&CR_OEPRIV(cr));
 319                 case PRIV_PERMITTED:
 320                         return (&CR_OPPRIV(cr));
 321                 }
 322         return (&CR_PRIVS(cr)->crprivs[set]);
 323 }
 324 
 325 /*
 326  * Buf must be allocated by caller and contain sufficient space to
 327  * contain all additional info structures using priv_info.priv_infosize.
 328  * The buffer must be properly aligned.
 329  */
 330 /*ARGSUSED*/
 331 void
 332 priv_getinfo(const cred_t *cr, void *buf)
 333 {
 334         struct priv_info_uint *ii;
 335 
 336         ii = buf;
 337         ii->val = CR_FLAGS(cr);
 338         ii->info.priv_info_size = (uint32_t)sizeof (*ii);
 339         ii->info.priv_info_type = PRIV_INFO_FLAGS;
 340 }
 341 
 342 int
 343 priv_getbyname(const char *name, uint_t flag)
 344 {
 345         int i;
 346         int wheld = 0;
 347         int len;
 348         char *p;
 349 
 350         if (flag != 0 && flag != PRIV_ALLOC)
 351                 return (-EINVAL);
 352 
 353         if (strncasecmp(name, "priv_", 5) == 0)
 354                 name += 5;
 355 
 356         rw_enter(&privinfo_lock, RW_READER);
 357 rescan:
 358         for (i = 0; i < nprivs; i++)
 359                 if (strcasecmp(priv_names[i], name) == 0) {
 360                         rw_exit(&privinfo_lock);
 361                         return (i);
 362                 }
 363 
 364 
 365         if (!wheld) {
 366                 if (!(flag & PRIV_ALLOC)) {
 367                         rw_exit(&privinfo_lock);
 368                         return (-EINVAL);
 369                 }
 370 
 371                 /* check length, validity and available space */
 372                 len = strlen(name) + 1;
 373 
 374                 if (len > PRIVNAME_MAX) {
 375                         rw_exit(&privinfo_lock);
 376                         return (-ENAMETOOLONG);
 377                 }
 378 
 379                 for (p = (char *)name; *p != '\0'; p++) {
 380                         char c = *p;
 381 
 382                         if (!((c >= 'A' && c <= 'Z') ||
 383                             (c >= 'a' && c <= 'z') ||
 384                             (c >= '0' && c <= '9') ||
 385                             c == '_')) {
 386                                 rw_exit(&privinfo_lock);
 387                                 return (-EINVAL);
 388                         }
 389                 }
 390 
 391                 if (!rw_tryupgrade(&privinfo_lock)) {
 392                         rw_exit(&privinfo_lock);
 393                         rw_enter(&privinfo_lock, RW_WRITER);
 394                         wheld = 1;
 395                         /* Someone may have added our privilege */
 396                         goto rescan;
 397                 }
 398         }
 399 
 400         if (nprivs == MAX_PRIVILEGE || len + privbytes > maxprivbytes) {
 401                 rw_exit(&privinfo_lock);
 402                 return (-ENOMEM);
 403         }
 404 
 405         priv_names[i] = p = priv_str + privbytes;
 406 
 407         bcopy(name, p, len);
 408 
 409         /* make the priv_names[i] and privilege name globally visible */
 410         membar_producer();
 411 
 412         /* adjust priv count and bytes count */
 413         priv_ninfo->cnt = priv_info->priv_max = ++nprivs;
 414         privbytes += len;
 415 
 416         rw_exit(&privinfo_lock);
 417         return (i);
 418 }
 419 
 420 /*
 421  * We can't afford locking the privileges here because of the locations
 422  * we call this from; so we make sure that the privileges table
 423  * is visible to us; it is made visible before the value of nprivs is
 424  * updated.
 425  */
 426 const char *
 427 priv_getbynum(int priv)
 428 {
 429         int maxpriv = nprivs;
 430 
 431         membar_consumer();
 432 
 433         if (priv >= 0 && priv < maxpriv)
 434                 return (priv_names[priv]);
 435 
 436         return (NULL);
 437 }
 438 
 439 const char *
 440 priv_getsetbynum(int setno)
 441 {
 442         if (!PRIV_VALIDSET(setno))
 443                 return (NULL);
 444 
 445         return (priv_setnames[setno]);
 446 }
 447 
 448 /*
 449  * Privilege sanity checking when setting: E <= P.
 450  */
 451 static boolean_t
 452 priv_valid(const cred_t *cr)
 453 {
 454         return (priv_issubset(&CR_EPRIV(cr), &CR_PPRIV(cr)));
 455 }
 456 
 457 /*
 458  * Privilege manipulation functions
 459  *
 460  * Without knowing the details of the privilege set implementation,
 461  * opaque pointers can be used to manipulate sets at will.
 462  */
 463 void
 464 priv_emptyset(priv_set_t *set)
 465 {
 466         bzero(set, sizeof (*set));
 467 }
 468 
 469 void
 470 priv_fillset(priv_set_t *set)
 471 {
 472         int i;
 473 
 474         /* memset? */
 475         for (i = 0; i < PRIV_SETSIZE; i++)
 476                 set->pbits[i] = ~(priv_chunk_t)0;
 477 }
 478 
 479 void
 480 priv_addset(priv_set_t *set, int priv)
 481 {
 482         ASSERT(priv >= 0 && priv < MAX_PRIVILEGE);
 483         __PRIV_ASSERT(set, priv);
 484 }
 485 
 486 void
 487 priv_delset(priv_set_t *set, int priv)
 488 {
 489         ASSERT(priv >= 0 && priv < MAX_PRIVILEGE);
 490         __PRIV_CLEAR(set, priv);
 491 }
 492 
 493 boolean_t
 494 priv_ismember(const priv_set_t *set, int priv)
 495 {
 496         ASSERT(priv >= 0 && priv < MAX_PRIVILEGE);
 497         return (__PRIV_ISASSERT(set, priv) ? B_TRUE : B_FALSE);
 498 }
 499 
 500 #define PRIV_TEST_BODY(test) \
 501         int i; \
 502 \
 503         for (i = 0; i < PRIV_SETSIZE; i++) \
 504                 if (!(test)) \
 505                         return (B_FALSE); \
 506 \
 507         return (B_TRUE)
 508 
 509 boolean_t
 510 priv_isequalset(const priv_set_t *a, const priv_set_t *b)
 511 {
 512         return ((boolean_t)(bcmp(a, b, sizeof (*a)) == 0));
 513 }
 514 
 515 boolean_t
 516 priv_isemptyset(const priv_set_t *set)
 517 {
 518         PRIV_TEST_BODY(set->pbits[i] == 0);
 519 }
 520 
 521 boolean_t
 522 priv_isfullset(const priv_set_t *set)
 523 {
 524         PRIV_TEST_BODY(set->pbits[i] == ~(priv_chunk_t)0);
 525 }
 526 
 527 /*
 528  * Return true if a is a subset of b
 529  */
 530 boolean_t
 531 priv_issubset(const priv_set_t *a, const priv_set_t *b)
 532 {
 533         PRIV_TEST_BODY((a->pbits[i] | b->pbits[i]) == b->pbits[i]);
 534 }
 535 
 536 #define PRIV_CHANGE_BODY(a, op, b) \
 537         int i; \
 538 \
 539         for (i = 0; i < PRIV_SETSIZE; i++) \
 540                 a->pbits[i] op b->pbits[i]
 541 
 542 /* B = A ^ B */
 543 void
 544 priv_intersect(const priv_set_t *a, priv_set_t *b)
 545 {
 546         /* CSTYLED */
 547         PRIV_CHANGE_BODY(b, &=, a);
 548 }
 549 
 550 /* B = A v B */
 551 void
 552 priv_union(const priv_set_t *a, priv_set_t *b)
 553 {
 554         /* CSTYLED */
 555         PRIV_CHANGE_BODY(b, |=, a);
 556 }
 557 
 558 /* A = ! A */
 559 void
 560 priv_inverse(priv_set_t *a)
 561 {
 562         PRIV_CHANGE_BODY(a, = ~, a);
 563 }
 564 
 565 /*
 566  * Can the source cred act on the target credential?
 567  *
 568  * We will you allow to gain uids this way but not privileges.
 569  */
 570 int
 571 priv_proc_cred_perm(const cred_t *scr, proc_t *tp, cred_t **pcr, int mode)
 572 {
 573         const priv_set_t *eset;
 574         int idsmatch;
 575         cred_t *tcr;
 576         int res = 0;
 577 
 578         /* prevent the cred from going away */
 579         mutex_enter(&tp->p_crlock);
 580         crhold(tcr = tp->p_cred);
 581         mutex_exit(&tp->p_crlock);
 582 
 583         if (scr == tcr && !(tp->p_flag & SNOCD))
 584                 goto out;
 585 
 586         idsmatch = (scr->cr_uid == tcr->cr_uid &&
 587             scr->cr_uid == tcr->cr_ruid &&
 588             scr->cr_uid == tcr->cr_suid &&
 589             scr->cr_gid == tcr->cr_gid &&
 590             scr->cr_gid == tcr->cr_rgid &&
 591             scr->cr_gid == tcr->cr_sgid &&
 592             !(tp->p_flag & SNOCD));
 593 
 594         /*
 595          * Source credential must have the proc_zone privilege if referencing
 596          * a process in another zone.
 597          */
 598         if (scr->cr_zone != tcr->cr_zone && secpolicy_proc_zone(scr) != 0) {
 599                 res = EACCES;
 600                 goto out;
 601         }
 602 
 603         if (!(mode & VWRITE)) {
 604                 if (!idsmatch && secpolicy_proc_owner(scr, tcr, 0) != 0)
 605                         res = EACCES;
 606                 goto out;
 607         }
 608 
 609         /*
 610          * For writing, the effective set of scr must dominate all sets of tcr,
 611          * We test Pt <= Es (Et <= Pt so no need to test) and It <= Es
 612          * The Limit set of scr must be a superset of the limitset of
 613          * tcr.
 614          */
 615         eset = &CR_OEPRIV(scr);
 616 
 617         if (!priv_issubset(&CR_IPRIV(tcr), eset) ||
 618             !priv_issubset(&CR_OPPRIV(tcr), eset) ||
 619             !priv_issubset(&CR_LPRIV(tcr), &CR_LPRIV(scr)) ||
 620             !idsmatch && secpolicy_proc_owner(scr, tcr, mode) != 0)
 621                 res = EACCES;
 622 
 623 out:
 624         if (res == 0 && pcr != NULL)
 625                 *pcr = tcr;
 626         else
 627                 crfree(tcr);
 628         return (res);
 629 }
 630 
 631 /*
 632  * Set the privilege aware bit, adding L to E/P if necessary.
 633  * Each time we set it, we also clear PRIV_AWARE_RESET.
 634  */
 635 void
 636 priv_set_PA(cred_t *cr)
 637 {
 638         ASSERT(cr->cr_ref <= 2);
 639 
 640         if ((CR_FLAGS(cr) & (PRIV_AWARE|PRIV_AWARE_RESET)) == PRIV_AWARE)
 641                 return;
 642 
 643         CR_FLAGS(cr) |= PRIV_AWARE;
 644         CR_FLAGS(cr) &= ~PRIV_AWARE_RESET;
 645 
 646         if (cr->cr_uid == 0)
 647                 priv_union(&CR_LPRIV(cr), &CR_EPRIV(cr));
 648 
 649         if (cr->cr_uid == 0 || cr->cr_suid == 0 || cr->cr_ruid == 0)
 650                 priv_union(&CR_LPRIV(cr), &CR_PPRIV(cr));
 651 }
 652 
 653 boolean_t
 654 priv_can_clear_PA(const cred_t *cr)
 655 {
 656         /*
 657          * We can clear PA in the following cases:
 658          *
 659          * None of the uids are 0.
 660          * Any uid == 0 and P == L and (Euid != 0 or E == L)
 661          */
 662         return ((cr->cr_suid != 0 && cr->cr_ruid != 0 && cr->cr_uid != 0) ||
 663             priv_isequalset(&CR_PPRIV(cr), &CR_LPRIV(cr)) &&
 664             (cr->cr_uid != 0 || priv_isequalset(&CR_EPRIV(cr), &CR_LPRIV(cr))));
 665 }
 666 
 667 /*
 668  * Clear privilege aware bit if it is an idempotent operation and by
 669  * clearing it the process cannot get to uid 0 and all privileges.
 670  *
 671  * This function should be called with caution as it may cause "E" to be
 672  * lost once a processes assumes euid 0 again.
 673  */
 674 void
 675 priv_adjust_PA(cred_t *cr)
 676 {
 677         ASSERT(cr->cr_ref <= 2);
 678 
 679         if (!(CR_FLAGS(cr) & PRIV_AWARE) ||
 680             !priv_can_clear_PA(cr)) {
 681                 CR_FLAGS(cr) &= ~PRIV_AWARE_RESET;
 682                 return;
 683         }
 684 
 685         if (CR_FLAGS(cr) & PRIV_AWARE_INHERIT)
 686                 return;
 687 
 688         /*
 689          * We now need to adjust P/E in those cases when uids
 690          * are zero; the rules are P' = I & L, E' = I & L;
 691          * but since P = L and E = L, we can use P &= I, E &= I,
 692          * depending on which uids are 0.
 693          */
 694         if (cr->cr_suid == 0 || cr->cr_ruid == 0 || cr->cr_uid == 0) {
 695                 if (cr->cr_uid == 0)
 696                         priv_intersect(&CR_IPRIV(cr), &CR_EPRIV(cr));
 697                 priv_intersect(&CR_IPRIV(cr), &CR_PPRIV(cr));
 698         }
 699 
 700         CR_FLAGS(cr) &= ~(PRIV_AWARE|PRIV_AWARE_RESET);
 701 }
 702 
 703 /*
 704  * Reset privilege aware bit if so requested by setting the PRIV_AWARE_RESET
 705  * flag.
 706  */
 707 void
 708 priv_reset_PA(cred_t *cr, boolean_t finalize)
 709 {
 710         ASSERT(cr->cr_ref <= 2);
 711 
 712         if ((CR_FLAGS(cr) & (PRIV_AWARE|PRIV_AWARE_RESET)) !=
 713             (PRIV_AWARE|PRIV_AWARE_RESET)) {
 714                 CR_FLAGS(cr) &= ~PRIV_AWARE_RESET;
 715                 return;
 716         }
 717 
 718         /*
 719          * When PRIV_AWARE_RESET is enabled, any change of uids causes
 720          * a change to the P and E sets.  Bracketing with
 721          * seteuid(0) ... seteuid(uid)/setreuid(-1, 0) .. setreuid(-1, uid)
 722          * will cause the privilege sets "do the right thing.".
 723          * When the change of the uid is "final", e.g., by using setuid(uid),
 724          * or setreuid(uid, uid) or when the last set*uid() call causes all
 725          * uids to be the same, we set P and E to I & L, like when you exec.
 726          * We make an exception when all the uids are 0; this is required
 727          * when we login as root as in that particular case we cannot
 728          * make a distinction between seteuid(0) and seteuid(uid).
 729          * We rely on seteuid/setreuid/setuid to tell us with the
 730          * "finalize" argument that we no longer expect new uid changes,
 731          * cf. setreuid(uid, uid) and setuid(uid).
 732          */
 733         if (cr->cr_suid == cr->cr_ruid && cr->cr_suid == cr->cr_uid) {
 734                 if (finalize || cr->cr_uid != 0) {
 735                         CR_EPRIV(cr) = CR_IPRIV(cr);
 736                         priv_intersect(&CR_LPRIV(cr), &CR_EPRIV(cr));
 737                         CR_PPRIV(cr) = CR_EPRIV(cr);
 738                         CR_FLAGS(cr) &= ~(PRIV_AWARE|PRIV_AWARE_RESET);
 739                 } else {
 740                         CR_EPRIV(cr) = CR_PPRIV(cr);
 741                 }
 742         } else if (cr->cr_uid != 0 && (cr->cr_ruid == 0 || cr->cr_suid == 0)) {
 743                 CR_EPRIV(cr) = CR_IPRIV(cr);
 744                 priv_intersect(&CR_LPRIV(cr), &CR_EPRIV(cr));
 745         }
 746 }