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