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