xref: /onnv-gate/usr/src/uts/common/os/sid.c (revision 7847:3b5331e410c6)
14321Scasper /*
24321Scasper  * CDDL HEADER START
34321Scasper  *
44321Scasper  * The contents of this file are subject to the terms of the
54321Scasper  * Common Development and Distribution License (the "License").
64321Scasper  * You may not use this file except in compliance with the License.
74321Scasper  *
84321Scasper  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94321Scasper  * or http://www.opensolaris.org/os/licensing.
104321Scasper  * See the License for the specific language governing permissions
114321Scasper  * and limitations under the License.
124321Scasper  *
134321Scasper  * When distributing Covered Code, include this CDDL HEADER in each
144321Scasper  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154321Scasper  * If applicable, add the following below this CDDL HEADER, with the
164321Scasper  * fields enclosed by brackets "[]" replaced with your own identifying
174321Scasper  * information: Portions Copyright [yyyy] [name of copyright owner]
184321Scasper  *
194321Scasper  * CDDL HEADER END
204321Scasper  */
214321Scasper 
224321Scasper /*
235771Sjp151216  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
244321Scasper  * Use is subject to license terms.
254321Scasper  */
264321Scasper 
274321Scasper /*
284321Scasper  * Sid manipulation (stubs).
294321Scasper  */
304321Scasper 
314321Scasper #include <sys/atomic.h>
324321Scasper #include <sys/avl.h>
334321Scasper #include <sys/cmn_err.h>
344321Scasper #include <sys/kmem.h>
354321Scasper #include <sys/mutex.h>
364321Scasper #include <sys/sid.h>
374321Scasper #include <sys/sysmacros.h>
384321Scasper #include <sys/systm.h>
394520Snw141292 #include <sys/kidmap.h>
404520Snw141292 #include <sys/idmap.h>
414520Snw141292 
424321Scasper static kmutex_t sid_lock;
434321Scasper static avl_tree_t sid_tree;
444321Scasper static boolean_t sid_inited = B_FALSE;
454321Scasper 
464321Scasper static ksiddomain_t
ksid_enterdomain(const char * dom)474321Scasper *ksid_enterdomain(const char *dom)
484321Scasper {
494321Scasper 	size_t len = strlen(dom) + 1;
504321Scasper 	ksiddomain_t *res;
514321Scasper 
524321Scasper 	ASSERT(MUTEX_HELD(&sid_lock));
534321Scasper 	res = kmem_alloc(sizeof (ksiddomain_t), KM_SLEEP);
544321Scasper 	res->kd_len = (uint_t)len;
554321Scasper 	res->kd_name = kmem_alloc(len, KM_SLEEP);
564321Scasper 	bcopy(dom, res->kd_name, len);
574321Scasper 
584321Scasper 	res->kd_ref = 1;
594321Scasper 
604321Scasper 	avl_add(&sid_tree, res);
614321Scasper 
624321Scasper 	return (res);
634321Scasper }
644321Scasper 
654321Scasper void
ksid_hold(ksid_t * ks)664321Scasper ksid_hold(ksid_t *ks)
674321Scasper {
684321Scasper 	if (ks->ks_domain != NULL)
694321Scasper 		ksiddomain_hold(ks->ks_domain);
704321Scasper }
714321Scasper 
724321Scasper void
ksid_rele(ksid_t * ks)734321Scasper ksid_rele(ksid_t *ks)
744321Scasper {
754321Scasper 	if (ks->ks_domain != NULL)
764321Scasper 		ksiddomain_rele(ks->ks_domain);
774321Scasper }
784321Scasper 
794321Scasper void
ksiddomain_hold(ksiddomain_t * kd)804321Scasper ksiddomain_hold(ksiddomain_t *kd)
814321Scasper {
824321Scasper 	atomic_add_32(&kd->kd_ref, 1);
834321Scasper }
844321Scasper 
854321Scasper void
ksiddomain_rele(ksiddomain_t * kd)864321Scasper ksiddomain_rele(ksiddomain_t *kd)
874321Scasper {
884321Scasper 	if (atomic_add_32_nv(&kd->kd_ref, -1) == 0) {
894321Scasper 		/*
904321Scasper 		 * The kd reference can only be incremented from 0 when
914321Scasper 		 * the sid_lock is held; so we lock and then check need to
924321Scasper 		 * check for 0 again.
934321Scasper 		 */
944321Scasper 		mutex_enter(&sid_lock);
954321Scasper 		if (kd->kd_ref == 0) {
964321Scasper 			avl_remove(&sid_tree, kd);
974321Scasper 			kmem_free(kd->kd_name, kd->kd_len);
984321Scasper 			kmem_free(kd, sizeof (*kd));
994321Scasper 		}
1004321Scasper 		mutex_exit(&sid_lock);
1014321Scasper 	}
1024321Scasper }
1034321Scasper 
1044321Scasper void
ksidlist_hold(ksidlist_t * ksl)1054321Scasper ksidlist_hold(ksidlist_t *ksl)
1064321Scasper {
1074321Scasper 	atomic_add_32(&ksl->ksl_ref, 1);
1084321Scasper }
1094321Scasper 
1104321Scasper void
ksidlist_rele(ksidlist_t * ksl)1114321Scasper ksidlist_rele(ksidlist_t *ksl)
1124321Scasper {
1134321Scasper 	if (atomic_add_32_nv(&ksl->ksl_ref, -1) == 0) {
1144321Scasper 		int i;
1154321Scasper 
1164321Scasper 		for (i = 0; i < ksl->ksl_nsid; i++)
1174321Scasper 			ksid_rele(&ksl->ksl_sids[i]);
1184321Scasper 
1194321Scasper 		kmem_free(ksl, KSIDLIST_MEM(ksl->ksl_nsid));
1204321Scasper 	}
1214321Scasper }
1224321Scasper 
1234321Scasper static int
ksid_cmp(const void * a,const void * b)1244321Scasper ksid_cmp(const void *a, const void *b)
1254321Scasper {
1264321Scasper 	const ksiddomain_t *ap = a;
1274321Scasper 	const ksiddomain_t *bp = b;
1284321Scasper 	int res;
1294321Scasper 
1304321Scasper 	res = strcmp(ap->kd_name, bp->kd_name);
1314321Scasper 	if (res > 0)
1324321Scasper 		return (1);
1334321Scasper 	if (res != 0)
1344321Scasper 		return (-1);
1354321Scasper 	return (0);
1364321Scasper }
1374321Scasper 
1384321Scasper /*
1394321Scasper  * Lookup the named domain in the AVL tree.
1404321Scasper  * If no entry is found, add the domain to the AVL tree.
1414321Scasper  * The domain is returned held and needs to be released
1424321Scasper  * when done.
1434321Scasper  */
1444321Scasper ksiddomain_t
ksid_lookupdomain(const char * dom)1454321Scasper *ksid_lookupdomain(const char *dom)
1464321Scasper {
1474321Scasper 	ksiddomain_t *res;
1484321Scasper 	ksiddomain_t tmpl;
1494321Scasper 
1504321Scasper 	mutex_enter(&sid_lock);
1514321Scasper 
1524321Scasper 	if (!sid_inited) {
1534321Scasper 		avl_create(&sid_tree, ksid_cmp, sizeof (ksiddomain_t),
1544321Scasper 		    offsetof(ksiddomain_t, kd_link));
1554321Scasper 
1564321Scasper 		res = ksid_enterdomain(dom);
1574321Scasper 		sid_inited = B_TRUE;
1584321Scasper 		mutex_exit(&sid_lock);
1594321Scasper 		return (res);
1604321Scasper 	}
1614321Scasper 
1624321Scasper 	tmpl.kd_name = (char *)dom;
1634321Scasper 
1644321Scasper 	res = avl_find(&sid_tree, &tmpl, NULL);
1654321Scasper 	if (res == NULL) {
1664321Scasper 		res = ksid_enterdomain(dom);
1674321Scasper 	} else {
1684321Scasper 		ksiddomain_hold(res);
1694321Scasper 	}
1704321Scasper 
1714321Scasper 	mutex_exit(&sid_lock);
1724321Scasper 	return (res);
1734321Scasper }
1744321Scasper 
1754321Scasper const char *
ksid_getdomain(ksid_t * ks)1764321Scasper ksid_getdomain(ksid_t *ks)
1774321Scasper {
1784321Scasper 	return (ks->ks_domain->kd_name);
1794321Scasper }
1804321Scasper 
1814321Scasper uint_t
ksid_getrid(ksid_t * ks)1824321Scasper ksid_getrid(ksid_t *ks)
1834321Scasper {
1844321Scasper 	return (ks->ks_rid);
1854321Scasper }
1864321Scasper 
187*7847SMark.Shellenbaum@Sun.COM uid_t
ksid_getid(ksid_t * ks)188*7847SMark.Shellenbaum@Sun.COM ksid_getid(ksid_t *ks)
189*7847SMark.Shellenbaum@Sun.COM {
190*7847SMark.Shellenbaum@Sun.COM 	return (ks->ks_id);
191*7847SMark.Shellenbaum@Sun.COM }
192*7847SMark.Shellenbaum@Sun.COM 
1934321Scasper int
ksid_lookupbyuid(zone_t * zone,uid_t id,ksid_t * res)1945771Sjp151216 ksid_lookupbyuid(zone_t *zone, uid_t id, ksid_t *res)
1954321Scasper {
1964520Snw141292 	const char *sid_prefix;
1974321Scasper 
1985771Sjp151216 	if (kidmap_getsidbyuid(zone, id, &sid_prefix, &res->ks_rid)
1995771Sjp151216 	    != IDMAP_SUCCESS)
2004321Scasper 		return (-1);
2014321Scasper 
2024520Snw141292 	res->ks_domain = ksid_lookupdomain(sid_prefix);
2034520Snw141292 
2044520Snw141292 	res->ks_id = id;
2054520Snw141292 
2064520Snw141292 	return (0);
2074520Snw141292 }
2084520Snw141292 
2094520Snw141292 int
ksid_lookupbygid(zone_t * zone,gid_t id,ksid_t * res)2105771Sjp151216 ksid_lookupbygid(zone_t *zone, gid_t id, ksid_t *res)
2114520Snw141292 {
2124520Snw141292 	const char *sid_prefix;
2134520Snw141292 
2145771Sjp151216 	if (kidmap_getsidbygid(zone, id, &sid_prefix, &res->ks_rid)
2155771Sjp151216 	    != IDMAP_SUCCESS)
2164520Snw141292 		return (-1);
2174520Snw141292 
2184520Snw141292 	res->ks_domain = ksid_lookupdomain(sid_prefix);
2194520Snw141292 
2204321Scasper 	res->ks_id = id;
2214321Scasper 
2224321Scasper 	return (0);
2234321Scasper }
2244321Scasper 
2254321Scasper credsid_t *
kcrsid_alloc(void)2264321Scasper kcrsid_alloc(void)
2274321Scasper {
2284321Scasper 	credsid_t *kcr = kmem_zalloc(sizeof (*kcr), KM_SLEEP);
2294321Scasper 	kcr->kr_ref = 1;
2304321Scasper 	return (kcr);
2314321Scasper }
2324321Scasper 
2334321Scasper /*
2344321Scasper  * Returns a credsid_t with a refcount of 1.
2354321Scasper  */
2364321Scasper static credsid_t *
kcrsid_dup(credsid_t * org)2374321Scasper kcrsid_dup(credsid_t *org)
2384321Scasper {
2394321Scasper 	credsid_t *new;
2404321Scasper 	ksid_index_t ki;
2414321Scasper 
2424321Scasper 	if (org == NULL)
2434321Scasper 		return (kcrsid_alloc());
2444321Scasper 	if (org->kr_ref == 1)
2454321Scasper 		return (org);
2464321Scasper 	new = kcrsid_alloc();
2474321Scasper 
2484321Scasper 	/* Copy, then update reference counts */
2494321Scasper 	*new = *org;
2504321Scasper 	new->kr_ref = 1;
2514321Scasper 	for (ki = 0; ki < KSID_COUNT; ki++)
2524321Scasper 		ksid_hold(&new->kr_sidx[ki]);
2534321Scasper 
2544321Scasper 	if (new->kr_sidlist != NULL)
2554321Scasper 		ksidlist_hold(new->kr_sidlist);
2564321Scasper 
2574321Scasper 	kcrsid_rele(org);
2584321Scasper 	return (new);
2594321Scasper }
2604321Scasper 
2614321Scasper void
kcrsid_hold(credsid_t * kcr)2624321Scasper kcrsid_hold(credsid_t *kcr)
2634321Scasper {
2644321Scasper 	atomic_add_32(&kcr->kr_ref, 1);
2654321Scasper }
2664321Scasper 
2674321Scasper void
kcrsid_rele(credsid_t * kcr)2684321Scasper kcrsid_rele(credsid_t *kcr)
2694321Scasper {
2704321Scasper 	if (atomic_add_32_nv(&kcr->kr_ref, -1) == 0) {
2714321Scasper 		ksid_index_t i;
2724321Scasper 
2734321Scasper 		for (i = 0; i < KSID_COUNT; i++)
2744321Scasper 			ksid_rele(&kcr->kr_sidx[i]);
2754321Scasper 
2764321Scasper 		if (kcr->kr_sidlist != NULL)
2774321Scasper 			ksidlist_rele(kcr->kr_sidlist);
2784321Scasper 
2794321Scasper 		kmem_free(kcr, sizeof (*kcr));
2804321Scasper 	}
2814321Scasper }
2824321Scasper 
2834321Scasper /*
2844321Scasper  * Copy the SID credential into a previously allocated piece of memory.
2854321Scasper  */
2864321Scasper void
kcrsidcopy_to(const credsid_t * okcr,credsid_t * nkcr)2874321Scasper kcrsidcopy_to(const credsid_t *okcr, credsid_t *nkcr)
2884321Scasper {
2894321Scasper 	int i;
2904321Scasper 
2914321Scasper 	ASSERT(nkcr->kr_ref == 1);
2924321Scasper 
2934321Scasper 	if (okcr == NULL)
2944321Scasper 		return;
2954321Scasper 	*nkcr = *okcr;
2964321Scasper 	for (i = 0; i < KSID_COUNT; i++)
2974321Scasper 		ksid_hold(&nkcr->kr_sidx[i]);
2984321Scasper 	if (nkcr->kr_sidlist != NULL)
2994321Scasper 		ksidlist_hold(nkcr->kr_sidlist);
3004321Scasper 	nkcr->kr_ref = 1;
3014321Scasper }
3024321Scasper 
3034321Scasper static int
kcrsid_sidcount(const credsid_t * kcr)3044321Scasper kcrsid_sidcount(const credsid_t *kcr)
3054321Scasper {
3064321Scasper 	int cnt = 0;
3074321Scasper 	int i;
3084321Scasper 
3094321Scasper 	if (kcr == NULL)
3104321Scasper 		return (0);
3114321Scasper 
3124321Scasper 	for (i = 0; i < KSID_COUNT; i++)
3134321Scasper 		if (kcr->kr_sidx[i].ks_domain != NULL)
3144321Scasper 			cnt++;
3154321Scasper 
3164321Scasper 	if (kcr->kr_sidlist != NULL)
3174321Scasper 		cnt += kcr->kr_sidlist->ksl_nsid;
3184321Scasper 	return (cnt);
3194321Scasper }
3204321Scasper 
3214321Scasper /*
3224321Scasper  * Argument needs to be a ksid_t with a properly held ks_domain reference.
3234321Scasper  */
3244321Scasper credsid_t *
kcrsid_setsid(credsid_t * okcr,ksid_t * ksp,ksid_index_t i)3254321Scasper kcrsid_setsid(credsid_t *okcr, ksid_t *ksp, ksid_index_t i)
3264321Scasper {
3274321Scasper 	int ocnt = kcrsid_sidcount(okcr);
3284321Scasper 	credsid_t *nkcr;
3294321Scasper 
3304321Scasper 	/*
3314321Scasper 	 * Unset the particular ksid; if there are no other SIDs or if this
3324321Scasper 	 * is the last SID, remove the auxilary data structure.
3334321Scasper 	 */
3344321Scasper 	if (ksp == NULL) {
3354321Scasper 		if (ocnt == 0 ||
3364321Scasper 		    (ocnt == 1 && okcr->kr_sidx[i].ks_domain != NULL)) {
3374321Scasper 			if (okcr != NULL)
3384321Scasper 				kcrsid_rele(okcr);
3394321Scasper 			return (NULL);
3404321Scasper 		}
3414321Scasper 	}
3424321Scasper 	nkcr = kcrsid_dup(okcr);
3434321Scasper 	ksid_rele(&nkcr->kr_sidx[i]);
3444321Scasper 	if (ksp == NULL)
3454321Scasper 		bzero(&nkcr->kr_sidx[i], sizeof (ksid_t));
3464321Scasper 	else
3474321Scasper 		nkcr->kr_sidx[i] = *ksp;
3484321Scasper 
3494321Scasper 	return (nkcr);
3504321Scasper }
3514321Scasper 
3524321Scasper /*
3534321Scasper  * Argument needs to be a ksidlist_t with properly held ks_domain references
3544321Scasper  * and a reference count taking the new reference into account.
3554321Scasper  */
3564321Scasper credsid_t *
kcrsid_setsidlist(credsid_t * okcr,ksidlist_t * ksl)3574321Scasper kcrsid_setsidlist(credsid_t *okcr, ksidlist_t *ksl)
3584321Scasper {
3594321Scasper 	int ocnt = kcrsid_sidcount(okcr);
3604321Scasper 	credsid_t *nkcr;
3614321Scasper 
3624321Scasper 	/*
3634321Scasper 	 * Unset the sidlist; if there are no further SIDs, remove the
3644321Scasper 	 * auxilary data structure.
3654321Scasper 	 */
3664321Scasper 	if (ksl == NULL) {
3674321Scasper 		if (ocnt == 0 || (okcr->kr_sidlist != NULL &&
3684321Scasper 		    ocnt == okcr->kr_sidlist->ksl_nsid)) {
3694321Scasper 			if (okcr != NULL)
3704321Scasper 				kcrsid_rele(okcr);
3714321Scasper 			return (NULL);
3724321Scasper 		}
3734321Scasper 	}
3744321Scasper 	nkcr = kcrsid_dup(okcr);
3754321Scasper 	if (nkcr->kr_sidlist != NULL)
3764321Scasper 		ksidlist_rele(nkcr->kr_sidlist);
3774321Scasper 
3784321Scasper 	nkcr->kr_sidlist = ksl;
3794321Scasper 	return (nkcr);
3804321Scasper }
3814321Scasper 
3824321Scasper ksidlist_t *
kcrsid_gidstosids(zone_t * zone,int ngrp,gid_t * grp)3835771Sjp151216 kcrsid_gidstosids(zone_t *zone, int ngrp, gid_t *grp)
3844321Scasper {
3854321Scasper 	int i;
3864321Scasper 	ksidlist_t *list;
3874321Scasper 	int cnt;
3884321Scasper 
3894321Scasper 	if (ngrp == 0)
3904321Scasper 		return (NULL);
3914321Scasper 
3924321Scasper 	cnt = 0;
3934321Scasper 	list = kmem_zalloc(KSIDLIST_MEM(ngrp), KM_SLEEP);
3944321Scasper 
3954321Scasper 	list->ksl_nsid = ngrp;
3964321Scasper 	list->ksl_ref = 1;
3974321Scasper 
3984321Scasper 	for (i = 0; i < ngrp; i++) {
3994321Scasper 		if (grp[i] > MAXUID) {
4004321Scasper 			list->ksl_neid++;
4015771Sjp151216 			if (ksid_lookupbygid(zone,
4025771Sjp151216 			    grp[i], &list->ksl_sids[i]) != 0) {
4034321Scasper 				while (--i >= 0)
4044321Scasper 					ksid_rele(&list->ksl_sids[i]);
4054321Scasper 				cnt = 0;
4064321Scasper 				break;
4074321Scasper 			}
4084321Scasper 			cnt++;
4094321Scasper 		} else {
4104321Scasper 			list->ksl_sids[i].ks_id = grp[i];
4114321Scasper 		}
4124321Scasper 	}
4134321Scasper 	if (cnt == 0) {
4144321Scasper 		kmem_free(list, KSIDLIST_MEM(ngrp));
4154321Scasper 		return (NULL);
4164321Scasper 	}
4174321Scasper 	return (list);
4184321Scasper }
419