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