xref: /illumos-gate/usr/src/test/zfs-tests/tests/functional/acl/cifs/cifs_attr_003_pos.ksh (revision 1d32ba663e202c24a5a1f2e5aef83fffb447cb7f)
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