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 2016 Nexenta Systems, Inc.
30#
31
32. $STF_SUITE/tests/functional/acl/acl_common.kshlib
33
34# DESCRIPTION:
35# Verify chmod have correct behaviour to directory and file when
36# filesystem has the different aclinherit setting
37#
38# STRATEGY:
39# 1. Use both super user and non-super user to run the test case.
40# 2. Create basedir and a set of subdirectores and files within it.
41# 3. Separately chmod basedir with different inherite options,
42#    combine with the variable setting of aclinherit:
43#    "discard", "noallow", "restricted" or "passthrough".
44# 4. Then create nested directories and files like the following.
45#
46#               ofile
47#               odir
48#    chmod -->  basedir -|
49#                        |_ nfile1
50#                        |_ ndir1 _
51#                                  |_ nfile2
52#                                  |_ ndir2 _
53#                                            |_ nfile3
54#                                            |_ ndir3
55#
56# 5. Verify each directories and files have the correct access control
57#    capability.
58
59verify_runnable "both"
60
61function cleanup
62{
63	[[ -f $ofile ]] && log_must rm -f $ofile
64	[[ -d $odir ]] && log_must rm -rf $odir
65	[[ -d $basedir ]] && log_must rm -rf $basedir
66}
67
68log_assert "Verify chmod have correct behaviour to directory and file when" \
69    "filesystem has the different aclinherit setting"
70log_onexit cleanup
71
72# Define inherit flag
73typeset aclinherit_flag=("discard" "noallow" "restricted" "passthrough")
74typeset object_flag=("f-" "-d" "fd")
75typeset strategy_flag=("--" "i-" "-n" "in")
76
77typeset ace_prefix1="owner@"
78typeset ace_prefix2="group@"
79typeset ace_prefix3="everyone@"
80
81# Define the base directory and file
82basedir=$TESTDIR/basedir; ofile=$TESTDIR/ofile; odir=$TESTDIR/odir
83
84# Define the files and directories that will be created after chmod
85ndir1=$basedir/ndir1; ndir2=$ndir1/ndir2; ndir3=$ndir2/ndir3
86nfile1=$basedir/nfile1; nfile2=$ndir1/nfile2; nfile3=$ndir2/nfile3
87
88# Verify all nodes have expected correct access control
89allnodes="$ndir1 $ndir2 $ndir3 $nfile1 $nfile2 $nfile3"
90
91# According to inherited flag, verify subdirectories and files within it has
92# correct inherited access control.
93function verify_inherit #<aclinherit> <object> [strategy]
94{
95	# Define the nodes which will be affected by inherit.
96	typeset inherit_nodes
97	typeset inherit=$1
98	typeset obj=$2
99	typeset str=$3
100
101	log_must usr_exec mkdir -p $ndir3
102	log_must usr_exec touch $nfile1 $nfile2 $nfile3
103
104	# Check if we have any inheritance flags set
105	if [[ $obj != "--" ]]; then
106		# Files should have inherited ACEs only if file_inherit is set
107		if [[ ${obj:0:1} == "f" ]]; then
108			inherit_nodes="$inherit_nodes $nfile1"
109			if [[ ${str:1:1} != "n" ]]; then
110				inherit_nodes="$inherit_nodes $nfile2 $nfile3"
111			fi
112		fi
113
114		# Directories should have inherited ACEs if file_inherit without
115		# no_propagate and/or dir_inherit is set
116		if [[ (${obj:0:1} == "f" && ${str:1:1} != "n") ||
117		    ${obj:1:1} == "d" ]]; then
118			inherit_nodes="$inherit_nodes $ndir1"
119			if [[ ${str:1:1} != "n" ]]; then
120				inherit_nodes="$inherit_nodes $ndir2 $ndir3"
121			fi
122		fi
123	fi
124
125	for node in $allnodes; do
126		typeset -i i=0 count=0 inherited=0
127		typeset expacl perm inh act
128
129		if [[ "$inherit_nodes" == *"$node"* ]]; then
130			inherited=1
131		fi
132
133		while ((i < $maxaces)); do
134			# If current node isn't in inherit list, there's
135			# nothing to check, skip to checking trivial ACL
136			if ((inherited == 0)); then
137				((count = maxaces + 1))
138				break
139			fi
140
141			eval expacl=\$acl$i
142			case $inherit in
143			discard)
144				# Do not inherit any ACEs
145				((count = maxaces + 1))
146				break
147				;;
148			noallow)
149				# Only inherit inheritable ACEs that specify
150				# "deny" permissions
151				if [[ $expacl == *":allow" ]] ; then
152					((i = i + 1))
153					continue
154				fi
155				;;
156			restricted)
157				# Remove write_acl and write_owner permissions
158				# when the ACEs is inherited
159				eval expacl=\$acls$i
160				;;
161			passthrough)
162				;;
163			esac
164
165			perm=${expacl%:*}
166			inh=${perm##*:}
167			inh=${inh:0:2}
168			perm=${perm%:*}
169			act=${expacl##*:}
170
171			if [[ -d $node ]]; then
172				# Clear inheritance flags if no_propagate is set
173				if [[ ${str:1:1} == "n" ]]; then
174					inh="--"
175				fi
176				expacl="$perm:$inh"
177				# Set inherit_only if there's a file_inherit
178				# without dir_inherit
179				if [[ ${obj:0:1} == "f" &&
180				    ${obj:1:1} != "d" ]]; then
181					expacl="${expacl}i---I:$act"
182				else
183					expacl="${expacl}----I:$act"
184				fi
185			elif [[ -f $node ]] ; then
186				expacl="$perm:------I:$act"
187			fi
188
189			aclcur=$(get_ACE $node $count compact)
190			aclcur=${aclcur#$count:}
191			if [[ -n $expacl && $expacl != $aclcur ]]; then
192				ls -Vd $basedir
193				ls -Vd $node
194				log_fail "$inherit $i #$count" \
195				    "expected: $expacl, current: $aclcur"
196			fi
197
198			((i = i + 1))
199			((count = count + 1))
200		done
201
202		# There were no non-trivial ACEs to check, do the trivial ones
203		if ((count == maxaces + 1)); then
204			if [[ -d $node ]]; then
205				compare_acls $node $odir
206			elif [[ -f $node ]]; then
207				compare_acls $node $ofile
208			fi
209
210			if [[ $? -ne 0 ]]; then
211				ls -Vd $basedir
212				ls -Vd $node
213				log_fail "unexpected acl: $node," \
214				    "$inherit ($str)"
215			fi
216		fi
217
218	done
219}
220
221typeset -i i=0 maxaces=6
222typeset acl0 acl1 acl2 acl3 acl4 acl5
223typeset acls0 acls1 acls2 acls3 acls4 acls5
224
225log_must zfs set aclmode=passthrough $TESTPOOL/$TESTFS
226
227for inherit in "${aclinherit_flag[@]}"; do
228	log_must zfs set aclinherit=$inherit $TESTPOOL/$TESTFS
229
230	for user in root $ZFS_ACL_STAFF1; do
231		log_must set_cur_usr $user
232
233		for obj in "${object_flag[@]}"; do
234			for str in "${strategy_flag[@]}"; do
235				typeset inh_opt=$obj
236				((${#str} != 0)) && inh_opt="${inh_opt}${str}--"
237
238				inh_a="${inh_opt}-"
239				inh_b="${inh_opt}I"
240
241				# deny - to verify "noallow"
242				# write_acl/write_owner - to verify "restricted"
243				acl0="$ace_prefix1:-------A-W-Co-:$inh_a:allow"
244				acl1="$ace_prefix2:-------A-W-Co-:$inh_a:deny"
245				acl2="$ace_prefix3:-------A-W-Co-:$inh_a:allow"
246				acl3="$ace_prefix1:-------A-W----:$inh_a:deny"
247				acl4="$ace_prefix2:-------A-W----:$inh_a:allow"
248				acl5="$ace_prefix3:-------A-W----:$inh_a:deny"
249
250				# ACEs filtered by write_acl/write_owner
251				acls0="$ace_prefix1:-------A-W----:$inh_b:allow"
252				acls1="$ace_prefix2:-------A-W-Co-:$inh_b:deny"
253				acls2="$ace_prefix3:-------A-W----:$inh_b:allow"
254				acls3="$ace_prefix1:-------A-W----:$inh_b:deny"
255				acls4="$ace_prefix2:-------A-W----:$inh_b:allow"
256				acls5="$ace_prefix3:-------A-W----:$inh_b:deny"
257
258				log_must usr_exec mkdir $basedir
259				log_must usr_exec mkdir $odir
260				log_must usr_exec touch $ofile
261
262				((i = maxaces - 1))
263				while ((i >= 0)); do
264					eval acl=\$acl$i
265					log_must usr_exec chmod A+$acl $basedir
266					((i = i - 1))
267				done
268
269				verify_inherit $inherit $obj $str
270
271				log_must usr_exec rm -rf $ofile $odir $basedir
272			done
273		done
274	done
275done
276
277log_pass "Verify chmod inherit behaviour co-op with aclinherit setting passed"
278