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