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