xref: /onnv-gate/usr/src/uts/common/os/sid.c (revision 4321:a8930ec16e52)
1*4321Scasper /*
2*4321Scasper  * CDDL HEADER START
3*4321Scasper  *
4*4321Scasper  * The contents of this file are subject to the terms of the
5*4321Scasper  * Common Development and Distribution License (the "License").
6*4321Scasper  * You may not use this file except in compliance with the License.
7*4321Scasper  *
8*4321Scasper  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4321Scasper  * or http://www.opensolaris.org/os/licensing.
10*4321Scasper  * See the License for the specific language governing permissions
11*4321Scasper  * and limitations under the License.
12*4321Scasper  *
13*4321Scasper  * When distributing Covered Code, include this CDDL HEADER in each
14*4321Scasper  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4321Scasper  * If applicable, add the following below this CDDL HEADER, with the
16*4321Scasper  * fields enclosed by brackets "[]" replaced with your own identifying
17*4321Scasper  * information: Portions Copyright [yyyy] [name of copyright owner]
18*4321Scasper  *
19*4321Scasper  * CDDL HEADER END
20*4321Scasper  */
21*4321Scasper 
22*4321Scasper /*
23*4321Scasper  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*4321Scasper  * Use is subject to license terms.
25*4321Scasper  */
26*4321Scasper 
27*4321Scasper #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*4321Scasper 
29*4321Scasper /*
30*4321Scasper  * Sid manipulation (stubs).
31*4321Scasper  */
32*4321Scasper 
33*4321Scasper #include <sys/atomic.h>
34*4321Scasper #include <sys/avl.h>
35*4321Scasper #include <sys/cmn_err.h>
36*4321Scasper #include <sys/kmem.h>
37*4321Scasper #include <sys/mutex.h>
38*4321Scasper #include <sys/sid.h>
39*4321Scasper #include <sys/sysmacros.h>
40*4321Scasper #include <sys/systm.h>
41*4321Scasper 
42*4321Scasper static kmutex_t sid_lock;
43*4321Scasper static avl_tree_t sid_tree;
44*4321Scasper static boolean_t sid_inited = B_FALSE;
45*4321Scasper 
46*4321Scasper static ksiddomain_t
47*4321Scasper *ksid_enterdomain(const char *dom)
48*4321Scasper {
49*4321Scasper 	size_t len = strlen(dom) + 1;
50*4321Scasper 	ksiddomain_t *res;
51*4321Scasper 
52*4321Scasper 	ASSERT(MUTEX_HELD(&sid_lock));
53*4321Scasper 	res = kmem_alloc(sizeof (ksiddomain_t), KM_SLEEP);
54*4321Scasper 	res->kd_len = (uint_t)len;
55*4321Scasper 	res->kd_name = kmem_alloc(len, KM_SLEEP);
56*4321Scasper 	bcopy(dom, res->kd_name, len);
57*4321Scasper 
58*4321Scasper 	res->kd_ref = 1;
59*4321Scasper 
60*4321Scasper 	avl_add(&sid_tree, res);
61*4321Scasper 
62*4321Scasper 	return (res);
63*4321Scasper }
64*4321Scasper 
65*4321Scasper void
66*4321Scasper ksid_hold(ksid_t *ks)
67*4321Scasper {
68*4321Scasper 	if (ks->ks_domain != NULL)
69*4321Scasper 		ksiddomain_hold(ks->ks_domain);
70*4321Scasper }
71*4321Scasper 
72*4321Scasper void
73*4321Scasper ksid_rele(ksid_t *ks)
74*4321Scasper {
75*4321Scasper 	if (ks->ks_domain != NULL)
76*4321Scasper 		ksiddomain_rele(ks->ks_domain);
77*4321Scasper }
78*4321Scasper 
79*4321Scasper void
80*4321Scasper ksiddomain_hold(ksiddomain_t *kd)
81*4321Scasper {
82*4321Scasper 	atomic_add_32(&kd->kd_ref, 1);
83*4321Scasper }
84*4321Scasper 
85*4321Scasper void
86*4321Scasper ksiddomain_rele(ksiddomain_t *kd)
87*4321Scasper {
88*4321Scasper 	if (atomic_add_32_nv(&kd->kd_ref, -1) == 0) {
89*4321Scasper 		/*
90*4321Scasper 		 * The kd reference can only be incremented from 0 when
91*4321Scasper 		 * the sid_lock is held; so we lock and then check need to
92*4321Scasper 		 * check for 0 again.
93*4321Scasper 		 */
94*4321Scasper 		mutex_enter(&sid_lock);
95*4321Scasper 		if (kd->kd_ref == 0) {
96*4321Scasper 			avl_remove(&sid_tree, kd);
97*4321Scasper 			kmem_free(kd->kd_name, kd->kd_len);
98*4321Scasper 			kmem_free(kd, sizeof (*kd));
99*4321Scasper 		}
100*4321Scasper 		mutex_exit(&sid_lock);
101*4321Scasper 	}
102*4321Scasper }
103*4321Scasper 
104*4321Scasper void
105*4321Scasper ksidlist_hold(ksidlist_t *ksl)
106*4321Scasper {
107*4321Scasper 	atomic_add_32(&ksl->ksl_ref, 1);
108*4321Scasper }
109*4321Scasper 
110*4321Scasper void
111*4321Scasper ksidlist_rele(ksidlist_t *ksl)
112*4321Scasper {
113*4321Scasper 	if (atomic_add_32_nv(&ksl->ksl_ref, -1) == 0) {
114*4321Scasper 		int i;
115*4321Scasper 
116*4321Scasper 		for (i = 0; i < ksl->ksl_nsid; i++)
117*4321Scasper 			ksid_rele(&ksl->ksl_sids[i]);
118*4321Scasper 
119*4321Scasper 		kmem_free(ksl, KSIDLIST_MEM(ksl->ksl_nsid));
120*4321Scasper 	}
121*4321Scasper }
122*4321Scasper 
123*4321Scasper static int
124*4321Scasper ksid_cmp(const void *a, const void *b)
125*4321Scasper {
126*4321Scasper 	const ksiddomain_t *ap = a;
127*4321Scasper 	const ksiddomain_t *bp = b;
128*4321Scasper 	int res;
129*4321Scasper 
130*4321Scasper 	res = strcmp(ap->kd_name, bp->kd_name);
131*4321Scasper 	if (res > 0)
132*4321Scasper 		return (1);
133*4321Scasper 	if (res != 0)
134*4321Scasper 		return (-1);
135*4321Scasper 	return (0);
136*4321Scasper }
137*4321Scasper 
138*4321Scasper /*
139*4321Scasper  * Lookup the named domain in the AVL tree.
140*4321Scasper  * If no entry is found, add the domain to the AVL tree.
141*4321Scasper  * The domain is returned held and needs to be released
142*4321Scasper  * when done.
143*4321Scasper  */
144*4321Scasper ksiddomain_t
145*4321Scasper *ksid_lookupdomain(const char *dom)
146*4321Scasper {
147*4321Scasper 	ksiddomain_t *res;
148*4321Scasper 	ksiddomain_t tmpl;
149*4321Scasper 
150*4321Scasper 	mutex_enter(&sid_lock);
151*4321Scasper 
152*4321Scasper 	if (!sid_inited) {
153*4321Scasper 		avl_create(&sid_tree, ksid_cmp, sizeof (ksiddomain_t),
154*4321Scasper 		    offsetof(ksiddomain_t, kd_link));
155*4321Scasper 
156*4321Scasper 		res = ksid_enterdomain(dom);
157*4321Scasper 		sid_inited = B_TRUE;
158*4321Scasper 		mutex_exit(&sid_lock);
159*4321Scasper 		return (res);
160*4321Scasper 	}
161*4321Scasper 
162*4321Scasper 	tmpl.kd_name = (char *)dom;
163*4321Scasper 
164*4321Scasper 	res = avl_find(&sid_tree, &tmpl, NULL);
165*4321Scasper 	if (res == NULL) {
166*4321Scasper 		res = ksid_enterdomain(dom);
167*4321Scasper 	} else {
168*4321Scasper 		ksiddomain_hold(res);
169*4321Scasper 	}
170*4321Scasper 
171*4321Scasper 	mutex_exit(&sid_lock);
172*4321Scasper 	return (res);
173*4321Scasper }
174*4321Scasper 
175*4321Scasper const char *
176*4321Scasper ksid_getdomain(ksid_t *ks)
177*4321Scasper {
178*4321Scasper 	return (ks->ks_domain->kd_name);
179*4321Scasper }
180*4321Scasper 
181*4321Scasper uint_t
182*4321Scasper ksid_getrid(ksid_t *ks)
183*4321Scasper {
184*4321Scasper 	return (ks->ks_rid);
185*4321Scasper }
186*4321Scasper 
187*4321Scasper int
188*4321Scasper ksid_lookup(uid_t id, ksid_t *res)
189*4321Scasper {
190*4321Scasper 	uid_t tmp;
191*4321Scasper 
192*4321Scasper 	if (idmap_call_byid(id, res) == -1)
193*4321Scasper 		return (-1);
194*4321Scasper 
195*4321Scasper 	tmp = idmap_call_bysid(res);
196*4321Scasper 	if (tmp != id)
197*4321Scasper 		cmn_err(CE_WARN, "The idmapper has gone bonkers");
198*4321Scasper 	res->ks_id = id;
199*4321Scasper 
200*4321Scasper 	return (0);
201*4321Scasper }
202*4321Scasper 
203*4321Scasper credsid_t *
204*4321Scasper kcrsid_alloc(void)
205*4321Scasper {
206*4321Scasper 	credsid_t *kcr = kmem_zalloc(sizeof (*kcr), KM_SLEEP);
207*4321Scasper 	kcr->kr_ref = 1;
208*4321Scasper 	return (kcr);
209*4321Scasper }
210*4321Scasper 
211*4321Scasper /*
212*4321Scasper  * Returns a credsid_t with a refcount of 1.
213*4321Scasper  */
214*4321Scasper static credsid_t *
215*4321Scasper kcrsid_dup(credsid_t *org)
216*4321Scasper {
217*4321Scasper 	credsid_t *new;
218*4321Scasper 	ksid_index_t ki;
219*4321Scasper 
220*4321Scasper 	if (org == NULL)
221*4321Scasper 		return (kcrsid_alloc());
222*4321Scasper 	if (org->kr_ref == 1)
223*4321Scasper 		return (org);
224*4321Scasper 	new = kcrsid_alloc();
225*4321Scasper 
226*4321Scasper 	/* Copy, then update reference counts */
227*4321Scasper 	*new = *org;
228*4321Scasper 	new->kr_ref = 1;
229*4321Scasper 	for (ki = 0; ki < KSID_COUNT; ki++)
230*4321Scasper 		ksid_hold(&new->kr_sidx[ki]);
231*4321Scasper 
232*4321Scasper 	if (new->kr_sidlist != NULL)
233*4321Scasper 		ksidlist_hold(new->kr_sidlist);
234*4321Scasper 
235*4321Scasper 	kcrsid_rele(org);
236*4321Scasper 	return (new);
237*4321Scasper }
238*4321Scasper 
239*4321Scasper void
240*4321Scasper kcrsid_hold(credsid_t *kcr)
241*4321Scasper {
242*4321Scasper 	atomic_add_32(&kcr->kr_ref, 1);
243*4321Scasper }
244*4321Scasper 
245*4321Scasper void
246*4321Scasper kcrsid_rele(credsid_t *kcr)
247*4321Scasper {
248*4321Scasper 	if (atomic_add_32_nv(&kcr->kr_ref, -1) == 0) {
249*4321Scasper 		ksid_index_t i;
250*4321Scasper 
251*4321Scasper 		for (i = 0; i < KSID_COUNT; i++)
252*4321Scasper 			ksid_rele(&kcr->kr_sidx[i]);
253*4321Scasper 
254*4321Scasper 		if (kcr->kr_sidlist != NULL)
255*4321Scasper 			ksidlist_rele(kcr->kr_sidlist);
256*4321Scasper 
257*4321Scasper 		kmem_free(kcr, sizeof (*kcr));
258*4321Scasper 	}
259*4321Scasper }
260*4321Scasper 
261*4321Scasper /*
262*4321Scasper  * Copy the SID credential into a previously allocated piece of memory.
263*4321Scasper  */
264*4321Scasper void
265*4321Scasper kcrsidcopy_to(const credsid_t *okcr, credsid_t *nkcr)
266*4321Scasper {
267*4321Scasper 	int i;
268*4321Scasper 
269*4321Scasper 	ASSERT(nkcr->kr_ref == 1);
270*4321Scasper 
271*4321Scasper 	if (okcr == NULL)
272*4321Scasper 		return;
273*4321Scasper 	*nkcr = *okcr;
274*4321Scasper 	for (i = 0; i < KSID_COUNT; i++)
275*4321Scasper 		ksid_hold(&nkcr->kr_sidx[i]);
276*4321Scasper 	if (nkcr->kr_sidlist != NULL)
277*4321Scasper 		ksidlist_hold(nkcr->kr_sidlist);
278*4321Scasper 	nkcr->kr_ref = 1;
279*4321Scasper }
280*4321Scasper 
281*4321Scasper static int
282*4321Scasper kcrsid_sidcount(const credsid_t *kcr)
283*4321Scasper {
284*4321Scasper 	int cnt = 0;
285*4321Scasper 	int i;
286*4321Scasper 
287*4321Scasper 	if (kcr == NULL)
288*4321Scasper 		return (0);
289*4321Scasper 
290*4321Scasper 	for (i = 0; i < KSID_COUNT; i++)
291*4321Scasper 		if (kcr->kr_sidx[i].ks_domain != NULL)
292*4321Scasper 			cnt++;
293*4321Scasper 
294*4321Scasper 	if (kcr->kr_sidlist != NULL)
295*4321Scasper 		cnt += kcr->kr_sidlist->ksl_nsid;
296*4321Scasper 	return (cnt);
297*4321Scasper }
298*4321Scasper 
299*4321Scasper /*
300*4321Scasper  * Argument needs to be a ksid_t with a properly held ks_domain reference.
301*4321Scasper  */
302*4321Scasper credsid_t *
303*4321Scasper kcrsid_setsid(credsid_t *okcr, ksid_t *ksp, ksid_index_t i)
304*4321Scasper {
305*4321Scasper 	int ocnt = kcrsid_sidcount(okcr);
306*4321Scasper 	credsid_t *nkcr;
307*4321Scasper 
308*4321Scasper 	/*
309*4321Scasper 	 * Unset the particular ksid; if there are no other SIDs or if this
310*4321Scasper 	 * is the last SID, remove the auxilary data structure.
311*4321Scasper 	 */
312*4321Scasper 	if (ksp == NULL) {
313*4321Scasper 		if (ocnt == 0 ||
314*4321Scasper 		    (ocnt == 1 && okcr->kr_sidx[i].ks_domain != NULL)) {
315*4321Scasper 			if (okcr != NULL)
316*4321Scasper 				kcrsid_rele(okcr);
317*4321Scasper 			return (NULL);
318*4321Scasper 		}
319*4321Scasper 	}
320*4321Scasper 	nkcr = kcrsid_dup(okcr);
321*4321Scasper 	ksid_rele(&nkcr->kr_sidx[i]);
322*4321Scasper 	if (ksp == NULL)
323*4321Scasper 		bzero(&nkcr->kr_sidx[i], sizeof (ksid_t));
324*4321Scasper 	else
325*4321Scasper 		nkcr->kr_sidx[i] = *ksp;
326*4321Scasper 
327*4321Scasper 	return (nkcr);
328*4321Scasper }
329*4321Scasper 
330*4321Scasper /*
331*4321Scasper  * Argument needs to be a ksidlist_t with properly held ks_domain references
332*4321Scasper  * and a reference count taking the new reference into account.
333*4321Scasper  */
334*4321Scasper credsid_t *
335*4321Scasper kcrsid_setsidlist(credsid_t *okcr, ksidlist_t *ksl)
336*4321Scasper {
337*4321Scasper 	int ocnt = kcrsid_sidcount(okcr);
338*4321Scasper 	credsid_t *nkcr;
339*4321Scasper 
340*4321Scasper 	/*
341*4321Scasper 	 * Unset the sidlist; if there are no further SIDs, remove the
342*4321Scasper 	 * auxilary data structure.
343*4321Scasper 	 */
344*4321Scasper 	if (ksl == NULL) {
345*4321Scasper 		if (ocnt == 0 || (okcr->kr_sidlist != NULL &&
346*4321Scasper 		    ocnt == okcr->kr_sidlist->ksl_nsid)) {
347*4321Scasper 			if (okcr != NULL)
348*4321Scasper 				kcrsid_rele(okcr);
349*4321Scasper 			return (NULL);
350*4321Scasper 		}
351*4321Scasper 	}
352*4321Scasper 	nkcr = kcrsid_dup(okcr);
353*4321Scasper 	if (nkcr->kr_sidlist != NULL)
354*4321Scasper 		ksidlist_rele(nkcr->kr_sidlist);
355*4321Scasper 
356*4321Scasper 	nkcr->kr_sidlist = ksl;
357*4321Scasper 	return (nkcr);
358*4321Scasper }
359*4321Scasper 
360*4321Scasper ksidlist_t *
361*4321Scasper kcrsid_gidstosids(int ngrp, gid_t *grp)
362*4321Scasper {
363*4321Scasper 	int i;
364*4321Scasper 	ksidlist_t *list;
365*4321Scasper 	int cnt;
366*4321Scasper 
367*4321Scasper 	if (ngrp == 0)
368*4321Scasper 		return (NULL);
369*4321Scasper 
370*4321Scasper 	cnt = 0;
371*4321Scasper 	list = kmem_zalloc(KSIDLIST_MEM(ngrp), KM_SLEEP);
372*4321Scasper 
373*4321Scasper 	list->ksl_nsid = ngrp;
374*4321Scasper 	list->ksl_ref = 1;
375*4321Scasper 
376*4321Scasper 	for (i = 0; i < ngrp; i++) {
377*4321Scasper 		if (grp[i] > MAXUID) {
378*4321Scasper 			list->ksl_neid++;
379*4321Scasper 			if (ksid_lookup(grp[i], &list->ksl_sids[i]) != 0) {
380*4321Scasper 				while (--i >= 0)
381*4321Scasper 					ksid_rele(&list->ksl_sids[i]);
382*4321Scasper 				cnt = 0;
383*4321Scasper 				break;
384*4321Scasper 			}
385*4321Scasper 			cnt++;
386*4321Scasper 		} else {
387*4321Scasper 			list->ksl_sids[i].ks_id = grp[i];
388*4321Scasper 		}
389*4321Scasper 	}
390*4321Scasper 	if (cnt == 0) {
391*4321Scasper 		kmem_free(list, KSIDLIST_MEM(ngrp));
392*4321Scasper 		return (NULL);
393*4321Scasper 	}
394*4321Scasper 	return (list);
395*4321Scasper }
396