1#!/usr/local/bin/ksh93 -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 2008 Sun Microsystems, Inc. All rights reserved. 25# Use is subject to license terms. 26 27. $STF_SUITE/tests/acl/acl_common.kshlib 28 29################################################################################# 30# 31# __stc_assertion_start 32# 33# ID: zfs_acl_chmod_aclmode_001_pos 34# 35# DESCRIPTION: 36# Verify chmod have correct behaviour to directory and file when 37# filesystem has the different aclmode setting 38# 39# STRATEGY: 40# 1. Loop super user and non-super user to run the test case. 41# 2. Create basedir and a set of subdirectores and files within it. 42# 3. Separately chmod basedir with different aclmode options, 43# combine with the variable setting of aclmode: 44# "discard", "groupmask", or "passthrough". 45# 4. Verify each directories and files have the correct access control 46# capability. 47# 48# TESTABILITY: explicit 49# 50# TEST_AUTOMATION_LEVEL: automated 51# 52# CODING_STATUS: COMPLETED (2006-03-02) 53# 54# __stc_assertion_end 55# 56################################################################################ 57 58verify_runnable "both" 59 60test_requires ZFS_ACL 61 62function cleanup 63{ 64 # Cleanup tarfile & basedir. 65 66 (( ${#cwd} != 0 )) && cd $cwd 67 68 if [[ -f $TARFILE ]]; then 69 log_must $RM -f $TARFILE 70 fi 71 72 if [[ -d $basedir ]]; then 73 log_must $RM -rf $basedir 74 fi 75} 76 77log_assert "Verify chmod have correct behaviour to directory and file when " \ 78 "filesystem has the different aclmode setting." 79log_onexit cleanup 80 81# Define aclmode flag 82set -A aclmode_flag discard groupmask passthrough 83 84set -A ace_prefix "user:$ZFS_ACL_OTHER1" \ 85 "user:$ZFS_ACL_OTHER2" \ 86 "group:$ZFS_ACL_STAFF_GROUP" \ 87 "group:$ZFS_ACL_OTHER_GROUP" 88 89set -A argv "000" "444" "644" "777" "755" "231" "562" "413" 90 91set -A ace_file_preset "read_data" \ 92 "write_data" \ 93 "append_data" \ 94 "execute" \ 95 "read_data/write_data" \ 96 "read_data/write_data/append_data" \ 97 "write_data/append_data" \ 98 "read_data/execute" \ 99 "write_data/append_data/execute" \ 100 "read_data/write_data/append_data/execute" 101 102# Defile the based directory and file 103basedir=$TESTDIR/basedir; ofile=$basedir/ofile; odir=$basedir/odir 104nfile=$basedir/nfile; ndir=$basedir/ndir 105 106TARFILE=$TESTDIR/tarfile 107 108# Verify all the node have expected correct access control 109allnodes="$nfile $ndir" 110 111# 112# According to the original bits, the input ACE access and ACE type, return the 113# expect bits after 'chmod A0{+|=}'. 114# 115# $1 isdir indicate if the target is a directory 116# $1 bits which was make up of three bit 'rwx' 117# $2 bits_limit which was make up of three bit 'rwx' 118# $3 ACE access which is read_data, write_data or execute 119# $4 ACE type which is allow or deny 120# 121function cal_bits #isdir bits bits_limit acl_access ctrl 122{ 123 typeset -i isdir=$1 124 typeset -i bits=$2 125 typeset -i bits_limit=$3 126 typeset acl_access=$4 127 typeset -i ctrl=${5:-0} 128 typeset flagr=0; flagw=0; flagx=0 129 typeset tmpstr 130 131 if (( ctrl == 0 )); then 132 if (( (( bits & 4 )) == 0 )); then 133 flagr=1 134 fi 135 if (( (( bits & 2 )) == 0 )); then 136 flagw=1 137 fi 138 if (( (( bits & 1 )) == 0 )); then 139 flagx=1 140 fi 141 else 142 # 143 # Tricky here: 144 # (1) flagr is always set to be 1, 145 # (2) flagw & flagx is set to be 0 only while 146 # bits_limit has lower permissions than bits 147 # 148 149 flagr=1 150 flagw=1 151 flagx=1 152 153 if (( (( bits & 2 )) != 0 )) && \ 154 (( (( bits_limit & 2 )) == 0 )) ; then 155 flagw=0 156 fi 157 if (( (( bits & 1 )) != 0 )) && \ 158 (( (( bits_limit & 1 )) == 0 )) ; then 159 flagx=0 160 fi 161 fi 162 163 if (( flagr != 0 )); then 164 if [[ $acl_access == *"read_data"* ]]; then 165 if (( isdir == 0 )) ; then 166 tmpstr=${tmpstr}/read_data 167 else 168 tmpstr=${tmpstr}/list_directory/read_data 169 fi 170 fi 171 fi 172 173 if (( flagw != 0 )); then 174 if [[ $acl_access == *"write_data"* ]]; then 175 if (( isdir == 0 )); then 176 tmpstr=${tmpstr}/write_data 177 else 178 tmpstr=${tmpstr}/add_file/write_data 179 fi 180 fi 181 182 if [[ $acl_access == *"append_data"* ]]; then 183 if (( isdir == 0 )); then 184 tmpstr=${tmpstr}/append_data 185 else 186 tmpstr=${tmpstr}/add_subdirectory/append_data 187 fi 188 fi 189 fi 190 if (( flagx != 0 )); then 191 [[ $acl_access == *"execute"* ]] && \ 192 tmpstr=${tmpstr}/execute 193 fi 194 195 tmpstr=${tmpstr#/} 196 197 $ECHO "$tmpstr" 198} 199 200# 201# To translate an ace if the node is dir 202# 203# $1 isdir indicate if the target is a directory 204# $2 acl to be translated 205# 206function translate_acl #isdir acl 207{ 208 typeset -i isdir=$1 209 typeset acl=$2 210 typeset who prefix acltemp action 211 212 if (( isdir != 0 )); then 213 who=${acl%%:*} 214 prefix=$who 215 acltemp=${acl#*:} 216 acltemp=${acltemp%%:*} 217 prefix=$prefix:$acltemp 218 action=${acl##*:} 219 220 acl=$prefix:$(cal_bits $isdir 7 7 $acl 1):$action 221 fi 222 $ECHO "$acl" 223} 224 225# 226# According to inherited flag, verify subdirectories and files within it has 227# correct inherited access control. 228# 229function verify_aclmode #<aclmode> <node> <newmode> 230{ 231 # Define the nodes which will be affected by inherit. 232 typeset aclmode=$1 233 typeset node=$2 234 typeset newmode=$3 235 236 # count: the ACE item to fetch 237 # pass: to mark if the current ACE should apply to the target 238 # passcnt: counter, if it achieves to maxnumber, 239 # then no additional ACE should apply. 240 # step: indicate if the ACE be split during aclmode. 241 242 typeset -i count=0 pass=0 passcnt=0 step=0 243 typeset -i bits=0 obits=0 bits_owner=0 isdir=0 244 245 if [[ -d $node ]]; then 246 (( isdir = 1 )) 247 fi 248 249 (( i = maxnumber - 1 )) 250 count=0 251 passcnt=0 252 while (( i >= 0 )); do 253 pass=0 254 step=0 255 expect1=${acls[$i]} 256 expect2="" 257 258 # 259 # aclmode=passthrough, 260 # no changes will be made to the ACL other than 261 # generating the necessary ACL entries to represent 262 # the new mode of the file or directory. 263 # 264 # aclmode=discard, 265 # delete all ACL entries that don't represent 266 # the mode of the file. 267 # 268 # aclmode=groupmask, 269 # reduce user or group permissions. The permissions are 270 # reduced, such that they are no greater than the group 271 # permission bits, unless it is a user entry that has the 272 # same UID as the owner of the file or directory. 273 # Then, the ACL permissions are reduced so that they are 274 # no greater than owner permission bits. 275 # 276 277 case $aclmode in 278 passthrough) 279 expect1=$(translate_acl $isdir $expect1) 280 ;; 281 groupmask) 282 if [[ $expect1 == *":allow" ]]; then 283 expect2=$expect1 284 who=${expect1%%:*} 285 prefix=$who 286 acltemp="" 287 reduce=0 288 289 # To determine the mask bits 290 # according to the entry type. 291 292 case $who in 293 owner@) 294 pos=1 295 ;; 296 group@) 297 pos=2 298 ;; 299 everyone@) 300 pos=3 301 ;; 302 user) 303 acltemp=${expect1#*:} 304 acltemp=${acltemp%%:*} 305 owner=$(get_owner $node) 306 group=$(get_group $node) 307 if [[ $acltemp == $owner ]]; then 308 pos=1 309 else 310 pos=2 311 fi 312 prefix=$prefix:$acltemp 313 ;; 314 group) 315 acltemp=${expect1#*:} 316 acltemp=${acltemp%%:*} 317 pos=2 318 prefix=$prefix:$acltemp 319 reduce=1 320 ;; 321 esac 322 323 obits=$(get_substr $newmode $pos 1) 324 (( bits = obits )) 325 # 326 # permission should no greater than the group permission bits 327 # 328 if (( reduce != 0 )); then 329 (( bits &= $(get_substr $newmode 2 1) )) 330 331 # The ACL permissions are reduced so that they are 332 # no greater than owner permission bits. 333 334 (( bits_owner = $(get_substr $newmode 1 1) )) 335 (( bits &= bits_owner )) 336 fi 337 338 if (( bits < obits )) && [[ -n $acltemp ]]; then 339 expect2=$prefix:$(cal_bits $isdir $obits $bits_owner $expect2 1):allow 340 else 341 expect2=$prefix:$(cal_bits $isdir $obits $obits $expect2 1):allow 342 343 fi 344 345 priv=$(cal_bits $isdir $obits $bits_owner $expect2 0) 346 expect1=$prefix:$priv:deny 347 step=1 348 else 349 expect1=$(translate_acl $isdir $expect1) 350 fi 351 ;; 352 discard) 353 passcnt=maxnumber 354 break 355 ;; 356 esac 357 358 if (( pass == 0 )) ; then 359 # Get the first ACE to do comparison 360 361 aclcur=$(get_ACE $node $count) 362 aclcur=${aclcur#$count:} 363 if [[ -n $expect1 && $expect1 != $aclcur ]]; then 364 $LS -vd $node 365 log_fail "$i #$count " \ 366 "ACE: $aclcur, expect to be " \ 367 "$expect1" 368 fi 369 370 # Get the second ACE (if should have) to do comparison 371 372 if (( step > 0 )); then 373 (( count = count + step )) 374 375 aclcur=$(get_ACE $node $count) 376 aclcur=${aclcur#$count:} 377 if [[ -n $expect2 && \ 378 $expect2 != $aclcur ]]; then 379 380 $LS -vd $node 381 log_fail "$i #$count " \ 382 "ACE: $aclcur, expect to be " \ 383 "$expect2" 384 fi 385 fi 386 (( count = count + 1 )) 387 fi 388 (( i = i - 1 )) 389 done 390 391 # 392 # If there's no any ACE be checked, it should be identify as 393 # an normal file/dir, verify it. 394 # 395 396 if (( passcnt == maxnumber )); then 397 if [[ -d $node ]]; then 398 compare_acls $node $odir 399 elif [[ -f $node ]]; then 400 compare_acls $node $ofile 401 fi 402 403 if [[ $? -ne 0 ]]; then 404 $LS -vd $node 405 log_fail "Unexpect acl: $node, $aclmode ($newmode)" 406 fi 407 fi 408} 409 410 411 412typeset -i maxnumber=0 413typeset acl 414typeset target 415 416cwd=$PWD 417cd $TESTDIR 418 419for mode in "${aclmode_flag[@]}"; do 420 421 # 422 # Set different value of aclmode 423 # 424 425 log_must $ZFS set aclmode=$mode $TESTPOOL/$TESTFS 426 427 for user in root $ZFS_ACL_STAFF1; do 428 log_must set_cur_usr $user 429 430 log_must usr_exec $MKDIR $basedir 431 432 log_must usr_exec $MKDIR $odir 433 log_must usr_exec $TOUCH $ofile 434 log_must usr_exec $MKDIR $ndir 435 log_must usr_exec $TOUCH $nfile 436 437 for obj in $allnodes ; do 438 maxnumber=0 439 for preset in "${ace_file_preset[@]}"; do 440 for prefix in "${ace_prefix[@]}"; do 441 acl=$prefix:$preset 442 443 case $(( maxnumber % 2 )) in 444 0) 445 acl=$acl:deny 446 ;; 447 1) 448 acl=$acl:allow 449 ;; 450 esac 451 452 # 453 # Place on the target should succeed. 454 # 455 log_must usr_exec $CHMOD A+$acl $obj 456 acls[$maxnumber]=$acl 457 458 (( maxnumber = maxnumber + 1 )) 459 done 460 done 461 462 # Archive the file and directory 463 log_must $TAR cpf@ $TARFILE basedir 464 465 if [[ -d $obj ]]; then 466 target=$odir 467 elif [[ -f $obj ]]; then 468 target=$ofile 469 fi 470 471 for newmode in "${argv[@]}" ; do 472 log_must usr_exec $CHMOD $newmode $obj 473 log_must usr_exec $CHMOD $newmode $target 474 verify_aclmode $mode $obj $newmode 475 476 # Restore the tar archive 477 log_must $TAR xpf@ $TARFILE 478 done 479 done 480 481 log_must usr_exec $RM -rf $basedir $TARFILE 482 done 483done 484 485log_pass "Verify chmod behaviour co-op with aclmode setting passed." 486