The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/module/zfs/dsl_deleg.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 533d53cfa2bdd035e3bcf7cd4b5ae726


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.