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