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