xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_fsops.c (revision bbf6f00c25b6a2bed23c35eac6d62998ecdb338c)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
227f667e74Sjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #include <sys/sid.h>
27dc20a302Sas200622 #include <sys/nbmlock.h>
28da6c28aaSamw #include <smbsrv/smb_fsops.h>
2955bf511dSas200622 #include <smbsrv/smb_kproto.h>
30da6c28aaSamw #include <acl/acl_common.h>
31dc20a302Sas200622 #include <sys/fcntl.h>
32dc20a302Sas200622 #include <sys/flock.h>
33dc20a302Sas200622 #include <fs/fs_subr.h>
34da6c28aaSamw 
35faa1795aSjb150015 extern caller_context_t smb_ct;
36faa1795aSjb150015 
378c10a865Sas200622 extern int smb_fem_oplock_install(smb_node_t *);
388c10a865Sas200622 extern void smb_fem_oplock_uninstall(smb_node_t *);
398c10a865Sas200622 
408c10a865Sas200622 extern int smb_vop_other_opens(vnode_t *, int);
418c10a865Sas200622 
42eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_stream(smb_request_t *, cred_t *, smb_node_t *,
43037cac00Sjoyce mcintosh     char *, char *, int, smb_attr_t *, smb_node_t **);
44eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
45eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_file(smb_request_t *, cred_t *, smb_node_t *,
46037cac00Sjoyce mcintosh     char *, int, smb_attr_t *, smb_node_t **);
47eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
48eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_with_sd(smb_request_t *, cred_t *, smb_node_t *,
49037cac00Sjoyce mcintosh     char *, smb_attr_t *, smb_node_t **, smb_fssd_t *);
50eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
51eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_sdinherit(smb_request_t *, smb_node_t *, smb_fssd_t *);
52da6c28aaSamw 
53da6c28aaSamw /*
54da6c28aaSamw  * The smb_fsop_* functions have knowledge of CIFS semantics.
55da6c28aaSamw  *
56da6c28aaSamw  * The smb_vop_* functions have minimal knowledge of CIFS semantics and
57da6c28aaSamw  * serve as an interface to the VFS layer.
58da6c28aaSamw  *
59da6c28aaSamw  * Hence, smb_request_t and smb_node_t structures should not be passed
60da6c28aaSamw  * from the smb_fsop_* layer to the smb_vop_* layer.
61da6c28aaSamw  *
62da6c28aaSamw  * In general, CIFS service code should only ever call smb_fsop_*
63da6c28aaSamw  * functions directly, and never smb_vop_* functions directly.
64da6c28aaSamw  *
65da6c28aaSamw  * smb_fsop_* functions should call smb_vop_* functions where possible, instead
66da6c28aaSamw  * of their smb_fsop_* counterparts.  However, there are times when
67da6c28aaSamw  * this cannot be avoided.
68da6c28aaSamw  */
69da6c28aaSamw 
70da6c28aaSamw /*
71da6c28aaSamw  * Note: Stream names cannot be mangled.
72da6c28aaSamw  */
73da6c28aaSamw 
74da6c28aaSamw /*
758c10a865Sas200622  * smb_fsop_amask_to_omode
768c10a865Sas200622  *
778c10a865Sas200622  * Convert the access mask to the open mode (for use
788c10a865Sas200622  * with the VOP_OPEN call).
798c10a865Sas200622  *
808c10a865Sas200622  * Note that opening a file for attribute only access
818c10a865Sas200622  * will also translate into an FREAD or FWRITE open mode
828c10a865Sas200622  * (i.e., it's not just for data).
838c10a865Sas200622  *
848c10a865Sas200622  * This is needed so that opens are tracked appropriately
858c10a865Sas200622  * for oplock processing.
86da6c28aaSamw  */
87da6c28aaSamw 
88da6c28aaSamw int
898c10a865Sas200622 smb_fsop_amask_to_omode(uint32_t access)
90da6c28aaSamw {
91da6c28aaSamw 	int mode = 0;
92da6c28aaSamw 
938c10a865Sas200622 	if (access & (FILE_READ_DATA | FILE_EXECUTE |
948c10a865Sas200622 	    FILE_READ_ATTRIBUTES | FILE_READ_EA))
95da6c28aaSamw 		mode |= FREAD;
96da6c28aaSamw 
978c10a865Sas200622 	if (access & (FILE_WRITE_DATA | FILE_APPEND_DATA |
988c10a865Sas200622 	    FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))
99da6c28aaSamw 		mode |= FWRITE;
100da6c28aaSamw 
1018c10a865Sas200622 	if (access & FILE_APPEND_DATA)
102da6c28aaSamw 		mode |= FAPPEND;
103da6c28aaSamw 
104da6c28aaSamw 	return (mode);
105da6c28aaSamw }
106da6c28aaSamw 
1078c10a865Sas200622 int
1088c10a865Sas200622 smb_fsop_open(smb_node_t *node, int mode, cred_t *cred)
1098c10a865Sas200622 {
1108c10a865Sas200622 	/*
1118c10a865Sas200622 	 * Assuming that the same vnode is returned as we had before.
1128c10a865Sas200622 	 * (I.e., with certain types of files or file systems, a
1138c10a865Sas200622 	 * different vnode might be returned by VOP_OPEN)
1148c10a865Sas200622 	 */
1158c10a865Sas200622 	return (smb_vop_open(&node->vp, mode, cred));
1168c10a865Sas200622 }
1178c10a865Sas200622 
118c8ec8eeaSjose borrego void
1198c10a865Sas200622 smb_fsop_close(smb_node_t *node, int mode, cred_t *cred)
1208c10a865Sas200622 {
121c8ec8eeaSjose borrego 	smb_vop_close(node->vp, mode, cred);
1228c10a865Sas200622 }
1238c10a865Sas200622 
1248c10a865Sas200622 int
1258c10a865Sas200622 smb_fsop_oplock_install(smb_node_t *node, int mode)
1268c10a865Sas200622 {
1278c10a865Sas200622 	int rc;
1288c10a865Sas200622 
1298c10a865Sas200622 	if (smb_vop_other_opens(node->vp, mode))
1308c10a865Sas200622 		return (EMFILE);
1318c10a865Sas200622 
1328c10a865Sas200622 	if ((rc = smb_fem_oplock_install(node)))
1338c10a865Sas200622 		return (rc);
1348c10a865Sas200622 
1358c10a865Sas200622 	if (smb_vop_other_opens(node->vp, mode)) {
1368c10a865Sas200622 		(void) smb_fem_oplock_uninstall(node);
1378c10a865Sas200622 		return (EMFILE);
1388c10a865Sas200622 	}
1398c10a865Sas200622 
1408c10a865Sas200622 	return (0);
1418c10a865Sas200622 }
1428c10a865Sas200622 
1438c10a865Sas200622 void
1448c10a865Sas200622 smb_fsop_oplock_uninstall(smb_node_t *node)
1458c10a865Sas200622 {
1468c10a865Sas200622 	smb_fem_oplock_uninstall(node);
1478c10a865Sas200622 }
1488c10a865Sas200622 
149da6c28aaSamw static int
150eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_with_sd(smb_request_t *sr, cred_t *cr,
151eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *dnode, char *name,
152037cac00Sjoyce mcintosh     smb_attr_t *attr, smb_node_t **ret_snode, smb_fssd_t *fs_sd)
153da6c28aaSamw {
154da6c28aaSamw 	vsecattr_t *vsap;
155da6c28aaSamw 	vsecattr_t vsecattr;
156da6c28aaSamw 	acl_t *acl, *dacl, *sacl;
157da6c28aaSamw 	smb_attr_t set_attr;
158da6c28aaSamw 	vnode_t *vp;
159da6c28aaSamw 	int aclbsize = 0;	/* size of acl list in bytes */
160da6c28aaSamw 	int flags = 0;
161da6c28aaSamw 	int rc;
1622c1b14e5Sjose borrego 	boolean_t is_dir;
163da6c28aaSamw 
164da6c28aaSamw 	ASSERT(fs_sd);
165da6c28aaSamw 
166c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
167da6c28aaSamw 		flags = SMB_IGNORE_CASE;
1688b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
1698b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
170da6c28aaSamw 
171da6c28aaSamw 	ASSERT(cr);
172da6c28aaSamw 
173da6c28aaSamw 	is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0);
174da6c28aaSamw 
175c8ec8eeaSjose borrego 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) {
176da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
177da6c28aaSamw 			dacl = fs_sd->sd_zdacl;
178da6c28aaSamw 			sacl = fs_sd->sd_zsacl;
179da6c28aaSamw 			ASSERT(dacl || sacl);
180da6c28aaSamw 			if (dacl && sacl) {
18155bf511dSas200622 				acl = smb_fsacl_merge(dacl, sacl);
182da6c28aaSamw 			} else if (dacl) {
183da6c28aaSamw 				acl = dacl;
184da6c28aaSamw 			} else {
185da6c28aaSamw 				acl = sacl;
186da6c28aaSamw 			}
187da6c28aaSamw 
18855bf511dSas200622 			rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize);
189da6c28aaSamw 
190da6c28aaSamw 			if (dacl && sacl)
191da6c28aaSamw 				acl_free(acl);
192da6c28aaSamw 
1932c1b14e5Sjose borrego 			if (rc != 0)
194da6c28aaSamw 				return (rc);
195da6c28aaSamw 
196da6c28aaSamw 			vsap = &vsecattr;
1972c1b14e5Sjose borrego 		} else {
198da6c28aaSamw 			vsap = NULL;
1992c1b14e5Sjose borrego 		}
200da6c28aaSamw 
201743a77edSAlan Wright 		/* The tree ACEs may prevent a create */
202743a77edSAlan Wright 		rc = EACCES;
203da6c28aaSamw 		if (is_dir) {
204743a77edSAlan Wright 			if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_SUBDIRECTORY) != 0)
205eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 				rc = smb_vop_mkdir(dnode->vp, name, attr,
206743a77edSAlan Wright 				    &vp, flags, cr, vsap);
207da6c28aaSamw 		} else {
208743a77edSAlan Wright 			if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_FILE) != 0)
209eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 				rc = smb_vop_create(dnode->vp, name, attr,
210743a77edSAlan Wright 				    &vp, flags, cr, vsap);
211da6c28aaSamw 		}
212da6c28aaSamw 
213da6c28aaSamw 		if (vsap != NULL)
214da6c28aaSamw 			kmem_free(vsap->vsa_aclentp, aclbsize);
215da6c28aaSamw 
216da6c28aaSamw 		if (rc != 0)
217da6c28aaSamw 			return (rc);
218da6c28aaSamw 
219da6c28aaSamw 		set_attr.sa_mask = 0;
220da6c28aaSamw 
221da6c28aaSamw 		/*
222da6c28aaSamw 		 * Ideally we should be able to specify the owner and owning
223da6c28aaSamw 		 * group at create time along with the ACL. Since we cannot
224da6c28aaSamw 		 * do that right now, kcred is passed to smb_vop_setattr so it
225da6c28aaSamw 		 * doesn't fail due to lack of permission.
226da6c28aaSamw 		 */
227da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
228da6c28aaSamw 			set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
229da6c28aaSamw 			set_attr.sa_mask |= SMB_AT_UID;
230da6c28aaSamw 		}
231da6c28aaSamw 
232da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
233da6c28aaSamw 			set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
234da6c28aaSamw 			set_attr.sa_mask |= SMB_AT_GID;
235da6c28aaSamw 		}
236da6c28aaSamw 
2379660e5cbSJanice Chang 		if (set_attr.sa_mask)
2389660e5cbSJanice Chang 			rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcred);
239da6c28aaSamw 
2402c1b14e5Sjose borrego 		if (rc == 0) {
2412c1b14e5Sjose borrego 			*ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
242037cac00Sjoyce mcintosh 			    name, dnode, NULL);
2432c1b14e5Sjose borrego 
2447f667e74Sjose borrego 			if (*ret_snode == NULL)
2452c1b14e5Sjose borrego 				rc = ENOMEM;
2467f667e74Sjose borrego 
2477f667e74Sjose borrego 			VN_RELE(vp);
2482c1b14e5Sjose borrego 		}
249da6c28aaSamw 	} else {
250da6c28aaSamw 		/*
251da6c28aaSamw 		 * For filesystems that don't support ACL-on-create, try
252da6c28aaSamw 		 * to set the specified SD after create, which could actually
253da6c28aaSamw 		 * fail because of conflicts between inherited security
254da6c28aaSamw 		 * attributes upon creation and the specified SD.
255da6c28aaSamw 		 *
256da6c28aaSamw 		 * Passing kcred to smb_fsop_sdwrite() to overcome this issue.
257da6c28aaSamw 		 */
258da6c28aaSamw 
259da6c28aaSamw 		if (is_dir) {
260eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_vop_mkdir(dnode->vp, name, attr, &vp,
2612c1b14e5Sjose borrego 			    flags, cr, NULL);
262da6c28aaSamw 		} else {
263eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_vop_create(dnode->vp, name, attr, &vp,
2642c1b14e5Sjose borrego 			    flags, cr, NULL);
265da6c28aaSamw 		}
266da6c28aaSamw 
26755bf511dSas200622 		if (rc != 0)
26855bf511dSas200622 			return (rc);
26955bf511dSas200622 
2702c1b14e5Sjose borrego 		*ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
271037cac00Sjoyce mcintosh 		    name, dnode, NULL);
272da6c28aaSamw 
2732c1b14e5Sjose borrego 		if (*ret_snode != NULL) {
2742c1b14e5Sjose borrego 			if (!smb_tree_has_feature(sr->tid_tree,
2752c1b14e5Sjose borrego 			    SMB_TREE_NFS_MOUNTED))
2762c1b14e5Sjose borrego 				rc = smb_fsop_sdwrite(sr, kcred, *ret_snode,
2772c1b14e5Sjose borrego 				    fs_sd, 1);
2782c1b14e5Sjose borrego 		} else {
279da6c28aaSamw 			rc = ENOMEM;
280da6c28aaSamw 		}
2817f667e74Sjose borrego 
2827f667e74Sjose borrego 		VN_RELE(vp);
283da6c28aaSamw 	}
284da6c28aaSamw 
28555bf511dSas200622 	if (rc != 0) {
2862c1b14e5Sjose borrego 		if (is_dir)
287eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			(void) smb_vop_rmdir(dnode->vp, name, flags, cr);
2882c1b14e5Sjose borrego 		else
289eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			(void) smb_vop_remove(dnode->vp, name, flags, cr);
29055bf511dSas200622 	}
29155bf511dSas200622 
292da6c28aaSamw 	return (rc);
293da6c28aaSamw }
294da6c28aaSamw 
295da6c28aaSamw /*
296da6c28aaSamw  * smb_fsop_create
297da6c28aaSamw  *
298da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
299da6c28aaSamw  * all the smb_vop_creates are performed with the appropriate credentials.
300eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * Please document any direct calls to explain the reason for avoiding
301eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * this wrapper.
302da6c28aaSamw  *
303da6c28aaSamw  * *ret_snode is returned with a reference upon success.  No reference is
304da6c28aaSamw  * taken if an error is returned.
305da6c28aaSamw  */
306da6c28aaSamw int
307037cac00Sjoyce mcintosh smb_fsop_create(smb_request_t *sr, cred_t *cr, smb_node_t *dnode,
308037cac00Sjoyce mcintosh     char *name, smb_attr_t *attr, smb_node_t **ret_snode)
309da6c28aaSamw {
310da6c28aaSamw 	int	rc = 0;
311eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	int	flags = 0;
312eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	char	*fname, *sname;
313eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	char	*longname = NULL;
314da6c28aaSamw 
315da6c28aaSamw 	ASSERT(cr);
316eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
317eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
318eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
319da6c28aaSamw 
320da6c28aaSamw 	ASSERT(ret_snode);
321da6c28aaSamw 	*ret_snode = 0;
322da6c28aaSamw 
323da6c28aaSamw 	ASSERT(name);
324da6c28aaSamw 	if (*name == 0)
325da6c28aaSamw 		return (EINVAL);
326da6c28aaSamw 
327da6c28aaSamw 	ASSERT(sr);
328da6c28aaSamw 	ASSERT(sr->tid_tree);
329c8ec8eeaSjose borrego 
330eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
331c8ec8eeaSjose borrego 		return (EACCES);
332c8ec8eeaSjose borrego 
333c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
334da6c28aaSamw 		return (EROFS);
335da6c28aaSamw 
336c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
337da6c28aaSamw 		flags = SMB_IGNORE_CASE;
3388b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
3398b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
340e3f2c991SKeyur Desai 	if (SMB_TREE_SUPPORTS_ABE(sr))
341e3f2c991SKeyur Desai 		flags |= SMB_ABE;
342da6c28aaSamw 
3438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_is_stream_name(name)) {
344da6c28aaSamw 		fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
345da6c28aaSamw 		sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
346eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_stream_parse_name(name, fname, sname);
347da6c28aaSamw 
348eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_create_stream(sr, cr, dnode,
349037cac00Sjoyce mcintosh 		    fname, sname, flags, attr, ret_snode);
3508b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
351da6c28aaSamw 		kmem_free(fname, MAXNAMELEN);
352da6c28aaSamw 		kmem_free(sname, MAXNAMELEN);
3538b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (rc);
354da6c28aaSamw 	}
3558b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
3568b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	/* Not a named stream */
357eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
3588b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_maybe_mangled_name(name)) {
3598b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
360e3f2c991SKeyur Desai 		rc = smb_unmangle_name(dnode, name, longname,
361e3f2c991SKeyur Desai 		    MAXNAMELEN, flags);
3628b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		kmem_free(longname, MAXNAMELEN);
3638b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
3648b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (rc == 0)
3658b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = EEXIST;
3668b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (rc != ENOENT)
3678b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			return (rc);
3688b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
3698b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
370eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_fsop_create_file(sr, cr, dnode, name, flags,
371037cac00Sjoyce mcintosh 	    attr, ret_snode);
372eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	return (rc);
373eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
374eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States }
375eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
376eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
377eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /*
378eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * smb_fsop_create_stream
379eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  *
380eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * Create NTFS named stream file (sname) on unnamed stream
381eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * file (fname), creating the unnamed stream file if it
382eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * doesn't exist.
383eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * If we created the unnamed stream file and then creation
384eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * of the named stream file fails, we delete the unnamed stream.
385eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * Since we use the real file name for the smb_vop_remove we
386eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * clear the SMB_IGNORE_CASE flag to ensure a case sensitive
387eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * match.
388eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  *
389eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * The second parameter of smb_vop_setattr() is set to
390eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * NULL, even though an unnamed stream exists.  This is
391eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * because we want to set the UID and GID on the named
392eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * stream in this case for consistency with the (unnamed
393eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * stream) file (see comments for smb_vop_setattr()).
394eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  */
395eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int
396eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_stream(smb_request_t *sr, cred_t *cr,
397eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *dnode, char *fname, char *sname, int flags,
398037cac00Sjoyce mcintosh     smb_attr_t *attr, smb_node_t **ret_snode)
399eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States {
400eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_node_t	*fnode;
401eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_attr_t	fattr;
402eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	vnode_t		*xattrdvp;
403eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	vnode_t		*vp;
404eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	int		rc = 0;
405eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	boolean_t	fcreate = B_FALSE;
406eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
407eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	/* Look up / create the unnamed stream, fname */
408eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
409037cac00Sjoyce mcintosh 	    sr->tid_tree->t_snode, dnode, fname, &fnode);
410eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (rc == ENOENT) {
411eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		fcreate = B_TRUE;
412eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_create_file(sr, cr, dnode, fname, flags,
413037cac00Sjoyce mcintosh 		    attr, &fnode);
414eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
415eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (rc != 0)
416eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (rc);
417eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
418037cac00Sjoyce mcintosh 	fattr.sa_mask = SMB_AT_UID | SMB_AT_GID;
419037cac00Sjoyce mcintosh 	rc = smb_vop_getattr(fnode->vp, NULL, &fattr, 0, kcred);
420037cac00Sjoyce mcintosh 
421037cac00Sjoyce mcintosh 	if (rc == 0) {
422eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		/* create the named stream, sname */
423037cac00Sjoyce mcintosh 		rc = smb_vop_stream_create(fnode->vp, sname, attr,
424037cac00Sjoyce mcintosh 		    &vp, &xattrdvp, flags, cr);
425037cac00Sjoyce mcintosh 	}
426eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (rc != 0) {
427eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (fcreate) {
428eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			flags &= ~SMB_IGNORE_CASE;
429eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			(void) smb_vop_remove(dnode->vp,
430eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			    fnode->od_name, flags, cr);
431eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		}
432eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_release(fnode);
433eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (rc);
434eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
435eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
436eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	attr->sa_vattr.va_uid = fattr.sa_vattr.va_uid;
437eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	attr->sa_vattr.va_gid = fattr.sa_vattr.va_gid;
438eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	attr->sa_mask = SMB_AT_UID | SMB_AT_GID;
439eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
440eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_setattr(vp, NULL, attr, 0, kcred);
441eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (rc != 0) {
442eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_release(fnode);
443eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (rc);
444eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
445eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
446eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	*ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdvp,
447037cac00Sjoyce mcintosh 	    vp, sname);
448eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
449eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_node_release(fnode);
450eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	VN_RELE(xattrdvp);
451eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	VN_RELE(vp);
452eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
453eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (*ret_snode == NULL)
454eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = ENOMEM;
455eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
456eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	return (rc);
457eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States }
458eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
459eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /*
460eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * smb_fsop_create_file
461eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  */
462eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int
463eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_file(smb_request_t *sr, cred_t *cr,
464eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *dnode, char *name, int flags,
465037cac00Sjoyce mcintosh     smb_attr_t *attr, smb_node_t **ret_snode)
466eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States {
467eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	open_param_t	*op = &sr->arg.open;
468eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	vnode_t		*vp;
469eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_fssd_t	fs_sd;
470eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	uint32_t	secinfo;
471eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	uint32_t	status;
472eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	int		rc = 0;
473eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
47455bf511dSas200622 	if (op->sd) {
475da6c28aaSamw 		/*
476da6c28aaSamw 		 * SD sent by client in Windows format. Needs to be
477da6c28aaSamw 		 * converted to FS format. No inheritance.
478da6c28aaSamw 		 */
47955bf511dSas200622 		secinfo = smb_sd_get_secinfo(op->sd);
48055bf511dSas200622 		smb_fssd_init(&fs_sd, secinfo, 0);
481da6c28aaSamw 
48255bf511dSas200622 		status = smb_sd_tofs(op->sd, &fs_sd);
483da6c28aaSamw 		if (status == NT_STATUS_SUCCESS) {
484eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
485037cac00Sjoyce mcintosh 			    name, attr, ret_snode, &fs_sd);
4868b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		} else {
487da6c28aaSamw 			rc = EINVAL;
4888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		}
48955bf511dSas200622 		smb_fssd_term(&fs_sd);
490da6c28aaSamw 	} else if (sr->tid_tree->t_acltype == ACE_T) {
491da6c28aaSamw 		/*
492da6c28aaSamw 		 * No incoming SD and filesystem is ZFS
493da6c28aaSamw 		 * Server applies Windows inheritance rules,
494da6c28aaSamw 		 * see smb_fsop_sdinherit() comments as to why.
495da6c28aaSamw 		 */
49655bf511dSas200622 		smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0);
497eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
498da6c28aaSamw 		if (rc == 0) {
499eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
500037cac00Sjoyce mcintosh 			    name, attr, ret_snode, &fs_sd);
501da6c28aaSamw 		}
502da6c28aaSamw 
50355bf511dSas200622 		smb_fssd_term(&fs_sd);
504da6c28aaSamw 	} else {
505da6c28aaSamw 		/*
506da6c28aaSamw 		 * No incoming SD and filesystem is not ZFS
507da6c28aaSamw 		 * let the filesystem handles the inheritance.
508da6c28aaSamw 		 */
509eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_create(dnode->vp, name, attr, &vp,
510dc20a302Sas200622 		    flags, cr, NULL);
511da6c28aaSamw 
512da6c28aaSamw 		if (rc == 0) {
513da6c28aaSamw 			*ret_snode = smb_node_lookup(sr, op, cr, vp,
514037cac00Sjoyce mcintosh 			    name, dnode, NULL);
515da6c28aaSamw 
5167f667e74Sjose borrego 			if (*ret_snode == NULL)
517da6c28aaSamw 				rc = ENOMEM;
5187f667e74Sjose borrego 
5197f667e74Sjose borrego 			VN_RELE(vp);
520da6c28aaSamw 		}
521da6c28aaSamw 
522da6c28aaSamw 	}
523da6c28aaSamw 	return (rc);
524da6c28aaSamw }
525da6c28aaSamw 
526da6c28aaSamw /*
527da6c28aaSamw  * smb_fsop_mkdir
528da6c28aaSamw  *
529da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
530da6c28aaSamw  * the the calls are performed with the appropriate credentials.
531da6c28aaSamw  * Please document any direct call to explain the reason
532da6c28aaSamw  * for avoiding this wrapper.
533da6c28aaSamw  *
534da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
535da6c28aaSamw  *
536da6c28aaSamw  * *ret_snode is returned with a reference upon success.  No reference is
537da6c28aaSamw  * taken if an error is returned.
538da6c28aaSamw  */
539da6c28aaSamw int
540da6c28aaSamw smb_fsop_mkdir(
541faa1795aSjb150015     smb_request_t *sr,
542da6c28aaSamw     cred_t *cr,
543eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *dnode,
544da6c28aaSamw     char *name,
545da6c28aaSamw     smb_attr_t *attr,
546037cac00Sjoyce mcintosh     smb_node_t **ret_snode)
547da6c28aaSamw {
548da6c28aaSamw 	struct open_param *op = &sr->arg.open;
549da6c28aaSamw 	char *longname;
550da6c28aaSamw 	vnode_t *vp;
551da6c28aaSamw 	int flags = 0;
552da6c28aaSamw 	smb_fssd_t fs_sd;
553da6c28aaSamw 	uint32_t secinfo;
554da6c28aaSamw 	uint32_t status;
555da6c28aaSamw 	int rc;
556da6c28aaSamw 	ASSERT(cr);
557eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
558eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
559eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
560da6c28aaSamw 
561da6c28aaSamw 	ASSERT(ret_snode);
562da6c28aaSamw 	*ret_snode = 0;
563da6c28aaSamw 
564da6c28aaSamw 	ASSERT(name);
565da6c28aaSamw 	if (*name == 0)
566da6c28aaSamw 		return (EINVAL);
567da6c28aaSamw 
568da6c28aaSamw 	ASSERT(sr);
569da6c28aaSamw 	ASSERT(sr->tid_tree);
570c8ec8eeaSjose borrego 
571eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
572c8ec8eeaSjose borrego 		return (EACCES);
573c8ec8eeaSjose borrego 
574c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
575da6c28aaSamw 		return (EROFS);
5768b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
5778b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
578e3f2c991SKeyur Desai 	if (SMB_TREE_SUPPORTS_ABE(sr))
579e3f2c991SKeyur Desai 		flags |= SMB_ABE;
580da6c28aaSamw 
581da6c28aaSamw 	if (smb_maybe_mangled_name(name)) {
582da6c28aaSamw 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
583e3f2c991SKeyur Desai 		rc = smb_unmangle_name(dnode, name, longname,
584e3f2c991SKeyur Desai 		    MAXNAMELEN, flags);
585da6c28aaSamw 		kmem_free(longname, MAXNAMELEN);
586da6c28aaSamw 
587da6c28aaSamw 		/*
588da6c28aaSamw 		 * If the name passed in by the client has an unmangled
589da6c28aaSamw 		 * equivalent that is found in the specified directory,
590da6c28aaSamw 		 * then the mkdir cannot succeed.  Return EEXIST.
591da6c28aaSamw 		 *
592da6c28aaSamw 		 * Only if ENOENT is returned will a mkdir be attempted.
593da6c28aaSamw 		 */
594da6c28aaSamw 
595da6c28aaSamw 		if (rc == 0)
596da6c28aaSamw 			rc = EEXIST;
597da6c28aaSamw 
598da6c28aaSamw 		if (rc != ENOENT)
599da6c28aaSamw 			return (rc);
600da6c28aaSamw 	}
601da6c28aaSamw 
602c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
603da6c28aaSamw 		flags = SMB_IGNORE_CASE;
604da6c28aaSamw 
60555bf511dSas200622 	if (op->sd) {
606da6c28aaSamw 		/*
607da6c28aaSamw 		 * SD sent by client in Windows format. Needs to be
608da6c28aaSamw 		 * converted to FS format. No inheritance.
609da6c28aaSamw 		 */
61055bf511dSas200622 		secinfo = smb_sd_get_secinfo(op->sd);
61155bf511dSas200622 		smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR);
612da6c28aaSamw 
61355bf511dSas200622 		status = smb_sd_tofs(op->sd, &fs_sd);
614da6c28aaSamw 		if (status == NT_STATUS_SUCCESS) {
615eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
616037cac00Sjoyce mcintosh 			    name, attr, ret_snode, &fs_sd);
617da6c28aaSamw 		}
618da6c28aaSamw 		else
619da6c28aaSamw 			rc = EINVAL;
62055bf511dSas200622 		smb_fssd_term(&fs_sd);
621da6c28aaSamw 	} else if (sr->tid_tree->t_acltype == ACE_T) {
622da6c28aaSamw 		/*
623da6c28aaSamw 		 * No incoming SD and filesystem is ZFS
624da6c28aaSamw 		 * Server applies Windows inheritance rules,
625da6c28aaSamw 		 * see smb_fsop_sdinherit() comments as to why.
626da6c28aaSamw 		 */
62755bf511dSas200622 		smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR);
628eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
629da6c28aaSamw 		if (rc == 0) {
630eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
631037cac00Sjoyce mcintosh 			    name, attr, ret_snode, &fs_sd);
632da6c28aaSamw 		}
633da6c28aaSamw 
63455bf511dSas200622 		smb_fssd_term(&fs_sd);
635da6c28aaSamw 
636da6c28aaSamw 	} else {
637eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, flags, cr,
638dc20a302Sas200622 		    NULL);
639da6c28aaSamw 
640da6c28aaSamw 		if (rc == 0) {
641da6c28aaSamw 			*ret_snode = smb_node_lookup(sr, op, cr, vp, name,
642037cac00Sjoyce mcintosh 			    dnode, NULL);
643da6c28aaSamw 
6447f667e74Sjose borrego 			if (*ret_snode == NULL)
645da6c28aaSamw 				rc = ENOMEM;
6467f667e74Sjose borrego 
6477f667e74Sjose borrego 			VN_RELE(vp);
648da6c28aaSamw 		}
649da6c28aaSamw 	}
650da6c28aaSamw 
651da6c28aaSamw 	return (rc);
652da6c28aaSamw }
653da6c28aaSamw 
654da6c28aaSamw /*
655da6c28aaSamw  * smb_fsop_remove
656da6c28aaSamw  *
657da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
658da6c28aaSamw  * the the calls are performed with the appropriate credentials.
659da6c28aaSamw  * Please document any direct call to explain the reason
660da6c28aaSamw  * for avoiding this wrapper.
661da6c28aaSamw  *
662da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
663da6c28aaSamw  *
664da6c28aaSamw  * A null smb_request might be passed to this function.
665da6c28aaSamw  */
666da6c28aaSamw int
667da6c28aaSamw smb_fsop_remove(
668faa1795aSjb150015     smb_request_t	*sr,
669da6c28aaSamw     cred_t		*cr,
670eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t		*dnode,
671da6c28aaSamw     char		*name,
6728b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States     uint32_t		flags)
673da6c28aaSamw {
674da6c28aaSamw 	smb_node_t	*fnode;
675da6c28aaSamw 	char		*longname;
676da6c28aaSamw 	char		*fname;
677da6c28aaSamw 	char		*sname;
678da6c28aaSamw 	int		rc;
679da6c28aaSamw 
680da6c28aaSamw 	ASSERT(cr);
681da6c28aaSamw 	/*
682da6c28aaSamw 	 * The state of the node could be SMB_NODE_STATE_DESTROYING if this
683da6c28aaSamw 	 * function is called during the deletion of the node (because of
684da6c28aaSamw 	 * DELETE_ON_CLOSE).
685da6c28aaSamw 	 */
686eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
687eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
688da6c28aaSamw 
689eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 ||
690743a77edSAlan Wright 	    SMB_TREE_HAS_ACCESS(sr, ACE_DELETE) == 0)
691da6c28aaSamw 		return (EACCES);
692da6c28aaSamw 
693c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
694da6c28aaSamw 		return (EROFS);
695da6c28aaSamw 
696da6c28aaSamw 	fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
697da6c28aaSamw 	sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
698da6c28aaSamw 
699eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (dnode->flags & NODE_XATTR_DIR) {
7001fcced4cSJordan Brown 		rc = smb_vop_stream_remove(dnode->n_dnode->vp,
701cbfb650aScp160787 		    name, flags, cr);
702eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	} else if (smb_is_stream_name(name)) {
703eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_stream_parse_name(name, fname, sname);
7048d7e4166Sjose borrego 
705cbfb650aScp160787 		/*
706da6c28aaSamw 		 * Look up the unnamed stream (i.e. fname).
707da6c28aaSamw 		 * Unmangle processing will be done on fname
708da6c28aaSamw 		 * as well as any link target.
709da6c28aaSamw 		 */
710da6c28aaSamw 
711da6c28aaSamw 		rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
712037cac00Sjoyce mcintosh 		    sr->tid_tree->t_snode, dnode, fname, &fnode);
713da6c28aaSamw 
714da6c28aaSamw 		if (rc != 0) {
715da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
716da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
717da6c28aaSamw 			return (rc);
718da6c28aaSamw 		}
719da6c28aaSamw 
720da6c28aaSamw 		/*
721da6c28aaSamw 		 * XXX
722da6c28aaSamw 		 * Need to find out what permission is required by NTFS
723da6c28aaSamw 		 * to remove a stream.
724da6c28aaSamw 		 */
725dc20a302Sas200622 		rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr);
726da6c28aaSamw 
727da6c28aaSamw 		smb_node_release(fnode);
728da6c28aaSamw 	} else {
729eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_remove(dnode->vp, name, flags, cr);
730da6c28aaSamw 
731da6c28aaSamw 		if (rc == ENOENT) {
732da6c28aaSamw 			if (smb_maybe_mangled_name(name) == 0) {
733da6c28aaSamw 				kmem_free(fname, MAXNAMELEN);
734da6c28aaSamw 				kmem_free(sname, MAXNAMELEN);
735da6c28aaSamw 				return (rc);
736da6c28aaSamw 			}
737da6c28aaSamw 			longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
738da6c28aaSamw 
739e3f2c991SKeyur Desai 			if (SMB_TREE_SUPPORTS_ABE(sr))
740e3f2c991SKeyur Desai 				flags |= SMB_ABE;
741e3f2c991SKeyur Desai 
742eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_unmangle_name(dnode, name,
743e3f2c991SKeyur Desai 			    longname, MAXNAMELEN, flags);
744da6c28aaSamw 
745da6c28aaSamw 			if (rc == 0) {
746da6c28aaSamw 				/*
7478b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 				 * longname is the real (case-sensitive)
7488b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 				 * on-disk name.
749da6c28aaSamw 				 * We make sure we do a remove on this exact
750da6c28aaSamw 				 * name, as the name was mangled and denotes
751da6c28aaSamw 				 * a unique file.
752da6c28aaSamw 				 */
753da6c28aaSamw 				flags &= ~SMB_IGNORE_CASE;
754eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 				rc = smb_vop_remove(dnode->vp, longname,
755dc20a302Sas200622 				    flags, cr);
756da6c28aaSamw 			}
757da6c28aaSamw 
758da6c28aaSamw 			kmem_free(longname, MAXNAMELEN);
759da6c28aaSamw 		}
760da6c28aaSamw 	}
761da6c28aaSamw 
762da6c28aaSamw 	kmem_free(fname, MAXNAMELEN);
763da6c28aaSamw 	kmem_free(sname, MAXNAMELEN);
764da6c28aaSamw 	return (rc);
765da6c28aaSamw }
766da6c28aaSamw 
767da6c28aaSamw /*
768da6c28aaSamw  * smb_fsop_remove_streams
769da6c28aaSamw  *
770da6c28aaSamw  * This function removes a file's streams without removing the
771da6c28aaSamw  * file itself.
772da6c28aaSamw  *
7737f667e74Sjose borrego  * It is assumed that fnode is not a link.
774da6c28aaSamw  */
775da6c28aaSamw int
776faa1795aSjb150015 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode)
777da6c28aaSamw {
7787f667e74Sjose borrego 	int rc, flags = 0;
7797f667e74Sjose borrego 	uint16_t odid;
7807f667e74Sjose borrego 	smb_odir_t *od;
7817f667e74Sjose borrego 	smb_odirent_t *odirent;
7827f667e74Sjose borrego 	boolean_t eos;
783da6c28aaSamw 
784c8ec8eeaSjose borrego 	ASSERT(sr);
785da6c28aaSamw 	ASSERT(cr);
786da6c28aaSamw 	ASSERT(fnode);
787da6c28aaSamw 	ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
788da6c28aaSamw 	ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
789da6c28aaSamw 
790eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0) {
791eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, EACCES);
792eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
793eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
794da6c28aaSamw 
795eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_IS_READONLY(sr)) {
796eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, EROFS);
797eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
798eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
799da6c28aaSamw 
800c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
801da6c28aaSamw 		flags = SMB_IGNORE_CASE;
802eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
8038b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
8048b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
805da6c28aaSamw 
806eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if ((odid = smb_odir_openat(sr, fnode)) == 0) {
807eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, ENOENT);
808eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
809eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
810eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
811eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) {
812eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, ENOENT);
813eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
814eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
8157f667e74Sjose borrego 
8167f667e74Sjose borrego 	odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
817da6c28aaSamw 	for (;;) {
8187f667e74Sjose borrego 		rc = smb_odir_read(sr, od, odirent, &eos);
8197f667e74Sjose borrego 		if ((rc != 0) || (eos))
820da6c28aaSamw 			break;
8217f667e74Sjose borrego 		(void) smb_vop_remove(od->d_dnode->vp, odirent->od_name,
8227f667e74Sjose borrego 		    flags, cr);
823da6c28aaSamw 	}
8247f667e74Sjose borrego 	kmem_free(odirent, sizeof (smb_odirent_t));
8257f667e74Sjose borrego 
8267f667e74Sjose borrego 	smb_odir_close(od);
827a1511e6bSjoyce mcintosh 	smb_odir_release(od);
828da6c28aaSamw 	return (rc);
829da6c28aaSamw }
830da6c28aaSamw 
831da6c28aaSamw /*
832da6c28aaSamw  * smb_fsop_rmdir
833da6c28aaSamw  *
834da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
835da6c28aaSamw  * the the calls are performed with the appropriate credentials.
836da6c28aaSamw  * Please document any direct call to explain the reason
837da6c28aaSamw  * for avoiding this wrapper.
838da6c28aaSamw  *
839da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
840da6c28aaSamw  */
841da6c28aaSamw int
842da6c28aaSamw smb_fsop_rmdir(
843faa1795aSjb150015     smb_request_t	*sr,
844da6c28aaSamw     cred_t		*cr,
845eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t		*dnode,
846da6c28aaSamw     char		*name,
8478b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States     uint32_t		flags)
848da6c28aaSamw {
849da6c28aaSamw 	int		rc;
850da6c28aaSamw 	char		*longname;
851da6c28aaSamw 
852da6c28aaSamw 	ASSERT(cr);
853da6c28aaSamw 	/*
854da6c28aaSamw 	 * The state of the node could be SMB_NODE_STATE_DESTROYING if this
855da6c28aaSamw 	 * function is called during the deletion of the node (because of
856da6c28aaSamw 	 * DELETE_ON_CLOSE).
857da6c28aaSamw 	 */
858eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
859eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
860da6c28aaSamw 
861eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 ||
862743a77edSAlan Wright 	    SMB_TREE_HAS_ACCESS(sr, ACE_DELETE_CHILD) == 0)
863da6c28aaSamw 		return (EACCES);
864da6c28aaSamw 
865c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
866da6c28aaSamw 		return (EROFS);
867da6c28aaSamw 
868eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_rmdir(dnode->vp, name, flags, cr);
869da6c28aaSamw 
870da6c28aaSamw 	if (rc == ENOENT) {
871da6c28aaSamw 		if (smb_maybe_mangled_name(name) == 0)
872da6c28aaSamw 			return (rc);
873da6c28aaSamw 
874da6c28aaSamw 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
875e3f2c991SKeyur Desai 
876e3f2c991SKeyur Desai 		if (SMB_TREE_SUPPORTS_ABE(sr))
877e3f2c991SKeyur Desai 			flags |= SMB_ABE;
878e3f2c991SKeyur Desai 		rc = smb_unmangle_name(dnode, name, longname,
879e3f2c991SKeyur Desai 		    MAXNAMELEN, flags);
880da6c28aaSamw 
881da6c28aaSamw 		if (rc == 0) {
882da6c28aaSamw 			/*
8838b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			 * longname is the real (case-sensitive)
8848b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			 * on-disk name.
885da6c28aaSamw 			 * We make sure we do a rmdir on this exact
886da6c28aaSamw 			 * name, as the name was mangled and denotes
887da6c28aaSamw 			 * a unique directory.
888da6c28aaSamw 			 */
889da6c28aaSamw 			flags &= ~SMB_IGNORE_CASE;
890eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_vop_rmdir(dnode->vp, longname, flags, cr);
891da6c28aaSamw 		}
892da6c28aaSamw 
893da6c28aaSamw 		kmem_free(longname, MAXNAMELEN);
894da6c28aaSamw 	}
895da6c28aaSamw 
896da6c28aaSamw 	return (rc);
897da6c28aaSamw }
898da6c28aaSamw 
899da6c28aaSamw /*
900da6c28aaSamw  * smb_fsop_getattr
901da6c28aaSamw  *
902da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
903da6c28aaSamw  * the the calls are performed with the appropriate credentials.
904da6c28aaSamw  * Please document any direct call to explain the reason
905da6c28aaSamw  * for avoiding this wrapper.
906da6c28aaSamw  *
907da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
908da6c28aaSamw  */
909da6c28aaSamw int
910faa1795aSjb150015 smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
911da6c28aaSamw     smb_attr_t *attr)
912da6c28aaSamw {
913da6c28aaSamw 	smb_node_t *unnamed_node;
914da6c28aaSamw 	vnode_t *unnamed_vp = NULL;
915da6c28aaSamw 	uint32_t status;
916da6c28aaSamw 	uint32_t access = 0;
917da6c28aaSamw 	int flags = 0;
918dc20a302Sas200622 	int rc;
919da6c28aaSamw 
920da6c28aaSamw 	ASSERT(cr);
921da6c28aaSamw 	ASSERT(snode);
922da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
923da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
924da6c28aaSamw 
925743a77edSAlan Wright 	if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0 ||
926743a77edSAlan Wright 	    SMB_TREE_HAS_ACCESS(sr, ACE_READ_ATTRIBUTES) == 0)
927da6c28aaSamw 		return (EACCES);
928da6c28aaSamw 
929037cac00Sjoyce mcintosh 	/* sr could be NULL in some cases */
930037cac00Sjoyce mcintosh 	if (sr && sr->fid_ofile) {
931da6c28aaSamw 		/* if uid and/or gid is requested */
932da6c28aaSamw 		if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID))
933da6c28aaSamw 			access |= READ_CONTROL;
934da6c28aaSamw 
935da6c28aaSamw 		/* if anything else is also requested */
936da6c28aaSamw 		if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID))
937da6c28aaSamw 			access |= FILE_READ_ATTRIBUTES;
938da6c28aaSamw 
939da6c28aaSamw 		status = smb_ofile_access(sr->fid_ofile, cr, access);
940da6c28aaSamw 		if (status != NT_STATUS_SUCCESS)
941da6c28aaSamw 			return (EACCES);
942da6c28aaSamw 
943c8ec8eeaSjose borrego 		if (smb_tree_has_feature(sr->tid_tree,
944c8ec8eeaSjose borrego 		    SMB_TREE_ACEMASKONACCESS))
945da6c28aaSamw 			flags = ATTR_NOACLCHECK;
946da6c28aaSamw 	}
947da6c28aaSamw 
948da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
949da6c28aaSamw 
950da6c28aaSamw 	if (unnamed_node) {
951da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
952da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
953da6c28aaSamw 		unnamed_vp = unnamed_node->vp;
954da6c28aaSamw 	}
955da6c28aaSamw 
956dc20a302Sas200622 	rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr);
957dc20a302Sas200622 	return (rc);
958da6c28aaSamw }
959da6c28aaSamw 
960da6c28aaSamw /*
961b1352070SAlan Wright  * smb_fsop_link
962b1352070SAlan Wright  *
963b1352070SAlan Wright  * All SMB functions should use this smb_vop_link wrapper to ensure that
964b1352070SAlan Wright  * the smb_vop_link is performed with the appropriate credentials.
965b1352070SAlan Wright  * Please document any direct call to smb_vop_link to explain the reason
966b1352070SAlan Wright  * for avoiding this wrapper.
967b1352070SAlan Wright  *
968b1352070SAlan Wright  * It is assumed that references exist on from_dnode and to_dnode coming
969b1352070SAlan Wright  * into this routine.
970b1352070SAlan Wright  */
971b1352070SAlan Wright int
972*bbf6f00cSJordan Brown smb_fsop_link(smb_request_t *sr, cred_t *cr, smb_node_t *from_fnode,
973*bbf6f00cSJordan Brown     smb_node_t *to_dnode, char *to_name)
974b1352070SAlan Wright {
975b1352070SAlan Wright 	char	*longname = NULL;
976b1352070SAlan Wright 	int	flags = 0;
977b1352070SAlan Wright 	int	rc;
978b1352070SAlan Wright 
979b1352070SAlan Wright 	ASSERT(sr);
980b1352070SAlan Wright 	ASSERT(sr->tid_tree);
981b1352070SAlan Wright 	ASSERT(cr);
982b1352070SAlan Wright 	ASSERT(to_dnode);
983b1352070SAlan Wright 	ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC);
984b1352070SAlan Wright 	ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING);
985b1352070SAlan Wright 	ASSERT(from_fnode);
986b1352070SAlan Wright 	ASSERT(from_fnode->n_magic == SMB_NODE_MAGIC);
987b1352070SAlan Wright 	ASSERT(from_fnode->n_state != SMB_NODE_STATE_DESTROYING);
988b1352070SAlan Wright 
989b1352070SAlan Wright 	if (SMB_TREE_CONTAINS_NODE(sr, from_fnode) == 0)
990b1352070SAlan Wright 		return (EACCES);
991b1352070SAlan Wright 
992b1352070SAlan Wright 	if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0)
993b1352070SAlan Wright 		return (EACCES);
994b1352070SAlan Wright 
995b1352070SAlan Wright 	if (SMB_TREE_IS_READONLY(sr))
996b1352070SAlan Wright 		return (EROFS);
997b1352070SAlan Wright 
998b1352070SAlan Wright 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
999b1352070SAlan Wright 		flags = SMB_IGNORE_CASE;
1000b1352070SAlan Wright 	if (SMB_TREE_SUPPORTS_CATIA(sr))
1001b1352070SAlan Wright 		flags |= SMB_CATIA;
1002e3f2c991SKeyur Desai 	if (SMB_TREE_SUPPORTS_ABE(sr))
1003e3f2c991SKeyur Desai 		flags |= SMB_ABE;
1004b1352070SAlan Wright 
1005b1352070SAlan Wright 	if (smb_maybe_mangled_name(to_name)) {
1006b1352070SAlan Wright 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1007e3f2c991SKeyur Desai 		rc = smb_unmangle_name(to_dnode, to_name,
1008e3f2c991SKeyur Desai 		    longname, MAXNAMELEN, flags);
1009b1352070SAlan Wright 		kmem_free(longname, MAXNAMELEN);
1010b1352070SAlan Wright 
1011b1352070SAlan Wright 		if (rc == 0)
1012b1352070SAlan Wright 			rc = EEXIST;
1013b1352070SAlan Wright 		if (rc != ENOENT)
1014b1352070SAlan Wright 			return (rc);
1015b1352070SAlan Wright 	}
1016b1352070SAlan Wright 
1017b1352070SAlan Wright 	rc = smb_vop_link(to_dnode->vp, from_fnode->vp, to_name, flags, cr);
1018b1352070SAlan Wright 	return (rc);
1019b1352070SAlan Wright }
1020b1352070SAlan Wright 
1021b1352070SAlan Wright /*
1022da6c28aaSamw  * smb_fsop_rename
1023da6c28aaSamw  *
1024da6c28aaSamw  * All SMB functions should use this smb_vop_rename wrapper to ensure that
1025da6c28aaSamw  * the smb_vop_rename is performed with the appropriate credentials.
1026da6c28aaSamw  * Please document any direct call to smb_vop_rename to explain the reason
1027da6c28aaSamw  * for avoiding this wrapper.
1028da6c28aaSamw  *
1029eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * It is assumed that references exist on from_dnode and to_dnode coming
1030da6c28aaSamw  * into this routine.
1031da6c28aaSamw  */
1032da6c28aaSamw int
1033da6c28aaSamw smb_fsop_rename(
1034faa1795aSjb150015     smb_request_t *sr,
1035da6c28aaSamw     cred_t *cr,
1036eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *from_dnode,
1037da6c28aaSamw     char *from_name,
1038eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *to_dnode,
1039da6c28aaSamw     char *to_name)
1040da6c28aaSamw {
1041da6c28aaSamw 	smb_node_t *from_snode;
1042da6c28aaSamw 	vnode_t *from_vp;
10438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	int flags = 0, ret_flags;
1044da6c28aaSamw 	int rc;
1045743a77edSAlan Wright 	boolean_t isdir;
1046da6c28aaSamw 
1047da6c28aaSamw 	ASSERT(cr);
1048eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(from_dnode);
1049eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(from_dnode->n_magic == SMB_NODE_MAGIC);
1050eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(from_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1051da6c28aaSamw 
1052eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(to_dnode);
1053eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC);
1054eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1055da6c28aaSamw 
1056eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, from_dnode) == 0)
1057da6c28aaSamw 		return (EACCES);
1058da6c28aaSamw 
1059eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0)
1060da6c28aaSamw 		return (EACCES);
1061da6c28aaSamw 
1062da6c28aaSamw 	ASSERT(sr);
1063da6c28aaSamw 	ASSERT(sr->tid_tree);
1064c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1065da6c28aaSamw 		return (EROFS);
1066da6c28aaSamw 
1067da6c28aaSamw 	/*
1068c8ec8eeaSjose borrego 	 * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE
1069da6c28aaSamw 	 * here.
1070da6c28aaSamw 	 *
1071da6c28aaSamw 	 * A case-sensitive rename is always done in this routine
1072da6c28aaSamw 	 * because we are using the on-disk name from an earlier lookup.
1073da6c28aaSamw 	 * If a mangled name was passed in by the caller (denoting a
1074da6c28aaSamw 	 * deterministic lookup), then the exact file must be renamed
1075da6c28aaSamw 	 * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or
1076da6c28aaSamw 	 * else the underlying file system might return a "first-match"
1077da6c28aaSamw 	 * on this on-disk name, possibly resulting in the wrong file).
1078da6c28aaSamw 	 */
1079da6c28aaSamw 
10808b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
10818b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
10828b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
1083da6c28aaSamw 	/*
1084da6c28aaSamw 	 * XXX: Lock required through smb_node_release() below?
1085da6c28aaSamw 	 */
1086da6c28aaSamw 
1087eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_lookup(from_dnode->vp, from_name, &from_vp, NULL,
10888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	    flags, &ret_flags, NULL, cr);
1089da6c28aaSamw 
1090da6c28aaSamw 	if (rc != 0)
1091da6c28aaSamw 		return (rc);
1092da6c28aaSamw 
1093743a77edSAlan Wright 	isdir = from_vp->v_type == VDIR;
1094743a77edSAlan Wright 
1095743a77edSAlan Wright 	if ((isdir && SMB_TREE_HAS_ACCESS(sr,
1096743a77edSAlan Wright 	    ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY) !=
1097743a77edSAlan Wright 	    (ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY)) ||
1098743a77edSAlan Wright 	    (!isdir && SMB_TREE_HAS_ACCESS(sr, ACE_DELETE | ACE_ADD_FILE) !=
1099743a77edSAlan Wright 	    (ACE_DELETE | ACE_ADD_FILE)))
1100743a77edSAlan Wright 		return (EACCES);
1101743a77edSAlan Wright 
1102*bbf6f00cSJordan Brown 	/*
1103*bbf6f00cSJordan Brown 	 * SMB checks access on open and retains an access granted
1104*bbf6f00cSJordan Brown 	 * mask for use while the file is open.  ACL changes should
1105*bbf6f00cSJordan Brown 	 * not affect access to an open file.
1106*bbf6f00cSJordan Brown 	 *
1107*bbf6f00cSJordan Brown 	 * If the rename is being performed on an ofile:
1108*bbf6f00cSJordan Brown 	 * - Check the ofile's access granted mask to see if the
1109*bbf6f00cSJordan Brown 	 *   rename is permitted - requires DELETE access.
1110*bbf6f00cSJordan Brown 	 * - If the file system does access checking, set the
1111*bbf6f00cSJordan Brown 	 *   ATTR_NOACLCHECK flag to ensure that the file system
1112*bbf6f00cSJordan Brown 	 *   does not check permissions on subsequent calls.
1113*bbf6f00cSJordan Brown 	 */
1114*bbf6f00cSJordan Brown 	if (sr && sr->fid_ofile) {
1115*bbf6f00cSJordan Brown 		rc = smb_ofile_access(sr->fid_ofile, cr, DELETE);
1116*bbf6f00cSJordan Brown 		if (rc != NT_STATUS_SUCCESS)
1117*bbf6f00cSJordan Brown 			return (EACCES);
1118*bbf6f00cSJordan Brown 
1119*bbf6f00cSJordan Brown 		if (smb_tree_has_feature(sr->tid_tree,
1120*bbf6f00cSJordan Brown 		    SMB_TREE_ACEMASKONACCESS))
1121*bbf6f00cSJordan Brown 			flags = ATTR_NOACLCHECK;
1122*bbf6f00cSJordan Brown 	}
1123*bbf6f00cSJordan Brown 
1124eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_rename(from_dnode->vp, from_name, to_dnode->vp,
1125dc20a302Sas200622 	    to_name, flags, cr);
1126da6c28aaSamw 
1127da6c28aaSamw 	if (rc == 0) {
1128da6c28aaSamw 		from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name,
1129037cac00Sjoyce mcintosh 		    from_dnode, NULL);
1130da6c28aaSamw 
1131da6c28aaSamw 		if (from_snode == NULL) {
11327f667e74Sjose borrego 			rc = ENOMEM;
1133da6c28aaSamw 		} else {
1134eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_node_rename(from_dnode, from_snode,
1135eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			    to_dnode, to_name);
11367f667e74Sjose borrego 			smb_node_release(from_snode);
1137da6c28aaSamw 		}
11387f667e74Sjose borrego 	}
11397f667e74Sjose borrego 	VN_RELE(from_vp);
1140da6c28aaSamw 
1141da6c28aaSamw 	/* XXX: unlock */
1142da6c28aaSamw 
1143da6c28aaSamw 	return (rc);
1144da6c28aaSamw }
1145da6c28aaSamw 
1146da6c28aaSamw /*
1147da6c28aaSamw  * smb_fsop_setattr
1148da6c28aaSamw  *
1149da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
1150da6c28aaSamw  * the the calls are performed with the appropriate credentials.
1151da6c28aaSamw  * Please document any direct call to explain the reason
1152da6c28aaSamw  * for avoiding this wrapper.
1153da6c28aaSamw  *
1154e3f2c991SKeyur Desai  * It is assumed that a reference exists on snode coming into
1155e3f2c991SKeyur Desai  * this function.
1156da6c28aaSamw  * A null smb_request might be passed to this function.
1157da6c28aaSamw  */
1158da6c28aaSamw int
1159da6c28aaSamw smb_fsop_setattr(
1160da6c28aaSamw     smb_request_t	*sr,
1161da6c28aaSamw     cred_t		*cr,
1162da6c28aaSamw     smb_node_t		*snode,
1163037cac00Sjoyce mcintosh     smb_attr_t		*set_attr)
1164da6c28aaSamw {
1165da6c28aaSamw 	smb_node_t *unnamed_node;
1166da6c28aaSamw 	vnode_t *unnamed_vp = NULL;
1167da6c28aaSamw 	uint32_t status;
11682c1b14e5Sjose borrego 	uint32_t access;
1169da6c28aaSamw 	int rc = 0;
1170da6c28aaSamw 	int flags = 0;
11712c1b14e5Sjose borrego 	uint_t sa_mask;
1172da6c28aaSamw 
1173da6c28aaSamw 	ASSERT(cr);
1174da6c28aaSamw 	ASSERT(snode);
1175da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1176da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1177da6c28aaSamw 
1178c8ec8eeaSjose borrego 	if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0)
1179da6c28aaSamw 		return (EACCES);
1180da6c28aaSamw 
1181c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1182da6c28aaSamw 		return (EROFS);
1183da6c28aaSamw 
1184743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr,
1185743a77edSAlan Wright 	    ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0)
1186743a77edSAlan Wright 		return (EACCES);
1187743a77edSAlan Wright 
1188e3f2c991SKeyur Desai 	/*
1189e3f2c991SKeyur Desai 	 * The file system cannot detect pending READDONLY
1190e3f2c991SKeyur Desai 	 * (i.e. if the file has been opened readonly but
1191e3f2c991SKeyur Desai 	 * not yet closed) so we need to test READONLY here.
1192e3f2c991SKeyur Desai 	 */
1193c8ec8eeaSjose borrego 	if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) {
1194c8ec8eeaSjose borrego 		if (sr->fid_ofile) {
1195c8ec8eeaSjose borrego 			if (SMB_OFILE_IS_READONLY(sr->fid_ofile))
1196c8ec8eeaSjose borrego 				return (EACCES);
1197c8ec8eeaSjose borrego 		} else {
1198c8ec8eeaSjose borrego 			if (SMB_PATHFILE_IS_READONLY(sr, snode))
1199c8ec8eeaSjose borrego 				return (EACCES);
1200c8ec8eeaSjose borrego 		}
1201c8ec8eeaSjose borrego 	}
1202c8ec8eeaSjose borrego 
1203e3f2c991SKeyur Desai 	/*
1204e3f2c991SKeyur Desai 	 * SMB checks access on open and retains an access granted
1205e3f2c991SKeyur Desai 	 * mask for use while the file is open.  ACL changes should
1206e3f2c991SKeyur Desai 	 * not affect access to an open file.
1207e3f2c991SKeyur Desai 	 *
1208e3f2c991SKeyur Desai 	 * If the setattr is being performed on an ofile:
1209e3f2c991SKeyur Desai 	 * - Check the ofile's access granted mask to see if the
1210e3f2c991SKeyur Desai 	 *   setattr is permitted.
1211e3f2c991SKeyur Desai 	 *   UID, GID - require WRITE_OWNER
1212e3f2c991SKeyur Desai 	 *   SIZE, ALLOCSZ - require FILE_WRITE_DATA
1213e3f2c991SKeyur Desai 	 *   all other attributes require FILE_WRITE_ATTRIBUTES
1214e3f2c991SKeyur Desai 	 *
1215e3f2c991SKeyur Desai 	 * - If the file system does access checking, set the
1216e3f2c991SKeyur Desai 	 *   ATTR_NOACLCHECK flag to ensure that the file system
1217e3f2c991SKeyur Desai 	 *   does not check permissions on subsequent calls.
1218e3f2c991SKeyur Desai 	 */
1219da6c28aaSamw 	if (sr && sr->fid_ofile) {
12202c1b14e5Sjose borrego 		sa_mask = set_attr->sa_mask;
12212c1b14e5Sjose borrego 		access = 0;
1222c8ec8eeaSjose borrego 
1223e3f2c991SKeyur Desai 		if (sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ)) {
12242c1b14e5Sjose borrego 			access |= FILE_WRITE_DATA;
1225e3f2c991SKeyur Desai 			sa_mask &= ~(SMB_AT_SIZE | SMB_AT_ALLOCSZ);
12262c1b14e5Sjose borrego 		}
12272c1b14e5Sjose borrego 
12282c1b14e5Sjose borrego 		if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) {
1229da6c28aaSamw 			access |= WRITE_OWNER;
12302c1b14e5Sjose borrego 			sa_mask &= ~(SMB_AT_UID|SMB_AT_GID);
12312c1b14e5Sjose borrego 		}
1232da6c28aaSamw 
12332c1b14e5Sjose borrego 		if (sa_mask)
1234da6c28aaSamw 			access |= FILE_WRITE_ATTRIBUTES;
1235da6c28aaSamw 
1236da6c28aaSamw 		status = smb_ofile_access(sr->fid_ofile, cr, access);
1237da6c28aaSamw 		if (status != NT_STATUS_SUCCESS)
1238da6c28aaSamw 			return (EACCES);
1239da6c28aaSamw 
1240c8ec8eeaSjose borrego 		if (smb_tree_has_feature(sr->tid_tree,
1241c8ec8eeaSjose borrego 		    SMB_TREE_ACEMASKONACCESS))
1242da6c28aaSamw 			flags = ATTR_NOACLCHECK;
1243da6c28aaSamw 	}
1244da6c28aaSamw 
1245da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1246da6c28aaSamw 
1247da6c28aaSamw 	if (unnamed_node) {
1248da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1249da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1250da6c28aaSamw 		unnamed_vp = unnamed_node->vp;
1251da6c28aaSamw 	}
1252da6c28aaSamw 
12539660e5cbSJanice Chang 	rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr);
1254da6c28aaSamw 	return (rc);
1255da6c28aaSamw }
1256da6c28aaSamw 
1257da6c28aaSamw /*
1258da6c28aaSamw  * smb_fsop_read
1259da6c28aaSamw  *
1260da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
1261da6c28aaSamw  * the the calls are performed with the appropriate credentials.
1262da6c28aaSamw  * Please document any direct call to explain the reason
1263da6c28aaSamw  * for avoiding this wrapper.
1264da6c28aaSamw  *
1265da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
1266da6c28aaSamw  */
1267da6c28aaSamw int
1268037cac00Sjoyce mcintosh smb_fsop_read(smb_request_t *sr, cred_t *cr, smb_node_t *snode, uio_t *uio)
1269da6c28aaSamw {
1270c8ec8eeaSjose borrego 	caller_context_t ct;
1271dc20a302Sas200622 	int svmand;
1272da6c28aaSamw 	int rc;
1273da6c28aaSamw 
1274da6c28aaSamw 	ASSERT(cr);
1275da6c28aaSamw 	ASSERT(snode);
1276da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1277da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1278da6c28aaSamw 
1279da6c28aaSamw 	ASSERT(sr);
1280da6c28aaSamw 	ASSERT(sr->fid_ofile);
1281da6c28aaSamw 
1282743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_DATA) == 0)
1283743a77edSAlan Wright 		return (EACCES);
1284743a77edSAlan Wright 
1285da6c28aaSamw 	rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA);
1286da6c28aaSamw 	if (rc != NT_STATUS_SUCCESS) {
1287da6c28aaSamw 		rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE);
1288da6c28aaSamw 		if (rc != NT_STATUS_SUCCESS)
1289da6c28aaSamw 			return (EACCES);
1290da6c28aaSamw 	}
1291da6c28aaSamw 
1292da6c28aaSamw 	/*
1293da6c28aaSamw 	 * Streams permission are checked against the unnamed stream,
1294da6c28aaSamw 	 * but in FS level they have their own permissions. To avoid
1295da6c28aaSamw 	 * rejection by FS due to lack of permission on the actual
1296da6c28aaSamw 	 * extended attr kcred is passed for streams.
1297da6c28aaSamw 	 */
1298037cac00Sjoyce mcintosh 	if (SMB_IS_STREAM(snode))
1299da6c28aaSamw 		cr = kcred;
1300da6c28aaSamw 
1301dc20a302Sas200622 	smb_node_start_crit(snode, RW_READER);
1302c8ec8eeaSjose borrego 	rc = nbl_svmand(snode->vp, kcred, &svmand);
1303dc20a302Sas200622 	if (rc) {
1304dc20a302Sas200622 		smb_node_end_crit(snode);
1305dc20a302Sas200622 		return (rc);
1306dc20a302Sas200622 	}
1307da6c28aaSamw 
1308c8ec8eeaSjose borrego 	ct = smb_ct;
1309c8ec8eeaSjose borrego 	ct.cc_pid = sr->fid_ofile->f_uniqid;
1310dc20a302Sas200622 	rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset,
1311c8ec8eeaSjose borrego 	    uio->uio_iov->iov_len, svmand, &ct);
1312dc20a302Sas200622 
1313dc20a302Sas200622 	if (rc) {
1314dc20a302Sas200622 		smb_node_end_crit(snode);
13156537f381Sas200622 		return (ERANGE);
1316dc20a302Sas200622 	}
1317037cac00Sjoyce mcintosh 
1318dc20a302Sas200622 	rc = smb_vop_read(snode->vp, uio, cr);
1319dc20a302Sas200622 	smb_node_end_crit(snode);
1320da6c28aaSamw 
1321da6c28aaSamw 	return (rc);
1322da6c28aaSamw }
1323da6c28aaSamw 
1324da6c28aaSamw /*
1325da6c28aaSamw  * smb_fsop_write
1326da6c28aaSamw  *
1327da6c28aaSamw  * This is a wrapper function used for smb_write and smb_write_raw operations.
1328da6c28aaSamw  *
1329da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
1330da6c28aaSamw  */
1331da6c28aaSamw int
1332da6c28aaSamw smb_fsop_write(
1333faa1795aSjb150015     smb_request_t *sr,
1334da6c28aaSamw     cred_t *cr,
1335da6c28aaSamw     smb_node_t *snode,
1336da6c28aaSamw     uio_t *uio,
1337da6c28aaSamw     uint32_t *lcount,
13383db3f65cSamw     int ioflag)
1339da6c28aaSamw {
1340c8ec8eeaSjose borrego 	caller_context_t ct;
1341dc20a302Sas200622 	int svmand;
1342da6c28aaSamw 	int rc;
1343da6c28aaSamw 
1344da6c28aaSamw 	ASSERT(cr);
1345da6c28aaSamw 	ASSERT(snode);
1346da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1347da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1348da6c28aaSamw 
1349da6c28aaSamw 	ASSERT(sr);
1350da6c28aaSamw 	ASSERT(sr->tid_tree);
1351da6c28aaSamw 	ASSERT(sr->fid_ofile);
1352da6c28aaSamw 
1353c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1354da6c28aaSamw 		return (EROFS);
1355dc20a302Sas200622 
1356743a77edSAlan Wright 	if (SMB_OFILE_IS_READONLY(sr->fid_ofile) ||
1357743a77edSAlan Wright 	    SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_DATA | ACE_APPEND_DATA) == 0)
1358c8ec8eeaSjose borrego 		return (EACCES);
1359c8ec8eeaSjose borrego 
1360da6c28aaSamw 	rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA);
1361dc20a302Sas200622 	if (rc != NT_STATUS_SUCCESS) {
1362dc20a302Sas200622 		rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA);
1363da6c28aaSamw 		if (rc != NT_STATUS_SUCCESS)
1364da6c28aaSamw 			return (EACCES);
1365dc20a302Sas200622 	}
1366da6c28aaSamw 
1367da6c28aaSamw 	/*
1368da6c28aaSamw 	 * Streams permission are checked against the unnamed stream,
1369da6c28aaSamw 	 * but in FS level they have their own permissions. To avoid
1370da6c28aaSamw 	 * rejection by FS due to lack of permission on the actual
1371da6c28aaSamw 	 * extended attr kcred is passed for streams.
1372da6c28aaSamw 	 */
1373037cac00Sjoyce mcintosh 	if (SMB_IS_STREAM(snode))
1374da6c28aaSamw 		cr = kcred;
1375da6c28aaSamw 
1376dc20a302Sas200622 	smb_node_start_crit(snode, RW_READER);
1377c8ec8eeaSjose borrego 	rc = nbl_svmand(snode->vp, kcred, &svmand);
1378dc20a302Sas200622 	if (rc) {
1379dc20a302Sas200622 		smb_node_end_crit(snode);
1380dc20a302Sas200622 		return (rc);
1381dc20a302Sas200622 	}
1382c8ec8eeaSjose borrego 
1383c8ec8eeaSjose borrego 	ct = smb_ct;
1384c8ec8eeaSjose borrego 	ct.cc_pid = sr->fid_ofile->f_uniqid;
1385dc20a302Sas200622 	rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset,
1386c8ec8eeaSjose borrego 	    uio->uio_iov->iov_len, svmand, &ct);
1387da6c28aaSamw 
1388dc20a302Sas200622 	if (rc) {
1389dc20a302Sas200622 		smb_node_end_crit(snode);
13906537f381Sas200622 		return (ERANGE);
1391dc20a302Sas200622 	}
1392037cac00Sjoyce mcintosh 
13933db3f65cSamw 	rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr);
1394dc20a302Sas200622 	smb_node_end_crit(snode);
1395da6c28aaSamw 
1396da6c28aaSamw 	return (rc);
1397da6c28aaSamw }
1398da6c28aaSamw 
1399da6c28aaSamw /*
1400da6c28aaSamw  * smb_fsop_statfs
1401da6c28aaSamw  *
1402da6c28aaSamw  * This is a wrapper function used for stat operations.
1403da6c28aaSamw  */
1404da6c28aaSamw int
1405da6c28aaSamw smb_fsop_statfs(
1406da6c28aaSamw     cred_t *cr,
1407da6c28aaSamw     smb_node_t *snode,
1408da6c28aaSamw     struct statvfs64 *statp)
1409da6c28aaSamw {
1410da6c28aaSamw 	ASSERT(cr);
1411da6c28aaSamw 	ASSERT(snode);
1412da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1413da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1414da6c28aaSamw 
1415da6c28aaSamw 	return (smb_vop_statfs(snode->vp, statp, cr));
1416da6c28aaSamw }
1417da6c28aaSamw 
1418da6c28aaSamw /*
1419da6c28aaSamw  * smb_fsop_access
1420ee60c47bSjm199354  *
1421ee60c47bSjm199354  * Named streams do not have separate permissions from the associated
1422ee60c47bSjm199354  * unnamed stream.  Thus, if node is a named stream, the permissions
1423ee60c47bSjm199354  * check will be performed on the associated unnamed stream.
1424ee60c47bSjm199354  *
1425ee60c47bSjm199354  * However, our named streams do have their own quarantine attribute,
1426ee60c47bSjm199354  * separate from that on the unnamed stream. If READ or EXECUTE
1427ee60c47bSjm199354  * access has been requested on a named stream, an additional access
1428ee60c47bSjm199354  * check is performed on the named stream in case it has been
1429ee60c47bSjm199354  * quarantined.  kcred is used to avoid issues with the permissions
1430ee60c47bSjm199354  * set on the extended attribute file representing the named stream.
1431da6c28aaSamw  */
1432da6c28aaSamw int
1433da6c28aaSamw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1434da6c28aaSamw     uint32_t faccess)
1435da6c28aaSamw {
1436da6c28aaSamw 	int access = 0;
1437da6c28aaSamw 	int error;
1438da6c28aaSamw 	vnode_t *dir_vp;
1439da6c28aaSamw 	boolean_t acl_check = B_TRUE;
1440da6c28aaSamw 	smb_node_t *unnamed_node;
1441da6c28aaSamw 
1442c8ec8eeaSjose borrego 	ASSERT(sr);
1443da6c28aaSamw 	ASSERT(cr);
1444da6c28aaSamw 	ASSERT(snode);
1445da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1446da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1447da6c28aaSamw 
1448da6c28aaSamw 	if (faccess == 0)
1449da6c28aaSamw 		return (NT_STATUS_SUCCESS);
1450da6c28aaSamw 
1451c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr)) {
1452da6c28aaSamw 		if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA|
1453da6c28aaSamw 		    FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES|
1454da6c28aaSamw 		    DELETE|WRITE_DAC|WRITE_OWNER)) {
1455da6c28aaSamw 			return (NT_STATUS_ACCESS_DENIED);
1456da6c28aaSamw 		}
1457da6c28aaSamw 	}
1458da6c28aaSamw 
1459da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1460da6c28aaSamw 	if (unnamed_node) {
1461da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1462da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1463ee60c47bSjm199354 
1464ee60c47bSjm199354 		/*
1465ee60c47bSjm199354 		 * Perform VREAD access check on the named stream in case it
1466ee60c47bSjm199354 		 * is quarantined. kcred is passed to smb_vop_access so it
1467ee60c47bSjm199354 		 * doesn't fail due to lack of permission.
1468ee60c47bSjm199354 		 */
1469ee60c47bSjm199354 		if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) {
1470ee60c47bSjm199354 			error = smb_vop_access(snode->vp, VREAD,
1471ee60c47bSjm199354 			    0, NULL, kcred);
1472ee60c47bSjm199354 			if (error)
1473ee60c47bSjm199354 				return (NT_STATUS_ACCESS_DENIED);
1474ee60c47bSjm199354 		}
1475ee60c47bSjm199354 
1476da6c28aaSamw 		/*
1477da6c28aaSamw 		 * Streams authorization should be performed against the
1478da6c28aaSamw 		 * unnamed stream.
1479da6c28aaSamw 		 */
1480da6c28aaSamw 		snode = unnamed_node;
1481da6c28aaSamw 	}
1482da6c28aaSamw 
1483da6c28aaSamw 	if (faccess & ACCESS_SYSTEM_SECURITY) {
1484da6c28aaSamw 		/*
1485da6c28aaSamw 		 * This permission is required for reading/writing SACL and
1486da6c28aaSamw 		 * it's not part of DACL. It's only granted via proper
1487da6c28aaSamw 		 * privileges.
1488da6c28aaSamw 		 */
1489da6c28aaSamw 		if ((sr->uid_user->u_privileges &
1490da6c28aaSamw 		    (SMB_USER_PRIV_BACKUP |
1491da6c28aaSamw 		    SMB_USER_PRIV_RESTORE |
1492da6c28aaSamw 		    SMB_USER_PRIV_SECURITY)) == 0)
1493da6c28aaSamw 			return (NT_STATUS_PRIVILEGE_NOT_HELD);
1494da6c28aaSamw 
1495da6c28aaSamw 		faccess &= ~ACCESS_SYSTEM_SECURITY;
1496da6c28aaSamw 	}
1497da6c28aaSamw 
1498da6c28aaSamw 	/* Links don't have ACL */
1499c8ec8eeaSjose borrego 	if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) ||
1500037cac00Sjoyce mcintosh 	    smb_node_is_link(snode))
1501da6c28aaSamw 		acl_check = B_FALSE;
1502da6c28aaSamw 
1503743a77edSAlan Wright 	/*
1504743a77edSAlan Wright 	 * Use the most restrictive parts of both faccess and the
1505743a77edSAlan Wright 	 * share access.  An AND of the two value masks gives us that
1506743a77edSAlan Wright 	 * since we've already converted to a mask of what we "can"
1507743a77edSAlan Wright 	 * do.
1508743a77edSAlan Wright 	 */
1509743a77edSAlan Wright 	faccess &= sr->tid_tree->t_access;
1510743a77edSAlan Wright 
1511da6c28aaSamw 	if (acl_check) {
15121fcced4cSJordan Brown 		dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
1513da6c28aaSamw 		error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp,
1514da6c28aaSamw 		    cr);
1515da6c28aaSamw 	} else {
1516da6c28aaSamw 		/*
1517da6c28aaSamw 		 * FS doesn't understand 32-bit mask, need to map
1518da6c28aaSamw 		 */
1519da6c28aaSamw 		if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))
1520da6c28aaSamw 			access |= VWRITE;
1521da6c28aaSamw 
1522da6c28aaSamw 		if (faccess & FILE_READ_DATA)
1523da6c28aaSamw 			access |= VREAD;
1524da6c28aaSamw 
1525da6c28aaSamw 		if (faccess & FILE_EXECUTE)
1526da6c28aaSamw 			access |= VEXEC;
1527da6c28aaSamw 
1528da6c28aaSamw 		error = smb_vop_access(snode->vp, access, 0, NULL, cr);
1529da6c28aaSamw 	}
1530da6c28aaSamw 
1531da6c28aaSamw 	return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS);
1532da6c28aaSamw }
1533da6c28aaSamw 
1534da6c28aaSamw /*
1535da6c28aaSamw  * smb_fsop_lookup_name()
1536da6c28aaSamw  *
1537b89a8333Snatalie li - Sun Microsystems - Irvine United States  * If name indicates that the file is a stream file, perform
1538b89a8333Snatalie li - Sun Microsystems - Irvine United States  * stream specific lookup, otherwise call smb_fsop_lookup.
1539da6c28aaSamw  *
1540b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Return an error if the looked-up file is in outside the tree.
1541b89a8333Snatalie li - Sun Microsystems - Irvine United States  * (Required when invoked from open path.)
1542da6c28aaSamw  */
1543da6c28aaSamw 
1544da6c28aaSamw int
1545da6c28aaSamw smb_fsop_lookup_name(
1546faa1795aSjb150015     smb_request_t *sr,
1547da6c28aaSamw     cred_t	*cr,
1548da6c28aaSamw     int		flags,
1549da6c28aaSamw     smb_node_t	*root_node,
1550eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t	*dnode,
1551da6c28aaSamw     char	*name,
1552037cac00Sjoyce mcintosh     smb_node_t	**ret_snode)
1553da6c28aaSamw {
1554da6c28aaSamw 	smb_node_t	*fnode;
1555da6c28aaSamw 	vnode_t		*xattrdirvp;
1556da6c28aaSamw 	vnode_t		*vp;
1557da6c28aaSamw 	char		*od_name;
1558da6c28aaSamw 	char		*fname;
1559da6c28aaSamw 	char		*sname;
1560da6c28aaSamw 	int		rc;
1561da6c28aaSamw 
1562da6c28aaSamw 	ASSERT(cr);
1563eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
1564eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
1565eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
1566da6c28aaSamw 
1567da6c28aaSamw 	/*
1568da6c28aaSamw 	 * The following check is required for streams processing, below
1569da6c28aaSamw 	 */
1570da6c28aaSamw 
1571c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1572da6c28aaSamw 		flags |= SMB_IGNORE_CASE;
1573da6c28aaSamw 
1574da6c28aaSamw 	fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1575da6c28aaSamw 	sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1576da6c28aaSamw 
1577eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_is_stream_name(name)) {
1578eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_stream_parse_name(name, fname, sname);
15798d7e4166Sjose borrego 
1580da6c28aaSamw 		/*
1581da6c28aaSamw 		 * Look up the unnamed stream (i.e. fname).
1582da6c28aaSamw 		 * Unmangle processing will be done on fname
1583da6c28aaSamw 		 * as well as any link target.
1584da6c28aaSamw 		 */
1585037cac00Sjoyce mcintosh 		rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode,
1586037cac00Sjoyce mcintosh 		    fname, &fnode);
1587da6c28aaSamw 
1588da6c28aaSamw 		if (rc != 0) {
1589da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
1590da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
1591da6c28aaSamw 			return (rc);
1592da6c28aaSamw 		}
1593da6c28aaSamw 
1594da6c28aaSamw 		od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1595da6c28aaSamw 
1596da6c28aaSamw 		/*
1597da6c28aaSamw 		 * od_name is the on-disk name of the stream, except
1598da6c28aaSamw 		 * without the prepended stream prefix (SMB_STREAM_PREFIX)
1599da6c28aaSamw 		 */
1600da6c28aaSamw 
1601da6c28aaSamw 		/*
1602da6c28aaSamw 		 * XXX
1603da6c28aaSamw 		 * What permissions NTFS requires for stream lookup if any?
1604da6c28aaSamw 		 */
1605da6c28aaSamw 		rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name,
1606dc20a302Sas200622 		    &xattrdirvp, flags, root_node->vp, cr);
1607da6c28aaSamw 
1608da6c28aaSamw 		if (rc != 0) {
1609da6c28aaSamw 			smb_node_release(fnode);
1610da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
1611da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
1612da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1613da6c28aaSamw 			return (rc);
1614da6c28aaSamw 		}
1615da6c28aaSamw 
1616da6c28aaSamw 		*ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
1617037cac00Sjoyce mcintosh 		    vp, od_name);
1618da6c28aaSamw 
1619da6c28aaSamw 		kmem_free(od_name, MAXNAMELEN);
1620da6c28aaSamw 		smb_node_release(fnode);
1621da6c28aaSamw 		VN_RELE(xattrdirvp);
1622da6c28aaSamw 		VN_RELE(vp);
16237f667e74Sjose borrego 
16247f667e74Sjose borrego 		if (*ret_snode == NULL) {
1625da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
1626da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
1627da6c28aaSamw 			return (ENOMEM);
1628da6c28aaSamw 		}
1629da6c28aaSamw 	} else {
1630eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, name,
1631037cac00Sjoyce mcintosh 		    ret_snode);
1632da6c28aaSamw 	}
1633da6c28aaSamw 
1634da6c28aaSamw 	if (rc == 0) {
1635da6c28aaSamw 		ASSERT(ret_snode);
1636c8ec8eeaSjose borrego 		if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) {
1637da6c28aaSamw 			smb_node_release(*ret_snode);
1638da6c28aaSamw 			*ret_snode = NULL;
1639da6c28aaSamw 			rc = EACCES;
1640da6c28aaSamw 		}
1641da6c28aaSamw 	}
1642da6c28aaSamw 
1643da6c28aaSamw 	kmem_free(fname, MAXNAMELEN);
1644da6c28aaSamw 	kmem_free(sname, MAXNAMELEN);
1645da6c28aaSamw 
1646da6c28aaSamw 	return (rc);
1647da6c28aaSamw }
1648da6c28aaSamw 
1649da6c28aaSamw /*
1650da6c28aaSamw  * smb_fsop_lookup
1651da6c28aaSamw  *
1652da6c28aaSamw  * All SMB functions should use this smb_vop_lookup wrapper to ensure that
1653da6c28aaSamw  * the smb_vop_lookup is performed with the appropriate credentials and using
1654da6c28aaSamw  * case insensitive compares. Please document any direct call to smb_vop_lookup
1655da6c28aaSamw  * to explain the reason for avoiding this wrapper.
1656da6c28aaSamw  *
1657eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * It is assumed that a reference exists on dnode coming into this routine
1658da6c28aaSamw  * (and that it is safe from deallocation).
1659da6c28aaSamw  *
1660da6c28aaSamw  * Same with the root_node.
1661da6c28aaSamw  *
1662da6c28aaSamw  * *ret_snode is returned with a reference upon success.  No reference is
1663da6c28aaSamw  * taken if an error is returned.
1664da6c28aaSamw  *
1665da6c28aaSamw  * Note: The returned ret_snode may be in a child mount.  This is ok for
16667f667e74Sjose borrego  * readdir.
1667da6c28aaSamw  *
1668c8ec8eeaSjose borrego  * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent
1669da6c28aaSamw  * operations on files not in the parent mount.
1670*bbf6f00cSJordan Brown  *
1671*bbf6f00cSJordan Brown  * Case sensitivity flags (SMB_IGNORE_CASE, SMB_CASE_SENSITIVE):
1672*bbf6f00cSJordan Brown  * if SMB_CASE_SENSITIVE is set, the SMB_IGNORE_CASE flag will NOT be set
1673*bbf6f00cSJordan Brown  * based on the tree's case sensitivity. However, if the SMB_IGNORE_CASE
1674*bbf6f00cSJordan Brown  * flag is set in the flags value passed as a parameter, a case insensitive
1675*bbf6f00cSJordan Brown  * lookup WILL be done (regardless of whether SMB_CASE_SENSITIVE is set
1676*bbf6f00cSJordan Brown  * or not).
1677da6c28aaSamw  */
1678da6c28aaSamw int
1679da6c28aaSamw smb_fsop_lookup(
1680faa1795aSjb150015     smb_request_t *sr,
1681da6c28aaSamw     cred_t	*cr,
1682da6c28aaSamw     int		flags,
1683da6c28aaSamw     smb_node_t	*root_node,
1684eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t	*dnode,
1685da6c28aaSamw     char	*name,
1686037cac00Sjoyce mcintosh     smb_node_t	**ret_snode)
1687da6c28aaSamw {
1688da6c28aaSamw 	smb_node_t *lnk_target_node;
1689da6c28aaSamw 	smb_node_t *lnk_dnode;
1690da6c28aaSamw 	char *longname;
1691da6c28aaSamw 	char *od_name;
1692da6c28aaSamw 	vnode_t *vp;
1693da6c28aaSamw 	int rc;
16948b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	int ret_flags;
1695da6c28aaSamw 
1696da6c28aaSamw 	ASSERT(cr);
1697eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
1698eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
1699eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
1700da6c28aaSamw 
1701da6c28aaSamw 	if (name == NULL)
1702da6c28aaSamw 		return (EINVAL);
1703da6c28aaSamw 
1704eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
1705da6c28aaSamw 		return (EACCES);
1706da6c28aaSamw 
1707*bbf6f00cSJordan Brown 	if (!(flags & SMB_CASE_SENSITIVE)) {
1708c8ec8eeaSjose borrego 		if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1709da6c28aaSamw 			flags |= SMB_IGNORE_CASE;
1710*bbf6f00cSJordan Brown 	}
17118b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
17128b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
1713e3f2c991SKeyur Desai 	if (SMB_TREE_SUPPORTS_ABE(sr))
1714e3f2c991SKeyur Desai 		flags |= SMB_ABE;
1715da6c28aaSamw 
1716da6c28aaSamw 	od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1717da6c28aaSamw 
1718eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_lookup(dnode->vp, name, &vp, od_name, flags,
17198b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	    &ret_flags, root_node ? root_node->vp : NULL, cr);
1720da6c28aaSamw 
1721da6c28aaSamw 	if (rc != 0) {
1722da6c28aaSamw 		if (smb_maybe_mangled_name(name) == 0) {
1723da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1724da6c28aaSamw 			return (rc);
1725da6c28aaSamw 		}
1726da6c28aaSamw 
1727da6c28aaSamw 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1728e3f2c991SKeyur Desai 		rc = smb_unmangle_name(dnode, name, longname,
1729e3f2c991SKeyur Desai 		    MAXNAMELEN, flags);
1730da6c28aaSamw 		if (rc != 0) {
1731da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1732da6c28aaSamw 			kmem_free(longname, MAXNAMELEN);
1733da6c28aaSamw 			return (rc);
1734da6c28aaSamw 		}
1735da6c28aaSamw 
1736da6c28aaSamw 		/*
17378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * longname is the real (case-sensitive)
17388b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * on-disk name.
1739da6c28aaSamw 		 * We make sure we do a lookup on this exact
1740da6c28aaSamw 		 * name, as the name was mangled and denotes
1741da6c28aaSamw 		 * a unique file.
1742da6c28aaSamw 		 */
1743da6c28aaSamw 
1744da6c28aaSamw 		if (flags & SMB_IGNORE_CASE)
1745da6c28aaSamw 			flags &= ~SMB_IGNORE_CASE;
1746da6c28aaSamw 
1747eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_lookup(dnode->vp, longname, &vp, od_name,
17488b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    flags, &ret_flags, root_node ? root_node->vp : NULL, cr);
1749da6c28aaSamw 
1750da6c28aaSamw 		kmem_free(longname, MAXNAMELEN);
1751da6c28aaSamw 
1752da6c28aaSamw 		if (rc != 0) {
1753da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1754da6c28aaSamw 			return (rc);
1755da6c28aaSamw 		}
1756da6c28aaSamw 	}
1757da6c28aaSamw 
1758da6c28aaSamw 	if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) {
1759da6c28aaSamw 
1760eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_pathname(sr, od_name, FOLLOW, root_node, dnode,
1761da6c28aaSamw 		    &lnk_dnode, &lnk_target_node, cr);
1762da6c28aaSamw 
1763da6c28aaSamw 		if (rc != 0) {
1764da6c28aaSamw 			/*
1765da6c28aaSamw 			 * The link is assumed to be for the last component
1766da6c28aaSamw 			 * of a path.  Hence any ENOTDIR error will be returned
1767da6c28aaSamw 			 * as ENOENT.
1768da6c28aaSamw 			 */
1769da6c28aaSamw 			if (rc == ENOTDIR)
1770da6c28aaSamw 				rc = ENOENT;
1771da6c28aaSamw 
1772da6c28aaSamw 			VN_RELE(vp);
1773da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1774da6c28aaSamw 			return (rc);
1775da6c28aaSamw 		}
1776da6c28aaSamw 
1777da6c28aaSamw 		/*
1778da6c28aaSamw 		 * Release the original VLNK vnode
1779da6c28aaSamw 		 */
1780da6c28aaSamw 
1781da6c28aaSamw 		VN_RELE(vp);
1782da6c28aaSamw 		vp = lnk_target_node->vp;
1783da6c28aaSamw 
1784da6c28aaSamw 		rc = smb_vop_traverse_check(&vp);
1785da6c28aaSamw 
1786da6c28aaSamw 		if (rc != 0) {
1787da6c28aaSamw 			smb_node_release(lnk_dnode);
1788da6c28aaSamw 			smb_node_release(lnk_target_node);
1789da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1790da6c28aaSamw 			return (rc);
1791da6c28aaSamw 		}
1792da6c28aaSamw 
1793da6c28aaSamw 		/*
1794da6c28aaSamw 		 * smb_vop_traverse_check() may have returned a different vnode
1795da6c28aaSamw 		 */
1796da6c28aaSamw 
1797da6c28aaSamw 		if (lnk_target_node->vp == vp) {
1798da6c28aaSamw 			*ret_snode = lnk_target_node;
1799da6c28aaSamw 		} else {
1800da6c28aaSamw 			*ret_snode = smb_node_lookup(sr, NULL, cr, vp,
1801037cac00Sjoyce mcintosh 			    lnk_target_node->od_name, lnk_dnode, NULL);
1802da6c28aaSamw 			VN_RELE(vp);
18037f667e74Sjose borrego 
18047f667e74Sjose borrego 			if (*ret_snode == NULL)
1805da6c28aaSamw 				rc = ENOMEM;
1806da6c28aaSamw 			smb_node_release(lnk_target_node);
1807da6c28aaSamw 		}
1808da6c28aaSamw 
1809da6c28aaSamw 		smb_node_release(lnk_dnode);
1810da6c28aaSamw 
1811da6c28aaSamw 	} else {
1812da6c28aaSamw 
1813da6c28aaSamw 		rc = smb_vop_traverse_check(&vp);
1814da6c28aaSamw 		if (rc) {
1815da6c28aaSamw 			VN_RELE(vp);
1816da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1817da6c28aaSamw 			return (rc);
1818da6c28aaSamw 		}
1819da6c28aaSamw 
1820da6c28aaSamw 		*ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name,
1821037cac00Sjoyce mcintosh 		    dnode, NULL);
1822da6c28aaSamw 		VN_RELE(vp);
18237f667e74Sjose borrego 
18247f667e74Sjose borrego 		if (*ret_snode == NULL)
1825da6c28aaSamw 			rc = ENOMEM;
1826da6c28aaSamw 	}
1827da6c28aaSamw 
1828da6c28aaSamw 	kmem_free(od_name, MAXNAMELEN);
1829da6c28aaSamw 	return (rc);
1830da6c28aaSamw }
1831da6c28aaSamw 
1832da6c28aaSamw int /*ARGSUSED*/
1833da6c28aaSamw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode)
1834da6c28aaSamw {
1835da6c28aaSamw 	ASSERT(cr);
1836da6c28aaSamw 	ASSERT(snode);
1837da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1838da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1839da6c28aaSamw 
1840da6c28aaSamw 	ASSERT(sr);
1841da6c28aaSamw 	ASSERT(sr->tid_tree);
1842c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1843da6c28aaSamw 		return (EROFS);
1844da6c28aaSamw 
1845dc20a302Sas200622 	return (smb_vop_commit(snode->vp, cr));
1846da6c28aaSamw }
1847da6c28aaSamw 
1848da6c28aaSamw /*
1849da6c28aaSamw  * smb_fsop_aclread
1850da6c28aaSamw  *
1851da6c28aaSamw  * Retrieve filesystem ACL. Depends on requested ACLs in
1852da6c28aaSamw  * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in
1853da6c28aaSamw  * fs_sd. Note that requesting a DACL/SACL doesn't mean that
1854da6c28aaSamw  * the corresponding field in fs_sd should be non-NULL upon
1855da6c28aaSamw  * return, since the target ACL might not contain that type of
1856da6c28aaSamw  * entries.
1857da6c28aaSamw  *
1858da6c28aaSamw  * Returned ACL is always in ACE_T (aka ZFS) format.
1859da6c28aaSamw  * If successful the allocated memory for the ACL should be freed
186055bf511dSas200622  * using smb_fsacl_free() or smb_fssd_term()
1861da6c28aaSamw  */
1862da6c28aaSamw int
1863da6c28aaSamw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1864da6c28aaSamw     smb_fssd_t *fs_sd)
1865da6c28aaSamw {
1866da6c28aaSamw 	int error = 0;
1867da6c28aaSamw 	int flags = 0;
1868da6c28aaSamw 	int access = 0;
1869da6c28aaSamw 	acl_t *acl;
1870da6c28aaSamw 	smb_node_t *unnamed_node;
1871da6c28aaSamw 
1872da6c28aaSamw 	ASSERT(cr);
1873da6c28aaSamw 
1874743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0)
1875743a77edSAlan Wright 		return (EACCES);
1876743a77edSAlan Wright 
1877da6c28aaSamw 	if (sr->fid_ofile) {
1878da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
1879da6c28aaSamw 			access = READ_CONTROL;
1880da6c28aaSamw 
1881da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
1882da6c28aaSamw 			access |= ACCESS_SYSTEM_SECURITY;
1883da6c28aaSamw 
1884da6c28aaSamw 		error = smb_ofile_access(sr->fid_ofile, cr, access);
1885da6c28aaSamw 		if (error != NT_STATUS_SUCCESS) {
1886da6c28aaSamw 			return (EACCES);
1887da6c28aaSamw 		}
1888da6c28aaSamw 	}
1889da6c28aaSamw 
1890da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1891da6c28aaSamw 	if (unnamed_node) {
1892da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1893da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1894da6c28aaSamw 		/*
1895da6c28aaSamw 		 * Streams don't have ACL, any read ACL attempt on a stream
1896da6c28aaSamw 		 * should be performed on the unnamed stream.
1897da6c28aaSamw 		 */
1898da6c28aaSamw 		snode = unnamed_node;
1899da6c28aaSamw 	}
1900da6c28aaSamw 
1901c8ec8eeaSjose borrego 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS))
1902da6c28aaSamw 		flags = ATTR_NOACLCHECK;
1903da6c28aaSamw 
1904da6c28aaSamw 	error = smb_vop_acl_read(snode->vp, &acl, flags,
1905dc20a302Sas200622 	    sr->tid_tree->t_acltype, cr);
1906da6c28aaSamw 	if (error != 0) {
1907da6c28aaSamw 		return (error);
1908da6c28aaSamw 	}
1909da6c28aaSamw 
1910da6c28aaSamw 	error = acl_translate(acl, _ACL_ACE_ENABLED,
1911da6c28aaSamw 	    (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid);
1912da6c28aaSamw 
1913da6c28aaSamw 	if (error == 0) {
191455bf511dSas200622 		smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl,
1915da6c28aaSamw 		    fs_sd->sd_secinfo);
1916da6c28aaSamw 	}
1917da6c28aaSamw 
1918da6c28aaSamw 	acl_free(acl);
1919da6c28aaSamw 	return (error);
1920da6c28aaSamw }
1921da6c28aaSamw 
1922da6c28aaSamw /*
1923da6c28aaSamw  * smb_fsop_aclwrite
1924da6c28aaSamw  *
1925da6c28aaSamw  * Stores the filesystem ACL provided in fs_sd->sd_acl.
1926da6c28aaSamw  */
1927da6c28aaSamw int
1928da6c28aaSamw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1929da6c28aaSamw     smb_fssd_t *fs_sd)
1930da6c28aaSamw {
1931da6c28aaSamw 	int target_flavor;
1932da6c28aaSamw 	int error = 0;
1933da6c28aaSamw 	int flags = 0;
1934da6c28aaSamw 	int access = 0;
1935da6c28aaSamw 	acl_t *acl, *dacl, *sacl;
1936da6c28aaSamw 	smb_node_t *unnamed_node;
1937da6c28aaSamw 
1938da6c28aaSamw 	ASSERT(cr);
1939da6c28aaSamw 
1940da6c28aaSamw 	ASSERT(sr);
1941da6c28aaSamw 	ASSERT(sr->tid_tree);
1942c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1943da6c28aaSamw 		return (EROFS);
1944da6c28aaSamw 
1945743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0)
1946743a77edSAlan Wright 		return (EACCES);
1947743a77edSAlan Wright 
1948da6c28aaSamw 	if (sr->fid_ofile) {
1949da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
1950da6c28aaSamw 			access = WRITE_DAC;
1951da6c28aaSamw 
1952da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
1953da6c28aaSamw 			access |= ACCESS_SYSTEM_SECURITY;
1954da6c28aaSamw 
1955da6c28aaSamw 		error = smb_ofile_access(sr->fid_ofile, cr, access);
1956da6c28aaSamw 		if (error != NT_STATUS_SUCCESS)
1957da6c28aaSamw 			return (EACCES);
1958da6c28aaSamw 	}
1959da6c28aaSamw 
1960da6c28aaSamw 	switch (sr->tid_tree->t_acltype) {
1961da6c28aaSamw 	case ACLENT_T:
1962da6c28aaSamw 		target_flavor = _ACL_ACLENT_ENABLED;
1963da6c28aaSamw 		break;
1964da6c28aaSamw 
1965da6c28aaSamw 	case ACE_T:
1966da6c28aaSamw 		target_flavor = _ACL_ACE_ENABLED;
1967da6c28aaSamw 		break;
1968da6c28aaSamw 	default:
1969da6c28aaSamw 		return (EINVAL);
1970da6c28aaSamw 	}
1971da6c28aaSamw 
1972da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1973da6c28aaSamw 	if (unnamed_node) {
1974da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1975da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1976da6c28aaSamw 		/*
1977da6c28aaSamw 		 * Streams don't have ACL, any write ACL attempt on a stream
1978da6c28aaSamw 		 * should be performed on the unnamed stream.
1979da6c28aaSamw 		 */
1980da6c28aaSamw 		snode = unnamed_node;
1981da6c28aaSamw 	}
1982da6c28aaSamw 
1983da6c28aaSamw 	dacl = fs_sd->sd_zdacl;
1984da6c28aaSamw 	sacl = fs_sd->sd_zsacl;
1985da6c28aaSamw 
1986da6c28aaSamw 	ASSERT(dacl || sacl);
1987da6c28aaSamw 	if ((dacl == NULL) && (sacl == NULL))
1988da6c28aaSamw 		return (EINVAL);
1989da6c28aaSamw 
1990da6c28aaSamw 	if (dacl && sacl)
199155bf511dSas200622 		acl = smb_fsacl_merge(dacl, sacl);
1992da6c28aaSamw 	else if (dacl)
1993da6c28aaSamw 		acl = dacl;
1994da6c28aaSamw 	else
1995da6c28aaSamw 		acl = sacl;
1996da6c28aaSamw 
1997da6c28aaSamw 	error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR),
1998da6c28aaSamw 	    fs_sd->sd_uid, fs_sd->sd_gid);
1999da6c28aaSamw 	if (error == 0) {
2000c8ec8eeaSjose borrego 		if (smb_tree_has_feature(sr->tid_tree,
2001c8ec8eeaSjose borrego 		    SMB_TREE_ACEMASKONACCESS))
2002da6c28aaSamw 			flags = ATTR_NOACLCHECK;
2003da6c28aaSamw 
2004dc20a302Sas200622 		error = smb_vop_acl_write(snode->vp, acl, flags, cr);
2005da6c28aaSamw 	}
2006da6c28aaSamw 
2007da6c28aaSamw 	if (dacl && sacl)
2008da6c28aaSamw 		acl_free(acl);
2009da6c28aaSamw 
2010da6c28aaSamw 	return (error);
2011da6c28aaSamw }
2012da6c28aaSamw 
2013da6c28aaSamw acl_type_t
2014da6c28aaSamw smb_fsop_acltype(smb_node_t *snode)
2015da6c28aaSamw {
2016da6c28aaSamw 	return (smb_vop_acl_type(snode->vp));
2017da6c28aaSamw }
2018da6c28aaSamw 
2019da6c28aaSamw /*
2020da6c28aaSamw  * smb_fsop_sdread
2021da6c28aaSamw  *
2022da6c28aaSamw  * Read the requested security descriptor items from filesystem.
2023da6c28aaSamw  * The items are specified in fs_sd->sd_secinfo.
2024da6c28aaSamw  */
2025da6c28aaSamw int
2026da6c28aaSamw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2027da6c28aaSamw     smb_fssd_t *fs_sd)
2028da6c28aaSamw {
2029da6c28aaSamw 	int error = 0;
2030da6c28aaSamw 	int getowner = 0;
2031da6c28aaSamw 	cred_t *ga_cred;
2032da6c28aaSamw 	smb_attr_t attr;
2033da6c28aaSamw 
2034da6c28aaSamw 	ASSERT(cr);
2035da6c28aaSamw 	ASSERT(fs_sd);
2036da6c28aaSamw 
2037da6c28aaSamw 	/*
2038da6c28aaSamw 	 * File's uid/gid is fetched in two cases:
2039da6c28aaSamw 	 *
2040da6c28aaSamw 	 * 1. it's explicitly requested
2041da6c28aaSamw 	 *
2042da6c28aaSamw 	 * 2. target ACL is ACE_T (ZFS ACL). They're needed for
2043da6c28aaSamw 	 *    owner@/group@ entries. In this case kcred should be used
2044da6c28aaSamw 	 *    because uid/gid are fetched on behalf of smb server.
2045da6c28aaSamw 	 */
2046da6c28aaSamw 	if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) {
2047da6c28aaSamw 		getowner = 1;
2048da6c28aaSamw 		ga_cred = cr;
2049da6c28aaSamw 	} else if (sr->tid_tree->t_acltype == ACE_T) {
2050da6c28aaSamw 		getowner = 1;
2051da6c28aaSamw 		ga_cred = kcred;
2052da6c28aaSamw 	}
2053da6c28aaSamw 
2054da6c28aaSamw 	if (getowner) {
2055da6c28aaSamw 		/*
2056da6c28aaSamw 		 * Windows require READ_CONTROL to read owner/group SID since
2057da6c28aaSamw 		 * they're part of Security Descriptor.
2058da6c28aaSamw 		 * ZFS only requires read_attribute. Need to have a explicit
2059da6c28aaSamw 		 * access check here.
2060da6c28aaSamw 		 */
2061da6c28aaSamw 		if (sr->fid_ofile == NULL) {
2062da6c28aaSamw 			error = smb_fsop_access(sr, ga_cred, snode,
2063da6c28aaSamw 			    READ_CONTROL);
2064da6c28aaSamw 			if (error)
2065b1352070SAlan Wright 				return (EACCES);
2066da6c28aaSamw 		}
2067da6c28aaSamw 
2068da6c28aaSamw 		attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
2069da6c28aaSamw 		error = smb_fsop_getattr(sr, ga_cred, snode, &attr);
2070da6c28aaSamw 		if (error == 0) {
2071da6c28aaSamw 			fs_sd->sd_uid = attr.sa_vattr.va_uid;
2072da6c28aaSamw 			fs_sd->sd_gid = attr.sa_vattr.va_gid;
2073da6c28aaSamw 		} else {
2074da6c28aaSamw 			return (error);
2075da6c28aaSamw 		}
2076da6c28aaSamw 	}
2077da6c28aaSamw 
2078da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2079da6c28aaSamw 		error = smb_fsop_aclread(sr, cr, snode, fs_sd);
2080da6c28aaSamw 	}
2081da6c28aaSamw 
2082da6c28aaSamw 	return (error);
2083da6c28aaSamw }
2084da6c28aaSamw 
2085da6c28aaSamw /*
2086da6c28aaSamw  * smb_fsop_sdmerge
2087da6c28aaSamw  *
2088da6c28aaSamw  * From SMB point of view DACL and SACL are two separate list
2089da6c28aaSamw  * which can be manipulated independently without one affecting
2090da6c28aaSamw  * the other, but entries for both DACL and SACL will end up
2091da6c28aaSamw  * in the same ACL if target filesystem supports ACE_T ACLs.
2092da6c28aaSamw  *
2093da6c28aaSamw  * So, if either DACL or SACL is present in the client set request
2094da6c28aaSamw  * the entries corresponding to the non-present ACL shouldn't
2095da6c28aaSamw  * be touched in the FS ACL.
2096da6c28aaSamw  *
2097da6c28aaSamw  * fs_sd parameter contains DACL and SACL specified by SMB
2098da6c28aaSamw  * client to be set on a file/directory. The client could
2099da6c28aaSamw  * specify both or one of these ACLs (if none is specified
2100da6c28aaSamw  * we don't get this far). When both DACL and SACL are given
2101da6c28aaSamw  * by client the existing ACL should be overwritten. If only
2102da6c28aaSamw  * one of them is specified the entries corresponding to the other
2103da6c28aaSamw  * ACL should not be touched. For example, if only DACL
2104da6c28aaSamw  * is specified in input fs_sd, the function reads audit entries
2105da6c28aaSamw  * of the existing ACL of the file and point fs_sd->sd_zsdacl
2106da6c28aaSamw  * pointer to the fetched SACL, this way when smb_fsop_sdwrite()
2107da6c28aaSamw  * function is called the passed fs_sd would point to the specified
2108da6c28aaSamw  * DACL by client and fetched SACL from filesystem, so the file
2109da6c28aaSamw  * will end up with correct ACL.
2110da6c28aaSamw  */
2111da6c28aaSamw static int
2112da6c28aaSamw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd)
2113da6c28aaSamw {
2114da6c28aaSamw 	smb_fssd_t cur_sd;
2115da6c28aaSamw 	int error = 0;
2116da6c28aaSamw 
2117da6c28aaSamw 	if (sr->tid_tree->t_acltype != ACE_T)
2118da6c28aaSamw 		/* Don't bother if target FS doesn't support ACE_T */
2119da6c28aaSamw 		return (0);
2120da6c28aaSamw 
2121da6c28aaSamw 	if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) {
2122da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
2123da6c28aaSamw 			/*
2124da6c28aaSamw 			 * Don't overwrite existing audit entries
2125da6c28aaSamw 			 */
212655bf511dSas200622 			smb_fssd_init(&cur_sd, SMB_SACL_SECINFO,
2127da6c28aaSamw 			    fs_sd->sd_flags);
2128da6c28aaSamw 
2129da6c28aaSamw 			error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
2130da6c28aaSamw 			if (error == 0) {
2131da6c28aaSamw 				ASSERT(fs_sd->sd_zsacl == NULL);
2132da6c28aaSamw 				fs_sd->sd_zsacl = cur_sd.sd_zsacl;
2133da6c28aaSamw 				if (fs_sd->sd_zsacl && fs_sd->sd_zdacl)
2134da6c28aaSamw 					fs_sd->sd_zsacl->acl_flags =
2135da6c28aaSamw 					    fs_sd->sd_zdacl->acl_flags;
2136da6c28aaSamw 			}
2137da6c28aaSamw 		} else {
2138da6c28aaSamw 			/*
2139da6c28aaSamw 			 * Don't overwrite existing access entries
2140da6c28aaSamw 			 */
214155bf511dSas200622 			smb_fssd_init(&cur_sd, SMB_DACL_SECINFO,
2142da6c28aaSamw 			    fs_sd->sd_flags);
2143da6c28aaSamw 
2144da6c28aaSamw 			error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
2145da6c28aaSamw 			if (error == 0) {
2146da6c28aaSamw 				ASSERT(fs_sd->sd_zdacl == NULL);
2147da6c28aaSamw 				fs_sd->sd_zdacl = cur_sd.sd_zdacl;
2148da6c28aaSamw 				if (fs_sd->sd_zdacl && fs_sd->sd_zsacl)
2149da6c28aaSamw 					fs_sd->sd_zdacl->acl_flags =
2150da6c28aaSamw 					    fs_sd->sd_zsacl->acl_flags;
2151da6c28aaSamw 			}
2152da6c28aaSamw 		}
2153da6c28aaSamw 
2154da6c28aaSamw 		if (error)
215555bf511dSas200622 			smb_fssd_term(&cur_sd);
2156da6c28aaSamw 	}
2157da6c28aaSamw 
2158da6c28aaSamw 	return (error);
2159da6c28aaSamw }
2160da6c28aaSamw 
2161da6c28aaSamw /*
2162da6c28aaSamw  * smb_fsop_sdwrite
2163da6c28aaSamw  *
2164da6c28aaSamw  * Stores the given uid, gid and acl in filesystem.
2165da6c28aaSamw  * Provided items in fs_sd are specified by fs_sd->sd_secinfo.
2166da6c28aaSamw  *
2167da6c28aaSamw  * A SMB security descriptor could contain owner, primary group,
2168da6c28aaSamw  * DACL and SACL. Setting an SD should be atomic but here it has to
2169da6c28aaSamw  * be done via two separate FS operations: VOP_SETATTR and
2170da6c28aaSamw  * VOP_SETSECATTR. Therefore, this function has to simulate the
2171da6c28aaSamw  * atomicity as well as it can.
21722c1b14e5Sjose borrego  *
21732c1b14e5Sjose borrego  * Get the current uid, gid before setting the new uid/gid
21742c1b14e5Sjose borrego  * so if smb_fsop_aclwrite fails they can be restored. root cred is
21752c1b14e5Sjose borrego  * used to get currend uid/gid since this operation is performed on
21762c1b14e5Sjose borrego  * behalf of the server not the user.
21772c1b14e5Sjose borrego  *
21782c1b14e5Sjose borrego  * If setting uid/gid fails with EPERM it means that and invalid
21792c1b14e5Sjose borrego  * owner has been specified. Callers should translate this to
21802c1b14e5Sjose borrego  * STATUS_INVALID_OWNER which is not the normal mapping for EPERM
21812c1b14e5Sjose borrego  * in upper layers, so EPERM is mapped to EBADE.
2182da6c28aaSamw  */
2183da6c28aaSamw int
2184da6c28aaSamw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2185da6c28aaSamw     smb_fssd_t *fs_sd, int overwrite)
2186da6c28aaSamw {
2187da6c28aaSamw 	int error = 0;
2188da6c28aaSamw 	int access = 0;
2189da6c28aaSamw 	smb_attr_t set_attr;
2190da6c28aaSamw 	smb_attr_t orig_attr;
2191da6c28aaSamw 
2192da6c28aaSamw 	ASSERT(cr);
2193da6c28aaSamw 	ASSERT(fs_sd);
2194da6c28aaSamw 
2195da6c28aaSamw 	ASSERT(sr);
2196da6c28aaSamw 	ASSERT(sr->tid_tree);
2197c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
2198da6c28aaSamw 		return (EROFS);
2199da6c28aaSamw 
2200da6c28aaSamw 	bzero(&set_attr, sizeof (smb_attr_t));
2201da6c28aaSamw 
2202da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
2203da6c28aaSamw 		set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
2204da6c28aaSamw 		set_attr.sa_mask |= SMB_AT_UID;
22052c1b14e5Sjose borrego 		access |= WRITE_OWNER;
2206da6c28aaSamw 	}
2207da6c28aaSamw 
2208da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
2209da6c28aaSamw 		set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
2210da6c28aaSamw 		set_attr.sa_mask |= SMB_AT_GID;
22112c1b14e5Sjose borrego 		access |= WRITE_OWNER;
2212da6c28aaSamw 	}
2213da6c28aaSamw 
2214da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
2215da6c28aaSamw 		access |= WRITE_DAC;
2216da6c28aaSamw 
2217da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
2218da6c28aaSamw 		access |= ACCESS_SYSTEM_SECURITY;
2219da6c28aaSamw 
2220da6c28aaSamw 	if (sr->fid_ofile)
2221da6c28aaSamw 		error = smb_ofile_access(sr->fid_ofile, cr, access);
2222da6c28aaSamw 	else
2223da6c28aaSamw 		error = smb_fsop_access(sr, cr, snode, access);
2224da6c28aaSamw 
2225da6c28aaSamw 	if (error)
2226da6c28aaSamw 		return (EACCES);
2227da6c28aaSamw 
2228da6c28aaSamw 	if (set_attr.sa_mask) {
2229da6c28aaSamw 		orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
2230da6c28aaSamw 		error = smb_fsop_getattr(sr, kcred, snode, &orig_attr);
22312c1b14e5Sjose borrego 		if (error == 0) {
2232037cac00Sjoyce mcintosh 			error = smb_fsop_setattr(sr, cr, snode, &set_attr);
22332c1b14e5Sjose borrego 			if (error == EPERM)
22342c1b14e5Sjose borrego 				error = EBADE;
22352c1b14e5Sjose borrego 		}
2236da6c28aaSamw 
2237da6c28aaSamw 		if (error)
2238da6c28aaSamw 			return (error);
2239da6c28aaSamw 	}
2240da6c28aaSamw 
2241da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2242da6c28aaSamw 		if (overwrite == 0) {
2243da6c28aaSamw 			error = smb_fsop_sdmerge(sr, snode, fs_sd);
2244da6c28aaSamw 			if (error)
2245da6c28aaSamw 				return (error);
2246da6c28aaSamw 		}
2247da6c28aaSamw 
2248da6c28aaSamw 		error = smb_fsop_aclwrite(sr, cr, snode, fs_sd);
2249da6c28aaSamw 		if (error) {
2250da6c28aaSamw 			/*
2251da6c28aaSamw 			 * Revert uid/gid changes if required.
2252da6c28aaSamw 			 */
2253da6c28aaSamw 			if (set_attr.sa_mask) {
2254da6c28aaSamw 				orig_attr.sa_mask = set_attr.sa_mask;
2255da6c28aaSamw 				(void) smb_fsop_setattr(sr, kcred, snode,
2256037cac00Sjoyce mcintosh 				    &orig_attr);
2257da6c28aaSamw 			}
2258da6c28aaSamw 		}
2259da6c28aaSamw 	}
2260da6c28aaSamw 
2261da6c28aaSamw 	return (error);
2262da6c28aaSamw }
2263da6c28aaSamw 
2264da6c28aaSamw /*
2265da6c28aaSamw  * smb_fsop_sdinherit
2266da6c28aaSamw  *
2267da6c28aaSamw  * Inherit the security descriptor from the parent container.
2268da6c28aaSamw  * This function is called after FS has created the file/folder
2269da6c28aaSamw  * so if this doesn't do anything it means FS inheritance is
2270da6c28aaSamw  * in place.
2271da6c28aaSamw  *
2272da6c28aaSamw  * Do inheritance for ZFS internally.
2273da6c28aaSamw  *
2274da6c28aaSamw  * If we want to let ZFS does the inheritance the
2275da6c28aaSamw  * following setting should be true:
2276da6c28aaSamw  *
2277da6c28aaSamw  *  - aclinherit = passthrough
2278da6c28aaSamw  *  - aclmode = passthrough
2279da6c28aaSamw  *  - smbd umask = 0777
2280da6c28aaSamw  *
2281da6c28aaSamw  * This will result in right effective permissions but
2282da6c28aaSamw  * ZFS will always add 6 ACEs for owner, owning group
2283da6c28aaSamw  * and others to be POSIX compliant. This is not what
2284da6c28aaSamw  * Windows clients/users expect, so we decided that CIFS
2285da6c28aaSamw  * implements Windows rules and overwrite whatever ZFS
2286da6c28aaSamw  * comes up with. This way we also don't have to care
2287da6c28aaSamw  * about ZFS aclinherit and aclmode settings.
2288da6c28aaSamw  */
2289da6c28aaSamw static int
2290da6c28aaSamw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd)
2291da6c28aaSamw {
2292da6c28aaSamw 	int is_dir;
229355bf511dSas200622 	acl_t *dacl = NULL;
229455bf511dSas200622 	acl_t *sacl = NULL;
2295da6c28aaSamw 	ksid_t *owner_sid;
2296da6c28aaSamw 	int error;
2297da6c28aaSamw 
2298da6c28aaSamw 	ASSERT(fs_sd);
2299da6c28aaSamw 
2300da6c28aaSamw 	if (sr->tid_tree->t_acltype != ACE_T) {
2301da6c28aaSamw 		/*
2302da6c28aaSamw 		 * No forced inheritance for non-ZFS filesystems.
2303da6c28aaSamw 		 */
2304da6c28aaSamw 		fs_sd->sd_secinfo = 0;
2305da6c28aaSamw 		return (0);
2306da6c28aaSamw 	}
2307da6c28aaSamw 
2308da6c28aaSamw 
2309da6c28aaSamw 	/* Fetch parent directory's ACL */
2310da6c28aaSamw 	error = smb_fsop_sdread(sr, kcred, dnode, fs_sd);
2311da6c28aaSamw 	if (error) {
2312da6c28aaSamw 		return (error);
2313da6c28aaSamw 	}
2314da6c28aaSamw 
2315da6c28aaSamw 	is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR);
2316da6c28aaSamw 	owner_sid = crgetsid(sr->user_cr, KSID_OWNER);
2317da6c28aaSamw 	ASSERT(owner_sid);
231855bf511dSas200622 	dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO,
2319da6c28aaSamw 	    owner_sid->ks_id);
232055bf511dSas200622 	sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO,
2321da6c28aaSamw 	    (uid_t)-1);
2322da6c28aaSamw 
232355bf511dSas200622 	if (sacl == NULL)
232455bf511dSas200622 		fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO;
232555bf511dSas200622 
232655bf511dSas200622 	smb_fsacl_free(fs_sd->sd_zdacl);
232755bf511dSas200622 	smb_fsacl_free(fs_sd->sd_zsacl);
2328da6c28aaSamw 
2329da6c28aaSamw 	fs_sd->sd_zdacl = dacl;
2330da6c28aaSamw 	fs_sd->sd_zsacl = sacl;
2331da6c28aaSamw 
2332da6c28aaSamw 	return (0);
2333da6c28aaSamw }
2334da6c28aaSamw 
2335da6c28aaSamw /*
2336da6c28aaSamw  * smb_fsop_eaccess
2337da6c28aaSamw  *
2338da6c28aaSamw  * Returns the effective permission of the given credential for the
2339da6c28aaSamw  * specified object.
2340da6c28aaSamw  *
2341da6c28aaSamw  * This is just a workaround. We need VFS/FS support for this.
2342da6c28aaSamw  */
2343da6c28aaSamw void
2344da6c28aaSamw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2345da6c28aaSamw     uint32_t *eaccess)
2346da6c28aaSamw {
2347da6c28aaSamw 	int access = 0;
2348da6c28aaSamw 	vnode_t *dir_vp;
2349da6c28aaSamw 	smb_node_t *unnamed_node;
2350da6c28aaSamw 
2351da6c28aaSamw 	ASSERT(cr);
2352da6c28aaSamw 	ASSERT(snode);
2353da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
2354da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
2355da6c28aaSamw 
2356da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
2357da6c28aaSamw 	if (unnamed_node) {
2358da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
2359da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
2360da6c28aaSamw 		/*
2361da6c28aaSamw 		 * Streams authorization should be performed against the
2362da6c28aaSamw 		 * unnamed stream.
2363da6c28aaSamw 		 */
2364da6c28aaSamw 		snode = unnamed_node;
2365da6c28aaSamw 	}
2366da6c28aaSamw 
2367c8ec8eeaSjose borrego 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) {
23681fcced4cSJordan Brown 		dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
2369da6c28aaSamw 		smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp,
2370da6c28aaSamw 		    cr);
2371da6c28aaSamw 		return;
2372da6c28aaSamw 	}
2373da6c28aaSamw 
2374da6c28aaSamw 	/*
2375da6c28aaSamw 	 * FS doesn't understand 32-bit mask
2376da6c28aaSamw 	 */
2377da6c28aaSamw 	smb_vop_eaccess(snode->vp, &access, 0, NULL, cr);
2378743a77edSAlan Wright 	access &= sr->tid_tree->t_access;
2379da6c28aaSamw 
2380da6c28aaSamw 	*eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES;
2381da6c28aaSamw 
2382da6c28aaSamw 	if (access & VREAD)
2383da6c28aaSamw 		*eaccess |= FILE_READ_DATA;
2384da6c28aaSamw 
2385da6c28aaSamw 	if (access & VEXEC)
2386da6c28aaSamw 		*eaccess |= FILE_EXECUTE;
2387da6c28aaSamw 
2388da6c28aaSamw 	if (access & VWRITE)
2389da6c28aaSamw 		*eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
2390da6c28aaSamw 		    FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
2391da6c28aaSamw }
239255bf511dSas200622 
2393dc20a302Sas200622 /*
2394dc20a302Sas200622  * smb_fsop_shrlock
2395dc20a302Sas200622  *
2396dc20a302Sas200622  * For the current open request, check file sharing rules
2397dc20a302Sas200622  * against existing opens.
2398dc20a302Sas200622  *
2399dc20a302Sas200622  * Returns NT_STATUS_SHARING_VIOLATION if there is any
2400dc20a302Sas200622  * sharing conflict.  Returns NT_STATUS_SUCCESS otherwise.
2401dc20a302Sas200622  *
2402dc20a302Sas200622  * Full system-wide share reservation synchronization is available
2403dc20a302Sas200622  * when the nbmand (non-blocking mandatory) mount option is set
2404dc20a302Sas200622  * (i.e. nbl_need_crit() is true) and nbmand critical regions are used.
2405dc20a302Sas200622  * This provides synchronization with NFS and local processes.  The
2406dc20a302Sas200622  * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called
2407dc20a302Sas200622  * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well
2408dc20a302Sas200622  * as the CIFS rename and delete paths.
2409dc20a302Sas200622  *
2410dc20a302Sas200622  * The CIFS server will also enter the nbl critical region in the open,
2411dc20a302Sas200622  * rename, and delete paths when nbmand is not set.  There is limited
2412dc20a302Sas200622  * coordination with local and VFS share reservations in this case.
2413dc20a302Sas200622  * Note that when the nbmand mount option is not set, the VFS layer
2414dc20a302Sas200622  * only processes advisory reservations and the delete mode is not checked.
2415dc20a302Sas200622  *
2416dc20a302Sas200622  * Whether or not the nbmand mount option is set, intra-CIFS share
2417dc20a302Sas200622  * checking is done in the open, delete, and rename paths using a CIFS
2418dc20a302Sas200622  * critical region (node->n_share_lock).
2419dc20a302Sas200622  */
2420dc20a302Sas200622 
2421dc20a302Sas200622 uint32_t
2422faa1795aSjb150015 smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid,
2423dc20a302Sas200622     uint32_t desired_access, uint32_t share_access)
242455bf511dSas200622 {
2425dc20a302Sas200622 	int rc;
2426dc20a302Sas200622 
2427037cac00Sjoyce mcintosh 	if (smb_node_is_dir(node))
2428dc20a302Sas200622 		return (NT_STATUS_SUCCESS);
2429dc20a302Sas200622 
2430dc20a302Sas200622 	/* Allow access if the request is just for meta data */
2431dc20a302Sas200622 	if ((desired_access & FILE_DATA_ALL) == 0)
2432dc20a302Sas200622 		return (NT_STATUS_SUCCESS);
2433dc20a302Sas200622 
2434dc20a302Sas200622 	rc = smb_node_open_check(node, cr, desired_access, share_access);
2435dc20a302Sas200622 	if (rc)
2436dc20a302Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
2437dc20a302Sas200622 
2438dc20a302Sas200622 	rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access,
2439dc20a302Sas200622 	    cr);
2440dc20a302Sas200622 	if (rc)
2441dc20a302Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
2442dc20a302Sas200622 
2443dc20a302Sas200622 	return (NT_STATUS_SUCCESS);
2444dc20a302Sas200622 }
2445dc20a302Sas200622 
2446dc20a302Sas200622 void
2447dc20a302Sas200622 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid)
2448dc20a302Sas200622 {
2449037cac00Sjoyce mcintosh 	if (smb_node_is_dir(node))
2450dc20a302Sas200622 		return;
2451dc20a302Sas200622 
2452dc20a302Sas200622 	(void) smb_vop_unshrlock(node->vp, uniq_fid, cr);
2453dc20a302Sas200622 }
24548c10a865Sas200622 
24558c10a865Sas200622 int
24568c10a865Sas200622 smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock,
24578c10a865Sas200622     cred_t *cr)
24588c10a865Sas200622 {
24598c10a865Sas200622 	flock64_t bf;
24608c10a865Sas200622 	int flag = F_REMOTELOCK;
24618c10a865Sas200622 
24623ad684d6Sjb150015 	/*
24633ad684d6Sjb150015 	 * VOP_FRLOCK() will not be called if:
24643ad684d6Sjb150015 	 *
24653ad684d6Sjb150015 	 * 1) The lock has a range of zero bytes. The semantics of Windows and
24663ad684d6Sjb150015 	 *    POSIX are different. In the case of POSIX it asks for the locking
24673ad684d6Sjb150015 	 *    of all the bytes from the offset provided until the end of the
24683ad684d6Sjb150015 	 *    file. In the case of Windows a range of zero locks nothing and
24693ad684d6Sjb150015 	 *    doesn't conflict with any other lock.
24703ad684d6Sjb150015 	 *
24713ad684d6Sjb150015 	 * 2) The lock rolls over (start + lenght < start). Solaris will assert
24723ad684d6Sjb150015 	 *    if such a request is submitted. This will not create
24733ad684d6Sjb150015 	 *    incompatibilities between POSIX and Windows. In the Windows world,
24743ad684d6Sjb150015 	 *    if a client submits such a lock, the server will not lock any
24753ad684d6Sjb150015 	 *    bytes. Interestingly if the same lock (same offset and length) is
24763ad684d6Sjb150015 	 *    resubmitted Windows will consider that there is an overlap and
24773ad684d6Sjb150015 	 *    the granting rules will then apply.
24783ad684d6Sjb150015 	 */
24793ad684d6Sjb150015 	if ((lock->l_length == 0) ||
24803ad684d6Sjb150015 	    ((lock->l_start + lock->l_length - 1) < lock->l_start))
24813ad684d6Sjb150015 		return (0);
24823ad684d6Sjb150015 
24838c10a865Sas200622 	bzero(&bf, sizeof (bf));
24848c10a865Sas200622 
24858c10a865Sas200622 	if (unlock) {
24868c10a865Sas200622 		bf.l_type = F_UNLCK;
24878c10a865Sas200622 	} else if (lock->l_type == SMB_LOCK_TYPE_READONLY) {
24888c10a865Sas200622 		bf.l_type = F_RDLCK;
24898c10a865Sas200622 		flag |= FREAD;
24908c10a865Sas200622 	} else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) {
24918c10a865Sas200622 		bf.l_type = F_WRLCK;
24928c10a865Sas200622 		flag |= FWRITE;
24938c10a865Sas200622 	}
24948c10a865Sas200622 
24958c10a865Sas200622 	bf.l_start = lock->l_start;
24968c10a865Sas200622 	bf.l_len = lock->l_length;
2497c8ec8eeaSjose borrego 	bf.l_pid = lock->l_file->f_uniqid;
24988c10a865Sas200622 	bf.l_sysid = smb_ct.cc_sysid;
24998c10a865Sas200622 
25008c10a865Sas200622 	return (smb_vop_frlock(node->vp, cr, flag, &bf));
25018c10a865Sas200622 }
2502