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