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