xref: /onnv-gate/usr/src/uts/common/os/sid.c (revision 5771:7ba3a2c57d6a)
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 /*
23*5771Sjp151216  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
244321Scasper  * Use is subject to license terms.
254321Scasper  */
264321Scasper 
274321Scasper #pragma ident	"%Z%%M%	%I%	%E% SMI"
284321Scasper 
294321Scasper /*
304321Scasper  * Sid manipulation (stubs).
314321Scasper  */
324321Scasper 
334321Scasper #include <sys/atomic.h>
344321Scasper #include <sys/avl.h>
354321Scasper #include <sys/cmn_err.h>
364321Scasper #include <sys/kmem.h>
374321Scasper #include <sys/mutex.h>
384321Scasper #include <sys/sid.h>
394321Scasper #include <sys/sysmacros.h>
404321Scasper #include <sys/systm.h>
414520Snw141292 #include <sys/kidmap.h>
424520Snw141292 #include <sys/idmap.h>
434520Snw141292 
444321Scasper static kmutex_t sid_lock;
454321Scasper static avl_tree_t sid_tree;
464321Scasper static boolean_t sid_inited = B_FALSE;
474321Scasper 
484321Scasper static ksiddomain_t
494321Scasper *ksid_enterdomain(const char *dom)
504321Scasper {
514321Scasper 	size_t len = strlen(dom) + 1;
524321Scasper 	ksiddomain_t *res;
534321Scasper 
544321Scasper 	ASSERT(MUTEX_HELD(&sid_lock));
554321Scasper 	res = kmem_alloc(sizeof (ksiddomain_t), KM_SLEEP);
564321Scasper 	res->kd_len = (uint_t)len;
574321Scasper 	res->kd_name = kmem_alloc(len, KM_SLEEP);
584321Scasper 	bcopy(dom, res->kd_name, len);
594321Scasper 
604321Scasper 	res->kd_ref = 1;
614321Scasper 
624321Scasper 	avl_add(&sid_tree, res);
634321Scasper 
644321Scasper 	return (res);
654321Scasper }
664321Scasper 
674321Scasper void
684321Scasper ksid_hold(ksid_t *ks)
694321Scasper {
704321Scasper 	if (ks->ks_domain != NULL)
714321Scasper 		ksiddomain_hold(ks->ks_domain);
724321Scasper }
734321Scasper 
744321Scasper void
754321Scasper ksid_rele(ksid_t *ks)
764321Scasper {
774321Scasper 	if (ks->ks_domain != NULL)
784321Scasper 		ksiddomain_rele(ks->ks_domain);
794321Scasper }
804321Scasper 
814321Scasper void
824321Scasper ksiddomain_hold(ksiddomain_t *kd)
834321Scasper {
844321Scasper 	atomic_add_32(&kd->kd_ref, 1);
854321Scasper }
864321Scasper 
874321Scasper void
884321Scasper ksiddomain_rele(ksiddomain_t *kd)
894321Scasper {
904321Scasper 	if (atomic_add_32_nv(&kd->kd_ref, -1) == 0) {
914321Scasper 		/*
924321Scasper 		 * The kd reference can only be incremented from 0 when
934321Scasper 		 * the sid_lock is held; so we lock and then check need to
944321Scasper 		 * check for 0 again.
954321Scasper 		 */
964321Scasper 		mutex_enter(&sid_lock);
974321Scasper 		if (kd->kd_ref == 0) {
984321Scasper 			avl_remove(&sid_tree, kd);
994321Scasper 			kmem_free(kd->kd_name, kd->kd_len);
1004321Scasper 			kmem_free(kd, sizeof (*kd));
1014321Scasper 		}
1024321Scasper 		mutex_exit(&sid_lock);
1034321Scasper 	}
1044321Scasper }
1054321Scasper 
1064321Scasper void
1074321Scasper ksidlist_hold(ksidlist_t *ksl)
1084321Scasper {
1094321Scasper 	atomic_add_32(&ksl->ksl_ref, 1);
1104321Scasper }
1114321Scasper 
1124321Scasper void
1134321Scasper ksidlist_rele(ksidlist_t *ksl)
1144321Scasper {
1154321Scasper 	if (atomic_add_32_nv(&ksl->ksl_ref, -1) == 0) {
1164321Scasper 		int i;
1174321Scasper 
1184321Scasper 		for (i = 0; i < ksl->ksl_nsid; i++)
1194321Scasper 			ksid_rele(&ksl->ksl_sids[i]);
1204321Scasper 
1214321Scasper 		kmem_free(ksl, KSIDLIST_MEM(ksl->ksl_nsid));
1224321Scasper 	}
1234321Scasper }
1244321Scasper 
1254321Scasper static int
1264321Scasper ksid_cmp(const void *a, const void *b)
1274321Scasper {
1284321Scasper 	const ksiddomain_t *ap = a;
1294321Scasper 	const ksiddomain_t *bp = b;
1304321Scasper 	int res;
1314321Scasper 
1324321Scasper 	res = strcmp(ap->kd_name, bp->kd_name);
1334321Scasper 	if (res > 0)
1344321Scasper 		return (1);
1354321Scasper 	if (res != 0)
1364321Scasper 		return (-1);
1374321Scasper 	return (0);
1384321Scasper }
1394321Scasper 
1404321Scasper /*
1414321Scasper  * Lookup the named domain in the AVL tree.
1424321Scasper  * If no entry is found, add the domain to the AVL tree.
1434321Scasper  * The domain is returned held and needs to be released
1444321Scasper  * when done.
1454321Scasper  */
1464321Scasper ksiddomain_t
1474321Scasper *ksid_lookupdomain(const char *dom)
1484321Scasper {
1494321Scasper 	ksiddomain_t *res;
1504321Scasper 	ksiddomain_t tmpl;
1514321Scasper 
1524321Scasper 	mutex_enter(&sid_lock);
1534321Scasper 
1544321Scasper 	if (!sid_inited) {
1554321Scasper 		avl_create(&sid_tree, ksid_cmp, sizeof (ksiddomain_t),
1564321Scasper 		    offsetof(ksiddomain_t, kd_link));
1574321Scasper 
1584321Scasper 		res = ksid_enterdomain(dom);
1594321Scasper 		sid_inited = B_TRUE;
1604321Scasper 		mutex_exit(&sid_lock);
1614321Scasper 		return (res);
1624321Scasper 	}
1634321Scasper 
1644321Scasper 	tmpl.kd_name = (char *)dom;
1654321Scasper 
1664321Scasper 	res = avl_find(&sid_tree, &tmpl, NULL);
1674321Scasper 	if (res == NULL) {
1684321Scasper 		res = ksid_enterdomain(dom);
1694321Scasper 	} else {
1704321Scasper 		ksiddomain_hold(res);
1714321Scasper 	}
1724321Scasper 
1734321Scasper 	mutex_exit(&sid_lock);
1744321Scasper 	return (res);
1754321Scasper }
1764321Scasper 
1774321Scasper const char *
1784321Scasper ksid_getdomain(ksid_t *ks)
1794321Scasper {
1804321Scasper 	return (ks->ks_domain->kd_name);
1814321Scasper }
1824321Scasper 
1834321Scasper uint_t
1844321Scasper ksid_getrid(ksid_t *ks)
1854321Scasper {
1864321Scasper 	return (ks->ks_rid);
1874321Scasper }
1884321Scasper 
1894321Scasper int
190*5771Sjp151216 ksid_lookupbyuid(zone_t *zone, uid_t id, ksid_t *res)
1914321Scasper {
1924520Snw141292 	const char *sid_prefix;
1934321Scasper 
194*5771Sjp151216 	if (kidmap_getsidbyuid(zone, id, &sid_prefix, &res->ks_rid)
195*5771Sjp151216 	    != IDMAP_SUCCESS)
1964321Scasper 		return (-1);
1974321Scasper 
1984520Snw141292 	res->ks_domain = ksid_lookupdomain(sid_prefix);
1994520Snw141292 
2004520Snw141292 	res->ks_id = id;
2014520Snw141292 
2024520Snw141292 	return (0);
2034520Snw141292 }
2044520Snw141292 
2054520Snw141292 int
206*5771Sjp151216 ksid_lookupbygid(zone_t *zone, gid_t id, ksid_t *res)
2074520Snw141292 {
2084520Snw141292 	const char *sid_prefix;
2094520Snw141292 
210*5771Sjp151216 	if (kidmap_getsidbygid(zone, id, &sid_prefix, &res->ks_rid)
211*5771Sjp151216 	    != IDMAP_SUCCESS)
2124520Snw141292 		return (-1);
2134520Snw141292 
2144520Snw141292 	res->ks_domain = ksid_lookupdomain(sid_prefix);
2154520Snw141292 
2164321Scasper 	res->ks_id = id;
2174321Scasper 
2184321Scasper 	return (0);
2194321Scasper }
2204321Scasper 
2214321Scasper credsid_t *
2224321Scasper kcrsid_alloc(void)
2234321Scasper {
2244321Scasper 	credsid_t *kcr = kmem_zalloc(sizeof (*kcr), KM_SLEEP);
2254321Scasper 	kcr->kr_ref = 1;
2264321Scasper 	return (kcr);
2274321Scasper }
2284321Scasper 
2294321Scasper /*
2304321Scasper  * Returns a credsid_t with a refcount of 1.
2314321Scasper  */
2324321Scasper static credsid_t *
2334321Scasper kcrsid_dup(credsid_t *org)
2344321Scasper {
2354321Scasper 	credsid_t *new;
2364321Scasper 	ksid_index_t ki;
2374321Scasper 
2384321Scasper 	if (org == NULL)
2394321Scasper 		return (kcrsid_alloc());
2404321Scasper 	if (org->kr_ref == 1)
2414321Scasper 		return (org);
2424321Scasper 	new = kcrsid_alloc();
2434321Scasper 
2444321Scasper 	/* Copy, then update reference counts */
2454321Scasper 	*new = *org;
2464321Scasper 	new->kr_ref = 1;
2474321Scasper 	for (ki = 0; ki < KSID_COUNT; ki++)
2484321Scasper 		ksid_hold(&new->kr_sidx[ki]);
2494321Scasper 
2504321Scasper 	if (new->kr_sidlist != NULL)
2514321Scasper 		ksidlist_hold(new->kr_sidlist);
2524321Scasper 
2534321Scasper 	kcrsid_rele(org);
2544321Scasper 	return (new);
2554321Scasper }
2564321Scasper 
2574321Scasper void
2584321Scasper kcrsid_hold(credsid_t *kcr)
2594321Scasper {
2604321Scasper 	atomic_add_32(&kcr->kr_ref, 1);
2614321Scasper }
2624321Scasper 
2634321Scasper void
2644321Scasper kcrsid_rele(credsid_t *kcr)
2654321Scasper {
2664321Scasper 	if (atomic_add_32_nv(&kcr->kr_ref, -1) == 0) {
2674321Scasper 		ksid_index_t i;
2684321Scasper 
2694321Scasper 		for (i = 0; i < KSID_COUNT; i++)
2704321Scasper 			ksid_rele(&kcr->kr_sidx[i]);
2714321Scasper 
2724321Scasper 		if (kcr->kr_sidlist != NULL)
2734321Scasper 			ksidlist_rele(kcr->kr_sidlist);
2744321Scasper 
2754321Scasper 		kmem_free(kcr, sizeof (*kcr));
2764321Scasper 	}
2774321Scasper }
2784321Scasper 
2794321Scasper /*
2804321Scasper  * Copy the SID credential into a previously allocated piece of memory.
2814321Scasper  */
2824321Scasper void
2834321Scasper kcrsidcopy_to(const credsid_t *okcr, credsid_t *nkcr)
2844321Scasper {
2854321Scasper 	int i;
2864321Scasper 
2874321Scasper 	ASSERT(nkcr->kr_ref == 1);
2884321Scasper 
2894321Scasper 	if (okcr == NULL)
2904321Scasper 		return;
2914321Scasper 	*nkcr = *okcr;
2924321Scasper 	for (i = 0; i < KSID_COUNT; i++)
2934321Scasper 		ksid_hold(&nkcr->kr_sidx[i]);
2944321Scasper 	if (nkcr->kr_sidlist != NULL)
2954321Scasper 		ksidlist_hold(nkcr->kr_sidlist);
2964321Scasper 	nkcr->kr_ref = 1;
2974321Scasper }
2984321Scasper 
2994321Scasper static int
3004321Scasper kcrsid_sidcount(const credsid_t *kcr)
3014321Scasper {
3024321Scasper 	int cnt = 0;
3034321Scasper 	int i;
3044321Scasper 
3054321Scasper 	if (kcr == NULL)
3064321Scasper 		return (0);
3074321Scasper 
3084321Scasper 	for (i = 0; i < KSID_COUNT; i++)
3094321Scasper 		if (kcr->kr_sidx[i].ks_domain != NULL)
3104321Scasper 			cnt++;
3114321Scasper 
3124321Scasper 	if (kcr->kr_sidlist != NULL)
3134321Scasper 		cnt += kcr->kr_sidlist->ksl_nsid;
3144321Scasper 	return (cnt);
3154321Scasper }
3164321Scasper 
3174321Scasper /*
3184321Scasper  * Argument needs to be a ksid_t with a properly held ks_domain reference.
3194321Scasper  */
3204321Scasper credsid_t *
3214321Scasper kcrsid_setsid(credsid_t *okcr, ksid_t *ksp, ksid_index_t i)
3224321Scasper {
3234321Scasper 	int ocnt = kcrsid_sidcount(okcr);
3244321Scasper 	credsid_t *nkcr;
3254321Scasper 
3264321Scasper 	/*
3274321Scasper 	 * Unset the particular ksid; if there are no other SIDs or if this
3284321Scasper 	 * is the last SID, remove the auxilary data structure.
3294321Scasper 	 */
3304321Scasper 	if (ksp == NULL) {
3314321Scasper 		if (ocnt == 0 ||
3324321Scasper 		    (ocnt == 1 && okcr->kr_sidx[i].ks_domain != NULL)) {
3334321Scasper 			if (okcr != NULL)
3344321Scasper 				kcrsid_rele(okcr);
3354321Scasper 			return (NULL);
3364321Scasper 		}
3374321Scasper 	}
3384321Scasper 	nkcr = kcrsid_dup(okcr);
3394321Scasper 	ksid_rele(&nkcr->kr_sidx[i]);
3404321Scasper 	if (ksp == NULL)
3414321Scasper 		bzero(&nkcr->kr_sidx[i], sizeof (ksid_t));
3424321Scasper 	else
3434321Scasper 		nkcr->kr_sidx[i] = *ksp;
3444321Scasper 
3454321Scasper 	return (nkcr);
3464321Scasper }
3474321Scasper 
3484321Scasper /*
3494321Scasper  * Argument needs to be a ksidlist_t with properly held ks_domain references
3504321Scasper  * and a reference count taking the new reference into account.
3514321Scasper  */
3524321Scasper credsid_t *
3534321Scasper kcrsid_setsidlist(credsid_t *okcr, ksidlist_t *ksl)
3544321Scasper {
3554321Scasper 	int ocnt = kcrsid_sidcount(okcr);
3564321Scasper 	credsid_t *nkcr;
3574321Scasper 
3584321Scasper 	/*
3594321Scasper 	 * Unset the sidlist; if there are no further SIDs, remove the
3604321Scasper 	 * auxilary data structure.
3614321Scasper 	 */
3624321Scasper 	if (ksl == NULL) {
3634321Scasper 		if (ocnt == 0 || (okcr->kr_sidlist != NULL &&
3644321Scasper 		    ocnt == okcr->kr_sidlist->ksl_nsid)) {
3654321Scasper 			if (okcr != NULL)
3664321Scasper 				kcrsid_rele(okcr);
3674321Scasper 			return (NULL);
3684321Scasper 		}
3694321Scasper 	}
3704321Scasper 	nkcr = kcrsid_dup(okcr);
3714321Scasper 	if (nkcr->kr_sidlist != NULL)
3724321Scasper 		ksidlist_rele(nkcr->kr_sidlist);
3734321Scasper 
3744321Scasper 	nkcr->kr_sidlist = ksl;
3754321Scasper 	return (nkcr);
3764321Scasper }
3774321Scasper 
3784321Scasper ksidlist_t *
379*5771Sjp151216 kcrsid_gidstosids(zone_t *zone, int ngrp, gid_t *grp)
3804321Scasper {
3814321Scasper 	int i;
3824321Scasper 	ksidlist_t *list;
3834321Scasper 	int cnt;
3844321Scasper 
3854321Scasper 	if (ngrp == 0)
3864321Scasper 		return (NULL);
3874321Scasper 
3884321Scasper 	cnt = 0;
3894321Scasper 	list = kmem_zalloc(KSIDLIST_MEM(ngrp), KM_SLEEP);
3904321Scasper 
3914321Scasper 	list->ksl_nsid = ngrp;
3924321Scasper 	list->ksl_ref = 1;
3934321Scasper 
3944321Scasper 	for (i = 0; i < ngrp; i++) {
3954321Scasper 		if (grp[i] > MAXUID) {
3964321Scasper 			list->ksl_neid++;
397*5771Sjp151216 			if (ksid_lookupbygid(zone,
398*5771Sjp151216 			    grp[i], &list->ksl_sids[i]) != 0) {
3994321Scasper 				while (--i >= 0)
4004321Scasper 					ksid_rele(&list->ksl_sids[i]);
4014321Scasper 				cnt = 0;
4024321Scasper 				break;
4034321Scasper 			}
4044321Scasper 			cnt++;
4054321Scasper 		} else {
4064321Scasper 			list->ksl_sids[i].ks_id = grp[i];
4074321Scasper 		}
4084321Scasper 	}
4094321Scasper 	if (cnt == 0) {
4104321Scasper 		kmem_free(list, KSIDLIST_MEM(ngrp));
4114321Scasper 		return (NULL);
4124321Scasper 	}
4134321Scasper 	return (list);
4144321Scasper }
415