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. $STF_SUITE/tests/functional/acl/acl_common.kshlib
29
30#
31# DESCRIPTION:
32#	chmod A{+|-|=} read_data|write_data|execute for owner@ group@ or
33#	everyone@ correctly alters mode bits .
34#
35# STRATEGY:
36#	1. Loop root and non-root user.
37#	2. Get the random initial map.
38#	3. Get the random ACL string.
39#	4. Separately chmod +|-|= read_data|write_data|execute
40#	5. Check map bits
41#
42
43verify_runnable "both"
44
45log_assert "chmod A{+|-|=} read_data|write_data|execute for owner@, group@ " \
46	"or everyone@ correctly alters mode bits."
47log_onexit cleanup
48
49set -A bits 0 1 2 3 4 5 6 7
50set -A a_flag owner group everyone
51set -A a_access read_data write_data execute
52set -A a_type allow deny
53
54#
55# Get a random item from an array.
56#
57# $1 the base set
58#
59function random_select #array_name
60{
61	typeset arr_name=$1
62	typeset -i ind
63
64	eval typeset -i cnt=\${#${arr_name}[@]}
65	(( ind = $RANDOM % cnt ))
66
67	eval print \${${arr_name}[$ind]}
68}
69
70#
71# Create a random string according to array name, the item number and
72# separated tag.
73#
74# $1 array name where the function get the elements
75# $2 the items number which you want to form the random string
76# $3 the separated tag
77#
78function form_random_str #<array_name> <count> <sep>
79{
80	typeset arr_name=$1
81	typeset -i count=${2:-1}
82	typeset sep=${3:-""}
83
84	typeset str=""
85	while (( count > 0 )); do
86		str="${str}$(random_select $arr_name)${sep}"
87
88		(( count -= 1 ))
89	done
90
91	print $str
92}
93
94#
95# According to the original bits, the input ACE access and ACE type, return the
96# expect bits after 'chmod A0{+|=}'.
97#
98# $1 bits which was make up of three bit 'rwx'
99# $2 ACE access which is read_data, write_data or execute
100# $3 ACE type which is allow or deny
101#
102function cal_bits #bits acl_access acl_type
103{
104	typeset bits=$1
105	typeset acl_access=$2
106	typeset acl_type=$3
107	set -A bit r w x
108
109	typeset tmpbits=""
110	typeset -i i=0 j
111	while (( i < 3 )); do
112		if [[ $acl_access == *"${a_access[i]}"* ]]; then
113			if [[ $acl_type == "allow" ]]; then
114				tmpbits="$tmpbits${bit[i]}"
115			elif [[ $acl_type == "deny" ]]; then
116				tmpbits="${tmpbits}-"
117			fi
118		else
119			(( j = i + 1 ))
120			tmpbits="$tmpbits$(get_substr $bits $j 1)"
121		fi
122
123		(( i += 1 ))
124	done
125
126	echo "$tmpbits"
127}
128
129#
130# Based on the initial node map before chmod and the ace-spec, check if chmod
131# has the correct behaven to map bits.
132#
133function check_test_result #init_mode node acl_flag acl_access a_type
134{
135	typeset init_mode=$1
136	typeset node=$2
137	typeset acl_flag=$3
138	typeset acl_access=$4
139	typeset acl_type=$5
140
141	typeset -L3 u_bits=$init_mode
142	typeset g_bits=$(get_substr $init_mode 4 3)
143	typeset -R3 o_bits=$init_mode
144
145	if [[ $acl_flag == "owner" || $acl_flag == "everyone" ]]; then
146		u_bits=$(cal_bits $u_bits $acl_access $acl_type)
147	fi
148	if [[ $acl_flag == "group" || $acl_flag == "everyone" ]]; then
149		g_bits=$(cal_bits $g_bits $acl_access $acl_type)
150	fi
151	if [[ $acl_flag == "everyone" ]]; then
152		o_bits=$(cal_bits $o_bits $acl_access $acl_type)
153	fi
154
155	typeset cur_mode=$(get_mode $node)
156	cur_mode=$(get_substr $cur_mode 2 9)
157
158	if [[ $cur_mode == $u_bits$g_bits$o_bits ]]; then
159		log_note "SUCCESS: Current map($cur_mode) == " \
160			"expected map($u_bits$g_bits$o_bits)"
161	else
162		log_fail "FAIL: Current map($cur_mode) != " \
163			"expected map($u_bits$g_bits$o_bits)"
164	fi
165}
166
167function test_chmod_map #<node>
168{
169	typeset node=$1
170	typeset init_mask acl_flag acl_access acl_type
171	typeset -i cnt
172
173	if (( ${#node} == 0 )); then
174		log_fail "FAIL: file name or directory name is not defined."
175	fi
176
177	# Get the initial map
178	init_mask=$(form_random_str bits 3)
179	# Get ACL flag, access & type
180	acl_flag=$(form_random_str a_flag)
181	(( cnt = ($RANDOM % ${#a_access[@]}) + 1 ))
182	acl_access=$(form_random_str a_access $cnt '/')
183	acl_access=${acl_access%/}
184	acl_type=$(form_random_str a_type)
185
186	typeset acl_spec=${acl_flag}@:${acl_access}:${acl_type}
187
188	# Set the initial map and back the initial ACEs
189	typeset orig_ace=/tmp/orig_ace.$$
190	typeset cur_ace=/tmp/cur_ace.$$
191
192	for operator in "A0+" "A0="; do
193		log_must usr_exec $CHMOD $init_mask $node
194		init_mode=$(get_mode $node)
195		init_mode=$(get_substr $init_mode 2 9)
196		log_must usr_exec eval "$LS -vd $node > $orig_ace"
197
198		# To "A=", firstly add one ACE which can't modify map
199		if [[ $operator == "A0=" ]]; then
200			log_must $CHMOD A0+user:$ZFS_ACL_OTHER1:execute:deny \
201				$node
202		fi
203		log_must usr_exec $CHMOD $operator$acl_spec $node
204		check_test_result \
205			$init_mode $node $acl_flag $acl_access $acl_type
206
207		# Check "chmod A-"
208		log_must usr_exec $CHMOD A0- $node
209		log_must usr_exec eval "$LS -vd $node > $cur_ace"
210
211		if $DIFF $orig_ace $cur_ace; then
212			log_note "SUCCESS: current ACEs are equal to " \
213				"original ACEs. 'chmod A-' succeeded."
214		else
215			log_fail "FAIL: 'chmod A-' failed."
216		fi
217	done
218
219	[[ -f $orig_ace ]] && log_must usr_exec $RM -f $orig_ace
220	[[ -f $cur_ace ]] && log_must usr_exec $RM -f $cur_ace
221}
222
223for user in root $ZFS_ACL_STAFF1; do
224	set_cur_usr $user
225
226	typeset -i loop_cnt=20
227	while (( loop_cnt > 0 )); do
228		log_must usr_exec $TOUCH $testfile
229		test_chmod_map $testfile
230		log_must $RM -f $testfile
231
232		log_must usr_exec $MKDIR $testdir
233		test_chmod_map $testdir
234		log_must $RM -rf $testdir
235
236		(( loop_cnt -= 1 ))
237	done
238done
239
240log_pass "chmod A{+|-|=} read_data|write_data|execute for owner@, group@ " \
241	"or everyone@ correctly alters mode bits passed."
242