xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_fsops.c (revision 1fcced4c370617db71610fecffd5451a5894ca5e)
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>
3055bf511dSas200622 #include <smbsrv/ntstatus.h>
3155bf511dSas200622 #include <smbsrv/ntaccess.h>
32dc20a302Sas200622 #include <smbsrv/smb_incl.h>
33da6c28aaSamw #include <acl/acl_common.h>
34dc20a302Sas200622 #include <sys/fcntl.h>
35dc20a302Sas200622 #include <sys/flock.h>
36dc20a302Sas200622 #include <fs/fs_subr.h>
37da6c28aaSamw 
38faa1795aSjb150015 extern caller_context_t smb_ct;
39faa1795aSjb150015 
408c10a865Sas200622 extern int smb_fem_oplock_install(smb_node_t *);
418c10a865Sas200622 extern void smb_fem_oplock_uninstall(smb_node_t *);
428c10a865Sas200622 
438c10a865Sas200622 extern int smb_vop_other_opens(vnode_t *, int);
448c10a865Sas200622 
45eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_stream(smb_request_t *, cred_t *, smb_node_t *,
46037cac00Sjoyce mcintosh     char *, 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_file(smb_request_t *, cred_t *, smb_node_t *,
49037cac00Sjoyce mcintosh     char *, int, smb_attr_t *, smb_node_t **);
50eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
51eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_with_sd(smb_request_t *, cred_t *, smb_node_t *,
52037cac00Sjoyce mcintosh     char *, smb_attr_t *, smb_node_t **, smb_fssd_t *);
53eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
54eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_sdinherit(smb_request_t *, smb_node_t *, smb_fssd_t *);
55da6c28aaSamw 
56da6c28aaSamw /*
57da6c28aaSamw  * The smb_fsop_* functions have knowledge of CIFS semantics.
58da6c28aaSamw  *
59da6c28aaSamw  * The smb_vop_* functions have minimal knowledge of CIFS semantics and
60da6c28aaSamw  * serve as an interface to the VFS layer.
61da6c28aaSamw  *
62da6c28aaSamw  * Hence, smb_request_t and smb_node_t structures should not be passed
63da6c28aaSamw  * from the smb_fsop_* layer to the smb_vop_* layer.
64da6c28aaSamw  *
65da6c28aaSamw  * In general, CIFS service code should only ever call smb_fsop_*
66da6c28aaSamw  * functions directly, and never smb_vop_* functions directly.
67da6c28aaSamw  *
68da6c28aaSamw  * smb_fsop_* functions should call smb_vop_* functions where possible, instead
69da6c28aaSamw  * of their smb_fsop_* counterparts.  However, there are times when
70da6c28aaSamw  * this cannot be avoided.
71da6c28aaSamw  */
72da6c28aaSamw 
73da6c28aaSamw /*
74da6c28aaSamw  * Note: Stream names cannot be mangled.
75da6c28aaSamw  */
76da6c28aaSamw 
77da6c28aaSamw /*
788c10a865Sas200622  * smb_fsop_amask_to_omode
798c10a865Sas200622  *
808c10a865Sas200622  * Convert the access mask to the open mode (for use
818c10a865Sas200622  * with the VOP_OPEN call).
828c10a865Sas200622  *
838c10a865Sas200622  * Note that opening a file for attribute only access
848c10a865Sas200622  * will also translate into an FREAD or FWRITE open mode
858c10a865Sas200622  * (i.e., it's not just for data).
868c10a865Sas200622  *
878c10a865Sas200622  * This is needed so that opens are tracked appropriately
888c10a865Sas200622  * for oplock processing.
89da6c28aaSamw  */
90da6c28aaSamw 
91da6c28aaSamw int
928c10a865Sas200622 smb_fsop_amask_to_omode(uint32_t access)
93da6c28aaSamw {
94da6c28aaSamw 	int mode = 0;
95da6c28aaSamw 
968c10a865Sas200622 	if (access & (FILE_READ_DATA | FILE_EXECUTE |
978c10a865Sas200622 	    FILE_READ_ATTRIBUTES | FILE_READ_EA))
98da6c28aaSamw 		mode |= FREAD;
99da6c28aaSamw 
1008c10a865Sas200622 	if (access & (FILE_WRITE_DATA | FILE_APPEND_DATA |
1018c10a865Sas200622 	    FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))
102da6c28aaSamw 		mode |= FWRITE;
103da6c28aaSamw 
1048c10a865Sas200622 	if (access & FILE_APPEND_DATA)
105da6c28aaSamw 		mode |= FAPPEND;
106da6c28aaSamw 
107da6c28aaSamw 	return (mode);
108da6c28aaSamw }
109da6c28aaSamw 
1108c10a865Sas200622 int
1118c10a865Sas200622 smb_fsop_open(smb_node_t *node, int mode, cred_t *cred)
1128c10a865Sas200622 {
1138c10a865Sas200622 	/*
1148c10a865Sas200622 	 * Assuming that the same vnode is returned as we had before.
1158c10a865Sas200622 	 * (I.e., with certain types of files or file systems, a
1168c10a865Sas200622 	 * different vnode might be returned by VOP_OPEN)
1178c10a865Sas200622 	 */
1188c10a865Sas200622 	return (smb_vop_open(&node->vp, mode, cred));
1198c10a865Sas200622 }
1208c10a865Sas200622 
121c8ec8eeaSjose borrego void
1228c10a865Sas200622 smb_fsop_close(smb_node_t *node, int mode, cred_t *cred)
1238c10a865Sas200622 {
124c8ec8eeaSjose borrego 	smb_vop_close(node->vp, mode, cred);
1258c10a865Sas200622 }
1268c10a865Sas200622 
1278c10a865Sas200622 int
1288c10a865Sas200622 smb_fsop_oplock_install(smb_node_t *node, int mode)
1298c10a865Sas200622 {
1308c10a865Sas200622 	int rc;
1318c10a865Sas200622 
1328c10a865Sas200622 	if (smb_vop_other_opens(node->vp, mode))
1338c10a865Sas200622 		return (EMFILE);
1348c10a865Sas200622 
1358c10a865Sas200622 	if ((rc = smb_fem_oplock_install(node)))
1368c10a865Sas200622 		return (rc);
1378c10a865Sas200622 
1388c10a865Sas200622 	if (smb_vop_other_opens(node->vp, mode)) {
1398c10a865Sas200622 		(void) smb_fem_oplock_uninstall(node);
1408c10a865Sas200622 		return (EMFILE);
1418c10a865Sas200622 	}
1428c10a865Sas200622 
1438c10a865Sas200622 	return (0);
1448c10a865Sas200622 }
1458c10a865Sas200622 
1468c10a865Sas200622 void
1478c10a865Sas200622 smb_fsop_oplock_uninstall(smb_node_t *node)
1488c10a865Sas200622 {
1498c10a865Sas200622 	smb_fem_oplock_uninstall(node);
1508c10a865Sas200622 }
1518c10a865Sas200622 
152da6c28aaSamw static int
153eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_with_sd(smb_request_t *sr, cred_t *cr,
154eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *dnode, char *name,
155037cac00Sjoyce mcintosh     smb_attr_t *attr, smb_node_t **ret_snode, smb_fssd_t *fs_sd)
156da6c28aaSamw {
157da6c28aaSamw 	vsecattr_t *vsap;
158da6c28aaSamw 	vsecattr_t vsecattr;
159da6c28aaSamw 	acl_t *acl, *dacl, *sacl;
160da6c28aaSamw 	smb_attr_t set_attr;
161da6c28aaSamw 	vnode_t *vp;
162da6c28aaSamw 	int aclbsize = 0;	/* size of acl list in bytes */
163da6c28aaSamw 	int flags = 0;
164da6c28aaSamw 	int rc;
1652c1b14e5Sjose borrego 	boolean_t is_dir;
166da6c28aaSamw 
167da6c28aaSamw 	ASSERT(fs_sd);
168da6c28aaSamw 
169c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
170da6c28aaSamw 		flags = SMB_IGNORE_CASE;
1718b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
1728b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
173da6c28aaSamw 
174da6c28aaSamw 	ASSERT(cr);
175da6c28aaSamw 
176da6c28aaSamw 	is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0);
177da6c28aaSamw 
178c8ec8eeaSjose borrego 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) {
179da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
180da6c28aaSamw 			dacl = fs_sd->sd_zdacl;
181da6c28aaSamw 			sacl = fs_sd->sd_zsacl;
182da6c28aaSamw 			ASSERT(dacl || sacl);
183da6c28aaSamw 			if (dacl && sacl) {
18455bf511dSas200622 				acl = smb_fsacl_merge(dacl, sacl);
185da6c28aaSamw 			} else if (dacl) {
186da6c28aaSamw 				acl = dacl;
187da6c28aaSamw 			} else {
188da6c28aaSamw 				acl = sacl;
189da6c28aaSamw 			}
190da6c28aaSamw 
19155bf511dSas200622 			rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize);
192da6c28aaSamw 
193da6c28aaSamw 			if (dacl && sacl)
194da6c28aaSamw 				acl_free(acl);
195da6c28aaSamw 
1962c1b14e5Sjose borrego 			if (rc != 0)
197da6c28aaSamw 				return (rc);
198da6c28aaSamw 
199da6c28aaSamw 			vsap = &vsecattr;
2002c1b14e5Sjose borrego 		} else {
201da6c28aaSamw 			vsap = NULL;
2022c1b14e5Sjose borrego 		}
203da6c28aaSamw 
204743a77edSAlan Wright 		/* The tree ACEs may prevent a create */
205743a77edSAlan Wright 		rc = EACCES;
206da6c28aaSamw 		if (is_dir) {
207743a77edSAlan Wright 			if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_SUBDIRECTORY) != 0)
208eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 				rc = smb_vop_mkdir(dnode->vp, name, attr,
209743a77edSAlan Wright 				    &vp, flags, cr, vsap);
210da6c28aaSamw 		} else {
211743a77edSAlan Wright 			if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_FILE) != 0)
212eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 				rc = smb_vop_create(dnode->vp, name, attr,
213743a77edSAlan Wright 				    &vp, flags, cr, vsap);
214da6c28aaSamw 		}
215da6c28aaSamw 
216da6c28aaSamw 		if (vsap != NULL)
217da6c28aaSamw 			kmem_free(vsap->vsa_aclentp, aclbsize);
218da6c28aaSamw 
219da6c28aaSamw 		if (rc != 0)
220da6c28aaSamw 			return (rc);
221da6c28aaSamw 
222da6c28aaSamw 		set_attr.sa_mask = 0;
223da6c28aaSamw 
224da6c28aaSamw 		/*
225da6c28aaSamw 		 * Ideally we should be able to specify the owner and owning
226da6c28aaSamw 		 * group at create time along with the ACL. Since we cannot
227da6c28aaSamw 		 * do that right now, kcred is passed to smb_vop_setattr so it
228da6c28aaSamw 		 * doesn't fail due to lack of permission.
229da6c28aaSamw 		 */
230da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
231da6c28aaSamw 			set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
232da6c28aaSamw 			set_attr.sa_mask |= SMB_AT_UID;
233da6c28aaSamw 		}
234da6c28aaSamw 
235da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
236da6c28aaSamw 			set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
237da6c28aaSamw 			set_attr.sa_mask |= SMB_AT_GID;
238da6c28aaSamw 		}
239da6c28aaSamw 
2409660e5cbSJanice Chang 		if (set_attr.sa_mask)
2419660e5cbSJanice Chang 			rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcred);
242da6c28aaSamw 
2432c1b14e5Sjose borrego 		if (rc == 0) {
2442c1b14e5Sjose borrego 			*ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
245037cac00Sjoyce mcintosh 			    name, dnode, NULL);
2462c1b14e5Sjose borrego 
2477f667e74Sjose borrego 			if (*ret_snode == NULL)
2482c1b14e5Sjose borrego 				rc = ENOMEM;
2497f667e74Sjose borrego 
2507f667e74Sjose borrego 			VN_RELE(vp);
2512c1b14e5Sjose borrego 		}
252da6c28aaSamw 	} else {
253da6c28aaSamw 		/*
254da6c28aaSamw 		 * For filesystems that don't support ACL-on-create, try
255da6c28aaSamw 		 * to set the specified SD after create, which could actually
256da6c28aaSamw 		 * fail because of conflicts between inherited security
257da6c28aaSamw 		 * attributes upon creation and the specified SD.
258da6c28aaSamw 		 *
259da6c28aaSamw 		 * Passing kcred to smb_fsop_sdwrite() to overcome this issue.
260da6c28aaSamw 		 */
261da6c28aaSamw 
262da6c28aaSamw 		if (is_dir) {
263eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_vop_mkdir(dnode->vp, name, attr, &vp,
2642c1b14e5Sjose borrego 			    flags, cr, NULL);
265da6c28aaSamw 		} else {
266eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_vop_create(dnode->vp, name, attr, &vp,
2672c1b14e5Sjose borrego 			    flags, cr, NULL);
268da6c28aaSamw 		}
269da6c28aaSamw 
27055bf511dSas200622 		if (rc != 0)
27155bf511dSas200622 			return (rc);
27255bf511dSas200622 
2732c1b14e5Sjose borrego 		*ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
274037cac00Sjoyce mcintosh 		    name, dnode, NULL);
275da6c28aaSamw 
2762c1b14e5Sjose borrego 		if (*ret_snode != NULL) {
2772c1b14e5Sjose borrego 			if (!smb_tree_has_feature(sr->tid_tree,
2782c1b14e5Sjose borrego 			    SMB_TREE_NFS_MOUNTED))
2792c1b14e5Sjose borrego 				rc = smb_fsop_sdwrite(sr, kcred, *ret_snode,
2802c1b14e5Sjose borrego 				    fs_sd, 1);
2812c1b14e5Sjose borrego 		} else {
282da6c28aaSamw 			rc = ENOMEM;
283da6c28aaSamw 		}
2847f667e74Sjose borrego 
2857f667e74Sjose borrego 		VN_RELE(vp);
286da6c28aaSamw 	}
287da6c28aaSamw 
28855bf511dSas200622 	if (rc != 0) {
2892c1b14e5Sjose borrego 		if (is_dir)
290eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			(void) smb_vop_rmdir(dnode->vp, name, flags, cr);
2912c1b14e5Sjose borrego 		else
292eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			(void) smb_vop_remove(dnode->vp, name, flags, cr);
29355bf511dSas200622 	}
29455bf511dSas200622 
295da6c28aaSamw 	return (rc);
296da6c28aaSamw }
297da6c28aaSamw 
298da6c28aaSamw /*
299da6c28aaSamw  * smb_fsop_create
300da6c28aaSamw  *
301da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
302da6c28aaSamw  * all the smb_vop_creates are performed with the appropriate credentials.
303eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * Please document any direct calls to explain the reason for avoiding
304eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * this wrapper.
305da6c28aaSamw  *
306da6c28aaSamw  * *ret_snode is returned with a reference upon success.  No reference is
307da6c28aaSamw  * taken if an error is returned.
308da6c28aaSamw  */
309da6c28aaSamw int
310037cac00Sjoyce mcintosh smb_fsop_create(smb_request_t *sr, cred_t *cr, smb_node_t *dnode,
311037cac00Sjoyce mcintosh     char *name, smb_attr_t *attr, smb_node_t **ret_snode)
312da6c28aaSamw {
313da6c28aaSamw 	int	rc = 0;
314eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	int	flags = 0;
315eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	char	*fname, *sname;
316eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	char	*longname = NULL;
317da6c28aaSamw 
318da6c28aaSamw 	ASSERT(cr);
319eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
320eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
321eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
322da6c28aaSamw 
323da6c28aaSamw 	ASSERT(ret_snode);
324da6c28aaSamw 	*ret_snode = 0;
325da6c28aaSamw 
326da6c28aaSamw 	ASSERT(name);
327da6c28aaSamw 	if (*name == 0)
328da6c28aaSamw 		return (EINVAL);
329da6c28aaSamw 
330da6c28aaSamw 	ASSERT(sr);
331da6c28aaSamw 	ASSERT(sr->tid_tree);
332c8ec8eeaSjose borrego 
333eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
334c8ec8eeaSjose borrego 		return (EACCES);
335c8ec8eeaSjose borrego 
336c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
337da6c28aaSamw 		return (EROFS);
338da6c28aaSamw 
339c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
340da6c28aaSamw 		flags = SMB_IGNORE_CASE;
3418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
3428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
343da6c28aaSamw 
3448b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_is_stream_name(name)) {
345da6c28aaSamw 		fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
346da6c28aaSamw 		sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
347eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_stream_parse_name(name, fname, sname);
348da6c28aaSamw 
349eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_create_stream(sr, cr, dnode,
350037cac00Sjoyce mcintosh 		    fname, sname, flags, attr, ret_snode);
3518b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
352da6c28aaSamw 		kmem_free(fname, MAXNAMELEN);
353da6c28aaSamw 		kmem_free(sname, MAXNAMELEN);
3548b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (rc);
355da6c28aaSamw 	}
3568b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
3578b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	/* Not a named stream */
358eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
3598b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_maybe_mangled_name(name)) {
3608b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
361eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
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;
578da6c28aaSamw 
579da6c28aaSamw 	if (smb_maybe_mangled_name(name)) {
580da6c28aaSamw 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
581eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
582da6c28aaSamw 		kmem_free(longname, MAXNAMELEN);
583da6c28aaSamw 
584da6c28aaSamw 		/*
585da6c28aaSamw 		 * If the name passed in by the client has an unmangled
586da6c28aaSamw 		 * equivalent that is found in the specified directory,
587da6c28aaSamw 		 * then the mkdir cannot succeed.  Return EEXIST.
588da6c28aaSamw 		 *
589da6c28aaSamw 		 * Only if ENOENT is returned will a mkdir be attempted.
590da6c28aaSamw 		 */
591da6c28aaSamw 
592da6c28aaSamw 		if (rc == 0)
593da6c28aaSamw 			rc = EEXIST;
594da6c28aaSamw 
595da6c28aaSamw 		if (rc != ENOENT)
596da6c28aaSamw 			return (rc);
597da6c28aaSamw 	}
598da6c28aaSamw 
599c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
600da6c28aaSamw 		flags = SMB_IGNORE_CASE;
601da6c28aaSamw 
60255bf511dSas200622 	if (op->sd) {
603da6c28aaSamw 		/*
604da6c28aaSamw 		 * SD sent by client in Windows format. Needs to be
605da6c28aaSamw 		 * converted to FS format. No inheritance.
606da6c28aaSamw 		 */
60755bf511dSas200622 		secinfo = smb_sd_get_secinfo(op->sd);
60855bf511dSas200622 		smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR);
609da6c28aaSamw 
61055bf511dSas200622 		status = smb_sd_tofs(op->sd, &fs_sd);
611da6c28aaSamw 		if (status == NT_STATUS_SUCCESS) {
612eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
613037cac00Sjoyce mcintosh 			    name, attr, ret_snode, &fs_sd);
614da6c28aaSamw 		}
615da6c28aaSamw 		else
616da6c28aaSamw 			rc = EINVAL;
61755bf511dSas200622 		smb_fssd_term(&fs_sd);
618da6c28aaSamw 	} else if (sr->tid_tree->t_acltype == ACE_T) {
619da6c28aaSamw 		/*
620da6c28aaSamw 		 * No incoming SD and filesystem is ZFS
621da6c28aaSamw 		 * Server applies Windows inheritance rules,
622da6c28aaSamw 		 * see smb_fsop_sdinherit() comments as to why.
623da6c28aaSamw 		 */
62455bf511dSas200622 		smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR);
625eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
626da6c28aaSamw 		if (rc == 0) {
627eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
628037cac00Sjoyce mcintosh 			    name, attr, ret_snode, &fs_sd);
629da6c28aaSamw 		}
630da6c28aaSamw 
63155bf511dSas200622 		smb_fssd_term(&fs_sd);
632da6c28aaSamw 
633da6c28aaSamw 	} else {
634eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, flags, cr,
635dc20a302Sas200622 		    NULL);
636da6c28aaSamw 
637da6c28aaSamw 		if (rc == 0) {
638da6c28aaSamw 			*ret_snode = smb_node_lookup(sr, op, cr, vp, name,
639037cac00Sjoyce mcintosh 			    dnode, NULL);
640da6c28aaSamw 
6417f667e74Sjose borrego 			if (*ret_snode == NULL)
642da6c28aaSamw 				rc = ENOMEM;
6437f667e74Sjose borrego 
6447f667e74Sjose borrego 			VN_RELE(vp);
645da6c28aaSamw 		}
646da6c28aaSamw 	}
647da6c28aaSamw 
648da6c28aaSamw 	return (rc);
649da6c28aaSamw }
650da6c28aaSamw 
651da6c28aaSamw /*
652da6c28aaSamw  * smb_fsop_remove
653da6c28aaSamw  *
654da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
655da6c28aaSamw  * the the calls are performed with the appropriate credentials.
656da6c28aaSamw  * Please document any direct call to explain the reason
657da6c28aaSamw  * for avoiding this wrapper.
658da6c28aaSamw  *
659da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
660da6c28aaSamw  *
661da6c28aaSamw  * A null smb_request might be passed to this function.
662da6c28aaSamw  */
663da6c28aaSamw int
664da6c28aaSamw smb_fsop_remove(
665faa1795aSjb150015     smb_request_t	*sr,
666da6c28aaSamw     cred_t		*cr,
667eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t		*dnode,
668da6c28aaSamw     char		*name,
6698b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States     uint32_t		flags)
670da6c28aaSamw {
671da6c28aaSamw 	smb_node_t	*fnode;
672da6c28aaSamw 	char		*longname;
673da6c28aaSamw 	char		*fname;
674da6c28aaSamw 	char		*sname;
675da6c28aaSamw 	int		rc;
676da6c28aaSamw 
677da6c28aaSamw 	ASSERT(cr);
678da6c28aaSamw 	/*
679da6c28aaSamw 	 * The state of the node could be SMB_NODE_STATE_DESTROYING if this
680da6c28aaSamw 	 * function is called during the deletion of the node (because of
681da6c28aaSamw 	 * DELETE_ON_CLOSE).
682da6c28aaSamw 	 */
683eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
684eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
685da6c28aaSamw 
686eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 ||
687743a77edSAlan Wright 	    SMB_TREE_HAS_ACCESS(sr, ACE_DELETE) == 0)
688da6c28aaSamw 		return (EACCES);
689da6c28aaSamw 
690c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
691da6c28aaSamw 		return (EROFS);
692da6c28aaSamw 
693da6c28aaSamw 	fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
694da6c28aaSamw 	sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
695da6c28aaSamw 
696eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (dnode->flags & NODE_XATTR_DIR) {
697*1fcced4cSJordan Brown 		rc = smb_vop_stream_remove(dnode->n_dnode->vp,
698cbfb650aScp160787 		    name, flags, cr);
699eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	} else if (smb_is_stream_name(name)) {
700eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_stream_parse_name(name, fname, sname);
7018d7e4166Sjose borrego 
702cbfb650aScp160787 		/*
703da6c28aaSamw 		 * Look up the unnamed stream (i.e. fname).
704da6c28aaSamw 		 * Unmangle processing will be done on fname
705da6c28aaSamw 		 * as well as any link target.
706da6c28aaSamw 		 */
707da6c28aaSamw 
708da6c28aaSamw 		rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
709037cac00Sjoyce mcintosh 		    sr->tid_tree->t_snode, dnode, fname, &fnode);
710da6c28aaSamw 
711da6c28aaSamw 		if (rc != 0) {
712da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
713da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
714da6c28aaSamw 			return (rc);
715da6c28aaSamw 		}
716da6c28aaSamw 
717da6c28aaSamw 		/*
718da6c28aaSamw 		 * XXX
719da6c28aaSamw 		 * Need to find out what permission is required by NTFS
720da6c28aaSamw 		 * to remove a stream.
721da6c28aaSamw 		 */
722dc20a302Sas200622 		rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr);
723da6c28aaSamw 
724da6c28aaSamw 		smb_node_release(fnode);
725da6c28aaSamw 	} else {
726eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_remove(dnode->vp, name, flags, cr);
727da6c28aaSamw 
728da6c28aaSamw 		if (rc == ENOENT) {
729da6c28aaSamw 			if (smb_maybe_mangled_name(name) == 0) {
730da6c28aaSamw 				kmem_free(fname, MAXNAMELEN);
731da6c28aaSamw 				kmem_free(sname, MAXNAMELEN);
732da6c28aaSamw 				return (rc);
733da6c28aaSamw 			}
734da6c28aaSamw 			longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
735da6c28aaSamw 
736eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_unmangle_name(dnode, name,
7378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			    longname, MAXNAMELEN);
738da6c28aaSamw 
739da6c28aaSamw 			if (rc == 0) {
740da6c28aaSamw 				/*
7418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 				 * longname is the real (case-sensitive)
7428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 				 * on-disk name.
743da6c28aaSamw 				 * We make sure we do a remove on this exact
744da6c28aaSamw 				 * name, as the name was mangled and denotes
745da6c28aaSamw 				 * a unique file.
746da6c28aaSamw 				 */
747da6c28aaSamw 				flags &= ~SMB_IGNORE_CASE;
748eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 				rc = smb_vop_remove(dnode->vp, longname,
749dc20a302Sas200622 				    flags, cr);
750da6c28aaSamw 			}
751da6c28aaSamw 
752da6c28aaSamw 			kmem_free(longname, MAXNAMELEN);
753da6c28aaSamw 		}
754da6c28aaSamw 	}
755da6c28aaSamw 
756da6c28aaSamw 	kmem_free(fname, MAXNAMELEN);
757da6c28aaSamw 	kmem_free(sname, MAXNAMELEN);
758da6c28aaSamw 	return (rc);
759da6c28aaSamw }
760da6c28aaSamw 
761da6c28aaSamw /*
762da6c28aaSamw  * smb_fsop_remove_streams
763da6c28aaSamw  *
764da6c28aaSamw  * This function removes a file's streams without removing the
765da6c28aaSamw  * file itself.
766da6c28aaSamw  *
7677f667e74Sjose borrego  * It is assumed that fnode is not a link.
768da6c28aaSamw  */
769da6c28aaSamw int
770faa1795aSjb150015 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode)
771da6c28aaSamw {
7727f667e74Sjose borrego 	int rc, flags = 0;
7737f667e74Sjose borrego 	uint16_t odid;
7747f667e74Sjose borrego 	smb_odir_t *od;
7757f667e74Sjose borrego 	smb_odirent_t *odirent;
7767f667e74Sjose borrego 	boolean_t eos;
777da6c28aaSamw 
778c8ec8eeaSjose borrego 	ASSERT(sr);
779da6c28aaSamw 	ASSERT(cr);
780da6c28aaSamw 	ASSERT(fnode);
781da6c28aaSamw 	ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
782da6c28aaSamw 	ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
783da6c28aaSamw 
784eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0) {
785eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, EACCES);
786eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
787eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
788da6c28aaSamw 
789eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_IS_READONLY(sr)) {
790eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, EROFS);
791eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
792eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
793da6c28aaSamw 
794c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
795da6c28aaSamw 		flags = SMB_IGNORE_CASE;
796eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
7978b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
7988b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
799da6c28aaSamw 
800eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if ((odid = smb_odir_openat(sr, fnode)) == 0) {
801eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, ENOENT);
802eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
803eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
804eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
805eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) {
806eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, ENOENT);
807eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
808eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
8097f667e74Sjose borrego 
8107f667e74Sjose borrego 	odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
811da6c28aaSamw 	for (;;) {
8127f667e74Sjose borrego 		rc = smb_odir_read(sr, od, odirent, &eos);
8137f667e74Sjose borrego 		if ((rc != 0) || (eos))
814da6c28aaSamw 			break;
8157f667e74Sjose borrego 		(void) smb_vop_remove(od->d_dnode->vp, odirent->od_name,
8167f667e74Sjose borrego 		    flags, cr);
817da6c28aaSamw 	}
8187f667e74Sjose borrego 	kmem_free(odirent, sizeof (smb_odirent_t));
8197f667e74Sjose borrego 
8207f667e74Sjose borrego 	smb_odir_close(od);
821a1511e6bSjoyce mcintosh 	smb_odir_release(od);
822da6c28aaSamw 	return (rc);
823da6c28aaSamw }
824da6c28aaSamw 
825da6c28aaSamw /*
826da6c28aaSamw  * smb_fsop_rmdir
827da6c28aaSamw  *
828da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
829da6c28aaSamw  * the the calls are performed with the appropriate credentials.
830da6c28aaSamw  * Please document any direct call to explain the reason
831da6c28aaSamw  * for avoiding this wrapper.
832da6c28aaSamw  *
833da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
834da6c28aaSamw  */
835da6c28aaSamw int
836da6c28aaSamw smb_fsop_rmdir(
837faa1795aSjb150015     smb_request_t	*sr,
838da6c28aaSamw     cred_t		*cr,
839eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t		*dnode,
840da6c28aaSamw     char		*name,
8418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States     uint32_t		flags)
842da6c28aaSamw {
843da6c28aaSamw 	int		rc;
844da6c28aaSamw 	char		*longname;
845da6c28aaSamw 
846da6c28aaSamw 	ASSERT(cr);
847da6c28aaSamw 	/*
848da6c28aaSamw 	 * The state of the node could be SMB_NODE_STATE_DESTROYING if this
849da6c28aaSamw 	 * function is called during the deletion of the node (because of
850da6c28aaSamw 	 * DELETE_ON_CLOSE).
851da6c28aaSamw 	 */
852eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
853eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
854da6c28aaSamw 
855eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 ||
856743a77edSAlan Wright 	    SMB_TREE_HAS_ACCESS(sr, ACE_DELETE_CHILD) == 0)
857da6c28aaSamw 		return (EACCES);
858da6c28aaSamw 
859c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
860da6c28aaSamw 		return (EROFS);
861da6c28aaSamw 
862eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_rmdir(dnode->vp, name, flags, cr);
863da6c28aaSamw 
864da6c28aaSamw 	if (rc == ENOENT) {
865da6c28aaSamw 		if (smb_maybe_mangled_name(name) == 0)
866da6c28aaSamw 			return (rc);
867da6c28aaSamw 
868da6c28aaSamw 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
869eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
870da6c28aaSamw 
871da6c28aaSamw 		if (rc == 0) {
872da6c28aaSamw 			/*
8738b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			 * longname is the real (case-sensitive)
8748b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			 * on-disk name.
875da6c28aaSamw 			 * We make sure we do a rmdir on this exact
876da6c28aaSamw 			 * name, as the name was mangled and denotes
877da6c28aaSamw 			 * a unique directory.
878da6c28aaSamw 			 */
879da6c28aaSamw 			flags &= ~SMB_IGNORE_CASE;
880eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_vop_rmdir(dnode->vp, longname, flags, cr);
881da6c28aaSamw 		}
882da6c28aaSamw 
883da6c28aaSamw 		kmem_free(longname, MAXNAMELEN);
884da6c28aaSamw 	}
885da6c28aaSamw 
886da6c28aaSamw 	return (rc);
887da6c28aaSamw }
888da6c28aaSamw 
889da6c28aaSamw /*
890da6c28aaSamw  * smb_fsop_getattr
891da6c28aaSamw  *
892da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
893da6c28aaSamw  * the the calls are performed with the appropriate credentials.
894da6c28aaSamw  * Please document any direct call to explain the reason
895da6c28aaSamw  * for avoiding this wrapper.
896da6c28aaSamw  *
897da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
898da6c28aaSamw  */
899da6c28aaSamw int
900faa1795aSjb150015 smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
901da6c28aaSamw     smb_attr_t *attr)
902da6c28aaSamw {
903da6c28aaSamw 	smb_node_t *unnamed_node;
904da6c28aaSamw 	vnode_t *unnamed_vp = NULL;
905da6c28aaSamw 	uint32_t status;
906da6c28aaSamw 	uint32_t access = 0;
907da6c28aaSamw 	int flags = 0;
908dc20a302Sas200622 	int rc;
909da6c28aaSamw 
910da6c28aaSamw 	ASSERT(cr);
911da6c28aaSamw 	ASSERT(snode);
912da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
913da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
914da6c28aaSamw 
915743a77edSAlan Wright 	if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0 ||
916743a77edSAlan Wright 	    SMB_TREE_HAS_ACCESS(sr, ACE_READ_ATTRIBUTES) == 0)
917da6c28aaSamw 		return (EACCES);
918da6c28aaSamw 
919037cac00Sjoyce mcintosh 	/* sr could be NULL in some cases */
920037cac00Sjoyce mcintosh 	if (sr && sr->fid_ofile) {
921da6c28aaSamw 		/* if uid and/or gid is requested */
922da6c28aaSamw 		if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID))
923da6c28aaSamw 			access |= READ_CONTROL;
924da6c28aaSamw 
925da6c28aaSamw 		/* if anything else is also requested */
926da6c28aaSamw 		if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID))
927da6c28aaSamw 			access |= FILE_READ_ATTRIBUTES;
928da6c28aaSamw 
929da6c28aaSamw 		status = smb_ofile_access(sr->fid_ofile, cr, access);
930da6c28aaSamw 		if (status != NT_STATUS_SUCCESS)
931da6c28aaSamw 			return (EACCES);
932da6c28aaSamw 
933c8ec8eeaSjose borrego 		if (smb_tree_has_feature(sr->tid_tree,
934c8ec8eeaSjose borrego 		    SMB_TREE_ACEMASKONACCESS))
935da6c28aaSamw 			flags = ATTR_NOACLCHECK;
936da6c28aaSamw 	}
937da6c28aaSamw 
938da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
939da6c28aaSamw 
940da6c28aaSamw 	if (unnamed_node) {
941da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
942da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
943da6c28aaSamw 		unnamed_vp = unnamed_node->vp;
944da6c28aaSamw 	}
945da6c28aaSamw 
946dc20a302Sas200622 	rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr);
947dc20a302Sas200622 	return (rc);
948da6c28aaSamw }
949da6c28aaSamw 
950da6c28aaSamw /*
951b1352070SAlan Wright  * smb_fsop_link
952b1352070SAlan Wright  *
953b1352070SAlan Wright  * All SMB functions should use this smb_vop_link wrapper to ensure that
954b1352070SAlan Wright  * the smb_vop_link is performed with the appropriate credentials.
955b1352070SAlan Wright  * Please document any direct call to smb_vop_link to explain the reason
956b1352070SAlan Wright  * for avoiding this wrapper.
957b1352070SAlan Wright  *
958b1352070SAlan Wright  * It is assumed that references exist on from_dnode and to_dnode coming
959b1352070SAlan Wright  * into this routine.
960b1352070SAlan Wright  */
961b1352070SAlan Wright int
962b1352070SAlan Wright smb_fsop_link(smb_request_t *sr, cred_t *cr, smb_node_t *to_dnode,
963b1352070SAlan Wright     smb_node_t *from_fnode, char *to_name)
964b1352070SAlan Wright {
965b1352070SAlan Wright 	char	*longname = NULL;
966b1352070SAlan Wright 	int	flags = 0;
967b1352070SAlan Wright 	int	rc;
968b1352070SAlan Wright 
969b1352070SAlan Wright 	ASSERT(sr);
970b1352070SAlan Wright 	ASSERT(sr->tid_tree);
971b1352070SAlan Wright 	ASSERT(cr);
972b1352070SAlan Wright 	ASSERT(to_dnode);
973b1352070SAlan Wright 	ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC);
974b1352070SAlan Wright 	ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING);
975b1352070SAlan Wright 	ASSERT(from_fnode);
976b1352070SAlan Wright 	ASSERT(from_fnode->n_magic == SMB_NODE_MAGIC);
977b1352070SAlan Wright 	ASSERT(from_fnode->n_state != SMB_NODE_STATE_DESTROYING);
978b1352070SAlan Wright 
979b1352070SAlan Wright 	if (SMB_TREE_CONTAINS_NODE(sr, from_fnode) == 0)
980b1352070SAlan Wright 		return (EACCES);
981b1352070SAlan Wright 
982b1352070SAlan Wright 	if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0)
983b1352070SAlan Wright 		return (EACCES);
984b1352070SAlan Wright 
985b1352070SAlan Wright 	if (SMB_TREE_IS_READONLY(sr))
986b1352070SAlan Wright 		return (EROFS);
987b1352070SAlan Wright 
988b1352070SAlan Wright 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
989b1352070SAlan Wright 		flags = SMB_IGNORE_CASE;
990b1352070SAlan Wright 	if (SMB_TREE_SUPPORTS_CATIA(sr))
991b1352070SAlan Wright 		flags |= SMB_CATIA;
992b1352070SAlan Wright 
993b1352070SAlan Wright 	if (smb_maybe_mangled_name(to_name)) {
994b1352070SAlan Wright 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
995b1352070SAlan Wright 		rc = smb_unmangle_name(to_dnode, to_name, longname, MAXNAMELEN);
996b1352070SAlan Wright 		kmem_free(longname, MAXNAMELEN);
997b1352070SAlan Wright 
998b1352070SAlan Wright 		if (rc == 0)
999b1352070SAlan Wright 			rc = EEXIST;
1000b1352070SAlan Wright 		if (rc != ENOENT)
1001b1352070SAlan Wright 			return (rc);
1002b1352070SAlan Wright 	}
1003b1352070SAlan Wright 
1004b1352070SAlan Wright 	rc = smb_vop_link(to_dnode->vp, from_fnode->vp, to_name, flags, cr);
1005b1352070SAlan Wright 	return (rc);
1006b1352070SAlan Wright }
1007b1352070SAlan Wright 
1008b1352070SAlan Wright /*
1009da6c28aaSamw  * smb_fsop_rename
1010da6c28aaSamw  *
1011da6c28aaSamw  * All SMB functions should use this smb_vop_rename wrapper to ensure that
1012da6c28aaSamw  * the smb_vop_rename is performed with the appropriate credentials.
1013da6c28aaSamw  * Please document any direct call to smb_vop_rename to explain the reason
1014da6c28aaSamw  * for avoiding this wrapper.
1015da6c28aaSamw  *
1016eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * It is assumed that references exist on from_dnode and to_dnode coming
1017da6c28aaSamw  * into this routine.
1018da6c28aaSamw  */
1019da6c28aaSamw int
1020da6c28aaSamw smb_fsop_rename(
1021faa1795aSjb150015     smb_request_t *sr,
1022da6c28aaSamw     cred_t *cr,
1023eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *from_dnode,
1024da6c28aaSamw     char *from_name,
1025eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *to_dnode,
1026da6c28aaSamw     char *to_name)
1027da6c28aaSamw {
1028da6c28aaSamw 	smb_node_t *from_snode;
1029da6c28aaSamw 	vnode_t *from_vp;
10308b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	int flags = 0, ret_flags;
1031da6c28aaSamw 	int rc;
1032743a77edSAlan Wright 	boolean_t isdir;
1033da6c28aaSamw 
1034da6c28aaSamw 	ASSERT(cr);
1035eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(from_dnode);
1036eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(from_dnode->n_magic == SMB_NODE_MAGIC);
1037eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(from_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1038da6c28aaSamw 
1039eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(to_dnode);
1040eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC);
1041eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1042da6c28aaSamw 
1043eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, from_dnode) == 0)
1044da6c28aaSamw 		return (EACCES);
1045da6c28aaSamw 
1046eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0)
1047da6c28aaSamw 		return (EACCES);
1048da6c28aaSamw 
1049da6c28aaSamw 	ASSERT(sr);
1050da6c28aaSamw 	ASSERT(sr->tid_tree);
1051c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1052da6c28aaSamw 		return (EROFS);
1053da6c28aaSamw 
1054da6c28aaSamw 	/*
1055c8ec8eeaSjose borrego 	 * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE
1056da6c28aaSamw 	 * here.
1057da6c28aaSamw 	 *
1058da6c28aaSamw 	 * A case-sensitive rename is always done in this routine
1059da6c28aaSamw 	 * because we are using the on-disk name from an earlier lookup.
1060da6c28aaSamw 	 * If a mangled name was passed in by the caller (denoting a
1061da6c28aaSamw 	 * deterministic lookup), then the exact file must be renamed
1062da6c28aaSamw 	 * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or
1063da6c28aaSamw 	 * else the underlying file system might return a "first-match"
1064da6c28aaSamw 	 * on this on-disk name, possibly resulting in the wrong file).
1065da6c28aaSamw 	 */
1066da6c28aaSamw 
10678b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
10688b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
10698b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
1070da6c28aaSamw 	/*
1071da6c28aaSamw 	 * XXX: Lock required through smb_node_release() below?
1072da6c28aaSamw 	 */
1073da6c28aaSamw 
1074eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_lookup(from_dnode->vp, from_name, &from_vp, NULL,
10758b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	    flags, &ret_flags, NULL, cr);
1076da6c28aaSamw 
1077da6c28aaSamw 	if (rc != 0)
1078da6c28aaSamw 		return (rc);
1079da6c28aaSamw 
1080743a77edSAlan Wright 	isdir = from_vp->v_type == VDIR;
1081743a77edSAlan Wright 
1082743a77edSAlan Wright 	if ((isdir && SMB_TREE_HAS_ACCESS(sr,
1083743a77edSAlan Wright 	    ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY) !=
1084743a77edSAlan Wright 	    (ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY)) ||
1085743a77edSAlan Wright 	    (!isdir && SMB_TREE_HAS_ACCESS(sr, ACE_DELETE | ACE_ADD_FILE) !=
1086743a77edSAlan Wright 	    (ACE_DELETE | ACE_ADD_FILE)))
1087743a77edSAlan Wright 		return (EACCES);
1088743a77edSAlan Wright 
1089eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_rename(from_dnode->vp, from_name, to_dnode->vp,
1090dc20a302Sas200622 	    to_name, flags, cr);
1091da6c28aaSamw 
1092da6c28aaSamw 	if (rc == 0) {
1093da6c28aaSamw 		from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name,
1094037cac00Sjoyce mcintosh 		    from_dnode, NULL);
1095da6c28aaSamw 
1096da6c28aaSamw 		if (from_snode == NULL) {
10977f667e74Sjose borrego 			rc = ENOMEM;
1098da6c28aaSamw 		} else {
1099eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_node_rename(from_dnode, from_snode,
1100eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			    to_dnode, to_name);
11017f667e74Sjose borrego 			smb_node_release(from_snode);
1102da6c28aaSamw 		}
11037f667e74Sjose borrego 	}
11047f667e74Sjose borrego 	VN_RELE(from_vp);
1105da6c28aaSamw 
1106da6c28aaSamw 	/* XXX: unlock */
1107da6c28aaSamw 
1108da6c28aaSamw 	return (rc);
1109da6c28aaSamw }
1110da6c28aaSamw 
1111da6c28aaSamw /*
1112da6c28aaSamw  * smb_fsop_setattr
1113da6c28aaSamw  *
1114da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
1115da6c28aaSamw  * the the calls are performed with the appropriate credentials.
1116da6c28aaSamw  * Please document any direct call to explain the reason
1117da6c28aaSamw  * for avoiding this wrapper.
1118da6c28aaSamw  *
1119da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
1120da6c28aaSamw  * A null smb_request might be passed to this function.
1121da6c28aaSamw  */
1122da6c28aaSamw int
1123da6c28aaSamw smb_fsop_setattr(
1124da6c28aaSamw     smb_request_t	*sr,
1125da6c28aaSamw     cred_t		*cr,
1126da6c28aaSamw     smb_node_t		*snode,
1127037cac00Sjoyce mcintosh     smb_attr_t		*set_attr)
1128da6c28aaSamw {
1129da6c28aaSamw 	smb_node_t *unnamed_node;
1130da6c28aaSamw 	vnode_t *unnamed_vp = NULL;
1131da6c28aaSamw 	uint32_t status;
11322c1b14e5Sjose borrego 	uint32_t access;
1133da6c28aaSamw 	int rc = 0;
1134da6c28aaSamw 	int flags = 0;
11352c1b14e5Sjose borrego 	uint_t sa_mask;
1136da6c28aaSamw 
1137da6c28aaSamw 	ASSERT(cr);
1138da6c28aaSamw 	ASSERT(snode);
1139da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1140da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1141da6c28aaSamw 
1142c8ec8eeaSjose borrego 	if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0)
1143da6c28aaSamw 		return (EACCES);
1144da6c28aaSamw 
1145c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1146da6c28aaSamw 		return (EROFS);
1147da6c28aaSamw 
1148743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr,
1149743a77edSAlan Wright 	    ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0)
1150743a77edSAlan Wright 		return (EACCES);
1151743a77edSAlan Wright 
1152c8ec8eeaSjose borrego 	if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) {
1153c8ec8eeaSjose borrego 		if (sr->fid_ofile) {
1154c8ec8eeaSjose borrego 			if (SMB_OFILE_IS_READONLY(sr->fid_ofile))
1155c8ec8eeaSjose borrego 				return (EACCES);
1156c8ec8eeaSjose borrego 		} else {
1157c8ec8eeaSjose borrego 			if (SMB_PATHFILE_IS_READONLY(sr, snode))
1158c8ec8eeaSjose borrego 				return (EACCES);
1159c8ec8eeaSjose borrego 		}
1160c8ec8eeaSjose borrego 	}
1161c8ec8eeaSjose borrego 
1162da6c28aaSamw 	/* sr could be NULL in some cases */
1163da6c28aaSamw 	if (sr && sr->fid_ofile) {
11642c1b14e5Sjose borrego 		sa_mask = set_attr->sa_mask;
11652c1b14e5Sjose borrego 		access = 0;
1166c8ec8eeaSjose borrego 
11672c1b14e5Sjose borrego 		if (sa_mask & SMB_AT_SIZE) {
11682c1b14e5Sjose borrego 			access |= FILE_WRITE_DATA;
11692c1b14e5Sjose borrego 			sa_mask &= ~SMB_AT_SIZE;
11702c1b14e5Sjose borrego 		}
11712c1b14e5Sjose borrego 
11722c1b14e5Sjose borrego 		if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) {
1173da6c28aaSamw 			access |= WRITE_OWNER;
11742c1b14e5Sjose borrego 			sa_mask &= ~(SMB_AT_UID|SMB_AT_GID);
11752c1b14e5Sjose borrego 		}
1176da6c28aaSamw 
11772c1b14e5Sjose borrego 		if (sa_mask)
1178da6c28aaSamw 			access |= FILE_WRITE_ATTRIBUTES;
1179da6c28aaSamw 
1180da6c28aaSamw 		status = smb_ofile_access(sr->fid_ofile, cr, access);
1181da6c28aaSamw 		if (status != NT_STATUS_SUCCESS)
1182da6c28aaSamw 			return (EACCES);
1183da6c28aaSamw 
1184c8ec8eeaSjose borrego 		if (smb_tree_has_feature(sr->tid_tree,
1185c8ec8eeaSjose borrego 		    SMB_TREE_ACEMASKONACCESS))
1186da6c28aaSamw 			flags = ATTR_NOACLCHECK;
1187da6c28aaSamw 	}
1188da6c28aaSamw 
1189da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1190da6c28aaSamw 
1191da6c28aaSamw 	if (unnamed_node) {
1192da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1193da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1194da6c28aaSamw 		unnamed_vp = unnamed_node->vp;
1195da6c28aaSamw 	}
1196da6c28aaSamw 
11979660e5cbSJanice Chang 	rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr);
1198da6c28aaSamw 	return (rc);
1199da6c28aaSamw }
1200da6c28aaSamw 
1201da6c28aaSamw /*
1202da6c28aaSamw  * smb_fsop_read
1203da6c28aaSamw  *
1204da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
1205da6c28aaSamw  * the the calls are performed with the appropriate credentials.
1206da6c28aaSamw  * Please document any direct call to explain the reason
1207da6c28aaSamw  * for avoiding this wrapper.
1208da6c28aaSamw  *
1209da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
1210da6c28aaSamw  */
1211da6c28aaSamw int
1212037cac00Sjoyce mcintosh smb_fsop_read(smb_request_t *sr, cred_t *cr, smb_node_t *snode, uio_t *uio)
1213da6c28aaSamw {
1214c8ec8eeaSjose borrego 	caller_context_t ct;
1215dc20a302Sas200622 	int svmand;
1216da6c28aaSamw 	int rc;
1217da6c28aaSamw 
1218da6c28aaSamw 	ASSERT(cr);
1219da6c28aaSamw 	ASSERT(snode);
1220da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1221da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1222da6c28aaSamw 
1223da6c28aaSamw 	ASSERT(sr);
1224da6c28aaSamw 	ASSERT(sr->fid_ofile);
1225da6c28aaSamw 
1226743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_DATA) == 0)
1227743a77edSAlan Wright 		return (EACCES);
1228743a77edSAlan Wright 
1229da6c28aaSamw 	rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA);
1230da6c28aaSamw 	if (rc != NT_STATUS_SUCCESS) {
1231da6c28aaSamw 		rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE);
1232da6c28aaSamw 		if (rc != NT_STATUS_SUCCESS)
1233da6c28aaSamw 			return (EACCES);
1234da6c28aaSamw 	}
1235da6c28aaSamw 
1236da6c28aaSamw 	/*
1237da6c28aaSamw 	 * Streams permission are checked against the unnamed stream,
1238da6c28aaSamw 	 * but in FS level they have their own permissions. To avoid
1239da6c28aaSamw 	 * rejection by FS due to lack of permission on the actual
1240da6c28aaSamw 	 * extended attr kcred is passed for streams.
1241da6c28aaSamw 	 */
1242037cac00Sjoyce mcintosh 	if (SMB_IS_STREAM(snode))
1243da6c28aaSamw 		cr = kcred;
1244da6c28aaSamw 
1245dc20a302Sas200622 	smb_node_start_crit(snode, RW_READER);
1246c8ec8eeaSjose borrego 	rc = nbl_svmand(snode->vp, kcred, &svmand);
1247dc20a302Sas200622 	if (rc) {
1248dc20a302Sas200622 		smb_node_end_crit(snode);
1249dc20a302Sas200622 		return (rc);
1250dc20a302Sas200622 	}
1251da6c28aaSamw 
1252c8ec8eeaSjose borrego 	ct = smb_ct;
1253c8ec8eeaSjose borrego 	ct.cc_pid = sr->fid_ofile->f_uniqid;
1254dc20a302Sas200622 	rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset,
1255c8ec8eeaSjose borrego 	    uio->uio_iov->iov_len, svmand, &ct);
1256dc20a302Sas200622 
1257dc20a302Sas200622 	if (rc) {
1258dc20a302Sas200622 		smb_node_end_crit(snode);
12596537f381Sas200622 		return (ERANGE);
1260dc20a302Sas200622 	}
1261037cac00Sjoyce mcintosh 
1262dc20a302Sas200622 	rc = smb_vop_read(snode->vp, uio, cr);
1263dc20a302Sas200622 	smb_node_end_crit(snode);
1264da6c28aaSamw 
1265da6c28aaSamw 	return (rc);
1266da6c28aaSamw }
1267da6c28aaSamw 
1268da6c28aaSamw /*
1269da6c28aaSamw  * smb_fsop_write
1270da6c28aaSamw  *
1271da6c28aaSamw  * This is a wrapper function used for smb_write and smb_write_raw operations.
1272da6c28aaSamw  *
1273da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
1274da6c28aaSamw  */
1275da6c28aaSamw int
1276da6c28aaSamw smb_fsop_write(
1277faa1795aSjb150015     smb_request_t *sr,
1278da6c28aaSamw     cred_t *cr,
1279da6c28aaSamw     smb_node_t *snode,
1280da6c28aaSamw     uio_t *uio,
1281da6c28aaSamw     uint32_t *lcount,
12823db3f65cSamw     int ioflag)
1283da6c28aaSamw {
1284c8ec8eeaSjose borrego 	caller_context_t ct;
1285dc20a302Sas200622 	int svmand;
1286da6c28aaSamw 	int rc;
1287da6c28aaSamw 
1288da6c28aaSamw 	ASSERT(cr);
1289da6c28aaSamw 	ASSERT(snode);
1290da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1291da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1292da6c28aaSamw 
1293da6c28aaSamw 	ASSERT(sr);
1294da6c28aaSamw 	ASSERT(sr->tid_tree);
1295da6c28aaSamw 	ASSERT(sr->fid_ofile);
1296da6c28aaSamw 
1297c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1298da6c28aaSamw 		return (EROFS);
1299dc20a302Sas200622 
1300743a77edSAlan Wright 	if (SMB_OFILE_IS_READONLY(sr->fid_ofile) ||
1301743a77edSAlan Wright 	    SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_DATA | ACE_APPEND_DATA) == 0)
1302c8ec8eeaSjose borrego 		return (EACCES);
1303c8ec8eeaSjose borrego 
1304da6c28aaSamw 	rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA);
1305dc20a302Sas200622 	if (rc != NT_STATUS_SUCCESS) {
1306dc20a302Sas200622 		rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA);
1307da6c28aaSamw 		if (rc != NT_STATUS_SUCCESS)
1308da6c28aaSamw 			return (EACCES);
1309dc20a302Sas200622 	}
1310da6c28aaSamw 
1311da6c28aaSamw 	/*
1312da6c28aaSamw 	 * Streams permission are checked against the unnamed stream,
1313da6c28aaSamw 	 * but in FS level they have their own permissions. To avoid
1314da6c28aaSamw 	 * rejection by FS due to lack of permission on the actual
1315da6c28aaSamw 	 * extended attr kcred is passed for streams.
1316da6c28aaSamw 	 */
1317037cac00Sjoyce mcintosh 	if (SMB_IS_STREAM(snode))
1318da6c28aaSamw 		cr = kcred;
1319da6c28aaSamw 
1320dc20a302Sas200622 	smb_node_start_crit(snode, RW_READER);
1321c8ec8eeaSjose borrego 	rc = nbl_svmand(snode->vp, kcred, &svmand);
1322dc20a302Sas200622 	if (rc) {
1323dc20a302Sas200622 		smb_node_end_crit(snode);
1324dc20a302Sas200622 		return (rc);
1325dc20a302Sas200622 	}
1326c8ec8eeaSjose borrego 
1327c8ec8eeaSjose borrego 	ct = smb_ct;
1328c8ec8eeaSjose borrego 	ct.cc_pid = sr->fid_ofile->f_uniqid;
1329dc20a302Sas200622 	rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset,
1330c8ec8eeaSjose borrego 	    uio->uio_iov->iov_len, svmand, &ct);
1331da6c28aaSamw 
1332dc20a302Sas200622 	if (rc) {
1333dc20a302Sas200622 		smb_node_end_crit(snode);
13346537f381Sas200622 		return (ERANGE);
1335dc20a302Sas200622 	}
1336037cac00Sjoyce mcintosh 
13373db3f65cSamw 	rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr);
1338dc20a302Sas200622 	smb_node_end_crit(snode);
1339da6c28aaSamw 
1340da6c28aaSamw 	return (rc);
1341da6c28aaSamw }
1342da6c28aaSamw 
1343da6c28aaSamw /*
1344da6c28aaSamw  * smb_fsop_statfs
1345da6c28aaSamw  *
1346da6c28aaSamw  * This is a wrapper function used for stat operations.
1347da6c28aaSamw  */
1348da6c28aaSamw int
1349da6c28aaSamw smb_fsop_statfs(
1350da6c28aaSamw     cred_t *cr,
1351da6c28aaSamw     smb_node_t *snode,
1352da6c28aaSamw     struct statvfs64 *statp)
1353da6c28aaSamw {
1354da6c28aaSamw 	ASSERT(cr);
1355da6c28aaSamw 	ASSERT(snode);
1356da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1357da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1358da6c28aaSamw 
1359da6c28aaSamw 	return (smb_vop_statfs(snode->vp, statp, cr));
1360da6c28aaSamw }
1361da6c28aaSamw 
1362da6c28aaSamw /*
1363da6c28aaSamw  * smb_fsop_access
1364ee60c47bSjm199354  *
1365ee60c47bSjm199354  * Named streams do not have separate permissions from the associated
1366ee60c47bSjm199354  * unnamed stream.  Thus, if node is a named stream, the permissions
1367ee60c47bSjm199354  * check will be performed on the associated unnamed stream.
1368ee60c47bSjm199354  *
1369ee60c47bSjm199354  * However, our named streams do have their own quarantine attribute,
1370ee60c47bSjm199354  * separate from that on the unnamed stream. If READ or EXECUTE
1371ee60c47bSjm199354  * access has been requested on a named stream, an additional access
1372ee60c47bSjm199354  * check is performed on the named stream in case it has been
1373ee60c47bSjm199354  * quarantined.  kcred is used to avoid issues with the permissions
1374ee60c47bSjm199354  * set on the extended attribute file representing the named stream.
1375da6c28aaSamw  */
1376da6c28aaSamw int
1377da6c28aaSamw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1378da6c28aaSamw     uint32_t faccess)
1379da6c28aaSamw {
1380da6c28aaSamw 	int access = 0;
1381da6c28aaSamw 	int error;
1382da6c28aaSamw 	vnode_t *dir_vp;
1383da6c28aaSamw 	boolean_t acl_check = B_TRUE;
1384da6c28aaSamw 	smb_node_t *unnamed_node;
1385da6c28aaSamw 
1386c8ec8eeaSjose borrego 	ASSERT(sr);
1387da6c28aaSamw 	ASSERT(cr);
1388da6c28aaSamw 	ASSERT(snode);
1389da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1390da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1391da6c28aaSamw 
1392da6c28aaSamw 	if (faccess == 0)
1393da6c28aaSamw 		return (NT_STATUS_SUCCESS);
1394da6c28aaSamw 
1395c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr)) {
1396da6c28aaSamw 		if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA|
1397da6c28aaSamw 		    FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES|
1398da6c28aaSamw 		    DELETE|WRITE_DAC|WRITE_OWNER)) {
1399da6c28aaSamw 			return (NT_STATUS_ACCESS_DENIED);
1400da6c28aaSamw 		}
1401da6c28aaSamw 	}
1402da6c28aaSamw 
1403da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1404da6c28aaSamw 	if (unnamed_node) {
1405da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1406da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1407ee60c47bSjm199354 
1408ee60c47bSjm199354 		/*
1409ee60c47bSjm199354 		 * Perform VREAD access check on the named stream in case it
1410ee60c47bSjm199354 		 * is quarantined. kcred is passed to smb_vop_access so it
1411ee60c47bSjm199354 		 * doesn't fail due to lack of permission.
1412ee60c47bSjm199354 		 */
1413ee60c47bSjm199354 		if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) {
1414ee60c47bSjm199354 			error = smb_vop_access(snode->vp, VREAD,
1415ee60c47bSjm199354 			    0, NULL, kcred);
1416ee60c47bSjm199354 			if (error)
1417ee60c47bSjm199354 				return (NT_STATUS_ACCESS_DENIED);
1418ee60c47bSjm199354 		}
1419ee60c47bSjm199354 
1420da6c28aaSamw 		/*
1421da6c28aaSamw 		 * Streams authorization should be performed against the
1422da6c28aaSamw 		 * unnamed stream.
1423da6c28aaSamw 		 */
1424da6c28aaSamw 		snode = unnamed_node;
1425da6c28aaSamw 	}
1426da6c28aaSamw 
1427da6c28aaSamw 	if (faccess & ACCESS_SYSTEM_SECURITY) {
1428da6c28aaSamw 		/*
1429da6c28aaSamw 		 * This permission is required for reading/writing SACL and
1430da6c28aaSamw 		 * it's not part of DACL. It's only granted via proper
1431da6c28aaSamw 		 * privileges.
1432da6c28aaSamw 		 */
1433da6c28aaSamw 		if ((sr->uid_user->u_privileges &
1434da6c28aaSamw 		    (SMB_USER_PRIV_BACKUP |
1435da6c28aaSamw 		    SMB_USER_PRIV_RESTORE |
1436da6c28aaSamw 		    SMB_USER_PRIV_SECURITY)) == 0)
1437da6c28aaSamw 			return (NT_STATUS_PRIVILEGE_NOT_HELD);
1438da6c28aaSamw 
1439da6c28aaSamw 		faccess &= ~ACCESS_SYSTEM_SECURITY;
1440da6c28aaSamw 	}
1441da6c28aaSamw 
1442da6c28aaSamw 	/* Links don't have ACL */
1443c8ec8eeaSjose borrego 	if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) ||
1444037cac00Sjoyce mcintosh 	    smb_node_is_link(snode))
1445da6c28aaSamw 		acl_check = B_FALSE;
1446da6c28aaSamw 
1447743a77edSAlan Wright 	/*
1448743a77edSAlan Wright 	 * Use the most restrictive parts of both faccess and the
1449743a77edSAlan Wright 	 * share access.  An AND of the two value masks gives us that
1450743a77edSAlan Wright 	 * since we've already converted to a mask of what we "can"
1451743a77edSAlan Wright 	 * do.
1452743a77edSAlan Wright 	 */
1453743a77edSAlan Wright 	faccess &= sr->tid_tree->t_access;
1454743a77edSAlan Wright 
1455da6c28aaSamw 	if (acl_check) {
1456*1fcced4cSJordan Brown 		dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
1457da6c28aaSamw 		error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp,
1458da6c28aaSamw 		    cr);
1459da6c28aaSamw 	} else {
1460da6c28aaSamw 		/*
1461da6c28aaSamw 		 * FS doesn't understand 32-bit mask, need to map
1462da6c28aaSamw 		 */
1463da6c28aaSamw 		if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))
1464da6c28aaSamw 			access |= VWRITE;
1465da6c28aaSamw 
1466da6c28aaSamw 		if (faccess & FILE_READ_DATA)
1467da6c28aaSamw 			access |= VREAD;
1468da6c28aaSamw 
1469da6c28aaSamw 		if (faccess & FILE_EXECUTE)
1470da6c28aaSamw 			access |= VEXEC;
1471da6c28aaSamw 
1472da6c28aaSamw 		error = smb_vop_access(snode->vp, access, 0, NULL, cr);
1473da6c28aaSamw 	}
1474da6c28aaSamw 
1475da6c28aaSamw 	return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS);
1476da6c28aaSamw }
1477da6c28aaSamw 
1478da6c28aaSamw /*
1479da6c28aaSamw  * smb_fsop_lookup_name()
1480da6c28aaSamw  *
1481b89a8333Snatalie li - Sun Microsystems - Irvine United States  * If name indicates that the file is a stream file, perform
1482b89a8333Snatalie li - Sun Microsystems - Irvine United States  * stream specific lookup, otherwise call smb_fsop_lookup.
1483da6c28aaSamw  *
1484b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Return an error if the looked-up file is in outside the tree.
1485b89a8333Snatalie li - Sun Microsystems - Irvine United States  * (Required when invoked from open path.)
1486da6c28aaSamw  */
1487da6c28aaSamw 
1488da6c28aaSamw int
1489da6c28aaSamw smb_fsop_lookup_name(
1490faa1795aSjb150015     smb_request_t *sr,
1491da6c28aaSamw     cred_t	*cr,
1492da6c28aaSamw     int		flags,
1493da6c28aaSamw     smb_node_t	*root_node,
1494eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t	*dnode,
1495da6c28aaSamw     char	*name,
1496037cac00Sjoyce mcintosh     smb_node_t	**ret_snode)
1497da6c28aaSamw {
1498da6c28aaSamw 	smb_node_t	*fnode;
1499da6c28aaSamw 	vnode_t		*xattrdirvp;
1500da6c28aaSamw 	vnode_t		*vp;
1501da6c28aaSamw 	char		*od_name;
1502da6c28aaSamw 	char		*fname;
1503da6c28aaSamw 	char		*sname;
1504da6c28aaSamw 	int		rc;
1505da6c28aaSamw 
1506da6c28aaSamw 	ASSERT(cr);
1507eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
1508eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
1509eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
1510da6c28aaSamw 
1511da6c28aaSamw 	/*
1512da6c28aaSamw 	 * The following check is required for streams processing, below
1513da6c28aaSamw 	 */
1514da6c28aaSamw 
1515c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1516da6c28aaSamw 		flags |= SMB_IGNORE_CASE;
1517da6c28aaSamw 
1518da6c28aaSamw 	fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1519da6c28aaSamw 	sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1520da6c28aaSamw 
1521eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_is_stream_name(name)) {
1522eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_stream_parse_name(name, fname, sname);
15238d7e4166Sjose borrego 
1524da6c28aaSamw 		/*
1525da6c28aaSamw 		 * Look up the unnamed stream (i.e. fname).
1526da6c28aaSamw 		 * Unmangle processing will be done on fname
1527da6c28aaSamw 		 * as well as any link target.
1528da6c28aaSamw 		 */
1529037cac00Sjoyce mcintosh 		rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode,
1530037cac00Sjoyce mcintosh 		    fname, &fnode);
1531da6c28aaSamw 
1532da6c28aaSamw 		if (rc != 0) {
1533da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
1534da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
1535da6c28aaSamw 			return (rc);
1536da6c28aaSamw 		}
1537da6c28aaSamw 
1538da6c28aaSamw 		od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1539da6c28aaSamw 
1540da6c28aaSamw 		/*
1541da6c28aaSamw 		 * od_name is the on-disk name of the stream, except
1542da6c28aaSamw 		 * without the prepended stream prefix (SMB_STREAM_PREFIX)
1543da6c28aaSamw 		 */
1544da6c28aaSamw 
1545da6c28aaSamw 		/*
1546da6c28aaSamw 		 * XXX
1547da6c28aaSamw 		 * What permissions NTFS requires for stream lookup if any?
1548da6c28aaSamw 		 */
1549da6c28aaSamw 		rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name,
1550dc20a302Sas200622 		    &xattrdirvp, flags, root_node->vp, cr);
1551da6c28aaSamw 
1552da6c28aaSamw 		if (rc != 0) {
1553da6c28aaSamw 			smb_node_release(fnode);
1554da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
1555da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
1556da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1557da6c28aaSamw 			return (rc);
1558da6c28aaSamw 		}
1559da6c28aaSamw 
1560da6c28aaSamw 		*ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
1561037cac00Sjoyce mcintosh 		    vp, od_name);
1562da6c28aaSamw 
1563da6c28aaSamw 		kmem_free(od_name, MAXNAMELEN);
1564da6c28aaSamw 		smb_node_release(fnode);
1565da6c28aaSamw 		VN_RELE(xattrdirvp);
1566da6c28aaSamw 		VN_RELE(vp);
15677f667e74Sjose borrego 
15687f667e74Sjose borrego 		if (*ret_snode == NULL) {
1569da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
1570da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
1571da6c28aaSamw 			return (ENOMEM);
1572da6c28aaSamw 		}
1573da6c28aaSamw 	} else {
1574eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, name,
1575037cac00Sjoyce mcintosh 		    ret_snode);
1576da6c28aaSamw 	}
1577da6c28aaSamw 
1578da6c28aaSamw 	if (rc == 0) {
1579da6c28aaSamw 		ASSERT(ret_snode);
1580c8ec8eeaSjose borrego 		if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) {
1581da6c28aaSamw 			smb_node_release(*ret_snode);
1582da6c28aaSamw 			*ret_snode = NULL;
1583da6c28aaSamw 			rc = EACCES;
1584da6c28aaSamw 		}
1585da6c28aaSamw 	}
1586da6c28aaSamw 
1587da6c28aaSamw 	kmem_free(fname, MAXNAMELEN);
1588da6c28aaSamw 	kmem_free(sname, MAXNAMELEN);
1589da6c28aaSamw 
1590da6c28aaSamw 	return (rc);
1591da6c28aaSamw }
1592da6c28aaSamw 
1593da6c28aaSamw /*
1594da6c28aaSamw  * smb_fsop_lookup
1595da6c28aaSamw  *
1596da6c28aaSamw  * All SMB functions should use this smb_vop_lookup wrapper to ensure that
1597da6c28aaSamw  * the smb_vop_lookup is performed with the appropriate credentials and using
1598da6c28aaSamw  * case insensitive compares. Please document any direct call to smb_vop_lookup
1599da6c28aaSamw  * to explain the reason for avoiding this wrapper.
1600da6c28aaSamw  *
1601eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * It is assumed that a reference exists on dnode coming into this routine
1602da6c28aaSamw  * (and that it is safe from deallocation).
1603da6c28aaSamw  *
1604da6c28aaSamw  * Same with the root_node.
1605da6c28aaSamw  *
1606da6c28aaSamw  * *ret_snode is returned with a reference upon success.  No reference is
1607da6c28aaSamw  * taken if an error is returned.
1608da6c28aaSamw  *
1609da6c28aaSamw  * Note: The returned ret_snode may be in a child mount.  This is ok for
16107f667e74Sjose borrego  * readdir.
1611da6c28aaSamw  *
1612c8ec8eeaSjose borrego  * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent
1613da6c28aaSamw  * operations on files not in the parent mount.
1614da6c28aaSamw  */
1615da6c28aaSamw int
1616da6c28aaSamw smb_fsop_lookup(
1617faa1795aSjb150015     smb_request_t *sr,
1618da6c28aaSamw     cred_t	*cr,
1619da6c28aaSamw     int		flags,
1620da6c28aaSamw     smb_node_t	*root_node,
1621eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t	*dnode,
1622da6c28aaSamw     char	*name,
1623037cac00Sjoyce mcintosh     smb_node_t	**ret_snode)
1624da6c28aaSamw {
1625da6c28aaSamw 	smb_node_t *lnk_target_node;
1626da6c28aaSamw 	smb_node_t *lnk_dnode;
1627da6c28aaSamw 	char *longname;
1628da6c28aaSamw 	char *od_name;
1629da6c28aaSamw 	vnode_t *vp;
1630da6c28aaSamw 	int rc;
16318b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	int ret_flags;
1632da6c28aaSamw 
1633da6c28aaSamw 	ASSERT(cr);
1634eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
1635eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
1636eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
1637da6c28aaSamw 
1638da6c28aaSamw 	if (name == NULL)
1639da6c28aaSamw 		return (EINVAL);
1640da6c28aaSamw 
1641eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
1642da6c28aaSamw 		return (EACCES);
1643da6c28aaSamw 
1644c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1645da6c28aaSamw 		flags |= SMB_IGNORE_CASE;
16468b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
16478b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
1648da6c28aaSamw 
1649da6c28aaSamw 	od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1650da6c28aaSamw 
1651eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_lookup(dnode->vp, name, &vp, od_name, flags,
16528b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	    &ret_flags, root_node ? root_node->vp : NULL, cr);
1653da6c28aaSamw 
1654da6c28aaSamw 	if (rc != 0) {
1655da6c28aaSamw 		if (smb_maybe_mangled_name(name) == 0) {
1656da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1657da6c28aaSamw 			return (rc);
1658da6c28aaSamw 		}
1659da6c28aaSamw 
1660da6c28aaSamw 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1661eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
1662da6c28aaSamw 		if (rc != 0) {
1663da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1664da6c28aaSamw 			kmem_free(longname, MAXNAMELEN);
1665da6c28aaSamw 			return (rc);
1666da6c28aaSamw 		}
1667da6c28aaSamw 
1668da6c28aaSamw 		/*
16698b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * longname is the real (case-sensitive)
16708b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * on-disk name.
1671da6c28aaSamw 		 * We make sure we do a lookup on this exact
1672da6c28aaSamw 		 * name, as the name was mangled and denotes
1673da6c28aaSamw 		 * a unique file.
1674da6c28aaSamw 		 */
1675da6c28aaSamw 
1676da6c28aaSamw 		if (flags & SMB_IGNORE_CASE)
1677da6c28aaSamw 			flags &= ~SMB_IGNORE_CASE;
1678da6c28aaSamw 
1679eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_lookup(dnode->vp, longname, &vp, od_name,
16808b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    flags, &ret_flags, root_node ? root_node->vp : NULL, cr);
1681da6c28aaSamw 
1682da6c28aaSamw 		kmem_free(longname, MAXNAMELEN);
1683da6c28aaSamw 
1684da6c28aaSamw 		if (rc != 0) {
1685da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1686da6c28aaSamw 			return (rc);
1687da6c28aaSamw 		}
1688da6c28aaSamw 	}
1689da6c28aaSamw 
1690da6c28aaSamw 	if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) {
1691da6c28aaSamw 
1692eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_pathname(sr, od_name, FOLLOW, root_node, dnode,
1693da6c28aaSamw 		    &lnk_dnode, &lnk_target_node, cr);
1694da6c28aaSamw 
1695da6c28aaSamw 		if (rc != 0) {
1696da6c28aaSamw 			/*
1697da6c28aaSamw 			 * The link is assumed to be for the last component
1698da6c28aaSamw 			 * of a path.  Hence any ENOTDIR error will be returned
1699da6c28aaSamw 			 * as ENOENT.
1700da6c28aaSamw 			 */
1701da6c28aaSamw 			if (rc == ENOTDIR)
1702da6c28aaSamw 				rc = ENOENT;
1703da6c28aaSamw 
1704da6c28aaSamw 			VN_RELE(vp);
1705da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1706da6c28aaSamw 			return (rc);
1707da6c28aaSamw 		}
1708da6c28aaSamw 
1709da6c28aaSamw 		/*
1710da6c28aaSamw 		 * Release the original VLNK vnode
1711da6c28aaSamw 		 */
1712da6c28aaSamw 
1713da6c28aaSamw 		VN_RELE(vp);
1714da6c28aaSamw 		vp = lnk_target_node->vp;
1715da6c28aaSamw 
1716da6c28aaSamw 		rc = smb_vop_traverse_check(&vp);
1717da6c28aaSamw 
1718da6c28aaSamw 		if (rc != 0) {
1719da6c28aaSamw 			smb_node_release(lnk_dnode);
1720da6c28aaSamw 			smb_node_release(lnk_target_node);
1721da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1722da6c28aaSamw 			return (rc);
1723da6c28aaSamw 		}
1724da6c28aaSamw 
1725da6c28aaSamw 		/*
1726da6c28aaSamw 		 * smb_vop_traverse_check() may have returned a different vnode
1727da6c28aaSamw 		 */
1728da6c28aaSamw 
1729da6c28aaSamw 		if (lnk_target_node->vp == vp) {
1730da6c28aaSamw 			*ret_snode = lnk_target_node;
1731da6c28aaSamw 		} else {
1732da6c28aaSamw 			*ret_snode = smb_node_lookup(sr, NULL, cr, vp,
1733037cac00Sjoyce mcintosh 			    lnk_target_node->od_name, lnk_dnode, NULL);
1734da6c28aaSamw 			VN_RELE(vp);
17357f667e74Sjose borrego 
17367f667e74Sjose borrego 			if (*ret_snode == NULL)
1737da6c28aaSamw 				rc = ENOMEM;
1738da6c28aaSamw 			smb_node_release(lnk_target_node);
1739da6c28aaSamw 		}
1740da6c28aaSamw 
1741da6c28aaSamw 		smb_node_release(lnk_dnode);
1742da6c28aaSamw 
1743da6c28aaSamw 	} else {
1744da6c28aaSamw 
1745da6c28aaSamw 		rc = smb_vop_traverse_check(&vp);
1746da6c28aaSamw 		if (rc) {
1747da6c28aaSamw 			VN_RELE(vp);
1748da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1749da6c28aaSamw 			return (rc);
1750da6c28aaSamw 		}
1751da6c28aaSamw 
1752da6c28aaSamw 		*ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name,
1753037cac00Sjoyce mcintosh 		    dnode, NULL);
1754da6c28aaSamw 		VN_RELE(vp);
17557f667e74Sjose borrego 
17567f667e74Sjose borrego 		if (*ret_snode == NULL)
1757da6c28aaSamw 			rc = ENOMEM;
1758da6c28aaSamw 	}
1759da6c28aaSamw 
1760da6c28aaSamw 	kmem_free(od_name, MAXNAMELEN);
1761da6c28aaSamw 	return (rc);
1762da6c28aaSamw }
1763da6c28aaSamw 
1764da6c28aaSamw int /*ARGSUSED*/
1765da6c28aaSamw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode)
1766da6c28aaSamw {
1767da6c28aaSamw 	ASSERT(cr);
1768da6c28aaSamw 	ASSERT(snode);
1769da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1770da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1771da6c28aaSamw 
1772da6c28aaSamw 	ASSERT(sr);
1773da6c28aaSamw 	ASSERT(sr->tid_tree);
1774c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1775da6c28aaSamw 		return (EROFS);
1776da6c28aaSamw 
1777dc20a302Sas200622 	return (smb_vop_commit(snode->vp, cr));
1778da6c28aaSamw }
1779da6c28aaSamw 
1780da6c28aaSamw /*
1781da6c28aaSamw  * smb_fsop_aclread
1782da6c28aaSamw  *
1783da6c28aaSamw  * Retrieve filesystem ACL. Depends on requested ACLs in
1784da6c28aaSamw  * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in
1785da6c28aaSamw  * fs_sd. Note that requesting a DACL/SACL doesn't mean that
1786da6c28aaSamw  * the corresponding field in fs_sd should be non-NULL upon
1787da6c28aaSamw  * return, since the target ACL might not contain that type of
1788da6c28aaSamw  * entries.
1789da6c28aaSamw  *
1790da6c28aaSamw  * Returned ACL is always in ACE_T (aka ZFS) format.
1791da6c28aaSamw  * If successful the allocated memory for the ACL should be freed
179255bf511dSas200622  * using smb_fsacl_free() or smb_fssd_term()
1793da6c28aaSamw  */
1794da6c28aaSamw int
1795da6c28aaSamw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1796da6c28aaSamw     smb_fssd_t *fs_sd)
1797da6c28aaSamw {
1798da6c28aaSamw 	int error = 0;
1799da6c28aaSamw 	int flags = 0;
1800da6c28aaSamw 	int access = 0;
1801da6c28aaSamw 	acl_t *acl;
1802da6c28aaSamw 	smb_node_t *unnamed_node;
1803da6c28aaSamw 
1804da6c28aaSamw 	ASSERT(cr);
1805da6c28aaSamw 
1806743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0)
1807743a77edSAlan Wright 		return (EACCES);
1808743a77edSAlan Wright 
1809da6c28aaSamw 	if (sr->fid_ofile) {
1810da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
1811da6c28aaSamw 			access = READ_CONTROL;
1812da6c28aaSamw 
1813da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
1814da6c28aaSamw 			access |= ACCESS_SYSTEM_SECURITY;
1815da6c28aaSamw 
1816da6c28aaSamw 		error = smb_ofile_access(sr->fid_ofile, cr, access);
1817da6c28aaSamw 		if (error != NT_STATUS_SUCCESS) {
1818da6c28aaSamw 			return (EACCES);
1819da6c28aaSamw 		}
1820da6c28aaSamw 	}
1821da6c28aaSamw 
1822da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1823da6c28aaSamw 	if (unnamed_node) {
1824da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1825da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1826da6c28aaSamw 		/*
1827da6c28aaSamw 		 * Streams don't have ACL, any read ACL attempt on a stream
1828da6c28aaSamw 		 * should be performed on the unnamed stream.
1829da6c28aaSamw 		 */
1830da6c28aaSamw 		snode = unnamed_node;
1831da6c28aaSamw 	}
1832da6c28aaSamw 
1833c8ec8eeaSjose borrego 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS))
1834da6c28aaSamw 		flags = ATTR_NOACLCHECK;
1835da6c28aaSamw 
1836da6c28aaSamw 	error = smb_vop_acl_read(snode->vp, &acl, flags,
1837dc20a302Sas200622 	    sr->tid_tree->t_acltype, cr);
1838da6c28aaSamw 	if (error != 0) {
1839da6c28aaSamw 		return (error);
1840da6c28aaSamw 	}
1841da6c28aaSamw 
1842da6c28aaSamw 	error = acl_translate(acl, _ACL_ACE_ENABLED,
1843da6c28aaSamw 	    (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid);
1844da6c28aaSamw 
1845da6c28aaSamw 	if (error == 0) {
184655bf511dSas200622 		smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl,
1847da6c28aaSamw 		    fs_sd->sd_secinfo);
1848da6c28aaSamw 	}
1849da6c28aaSamw 
1850da6c28aaSamw 	acl_free(acl);
1851da6c28aaSamw 	return (error);
1852da6c28aaSamw }
1853da6c28aaSamw 
1854da6c28aaSamw /*
1855da6c28aaSamw  * smb_fsop_aclwrite
1856da6c28aaSamw  *
1857da6c28aaSamw  * Stores the filesystem ACL provided in fs_sd->sd_acl.
1858da6c28aaSamw  */
1859da6c28aaSamw int
1860da6c28aaSamw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1861da6c28aaSamw     smb_fssd_t *fs_sd)
1862da6c28aaSamw {
1863da6c28aaSamw 	int target_flavor;
1864da6c28aaSamw 	int error = 0;
1865da6c28aaSamw 	int flags = 0;
1866da6c28aaSamw 	int access = 0;
1867da6c28aaSamw 	acl_t *acl, *dacl, *sacl;
1868da6c28aaSamw 	smb_node_t *unnamed_node;
1869da6c28aaSamw 
1870da6c28aaSamw 	ASSERT(cr);
1871da6c28aaSamw 
1872da6c28aaSamw 	ASSERT(sr);
1873da6c28aaSamw 	ASSERT(sr->tid_tree);
1874c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1875da6c28aaSamw 		return (EROFS);
1876da6c28aaSamw 
1877743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0)
1878743a77edSAlan Wright 		return (EACCES);
1879743a77edSAlan Wright 
1880da6c28aaSamw 	if (sr->fid_ofile) {
1881da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
1882da6c28aaSamw 			access = WRITE_DAC;
1883da6c28aaSamw 
1884da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
1885da6c28aaSamw 			access |= ACCESS_SYSTEM_SECURITY;
1886da6c28aaSamw 
1887da6c28aaSamw 		error = smb_ofile_access(sr->fid_ofile, cr, access);
1888da6c28aaSamw 		if (error != NT_STATUS_SUCCESS)
1889da6c28aaSamw 			return (EACCES);
1890da6c28aaSamw 	}
1891da6c28aaSamw 
1892da6c28aaSamw 	switch (sr->tid_tree->t_acltype) {
1893da6c28aaSamw 	case ACLENT_T:
1894da6c28aaSamw 		target_flavor = _ACL_ACLENT_ENABLED;
1895da6c28aaSamw 		break;
1896da6c28aaSamw 
1897da6c28aaSamw 	case ACE_T:
1898da6c28aaSamw 		target_flavor = _ACL_ACE_ENABLED;
1899da6c28aaSamw 		break;
1900da6c28aaSamw 	default:
1901da6c28aaSamw 		return (EINVAL);
1902da6c28aaSamw 	}
1903da6c28aaSamw 
1904da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1905da6c28aaSamw 	if (unnamed_node) {
1906da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1907da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1908da6c28aaSamw 		/*
1909da6c28aaSamw 		 * Streams don't have ACL, any write ACL attempt on a stream
1910da6c28aaSamw 		 * should be performed on the unnamed stream.
1911da6c28aaSamw 		 */
1912da6c28aaSamw 		snode = unnamed_node;
1913da6c28aaSamw 	}
1914da6c28aaSamw 
1915da6c28aaSamw 	dacl = fs_sd->sd_zdacl;
1916da6c28aaSamw 	sacl = fs_sd->sd_zsacl;
1917da6c28aaSamw 
1918da6c28aaSamw 	ASSERT(dacl || sacl);
1919da6c28aaSamw 	if ((dacl == NULL) && (sacl == NULL))
1920da6c28aaSamw 		return (EINVAL);
1921da6c28aaSamw 
1922da6c28aaSamw 	if (dacl && sacl)
192355bf511dSas200622 		acl = smb_fsacl_merge(dacl, sacl);
1924da6c28aaSamw 	else if (dacl)
1925da6c28aaSamw 		acl = dacl;
1926da6c28aaSamw 	else
1927da6c28aaSamw 		acl = sacl;
1928da6c28aaSamw 
1929da6c28aaSamw 	error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR),
1930da6c28aaSamw 	    fs_sd->sd_uid, fs_sd->sd_gid);
1931da6c28aaSamw 	if (error == 0) {
1932c8ec8eeaSjose borrego 		if (smb_tree_has_feature(sr->tid_tree,
1933c8ec8eeaSjose borrego 		    SMB_TREE_ACEMASKONACCESS))
1934da6c28aaSamw 			flags = ATTR_NOACLCHECK;
1935da6c28aaSamw 
1936dc20a302Sas200622 		error = smb_vop_acl_write(snode->vp, acl, flags, cr);
1937da6c28aaSamw 	}
1938da6c28aaSamw 
1939da6c28aaSamw 	if (dacl && sacl)
1940da6c28aaSamw 		acl_free(acl);
1941da6c28aaSamw 
1942da6c28aaSamw 	return (error);
1943da6c28aaSamw }
1944da6c28aaSamw 
1945da6c28aaSamw acl_type_t
1946da6c28aaSamw smb_fsop_acltype(smb_node_t *snode)
1947da6c28aaSamw {
1948da6c28aaSamw 	return (smb_vop_acl_type(snode->vp));
1949da6c28aaSamw }
1950da6c28aaSamw 
1951da6c28aaSamw /*
1952da6c28aaSamw  * smb_fsop_sdread
1953da6c28aaSamw  *
1954da6c28aaSamw  * Read the requested security descriptor items from filesystem.
1955da6c28aaSamw  * The items are specified in fs_sd->sd_secinfo.
1956da6c28aaSamw  */
1957da6c28aaSamw int
1958da6c28aaSamw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1959da6c28aaSamw     smb_fssd_t *fs_sd)
1960da6c28aaSamw {
1961da6c28aaSamw 	int error = 0;
1962da6c28aaSamw 	int getowner = 0;
1963da6c28aaSamw 	cred_t *ga_cred;
1964da6c28aaSamw 	smb_attr_t attr;
1965da6c28aaSamw 
1966da6c28aaSamw 	ASSERT(cr);
1967da6c28aaSamw 	ASSERT(fs_sd);
1968da6c28aaSamw 
1969da6c28aaSamw 	/*
1970da6c28aaSamw 	 * File's uid/gid is fetched in two cases:
1971da6c28aaSamw 	 *
1972da6c28aaSamw 	 * 1. it's explicitly requested
1973da6c28aaSamw 	 *
1974da6c28aaSamw 	 * 2. target ACL is ACE_T (ZFS ACL). They're needed for
1975da6c28aaSamw 	 *    owner@/group@ entries. In this case kcred should be used
1976da6c28aaSamw 	 *    because uid/gid are fetched on behalf of smb server.
1977da6c28aaSamw 	 */
1978da6c28aaSamw 	if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) {
1979da6c28aaSamw 		getowner = 1;
1980da6c28aaSamw 		ga_cred = cr;
1981da6c28aaSamw 	} else if (sr->tid_tree->t_acltype == ACE_T) {
1982da6c28aaSamw 		getowner = 1;
1983da6c28aaSamw 		ga_cred = kcred;
1984da6c28aaSamw 	}
1985da6c28aaSamw 
1986da6c28aaSamw 	if (getowner) {
1987da6c28aaSamw 		/*
1988da6c28aaSamw 		 * Windows require READ_CONTROL to read owner/group SID since
1989da6c28aaSamw 		 * they're part of Security Descriptor.
1990da6c28aaSamw 		 * ZFS only requires read_attribute. Need to have a explicit
1991da6c28aaSamw 		 * access check here.
1992da6c28aaSamw 		 */
1993da6c28aaSamw 		if (sr->fid_ofile == NULL) {
1994da6c28aaSamw 			error = smb_fsop_access(sr, ga_cred, snode,
1995da6c28aaSamw 			    READ_CONTROL);
1996da6c28aaSamw 			if (error)
1997b1352070SAlan Wright 				return (EACCES);
1998da6c28aaSamw 		}
1999da6c28aaSamw 
2000da6c28aaSamw 		attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
2001da6c28aaSamw 		error = smb_fsop_getattr(sr, ga_cred, snode, &attr);
2002da6c28aaSamw 		if (error == 0) {
2003da6c28aaSamw 			fs_sd->sd_uid = attr.sa_vattr.va_uid;
2004da6c28aaSamw 			fs_sd->sd_gid = attr.sa_vattr.va_gid;
2005da6c28aaSamw 		} else {
2006da6c28aaSamw 			return (error);
2007da6c28aaSamw 		}
2008da6c28aaSamw 	}
2009da6c28aaSamw 
2010da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2011da6c28aaSamw 		error = smb_fsop_aclread(sr, cr, snode, fs_sd);
2012da6c28aaSamw 	}
2013da6c28aaSamw 
2014da6c28aaSamw 	return (error);
2015da6c28aaSamw }
2016da6c28aaSamw 
2017da6c28aaSamw /*
2018da6c28aaSamw  * smb_fsop_sdmerge
2019da6c28aaSamw  *
2020da6c28aaSamw  * From SMB point of view DACL and SACL are two separate list
2021da6c28aaSamw  * which can be manipulated independently without one affecting
2022da6c28aaSamw  * the other, but entries for both DACL and SACL will end up
2023da6c28aaSamw  * in the same ACL if target filesystem supports ACE_T ACLs.
2024da6c28aaSamw  *
2025da6c28aaSamw  * So, if either DACL or SACL is present in the client set request
2026da6c28aaSamw  * the entries corresponding to the non-present ACL shouldn't
2027da6c28aaSamw  * be touched in the FS ACL.
2028da6c28aaSamw  *
2029da6c28aaSamw  * fs_sd parameter contains DACL and SACL specified by SMB
2030da6c28aaSamw  * client to be set on a file/directory. The client could
2031da6c28aaSamw  * specify both or one of these ACLs (if none is specified
2032da6c28aaSamw  * we don't get this far). When both DACL and SACL are given
2033da6c28aaSamw  * by client the existing ACL should be overwritten. If only
2034da6c28aaSamw  * one of them is specified the entries corresponding to the other
2035da6c28aaSamw  * ACL should not be touched. For example, if only DACL
2036da6c28aaSamw  * is specified in input fs_sd, the function reads audit entries
2037da6c28aaSamw  * of the existing ACL of the file and point fs_sd->sd_zsdacl
2038da6c28aaSamw  * pointer to the fetched SACL, this way when smb_fsop_sdwrite()
2039da6c28aaSamw  * function is called the passed fs_sd would point to the specified
2040da6c28aaSamw  * DACL by client and fetched SACL from filesystem, so the file
2041da6c28aaSamw  * will end up with correct ACL.
2042da6c28aaSamw  */
2043da6c28aaSamw static int
2044da6c28aaSamw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd)
2045da6c28aaSamw {
2046da6c28aaSamw 	smb_fssd_t cur_sd;
2047da6c28aaSamw 	int error = 0;
2048da6c28aaSamw 
2049da6c28aaSamw 	if (sr->tid_tree->t_acltype != ACE_T)
2050da6c28aaSamw 		/* Don't bother if target FS doesn't support ACE_T */
2051da6c28aaSamw 		return (0);
2052da6c28aaSamw 
2053da6c28aaSamw 	if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) {
2054da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
2055da6c28aaSamw 			/*
2056da6c28aaSamw 			 * Don't overwrite existing audit entries
2057da6c28aaSamw 			 */
205855bf511dSas200622 			smb_fssd_init(&cur_sd, SMB_SACL_SECINFO,
2059da6c28aaSamw 			    fs_sd->sd_flags);
2060da6c28aaSamw 
2061da6c28aaSamw 			error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
2062da6c28aaSamw 			if (error == 0) {
2063da6c28aaSamw 				ASSERT(fs_sd->sd_zsacl == NULL);
2064da6c28aaSamw 				fs_sd->sd_zsacl = cur_sd.sd_zsacl;
2065da6c28aaSamw 				if (fs_sd->sd_zsacl && fs_sd->sd_zdacl)
2066da6c28aaSamw 					fs_sd->sd_zsacl->acl_flags =
2067da6c28aaSamw 					    fs_sd->sd_zdacl->acl_flags;
2068da6c28aaSamw 			}
2069da6c28aaSamw 		} else {
2070da6c28aaSamw 			/*
2071da6c28aaSamw 			 * Don't overwrite existing access entries
2072da6c28aaSamw 			 */
207355bf511dSas200622 			smb_fssd_init(&cur_sd, SMB_DACL_SECINFO,
2074da6c28aaSamw 			    fs_sd->sd_flags);
2075da6c28aaSamw 
2076da6c28aaSamw 			error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
2077da6c28aaSamw 			if (error == 0) {
2078da6c28aaSamw 				ASSERT(fs_sd->sd_zdacl == NULL);
2079da6c28aaSamw 				fs_sd->sd_zdacl = cur_sd.sd_zdacl;
2080da6c28aaSamw 				if (fs_sd->sd_zdacl && fs_sd->sd_zsacl)
2081da6c28aaSamw 					fs_sd->sd_zdacl->acl_flags =
2082da6c28aaSamw 					    fs_sd->sd_zsacl->acl_flags;
2083da6c28aaSamw 			}
2084da6c28aaSamw 		}
2085da6c28aaSamw 
2086da6c28aaSamw 		if (error)
208755bf511dSas200622 			smb_fssd_term(&cur_sd);
2088da6c28aaSamw 	}
2089da6c28aaSamw 
2090da6c28aaSamw 	return (error);
2091da6c28aaSamw }
2092da6c28aaSamw 
2093da6c28aaSamw /*
2094da6c28aaSamw  * smb_fsop_sdwrite
2095da6c28aaSamw  *
2096da6c28aaSamw  * Stores the given uid, gid and acl in filesystem.
2097da6c28aaSamw  * Provided items in fs_sd are specified by fs_sd->sd_secinfo.
2098da6c28aaSamw  *
2099da6c28aaSamw  * A SMB security descriptor could contain owner, primary group,
2100da6c28aaSamw  * DACL and SACL. Setting an SD should be atomic but here it has to
2101da6c28aaSamw  * be done via two separate FS operations: VOP_SETATTR and
2102da6c28aaSamw  * VOP_SETSECATTR. Therefore, this function has to simulate the
2103da6c28aaSamw  * atomicity as well as it can.
21042c1b14e5Sjose borrego  *
21052c1b14e5Sjose borrego  * Get the current uid, gid before setting the new uid/gid
21062c1b14e5Sjose borrego  * so if smb_fsop_aclwrite fails they can be restored. root cred is
21072c1b14e5Sjose borrego  * used to get currend uid/gid since this operation is performed on
21082c1b14e5Sjose borrego  * behalf of the server not the user.
21092c1b14e5Sjose borrego  *
21102c1b14e5Sjose borrego  * If setting uid/gid fails with EPERM it means that and invalid
21112c1b14e5Sjose borrego  * owner has been specified. Callers should translate this to
21122c1b14e5Sjose borrego  * STATUS_INVALID_OWNER which is not the normal mapping for EPERM
21132c1b14e5Sjose borrego  * in upper layers, so EPERM is mapped to EBADE.
2114da6c28aaSamw  */
2115da6c28aaSamw int
2116da6c28aaSamw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2117da6c28aaSamw     smb_fssd_t *fs_sd, int overwrite)
2118da6c28aaSamw {
2119da6c28aaSamw 	int error = 0;
2120da6c28aaSamw 	int access = 0;
2121da6c28aaSamw 	smb_attr_t set_attr;
2122da6c28aaSamw 	smb_attr_t orig_attr;
2123da6c28aaSamw 
2124da6c28aaSamw 	ASSERT(cr);
2125da6c28aaSamw 	ASSERT(fs_sd);
2126da6c28aaSamw 
2127da6c28aaSamw 	ASSERT(sr);
2128da6c28aaSamw 	ASSERT(sr->tid_tree);
2129c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
2130da6c28aaSamw 		return (EROFS);
2131da6c28aaSamw 
2132da6c28aaSamw 	bzero(&set_attr, sizeof (smb_attr_t));
2133da6c28aaSamw 
2134da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
2135da6c28aaSamw 		set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
2136da6c28aaSamw 		set_attr.sa_mask |= SMB_AT_UID;
21372c1b14e5Sjose borrego 		access |= WRITE_OWNER;
2138da6c28aaSamw 	}
2139da6c28aaSamw 
2140da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
2141da6c28aaSamw 		set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
2142da6c28aaSamw 		set_attr.sa_mask |= SMB_AT_GID;
21432c1b14e5Sjose borrego 		access |= WRITE_OWNER;
2144da6c28aaSamw 	}
2145da6c28aaSamw 
2146da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
2147da6c28aaSamw 		access |= WRITE_DAC;
2148da6c28aaSamw 
2149da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
2150da6c28aaSamw 		access |= ACCESS_SYSTEM_SECURITY;
2151da6c28aaSamw 
2152da6c28aaSamw 	if (sr->fid_ofile)
2153da6c28aaSamw 		error = smb_ofile_access(sr->fid_ofile, cr, access);
2154da6c28aaSamw 	else
2155da6c28aaSamw 		error = smb_fsop_access(sr, cr, snode, access);
2156da6c28aaSamw 
2157da6c28aaSamw 	if (error)
2158da6c28aaSamw 		return (EACCES);
2159da6c28aaSamw 
2160da6c28aaSamw 	if (set_attr.sa_mask) {
2161da6c28aaSamw 		orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
2162da6c28aaSamw 		error = smb_fsop_getattr(sr, kcred, snode, &orig_attr);
21632c1b14e5Sjose borrego 		if (error == 0) {
2164037cac00Sjoyce mcintosh 			error = smb_fsop_setattr(sr, cr, snode, &set_attr);
21652c1b14e5Sjose borrego 			if (error == EPERM)
21662c1b14e5Sjose borrego 				error = EBADE;
21672c1b14e5Sjose borrego 		}
2168da6c28aaSamw 
2169da6c28aaSamw 		if (error)
2170da6c28aaSamw 			return (error);
2171da6c28aaSamw 	}
2172da6c28aaSamw 
2173da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2174da6c28aaSamw 		if (overwrite == 0) {
2175da6c28aaSamw 			error = smb_fsop_sdmerge(sr, snode, fs_sd);
2176da6c28aaSamw 			if (error)
2177da6c28aaSamw 				return (error);
2178da6c28aaSamw 		}
2179da6c28aaSamw 
2180da6c28aaSamw 		error = smb_fsop_aclwrite(sr, cr, snode, fs_sd);
2181da6c28aaSamw 		if (error) {
2182da6c28aaSamw 			/*
2183da6c28aaSamw 			 * Revert uid/gid changes if required.
2184da6c28aaSamw 			 */
2185da6c28aaSamw 			if (set_attr.sa_mask) {
2186da6c28aaSamw 				orig_attr.sa_mask = set_attr.sa_mask;
2187da6c28aaSamw 				(void) smb_fsop_setattr(sr, kcred, snode,
2188037cac00Sjoyce mcintosh 				    &orig_attr);
2189da6c28aaSamw 			}
2190da6c28aaSamw 		}
2191da6c28aaSamw 	}
2192da6c28aaSamw 
2193da6c28aaSamw 	return (error);
2194da6c28aaSamw }
2195da6c28aaSamw 
2196da6c28aaSamw /*
2197da6c28aaSamw  * smb_fsop_sdinherit
2198da6c28aaSamw  *
2199da6c28aaSamw  * Inherit the security descriptor from the parent container.
2200da6c28aaSamw  * This function is called after FS has created the file/folder
2201da6c28aaSamw  * so if this doesn't do anything it means FS inheritance is
2202da6c28aaSamw  * in place.
2203da6c28aaSamw  *
2204da6c28aaSamw  * Do inheritance for ZFS internally.
2205da6c28aaSamw  *
2206da6c28aaSamw  * If we want to let ZFS does the inheritance the
2207da6c28aaSamw  * following setting should be true:
2208da6c28aaSamw  *
2209da6c28aaSamw  *  - aclinherit = passthrough
2210da6c28aaSamw  *  - aclmode = passthrough
2211da6c28aaSamw  *  - smbd umask = 0777
2212da6c28aaSamw  *
2213da6c28aaSamw  * This will result in right effective permissions but
2214da6c28aaSamw  * ZFS will always add 6 ACEs for owner, owning group
2215da6c28aaSamw  * and others to be POSIX compliant. This is not what
2216da6c28aaSamw  * Windows clients/users expect, so we decided that CIFS
2217da6c28aaSamw  * implements Windows rules and overwrite whatever ZFS
2218da6c28aaSamw  * comes up with. This way we also don't have to care
2219da6c28aaSamw  * about ZFS aclinherit and aclmode settings.
2220da6c28aaSamw  */
2221da6c28aaSamw static int
2222da6c28aaSamw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd)
2223da6c28aaSamw {
2224da6c28aaSamw 	int is_dir;
222555bf511dSas200622 	acl_t *dacl = NULL;
222655bf511dSas200622 	acl_t *sacl = NULL;
2227da6c28aaSamw 	ksid_t *owner_sid;
2228da6c28aaSamw 	int error;
2229da6c28aaSamw 
2230da6c28aaSamw 	ASSERT(fs_sd);
2231da6c28aaSamw 
2232da6c28aaSamw 	if (sr->tid_tree->t_acltype != ACE_T) {
2233da6c28aaSamw 		/*
2234da6c28aaSamw 		 * No forced inheritance for non-ZFS filesystems.
2235da6c28aaSamw 		 */
2236da6c28aaSamw 		fs_sd->sd_secinfo = 0;
2237da6c28aaSamw 		return (0);
2238da6c28aaSamw 	}
2239da6c28aaSamw 
2240da6c28aaSamw 
2241da6c28aaSamw 	/* Fetch parent directory's ACL */
2242da6c28aaSamw 	error = smb_fsop_sdread(sr, kcred, dnode, fs_sd);
2243da6c28aaSamw 	if (error) {
2244da6c28aaSamw 		return (error);
2245da6c28aaSamw 	}
2246da6c28aaSamw 
2247da6c28aaSamw 	is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR);
2248da6c28aaSamw 	owner_sid = crgetsid(sr->user_cr, KSID_OWNER);
2249da6c28aaSamw 	ASSERT(owner_sid);
225055bf511dSas200622 	dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO,
2251da6c28aaSamw 	    owner_sid->ks_id);
225255bf511dSas200622 	sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO,
2253da6c28aaSamw 	    (uid_t)-1);
2254da6c28aaSamw 
225555bf511dSas200622 	if (sacl == NULL)
225655bf511dSas200622 		fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO;
225755bf511dSas200622 
225855bf511dSas200622 	smb_fsacl_free(fs_sd->sd_zdacl);
225955bf511dSas200622 	smb_fsacl_free(fs_sd->sd_zsacl);
2260da6c28aaSamw 
2261da6c28aaSamw 	fs_sd->sd_zdacl = dacl;
2262da6c28aaSamw 	fs_sd->sd_zsacl = sacl;
2263da6c28aaSamw 
2264da6c28aaSamw 	return (0);
2265da6c28aaSamw }
2266da6c28aaSamw 
2267da6c28aaSamw /*
2268da6c28aaSamw  * smb_fsop_eaccess
2269da6c28aaSamw  *
2270da6c28aaSamw  * Returns the effective permission of the given credential for the
2271da6c28aaSamw  * specified object.
2272da6c28aaSamw  *
2273da6c28aaSamw  * This is just a workaround. We need VFS/FS support for this.
2274da6c28aaSamw  */
2275da6c28aaSamw void
2276da6c28aaSamw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2277da6c28aaSamw     uint32_t *eaccess)
2278da6c28aaSamw {
2279da6c28aaSamw 	int access = 0;
2280da6c28aaSamw 	vnode_t *dir_vp;
2281da6c28aaSamw 	smb_node_t *unnamed_node;
2282da6c28aaSamw 
2283da6c28aaSamw 	ASSERT(cr);
2284da6c28aaSamw 	ASSERT(snode);
2285da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
2286da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
2287da6c28aaSamw 
2288da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
2289da6c28aaSamw 	if (unnamed_node) {
2290da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
2291da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
2292da6c28aaSamw 		/*
2293da6c28aaSamw 		 * Streams authorization should be performed against the
2294da6c28aaSamw 		 * unnamed stream.
2295da6c28aaSamw 		 */
2296da6c28aaSamw 		snode = unnamed_node;
2297da6c28aaSamw 	}
2298da6c28aaSamw 
2299c8ec8eeaSjose borrego 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) {
2300*1fcced4cSJordan Brown 		dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
2301da6c28aaSamw 		smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp,
2302da6c28aaSamw 		    cr);
2303da6c28aaSamw 		return;
2304da6c28aaSamw 	}
2305da6c28aaSamw 
2306da6c28aaSamw 	/*
2307da6c28aaSamw 	 * FS doesn't understand 32-bit mask
2308da6c28aaSamw 	 */
2309da6c28aaSamw 	smb_vop_eaccess(snode->vp, &access, 0, NULL, cr);
2310743a77edSAlan Wright 	access &= sr->tid_tree->t_access;
2311da6c28aaSamw 
2312da6c28aaSamw 	*eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES;
2313da6c28aaSamw 
2314da6c28aaSamw 	if (access & VREAD)
2315da6c28aaSamw 		*eaccess |= FILE_READ_DATA;
2316da6c28aaSamw 
2317da6c28aaSamw 	if (access & VEXEC)
2318da6c28aaSamw 		*eaccess |= FILE_EXECUTE;
2319da6c28aaSamw 
2320da6c28aaSamw 	if (access & VWRITE)
2321da6c28aaSamw 		*eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
2322da6c28aaSamw 		    FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
2323da6c28aaSamw }
232455bf511dSas200622 
2325dc20a302Sas200622 /*
2326dc20a302Sas200622  * smb_fsop_shrlock
2327dc20a302Sas200622  *
2328dc20a302Sas200622  * For the current open request, check file sharing rules
2329dc20a302Sas200622  * against existing opens.
2330dc20a302Sas200622  *
2331dc20a302Sas200622  * Returns NT_STATUS_SHARING_VIOLATION if there is any
2332dc20a302Sas200622  * sharing conflict.  Returns NT_STATUS_SUCCESS otherwise.
2333dc20a302Sas200622  *
2334dc20a302Sas200622  * Full system-wide share reservation synchronization is available
2335dc20a302Sas200622  * when the nbmand (non-blocking mandatory) mount option is set
2336dc20a302Sas200622  * (i.e. nbl_need_crit() is true) and nbmand critical regions are used.
2337dc20a302Sas200622  * This provides synchronization with NFS and local processes.  The
2338dc20a302Sas200622  * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called
2339dc20a302Sas200622  * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well
2340dc20a302Sas200622  * as the CIFS rename and delete paths.
2341dc20a302Sas200622  *
2342dc20a302Sas200622  * The CIFS server will also enter the nbl critical region in the open,
2343dc20a302Sas200622  * rename, and delete paths when nbmand is not set.  There is limited
2344dc20a302Sas200622  * coordination with local and VFS share reservations in this case.
2345dc20a302Sas200622  * Note that when the nbmand mount option is not set, the VFS layer
2346dc20a302Sas200622  * only processes advisory reservations and the delete mode is not checked.
2347dc20a302Sas200622  *
2348dc20a302Sas200622  * Whether or not the nbmand mount option is set, intra-CIFS share
2349dc20a302Sas200622  * checking is done in the open, delete, and rename paths using a CIFS
2350dc20a302Sas200622  * critical region (node->n_share_lock).
2351dc20a302Sas200622  */
2352dc20a302Sas200622 
2353dc20a302Sas200622 uint32_t
2354faa1795aSjb150015 smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid,
2355dc20a302Sas200622     uint32_t desired_access, uint32_t share_access)
235655bf511dSas200622 {
2357dc20a302Sas200622 	int rc;
2358dc20a302Sas200622 
2359037cac00Sjoyce mcintosh 	if (smb_node_is_dir(node))
2360dc20a302Sas200622 		return (NT_STATUS_SUCCESS);
2361dc20a302Sas200622 
2362dc20a302Sas200622 	/* Allow access if the request is just for meta data */
2363dc20a302Sas200622 	if ((desired_access & FILE_DATA_ALL) == 0)
2364dc20a302Sas200622 		return (NT_STATUS_SUCCESS);
2365dc20a302Sas200622 
2366dc20a302Sas200622 	rc = smb_node_open_check(node, cr, desired_access, share_access);
2367dc20a302Sas200622 	if (rc)
2368dc20a302Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
2369dc20a302Sas200622 
2370dc20a302Sas200622 	rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access,
2371dc20a302Sas200622 	    cr);
2372dc20a302Sas200622 	if (rc)
2373dc20a302Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
2374dc20a302Sas200622 
2375dc20a302Sas200622 	return (NT_STATUS_SUCCESS);
2376dc20a302Sas200622 }
2377dc20a302Sas200622 
2378dc20a302Sas200622 void
2379dc20a302Sas200622 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid)
2380dc20a302Sas200622 {
2381037cac00Sjoyce mcintosh 	if (smb_node_is_dir(node))
2382dc20a302Sas200622 		return;
2383dc20a302Sas200622 
2384dc20a302Sas200622 	(void) smb_vop_unshrlock(node->vp, uniq_fid, cr);
2385dc20a302Sas200622 }
23868c10a865Sas200622 
23878c10a865Sas200622 int
23888c10a865Sas200622 smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock,
23898c10a865Sas200622     cred_t *cr)
23908c10a865Sas200622 {
23918c10a865Sas200622 	flock64_t bf;
23928c10a865Sas200622 	int flag = F_REMOTELOCK;
23938c10a865Sas200622 
23943ad684d6Sjb150015 	/*
23953ad684d6Sjb150015 	 * VOP_FRLOCK() will not be called if:
23963ad684d6Sjb150015 	 *
23973ad684d6Sjb150015 	 * 1) The lock has a range of zero bytes. The semantics of Windows and
23983ad684d6Sjb150015 	 *    POSIX are different. In the case of POSIX it asks for the locking
23993ad684d6Sjb150015 	 *    of all the bytes from the offset provided until the end of the
24003ad684d6Sjb150015 	 *    file. In the case of Windows a range of zero locks nothing and
24013ad684d6Sjb150015 	 *    doesn't conflict with any other lock.
24023ad684d6Sjb150015 	 *
24033ad684d6Sjb150015 	 * 2) The lock rolls over (start + lenght < start). Solaris will assert
24043ad684d6Sjb150015 	 *    if such a request is submitted. This will not create
24053ad684d6Sjb150015 	 *    incompatibilities between POSIX and Windows. In the Windows world,
24063ad684d6Sjb150015 	 *    if a client submits such a lock, the server will not lock any
24073ad684d6Sjb150015 	 *    bytes. Interestingly if the same lock (same offset and length) is
24083ad684d6Sjb150015 	 *    resubmitted Windows will consider that there is an overlap and
24093ad684d6Sjb150015 	 *    the granting rules will then apply.
24103ad684d6Sjb150015 	 */
24113ad684d6Sjb150015 	if ((lock->l_length == 0) ||
24123ad684d6Sjb150015 	    ((lock->l_start + lock->l_length - 1) < lock->l_start))
24133ad684d6Sjb150015 		return (0);
24143ad684d6Sjb150015 
24158c10a865Sas200622 	bzero(&bf, sizeof (bf));
24168c10a865Sas200622 
24178c10a865Sas200622 	if (unlock) {
24188c10a865Sas200622 		bf.l_type = F_UNLCK;
24198c10a865Sas200622 	} else if (lock->l_type == SMB_LOCK_TYPE_READONLY) {
24208c10a865Sas200622 		bf.l_type = F_RDLCK;
24218c10a865Sas200622 		flag |= FREAD;
24228c10a865Sas200622 	} else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) {
24238c10a865Sas200622 		bf.l_type = F_WRLCK;
24248c10a865Sas200622 		flag |= FWRITE;
24258c10a865Sas200622 	}
24268c10a865Sas200622 
24278c10a865Sas200622 	bf.l_start = lock->l_start;
24288c10a865Sas200622 	bf.l_len = lock->l_length;
2429c8ec8eeaSjose borrego 	bf.l_pid = lock->l_file->f_uniqid;
24308c10a865Sas200622 	bf.l_sysid = smb_ct.cc_sysid;
24318c10a865Sas200622 
24328c10a865Sas200622 	return (smb_vop_frlock(node->vp, cr, flag, &bf));
24338c10a865Sas200622 }
2434