1*4543Smarks /* 2*4543Smarks * CDDL HEADER START 3*4543Smarks * 4*4543Smarks * The contents of this file are subject to the terms of the 5*4543Smarks * Common Development and Distribution License (the "License"). 6*4543Smarks * You may not use this file except in compliance with the License. 7*4543Smarks * 8*4543Smarks * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*4543Smarks * or http://www.opensolaris.org/os/licensing. 10*4543Smarks * See the License for the specific language governing permissions 11*4543Smarks * and limitations under the License. 12*4543Smarks * 13*4543Smarks * When distributing Covered Code, include this CDDL HEADER in each 14*4543Smarks * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*4543Smarks * If applicable, add the following below this CDDL HEADER, with the 16*4543Smarks * fields enclosed by brackets "[]" replaced with your own identifying 17*4543Smarks * information: Portions Copyright [yyyy] [name of copyright owner] 18*4543Smarks * 19*4543Smarks * CDDL HEADER END 20*4543Smarks */ 21*4543Smarks /* 22*4543Smarks * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*4543Smarks * Use is subject to license terms. 24*4543Smarks */ 25*4543Smarks 26*4543Smarks /* 27*4543Smarks * DSL permissions are stored in a two level zap attribute 28*4543Smarks * mechanism. The first level identifies the "class" of 29*4543Smarks * entry. The class is identified by the first 2 letters of 30*4543Smarks * the attribute. The second letter "l" or "d" identifies whether 31*4543Smarks * it is a local or descendent permission. The first letter 32*4543Smarks * identifies the type of entry. 33*4543Smarks * 34*4543Smarks * ul$<id> identifies permssions granted locally for this userid. 35*4543Smarks * ud$<id> identifies permissions granted on descendent datasets for 36*4543Smarks * this userid. 37*4543Smarks * Ul$<id> identifies permission sets granted locally for this userid. 38*4543Smarks * Ud$<id> identifies permission sets granted on descendent datasets for 39*4543Smarks * this userid. 40*4543Smarks * gl$<id> identifies permissions granted locally for this groupid. 41*4543Smarks * gd$<id> identifies permissions granted on descendent datasets for 42*4543Smarks * this groupid. 43*4543Smarks * Gl$<id> identifies permission sets granted locally for this groupid. 44*4543Smarks * Gd$<id> identifies permission sets granted on descendent datasets for 45*4543Smarks * this groupid. 46*4543Smarks * el$ identifies permissions granted locally for everyone. 47*4543Smarks * ed$ identifies permissions granted on descendent datasets 48*4543Smarks * for everyone. 49*4543Smarks * El$ identifies permission sets granted locally for everyone. 50*4543Smarks * Ed$ identifies permission sets granted to descendent datasets for 51*4543Smarks * everyone. 52*4543Smarks * c-$ identifies permission to create at dataset creation time. 53*4543Smarks * C-$ identifies permission sets to grant locally at dataset creation 54*4543Smarks * time. 55*4543Smarks * s-$@<name> permissions defined in specified set @<name> 56*4543Smarks * S-$@<name> Sets defined in named set @<name> 57*4543Smarks * 58*4543Smarks * Each of the above entiies points to another zap attribute that contains one 59*4543Smarks * attribute for each allowed permission, such as create, destroy,... 60*4543Smarks * All of the "upper" case class types will specify permission set names 61*4543Smarks * rather than permissions. 62*4543Smarks * 63*4543Smarks * Basically it looks something like this: 64*4543Smarks * ul$12 -> ZAP OBJ -> permissions... 65*4543Smarks * 66*4543Smarks * The ZAP OBJ is referred to as the jump object. 67*4543Smarks */ 68*4543Smarks 69*4543Smarks #pragma ident "%Z%%M% %I% %E% SMI" 70*4543Smarks 71*4543Smarks #include <sys/dmu.h> 72*4543Smarks #include <sys/dmu_objset.h> 73*4543Smarks #include <sys/dmu_tx.h> 74*4543Smarks #include <sys/dsl_dataset.h> 75*4543Smarks #include <sys/dsl_dir.h> 76*4543Smarks #include <sys/dsl_prop.h> 77*4543Smarks #include <sys/dsl_synctask.h> 78*4543Smarks #include <sys/dsl_deleg.h> 79*4543Smarks #include <sys/spa.h> 80*4543Smarks #include <sys/spa_impl.h> 81*4543Smarks #include <sys/zio_checksum.h> /* for the default checksum value */ 82*4543Smarks #include <sys/zap.h> 83*4543Smarks #include <sys/fs/zfs.h> 84*4543Smarks #include <sys/cred.h> 85*4543Smarks #include <sys/sunddi.h> 86*4543Smarks 87*4543Smarks #include "zfs_deleg.h" 88*4543Smarks 89*4543Smarks /* 90*4543Smarks * Validate that user is allowed to delegate specified permissions. 91*4543Smarks * 92*4543Smarks * In order to delegate "create" you must have create" 93*4543Smarks * and "allow". 94*4543Smarks */ 95*4543Smarks int 96*4543Smarks dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr) 97*4543Smarks { 98*4543Smarks nvpair_t *whopair = NULL; 99*4543Smarks int error = 0; 100*4543Smarks 101*4543Smarks if ((error = dsl_deleg_access(ddname, 102*4543Smarks ZFS_DELEG_PERM_ALLOW, cr)) != 0) 103*4543Smarks return (error); 104*4543Smarks 105*4543Smarks while (whopair = nvlist_next_nvpair(nvp, whopair)) { 106*4543Smarks nvlist_t *perms; 107*4543Smarks nvpair_t *permpair = NULL; 108*4543Smarks 109*4543Smarks VERIFY(nvpair_value_nvlist(whopair, &perms) == 0); 110*4543Smarks 111*4543Smarks while (permpair = nvlist_next_nvpair(perms, permpair)) { 112*4543Smarks const char *perm = nvpair_name(permpair); 113*4543Smarks 114*4543Smarks if (strcmp(perm, ZFS_DELEG_PERM_ALLOW) == 0) 115*4543Smarks return (EPERM); 116*4543Smarks 117*4543Smarks if ((error = dsl_deleg_access(ddname, 118*4543Smarks perm, cr)) != 0) 119*4543Smarks return (error); 120*4543Smarks } 121*4543Smarks } 122*4543Smarks return (error); 123*4543Smarks } 124*4543Smarks 125*4543Smarks /* 126*4543Smarks * Validate that user is allowed to unallow specified permissions. They 127*4543Smarks * must have the 'allow' permission, and even then can only unallow 128*4543Smarks * perms for their uid. 129*4543Smarks */ 130*4543Smarks int 131*4543Smarks dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr) 132*4543Smarks { 133*4543Smarks nvpair_t *whopair = NULL; 134*4543Smarks int error; 135*4543Smarks 136*4543Smarks if ((error = dsl_deleg_access(ddname, 137*4543Smarks ZFS_DELEG_PERM_ALLOW, cr)) != 0) 138*4543Smarks return (error); 139*4543Smarks 140*4543Smarks while (whopair = nvlist_next_nvpair(nvp, whopair)) { 141*4543Smarks zfs_deleg_who_type_t type = nvpair_name(whopair)[0]; 142*4543Smarks char idstr[32]; 143*4543Smarks 144*4543Smarks if (type != ZFS_DELEG_USER && 145*4543Smarks type != ZFS_DELEG_USER_SETS) 146*4543Smarks return (EPERM); 147*4543Smarks 148*4543Smarks (void) snprintf(idstr, sizeof (idstr), "%lld", 149*4543Smarks (longlong_t)crgetuid(cr)); 150*4543Smarks if (strcmp(idstr, &nvpair_name(whopair)[3]) != 0) 151*4543Smarks return (EPERM); 152*4543Smarks 153*4543Smarks continue; 154*4543Smarks } 155*4543Smarks return (0); 156*4543Smarks } 157*4543Smarks 158*4543Smarks typedef struct { 159*4543Smarks nvlist_t *p_nvp; 160*4543Smarks boolean_t p_unset; 161*4543Smarks } perm_args_t; 162*4543Smarks 163*4543Smarks static void 164*4543Smarks dsl_deleg_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 165*4543Smarks { 166*4543Smarks dsl_dir_t *dd = arg1; 167*4543Smarks perm_args_t *pa = arg2; 168*4543Smarks objset_t *mos = dd->dd_pool->dp_meta_objset; 169*4543Smarks nvpair_t *whopair = NULL; 170*4543Smarks uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj; 171*4543Smarks 172*4543Smarks if (zapobj == 0) { 173*4543Smarks if (pa->p_unset) 174*4543Smarks return; 175*4543Smarks dmu_buf_will_dirty(dd->dd_dbuf, tx); 176*4543Smarks zapobj = dd->dd_phys->dd_deleg_zapobj = zap_create(mos, 177*4543Smarks DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx); 178*4543Smarks } 179*4543Smarks 180*4543Smarks while (whopair = nvlist_next_nvpair(pa->p_nvp, whopair)) { 181*4543Smarks const char *whokey = nvpair_name(whopair); 182*4543Smarks nvlist_t *perms; 183*4543Smarks nvpair_t *permpair = NULL; 184*4543Smarks uint64_t jumpobj; 185*4543Smarks 186*4543Smarks if (nvpair_value_nvlist(whopair, &perms) != 0) { 187*4543Smarks if (zap_lookup(mos, zapobj, whokey, 8, 188*4543Smarks 1, &jumpobj) == 0) { 189*4543Smarks (void) zap_remove(mos, zapobj, whokey, tx); 190*4543Smarks VERIFY(0 == zap_destroy(mos, jumpobj, tx)); 191*4543Smarks } 192*4543Smarks spa_history_internal_log(LOG_DS_PERM_WHO_REMOVE, 193*4543Smarks dd->dd_pool->dp_spa, tx, cr, 194*4543Smarks "%s dataset = %llu", whokey, 195*4543Smarks dd->dd_phys->dd_head_dataset_obj); 196*4543Smarks continue; 197*4543Smarks } 198*4543Smarks 199*4543Smarks if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) { 200*4543Smarks /* 201*4543Smarks * If object doesn't exist and we are removing 202*4543Smarks * it, then just continue to next item in nvlist 203*4543Smarks */ 204*4543Smarks if (pa->p_unset == 1) 205*4543Smarks continue; 206*4543Smarks jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, 207*4543Smarks DMU_OT_NONE, 0, tx); 208*4543Smarks VERIFY(zap_update(mos, zapobj, 209*4543Smarks whokey, 8, 1, &jumpobj, tx) == 0); 210*4543Smarks } 211*4543Smarks 212*4543Smarks while (permpair = nvlist_next_nvpair(perms, permpair)) { 213*4543Smarks const char *perm = nvpair_name(permpair); 214*4543Smarks uint64_t n = 0; 215*4543Smarks 216*4543Smarks if (pa->p_unset) { 217*4543Smarks (void) zap_remove(mos, jumpobj, perm, tx); 218*4543Smarks if (zap_count(mos, jumpobj, &n) == 0 && !n) { 219*4543Smarks (void) zap_remove(mos, zapobj, 220*4543Smarks whokey, tx); 221*4543Smarks VERIFY(0 == zap_destroy(mos, 222*4543Smarks jumpobj, tx)); 223*4543Smarks } 224*4543Smarks } else { 225*4543Smarks VERIFY(zap_update(mos, jumpobj, 226*4543Smarks perm, 8, 1, &n, tx) == 0); 227*4543Smarks } 228*4543Smarks spa_history_internal_log((pa->p_unset == B_FALSE) ? 229*4543Smarks LOG_DS_PERM_UPDATE : LOG_DS_PERM_REMOVE, 230*4543Smarks dd->dd_pool->dp_spa, tx, cr, 231*4543Smarks "%s %s dataset = %llu", whokey, perm, 232*4543Smarks dd->dd_phys->dd_head_dataset_obj); 233*4543Smarks } 234*4543Smarks } 235*4543Smarks } 236*4543Smarks 237*4543Smarks int 238*4543Smarks dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset) 239*4543Smarks { 240*4543Smarks dsl_dir_t *dd; 241*4543Smarks int error; 242*4543Smarks perm_args_t pa; 243*4543Smarks nvpair_t *whopair = NULL; 244*4543Smarks int blocks_modified = 0; 245*4543Smarks 246*4543Smarks error = dsl_dir_open(ddname, FTAG, &dd, NULL); 247*4543Smarks if (error) 248*4543Smarks return (error); 249*4543Smarks 250*4543Smarks if (spa_version(dmu_objset_spa(dd->dd_pool->dp_meta_objset)) < 251*4543Smarks ZFS_VERSION_DELEGATED_PERMS) { 252*4543Smarks dsl_dir_close(dd, FTAG); 253*4543Smarks return (ENOTSUP); 254*4543Smarks } 255*4543Smarks 256*4543Smarks while (whopair = nvlist_next_nvpair(nvp, whopair)) 257*4543Smarks blocks_modified++; 258*4543Smarks 259*4543Smarks pa.p_nvp = nvp; 260*4543Smarks pa.p_unset = unset; 261*4543Smarks 262*4543Smarks error = dsl_sync_task_do(dd->dd_pool, NULL, dsl_deleg_set_sync, 263*4543Smarks dd, &pa, blocks_modified); 264*4543Smarks dsl_dir_close(dd, FTAG); 265*4543Smarks 266*4543Smarks return (error); 267*4543Smarks } 268*4543Smarks 269*4543Smarks /* 270*4543Smarks * Find all 'allow' permissions from a given point and then continue 271*4543Smarks * traversing up to the root. 272*4543Smarks * 273*4543Smarks * This function constructs an nvlist of nvlists. 274*4543Smarks * each setpoint is an nvlist composed of an nvlist of an nvlist 275*4543Smarks * of the individual * users/groups/everyone/create 276*4543Smarks * permissions. 277*4543Smarks * 278*4543Smarks * The nvlist will look like this. 279*4543Smarks * 280*4543Smarks * { source fsname -> { whokeys { permissions,...}, ...}} 281*4543Smarks * 282*4543Smarks * The fsname nvpairs will be arranged in a bottom up order. For example, 283*4543Smarks * if we have the following structure a/b/c then the nvpairs for the fsnames 284*4543Smarks * will be ordered a/b/c, a/b, a. 285*4543Smarks */ 286*4543Smarks int 287*4543Smarks dsl_deleg_get(const char *ddname, nvlist_t **nvp) 288*4543Smarks { 289*4543Smarks dsl_dir_t *dd, *startdd; 290*4543Smarks dsl_pool_t *dp; 291*4543Smarks int error; 292*4543Smarks objset_t *mos; 293*4543Smarks 294*4543Smarks error = dsl_dir_open(ddname, FTAG, &startdd, NULL); 295*4543Smarks if (error) 296*4543Smarks return (error); 297*4543Smarks 298*4543Smarks dp = startdd->dd_pool; 299*4543Smarks mos = dp->dp_meta_objset; 300*4543Smarks 301*4543Smarks VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 302*4543Smarks 303*4543Smarks rw_enter(&dp->dp_config_rwlock, RW_READER); 304*4543Smarks for (dd = startdd; dd != NULL; dd = dd->dd_parent) { 305*4543Smarks zap_cursor_t basezc; 306*4543Smarks zap_attribute_t baseza; 307*4543Smarks nvlist_t *sp_nvp; 308*4543Smarks uint64_t n; 309*4543Smarks char source[MAXNAMELEN]; 310*4543Smarks 311*4543Smarks if (dd->dd_phys->dd_deleg_zapobj && 312*4543Smarks (zap_count(mos, dd->dd_phys->dd_deleg_zapobj, 313*4543Smarks &n) == 0) && n) { 314*4543Smarks VERIFY(nvlist_alloc(&sp_nvp, 315*4543Smarks NV_UNIQUE_NAME, KM_SLEEP) == 0); 316*4543Smarks } else { 317*4543Smarks continue; 318*4543Smarks } 319*4543Smarks 320*4543Smarks for (zap_cursor_init(&basezc, mos, 321*4543Smarks dd->dd_phys->dd_deleg_zapobj); 322*4543Smarks zap_cursor_retrieve(&basezc, &baseza) == 0; 323*4543Smarks zap_cursor_advance(&basezc)) { 324*4543Smarks zap_cursor_t zc; 325*4543Smarks zap_attribute_t za; 326*4543Smarks nvlist_t *perms_nvp; 327*4543Smarks 328*4543Smarks ASSERT(baseza.za_integer_length == 8); 329*4543Smarks ASSERT(baseza.za_num_integers == 1); 330*4543Smarks 331*4543Smarks VERIFY(nvlist_alloc(&perms_nvp, 332*4543Smarks NV_UNIQUE_NAME, KM_SLEEP) == 0); 333*4543Smarks for (zap_cursor_init(&zc, mos, baseza.za_first_integer); 334*4543Smarks zap_cursor_retrieve(&zc, &za) == 0; 335*4543Smarks zap_cursor_advance(&zc)) { 336*4543Smarks VERIFY(nvlist_add_boolean(perms_nvp, 337*4543Smarks za.za_name) == 0); 338*4543Smarks } 339*4543Smarks zap_cursor_fini(&zc); 340*4543Smarks VERIFY(nvlist_add_nvlist(sp_nvp, baseza.za_name, 341*4543Smarks perms_nvp) == 0); 342*4543Smarks nvlist_free(perms_nvp); 343*4543Smarks } 344*4543Smarks 345*4543Smarks zap_cursor_fini(&basezc); 346*4543Smarks 347*4543Smarks dsl_dir_name(dd, source); 348*4543Smarks VERIFY(nvlist_add_nvlist(*nvp, source, sp_nvp) == 0); 349*4543Smarks nvlist_free(sp_nvp); 350*4543Smarks } 351*4543Smarks rw_exit(&dp->dp_config_rwlock); 352*4543Smarks 353*4543Smarks dsl_dir_close(startdd, FTAG); 354*4543Smarks return (0); 355*4543Smarks } 356*4543Smarks 357*4543Smarks /* 358*4543Smarks * Routines for dsl_deleg_access() -- access checking. 359*4543Smarks */ 360*4543Smarks typedef struct perm_set { 361*4543Smarks avl_node_t p_node; 362*4543Smarks char p_setname[ZFS_MAX_DELEG_NAME]; 363*4543Smarks boolean_t p_matched; 364*4543Smarks } perm_set_t; 365*4543Smarks 366*4543Smarks static int 367*4543Smarks perm_set_compare(const void *arg1, const void *arg2) 368*4543Smarks { 369*4543Smarks const perm_set_t *node1 = arg1; 370*4543Smarks const perm_set_t *node2 = arg2; 371*4543Smarks int val; 372*4543Smarks 373*4543Smarks val = strcmp(node1->p_setname, node2->p_setname); 374*4543Smarks if (val == 0) 375*4543Smarks return (0); 376*4543Smarks return (val > 0 ? 1 : -1); 377*4543Smarks } 378*4543Smarks 379*4543Smarks /* 380*4543Smarks * Determine whether a specified permission exists. 381*4543Smarks * 382*4543Smarks * First the base attribute has to be retrieved. i.e. ul$12 383*4543Smarks * Once the base object has been retrieved the actual permission 384*4543Smarks * is lookup up in the zap object the base object points to. 385*4543Smarks * 386*4543Smarks * Return 0 if permission exists, ENOENT if there is no whokey, EPERM if 387*4543Smarks * there is no perm in that jumpobj. 388*4543Smarks */ 389*4543Smarks static int 390*4543Smarks dsl_check_access(objset_t *mos, uint64_t zapobj, 391*4543Smarks char type, char checkflag, void *valp, const char *perm) 392*4543Smarks { 393*4543Smarks int error; 394*4543Smarks uint64_t jumpobj, zero; 395*4543Smarks char whokey[ZFS_MAX_DELEG_NAME]; 396*4543Smarks 397*4543Smarks zfs_deleg_whokey(whokey, type, checkflag, valp); 398*4543Smarks error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj); 399*4543Smarks if (error == 0) { 400*4543Smarks error = zap_lookup(mos, jumpobj, perm, 8, 1, &zero); 401*4543Smarks if (error == ENOENT) 402*4543Smarks error = EPERM; 403*4543Smarks } 404*4543Smarks return (error); 405*4543Smarks } 406*4543Smarks 407*4543Smarks /* 408*4543Smarks * check a specified user/group for a requested permission 409*4543Smarks */ 410*4543Smarks static int 411*4543Smarks dsl_check_user_access(objset_t *os, uint64_t zapobj, const char *perm, 412*4543Smarks int checkflag, cred_t *cr) 413*4543Smarks { 414*4543Smarks const gid_t *gids; 415*4543Smarks int ngids; 416*4543Smarks int i; 417*4543Smarks uint64_t id; 418*4543Smarks 419*4543Smarks /* check for user */ 420*4543Smarks id = crgetuid(cr); 421*4543Smarks if (dsl_check_access(os, zapobj, 422*4543Smarks ZFS_DELEG_USER, checkflag, &id, perm) == 0) 423*4543Smarks return (0); 424*4543Smarks 425*4543Smarks /* check for users primary group */ 426*4543Smarks id = crgetgid(cr); 427*4543Smarks if (dsl_check_access(os, zapobj, 428*4543Smarks ZFS_DELEG_GROUP, checkflag, &id, perm) == 0) 429*4543Smarks return (0); 430*4543Smarks 431*4543Smarks /* check for everyone entry */ 432*4543Smarks id = -1; 433*4543Smarks if (dsl_check_access(os, zapobj, 434*4543Smarks ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0) 435*4543Smarks return (0); 436*4543Smarks 437*4543Smarks /* check each supplemental group user is a member of */ 438*4543Smarks ngids = crgetngroups(cr); 439*4543Smarks gids = crgetgroups(cr); 440*4543Smarks for (i = 0; i != ngids; i++) { 441*4543Smarks id = gids[i]; 442*4543Smarks if (dsl_check_access(os, zapobj, 443*4543Smarks ZFS_DELEG_GROUP, checkflag, &id, perm) == 0) 444*4543Smarks return (0); 445*4543Smarks } 446*4543Smarks 447*4543Smarks return (EPERM); 448*4543Smarks } 449*4543Smarks 450*4543Smarks /* 451*4543Smarks * Iterate over the sets specified in the specified zapobj 452*4543Smarks * and load them into the permsets avl tree. 453*4543Smarks */ 454*4543Smarks static int 455*4543Smarks dsl_load_sets(objset_t *mos, uint64_t zapobj, 456*4543Smarks char type, char checkflag, void *valp, avl_tree_t *avl) 457*4543Smarks { 458*4543Smarks zap_cursor_t zc; 459*4543Smarks zap_attribute_t za; 460*4543Smarks perm_set_t *permnode; 461*4543Smarks avl_index_t idx; 462*4543Smarks uint64_t jumpobj; 463*4543Smarks int error; 464*4543Smarks char whokey[ZFS_MAX_DELEG_NAME]; 465*4543Smarks 466*4543Smarks zfs_deleg_whokey(whokey, type, checkflag, valp); 467*4543Smarks 468*4543Smarks error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj); 469*4543Smarks if (error != 0) 470*4543Smarks return (error); 471*4543Smarks 472*4543Smarks for (zap_cursor_init(&zc, mos, jumpobj); 473*4543Smarks zap_cursor_retrieve(&zc, &za) == 0; 474*4543Smarks zap_cursor_advance(&zc)) { 475*4543Smarks permnode = kmem_alloc(sizeof (perm_set_t), KM_SLEEP); 476*4543Smarks (void) strlcpy(permnode->p_setname, za.za_name, 477*4543Smarks sizeof (permnode->p_setname)); 478*4543Smarks permnode->p_matched = B_FALSE; 479*4543Smarks 480*4543Smarks if (avl_find(avl, permnode, &idx) == NULL) { 481*4543Smarks avl_insert(avl, permnode, idx); 482*4543Smarks } else { 483*4543Smarks kmem_free(permnode, sizeof (perm_set_t)); 484*4543Smarks } 485*4543Smarks } 486*4543Smarks zap_cursor_fini(&zc); 487*4543Smarks return (0); 488*4543Smarks } 489*4543Smarks 490*4543Smarks /* 491*4543Smarks * Load all permissions user based on cred belongs to. 492*4543Smarks */ 493*4543Smarks static void 494*4543Smarks dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl, 495*4543Smarks char checkflag, cred_t *cr) 496*4543Smarks { 497*4543Smarks const gid_t *gids; 498*4543Smarks int ngids, i; 499*4543Smarks uint64_t id; 500*4543Smarks 501*4543Smarks id = crgetuid(cr); 502*4543Smarks (void) dsl_load_sets(mos, zapobj, 503*4543Smarks ZFS_DELEG_USER_SETS, checkflag, &id, avl); 504*4543Smarks 505*4543Smarks id = crgetgid(cr); 506*4543Smarks (void) dsl_load_sets(mos, zapobj, 507*4543Smarks ZFS_DELEG_GROUP_SETS, checkflag, &id, avl); 508*4543Smarks 509*4543Smarks (void) dsl_load_sets(mos, zapobj, 510*4543Smarks ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl); 511*4543Smarks 512*4543Smarks ngids = crgetngroups(cr); 513*4543Smarks gids = crgetgroups(cr); 514*4543Smarks for (i = 0; i != ngids; i++) { 515*4543Smarks id = gids[i]; 516*4543Smarks (void) dsl_load_sets(mos, zapobj, 517*4543Smarks ZFS_DELEG_GROUP_SETS, checkflag, &id, avl); 518*4543Smarks } 519*4543Smarks } 520*4543Smarks 521*4543Smarks /* 522*4543Smarks * Check if user has requested permission. 523*4543Smarks */ 524*4543Smarks int 525*4543Smarks dsl_deleg_access(const char *ddname, const char *perm, cred_t *cr) 526*4543Smarks { 527*4543Smarks dsl_dir_t *dd, *startdd; 528*4543Smarks dsl_pool_t *dp; 529*4543Smarks void *cookie; 530*4543Smarks int error; 531*4543Smarks char checkflag = ZFS_DELEG_LOCAL; 532*4543Smarks const char *tail; 533*4543Smarks objset_t *mos; 534*4543Smarks avl_tree_t permsets; 535*4543Smarks perm_set_t *setnode; 536*4543Smarks 537*4543Smarks /* 538*4543Smarks * Use tail so that zfs_ioctl() code doesn't have 539*4543Smarks * to always to to figure out parent name in order 540*4543Smarks * to do access check. for example renaming a snapshot 541*4543Smarks */ 542*4543Smarks error = dsl_dir_open(ddname, FTAG, &startdd, &tail); 543*4543Smarks if (error) 544*4543Smarks return (error); 545*4543Smarks 546*4543Smarks if (tail && tail[0] != '@') { 547*4543Smarks dsl_dir_close(startdd, FTAG); 548*4543Smarks return (ENOENT); 549*4543Smarks } 550*4543Smarks dp = startdd->dd_pool; 551*4543Smarks mos = dp->dp_meta_objset; 552*4543Smarks 553*4543Smarks if (dsl_delegation_on(mos) == B_FALSE) { 554*4543Smarks dsl_dir_close(startdd, FTAG); 555*4543Smarks return (ECANCELED); 556*4543Smarks } 557*4543Smarks 558*4543Smarks if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) < 559*4543Smarks ZFS_VERSION_DELEGATED_PERMS) { 560*4543Smarks dsl_dir_close(startdd, FTAG); 561*4543Smarks return (EPERM); 562*4543Smarks } 563*4543Smarks 564*4543Smarks avl_create(&permsets, perm_set_compare, sizeof (perm_set_t), 565*4543Smarks offsetof(perm_set_t, p_node)); 566*4543Smarks 567*4543Smarks rw_enter(&dp->dp_config_rwlock, RW_READER); 568*4543Smarks for (dd = startdd; dd != NULL; dd = dd->dd_parent, 569*4543Smarks checkflag = ZFS_DELEG_DESCENDENT) { 570*4543Smarks uint64_t zapobj; 571*4543Smarks boolean_t expanded; 572*4543Smarks 573*4543Smarks /* 574*4543Smarks * If not in global zone then make sure 575*4543Smarks * the zoned property is set 576*4543Smarks */ 577*4543Smarks if (!INGLOBALZONE(curproc)) { 578*4543Smarks uint64_t zoned; 579*4543Smarks 580*4543Smarks if (dsl_prop_get_ds_locked(dd, 581*4543Smarks zfs_prop_to_name(ZFS_PROP_ZONED), 582*4543Smarks 8, 1, &zoned, NULL) != 0) 583*4543Smarks break; 584*4543Smarks 585*4543Smarks /* 586*4543Smarks * if zoned property isn't set then break 587*4543Smarks * out and return EPERM. 588*4543Smarks */ 589*4543Smarks if (!zoned) 590*4543Smarks break; 591*4543Smarks } 592*4543Smarks zapobj = dd->dd_phys->dd_deleg_zapobj; 593*4543Smarks 594*4543Smarks if (zapobj == 0) 595*4543Smarks continue; 596*4543Smarks 597*4543Smarks dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr); 598*4543Smarks setnode = avl_first(&permsets); 599*4543Smarks again: 600*4543Smarks expanded = B_FALSE; 601*4543Smarks for (setnode = avl_first(&permsets); setnode; 602*4543Smarks setnode = AVL_NEXT(&permsets, setnode)) { 603*4543Smarks 604*4543Smarks if (setnode->p_matched == B_TRUE) 605*4543Smarks continue; 606*4543Smarks 607*4543Smarks /* See if this set directly grants this permission */ 608*4543Smarks error = dsl_check_access(mos, zapobj, 609*4543Smarks ZFS_DELEG_NAMED_SET, 0, setnode->p_setname, perm); 610*4543Smarks if (error == 0) 611*4543Smarks goto success; 612*4543Smarks if (error == EPERM) 613*4543Smarks setnode->p_matched = B_TRUE; 614*4543Smarks 615*4543Smarks /* See if this set includes other sets */ 616*4543Smarks error = dsl_load_sets(mos, zapobj, 617*4543Smarks ZFS_DELEG_NAMED_SET_SETS, 0, 618*4543Smarks setnode->p_setname, &permsets); 619*4543Smarks if (error == 0) 620*4543Smarks setnode->p_matched = expanded = B_TRUE; 621*4543Smarks } 622*4543Smarks /* 623*4543Smarks * If we expanded any sets, that will define more sets, 624*4543Smarks * which we need to check. 625*4543Smarks */ 626*4543Smarks if (expanded) 627*4543Smarks goto again; 628*4543Smarks 629*4543Smarks error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr); 630*4543Smarks if (error == 0) 631*4543Smarks goto success; 632*4543Smarks } 633*4543Smarks error = EPERM; 634*4543Smarks success: 635*4543Smarks rw_exit(&dp->dp_config_rwlock); 636*4543Smarks dsl_dir_close(startdd, FTAG); 637*4543Smarks 638*4543Smarks cookie = NULL; 639*4543Smarks while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL) { 640*4543Smarks /* These sets were used but never defined! */ 641*4543Smarks kmem_free(setnode, sizeof (perm_set_t)); 642*4543Smarks } 643*4543Smarks 644*4543Smarks return (error); 645*4543Smarks } 646*4543Smarks 647*4543Smarks /* 648*4543Smarks * Other routines. 649*4543Smarks */ 650*4543Smarks 651*4543Smarks static void 652*4543Smarks copy_create_perms(objset_t *mos, uint64_t pzapobj, dsl_dir_t *dd, 653*4543Smarks boolean_t dosets, uint64_t uid, dmu_tx_t *tx) 654*4543Smarks { 655*4543Smarks int error; 656*4543Smarks uint64_t jumpobj, pjumpobj; 657*4543Smarks uint64_t zero = 0; 658*4543Smarks uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj; 659*4543Smarks zap_cursor_t zc; 660*4543Smarks zap_attribute_t za; 661*4543Smarks char whokey[ZFS_MAX_DELEG_NAME]; 662*4543Smarks 663*4543Smarks zfs_deleg_whokey(whokey, 664*4543Smarks dosets ? ZFS_DELEG_CREATE_SETS : ZFS_DELEG_CREATE, 665*4543Smarks ZFS_DELEG_LOCAL, NULL); 666*4543Smarks error = zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj); 667*4543Smarks if (error != 0) 668*4543Smarks return; 669*4543Smarks 670*4543Smarks zfs_deleg_whokey(whokey, 671*4543Smarks dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER, 672*4543Smarks ZFS_DELEG_LOCAL, &uid); 673*4543Smarks 674*4543Smarks if (zapobj == 0) { 675*4543Smarks dmu_buf_will_dirty(dd->dd_dbuf, tx); 676*4543Smarks zapobj = dd->dd_phys->dd_deleg_zapobj = zap_create(mos, 677*4543Smarks DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx); 678*4543Smarks } 679*4543Smarks 680*4543Smarks if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) { 681*4543Smarks jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx); 682*4543Smarks VERIFY(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx) == 0); 683*4543Smarks } 684*4543Smarks 685*4543Smarks for (zap_cursor_init(&zc, mos, pjumpobj); 686*4543Smarks zap_cursor_retrieve(&zc, &za) == 0; 687*4543Smarks zap_cursor_advance(&zc)) { 688*4543Smarks ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1); 689*4543Smarks 690*4543Smarks VERIFY(zap_update(mos, jumpobj, za.za_name, 691*4543Smarks 8, 1, &zero, tx) == 0); 692*4543Smarks } 693*4543Smarks zap_cursor_fini(&zc); 694*4543Smarks } 695*4543Smarks 696*4543Smarks /* 697*4543Smarks * set all create time permission on new dataset. 698*4543Smarks */ 699*4543Smarks void 700*4543Smarks dsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr) 701*4543Smarks { 702*4543Smarks dsl_dir_t *dd; 703*4543Smarks objset_t *mos = sdd->dd_pool->dp_meta_objset; 704*4543Smarks 705*4543Smarks if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) < 706*4543Smarks ZFS_VERSION_DELEGATED_PERMS) 707*4543Smarks return; 708*4543Smarks 709*4543Smarks for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) { 710*4543Smarks uint64_t pobj = dd->dd_phys->dd_deleg_zapobj; 711*4543Smarks 712*4543Smarks if (pobj == 0) 713*4543Smarks continue; 714*4543Smarks 715*4543Smarks copy_create_perms(mos, pobj, sdd, B_FALSE, crgetuid(cr), tx); 716*4543Smarks copy_create_perms(mos, pobj, sdd, B_TRUE, crgetuid(cr), tx); 717*4543Smarks } 718*4543Smarks } 719*4543Smarks 720*4543Smarks int 721*4543Smarks dsl_deleg_destroy(objset_t *mos, uint64_t zapobj, dmu_tx_t *tx) 722*4543Smarks { 723*4543Smarks zap_cursor_t zc; 724*4543Smarks zap_attribute_t za; 725*4543Smarks 726*4543Smarks if (zapobj == 0) 727*4543Smarks return (0); 728*4543Smarks 729*4543Smarks for (zap_cursor_init(&zc, mos, zapobj); 730*4543Smarks zap_cursor_retrieve(&zc, &za) == 0; 731*4543Smarks zap_cursor_advance(&zc)) { 732*4543Smarks ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1); 733*4543Smarks VERIFY(0 == zap_destroy(mos, za.za_first_integer, tx)); 734*4543Smarks } 735*4543Smarks zap_cursor_fini(&zc); 736*4543Smarks VERIFY(0 == zap_destroy(mos, zapobj, tx)); 737*4543Smarks return (0); 738*4543Smarks } 739*4543Smarks 740*4543Smarks boolean_t 741*4543Smarks dsl_delegation_on(objset_t *os) 742*4543Smarks { 743*4543Smarks return (os->os->os_spa->spa_delegation); 744*4543Smarks } 745