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#
23# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26
27#
28# Copyright (c) 2013, 2016 by Delphix. All rights reserved.
29# Copyright 2016 Nexenta Systems, Inc.
30# Copyright 2023 Bill Sommerfeld <sommerfeld@alum.mit.edu>
31#
32
33. $STF_SUITE/include/libtest.shlib
34. $STF_SUITE/tests/functional/delegate/delegate.cfg
35
36#
37# Cleanup exist user/group.
38#
39function cleanup_user_group
40{
41	typeset i
42	for i in $STAFF1 $STAFF2 $OTHER1 $OTHER2 ; do
43		del_user $i
44	done
45	for i in $STAFF_GROUP $OTHER_GROUP ; do
46		del_group $i
47	done
48
49	return 0
50}
51
52#
53# Restore test file system to the original status.
54#
55function restore_root_datasets
56{
57	if datasetexists $ROOT_TESTFS ; then
58		log_must zfs destroy -Rf $ROOT_TESTFS
59	fi
60	log_must zfs create $ROOT_TESTFS
61
62	if is_global_zone ; then
63		if datasetexists $ROOT_TESTVOL ; then
64			log_must zfs destroy -Rf $ROOT_TESTVOL
65		fi
66		log_must zfs create -V $VOLSIZE $ROOT_TESTVOL
67	fi
68
69	return 0
70}
71
72#
73# Verify the specified user have permission on the dataset
74#
75# $1 dataset
76# $2 permissions which are separated by comma(,)
77# $3-n users
78#
79function verify_perm
80{
81	typeset dtst=$1
82	typeset permissions=$2
83	shift 2
84
85	if [[ -z $@ || -z $permissions || -z $dtst ]]; then
86		return 1
87	fi
88
89	typeset type=$(get_prop type $dtst)
90	permissions=$(echo $permissions | tr -s "," " ")
91
92	typeset user
93	for user in $@; do
94		typeset perm
95		for perm in $permissions; do
96			typeset -i ret=1
97			if [[ $type == "filesystem" ]]; then
98				check_fs_perm $user $perm $dtst
99				ret=$?
100			elif [[ $type == "volume" ]]; then
101				check_vol_perm $user $perm $dtst
102				ret=$?
103			fi
104
105			if ((ret != 0)) ; then
106				log_note "Fail: $user should have $perm " \
107					"on $dtst"
108				return 1
109			fi
110		done
111	done
112
113	return 0
114}
115
116#
117# Verify the specified user have no permission on the dataset
118#
119# $1 dataset
120# $2 permissions which are separated by comma(,)
121# $3-n users
122#
123function verify_noperm
124{
125	typeset dtst=$1
126	typeset permissions=$2
127	shift 2
128
129	if [[ -z $@ || -z $permissions || -z $dtst ]]; then
130		return 1
131	fi
132
133	typeset type=$(get_prop type $dtst)
134	permissions=$(echo $permissions | tr -s "," " ")
135
136	typeset user
137	for user in $@; do
138		typeset perm
139		for perm in $permissions; do
140			typeset -i ret=1
141			if [[ $type == "filesystem" ]]; then
142				check_fs_perm $user $perm $dtst
143				ret=$?
144			elif [[ $type == "volume" ]]; then
145				check_vol_perm $user $perm $dtst
146				ret=$?
147			fi
148
149			if ((ret == 0)) ; then
150				log_note "Fail: $user should not have $perm " \
151					"on $dtst"
152				return 1
153			fi
154		done
155	done
156
157	return 0
158}
159
160function common_perm
161{
162	typeset user=$1
163	typeset perm=$2
164	typeset dtst=$3
165
166	typeset -i ret=1
167	case $perm in
168		send)
169			verify_send $user $perm $dtst
170			ret=$?
171			;;
172		allow)
173			verify_allow $user $perm $dtst
174			ret=$?
175			;;
176		userprop)
177			verify_userprop $user $perm $dtst
178			ret=$?
179			;;
180		compression|checksum|readonly)
181			verify_ccr $user $perm $dtst
182			ret=$?
183			;;
184		copies)
185			verify_copies $user $perm $dtst
186			ret=$?
187			;;
188		reservation)
189			verify_reservation $user $perm $dtst
190			ret=$?
191			;;
192		*)
193			ret=1
194			;;
195	esac
196
197	return $ret
198}
199
200function check_fs_perm
201{
202	typeset user=$1
203	typeset perm=$2
204	typeset fs=$3
205
206	typeset -i ret=1
207	case $perm in
208		create)
209			verify_fs_create $user $perm $fs
210			ret=$?
211			;;
212		destroy)
213			verify_fs_destroy $user $perm $fs
214			ret=$?
215			;;
216		snapshot)
217			verify_fs_snapshot $user $perm $fs
218			ret=$?
219			;;
220		rollback)
221			verify_fs_rollback $user $perm $fs
222			ret=$?
223			;;
224		clone)
225			verify_fs_clone $user $perm $fs
226			ret=$?
227			;;
228		rename)
229			verify_fs_rename $user $perm $fs
230			ret=$?
231			;;
232		mount)
233			verify_fs_mount $user $perm $fs
234			ret=$?
235			;;
236		share)
237			verify_fs_share $user $perm $fs
238			ret=$?
239			;;
240		mountpoint)
241			verify_fs_mountpoint $user $perm $fs
242			ret=$?
243			;;
244		promote)
245			verify_fs_promote $user $perm $fs
246			ret=$?
247			;;
248		canmount)
249			verify_fs_canmount $user $perm $fs
250			ret=$?
251			;;
252		dnodesize)
253			verify_fs_dnodesize $user $perm $fs
254			ret=$?
255			;;
256		recordsize)
257			verify_fs_recordsize $user $perm $fs
258			ret=$?
259			;;
260		quota)
261			verify_fs_quota $user $perm $fs
262			ret=$?
263			;;
264		aclmode)
265			verify_fs_aclmode $user $perm $fs
266			ret=$?
267			;;
268		aclinherit)
269			verify_fs_aclinherit $user $perm $fs
270			ret=$?
271			;;
272		snapdir)
273			verify_fs_snapdir $user $perm $fs
274			ret=$?
275			;;
276		atime|exec|devices|setuid|xattr)
277			verify_fs_aedsx $user $perm $fs
278			ret=$?
279			;;
280		zoned)
281			verify_fs_zoned $user $perm $fs
282			ret=$?
283			;;
284		sharenfs)
285			verify_fs_sharenfs $user $perm $fs
286			ret=$?
287			;;
288		receive)
289			verify_fs_receive $user $perm $fs
290			ret=$?
291			;;
292		*)
293			common_perm $user $perm $fs
294			ret=$?
295			;;
296	esac
297
298	return $ret
299}
300
301function check_vol_perm
302{
303	typeset user=$1
304	typeset perm=$2
305	typeset vol=$3
306
307	typeset -i ret=1
308	case $perm in
309		destroy)
310			verify_vol_destroy $user $perm $vol
311			ret=$?
312			;;
313		snapshot)
314			verify_vol_snapshot $user $perm $vol
315			ret=$?
316			;;
317		rollback)
318			verify_vol_rollback $user $perm $vol
319			ret=$?
320			;;
321		clone)
322			verify_vol_clone $user $perm $vol
323			ret=$?
324			;;
325		rename)
326			verify_vol_rename $user $perm $vol
327			ret=$?
328			;;
329		promote)
330			verify_vol_promote $user $perm $vol
331			ret=$?
332			;;
333		volsize)
334			verify_vol_volsize $user $perm $vol
335			ret=$?
336			;;
337		*)
338			common_perm $user $perm $vol
339			ret=$?
340			;;
341	esac
342
343	return $ret
344}
345
346function setup_unallow_testenv
347{
348	log_must restore_root_datasets
349
350	log_must zfs create $SUBFS
351
352	for dtst in $DATASETS ; do
353		log_must zfs allow -l $STAFF1 $LOCAL_SET $dtst
354		log_must zfs allow -d $STAFF2 $DESC_SET  $dtst
355		log_must zfs allow $OTHER1 $LOCAL_DESC_SET $dtst
356		log_must zfs allow $OTHER2 $LOCAL_DESC_SET $dtst
357
358		log_must verify_perm $dtst $LOCAL_SET $STAFF1
359		log_must verify_perm $dtst $LOCAL_DESC_SET $OTHER1
360		log_must verify_perm $dtst $LOCAL_DESC_SET $OTHER2
361		if [[ $dtst == $ROOT_TESTFS ]]; then
362			log_must verify_perm $SUBFS $DESC_SET $STAFF2
363			log_must verify_perm $SUBFS $LOCAL_DESC_SET $OTHER1
364			log_must verify_perm $SUBFS $LOCAL_DESC_SET $OTHER2
365		fi
366	done
367
368	return 0
369}
370
371#
372# Verify permission send for specified user on the dataset
373# $1 user
374# $2 permission
375# $3 dataset
376#
377function verify_send
378{
379	typeset user=$1
380	typeset perm=$2
381	typeset dtst=$3
382
383	typeset oldval
384	typeset stamp=${perm}.${user}.$RANDOM
385	typeset snap=$dtst@snap.$stamp
386
387	typeset -i ret=1
388
389	log_must zfs snapshot $snap
390	typeset bak_user=/tmp/bak.$user.$stamp
391	typeset bak_root=/tmp/bak.root.$stamp
392
393	user_run $user eval "zfs send $snap > $bak_user"
394	log_must eval "zfs send $snap > $bak_root"
395
396	if [[ $(checksum $bak_user) == $(checksum $bak_root) ]]; then
397		ret=0
398	fi
399
400	rm -rf $bak_user > /dev/null
401	rm -rf $bak_root > /dev/null
402
403	return $ret
404}
405
406function verify_fs_receive
407{
408	typeset user=$1
409	typeset perm=$2
410	typeset fs=$3
411
412	typeset dtst
413	typeset stamp=${perm}.${user}.$RANDOM
414	typeset newfs=$fs/newfs.$stamp
415	typeset newvol=$fs/newvol.$stamp
416	typeset bak_user=/tmp/bak.$user.$stamp
417	typeset bak_root=/tmp/bak.root.$stamp
418
419	log_must zfs create $newfs
420	typeset datasets="$newfs"
421	if is_global_zone ; then
422		log_must zfs create -V $VOLSIZE $newvol
423		datasets="$newfs $newvol"
424	fi
425
426	for dtst in $datasets ; do
427
428		typeset dtstsnap=$dtst@snap.$stamp
429		log_must zfs snapshot $dtstsnap
430
431		log_must eval "zfs send $dtstsnap > $bak_root"
432		log_must zfs destroy -rf $dtst
433
434		user_run $user eval "zfs receive $dtst < $bak_root"
435		if datasetexists $dtstsnap ; then
436			return 1
437		fi
438
439		log_must zfs allow $user create $fs
440		user_run $user eval "zfs receive $dtst < $bak_root"
441		log_must zfs unallow $user create $fs
442		if datasetexists $dtstsnap ; then
443			return 1
444		fi
445
446		log_must zfs allow $user mount $fs
447		user_run $user eval "zfs receive $dtst < $bak_root"
448		log_must zfs unallow $user mount $fs
449		if datasetexists $dtstsnap ; then
450			return 1
451		fi
452
453		log_must zfs allow $user mount,create $fs
454		user_run $user eval "zfs receive $dtst < $bak_root"
455		log_must zfs unallow $user mount,create $fs
456		if ! datasetexists $dtstsnap ; then
457			return 1
458		fi
459
460		# check the data integrity
461		log_must eval "zfs send $dtstsnap > $bak_user"
462		log_must zfs destroy -rf $dtst
463		log_must eval "zfs receive $dtst < $bak_root"
464		log_must eval "zfs send $dtstsnap > $bak_root"
465		log_must zfs destroy -rf $dtst
466		if [[ $(checksum $bak_user) != $(checksum $bak_root) ]]; then
467			return 1
468		fi
469
470		rm -rf $bak_user > /dev/null
471		rm -rf $bak_root > /dev/null
472
473	done
474
475	return 0
476}
477
478function verify_userprop
479{
480	typeset user=$1
481	typeset perm=$2
482	typeset dtst=$3
483
484	typeset stamp=${perm}.${user}.$RANDOM
485
486	user_run $user zfs set "$user:ts=$stamp" $dtst
487	sync_pool ${dtst%%/*}
488	if [[ $stamp != $(get_prop "$user:ts" $dtst) ]]; then
489		return 1
490	fi
491	user_run $user zfs inherit "$user:ts" $dtst
492
493	return 0
494}
495
496function verify_ccr
497{
498	typeset user=$1
499	typeset perm=$2
500	typeset dtst=$3
501
502	typeset oldval
503
504	set -A modes "on" "off"
505	oldval=$(get_prop $perm $dtst)
506	if [[ $oldval == "on" ]]; then
507		n=1
508	elif [[ $oldval == "off" ]]; then
509		n=0
510	fi
511	log_note "$user zfs set $perm=${modes[$n]} $dtst"
512	user_run $user zfs set $perm=${modes[$n]} $dtst
513	if [[ ${modes[$n]} != $(get_prop $perm $dtst) ]]; then
514		return 1
515	fi
516
517	return 0
518}
519
520function verify_copies
521{
522	typeset user=$1
523	typeset perm=$2
524	typeset dtst=$3
525
526	typeset oldval
527
528	set -A modes 1 2 3
529	oldval=$(get_prop $perm $dtst)
530	if [[ $oldval -eq 1 ]]; then
531		n=1
532	elif [[ $oldval -eq 2 ]]; then
533		n=2
534	elif [[ $oldval -eq 3 ]]; then
535		n=0
536	fi
537	log_note "$user zfs set $perm=${modes[$n]} $dtst"
538	user_run $user zfs set $perm=${modes[$n]} $dtst
539	if [[ ${modes[$n]} != $(get_prop $perm $dtst) ]]; then
540		return 1
541	fi
542
543	return 0
544}
545
546function verify_reservation
547{
548	typeset user=$1
549	typeset perm=$2
550	typeset dtst=$3
551
552	typeset value32m=$(( 1024 * 1024 * 32 ))
553	typeset oldval=$(get_prop reservation $dtst)
554	user_run $user zfs set reservation=$value32m $dtst
555	if [[ $value32m != $(get_prop reservation $dtst) ]]; then
556		log_must zfs set reservation=$oldval $dtst
557		return 1
558	fi
559
560	log_must zfs set reservation=$oldval $dtst
561	return 0
562}
563
564function verify_fs_create
565{
566	typeset user=$1
567	typeset perm=$2
568	typeset fs=$3
569
570	typeset stamp=${perm}.${user}.$RANDOM
571	typeset newfs=$fs/nfs.$stamp
572	typeset newvol=$fs/nvol.$stamp
573
574	user_run $user zfs create $newfs
575	if datasetexists $newfs ; then
576		return 1
577	fi
578
579	log_must zfs allow $user mount $fs
580	user_run $user zfs create $newfs
581	log_must zfs unallow $user mount $fs
582	if ! datasetexists $newfs ; then
583		return 1
584	fi
585
586	log_must zfs destroy $newfs
587
588	if is_global_zone ; then
589		# mount permission is required for sparse volume
590		user_run $user zfs create -V 150m -s $newvol
591		if datasetexists $newvol ; then
592			return 1
593		fi
594
595		log_must zfs allow $user mount $fs
596		user_run $user zfs create -V 150m -s $newvol
597		log_must zfs unallow $user mount $fs
598		if ! datasetexists $newvol ; then
599			return 1
600		fi
601		log_must zfs destroy $newvol
602
603		# mount and reserveration permission are
604		# required for normal volume
605		user_run $user zfs create -V 150m $newvol
606		if datasetexists $newvol ; then
607			return 1
608		fi
609
610		log_must zfs allow $user mount $fs
611		user_run $user zfs create -V 150m $newvol
612		log_must zfs unallow $user mount $fs
613		if datasetexists $newvol ; then
614			return 1
615		fi
616
617		log_must zfs allow $user reservation $fs
618		user_run $user zfs create -V 150m $newvol
619		log_must zfs unallow $user reservation $fs
620		if datasetexists $newvol ; then
621			return 1
622		fi
623
624		log_must zfs allow $user refreservation $fs
625		user_run $user zfs create -V 150m $newvol
626		log_must zfs unallow $user refreservation $fs
627		if datasetexists $newvol ; then
628			return 1
629		fi
630
631		log_must zfs allow $user mount $fs
632		log_must zfs allow $user reservation $fs
633		log_must zfs allow $user refreservation $fs
634		user_run $user zfs create -V 150m $newvol
635		log_must zfs unallow $user mount $fs
636		log_must zfs unallow $user reservation $fs
637		log_must zfs unallow $user refreservation $fs
638		if ! datasetexists $newvol ; then
639			return 1
640		fi
641		log_must zfs destroy $newvol
642	fi
643
644	return 0
645}
646
647function verify_fs_destroy
648{
649	typeset user=$1
650	typeset perm=$2
651	typeset fs=$3
652
653	if ! ismounted $fs ; then
654		user_run $user zfs destroy $fs
655		if datasetexists $fs ; then
656			return 1
657		fi
658	fi
659
660	if ismounted $fs ; then
661		user_run $user zfs destroy $fs
662		if ! datasetexists $fs ; then
663			return 1
664		fi
665
666		# mount permission is required
667		log_must zfs allow $user mount $fs
668		user_run $user zfs destroy $fs
669		if datasetexists $fs ; then
670			return 1
671		fi
672	fi
673
674	return 0
675}
676
677# Verify that given the correct delegation, a regular user can:
678#	Take a snapshot of an unmounted dataset
679#	Take a snapshot of an mounted dataset
680#	Create a snapshot by making a directory in the .zfs/snapshot directory
681function verify_fs_snapshot
682{
683	typeset user=$1
684	typeset perm=$2
685	typeset fs=$3
686
687	typeset stamp=${perm}.${user}.$RANDOM
688	typeset snap=$fs@snap.$stamp
689	typeset mntpt=$(get_prop mountpoint $fs)
690
691	if [[ "yes" == $(get_prop mounted $fs) ]]; then
692		log_must zfs umount $fs
693	fi
694
695	user_run $user zfs snapshot $snap
696	if ! datasetexists $snap ; then
697		return 1
698	fi
699	log_must zfs destroy $snap
700
701	if [[ "no" == $(get_prop mounted $fs) ]]; then
702		log_must zfs mount $fs
703	fi
704
705	user_run $user zfs snapshot $snap
706	if ! datasetexists $snap ; then
707		return 1
708	fi
709	log_must zfs destroy $snap
710
711	typeset snapdir=${mntpt}/.zfs/snapshot/snap.$stamp
712	user_run $user mkdir $snapdir
713	if ! datasetexists $snap ; then
714		return 1
715	fi
716	log_must zfs destroy $snap
717
718	return 0
719}
720
721function verify_fs_rollback
722{
723	typeset user=$1
724	typeset perm=$2
725	typeset fs=$3
726
727	typeset oldval
728	typeset stamp=${perm}.${user}.$RANDOM
729	typeset snap=$fs@snap.$stamp
730	typeset mntpt=$(get_prop mountpoint $fs)
731
732	oldval=$(datasetcksum $fs)
733	log_must zfs snapshot $snap
734
735	if ! ismounted $fs; then
736		log_must zfs mount $fs
737	fi
738	log_must touch $mntpt/testfile.$stamp
739
740	user_run $user zfs rollback -R $snap
741	if is_global_zone ; then
742		if [[ $oldval != $(datasetcksum $fs) ]]; then
743			return 1
744		fi
745	else
746		# datasetcksum can not be used in local zone
747		if [[ -e $mntpt/testfile.$stamp ]]; then
748			return 1
749		fi
750	fi
751
752	return 0
753}
754
755function verify_fs_clone
756{
757	typeset user=$1
758	typeset perm=$2
759	typeset fs=$3
760
761	typeset stamp=${perm}.${user}.$RANDOM
762	typeset basefs=${fs%/*}
763	typeset snap=$fs@snap.$stamp
764	typeset clone=$basefs/cfs.$stamp
765
766	log_must zfs snapshot $snap
767	user_run $user zfs clone $snap $clone
768	if datasetexists $clone ; then
769		return 1
770	fi
771
772	log_must zfs allow $user create $basefs
773	user_run $user zfs clone $snap $clone
774	log_must zfs unallow $user create $basefs
775	if datasetexists $clone ; then
776		return 1
777	fi
778
779	log_must zfs allow $user mount $basefs
780	user_run $user zfs clone $snap $clone
781	log_must zfs unallow $user mount $basefs
782	if datasetexists $clone ; then
783		return 1
784	fi
785
786	log_must zfs allow $user mount $basefs
787	log_must zfs allow $user create $basefs
788	user_run $user zfs clone $snap $clone
789	log_must zfs unallow $user create $basefs
790	log_must zfs unallow $user mount $basefs
791	if ! datasetexists $clone ; then
792		return 1
793	fi
794
795	log_must zfs destroy -R $snap
796
797	return 0
798}
799
800function verify_fs_rename
801{
802	typeset user=$1
803	typeset perm=$2
804	typeset fs=$3
805
806	typeset stamp=${perm}.${user}.$RANDOM
807	typeset basefs=${fs%/*}
808	typeset snap=$fs@snap.$stamp
809	typeset renamefs=$basefs/nfs.$stamp
810
811	if ! ismounted $fs; then
812		log_must zfs mount $fs
813	fi
814
815	# case 1
816	user_run $user zfs rename $fs $renamefs
817	if datasetexists $renamefs ; then
818		return 1
819	fi
820
821	# case 2
822	log_must zfs allow $user create $basefs
823	user_run $user zfs rename $fs $renamefs
824	log_must zfs unallow $user create $basefs
825	if datasetexists $renamefs ; then
826		return 1
827	fi
828
829	# case 3
830	log_must zfs allow $user mount $basefs
831	user_run $user zfs rename $fs $renamefs
832	log_must zfs unallow $user mount $basefs
833	if datasetexists $renamefs ; then
834		return 1
835	fi
836
837	# case 4
838	log_must zfs allow $user mount $fs
839	user_run $user zfs rename $fs $renamefs
840	if datasetexists $renamefs ; then
841		log_must zfs unallow $user mount $renamefs
842		return 1
843	fi
844	log_must zfs unallow $user mount $fs
845
846	# case 5
847	log_must zfs allow $user create $basefs
848	log_must zfs allow $user mount $fs
849	user_run $user zfs rename $fs $renamefs
850	log_must zfs unallow $user create $basefs
851	if datasetexists $renamefs ; then
852		log_must zfs unallow $user mount $renamefs
853		return 1
854	fi
855	log_must zfs unallow $user mount $fs
856
857	# case 6
858	log_must zfs allow $user mount $basefs
859	log_must zfs allow $user mount $fs
860	user_run $user zfs rename $fs $renamefs
861	log_must zfs unallow $user mount $basefs
862	if datasetexists $renamefs ; then
863		log_must zfs unallow $user mount $renamefs
864		return 1
865	fi
866	log_must zfs unallow $user mount $fs
867
868	# case 7
869	log_must zfs allow $user create $basefs
870	log_must zfs allow $user mount $basefs
871	user_run $user zfs rename $fs $renamefs
872	log_must zfs unallow $user mount $basefs
873	log_must zfs unallow $user create $basefs
874	if ! datasetexists $renamefs ; then
875		return 1
876	fi
877
878	log_must zfs rename $renamefs $fs
879
880	return 0
881}
882
883function verify_fs_mount
884{
885	typeset user=$1
886	typeset perm=$2
887	typeset fs=$3
888
889	typeset stamp=${perm}.${user}.$RANDOM
890	typeset mntpt=$(get_prop mountpoint $fs)
891	typeset newmntpt=/tmp/mnt.$stamp
892
893	if ismounted $fs ; then
894		user_run $user zfs unmount $fs
895		if ismounted $fs ; then
896			return 1
897		fi
898	fi
899
900	if ! ismounted $fs ; then
901		log_must zfs set mountpoint=$newmntpt $fs
902		log_must rm -rf $newmntpt
903		log_must mkdir $newmntpt
904
905		user_run $user zfs mount $fs
906		if ismounted $fs ; then
907			return 1
908		fi
909
910		# mountpoint's owner must be the user
911		log_must chown $user $newmntpt
912		user_run $user zfs mount $fs
913		if ! ismounted $fs ; then
914			return 1
915		fi
916		log_must zfs umount $fs
917		log_must rm -rf $newmntpt
918		log_must zfs set mountpoint=$mntpt $fs
919	fi
920
921	return 0
922}
923
924function verify_fs_share
925{
926	typeset user=$1
927	typeset perm=$2
928	typeset fs=$3
929	typeset -i ret=0
930
931	svcadm enable -rs nfs/server
932	typeset stat=$(svcs -H -o STA nfs/server:default)
933	if [[ $stat != "ON" ]]; then
934		log_fail "Could not enable nfs/server"
935	fi
936
937	log_must zfs set sharenfs=on $fs
938	zfs unshare $fs
939
940	user_run $user zfs share $fs
941	if ! is_shared $fs; then
942		ret=1
943	fi
944
945	zfs unshare $fs
946	log_must zfs set sharenfs=off $fs
947
948	return $ret
949}
950
951function verify_fs_mountpoint
952{
953	typeset user=$1
954	typeset perm=$2
955	typeset fs=$3
956
957	typeset stamp=${perm}.${user}.$RANDOM
958	typeset mntpt=$(get_prop mountpoint $fs)
959	typeset newmntpt=/tmp/mnt.$stamp
960
961	if ! ismounted $fs ; then
962		user_run $user zfs set mountpoint=$newmntpt $fs
963		if [[ $newmntpt != \
964			$(get_prop mountpoint $fs) ]] ; then
965			return 1
966		fi
967		log_must zfs set mountpoint=$mntpt $fs
968	fi
969
970	if ismounted $fs ; then
971		user_run $user zfs set mountpoint=$newmntpt $fs
972		if [[ $mntpt != $(get_prop mountpoint $fs) ]]; then
973			return 1
974		fi
975
976		# require mount permission when fs is mounted
977		log_must zfs allow $user mount $fs
978		user_run $user zfs set mountpoint=$newmntpt $fs
979		log_must zfs unallow $user mount $fs
980		if [[ $newmntpt != \
981			$(get_prop mountpoint $fs) ]] ; then
982			return 1
983		fi
984		log_must zfs set mountpoint=$mntpt $fs
985	fi
986
987	return 0
988}
989
990function verify_fs_promote
991{
992	typeset user=$1
993	typeset perm=$2
994	typeset fs=$3
995
996	typeset stamp=${perm}.${user}.$RANDOM
997	typeset basefs=${fs%/*}
998	typeset snap=$fs@snap.$stamp
999	typeset clone=$basefs/cfs.$stamp
1000
1001	log_must zfs snapshot $snap
1002	log_must zfs clone $snap $clone
1003	log_must zfs promote $clone
1004
1005	typeset fs_orig=$(get_prop origin $fs)
1006	typeset clone_orig=$(get_prop origin $clone)
1007
1008	user_run $user zfs promote $fs
1009	# promote should fail if original fs does not have
1010	# promote permission
1011	if [[ $fs_orig != $(get_prop origin $fs) || \
1012		$clone_orig != $(get_prop origin $clone) ]]; then
1013		return 1
1014	fi
1015
1016	log_must zfs allow $user promote $clone
1017	user_run $user zfs promote $fs
1018	log_must zfs unallow $user promote $clone
1019	if [[ $fs_orig != $(get_prop origin $fs) || \
1020		$clone_orig != $(get_prop origin $clone) ]]; then
1021		return 1
1022	fi
1023
1024	log_must zfs allow $user mount $fs
1025	user_run $user zfs promote $fs
1026	log_must zfs unallow $user mount $fs
1027	if [[ $fs_orig != $(get_prop origin $fs) || \
1028		$clone_orig != $(get_prop origin $clone) ]]; then
1029		return 1
1030	fi
1031
1032	log_must zfs allow $user mount $fs
1033	log_must zfs allow $user promote $clone
1034	user_run $user zfs promote $fs
1035	log_must zfs unallow $user promote $clone
1036	log_must zfs unallow $user mount $fs
1037	if [[ $snap != $(get_prop origin $clone) || \
1038		$clone_orig != $(get_prop origin $fs) ]]; then
1039		return 1
1040	fi
1041
1042	return 0
1043}
1044
1045function verify_fs_canmount
1046{
1047	typeset user=$1
1048	typeset perm=$2
1049	typeset fs=$3
1050
1051	typeset oldval
1052	typeset stamp=${perm}.${user}.$RANDOM
1053
1054	if ! ismounted $fs ; then
1055		set -A modes "on" "off"
1056		oldval=$(get_prop $perm $fs)
1057		if [[ $oldval == "on" ]]; then
1058			n=1
1059		elif [[ $oldval == "off" ]]; then
1060			n=0
1061		fi
1062		log_note "$user zfs set $perm=${modes[$n]} $fs"
1063		user_run $user zfs set $perm=${modes[$n]} $fs
1064		if [[ ${modes[$n]} != $(get_prop $perm $fs) ]]; then
1065			return 1
1066		fi
1067	fi
1068
1069
1070	# fs is mounted
1071	if ismounted $fs ; then
1072		# property value does not change if
1073		# no mount permission
1074		set -A modes "on" "off"
1075		oldval=$(get_prop $perm $fs)
1076		if [[ $oldval == "on" ]]; then
1077			n=1
1078		elif [[ $oldval == "off" ]]; then
1079			n=0
1080		fi
1081		log_note "$user zfs set $perm=${modes[$n]} $fs"
1082		log_must zfs allow $user mount $fs
1083		user_run $user zfs set $perm=${modes[$n]} $fs
1084		log_must zfs unallow $user mount $fs
1085		if [[ ${modes[$n]} != $(get_prop $perm $fs) ]]; then
1086			return 1
1087		fi
1088	fi
1089
1090	return 0
1091}
1092
1093function verify_fs_recordsize
1094{
1095	typeset user=$1
1096	typeset perm=$2
1097	typeset fs=$3
1098
1099	typeset value8k=$(( 1024 * 8 ))
1100	user_run $user zfs set recordsize=$value8k $fs
1101	if [[ $value8k != $(get_prop recordsize $fs) ]]; then
1102		return 1
1103	fi
1104
1105	return 0
1106}
1107
1108function verify_fs_dnodesize
1109{
1110	typeset user=$1
1111	typeset perm=$2
1112	typeset fs=$3
1113	value="2k"
1114
1115	user_run $user zfs set dnodesize=$value $fs
1116	if [[ $value != $(get_prop dnodesize $fs) ]]; then
1117		return 1
1118	fi
1119
1120	return 0
1121}
1122
1123function verify_fs_quota
1124{
1125	typeset user=$1
1126	typeset perm=$2
1127	typeset fs=$3
1128
1129	typeset value32m=$(( 1024 * 1024 * 32 ))
1130	user_run $user zfs set quota=$value32m $fs
1131	if [[ $value32m != $(get_prop quota $fs) ]]; then
1132		return 1
1133	fi
1134
1135	return 0
1136}
1137
1138function verify_fs_aclmode
1139{
1140	typeset user=$1
1141	typeset perm=$2
1142	typeset fs=$3
1143
1144	typeset oldval
1145	set -A modes "discard" "groupmask" "passthrough"
1146	oldval=$(get_prop $perm $fs)
1147	if [[ $oldval == "discard" ]]; then
1148		n=1
1149	elif [[ $oldval == "groupmask" ]]; then
1150		n=2
1151	elif [[ $oldval == "passthrough" ]]; then
1152		n=0
1153	fi
1154	log_note "$user zfs set aclmode=${modes[$n]} $fs"
1155	user_run $user zfs set aclmode=${modes[$n]} $fs
1156	if [[ ${modes[$n]} != $(get_prop aclmode $fs) ]]; then
1157		return 1
1158	fi
1159
1160	return 0
1161}
1162
1163function verify_fs_aclinherit
1164{
1165	typeset user=$1
1166	typeset perm=$2
1167	typeset fs=$3
1168
1169	#
1170	# PSARC/2008/231 change the default value of aclinherit to "restricted"
1171	# but still keep the old interface of "secure"
1172	#
1173
1174	typeset oldval
1175	set -A modes "discard" "noallow" "secure" "passthrough"
1176	oldval=$(get_prop $perm $fs)
1177	if [[ $oldval == "discard" ]]; then
1178		n=1
1179	elif [[ $oldval == "noallow" ]]; then
1180		n=2
1181	elif [[ $oldval == "secure" || $oldval == "restricted" ]]; then
1182		n=3
1183	elif [[ $oldval == "passthrough" ]]; then
1184		n=0
1185	fi
1186	log_note "$user zfs set aclinherit=${modes[$n]} $fs"
1187	user_run $user zfs set aclinherit=${modes[$n]} $fs
1188
1189	typeset newval=$(get_prop aclinherit $fs)
1190	if [[ ${modes[$n]} == "secure" && $newval == "restricted" ]]; then
1191		return 0
1192	elif [[ ${modes[$n]} != $(get_prop aclinherit $fs) ]]; then
1193		return 1
1194	fi
1195
1196	return 0
1197}
1198
1199function verify_fs_snapdir
1200{
1201	typeset user=$1
1202	typeset perm=$2
1203	typeset fs=$3
1204
1205	typeset oldval
1206	set -A modes "visible" "hidden"
1207	oldval=$(get_prop $perm $fs)
1208	if [[ $oldval == "visible" ]]; then
1209		n=1
1210	elif [[ $oldval == "hidden" ]]; then
1211		n=0
1212	fi
1213	log_note "$user zfs set snapdir=${modes[$n]} $fs"
1214	user_run $user zfs set snapdir=${modes[$n]} $fs
1215	if [[ ${modes[$n]} != $(get_prop snapdir $fs) ]]; then
1216		return 1
1217	fi
1218
1219	return 0
1220}
1221
1222function verify_fs_aedsx
1223{
1224	typeset user=$1
1225	typeset perm=$2
1226	typeset fs=$3
1227
1228	typeset oldval
1229	set -A modes "on" "off"
1230	oldval=$(get_prop $perm $fs)
1231	if [[ $oldval == "on" ]]; then
1232		n=1
1233	elif [[ $oldval == "off" ]]; then
1234		n=0
1235	fi
1236	log_note "$user zfs set $perm=${modes[$n]} $fs"
1237	user_run $user zfs set $perm=${modes[$n]} $fs
1238	if [[ ${modes[$n]} != $(get_prop $perm $fs) ]]; then
1239		return 1
1240	fi
1241
1242	return 0
1243}
1244
1245function verify_fs_zoned
1246{
1247	typeset user=$1
1248	typeset perm=$2
1249	typeset fs=$3
1250
1251	typeset oldval
1252	set -A modes "on" "off"
1253	oldval=$(get_prop $perm $fs)
1254	if [[ $oldval == "on" ]]; then
1255		n=1
1256	elif [[ $oldval == "off" ]]; then
1257		n=0
1258	fi
1259	log_note "$user zfs set $perm=${modes[$n]} $fs"
1260	if is_global_zone ; then
1261		if ! ismounted $fs ; then
1262			user_run $user zfs set \
1263				$perm=${modes[$n]} $fs
1264			if [[ ${modes[$n]} != \
1265				$(get_prop $perm $fs) ]]; then
1266				return 1
1267			fi
1268			if [[ $n -eq 0 ]]; then
1269				log_mustnot zfs mount $fs
1270			else
1271				log_must zfs mount $fs
1272			fi
1273		fi
1274
1275		if ismounted $fs; then
1276			# n always is 1 in this case
1277			user_run $user zfs set \
1278				$perm=${modes[$n]} $fs
1279			if [[ $oldval != \
1280				$(get_prop $perm $fs) ]]; then
1281				return 1
1282			fi
1283
1284			# mount permission is needed
1285			# to make zoned=on
1286			log_must zfs allow $user mount $fs
1287			user_run $user zfs set \
1288				$perm=${modes[$n]} $fs
1289			log_must zfs unallow $user mount $fs
1290			if [[ ${modes[$n]} != \
1291				$(get_prop $perm $fs) ]]; then
1292				return 1
1293			fi
1294		fi
1295	fi
1296
1297	if ! is_global_zone; then
1298		user_run $user zfs set $perm=${modes[$n]} $fs
1299		if [[ $oldval != $(get_prop $perm $fs) ]]; then
1300			return 1
1301		fi
1302	fi
1303
1304	return 0
1305}
1306
1307function verify_fs_sharenfs
1308{
1309	typeset user=$1
1310	typeset perm=$2
1311	typeset fs=$3
1312	typeset nmode omode
1313
1314	omode=$(get_prop $perm $fs)
1315	if [[ $omode == "off" ]]; then
1316		nmode="on"
1317	else
1318		nmode="off"
1319	fi
1320
1321	log_note "$user zfs set $perm=$nmode $fs"
1322	user_run $user zfs set $perm=$nmode $fs
1323	if [[ $(get_prop $perm $fs) != $nmode ]]; then
1324		return 1
1325	fi
1326
1327	log_note "$user zfs set $perm=$omode $fs"
1328	user_run $user zfs set $perm=$omode $fs
1329	if [[ $(get_prop $perm $fs) != $omode ]]; then
1330		return 1
1331	fi
1332
1333	return 0
1334}
1335
1336function verify_vol_destroy
1337{
1338	typeset user=$1
1339	typeset perm=$2
1340	typeset vol=$3
1341
1342	user_run $user zfs destroy $vol
1343	if ! datasetexists $vol ; then
1344		return 1
1345	fi
1346
1347	# mount permission is required
1348	log_must zfs allow $user mount $vol
1349	user_run $user zfs destroy $vol
1350	if datasetexists $vol ; then
1351		return 1
1352	fi
1353
1354	return 0
1355}
1356
1357function verify_vol_snapshot
1358{
1359	typeset user=$1
1360	typeset perm=$2
1361	typeset vol=$3
1362
1363	typeset stamp=${perm}.${user}.$RANDOM
1364	typeset basevol=${vol%/*}
1365	typeset snap=$vol@snap.$stamp
1366
1367	user_run $user zfs snapshot $snap
1368	if datasetexists $snap ; then
1369		return 1
1370	fi
1371
1372	log_must zfs allow $user mount $vol
1373	user_run $user zfs snapshot $snap
1374	log_must zfs unallow $user mount $vol
1375	if ! datasetexists $snap ; then
1376		return 1
1377	fi
1378
1379	return 0
1380}
1381
1382function verify_vol_rollback
1383{
1384	typeset user=$1
1385	typeset perm=$2
1386	typeset vol=$3
1387
1388	typeset stamp=${perm}.${user}.$RANDOM
1389	typeset basevol=${vol%/*}
1390	typeset snap=$vol@snap.$stamp
1391
1392	typeset oldval
1393	log_must zfs snapshot $snap
1394	oldval=$(datasetcksum $vol)
1395
1396	log_must dd if=/dev/random of=/dev/zvol/rdsk/$vol \
1397		bs=512 count=1
1398
1399	user_run $user zfs rollback -R $snap
1400	sleep 10
1401	if [[ $oldval == $(datasetcksum $vol) ]]; then
1402		return 1
1403	fi
1404
1405	# rollback on volume has to be with mount permission
1406	log_must zfs allow $user mount $vol
1407	user_run $user zfs rollback -R $snap
1408	sleep 10
1409	log_must zfs unallow $user mount $vol
1410	if [[ $oldval != $(datasetcksum $vol) ]]; then
1411		return 1
1412	fi
1413
1414	return 0
1415}
1416
1417function verify_vol_clone
1418{
1419	typeset user=$1
1420	typeset perm=$2
1421	typeset vol=$3
1422
1423	typeset stamp=${perm}.${user}.$RANDOM
1424	typeset basevol=${vol%/*}
1425	typeset snap=$vol@snap.$stamp
1426	typeset clone=$basevol/cvol.$stamp
1427
1428	log_must zfs snapshot $snap
1429
1430	user_run $user zfs clone $snap $clone
1431	if datasetexists $clone ; then
1432		return 1
1433	fi
1434
1435	log_must zfs allow $user create $basevol
1436	user_run $user zfs clone $snap $clone
1437	log_must zfs unallow $user create $basevol
1438	if datasetexists $clone ; then
1439		return 1
1440	fi
1441
1442	log_must zfs allow $user mount $basevol
1443	user_run $user zfs clone $snap $clone
1444	log_must zfs unallow $user mount $basevol
1445	if datasetexists $clone ; then
1446		return 1
1447	fi
1448
1449	# require create permission on parent and
1450	# mount permission on itself as well
1451	log_must zfs allow $user mount $basevol
1452	log_must zfs allow $user create $basevol
1453	user_run $user zfs clone $snap $clone
1454	log_must zfs unallow $user create $basevol
1455	log_must zfs unallow $user mount $basevol
1456	if ! datasetexists $clone ; then
1457		return 1
1458	fi
1459
1460	return 0
1461}
1462
1463function verify_vol_rename
1464{
1465	typeset user=$1
1466	typeset perm=$2
1467	typeset vol=$3
1468
1469	typeset stamp=${perm}.${user}.$RANDOM
1470	typeset basevol=${vol%/*}
1471	typeset snap=$vol@snap.$stamp
1472	typeset clone=$basevol/cvol.$stamp
1473	typeset renamevol=$basevol/nvol.$stamp
1474
1475	user_run $user zfs rename $vol $renamevol
1476	if datasetexists $renamevol ; then
1477		return 1
1478	fi
1479
1480	log_must zfs allow $user create $basevol
1481	user_run $user zfs rename $vol $renamevol
1482	log_must zfs unallow $user create $basevol
1483	if datasetexists $renamevol ; then
1484		return 1
1485	fi
1486
1487	log_must zfs allow $user mount $basevol
1488	user_run $user zfs rename $vol $renamevol
1489	log_must zfs unallow $user mount $basevol
1490	if datasetexists $renamevol ; then
1491		return 1
1492	fi
1493
1494	# require both create permission on parent and
1495	# mount permission on parent as well
1496	log_must zfs allow $user mount $basevol
1497	log_must zfs allow $user create $basevol
1498	user_run $user zfs rename $vol $renamevol
1499	log_must zfs unallow $user mount $basevol
1500	log_must zfs unallow $user create $basevol
1501	if ! datasetexists $renamevol ; then
1502		return 1
1503	fi
1504
1505	log_must zfs rename $renamevol $vol
1506
1507	return 0
1508}
1509
1510function verify_vol_promote
1511{
1512	typeset user=$1
1513	typeset perm=$2
1514	typeset vol=$3
1515
1516	typeset stamp=${perm}.${user}.$RANDOM
1517	typeset basevol=${vol%/*}
1518	typeset snap=$vol@snap.$stamp
1519	typeset clone=$basevol/cvol.$stamp
1520
1521	log_must zfs snapshot $snap
1522	log_must zfs clone $snap $clone
1523	log_must zfs promote $clone
1524
1525	typeset vol_orig=$(get_prop origin $vol)
1526	typeset clone_orig=$(get_prop origin $clone)
1527
1528	# promote should fail if $vol and $clone
1529	# miss either mount or promote permission
1530	# case 1
1531	user_run $user zfs promote $vol
1532	if [[ $vol_orig != $(get_prop origin $vol) || \
1533		$clone_orig != $(get_prop origin $clone) ]];
1534	then
1535		return 1
1536	fi
1537
1538	# promote should fail if $vol and $clone
1539	# miss either mount or promote permission
1540	# case 2
1541	log_must zfs allow $user promote $clone
1542	user_run $user zfs promote $vol
1543	log_must zfs unallow $user promote $clone
1544	if [[ $vol_orig != $(get_prop origin $vol) || \
1545		$clone_orig != $(get_prop origin $clone) ]];
1546	then
1547		return 1
1548	fi
1549
1550	# promote should fail if $vol and $clone
1551	# miss either mount or promote permission
1552	# case 3
1553	log_must zfs allow $user mount $vol
1554	user_run $user zfs promote $vol
1555	log_must zfs unallow $user mount $vol
1556	if [[ $vol_orig != $(get_prop origin $vol) || \
1557		$clone_orig != $(get_prop origin $clone) ]];
1558	then
1559		return 1
1560	fi
1561
1562	# promote should fail if $vol and $clone
1563	# miss either mount or promote permission
1564	# case 4
1565	log_must zfs allow $user mount $clone
1566	user_run $user zfs promote $vol
1567	log_must zfs unallow $user mount $clone
1568	if [[ $vol_orig != $(get_prop origin $vol) || \
1569		$clone_orig != $(get_prop origin $clone) ]];
1570	then
1571		return 1
1572	fi
1573
1574	# promote should fail if $vol and $clone
1575	# miss either mount or promote permission
1576	# case 5
1577	log_must zfs allow $user promote $clone
1578	log_must zfs allow $user mount $vol
1579	user_run $user zfs promote $vol
1580	log_must zfs unallow $user promote $clone
1581	log_must zfs unallow $user mount $vol
1582	if [[ $vol_orig != $(get_prop origin $vol) || \
1583		$clone_orig != $(get_prop origin $clone) ]];
1584	then
1585		return 1
1586	fi
1587
1588	# promote should fail if $vol and $clone
1589	# miss either mount or promote permission
1590	# case 6
1591	log_must zfs allow $user promote $clone
1592	log_must zfs allow $user mount $clone
1593	user_run $user zfs promote $vol
1594	log_must zfs unallow $user promote $clone
1595	log_must zfs unallow $user mount $vol
1596	if [[ $vol_orig != $(get_prop origin $vol) || \
1597		$clone_orig != $(get_prop origin $clone) ]];
1598	then
1599		return 1
1600	fi
1601
1602	# promote should fail if $vol and $clone
1603	# miss either mount or promote permission
1604	# case 7
1605	log_must zfs allow $user mount $vol
1606	log_must zfs allow $user mount $clone
1607	user_run $user zfs promote $vol
1608	log_must zfs unallow $user mount $vol
1609	log_must zfs unallow $user mount $clone
1610	if [[ $vol_orig != $(get_prop origin $vol) || \
1611		$clone_orig != $(get_prop origin $clone) ]];
1612	then
1613		return 1
1614	fi
1615
1616	# promote only succeeds when $vol and $clone
1617	# have both mount and promote permission
1618	# case 8
1619	log_must zfs allow $user promote $clone
1620	log_must zfs allow $user mount $vol
1621	log_must zfs allow $user mount $clone
1622	user_run $user zfs promote $vol
1623	log_must zfs unallow $user promote $clone
1624	log_must zfs unallow $user mount $vol
1625	log_must zfs unallow $user mount $clone
1626	if [[ $snap != $(get_prop origin $clone) || \
1627		$clone_orig != $(get_prop origin $vol) ]]; then
1628		return 1
1629	fi
1630
1631	return 0
1632}
1633
1634function verify_vol_volsize
1635{
1636	typeset user=$1
1637	typeset perm=$2
1638	typeset vol=$3
1639
1640	typeset oldval
1641	oldval=$(get_prop volsize $vol)
1642	(( newval = oldval * 2 ))
1643
1644	reserv_size=$(get_prop refreservation $vol)
1645
1646	if [[ "0" == $reserv_size ]]; then
1647		# sparse volume
1648		user_run $user zfs set volsize=$newval $vol
1649		if [[ $oldval == $(get_prop volsize $vol) ]];
1650		then
1651			return 1
1652		fi
1653
1654	else
1655		# normal volume, reservation permission
1656		# is required
1657		user_run $user zfs set volsize=$newval $vol
1658		if [[ $newval == $(get_prop volsize $vol) ]];
1659		then
1660			return 1
1661		fi
1662
1663		log_must zfs allow $user reservation $vol
1664		log_must zfs allow $user refreservation $vol
1665		user_run $user zfs set volsize=$newval $vol
1666		log_must zfs unallow $user reservation $vol
1667		log_must zfs unallow $user refreservation $vol
1668		if [[ $oldval == $(get_prop volsize $vol) ]];
1669		then
1670			return 1
1671		fi
1672	fi
1673
1674	return 0
1675}
1676
1677function verify_allow
1678{
1679	typeset user=$1
1680	typeset perm=$2
1681	typeset dtst=$3
1682
1683	typeset -i ret
1684
1685	user_run $user zfs allow $user allow $dtst
1686	ret=$?
1687	if [[ $ret -eq 0 ]]; then
1688		return 1
1689	fi
1690
1691	log_must zfs allow $user copies $dtst
1692	user_run $user zfs allow $user copies $dtst
1693	ret=$?
1694	log_must zfs unallow $user copies $dtst
1695	if [[ $ret -eq 1 ]]; then
1696		return 1
1697	fi
1698
1699	return 0
1700
1701}
1702
1703function verify_allow_output
1704{
1705	typeset dtst=$1
1706
1707	shift
1708	cat >>/tmp/allow_template.$$ <<EOF
1709---- Permissions on $dtst
1710EOF
1711
1712	while (( $# > 0 )); do
1713		typeset section=$1
1714		typeset content=$2
1715
1716		cat >>/tmp/allow_template.$$ <<EOF
1717${section}:
1718	$content
1719EOF
1720		shift 2
1721	done
1722
1723	# chop variable-length trailing dashes
1724	zfs allow $dtst | sed 's/ --*$//' >/tmp/allow_output.$$
1725
1726	typeset -i ret
1727	log_must diff -u /tmp/allow_template.$$ /tmp/allow_output.$$
1728	ret=$?
1729	rm -f  /tmp/allow_template.$$ /tmp/allow_output.$$
1730
1731	if [[ $ret -eq 0 ]]; then
1732		return 0
1733	fi
1734
1735	return 1
1736}
1737