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 (c) 2012 by Delphix. All rights reserved.
30#
31
32. $STF_SUITE/tests/functional/acl/acl_common.kshlib
33
34#
35# DESCRIPTION:
36#	Verify that the write_owner for
37#	owner/group/everyone are correct.
38#
39# STRATEGY:
40# 1. Create file and  directory in zfs filesystem
41# 2. Set special write_owner ACE to the file and directory
42# 3. Try to chown/chgrp of the file and directory to take owner/group
43# 4. Verify that the owner/group are correct. Follow these rules:
44#	(1) If uid is granted the write_owner permission, then it can only do
45#	    chown to its own uid, or a group that they are a member of.
46#	(2) Owner will ignore permission of (1) even write_owner not granted.
47#	(3) Superuser will always permit whatever they do.
48#
49
50verify_runnable "both"
51
52function cleanup
53{
54	[[ -d $basedir ]] && $RM -rf $basedir
55	[[ -f $TESTDIR/$ARCHIVEFILE ]] && log_must $RM -f $TESTDIR/$ARCHIVEFILE
56	return 0
57}
58
59log_assert "Verify that the chown/chgrp could take owner/group " \
60	"while permission is granted."
61log_onexit cleanup
62
63#
64# Get the owner of a file/directory
65#
66function get_owner
67{
68	typeset node=$1
69
70	if [[ -z $node ]]; then
71		log_fail "node are not defined."
72	fi
73
74	$ECHO $($LS -dl $node | $AWK '{print $3}')
75}
76
77#
78# Get the group of a file/directory
79#
80function get_group
81{
82	typeset node=$1
83
84	if [[ -z $node ]]; then
85		log_fail "node are not defined."
86	fi
87
88	$ECHO $($LS -dl $node | $AWK '{print $4}')
89}
90
91
92#
93# Get the group name that a UID belongs to
94#
95function get_user_group
96{
97	typeset uid=$1
98	typeset value
99
100	if [[ -z $uid ]]; then
101		log_fail "UID not defined."
102	fi
103
104	value=$(id $uid)
105
106	if [[ $? -eq 0 ]]; then
107		value=${value##*\(}
108		value=${value%%\)*}
109		$ECHO $value
110	else
111		log_fail "Invalid UID (uid)."
112	fi
113}
114
115function operate_node_owner
116{
117	typeset user=$1
118	typeset node=$2
119	typeset old_owner=$3
120	typeset expect_owner=$4
121	typeset ret new_owner
122
123	if [[ $user == "" || $node == "" ]]; then
124		log_fail "user, node are not defined."
125	fi
126
127	$SU $user -c "$CHOWN $expect_owner $node"
128	ret=$?
129	new_owner=$(get_owner $node)
130
131	if [[ $new_owner != $old_owner ]]; then
132		$TAR xpf $TESTDIR/$ARCHIVEFILE
133	fi
134
135	if [[ $ret -eq 0 ]]; then
136		if [[ $new_owner != $expect_owner ]]; then
137			log_note "Owner not changed as expected " \
138				"($old_owner|$new_owner|$expect_owner), " \
139				"but return code is $ret."
140			return 1
141		fi
142	elif [[ $ret -ne 0 && $new_owner != $old_owner ]]; then
143		log_note "Owner changed ($old_owner|$new_owner), " \
144			"but return code is $ret."
145		return 2
146	fi
147
148	return $ret
149}
150
151function operate_node_group
152{
153	typeset user=$1
154	typeset node=$2
155	typeset old_group=$3
156	typeset expect_group=$4
157	typeset ret new_group
158
159	if [[ $user == "" || $node == "" ]]; then
160		log_fail "user, node are not defined."
161	fi
162
163	$SU $user -c "$CHGRP $expect_group $node"
164	ret=$?
165	new_group=$(get_group $node)
166
167	if [[ $new_group != $old_group ]]; then
168		$TAR xpf $TESTDIR/$ARCHIVEFILE
169	fi
170
171	if [[ $ret -eq 0 ]]; then
172		if [[ $new_group != $expect_group ]]; then
173			log_note "Group not changed as expected " \
174				"($old_group|$new_group|$expect_group), " \
175				"but return code is $ret."
176			return 1
177		fi
178	elif [[ $ret -ne 0 && $new_group != $old_group ]]; then
179		log_note "Group changed ($old_group|$new_group), " \
180			"but return code is $ret."
181		return 2
182	fi
183
184	return $ret
185}
186
187function logname
188{
189	typeset acl_target=$1
190	typeset user=$2
191	typeset old=$3
192	typeset new=$4
193	typeset ret="log_mustnot"
194
195	# To super user, read and write deny permission was override.
196	if [[ $user == root ]]; then
197		ret="log_must"
198	elif [[ $user == $new ]] ; then
199		if [[ $user == $old || $acl_target == *:allow ]]; then
200			ret="log_must"
201		fi
202	fi
203
204	print $ret
205}
206
207function check_chmod_results
208{
209	typeset user=$1
210	typeset node=$2
211	typeset flag=$3
212	typeset acl_target=$3:$4
213	typeset g_usr=$5
214	typeset o_usr=$6
215	typeset log old_owner old_group new_owner new_group
216
217	old_owner=$(get_owner $node)
218	old_group=$(get_group $node)
219
220	if [[ $flag == "owner@" || $flag == "everyone@" ]]; then
221		for new_owner in $user "nobody"; do
222			new_group=$(get_user_group $new_owner)
223
224			log=$(logname $acl_target $user \
225				$old_owner $new_owner)
226
227			$log operate_node_owner $user $node \
228				$old_owner $new_owner
229
230			$log operate_node_group $user $node \
231				$old_group $new_group
232		done
233	fi
234	if [[ $flag == "group@" || $flag == "everyone@" ]]; then
235		for new_owner in $g_usr "nobody"; do
236			new_group=$(get_user_group $new_owner)
237
238			log=$(logname $acl_target $g_usr $old_owner \
239				$new_owner)
240
241			$log operate_node_owner $g_usr $node \
242				$old_owner $new_owner
243
244			$log operate_node_group $g_usr \
245				$node $old_group $new_group
246		done
247	fi
248	if [[ $flag == "everyone@" ]]; then
249		for new_owner in $g_usr "nobody"; do
250			new_group=$(get_user_group $new_owner)
251
252			log=$(logname $acl_target $o_usr $old_owner \
253				$new_owner)
254
255			$log operate_node_owner $o_usr $node \
256				$old_owner $new_owner
257
258			$log operate_node_group $o_usr $node \
259				$old_group $new_group
260		done
261	fi
262}
263
264function test_chmod_basic_access
265{
266	typeset user=$1
267	typeset node=${2%/}
268	typeset g_usr=$3
269	typeset o_usr=$4
270	typeset flag acl_t
271
272	for flag in $a_flag; do
273		for acl_t in $a_access; do
274			log_must $SU $user -c "$CHMOD A+$flag:$acl_t $node"
275
276			$TAR cpf $TESTDIR/$ARCHIVEFILE basedir
277
278			check_chmod_results $user $node $flag $acl_t $g_usr \
279			    $o_usr
280
281			log_must $SU $user -c "$CHMOD A0- $node"
282		done
283	done
284}
285
286function setup_test_files
287{
288	typeset base_node=$1
289	typeset user=$2
290	typeset group=$3
291
292	$RM -rf $base_node
293
294	log_must $MKDIR -p $base_node
295	log_must $CHOWN $user:$group $base_node
296
297	# Prepare all files/sub-dirs for testing.
298	log_must $SU $user -c "$TOUCH $file"
299	log_must $SU $user -c "$CHMOD 444 $file"
300	log_must $SU $user -c "$MKDIR -p $dir"
301	log_must $SU $user -c "$CHMOD 444 $dir"
302	log_must $SU $user -c "$CHMOD 555 $base_node"
303}
304
305typeset ARCHIVEFILE=archive.tar
306typeset a_access="write_owner:allow write_owner:deny"
307typeset a_flag="owner@ group@ everyone@"
308typeset basedir="$TESTDIR/basedir"
309typeset file="$basedir/file"
310typeset dir="$basedir/dir"
311
312cd $TESTDIR
313setup_test_files $basedir 'root' 'root'
314test_chmod_basic_access 'root' $file $ZFS_ACL_ADMIN  $ZFS_ACL_OTHER1
315test_chmod_basic_access 'root' $dir $ZFS_ACL_ADMIN  $ZFS_ACL_OTHER1
316$RM -rf $basedir
317
318setup_test_files $basedir $ZFS_ACL_STAFF1 $ZFS_ACL_STAFF_GROUP
319test_chmod_basic_access $ZFS_ACL_STAFF1 $file $ZFS_ACL_STAFF2 $ZFS_ACL_OTHER1
320test_chmod_basic_access $ZFS_ACL_STAFF1 $dir $ZFS_ACL_STAFF2 $ZFS_ACL_OTHER1
321$RM -rf $basedir
322
323log_pass "Verify that the chown/chgrp could take owner/group " \
324    "while permission is granted."
325