5045 use atomic_{inc,dec}_* instead of atomic_add_*
[illumos-gate.git] / usr / src / uts / common / os / sid.c
blobe2aa18dc203d031b65674de69b5cefd9e5fa089e
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Sid manipulation (stubs).
31 #include <sys/atomic.h>
32 #include <sys/avl.h>
33 #include <sys/cmn_err.h>
34 #include <sys/kmem.h>
35 #include <sys/mutex.h>
36 #include <sys/sid.h>
37 #include <sys/sysmacros.h>
38 #include <sys/systm.h>
39 #include <sys/kidmap.h>
40 #include <sys/idmap.h>
42 static kmutex_t sid_lock;
43 static avl_tree_t sid_tree;
44 static boolean_t sid_inited = B_FALSE;
46 static ksiddomain_t
47 *ksid_enterdomain(const char *dom)
49 size_t len = strlen(dom) + 1;
50 ksiddomain_t *res;
52 ASSERT(MUTEX_HELD(&sid_lock));
53 res = kmem_alloc(sizeof (ksiddomain_t), KM_SLEEP);
54 res->kd_len = (uint_t)len;
55 res->kd_name = kmem_alloc(len, KM_SLEEP);
56 bcopy(dom, res->kd_name, len);
58 res->kd_ref = 1;
60 avl_add(&sid_tree, res);
62 return (res);
65 void
66 ksid_hold(ksid_t *ks)
68 if (ks->ks_domain != NULL)
69 ksiddomain_hold(ks->ks_domain);
72 void
73 ksid_rele(ksid_t *ks)
75 if (ks->ks_domain != NULL)
76 ksiddomain_rele(ks->ks_domain);
79 void
80 ksiddomain_hold(ksiddomain_t *kd)
82 atomic_inc_32(&kd->kd_ref);
85 void
86 ksiddomain_rele(ksiddomain_t *kd)
88 if (atomic_dec_32_nv(&kd->kd_ref) == 0) {
90 * The kd reference can only be incremented from 0 when
91 * the sid_lock is held; so we lock and then check need to
92 * check for 0 again.
94 mutex_enter(&sid_lock);
95 if (kd->kd_ref == 0) {
96 avl_remove(&sid_tree, kd);
97 kmem_free(kd->kd_name, kd->kd_len);
98 kmem_free(kd, sizeof (*kd));
100 mutex_exit(&sid_lock);
104 void
105 ksidlist_hold(ksidlist_t *ksl)
107 atomic_inc_32(&ksl->ksl_ref);
110 void
111 ksidlist_rele(ksidlist_t *ksl)
113 if (atomic_dec_32_nv(&ksl->ksl_ref) == 0) {
114 int i;
116 for (i = 0; i < ksl->ksl_nsid; i++)
117 ksid_rele(&ksl->ksl_sids[i]);
119 kmem_free(ksl, KSIDLIST_MEM(ksl->ksl_nsid));
123 static int
124 ksid_cmp(const void *a, const void *b)
126 const ksiddomain_t *ap = a;
127 const ksiddomain_t *bp = b;
128 int res;
130 res = strcmp(ap->kd_name, bp->kd_name);
131 if (res > 0)
132 return (1);
133 if (res != 0)
134 return (-1);
135 return (0);
139 * Lookup the named domain in the AVL tree.
140 * If no entry is found, add the domain to the AVL tree.
141 * The domain is returned held and needs to be released
142 * when done.
144 ksiddomain_t
145 *ksid_lookupdomain(const char *dom)
147 ksiddomain_t *res;
148 ksiddomain_t tmpl;
150 mutex_enter(&sid_lock);
152 if (!sid_inited) {
153 avl_create(&sid_tree, ksid_cmp, sizeof (ksiddomain_t),
154 offsetof(ksiddomain_t, kd_link));
156 res = ksid_enterdomain(dom);
157 sid_inited = B_TRUE;
158 mutex_exit(&sid_lock);
159 return (res);
162 tmpl.kd_name = (char *)dom;
164 res = avl_find(&sid_tree, &tmpl, NULL);
165 if (res == NULL) {
166 res = ksid_enterdomain(dom);
167 } else {
168 ksiddomain_hold(res);
171 mutex_exit(&sid_lock);
172 return (res);
175 const char *
176 ksid_getdomain(ksid_t *ks)
178 return (ks->ks_domain->kd_name);
181 uint_t
182 ksid_getrid(ksid_t *ks)
184 return (ks->ks_rid);
187 uid_t
188 ksid_getid(ksid_t *ks)
190 return (ks->ks_id);
194 ksid_lookupbyuid(zone_t *zone, uid_t id, ksid_t *res)
196 const char *sid_prefix;
198 if (kidmap_getsidbyuid(zone, id, &sid_prefix, &res->ks_rid)
199 != IDMAP_SUCCESS)
200 return (-1);
202 res->ks_domain = ksid_lookupdomain(sid_prefix);
204 res->ks_id = id;
206 return (0);
210 ksid_lookupbygid(zone_t *zone, gid_t id, ksid_t *res)
212 const char *sid_prefix;
214 if (kidmap_getsidbygid(zone, id, &sid_prefix, &res->ks_rid)
215 != IDMAP_SUCCESS)
216 return (-1);
218 res->ks_domain = ksid_lookupdomain(sid_prefix);
220 res->ks_id = id;
222 return (0);
225 credsid_t *
226 kcrsid_alloc(void)
228 credsid_t *kcr = kmem_zalloc(sizeof (*kcr), KM_SLEEP);
229 kcr->kr_ref = 1;
230 return (kcr);
234 * Returns a credsid_t with a refcount of 1.
236 static credsid_t *
237 kcrsid_dup(credsid_t *org)
239 credsid_t *new;
240 ksid_index_t ki;
242 if (org == NULL)
243 return (kcrsid_alloc());
244 if (org->kr_ref == 1)
245 return (org);
246 new = kcrsid_alloc();
248 /* Copy, then update reference counts */
249 *new = *org;
250 new->kr_ref = 1;
251 for (ki = 0; ki < KSID_COUNT; ki++)
252 ksid_hold(&new->kr_sidx[ki]);
254 if (new->kr_sidlist != NULL)
255 ksidlist_hold(new->kr_sidlist);
257 kcrsid_rele(org);
258 return (new);
261 void
262 kcrsid_hold(credsid_t *kcr)
264 atomic_inc_32(&kcr->kr_ref);
267 void
268 kcrsid_rele(credsid_t *kcr)
270 if (atomic_dec_32_nv(&kcr->kr_ref) == 0) {
271 ksid_index_t i;
273 for (i = 0; i < KSID_COUNT; i++)
274 ksid_rele(&kcr->kr_sidx[i]);
276 if (kcr->kr_sidlist != NULL)
277 ksidlist_rele(kcr->kr_sidlist);
279 kmem_free(kcr, sizeof (*kcr));
284 * Copy the SID credential into a previously allocated piece of memory.
286 void
287 kcrsidcopy_to(const credsid_t *okcr, credsid_t *nkcr)
289 int i;
291 ASSERT(nkcr->kr_ref == 1);
293 if (okcr == NULL)
294 return;
295 *nkcr = *okcr;
296 for (i = 0; i < KSID_COUNT; i++)
297 ksid_hold(&nkcr->kr_sidx[i]);
298 if (nkcr->kr_sidlist != NULL)
299 ksidlist_hold(nkcr->kr_sidlist);
300 nkcr->kr_ref = 1;
303 static int
304 kcrsid_sidcount(const credsid_t *kcr)
306 int cnt = 0;
307 int i;
309 if (kcr == NULL)
310 return (0);
312 for (i = 0; i < KSID_COUNT; i++)
313 if (kcr->kr_sidx[i].ks_domain != NULL)
314 cnt++;
316 if (kcr->kr_sidlist != NULL)
317 cnt += kcr->kr_sidlist->ksl_nsid;
318 return (cnt);
322 * Argument needs to be a ksid_t with a properly held ks_domain reference.
324 credsid_t *
325 kcrsid_setsid(credsid_t *okcr, ksid_t *ksp, ksid_index_t i)
327 int ocnt = kcrsid_sidcount(okcr);
328 credsid_t *nkcr;
331 * Unset the particular ksid; if there are no other SIDs or if this
332 * is the last SID, remove the auxilary data structure.
334 if (ksp == NULL) {
335 if (ocnt == 0 ||
336 (ocnt == 1 && okcr->kr_sidx[i].ks_domain != NULL)) {
337 if (okcr != NULL)
338 kcrsid_rele(okcr);
339 return (NULL);
342 nkcr = kcrsid_dup(okcr);
343 ksid_rele(&nkcr->kr_sidx[i]);
344 if (ksp == NULL)
345 bzero(&nkcr->kr_sidx[i], sizeof (ksid_t));
346 else
347 nkcr->kr_sidx[i] = *ksp;
349 return (nkcr);
353 * Argument needs to be a ksidlist_t with properly held ks_domain references
354 * and a reference count taking the new reference into account.
356 credsid_t *
357 kcrsid_setsidlist(credsid_t *okcr, ksidlist_t *ksl)
359 int ocnt = kcrsid_sidcount(okcr);
360 credsid_t *nkcr;
363 * Unset the sidlist; if there are no further SIDs, remove the
364 * auxilary data structure.
366 if (ksl == NULL) {
367 if (ocnt == 0 || (okcr->kr_sidlist != NULL &&
368 ocnt == okcr->kr_sidlist->ksl_nsid)) {
369 if (okcr != NULL)
370 kcrsid_rele(okcr);
371 return (NULL);
374 nkcr = kcrsid_dup(okcr);
375 if (nkcr->kr_sidlist != NULL)
376 ksidlist_rele(nkcr->kr_sidlist);
378 nkcr->kr_sidlist = ksl;
379 return (nkcr);
382 ksidlist_t *
383 kcrsid_gidstosids(zone_t *zone, int ngrp, gid_t *grp)
385 int i;
386 ksidlist_t *list;
387 int cnt;
389 if (ngrp == 0)
390 return (NULL);
392 cnt = 0;
393 list = kmem_zalloc(KSIDLIST_MEM(ngrp), KM_SLEEP);
395 list->ksl_nsid = ngrp;
396 list->ksl_ref = 1;
398 for (i = 0; i < ngrp; i++) {
399 if (grp[i] > MAXUID) {
400 list->ksl_neid++;
401 if (ksid_lookupbygid(zone,
402 grp[i], &list->ksl_sids[i]) != 0) {
403 while (--i >= 0)
404 ksid_rele(&list->ksl_sids[i]);
405 cnt = 0;
406 break;
408 cnt++;
409 } else {
410 list->ksl_sids[i].ks_id = grp[i];
413 if (cnt == 0) {
414 kmem_free(list, KSIDLIST_MEM(ngrp));
415 return (NULL);
417 return (list);