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 2009 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 that the combined delete_child/delete permission for
36# owner/group/everyone are correct.
37#
38#        -------------------------------------------------------
39#        |   Parent Dir  |           Target Object Permissions |
40#        |  permissions  |                                     |
41#        -------------------------------------------------------
42#        |               | ACL Allows | ACL Denies| Delete     |
43#        |               |  Delete    |  Delete   | unspecified|
44#        -------------------------------------------------------
45#        | ACL Denies    | Permit     | Deny      | Deny       |
46#        | DELETE_CHILD  |            |           |            |
47#        | or WRITE_DATA |            |           |            |
48#        -------------------------------------------------------
49#        | ACL Allows    | Permit     | Deny      | Permit     |
50#        | DELETE_CHILD  |            |           |            |
51#        | or WRITE_DATA |            |           |            |
52#        -------------------------------------------------------
53#
54# STRATEGY:
55# 1. Create file and  directory in zfs filesystem
56# 2. Set special ACE combination to the file and directory
57# 3. Try to remove the file
58# 4. Verify that combined permissions for owner/group/everyone are correct.
59
60verify_runnable "both"
61
62function cleanup
63{
64	if [[ ! -e $target ]]; then
65		log_must tar xpf $TESTDIR/$ARCHIVEFILE
66	fi
67
68	(( ${#cwd} != 0 )) && cd $cwd
69	cleanup_test_files $TESTDIR/basedir
70	if [[ -e $TESTDIR/$ARCHIVEFILE ]]; then
71		log_must rm -f $TESTDIR/$ARCHIVEFILE
72	fi
73	return 0
74}
75
76#owner@	          group	                 group_users       other_users
77set -A users \
78"root"            "root"                 "$ZFS_ACL_ADMIN"  "$ZFS_ACL_OTHER1" \
79"$ZFS_ACL_STAFF1" "$ZFS_ACL_STAFF_GROUP" "$ZFS_ACL_STAFF2" "$ZFS_ACL_OTHER1"
80
81set -A access_parent \
82	"delete_child:allow" \
83	"delete_child:deny" \
84	"write_data:allow" \
85	"write_data:deny" \
86	"delete_child:deny write_data:allow" \
87	"delete_child:allow write_data:deny"
88
89set -A access_target \
90	"delete:allow" \
91	"delete:deny" \
92	""
93
94set -A a_flag "owner@" "group@" "everyone@" "user:$ZFS_ACL_STAFF1"
95
96log_assert "Verify that the combined delete_child/delete permission for" \
97    "owner/group/everyone are correct."
98log_onexit cleanup
99
100function operate_node #user node
101{
102	typeset user=$1
103	typeset node=$2
104	typeset ret
105
106	if [[ $user == "" || $node == "" ]]; then
107		log_fail "user, node are not defined."
108	fi
109	if [[ -d $node ]]; then
110		chgusr_exec $user rm -rf $node ; ret=$?
111	else
112		chgusr_exec $user rm -f $node ; ret=$?
113	fi
114
115	if [[ -e $node ]]; then
116		if [[ $ret -eq 0 ]]; then
117			log_note "$node not removed, but return code is 0."
118			return 1
119		fi
120	else
121		log_must tar xpf $TESTDIR/$ARCHIVEFILE
122		if [[ $ret -ne 0 ]]; then
123			log_note "$node removed, but return code is $ret."
124			return 1
125		fi
126	fi
127	return $ret
128}
129
130function logname #acl_parent acl_target user
131{
132	typeset acl_parent=$1
133	typeset acl_target=$2
134	typeset user=$3
135
136	# To super user, read and write deny permission was override.
137	if [[ $user == "root" || $acl_target == *":allow"* ]]; then
138		print "log_must"
139	# If target ACL has an ACE deny'ing delete, DENY
140	elif [[ $acl_target == *"delete:deny"* ]]; then
141		print "log_mustnot"
142	# If target ACL has an ACE allow'ing delete, ALLOW
143	elif [[ $acl_target == *"delete:allow"* ]]; then
144		print "log_must"
145	# If container ACL has an ACE deny'ing delete_child or
146	# write_data, DENY
147	elif [[ $acl_parent == *"delete_child:deny"* ||
148	    $acl_parent == *"write_data:deny"* ]]; then
149		print "log_mustnot"
150	# If container ACL has an ACE allow'ing delete_child or
151	# write_data, ALLOW
152	elif [[ $acl_parent == *"delete_child:allow"* ||
153	    $acl_parent == *"write_data:allow"* ]]; then
154		print "log_must"
155	# Otherwise, DENY
156	else
157		print "log_mustnot"
158	fi
159}
160
161function check_chmod_results #node flag acl_parent acl_target g_usr o_usr
162{
163	typeset node=$1
164	typeset flag=$2
165	typeset acl_parent=$3
166	typeset acl_target=$2:$4
167	typeset g_usr=$5
168	typeset o_usr=$6
169	typeset log acl_tmp
170
171	for acl in $acl_parent ; do
172		acl_tmp="$2:$acl $acl_tmp"
173	done
174	acl_parent=$acl_tmp
175
176	if [[ $flag == "owner@" || $flag == "everyone@" ]]; then
177		log=$(logname "$acl_parent" $acl_target $ZFS_ACL_CUR_USER)
178		$log operate_node $ZFS_ACL_CUR_USER $node
179	fi
180	if [[ $flag == "group@" || $flag == "everyone@" ]]; then
181		log=$(logname "$acl_parent" $acl_target $g_usr)
182		$log operate_node $g_usr $node
183	fi
184	if [[ $flag == "everyone@" ]]; then
185		log=$(logname "$acl_parent" $acl_target $o_usr)
186		$log operate_node $o_usr $node
187	fi
188	if [[ $flag == "user:"* ]]; then
189		typeset user=${flag#user:}
190		log=$(logname "$acl_parent" $acl_target $user)
191		$log operate_node $user $node
192	fi
193}
194
195function test_chmod_basic_access #node g_usr o_usr
196{
197	typeset node=${1%/}
198	typeset g_usr=$2
199	typeset o_usr=$3
200	typeset flag acl_p acl_t parent
201	typeset -i i=0
202
203	parent=${node%/*}
204
205	for flag in ${a_flag[@]}; do
206	for acl_p in "${access_parent[@]}"; do
207		i=0
208		for acl in $acl_p ; do
209			log_must usr_exec chmod A+$flag:$acl $parent
210			(( i = i + 1))
211		done
212
213		for acl_t in "${access_target[@]}"; do
214			[[ -n $acl_t ]] && \
215				log_must usr_exec chmod A+$flag:$acl_t $node
216
217			log_must tar cpf $TESTDIR/$ARCHIVEFILE basedir
218
219			check_chmod_results "$node" "$flag" \
220				 "$acl_p" "$acl_t" "$g_usr" "$o_usr"
221
222			[[ -n $acl_t ]] && \
223				log_must usr_exec chmod A0- $node
224		done
225
226		while (( i > 0 )); do
227			log_must usr_exec chmod A0- $parent
228			(( i = i - 1 ))
229		done
230	done
231	done
232}
233
234function setup_test_files #base_node user group
235{
236	typeset base_node=$1
237	typeset user=$2
238	typeset group=$3
239
240	cleanup_test_files $base_node
241
242	log_must mkdir -p $base_node
243	log_must chown $user:$group $base_node
244
245	log_must set_cur_usr $user
246
247	# Prepare all files/sub-dirs for testing.
248	file0=$base_node/testfile_rm
249	dir0=$base_node/testdir_rm
250
251	log_must usr_exec touch $file0
252	log_must usr_exec chmod 444 $file0
253
254	log_must usr_exec mkdir -p $dir0
255	log_must usr_exec chmod 444 $dir0
256
257	log_must usr_exec chmod 555 $base_node
258	return 0
259}
260
261function cleanup_test_files #base_node
262{
263	typeset base_node=$1
264
265	if [[ -d $base_node ]]; then
266		log_must rm -rf $base_node
267	elif [[ -e $base_node ]]; then
268		log_must rm -f $base_node
269	fi
270
271	return 0
272}
273
274typeset cwd=$PWD
275typeset ARCHIVEFILE=archive.tar
276
277typeset -i i=0
278typeset -i j=0
279typeset target
280cd $TESTDIR
281while (( i < ${#users[@]} )); do
282	setup_test_files $TESTDIR/basedir ${users[i]} ${users[((i+1))]}
283
284	j=0
285	while (( j < 1 )); do
286		eval target=\$file$j
287		test_chmod_basic_access $target \
288			"${users[((i+2))]}" "${users[((i+3))]}"
289
290		eval target=\$dir$j
291		test_chmod_basic_access $target \
292			"${users[((i+2))]}" "${users[((i+3))]}"
293
294		(( j = j + 1 ))
295	done
296
297	(( i += 4 ))
298done
299
300log_pass "Verify that the combined delete_child/delete permission for" \
301    "owner/group/everyone are correct."
302