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