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