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# 29# Copyright (c) 2012, 2016 by Delphix. All rights reserved. 30# 31 32. $STF_SUITE/tests/functional/acl/acl_common.kshlib 33. $STF_SUITE/tests/functional/acl/cifs/cifs.kshlib 34 35# 36# DESCRIPTION: 37# Verify the DOS attributes (Readonly, Hidden, Archive, System) 38# and BSD'ish attributes (Immutable, nounlink, and appendonly) 39# will provide the proper access limitation as expected. 40# 41# Readonly means that the content of a file can't be modified, but 42# timestamps, mode and so on can. 43# 44# Archive - Indicates if a file should be included in the next backup 45# of the file system. ZFS will set this bit whenever a file is 46# modified. 47# 48# Hidden and System (ZFS does nothing special with these, other than 49# letting a user/application set them. 50# 51# Immutable (The data can't, change nor can mode, ACL, size and so on) 52# The only attribute that can be updated is the access time. 53# 54# Nonunlink - Sort of like immutable except that a file/dir can't be 55# removed. 56# This will also effect a rename operation, since that involes a 57# remove. 58# 59# Appendonly - File can only be appended to. 60# 61# nodump, settable, opaque (These are for the MacOS port) we will 62# allow them to be set, but have no semantics tied to them. 63# 64# STRATEGY: 65# 1. Loop super user and non-super user to run the test case. 66# 2. Create basedir and a set of subdirectores and files within it. 67# 3. Set the file/dir with each kind of special attribute. 68# 4. Verify the access limitation works as expected. 69# 70 71verify_runnable "both" 72 73function cleanup 74{ 75 if [[ -n $gobject ]]; then 76 destroy_object $gobject 77 fi 78 79 for fs in $TESTPOOL/$TESTFS $TESTPOOL ; do 80 mtpt=$(get_prop mountpoint $fs) 81 log_must rm -rf $mtpt/file.* $mtpt/dir.* 82 done 83 84 [[ -f $TESTFILE ]] && rm $TESTFILE 85} 86 87# 88# Set the special attribute to the given node 89# 90# $1: The given node (file/dir) 91# $2: The special attribute to be set 92# 93function set_attribute 94{ 95 typeset object=$1 96 typeset attr=$2 97 98 if [[ -z $attr ]]; then 99 attr="AHRSadimu" 100 if [[ -f $object ]]; then 101 attr="${attr}q" 102 fi 103 fi 104 chmod S+c${attr} $object 105 return $? 106} 107 108# 109# Clear the special attribute to the given node 110# 111# $1: The given node (file/dir) 112# $2: The special attribute to be cleared 113# 114function clear_attribute 115{ 116 typeset object=$1 117 typeset attr=$2 118 119 if [[ -z $attr ]]; then 120 if is_global_zone ; then 121 attr="AHRSadimu" 122 if [[ -f $object ]]; then 123 attr="${attr}q" 124 fi 125 else 126 attr="AHRS" 127 fi 128 fi 129 130 chmod S-c${attr} $object 131 return $? 132} 133 134# 135# A wrapper function to call test function according to the given attr 136# 137# $1: The given node (file/dir) 138# $2: The special attribute to be test 139# 140function test_wrapper 141{ 142 typeset object=$1 143 typeset attr=$2 144 145 if [[ -z $object || -z $attr ]]; then 146 log_fail "Object($object), Attr($attr) not defined." 147 fi 148 149 case $attr in 150 R) func=test_readonly 151 ;; 152 i) func=test_immutable 153 ;; 154 u) func=test_nounlink 155 ;; 156 a) func=test_appendonly 157 ;; 158 esac 159 160 if [[ -n $func ]]; then 161 $func $object 162 fi 163} 164 165# 166# Invoke the function and verify whether its return code as expected 167# 168# $1: Expect value 169# $2-$n: Function and args need to be invoked 170# 171function verify_expect 172{ 173 typeset -i expect=$1 174 typeset status 175 176 shift 177 178 "$@" > /dev/null 2>&1 179 status=$? 180 if [[ $status -eq 0 ]]; then 181 if ((expect != 0)); then 182 log_fail "$@ unexpect return 0" 183 fi 184 else 185 if ((expect == 0)); then 186 log_fail "$@ unexpect return $status" 187 fi 188 fi 189} 190 191# 192# Unit testing function against overwrite file 193# 194# $1: The given file node 195# $2: Execute user 196# $3: Expect value, default to be zero 197# 198function unit_writefile 199{ 200 typeset object=$1 201 typeset user=$2 202 typeset expect=${3:-0} 203 if [[ -f $object ]]; then 204 verify_expect $expect chg_usr_exec $user \ 205 cp $TESTFILE $object 206 verify_expect $expect chg_usr_exec $user \ 207 "echo '$TESTSTR' > $object" 208 fi 209} 210 211# 212# Unit testing function against write new stuffs into a directory 213# 214# $1: The given directory node 215# $2: Execute user 216# $3: Expect value, default to be zero 217# 218function unit_writedir 219{ 220 typeset object=$1 221 typeset user=$2 222 typeset expect=${3:-0} 223 224 if [[ -d $object ]]; then 225 verify_expect $expect chg_usr_exec $user \ 226 cp $TESTFILE $object 227 verify_expect $expect chg_usr_exec $user \ 228 mkdir -p $object/$TESTDIR 229 fi 230} 231 232function unit_appenddata 233{ 234 typeset object=$1 235 typeset user=$2 236 typeset expect=${3:-0} 237 238 if [[ ! -d $object ]]; then 239 verify_expect $expect chg_usr_exec $user \ 240 "echo '$TESTSTR' >> $object" 241 fi 242} 243 244# 245# Unit testing function against delete content from a directory 246# 247# $1: The given node, dir 248# $2: Execute user 249# $3: Expect value, default to be zero 250# 251function unit_deletecontent 252{ 253 typeset object=$1 254 typeset user=$2 255 typeset expect=${3:-0} 256 257 if [[ -d $object ]]; then 258 for target in $object/${TESTFILE##*/} $object/$TESTDIR ; do 259 if [[ -e $target ]]; then 260 verify_expect $expect chg_usr_exec $user \ 261 "mv $target $target.new" 262 verify_expect $expect chg_usr_exec $user \ 263 "echo y | rm -r $target.new" 264 fi 265 done 266 fi 267} 268 269# 270# Unit testing function against delete a node 271# 272# $1: The given node, file/dir 273# $2: Execute user 274# $3: Expect value, default to be zero 275# 276function unit_deletedata 277{ 278 typeset object=$1 279 typeset user=$2 280 typeset expect=${3:-0} 281 282 verify_expect $expect chg_usr_exec $user \ 283 "echo y | rm -r $object" 284 285} 286 287# 288# Unit testing function against write xattr to a node 289# 290# $1: The given node, file/dir 291# $2: Execute user 292# $3: Expect value, default to be zero 293# 294function unit_writexattr 295{ 296 typeset object=$1 297 typeset user=$2 298 typeset expect=${3:-0} 299 300 verify_expect $expect chg_usr_exec $user \ 301 runat $object "cp $TESTFILE $TESTATTR" 302 verify_expect $expect chg_usr_exec $user \ 303 "runat $object \"echo '$TESTSTR' > $TESTATTR\"" 304 verify_expect $expect chg_usr_exec $user \ 305 "runat $object \"echo '$TESTSTR' >> $TESTATTR\"" 306 if [[ $expect -eq 0 ]]; then 307 verify_expect $expect chg_usr_exec $user \ 308 runat $object "rm -f $TESTATTR" 309 fi 310} 311 312# 313# Unit testing function against modify accesstime of a node 314# 315# $1: The given node, file/dir 316# $2: Execute user 317# $3: Expect value, default to be zero 318# 319function unit_accesstime 320{ 321 typeset object=$1 322 typeset user=$2 323 typeset expect=${3:-0} 324 325 if [[ -d $object ]]; then 326 verify_expect $expect chg_usr_exec $user ls $object 327 else 328 verify_expect $expect chg_usr_exec $user cat $object 329 fi 330} 331 332# 333# Unit testing function against modify updatetime of a node 334# 335# $1: The given node, file/dir 336# $2: Execute user 337# $3: Expect value, default to be zero 338# 339function unit_updatetime 340{ 341 typeset object=$1 342 typeset user=$2 343 typeset expect=${3:-0} 344 typeset immutable_expect=${4:-$expect} 345 verify_expect $expect chg_usr_exec $user touch $object 346 verify_expect $immutable_expect chg_usr_exec $user touch -a $object 347 verify_expect $expect chg_usr_exec $user touch -m $object 348} 349 350# 351# Unit testing function against write acl of a node 352# 353# $1: The given node, file/dir 354# $2: Execute user 355# $3: Expect value, default to be zero 356# 357function unit_writeacl 358{ 359 typeset object=$1 360 typeset user=$2 361 typeset expect=${3:-0} 362 363 verify_expect $expect chg_usr_exec $user chmod A+$TESTACL $object 364 verify_expect $expect chg_usr_exec $user chmod A+$TESTACL $object 365 verify_expect $expect chg_usr_exec $user chmod A0- $object 366 verify_expect $expect chg_usr_exec $user chmod A0- $object 367 oldmode=$(get_mode $object) 368 verify_expect $expect chg_usr_exec $user chmod $TESTMODE $object 369} 370 371# 372# Testing function to verify the given node is readonly 373# 374# $1: The given node, file/dir 375# 376function test_readonly 377{ 378 typeset object=$1 379 380 if [[ -z $object ]]; then 381 log_fail "Object($object) not defined." 382 fi 383 384 log_note "Testing readonly of $object" 385 386 for user in $ZFS_ACL_CUR_USER root $ZFS_ACL_STAFF2; do 387 if [[ -d $object ]]; then 388 log_must usr_exec chmod \ 389 A+user:$user:${ace_dir}:allow $object 390 else 391 log_must usr_exec chmod \ 392 A+user:$user:${ace_file}:allow $object 393 fi 394 395 log_must set_attribute $object "R" 396 397 unit_writefile $object $user 1 398 unit_writedir $object $user 399 unit_appenddata $object $user 1 400 401 if [[ -d $object ]]; then 402 unit_writexattr $object $user 403 else 404 unit_writexattr $object $user 1 405 fi 406 407 unit_accesstime $object $user 408 unit_updatetime $object $user 409 unit_writeacl $object $user 410 unit_deletecontent $object $user 411 unit_deletedata $object $user 412 413 if [[ -d $object ]] ;then 414 create_object "dir" $object $ZFS_ACL_CUR_USER 415 else 416 create_object "file" $object $ZFS_ACL_CUR_USER 417 fi 418 done 419} 420 421# 422# Testing function to verify the given node is immutable 423# 424# $1: The given node, file/dir 425# 426function test_immutable 427{ 428 typeset object=$1 429 430 if [[ -z $object ]]; then 431 log_fail "Object($object) not defined." 432 fi 433 434 log_note "Testing immutable of $object" 435 436 for user in $ZFS_ACL_CUR_USER root $ZFS_ACL_STAFF2; do 437 if [[ -d $object ]]; then 438 log_must usr_exec chmod \ 439 A+user:$user:${ace_dir}:allow $object 440 else 441 log_must usr_exec chmod \ 442 A+user:$user:${ace_file}:allow $object 443 fi 444 log_must set_attribute $object "i" 445 446 unit_writefile $object $user 1 447 unit_writedir $object $user 1 448 unit_appenddata $object $user 1 449 unit_writexattr $object $user 1 450 unit_accesstime $object $user 451 unit_updatetime $object $user 1 0 452 unit_writeacl $object $user 1 453 unit_deletecontent $object $user 1 454 unit_deletedata $object $user 1 455 456 if [[ -d $object ]] ;then 457 create_object "dir" $object $ZFS_ACL_CUR_USER 458 else 459 create_object "file" $object $ZFS_ACL_CUR_USER 460 fi 461 done 462} 463 464# 465# Testing function to verify the given node is nounlink 466# 467# $1: The given node, file/dir 468# 469function test_nounlink 470{ 471 typeset object=$1 472 473 if [[ -z $object ]]; then 474 log_fail "Object($object) not defined." 475 fi 476 477 echo "Testing nounlink of $object" 478 479 for user in $ZFS_ACL_CUR_USER root $ZFS_ACL_STAFF2; do 480 if [[ -d $object ]]; then 481 log_must usr_exec chmod \ 482 A+user:$user:${ace_dir}:allow $object 483 else 484 log_must usr_exec chmod \ 485 A+user:$user:${ace_file}:allow $object 486 fi 487 log_must set_attribute $object "u" 488 489 unit_writefile $object $user 490 unit_writedir $object $user 491 unit_appenddata $object $user 492 unit_writexattr $object $user 493 unit_accesstime $object $user 494 unit_updatetime $object $user 495 unit_writeacl $object $user 496 unit_deletecontent $object $user 1 497 unit_deletedata $object $user 1 498 499 if [[ -d $object ]] ;then 500 create_object "dir" $object $ZFS_ACL_CUR_USER 501 else 502 create_object "file" $object $ZFS_ACL_CUR_USER 503 fi 504 done 505} 506 507# 508# Testing function to verify the given node is appendonly 509# 510# $1: The given node, file/dir 511# 512function test_appendonly 513{ 514 typeset object=$1 515 516 if [[ -z $object ]]; then 517 log_fail "Object($object) not defined." 518 fi 519 520 log_note "Testing appendonly of $object" 521 522 for user in $ZFS_ACL_CUR_USER root $ZFS_ACL_STAFF2; do 523 if [[ -d $object ]]; then 524 log_must usr_exec chmod \ 525 A+user:$user:${ace_dir}:allow $object 526 else 527 log_must usr_exec chmod \ 528 A+user:$user:${ace_file}:allow $object 529 fi 530 log_must set_attribute $object "a" 531 532 unit_writefile $object $user 1 533 unit_writedir $object $user 534 unit_appenddata $object $user 535 unit_writexattr $object $user 536 unit_accesstime $object $user 537 unit_updatetime $object $user 538 unit_writeacl $object $user 539 unit_deletecontent $object $user 540 unit_deletedata $object $user 541 542 if [[ -d $object ]] ;then 543 create_object "dir" $object $ZFS_ACL_CUR_USER 544 else 545 create_object "file" $object $ZFS_ACL_CUR_USER 546 fi 547 done 548} 549 550FILES="file.0 file.1" 551DIRS="dir.0 dir.1" 552XATTRS="attr.0 attr.1" 553FS="$TESTPOOL $TESTPOOL/$TESTFS" 554 555if is_global_zone ; then 556 ATTRS="R i u a" 557else 558 ATTRS="R" 559fi 560 561TESTFILE=/tmp/tfile 562TESTDIR=tdir 563TESTATTR=tattr 564TESTACL=user:$ZFS_ACL_OTHER1:write_data:allow 565TESTMODE=777 566TESTSTR="ZFS test suites" 567 568ace_file="write_data/append_data/write_xattr/write_acl/write_attributes" 569ace_dir="add_file/add_subdirectory/${ace_file}" 570 571log_assert "Verify DOS & BSD'ish attributes will provide the " \ 572 "access limitation as expected." 573log_onexit cleanup 574 575echo "$TESTSTR" > $TESTFILE 576 577typeset gobject 578typeset gattr 579for gattr in $ATTRS ; do 580 for fs in $FS ; do 581 mtpt=$(get_prop mountpoint $fs) 582 chmod 777 $mtpt 583 for user in root $ZFS_ACL_STAFF1; do 584 log_must set_cur_usr $user 585 for file in $FILES ; do 586 gobject=$mtpt/$file 587 create_object "file" $gobject $ZFS_ACL_CUR_USER 588 test_wrapper $gobject $gattr 589 destroy_object $gobject 590 done 591 592 for dir in $DIRS ; do 593 gobject=$mtpt/$dir 594 create_object "dir" $gobject $ZFS_ACL_CUR_USER 595 test_wrapper $gobject $gattr 596 destroy_object $gobject 597 done 598 done 599 done 600done 601 602log_pass "DOS & BSD'ish attributes provide the access limitation as expected." 603