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