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