1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (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
dsl_deleg_can_allow(char * ddname,nvlist_t * nvp,cred_t * cr)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
dsl_deleg_can_unallow(char * ddname,nvlist_t * nvp,cred_t * cr)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
dsl_deleg_set_sync(void * arg,dmu_tx_t * tx)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
dsl_deleg_unset_sync(void * arg,dmu_tx_t * tx)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
dsl_deleg_check(void * arg,dmu_tx_t * tx)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
dsl_deleg_set(const char * ddname,nvlist_t * nvp,boolean_t unset)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
dsl_deleg_get(const char * ddname,nvlist_t ** nvp)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 
313           error = dsl_pool_hold(ddname, FTAG, &dp);
314           if (error != 0)
315                     return (error);
316 
317           error = dsl_dir_hold(dp, ddname, FTAG, &startdd, NULL);
318           if (error != 0) {
319                     dsl_pool_rele(dp, FTAG);
320                     return (error);
321           }
322 
323           dp = startdd->dd_pool;
324           mos = dp->dp_meta_objset;
325 
326           VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
327 
328           for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
329                     zap_cursor_t basezc;
330                     zap_attribute_t baseza;
331                     nvlist_t *sp_nvp;
332                     uint64_t n;
333                     char source[ZFS_MAX_DATASET_NAME_LEN];
334 
335                     if (dsl_dir_phys(dd)->dd_deleg_zapobj == 0 ||
336                         zap_count(mos,
337                         dsl_dir_phys(dd)->dd_deleg_zapobj, &n) != 0 || n == 0)
338                               continue;
339 
340                     sp_nvp = fnvlist_alloc();
341                     for (zap_cursor_init(&basezc, mos,
342                         dsl_dir_phys(dd)->dd_deleg_zapobj);
343                         zap_cursor_retrieve(&basezc, &baseza) == 0;
344                         zap_cursor_advance(&basezc)) {
345                               zap_cursor_t zc;
346                               zap_attribute_t za;
347                               nvlist_t *perms_nvp;
348 
349                               ASSERT(baseza.za_integer_length == 8);
350                               ASSERT(baseza.za_num_integers == 1);
351 
352                               perms_nvp = fnvlist_alloc();
353                               for (zap_cursor_init(&zc, mos, baseza.za_first_integer);
354                                   zap_cursor_retrieve(&zc, &za) == 0;
355                                   zap_cursor_advance(&zc)) {
356                                         fnvlist_add_boolean(perms_nvp, za.za_name);
357                               }
358                               zap_cursor_fini(&zc);
359                               fnvlist_add_nvlist(sp_nvp, baseza.za_name, perms_nvp);
360                               fnvlist_free(perms_nvp);
361                     }
362 
363                     zap_cursor_fini(&basezc);
364 
365                     dsl_dir_name(dd, source);
366                     fnvlist_add_nvlist(*nvp, source, sp_nvp);
367                     nvlist_free(sp_nvp);
368           }
369 
370           dsl_dir_rele(startdd, FTAG);
371           dsl_pool_rele(dp, FTAG);
372           return (0);
373 }
374 
375 /*
376  * Routines for dsl_deleg_access() -- access checking.
377  */
378 typedef struct perm_set {
379           avl_node_t          p_node;
380           boolean_t p_matched;
381           char                p_setname[ZFS_MAX_DELEG_NAME];
382 } perm_set_t;
383 
384 static int
perm_set_compare(const void * arg1,const void * arg2)385 perm_set_compare(const void *arg1, const void *arg2)
386 {
387           const perm_set_t *node1 = arg1;
388           const perm_set_t *node2 = arg2;
389           int val;
390 
391           val = strcmp(node1->p_setname, node2->p_setname);
392           if (val == 0)
393                     return (0);
394           return (val > 0 ? 1 : -1);
395 }
396 
397 /*
398  * Determine whether a specified permission exists.
399  *
400  * First the base attribute has to be retrieved.  i.e. ul$12
401  * Once the base object has been retrieved the actual permission
402  * is lookup up in the zap object the base object points to.
403  *
404  * Return 0 if permission exists, ENOENT if there is no whokey, EPERM if
405  * there is no perm in that jumpobj.
406  */
407 static int
dsl_check_access(objset_t * mos,uint64_t zapobj,char type,char checkflag,void * valp,const char * perm)408 dsl_check_access(objset_t *mos, uint64_t zapobj,
409     char type, char checkflag, void *valp, const char *perm)
410 {
411           int error;
412           uint64_t jumpobj, zero;
413           char whokey[ZFS_MAX_DELEG_NAME];
414 
415           zfs_deleg_whokey(whokey, type, checkflag, valp);
416           error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
417           if (error == 0) {
418                     error = zap_lookup(mos, jumpobj, perm, 8, 1, &zero);
419                     if (error == ENOENT)
420                               error = SET_ERROR(EPERM);
421           }
422           return (error);
423 }
424 
425 /*
426  * check a specified user/group for a requested permission
427  */
428 static int
dsl_check_user_access(objset_t * mos,uint64_t zapobj,const char * perm,int checkflag,cred_t * cr)429 dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
430     int checkflag, cred_t *cr)
431 {
432           const     gid_t *gids;
433           int       ngids;
434           int       i;
435           uint64_t id;
436 
437           /* check for user */
438           id = crgetuid(cr);
439           if (dsl_check_access(mos, zapobj,
440               ZFS_DELEG_USER, checkflag, &id, perm) == 0)
441                     return (0);
442 
443           /* check for users primary group */
444           id = crgetgid(cr);
445           if (dsl_check_access(mos, zapobj,
446               ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
447                     return (0);
448 
449           /* check for everyone entry */
450           id = -1;
451           if (dsl_check_access(mos, zapobj,
452               ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0)
453                     return (0);
454 
455           /* check each supplemental group user is a member of */
456           ngids = crgetngroups(cr);
457           gids = crgetgroups(cr);
458           for (i = 0; i != ngids; i++) {
459                     id = gids[i];
460                     if (dsl_check_access(mos, zapobj,
461                         ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
462                               return (0);
463           }
464 
465           return (SET_ERROR(EPERM));
466 }
467 
468 /*
469  * Iterate over the sets specified in the specified zapobj
470  * and load them into the permsets avl tree.
471  */
472 static int
dsl_load_sets(objset_t * mos,uint64_t zapobj,char type,char checkflag,void * valp,avl_tree_t * avl)473 dsl_load_sets(objset_t *mos, uint64_t zapobj,
474     char type, char checkflag, void *valp, avl_tree_t *avl)
475 {
476           zap_cursor_t zc;
477           zap_attribute_t za;
478           perm_set_t *permnode;
479           avl_index_t idx;
480           uint64_t jumpobj;
481           int error;
482           char whokey[ZFS_MAX_DELEG_NAME];
483 
484           zfs_deleg_whokey(whokey, type, checkflag, valp);
485 
486           error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
487           if (error != 0)
488                     return (error);
489 
490           for (zap_cursor_init(&zc, mos, jumpobj);
491               zap_cursor_retrieve(&zc, &za) == 0;
492               zap_cursor_advance(&zc)) {
493                     permnode = kmem_alloc(sizeof (perm_set_t), KM_SLEEP);
494                     (void) strlcpy(permnode->p_setname, za.za_name,
495                         sizeof (permnode->p_setname));
496                     permnode->p_matched = B_FALSE;
497 
498                     if (avl_find(avl, permnode, &idx) == NULL) {
499                               avl_insert(avl, permnode, idx);
500                     } else {
501                               kmem_free(permnode, sizeof (perm_set_t));
502                     }
503           }
504           zap_cursor_fini(&zc);
505           return (0);
506 }
507 
508 /*
509  * Load all permissions user based on cred belongs to.
510  */
511 static void
dsl_load_user_sets(objset_t * mos,uint64_t zapobj,avl_tree_t * avl,char checkflag,cred_t * cr)512 dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
513     char checkflag, cred_t *cr)
514 {
515           const     gid_t *gids;
516           int       ngids, i;
517           uint64_t id;
518 
519           id = crgetuid(cr);
520           (void) dsl_load_sets(mos, zapobj,
521               ZFS_DELEG_USER_SETS, checkflag, &id, avl);
522 
523           id = crgetgid(cr);
524           (void) dsl_load_sets(mos, zapobj,
525               ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
526 
527           (void) dsl_load_sets(mos, zapobj,
528               ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl);
529 
530           ngids = crgetngroups(cr);
531           gids = crgetgroups(cr);
532           for (i = 0; i != ngids; i++) {
533                     id = gids[i];
534                     (void) dsl_load_sets(mos, zapobj,
535                         ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
536           }
537 }
538 
539 /*
540  * Check if user has requested permission.
541  */
542 int
dsl_deleg_access_impl(dsl_dataset_t * ds,const char * perm,cred_t * cr)543 dsl_deleg_access_impl(dsl_dataset_t *ds, const char *perm, cred_t *cr)
544 {
545           dsl_dir_t *dd;
546           dsl_pool_t *dp;
547           void *cookie;
548           int       error;
549           char      checkflag;
550           objset_t *mos;
551           avl_tree_t permsets;
552           perm_set_t *setnode;
553 
554           dp = ds->ds_dir->dd_pool;
555           mos = dp->dp_meta_objset;
556 
557           if (dsl_delegation_on(mos) == B_FALSE)
558                     return (SET_ERROR(ECANCELED));
559 
560           if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) <
561               SPA_VERSION_DELEGATED_PERMS)
562                     return (SET_ERROR(EPERM));
563 
564           if (ds->ds_is_snapshot) {
565                     /*
566                      * Snapshots are treated as descendents only,
567                      * local permissions do not apply.
568                      */
569                     checkflag = ZFS_DELEG_DESCENDENT;
570           } else {
571                     checkflag = ZFS_DELEG_LOCAL;
572           }
573 
574           avl_create(&permsets, perm_set_compare, sizeof (perm_set_t),
575               offsetof(perm_set_t, p_node));
576 
577           ASSERT(dsl_pool_config_held(dp));
578           for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent,
579               checkflag = ZFS_DELEG_DESCENDENT) {
580                     uint64_t zapobj;
581                     boolean_t expanded;
582 
583                     /*
584                      * If not in global zone then make sure
585                      * the zoned property is set
586                      */
587                     if (!INGLOBALZONE(curthread)) {
588                               uint64_t zoned;
589 
590                               if (dsl_prop_get_dd(dd,
591                                   zfs_prop_to_name(ZFS_PROP_ZONED),
592                                   8, 1, &zoned, NULL, B_FALSE) != 0)
593                                         break;
594                               if (!zoned)
595                                         break;
596                     }
597                     zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
598 
599                     if (zapobj == 0)
600                               continue;
601 
602                     dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr);
603 again:
604                     expanded = B_FALSE;
605                     for (setnode = avl_first(&permsets); setnode;
606                         setnode = AVL_NEXT(&permsets, setnode)) {
607                               if (setnode->p_matched == B_TRUE)
608                                         continue;
609 
610                               /* See if this set directly grants this permission */
611                               error = dsl_check_access(mos, zapobj,
612                                   ZFS_DELEG_NAMED_SET, 0, setnode->p_setname, perm);
613                               if (error == 0)
614                                         goto success;
615                               if (error == EPERM)
616                                         setnode->p_matched = B_TRUE;
617 
618                               /* See if this set includes other sets */
619                               error = dsl_load_sets(mos, zapobj,
620                                   ZFS_DELEG_NAMED_SET_SETS, 0,
621                                   setnode->p_setname, &permsets);
622                               if (error == 0)
623                                         setnode->p_matched = expanded = B_TRUE;
624                     }
625                     /*
626                      * If we expanded any sets, that will define more sets,
627                      * which we need to check.
628                      */
629                     if (expanded)
630                               goto again;
631 
632                     error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr);
633                     if (error == 0)
634                               goto success;
635           }
636           error = SET_ERROR(EPERM);
637 success:
638 
639           cookie = NULL;
640           while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
641                     kmem_free(setnode, sizeof (perm_set_t));
642 
643           return (error);
644 }
645 
646 int
dsl_deleg_access(const char * dsname,const char * perm,cred_t * cr)647 dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
648 {
649           dsl_pool_t *dp;
650           dsl_dataset_t *ds;
651           int error;
652 
653           error = dsl_pool_hold(dsname, FTAG, &dp);
654           if (error != 0)
655                     return (error);
656           error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
657           if (error == 0) {
658                     error = dsl_deleg_access_impl(ds, perm, cr);
659                     dsl_dataset_rele(ds, FTAG);
660           }
661           dsl_pool_rele(dp, FTAG);
662 
663           return (error);
664 }
665 
666 /*
667  * Other routines.
668  */
669 
670 static void
copy_create_perms(dsl_dir_t * dd,uint64_t pzapobj,boolean_t dosets,uint64_t uid,dmu_tx_t * tx)671 copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj,
672     boolean_t dosets, uint64_t uid, dmu_tx_t *tx)
673 {
674           objset_t *mos = dd->dd_pool->dp_meta_objset;
675           uint64_t jumpobj, pjumpobj;
676           uint64_t zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
677           zap_cursor_t zc;
678           zap_attribute_t za;
679           char whokey[ZFS_MAX_DELEG_NAME];
680 
681           zfs_deleg_whokey(whokey,
682               dosets ? ZFS_DELEG_CREATE_SETS : ZFS_DELEG_CREATE,
683               ZFS_DELEG_LOCAL, NULL);
684           if (zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj) != 0)
685                     return;
686 
687           if (zapobj == 0) {
688                     dmu_buf_will_dirty(dd->dd_dbuf, tx);
689                     zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj = zap_create(mos,
690                         DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
691           }
692 
693           zfs_deleg_whokey(whokey,
694               dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER,
695               ZFS_DELEG_LOCAL, &uid);
696           if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) {
697                     jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
698                     VERIFY(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx) == 0);
699           }
700 
701           for (zap_cursor_init(&zc, mos, pjumpobj);
702               zap_cursor_retrieve(&zc, &za) == 0;
703               zap_cursor_advance(&zc)) {
704                     uint64_t zero = 0;
705                     ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
706 
707                     VERIFY(zap_update(mos, jumpobj, za.za_name,
708                         8, 1, &zero, tx) == 0);
709           }
710           zap_cursor_fini(&zc);
711 }
712 
713 /*
714  * set all create time permission on new dataset.
715  */
716 void
dsl_deleg_set_create_perms(dsl_dir_t * sdd,dmu_tx_t * tx,cred_t * cr)717 dsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr)
718 {
719           dsl_dir_t *dd;
720           uint64_t uid = crgetuid(cr);
721 
722           if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) <
723               SPA_VERSION_DELEGATED_PERMS)
724                     return;
725 
726           for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) {
727                     uint64_t pzapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
728 
729                     if (pzapobj == 0)
730                               continue;
731 
732                     copy_create_perms(sdd, pzapobj, B_FALSE, uid, tx);
733                     copy_create_perms(sdd, pzapobj, B_TRUE, uid, tx);
734           }
735 }
736 
737 int
dsl_deleg_destroy(objset_t * mos,uint64_t zapobj,dmu_tx_t * tx)738 dsl_deleg_destroy(objset_t *mos, uint64_t zapobj, dmu_tx_t *tx)
739 {
740           zap_cursor_t zc;
741           zap_attribute_t za;
742 
743           if (zapobj == 0)
744                     return (0);
745 
746           for (zap_cursor_init(&zc, mos, zapobj);
747               zap_cursor_retrieve(&zc, &za) == 0;
748               zap_cursor_advance(&zc)) {
749                     ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
750                     VERIFY(0 == zap_destroy(mos, za.za_first_integer, tx));
751           }
752           zap_cursor_fini(&zc);
753           VERIFY(0 == zap_destroy(mos, zapobj, tx));
754           return (0);
755 }
756 
757 boolean_t
dsl_delegation_on(objset_t * os)758 dsl_delegation_on(objset_t *os)
759 {
760           return (!!spa_delegation(os->os_spa));
761 }
762