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 2008 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26#
27
28#
29# Copyright (c) 2012 by Delphix. All rights reserved.
30# Copyright 2016 Nexenta Systems, Inc.
31#
32
33. $STF_SUITE/tests/functional/acl/acl_common.kshlib
34. $STF_SUITE/tests/functional/acl/cifs/cifs.kshlib
35
36#
37# DESCRIPTION:
38#	Verify the user with PRIV_FILE_FLAG_SET/PRIV_FILE_FLAG_CLEAR
39#	could set/clear BSD'ish attributes.
40#	(Immutable, nounlink, and appendonly)
41#
42# STRATEGY:
43#	1. Loop super user and non-super user to run the test case.
44#	2. Create basedir and a set of subdirectores and files within it.
45#	3. Grant user has PRIV_FILE_FLAG_SET/PRIV_FILE_FLAG_CLEAR separately.
46#	4. Verify set/clear BSD'ish attributes should succeed.
47#
48
49verify_runnable "global"
50
51function cleanup
52{
53	$RM -rf $mntpt/file $mntpt/dir >/dev/null 2>&1
54
55	log_must $CP $orig_user_attr /etc/user_attr
56	log_must $RM -f $orig_user_attr
57}
58
59function try
60{
61	typeset obj=$1		# The file or dir to operate on
62	typeset attr=$2		# The attribute to set or clear
63	typeset user=$3		# The user to run the command as
64	typeset priv=$4		# What privilege to run with if non-root
65	typeset op=$5		# Whether to set or clear the attribute
66
67	typeset cmd="$CHMOD $op$attr $obj"
68
69	#
70	# No one can add 'q' (av_quarantine) to a directory. root can do
71	# anything else. A regular user can remove no attributes without the
72	# 'all' privilege, and can add attributes (other than 'q' on a
73	# directory) with the 'file_flag_set' or 'all' privileges.
74	#
75	if [[ $user == 'root' ]]; then
76		if [[ $attr =~ 'q' && -d $obj && $op == $add ]]; then
77			log_mustnot $cmd
78		else
79			log_must $cmd
80		fi
81	else
82		if [[ $attr =~ 'q' && -d $obj && $op == $add ]]; then
83			log_mustnot $SU $user -c "$cmd"
84		else
85			if [[ $op == $add ]]; then
86				if [[ -n $priv ]]; then
87					log_must $SU $user -c "$cmd"
88				else
89					log_mustnot $SU $user -c "$cmd"
90				fi
91			else
92				if [[ $attr = 'q' && -d $obj ]]; then
93					log_must $SU $user -c "$cmd"
94				elif [[ $priv =~ 'all' ]]; then
95					log_must $SU $user -c "$cmd"
96				else
97					log_mustnot $SU $user -c "$cmd"
98					#
99					# Remove the attribute, so the next
100					# iteration starts with a known state.
101					#
102					log_must $cmd
103				fi
104			fi
105		fi
106	fi
107
108
109	# Can't add av_quarantine to a directory, so don't check for that
110	[[ $attr == 'q' && $op == $add && -d $obj ]] && return
111	chk_attr $op $obj $attr
112}
113
114function chk_attr
115{
116	typeset op=$1
117	typeset obj=$2
118	typeset attr=$3
119
120	# Extract the attribute string - just the text inside the braces
121	typeset attrstr="$($LS -d/ c $obj | $SED '1d; s/.*{\(.*\)}.*/\1/g')"
122
123	if [[ $op == $add ]]; then
124		[[ $attrstr =~ $attr ]] || log_fail "$op $attr -> $attrstr"
125	else
126		[[ $attrstr =~ $attr ]] && log_fail "$op $attr -> $attrstr"
127	fi
128}
129
130#
131# Grant the privset to the given user
132#
133# $1: The given user
134# $2: The given privset
135#
136function grant_priv
137{
138	typeset user=$1
139	typeset priv=$2
140
141	if [[ -z $user || -z $priv ]]; then
142		log_fail "User($user), Priv($priv) not defined."
143	fi
144
145	priv_mod=",$priv"
146
147	# If we're root, don't modify /etc/user_attr
148	[[ $user == 'root' ]] && return 0
149
150	$ECHO "$user::::type=normal;defaultpriv=basic$priv_mod" >> \
151	    /etc/user_attr
152	return $?
153}
154
155#
156# Revoke the all additional privset from the given user
157#
158# $1: The given user
159#
160function reset_privs
161{
162	typeset user=$1
163
164	if [[ -z $user ]]; then
165		log_fail "User not defined."
166	fi
167
168	priv_mod=
169
170	$CP $orig_user_attr /etc/user_attr || log_fail "Couldn't modify user_attr"
171	return 0
172}
173
174log_assert "Verify set/clear BSD'ish attributes will succeed while user has " \
175    "file_flag_set or all privilege"
176log_onexit cleanup
177
178add='S+c'
179del='S-c'
180mntpt=$(get_prop mountpoint $TESTPOOL/$TESTFS)
181orig_user_attr="/tmp/user_attr.$$"
182attributes="u i a d q m"
183
184log_must $CP /etc/user_attr $orig_user_attr
185
186for owner in root $ZFS_ACL_STAFF1 $ZFS_ACL_STAFF2; do
187	$TOUCH $mntpt/file || log_fail "Failed to create $mntpt/file"
188	$MKDIR $mntpt/dir || log_fail "Failed to mkdir $mntpt/dir"
189	$CHOWN $owner $mntpt/file $mntpt/dir || log_fail "Failed to chown file"
190	for user in 'root' $ZFS_ACL_STAFF2; do
191		for attr in $attributes; do
192			for priv in 'file_flag_set' 'all'; do
193				log_note "Trying $owner $user $attr $priv"
194				grant_priv $user $priv
195				try $mntpt/file $attr $user $priv $add
196				try $mntpt/file $attr $user $priv $del
197				try $mntpt/dir $attr $user $priv $add
198				try $mntpt/dir $attr $user $priv $del
199				reset_privs $user
200			done
201		done
202	done
203	$RM -rf $mntpt/file $mntpt/dir || log_fail \
204	    "$($LS -d/ c $mntpt/file $mntpt/dir)"
205done
206
207log_pass "Set/Clear BSD'ish attributes succeed while user has " \
208    "PRIV_FILE_FLAG_SET/PRIV_FILE_FLAG_CLEAR privilege"
209