xref: /onnv-gate/usr/src/uts/common/os/cred.c (revision 11134:8aa0c4ca6639)
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 /*
229151SThomas.Haynes@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
270Sstevel@tonic-gate /*	  All Rights Reserved  	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
310Sstevel@tonic-gate  * The Regents of the University of California
320Sstevel@tonic-gate  * All Rights Reserved
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
350Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
360Sstevel@tonic-gate  * contributors.
370Sstevel@tonic-gate  */
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include <sys/types.h>
400Sstevel@tonic-gate #include <sys/sysmacros.h>
410Sstevel@tonic-gate #include <sys/param.h>
420Sstevel@tonic-gate #include <sys/systm.h>
430Sstevel@tonic-gate #include <sys/cred_impl.h>
440Sstevel@tonic-gate #include <sys/policy.h>
450Sstevel@tonic-gate #include <sys/vnode.h>
460Sstevel@tonic-gate #include <sys/errno.h>
470Sstevel@tonic-gate #include <sys/kmem.h>
480Sstevel@tonic-gate #include <sys/user.h>
490Sstevel@tonic-gate #include <sys/proc.h>
500Sstevel@tonic-gate #include <sys/syscall.h>
510Sstevel@tonic-gate #include <sys/debug.h>
520Sstevel@tonic-gate #include <sys/atomic.h>
530Sstevel@tonic-gate #include <sys/ucred.h>
540Sstevel@tonic-gate #include <sys/prsystm.h>
550Sstevel@tonic-gate #include <sys/modctl.h>
564321Scasper #include <sys/avl.h>
575331Samw #include <sys/door.h>
580Sstevel@tonic-gate #include <c2/audit.h>
590Sstevel@tonic-gate #include <sys/zone.h>
601676Sjpk #include <sys/tsol/label.h>
614321Scasper #include <sys/sid.h>
624520Snw141292 #include <sys/idmap.h>
636134Scasper #include <sys/klpd.h>
645331Samw #include <sys/varargs.h>
65*11134SCasper.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 
78*11134SCasper.Dik@Sun.COM /* Supplemental groups list. */
79*11134SCasper.Dik@Sun.COM typedef struct credgrp {
80*11134SCasper.Dik@Sun.COM 	uint_t		crg_ref;
81*11134SCasper.Dik@Sun.COM 	uint_t		crg_ngroups;
82*11134SCasper.Dik@Sun.COM 	gid_t		crg_groups[1];
83*11134SCasper.Dik@Sun.COM } credgrp_t;
84*11134SCasper.Dik@Sun.COM 
85*11134SCasper.Dik@Sun.COM static void crgrphold(credgrp_t *);
86*11134SCasper.Dik@Sun.COM 
87*11134SCasper.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 
108*11134SCasper.Dik@Sun.COM #define	BIN_GROUP_SEARCH_CUTOFF	16
1094321Scasper 
1104321Scasper static boolean_t hasephids = B_FALSE;
1114321Scasper 
1125771Sjp151216 static ephemeral_zsd_t *
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 */
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
1710Sstevel@tonic-gate cred_init(void)
1720Sstevel@tonic-gate {
1730Sstevel@tonic-gate 	priv_init();
1740Sstevel@tonic-gate 
175*11134SCasper.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 *
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;
262*11134SCasper.Dik@Sun.COM 	cr->cr_grps = NULL;
2634321Scasper 	return (cr);
2644321Scasper }
2654321Scasper 
2666134Scasper cred_t *
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 *
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 *
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);
299*11134SCasper.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
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
3480Sstevel@tonic-gate crhold(cred_t *cr)
3490Sstevel@tonic-gate {
3500Sstevel@tonic-gate 	atomic_add_32(&cr->cr_ref, 1);
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate /*
3540Sstevel@tonic-gate  * Release previous hold on a cred structure.  Free it if refcnt == 0.
3551676Sjpk  * If cred uses label different from zone label, free it.
3560Sstevel@tonic-gate  */
3570Sstevel@tonic-gate void
3580Sstevel@tonic-gate crfree(cred_t *cr)
3590Sstevel@tonic-gate {
3600Sstevel@tonic-gate 	if (atomic_add_32_nv(&cr->cr_ref, -1) == 0) {
3610Sstevel@tonic-gate 		ASSERT(cr != kcred);
3621676Sjpk 		if (cr->cr_label)
3631676Sjpk 			label_rele(cr->cr_label);
3646134Scasper 		if (cr->cr_klpd)
3656134Scasper 			crklpd_rele(cr->cr_klpd);
3660Sstevel@tonic-gate 		if (cr->cr_zone)
3670Sstevel@tonic-gate 			zone_cred_rele(cr->cr_zone);
3684321Scasper 		if (cr->cr_ksid)
3694321Scasper 			kcrsid_rele(cr->cr_ksid);
370*11134SCasper.Dik@Sun.COM 		if (cr->cr_grps)
371*11134SCasper.Dik@Sun.COM 			crgrprele(cr->cr_grps);
372*11134SCasper.Dik@Sun.COM 
3730Sstevel@tonic-gate 		kmem_cache_free(cred_cache, cr);
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate /*
3780Sstevel@tonic-gate  * Copy a cred structure to a new one and free the old one.
3790Sstevel@tonic-gate  *	The new cred will have two references.  One for the calling process,
3800Sstevel@tonic-gate  * 	and one for the thread.
3810Sstevel@tonic-gate  */
3820Sstevel@tonic-gate cred_t *
3830Sstevel@tonic-gate crcopy(cred_t *cr)
3840Sstevel@tonic-gate {
3850Sstevel@tonic-gate 	cred_t *newcr;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	newcr = cralloc();
3880Sstevel@tonic-gate 	bcopy(cr, newcr, crsize);
3890Sstevel@tonic-gate 	if (newcr->cr_zone)
3900Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
3911676Sjpk 	if (newcr->cr_label)
3926134Scasper 		label_hold(newcr->cr_label);
3934321Scasper 	if (newcr->cr_ksid)
3946134Scasper 		kcrsid_hold(newcr->cr_ksid);
3956134Scasper 	if (newcr->cr_klpd)
3966134Scasper 		crklpd_hold(newcr->cr_klpd);
397*11134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
398*11134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
3990Sstevel@tonic-gate 	crfree(cr);
4000Sstevel@tonic-gate 	newcr->cr_ref = 2;		/* caller gets two references */
4010Sstevel@tonic-gate 	return (newcr);
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate /*
4050Sstevel@tonic-gate  * Copy a cred structure to a new one and free the old one.
4060Sstevel@tonic-gate  *	The new cred will have two references.  One for the calling process,
4070Sstevel@tonic-gate  * 	and one for the thread.
4080Sstevel@tonic-gate  * This variation on crcopy uses a pre-allocated structure for the
4090Sstevel@tonic-gate  * "new" cred.
4100Sstevel@tonic-gate  */
4110Sstevel@tonic-gate void
4120Sstevel@tonic-gate crcopy_to(cred_t *oldcr, cred_t *newcr)
4130Sstevel@tonic-gate {
4144321Scasper 	credsid_t *nkcr = newcr->cr_ksid;
4154321Scasper 
4160Sstevel@tonic-gate 	bcopy(oldcr, newcr, crsize);
4170Sstevel@tonic-gate 	if (newcr->cr_zone)
4180Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
4191676Sjpk 	if (newcr->cr_label)
4201676Sjpk 		label_hold(newcr->cr_label);
4216134Scasper 	if (newcr->cr_klpd)
4226134Scasper 		crklpd_hold(newcr->cr_klpd);
423*11134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
424*11134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
4254321Scasper 	if (nkcr) {
4264321Scasper 		newcr->cr_ksid = nkcr;
4274321Scasper 		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
4284321Scasper 	} else if (newcr->cr_ksid)
4294321Scasper 		kcrsid_hold(newcr->cr_ksid);
4300Sstevel@tonic-gate 	crfree(oldcr);
4310Sstevel@tonic-gate 	newcr->cr_ref = 2;		/* caller gets two references */
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate /*
4350Sstevel@tonic-gate  * Dup a cred struct to a new held one.
4360Sstevel@tonic-gate  *	The old cred is not freed.
4370Sstevel@tonic-gate  */
4386134Scasper static cred_t *
4399710SKen.Powell@Sun.COM crdup_flags(const cred_t *cr, int flgs)
4400Sstevel@tonic-gate {
4410Sstevel@tonic-gate 	cred_t *newcr;
4420Sstevel@tonic-gate 
4436134Scasper 	newcr = cralloc_flags(flgs);
4446134Scasper 
4456134Scasper 	if (newcr == NULL)
4466134Scasper 		return (NULL);
4476134Scasper 
4480Sstevel@tonic-gate 	bcopy(cr, newcr, crsize);
4490Sstevel@tonic-gate 	if (newcr->cr_zone)
4500Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
4511676Sjpk 	if (newcr->cr_label)
4521676Sjpk 		label_hold(newcr->cr_label);
4536134Scasper 	if (newcr->cr_klpd)
4546134Scasper 		crklpd_hold(newcr->cr_klpd);
4554321Scasper 	if (newcr->cr_ksid)
4564321Scasper 		kcrsid_hold(newcr->cr_ksid);
457*11134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
458*11134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
4590Sstevel@tonic-gate 	newcr->cr_ref = 1;
4600Sstevel@tonic-gate 	return (newcr);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate 
4636134Scasper cred_t *
4646134Scasper crdup(cred_t *cr)
4656134Scasper {
4666134Scasper 	return (crdup_flags(cr, KM_SLEEP));
4676134Scasper }
4686134Scasper 
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate  * Dup a cred struct to a new held one.
4710Sstevel@tonic-gate  *	The old cred is not freed.
4720Sstevel@tonic-gate  * This variation on crdup uses a pre-allocated structure for the
4730Sstevel@tonic-gate  * "new" cred.
4740Sstevel@tonic-gate  */
4750Sstevel@tonic-gate void
4760Sstevel@tonic-gate crdup_to(cred_t *oldcr, cred_t *newcr)
4770Sstevel@tonic-gate {
4784321Scasper 	credsid_t *nkcr = newcr->cr_ksid;
4794321Scasper 
4800Sstevel@tonic-gate 	bcopy(oldcr, newcr, crsize);
4810Sstevel@tonic-gate 	if (newcr->cr_zone)
4820Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
4831676Sjpk 	if (newcr->cr_label)
4841676Sjpk 		label_hold(newcr->cr_label);
4856134Scasper 	if (newcr->cr_klpd)
4866134Scasper 		crklpd_hold(newcr->cr_klpd);
487*11134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
488*11134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
4894321Scasper 	if (nkcr) {
4904321Scasper 		newcr->cr_ksid = nkcr;
4914321Scasper 		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
4924321Scasper 	} else if (newcr->cr_ksid)
4934321Scasper 		kcrsid_hold(newcr->cr_ksid);
4940Sstevel@tonic-gate 	newcr->cr_ref = 1;
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate /*
4980Sstevel@tonic-gate  * Return the (held) credentials for the current running process.
4990Sstevel@tonic-gate  */
5000Sstevel@tonic-gate cred_t *
5011676Sjpk crgetcred(void)
5020Sstevel@tonic-gate {
5030Sstevel@tonic-gate 	cred_t *cr;
5040Sstevel@tonic-gate 	proc_t *p;
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	p = ttoproc(curthread);
5070Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
5080Sstevel@tonic-gate 	crhold(cr = p->p_cred);
5090Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
5100Sstevel@tonic-gate 	return (cr);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate /*
5140Sstevel@tonic-gate  * Backward compatibility check for suser().
5150Sstevel@tonic-gate  * Accounting flag is now set in the policy functions; auditing is
5160Sstevel@tonic-gate  * done through use of privilege in the audit trail.
5170Sstevel@tonic-gate  */
5180Sstevel@tonic-gate int
5190Sstevel@tonic-gate suser(cred_t *cr)
5200Sstevel@tonic-gate {
5210Sstevel@tonic-gate 	return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL)
5220Sstevel@tonic-gate 	    == 0);
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate /*
5260Sstevel@tonic-gate  * Determine whether the supplied group id is a member of the group
5270Sstevel@tonic-gate  * described by the supplied credentials.
5280Sstevel@tonic-gate  */
5290Sstevel@tonic-gate int
5300Sstevel@tonic-gate groupmember(gid_t gid, const cred_t *cr)
5310Sstevel@tonic-gate {
5320Sstevel@tonic-gate 	if (gid == cr->cr_gid)
5330Sstevel@tonic-gate 		return (1);
5340Sstevel@tonic-gate 	return (supgroupmember(gid, cr));
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate /*
5380Sstevel@tonic-gate  * As groupmember but only check against the supplemental groups.
5390Sstevel@tonic-gate  */
5400Sstevel@tonic-gate int
5410Sstevel@tonic-gate supgroupmember(gid_t gid, const cred_t *cr)
5420Sstevel@tonic-gate {
543*11134SCasper.Dik@Sun.COM 	int hi, lo;
544*11134SCasper.Dik@Sun.COM 	credgrp_t *grps = cr->cr_grps;
5450Sstevel@tonic-gate 	const gid_t *gp, *endgp;
5460Sstevel@tonic-gate 
547*11134SCasper.Dik@Sun.COM 	if (grps == NULL)
548*11134SCasper.Dik@Sun.COM 		return (0);
549*11134SCasper.Dik@Sun.COM 
550*11134SCasper.Dik@Sun.COM 	/* For a small number of groups, use sequentials search. */
551*11134SCasper.Dik@Sun.COM 	if (grps->crg_ngroups <= BIN_GROUP_SEARCH_CUTOFF) {
552*11134SCasper.Dik@Sun.COM 		endgp = &grps->crg_groups[grps->crg_ngroups];
553*11134SCasper.Dik@Sun.COM 		for (gp = grps->crg_groups; gp < endgp; gp++)
554*11134SCasper.Dik@Sun.COM 			if (*gp == gid)
555*11134SCasper.Dik@Sun.COM 				return (1);
556*11134SCasper.Dik@Sun.COM 		return (0);
557*11134SCasper.Dik@Sun.COM 	}
558*11134SCasper.Dik@Sun.COM 
559*11134SCasper.Dik@Sun.COM 	/* We use binary search when we have many groups. */
560*11134SCasper.Dik@Sun.COM 	lo = 0;
561*11134SCasper.Dik@Sun.COM 	hi = grps->crg_ngroups - 1;
562*11134SCasper.Dik@Sun.COM 	gp = grps->crg_groups;
563*11134SCasper.Dik@Sun.COM 
564*11134SCasper.Dik@Sun.COM 	do {
565*11134SCasper.Dik@Sun.COM 		int m = (lo + hi) / 2;
566*11134SCasper.Dik@Sun.COM 
567*11134SCasper.Dik@Sun.COM 		if (gid > gp[m])
568*11134SCasper.Dik@Sun.COM 			lo = m + 1;
569*11134SCasper.Dik@Sun.COM 		else if (gid < gp[m])
570*11134SCasper.Dik@Sun.COM 			hi = m - 1;
571*11134SCasper.Dik@Sun.COM 		else
5720Sstevel@tonic-gate 			return (1);
573*11134SCasper.Dik@Sun.COM 	} while (lo <= hi);
574*11134SCasper.Dik@Sun.COM 
5750Sstevel@tonic-gate 	return (0);
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate /*
5790Sstevel@tonic-gate  * This function is called to check whether the credentials set
5800Sstevel@tonic-gate  * "scrp" has permission to act on credentials set "tcrp".  It enforces the
5810Sstevel@tonic-gate  * permission requirements needed to send a signal to a process.
5820Sstevel@tonic-gate  * The same requirements are imposed by other system calls, however.
5830Sstevel@tonic-gate  *
5840Sstevel@tonic-gate  * The rules are:
5850Sstevel@tonic-gate  * (1) if the credentials are the same, the check succeeds
5860Sstevel@tonic-gate  * (2) if the zone ids don't match, and scrp is not in the global zone or
5870Sstevel@tonic-gate  *     does not have the PRIV_PROC_ZONE privilege, the check fails
5880Sstevel@tonic-gate  * (3) if the real or effective user id of scrp matches the real or saved
5890Sstevel@tonic-gate  *     user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check
5900Sstevel@tonic-gate  *     succeeds
5910Sstevel@tonic-gate  * (4) otherwise, the check fails
5920Sstevel@tonic-gate  */
5930Sstevel@tonic-gate int
5940Sstevel@tonic-gate hasprocperm(const cred_t *tcrp, const cred_t *scrp)
5950Sstevel@tonic-gate {
5960Sstevel@tonic-gate 	if (scrp == tcrp)
5970Sstevel@tonic-gate 		return (1);
5980Sstevel@tonic-gate 	if (scrp->cr_zone != tcrp->cr_zone &&
5990Sstevel@tonic-gate 	    (scrp->cr_zone != global_zone ||
6000Sstevel@tonic-gate 	    secpolicy_proc_zone(scrp) != 0))
6010Sstevel@tonic-gate 		return (0);
6020Sstevel@tonic-gate 	if (scrp->cr_uid == tcrp->cr_ruid ||
6030Sstevel@tonic-gate 	    scrp->cr_ruid == tcrp->cr_ruid ||
6040Sstevel@tonic-gate 	    scrp->cr_uid  == tcrp->cr_suid ||
6050Sstevel@tonic-gate 	    scrp->cr_ruid == tcrp->cr_suid ||
6060Sstevel@tonic-gate 	    !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm"))
6070Sstevel@tonic-gate 		return (1);
6080Sstevel@tonic-gate 	return (0);
6090Sstevel@tonic-gate }
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate /*
6120Sstevel@tonic-gate  * This interface replaces hasprocperm; it works like hasprocperm but
6130Sstevel@tonic-gate  * additionally returns success if the proc_t's match
6140Sstevel@tonic-gate  * It is the preferred interface for most uses.
6156134Scasper  * And it will acquire p_crlock itself, so it assert's that it shouldn't
6160Sstevel@tonic-gate  * be held.
6170Sstevel@tonic-gate  */
6180Sstevel@tonic-gate int
6190Sstevel@tonic-gate prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp)
6200Sstevel@tonic-gate {
6210Sstevel@tonic-gate 	int rets;
6220Sstevel@tonic-gate 	cred_t *tcrp;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&tp->p_crlock));
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	if (tp == sp)
6270Sstevel@tonic-gate 		return (1);
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0)
6300Sstevel@tonic-gate 		return (0);
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	mutex_enter(&tp->p_crlock);
6336134Scasper 	crhold(tcrp = tp->p_cred);
6346134Scasper 	mutex_exit(&tp->p_crlock);
6350Sstevel@tonic-gate 	rets = hasprocperm(tcrp, scrp);
6366134Scasper 	crfree(tcrp);
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	return (rets);
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate /*
6420Sstevel@tonic-gate  * This routine is used to compare two credentials to determine if
6430Sstevel@tonic-gate  * they refer to the same "user".  If the pointers are equal, then
6440Sstevel@tonic-gate  * they must refer to the same user.  Otherwise, the contents of
6450Sstevel@tonic-gate  * the credentials are compared to see whether they are equivalent.
6460Sstevel@tonic-gate  *
6470Sstevel@tonic-gate  * This routine returns 0 if the credentials refer to the same user,
6480Sstevel@tonic-gate  * 1 if they do not.
6490Sstevel@tonic-gate  */
6500Sstevel@tonic-gate int
6510Sstevel@tonic-gate crcmp(const cred_t *cr1, const cred_t *cr2)
6520Sstevel@tonic-gate {
653*11134SCasper.Dik@Sun.COM 	credgrp_t *grp1, *grp2;
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	if (cr1 == cr2)
6560Sstevel@tonic-gate 		return (0);
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	if (cr1->cr_uid == cr2->cr_uid &&
6590Sstevel@tonic-gate 	    cr1->cr_gid == cr2->cr_gid &&
6600Sstevel@tonic-gate 	    cr1->cr_ruid == cr2->cr_ruid &&
6610Sstevel@tonic-gate 	    cr1->cr_rgid == cr2->cr_rgid &&
6620Sstevel@tonic-gate 	    cr1->cr_zone == cr2->cr_zone &&
663*11134SCasper.Dik@Sun.COM 	    ((grp1 = cr1->cr_grps) == (grp2 = cr2->cr_grps) ||
664*11134SCasper.Dik@Sun.COM 	    (grp1 != NULL && grp2 != NULL &&
665*11134SCasper.Dik@Sun.COM 	    grp1->crg_ngroups == grp2->crg_ngroups &&
666*11134SCasper.Dik@Sun.COM 	    bcmp(grp1->crg_groups, grp2->crg_groups,
667*11134SCasper.Dik@Sun.COM 	    grp1->crg_ngroups * sizeof (gid_t)) == 0))) {
6680Sstevel@tonic-gate 		return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2)));
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 	return (1);
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate /*
6740Sstevel@tonic-gate  * Read access functions to cred_t.
6750Sstevel@tonic-gate  */
6760Sstevel@tonic-gate uid_t
6770Sstevel@tonic-gate crgetuid(const cred_t *cr)
6780Sstevel@tonic-gate {
6790Sstevel@tonic-gate 	return (cr->cr_uid);
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate uid_t
6830Sstevel@tonic-gate crgetruid(const cred_t *cr)
6840Sstevel@tonic-gate {
6850Sstevel@tonic-gate 	return (cr->cr_ruid);
6860Sstevel@tonic-gate }
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate uid_t
6890Sstevel@tonic-gate crgetsuid(const cred_t *cr)
6900Sstevel@tonic-gate {
6910Sstevel@tonic-gate 	return (cr->cr_suid);
6920Sstevel@tonic-gate }
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate gid_t
6950Sstevel@tonic-gate crgetgid(const cred_t *cr)
6960Sstevel@tonic-gate {
6970Sstevel@tonic-gate 	return (cr->cr_gid);
6980Sstevel@tonic-gate }
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate gid_t
7010Sstevel@tonic-gate crgetrgid(const cred_t *cr)
7020Sstevel@tonic-gate {
7030Sstevel@tonic-gate 	return (cr->cr_rgid);
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate gid_t
7070Sstevel@tonic-gate crgetsgid(const cred_t *cr)
7080Sstevel@tonic-gate {
7090Sstevel@tonic-gate 	return (cr->cr_sgid);
7100Sstevel@tonic-gate }
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate const auditinfo_addr_t *
7130Sstevel@tonic-gate crgetauinfo(const cred_t *cr)
7140Sstevel@tonic-gate {
7150Sstevel@tonic-gate 	return ((const auditinfo_addr_t *)CR_AUINFO(cr));
7160Sstevel@tonic-gate }
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate auditinfo_addr_t *
7190Sstevel@tonic-gate crgetauinfo_modifiable(cred_t *cr)
7200Sstevel@tonic-gate {
7210Sstevel@tonic-gate 	return (CR_AUINFO(cr));
7220Sstevel@tonic-gate }
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate zoneid_t
7250Sstevel@tonic-gate crgetzoneid(const cred_t *cr)
7260Sstevel@tonic-gate {
7271676Sjpk 	return (cr->cr_zone == NULL ?
7281676Sjpk 	    (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) :
7291676Sjpk 	    cr->cr_zone->zone_id);
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate projid_t
7330Sstevel@tonic-gate crgetprojid(const cred_t *cr)
7340Sstevel@tonic-gate {
7350Sstevel@tonic-gate 	return (cr->cr_projid);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate 
7381676Sjpk zone_t *
7391676Sjpk crgetzone(const cred_t *cr)
7401676Sjpk {
7411676Sjpk 	return (cr->cr_zone);
7421676Sjpk }
7431676Sjpk 
7441676Sjpk struct ts_label_s *
7451676Sjpk crgetlabel(const cred_t *cr)
7461676Sjpk {
7471676Sjpk 	return (cr->cr_label ?
7481676Sjpk 	    cr->cr_label :
7491676Sjpk 	    (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL));
7501676Sjpk }
7511676Sjpk 
7521676Sjpk boolean_t
7531676Sjpk crisremote(const cred_t *cr)
7541676Sjpk {
7551676Sjpk 	return (REMOTE_PEER_CRED(cr));
7561676Sjpk }
7571676Sjpk 
7585771Sjp151216 #define	BADUID(x, zn)	((x) != -1 && !VALID_UID((x), (zn)))
7595771Sjp151216 #define	BADGID(x, zn)	((x) != -1 && !VALID_GID((x), (zn)))
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate int
7620Sstevel@tonic-gate crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s)
7630Sstevel@tonic-gate {
7645771Sjp151216 	zone_t	*zone = crgetzone(cr);
7655771Sjp151216 
7660Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
7670Sstevel@tonic-gate 
7685771Sjp151216 	if (BADUID(r, zone) || BADUID(e, zone) || BADUID(s, zone))
7690Sstevel@tonic-gate 		return (-1);
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	if (r != -1)
7720Sstevel@tonic-gate 		cr->cr_ruid = r;
7730Sstevel@tonic-gate 	if (e != -1)
7740Sstevel@tonic-gate 		cr->cr_uid = e;
7750Sstevel@tonic-gate 	if (s != -1)
7760Sstevel@tonic-gate 		cr->cr_suid = s;
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	return (0);
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate int
7820Sstevel@tonic-gate crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s)
7830Sstevel@tonic-gate {
7845771Sjp151216 	zone_t	*zone = crgetzone(cr);
7855771Sjp151216 
7860Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
7870Sstevel@tonic-gate 
7885771Sjp151216 	if (BADGID(r, zone) || BADGID(e, zone) || BADGID(s, zone))
7890Sstevel@tonic-gate 		return (-1);
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	if (r != -1)
7920Sstevel@tonic-gate 		cr->cr_rgid = r;
7930Sstevel@tonic-gate 	if (e != -1)
7940Sstevel@tonic-gate 		cr->cr_gid = e;
7950Sstevel@tonic-gate 	if (s != -1)
7960Sstevel@tonic-gate 		cr->cr_sgid = s;
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	return (0);
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate int
8020Sstevel@tonic-gate crsetugid(cred_t *cr, uid_t uid, gid_t gid)
8030Sstevel@tonic-gate {
8045771Sjp151216 	zone_t	*zone = crgetzone(cr);
8055771Sjp151216 
8060Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
8070Sstevel@tonic-gate 
8085771Sjp151216 	if (!VALID_UID(uid, zone) || !VALID_GID(gid, zone))
8090Sstevel@tonic-gate 		return (-1);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid;
8120Sstevel@tonic-gate 	cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid;
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	return (0);
8150Sstevel@tonic-gate }
8160Sstevel@tonic-gate 
817*11134SCasper.Dik@Sun.COM static int
818*11134SCasper.Dik@Sun.COM gidcmp(const void *v1, const void *v2)
819*11134SCasper.Dik@Sun.COM {
820*11134SCasper.Dik@Sun.COM 	gid_t g1 = *(gid_t *)v1;
821*11134SCasper.Dik@Sun.COM 	gid_t g2 = *(gid_t *)v2;
822*11134SCasper.Dik@Sun.COM 
823*11134SCasper.Dik@Sun.COM 	if (g1 < g2)
824*11134SCasper.Dik@Sun.COM 		return (-1);
825*11134SCasper.Dik@Sun.COM 	else if (g1 > g2)
826*11134SCasper.Dik@Sun.COM 		return (1);
827*11134SCasper.Dik@Sun.COM 	else
828*11134SCasper.Dik@Sun.COM 		return (0);
829*11134SCasper.Dik@Sun.COM }
830*11134SCasper.Dik@Sun.COM 
8310Sstevel@tonic-gate int
8320Sstevel@tonic-gate crsetgroups(cred_t *cr, int n, gid_t *grp)
8330Sstevel@tonic-gate {
8340Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	if (n > ngroups_max || n < 0)
8370Sstevel@tonic-gate 		return (-1);
8380Sstevel@tonic-gate 
839*11134SCasper.Dik@Sun.COM 	if (cr->cr_grps != NULL)
840*11134SCasper.Dik@Sun.COM 		crgrprele(cr->cr_grps);
8410Sstevel@tonic-gate 
842*11134SCasper.Dik@Sun.COM 	if (n > 0) {
843*11134SCasper.Dik@Sun.COM 		cr->cr_grps = kmem_alloc(CREDGRPSZ(n), KM_SLEEP);
844*11134SCasper.Dik@Sun.COM 		bcopy(grp, cr->cr_grps->crg_groups, n * sizeof (gid_t));
845*11134SCasper.Dik@Sun.COM 		cr->cr_grps->crg_ref = 1;
846*11134SCasper.Dik@Sun.COM 		cr->cr_grps->crg_ngroups = n;
847*11134SCasper.Dik@Sun.COM 		qsort(cr->cr_grps->crg_groups, n, sizeof (gid_t), gidcmp);
848*11134SCasper.Dik@Sun.COM 	} else {
849*11134SCasper.Dik@Sun.COM 		cr->cr_grps = NULL;
850*11134SCasper.Dik@Sun.COM 	}
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	return (0);
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate void
8560Sstevel@tonic-gate crsetprojid(cred_t *cr, projid_t projid)
8570Sstevel@tonic-gate {
8580Sstevel@tonic-gate 	ASSERT(projid >= 0 && projid <= MAXPROJID);
8590Sstevel@tonic-gate 	cr->cr_projid = projid;
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate /*
863*11134SCasper.Dik@Sun.COM  * This routine returns the pointer to the first element of the crg_groups
8640Sstevel@tonic-gate  * array.  It can move around in an implementation defined way.
865*11134SCasper.Dik@Sun.COM  * Note that when we have no grouplist, we return one element but the
866*11134SCasper.Dik@Sun.COM  * caller should never reference it.
8670Sstevel@tonic-gate  */
8680Sstevel@tonic-gate const gid_t *
8690Sstevel@tonic-gate crgetgroups(const cred_t *cr)
8700Sstevel@tonic-gate {
871*11134SCasper.Dik@Sun.COM 	return (cr->cr_grps == NULL ? &cr->cr_gid : cr->cr_grps->crg_groups);
8720Sstevel@tonic-gate }
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate int
8750Sstevel@tonic-gate crgetngroups(const cred_t *cr)
8760Sstevel@tonic-gate {
877*11134SCasper.Dik@Sun.COM 	return (cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups);
8780Sstevel@tonic-gate }
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate void
8810Sstevel@tonic-gate cred2prcred(const cred_t *cr, prcred_t *pcrp)
8820Sstevel@tonic-gate {
8830Sstevel@tonic-gate 	pcrp->pr_euid = cr->cr_uid;
8840Sstevel@tonic-gate 	pcrp->pr_ruid = cr->cr_ruid;
8850Sstevel@tonic-gate 	pcrp->pr_suid = cr->cr_suid;
8860Sstevel@tonic-gate 	pcrp->pr_egid = cr->cr_gid;
8870Sstevel@tonic-gate 	pcrp->pr_rgid = cr->cr_rgid;
8880Sstevel@tonic-gate 	pcrp->pr_sgid = cr->cr_sgid;
889*11134SCasper.Dik@Sun.COM 	pcrp->pr_groups[0] = 0; /* in case ngroups == 0 */
890*11134SCasper.Dik@Sun.COM 	pcrp->pr_ngroups = cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups;
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	if (pcrp->pr_ngroups != 0)
893*11134SCasper.Dik@Sun.COM 		bcopy(cr->cr_grps->crg_groups, pcrp->pr_groups,
894*11134SCasper.Dik@Sun.COM 		    sizeof (gid_t) * pcrp->pr_ngroups);
8950Sstevel@tonic-gate }
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate static int
8981676Sjpk cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr)
8990Sstevel@tonic-gate {
9000Sstevel@tonic-gate 	auditinfo_addr_t	*ai;
9010Sstevel@tonic-gate 	au_tid_addr_t	tid;
9020Sstevel@tonic-gate 
9031676Sjpk 	if (secpolicy_audit_getattr(rcr) != 0)
9040Sstevel@tonic-gate 		return (-1);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	ai = CR_AUINFO(cr);	/* caller makes sure this is non-NULL */
9070Sstevel@tonic-gate 	tid = ai->ai_termid;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	ainfo->ai_auid = ai->ai_auid;
9100Sstevel@tonic-gate 	ainfo->ai_mask = ai->ai_mask;
9110Sstevel@tonic-gate 	ainfo->ai_asid = ai->ai_asid;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	ainfo->ai_termid.at_type = tid.at_type;
9140Sstevel@tonic-gate 	bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t));
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port);
9170Sstevel@tonic-gate 	ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port);
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	return (0);
9200Sstevel@tonic-gate }
9210Sstevel@tonic-gate 
9221676Sjpk void
9231676Sjpk cred2uclabel(const cred_t *cr, bslabel_t *labelp)
9241676Sjpk {
9251676Sjpk 	ts_label_t	*tslp;
9261676Sjpk 
9271676Sjpk 	if ((tslp = crgetlabel(cr)) != NULL)
9281676Sjpk 		bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t));
9291676Sjpk }
9301676Sjpk 
9310Sstevel@tonic-gate /*
9320Sstevel@tonic-gate  * Convert a credential into a "ucred".  Allow the caller to specify
9330Sstevel@tonic-gate  * and aligned buffer, e.g., in an mblk, so we don't have to allocate
9340Sstevel@tonic-gate  * memory and copy it twice.
9351676Sjpk  *
9361676Sjpk  * This function may call cred2ucaud(), which calls CRED(). Since this
9371676Sjpk  * can be called from an interrupt thread, receiver's cred (rcr) is needed
9381676Sjpk  * to determine whether audit info should be included.
9390Sstevel@tonic-gate  */
9400Sstevel@tonic-gate struct ucred_s *
9411676Sjpk cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr)
9420Sstevel@tonic-gate {
9430Sstevel@tonic-gate 	struct ucred_s *uc;
944*11134SCasper.Dik@Sun.COM 	uint32_t realsz = ucredminsize(cr);
945*11134SCasper.Dik@Sun.COM 	ts_label_t *tslp = is_system_labeled() ? crgetlabel(cr) : NULL;
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	/* The structure isn't always completely filled in, so zero it */
9480Sstevel@tonic-gate 	if (buf == NULL) {
949*11134SCasper.Dik@Sun.COM 		uc = kmem_zalloc(realsz, KM_SLEEP);
9500Sstevel@tonic-gate 	} else {
951*11134SCasper.Dik@Sun.COM 		bzero(buf, realsz);
9520Sstevel@tonic-gate 		uc = buf;
9530Sstevel@tonic-gate 	}
954*11134SCasper.Dik@Sun.COM 	uc->uc_size = realsz;
9550Sstevel@tonic-gate 	uc->uc_pid = pid;
9560Sstevel@tonic-gate 	uc->uc_projid = cr->cr_projid;
9570Sstevel@tonic-gate 	uc->uc_zoneid = crgetzoneid(cr);
9580Sstevel@tonic-gate 
9591676Sjpk 	if (REMOTE_PEER_CRED(cr)) {
9601676Sjpk 		/*
961*11134SCasper.Dik@Sun.COM 		 * Other than label, the rest of cred info about a
962*11134SCasper.Dik@Sun.COM 		 * remote peer isn't available. Copy the label directly
963*11134SCasper.Dik@Sun.COM 		 * after the header where we generally copy the prcred.
964*11134SCasper.Dik@Sun.COM 		 * That's why we use sizeof (struct ucred_s).  The other
965*11134SCasper.Dik@Sun.COM 		 * offset fields are initialized to 0.
9661676Sjpk 		 */
967*11134SCasper.Dik@Sun.COM 		uc->uc_labeloff = tslp == NULL ? 0 : sizeof (struct ucred_s);
9681676Sjpk 	} else {
969*11134SCasper.Dik@Sun.COM 		uc->uc_credoff = UCRED_CRED_OFF;
970*11134SCasper.Dik@Sun.COM 		uc->uc_privoff = UCRED_PRIV_OFF;
971*11134SCasper.Dik@Sun.COM 		uc->uc_audoff = UCRED_AUD_OFF;
972*11134SCasper.Dik@Sun.COM 		uc->uc_labeloff = tslp == NULL ? 0 : UCRED_LABEL_OFF;
973*11134SCasper.Dik@Sun.COM 
9741676Sjpk 		cred2prcred(cr, UCCRED(uc));
9751676Sjpk 		cred2prpriv(cr, UCPRIV(uc));
976*11134SCasper.Dik@Sun.COM 
9771676Sjpk 		if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0)
9781676Sjpk 			uc->uc_audoff = 0;
979*11134SCasper.Dik@Sun.COM 	}
980*11134SCasper.Dik@Sun.COM 	if (tslp != NULL)
981*11134SCasper.Dik@Sun.COM 		bcopy(&tslp->tsl_label, UCLABEL(uc), sizeof (bslabel_t));
982*11134SCasper.Dik@Sun.COM 
983*11134SCasper.Dik@Sun.COM 	return (uc);
984*11134SCasper.Dik@Sun.COM }
985*11134SCasper.Dik@Sun.COM 
986*11134SCasper.Dik@Sun.COM /*
987*11134SCasper.Dik@Sun.COM  * Don't allocate the non-needed group entries.  Note: this function
988*11134SCasper.Dik@Sun.COM  * must match the code in cred2ucred; they must agree about the
989*11134SCasper.Dik@Sun.COM  * minimal size of the ucred.
990*11134SCasper.Dik@Sun.COM  */
991*11134SCasper.Dik@Sun.COM uint32_t
992*11134SCasper.Dik@Sun.COM ucredminsize(const cred_t *cr)
993*11134SCasper.Dik@Sun.COM {
994*11134SCasper.Dik@Sun.COM 	int ndiff;
995*11134SCasper.Dik@Sun.COM 
996*11134SCasper.Dik@Sun.COM 	if (cr == NULL)
997*11134SCasper.Dik@Sun.COM 		return (ucredsize);
998*11134SCasper.Dik@Sun.COM 
999*11134SCasper.Dik@Sun.COM 	if (REMOTE_PEER_CRED(cr)) {
1000*11134SCasper.Dik@Sun.COM 		if (is_system_labeled())
1001*11134SCasper.Dik@Sun.COM 			return (sizeof (struct ucred_s) + sizeof (bslabel_t));
1002*11134SCasper.Dik@Sun.COM 		else
1003*11134SCasper.Dik@Sun.COM 			return (sizeof (struct ucred_s));
10041676Sjpk 	}
10050Sstevel@tonic-gate 
1006*11134SCasper.Dik@Sun.COM 	if (cr->cr_grps == NULL)
1007*11134SCasper.Dik@Sun.COM 		ndiff = ngroups_max - 1;	/* Needs one for prcred_t */
1008*11134SCasper.Dik@Sun.COM 	else
1009*11134SCasper.Dik@Sun.COM 		ndiff = ngroups_max - cr->cr_grps->crg_ngroups;
1010*11134SCasper.Dik@Sun.COM 
1011*11134SCasper.Dik@Sun.COM 	return (ucredsize - ndiff * sizeof (gid_t));
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate /*
10150Sstevel@tonic-gate  * Get the "ucred" of a process.
10160Sstevel@tonic-gate  */
10170Sstevel@tonic-gate struct ucred_s *
10180Sstevel@tonic-gate pgetucred(proc_t *p)
10190Sstevel@tonic-gate {
10200Sstevel@tonic-gate 	cred_t *cr;
10210Sstevel@tonic-gate 	struct ucred_s *uc;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
10240Sstevel@tonic-gate 	cr = p->p_cred;
10250Sstevel@tonic-gate 	crhold(cr);
10260Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
10270Sstevel@tonic-gate 
10281676Sjpk 	uc = cred2ucred(cr, p->p_pid, NULL, CRED());
10290Sstevel@tonic-gate 	crfree(cr);
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 	return (uc);
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate /*
10350Sstevel@tonic-gate  * If the reply status is NFSERR_EACCES, it may be because we are
10360Sstevel@tonic-gate  * root (no root net access).  Check the real uid, if it isn't root
10370Sstevel@tonic-gate  * make that the uid instead and retry the call.
10380Sstevel@tonic-gate  * Private interface for NFS.
10390Sstevel@tonic-gate  */
10400Sstevel@tonic-gate cred_t *
10410Sstevel@tonic-gate crnetadjust(cred_t *cr)
10420Sstevel@tonic-gate {
10430Sstevel@tonic-gate 	if (cr->cr_uid == 0 && cr->cr_ruid != 0) {
10440Sstevel@tonic-gate 		cr = crdup(cr);
10450Sstevel@tonic-gate 		cr->cr_uid = cr->cr_ruid;
10460Sstevel@tonic-gate 		return (cr);
10470Sstevel@tonic-gate 	}
10480Sstevel@tonic-gate 	return (NULL);
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate /*
10520Sstevel@tonic-gate  * The reference count is of interest when you want to check
10530Sstevel@tonic-gate  * whether it is ok to modify the credential in place.
10540Sstevel@tonic-gate  */
10550Sstevel@tonic-gate uint_t
10560Sstevel@tonic-gate crgetref(const cred_t *cr)
10570Sstevel@tonic-gate {
10580Sstevel@tonic-gate 	return (cr->cr_ref);
10590Sstevel@tonic-gate }
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate static int
10620Sstevel@tonic-gate get_c2audit_load(void)
10630Sstevel@tonic-gate {
10640Sstevel@tonic-gate 	static int	gotit = 0;
10650Sstevel@tonic-gate 	static int	c2audit_load;
10660Sstevel@tonic-gate 	u_longlong_t	audit_load_val;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	if (gotit)
10690Sstevel@tonic-gate 		return (c2audit_load);
10700Sstevel@tonic-gate 	audit_load_val = 0;		/* set default value once */
10710Sstevel@tonic-gate 	(void) mod_sysvar("c2audit", "audit_load", &audit_load_val);
10720Sstevel@tonic-gate 	c2audit_load = (int)audit_load_val;
10730Sstevel@tonic-gate 	gotit++;
10740Sstevel@tonic-gate 	return (c2audit_load);
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate int
10780Sstevel@tonic-gate get_audit_ucrsize(void)
10790Sstevel@tonic-gate {
10800Sstevel@tonic-gate 	return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0);
10810Sstevel@tonic-gate }
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate /*
10840Sstevel@tonic-gate  * Set zone pointer in credential to indicated value.  First adds a
10850Sstevel@tonic-gate  * hold for the new zone, then drops the hold on previous zone (if any).
10860Sstevel@tonic-gate  * This is done in this order in case the old and new zones are the
10870Sstevel@tonic-gate  * same.
10880Sstevel@tonic-gate  */
10890Sstevel@tonic-gate void
10900Sstevel@tonic-gate crsetzone(cred_t *cr, zone_t *zptr)
10910Sstevel@tonic-gate {
10920Sstevel@tonic-gate 	zone_t *oldzptr = cr->cr_zone;
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	ASSERT(cr != kcred);
10950Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
10960Sstevel@tonic-gate 	cr->cr_zone = zptr;
10970Sstevel@tonic-gate 	zone_cred_hold(zptr);
10980Sstevel@tonic-gate 	if (oldzptr)
10990Sstevel@tonic-gate 		zone_cred_rele(oldzptr);
11000Sstevel@tonic-gate }
11011676Sjpk 
11021676Sjpk /*
11031676Sjpk  * Create a new cred based on the supplied label
11041676Sjpk  */
11051676Sjpk cred_t *
11061676Sjpk newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags)
11071676Sjpk {
11081676Sjpk 	ts_label_t *lbl = labelalloc(blabel, doi, flags);
11091676Sjpk 	cred_t *cr = NULL;
11101676Sjpk 
11111676Sjpk 	if (lbl != NULL) {
11126134Scasper 		if ((cr = crdup_flags(dummycr, flags)) != NULL) {
11131676Sjpk 			cr->cr_label = lbl;
11141676Sjpk 		} else {
11151676Sjpk 			label_rele(lbl);
11161676Sjpk 		}
11171676Sjpk 	}
11181676Sjpk 
11191676Sjpk 	return (cr);
11201676Sjpk }
11211676Sjpk 
11221676Sjpk /*
11231676Sjpk  * Derive a new cred from the existing cred, but with a different label.
11241676Sjpk  * To be used when a cred is being shared, but the label needs to be changed
11251676Sjpk  * by a caller without affecting other users
11261676Sjpk  */
11271676Sjpk cred_t *
11289710SKen.Powell@Sun.COM copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags)
11299710SKen.Powell@Sun.COM {
11309710SKen.Powell@Sun.COM 	cred_t *newcr = NULL;
11319710SKen.Powell@Sun.COM 
11329710SKen.Powell@Sun.COM 	if ((newcr = crdup_flags(cr, flags)) != NULL) {
11339710SKen.Powell@Sun.COM 		if (newcr->cr_label != NULL)
11349710SKen.Powell@Sun.COM 			label_rele(newcr->cr_label);
11359710SKen.Powell@Sun.COM 		label_hold(label);
11369710SKen.Powell@Sun.COM 		newcr->cr_label = label;
11379710SKen.Powell@Sun.COM 	}
11389710SKen.Powell@Sun.COM 
11399710SKen.Powell@Sun.COM 	return (newcr);
11409710SKen.Powell@Sun.COM }
11419710SKen.Powell@Sun.COM 
11429710SKen.Powell@Sun.COM /*
11439710SKen.Powell@Sun.COM  * Derive a new cred from the existing cred, but with a different label.
11449710SKen.Powell@Sun.COM  */
11459710SKen.Powell@Sun.COM cred_t *
11469710SKen.Powell@Sun.COM copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel,
11479710SKen.Powell@Sun.COM     uint32_t doi, int flags)
11481676Sjpk {
11491676Sjpk 	ts_label_t *lbl = labelalloc(blabel, doi, flags);
11509710SKen.Powell@Sun.COM 	cred_t  *newcr = NULL;
11511676Sjpk 
11521676Sjpk 	if (lbl != NULL) {
11539710SKen.Powell@Sun.COM 		newcr = copycred_from_tslabel(cr, lbl, flags);
11549710SKen.Powell@Sun.COM 		label_rele(lbl);
11551676Sjpk 	}
11561676Sjpk 
11571676Sjpk 	return (newcr);
11581676Sjpk }
11591676Sjpk 
11601676Sjpk /*
11611676Sjpk  * This function returns a pointer to the kcred-equivalent in the current zone.
11621676Sjpk  */
11631676Sjpk cred_t *
11641676Sjpk zone_kcred(void)
11651676Sjpk {
11661676Sjpk 	zone_t *zone;
11671676Sjpk 
11681676Sjpk 	if ((zone = CRED()->cr_zone) != NULL)
11691676Sjpk 		return (zone->zone_kcred);
11701676Sjpk 	else
11711676Sjpk 		return (kcred);
11721676Sjpk }
11734321Scasper 
11744321Scasper boolean_t
11755771Sjp151216 valid_ephemeral_uid(zone_t *zone, uid_t id)
11764321Scasper {
11775771Sjp151216 	ephemeral_zsd_t *eph_zsd;
11785908Sjp151216 	if (id <= IDMAP_WK__MAX_UID)
11795771Sjp151216 		return (B_TRUE);
11805771Sjp151216 
11815771Sjp151216 	eph_zsd = get_ephemeral_zsd(zone);
11825771Sjp151216 	ASSERT(eph_zsd != NULL);
11834321Scasper 	membar_consumer();
11845771Sjp151216 	return (id > eph_zsd->min_uid && id <= eph_zsd->last_uid);
11854321Scasper }
11864321Scasper 
11874321Scasper boolean_t
11885771Sjp151216 valid_ephemeral_gid(zone_t *zone, gid_t id)
11894321Scasper {
11905771Sjp151216 	ephemeral_zsd_t *eph_zsd;
11915908Sjp151216 	if (id <= IDMAP_WK__MAX_GID)
11925771Sjp151216 		return (B_TRUE);
11935771Sjp151216 
11945771Sjp151216 	eph_zsd = get_ephemeral_zsd(zone);
11955771Sjp151216 	ASSERT(eph_zsd != NULL);
11964321Scasper 	membar_consumer();
11975771Sjp151216 	return (id > eph_zsd->min_gid && id <= eph_zsd->last_gid);
11984321Scasper }
11994321Scasper 
12004321Scasper int
12015771Sjp151216 eph_uid_alloc(zone_t *zone, int flags, uid_t *start, int count)
12024321Scasper {
12035771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12045771Sjp151216 
12055771Sjp151216 	ASSERT(eph_zsd != NULL);
12065771Sjp151216 
12075771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12084321Scasper 
12094321Scasper 	/* Test for unsigned integer wrap around */
12105771Sjp151216 	if (eph_zsd->last_uid + count < eph_zsd->last_uid) {
12115771Sjp151216 		mutex_exit(&eph_zsd->eph_lock);
12124321Scasper 		return (-1);
12134321Scasper 	}
12144321Scasper 
12154321Scasper 	/* first call or idmap crashed and state corrupted */
12164321Scasper 	if (flags != 0)
12175771Sjp151216 		eph_zsd->min_uid = eph_zsd->last_uid;
12184321Scasper 
12194321Scasper 	hasephids = B_TRUE;
12205771Sjp151216 	*start = eph_zsd->last_uid + 1;
12215771Sjp151216 	atomic_add_32(&eph_zsd->last_uid, count);
12225771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12234321Scasper 	return (0);
12244321Scasper }
12254321Scasper 
12264321Scasper int
12275771Sjp151216 eph_gid_alloc(zone_t *zone, int flags, gid_t *start, int count)
12284321Scasper {
12295771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12305771Sjp151216 
12315771Sjp151216 	ASSERT(eph_zsd != NULL);
12325771Sjp151216 
12335771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12344321Scasper 
12354321Scasper 	/* Test for unsigned integer wrap around */
12365771Sjp151216 	if (eph_zsd->last_gid + count < eph_zsd->last_gid) {
12375771Sjp151216 		mutex_exit(&eph_zsd->eph_lock);
12384321Scasper 		return (-1);
12394321Scasper 	}
12404321Scasper 
12414321Scasper 	/* first call or idmap crashed and state corrupted */
12424321Scasper 	if (flags != 0)
12435771Sjp151216 		eph_zsd->min_gid = eph_zsd->last_gid;
12444321Scasper 
12454321Scasper 	hasephids = B_TRUE;
12465771Sjp151216 	*start = eph_zsd->last_gid + 1;
12475771Sjp151216 	atomic_add_32(&eph_zsd->last_gid, count);
12485771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12494321Scasper 	return (0);
12504321Scasper }
12514321Scasper 
12524321Scasper /*
12535771Sjp151216  * IMPORTANT.The two functions get_ephemeral_data() and set_ephemeral_data()
12545771Sjp151216  * are project private functions that are for use of the test system only and
12555771Sjp151216  * are not to be used for other purposes.
12565771Sjp151216  */
12575771Sjp151216 
12585771Sjp151216 void
12595771Sjp151216 get_ephemeral_data(zone_t *zone, uid_t *min_uid, uid_t *last_uid,
12605771Sjp151216 	gid_t *min_gid, gid_t *last_gid)
12615771Sjp151216 {
12625771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12635771Sjp151216 
12645771Sjp151216 	ASSERT(eph_zsd != NULL);
12655771Sjp151216 
12665771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12675771Sjp151216 
12685771Sjp151216 	*min_uid = eph_zsd->min_uid;
12695771Sjp151216 	*last_uid = eph_zsd->last_uid;
12705771Sjp151216 	*min_gid = eph_zsd->min_gid;
12715771Sjp151216 	*last_gid = eph_zsd->last_gid;
12725771Sjp151216 
12735771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12745771Sjp151216 }
12755771Sjp151216 
12765771Sjp151216 
12775771Sjp151216 void
12785771Sjp151216 set_ephemeral_data(zone_t *zone, uid_t min_uid, uid_t last_uid,
12795771Sjp151216 	gid_t min_gid, gid_t last_gid)
12805771Sjp151216 {
12815771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12825771Sjp151216 
12835771Sjp151216 	ASSERT(eph_zsd != NULL);
12845771Sjp151216 
12855771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12865771Sjp151216 
12875771Sjp151216 	if (min_uid != 0)
12885771Sjp151216 		eph_zsd->min_uid = min_uid;
12895771Sjp151216 	if (last_uid != 0)
12905771Sjp151216 		eph_zsd->last_uid = last_uid;
12915771Sjp151216 	if (min_gid != 0)
12925771Sjp151216 		eph_zsd->min_gid = min_gid;
12935771Sjp151216 	if (last_gid != 0)
12945771Sjp151216 		eph_zsd->last_gid = last_gid;
12955771Sjp151216 
12965771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12975771Sjp151216 }
12985771Sjp151216 
12995771Sjp151216 /*
13005331Samw  * If the credential user SID or group SID is mapped to an ephemeral
13015331Samw  * ID, map the credential to nobody.
13024321Scasper  */
13034321Scasper cred_t *
13044321Scasper crgetmapped(const cred_t *cr)
13054321Scasper {
13065771Sjp151216 	ephemeral_zsd_t *eph_zsd;
13074406Scasper 	/*
13084406Scasper 	 * Someone incorrectly passed a NULL cred to a vnode operation
13094406Scasper 	 * either on purpose or by calling CRED() in interrupt context.
13104406Scasper 	 */
13114406Scasper 	if (cr == NULL)
13124406Scasper 		return (NULL);
13134406Scasper 
13144321Scasper 	if (cr->cr_ksid != NULL) {
13155771Sjp151216 		if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID) {
13165771Sjp151216 			eph_zsd = get_ephemeral_zsd(crgetzone(cr));
13175771Sjp151216 			return (eph_zsd->eph_nobody);
13185771Sjp151216 		}
13194321Scasper 
13205771Sjp151216 		if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID) {
13215771Sjp151216 			eph_zsd = get_ephemeral_zsd(crgetzone(cr));
13225771Sjp151216 			return (eph_zsd->eph_nobody);
13235771Sjp151216 		}
13244321Scasper 	}
13254321Scasper 
13264321Scasper 	return ((cred_t *)cr);
13274321Scasper }
13284321Scasper 
13294321Scasper /* index should be in range for a ksidindex_t */
13304321Scasper void
13314321Scasper crsetsid(cred_t *cr, ksid_t *ksp, int index)
13324321Scasper {
13334321Scasper 	ASSERT(cr->cr_ref <= 2);
13344321Scasper 	ASSERT(index >= 0 && index < KSID_COUNT);
13354321Scasper 	if (cr->cr_ksid == NULL && ksp == NULL)
13364321Scasper 		return;
13374321Scasper 	cr->cr_ksid = kcrsid_setsid(cr->cr_ksid, ksp, index);
13384321Scasper }
13394321Scasper 
13404321Scasper void
13414321Scasper crsetsidlist(cred_t *cr, ksidlist_t *ksl)
13424321Scasper {
13434321Scasper 	ASSERT(cr->cr_ref <= 2);
13444321Scasper 	if (cr->cr_ksid == NULL && ksl == NULL)
13454321Scasper 		return;
13464321Scasper 	cr->cr_ksid = kcrsid_setsidlist(cr->cr_ksid, ksl);
13474321Scasper }
13484321Scasper 
13494321Scasper ksid_t *
13504321Scasper crgetsid(const cred_t *cr, int i)
13514321Scasper {
13524321Scasper 	ASSERT(i >= 0 && i < KSID_COUNT);
13534321Scasper 	if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidx[i].ks_domain)
13544321Scasper 		return ((ksid_t *)&cr->cr_ksid->kr_sidx[i]);
13554321Scasper 	return (NULL);
13564321Scasper }
13574321Scasper 
13584321Scasper ksidlist_t *
13594321Scasper crgetsidlist(const cred_t *cr)
13604321Scasper {
13615331Samw 	if (cr->cr_ksid != NULL)
13624923Scasper 		return (cr->cr_ksid->kr_sidlist);
13634321Scasper 	return (NULL);
13644321Scasper }
13655331Samw 
13665331Samw /*
13675331Samw  * Interface to set the effective and permitted privileges for
13685331Samw  * a credential; this interface does no security checks and is
13695331Samw  * intended for kernel (file)servers creating credentials with
13705331Samw  * specific privileges.
13715331Samw  */
13725331Samw int
13735331Samw crsetpriv(cred_t *cr, ...)
13745331Samw {
13755331Samw 	va_list ap;
13765331Samw 	const char *privnm;
13775331Samw 
13785331Samw 	ASSERT(cr->cr_ref <= 2);
13795331Samw 
13805331Samw 	priv_set_PA(cr);
13815331Samw 
13825331Samw 	va_start(ap, cr);
13835331Samw 
13845331Samw 	while ((privnm = va_arg(ap, const char *)) != NULL) {
13855331Samw 		int priv = priv_getbyname(privnm, 0);
13865331Samw 		if (priv < 0)
13875331Samw 			return (-1);
13885331Samw 
13895331Samw 		priv_addset(&CR_PPRIV(cr), priv);
13905331Samw 		priv_addset(&CR_EPRIV(cr), priv);
13915331Samw 	}
13925331Samw 	priv_adjust_PA(cr);
13935331Samw 	va_end(ap);
13945331Samw 	return (0);
13955331Samw }
13966134Scasper 
13979151SThomas.Haynes@Sun.COM /*
13989151SThomas.Haynes@Sun.COM  * Interface to effectively set the PRIV_ALL for
13999151SThomas.Haynes@Sun.COM  * a credential; this interface does no security checks and is
14009151SThomas.Haynes@Sun.COM  * intended for kernel (file)servers to extend the user credentials
14019151SThomas.Haynes@Sun.COM  * to be ALL, like either kcred or zcred.
14029151SThomas.Haynes@Sun.COM  */
14039151SThomas.Haynes@Sun.COM void
14049151SThomas.Haynes@Sun.COM crset_zone_privall(cred_t *cr)
14059151SThomas.Haynes@Sun.COM {
14069151SThomas.Haynes@Sun.COM 	zone_t	*zone = crgetzone(cr);
14079151SThomas.Haynes@Sun.COM 
14089151SThomas.Haynes@Sun.COM 	priv_fillset(&CR_LPRIV(cr));
14099151SThomas.Haynes@Sun.COM 	CR_EPRIV(cr) = CR_PPRIV(cr) = CR_IPRIV(cr) = CR_LPRIV(cr);
14109151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_LPRIV(cr));
14119151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_EPRIV(cr));
14129151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_IPRIV(cr));
14139151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_PPRIV(cr));
14149151SThomas.Haynes@Sun.COM }
14159151SThomas.Haynes@Sun.COM 
14166134Scasper struct credklpd *
14176134Scasper crgetcrklpd(const cred_t *cr)
14186134Scasper {
14196134Scasper 	return (cr->cr_klpd);
14206134Scasper }
14216134Scasper 
14226134Scasper void
14236134Scasper crsetcrklpd(cred_t *cr, struct credklpd *crklpd)
14246134Scasper {
14256134Scasper 	ASSERT(cr->cr_ref <= 2);
14266134Scasper 
14276134Scasper 	if (cr->cr_klpd != NULL)
14286134Scasper 		crklpd_rele(cr->cr_klpd);
14296134Scasper 	cr->cr_klpd = crklpd;
14306134Scasper }
1431*11134SCasper.Dik@Sun.COM 
1432*11134SCasper.Dik@Sun.COM credgrp_t *
1433*11134SCasper.Dik@Sun.COM crgrpcopyin(int n, gid_t *gidset)
1434*11134SCasper.Dik@Sun.COM {
1435*11134SCasper.Dik@Sun.COM 	credgrp_t *mem;
1436*11134SCasper.Dik@Sun.COM 	size_t sz = CREDGRPSZ(n);
1437*11134SCasper.Dik@Sun.COM 
1438*11134SCasper.Dik@Sun.COM 	ASSERT(n > 0);
1439*11134SCasper.Dik@Sun.COM 
1440*11134SCasper.Dik@Sun.COM 	mem = kmem_alloc(sz, KM_SLEEP);
1441*11134SCasper.Dik@Sun.COM 
1442*11134SCasper.Dik@Sun.COM 	if (copyin(gidset, mem->crg_groups, sizeof (gid_t) * n)) {
1443*11134SCasper.Dik@Sun.COM 		kmem_free(mem, sz);
1444*11134SCasper.Dik@Sun.COM 		return (NULL);
1445*11134SCasper.Dik@Sun.COM 	}
1446*11134SCasper.Dik@Sun.COM 	mem->crg_ref = 1;
1447*11134SCasper.Dik@Sun.COM 	mem->crg_ngroups = n;
1448*11134SCasper.Dik@Sun.COM 	return (mem);
1449*11134SCasper.Dik@Sun.COM }
1450*11134SCasper.Dik@Sun.COM 
1451*11134SCasper.Dik@Sun.COM const gid_t *
1452*11134SCasper.Dik@Sun.COM crgetggroups(const credgrp_t *grps)
1453*11134SCasper.Dik@Sun.COM {
1454*11134SCasper.Dik@Sun.COM 	return (grps->crg_groups);
1455*11134SCasper.Dik@Sun.COM }
1456*11134SCasper.Dik@Sun.COM 
1457*11134SCasper.Dik@Sun.COM void
1458*11134SCasper.Dik@Sun.COM crsetcredgrp(cred_t *cr, credgrp_t *grps)
1459*11134SCasper.Dik@Sun.COM {
1460*11134SCasper.Dik@Sun.COM 	ASSERT(cr->cr_ref <= 2);
1461*11134SCasper.Dik@Sun.COM 
1462*11134SCasper.Dik@Sun.COM 	if (cr->cr_grps != NULL)
1463*11134SCasper.Dik@Sun.COM 		crgrprele(cr->cr_grps);
1464*11134SCasper.Dik@Sun.COM 
1465*11134SCasper.Dik@Sun.COM 	cr->cr_grps = grps;
1466*11134SCasper.Dik@Sun.COM }
1467*11134SCasper.Dik@Sun.COM 
1468*11134SCasper.Dik@Sun.COM void
1469*11134SCasper.Dik@Sun.COM crgrprele(credgrp_t *grps)
1470*11134SCasper.Dik@Sun.COM {
1471*11134SCasper.Dik@Sun.COM 	if (atomic_add_32_nv(&grps->crg_ref, -1) == 0)
1472*11134SCasper.Dik@Sun.COM 		kmem_free(grps, CREDGRPSZ(grps->crg_ngroups));
1473*11134SCasper.Dik@Sun.COM }
1474*11134SCasper.Dik@Sun.COM 
1475*11134SCasper.Dik@Sun.COM static void
1476*11134SCasper.Dik@Sun.COM crgrphold(credgrp_t *grps)
1477*11134SCasper.Dik@Sun.COM {
1478*11134SCasper.Dik@Sun.COM 	atomic_add_32(&grps->crg_ref, 1);
1479*11134SCasper.Dik@Sun.COM }
1480