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