1#!/usr/local/bin/ksh93 -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. $STF_SUITE/tests/acl/acl_common.kshlib
28. $STF_SUITE/tests/acl/cifs/cifs.kshlib
29
30#################################################################################
31#
32# __stc_assertion_start
33#
34# ID: zfs_acl_chmod_inherit_003_pos
35#
36# DESCRIPTION:
37#	Verify chmod have correct behaviour to directory and file when
38#	filesystem has the different aclinherit setting
39#	
40# STRATEGY:
41#	1. Loop super user and non-super user to run the test case.
42#	2. Create basedir and a set of subdirectores and files within it.
43#	3. Separately chmod basedir with different inherite options,
44#	 	combine with the variable setting of aclinherit:
45#		"discard", "noallow", "secure" or "passthrough".
46#	4. Then create nested directories and files like the following.
47#	
48#                     ofile    
49#                     odir     	
50#          chmod -->  basedir -| 
51#                              |_ nfile1
52#                              |_ ndir1 _ 
53#                                        |_ nfile2
54#                                        |_ ndir2 _
55#                                                  |_ nfile3
56#                                                  |_ ndir3
57#
58#	5. Verify each directories and files have the correct access control
59#	   capability.
60#	
61# TESTABILITY: explicit
62#
63# TEST_AUTOMATION_LEVEL: automated
64#
65# CODING_STATUS: COMPLETED (2008-07-04)
66#
67# __stc_assertion_end
68#
69################################################################################
70
71verify_runnable "both"
72
73function cleanup
74{
75	typeset dir
76
77	# Cleanup basedir, compared file and dir.
78
79	if [[ -f $ofile ]]; then
80		log_must $RM -f $ofile
81	fi
82
83	for dir in $odir $basedir ; do
84		if [[ -d $dir ]]; then
85			log_must $RM -rf $dir
86		fi
87	done		
88}
89
90log_assert "Verify chmod have correct behaviour to directory and file when " \
91	"filesystem has the different aclinherit setting."
92log_onexit cleanup
93
94# Define inherit flag
95set -A aclinherit_flag discard noallow secure passthrough
96set -A object_flag "f-" "-d" "fd"
97set -A strategy_flag "--" "i-" "-n" "in"
98
99typeset ace_prefix1="owner@" 
100typeset ace_prefix2="group@"
101typeset ace_prefix3="everyone@" 
102typeset ace_discard ace_noallow ace_secure ace_passthrough
103typeset ace_secure_new
104
105# Defile the based directory and file
106basedir=$TESTDIR/basedir;  ofile=$TESTDIR/ofile; odir=$TESTDIR/odir
107
108test_requires ZFS_ACL
109
110# Define the files and directories will be created after chmod
111ndir1=$basedir/ndir1; ndir2=$ndir1/ndir2; ndir3=$ndir2/ndir3
112nfile1=$basedir/nfile1; nfile2=$ndir1/nfile2; nfile3=$ndir2/nfile3
113
114# Verify all the node have expected correct access control
115allnodes="$ndir1 $ndir2 $ndir3 $nfile1 $nfile2 $nfile3"
116
117typeset cifs=""
118if cifs_supported ; then
119	cifs="true"
120fi
121
122#
123# According to inherited flag, verify subdirectories and files within it has
124# correct inherited access control.
125#
126function verify_inherit #<aclinherit> <object> [strategy]
127{
128	# Define the nodes which will be affected by inherit.
129	typeset inherit_nodes
130	typeset inherit=$1
131	typeset obj=$2
132	typeset str=$3
133
134	# count: the ACE item to fetch
135	# pass: to mark if the current ACE should apply to the target
136	# maxnumber: predefine as 4
137	# passcnt: counter, if it achieves to maxnumber, 
138	#	then no additional ACE should apply.
139	# isinherit: indicate if the current target is in the inherit list.
140	# step: indicate if the ACE be split during inherit.
141
142	typeset -i count=0 pass=0 passcnt=0 isinherit=0 maxnumber=4 step=0
143
144	log_must usr_exec $MKDIR -p $ndir3
145	log_must usr_exec $TOUCH $nfile1 $nfile2 $nfile3
146
147	# Get the files which inherited ACE.
148	if [[ $(get_substr $obj 1 1) == f ]]; then
149		inherit_nodes="$inherit_nodes $nfile1"
150
151		if [[ $(get_substr $str 2 1) != n ]]; then
152			inherit_nodes="$inherit_nodes $nfile2 $nfile3"
153		fi
154	fi
155	# Get the directores which inherited ACE.
156	if [[ $(get_substr $obj 2 1) == d ]]; then
157		inherit_nodes="$inherit_nodes $ndir1"
158
159		if [[ $(get_substr $str 2 1) != n ]]; then
160			inherit_nodes="$inherit_nodes $ndir2 $ndir3"
161		fi
162	fi
163	
164	for node in $allnodes; do
165		step=0
166		if [[ " $inherit_nodes " == *" $node "* ]]; then
167			isinherit=1
168			if [[ -d $node ]] ; then
169				step=1
170			fi
171		else
172			isinherit=0
173		fi
174
175		i=0
176		count=0
177		passcnt=0
178		while (( i < maxnumber )); do
179			pass=0
180			eval expect1=\$acl$i
181			expect2=$expect1
182
183		#
184		# aclinherit=passthrough,
185		# inherit all inheritable ACL entries without any 
186		# modifications made to the ACL entries when they
187		# are inherited.
188		#
189		# aclinherit=secure,
190		# any inheritable ACL entries will remove
191		# write_acl and write_owner permissions when the ACL entry is
192		# inherited.
193		#
194		# aclinherit=noallow,
195		# only inherit inheritable ACE that specify "deny" permissions
196		#
197		# aclinherit=discard
198		# will not inherit any ACL entries
199		#
200
201			case $inherit in
202				passthrough)
203					if [[ -z $cifs ]]; then
204						break
205					fi
206
207					action=${expect1##*:}
208					expect1=${expect1%:$action}
209					expect1=${expect1%-}
210					expect1=${expect1%I}
211					expect1=${expect1}I:$action
212					;;
213				secure)
214					eval expect2=\$acls$i
215					;;
216				noallow)
217					if [[ $expect1 == *":allow" ]] ; then
218						pass=1
219						(( passcnt = passcnt + 1 ))
220					else
221						eval expect2=\$acls$i
222					fi
223					;;	
224				discard)
225					passcnt=maxnumber
226					break
227					;;
228			esac
229
230			if (( pass == 0 )) ; then
231				acltemp=${expect2%:*}
232				acltemp=${acltemp%:*}
233				aclaction=${expect2##*:}
234
235				if [[ -n $cifs ]]; then
236					expect2=${acltemp}:------I:${aclaction}
237				else
238					expect2=${acltemp}:------:${aclaction}
239				fi
240
241				acltemp=${expect1%:*}
242				inh=${acltemp##*:}
243
244				if [[ -d $node ]]; then
245					if [[ $(get_substr $inh 4 1) == n ]]; then
246
247						#
248						# if no_propagate is set,
249						# then clear all inherit flags,
250						# only one ACE should left.
251						#
252
253						step=0
254						expect1=""
255							
256					elif [[ $(get_substr $inh 3 1) != i ]]; then
257
258						#
259						# directory should append 
260						# "inherit_only" if not have
261						#
262						acltemp=${acltemp%i*}
263						if [[ -n $cifs ]]; then
264
265							expect1=${acltemp}i---I:${aclaction}
266						else
267							expect1=${acltemp}i---:${aclaction}
268						fi
269					elif [[ -n $cifs ]]; then
270						acltemp=${acltemp%-}
271						acltemp=${acltemp%I}
272						expect1=${acltemp}I:${aclaction}
273					fi
274
275					#
276					# cleanup the first ACE if the directory 
277					# not in inherit list
278					#
279
280					if (( isinherit == 0 )); then
281						expect1=""
282					fi
283				elif [[ -f $node ]] ; then
284					expect1=""
285				fi
286
287				# Get the first ACE to do comparison
288
289				aclcur=$(get_ACE $node $count compact)
290				aclcur=${aclcur#$count:}
291				if [[ -n $expect1 && $expect1 != $aclcur ]]; then
292					$LS -Vd $basedir
293					$LS -Vd $node
294					log_fail "$inherit $i #$count " \
295						"ACE: $aclcur, expect to be " \
296						"$expect1"
297				fi
298
299				# Get the second ACE (if should have) to do comparison
300
301				if (( step > 0 )); then
302					(( count = count + step ))
303
304					aclcur=$(get_ACE $node $count compact)
305					aclcur=${aclcur#$count:}
306					if [[ -n $expect2 && \
307						$expect2 != $aclcur ]]; then
308
309						$LS -Vd $basedir
310						$LS -Vd $node
311						log_fail "$inherit $i #$count " \
312							"ACE: $aclcur, expect to be " \
313							"$expect2"
314					fi
315				fi
316				(( count = count + 1 ))
317			fi
318			(( i = i + 1 ))
319		done
320
321		#
322		# If there's no any ACE be checked, it should be identify as
323		# an normal file/dir, verify it.
324		#
325 
326		if (( passcnt == maxnumber )); then
327			if [[ -d $node ]]; then
328				compare_acls $node $odir
329			elif [[	-f $node ]]; then
330				compare_acls $node $ofile
331			fi
332
333			if [[ $? -ne 0 ]]; then
334				$LS -Vd $basedir
335				$LS -Vd $node
336				log_fail "Unexpect acl: $node, $inherit ($str)"
337			fi
338		fi
339	done
340}
341
342typeset -i i=0
343typeset acl0 acl1 acl2 acl3
344typeset acls0 acls1 acls2 acls3
345
346#
347# Set aclmode=passthrough to make sure
348# the acl will not change during chmod.
349# A general testing should verify the combination of 
350# aclmode/aclinherit works well,
351# here we just simple test them separately.
352#
353
354log_must $ZFS set aclmode=passthrough $TESTPOOL/$TESTFS
355
356for inherit in "${aclinherit_flag[@]}"; do
357
358	#
359	# Set different value of aclinherit
360	#
361
362	log_must $ZFS set aclinherit=$inherit $TESTPOOL/$TESTFS
363
364	for user in root $ZFS_ACL_STAFF1; do
365		log_must set_cur_usr $user
366
367		for obj in "${object_flag[@]}"; do
368			for str in "${strategy_flag[@]}"; do
369				typeset inh_opt=$obj
370				(( ${#str} != 0 )) && inh_opt=${inh_opt}${str}--
371
372				if [[ -n $cifs ]]; then
373					inh_a=${inh_opt}-
374					inh_b=${inh_opt}I
375				else
376					inh_a=${inh_opt}
377					inh_b=${inh_opt}
378				fi
379
380				#
381				# Prepare 4 ACES, which should include :
382				# deny -> to verify "noallow"
383				# write_acl/write_owner -> to verify "secure"
384				#
385
386				acl0="$ace_prefix1:rwxp---A-W-Co-:${inh_a}:allow"
387				acl1="$ace_prefix2:rwxp---A-W-Co-:${inh_a}:deny"
388				acl2="$ace_prefix3:rwxp---A-W-Co-:${inh_a}:allow"
389				acl3="$ace_prefix1:-------A-W----:${inh_a}:deny"
390				acl4="$ace_prefix2:-------A-W----:${inh_a}:allow"
391				acl5="$ace_prefix3:-------A-W----:${inh_a}:deny"
392
393
394				#
395				# The ACE filtered by write_acl/write_owner
396				#
397
398				if [[ $inheri == "passthrough" ]]; then
399					acls0="$ace_prefix1:rwxp---A-W----:${inh_b}:allow"
400					acls1="$ace_prefix2:rwxp---A-W----:${inh_b}:deny"
401					acls2="$ace_prefix3:rwxp---A-W----:${inh_b}:allow"
402					acls3="$ace_prefix1:rwxp---A-W----:${inh_b}:deny"
403					acls4="$ace_prefix2:rwxp---A-W----:${inh_b}:allow"
404					acls5="$ace_prefix3:rwxp---A-W----:${inh_b}:deny"
405				else
406					acls0="$ace_prefix1:-------A-W----:${inh_b}:allow"
407					acls1="$ace_prefix2:-------A-W-Co-:${inh_b}:deny"
408					acls2="$ace_prefix3:-------A-W----:${inh_b}:allow"
409					acls3="$ace_prefix1:-------A-W----:${inh_b}:deny"
410					acls4="$ace_prefix2:-------A-W----:${inh_b}:allow"
411					acls5="$ace_prefix3:-------A-W----:${inh_b}:deny"
412				fi
413
414				#
415				# Create basedir and tmp dir/file
416				# for comparison.
417				#
418				
419				log_note "$user: $CHMOD $acl $basedir"
420				log_must usr_exec $MKDIR $basedir
421				log_must usr_exec $MKDIR $odir
422				log_must usr_exec $TOUCH $ofile 
423
424				i=5
425				while (( i >= 0 )); do
426					eval acl=\$acl$i 
427
428				#
429				# Place on a directory should succeed.
430				#
431					log_must usr_exec $CHMOD A+$acl $basedir
432
433					(( i = i - 1 ))
434				done
435			
436				verify_inherit $inherit $obj $str
437			
438				log_must usr_exec $RM -rf $ofile $odir $basedir
439			done
440		done
441	done
442done
443
444log_pass "Verify chmod inherit behaviour co-op with aclinherit setting passed."
445