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