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#
29# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
30# Copyright 2016 Nexenta Systems, Inc.
31#
32
33. $STF_SUITE/tests/functional/acl/acl_common.kshlib
34
35# DESCRIPTION:
36# Verify chmod have correct behaviour to directory and file not inherited
37# when filesystem has the different aclinherit setting
38#
39# STRATEGY:
40# 1. Use both super user and non-super user to run the test case.
41# 2. Create basedir and a set of subdirectores and files inside of it.
42# 3. For the following values of the aclinherity property, add ACEs with
43#    different inherit options to basedir:
44#    "discard", "noallow", "restricted" and "passthrough".
45# 4. Create nested directories and files like the following.
46#
47#               ofile
48#               odir
49#    chmod -->  basedir -|
50#                        |_ nfile1
51#                        |_ ndir1 _
52#                                  |_ nfile2
53#                                  |_ ndir2 _
54#                                            |_ nfile3
55#                                            |_ ndir3
56#
57# 5. Verify non-inherited directories and files have the correct access
58#    control capability.
59
60verify_runnable "both"
61
62function cleanup
63{
64	[[ -f $ofile ]] && log_must rm -f $ofile
65	[[ -d $odir ]] && log_must rm -rf $odir
66	[[ -d $basedir ]] && log_must rm -rf $basedir
67
68	log_must zfs set aclmode=discard $TESTPOOL/$TESTFS
69}
70
71log_assert "Verify different inherit options combined with different" \
72    "aclinherit property values"
73log_onexit cleanup
74
75# Define inherit flag
76typeset aclinherit_flag=(discard noallow restricted passthrough)
77typeset object_flag=(file_inherit dir_inherit file_inherit/dir_inherit)
78typeset strategy_flag=("" inherit_only no_propagate inherit_only/no_propagate)
79
80typeset ace_prefix1="user:$ZFS_ACL_OTHER1"
81typeset ace_prefix2="user:$ZFS_ACL_OTHER2"
82
83# Define the base directory and file
84basedir=$TESTDIR/basedir;  ofile=$TESTDIR/ofile; odir=$TESTDIR/odir
85
86# Define the files and directories will be created after chmod
87ndir1=$basedir/ndir1; ndir2=$ndir1/ndir2; ndir3=$ndir2/ndir3
88nfile1=$basedir/nfile1; nfile2=$ndir1/nfile2; nfile3=$ndir2/nfile3
89
90# Verify all the node have expected correct access control
91allnodes="$ndir1 $ndir2 $ndir3 $nfile1 $nfile2 $nfile3"
92
93# According to inherited flag, verify subdirectories and files within it has
94# correct inherited access control.
95function verify_inherit #<aclinherit> <object> [strategy]
96{
97	# Define the nodes which will be affected by inherit.
98	typeset non_inherit_nodes=""
99	typeset inherit=$1
100	typeset obj=$2
101	typeset str=$3
102	typeset inherit_type
103	typeset str1="/inherit_only/inherited:"
104	typeset str2="/inherited:"
105
106	# count: the ACE item to fetch
107	# passcnt: counter, if it achieves to maxaces,
108	#	then no additional ACE should apply.
109	# isinherit: indicate if the current target is in the inherit list.
110	typeset -i count=0 pass=0 passcnt=0 isinherit=0 no_propagate=0
111
112	log_must usr_exec mkdir -p $ndir3
113	log_must usr_exec touch $nfile1 $nfile2 $nfile3
114
115	# Get the inherit type/object_flag and non-inherited nodes.
116	if [[ $obj == *"file_inherit"* && $obj == *"dir_inherit"* ]]; then
117		inherit_type="both"
118		if [[ $str == *"no_propagate"* ]]; then
119			non_inherit_nodes= $ndir2 $ndir3 $nfile2 $nfile3
120			no_propagate=1
121		fi
122	elif [[ $obj == *"dir_inherit"* ]]; then
123		inherit_type="directory"
124		non_inherit_nodes="$nfile1 $nfile2 $nfile3"
125		if [[ $str == *"no_propagate"* ]]; then
126			non_inherit_nodes="$non_inherit_nodes $ndir2 $ndir3"
127			no_propagate=1
128		fi
129	else
130		inherit_type="file"
131		non_inherit_nodes="$ndir1 $ndir2 $ndir3"
132		if [[ $str == *"no_propagate"* ]]; then
133			non_inherit_nodes="$non_inherit_nodes $nfile2 $nfile3"
134			no_propagate=1
135		fi
136	fi
137	# Verify ACEs for all the dirs/files under basedir
138	for node in $allnodes; do
139		if [[ " $non_inherit_nodes " == *" $node "* ]]; then
140			no_inherit=1
141		else
142			no_inherit=0
143		fi
144		i=0
145		count=0
146		passcnt=0
147		while ((i < maxaces)); do
148			typeset expacl
149
150			if [[ $inherit == "restricted" ]]; then
151				eval expacl=\$acls$i
152			else
153				eval expacl=\$acl$i
154			fi
155			case $inherit in
156			noallow)
157				if [[ $expacl == *":allow" ]]; then
158					((i = i + 1))
159					continue
160				fi
161				;;
162			discard)
163				((passcnt = maxaces))
164				break
165				;;
166			esac
167			if ((no_inherit == 0)); then
168				((i = i + 1))
169				continue
170			fi
171
172			if [[ -d $node ]]; then
173				# Verify ACEs for subdirectory
174				aclaction=${expacl##*:}
175				acltemp=${expacl%:*}
176				if [[ $inherit_type == "directory" ||
177				    $inherit_type == "both" ]]; then
178					expacl=${acltemp}${str2}
179					expacl=${expacl}${aclaction}
180				elif [[ $inherit_type == "file" ]]; then
181					if [[ $expacl != *"inherit_only"* ]]; then
182						# Directory should have
183						# "inherit_only" appended
184						expacl=${acltemp}${str1}
185						expacl=${expacl}${aclaction}
186					else
187						expacl=${acltemp}${str2}
188						expacl=${expacl}${aclaction}
189					fi
190				fi
191				aclcur=$(get_ACE $node $count)
192				aclcur=${aclcur#$count:}
193				if [[ $no_propagate == 0 ]]; then
194					if [[ $expacl != $aclcur ]]; then
195						ls -vd $basedir
196						ls -vd $node
197						log_fail "$inherit $i #$count" \
198						    "ACE: $aclcur," \
199						    "expected: $expacl"
200					fi
201				else
202					# Compare if directory has trivial ACL
203					compare_acls $node $odir
204					if [[ $? -ne 0 ]]; then
205						ls -vd $basedir
206						ls -vd $node
207						log_fail "unexpected ACE:"
208						    "$node, $inherit ($str)"
209					fi
210				fi
211			# Verify ACE's for nested file
212			elif [[ -f $node ]]; then
213				compare_acls $node $ofile
214				if [[ $? -ne 0 ]]; then
215					ls -vd $basedir
216					ls -vd $node
217					log_fail "unexpected ACE:" \
218					    "$node, $inherit ($str)"
219				fi
220			fi
221			((count = count + 1))
222			((i = i + 1))
223		done
224
225		# If there are no ACEs to be checked, compare the trivial ones.
226		if ((passcnt == maxaces)); then
227			if [[ -d $node ]]; then
228				compare_acls $node $odir
229			elif [[	-f $node ]]; then
230				compare_acls $node $ofile
231			fi
232
233			if [[ $? -ne 0 ]]; then
234				ls -vd $basedir
235				ls -vd $node
236				log_fail "Unexpected ACE: $node, $inherit ($str)"
237			fi
238		fi
239	done
240}
241
242typeset -i i=0 maxaces=4
243typeset acl0 acl1 acl2 acl3
244typeset acls0 acls1 acls2 acls3
245
246log_must zfs set aclmode=passthrough $TESTPOOL/$TESTFS
247
248for inherit in "${aclinherit_flag[@]}"; do
249	log_must zfs set aclinherit=$inherit $TESTPOOL/$TESTFS
250
251	for user in root $ZFS_ACL_STAFF1; do
252		log_must set_cur_usr $user
253
254		for obj in "${object_flag[@]}"; do
255			for str in "${strategy_flag[@]}"; do
256				typeset inh_opt=$obj
257				((${#str} != 0)) && inh_opt=$inh_opt/$str
258
259				# Prepare 4 ACES, which should include:
260				# deny -> to verify "noallow"
261				# write_acl/write_owner -> to verify "restricted"
262				acl0="${ace_prefix1}:read_xattr/write_acl"
263				acl0="${acl0}/write_owner:${inh_opt}:deny"
264				acl1="${ace_prefix2}:read_xattr/write_acl"
265				acl1="${acl1}/write_owner:${inh_opt}:allow"
266				acl2="${ace_prefix1}:read_xattr:${inh_opt}:deny"
267				acl3="${ace_prefix2}:read_xattr:${inh_opt}:allow"
268
269				# The ACEs filtered by write_acl/write_owner
270				acls0=$acl0
271				acls1="${ace_prefix2}:read_xattr"
272				acls1="${acls1}:${inh_opt}:allow"
273				acls2=$acl2
274				acls3=$acl3
275				#
276				# Create basedir and tmp dir/file
277				# for comparison.
278				#
279				log_note "$user: chmod $acl $basedir"
280				log_must usr_exec mkdir $basedir
281				log_must usr_exec mkdir $odir
282				log_must usr_exec touch $ofile
283
284				i=3
285				while ((i >= 0)); do
286					eval acl=\$acl$i
287					log_must usr_exec chmod A+$acl $basedir
288					((i = i - 1))
289				done
290				log_note "verify_inherit $inherit $obj $str"
291				log_must verify_inherit $inherit $obj $str
292
293				log_must usr_exec rm -rf $ofile $odir $basedir
294			done
295		done
296	done
297done
298
299log_pass "Verify different inherit options combined with different" \
300    "aclinherit property values"
301