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