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