6875 fix zfs-tests ACL cases
[unleashed.git] / usr / src / test / zfs-tests / tests / functional / acl / nontrivial / zfs_acl_chmod_aclmode_001_pos.ksh
blob6486f5846404874d9ebcc5a334c0fb07edcb6d68
1 #!/usr/bin/ksh -p
3 # CDDL HEADER START
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.
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.
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]
20 # CDDL HEADER END
24 # Copyright 2008 Sun Microsystems, Inc. All rights reserved.
25 # Use is subject to license terms.
29 # Copyright (c) 2012 by Delphix. All rights reserved.
30 # Copyright 2016 Nexenta Systems, Inc.
34 . $STF_SUITE/tests/functional/acl/acl_common.kshlib
36 # DESCRIPTION:
37 # Verify chmod have correct behaviour on directories and files when
38 # filesystem has the different aclmode setting
40 # STRATEGY:
41 # 1. Loop super user and non-super user to run the test case.
42 # 2. Create basedir and a set of subdirectores and files within it.
43 # 3. Separately chmod basedir with different aclmode options,
44 # combine with the variable setting of aclmode:
45 # "discard", "groupmask", or "passthrough".
46 # 4. Verify each directories and files have the correct access control
47 # capability.
49 verify_runnable "both"
51 function cleanup
53 (( ${#cwd} != 0 )) && cd $cwd
55 [[ -f $TARFILE ]] && log_must $RM -f $TARFILE
56 [[ -d $basedir ]] && log_must $RM -rf $basedir
59 log_assert "Verify chmod have correct behaviour to directory and file when" \
60 "filesystem has the different aclmode setting"
61 log_onexit cleanup
63 set -A aclmode_flag "discard" "groupmask" "passthrough"
65 set -A ace_prefix \
66 "user:$ZFS_ACL_OTHER1" \
67 "user:$ZFS_ACL_OTHER2" \
68 "group:$ZFS_ACL_STAFF_GROUP" \
69 "group:$ZFS_ACL_OTHER_GROUP"
71 set -A argv "000" "444" "644" "777" "755" "231" "562" "413"
73 set -A ace_file_preset \
74 "read_data" \
75 "write_data" \
76 "append_data" \
77 "execute" \
78 "read_data/write_data" \
79 "read_data/write_data/append_data" \
80 "write_data/append_data" \
81 "read_data/execute" \
82 "write_data/append_data/execute" \
83 "read_data/write_data/append_data/execute"
85 # Define the base directory and file
86 basedir=$TESTDIR/basedir; ofile=$basedir/ofile; odir=$basedir/odir
87 nfile=$basedir/nfile; ndir=$basedir/ndir
89 TARFILE=$TESTDIR/tarfile
91 # Verify all the node have expected correct access control
92 allnodes="$nfile $ndir"
94 # According to the original bits, the input ACE access and ACE type, return the
95 # expect bits after 'chmod A0{+|=}'.
97 # $1 isdir indicate if the target is a directory
98 # $2 bits which was make up of three bit 'rwx'
99 # $3 bits_limit which was make up of three bit 'rwx'
100 # $4 ACE access which is read_data, write_data or execute
101 # $5 ctrl which is to determine allow or deny according to owner/group bit
102 function cal_bits # isdir bits bits_limit acl_access ctrl
104 typeset -i isdir=$1
105 typeset -i bits=$2
106 typeset -i bits_limit=$3
107 typeset acl_access=$4
108 typeset -i ctrl=${5:-0}
109 typeset flagr=0 flagw=0 flagx=0
110 typeset tmpstr
112 if (( ctrl == 0 )); then
113 if (( (( bits & 4 )) != 0 )); then
114 flagr=1
116 if (( (( bits & 2 )) != 0 )); then
117 flagw=1
119 if (( (( bits & 1 )) != 0 )); then
120 flagx=1
122 else
123 # Determine ACE as per owner/group bit
124 flagr=1
125 flagw=1
126 flagx=1
128 if (( ((bits & 4)) != 0 )) && \
129 (( ((bits_limit & 4)) != 0 )); then
130 flagr=0
132 if (( ((bits & 2)) != 0 )) && \
133 (( ((bits_limit & 2)) != 0 )); then
134 flagw=0
136 if (( ((bits & 1)) != 0 )) && \
137 (( ((bits_limit & 1)) != 0 )); then
138 flagx=0
142 if ((flagr != 0)); then
143 if [[ $acl_access == *"read_data"* ]]; then
144 if [[ $acl_access == *"allow"* &&
145 $passthrough == 0 ]]; then
146 tmpstr=${tmpstr}
147 elif ((isdir == 0)); then
148 tmpstr=${tmpstr}/read_data
149 else
150 tmpstr=${tmpstr}/list_directory/read_data
155 if ((flagw != 0)); then
156 if [[ $acl_access == *"allow"* && $passthrough == 0 ]]; then
157 tmpstr=${tmpstr}
158 else
159 if [[ $acl_access == *"write_data"* ]]; then
160 if ((isdir == 0)); then
161 tmpstr=${tmpstr}/write_data
162 else
163 tmpstr=${tmpstr}/add_file/write_data
166 if [[ $acl_access == *"append_data"* ]]; then
167 if ((isdir == 0)); then
168 tmpstr=${tmpstr}/append_data
169 else
170 tmpstr=${tmpstr}/add_subdirectory
171 tmpstr=${tmpstr}/append_data
177 if ((flagx != 0)); then
178 if [[ $acl_access == *"execute"* ]]; then
179 if [[ $acl_access == *"allow"* &&
180 $passthrough == 0 ]]; then
181 tmpstr=${tmpstr}
182 else
183 tmpstr=${tmpstr}/execute
188 tmpstr=${tmpstr#/}
190 $ECHO "$tmpstr"
194 # To translate an ace if the node is dir
196 # $1 isdir indicate if the target is a directory
197 # $2 acl to be translated
199 function translate_acl # isdir acl
201 typeset -i isdir=$1
202 typeset acl=$2
203 typeset who prefix acltemp action
205 if ((isdir != 0)); then
206 who=${acl%%:*}
207 prefix=$who
208 acltemp=${acl#*:}
209 acltemp=${acltemp%%:*}
210 prefix=$prefix:$acltemp
211 action=${acl##*:}
212 acl=$prefix:$(cal_bits $isdir 7 7 $acl 0):$action
214 $ECHO "$acl"
218 # To verify if a new ACL is generated as result of
219 # chmod operation.
221 # $1 bit indicates whether owner/group bit
222 # $2 newmode indicates the mode changed using chmod
223 # $3 isdir indicate if the target is a directory
225 function check_new_acl # bit newmode isdir
227 typeset bits=$1
228 typeset mode=$2
229 typeset -i isdir=$3
230 typeset new_acl
231 typeset gbit
232 typeset ebit
233 typeset str=":"
234 typeset dc=""
236 gbit=${mode:1:1}
237 ebit=${mode:2:1}
238 if (( ((bits & 4)) == 0 )); then
239 if (( ((gbit & 4)) != 0 || \
240 ((ebit & 4)) != 0 )); then
241 if ((isdir == 0)); then
242 new_acl=${new_acl}${str}read_data
243 else
244 new_acl=${new_acl}${str}list_directory/read_data
246 str="/"
249 if (( ((bits & 2)) == 0 )); then
250 if (( ((gbit & 2)) != 0 || \
251 ((ebit & 2)) != 0 )); then
252 if ((isdir == 0)); then
253 new_acl=${new_acl}${str}write_data/append_data
254 else
255 new_acl=${new_acl}${str}add_file/write_data/
256 new_acl=${new_acl}add_subdirectory/append_data
257 dc="/delete_child"
259 str="/"
262 if (( ((bits & 1)) == 0 )); then
263 if (( ((gbit & 1)) != 0 || \
264 ((ebit & 1)) != 0 )); then
265 new_acl=${new_acl}${str}execute
268 new_acl=${new_acl}${dc}
269 $ECHO "$new_acl"
272 function build_new_acl # newmode isdir
274 typeset newmode=$1
275 typeset isdir=$2
276 typeset expect
277 if ((flag == 0)); then
278 prefix="owner@"
279 bit=${newmode:0:1}
280 status=$(check_new_acl $bit $newmode $isdir)
282 else
283 prefix="group@"
284 bit=${newmode:1:1}
285 status=$(check_new_acl $bit $newmode $isdir)
287 expect=$prefix$status:deny
288 $ECHO $expect
291 # According to inherited flag, verify subdirectories and files within it has
292 # correct inherited access control.
293 function verify_aclmode # <aclmode> <node> <newmode>
295 # Define the nodes which will be affected by inherit.
296 typeset aclmode=$1
297 typeset node=$2
298 typeset newmode=$3
300 # count: the ACE item to fetch
301 # pass: to mark if the current ACE should apply to the target
302 # passcnt: counter, if it achieves to maxnumber,
303 # then no additional ACE should apply.
305 typeset -i count=0 pass=0 passcnt=0
306 typeset -i bits=0 obits=0 bits_owner=0 isdir=0
307 typeset -i total_acl
308 typeset -i acl_count=$(count_ACE $node)
310 ((total_acl = maxnumber + 3))
312 if [[ -d $node ]]; then
313 ((isdir = 1))
316 ((i = maxnumber - 1))
317 count=0
318 passcnt=0
319 flag=0
320 while ((i >= 0)); do
321 pass=0
322 expect1=${acls[$i]}
323 passthrough=0
325 # aclmode=passthrough,
326 # no changes will be made to the ACL other than
327 # generating the necessary ACL entries to represent
328 # the new mode of the file or directory.
330 # aclmode=discard,
331 # delete all ACL entries that don't represent
332 # the mode of the file.
334 # aclmode=groupmask,
335 # reduce user or group permissions. The permissions are
336 # reduced, such that they are no greater than the group
337 # permission bits, unless it is a user entry that has the
338 # same UID as the owner of the file or directory.
339 # Then, the ACL permissions are reduced so that they are
340 # no greater than owner permission bits.
343 case $aclmode in
344 passthrough)
345 if ((acl_count > total_acl)); then
346 expect1=$(build_new_acl $newmode $isdir)
347 flag=1
348 ((total_acl = total_acl + 1))
349 ((i = i + 1))
350 else
351 passthrough=1
352 expect1=$(translate_acl $isdir $expect1)
355 groupmask)
356 if ((acl_count > total_acl)); then
357 expect1=$(build_new_acl $newmode $isdir)
358 flag=1
359 ((total_acl = total_acl + 1))
360 ((i = i + 1))
361 elif [[ $expect1 == *":allow"* ]]; then
362 who=${expect1%%:*}
363 aclaction=${expect1##*:}
364 prefix=$who
365 acltemp=""
366 reduce=0
367 # To determine the mask bits
368 # according to the entry type.
370 case $who in
371 owner@)
372 pos=0
374 group@)
375 pos=1
377 everyone@)
378 pos=2
380 user)
381 acltemp=${expect1#*:}
382 acltemp=${acltemp%%:*}
383 owner=$(get_owner $node)
384 group=$(get_group $node)
385 if [[ $acltemp == $owner ]]; then
386 pos=0
387 else
388 pos=1
390 prefix=$prefix:$acltemp
392 group)
393 acltemp=${expect1#*:}
394 acltemp=${acltemp%%:*}
395 pos=1
396 prefix=$prefix:$acltemp
397 reduce=1
399 esac
401 obits=${newmode:$pos:1}
402 ((bits = $obits))
403 # permission should be no greater than the
404 # group permission bits
405 if ((reduce != 0)); then
406 ((bits &= ${newmode:1:1}))
407 # The ACL permissions are reduced so
408 # that they are no greater than owner
409 # permission bits.
410 ((bits_owner = ${newmode:0:1}))
411 ((bits &= $bits_owner))
414 if ((bits < obits)) && [[ -n $acltemp ]]; then
415 expect2=$prefix:
416 new_bit=$(cal_bits $isdir $obits \
417 $bits_owner $expect1 1)
418 expect2=${expect2}${new_bit}:allow
419 else
420 expect2=$prefix:
421 new_bit=$(cal_bits $isdir $obits \
422 $obits $expect1 1)
423 expect2=${expect2}${new_bit}:allow
426 priv=$(cal_bits $isdir $obits $bits_owner \
427 $expect2 0)
428 expect1=$prefix:$priv:$aclaction
429 else
430 expect1=$(translate_acl $isdir $expect1)
433 discard)
434 passcnt=maxnumber
435 break
437 esac
439 if ((pass == 0)) ; then
440 # Get the first ACE to do comparison
441 aclcur=$(get_ACE $node $count)
442 aclcur=${aclcur#$count:}
443 if [[ -n $expect1 && $expect1 != $aclcur ]]; then
444 $LS -vd $node
445 log_fail "$aclmode $i #$count " \
446 "ACE: $aclcur, expect to be " \
447 "$expect1"
449 ((count = count + 1))
451 ((i = i - 1))
452 done
455 # If there's no any ACE be checked, it should be identify as
456 # an normal file/dir, verify it.
458 if ((passcnt == maxnumber)); then
459 if [[ -d $node ]]; then
460 compare_acls $node $odir
461 elif [[ -f $node ]]; then
462 compare_acls $node $ofile
465 if [[ $? -ne 0 ]]; then
466 $LS -vd $node
467 log_fail "Unexpect acl: $node, $aclmode ($newmode)"
474 typeset -i maxnumber=0
475 typeset acl
476 typeset target
477 typeset -i passthrough=0
478 typeset -i flag=0
479 cwd=$PWD
480 cd $TESTDIR
482 for mode in "${aclmode_flag[@]}"; do
483 log_must $ZFS set aclmode=$mode $TESTPOOL/$TESTFS
485 for user in root $ZFS_ACL_STAFF1; do
486 log_must set_cur_usr $user
488 log_must usr_exec $MKDIR $basedir
490 log_must usr_exec $MKDIR $odir
491 log_must usr_exec $TOUCH $ofile
492 log_must usr_exec $MKDIR $ndir
493 log_must usr_exec $TOUCH $nfile
495 for obj in $allnodes; do
496 maxnumber=0
497 for preset in "${ace_file_preset[@]}"; do
498 for prefix in "${ace_prefix[@]}"; do
499 acl=$prefix:$preset
501 case $((maxnumber % 2)) in
503 acl=$acl:deny
506 acl=$acl:allow
508 esac
510 log_must usr_exec $CHMOD A+$acl $obj
511 acls[$maxnumber]=$acl
513 ((maxnumber = maxnumber + 1))
514 done
515 done
516 # Archive the file and directory
517 log_must $TAR cpf@ $TARFILE $basedir
519 if [[ -d $obj ]]; then
520 target=$odir
521 elif [[ -f $obj ]]; then
522 target=$ofile
524 for newmode in "${argv[@]}"; do
525 log_must usr_exec $CHMOD $newmode $obj
526 log_must usr_exec $CHMOD $newmode $target
527 log_must verify_aclmode $mode $obj $newmode
528 log_must $TAR xpf@ $TARFILE
529 done
530 done
532 log_must usr_exec $RM -rf $basedir $TARFILE
533 done
534 done
536 log_pass "Verify chmod behaviour co-op with aclmode setting passed"