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