1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/zfs_context.h> 27 #include <sys/sunddi.h> 28 #include <sys/dmu.h> 29 #include <sys/avl.h> 30 #include <sys/zap.h> 31 #include <sys/refcount.h> 32 #include <sys/nvpair.h> 33 #ifdef _KERNEL 34 #include <sys/kidmap.h> 35 #include <sys/sid.h> 36 #include <sys/zfs_vfsops.h> 37 #include <sys/zfs_znode.h> 38 #endif 39 #include <sys/zfs_fuid.h> 40 41 /* 42 * FUID Domain table(s). 43 * 44 * The FUID table is stored as a packed nvlist of an array 45 * of nvlists which contain an index, domain string and offset 46 * 47 * During file system initialization the nvlist(s) are read and 48 * two AVL trees are created. One tree is keyed by the index number 49 * and the other by the domain string. Nodes are never removed from 50 * trees, but new entries may be added. If a new entry is added then the 51 * on-disk packed nvlist will also be updated. 52 */ 53 54 #define FUID_IDX "fuid_idx" 55 #define FUID_DOMAIN "fuid_domain" 56 #define FUID_OFFSET "fuid_offset" 57 #define FUID_NVP_ARRAY "fuid_nvlist" 58 59 typedef struct fuid_domain { 60 avl_node_t f_domnode; 61 avl_node_t f_idxnode; 62 ksiddomain_t *f_ksid; 63 uint64_t f_idx; 64 } fuid_domain_t; 65 66 /* 67 * Compare two indexes. 68 */ 69 static int 70 idx_compare(const void *arg1, const void *arg2) 71 { 72 const fuid_domain_t *node1 = arg1; 73 const fuid_domain_t *node2 = arg2; 74 75 if (node1->f_idx < node2->f_idx) 76 return (-1); 77 else if (node1->f_idx > node2->f_idx) 78 return (1); 79 return (0); 80 } 81 82 /* 83 * Compare two domain strings. 84 */ 85 static int 86 domain_compare(const void *arg1, const void *arg2) 87 { 88 const fuid_domain_t *node1 = arg1; 89 const fuid_domain_t *node2 = arg2; 90 int val; 91 92 val = strcmp(node1->f_ksid->kd_name, node2->f_ksid->kd_name); 93 if (val == 0) 94 return (0); 95 return (val > 0 ? 1 : -1); 96 } 97 98 /* 99 * load initial fuid domain and idx trees. This function is used by 100 * both the kernel and zdb. 101 */ 102 uint64_t 103 zfs_fuid_table_load(objset_t *os, uint64_t fuid_obj, avl_tree_t *idx_tree, 104 avl_tree_t *domain_tree) 105 { 106 dmu_buf_t *db; 107 uint64_t fuid_size; 108 109 avl_create(idx_tree, idx_compare, 110 sizeof (fuid_domain_t), offsetof(fuid_domain_t, f_idxnode)); 111 avl_create(domain_tree, domain_compare, 112 sizeof (fuid_domain_t), offsetof(fuid_domain_t, f_domnode)); 113 114 VERIFY(0 == dmu_bonus_hold(os, fuid_obj, FTAG, &db)); 115 fuid_size = *(uint64_t *)db->db_data; 116 dmu_buf_rele(db, FTAG); 117 118 if (fuid_size) { 119 nvlist_t **fuidnvp; 120 nvlist_t *nvp = NULL; 121 uint_t count; 122 char *packed; 123 int i; 124 125 packed = kmem_alloc(fuid_size, KM_SLEEP); 126 VERIFY(dmu_read(os, fuid_obj, 0, fuid_size, packed) == 0); 127 VERIFY(nvlist_unpack(packed, fuid_size, 128 &nvp, 0) == 0); 129 VERIFY(nvlist_lookup_nvlist_array(nvp, FUID_NVP_ARRAY, 130 &fuidnvp, &count) == 0); 131 132 for (i = 0; i != count; i++) { 133 fuid_domain_t *domnode; 134 char *domain; 135 uint64_t idx; 136 137 VERIFY(nvlist_lookup_string(fuidnvp[i], FUID_DOMAIN, 138 &domain) == 0); 139 VERIFY(nvlist_lookup_uint64(fuidnvp[i], FUID_IDX, 140 &idx) == 0); 141 142 domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP); 143 144 domnode->f_idx = idx; 145 domnode->f_ksid = ksid_lookupdomain(domain); 146 avl_add(idx_tree, domnode); 147 avl_add(domain_tree, domnode); 148 } 149 nvlist_free(nvp); 150 kmem_free(packed, fuid_size); 151 } 152 return (fuid_size); 153 } 154 155 void 156 zfs_fuid_table_destroy(avl_tree_t *idx_tree, avl_tree_t *domain_tree) 157 { 158 fuid_domain_t *domnode; 159 void *cookie; 160 161 cookie = NULL; 162 while (domnode = avl_destroy_nodes(domain_tree, &cookie)) 163 ksiddomain_rele(domnode->f_ksid); 164 165 avl_destroy(domain_tree); 166 cookie = NULL; 167 while (domnode = avl_destroy_nodes(idx_tree, &cookie)) 168 kmem_free(domnode, sizeof (fuid_domain_t)); 169 avl_destroy(idx_tree); 170 } 171 172 char * 173 zfs_fuid_idx_domain(avl_tree_t *idx_tree, uint32_t idx) 174 { 175 fuid_domain_t searchnode, *findnode; 176 avl_index_t loc; 177 178 searchnode.f_idx = idx; 179 180 findnode = avl_find(idx_tree, &searchnode, &loc); 181 182 return (findnode->f_ksid->kd_name); 183 } 184 185 #ifdef _KERNEL 186 /* 187 * Load the fuid table(s) into memory. 188 */ 189 static void 190 zfs_fuid_init(zfsvfs_t *zfsvfs, dmu_tx_t *tx) 191 { 192 int error = 0; 193 194 rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER); 195 196 if (zfsvfs->z_fuid_loaded) { 197 rw_exit(&zfsvfs->z_fuid_lock); 198 return; 199 } 200 201 if (zfsvfs->z_fuid_obj == 0) { 202 203 /* first make sure we need to allocate object */ 204 205 error = zap_lookup(zfsvfs->z_os, MASTER_NODE_OBJ, 206 ZFS_FUID_TABLES, 8, 1, &zfsvfs->z_fuid_obj); 207 if (error == ENOENT && tx != NULL) { 208 zfsvfs->z_fuid_obj = dmu_object_alloc(zfsvfs->z_os, 209 DMU_OT_FUID, 1 << 14, DMU_OT_FUID_SIZE, 210 sizeof (uint64_t), tx); 211 VERIFY(zap_add(zfsvfs->z_os, MASTER_NODE_OBJ, 212 ZFS_FUID_TABLES, sizeof (uint64_t), 1, 213 &zfsvfs->z_fuid_obj, tx) == 0); 214 } 215 } 216 217 zfsvfs->z_fuid_size = zfs_fuid_table_load(zfsvfs->z_os, 218 zfsvfs->z_fuid_obj, &zfsvfs->z_fuid_idx, &zfsvfs->z_fuid_domain); 219 220 zfsvfs->z_fuid_loaded = B_TRUE; 221 rw_exit(&zfsvfs->z_fuid_lock); 222 } 223 224 /* 225 * Query domain table for a given domain. 226 * 227 * If domain isn't found it is added to AVL trees and 228 * the results are pushed out to disk. 229 */ 230 int 231 zfs_fuid_find_by_domain(zfsvfs_t *zfsvfs, const char *domain, char **retdomain, 232 dmu_tx_t *tx) 233 { 234 fuid_domain_t searchnode, *findnode; 235 avl_index_t loc; 236 krw_t rw = RW_READER; 237 238 /* 239 * If the dummy "nobody" domain then return an index of 0 240 * to cause the created FUID to be a standard POSIX id 241 * for the user nobody. 242 */ 243 if (domain[0] == '\0') { 244 *retdomain = ""; 245 return (0); 246 } 247 248 searchnode.f_ksid = ksid_lookupdomain(domain); 249 if (retdomain) { 250 *retdomain = searchnode.f_ksid->kd_name; 251 } 252 if (!zfsvfs->z_fuid_loaded) 253 zfs_fuid_init(zfsvfs, tx); 254 255 retry: 256 rw_enter(&zfsvfs->z_fuid_lock, rw); 257 findnode = avl_find(&zfsvfs->z_fuid_domain, &searchnode, &loc); 258 259 if (findnode) { 260 rw_exit(&zfsvfs->z_fuid_lock); 261 ksiddomain_rele(searchnode.f_ksid); 262 return (findnode->f_idx); 263 } else { 264 fuid_domain_t *domnode; 265 nvlist_t *nvp; 266 nvlist_t **fuids; 267 uint64_t retidx; 268 size_t nvsize = 0; 269 char *packed; 270 dmu_buf_t *db; 271 int i = 0; 272 273 if (rw == RW_READER && !rw_tryupgrade(&zfsvfs->z_fuid_lock)) { 274 rw_exit(&zfsvfs->z_fuid_lock); 275 rw = RW_WRITER; 276 goto retry; 277 } 278 279 domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP); 280 domnode->f_ksid = searchnode.f_ksid; 281 282 retidx = domnode->f_idx = avl_numnodes(&zfsvfs->z_fuid_idx) + 1; 283 284 avl_add(&zfsvfs->z_fuid_domain, domnode); 285 avl_add(&zfsvfs->z_fuid_idx, domnode); 286 /* 287 * Now resync the on-disk nvlist. 288 */ 289 VERIFY(nvlist_alloc(&nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 290 291 domnode = avl_first(&zfsvfs->z_fuid_domain); 292 fuids = kmem_alloc(retidx * sizeof (void *), KM_SLEEP); 293 while (domnode) { 294 VERIFY(nvlist_alloc(&fuids[i], 295 NV_UNIQUE_NAME, KM_SLEEP) == 0); 296 VERIFY(nvlist_add_uint64(fuids[i], FUID_IDX, 297 domnode->f_idx) == 0); 298 VERIFY(nvlist_add_uint64(fuids[i], 299 FUID_OFFSET, 0) == 0); 300 VERIFY(nvlist_add_string(fuids[i++], FUID_DOMAIN, 301 domnode->f_ksid->kd_name) == 0); 302 domnode = AVL_NEXT(&zfsvfs->z_fuid_domain, domnode); 303 } 304 VERIFY(nvlist_add_nvlist_array(nvp, FUID_NVP_ARRAY, 305 fuids, retidx) == 0); 306 for (i = 0; i != retidx; i++) 307 nvlist_free(fuids[i]); 308 kmem_free(fuids, retidx * sizeof (void *)); 309 VERIFY(nvlist_size(nvp, &nvsize, NV_ENCODE_XDR) == 0); 310 packed = kmem_alloc(nvsize, KM_SLEEP); 311 VERIFY(nvlist_pack(nvp, &packed, &nvsize, 312 NV_ENCODE_XDR, KM_SLEEP) == 0); 313 nvlist_free(nvp); 314 zfsvfs->z_fuid_size = nvsize; 315 dmu_write(zfsvfs->z_os, zfsvfs->z_fuid_obj, 0, 316 zfsvfs->z_fuid_size, packed, tx); 317 kmem_free(packed, zfsvfs->z_fuid_size); 318 VERIFY(0 == dmu_bonus_hold(zfsvfs->z_os, zfsvfs->z_fuid_obj, 319 FTAG, &db)); 320 dmu_buf_will_dirty(db, tx); 321 *(uint64_t *)db->db_data = zfsvfs->z_fuid_size; 322 dmu_buf_rele(db, FTAG); 323 324 rw_exit(&zfsvfs->z_fuid_lock); 325 return (retidx); 326 } 327 } 328 329 /* 330 * Query domain table by index, returning domain string 331 * 332 * Returns a pointer from an avl node of the domain string. 333 * 334 */ 335 static char * 336 zfs_fuid_find_by_idx(zfsvfs_t *zfsvfs, uint32_t idx) 337 { 338 char *domain; 339 340 if (idx == 0 || !zfsvfs->z_use_fuids) 341 return (NULL); 342 343 if (!zfsvfs->z_fuid_loaded) 344 zfs_fuid_init(zfsvfs, NULL); 345 346 rw_enter(&zfsvfs->z_fuid_lock, RW_READER); 347 domain = zfs_fuid_idx_domain(&zfsvfs->z_fuid_idx, idx); 348 rw_exit(&zfsvfs->z_fuid_lock); 349 350 ASSERT(domain); 351 return (domain); 352 } 353 354 void 355 zfs_fuid_map_ids(znode_t *zp, cred_t *cr, uid_t *uidp, uid_t *gidp) 356 { 357 *uidp = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_phys->zp_uid, 358 cr, ZFS_OWNER); 359 *gidp = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_phys->zp_gid, 360 cr, ZFS_GROUP); 361 } 362 363 uid_t 364 zfs_fuid_map_id(zfsvfs_t *zfsvfs, uint64_t fuid, 365 cred_t *cr, zfs_fuid_type_t type) 366 { 367 uint32_t index = FUID_INDEX(fuid); 368 char *domain; 369 uid_t id; 370 371 if (index == 0) 372 return (fuid); 373 374 domain = zfs_fuid_find_by_idx(zfsvfs, index); 375 ASSERT(domain != NULL); 376 377 if (type == ZFS_OWNER || type == ZFS_ACE_USER) { 378 (void) kidmap_getuidbysid(crgetzone(cr), domain, 379 FUID_RID(fuid), &id); 380 } else { 381 (void) kidmap_getgidbysid(crgetzone(cr), domain, 382 FUID_RID(fuid), &id); 383 } 384 return (id); 385 } 386 387 /* 388 * Add a FUID node to the list of fuid's being created for this 389 * ACL 390 * 391 * If ACL has multiple domains, then keep only one copy of each unique 392 * domain. 393 */ 394 static void 395 zfs_fuid_node_add(zfs_fuid_info_t **fuidpp, const char *domain, uint32_t rid, 396 uint64_t idx, uint64_t id, zfs_fuid_type_t type) 397 { 398 zfs_fuid_t *fuid; 399 zfs_fuid_domain_t *fuid_domain; 400 zfs_fuid_info_t *fuidp; 401 uint64_t fuididx; 402 boolean_t found = B_FALSE; 403 404 if (*fuidpp == NULL) 405 *fuidpp = zfs_fuid_info_alloc(); 406 407 fuidp = *fuidpp; 408 /* 409 * First find fuid domain index in linked list 410 * 411 * If one isn't found then create an entry. 412 */ 413 414 for (fuididx = 1, fuid_domain = list_head(&fuidp->z_domains); 415 fuid_domain; fuid_domain = list_next(&fuidp->z_domains, 416 fuid_domain), fuididx++) { 417 if (idx == fuid_domain->z_domidx) { 418 found = B_TRUE; 419 break; 420 } 421 } 422 423 if (!found) { 424 fuid_domain = kmem_alloc(sizeof (zfs_fuid_domain_t), KM_SLEEP); 425 fuid_domain->z_domain = domain; 426 fuid_domain->z_domidx = idx; 427 list_insert_tail(&fuidp->z_domains, fuid_domain); 428 fuidp->z_domain_str_sz += strlen(domain) + 1; 429 fuidp->z_domain_cnt++; 430 } 431 432 if (type == ZFS_ACE_USER || type == ZFS_ACE_GROUP) { 433 /* 434 * Now allocate fuid entry and add it on the end of the list 435 */ 436 437 fuid = kmem_alloc(sizeof (zfs_fuid_t), KM_SLEEP); 438 fuid->z_id = id; 439 fuid->z_domidx = idx; 440 fuid->z_logfuid = FUID_ENCODE(fuididx, rid); 441 442 list_insert_tail(&fuidp->z_fuids, fuid); 443 fuidp->z_fuid_cnt++; 444 } else { 445 if (type == ZFS_OWNER) 446 fuidp->z_fuid_owner = FUID_ENCODE(fuididx, rid); 447 else 448 fuidp->z_fuid_group = FUID_ENCODE(fuididx, rid); 449 } 450 } 451 452 /* 453 * Create a file system FUID, based on information in the users cred 454 */ 455 uint64_t 456 zfs_fuid_create_cred(zfsvfs_t *zfsvfs, zfs_fuid_type_t type, 457 dmu_tx_t *tx, cred_t *cr, zfs_fuid_info_t **fuidp) 458 { 459 uint64_t idx; 460 ksid_t *ksid; 461 uint32_t rid; 462 char *kdomain; 463 const char *domain; 464 uid_t id; 465 466 VERIFY(type == ZFS_OWNER || type == ZFS_GROUP); 467 468 if (type == ZFS_OWNER) 469 id = crgetuid(cr); 470 else 471 id = crgetgid(cr); 472 473 if (!zfsvfs->z_use_fuids || !IS_EPHEMERAL(id)) 474 return ((uint64_t)id); 475 476 ksid = crgetsid(cr, (type == ZFS_OWNER) ? KSID_OWNER : KSID_GROUP); 477 478 VERIFY(ksid != NULL); 479 rid = ksid_getrid(ksid); 480 domain = ksid_getdomain(ksid); 481 482 idx = zfs_fuid_find_by_domain(zfsvfs, domain, &kdomain, tx); 483 484 zfs_fuid_node_add(fuidp, kdomain, rid, idx, id, type); 485 486 return (FUID_ENCODE(idx, rid)); 487 } 488 489 /* 490 * Create a file system FUID for an ACL ace 491 * or a chown/chgrp of the file. 492 * This is similar to zfs_fuid_create_cred, except that 493 * we can't find the domain + rid information in the 494 * cred. Instead we have to query Winchester for the 495 * domain and rid. 496 * 497 * During replay operations the domain+rid information is 498 * found in the zfs_fuid_info_t that the replay code has 499 * attached to the zfsvfs of the file system. 500 */ 501 uint64_t 502 zfs_fuid_create(zfsvfs_t *zfsvfs, uint64_t id, cred_t *cr, 503 zfs_fuid_type_t type, dmu_tx_t *tx, zfs_fuid_info_t **fuidpp) 504 { 505 const char *domain; 506 char *kdomain; 507 uint32_t fuid_idx = FUID_INDEX(id); 508 uint32_t rid; 509 idmap_stat status; 510 uint64_t idx; 511 boolean_t is_replay = (zfsvfs->z_assign >= TXG_INITIAL); 512 zfs_fuid_t *zfuid = NULL; 513 zfs_fuid_info_t *fuidp; 514 515 /* 516 * If POSIX ID, or entry is already a FUID then 517 * just return the id 518 * 519 * We may also be handed an already FUID'ized id via 520 * chmod. 521 */ 522 523 if (!zfsvfs->z_use_fuids || !IS_EPHEMERAL(id) || fuid_idx != 0) 524 return (id); 525 526 if (is_replay) { 527 fuidp = zfsvfs->z_fuid_replay; 528 529 /* 530 * If we are passed an ephemeral id, but no 531 * fuid_info was logged then return NOBODY. 532 * This is most likely a result of idmap service 533 * not being available. 534 */ 535 if (fuidp == NULL) 536 return (UID_NOBODY); 537 538 switch (type) { 539 case ZFS_ACE_USER: 540 case ZFS_ACE_GROUP: 541 zfuid = list_head(&fuidp->z_fuids); 542 rid = FUID_RID(zfuid->z_logfuid); 543 idx = FUID_INDEX(zfuid->z_logfuid); 544 break; 545 case ZFS_OWNER: 546 rid = FUID_RID(fuidp->z_fuid_owner); 547 idx = FUID_INDEX(fuidp->z_fuid_owner); 548 break; 549 case ZFS_GROUP: 550 rid = FUID_RID(fuidp->z_fuid_group); 551 idx = FUID_INDEX(fuidp->z_fuid_group); 552 break; 553 }; 554 domain = fuidp->z_domain_table[idx -1]; 555 } else { 556 if (type == ZFS_OWNER || type == ZFS_ACE_USER) 557 status = kidmap_getsidbyuid(crgetzone(cr), id, 558 &domain, &rid); 559 else 560 status = kidmap_getsidbygid(crgetzone(cr), id, 561 &domain, &rid); 562 563 if (status != 0) { 564 /* 565 * When returning nobody we will need to 566 * make a dummy fuid table entry for logging 567 * purposes. 568 */ 569 rid = UID_NOBODY; 570 domain = ""; 571 } 572 } 573 574 idx = zfs_fuid_find_by_domain(zfsvfs, domain, &kdomain, tx); 575 576 if (!is_replay) 577 zfs_fuid_node_add(fuidpp, kdomain, rid, idx, id, type); 578 else if (zfuid != NULL) { 579 list_remove(&fuidp->z_fuids, zfuid); 580 kmem_free(zfuid, sizeof (zfs_fuid_t)); 581 } 582 return (FUID_ENCODE(idx, rid)); 583 } 584 585 void 586 zfs_fuid_destroy(zfsvfs_t *zfsvfs) 587 { 588 rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER); 589 if (!zfsvfs->z_fuid_loaded) { 590 rw_exit(&zfsvfs->z_fuid_lock); 591 return; 592 } 593 zfs_fuid_table_destroy(&zfsvfs->z_fuid_idx, &zfsvfs->z_fuid_domain); 594 rw_exit(&zfsvfs->z_fuid_lock); 595 } 596 597 /* 598 * Allocate zfs_fuid_info for tracking FUIDs created during 599 * zfs_mknode, VOP_SETATTR() or VOP_SETSECATTR() 600 */ 601 zfs_fuid_info_t * 602 zfs_fuid_info_alloc(void) 603 { 604 zfs_fuid_info_t *fuidp; 605 606 fuidp = kmem_zalloc(sizeof (zfs_fuid_info_t), KM_SLEEP); 607 list_create(&fuidp->z_domains, sizeof (zfs_fuid_domain_t), 608 offsetof(zfs_fuid_domain_t, z_next)); 609 list_create(&fuidp->z_fuids, sizeof (zfs_fuid_t), 610 offsetof(zfs_fuid_t, z_next)); 611 return (fuidp); 612 } 613 614 /* 615 * Release all memory associated with zfs_fuid_info_t 616 */ 617 void 618 zfs_fuid_info_free(zfs_fuid_info_t *fuidp) 619 { 620 zfs_fuid_t *zfuid; 621 zfs_fuid_domain_t *zdomain; 622 623 while ((zfuid = list_head(&fuidp->z_fuids)) != NULL) { 624 list_remove(&fuidp->z_fuids, zfuid); 625 kmem_free(zfuid, sizeof (zfs_fuid_t)); 626 } 627 628 if (fuidp->z_domain_table != NULL) 629 kmem_free(fuidp->z_domain_table, 630 (sizeof (char **)) * fuidp->z_domain_cnt); 631 632 while ((zdomain = list_head(&fuidp->z_domains)) != NULL) { 633 list_remove(&fuidp->z_domains, zdomain); 634 kmem_free(zdomain, sizeof (zfs_fuid_domain_t)); 635 } 636 637 kmem_free(fuidp, sizeof (zfs_fuid_info_t)); 638 } 639 640 /* 641 * Check to see if id is a groupmember. If cred 642 * has ksid info then sidlist is checked first 643 * and if still not found then POSIX groups are checked 644 * 645 * Will use a straight FUID compare when possible. 646 */ 647 boolean_t 648 zfs_groupmember(zfsvfs_t *zfsvfs, uint64_t id, cred_t *cr) 649 { 650 ksid_t *ksid = crgetsid(cr, KSID_GROUP); 651 uid_t gid; 652 653 if (ksid) { 654 int i; 655 ksid_t *ksid_groups; 656 ksidlist_t *ksidlist = crgetsidlist(cr); 657 uint32_t idx = FUID_INDEX(id); 658 uint32_t rid = FUID_RID(id); 659 660 ASSERT(ksidlist); 661 ksid_groups = ksidlist->ksl_sids; 662 663 for (i = 0; i != ksidlist->ksl_nsid; i++) { 664 if (idx == 0) { 665 if (id != IDMAP_WK_CREATOR_GROUP_GID && 666 id == ksid_groups[i].ks_id) { 667 return (B_TRUE); 668 } 669 } else { 670 char *domain; 671 672 domain = zfs_fuid_find_by_idx(zfsvfs, idx); 673 ASSERT(domain != NULL); 674 675 if (strcmp(domain, 676 IDMAP_WK_CREATOR_SID_AUTHORITY) == 0) 677 return (B_FALSE); 678 679 if ((strcmp(domain, 680 ksid_groups[i].ks_domain->kd_name) == 0) && 681 rid == ksid_groups[i].ks_rid) 682 return (B_TRUE); 683 } 684 } 685 } 686 687 /* 688 * Not found in ksidlist, check posix groups 689 */ 690 gid = zfs_fuid_map_id(zfsvfs, id, cr, ZFS_GROUP); 691 return (groupmember(gid, cr)); 692 } 693 #endif 694