xref: /onnv-gate/usr/src/uts/common/os/cred.c (revision 11861:a63258283f8f)
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*11861SMarek.Pospisil@Sun.COM  * Copyright 2010 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*11861SMarek.Pospisil@Sun.COM #include <sys/sysconf.h>
6611134SCasper.Dik@Sun.COM #include <util/qsort.h>
674321Scasper 
685771Sjp151216 
695771Sjp151216 /* Ephemeral IDs Zones specific data */
705771Sjp151216 typedef struct ephemeral_zsd {
715771Sjp151216 	uid_t		min_uid;
725771Sjp151216 	uid_t		last_uid;
735771Sjp151216 	gid_t		min_gid;
745771Sjp151216 	gid_t		last_gid;
754321Scasper 	kmutex_t	eph_lock;
765771Sjp151216 	cred_t		*eph_nobody;
775771Sjp151216 } ephemeral_zsd_t;
785771Sjp151216 
7911134SCasper.Dik@Sun.COM /* Supplemental groups list. */
8011134SCasper.Dik@Sun.COM typedef struct credgrp {
8111134SCasper.Dik@Sun.COM 	uint_t		crg_ref;
8211134SCasper.Dik@Sun.COM 	uint_t		crg_ngroups;
8311134SCasper.Dik@Sun.COM 	gid_t		crg_groups[1];
8411134SCasper.Dik@Sun.COM } credgrp_t;
8511134SCasper.Dik@Sun.COM 
8611134SCasper.Dik@Sun.COM static void crgrphold(credgrp_t *);
8711134SCasper.Dik@Sun.COM 
8811134SCasper.Dik@Sun.COM #define	CREDGRPSZ(ngrp)	(sizeof (credgrp_t) + ((ngrp - 1) * sizeof (gid_t)))
895771Sjp151216 
905771Sjp151216 static kmutex_t		ephemeral_zone_mutex;
915771Sjp151216 static zone_key_t	ephemeral_zone_key;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate static struct kmem_cache *cred_cache;
945771Sjp151216 static size_t		crsize = 0;
955771Sjp151216 static int		audoff = 0;
965771Sjp151216 uint32_t		ucredsize;
975771Sjp151216 cred_t			*kcred;
985771Sjp151216 static cred_t		*dummycr;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate int rstlink;		/* link(2) restricted to files owned by user? */
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static int get_c2audit_load(void);
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #define	CR_AUINFO(c)	(auditinfo_addr_t *)((audoff == 0) ? NULL : \
1050Sstevel@tonic-gate 			    ((char *)(c)) + audoff)
1060Sstevel@tonic-gate 
1071676Sjpk #define	REMOTE_PEER_CRED(c)	((c)->cr_gid == -1)
1080Sstevel@tonic-gate 
10911134SCasper.Dik@Sun.COM #define	BIN_GROUP_SEARCH_CUTOFF	16
1104321Scasper 
1114321Scasper static boolean_t hasephids = B_FALSE;
1124321Scasper 
1135771Sjp151216 static ephemeral_zsd_t *
1145771Sjp151216 get_ephemeral_zsd(zone_t *zone)
1155771Sjp151216 {
1165771Sjp151216 	ephemeral_zsd_t *eph_zsd;
1175771Sjp151216 
1185771Sjp151216 	eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
1195771Sjp151216 	if (eph_zsd != NULL) {
1205771Sjp151216 		return (eph_zsd);
1215771Sjp151216 	}
1225771Sjp151216 
1235771Sjp151216 	mutex_enter(&ephemeral_zone_mutex);
1245771Sjp151216 	eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
1255771Sjp151216 	if (eph_zsd == NULL) {
1265771Sjp151216 		eph_zsd = kmem_zalloc(sizeof (ephemeral_zsd_t), KM_SLEEP);
1275771Sjp151216 		eph_zsd->min_uid = MAXUID;
1285771Sjp151216 		eph_zsd->last_uid = IDMAP_WK__MAX_UID;
1295771Sjp151216 		eph_zsd->min_gid = MAXUID;
1305771Sjp151216 		eph_zsd->last_gid = IDMAP_WK__MAX_GID;
1315771Sjp151216 		mutex_init(&eph_zsd->eph_lock, NULL, MUTEX_DEFAULT, NULL);
1325771Sjp151216 
1335771Sjp151216 		/*
1345771Sjp151216 		 * nobody is used to map SID containing CRs.
1355771Sjp151216 		 */
1365771Sjp151216 		eph_zsd->eph_nobody = crdup(zone->zone_kcred);
1375771Sjp151216 		(void) crsetugid(eph_zsd->eph_nobody, UID_NOBODY, GID_NOBODY);
1385771Sjp151216 		CR_FLAGS(eph_zsd->eph_nobody) = 0;
1395771Sjp151216 		eph_zsd->eph_nobody->cr_zone = zone;
1405771Sjp151216 
1415771Sjp151216 		(void) zone_setspecific(ephemeral_zone_key, zone, eph_zsd);
1425771Sjp151216 	}
1435771Sjp151216 	mutex_exit(&ephemeral_zone_mutex);
1445771Sjp151216 	return (eph_zsd);
1455771Sjp151216 }
1465771Sjp151216 
1479710SKen.Powell@Sun.COM static cred_t *crdup_flags(const cred_t *, int);
1486134Scasper static cred_t *cralloc_flags(int);
1496134Scasper 
1505771Sjp151216 /*
1515771Sjp151216  * This function is called when a zone is destroyed
1525771Sjp151216  */
1535771Sjp151216 static void
1545771Sjp151216 /* ARGSUSED */
1555771Sjp151216 destroy_ephemeral_zsd(zoneid_t zone_id, void *arg)
1565771Sjp151216 {
1575771Sjp151216 	ephemeral_zsd_t *eph_zsd = arg;
1585771Sjp151216 	if (eph_zsd != NULL) {
1595771Sjp151216 		mutex_destroy(&eph_zsd->eph_lock);
1605771Sjp151216 		crfree(eph_zsd->eph_nobody);
1615771Sjp151216 		kmem_free(eph_zsd, sizeof (ephemeral_zsd_t));
1625771Sjp151216 	}
1635771Sjp151216 }
1645771Sjp151216 
1655771Sjp151216 
1665771Sjp151216 
1674321Scasper /*
1680Sstevel@tonic-gate  * Initialize credentials data structures.
1690Sstevel@tonic-gate  */
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate void
1720Sstevel@tonic-gate cred_init(void)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate 	priv_init();
1750Sstevel@tonic-gate 
17611134SCasper.Dik@Sun.COM 	crsize = sizeof (cred_t);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	if (get_c2audit_load() > 0) {
1790Sstevel@tonic-gate #ifdef _LP64
1800Sstevel@tonic-gate 		/* assure audit context is 64-bit aligned */
1810Sstevel@tonic-gate 		audoff = (crsize +
1820Sstevel@tonic-gate 		    sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1);
1830Sstevel@tonic-gate #else	/* _LP64 */
1840Sstevel@tonic-gate 		audoff = crsize;
1850Sstevel@tonic-gate #endif	/* _LP64 */
1860Sstevel@tonic-gate 		crsize = audoff + sizeof (auditinfo_addr_t);
1870Sstevel@tonic-gate 		crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1);
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	cred_cache = kmem_cache_create("cred_cache", crsize, 0,
1914520Snw141292 	    NULL, NULL, NULL, NULL, NULL, 0);
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	/*
1941676Sjpk 	 * dummycr is used to copy initial state for creds.
1951676Sjpk 	 */
1961676Sjpk 	dummycr = cralloc();
1971676Sjpk 	bzero(dummycr, crsize);
1981676Sjpk 	dummycr->cr_ref = 1;
1994321Scasper 	dummycr->cr_uid = (uid_t)-1;
2004321Scasper 	dummycr->cr_gid = (gid_t)-1;
2014321Scasper 	dummycr->cr_ruid = (uid_t)-1;
2024321Scasper 	dummycr->cr_rgid = (gid_t)-1;
2034321Scasper 	dummycr->cr_suid = (uid_t)-1;
2044321Scasper 	dummycr->cr_sgid = (gid_t)-1;
2054321Scasper 
2061676Sjpk 
2071676Sjpk 	/*
2080Sstevel@tonic-gate 	 * kcred is used by anything that needs all privileges; it's
2090Sstevel@tonic-gate 	 * also the template used for crget as it has all the compatible
2100Sstevel@tonic-gate 	 * sets filled in.
2110Sstevel@tonic-gate 	 */
2120Sstevel@tonic-gate 	kcred = cralloc();
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	bzero(kcred, crsize);
2150Sstevel@tonic-gate 	kcred->cr_ref = 1;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	/* kcred is never freed, so we don't need zone_cred_hold here */
2180Sstevel@tonic-gate 	kcred->cr_zone = &zone0;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	priv_fillset(&CR_LPRIV(kcred));
2210Sstevel@tonic-gate 	CR_IPRIV(kcred) = *priv_basic;
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	/* Not a basic privilege, if chown is not restricted add it to I0 */
2240Sstevel@tonic-gate 	if (!rstchown)
2250Sstevel@tonic-gate 		priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	/* Basic privilege, if link is restricted remove it from I0 */
2280Sstevel@tonic-gate 	if (rstlink)
2290Sstevel@tonic-gate 		priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY);
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred);
2321676Sjpk 
2331676Sjpk 	CR_FLAGS(kcred) = NET_MAC_AWARE;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	/*
2360Sstevel@tonic-gate 	 * Set up credentials of p0.
2370Sstevel@tonic-gate 	 */
2380Sstevel@tonic-gate 	ttoproc(curthread)->p_cred = kcred;
2390Sstevel@tonic-gate 	curthread->t_cred = kcred;
2400Sstevel@tonic-gate 
2415771Sjp151216 	ucredsize = UCRED_SIZE;
2424321Scasper 
2435771Sjp151216 	mutex_init(&ephemeral_zone_mutex, NULL, MUTEX_DEFAULT, NULL);
2445771Sjp151216 	zone_key_create(&ephemeral_zone_key, NULL, NULL, destroy_ephemeral_zsd);
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate /*
2480Sstevel@tonic-gate  * Allocate (nearly) uninitialized cred_t.
2490Sstevel@tonic-gate  */
2506134Scasper static cred_t *
2516134Scasper cralloc_flags(int flgs)
2520Sstevel@tonic-gate {
2536134Scasper 	cred_t *cr = kmem_cache_alloc(cred_cache, flgs);
2546134Scasper 
2556134Scasper 	if (cr == NULL)
2566134Scasper 		return (NULL);
2576134Scasper 
2580Sstevel@tonic-gate 	cr->cr_ref = 1;		/* So we can crfree() */
2590Sstevel@tonic-gate 	cr->cr_zone = NULL;
2601676Sjpk 	cr->cr_label = NULL;
2614321Scasper 	cr->cr_ksid = NULL;
2626134Scasper 	cr->cr_klpd = NULL;
26311134SCasper.Dik@Sun.COM 	cr->cr_grps = NULL;
2644321Scasper 	return (cr);
2654321Scasper }
2664321Scasper 
2676134Scasper cred_t *
2686134Scasper cralloc(void)
2696134Scasper {
2706134Scasper 	return (cralloc_flags(KM_SLEEP));
2716134Scasper }
2726134Scasper 
2734321Scasper /*
2744321Scasper  * As cralloc but prepared for ksid change (if appropriate).
2754321Scasper  */
2764321Scasper cred_t *
2774321Scasper cralloc_ksid(void)
2784321Scasper {
2794321Scasper 	cred_t *cr = cralloc();
2804321Scasper 	if (hasephids)
2814321Scasper 		cr->cr_ksid = kcrsid_alloc();
2820Sstevel@tonic-gate 	return (cr);
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate  * Allocate a initialized cred structure and crhold() it.
2870Sstevel@tonic-gate  * Initialized means: all ids 0, group count 0, L=Full, E=P=I=I0
2880Sstevel@tonic-gate  */
2890Sstevel@tonic-gate cred_t *
2900Sstevel@tonic-gate crget(void)
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate 	cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	bcopy(kcred, cr, crsize);
2950Sstevel@tonic-gate 	cr->cr_ref = 1;
2960Sstevel@tonic-gate 	zone_cred_hold(cr->cr_zone);
2971676Sjpk 	if (cr->cr_label)
2981676Sjpk 		label_hold(cr->cr_label);
2996134Scasper 	ASSERT(cr->cr_klpd == NULL);
30011134SCasper.Dik@Sun.COM 	ASSERT(cr->cr_grps == NULL);
3010Sstevel@tonic-gate 	return (cr);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate /*
3050Sstevel@tonic-gate  * Broadcast the cred to all the threads in the process.
3060Sstevel@tonic-gate  * The current thread's credentials can be set right away, but other
3070Sstevel@tonic-gate  * threads must wait until the start of the next system call or trap.
3080Sstevel@tonic-gate  * This avoids changing the cred in the middle of a system call.
3090Sstevel@tonic-gate  *
3100Sstevel@tonic-gate  * The cred has already been held for the process and the thread (2 holds),
3110Sstevel@tonic-gate  * and p->p_cred set.
3120Sstevel@tonic-gate  *
3130Sstevel@tonic-gate  * p->p_crlock shouldn't be held here, since p_lock must be acquired.
3140Sstevel@tonic-gate  */
3150Sstevel@tonic-gate void
3160Sstevel@tonic-gate crset(proc_t *p, cred_t *cr)
3170Sstevel@tonic-gate {
3180Sstevel@tonic-gate 	kthread_id_t	t;
3190Sstevel@tonic-gate 	kthread_id_t	first;
3200Sstevel@tonic-gate 	cred_t *oldcr;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	ASSERT(p == curproc);	/* assumes p_lwpcnt can't change */
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	/*
3250Sstevel@tonic-gate 	 * DTrace accesses t_cred in probe context.  t_cred must always be
3260Sstevel@tonic-gate 	 * either NULL, or point to a valid, allocated cred structure.
3270Sstevel@tonic-gate 	 */
3280Sstevel@tonic-gate 	t = curthread;
3290Sstevel@tonic-gate 	oldcr = t->t_cred;
3300Sstevel@tonic-gate 	t->t_cred = cr;		/* the cred is held by caller for this thread */
3310Sstevel@tonic-gate 	crfree(oldcr);		/* free the old cred for the thread */
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	/*
3340Sstevel@tonic-gate 	 * Broadcast to other threads, if any.
3350Sstevel@tonic-gate 	 */
3360Sstevel@tonic-gate 	if (p->p_lwpcnt > 1) {
3370Sstevel@tonic-gate 		mutex_enter(&p->p_lock);	/* to keep thread list safe */
3380Sstevel@tonic-gate 		first = curthread;
3390Sstevel@tonic-gate 		for (t = first->t_forw; t != first; t = t->t_forw)
3400Sstevel@tonic-gate 			t->t_pre_sys = 1; /* so syscall will get new cred */
3410Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate /*
3460Sstevel@tonic-gate  * Put a hold on a cred structure.
3470Sstevel@tonic-gate  */
3480Sstevel@tonic-gate void
3490Sstevel@tonic-gate crhold(cred_t *cr)
3500Sstevel@tonic-gate {
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
3590Sstevel@tonic-gate crfree(cred_t *cr)
3600Sstevel@tonic-gate {
3610Sstevel@tonic-gate 	if (atomic_add_32_nv(&cr->cr_ref, -1) == 0) {
3620Sstevel@tonic-gate 		ASSERT(cr != kcred);
3631676Sjpk 		if (cr->cr_label)
3641676Sjpk 			label_rele(cr->cr_label);
3656134Scasper 		if (cr->cr_klpd)
3666134Scasper 			crklpd_rele(cr->cr_klpd);
3670Sstevel@tonic-gate 		if (cr->cr_zone)
3680Sstevel@tonic-gate 			zone_cred_rele(cr->cr_zone);
3694321Scasper 		if (cr->cr_ksid)
3704321Scasper 			kcrsid_rele(cr->cr_ksid);
37111134SCasper.Dik@Sun.COM 		if (cr->cr_grps)
37211134SCasper.Dik@Sun.COM 			crgrprele(cr->cr_grps);
37311134SCasper.Dik@Sun.COM 
3740Sstevel@tonic-gate 		kmem_cache_free(cred_cache, cr);
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate /*
3790Sstevel@tonic-gate  * Copy a cred structure to a new one and free the old one.
3800Sstevel@tonic-gate  *	The new cred will have two references.  One for the calling process,
3810Sstevel@tonic-gate  * 	and one for the thread.
3820Sstevel@tonic-gate  */
3830Sstevel@tonic-gate cred_t *
3840Sstevel@tonic-gate crcopy(cred_t *cr)
3850Sstevel@tonic-gate {
3860Sstevel@tonic-gate 	cred_t *newcr;
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	newcr = cralloc();
3890Sstevel@tonic-gate 	bcopy(cr, newcr, crsize);
3900Sstevel@tonic-gate 	if (newcr->cr_zone)
3910Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
3921676Sjpk 	if (newcr->cr_label)
3936134Scasper 		label_hold(newcr->cr_label);
3944321Scasper 	if (newcr->cr_ksid)
3956134Scasper 		kcrsid_hold(newcr->cr_ksid);
3966134Scasper 	if (newcr->cr_klpd)
3976134Scasper 		crklpd_hold(newcr->cr_klpd);
39811134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
39911134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
4000Sstevel@tonic-gate 	crfree(cr);
4010Sstevel@tonic-gate 	newcr->cr_ref = 2;		/* caller gets two references */
4020Sstevel@tonic-gate 	return (newcr);
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate /*
4060Sstevel@tonic-gate  * Copy a cred structure to a new one and free the old one.
4070Sstevel@tonic-gate  *	The new cred will have two references.  One for the calling process,
4080Sstevel@tonic-gate  * 	and one for the thread.
4090Sstevel@tonic-gate  * This variation on crcopy uses a pre-allocated structure for the
4100Sstevel@tonic-gate  * "new" cred.
4110Sstevel@tonic-gate  */
4120Sstevel@tonic-gate void
4130Sstevel@tonic-gate crcopy_to(cred_t *oldcr, cred_t *newcr)
4140Sstevel@tonic-gate {
4154321Scasper 	credsid_t *nkcr = newcr->cr_ksid;
4164321Scasper 
4170Sstevel@tonic-gate 	bcopy(oldcr, newcr, crsize);
4180Sstevel@tonic-gate 	if (newcr->cr_zone)
4190Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
4201676Sjpk 	if (newcr->cr_label)
4211676Sjpk 		label_hold(newcr->cr_label);
4226134Scasper 	if (newcr->cr_klpd)
4236134Scasper 		crklpd_hold(newcr->cr_klpd);
42411134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
42511134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
4264321Scasper 	if (nkcr) {
4274321Scasper 		newcr->cr_ksid = nkcr;
4284321Scasper 		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
4294321Scasper 	} else if (newcr->cr_ksid)
4304321Scasper 		kcrsid_hold(newcr->cr_ksid);
4310Sstevel@tonic-gate 	crfree(oldcr);
4320Sstevel@tonic-gate 	newcr->cr_ref = 2;		/* caller gets two references */
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate /*
4360Sstevel@tonic-gate  * Dup a cred struct to a new held one.
4370Sstevel@tonic-gate  *	The old cred is not freed.
4380Sstevel@tonic-gate  */
4396134Scasper static cred_t *
4409710SKen.Powell@Sun.COM crdup_flags(const cred_t *cr, int flgs)
4410Sstevel@tonic-gate {
4420Sstevel@tonic-gate 	cred_t *newcr;
4430Sstevel@tonic-gate 
4446134Scasper 	newcr = cralloc_flags(flgs);
4456134Scasper 
4466134Scasper 	if (newcr == NULL)
4476134Scasper 		return (NULL);
4486134Scasper 
4490Sstevel@tonic-gate 	bcopy(cr, newcr, crsize);
4500Sstevel@tonic-gate 	if (newcr->cr_zone)
4510Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
4521676Sjpk 	if (newcr->cr_label)
4531676Sjpk 		label_hold(newcr->cr_label);
4546134Scasper 	if (newcr->cr_klpd)
4556134Scasper 		crklpd_hold(newcr->cr_klpd);
4564321Scasper 	if (newcr->cr_ksid)
4574321Scasper 		kcrsid_hold(newcr->cr_ksid);
45811134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
45911134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
4600Sstevel@tonic-gate 	newcr->cr_ref = 1;
4610Sstevel@tonic-gate 	return (newcr);
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate 
4646134Scasper cred_t *
4656134Scasper crdup(cred_t *cr)
4666134Scasper {
4676134Scasper 	return (crdup_flags(cr, KM_SLEEP));
4686134Scasper }
4696134Scasper 
4700Sstevel@tonic-gate /*
4710Sstevel@tonic-gate  * Dup a cred struct to a new held one.
4720Sstevel@tonic-gate  *	The old cred is not freed.
4730Sstevel@tonic-gate  * This variation on crdup uses a pre-allocated structure for the
4740Sstevel@tonic-gate  * "new" cred.
4750Sstevel@tonic-gate  */
4760Sstevel@tonic-gate void
4770Sstevel@tonic-gate crdup_to(cred_t *oldcr, cred_t *newcr)
4780Sstevel@tonic-gate {
4794321Scasper 	credsid_t *nkcr = newcr->cr_ksid;
4804321Scasper 
4810Sstevel@tonic-gate 	bcopy(oldcr, newcr, crsize);
4820Sstevel@tonic-gate 	if (newcr->cr_zone)
4830Sstevel@tonic-gate 		zone_cred_hold(newcr->cr_zone);
4841676Sjpk 	if (newcr->cr_label)
4851676Sjpk 		label_hold(newcr->cr_label);
4866134Scasper 	if (newcr->cr_klpd)
4876134Scasper 		crklpd_hold(newcr->cr_klpd);
48811134SCasper.Dik@Sun.COM 	if (newcr->cr_grps)
48911134SCasper.Dik@Sun.COM 		crgrphold(newcr->cr_grps);
4904321Scasper 	if (nkcr) {
4914321Scasper 		newcr->cr_ksid = nkcr;
4924321Scasper 		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
4934321Scasper 	} else if (newcr->cr_ksid)
4944321Scasper 		kcrsid_hold(newcr->cr_ksid);
4950Sstevel@tonic-gate 	newcr->cr_ref = 1;
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate  * Return the (held) credentials for the current running process.
5000Sstevel@tonic-gate  */
5010Sstevel@tonic-gate cred_t *
5021676Sjpk crgetcred(void)
5030Sstevel@tonic-gate {
5040Sstevel@tonic-gate 	cred_t *cr;
5050Sstevel@tonic-gate 	proc_t *p;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	p = ttoproc(curthread);
5080Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
5090Sstevel@tonic-gate 	crhold(cr = p->p_cred);
5100Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
5110Sstevel@tonic-gate 	return (cr);
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate /*
5150Sstevel@tonic-gate  * Backward compatibility check for suser().
5160Sstevel@tonic-gate  * Accounting flag is now set in the policy functions; auditing is
5170Sstevel@tonic-gate  * done through use of privilege in the audit trail.
5180Sstevel@tonic-gate  */
5190Sstevel@tonic-gate int
5200Sstevel@tonic-gate suser(cred_t *cr)
5210Sstevel@tonic-gate {
5220Sstevel@tonic-gate 	return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL)
5230Sstevel@tonic-gate 	    == 0);
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate /*
5270Sstevel@tonic-gate  * Determine whether the supplied group id is a member of the group
5280Sstevel@tonic-gate  * described by the supplied credentials.
5290Sstevel@tonic-gate  */
5300Sstevel@tonic-gate int
5310Sstevel@tonic-gate groupmember(gid_t gid, const cred_t *cr)
5320Sstevel@tonic-gate {
5330Sstevel@tonic-gate 	if (gid == cr->cr_gid)
5340Sstevel@tonic-gate 		return (1);
5350Sstevel@tonic-gate 	return (supgroupmember(gid, cr));
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate /*
5390Sstevel@tonic-gate  * As groupmember but only check against the supplemental groups.
5400Sstevel@tonic-gate  */
5410Sstevel@tonic-gate int
5420Sstevel@tonic-gate supgroupmember(gid_t gid, const cred_t *cr)
5430Sstevel@tonic-gate {
54411134SCasper.Dik@Sun.COM 	int hi, lo;
54511134SCasper.Dik@Sun.COM 	credgrp_t *grps = cr->cr_grps;
5460Sstevel@tonic-gate 	const gid_t *gp, *endgp;
5470Sstevel@tonic-gate 
54811134SCasper.Dik@Sun.COM 	if (grps == NULL)
54911134SCasper.Dik@Sun.COM 		return (0);
55011134SCasper.Dik@Sun.COM 
55111134SCasper.Dik@Sun.COM 	/* For a small number of groups, use sequentials search. */
55211134SCasper.Dik@Sun.COM 	if (grps->crg_ngroups <= BIN_GROUP_SEARCH_CUTOFF) {
55311134SCasper.Dik@Sun.COM 		endgp = &grps->crg_groups[grps->crg_ngroups];
55411134SCasper.Dik@Sun.COM 		for (gp = grps->crg_groups; gp < endgp; gp++)
55511134SCasper.Dik@Sun.COM 			if (*gp == gid)
55611134SCasper.Dik@Sun.COM 				return (1);
55711134SCasper.Dik@Sun.COM 		return (0);
55811134SCasper.Dik@Sun.COM 	}
55911134SCasper.Dik@Sun.COM 
56011134SCasper.Dik@Sun.COM 	/* We use binary search when we have many groups. */
56111134SCasper.Dik@Sun.COM 	lo = 0;
56211134SCasper.Dik@Sun.COM 	hi = grps->crg_ngroups - 1;
56311134SCasper.Dik@Sun.COM 	gp = grps->crg_groups;
56411134SCasper.Dik@Sun.COM 
56511134SCasper.Dik@Sun.COM 	do {
56611134SCasper.Dik@Sun.COM 		int m = (lo + hi) / 2;
56711134SCasper.Dik@Sun.COM 
56811134SCasper.Dik@Sun.COM 		if (gid > gp[m])
56911134SCasper.Dik@Sun.COM 			lo = m + 1;
57011134SCasper.Dik@Sun.COM 		else if (gid < gp[m])
57111134SCasper.Dik@Sun.COM 			hi = m - 1;
57211134SCasper.Dik@Sun.COM 		else
5730Sstevel@tonic-gate 			return (1);
57411134SCasper.Dik@Sun.COM 	} while (lo <= hi);
57511134SCasper.Dik@Sun.COM 
5760Sstevel@tonic-gate 	return (0);
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate /*
5800Sstevel@tonic-gate  * This function is called to check whether the credentials set
5810Sstevel@tonic-gate  * "scrp" has permission to act on credentials set "tcrp".  It enforces the
5820Sstevel@tonic-gate  * permission requirements needed to send a signal to a process.
5830Sstevel@tonic-gate  * The same requirements are imposed by other system calls, however.
5840Sstevel@tonic-gate  *
5850Sstevel@tonic-gate  * The rules are:
5860Sstevel@tonic-gate  * (1) if the credentials are the same, the check succeeds
5870Sstevel@tonic-gate  * (2) if the zone ids don't match, and scrp is not in the global zone or
5880Sstevel@tonic-gate  *     does not have the PRIV_PROC_ZONE privilege, the check fails
5890Sstevel@tonic-gate  * (3) if the real or effective user id of scrp matches the real or saved
5900Sstevel@tonic-gate  *     user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check
5910Sstevel@tonic-gate  *     succeeds
5920Sstevel@tonic-gate  * (4) otherwise, the check fails
5930Sstevel@tonic-gate  */
5940Sstevel@tonic-gate int
5950Sstevel@tonic-gate hasprocperm(const cred_t *tcrp, const cred_t *scrp)
5960Sstevel@tonic-gate {
5970Sstevel@tonic-gate 	if (scrp == tcrp)
5980Sstevel@tonic-gate 		return (1);
5990Sstevel@tonic-gate 	if (scrp->cr_zone != tcrp->cr_zone &&
6000Sstevel@tonic-gate 	    (scrp->cr_zone != global_zone ||
6010Sstevel@tonic-gate 	    secpolicy_proc_zone(scrp) != 0))
6020Sstevel@tonic-gate 		return (0);
6030Sstevel@tonic-gate 	if (scrp->cr_uid == tcrp->cr_ruid ||
6040Sstevel@tonic-gate 	    scrp->cr_ruid == tcrp->cr_ruid ||
6050Sstevel@tonic-gate 	    scrp->cr_uid  == tcrp->cr_suid ||
6060Sstevel@tonic-gate 	    scrp->cr_ruid == tcrp->cr_suid ||
6070Sstevel@tonic-gate 	    !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm"))
6080Sstevel@tonic-gate 		return (1);
6090Sstevel@tonic-gate 	return (0);
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate /*
6130Sstevel@tonic-gate  * This interface replaces hasprocperm; it works like hasprocperm but
6140Sstevel@tonic-gate  * additionally returns success if the proc_t's match
6150Sstevel@tonic-gate  * It is the preferred interface for most uses.
6166134Scasper  * And it will acquire p_crlock itself, so it assert's that it shouldn't
6170Sstevel@tonic-gate  * be held.
6180Sstevel@tonic-gate  */
6190Sstevel@tonic-gate int
6200Sstevel@tonic-gate prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp)
6210Sstevel@tonic-gate {
6220Sstevel@tonic-gate 	int rets;
6230Sstevel@tonic-gate 	cred_t *tcrp;
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&tp->p_crlock));
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	if (tp == sp)
6280Sstevel@tonic-gate 		return (1);
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0)
6310Sstevel@tonic-gate 		return (0);
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	mutex_enter(&tp->p_crlock);
6346134Scasper 	crhold(tcrp = tp->p_cred);
6356134Scasper 	mutex_exit(&tp->p_crlock);
6360Sstevel@tonic-gate 	rets = hasprocperm(tcrp, scrp);
6376134Scasper 	crfree(tcrp);
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	return (rets);
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate /*
6430Sstevel@tonic-gate  * This routine is used to compare two credentials to determine if
6440Sstevel@tonic-gate  * they refer to the same "user".  If the pointers are equal, then
6450Sstevel@tonic-gate  * they must refer to the same user.  Otherwise, the contents of
6460Sstevel@tonic-gate  * the credentials are compared to see whether they are equivalent.
6470Sstevel@tonic-gate  *
6480Sstevel@tonic-gate  * This routine returns 0 if the credentials refer to the same user,
6490Sstevel@tonic-gate  * 1 if they do not.
6500Sstevel@tonic-gate  */
6510Sstevel@tonic-gate int
6520Sstevel@tonic-gate crcmp(const cred_t *cr1, const cred_t *cr2)
6530Sstevel@tonic-gate {
65411134SCasper.Dik@Sun.COM 	credgrp_t *grp1, *grp2;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	if (cr1 == cr2)
6570Sstevel@tonic-gate 		return (0);
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	if (cr1->cr_uid == cr2->cr_uid &&
6600Sstevel@tonic-gate 	    cr1->cr_gid == cr2->cr_gid &&
6610Sstevel@tonic-gate 	    cr1->cr_ruid == cr2->cr_ruid &&
6620Sstevel@tonic-gate 	    cr1->cr_rgid == cr2->cr_rgid &&
6630Sstevel@tonic-gate 	    cr1->cr_zone == cr2->cr_zone &&
66411134SCasper.Dik@Sun.COM 	    ((grp1 = cr1->cr_grps) == (grp2 = cr2->cr_grps) ||
66511134SCasper.Dik@Sun.COM 	    (grp1 != NULL && grp2 != NULL &&
66611134SCasper.Dik@Sun.COM 	    grp1->crg_ngroups == grp2->crg_ngroups &&
66711134SCasper.Dik@Sun.COM 	    bcmp(grp1->crg_groups, grp2->crg_groups,
66811134SCasper.Dik@Sun.COM 	    grp1->crg_ngroups * sizeof (gid_t)) == 0))) {
6690Sstevel@tonic-gate 		return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2)));
6700Sstevel@tonic-gate 	}
6710Sstevel@tonic-gate 	return (1);
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate /*
6750Sstevel@tonic-gate  * Read access functions to cred_t.
6760Sstevel@tonic-gate  */
6770Sstevel@tonic-gate uid_t
6780Sstevel@tonic-gate crgetuid(const cred_t *cr)
6790Sstevel@tonic-gate {
6800Sstevel@tonic-gate 	return (cr->cr_uid);
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate uid_t
6840Sstevel@tonic-gate crgetruid(const cred_t *cr)
6850Sstevel@tonic-gate {
6860Sstevel@tonic-gate 	return (cr->cr_ruid);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate uid_t
6900Sstevel@tonic-gate crgetsuid(const cred_t *cr)
6910Sstevel@tonic-gate {
6920Sstevel@tonic-gate 	return (cr->cr_suid);
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate gid_t
6960Sstevel@tonic-gate crgetgid(const cred_t *cr)
6970Sstevel@tonic-gate {
6980Sstevel@tonic-gate 	return (cr->cr_gid);
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate gid_t
7020Sstevel@tonic-gate crgetrgid(const cred_t *cr)
7030Sstevel@tonic-gate {
7040Sstevel@tonic-gate 	return (cr->cr_rgid);
7050Sstevel@tonic-gate }
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate gid_t
7080Sstevel@tonic-gate crgetsgid(const cred_t *cr)
7090Sstevel@tonic-gate {
7100Sstevel@tonic-gate 	return (cr->cr_sgid);
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate const auditinfo_addr_t *
7140Sstevel@tonic-gate crgetauinfo(const cred_t *cr)
7150Sstevel@tonic-gate {
7160Sstevel@tonic-gate 	return ((const auditinfo_addr_t *)CR_AUINFO(cr));
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate auditinfo_addr_t *
7200Sstevel@tonic-gate crgetauinfo_modifiable(cred_t *cr)
7210Sstevel@tonic-gate {
7220Sstevel@tonic-gate 	return (CR_AUINFO(cr));
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate zoneid_t
7260Sstevel@tonic-gate crgetzoneid(const cred_t *cr)
7270Sstevel@tonic-gate {
7281676Sjpk 	return (cr->cr_zone == NULL ?
7291676Sjpk 	    (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) :
7301676Sjpk 	    cr->cr_zone->zone_id);
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate projid_t
7340Sstevel@tonic-gate crgetprojid(const cred_t *cr)
7350Sstevel@tonic-gate {
7360Sstevel@tonic-gate 	return (cr->cr_projid);
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate 
7391676Sjpk zone_t *
7401676Sjpk crgetzone(const cred_t *cr)
7411676Sjpk {
7421676Sjpk 	return (cr->cr_zone);
7431676Sjpk }
7441676Sjpk 
7451676Sjpk struct ts_label_s *
7461676Sjpk crgetlabel(const cred_t *cr)
7471676Sjpk {
7481676Sjpk 	return (cr->cr_label ?
7491676Sjpk 	    cr->cr_label :
7501676Sjpk 	    (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL));
7511676Sjpk }
7521676Sjpk 
7531676Sjpk boolean_t
7541676Sjpk crisremote(const cred_t *cr)
7551676Sjpk {
7561676Sjpk 	return (REMOTE_PEER_CRED(cr));
7571676Sjpk }
7581676Sjpk 
7595771Sjp151216 #define	BADUID(x, zn)	((x) != -1 && !VALID_UID((x), (zn)))
7605771Sjp151216 #define	BADGID(x, zn)	((x) != -1 && !VALID_GID((x), (zn)))
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate int
7630Sstevel@tonic-gate crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s)
7640Sstevel@tonic-gate {
7655771Sjp151216 	zone_t	*zone = crgetzone(cr);
7665771Sjp151216 
7670Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
7680Sstevel@tonic-gate 
7695771Sjp151216 	if (BADUID(r, zone) || BADUID(e, zone) || BADUID(s, zone))
7700Sstevel@tonic-gate 		return (-1);
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	if (r != -1)
7730Sstevel@tonic-gate 		cr->cr_ruid = r;
7740Sstevel@tonic-gate 	if (e != -1)
7750Sstevel@tonic-gate 		cr->cr_uid = e;
7760Sstevel@tonic-gate 	if (s != -1)
7770Sstevel@tonic-gate 		cr->cr_suid = s;
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	return (0);
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate int
7830Sstevel@tonic-gate crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s)
7840Sstevel@tonic-gate {
7855771Sjp151216 	zone_t	*zone = crgetzone(cr);
7865771Sjp151216 
7870Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
7880Sstevel@tonic-gate 
7895771Sjp151216 	if (BADGID(r, zone) || BADGID(e, zone) || BADGID(s, zone))
7900Sstevel@tonic-gate 		return (-1);
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	if (r != -1)
7930Sstevel@tonic-gate 		cr->cr_rgid = r;
7940Sstevel@tonic-gate 	if (e != -1)
7950Sstevel@tonic-gate 		cr->cr_gid = e;
7960Sstevel@tonic-gate 	if (s != -1)
7970Sstevel@tonic-gate 		cr->cr_sgid = s;
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	return (0);
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate int
8030Sstevel@tonic-gate crsetugid(cred_t *cr, uid_t uid, gid_t gid)
8040Sstevel@tonic-gate {
8055771Sjp151216 	zone_t	*zone = crgetzone(cr);
8065771Sjp151216 
8070Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
8080Sstevel@tonic-gate 
8095771Sjp151216 	if (!VALID_UID(uid, zone) || !VALID_GID(gid, zone))
8100Sstevel@tonic-gate 		return (-1);
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid;
8130Sstevel@tonic-gate 	cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid;
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	return (0);
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate 
81811134SCasper.Dik@Sun.COM static int
81911134SCasper.Dik@Sun.COM gidcmp(const void *v1, const void *v2)
82011134SCasper.Dik@Sun.COM {
82111134SCasper.Dik@Sun.COM 	gid_t g1 = *(gid_t *)v1;
82211134SCasper.Dik@Sun.COM 	gid_t g2 = *(gid_t *)v2;
82311134SCasper.Dik@Sun.COM 
82411134SCasper.Dik@Sun.COM 	if (g1 < g2)
82511134SCasper.Dik@Sun.COM 		return (-1);
82611134SCasper.Dik@Sun.COM 	else if (g1 > g2)
82711134SCasper.Dik@Sun.COM 		return (1);
82811134SCasper.Dik@Sun.COM 	else
82911134SCasper.Dik@Sun.COM 		return (0);
83011134SCasper.Dik@Sun.COM }
83111134SCasper.Dik@Sun.COM 
8320Sstevel@tonic-gate int
8330Sstevel@tonic-gate crsetgroups(cred_t *cr, int n, gid_t *grp)
8340Sstevel@tonic-gate {
8350Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	if (n > ngroups_max || n < 0)
8380Sstevel@tonic-gate 		return (-1);
8390Sstevel@tonic-gate 
84011134SCasper.Dik@Sun.COM 	if (cr->cr_grps != NULL)
84111134SCasper.Dik@Sun.COM 		crgrprele(cr->cr_grps);
8420Sstevel@tonic-gate 
84311134SCasper.Dik@Sun.COM 	if (n > 0) {
84411134SCasper.Dik@Sun.COM 		cr->cr_grps = kmem_alloc(CREDGRPSZ(n), KM_SLEEP);
84511134SCasper.Dik@Sun.COM 		bcopy(grp, cr->cr_grps->crg_groups, n * sizeof (gid_t));
84611134SCasper.Dik@Sun.COM 		cr->cr_grps->crg_ref = 1;
84711134SCasper.Dik@Sun.COM 		cr->cr_grps->crg_ngroups = n;
84811134SCasper.Dik@Sun.COM 		qsort(cr->cr_grps->crg_groups, n, sizeof (gid_t), gidcmp);
84911134SCasper.Dik@Sun.COM 	} else {
85011134SCasper.Dik@Sun.COM 		cr->cr_grps = NULL;
85111134SCasper.Dik@Sun.COM 	}
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	return (0);
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate void
8570Sstevel@tonic-gate crsetprojid(cred_t *cr, projid_t projid)
8580Sstevel@tonic-gate {
8590Sstevel@tonic-gate 	ASSERT(projid >= 0 && projid <= MAXPROJID);
8600Sstevel@tonic-gate 	cr->cr_projid = projid;
8610Sstevel@tonic-gate }
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate /*
86411134SCasper.Dik@Sun.COM  * This routine returns the pointer to the first element of the crg_groups
8650Sstevel@tonic-gate  * array.  It can move around in an implementation defined way.
86611134SCasper.Dik@Sun.COM  * Note that when we have no grouplist, we return one element but the
86711134SCasper.Dik@Sun.COM  * caller should never reference it.
8680Sstevel@tonic-gate  */
8690Sstevel@tonic-gate const gid_t *
8700Sstevel@tonic-gate crgetgroups(const cred_t *cr)
8710Sstevel@tonic-gate {
87211134SCasper.Dik@Sun.COM 	return (cr->cr_grps == NULL ? &cr->cr_gid : cr->cr_grps->crg_groups);
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate int
8760Sstevel@tonic-gate crgetngroups(const cred_t *cr)
8770Sstevel@tonic-gate {
87811134SCasper.Dik@Sun.COM 	return (cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups);
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate void
8820Sstevel@tonic-gate cred2prcred(const cred_t *cr, prcred_t *pcrp)
8830Sstevel@tonic-gate {
8840Sstevel@tonic-gate 	pcrp->pr_euid = cr->cr_uid;
8850Sstevel@tonic-gate 	pcrp->pr_ruid = cr->cr_ruid;
8860Sstevel@tonic-gate 	pcrp->pr_suid = cr->cr_suid;
8870Sstevel@tonic-gate 	pcrp->pr_egid = cr->cr_gid;
8880Sstevel@tonic-gate 	pcrp->pr_rgid = cr->cr_rgid;
8890Sstevel@tonic-gate 	pcrp->pr_sgid = cr->cr_sgid;
89011134SCasper.Dik@Sun.COM 	pcrp->pr_groups[0] = 0; /* in case ngroups == 0 */
89111134SCasper.Dik@Sun.COM 	pcrp->pr_ngroups = cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups;
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	if (pcrp->pr_ngroups != 0)
89411134SCasper.Dik@Sun.COM 		bcopy(cr->cr_grps->crg_groups, pcrp->pr_groups,
89511134SCasper.Dik@Sun.COM 		    sizeof (gid_t) * pcrp->pr_ngroups);
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate static int
8991676Sjpk cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr)
9000Sstevel@tonic-gate {
9010Sstevel@tonic-gate 	auditinfo_addr_t	*ai;
9020Sstevel@tonic-gate 	au_tid_addr_t	tid;
9030Sstevel@tonic-gate 
9041676Sjpk 	if (secpolicy_audit_getattr(rcr) != 0)
9050Sstevel@tonic-gate 		return (-1);
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	ai = CR_AUINFO(cr);	/* caller makes sure this is non-NULL */
9080Sstevel@tonic-gate 	tid = ai->ai_termid;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	ainfo->ai_auid = ai->ai_auid;
9110Sstevel@tonic-gate 	ainfo->ai_mask = ai->ai_mask;
9120Sstevel@tonic-gate 	ainfo->ai_asid = ai->ai_asid;
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	ainfo->ai_termid.at_type = tid.at_type;
9150Sstevel@tonic-gate 	bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t));
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port);
9180Sstevel@tonic-gate 	ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port);
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	return (0);
9210Sstevel@tonic-gate }
9220Sstevel@tonic-gate 
9231676Sjpk void
9241676Sjpk cred2uclabel(const cred_t *cr, bslabel_t *labelp)
9251676Sjpk {
9261676Sjpk 	ts_label_t	*tslp;
9271676Sjpk 
9281676Sjpk 	if ((tslp = crgetlabel(cr)) != NULL)
9291676Sjpk 		bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t));
9301676Sjpk }
9311676Sjpk 
9320Sstevel@tonic-gate /*
9330Sstevel@tonic-gate  * Convert a credential into a "ucred".  Allow the caller to specify
9340Sstevel@tonic-gate  * and aligned buffer, e.g., in an mblk, so we don't have to allocate
9350Sstevel@tonic-gate  * memory and copy it twice.
9361676Sjpk  *
9371676Sjpk  * This function may call cred2ucaud(), which calls CRED(). Since this
9381676Sjpk  * can be called from an interrupt thread, receiver's cred (rcr) is needed
9391676Sjpk  * to determine whether audit info should be included.
9400Sstevel@tonic-gate  */
9410Sstevel@tonic-gate struct ucred_s *
9421676Sjpk cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr)
9430Sstevel@tonic-gate {
9440Sstevel@tonic-gate 	struct ucred_s *uc;
94511134SCasper.Dik@Sun.COM 	uint32_t realsz = ucredminsize(cr);
94611134SCasper.Dik@Sun.COM 	ts_label_t *tslp = is_system_labeled() ? crgetlabel(cr) : NULL;
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	/* The structure isn't always completely filled in, so zero it */
9490Sstevel@tonic-gate 	if (buf == NULL) {
95011134SCasper.Dik@Sun.COM 		uc = kmem_zalloc(realsz, KM_SLEEP);
9510Sstevel@tonic-gate 	} else {
95211134SCasper.Dik@Sun.COM 		bzero(buf, realsz);
9530Sstevel@tonic-gate 		uc = buf;
9540Sstevel@tonic-gate 	}
95511134SCasper.Dik@Sun.COM 	uc->uc_size = realsz;
9560Sstevel@tonic-gate 	uc->uc_pid = pid;
9570Sstevel@tonic-gate 	uc->uc_projid = cr->cr_projid;
9580Sstevel@tonic-gate 	uc->uc_zoneid = crgetzoneid(cr);
9590Sstevel@tonic-gate 
9601676Sjpk 	if (REMOTE_PEER_CRED(cr)) {
9611676Sjpk 		/*
96211134SCasper.Dik@Sun.COM 		 * Other than label, the rest of cred info about a
96311134SCasper.Dik@Sun.COM 		 * remote peer isn't available. Copy the label directly
96411134SCasper.Dik@Sun.COM 		 * after the header where we generally copy the prcred.
96511134SCasper.Dik@Sun.COM 		 * That's why we use sizeof (struct ucred_s).  The other
96611134SCasper.Dik@Sun.COM 		 * offset fields are initialized to 0.
9671676Sjpk 		 */
96811134SCasper.Dik@Sun.COM 		uc->uc_labeloff = tslp == NULL ? 0 : sizeof (struct ucred_s);
9691676Sjpk 	} else {
97011134SCasper.Dik@Sun.COM 		uc->uc_credoff = UCRED_CRED_OFF;
97111134SCasper.Dik@Sun.COM 		uc->uc_privoff = UCRED_PRIV_OFF;
97211134SCasper.Dik@Sun.COM 		uc->uc_audoff = UCRED_AUD_OFF;
97311134SCasper.Dik@Sun.COM 		uc->uc_labeloff = tslp == NULL ? 0 : UCRED_LABEL_OFF;
97411134SCasper.Dik@Sun.COM 
9751676Sjpk 		cred2prcred(cr, UCCRED(uc));
9761676Sjpk 		cred2prpriv(cr, UCPRIV(uc));
97711134SCasper.Dik@Sun.COM 
9781676Sjpk 		if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0)
9791676Sjpk 			uc->uc_audoff = 0;
98011134SCasper.Dik@Sun.COM 	}
98111134SCasper.Dik@Sun.COM 	if (tslp != NULL)
98211134SCasper.Dik@Sun.COM 		bcopy(&tslp->tsl_label, UCLABEL(uc), sizeof (bslabel_t));
98311134SCasper.Dik@Sun.COM 
98411134SCasper.Dik@Sun.COM 	return (uc);
98511134SCasper.Dik@Sun.COM }
98611134SCasper.Dik@Sun.COM 
98711134SCasper.Dik@Sun.COM /*
98811134SCasper.Dik@Sun.COM  * Don't allocate the non-needed group entries.  Note: this function
98911134SCasper.Dik@Sun.COM  * must match the code in cred2ucred; they must agree about the
99011134SCasper.Dik@Sun.COM  * minimal size of the ucred.
99111134SCasper.Dik@Sun.COM  */
99211134SCasper.Dik@Sun.COM uint32_t
99311134SCasper.Dik@Sun.COM ucredminsize(const cred_t *cr)
99411134SCasper.Dik@Sun.COM {
99511134SCasper.Dik@Sun.COM 	int ndiff;
99611134SCasper.Dik@Sun.COM 
99711134SCasper.Dik@Sun.COM 	if (cr == NULL)
99811134SCasper.Dik@Sun.COM 		return (ucredsize);
99911134SCasper.Dik@Sun.COM 
100011134SCasper.Dik@Sun.COM 	if (REMOTE_PEER_CRED(cr)) {
100111134SCasper.Dik@Sun.COM 		if (is_system_labeled())
100211134SCasper.Dik@Sun.COM 			return (sizeof (struct ucred_s) + sizeof (bslabel_t));
100311134SCasper.Dik@Sun.COM 		else
100411134SCasper.Dik@Sun.COM 			return (sizeof (struct ucred_s));
10051676Sjpk 	}
10060Sstevel@tonic-gate 
100711134SCasper.Dik@Sun.COM 	if (cr->cr_grps == NULL)
100811134SCasper.Dik@Sun.COM 		ndiff = ngroups_max - 1;	/* Needs one for prcred_t */
100911134SCasper.Dik@Sun.COM 	else
101011134SCasper.Dik@Sun.COM 		ndiff = ngroups_max - cr->cr_grps->crg_ngroups;
101111134SCasper.Dik@Sun.COM 
101211134SCasper.Dik@Sun.COM 	return (ucredsize - ndiff * sizeof (gid_t));
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate /*
10160Sstevel@tonic-gate  * Get the "ucred" of a process.
10170Sstevel@tonic-gate  */
10180Sstevel@tonic-gate struct ucred_s *
10190Sstevel@tonic-gate pgetucred(proc_t *p)
10200Sstevel@tonic-gate {
10210Sstevel@tonic-gate 	cred_t *cr;
10220Sstevel@tonic-gate 	struct ucred_s *uc;
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
10250Sstevel@tonic-gate 	cr = p->p_cred;
10260Sstevel@tonic-gate 	crhold(cr);
10270Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
10280Sstevel@tonic-gate 
10291676Sjpk 	uc = cred2ucred(cr, p->p_pid, NULL, CRED());
10300Sstevel@tonic-gate 	crfree(cr);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	return (uc);
10330Sstevel@tonic-gate }
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate /*
10360Sstevel@tonic-gate  * If the reply status is NFSERR_EACCES, it may be because we are
10370Sstevel@tonic-gate  * root (no root net access).  Check the real uid, if it isn't root
10380Sstevel@tonic-gate  * make that the uid instead and retry the call.
10390Sstevel@tonic-gate  * Private interface for NFS.
10400Sstevel@tonic-gate  */
10410Sstevel@tonic-gate cred_t *
10420Sstevel@tonic-gate crnetadjust(cred_t *cr)
10430Sstevel@tonic-gate {
10440Sstevel@tonic-gate 	if (cr->cr_uid == 0 && cr->cr_ruid != 0) {
10450Sstevel@tonic-gate 		cr = crdup(cr);
10460Sstevel@tonic-gate 		cr->cr_uid = cr->cr_ruid;
10470Sstevel@tonic-gate 		return (cr);
10480Sstevel@tonic-gate 	}
10490Sstevel@tonic-gate 	return (NULL);
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate /*
10530Sstevel@tonic-gate  * The reference count is of interest when you want to check
10540Sstevel@tonic-gate  * whether it is ok to modify the credential in place.
10550Sstevel@tonic-gate  */
10560Sstevel@tonic-gate uint_t
10570Sstevel@tonic-gate crgetref(const cred_t *cr)
10580Sstevel@tonic-gate {
10590Sstevel@tonic-gate 	return (cr->cr_ref);
10600Sstevel@tonic-gate }
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate static int
10630Sstevel@tonic-gate get_c2audit_load(void)
10640Sstevel@tonic-gate {
10650Sstevel@tonic-gate 	static int	gotit = 0;
10660Sstevel@tonic-gate 	static int	c2audit_load;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	if (gotit)
10690Sstevel@tonic-gate 		return (c2audit_load);
1070*11861SMarek.Pospisil@Sun.COM 	c2audit_load = 1;		/* set default value once */
1071*11861SMarek.Pospisil@Sun.COM 	if (mod_sysctl(SYS_CHECK_EXCLUDE, "c2audit") != 0)
1072*11861SMarek.Pospisil@Sun.COM 		c2audit_load = 0;
10730Sstevel@tonic-gate 	gotit++;
1074*11861SMarek.Pospisil@Sun.COM 
10750Sstevel@tonic-gate 	return (c2audit_load);
10760Sstevel@tonic-gate }
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate int
10790Sstevel@tonic-gate get_audit_ucrsize(void)
10800Sstevel@tonic-gate {
10810Sstevel@tonic-gate 	return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0);
10820Sstevel@tonic-gate }
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate /*
10850Sstevel@tonic-gate  * Set zone pointer in credential to indicated value.  First adds a
10860Sstevel@tonic-gate  * hold for the new zone, then drops the hold on previous zone (if any).
10870Sstevel@tonic-gate  * This is done in this order in case the old and new zones are the
10880Sstevel@tonic-gate  * same.
10890Sstevel@tonic-gate  */
10900Sstevel@tonic-gate void
10910Sstevel@tonic-gate crsetzone(cred_t *cr, zone_t *zptr)
10920Sstevel@tonic-gate {
10930Sstevel@tonic-gate 	zone_t *oldzptr = cr->cr_zone;
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 	ASSERT(cr != kcred);
10960Sstevel@tonic-gate 	ASSERT(cr->cr_ref <= 2);
10970Sstevel@tonic-gate 	cr->cr_zone = zptr;
10980Sstevel@tonic-gate 	zone_cred_hold(zptr);
10990Sstevel@tonic-gate 	if (oldzptr)
11000Sstevel@tonic-gate 		zone_cred_rele(oldzptr);
11010Sstevel@tonic-gate }
11021676Sjpk 
11031676Sjpk /*
11041676Sjpk  * Create a new cred based on the supplied label
11051676Sjpk  */
11061676Sjpk cred_t *
11071676Sjpk newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags)
11081676Sjpk {
11091676Sjpk 	ts_label_t *lbl = labelalloc(blabel, doi, flags);
11101676Sjpk 	cred_t *cr = NULL;
11111676Sjpk 
11121676Sjpk 	if (lbl != NULL) {
11136134Scasper 		if ((cr = crdup_flags(dummycr, flags)) != NULL) {
11141676Sjpk 			cr->cr_label = lbl;
11151676Sjpk 		} else {
11161676Sjpk 			label_rele(lbl);
11171676Sjpk 		}
11181676Sjpk 	}
11191676Sjpk 
11201676Sjpk 	return (cr);
11211676Sjpk }
11221676Sjpk 
11231676Sjpk /*
11241676Sjpk  * Derive a new cred from the existing cred, but with a different label.
11251676Sjpk  * To be used when a cred is being shared, but the label needs to be changed
11261676Sjpk  * by a caller without affecting other users
11271676Sjpk  */
11281676Sjpk cred_t *
11299710SKen.Powell@Sun.COM copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags)
11309710SKen.Powell@Sun.COM {
11319710SKen.Powell@Sun.COM 	cred_t *newcr = NULL;
11329710SKen.Powell@Sun.COM 
11339710SKen.Powell@Sun.COM 	if ((newcr = crdup_flags(cr, flags)) != NULL) {
11349710SKen.Powell@Sun.COM 		if (newcr->cr_label != NULL)
11359710SKen.Powell@Sun.COM 			label_rele(newcr->cr_label);
11369710SKen.Powell@Sun.COM 		label_hold(label);
11379710SKen.Powell@Sun.COM 		newcr->cr_label = label;
11389710SKen.Powell@Sun.COM 	}
11399710SKen.Powell@Sun.COM 
11409710SKen.Powell@Sun.COM 	return (newcr);
11419710SKen.Powell@Sun.COM }
11429710SKen.Powell@Sun.COM 
11439710SKen.Powell@Sun.COM /*
11449710SKen.Powell@Sun.COM  * Derive a new cred from the existing cred, but with a different label.
11459710SKen.Powell@Sun.COM  */
11469710SKen.Powell@Sun.COM cred_t *
11479710SKen.Powell@Sun.COM copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel,
11489710SKen.Powell@Sun.COM     uint32_t doi, int flags)
11491676Sjpk {
11501676Sjpk 	ts_label_t *lbl = labelalloc(blabel, doi, flags);
11519710SKen.Powell@Sun.COM 	cred_t  *newcr = NULL;
11521676Sjpk 
11531676Sjpk 	if (lbl != NULL) {
11549710SKen.Powell@Sun.COM 		newcr = copycred_from_tslabel(cr, lbl, flags);
11559710SKen.Powell@Sun.COM 		label_rele(lbl);
11561676Sjpk 	}
11571676Sjpk 
11581676Sjpk 	return (newcr);
11591676Sjpk }
11601676Sjpk 
11611676Sjpk /*
11621676Sjpk  * This function returns a pointer to the kcred-equivalent in the current zone.
11631676Sjpk  */
11641676Sjpk cred_t *
11651676Sjpk zone_kcred(void)
11661676Sjpk {
11671676Sjpk 	zone_t *zone;
11681676Sjpk 
11691676Sjpk 	if ((zone = CRED()->cr_zone) != NULL)
11701676Sjpk 		return (zone->zone_kcred);
11711676Sjpk 	else
11721676Sjpk 		return (kcred);
11731676Sjpk }
11744321Scasper 
11754321Scasper boolean_t
11765771Sjp151216 valid_ephemeral_uid(zone_t *zone, uid_t id)
11774321Scasper {
11785771Sjp151216 	ephemeral_zsd_t *eph_zsd;
11795908Sjp151216 	if (id <= IDMAP_WK__MAX_UID)
11805771Sjp151216 		return (B_TRUE);
11815771Sjp151216 
11825771Sjp151216 	eph_zsd = get_ephemeral_zsd(zone);
11835771Sjp151216 	ASSERT(eph_zsd != NULL);
11844321Scasper 	membar_consumer();
11855771Sjp151216 	return (id > eph_zsd->min_uid && id <= eph_zsd->last_uid);
11864321Scasper }
11874321Scasper 
11884321Scasper boolean_t
11895771Sjp151216 valid_ephemeral_gid(zone_t *zone, gid_t id)
11904321Scasper {
11915771Sjp151216 	ephemeral_zsd_t *eph_zsd;
11925908Sjp151216 	if (id <= IDMAP_WK__MAX_GID)
11935771Sjp151216 		return (B_TRUE);
11945771Sjp151216 
11955771Sjp151216 	eph_zsd = get_ephemeral_zsd(zone);
11965771Sjp151216 	ASSERT(eph_zsd != NULL);
11974321Scasper 	membar_consumer();
11985771Sjp151216 	return (id > eph_zsd->min_gid && id <= eph_zsd->last_gid);
11994321Scasper }
12004321Scasper 
12014321Scasper int
12025771Sjp151216 eph_uid_alloc(zone_t *zone, int flags, uid_t *start, int count)
12034321Scasper {
12045771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12055771Sjp151216 
12065771Sjp151216 	ASSERT(eph_zsd != NULL);
12075771Sjp151216 
12085771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12094321Scasper 
12104321Scasper 	/* Test for unsigned integer wrap around */
12115771Sjp151216 	if (eph_zsd->last_uid + count < eph_zsd->last_uid) {
12125771Sjp151216 		mutex_exit(&eph_zsd->eph_lock);
12134321Scasper 		return (-1);
12144321Scasper 	}
12154321Scasper 
12164321Scasper 	/* first call or idmap crashed and state corrupted */
12174321Scasper 	if (flags != 0)
12185771Sjp151216 		eph_zsd->min_uid = eph_zsd->last_uid;
12194321Scasper 
12204321Scasper 	hasephids = B_TRUE;
12215771Sjp151216 	*start = eph_zsd->last_uid + 1;
12225771Sjp151216 	atomic_add_32(&eph_zsd->last_uid, count);
12235771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12244321Scasper 	return (0);
12254321Scasper }
12264321Scasper 
12274321Scasper int
12285771Sjp151216 eph_gid_alloc(zone_t *zone, int flags, gid_t *start, int count)
12294321Scasper {
12305771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12315771Sjp151216 
12325771Sjp151216 	ASSERT(eph_zsd != NULL);
12335771Sjp151216 
12345771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12354321Scasper 
12364321Scasper 	/* Test for unsigned integer wrap around */
12375771Sjp151216 	if (eph_zsd->last_gid + count < eph_zsd->last_gid) {
12385771Sjp151216 		mutex_exit(&eph_zsd->eph_lock);
12394321Scasper 		return (-1);
12404321Scasper 	}
12414321Scasper 
12424321Scasper 	/* first call or idmap crashed and state corrupted */
12434321Scasper 	if (flags != 0)
12445771Sjp151216 		eph_zsd->min_gid = eph_zsd->last_gid;
12454321Scasper 
12464321Scasper 	hasephids = B_TRUE;
12475771Sjp151216 	*start = eph_zsd->last_gid + 1;
12485771Sjp151216 	atomic_add_32(&eph_zsd->last_gid, count);
12495771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12504321Scasper 	return (0);
12514321Scasper }
12524321Scasper 
12534321Scasper /*
12545771Sjp151216  * IMPORTANT.The two functions get_ephemeral_data() and set_ephemeral_data()
12555771Sjp151216  * are project private functions that are for use of the test system only and
12565771Sjp151216  * are not to be used for other purposes.
12575771Sjp151216  */
12585771Sjp151216 
12595771Sjp151216 void
12605771Sjp151216 get_ephemeral_data(zone_t *zone, uid_t *min_uid, uid_t *last_uid,
12615771Sjp151216 	gid_t *min_gid, gid_t *last_gid)
12625771Sjp151216 {
12635771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12645771Sjp151216 
12655771Sjp151216 	ASSERT(eph_zsd != NULL);
12665771Sjp151216 
12675771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12685771Sjp151216 
12695771Sjp151216 	*min_uid = eph_zsd->min_uid;
12705771Sjp151216 	*last_uid = eph_zsd->last_uid;
12715771Sjp151216 	*min_gid = eph_zsd->min_gid;
12725771Sjp151216 	*last_gid = eph_zsd->last_gid;
12735771Sjp151216 
12745771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12755771Sjp151216 }
12765771Sjp151216 
12775771Sjp151216 
12785771Sjp151216 void
12795771Sjp151216 set_ephemeral_data(zone_t *zone, uid_t min_uid, uid_t last_uid,
12805771Sjp151216 	gid_t min_gid, gid_t last_gid)
12815771Sjp151216 {
12825771Sjp151216 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12835771Sjp151216 
12845771Sjp151216 	ASSERT(eph_zsd != NULL);
12855771Sjp151216 
12865771Sjp151216 	mutex_enter(&eph_zsd->eph_lock);
12875771Sjp151216 
12885771Sjp151216 	if (min_uid != 0)
12895771Sjp151216 		eph_zsd->min_uid = min_uid;
12905771Sjp151216 	if (last_uid != 0)
12915771Sjp151216 		eph_zsd->last_uid = last_uid;
12925771Sjp151216 	if (min_gid != 0)
12935771Sjp151216 		eph_zsd->min_gid = min_gid;
12945771Sjp151216 	if (last_gid != 0)
12955771Sjp151216 		eph_zsd->last_gid = last_gid;
12965771Sjp151216 
12975771Sjp151216 	mutex_exit(&eph_zsd->eph_lock);
12985771Sjp151216 }
12995771Sjp151216 
13005771Sjp151216 /*
13015331Samw  * If the credential user SID or group SID is mapped to an ephemeral
13025331Samw  * ID, map the credential to nobody.
13034321Scasper  */
13044321Scasper cred_t *
13054321Scasper crgetmapped(const cred_t *cr)
13064321Scasper {
13075771Sjp151216 	ephemeral_zsd_t *eph_zsd;
13084406Scasper 	/*
13094406Scasper 	 * Someone incorrectly passed a NULL cred to a vnode operation
13104406Scasper 	 * either on purpose or by calling CRED() in interrupt context.
13114406Scasper 	 */
13124406Scasper 	if (cr == NULL)
13134406Scasper 		return (NULL);
13144406Scasper 
13154321Scasper 	if (cr->cr_ksid != NULL) {
13165771Sjp151216 		if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID) {
13175771Sjp151216 			eph_zsd = get_ephemeral_zsd(crgetzone(cr));
13185771Sjp151216 			return (eph_zsd->eph_nobody);
13195771Sjp151216 		}
13204321Scasper 
13215771Sjp151216 		if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID) {
13225771Sjp151216 			eph_zsd = get_ephemeral_zsd(crgetzone(cr));
13235771Sjp151216 			return (eph_zsd->eph_nobody);
13245771Sjp151216 		}
13254321Scasper 	}
13264321Scasper 
13274321Scasper 	return ((cred_t *)cr);
13284321Scasper }
13294321Scasper 
13304321Scasper /* index should be in range for a ksidindex_t */
13314321Scasper void
13324321Scasper crsetsid(cred_t *cr, ksid_t *ksp, int index)
13334321Scasper {
13344321Scasper 	ASSERT(cr->cr_ref <= 2);
13354321Scasper 	ASSERT(index >= 0 && index < KSID_COUNT);
13364321Scasper 	if (cr->cr_ksid == NULL && ksp == NULL)
13374321Scasper 		return;
13384321Scasper 	cr->cr_ksid = kcrsid_setsid(cr->cr_ksid, ksp, index);
13394321Scasper }
13404321Scasper 
13414321Scasper void
13424321Scasper crsetsidlist(cred_t *cr, ksidlist_t *ksl)
13434321Scasper {
13444321Scasper 	ASSERT(cr->cr_ref <= 2);
13454321Scasper 	if (cr->cr_ksid == NULL && ksl == NULL)
13464321Scasper 		return;
13474321Scasper 	cr->cr_ksid = kcrsid_setsidlist(cr->cr_ksid, ksl);
13484321Scasper }
13494321Scasper 
13504321Scasper ksid_t *
13514321Scasper crgetsid(const cred_t *cr, int i)
13524321Scasper {
13534321Scasper 	ASSERT(i >= 0 && i < KSID_COUNT);
13544321Scasper 	if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidx[i].ks_domain)
13554321Scasper 		return ((ksid_t *)&cr->cr_ksid->kr_sidx[i]);
13564321Scasper 	return (NULL);
13574321Scasper }
13584321Scasper 
13594321Scasper ksidlist_t *
13604321Scasper crgetsidlist(const cred_t *cr)
13614321Scasper {
13625331Samw 	if (cr->cr_ksid != NULL)
13634923Scasper 		return (cr->cr_ksid->kr_sidlist);
13644321Scasper 	return (NULL);
13654321Scasper }
13665331Samw 
13675331Samw /*
13685331Samw  * Interface to set the effective and permitted privileges for
13695331Samw  * a credential; this interface does no security checks and is
13705331Samw  * intended for kernel (file)servers creating credentials with
13715331Samw  * specific privileges.
13725331Samw  */
13735331Samw int
13745331Samw crsetpriv(cred_t *cr, ...)
13755331Samw {
13765331Samw 	va_list ap;
13775331Samw 	const char *privnm;
13785331Samw 
13795331Samw 	ASSERT(cr->cr_ref <= 2);
13805331Samw 
13815331Samw 	priv_set_PA(cr);
13825331Samw 
13835331Samw 	va_start(ap, cr);
13845331Samw 
13855331Samw 	while ((privnm = va_arg(ap, const char *)) != NULL) {
13865331Samw 		int priv = priv_getbyname(privnm, 0);
13875331Samw 		if (priv < 0)
13885331Samw 			return (-1);
13895331Samw 
13905331Samw 		priv_addset(&CR_PPRIV(cr), priv);
13915331Samw 		priv_addset(&CR_EPRIV(cr), priv);
13925331Samw 	}
13935331Samw 	priv_adjust_PA(cr);
13945331Samw 	va_end(ap);
13955331Samw 	return (0);
13965331Samw }
13976134Scasper 
13989151SThomas.Haynes@Sun.COM /*
13999151SThomas.Haynes@Sun.COM  * Interface to effectively set the PRIV_ALL for
14009151SThomas.Haynes@Sun.COM  * a credential; this interface does no security checks and is
14019151SThomas.Haynes@Sun.COM  * intended for kernel (file)servers to extend the user credentials
14029151SThomas.Haynes@Sun.COM  * to be ALL, like either kcred or zcred.
14039151SThomas.Haynes@Sun.COM  */
14049151SThomas.Haynes@Sun.COM void
14059151SThomas.Haynes@Sun.COM crset_zone_privall(cred_t *cr)
14069151SThomas.Haynes@Sun.COM {
14079151SThomas.Haynes@Sun.COM 	zone_t	*zone = crgetzone(cr);
14089151SThomas.Haynes@Sun.COM 
14099151SThomas.Haynes@Sun.COM 	priv_fillset(&CR_LPRIV(cr));
14109151SThomas.Haynes@Sun.COM 	CR_EPRIV(cr) = CR_PPRIV(cr) = CR_IPRIV(cr) = CR_LPRIV(cr);
14119151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_LPRIV(cr));
14129151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_EPRIV(cr));
14139151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_IPRIV(cr));
14149151SThomas.Haynes@Sun.COM 	priv_intersect(zone->zone_privset, &CR_PPRIV(cr));
14159151SThomas.Haynes@Sun.COM }
14169151SThomas.Haynes@Sun.COM 
14176134Scasper struct credklpd *
14186134Scasper crgetcrklpd(const cred_t *cr)
14196134Scasper {
14206134Scasper 	return (cr->cr_klpd);
14216134Scasper }
14226134Scasper 
14236134Scasper void
14246134Scasper crsetcrklpd(cred_t *cr, struct credklpd *crklpd)
14256134Scasper {
14266134Scasper 	ASSERT(cr->cr_ref <= 2);
14276134Scasper 
14286134Scasper 	if (cr->cr_klpd != NULL)
14296134Scasper 		crklpd_rele(cr->cr_klpd);
14306134Scasper 	cr->cr_klpd = crklpd;
14316134Scasper }
143211134SCasper.Dik@Sun.COM 
143311134SCasper.Dik@Sun.COM credgrp_t *
143411134SCasper.Dik@Sun.COM crgrpcopyin(int n, gid_t *gidset)
143511134SCasper.Dik@Sun.COM {
143611134SCasper.Dik@Sun.COM 	credgrp_t *mem;
143711134SCasper.Dik@Sun.COM 	size_t sz = CREDGRPSZ(n);
143811134SCasper.Dik@Sun.COM 
143911134SCasper.Dik@Sun.COM 	ASSERT(n > 0);
144011134SCasper.Dik@Sun.COM 
144111134SCasper.Dik@Sun.COM 	mem = kmem_alloc(sz, KM_SLEEP);
144211134SCasper.Dik@Sun.COM 
144311134SCasper.Dik@Sun.COM 	if (copyin(gidset, mem->crg_groups, sizeof (gid_t) * n)) {
144411134SCasper.Dik@Sun.COM 		kmem_free(mem, sz);
144511134SCasper.Dik@Sun.COM 		return (NULL);
144611134SCasper.Dik@Sun.COM 	}
144711134SCasper.Dik@Sun.COM 	mem->crg_ref = 1;
144811134SCasper.Dik@Sun.COM 	mem->crg_ngroups = n;
144911134SCasper.Dik@Sun.COM 	return (mem);
145011134SCasper.Dik@Sun.COM }
145111134SCasper.Dik@Sun.COM 
145211134SCasper.Dik@Sun.COM const gid_t *
145311134SCasper.Dik@Sun.COM crgetggroups(const credgrp_t *grps)
145411134SCasper.Dik@Sun.COM {
145511134SCasper.Dik@Sun.COM 	return (grps->crg_groups);
145611134SCasper.Dik@Sun.COM }
145711134SCasper.Dik@Sun.COM 
145811134SCasper.Dik@Sun.COM void
145911134SCasper.Dik@Sun.COM crsetcredgrp(cred_t *cr, credgrp_t *grps)
146011134SCasper.Dik@Sun.COM {
146111134SCasper.Dik@Sun.COM 	ASSERT(cr->cr_ref <= 2);
146211134SCasper.Dik@Sun.COM 
146311134SCasper.Dik@Sun.COM 	if (cr->cr_grps != NULL)
146411134SCasper.Dik@Sun.COM 		crgrprele(cr->cr_grps);
146511134SCasper.Dik@Sun.COM 
146611134SCasper.Dik@Sun.COM 	cr->cr_grps = grps;
146711134SCasper.Dik@Sun.COM }
146811134SCasper.Dik@Sun.COM 
146911134SCasper.Dik@Sun.COM void
147011134SCasper.Dik@Sun.COM crgrprele(credgrp_t *grps)
147111134SCasper.Dik@Sun.COM {
147211134SCasper.Dik@Sun.COM 	if (atomic_add_32_nv(&grps->crg_ref, -1) == 0)
147311134SCasper.Dik@Sun.COM 		kmem_free(grps, CREDGRPSZ(grps->crg_ngroups));
147411134SCasper.Dik@Sun.COM }
147511134SCasper.Dik@Sun.COM 
147611134SCasper.Dik@Sun.COM static void
147711134SCasper.Dik@Sun.COM crgrphold(credgrp_t *grps)
147811134SCasper.Dik@Sun.COM {
147911134SCasper.Dik@Sun.COM 	atomic_add_32(&grps->crg_ref, 1);
148011134SCasper.Dik@Sun.COM }
1481