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
29#################################################################################
30#
31# __stc_assertion_start
32#
33# ID: zfs_acl_chmod_aclmode_001_pos
34#
35# DESCRIPTION:
36#	Verify chmod have correct behaviour to directory and file when
37#	filesystem has the different aclmode 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 aclmode options,
43#	 	combine with the variable setting of aclmode:
44#		"discard", "groupmask", or "passthrough".
45#	4. Verify each directories and files have the correct access control
46#	   capability.
47#
48# TESTABILITY: explicit
49#
50# TEST_AUTOMATION_LEVEL: automated
51#
52# CODING_STATUS: COMPLETED (2006-03-02)
53#
54# __stc_assertion_end
55#
56################################################################################
57
58verify_runnable "both"
59
60test_requires ZFS_ACL
61
62function cleanup
63{
64	# Cleanup tarfile & basedir.
65
66	(( ${#cwd} != 0 )) && cd $cwd
67
68	if [[ -f $TARFILE ]]; then
69		log_must $RM -f $TARFILE
70	fi
71
72	if [[ -d $basedir ]]; then
73		log_must $RM -rf $basedir
74	fi
75}
76
77log_assert "Verify chmod have correct behaviour to directory and file when " \
78	"filesystem has the different aclmode setting."
79log_onexit cleanup
80
81# Define aclmode flag
82set -A aclmode_flag discard groupmask passthrough
83
84set -A ace_prefix "user:$ZFS_ACL_OTHER1" \
85		"user:$ZFS_ACL_OTHER2" \
86		"group:$ZFS_ACL_STAFF_GROUP" \
87		"group:$ZFS_ACL_OTHER_GROUP"
88
89set -A argv  "000" "444" "644" "777" "755" "231" "562" "413"
90
91set -A ace_file_preset "read_data" \
92		"write_data" \
93		"append_data" \
94		"execute" \
95		"read_data/write_data" \
96		"read_data/write_data/append_data" \
97		"write_data/append_data" \
98		"read_data/execute" \
99		"write_data/append_data/execute" \
100		"read_data/write_data/append_data/execute"
101
102# Defile the based directory and file
103basedir=$TESTDIR/basedir;  ofile=$basedir/ofile; odir=$basedir/odir
104nfile=$basedir/nfile; ndir=$basedir/ndir
105
106TARFILE=$TESTDIR/tarfile
107
108# Verify all the node have expected correct access control
109allnodes="$nfile $ndir"
110
111#
112# According to the original bits, the input ACE access and ACE type, return the
113# expect bits after 'chmod A0{+|=}'.
114#
115# $1 isdir indicate if the target is a directory
116# $1 bits which was make up of three bit 'rwx'
117# $2 bits_limit which was make up of three bit 'rwx'
118# $3 ACE access which is read_data, write_data or execute
119# $4 ACE type which is allow or deny
120#
121function cal_bits #isdir bits bits_limit acl_access ctrl
122{
123	typeset -i isdir=$1
124	typeset -i bits=$2
125	typeset -i bits_limit=$3
126	typeset acl_access=$4
127	typeset -i ctrl=${5:-0}
128	typeset flagr=0; flagw=0; flagx=0
129	typeset tmpstr
130
131	if (( ctrl == 0 )); then
132		if (( (( bits & 4 )) == 0 )); then
133			flagr=1
134		fi
135		if (( (( bits & 2 )) == 0 )); then
136			flagw=1
137		fi
138		if (( (( bits & 1 )) == 0 )); then
139			flagx=1
140		fi
141	else
142		#
143		# Tricky here:
144		# (1) flagr is always set to be 1,
145		# (2) flagw & flagx is set to be 0 only while
146		#	bits_limit has lower permissions than bits
147		#
148
149		flagr=1
150		flagw=1
151		flagx=1
152
153		if (( (( bits & 2 )) != 0 )) && \
154			(( (( bits_limit & 2 )) == 0 )) ; then
155			flagw=0
156		fi
157		if (( (( bits & 1 )) != 0 )) && \
158			(( (( bits_limit & 1 )) == 0 )) ; then
159			flagx=0
160		fi
161	fi
162
163	if (( flagr != 0 )); then
164		if [[ $acl_access == *"read_data"* ]]; then
165			if (( isdir == 0 )) ; then
166				tmpstr=${tmpstr}/read_data
167			else
168				tmpstr=${tmpstr}/list_directory/read_data
169			fi
170		fi
171	fi
172
173	if (( flagw != 0 )); then
174		if [[ $acl_access == *"write_data"* ]]; then
175			if (( isdir == 0 )); then
176				tmpstr=${tmpstr}/write_data
177			else
178				tmpstr=${tmpstr}/add_file/write_data
179			fi
180		fi
181
182		if [[ $acl_access == *"append_data"* ]]; then
183			if (( isdir == 0 )); then
184				tmpstr=${tmpstr}/append_data
185			else
186				tmpstr=${tmpstr}/add_subdirectory/append_data
187			fi
188		fi
189	fi
190	if (( flagx != 0 )); then
191		[[ $acl_access == *"execute"* ]] && \
192			tmpstr=${tmpstr}/execute
193	fi
194
195	tmpstr=${tmpstr#/}
196
197	$ECHO "$tmpstr"
198}
199
200#
201# To translate an ace if the node is dir
202#
203# $1 isdir indicate if the target is a directory
204# $2 acl to be translated
205#
206function translate_acl #isdir acl
207{
208	typeset -i isdir=$1
209	typeset acl=$2
210	typeset who prefix acltemp action
211
212	if (( isdir != 0 )); then
213		who=${acl%%:*}
214		prefix=$who
215		acltemp=${acl#*:}
216		acltemp=${acltemp%%:*}
217		prefix=$prefix:$acltemp
218		action=${acl##*:}
219
220		acl=$prefix:$(cal_bits $isdir 7 7 $acl 1):$action
221	fi
222	$ECHO "$acl"
223}
224
225#
226# According to inherited flag, verify subdirectories and files within it has
227# correct inherited access control.
228#
229function verify_aclmode #<aclmode> <node> <newmode>
230{
231	# Define the nodes which will be affected by inherit.
232	typeset aclmode=$1
233	typeset node=$2
234	typeset newmode=$3
235
236	# count: the ACE item to fetch
237	# pass: to mark if the current ACE should apply to the target
238	# passcnt: counter, if it achieves to maxnumber,
239	#	then no additional ACE should apply.
240	# step: indicate if the ACE be split during aclmode.
241
242	typeset -i count=0 pass=0 passcnt=0 step=0
243	typeset -i bits=0 obits=0 bits_owner=0 isdir=0
244
245	if [[ -d $node ]]; then
246		(( isdir = 1 ))
247	fi
248
249	(( i = maxnumber - 1 ))
250	count=0
251	passcnt=0
252	while (( i >= 0 )); do
253		pass=0
254		step=0
255		expect1=${acls[$i]}
256		expect2=""
257
258		#
259		# aclmode=passthrough,
260		# no changes will be made to the ACL other than
261		# generating the necessary ACL entries to represent
262		# the new mode of the file or directory.
263		#
264		# aclmode=discard,
265		# delete all ACL entries that don't represent
266		# the mode of the file.
267		#
268		# aclmode=groupmask,
269		# reduce user or group permissions.  The permissions are
270		# reduced, such that they are no greater than the group
271		# permission bits, unless it is a user entry that has the
272		# same UID as the owner of the file or directory.
273		# Then, the ACL permissions are reduced so that they are
274		# no greater than owner permission bits.
275		#
276
277		case $aclmode in
278			passthrough)
279				expect1=$(translate_acl $isdir $expect1)
280				;;
281			groupmask)
282				if [[ $expect1 == *":allow" ]]; then
283					expect2=$expect1
284					who=${expect1%%:*}
285					prefix=$who
286					acltemp=""
287					reduce=0
288
289					# To determine the mask bits
290					# according to the entry type.
291
292					case $who in
293						owner@)
294							pos=1
295							;;
296						group@)
297							pos=2
298							;;
299						everyone@)
300							pos=3
301							;;
302						user)
303							acltemp=${expect1#*:}
304							acltemp=${acltemp%%:*}
305							owner=$(get_owner $node)
306							group=$(get_group $node)
307							if [[ $acltemp == $owner ]]; then
308								pos=1
309							else
310								pos=2
311							fi
312							prefix=$prefix:$acltemp
313							;;
314						group)
315							acltemp=${expect1#*:}
316							acltemp=${acltemp%%:*}
317							pos=2
318							prefix=$prefix:$acltemp
319							reduce=1
320							;;
321					esac
322
323					obits=$(get_substr $newmode $pos 1)
324					(( bits = obits ))
325		#
326		# permission should no greater than the group permission bits
327		#
328					if (( reduce != 0 )); then
329						(( bits &= $(get_substr $newmode 2 1) ))
330
331		# The ACL permissions are reduced so that they are
332                # no greater than owner permission bits.
333
334						(( bits_owner = $(get_substr $newmode 1 1) ))
335						(( bits &= bits_owner ))
336					fi
337
338					if (( bits < obits )) && [[ -n $acltemp ]]; then
339						expect2=$prefix:$(cal_bits $isdir $obits $bits_owner $expect2 1):allow
340					else
341						expect2=$prefix:$(cal_bits $isdir $obits $obits $expect2 1):allow
342
343					fi
344
345					priv=$(cal_bits $isdir $obits $bits_owner $expect2 0)
346					expect1=$prefix:$priv:deny
347					step=1
348				else
349					expect1=$(translate_acl $isdir $expect1)
350				fi
351				;;
352			discard)
353				passcnt=maxnumber
354				break
355				;;
356		esac
357
358		if (( pass == 0 )) ; then
359			# Get the first ACE to do comparison
360
361			aclcur=$(get_ACE $node $count)
362			aclcur=${aclcur#$count:}
363			if [[ -n $expect1 && $expect1 != $aclcur ]]; then
364				$LS -vd $node
365				log_fail "$i #$count " \
366					"ACE: $aclcur, expect to be " \
367					"$expect1"
368			fi
369
370			# Get the second ACE (if should have) to do comparison
371
372			if (( step > 0 )); then
373				(( count = count + step ))
374
375				aclcur=$(get_ACE $node $count)
376				aclcur=${aclcur#$count:}
377				if [[ -n $expect2 && \
378					$expect2 != $aclcur ]]; then
379
380					$LS -vd $node
381					log_fail "$i #$count " \
382						"ACE: $aclcur, expect to be " \
383						"$expect2"
384				fi
385			fi
386			(( count = count + 1 ))
387		fi
388		(( i = i - 1 ))
389	done
390
391	#
392	# If there's no any ACE be checked, it should be identify as
393	# an normal file/dir, verify it.
394	#
395
396	if (( passcnt == maxnumber )); then
397		if [[ -d $node ]]; then
398			compare_acls $node $odir
399		elif [[	-f $node ]]; then
400			compare_acls $node $ofile
401		fi
402
403		if [[ $? -ne 0 ]]; then
404			$LS -vd $node
405			log_fail "Unexpect acl: $node, $aclmode ($newmode)"
406		fi
407	fi
408}
409
410
411
412typeset -i maxnumber=0
413typeset acl
414typeset target
415
416cwd=$PWD
417cd $TESTDIR
418
419for mode in "${aclmode_flag[@]}"; do
420
421	#
422	# Set different value of aclmode
423	#
424
425	log_must $ZFS set aclmode=$mode $TESTPOOL/$TESTFS
426
427	for user in root $ZFS_ACL_STAFF1; do
428		log_must set_cur_usr $user
429
430		log_must usr_exec $MKDIR $basedir
431
432		log_must usr_exec $MKDIR $odir
433		log_must usr_exec $TOUCH $ofile
434		log_must usr_exec $MKDIR $ndir
435		log_must usr_exec $TOUCH $nfile
436
437		for obj in $allnodes ; do
438			maxnumber=0
439			for preset in "${ace_file_preset[@]}"; do
440				for prefix in "${ace_prefix[@]}"; do
441					acl=$prefix:$preset
442
443					case $(( maxnumber % 2 )) in
444						0)
445							acl=$acl:deny
446							;;
447						1)
448							acl=$acl:allow
449							;;
450					esac
451
452				#
453				# Place on the target should succeed.
454				#
455					log_must usr_exec $CHMOD A+$acl $obj
456					acls[$maxnumber]=$acl
457
458					(( maxnumber = maxnumber + 1 ))
459				done
460			done
461
462			# Archive the file and directory
463			log_must $TAR cpf@ $TARFILE basedir
464
465			if [[ -d $obj ]]; then
466				target=$odir
467			elif [[ -f $obj ]]; then
468				target=$ofile
469               		fi
470
471			for newmode in "${argv[@]}" ; do
472				log_must usr_exec $CHMOD $newmode $obj
473				log_must usr_exec $CHMOD $newmode $target
474				verify_aclmode $mode $obj $newmode
475
476			 	# Restore the tar archive
477				log_must $TAR xpf@ $TARFILE
478			done
479		done
480
481		log_must usr_exec $RM -rf $basedir $TARFILE
482	done
483done
484
485log_pass "Verify chmod behaviour co-op with aclmode setting passed."
486