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