xref: /onnv-gate/usr/src/uts/common/os/sid.c (revision 4520:7dbeadedd7fe)
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 /*
234321Scasper  * Copyright 2007 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>
41*4520Snw141292 #include <sys/kidmap.h>
42*4520Snw141292 #include <sys/idmap.h>
43*4520Snw141292 
44*4520Snw141292 #define	KSIDLIST_MEM(n)	(sizeof (ksidlist_t) + ((n) - 1) * sizeof (ksid_t))
454321Scasper 
464321Scasper static kmutex_t sid_lock;
474321Scasper static avl_tree_t sid_tree;
484321Scasper static boolean_t sid_inited = B_FALSE;
494321Scasper 
504321Scasper static ksiddomain_t
514321Scasper *ksid_enterdomain(const char *dom)
524321Scasper {
534321Scasper 	size_t len = strlen(dom) + 1;
544321Scasper 	ksiddomain_t *res;
554321Scasper 
564321Scasper 	ASSERT(MUTEX_HELD(&sid_lock));
574321Scasper 	res = kmem_alloc(sizeof (ksiddomain_t), KM_SLEEP);
584321Scasper 	res->kd_len = (uint_t)len;
594321Scasper 	res->kd_name = kmem_alloc(len, KM_SLEEP);
604321Scasper 	bcopy(dom, res->kd_name, len);
614321Scasper 
624321Scasper 	res->kd_ref = 1;
634321Scasper 
644321Scasper 	avl_add(&sid_tree, res);
654321Scasper 
664321Scasper 	return (res);
674321Scasper }
684321Scasper 
694321Scasper void
704321Scasper ksid_hold(ksid_t *ks)
714321Scasper {
724321Scasper 	if (ks->ks_domain != NULL)
734321Scasper 		ksiddomain_hold(ks->ks_domain);
744321Scasper }
754321Scasper 
764321Scasper void
774321Scasper ksid_rele(ksid_t *ks)
784321Scasper {
794321Scasper 	if (ks->ks_domain != NULL)
804321Scasper 		ksiddomain_rele(ks->ks_domain);
814321Scasper }
824321Scasper 
834321Scasper void
844321Scasper ksiddomain_hold(ksiddomain_t *kd)
854321Scasper {
864321Scasper 	atomic_add_32(&kd->kd_ref, 1);
874321Scasper }
884321Scasper 
894321Scasper void
904321Scasper ksiddomain_rele(ksiddomain_t *kd)
914321Scasper {
924321Scasper 	if (atomic_add_32_nv(&kd->kd_ref, -1) == 0) {
934321Scasper 		/*
944321Scasper 		 * The kd reference can only be incremented from 0 when
954321Scasper 		 * the sid_lock is held; so we lock and then check need to
964321Scasper 		 * check for 0 again.
974321Scasper 		 */
984321Scasper 		mutex_enter(&sid_lock);
994321Scasper 		if (kd->kd_ref == 0) {
1004321Scasper 			avl_remove(&sid_tree, kd);
1014321Scasper 			kmem_free(kd->kd_name, kd->kd_len);
1024321Scasper 			kmem_free(kd, sizeof (*kd));
1034321Scasper 		}
1044321Scasper 		mutex_exit(&sid_lock);
1054321Scasper 	}
1064321Scasper }
1074321Scasper 
1084321Scasper void
1094321Scasper ksidlist_hold(ksidlist_t *ksl)
1104321Scasper {
1114321Scasper 	atomic_add_32(&ksl->ksl_ref, 1);
1124321Scasper }
1134321Scasper 
1144321Scasper void
1154321Scasper ksidlist_rele(ksidlist_t *ksl)
1164321Scasper {
1174321Scasper 	if (atomic_add_32_nv(&ksl->ksl_ref, -1) == 0) {
1184321Scasper 		int i;
1194321Scasper 
1204321Scasper 		for (i = 0; i < ksl->ksl_nsid; i++)
1214321Scasper 			ksid_rele(&ksl->ksl_sids[i]);
1224321Scasper 
1234321Scasper 		kmem_free(ksl, KSIDLIST_MEM(ksl->ksl_nsid));
1244321Scasper 	}
1254321Scasper }
1264321Scasper 
1274321Scasper static int
1284321Scasper ksid_cmp(const void *a, const void *b)
1294321Scasper {
1304321Scasper 	const ksiddomain_t *ap = a;
1314321Scasper 	const ksiddomain_t *bp = b;
1324321Scasper 	int res;
1334321Scasper 
1344321Scasper 	res = strcmp(ap->kd_name, bp->kd_name);
1354321Scasper 	if (res > 0)
1364321Scasper 		return (1);
1374321Scasper 	if (res != 0)
1384321Scasper 		return (-1);
1394321Scasper 	return (0);
1404321Scasper }
1414321Scasper 
1424321Scasper /*
1434321Scasper  * Lookup the named domain in the AVL tree.
1444321Scasper  * If no entry is found, add the domain to the AVL tree.
1454321Scasper  * The domain is returned held and needs to be released
1464321Scasper  * when done.
1474321Scasper  */
1484321Scasper ksiddomain_t
1494321Scasper *ksid_lookupdomain(const char *dom)
1504321Scasper {
1514321Scasper 	ksiddomain_t *res;
1524321Scasper 	ksiddomain_t tmpl;
1534321Scasper 
1544321Scasper 	mutex_enter(&sid_lock);
1554321Scasper 
1564321Scasper 	if (!sid_inited) {
1574321Scasper 		avl_create(&sid_tree, ksid_cmp, sizeof (ksiddomain_t),
1584321Scasper 		    offsetof(ksiddomain_t, kd_link));
1594321Scasper 
1604321Scasper 		res = ksid_enterdomain(dom);
1614321Scasper 		sid_inited = B_TRUE;
1624321Scasper 		mutex_exit(&sid_lock);
1634321Scasper 		return (res);
1644321Scasper 	}
1654321Scasper 
1664321Scasper 	tmpl.kd_name = (char *)dom;
1674321Scasper 
1684321Scasper 	res = avl_find(&sid_tree, &tmpl, NULL);
1694321Scasper 	if (res == NULL) {
1704321Scasper 		res = ksid_enterdomain(dom);
1714321Scasper 	} else {
1724321Scasper 		ksiddomain_hold(res);
1734321Scasper 	}
1744321Scasper 
1754321Scasper 	mutex_exit(&sid_lock);
1764321Scasper 	return (res);
1774321Scasper }
1784321Scasper 
1794321Scasper const char *
1804321Scasper ksid_getdomain(ksid_t *ks)
1814321Scasper {
1824321Scasper 	return (ks->ks_domain->kd_name);
1834321Scasper }
1844321Scasper 
1854321Scasper uint_t
1864321Scasper ksid_getrid(ksid_t *ks)
1874321Scasper {
1884321Scasper 	return (ks->ks_rid);
1894321Scasper }
1904321Scasper 
1914321Scasper int
192*4520Snw141292 ksid_lookupbyuid(uid_t id, ksid_t *res)
1934321Scasper {
194*4520Snw141292 	const char *sid_prefix;
1954321Scasper 
196*4520Snw141292 	if (kidmap_getsidbyuid(id, &sid_prefix, &res->ks_rid) != IDMAP_SUCCESS)
1974321Scasper 		return (-1);
1984321Scasper 
199*4520Snw141292 	res->ks_domain = ksid_lookupdomain(sid_prefix);
200*4520Snw141292 
201*4520Snw141292 	res->ks_id = id;
202*4520Snw141292 
203*4520Snw141292 	return (0);
204*4520Snw141292 }
205*4520Snw141292 
206*4520Snw141292 int
207*4520Snw141292 ksid_lookupbygid(gid_t id, ksid_t *res)
208*4520Snw141292 {
209*4520Snw141292 	const char *sid_prefix;
210*4520Snw141292 
211*4520Snw141292 	if (kidmap_getsidbygid(id, &sid_prefix, &res->ks_rid) != IDMAP_SUCCESS)
212*4520Snw141292 		return (-1);
213*4520Snw141292 
214*4520Snw141292 	res->ks_domain = ksid_lookupdomain(sid_prefix);
215*4520Snw141292 
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 *
3794321Scasper kcrsid_gidstosids(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*4520Snw141292 			if (ksid_lookupbygid(grp[i], &list->ksl_sids[i]) != 0) {
3984321Scasper 				while (--i >= 0)
3994321Scasper 					ksid_rele(&list->ksl_sids[i]);
4004321Scasper 				cnt = 0;
4014321Scasper 				break;
4024321Scasper 			}
4034321Scasper 			cnt++;
4044321Scasper 		} else {
4054321Scasper 			list->ksl_sids[i].ks_id = grp[i];
4064321Scasper 		}
4074321Scasper 	}
4084321Scasper 	if (cnt == 0) {
4094321Scasper 		kmem_free(list, KSIDLIST_MEM(ngrp));
4104321Scasper 		return (NULL);
4114321Scasper 	}
4124321Scasper 	return (list);
4134321Scasper }
414