xref: /onnv-gate/usr/src/uts/common/os/cred.c (revision 12273:63678502e95e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12273SCasper.Dik@Sun.COM  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
260Sstevel@tonic-gate /*	  All Rights Reserved  	*/
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
300Sstevel@tonic-gate  * The Regents of the University of California
310Sstevel@tonic-gate  * All Rights Reserved
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
340Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
350Sstevel@tonic-gate  * contributors.
360Sstevel@tonic-gate  */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <sys/types.h>
390Sstevel@tonic-gate #include <sys/sysmacros.h>
400Sstevel@tonic-gate #include <sys/param.h>
410Sstevel@tonic-gate #include <sys/systm.h>
420Sstevel@tonic-gate #include <sys/cred_impl.h>
430Sstevel@tonic-gate #include <sys/policy.h>
440Sstevel@tonic-gate #include <sys/vnode.h>
450Sstevel@tonic-gate #include <sys/errno.h>
460Sstevel@tonic-gate #include <sys/kmem.h>
470Sstevel@tonic-gate #include <sys/user.h>
480Sstevel@tonic-gate #include <sys/proc.h>
490Sstevel@tonic-gate #include <sys/syscall.h>
500Sstevel@tonic-gate #include <sys/debug.h>
510Sstevel@tonic-gate #include <sys/atomic.h>
520Sstevel@tonic-gate #include <sys/ucred.h>
530Sstevel@tonic-gate #include <sys/prsystm.h>
540Sstevel@tonic-gate #include <sys/modctl.h>
554321Scasper #include <sys/avl.h>
565331Samw #include <sys/door.h>
570Sstevel@tonic-gate #include <c2/audit.h>
580Sstevel@tonic-gate #include <sys/zone.h>
591676Sjpk #include <sys/tsol/label.h>
604321Scasper #include <sys/sid.h>
614520Snw141292 #include <sys/idmap.h>
626134Scasper #include <sys/klpd.h>
635331Samw #include <sys/varargs.h>
6411861SMarek.Pospisil@Sun.COM #include <sys/sysconf.h>
6511134SCasper.Dik@Sun.COM #include <util/qsort.h>
664321Scasper 
675771Sjp151216 
685771Sjp151216 /* Ephemeral IDs Zones specific data */
695771Sjp151216 typedef struct ephemeral_zsd {
705771Sjp151216 	uid_t		min_uid;
715771Sjp151216 	uid_t		last_uid;
725771Sjp151216 	gid_t		min_gid;
735771Sjp151216 	gid_t		last_gid;
744321Scasper 	kmutex_t	eph_lock;
755771Sjp151216 	cred_t		*eph_nobody;
765771Sjp151216 } ephemeral_zsd_t;
775771Sjp151216 
7811134SCasper.Dik@Sun.COM /* Supplemental groups list. */
7911134SCasper.Dik@Sun.COM typedef struct credgrp {
8011134SCasper.Dik@Sun.COM 	uint_t		crg_ref;
8111134SCasper.Dik@Sun.COM 	uint_t		crg_ngroups;
8211134SCasper.Dik@Sun.COM 	gid_t		crg_groups[1];
8311134SCasper.Dik@Sun.COM } credgrp_t;
8411134SCasper.Dik@Sun.COM 
8511134SCasper.Dik@Sun.COM static void crgrphold(credgrp_t *);
8611134SCasper.Dik@Sun.COM 
8711134SCasper.Dik@Sun.COM #define	CREDGRPSZ(ngrp)	(sizeof (credgrp_t) + ((ngrp - 1) * sizeof (gid_t)))
885771Sjp151216 
895771Sjp151216 static kmutex_t		ephemeral_zone_mutex;
905771Sjp151216 static zone_key_t	ephemeral_zone_key;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate static struct kmem_cache *cred_cache;
935771Sjp151216 static size_t		crsize = 0;
945771Sjp151216 static int		audoff = 0;
955771Sjp151216 uint32_t		ucredsize;
965771Sjp151216 cred_t			*kcred;
975771Sjp151216 static cred_t		*dummycr;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate int rstlink;		/* link(2) restricted to files owned by user? */
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate static int get_c2audit_load(void);
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate #define	CR_AUINFO(c)	(auditinfo_addr_t *)((audoff == 0) ? NULL : \
1040Sstevel@tonic-gate 			    ((char *)(c)) + audoff)
1050Sstevel@tonic-gate 
1061676Sjpk #define	REMOTE_PEER_CRED(c)	((c)->cr_gid == -1)
1070Sstevel@tonic-gate 
10811134SCasper.Dik@Sun.COM #define	BIN_GROUP_SEARCH_CUTOFF	16
1094321Scasper 
1104321Scasper static boolean_t hasephids = B_FALSE;
1114321Scasper 
1125771Sjp151216 static ephemeral_zsd_t *
get_ephemeral_zsd(zone_t * zone)1135771Sjp151216 get_ephemeral_zsd(zone_t *zone)
1145771Sjp151216 {
1155771Sjp151216 	ephemeral_zsd_t *eph_zsd;
1165771Sjp151216 
1175771Sjp151216 	eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
1185771Sjp151216 	if (eph_zsd != NULL) {
1195771Sjp151216 		return (eph_zsd);
1205771Sjp151216 	}
1215771Sjp151216 
1225771Sjp151216 	mutex_enter(&ephemeral_zone_mutex);
1235771Sjp151216 	eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
1245771Sjp151216 	if (eph_zsd == NULL) {
1255771Sjp151216 		eph_zsd = kmem_zalloc(sizeof (ephemeral_zsd_t), KM_SLEEP);
1265771Sjp151216 		eph_zsd->min_uid = MAXUID;
1275771Sjp151216 		eph_zsd->last_uid = IDMAP_WK__MAX_UID;
1285771Sjp151216 		eph_zsd->min_gid = MAXUID;
1295771Sjp151216 		eph_zsd->last_gid = IDMAP_WK__MAX_GID;
1305771Sjp151216 		mutex_init(&eph_zsd->eph_lock, NULL, MUTEX_DEFAULT, NULL);
1315771Sjp151216 
1325771Sjp151216 		/*
1335771Sjp151216 		 * nobody is used to map SID containing CRs.
1345771Sjp151216 		 */
1355771Sjp151216 		eph_zsd->eph_nobody = crdup(zone->zone_kcred);
1365771Sjp151216 		(void) crsetugid(eph_zsd->eph_nobody, UID_NOBODY, GID_NOBODY);
1375771Sjp151216 		CR_FLAGS(eph_zsd->eph_nobody) = 0;
1385771Sjp151216 		eph_zsd->eph_nobody->cr_zone = zone;
1395771Sjp151216 
1405771Sjp151216 		(void) zone_setspecific(ephemeral_zone_key, zone, eph_zsd);
1415771Sjp151216 	}
1425771Sjp151216 	mutex_exit(&ephemeral_zone_mutex);
1435771Sjp151216 	return (eph_zsd);
1445771Sjp151216 }
1455771Sjp151216 
1469710SKen.Powell@Sun.COM static cred_t *crdup_flags(const cred_t *, int);
1476134Scasper static cred_t *cralloc_flags(int);
1486134Scasper 
1495771Sjp151216 /*
1505771Sjp151216  * This function is called when a zone is destroyed
1515771Sjp151216  */
1525771Sjp151216 static void
1535771Sjp151216 /* ARGSUSED */
destroy_ephemeral_zsd(zoneid_t zone_id,void * arg)1545771Sjp151216 destroy_ephemeral_zsd(zoneid_t zone_id, void *arg)
1555771Sjp151216 {
1565771Sjp151216 	ephemeral_zsd_t *eph_zsd = arg;
1575771Sjp151216 	if (eph_zsd != NULL) {
1585771Sjp151216 		mutex_destroy(&eph_zsd->eph_lock);
1595771Sjp151216 		crfree(eph_zsd->eph_nobody);
1605771Sjp151216 		kmem_free(eph_zsd, sizeof (ephemeral_zsd_t));
1615771Sjp151216 	}
1625771Sjp151216 }
1635771Sjp151216 
1645771Sjp151216 
1655771Sjp151216 
1664321Scasper /*
1670Sstevel@tonic-gate  * Initialize credentials data structures.
1680Sstevel@tonic-gate  */
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate void
cred_init(void)1710Sstevel@tonic-gate cred_init(void)
1720Sstevel@tonic-gate {
1730Sstevel@tonic-gate 	priv_init();
1740Sstevel@tonic-gate 
17511134SCasper.Dik@Sun.COM 	crsize = sizeof (cred_t);
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	if (get_c2audit_load() > 0) {
1780Sstevel@tonic-gate #ifdef _LP64
1790Sstevel@tonic-gate 		/* assure audit context is 64-bit aligned */
1800Sstevel@tonic-gate 		audoff = (crsize +
1810Sstevel@tonic-gate 		    sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1);
1820Sstevel@tonic-gate #else	/* _LP64 */
1830Sstevel@tonic-gate 		audoff = crsize;
1840Sstevel@tonic-gate #endif	/* _LP64 */
1850Sstevel@tonic-gate 		crsize = audoff + sizeof (auditinfo_addr_t);
1860Sstevel@tonic-gate 		crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1);
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	cred_cache = kmem_cache_create("cred_cache", crsize, 0,
1904520Snw141292 	    NULL, NULL, NULL, NULL, NULL, 0);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	/*
1931676Sjpk 	 * dummycr is used to copy initial state for creds.
1941676Sjpk 	 */
1951676Sjpk 	dummycr = cralloc();
1961676Sjpk 	bzero(dummycr, crsize);
1971676Sjpk 	dummycr->cr_ref = 1;
1984321Scasper 	dummycr->cr_uid = (uid_t)-1;
1994321Scasper 	dummycr->cr_gid = (gid_t)-1;
2004321Scasper 	dummycr->cr_ruid = (uid_t)-1;
2014321Scasper 	dummycr->cr_rgid = (gid_t)-1;
2024321Scasper 	dummycr->cr_suid = (uid_t)-1;
2034321Scasper 	dummycr->cr_sgid = (gid_t)-1;
2044321Scasper 
2051676Sjpk 
2061676Sjpk 	/*
2070Sstevel@tonic-gate 	 * kcred is used by anything that needs all privileges; it's
2080Sstevel@tonic-gate 	 * also the template used for crget as it has all the compatible
2090Sstevel@tonic-gate 	 * sets filled in.
2100Sstevel@tonic-gate 	 */
2110Sstevel@tonic-gate 	kcred = cralloc();
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	bzero(kcred, crsize);
2140Sstevel@tonic-gate 	kcred->cr_ref = 1;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	/* kcred is never freed, so we don't need zone_cred_hold here */
2170Sstevel@tonic-gate 	kcred->cr_zone = &zone0;
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	priv_fillset(&CR_LPRIV(kcred));
2200Sstevel@tonic-gate 	CR_IPRIV(kcred) = *priv_basic;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	/* Not a basic privilege, if chown is not restricted add it to I0 */
2230Sstevel@tonic-gate 	if (!rstchown)
2240Sstevel@tonic-gate 		priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF);
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	/* Basic privilege, if link is restricted remove it from I0 */
2270Sstevel@tonic-gate 	if (rstlink)
2280Sstevel@tonic-gate 		priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY);
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred);
2311676Sjpk 
2321676Sjpk 	CR_FLAGS(kcred) = NET_MAC_AWARE;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	/*
2350Sstevel@tonic-gate 	 * Set up credentials of p0.
2360Sstevel@tonic-gate 	 */
2370Sstevel@tonic-gate 	ttoproc(curthread)->p_cred = kcred;
2380Sstevel@tonic-gate 	curthread->t_cred = kcred;
2390Sstevel@tonic-gate 
2405771Sjp151216 	ucredsize = UCRED_SIZE;
2414321Scasper 
2425771Sjp151216 	mutex_init(&ephemeral_zone_mutex, NULL, MUTEX_DEFAULT, NULL);
2435771Sjp151216 	zone_key_create(&ephemeral_zone_key, NULL, NULL, destroy_ephemeral_zsd);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate  * Allocate (nearly) uninitialized cred_t.
2480Sstevel@tonic-gate  */
2496134Scasper static cred_t *
cralloc_flags(int flgs)2506134Scasper cralloc_flags(int flgs)
2510Sstevel@tonic-gate {
2526134Scasper 	cred_t *cr = kmem_cache_alloc(cred_cache, flgs);
2536134Scasper 
2546134Scasper 	if (cr == NULL)
2556134Scasper 		return (NULL);
2566134Scasper 
2570Sstevel@tonic-gate 	cr->cr_ref = 1;		/* So we can crfree() */
2580Sstevel@tonic-gate 	cr->cr_zone = NULL;
2591676Sjpk 	cr->cr_label = NULL;
2604321Scasper 	cr->cr_ksid = NULL;
2616134Scasper 	cr->cr_klpd = NULL;
26211134SCasper.Dik@Sun.COM 	cr->cr_grps = NULL;
2634321Scasper 	return (cr);
2644321Scasper }
2654321Scasper 
2666134Scasper cred_t *
cralloc(void)2676134Scasper cralloc(void)
2686134Scasper {
2696134Scasper 	return (cralloc_flags(KM_SLEEP));
2706134Scasper }
2716134Scasper 
2724321Scasper /*
2734321Scasper  * As cralloc but prepared for ksid change (if appropriate).
2744321Scasper  */
2754321Scasper cred_t *
cralloc_ksid(void)2764321Scasper cralloc_ksid(void)
2774321Scasper {
2784321Scasper 	cred_t *cr = cralloc();
2794321Scasper 	if (hasephids)
2804321Scasper 		cr->cr_ksid = kcrsid_alloc();
2810Sstevel@tonic-gate 	return (cr);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate /*
2850Sstevel@tonic-gate  * Allocate a initialized cred structure and crhold() it.
2860Sstevel@tonic-gate  * Initialized means: all ids 0, group count 0, L=Full, E=P=I=I0
2870Sstevel@tonic-gate  */
2880Sstevel@tonic-gate cred_t *
crget(void)2890Sstevel@tonic-gate crget(void)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate 	cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP);
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	bcopy(kcred, cr, crsize);
2940Sstevel@tonic-gate 	cr->cr_ref = 1;
2950Sstevel@tonic-gate 	zone_cred_hold(cr->cr_zone);
2961676Sjpk 	if (cr->cr_label)
2971676Sjpk 		label_hold(cr->cr_label);
2986134Scasper 	ASSERT(cr->cr_klpd == NULL);
29911134SCasper.Dik@Sun.COM 	ASSERT(cr->cr_grps == NULL);
3000Sstevel@tonic-gate 	return (cr);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate /*
3040Sstevel@tonic-gate  * Broadcast the cred to all the threads in the process.
3050Sstevel@tonic-gate  * The current thread's credentials can be set right away, but other
3060Sstevel@tonic-gate  * threads must wait until the start of the next system call or trap.
3070Sstevel@tonic-gate  * This avoids changing the cred in the middle of a system call.
3080Sstevel@tonic-gate  *
3090Sstevel@tonic-gate  * The cred has already been held for the process and the thread (2 holds),
3100Sstevel@tonic-gate  * and p->p_cred set.
3110Sstevel@tonic-gate  *
3120Sstevel@tonic-gate  * p->p_crlock shouldn't be held here, since p_lock must be acquired.
3130Sstevel@tonic-gate  */
3140Sstevel@tonic-gate void
crset(proc_t * p,cred_t * cr)3150Sstevel@tonic-gate crset(proc_t *p, cred_t *cr)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate 	kthread_id_t	t;
3180Sstevel@tonic-gate 	kthread_id_t	first;
3190Sstevel@tonic-gate 	cred_t *oldcr;
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	ASSERT(p == curproc);	/* assumes p_lwpcnt can't change */
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	/*
3240Sstevel@tonic-gate 	 * DTrace accesses t_cred in probe context.  t_cred must always be
3250Sstevel@tonic-gate 	 * either NULL, or point to a valid, allocated cred structure.
3260Sstevel@tonic-gate 	 */
3270Sstevel@tonic-gate 	t = curthread;
3280Sstevel@tonic-gate 	oldcr = t->t_cred;
3290Sstevel@tonic-gate 	t->t_cred = cr;		/* the cred is held by caller for this thread */
3300Sstevel@tonic-gate 	crfree(oldcr);		/* free the old cred for the thread */
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	/*
3330Sstevel@tonic-gate 	 * Broadcast to other threads, if any.
3340Sstevel@tonic-gate 	 */
3350Sstevel@tonic-gate 	if (p->p_lwpcnt > 1) {
3360Sstevel@tonic-gate 		mutex_enter(&p->p_lock);	/* to keep thread list safe */
3370Sstevel@tonic-gate 		first = curthread;
3380Sstevel@tonic-gate 		for (t = first->t_forw; t != first; t = t->t_forw)
3390Sstevel@tonic-gate 			t->t_pre_sys = 1; /* so syscall will get new cred */
3400Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
3410Sstevel@tonic-gate 	}
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate /*
3450Sstevel@tonic-gate  * Put a hold on a cred structure.
3460Sstevel@tonic-gate  */
3470Sstevel@tonic-gate void
crhold(cred_t * cr)3480Sstevel@tonic-gate crhold(cred_t *cr)
3490Sstevel@tonic-gate {
350*12273SCasper.Dik@Sun.COM 	ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
3510Sstevel@tonic-gate 	atomic_add_32(&cr->cr_ref, 1);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate  * Release previous hold on a cred structure.  Free it if refcnt == 0.
3561676Sjpk  * If cred uses label different from zone label, free it.
3570Sstevel@tonic-gate  */
3580Sstevel@tonic-gate void
crfree(cred_t * cr)3590Sstevel@tonic-gate crfree(cred_t *cr)
3600Sstevel@tonic-gate {
361*12273SCasper.Dik@Sun.COM 	ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
3620Sstevel@tonic-gate 	if (atomic_add_32_nv(&cr->cr_ref, -1) == 0) {
3630Sstevel@tonic-gate 		ASSERT(cr != kcred);
3641676Sjpk 		if (cr->cr_label)
3651676Sjpk 			label_rele(cr->cr_label);
3666134Scasper 		if (cr->cr_klpd)
3676134Scasper 			crklpd_rele(cr->cr_klpd);
3680Sstevel@tonic-gate 		if (cr->cr_zone)
3690Sstevel@tonic-gate 			zone_cred_rele(cr->cr_zone);
3704321Scasper 		if (cr->cr_ksid)
3714321Scasper 			kcrsid_rele(cr->cr_ksid);
37211134SCasper.Dik@Sun.COM 		if (cr->cr_grps)
37311134SCasper.Dik@Sun.COM 			crgrprele(cr->cr_grps);
37411134SCasper.Dik@Sun.COM 
3750Sstevel@tonic-gate 		kmem_cache_free(cred_cache, cr);
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate  * Copy a cred structure to a new one and free the old one.
3810Sstevel@tonic-gate  *	The new cred will have two references.  One for the calling process,
3820Sstevel@tonic-gate  * 	and one for the thread.
3830Sstevel@tonic-gate  */
3840Sstevel@tonic-gate cred_t *
crcopy(cred_t * cr)3850Sstevel@tonic-gate crcopy(cred_t *cr)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate 	cred_t *newcr;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	newcr = cralloc();
3900Sstevel@tonic-gate 	bcopy(cr, newcr, crsize);
3910Sstevel@tonic-gate 	if (newcr->cr_zone)
3920Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
3931676Sjpk 	if (newcr->cr_label)
3946134Scasper 		label_hold(newcr->cr_label);
3954321Scasper 	if (newcr->cr_ksid)
3966134Scasper 		kcrsid_hold(newcr->cr_ksid);
3976134Scasper 	if (newcr->cr_klpd)
3986134Scasper 		crklpd_hold(newcr->cr_klpd);
39911134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
40011134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
4010Sstevel@tonic-gate 	crfree(cr);
4020Sstevel@tonic-gate 	newcr->cr_ref = 2;		/* caller gets two references */
4030Sstevel@tonic-gate 	return (newcr);
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate /*
4070Sstevel@tonic-gate  * Copy a cred structure to a new one and free the old one.
4080Sstevel@tonic-gate  *	The new cred will have two references.  One for the calling process,
4090Sstevel@tonic-gate  * 	and one for the thread.
4100Sstevel@tonic-gate  * This variation on crcopy uses a pre-allocated structure for the
4110Sstevel@tonic-gate  * "new" cred.
4120Sstevel@tonic-gate  */
4130Sstevel@tonic-gate void
crcopy_to(cred_t * oldcr,cred_t * newcr)4140Sstevel@tonic-gate crcopy_to(cred_t *oldcr, cred_t *newcr)
4150Sstevel@tonic-gate {
4164321Scasper 	credsid_t *nkcr = newcr->cr_ksid;
4174321Scasper 
4180Sstevel@tonic-gate 	bcopy(oldcr, newcr, crsize);
4190Sstevel@tonic-gate 	if (newcr->cr_zone)
4200Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
4211676Sjpk 	if (newcr->cr_label)
4221676Sjpk 		label_hold(newcr->cr_label);
4236134Scasper 	if (newcr->cr_klpd)
4246134Scasper 		crklpd_hold(newcr->cr_klpd);
42511134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
42611134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
4274321Scasper 	if (nkcr) {
4284321Scasper 		newcr->cr_ksid = nkcr;
4294321Scasper 		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
4304321Scasper 	} else if (newcr->cr_ksid)
4314321Scasper 		kcrsid_hold(newcr->cr_ksid);
4320Sstevel@tonic-gate 	crfree(oldcr);
4330Sstevel@tonic-gate 	newcr->cr_ref = 2;		/* caller gets two references */
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate /*
4370Sstevel@tonic-gate  * Dup a cred struct to a new held one.
4380Sstevel@tonic-gate  *	The old cred is not freed.
4390Sstevel@tonic-gate  */
4406134Scasper static cred_t *
crdup_flags(const cred_t * cr,int flgs)4419710SKen.Powell@Sun.COM crdup_flags(const cred_t *cr, int flgs)
4420Sstevel@tonic-gate {
4430Sstevel@tonic-gate 	cred_t *newcr;
4440Sstevel@tonic-gate 
4456134Scasper 	newcr = cralloc_flags(flgs);
4466134Scasper 
4476134Scasper 	if (newcr == NULL)
4486134Scasper 		return (NULL);
4496134Scasper 
4500Sstevel@tonic-gate 	bcopy(cr, newcr, crsize);
4510Sstevel@tonic-gate 	if (newcr->cr_zone)
4520Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
4531676Sjpk 	if (newcr->cr_label)
4541676Sjpk 		label_hold(newcr->cr_label);
4556134Scasper 	if (newcr->cr_klpd)
4566134Scasper 		crklpd_hold(newcr->cr_klpd);
4574321Scasper 	if (newcr->cr_ksid)
4584321Scasper 		kcrsid_hold(newcr->cr_ksid);
45911134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
46011134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
4610Sstevel@tonic-gate 	newcr->cr_ref = 1;
4620Sstevel@tonic-gate 	return (newcr);
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate 
4656134Scasper cred_t *
crdup(cred_t * cr)4666134Scasper crdup(cred_t *cr)
4676134Scasper {
4686134Scasper 	return (crdup_flags(cr, KM_SLEEP));
4696134Scasper }
4706134Scasper 
4710Sstevel@tonic-gate /*
4720Sstevel@tonic-gate  * Dup a cred struct to a new held one.
4730Sstevel@tonic-gate  *	The old cred is not freed.
4740Sstevel@tonic-gate  * This variation on crdup uses a pre-allocated structure for the
4750Sstevel@tonic-gate  * "new" cred.
4760Sstevel@tonic-gate  */
4770Sstevel@tonic-gate void
crdup_to(cred_t * oldcr,cred_t * newcr)4780Sstevel@tonic-gate crdup_to(cred_t *oldcr, cred_t *newcr)
4790Sstevel@tonic-gate {
4804321Scasper 	credsid_t *nkcr = newcr->cr_ksid;
4814321Scasper 
4820Sstevel@tonic-gate 	bcopy(oldcr, newcr, crsize);
4830Sstevel@tonic-gate 	if (newcr->cr_zone)
4840Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
4851676Sjpk 	if (newcr->cr_label)
4861676Sjpk 		label_hold(newcr->cr_label);
4876134Scasper 	if (newcr->cr_klpd)
4886134Scasper 		crklpd_hold(newcr->cr_klpd);
48911134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
49011134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
4914321Scasper 	if (nkcr) {
4924321Scasper 		newcr->cr_ksid = nkcr;
4934321Scasper 		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
4944321Scasper 	} else if (newcr->cr_ksid)
4954321Scasper 		kcrsid_hold(newcr->cr_ksid);
4960Sstevel@tonic-gate 	newcr->cr_ref = 1;
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate /*
5000Sstevel@tonic-gate  * Return the (held) credentials for the current running process.
5010Sstevel@tonic-gate  */
5020Sstevel@tonic-gate cred_t *
crgetcred(void)5031676Sjpk crgetcred(void)
5040Sstevel@tonic-gate {
5050Sstevel@tonic-gate 	cred_t *cr;
5060Sstevel@tonic-gate 	proc_t *p;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	p = ttoproc(curthread);
5090Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
5100Sstevel@tonic-gate 	crhold(cr = p->p_cred);
5110Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
5120Sstevel@tonic-gate 	return (cr);
5130Sstevel@tonic-gate }
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate /*
5160Sstevel@tonic-gate  * Backward compatibility check for suser().
5170Sstevel@tonic-gate  * Accounting flag is now set in the policy functions; auditing is
5180Sstevel@tonic-gate  * done through use of privilege in the audit trail.
5190Sstevel@tonic-gate  */
5200Sstevel@tonic-gate int
suser(cred_t * cr)5210Sstevel@tonic-gate suser(cred_t *cr)
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate 	return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL)
5240Sstevel@tonic-gate 	    == 0);
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate /*
5280Sstevel@tonic-gate  * Determine whether the supplied group id is a member of the group
5290Sstevel@tonic-gate  * described by the supplied credentials.
5300Sstevel@tonic-gate  */
5310Sstevel@tonic-gate int
groupmember(gid_t gid,const cred_t * cr)5320Sstevel@tonic-gate groupmember(gid_t gid, const cred_t *cr)
5330Sstevel@tonic-gate {
5340Sstevel@tonic-gate 	if (gid == cr->cr_gid)
5350Sstevel@tonic-gate 		return (1);
5360Sstevel@tonic-gate 	return (supgroupmember(gid, cr));
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate /*
5400Sstevel@tonic-gate  * As groupmember but only check against the supplemental groups.
5410Sstevel@tonic-gate  */
5420Sstevel@tonic-gate int
supgroupmember(gid_t gid,const cred_t * cr)5430Sstevel@tonic-gate supgroupmember(gid_t gid, const cred_t *cr)
5440Sstevel@tonic-gate {
54511134SCasper.Dik@Sun.COM 	int hi, lo;
54611134SCasper.Dik@Sun.COM 	credgrp_t *grps = cr->cr_grps;
5470Sstevel@tonic-gate 	const gid_t *gp, *endgp;
5480Sstevel@tonic-gate 
54911134SCasper.Dik@Sun.COM 	if (grps == NULL)
55011134SCasper.Dik@Sun.COM 		return (0);
55111134SCasper.Dik@Sun.COM 
55211134SCasper.Dik@Sun.COM 	/* For a small number of groups, use sequentials search. */
55311134SCasper.Dik@Sun.COM 	if (grps->crg_ngroups <= BIN_GROUP_SEARCH_CUTOFF) {
55411134SCasper.Dik@Sun.COM 		endgp = &grps->crg_groups[grps->crg_ngroups];
55511134SCasper.Dik@Sun.COM 		for (gp = grps->crg_groups; gp < endgp; gp++)
55611134SCasper.Dik@Sun.COM 			if (*gp == gid)
55711134SCasper.Dik@Sun.COM 				return (1);
55811134SCasper.Dik@Sun.COM 		return (0);
55911134SCasper.Dik@Sun.COM 	}
56011134SCasper.Dik@Sun.COM 
56111134SCasper.Dik@Sun.COM 	/* We use binary search when we have many groups. */
56211134SCasper.Dik@Sun.COM 	lo = 0;
56311134SCasper.Dik@Sun.COM 	hi = grps->crg_ngroups - 1;
56411134SCasper.Dik@Sun.COM 	gp = grps->crg_groups;
56511134SCasper.Dik@Sun.COM 
56611134SCasper.Dik@Sun.COM 	do {
56711134SCasper.Dik@Sun.COM 		int m = (lo + hi) / 2;
56811134SCasper.Dik@Sun.COM 
56911134SCasper.Dik@Sun.COM 		if (gid > gp[m])
57011134SCasper.Dik@Sun.COM 			lo = m + 1;
57111134SCasper.Dik@Sun.COM 		else if (gid < gp[m])
57211134SCasper.Dik@Sun.COM 			hi = m - 1;
57311134SCasper.Dik@Sun.COM 		else
5740Sstevel@tonic-gate 			return (1);
57511134SCasper.Dik@Sun.COM 	} while (lo <= hi);
57611134SCasper.Dik@Sun.COM 
5770Sstevel@tonic-gate 	return (0);
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate /*
5810Sstevel@tonic-gate  * This function is called to check whether the credentials set
5820Sstevel@tonic-gate  * "scrp" has permission to act on credentials set "tcrp".  It enforces the
5830Sstevel@tonic-gate  * permission requirements needed to send a signal to a process.
5840Sstevel@tonic-gate  * The same requirements are imposed by other system calls, however.
5850Sstevel@tonic-gate  *
5860Sstevel@tonic-gate  * The rules are:
5870Sstevel@tonic-gate  * (1) if the credentials are the same, the check succeeds
5880Sstevel@tonic-gate  * (2) if the zone ids don't match, and scrp is not in the global zone or
5890Sstevel@tonic-gate  *     does not have the PRIV_PROC_ZONE privilege, the check fails
5900Sstevel@tonic-gate  * (3) if the real or effective user id of scrp matches the real or saved
5910Sstevel@tonic-gate  *     user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check
5920Sstevel@tonic-gate  *     succeeds
5930Sstevel@tonic-gate  * (4) otherwise, the check fails
5940Sstevel@tonic-gate  */
5950Sstevel@tonic-gate int
hasprocperm(const cred_t * tcrp,const cred_t * scrp)5960Sstevel@tonic-gate hasprocperm(const cred_t *tcrp, const cred_t *scrp)
5970Sstevel@tonic-gate {
5980Sstevel@tonic-gate 	if (scrp == tcrp)
5990Sstevel@tonic-gate 		return (1);
6000Sstevel@tonic-gate 	if (scrp->cr_zone != tcrp->cr_zone &&
6010Sstevel@tonic-gate 	    (scrp->cr_zone != global_zone ||
6020Sstevel@tonic-gate 	    secpolicy_proc_zone(scrp) != 0))
6030Sstevel@tonic-gate 		return (0);
6040Sstevel@tonic-gate 	if (scrp->cr_uid == tcrp->cr_ruid ||
6050Sstevel@tonic-gate 	    scrp->cr_ruid == tcrp->cr_ruid ||
6060Sstevel@tonic-gate 	    scrp->cr_uid  == tcrp->cr_suid ||
6070Sstevel@tonic-gate 	    scrp->cr_ruid == tcrp->cr_suid ||
6080Sstevel@tonic-gate 	    !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm"))
6090Sstevel@tonic-gate 		return (1);
6100Sstevel@tonic-gate 	return (0);
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate /*
6140Sstevel@tonic-gate  * This interface replaces hasprocperm; it works like hasprocperm but
6150Sstevel@tonic-gate  * additionally returns success if the proc_t's match
6160Sstevel@tonic-gate  * It is the preferred interface for most uses.
6176134Scasper  * And it will acquire p_crlock itself, so it assert's that it shouldn't
6180Sstevel@tonic-gate  * be held.
6190Sstevel@tonic-gate  */
6200Sstevel@tonic-gate int
prochasprocperm(proc_t * tp,proc_t * sp,const cred_t * scrp)6210Sstevel@tonic-gate prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp)
6220Sstevel@tonic-gate {
6230Sstevel@tonic-gate 	int rets;
6240Sstevel@tonic-gate 	cred_t *tcrp;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&tp->p_crlock));
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	if (tp == sp)
6290Sstevel@tonic-gate 		return (1);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0)
6320Sstevel@tonic-gate 		return (0);
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	mutex_enter(&tp->p_crlock);
6356134Scasper 	crhold(tcrp = tp->p_cred);
6366134Scasper 	mutex_exit(&tp->p_crlock);
6370Sstevel@tonic-gate 	rets = hasprocperm(tcrp, scrp);
6386134Scasper 	crfree(tcrp);
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	return (rets);
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate /*
6440Sstevel@tonic-gate  * This routine is used to compare two credentials to determine if
6450Sstevel@tonic-gate  * they refer to the same "user".  If the pointers are equal, then
6460Sstevel@tonic-gate  * they must refer to the same user.  Otherwise, the contents of
6470Sstevel@tonic-gate  * the credentials are compared to see whether they are equivalent.
6480Sstevel@tonic-gate  *
6490Sstevel@tonic-gate  * This routine returns 0 if the credentials refer to the same user,
6500Sstevel@tonic-gate  * 1 if they do not.
6510Sstevel@tonic-gate  */
6520Sstevel@tonic-gate int
crcmp(const cred_t * cr1,const cred_t * cr2)6530Sstevel@tonic-gate crcmp(const cred_t *cr1, const cred_t *cr2)
6540Sstevel@tonic-gate {
65511134SCasper.Dik@Sun.COM 	credgrp_t *grp1, *grp2;
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	if (cr1 == cr2)
6580Sstevel@tonic-gate 		return (0);
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	if (cr1->cr_uid == cr2->cr_uid &&
6610Sstevel@tonic-gate 	    cr1->cr_gid == cr2->cr_gid &&
6620Sstevel@tonic-gate 	    cr1->cr_ruid == cr2->cr_ruid &&
6630Sstevel@tonic-gate 	    cr1->cr_rgid == cr2->cr_rgid &&
6640Sstevel@tonic-gate 	    cr1->cr_zone == cr2->cr_zone &&
66511134SCasper.Dik@Sun.COM 	    ((grp1 = cr1->cr_grps) == (grp2 = cr2->cr_grps) ||
66611134SCasper.Dik@Sun.COM 	    (grp1 != NULL && grp2 != NULL &&
66711134SCasper.Dik@Sun.COM 	    grp1->crg_ngroups == grp2->crg_ngroups &&
66811134SCasper.Dik@Sun.COM 	    bcmp(grp1->crg_groups, grp2->crg_groups,
66911134SCasper.Dik@Sun.COM 	    grp1->crg_ngroups * sizeof (gid_t)) == 0))) {
6700Sstevel@tonic-gate 		return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2)));
6710Sstevel@tonic-gate 	}
6720Sstevel@tonic-gate 	return (1);
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate /*
6760Sstevel@tonic-gate  * Read access functions to cred_t.
6770Sstevel@tonic-gate  */
6780Sstevel@tonic-gate uid_t
crgetuid(const cred_t * cr)6790Sstevel@tonic-gate crgetuid(const cred_t *cr)
6800Sstevel@tonic-gate {
6810Sstevel@tonic-gate 	return (cr->cr_uid);
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate uid_t
crgetruid(const cred_t * cr)6850Sstevel@tonic-gate crgetruid(const cred_t *cr)
6860Sstevel@tonic-gate {
6870Sstevel@tonic-gate 	return (cr->cr_ruid);
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate uid_t
crgetsuid(const cred_t * cr)6910Sstevel@tonic-gate crgetsuid(const cred_t *cr)
6920Sstevel@tonic-gate {
6930Sstevel@tonic-gate 	return (cr->cr_suid);
6940Sstevel@tonic-gate }
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate gid_t
crgetgid(const cred_t * cr)6970Sstevel@tonic-gate crgetgid(const cred_t *cr)
6980Sstevel@tonic-gate {
6990Sstevel@tonic-gate 	return (cr->cr_gid);
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate gid_t
crgetrgid(const cred_t * cr)7030Sstevel@tonic-gate crgetrgid(const cred_t *cr)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate 	return (cr->cr_rgid);
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate gid_t
crgetsgid(const cred_t * cr)7090Sstevel@tonic-gate crgetsgid(const cred_t *cr)
7100Sstevel@tonic-gate {
7110Sstevel@tonic-gate 	return (cr->cr_sgid);
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate const auditinfo_addr_t *
crgetauinfo(const cred_t * cr)7150Sstevel@tonic-gate crgetauinfo(const cred_t *cr)
7160Sstevel@tonic-gate {
7170Sstevel@tonic-gate 	return ((const auditinfo_addr_t *)CR_AUINFO(cr));
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate auditinfo_addr_t *
crgetauinfo_modifiable(cred_t * cr)7210Sstevel@tonic-gate crgetauinfo_modifiable(cred_t *cr)
7220Sstevel@tonic-gate {
7230Sstevel@tonic-gate 	return (CR_AUINFO(cr));
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate zoneid_t
crgetzoneid(const cred_t * cr)7270Sstevel@tonic-gate crgetzoneid(const cred_t *cr)
7280Sstevel@tonic-gate {
7291676Sjpk 	return (cr->cr_zone == NULL ?
7301676Sjpk 	    (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) :
7311676Sjpk 	    cr->cr_zone->zone_id);
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate projid_t
crgetprojid(const cred_t * cr)7350Sstevel@tonic-gate crgetprojid(const cred_t *cr)
7360Sstevel@tonic-gate {
7370Sstevel@tonic-gate 	return (cr->cr_projid);
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate 
7401676Sjpk zone_t *
crgetzone(const cred_t * cr)7411676Sjpk crgetzone(const cred_t *cr)
7421676Sjpk {
7431676Sjpk 	return (cr->cr_zone);
7441676Sjpk }
7451676Sjpk 
7461676Sjpk struct ts_label_s *
crgetlabel(const cred_t * cr)7471676Sjpk crgetlabel(const cred_t *cr)
7481676Sjpk {
7491676Sjpk 	return (cr->cr_label ?
7501676Sjpk 	    cr->cr_label :
7511676Sjpk 	    (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL));
7521676Sjpk }
7531676Sjpk 
7541676Sjpk boolean_t
crisremote(const cred_t * cr)7551676Sjpk crisremote(const cred_t *cr)
7561676Sjpk {
7571676Sjpk 	return (REMOTE_PEER_CRED(cr));
7581676Sjpk }
7591676Sjpk 
7605771Sjp151216 #define	BADUID(x, zn)	((x) != -1 && !VALID_UID((x), (zn)))
7615771Sjp151216 #define	BADGID(x, zn)	((x) != -1 && !VALID_GID((x), (zn)))
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate int
crsetresuid(cred_t * cr,uid_t r,uid_t e,uid_t s)7640Sstevel@tonic-gate crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s)
7650Sstevel@tonic-gate {
7665771Sjp151216 	zone_t	*zone = crgetzone(cr);
7675771Sjp151216 
7680Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
7690Sstevel@tonic-gate 
7705771Sjp151216 	if (BADUID(r, zone) || BADUID(e, zone) || BADUID(s, zone))
7710Sstevel@tonic-gate 		return (-1);
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	if (r != -1)
7740Sstevel@tonic-gate 		cr->cr_ruid = r;
7750Sstevel@tonic-gate 	if (e != -1)
7760Sstevel@tonic-gate 		cr->cr_uid = e;
7770Sstevel@tonic-gate 	if (s != -1)
7780Sstevel@tonic-gate 		cr->cr_suid = s;
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	return (0);
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate int
crsetresgid(cred_t * cr,gid_t r,gid_t e,gid_t s)7840Sstevel@tonic-gate crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s)
7850Sstevel@tonic-gate {
7865771Sjp151216 	zone_t	*zone = crgetzone(cr);
7875771Sjp151216 
7880Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
7890Sstevel@tonic-gate 
7905771Sjp151216 	if (BADGID(r, zone) || BADGID(e, zone) || BADGID(s, zone))
7910Sstevel@tonic-gate 		return (-1);
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	if (r != -1)
7940Sstevel@tonic-gate 		cr->cr_rgid = r;
7950Sstevel@tonic-gate 	if (e != -1)
7960Sstevel@tonic-gate 		cr->cr_gid = e;
7970Sstevel@tonic-gate 	if (s != -1)
7980Sstevel@tonic-gate 		cr->cr_sgid = s;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	return (0);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate int
crsetugid(cred_t * cr,uid_t uid,gid_t gid)8040Sstevel@tonic-gate crsetugid(cred_t *cr, uid_t uid, gid_t gid)
8050Sstevel@tonic-gate {
8065771Sjp151216 	zone_t	*zone = crgetzone(cr);
8075771Sjp151216 
8080Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
8090Sstevel@tonic-gate 
8105771Sjp151216 	if (!VALID_UID(uid, zone) || !VALID_GID(gid, zone))
8110Sstevel@tonic-gate 		return (-1);
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid;
8140Sstevel@tonic-gate 	cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid;
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	return (0);
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate 
81911134SCasper.Dik@Sun.COM static int
gidcmp(const void * v1,const void * v2)82011134SCasper.Dik@Sun.COM gidcmp(const void *v1, const void *v2)
82111134SCasper.Dik@Sun.COM {
82211134SCasper.Dik@Sun.COM 	gid_t g1 = *(gid_t *)v1;
82311134SCasper.Dik@Sun.COM 	gid_t g2 = *(gid_t *)v2;
82411134SCasper.Dik@Sun.COM 
82511134SCasper.Dik@Sun.COM 	if (g1 < g2)
82611134SCasper.Dik@Sun.COM 		return (-1);
82711134SCasper.Dik@Sun.COM 	else if (g1 > g2)
82811134SCasper.Dik@Sun.COM 		return (1);
82911134SCasper.Dik@Sun.COM 	else
83011134SCasper.Dik@Sun.COM 		return (0);
83111134SCasper.Dik@Sun.COM }
83211134SCasper.Dik@Sun.COM 
8330Sstevel@tonic-gate int
crsetgroups(cred_t * cr,int n,gid_t * grp)8340Sstevel@tonic-gate crsetgroups(cred_t *cr, int n, gid_t *grp)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	if (n > ngroups_max || n < 0)
8390Sstevel@tonic-gate 		return (-1);
8400Sstevel@tonic-gate 
84111134SCasper.Dik@Sun.COM 	if (cr->cr_grps != NULL)
84211134SCasper.Dik@Sun.COM 		crgrprele(cr->cr_grps);
8430Sstevel@tonic-gate 
84411134SCasper.Dik@Sun.COM 	if (n > 0) {
84511134SCasper.Dik@Sun.COM 		cr->cr_grps = kmem_alloc(CREDGRPSZ(n), KM_SLEEP);
84611134SCasper.Dik@Sun.COM 		bcopy(grp, cr->cr_grps->crg_groups, n * sizeof (gid_t));
84711134SCasper.Dik@Sun.COM 		cr->cr_grps->crg_ref = 1;
84811134SCasper.Dik@Sun.COM 		cr->cr_grps->crg_ngroups = n;
84911134SCasper.Dik@Sun.COM 		qsort(cr->cr_grps->crg_groups, n, sizeof (gid_t), gidcmp);
85011134SCasper.Dik@Sun.COM 	} else {
85111134SCasper.Dik@Sun.COM 		cr->cr_grps = NULL;
85211134SCasper.Dik@Sun.COM 	}
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	return (0);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate void
crsetprojid(cred_t * cr,projid_t projid)8580Sstevel@tonic-gate crsetprojid(cred_t *cr, projid_t projid)
8590Sstevel@tonic-gate {
8600Sstevel@tonic-gate 	ASSERT(projid >= 0 && projid <= MAXPROJID);
8610Sstevel@tonic-gate 	cr->cr_projid = projid;
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate /*
86511134SCasper.Dik@Sun.COM  * This routine returns the pointer to the first element of the crg_groups
8660Sstevel@tonic-gate  * array.  It can move around in an implementation defined way.
86711134SCasper.Dik@Sun.COM  * Note that when we have no grouplist, we return one element but the
86811134SCasper.Dik@Sun.COM  * caller should never reference it.
8690Sstevel@tonic-gate  */
8700Sstevel@tonic-gate const gid_t *
crgetgroups(const cred_t * cr)8710Sstevel@tonic-gate crgetgroups(const cred_t *cr)
8720Sstevel@tonic-gate {
87311134SCasper.Dik@Sun.COM 	return (cr->cr_grps == NULL ? &cr->cr_gid : cr->cr_grps->crg_groups);
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate int
crgetngroups(const cred_t * cr)8770Sstevel@tonic-gate crgetngroups(const cred_t *cr)
8780Sstevel@tonic-gate {
87911134SCasper.Dik@Sun.COM 	return (cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups);
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate void
cred2prcred(const cred_t * cr,prcred_t * pcrp)8830Sstevel@tonic-gate cred2prcred(const cred_t *cr, prcred_t *pcrp)
8840Sstevel@tonic-gate {
8850Sstevel@tonic-gate 	pcrp->pr_euid = cr->cr_uid;
8860Sstevel@tonic-gate 	pcrp->pr_ruid = cr->cr_ruid;
8870Sstevel@tonic-gate 	pcrp->pr_suid = cr->cr_suid;
8880Sstevel@tonic-gate 	pcrp->pr_egid = cr->cr_gid;
8890Sstevel@tonic-gate 	pcrp->pr_rgid = cr->cr_rgid;
8900Sstevel@tonic-gate 	pcrp->pr_sgid = cr->cr_sgid;
89111134SCasper.Dik@Sun.COM 	pcrp->pr_groups[0] = 0; /* in case ngroups == 0 */
89211134SCasper.Dik@Sun.COM 	pcrp->pr_ngroups = cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups;
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	if (pcrp->pr_ngroups != 0)
89511134SCasper.Dik@Sun.COM 		bcopy(cr->cr_grps->crg_groups, pcrp->pr_groups,
89611134SCasper.Dik@Sun.COM 		    sizeof (gid_t) * pcrp->pr_ngroups);
8970Sstevel@tonic-gate }
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate static int
cred2ucaud(const cred_t * cr,auditinfo64_addr_t * ainfo,const cred_t * rcr)9001676Sjpk cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr)
9010Sstevel@tonic-gate {
9020Sstevel@tonic-gate 	auditinfo_addr_t	*ai;
9030Sstevel@tonic-gate 	au_tid_addr_t	tid;
9040Sstevel@tonic-gate 
905*12273SCasper.Dik@Sun.COM 	if (secpolicy_audit_getattr(rcr, B_TRUE) != 0)
9060Sstevel@tonic-gate 		return (-1);
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	ai = CR_AUINFO(cr);	/* caller makes sure this is non-NULL */
9090Sstevel@tonic-gate 	tid = ai->ai_termid;
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	ainfo->ai_auid = ai->ai_auid;
9120Sstevel@tonic-gate 	ainfo->ai_mask = ai->ai_mask;
9130Sstevel@tonic-gate 	ainfo->ai_asid = ai->ai_asid;
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	ainfo->ai_termid.at_type = tid.at_type;
9160Sstevel@tonic-gate 	bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t));
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port);
9190Sstevel@tonic-gate 	ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port);
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	return (0);
9220Sstevel@tonic-gate }
9230Sstevel@tonic-gate 
9241676Sjpk void
cred2uclabel(const cred_t * cr,bslabel_t * labelp)9251676Sjpk cred2uclabel(const cred_t *cr, bslabel_t *labelp)
9261676Sjpk {
9271676Sjpk 	ts_label_t	*tslp;
9281676Sjpk 
9291676Sjpk 	if ((tslp = crgetlabel(cr)) != NULL)
9301676Sjpk 		bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t));
9311676Sjpk }
9321676Sjpk 
9330Sstevel@tonic-gate /*
9340Sstevel@tonic-gate  * Convert a credential into a "ucred".  Allow the caller to specify
9350Sstevel@tonic-gate  * and aligned buffer, e.g., in an mblk, so we don't have to allocate
9360Sstevel@tonic-gate  * memory and copy it twice.
9371676Sjpk  *
9381676Sjpk  * This function may call cred2ucaud(), which calls CRED(). Since this
9391676Sjpk  * can be called from an interrupt thread, receiver's cred (rcr) is needed
9401676Sjpk  * to determine whether audit info should be included.
9410Sstevel@tonic-gate  */
9420Sstevel@tonic-gate struct ucred_s *
cred2ucred(const cred_t * cr,pid_t pid,void * buf,const cred_t * rcr)9431676Sjpk cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr)
9440Sstevel@tonic-gate {
9450Sstevel@tonic-gate 	struct ucred_s *uc;
94611134SCasper.Dik@Sun.COM 	uint32_t realsz = ucredminsize(cr);
94711134SCasper.Dik@Sun.COM 	ts_label_t *tslp = is_system_labeled() ? crgetlabel(cr) : NULL;
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	/* The structure isn't always completely filled in, so zero it */
9500Sstevel@tonic-gate 	if (buf == NULL) {
95111134SCasper.Dik@Sun.COM 		uc = kmem_zalloc(realsz, KM_SLEEP);
9520Sstevel@tonic-gate 	} else {
95311134SCasper.Dik@Sun.COM 		bzero(buf, realsz);
9540Sstevel@tonic-gate 		uc = buf;
9550Sstevel@tonic-gate 	}
95611134SCasper.Dik@Sun.COM 	uc->uc_size = realsz;
9570Sstevel@tonic-gate 	uc->uc_pid = pid;
9580Sstevel@tonic-gate 	uc->uc_projid = cr->cr_projid;
9590Sstevel@tonic-gate 	uc->uc_zoneid = crgetzoneid(cr);
9600Sstevel@tonic-gate 
9611676Sjpk 	if (REMOTE_PEER_CRED(cr)) {
9621676Sjpk 		/*
96311134SCasper.Dik@Sun.COM 		 * Other than label, the rest of cred info about a
96411134SCasper.Dik@Sun.COM 		 * remote peer isn't available. Copy the label directly
96511134SCasper.Dik@Sun.COM 		 * after the header where we generally copy the prcred.
96611134SCasper.Dik@Sun.COM 		 * That's why we use sizeof (struct ucred_s).  The other
96711134SCasper.Dik@Sun.COM 		 * offset fields are initialized to 0.
9681676Sjpk 		 */
96911134SCasper.Dik@Sun.COM 		uc->uc_labeloff = tslp == NULL ? 0 : sizeof (struct ucred_s);
9701676Sjpk 	} else {
97111134SCasper.Dik@Sun.COM 		uc->uc_credoff = UCRED_CRED_OFF;
97211134SCasper.Dik@Sun.COM 		uc->uc_privoff = UCRED_PRIV_OFF;
97311134SCasper.Dik@Sun.COM 		uc->uc_audoff = UCRED_AUD_OFF;
97411134SCasper.Dik@Sun.COM 		uc->uc_labeloff = tslp == NULL ? 0 : UCRED_LABEL_OFF;
97511134SCasper.Dik@Sun.COM 
9761676Sjpk 		cred2prcred(cr, UCCRED(uc));
9771676Sjpk 		cred2prpriv(cr, UCPRIV(uc));
97811134SCasper.Dik@Sun.COM 
9791676Sjpk 		if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0)
9801676Sjpk 			uc->uc_audoff = 0;
98111134SCasper.Dik@Sun.COM 	}
98211134SCasper.Dik@Sun.COM 	if (tslp != NULL)
98311134SCasper.Dik@Sun.COM 		bcopy(&tslp->tsl_label, UCLABEL(uc), sizeof (bslabel_t));
98411134SCasper.Dik@Sun.COM 
98511134SCasper.Dik@Sun.COM 	return (uc);
98611134SCasper.Dik@Sun.COM }
98711134SCasper.Dik@Sun.COM 
98811134SCasper.Dik@Sun.COM /*
98911134SCasper.Dik@Sun.COM  * Don't allocate the non-needed group entries.  Note: this function
99011134SCasper.Dik@Sun.COM  * must match the code in cred2ucred; they must agree about the
99111134SCasper.Dik@Sun.COM  * minimal size of the ucred.
99211134SCasper.Dik@Sun.COM  */
99311134SCasper.Dik@Sun.COM uint32_t
ucredminsize(const cred_t * cr)99411134SCasper.Dik@Sun.COM ucredminsize(const cred_t *cr)
99511134SCasper.Dik@Sun.COM {
99611134SCasper.Dik@Sun.COM 	int ndiff;
99711134SCasper.Dik@Sun.COM 
99811134SCasper.Dik@Sun.COM 	if (cr == NULL)
99911134SCasper.Dik@Sun.COM 		return (ucredsize);
100011134SCasper.Dik@Sun.COM 
100111134SCasper.Dik@Sun.COM 	if (REMOTE_PEER_CRED(cr)) {
100211134SCasper.Dik@Sun.COM 		if (is_system_labeled())
100311134SCasper.Dik@Sun.COM 			return (sizeof (struct ucred_s) + sizeof (bslabel_t));
100411134SCasper.Dik@Sun.COM 		else
100511134SCasper.Dik@Sun.COM 			return (sizeof (struct ucred_s));
10061676Sjpk 	}
10070Sstevel@tonic-gate 
100811134SCasper.Dik@Sun.COM 	if (cr->cr_grps == NULL)
100911134SCasper.Dik@Sun.COM 		ndiff = ngroups_max - 1;	/* Needs one for prcred_t */
101011134SCasper.Dik@Sun.COM 	else
101111134SCasper.Dik@Sun.COM 		ndiff = ngroups_max - cr->cr_grps->crg_ngroups;
101211134SCasper.Dik@Sun.COM 
101311134SCasper.Dik@Sun.COM 	return (ucredsize - ndiff * sizeof (gid_t));
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate /*
10170Sstevel@tonic-gate  * Get the "ucred" of a process.
10180Sstevel@tonic-gate  */
10190Sstevel@tonic-gate struct ucred_s *
pgetucred(proc_t * p)10200Sstevel@tonic-gate pgetucred(proc_t *p)
10210Sstevel@tonic-gate {
10220Sstevel@tonic-gate 	cred_t *cr;
10230Sstevel@tonic-gate 	struct ucred_s *uc;
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
10260Sstevel@tonic-gate 	cr = p->p_cred;
10270Sstevel@tonic-gate 	crhold(cr);
10280Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
10290Sstevel@tonic-gate 
10301676Sjpk 	uc = cred2ucred(cr, p->p_pid, NULL, CRED());
10310Sstevel@tonic-gate 	crfree(cr);
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	return (uc);
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate /*
10370Sstevel@tonic-gate  * If the reply status is NFSERR_EACCES, it may be because we are
10380Sstevel@tonic-gate  * root (no root net access).  Check the real uid, if it isn't root
10390Sstevel@tonic-gate  * make that the uid instead and retry the call.
10400Sstevel@tonic-gate  * Private interface for NFS.
10410Sstevel@tonic-gate  */
10420Sstevel@tonic-gate cred_t *
crnetadjust(cred_t * cr)10430Sstevel@tonic-gate crnetadjust(cred_t *cr)
10440Sstevel@tonic-gate {
10450Sstevel@tonic-gate 	if (cr->cr_uid == 0 && cr->cr_ruid != 0) {
10460Sstevel@tonic-gate 		cr = crdup(cr);
10470Sstevel@tonic-gate 		cr->cr_uid = cr->cr_ruid;
10480Sstevel@tonic-gate 		return (cr);
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 	return (NULL);
10510Sstevel@tonic-gate }
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate /*
10540Sstevel@tonic-gate  * The reference count is of interest when you want to check
10550Sstevel@tonic-gate  * whether it is ok to modify the credential in place.
10560Sstevel@tonic-gate  */
10570Sstevel@tonic-gate uint_t
crgetref(const cred_t * cr)10580Sstevel@tonic-gate crgetref(const cred_t *cr)
10590Sstevel@tonic-gate {
10600Sstevel@tonic-gate 	return (cr->cr_ref);
10610Sstevel@tonic-gate }
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate static int
get_c2audit_load(void)10640Sstevel@tonic-gate get_c2audit_load(void)
10650Sstevel@tonic-gate {
10660Sstevel@tonic-gate 	static int	gotit = 0;
10670Sstevel@tonic-gate 	static int	c2audit_load;
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	if (gotit)
10700Sstevel@tonic-gate 		return (c2audit_load);
107111861SMarek.Pospisil@Sun.COM 	c2audit_load = 1;		/* set default value once */
107211861SMarek.Pospisil@Sun.COM 	if (mod_sysctl(SYS_CHECK_EXCLUDE, "c2audit") != 0)
107311861SMarek.Pospisil@Sun.COM 		c2audit_load = 0;
10740Sstevel@tonic-gate 	gotit++;
107511861SMarek.Pospisil@Sun.COM 
10760Sstevel@tonic-gate 	return (c2audit_load);
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate int
get_audit_ucrsize(void)10800Sstevel@tonic-gate get_audit_ucrsize(void)
10810Sstevel@tonic-gate {
10820Sstevel@tonic-gate 	return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0);
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate /*
10860Sstevel@tonic-gate  * Set zone pointer in credential to indicated value.  First adds a
10870Sstevel@tonic-gate  * hold for the new zone, then drops the hold on previous zone (if any).
10880Sstevel@tonic-gate  * This is done in this order in case the old and new zones are the
10890Sstevel@tonic-gate  * same.
10900Sstevel@tonic-gate  */
10910Sstevel@tonic-gate void
crsetzone(cred_t * cr,zone_t * zptr)10920Sstevel@tonic-gate crsetzone(cred_t *cr, zone_t *zptr)
10930Sstevel@tonic-gate {
10940Sstevel@tonic-gate 	zone_t *oldzptr = cr->cr_zone;
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	ASSERT(cr != kcred);
10970Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
10980Sstevel@tonic-gate 	cr->cr_zone = zptr;
10990Sstevel@tonic-gate 	zone_cred_hold(zptr);
11000Sstevel@tonic-gate 	if (oldzptr)
11010Sstevel@tonic-gate 		zone_cred_rele(oldzptr);
11020Sstevel@tonic-gate }
11031676Sjpk 
11041676Sjpk /*
11051676Sjpk  * Create a new cred based on the supplied label
11061676Sjpk  */
11071676Sjpk cred_t *
newcred_from_bslabel(bslabel_t * blabel,uint32_t doi,int flags)11081676Sjpk newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags)
11091676Sjpk {
11101676Sjpk 	ts_label_t *lbl = labelalloc(blabel, doi, flags);
11111676Sjpk 	cred_t *cr = NULL;
11121676Sjpk 
11131676Sjpk 	if (lbl != NULL) {
11146134Scasper 		if ((cr = crdup_flags(dummycr, flags)) != NULL) {
11151676Sjpk 			cr->cr_label = lbl;
11161676Sjpk 		} else {
11171676Sjpk 			label_rele(lbl);
11181676Sjpk 		}
11191676Sjpk 	}
11201676Sjpk 
11211676Sjpk 	return (cr);
11221676Sjpk }
11231676Sjpk 
11241676Sjpk /*
11251676Sjpk  * Derive a new cred from the existing cred, but with a different label.
11261676Sjpk  * To be used when a cred is being shared, but the label needs to be changed
11271676Sjpk  * by a caller without affecting other users
11281676Sjpk  */
11291676Sjpk cred_t *
copycred_from_tslabel(const cred_t * cr,ts_label_t * label,int flags)11309710SKen.Powell@Sun.COM copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags)
11319710SKen.Powell@Sun.COM {
11329710SKen.Powell@Sun.COM 	cred_t *newcr = NULL;
11339710SKen.Powell@Sun.COM 
11349710SKen.Powell@Sun.COM 	if ((newcr = crdup_flags(cr, flags)) != NULL) {
11359710SKen.Powell@Sun.COM 		if (newcr->cr_label != NULL)
11369710SKen.Powell@Sun.COM 			label_rele(newcr->cr_label);
11379710SKen.Powell@Sun.COM 		label_hold(label);
11389710SKen.Powell@Sun.COM 		newcr->cr_label = label;
11399710SKen.Powell@Sun.COM 	}
11409710SKen.Powell@Sun.COM 
11419710SKen.Powell@Sun.COM 	return (newcr);
11429710SKen.Powell@Sun.COM }
11439710SKen.Powell@Sun.COM 
11449710SKen.Powell@Sun.COM /*
11459710SKen.Powell@Sun.COM  * Derive a new cred from the existing cred, but with a different label.
11469710SKen.Powell@Sun.COM  */
11479710SKen.Powell@Sun.COM cred_t *
copycred_from_bslabel(const cred_t * cr,bslabel_t * blabel,uint32_t doi,int flags)11489710SKen.Powell@Sun.COM copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel,
11499710SKen.Powell@Sun.COM     uint32_t doi, int flags)
11501676Sjpk {
11511676Sjpk 	ts_label_t *lbl = labelalloc(blabel, doi, flags);
11529710SKen.Powell@Sun.COM 	cred_t  *newcr = NULL;
11531676Sjpk 
11541676Sjpk 	if (lbl != NULL) {
11559710SKen.Powell@Sun.COM 		newcr = copycred_from_tslabel(cr, lbl, flags);
11569710SKen.Powell@Sun.COM 		label_rele(lbl);
11571676Sjpk 	}
11581676Sjpk 
11591676Sjpk 	return (newcr);
11601676Sjpk }
11611676Sjpk 
11621676Sjpk /*
11631676Sjpk  * This function returns a pointer to the kcred-equivalent in the current zone.
11641676Sjpk  */
11651676Sjpk cred_t *
zone_kcred(void)11661676Sjpk zone_kcred(void)
11671676Sjpk {
11681676Sjpk 	zone_t *zone;
11691676Sjpk 
11701676Sjpk 	if ((zone = CRED()->cr_zone) != NULL)
11711676Sjpk 		return (zone->zone_kcred);
11721676Sjpk 	else
11731676Sjpk 		return (kcred);
11741676Sjpk }
11754321Scasper 
11764321Scasper boolean_t
valid_ephemeral_uid(zone_t * zone,uid_t id)11775771Sjp151216 valid_ephemeral_uid(zone_t *zone, uid_t id)
11784321Scasper {
11795771Sjp151216 	ephemeral_zsd_t *eph_zsd;
11805908Sjp151216 	if (id <= IDMAP_WK__MAX_UID)
11815771Sjp151216 		return (B_TRUE);
11825771Sjp151216 
11835771Sjp151216 	eph_zsd = get_ephemeral_zsd(zone);
11845771Sjp151216 	ASSERT(eph_zsd != NULL);
11854321Scasper 	membar_consumer();
11865771Sjp151216 	return (id > eph_zsd->min_uid && id <= eph_zsd->last_uid);
11874321Scasper }
11884321Scasper 
11894321Scasper boolean_t
valid_ephemeral_gid(zone_t * zone,gid_t id)11905771Sjp151216 valid_ephemeral_gid(zone_t *zone, gid_t id)
11914321Scasper {
11925771Sjp151216 	ephemeral_zsd_t *eph_zsd;
11935908Sjp151216 	if (id <= IDMAP_WK__MAX_GID)
11945771Sjp151216 		return (B_TRUE);
11955771Sjp151216 
11965771Sjp151216 	eph_zsd = get_ephemeral_zsd(zone);
11975771Sjp151216 	ASSERT(eph_zsd != NULL);
11984321Scasper 	membar_consumer();
11995771Sjp151216 	return (id > eph_zsd->min_gid && id <= eph_zsd->last_gid);
12004321Scasper }
12014321Scasper 
12024321Scasper int
eph_uid_alloc(zone_t * zone,int flags,uid_t * start,int count)12035771Sjp151216 eph_uid_alloc(zone_t *zone, int flags, uid_t *start, int count)
12044321Scasper {
12055771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12065771Sjp151216 
12075771Sjp151216 	ASSERT(eph_zsd != NULL);
12085771Sjp151216 
12095771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12104321Scasper 
12114321Scasper 	/* Test for unsigned integer wrap around */
12125771Sjp151216 	if (eph_zsd->last_uid + count < eph_zsd->last_uid) {
12135771Sjp151216 		mutex_exit(&eph_zsd->eph_lock);
12144321Scasper 		return (-1);
12154321Scasper 	}
12164321Scasper 
12174321Scasper 	/* first call or idmap crashed and state corrupted */
12184321Scasper 	if (flags != 0)
12195771Sjp151216 		eph_zsd->min_uid = eph_zsd->last_uid;
12204321Scasper 
12214321Scasper 	hasephids = B_TRUE;
12225771Sjp151216 	*start = eph_zsd->last_uid + 1;
12235771Sjp151216 	atomic_add_32(&eph_zsd->last_uid, count);
12245771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12254321Scasper 	return (0);
12264321Scasper }
12274321Scasper 
12284321Scasper int
eph_gid_alloc(zone_t * zone,int flags,gid_t * start,int count)12295771Sjp151216 eph_gid_alloc(zone_t *zone, int flags, gid_t *start, int count)
12304321Scasper {
12315771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12325771Sjp151216 
12335771Sjp151216 	ASSERT(eph_zsd != NULL);
12345771Sjp151216 
12355771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12364321Scasper 
12374321Scasper 	/* Test for unsigned integer wrap around */
12385771Sjp151216 	if (eph_zsd->last_gid + count < eph_zsd->last_gid) {
12395771Sjp151216 		mutex_exit(&eph_zsd->eph_lock);
12404321Scasper 		return (-1);
12414321Scasper 	}
12424321Scasper 
12434321Scasper 	/* first call or idmap crashed and state corrupted */
12444321Scasper 	if (flags != 0)
12455771Sjp151216 		eph_zsd->min_gid = eph_zsd->last_gid;
12464321Scasper 
12474321Scasper 	hasephids = B_TRUE;
12485771Sjp151216 	*start = eph_zsd->last_gid + 1;
12495771Sjp151216 	atomic_add_32(&eph_zsd->last_gid, count);
12505771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12514321Scasper 	return (0);
12524321Scasper }
12534321Scasper 
12544321Scasper /*
12555771Sjp151216  * IMPORTANT.The two functions get_ephemeral_data() and set_ephemeral_data()
12565771Sjp151216  * are project private functions that are for use of the test system only and
12575771Sjp151216  * are not to be used for other purposes.
12585771Sjp151216  */
12595771Sjp151216 
12605771Sjp151216 void
get_ephemeral_data(zone_t * zone,uid_t * min_uid,uid_t * last_uid,gid_t * min_gid,gid_t * last_gid)12615771Sjp151216 get_ephemeral_data(zone_t *zone, uid_t *min_uid, uid_t *last_uid,
12625771Sjp151216 	gid_t *min_gid, gid_t *last_gid)
12635771Sjp151216 {
12645771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12655771Sjp151216 
12665771Sjp151216 	ASSERT(eph_zsd != NULL);
12675771Sjp151216 
12685771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12695771Sjp151216 
12705771Sjp151216 	*min_uid = eph_zsd->min_uid;
12715771Sjp151216 	*last_uid = eph_zsd->last_uid;
12725771Sjp151216 	*min_gid = eph_zsd->min_gid;
12735771Sjp151216 	*last_gid = eph_zsd->last_gid;
12745771Sjp151216 
12755771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12765771Sjp151216 }
12775771Sjp151216 
12785771Sjp151216 
12795771Sjp151216 void
set_ephemeral_data(zone_t * zone,uid_t min_uid,uid_t last_uid,gid_t min_gid,gid_t last_gid)12805771Sjp151216 set_ephemeral_data(zone_t *zone, uid_t min_uid, uid_t last_uid,
12815771Sjp151216 	gid_t min_gid, gid_t last_gid)
12825771Sjp151216 {
12835771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12845771Sjp151216 
12855771Sjp151216 	ASSERT(eph_zsd != NULL);
12865771Sjp151216 
12875771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12885771Sjp151216 
12895771Sjp151216 	if (min_uid != 0)
12905771Sjp151216 		eph_zsd->min_uid = min_uid;
12915771Sjp151216 	if (last_uid != 0)
12925771Sjp151216 		eph_zsd->last_uid = last_uid;
12935771Sjp151216 	if (min_gid != 0)
12945771Sjp151216 		eph_zsd->min_gid = min_gid;
12955771Sjp151216 	if (last_gid != 0)
12965771Sjp151216 		eph_zsd->last_gid = last_gid;
12975771Sjp151216 
12985771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12995771Sjp151216 }
13005771Sjp151216 
13015771Sjp151216 /*
13025331Samw  * If the credential user SID or group SID is mapped to an ephemeral
13035331Samw  * ID, map the credential to nobody.
13044321Scasper  */
13054321Scasper cred_t *
crgetmapped(const cred_t * cr)13064321Scasper crgetmapped(const cred_t *cr)
13074321Scasper {
13085771Sjp151216 	ephemeral_zsd_t *eph_zsd;
13094406Scasper 	/*
13104406Scasper 	 * Someone incorrectly passed a NULL cred to a vnode operation
13114406Scasper 	 * either on purpose or by calling CRED() in interrupt context.
13124406Scasper 	 */
13134406Scasper 	if (cr == NULL)
13144406Scasper 		return (NULL);
13154406Scasper 
13164321Scasper 	if (cr->cr_ksid != NULL) {
13175771Sjp151216 		if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID) {
13185771Sjp151216 			eph_zsd = get_ephemeral_zsd(crgetzone(cr));
13195771Sjp151216 			return (eph_zsd->eph_nobody);
13205771Sjp151216 		}
13214321Scasper 
13225771Sjp151216 		if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID) {
13235771Sjp151216 			eph_zsd = get_ephemeral_zsd(crgetzone(cr));
13245771Sjp151216 			return (eph_zsd->eph_nobody);
13255771Sjp151216 		}
13264321Scasper 	}
13274321Scasper 
13284321Scasper 	return ((cred_t *)cr);
13294321Scasper }
13304321Scasper 
13314321Scasper /* index should be in range for a ksidindex_t */
13324321Scasper void
crsetsid(cred_t * cr,ksid_t * ksp,int index)13334321Scasper crsetsid(cred_t *cr, ksid_t *ksp, int index)
13344321Scasper {
13354321Scasper 	ASSERT(cr->cr_ref <= 2);
13364321Scasper 	ASSERT(index >= 0 && index < KSID_COUNT);
13374321Scasper 	if (cr->cr_ksid == NULL && ksp == NULL)
13384321Scasper 		return;
13394321Scasper 	cr->cr_ksid = kcrsid_setsid(cr->cr_ksid, ksp, index);
13404321Scasper }
13414321Scasper 
13424321Scasper void
crsetsidlist(cred_t * cr,ksidlist_t * ksl)13434321Scasper crsetsidlist(cred_t *cr, ksidlist_t *ksl)
13444321Scasper {
13454321Scasper 	ASSERT(cr->cr_ref <= 2);
13464321Scasper 	if (cr->cr_ksid == NULL && ksl == NULL)
13474321Scasper 		return;
13484321Scasper 	cr->cr_ksid = kcrsid_setsidlist(cr->cr_ksid, ksl);
13494321Scasper }
13504321Scasper 
13514321Scasper ksid_t *
crgetsid(const cred_t * cr,int i)13524321Scasper crgetsid(const cred_t *cr, int i)
13534321Scasper {
13544321Scasper 	ASSERT(i >= 0 && i < KSID_COUNT);
13554321Scasper 	if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidx[i].ks_domain)
13564321Scasper 		return ((ksid_t *)&cr->cr_ksid->kr_sidx[i]);
13574321Scasper 	return (NULL);
13584321Scasper }
13594321Scasper 
13604321Scasper ksidlist_t *
crgetsidlist(const cred_t * cr)13614321Scasper crgetsidlist(const cred_t *cr)
13624321Scasper {
13635331Samw 	if (cr->cr_ksid != NULL)
13644923Scasper 		return (cr->cr_ksid->kr_sidlist);
13654321Scasper 	return (NULL);
13664321Scasper }
13675331Samw 
13685331Samw /*
13695331Samw  * Interface to set the effective and permitted privileges for
13705331Samw  * a credential; this interface does no security checks and is
13715331Samw  * intended for kernel (file)servers creating credentials with
13725331Samw  * specific privileges.
13735331Samw  */
13745331Samw int
crsetpriv(cred_t * cr,...)13755331Samw crsetpriv(cred_t *cr, ...)
13765331Samw {
13775331Samw 	va_list ap;
13785331Samw 	const char *privnm;
13795331Samw 
13805331Samw 	ASSERT(cr->cr_ref <= 2);
13815331Samw 
13825331Samw 	priv_set_PA(cr);
13835331Samw 
13845331Samw 	va_start(ap, cr);
13855331Samw 
13865331Samw 	while ((privnm = va_arg(ap, const char *)) != NULL) {
13875331Samw 		int priv = priv_getbyname(privnm, 0);
13885331Samw 		if (priv < 0)
13895331Samw 			return (-1);
13905331Samw 
13915331Samw 		priv_addset(&CR_PPRIV(cr), priv);
13925331Samw 		priv_addset(&CR_EPRIV(cr), priv);
13935331Samw 	}
13945331Samw 	priv_adjust_PA(cr);
13955331Samw 	va_end(ap);
13965331Samw 	return (0);
13975331Samw }
13986134Scasper 
13999151SThomas.Haynes@Sun.COM /*
14009151SThomas.Haynes@Sun.COM  * Interface to effectively set the PRIV_ALL for
14019151SThomas.Haynes@Sun.COM  * a credential; this interface does no security checks and is
14029151SThomas.Haynes@Sun.COM  * intended for kernel (file)servers to extend the user credentials
14039151SThomas.Haynes@Sun.COM  * to be ALL, like either kcred or zcred.
14049151SThomas.Haynes@Sun.COM  */
14059151SThomas.Haynes@Sun.COM void
crset_zone_privall(cred_t * cr)14069151SThomas.Haynes@Sun.COM crset_zone_privall(cred_t *cr)
14079151SThomas.Haynes@Sun.COM {
14089151SThomas.Haynes@Sun.COM 	zone_t	*zone = crgetzone(cr);
14099151SThomas.Haynes@Sun.COM 
14109151SThomas.Haynes@Sun.COM 	priv_fillset(&CR_LPRIV(cr));
14119151SThomas.Haynes@Sun.COM 	CR_EPRIV(cr) = CR_PPRIV(cr) = CR_IPRIV(cr) = CR_LPRIV(cr);
14129151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_LPRIV(cr));
14139151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_EPRIV(cr));
14149151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_IPRIV(cr));
14159151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_PPRIV(cr));
14169151SThomas.Haynes@Sun.COM }
14179151SThomas.Haynes@Sun.COM 
14186134Scasper struct credklpd *
crgetcrklpd(const cred_t * cr)14196134Scasper crgetcrklpd(const cred_t *cr)
14206134Scasper {
14216134Scasper 	return (cr->cr_klpd);
14226134Scasper }
14236134Scasper 
14246134Scasper void
crsetcrklpd(cred_t * cr,struct credklpd * crklpd)14256134Scasper crsetcrklpd(cred_t *cr, struct credklpd *crklpd)
14266134Scasper {
14276134Scasper 	ASSERT(cr->cr_ref <= 2);
14286134Scasper 
14296134Scasper 	if (cr->cr_klpd != NULL)
14306134Scasper 		crklpd_rele(cr->cr_klpd);
14316134Scasper 	cr->cr_klpd = crklpd;
14326134Scasper }
143311134SCasper.Dik@Sun.COM 
143411134SCasper.Dik@Sun.COM credgrp_t *
crgrpcopyin(int n,gid_t * gidset)143511134SCasper.Dik@Sun.COM crgrpcopyin(int n, gid_t *gidset)
143611134SCasper.Dik@Sun.COM {
143711134SCasper.Dik@Sun.COM 	credgrp_t *mem;
143811134SCasper.Dik@Sun.COM 	size_t sz = CREDGRPSZ(n);
143911134SCasper.Dik@Sun.COM 
144011134SCasper.Dik@Sun.COM 	ASSERT(n > 0);
144111134SCasper.Dik@Sun.COM 
144211134SCasper.Dik@Sun.COM 	mem = kmem_alloc(sz, KM_SLEEP);
144311134SCasper.Dik@Sun.COM 
144411134SCasper.Dik@Sun.COM 	if (copyin(gidset, mem->crg_groups, sizeof (gid_t) * n)) {
144511134SCasper.Dik@Sun.COM 		kmem_free(mem, sz);
144611134SCasper.Dik@Sun.COM 		return (NULL);
144711134SCasper.Dik@Sun.COM 	}
144811134SCasper.Dik@Sun.COM 	mem->crg_ref = 1;
144911134SCasper.Dik@Sun.COM 	mem->crg_ngroups = n;
145011134SCasper.Dik@Sun.COM 	return (mem);
145111134SCasper.Dik@Sun.COM }
145211134SCasper.Dik@Sun.COM 
145311134SCasper.Dik@Sun.COM const gid_t *
crgetggroups(const credgrp_t * grps)145411134SCasper.Dik@Sun.COM crgetggroups(const credgrp_t *grps)
145511134SCasper.Dik@Sun.COM {
145611134SCasper.Dik@Sun.COM 	return (grps->crg_groups);
145711134SCasper.Dik@Sun.COM }
145811134SCasper.Dik@Sun.COM 
145911134SCasper.Dik@Sun.COM void
crsetcredgrp(cred_t * cr,credgrp_t * grps)146011134SCasper.Dik@Sun.COM crsetcredgrp(cred_t *cr, credgrp_t *grps)
146111134SCasper.Dik@Sun.COM {
146211134SCasper.Dik@Sun.COM 	ASSERT(cr->cr_ref <= 2);
146311134SCasper.Dik@Sun.COM 
146411134SCasper.Dik@Sun.COM 	if (cr->cr_grps != NULL)
146511134SCasper.Dik@Sun.COM 		crgrprele(cr->cr_grps);
146611134SCasper.Dik@Sun.COM 
146711134SCasper.Dik@Sun.COM 	cr->cr_grps = grps;
146811134SCasper.Dik@Sun.COM }
146911134SCasper.Dik@Sun.COM 
147011134SCasper.Dik@Sun.COM void
crgrprele(credgrp_t * grps)147111134SCasper.Dik@Sun.COM crgrprele(credgrp_t *grps)
147211134SCasper.Dik@Sun.COM {
147311134SCasper.Dik@Sun.COM 	if (atomic_add_32_nv(&grps->crg_ref, -1) == 0)
147411134SCasper.Dik@Sun.COM 		kmem_free(grps, CREDGRPSZ(grps->crg_ngroups));
147511134SCasper.Dik@Sun.COM }
147611134SCasper.Dik@Sun.COM 
147711134SCasper.Dik@Sun.COM static void
crgrphold(credgrp_t * grps)147811134SCasper.Dik@Sun.COM crgrphold(credgrp_t *grps)
147911134SCasper.Dik@Sun.COM {
148011134SCasper.Dik@Sun.COM 	atomic_add_32(&grps->crg_ref, 1);
148111134SCasper.Dik@Sun.COM }
1482