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 (c) 2013, Ira Cooper.  All rights reserved.
  23  * Copyright 2020 Nexenta by DDN, Inc. All rights reserved.
  24  */
  25 /*
  26  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  27  */
  28 
  29 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  30 /*        All Rights Reserved   */
  31 
  32 /*
  33  * University Copyright- Copyright (c) 1982, 1986, 1988
  34  * The Regents of the University of California
  35  * All Rights Reserved
  36  *
  37  * University Acknowledgment- Portions of this document are derived from
  38  * software developed by the University of California, Berkeley, and its
  39  * contributors.
  40  */
  41 
  42 #include <sys/types.h>
  43 #include <sys/sysmacros.h>
  44 #include <sys/param.h>
  45 #include <sys/systm.h>
  46 #include <sys/cred_impl.h>
  47 #include <sys/policy.h>
  48 #include <sys/vnode.h>
  49 #include <sys/errno.h>
  50 #include <sys/kmem.h>
  51 #include <sys/user.h>
  52 #include <sys/proc.h>
  53 #include <sys/syscall.h>
  54 #include <sys/debug.h>
  55 #include <sys/atomic.h>
  56 #include <sys/ucred.h>
  57 #include <sys/prsystm.h>
  58 #include <sys/modctl.h>
  59 #include <sys/avl.h>
  60 #include <sys/door.h>
  61 #include <c2/audit.h>
  62 #include <sys/zone.h>
  63 #include <sys/tsol/label.h>
  64 #include <sys/sid.h>
  65 #include <sys/idmap.h>
  66 #include <sys/klpd.h>
  67 #include <sys/varargs.h>
  68 #include <sys/sysconf.h>
  69 #include <util/qsort.h>
  70 
  71 
  72 /* Ephemeral IDs Zones specific data */
  73 typedef struct ephemeral_zsd {
  74         uid_t           min_uid;
  75         uid_t           last_uid;
  76         gid_t           min_gid;
  77         gid_t           last_gid;
  78         kmutex_t        eph_lock;
  79         cred_t          *eph_nobody;
  80 } ephemeral_zsd_t;
  81 
  82 static void crgrphold(credgrp_t *);
  83 
  84 #define CREDGRPSZ(ngrp) (sizeof (credgrp_t) + ((ngrp - 1) * sizeof (gid_t)))
  85 
  86 static kmutex_t         ephemeral_zone_mutex;
  87 static zone_key_t       ephemeral_zone_key;
  88 
  89 static struct kmem_cache *cred_cache;
  90 static size_t           crsize = 0;
  91 static int              audoff = 0;
  92 uint32_t                ucredsize;
  93 cred_t                  *kcred;
  94 static cred_t           *dummycr;
  95 
  96 int rstlink;            /* link(2) restricted to files owned by user? */
  97 
  98 static int get_c2audit_load(void);
  99 
 100 #define CR_AUINFO(c)    (auditinfo_addr_t *)((audoff == 0) ? NULL : \
 101                             ((char *)(c)) + audoff)
 102 
 103 #define REMOTE_PEER_CRED(c)     ((c)->cr_gid == -1)
 104 
 105 #define BIN_GROUP_SEARCH_CUTOFF 16
 106 
 107 static boolean_t hasephids = B_FALSE;
 108 
 109 static ephemeral_zsd_t *
 110 get_ephemeral_zsd(zone_t *zone)
 111 {
 112         ephemeral_zsd_t *eph_zsd;
 113 
 114         eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
 115         if (eph_zsd != NULL) {
 116                 return (eph_zsd);
 117         }
 118 
 119         mutex_enter(&ephemeral_zone_mutex);
 120         eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
 121         if (eph_zsd == NULL) {
 122                 eph_zsd = kmem_zalloc(sizeof (ephemeral_zsd_t), KM_SLEEP);
 123                 eph_zsd->min_uid = MAXUID;
 124                 eph_zsd->last_uid = IDMAP_WK__MAX_UID;
 125                 eph_zsd->min_gid = MAXUID;
 126                 eph_zsd->last_gid = IDMAP_WK__MAX_GID;
 127                 mutex_init(&eph_zsd->eph_lock, NULL, MUTEX_DEFAULT, NULL);
 128 
 129                 /*
 130                  * nobody is used to map SID containing CRs.
 131                  */
 132                 eph_zsd->eph_nobody = crdup(zone->zone_kcred);
 133                 (void) crsetugid(eph_zsd->eph_nobody, UID_NOBODY, GID_NOBODY);
 134                 CR_FLAGS(eph_zsd->eph_nobody) = 0;
 135                 eph_zsd->eph_nobody->cr_zone = zone;
 136 
 137                 (void) zone_setspecific(ephemeral_zone_key, zone, eph_zsd);
 138         }
 139         mutex_exit(&ephemeral_zone_mutex);
 140         return (eph_zsd);
 141 }
 142 
 143 static cred_t *crdup_flags(const cred_t *, int);
 144 static cred_t *cralloc_flags(int);
 145 
 146 /*
 147  * This function is called when a zone is destroyed
 148  */
 149 static void
 150 /* ARGSUSED */
 151 destroy_ephemeral_zsd(zoneid_t zone_id, void *arg)
 152 {
 153         ephemeral_zsd_t *eph_zsd = arg;
 154         if (eph_zsd != NULL) {
 155                 mutex_destroy(&eph_zsd->eph_lock);
 156                 crfree(eph_zsd->eph_nobody);
 157                 kmem_free(eph_zsd, sizeof (ephemeral_zsd_t));
 158         }
 159 }
 160 
 161 
 162 
 163 /*
 164  * Initialize credentials data structures.
 165  */
 166 
 167 void
 168 cred_init(void)
 169 {
 170         priv_init();
 171 
 172         crsize = sizeof (cred_t);
 173 
 174         if (get_c2audit_load() > 0) {
 175 #ifdef _LP64
 176                 /* assure audit context is 64-bit aligned */
 177                 audoff = (crsize +
 178                     sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1);
 179 #else   /* _LP64 */
 180                 audoff = crsize;
 181 #endif  /* _LP64 */
 182                 crsize = audoff + sizeof (auditinfo_addr_t);
 183                 crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1);
 184         }
 185 
 186         cred_cache = kmem_cache_create("cred_cache", crsize, 0,
 187             NULL, NULL, NULL, NULL, NULL, 0);
 188 
 189         /*
 190          * dummycr is used to copy initial state for creds.
 191          */
 192         dummycr = cralloc();
 193         bzero(dummycr, crsize);
 194         dummycr->cr_ref = 1;
 195         dummycr->cr_uid = (uid_t)-1;
 196         dummycr->cr_gid = (gid_t)-1;
 197         dummycr->cr_ruid = (uid_t)-1;
 198         dummycr->cr_rgid = (gid_t)-1;
 199         dummycr->cr_suid = (uid_t)-1;
 200         dummycr->cr_sgid = (gid_t)-1;
 201 
 202 
 203         /*
 204          * kcred is used by anything that needs all privileges; it's
 205          * also the template used for crget as it has all the compatible
 206          * sets filled in.
 207          */
 208         kcred = cralloc();
 209 
 210         bzero(kcred, crsize);
 211         kcred->cr_ref = 1;
 212 
 213         /* kcred is never freed, so we don't need zone_cred_hold here */
 214         kcred->cr_zone = &zone0;
 215 
 216         priv_fillset(&CR_LPRIV(kcred));
 217         CR_IPRIV(kcred) = *priv_basic;
 218 
 219         priv_addset(&CR_IPRIV(kcred), PRIV_PROC_SECFLAGS);
 220 
 221         /* Not a basic privilege, if chown is not restricted add it to I0 */
 222         if (!rstchown)
 223                 priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF);
 224 
 225         /* Basic privilege, if link is restricted remove it from I0 */
 226         if (rstlink)
 227                 priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY);
 228 
 229         CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred);
 230 
 231         CR_FLAGS(kcred) = NET_MAC_AWARE;
 232 
 233         /*
 234          * Set up credentials of p0.
 235          */
 236         ttoproc(curthread)->p_cred = kcred;
 237         curthread->t_cred = kcred;
 238 
 239         ucredsize = UCRED_SIZE;
 240 
 241         mutex_init(&ephemeral_zone_mutex, NULL, MUTEX_DEFAULT, NULL);
 242         zone_key_create(&ephemeral_zone_key, NULL, NULL, destroy_ephemeral_zsd);
 243 }
 244 
 245 /*
 246  * Allocate (nearly) uninitialized cred_t.
 247  */
 248 static cred_t *
 249 cralloc_flags(int flgs)
 250 {
 251         cred_t *cr = kmem_cache_alloc(cred_cache, flgs);
 252 
 253         if (cr == NULL)
 254                 return (NULL);
 255 
 256         cr->cr_ref = 1;              /* So we can crfree() */
 257         cr->cr_zone = NULL;
 258         cr->cr_label = NULL;
 259         cr->cr_ksid = NULL;
 260         cr->cr_klpd = NULL;
 261         cr->cr_grps = NULL;
 262         return (cr);
 263 }
 264 
 265 cred_t *
 266 cralloc(void)
 267 {
 268         return (cralloc_flags(KM_SLEEP));
 269 }
 270 
 271 /*
 272  * As cralloc but prepared for ksid change (if appropriate).
 273  */
 274 cred_t *
 275 cralloc_ksid(void)
 276 {
 277         cred_t *cr = cralloc();
 278         if (hasephids)
 279                 cr->cr_ksid = kcrsid_alloc();
 280         return (cr);
 281 }
 282 
 283 /*
 284  * Allocate a initialized cred structure and crhold() it.
 285  * Initialized means: all ids 0, group count 0, L=Full, E=P=I=I0
 286  */
 287 cred_t *
 288 crget(void)
 289 {
 290         cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP);
 291 
 292         bcopy(zone_kcred(), cr, crsize);
 293         cr->cr_ref = 1;
 294         zone_cred_hold(cr->cr_zone);
 295         if (cr->cr_label)
 296                 label_hold(cr->cr_label);
 297         ASSERT(cr->cr_klpd == NULL);
 298         ASSERT(cr->cr_grps == NULL);
 299         return (cr);
 300 }
 301 
 302 /*
 303  * Broadcast the cred to all the threads in the process.
 304  * The current thread's credentials can be set right away, but other
 305  * threads must wait until the start of the next system call or trap.
 306  * This avoids changing the cred in the middle of a system call.
 307  *
 308  * The cred has already been held for the process and the thread (2 holds),
 309  * and p->p_cred set.
 310  *
 311  * p->p_crlock shouldn't be held here, since p_lock must be acquired.
 312  */
 313 void
 314 crset(proc_t *p, cred_t *cr)
 315 {
 316         kthread_id_t    t;
 317         kthread_id_t    first;
 318         cred_t *oldcr;
 319 
 320         ASSERT(p == curproc);   /* assumes p_lwpcnt can't change */
 321 
 322         /*
 323          * DTrace accesses t_cred in probe context.  t_cred must always be
 324          * either NULL, or point to a valid, allocated cred structure.
 325          */
 326         t = curthread;
 327         oldcr = t->t_cred;
 328         t->t_cred = cr;              /* the cred is held by caller for this thread */
 329         crfree(oldcr);          /* free the old cred for the thread */
 330 
 331         /*
 332          * Broadcast to other threads, if any.
 333          */
 334         if (p->p_lwpcnt > 1) {
 335                 mutex_enter(&p->p_lock); /* to keep thread list safe */
 336                 first = curthread;
 337                 for (t = first->t_forw; t != first; t = t->t_forw)
 338                         t->t_pre_sys = 1; /* so syscall will get new cred */
 339                 mutex_exit(&p->p_lock);
 340         }
 341 }
 342 
 343 /*
 344  * Put a hold on a cred structure.
 345  */
 346 void
 347 crhold(cred_t *cr)
 348 {
 349         ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
 350         atomic_inc_32(&cr->cr_ref);
 351 }
 352 
 353 /*
 354  * Release previous hold on a cred structure.  Free it if refcnt == 0.
 355  * If cred uses label different from zone label, free it.
 356  */
 357 void
 358 crfree(cred_t *cr)
 359 {
 360         ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
 361         if (atomic_dec_32_nv(&cr->cr_ref) == 0) {
 362                 ASSERT(cr != kcred);
 363                 if (cr->cr_label)
 364                         label_rele(cr->cr_label);
 365                 if (cr->cr_klpd)
 366                         crklpd_rele(cr->cr_klpd);
 367                 if (cr->cr_zone)
 368                         zone_cred_rele(cr->cr_zone);
 369                 if (cr->cr_ksid)
 370                         kcrsid_rele(cr->cr_ksid);
 371                 if (cr->cr_grps)
 372                         crgrprele(cr->cr_grps);
 373 
 374                 kmem_cache_free(cred_cache, cr);
 375         }
 376 }
 377 
 378 /*
 379  * Copy a cred structure to a new one and free the old one.
 380  *      The new cred will have two references.  One for the calling process,
 381  *      and one for the thread.
 382  */
 383 cred_t *
 384 crcopy(cred_t *cr)
 385 {
 386         cred_t *newcr;
 387 
 388         newcr = cralloc();
 389         bcopy(cr, newcr, crsize);
 390         if (newcr->cr_zone)
 391                 zone_cred_hold(newcr->cr_zone);
 392         if (newcr->cr_label)
 393                 label_hold(newcr->cr_label);
 394         if (newcr->cr_ksid)
 395                 kcrsid_hold(newcr->cr_ksid);
 396         if (newcr->cr_klpd)
 397                 crklpd_hold(newcr->cr_klpd);
 398         if (newcr->cr_grps)
 399                 crgrphold(newcr->cr_grps);
 400         crfree(cr);
 401         newcr->cr_ref = 2;           /* caller gets two references */
 402         return (newcr);
 403 }
 404 
 405 /*
 406  * Copy a cred structure to a new one and free the old one.
 407  *      The new cred will have two references.  One for the calling process,
 408  *      and one for the thread.
 409  * This variation on crcopy uses a pre-allocated structure for the
 410  * "new" cred.
 411  */
 412 void
 413 crcopy_to(cred_t *oldcr, cred_t *newcr)
 414 {
 415         credsid_t *nkcr = newcr->cr_ksid;
 416 
 417         bcopy(oldcr, newcr, crsize);
 418         if (newcr->cr_zone)
 419                 zone_cred_hold(newcr->cr_zone);
 420         if (newcr->cr_label)
 421                 label_hold(newcr->cr_label);
 422         if (newcr->cr_klpd)
 423                 crklpd_hold(newcr->cr_klpd);
 424         if (newcr->cr_grps)
 425                 crgrphold(newcr->cr_grps);
 426         if (nkcr) {
 427                 newcr->cr_ksid = nkcr;
 428                 kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
 429         } else if (newcr->cr_ksid)
 430                 kcrsid_hold(newcr->cr_ksid);
 431         crfree(oldcr);
 432         newcr->cr_ref = 2;           /* caller gets two references */
 433 }
 434 
 435 /*
 436  * Dup a cred struct to a new held one.
 437  *      The old cred is not freed.
 438  */
 439 static cred_t *
 440 crdup_flags(const cred_t *cr, int flgs)
 441 {
 442         cred_t *newcr;
 443 
 444         newcr = cralloc_flags(flgs);
 445 
 446         if (newcr == NULL)
 447                 return (NULL);
 448 
 449         bcopy(cr, newcr, crsize);
 450         if (newcr->cr_zone)
 451                 zone_cred_hold(newcr->cr_zone);
 452         if (newcr->cr_label)
 453                 label_hold(newcr->cr_label);
 454         if (newcr->cr_klpd)
 455                 crklpd_hold(newcr->cr_klpd);
 456         if (newcr->cr_ksid)
 457                 kcrsid_hold(newcr->cr_ksid);
 458         if (newcr->cr_grps)
 459                 crgrphold(newcr->cr_grps);
 460         newcr->cr_ref = 1;
 461         return (newcr);
 462 }
 463 
 464 cred_t *
 465 crdup(cred_t *cr)
 466 {
 467         return (crdup_flags(cr, KM_SLEEP));
 468 }
 469 
 470 /*
 471  * Dup a cred struct to a new held one.
 472  *      The old cred is not freed.
 473  * This variation on crdup uses a pre-allocated structure for the
 474  * "new" cred.
 475  */
 476 void
 477 crdup_to(cred_t *oldcr, cred_t *newcr)
 478 {
 479         credsid_t *nkcr = newcr->cr_ksid;
 480 
 481         bcopy(oldcr, newcr, crsize);
 482         if (newcr->cr_zone)
 483                 zone_cred_hold(newcr->cr_zone);
 484         if (newcr->cr_label)
 485                 label_hold(newcr->cr_label);
 486         if (newcr->cr_klpd)
 487                 crklpd_hold(newcr->cr_klpd);
 488         if (newcr->cr_grps)
 489                 crgrphold(newcr->cr_grps);
 490         if (nkcr) {
 491                 newcr->cr_ksid = nkcr;
 492                 kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
 493         } else if (newcr->cr_ksid)
 494                 kcrsid_hold(newcr->cr_ksid);
 495         newcr->cr_ref = 1;
 496 }
 497 
 498 /*
 499  * Return the (held) credentials for the current running process.
 500  */
 501 cred_t *
 502 crgetcred(void)
 503 {
 504         cred_t *cr;
 505         proc_t *p;
 506 
 507         p = ttoproc(curthread);
 508         mutex_enter(&p->p_crlock);
 509         crhold(cr = p->p_cred);
 510         mutex_exit(&p->p_crlock);
 511         return (cr);
 512 }
 513 
 514 /*
 515  * Backward compatibility check for suser().
 516  * Accounting flag is now set in the policy functions; auditing is
 517  * done through use of privilege in the audit trail.
 518  */
 519 int
 520 suser(cred_t *cr)
 521 {
 522         return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL)
 523             == 0);
 524 }
 525 
 526 /*
 527  * Determine whether the supplied group id is a member of the group
 528  * described by the supplied credentials.
 529  */
 530 int
 531 groupmember(gid_t gid, const cred_t *cr)
 532 {
 533         if (gid == cr->cr_gid)
 534                 return (1);
 535         return (supgroupmember(gid, cr));
 536 }
 537 
 538 /*
 539  * As groupmember but only check against the supplemental groups.
 540  */
 541 int
 542 supgroupmember(gid_t gid, const cred_t *cr)
 543 {
 544         int hi, lo;
 545         credgrp_t *grps = cr->cr_grps;
 546         const gid_t *gp, *endgp;
 547 
 548         if (grps == NULL)
 549                 return (0);
 550 
 551         /* For a small number of groups, use sequentials search. */
 552         if (grps->crg_ngroups <= BIN_GROUP_SEARCH_CUTOFF) {
 553                 endgp = &grps->crg_groups[grps->crg_ngroups];
 554                 for (gp = grps->crg_groups; gp < endgp; gp++)
 555                         if (*gp == gid)
 556                                 return (1);
 557                 return (0);
 558         }
 559 
 560         /* We use binary search when we have many groups. */
 561         lo = 0;
 562         hi = grps->crg_ngroups - 1;
 563         gp = grps->crg_groups;
 564 
 565         do {
 566                 int m = (lo + hi) / 2;
 567 
 568                 if (gid > gp[m])
 569                         lo = m + 1;
 570                 else if (gid < gp[m])
 571                         hi = m - 1;
 572                 else
 573                         return (1);
 574         } while (lo <= hi);
 575 
 576         return (0);
 577 }
 578 
 579 /*
 580  * This function is called to check whether the credentials set
 581  * "scrp" has permission to act on credentials set "tcrp".  It enforces the
 582  * permission requirements needed to send a signal to a process.
 583  * The same requirements are imposed by other system calls, however.
 584  *
 585  * The rules are:
 586  * (1) if the credentials are the same, the check succeeds
 587  * (2) if the zone ids don't match, and scrp is not in the global zone or
 588  *     does not have the PRIV_PROC_ZONE privilege, the check fails
 589  * (3) if the real or effective user id of scrp matches the real or saved
 590  *     user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check
 591  *     succeeds
 592  * (4) otherwise, the check fails
 593  */
 594 int
 595 hasprocperm(const cred_t *tcrp, const cred_t *scrp)
 596 {
 597         if (scrp == tcrp)
 598                 return (1);
 599         if (scrp->cr_zone != tcrp->cr_zone &&
 600             (scrp->cr_zone != global_zone ||
 601             secpolicy_proc_zone(scrp) != 0))
 602                 return (0);
 603         if (scrp->cr_uid == tcrp->cr_ruid ||
 604             scrp->cr_ruid == tcrp->cr_ruid ||
 605             scrp->cr_uid  == tcrp->cr_suid ||
 606             scrp->cr_ruid == tcrp->cr_suid ||
 607             !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm"))
 608                 return (1);
 609         return (0);
 610 }
 611 
 612 /*
 613  * This interface replaces hasprocperm; it works like hasprocperm but
 614  * additionally returns success if the proc_t's match
 615  * It is the preferred interface for most uses.
 616  * And it will acquire p_crlock itself, so it assert's that it shouldn't
 617  * be held.
 618  */
 619 int
 620 prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp)
 621 {
 622         int rets;
 623         cred_t *tcrp;
 624 
 625         ASSERT(MUTEX_NOT_HELD(&tp->p_crlock));
 626 
 627         if (tp == sp)
 628                 return (1);
 629 
 630         if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0)
 631                 return (0);
 632 
 633         mutex_enter(&tp->p_crlock);
 634         crhold(tcrp = tp->p_cred);
 635         mutex_exit(&tp->p_crlock);
 636         rets = hasprocperm(tcrp, scrp);
 637         crfree(tcrp);
 638 
 639         return (rets);
 640 }
 641 
 642 /*
 643  * This routine is used to compare two credentials to determine if
 644  * they refer to the same "user".  If the pointers are equal, then
 645  * they must refer to the same user.  Otherwise, the contents of
 646  * the credentials are compared to see whether they are equivalent.
 647  *
 648  * This routine returns 0 if the credentials refer to the same user,
 649  * 1 if they do not.
 650  */
 651 int
 652 crcmp(const cred_t *cr1, const cred_t *cr2)
 653 {
 654         credgrp_t *grp1, *grp2;
 655 
 656         if (cr1 == cr2)
 657                 return (0);
 658 
 659         if (cr1->cr_uid == cr2->cr_uid &&
 660             cr1->cr_gid == cr2->cr_gid &&
 661             cr1->cr_ruid == cr2->cr_ruid &&
 662             cr1->cr_rgid == cr2->cr_rgid &&
 663             cr1->cr_zone == cr2->cr_zone &&
 664             ((grp1 = cr1->cr_grps) == (grp2 = cr2->cr_grps) ||
 665             (grp1 != NULL && grp2 != NULL &&
 666             grp1->crg_ngroups == grp2->crg_ngroups &&
 667             bcmp(grp1->crg_groups, grp2->crg_groups,
 668             grp1->crg_ngroups * sizeof (gid_t)) == 0))) {
 669                 return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2)));
 670         }
 671         return (1);
 672 }
 673 
 674 /*
 675  * Read access functions to cred_t.
 676  */
 677 uid_t
 678 crgetuid(const cred_t *cr)
 679 {
 680         return (cr->cr_uid);
 681 }
 682 
 683 uid_t
 684 crgetruid(const cred_t *cr)
 685 {
 686         return (cr->cr_ruid);
 687 }
 688 
 689 uid_t
 690 crgetsuid(const cred_t *cr)
 691 {
 692         return (cr->cr_suid);
 693 }
 694 
 695 gid_t
 696 crgetgid(const cred_t *cr)
 697 {
 698         return (cr->cr_gid);
 699 }
 700 
 701 gid_t
 702 crgetrgid(const cred_t *cr)
 703 {
 704         return (cr->cr_rgid);
 705 }
 706 
 707 gid_t
 708 crgetsgid(const cred_t *cr)
 709 {
 710         return (cr->cr_sgid);
 711 }
 712 
 713 const auditinfo_addr_t *
 714 crgetauinfo(const cred_t *cr)
 715 {
 716         return ((const auditinfo_addr_t *)CR_AUINFO(cr));
 717 }
 718 
 719 auditinfo_addr_t *
 720 crgetauinfo_modifiable(cred_t *cr)
 721 {
 722         return (CR_AUINFO(cr));
 723 }
 724 
 725 zoneid_t
 726 crgetzoneid(const cred_t *cr)
 727 {
 728         return (cr->cr_zone == NULL ?
 729             (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) :
 730             cr->cr_zone->zone_id);
 731 }
 732 
 733 projid_t
 734 crgetprojid(const cred_t *cr)
 735 {
 736         return (cr->cr_projid);
 737 }
 738 
 739 zone_t *
 740 crgetzone(const cred_t *cr)
 741 {
 742         return (cr->cr_zone);
 743 }
 744 
 745 struct ts_label_s *
 746 crgetlabel(const cred_t *cr)
 747 {
 748         return (cr->cr_label ?
 749             cr->cr_label :
 750             (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL));
 751 }
 752 
 753 boolean_t
 754 crisremote(const cred_t *cr)
 755 {
 756         return (REMOTE_PEER_CRED(cr));
 757 }
 758 
 759 #define BADUID(x, zn)   ((x) != -1 && !VALID_UID((x), (zn)))
 760 #define BADGID(x, zn)   ((x) != -1 && !VALID_GID((x), (zn)))
 761 
 762 int
 763 crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s)
 764 {
 765         zone_t  *zone = crgetzone(cr);
 766 
 767         ASSERT(cr->cr_ref <= 2);
 768 
 769         if (BADUID(r, zone) || BADUID(e, zone) || BADUID(s, zone))
 770                 return (-1);
 771 
 772         if (r != -1)
 773                 cr->cr_ruid = r;
 774         if (e != -1)
 775                 cr->cr_uid = e;
 776         if (s != -1)
 777                 cr->cr_suid = s;
 778 
 779         return (0);
 780 }
 781 
 782 int
 783 crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s)
 784 {
 785         zone_t  *zone = crgetzone(cr);
 786 
 787         ASSERT(cr->cr_ref <= 2);
 788 
 789         if (BADGID(r, zone) || BADGID(e, zone) || BADGID(s, zone))
 790                 return (-1);
 791 
 792         if (r != -1)
 793                 cr->cr_rgid = r;
 794         if (e != -1)
 795                 cr->cr_gid = e;
 796         if (s != -1)
 797                 cr->cr_sgid = s;
 798 
 799         return (0);
 800 }
 801 
 802 int
 803 crsetugid(cred_t *cr, uid_t uid, gid_t gid)
 804 {
 805         zone_t  *zone = crgetzone(cr);
 806 
 807         ASSERT(cr->cr_ref <= 2);
 808 
 809         if (!VALID_UID(uid, zone) || !VALID_GID(gid, zone))
 810                 return (-1);
 811 
 812         cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid;
 813         cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid;
 814 
 815         return (0);
 816 }
 817 
 818 static int
 819 gidcmp(const void *v1, const void *v2)
 820 {
 821         gid_t g1 = *(gid_t *)v1;
 822         gid_t g2 = *(gid_t *)v2;
 823 
 824         if (g1 < g2)
 825                 return (-1);
 826         else if (g1 > g2)
 827                 return (1);
 828         else
 829                 return (0);
 830 }
 831 
 832 int
 833 crsetgroups(cred_t *cr, int n, gid_t *grp)
 834 {
 835         ASSERT(cr->cr_ref <= 2);
 836 
 837         if (n > ngroups_max || n < 0)
 838                 return (-1);
 839 
 840         if (cr->cr_grps != NULL)
 841                 crgrprele(cr->cr_grps);
 842 
 843         if (n > 0) {
 844                 cr->cr_grps = kmem_alloc(CREDGRPSZ(n), KM_SLEEP);
 845                 bcopy(grp, cr->cr_grps->crg_groups, n * sizeof (gid_t));
 846                 cr->cr_grps->crg_ref = 1;
 847                 cr->cr_grps->crg_ngroups = n;
 848                 qsort(cr->cr_grps->crg_groups, n, sizeof (gid_t), gidcmp);
 849         } else {
 850                 cr->cr_grps = NULL;
 851         }
 852 
 853         return (0);
 854 }
 855 
 856 void
 857 crsetprojid(cred_t *cr, projid_t projid)
 858 {
 859         ASSERT(projid >= 0 && projid <= MAXPROJID);
 860         cr->cr_projid = projid;
 861 }
 862 
 863 /*
 864  * This routine returns the pointer to the first element of the crg_groups
 865  * array.  It can move around in an implementation defined way.
 866  * Note that when we have no grouplist, we return one element but the
 867  * caller should never reference it.
 868  */
 869 const gid_t *
 870 crgetgroups(const cred_t *cr)
 871 {
 872         return (cr->cr_grps == NULL ? &cr->cr_gid : cr->cr_grps->crg_groups);
 873 }
 874 
 875 int
 876 crgetngroups(const cred_t *cr)
 877 {
 878         return (cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups);
 879 }
 880 
 881 void
 882 cred2prcred(const cred_t *cr, prcred_t *pcrp)
 883 {
 884         pcrp->pr_euid = cr->cr_uid;
 885         pcrp->pr_ruid = cr->cr_ruid;
 886         pcrp->pr_suid = cr->cr_suid;
 887         pcrp->pr_egid = cr->cr_gid;
 888         pcrp->pr_rgid = cr->cr_rgid;
 889         pcrp->pr_sgid = cr->cr_sgid;
 890         pcrp->pr_groups[0] = 0; /* in case ngroups == 0 */
 891         pcrp->pr_ngroups = cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups;
 892 
 893         if (pcrp->pr_ngroups != 0)
 894                 bcopy(cr->cr_grps->crg_groups, pcrp->pr_groups,
 895                     sizeof (gid_t) * pcrp->pr_ngroups);
 896 }
 897 
 898 static int
 899 cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr)
 900 {
 901         auditinfo_addr_t        *ai;
 902         au_tid_addr_t   tid;
 903 
 904         if (secpolicy_audit_getattr(rcr, B_TRUE) != 0)
 905                 return (-1);
 906 
 907         ai = CR_AUINFO(cr);     /* caller makes sure this is non-NULL */
 908         tid = ai->ai_termid;
 909 
 910         ainfo->ai_auid = ai->ai_auid;
 911         ainfo->ai_mask = ai->ai_mask;
 912         ainfo->ai_asid = ai->ai_asid;
 913 
 914         ainfo->ai_termid.at_type = tid.at_type;
 915         bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t));
 916 
 917         ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port);
 918         ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port);
 919 
 920         return (0);
 921 }
 922 
 923 void
 924 cred2uclabel(const cred_t *cr, bslabel_t *labelp)
 925 {
 926         ts_label_t      *tslp;
 927 
 928         if ((tslp = crgetlabel(cr)) != NULL)
 929                 bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t));
 930 }
 931 
 932 /*
 933  * Convert a credential into a "ucred".  Allow the caller to specify
 934  * and aligned buffer, e.g., in an mblk, so we don't have to allocate
 935  * memory and copy it twice.
 936  *
 937  * This function may call cred2ucaud(), which calls CRED(). Since this
 938  * can be called from an interrupt thread, receiver's cred (rcr) is needed
 939  * to determine whether audit info should be included.
 940  */
 941 struct ucred_s *
 942 cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr)
 943 {
 944         struct ucred_s *uc;
 945         uint32_t realsz = ucredminsize(cr);
 946         ts_label_t *tslp = is_system_labeled() ? crgetlabel(cr) : NULL;
 947 
 948         /* The structure isn't always completely filled in, so zero it */
 949         if (buf == NULL) {
 950                 uc = kmem_zalloc(realsz, KM_SLEEP);
 951         } else {
 952                 bzero(buf, realsz);
 953                 uc = buf;
 954         }
 955         uc->uc_size = realsz;
 956         uc->uc_pid = pid;
 957         uc->uc_projid = cr->cr_projid;
 958         uc->uc_zoneid = crgetzoneid(cr);
 959 
 960         if (REMOTE_PEER_CRED(cr)) {
 961                 /*
 962                  * Other than label, the rest of cred info about a
 963                  * remote peer isn't available. Copy the label directly
 964                  * after the header where we generally copy the prcred.
 965                  * That's why we use sizeof (struct ucred_s).  The other
 966                  * offset fields are initialized to 0.
 967                  */
 968                 uc->uc_labeloff = tslp == NULL ? 0 : sizeof (struct ucred_s);
 969         } else {
 970                 uc->uc_credoff = UCRED_CRED_OFF;
 971                 uc->uc_privoff = UCRED_PRIV_OFF;
 972                 uc->uc_audoff = UCRED_AUD_OFF;
 973                 uc->uc_labeloff = tslp == NULL ? 0 : UCRED_LABEL_OFF;
 974 
 975                 cred2prcred(cr, UCCRED(uc));
 976                 cred2prpriv(cr, UCPRIV(uc));
 977 
 978                 if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0)
 979                         uc->uc_audoff = 0;
 980         }
 981         if (tslp != NULL)
 982                 bcopy(&tslp->tsl_label, UCLABEL(uc), sizeof (bslabel_t));
 983 
 984         return (uc);
 985 }
 986 
 987 /*
 988  * Don't allocate the non-needed group entries.  Note: this function
 989  * must match the code in cred2ucred; they must agree about the
 990  * minimal size of the ucred.
 991  */
 992 uint32_t
 993 ucredminsize(const cred_t *cr)
 994 {
 995         int ndiff;
 996 
 997         if (cr == NULL)
 998                 return (ucredsize);
 999 
1000         if (REMOTE_PEER_CRED(cr)) {
1001                 if (is_system_labeled())
1002                         return (sizeof (struct ucred_s) + sizeof (bslabel_t));
1003                 else
1004                         return (sizeof (struct ucred_s));
1005         }
1006 
1007         if (cr->cr_grps == NULL)
1008                 ndiff = ngroups_max - 1;        /* Needs one for prcred_t */
1009         else
1010                 ndiff = ngroups_max - cr->cr_grps->crg_ngroups;
1011 
1012         return (ucredsize - ndiff * sizeof (gid_t));
1013 }
1014 
1015 /*
1016  * Get the "ucred" of a process.
1017  */
1018 struct ucred_s *
1019 pgetucred(proc_t *p)
1020 {
1021         cred_t *cr;
1022         struct ucred_s *uc;
1023 
1024         mutex_enter(&p->p_crlock);
1025         cr = p->p_cred;
1026         crhold(cr);
1027         mutex_exit(&p->p_crlock);
1028 
1029         uc = cred2ucred(cr, p->p_pid, NULL, CRED());
1030         crfree(cr);
1031 
1032         return (uc);
1033 }
1034 
1035 /*
1036  * If the reply status is NFSERR_EACCES, it may be because we are
1037  * root (no root net access).  Check the real uid, if it isn't root
1038  * make that the uid instead and retry the call.
1039  * Private interface for NFS.
1040  */
1041 cred_t *
1042 crnetadjust(cred_t *cr)
1043 {
1044         if (cr->cr_uid == 0 && cr->cr_ruid != 0) {
1045                 cr = crdup(cr);
1046                 cr->cr_uid = cr->cr_ruid;
1047                 return (cr);
1048         }
1049         return (NULL);
1050 }
1051 
1052 /*
1053  * The reference count is of interest when you want to check
1054  * whether it is ok to modify the credential in place.
1055  */
1056 uint_t
1057 crgetref(const cred_t *cr)
1058 {
1059         return (cr->cr_ref);
1060 }
1061 
1062 static int
1063 get_c2audit_load(void)
1064 {
1065         static int      gotit = 0;
1066         static int      c2audit_load;
1067 
1068         if (gotit)
1069                 return (c2audit_load);
1070         c2audit_load = 1;               /* set default value once */
1071         if (mod_sysctl(SYS_CHECK_EXCLUDE, "c2audit") != 0)
1072                 c2audit_load = 0;
1073         gotit++;
1074 
1075         return (c2audit_load);
1076 }
1077 
1078 int
1079 get_audit_ucrsize(void)
1080 {
1081         return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0);
1082 }
1083 
1084 /*
1085  * Set zone pointer in credential to indicated value.  First adds a
1086  * hold for the new zone, then drops the hold on previous zone (if any).
1087  * This is done in this order in case the old and new zones are the
1088  * same.
1089  */
1090 void
1091 crsetzone(cred_t *cr, zone_t *zptr)
1092 {
1093         zone_t *oldzptr = cr->cr_zone;
1094 
1095         ASSERT(cr != kcred);
1096         ASSERT(cr->cr_ref <= 2);
1097         cr->cr_zone = zptr;
1098         zone_cred_hold(zptr);
1099         if (oldzptr)
1100                 zone_cred_rele(oldzptr);
1101 }
1102 
1103 /*
1104  * Create a new cred based on the supplied label
1105  */
1106 cred_t *
1107 newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags)
1108 {
1109         ts_label_t *lbl = labelalloc(blabel, doi, flags);
1110         cred_t *cr = NULL;
1111 
1112         if (lbl != NULL) {
1113                 if ((cr = crdup_flags(dummycr, flags)) != NULL) {
1114                         cr->cr_label = lbl;
1115                 } else {
1116                         label_rele(lbl);
1117                 }
1118         }
1119 
1120         return (cr);
1121 }
1122 
1123 /*
1124  * Derive a new cred from the existing cred, but with a different label.
1125  * To be used when a cred is being shared, but the label needs to be changed
1126  * by a caller without affecting other users
1127  */
1128 cred_t *
1129 copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags)
1130 {
1131         cred_t *newcr = NULL;
1132 
1133         if ((newcr = crdup_flags(cr, flags)) != NULL) {
1134                 if (newcr->cr_label != NULL)
1135                         label_rele(newcr->cr_label);
1136                 label_hold(label);
1137                 newcr->cr_label = label;
1138         }
1139 
1140         return (newcr);
1141 }
1142 
1143 /*
1144  * Derive a new cred from the existing cred, but with a different label.
1145  */
1146 cred_t *
1147 copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel,
1148     uint32_t doi, int flags)
1149 {
1150         ts_label_t *lbl = labelalloc(blabel, doi, flags);
1151         cred_t  *newcr = NULL;
1152 
1153         if (lbl != NULL) {
1154                 newcr = copycred_from_tslabel(cr, lbl, flags);
1155                 label_rele(lbl);
1156         }
1157 
1158         return (newcr);
1159 }
1160 
1161 /*
1162  * This function returns a pointer to the kcred-equivalent in the current zone.
1163  */
1164 cred_t *
1165 zone_kcred(void)
1166 {
1167         zone_t *zone;
1168 
1169         if ((zone = CRED()->cr_zone) != NULL)
1170                 return (zone->zone_kcred);
1171         else
1172                 return (kcred);
1173 }
1174 
1175 boolean_t
1176 valid_ephemeral_uid(zone_t *zone, uid_t id)
1177 {
1178         ephemeral_zsd_t *eph_zsd;
1179         if (id <= IDMAP_WK__MAX_UID)
1180                 return (B_TRUE);
1181 
1182         eph_zsd = get_ephemeral_zsd(zone);
1183         ASSERT(eph_zsd != NULL);
1184         membar_consumer();
1185         return (id > eph_zsd->min_uid && id <= eph_zsd->last_uid);
1186 }
1187 
1188 boolean_t
1189 valid_ephemeral_gid(zone_t *zone, gid_t id)
1190 {
1191         ephemeral_zsd_t *eph_zsd;
1192         if (id <= IDMAP_WK__MAX_GID)
1193                 return (B_TRUE);
1194 
1195         eph_zsd = get_ephemeral_zsd(zone);
1196         ASSERT(eph_zsd != NULL);
1197         membar_consumer();
1198         return (id > eph_zsd->min_gid && id <= eph_zsd->last_gid);
1199 }
1200 
1201 int
1202 eph_uid_alloc(zone_t *zone, int flags, uid_t *start, int count)
1203 {
1204         ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1205 
1206         ASSERT(eph_zsd != NULL);
1207 
1208         mutex_enter(&eph_zsd->eph_lock);
1209 
1210         /* Test for unsigned integer wrap around */
1211         if (eph_zsd->last_uid + count < eph_zsd->last_uid) {
1212                 mutex_exit(&eph_zsd->eph_lock);
1213                 return (-1);
1214         }
1215 
1216         /* first call or idmap crashed and state corrupted */
1217         if (flags != 0)
1218                 eph_zsd->min_uid = eph_zsd->last_uid;
1219 
1220         hasephids = B_TRUE;
1221         *start = eph_zsd->last_uid + 1;
1222         atomic_add_32(&eph_zsd->last_uid, count);
1223         mutex_exit(&eph_zsd->eph_lock);
1224         return (0);
1225 }
1226 
1227 int
1228 eph_gid_alloc(zone_t *zone, int flags, gid_t *start, int count)
1229 {
1230         ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1231 
1232         ASSERT(eph_zsd != NULL);
1233 
1234         mutex_enter(&eph_zsd->eph_lock);
1235 
1236         /* Test for unsigned integer wrap around */
1237         if (eph_zsd->last_gid + count < eph_zsd->last_gid) {
1238                 mutex_exit(&eph_zsd->eph_lock);
1239                 return (-1);
1240         }
1241 
1242         /* first call or idmap crashed and state corrupted */
1243         if (flags != 0)
1244                 eph_zsd->min_gid = eph_zsd->last_gid;
1245 
1246         hasephids = B_TRUE;
1247         *start = eph_zsd->last_gid + 1;
1248         atomic_add_32(&eph_zsd->last_gid, count);
1249         mutex_exit(&eph_zsd->eph_lock);
1250         return (0);
1251 }
1252 
1253 /*
1254  * IMPORTANT.The two functions get_ephemeral_data() and set_ephemeral_data()
1255  * are project private functions that are for use of the test system only and
1256  * are not to be used for other purposes.
1257  */
1258 
1259 void
1260 get_ephemeral_data(zone_t *zone, uid_t *min_uid, uid_t *last_uid,
1261     gid_t *min_gid, gid_t *last_gid)
1262 {
1263         ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1264 
1265         ASSERT(eph_zsd != NULL);
1266 
1267         mutex_enter(&eph_zsd->eph_lock);
1268 
1269         *min_uid = eph_zsd->min_uid;
1270         *last_uid = eph_zsd->last_uid;
1271         *min_gid = eph_zsd->min_gid;
1272         *last_gid = eph_zsd->last_gid;
1273 
1274         mutex_exit(&eph_zsd->eph_lock);
1275 }
1276 
1277 
1278 void
1279 set_ephemeral_data(zone_t *zone, uid_t min_uid, uid_t last_uid,
1280     gid_t min_gid, gid_t last_gid)
1281 {
1282         ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1283 
1284         ASSERT(eph_zsd != NULL);
1285 
1286         mutex_enter(&eph_zsd->eph_lock);
1287 
1288         if (min_uid != 0)
1289                 eph_zsd->min_uid = min_uid;
1290         if (last_uid != 0)
1291                 eph_zsd->last_uid = last_uid;
1292         if (min_gid != 0)
1293                 eph_zsd->min_gid = min_gid;
1294         if (last_gid != 0)
1295                 eph_zsd->last_gid = last_gid;
1296 
1297         mutex_exit(&eph_zsd->eph_lock);
1298 }
1299 
1300 /*
1301  * If the credential user SID or group SID is mapped to an ephemeral
1302  * ID, map the credential to nobody.
1303  */
1304 cred_t *
1305 crgetmapped(const cred_t *cr)
1306 {
1307         ephemeral_zsd_t *eph_zsd;
1308         /*
1309          * Someone incorrectly passed a NULL cred to a vnode operation
1310          * either on purpose or by calling CRED() in interrupt context.
1311          */
1312         if (cr == NULL)
1313                 return (NULL);
1314 
1315         if (cr->cr_ksid != NULL) {
1316                 if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID) {
1317                         eph_zsd = get_ephemeral_zsd(crgetzone(cr));
1318                         return (eph_zsd->eph_nobody);
1319                 }
1320 
1321                 if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID) {
1322                         eph_zsd = get_ephemeral_zsd(crgetzone(cr));
1323                         return (eph_zsd->eph_nobody);
1324                 }
1325         }
1326 
1327         return ((cred_t *)cr);
1328 }
1329 
1330 /* index should be in range for a ksidindex_t */
1331 void
1332 crsetsid(cred_t *cr, ksid_t *ksp, int index)
1333 {
1334         ASSERT(cr->cr_ref <= 2);
1335         ASSERT(index >= 0 && index < KSID_COUNT);
1336         if (cr->cr_ksid == NULL && ksp == NULL)
1337                 return;
1338         cr->cr_ksid = kcrsid_setsid(cr->cr_ksid, ksp, index);
1339 }
1340 
1341 void
1342 crsetsidlist(cred_t *cr, ksidlist_t *ksl)
1343 {
1344         ASSERT(cr->cr_ref <= 2);
1345         if (cr->cr_ksid == NULL && ksl == NULL)
1346                 return;
1347         cr->cr_ksid = kcrsid_setsidlist(cr->cr_ksid, ksl);
1348 }
1349 
1350 ksid_t *
1351 crgetsid(const cred_t *cr, int i)
1352 {
1353         ASSERT(i >= 0 && i < KSID_COUNT);
1354         if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidx[i].ks_domain)
1355                 return ((ksid_t *)&cr->cr_ksid->kr_sidx[i]);
1356         return (NULL);
1357 }
1358 
1359 ksidlist_t *
1360 crgetsidlist(const cred_t *cr)
1361 {
1362         if (cr->cr_ksid != NULL)
1363                 return (cr->cr_ksid->kr_sidlist);
1364         return (NULL);
1365 }
1366 
1367 /*
1368  * Interface to set the effective and permitted privileges for
1369  * a credential; this interface does no security checks and is
1370  * intended for kernel (file)servers creating credentials with
1371  * specific privileges.
1372  */
1373 int
1374 crsetpriv(cred_t *cr, ...)
1375 {
1376         va_list ap;
1377         const char *privnm;
1378 
1379         ASSERT(cr->cr_ref <= 2);
1380 
1381         priv_set_PA(cr);
1382 
1383         va_start(ap, cr);
1384 
1385         while ((privnm = va_arg(ap, const char *)) != NULL) {
1386                 int priv = priv_getbyname(privnm, 0);
1387                 if (priv < 0)
1388                         return (-1);
1389 
1390                 priv_addset(&CR_PPRIV(cr), priv);
1391                 priv_addset(&CR_EPRIV(cr), priv);
1392         }
1393         priv_adjust_PA(cr);
1394         va_end(ap);
1395         return (0);
1396 }
1397 
1398 /*
1399  * Interface to effectively set the PRIV_ALL for
1400  * a credential; this interface does no security checks and is
1401  * intended for kernel (file)servers to extend the user credentials
1402  * to be ALL, like either kcred or zcred.
1403  */
1404 void
1405 crset_zone_privall(cred_t *cr)
1406 {
1407         zone_t  *zone = crgetzone(cr);
1408 
1409         priv_fillset(&CR_LPRIV(cr));
1410         CR_EPRIV(cr) = CR_PPRIV(cr) = CR_IPRIV(cr) = CR_LPRIV(cr);
1411         priv_intersect(zone->zone_privset, &CR_LPRIV(cr));
1412         priv_intersect(zone->zone_privset, &CR_EPRIV(cr));
1413         priv_intersect(zone->zone_privset, &CR_IPRIV(cr));
1414         priv_intersect(zone->zone_privset, &CR_PPRIV(cr));
1415 }
1416 
1417 struct credklpd *
1418 crgetcrklpd(const cred_t *cr)
1419 {
1420         return (cr->cr_klpd);
1421 }
1422 
1423 void
1424 crsetcrklpd(cred_t *cr, struct credklpd *crklpd)
1425 {
1426         ASSERT(cr->cr_ref <= 2);
1427 
1428         if (cr->cr_klpd != NULL)
1429                 crklpd_rele(cr->cr_klpd);
1430         cr->cr_klpd = crklpd;
1431 }
1432 
1433 credgrp_t *
1434 crgrpcopyin(int n, gid_t *gidset)
1435 {
1436         credgrp_t *mem;
1437         size_t sz = CREDGRPSZ(n);
1438 
1439         ASSERT(n > 0);
1440 
1441         mem = kmem_alloc(sz, KM_SLEEP);
1442 
1443         if (copyin(gidset, mem->crg_groups, sizeof (gid_t) * n)) {
1444                 kmem_free(mem, sz);
1445                 return (NULL);
1446         }
1447         mem->crg_ref = 1;
1448         mem->crg_ngroups = n;
1449         qsort(mem->crg_groups, n, sizeof (gid_t), gidcmp);
1450         return (mem);
1451 }
1452 
1453 const gid_t *
1454 crgetggroups(const credgrp_t *grps)
1455 {
1456         return (grps->crg_groups);
1457 }
1458 
1459 void
1460 crsetcredgrp(cred_t *cr, credgrp_t *grps)
1461 {
1462         ASSERT(cr->cr_ref <= 2);
1463 
1464         if (cr->cr_grps != NULL)
1465                 crgrprele(cr->cr_grps);
1466 
1467         cr->cr_grps = grps;
1468 }
1469 
1470 void
1471 crgrprele(credgrp_t *grps)
1472 {
1473         if (atomic_dec_32_nv(&grps->crg_ref) == 0)
1474                 kmem_free(grps, CREDGRPSZ(grps->crg_ngroups));
1475 }
1476 
1477 static void
1478 crgrphold(credgrp_t *grps)
1479 {
1480         atomic_inc_32(&grps->crg_ref);
1481 }