1#!/bin/ksh -p
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22
23#
24# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26#
27
28#
29# Copyright (c) 2012 by Delphix. All rights reserved.
30#
31
32. $STF_SUITE/tests/functional/acl/acl_common.kshlib
33
34#
35# DESCRIPTION:
36#	Verify chmod have correct behaviour to directory and file not inherited
37#	when filesystem has the different aclinherit setting
38#
39# STRATEGY:
40#	1. Loop super user and non-super user to run the test case.
41#	2. Create basedir and a set of subdirectores and files within it.
42#	3. Separately chmod basedir with different inherite options,
43#	combine with the variable setting of aclinherit:
44#		"discard", "noallow", "restricted" or "passthrough".
45#	4. Then create nested directories and files like the following.
46#
47#                     ofile
48#                     odir
49#          chmod -->  basedir -|
50#                              |_ nfile1
51#                              |_ ndir1 _
52#                                        |_ nfile2
53#                                        |_ ndir2 _
54#                                                  |_ nfile3
55#                                                  |_ ndir3
56#
57#	5. Verify non-inherited directories and files have the correct access
58#	   control capability.
59#
60
61verify_runnable "both"
62
63function cleanup
64{
65	typeset dir
66
67	# Cleanup basedir, compared file and dir.
68
69	if [[ -f $ofile ]]; then
70		log_must $RM -f $ofile
71	fi
72
73	for dir in $odir $basedir ; do
74		if [[ -d $dir ]]; then
75			log_must $RM -rf $dir
76		fi
77	done
78	log_must $ZFS set aclmode=discard $TESTPOOL/$TESTFS
79}
80
81log_assert "Verify chmod have correct behaviour to directory and file when " \
82    "filesystem has the different aclinherit setting."
83log_onexit cleanup
84
85# Define inherit flag
86typeset aclinherit_flag=(discard noallow restricted passthrough)
87typeset object_flag=(file_inherit dir_inherit file_inherit/dir_inherit)
88typeset strategy_flag=("" inherit_only no_propagate inherit_only/no_propagate)
89
90typeset ace_prefix1="user:$ZFS_ACL_OTHER1"
91typeset ace_prefix2="user:$ZFS_ACL_OTHER2"
92typeset ace_discard ace_noallow ace_secure ace_passthrough
93typeset ace_secure_new
94
95# Defile the based directory and file
96basedir=$TESTDIR/basedir;  ofile=$TESTDIR/ofile; odir=$TESTDIR/odir
97
98# Define the files and directories will be created after chmod
99ndir1=$basedir/ndir1; ndir2=$ndir1/ndir2; ndir3=$ndir2/ndir3
100nfile1=$basedir/nfile1; nfile2=$ndir1/nfile2; nfile3=$ndir2/nfile3
101
102# Verify all the node have expected correct access control
103allnodes="$ndir1 $ndir2 $ndir3 $nfile1 $nfile2 $nfile3"
104
105#
106# According to inherited flag, verify subdirectories and files within it has
107# correct inherited access control.
108#
109function verify_inherit #<aclinherit> <object> [strategy]
110{
111	# Define the nodes which will be affected by inherit.
112	typeset non_inherit_nodes=""
113	typeset inherit=$1
114	typeset obj=$2
115	typeset str=$3
116	typeset inherit_type
117	typeset str1="/inherit_only/inherited:"
118	typeset str2="/inherited:"
119
120	# count: the ACE item to fetch
121	# maxnumber: predefine as 4
122	# passcnt: counter, if it achieves to maxnumber,
123	#	then no additional ACE should apply.
124	# isinherit: indicate if the current target is in the inherit list.
125
126	typeset -i count=0 pass=0 passcnt=0 isinherit=0 maxnumber=4 no_propagate=0
127
128	log_must usr_exec $MKDIR -p $ndir3
129	log_must usr_exec $TOUCH $nfile1 $nfile2 $nfile3
130
131	# Get the inherit type/object_flag and non-inherited nodes.
132	if [[ $obj == *"file_inherit"* && $obj == *"dir_inherit"* ]]; then
133		inherit_type="both"
134		if [[ $str == *"no_propagate"* ]]; then
135			non_inherit_nodes= $ndir2 $ndir3 $nfile2 $nfile3
136			no_propagate=1
137		fi
138	elif [[ $obj == *"dir_inherit"* ]]; then
139		inherit_type="directory"
140		non_inherit_nodes="$nfile1 $nfile2 $nfile3"
141		if [[ $str == *"no_propagate"* ]]; then
142			non_inherit_nodes="$non_inherit_nodes $ndir2 $ndir3"
143			no_propagate=1
144		fi
145	else
146		inherit_type="file"
147		non_inherit_nodes="$ndir1 $ndir2 $ndir3"
148		if [[ $str == *"no_propagate"* ]]; then
149			non_inherit_nodes="$non_inherit_nodes $nfile2 $nfile3"
150			no_propagate=1
151		fi
152	fi
153	# Verify ACE's for all the dirs/files under $basedir
154	for node in $allnodes; do
155		if [[ " $non_inherit_nodes " == *" $node "* ]]; then
156			no_inherit=1
157		else
158			no_inherit=0
159		fi
160		i=0
161		count=0
162		passcnt=0
163		while ((i < maxnumber)); do
164			pass=0
165			eval expect1=\$acl$i
166			case $inherit in
167				noallow)
168					[[ $expect1 == *":allow" ]] && pass=1
169					;;
170				discard)
171					passcnt=maxnumber
172					break
173					;;
174			esac
175			if ((pass == 0 && no_inherit == 1)); then
176				aclaction=${expect1##*:}
177				acltemp=${expect1%:*}
178				# Verify ACE's for sub-directory
179				if [[ -d $node ]]; then
180					eval expect1=\$acl$i
181					acltemp=${expect1%:*}
182					if [[ $inherit_type == "directory" || \
183					    $inherit_type == "both" ]]; then
184						expect1=${acltemp}/inherited:
185						expect1=${expect1}${aclaction}
186					elif [[ $inherit_type == "file" ]]; then
187						if [[ $expect1 != \
188						    *"inherit_only"* ]]; then
189							#
190							# directory should append
191							# "inherit_only" if not have
192							#
193							expect1=${acltemp}${str1}
194							expect1=${expect1}${aclaction}
195						else
196							expect1=${acltemp}${str2}
197							expect1=${expect1}${aclaction}
198						fi
199					fi
200					aclcur=$(get_ACE $node $count)
201					aclcur=${aclcur#$count:}
202					if [[ $no_propagate == 0 ]]; then
203						if [[ $expect1 != $aclcur ]]; then
204							$LS -vd $basedir
205							$LS -vd $node
206							log_fail "$inherit $i #"\
207							    "$count ACE: $aclcur"\
208							    "expect to be $expect1"
209						fi
210					else
211						# compare if directory has basic
212						# ACL's
213						compare_acls $node $odir
214						if [[ $? -ne 0 ]]; then
215							$LS -vd $basedir
216							$LS -vd $node
217							log_fail "Unexpect acl:"\
218							    " $node, $inherit"
219							    "($str)"
220						fi
221					fi
222				# Verify ACE's for nested file
223				elif [[ -f $node ]]; then
224					compare_acls $node $ofile
225					if [[ $? -ne 0 ]]; then
226						$LS -vd $basedir
227						$LS -vd $node
228						log_fail "Unexpect acl: $node," \
229						    "$inherit ($str)"
230					fi
231
232				fi
233				((count = count + 1))
234			fi
235			((i = i + 1))
236		done
237
238		#
239		# If there's no any ACE be checked, it should be identify as
240		# an normal file/dir, verify it.
241		#
242
243		if ((passcnt == maxnumber)); then
244			if [[ -d $node ]]; then
245				compare_acls $node $odir
246			elif [[	-f $node ]]; then
247				compare_acls $node $ofile
248			fi
249
250			if [[ $? -ne 0 ]]; then
251				$LS -vd $basedir
252				$LS -vd $node
253				log_fail "Unexpect acl: $node, $inherit ($str)"
254			fi
255		fi
256	done
257}
258
259typeset -i i=0
260typeset acl0 acl1 acl2 acl3
261typeset acls0 acls1 acls2 acls3
262
263#
264# Set aclmode=passthrough to make sure
265# the acl will not change during chmod.
266# A general testing should verify the combination of
267# aclmode/aclinherit works well,
268# here we just simple test them separately.
269#
270
271log_must $ZFS set aclmode=passthrough $TESTPOOL/$TESTFS
272
273for inherit in "${aclinherit_flag[@]}"; do
274
275	#
276	# Set different value of aclinherit
277	#
278
279	log_must $ZFS set aclinherit=$inherit $TESTPOOL/$TESTFS
280
281	for user in root $ZFS_ACL_STAFF1; do
282		log_must set_cur_usr $user
283
284		for obj in "${object_flag[@]}"; do
285			for str in "${strategy_flag[@]}"; do
286				typeset inh_opt=$obj
287				((${#str} != 0)) && inh_opt=$inh_opt/$str
288
289				#
290				# Prepare 4 ACES, which should include :
291				# deny -> to verify "noallow"
292				# write_acl/write_owner -> to verify "secure"
293				#
294
295				acl0=${ace_prefix1}":read_xattr/write_acl/"
296				acl0=${acl0}"write_owner:"${inh_opt}":deny"
297				acl1="$ace_prefix2:read_xattr/write_acl/"
298				acl1=${acl1}"write_owner:$inh_opt:allow"
299				acl2="$ace_prefix1:read_xattr:$inh_opt:deny"
300				acl3="$ace_prefix2:read_xattr:$inh_opt:allow"
301
302				#
303				# The ACE filtered by write_acl/write_owner
304				#
305
306				acls0="$ace_prefix1:read_xattr:$inh_opt:deny"
307				acls1="$ace_prefix2:read_xattr:$inh_opt:allow"
308				acls2=$acl2
309				acls3=$acl3
310				#
311				# Create basedir and tmp dir/file
312				# for comparison.
313				#
314				log_note "$user: $CHMOD $acl $basedir"
315				log_must usr_exec $MKDIR $basedir
316				log_must usr_exec $MKDIR $odir
317				log_must usr_exec $TOUCH $ofile
318
319				i=3
320				while ((i >= 0)); do
321					eval acl=\$acl$i
322
323				#
324				# Place on a directory should succeed.
325				#
326					log_must usr_exec $CHMOD A+$acl $basedir
327
328					((i = i - 1))
329				done
330				log_note "verify_inherit $inherit $obj $str"
331				log_must verify_inherit $inherit $obj $str
332
333				log_must usr_exec $RM -rf $ofile $odir $basedir
334			done
335		done
336	done
337done
338
339log_pass "Verify chmod inherit behaviour co-op with aclinherit setting passed."
340