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