xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_fsops.c (revision eb1d736b1c19f6abeee90c921a9320b67fedd016)
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>
27dc20a302Sas #include <sys/nbmlock.h>
28da6c28aaSamw #include <smbsrv/smb_fsops.h>
2955bf511dSas #include <smbsrv/smb_kproto.h>
3055bf511dSas #include <smbsrv/ntstatus.h>
3155bf511dSas #include <smbsrv/ntaccess.h>
32dc20a302Sas #include <smbsrv/smb_incl.h>
33da6c28aaSamw #include <acl/acl_common.h>
34dc20a302Sas #include <sys/fcntl.h>
35dc20a302Sas #include <sys/flock.h>
36dc20a302Sas #include <fs/fs_subr.h>
37da6c28aaSamw 
38faa1795aSjb extern caller_context_t smb_ct;
39faa1795aSjb 
408c10a865Sas extern int smb_fem_oplock_install(smb_node_t *);
418c10a865Sas extern void smb_fem_oplock_uninstall(smb_node_t *);
428c10a865Sas 
438c10a865Sas extern int smb_vop_other_opens(vnode_t *, int);
448c10a865Sas 
45*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_stream(smb_request_t *, cred_t *, smb_node_t *,
46*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     char *, char *, int, smb_attr_t *, smb_node_t **, smb_attr_t *);
47*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
48*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_file(smb_request_t *, cred_t *, smb_node_t *,
49*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     char *, int, smb_attr_t *, smb_node_t **, smb_attr_t *);
50*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
51*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_with_sd(smb_request_t *, cred_t *, smb_node_t *,
52*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     char *, smb_attr_t *, smb_node_t **, smb_attr_t *, smb_fssd_t *);
53*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
54*eb1d736bSafshin 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 
778c10a865Sas /*
788c10a865Sas  * smb_fsop_amask_to_omode
798c10a865Sas  *
808c10a865Sas  * Convert the access mask to the open mode (for use
818c10a865Sas  * with the VOP_OPEN call).
828c10a865Sas  *
838c10a865Sas  * Note that opening a file for attribute only access
848c10a865Sas  * will also translate into an FREAD or FWRITE open mode
858c10a865Sas  * (i.e., it's not just for data).
868c10a865Sas  *
878c10a865Sas  * This is needed so that opens are tracked appropriately
888c10a865Sas  * for oplock processing.
898c10a865Sas  */
908c10a865Sas 
91da6c28aaSamw int
928c10a865Sas smb_fsop_amask_to_omode(uint32_t access)
93da6c28aaSamw {
948c10a865Sas 	int mode = 0;
958c10a865Sas 
968c10a865Sas 	if (access & (FILE_READ_DATA | FILE_EXECUTE |
978c10a865Sas 	    FILE_READ_ATTRIBUTES | FILE_READ_EA))
988c10a865Sas 		mode |= FREAD;
99da6c28aaSamw 
1008c10a865Sas 	if (access & (FILE_WRITE_DATA | FILE_APPEND_DATA |
1018c10a865Sas 	    FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))
1028c10a865Sas 		mode |= FWRITE;
1038c10a865Sas 
1048c10a865Sas 	if (access & FILE_APPEND_DATA)
1058c10a865Sas 		mode |= FAPPEND;
1068c10a865Sas 
1078c10a865Sas 	return (mode);
1088c10a865Sas }
109da6c28aaSamw 
1108c10a865Sas int
1118c10a865Sas smb_fsop_open(smb_node_t *node, int mode, cred_t *cred)
1128c10a865Sas {
113da6c28aaSamw 	/*
1148c10a865Sas 	 * Assuming that the same vnode is returned as we had before.
1158c10a865Sas 	 * (I.e., with certain types of files or file systems, a
1168c10a865Sas 	 * different vnode might be returned by VOP_OPEN)
117da6c28aaSamw 	 */
1188c10a865Sas 	return (smb_vop_open(&node->vp, mode, cred));
119da6c28aaSamw }
120da6c28aaSamw 
121c8ec8eeaSjose borrego void
1228c10a865Sas smb_fsop_close(smb_node_t *node, int mode, cred_t *cred)
123da6c28aaSamw {
124c8ec8eeaSjose borrego 	smb_vop_close(node->vp, mode, cred);
125da6c28aaSamw }
126da6c28aaSamw 
1278c10a865Sas int
1288c10a865Sas smb_fsop_oplock_install(smb_node_t *node, int mode)
129da6c28aaSamw {
1308c10a865Sas 	int rc;
131da6c28aaSamw 
1328c10a865Sas 	if (smb_vop_other_opens(node->vp, mode))
1338c10a865Sas 		return (EMFILE);
134da6c28aaSamw 
1358c10a865Sas 	if ((rc = smb_fem_oplock_install(node)))
1368c10a865Sas 		return (rc);
137da6c28aaSamw 
1388c10a865Sas 	if (smb_vop_other_opens(node->vp, mode)) {
1398c10a865Sas 		(void) smb_fem_oplock_uninstall(node);
1408c10a865Sas 		return (EMFILE);
1418c10a865Sas 	}
142da6c28aaSamw 
1438c10a865Sas 	return (0);
1448c10a865Sas }
1458c10a865Sas 
1468c10a865Sas void
1478c10a865Sas smb_fsop_oplock_uninstall(smb_node_t *node)
1488c10a865Sas {
1498c10a865Sas 	smb_fem_oplock_uninstall(node);
150da6c28aaSamw }
151da6c28aaSamw 
152da6c28aaSamw static int
153*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_with_sd(smb_request_t *sr, cred_t *cr,
154*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *dnode, char *name,
155*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr,
156*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_fssd_t *fs_sd)
157da6c28aaSamw {
158da6c28aaSamw 	vsecattr_t *vsap;
159da6c28aaSamw 	vsecattr_t vsecattr;
160da6c28aaSamw 	acl_t *acl, *dacl, *sacl;
161da6c28aaSamw 	smb_attr_t set_attr;
162da6c28aaSamw 	vnode_t *vp;
163da6c28aaSamw 	int aclbsize = 0;	/* size of acl list in bytes */
164da6c28aaSamw 	int flags = 0;
165da6c28aaSamw 	int rc;
1662c1b14e5Sjose borrego 	boolean_t is_dir;
167da6c28aaSamw 
168da6c28aaSamw 	ASSERT(fs_sd);
169da6c28aaSamw 
170c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
171da6c28aaSamw 		flags = SMB_IGNORE_CASE;
1728b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
1738b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
174da6c28aaSamw 
175da6c28aaSamw 	ASSERT(cr);
176da6c28aaSamw 
177da6c28aaSamw 	is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0);
178da6c28aaSamw 
179c8ec8eeaSjose borrego 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) {
180da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
181da6c28aaSamw 			dacl = fs_sd->sd_zdacl;
182da6c28aaSamw 			sacl = fs_sd->sd_zsacl;
183da6c28aaSamw 			ASSERT(dacl || sacl);
184da6c28aaSamw 			if (dacl && sacl) {
18555bf511dSas 				acl = smb_fsacl_merge(dacl, sacl);
186da6c28aaSamw 			} else if (dacl) {
187da6c28aaSamw 				acl = dacl;
188da6c28aaSamw 			} else {
189da6c28aaSamw 				acl = sacl;
190da6c28aaSamw 			}
191da6c28aaSamw 
19255bf511dSas 			rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize);
193da6c28aaSamw 
194da6c28aaSamw 			if (dacl && sacl)
195da6c28aaSamw 				acl_free(acl);
196da6c28aaSamw 
1972c1b14e5Sjose borrego 			if (rc != 0)
198da6c28aaSamw 				return (rc);
199da6c28aaSamw 
200da6c28aaSamw 			vsap = &vsecattr;
2012c1b14e5Sjose borrego 		} else {
202da6c28aaSamw 			vsap = NULL;
2032c1b14e5Sjose borrego 		}
204da6c28aaSamw 
205743a77edSAlan Wright 		/* The tree ACEs may prevent a create */
206743a77edSAlan Wright 		rc = EACCES;
207da6c28aaSamw 		if (is_dir) {
208743a77edSAlan Wright 			if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_SUBDIRECTORY) != 0)
209*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 				rc = smb_vop_mkdir(dnode->vp, name, attr,
210743a77edSAlan Wright 				    &vp, flags, cr, vsap);
211da6c28aaSamw 		} else {
212743a77edSAlan Wright 			if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_FILE) != 0)
213*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 				rc = smb_vop_create(dnode->vp, name, attr,
214743a77edSAlan Wright 				    &vp, flags, cr, vsap);
215da6c28aaSamw 		}
216da6c28aaSamw 
217da6c28aaSamw 		if (vsap != NULL)
218da6c28aaSamw 			kmem_free(vsap->vsa_aclentp, aclbsize);
219da6c28aaSamw 
220da6c28aaSamw 		if (rc != 0)
221da6c28aaSamw 			return (rc);
222da6c28aaSamw 
223da6c28aaSamw 		set_attr.sa_mask = 0;
224da6c28aaSamw 
225da6c28aaSamw 		/*
226da6c28aaSamw 		 * Ideally we should be able to specify the owner and owning
227da6c28aaSamw 		 * group at create time along with the ACL. Since we cannot
228da6c28aaSamw 		 * do that right now, kcred is passed to smb_vop_setattr so it
229da6c28aaSamw 		 * doesn't fail due to lack of permission.
230da6c28aaSamw 		 */
231da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
232da6c28aaSamw 			set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
233da6c28aaSamw 			set_attr.sa_mask |= SMB_AT_UID;
234da6c28aaSamw 		}
235da6c28aaSamw 
236da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
237da6c28aaSamw 			set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
238da6c28aaSamw 			set_attr.sa_mask |= SMB_AT_GID;
239da6c28aaSamw 		}
240da6c28aaSamw 
2419660e5cbSJanice Chang 		if (set_attr.sa_mask)
2429660e5cbSJanice Chang 			rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcred);
243da6c28aaSamw 
2442c1b14e5Sjose borrego 		if (rc == 0) {
2452c1b14e5Sjose borrego 			*ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
246*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			    name, dnode, NULL, ret_attr);
2472c1b14e5Sjose borrego 
2487f667e74Sjose borrego 			if (*ret_snode == NULL)
2492c1b14e5Sjose borrego 				rc = ENOMEM;
2507f667e74Sjose borrego 
2517f667e74Sjose borrego 			VN_RELE(vp);
2522c1b14e5Sjose borrego 		}
253da6c28aaSamw 	} else {
254da6c28aaSamw 		/*
255da6c28aaSamw 		 * For filesystems that don't support ACL-on-create, try
256da6c28aaSamw 		 * to set the specified SD after create, which could actually
257da6c28aaSamw 		 * fail because of conflicts between inherited security
258da6c28aaSamw 		 * attributes upon creation and the specified SD.
259da6c28aaSamw 		 *
260da6c28aaSamw 		 * Passing kcred to smb_fsop_sdwrite() to overcome this issue.
261da6c28aaSamw 		 */
262da6c28aaSamw 
263da6c28aaSamw 		if (is_dir) {
264*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_vop_mkdir(dnode->vp, name, attr, &vp,
2652c1b14e5Sjose borrego 			    flags, cr, NULL);
266da6c28aaSamw 		} else {
267*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_vop_create(dnode->vp, name, attr, &vp,
2682c1b14e5Sjose borrego 			    flags, cr, NULL);
269da6c28aaSamw 		}
270da6c28aaSamw 
27155bf511dSas 		if (rc != 0)
27255bf511dSas 			return (rc);
27355bf511dSas 
2742c1b14e5Sjose borrego 		*ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
275*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		    name, dnode, NULL, ret_attr);
276da6c28aaSamw 
2772c1b14e5Sjose borrego 		if (*ret_snode != NULL) {
2782c1b14e5Sjose borrego 			if (!smb_tree_has_feature(sr->tid_tree,
2792c1b14e5Sjose borrego 			    SMB_TREE_NFS_MOUNTED))
2802c1b14e5Sjose borrego 				rc = smb_fsop_sdwrite(sr, kcred, *ret_snode,
2812c1b14e5Sjose borrego 				    fs_sd, 1);
2822c1b14e5Sjose borrego 		} else {
283da6c28aaSamw 			rc = ENOMEM;
284da6c28aaSamw 		}
2857f667e74Sjose borrego 
2867f667e74Sjose borrego 		VN_RELE(vp);
287da6c28aaSamw 	}
288da6c28aaSamw 
28955bf511dSas 	if (rc != 0) {
2902c1b14e5Sjose borrego 		if (is_dir)
291*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			(void) smb_vop_rmdir(dnode->vp, name, flags, cr);
2922c1b14e5Sjose borrego 		else
293*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			(void) smb_vop_remove(dnode->vp, name, flags, cr);
29455bf511dSas 	}
29555bf511dSas 
296da6c28aaSamw 	return (rc);
297da6c28aaSamw }
298da6c28aaSamw 
299da6c28aaSamw /*
300da6c28aaSamw  * smb_fsop_create
301da6c28aaSamw  *
302da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
303da6c28aaSamw  * all the smb_vop_creates are performed with the appropriate credentials.
304*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * Please document any direct calls to explain the reason for avoiding
305*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * this wrapper.
306da6c28aaSamw  *
307da6c28aaSamw  * *ret_snode is returned with a reference upon success.  No reference is
308da6c28aaSamw  * taken if an error is returned.
309da6c28aaSamw  */
310da6c28aaSamw int
311*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create(smb_request_t *sr, cred_t *cr,
312*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *dnode, char *name,
313*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr)
314da6c28aaSamw {
315*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	int	rc = 0;
316*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	int	flags = 0;
317*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	char	*fname, *sname;
318*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	char	*longname = NULL;
319da6c28aaSamw 
320da6c28aaSamw 	ASSERT(cr);
321*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
322*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
323*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
324da6c28aaSamw 
325da6c28aaSamw 	ASSERT(ret_snode);
326da6c28aaSamw 	*ret_snode = 0;
327da6c28aaSamw 
328da6c28aaSamw 	ASSERT(name);
329da6c28aaSamw 	if (*name == 0)
330da6c28aaSamw 		return (EINVAL);
331da6c28aaSamw 
332da6c28aaSamw 	ASSERT(sr);
333da6c28aaSamw 	ASSERT(sr->tid_tree);
334c8ec8eeaSjose borrego 
335*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
336c8ec8eeaSjose borrego 		return (EACCES);
337c8ec8eeaSjose borrego 
338c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
339da6c28aaSamw 		return (EROFS);
340da6c28aaSamw 
341c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
342da6c28aaSamw 		flags = SMB_IGNORE_CASE;
3438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
3448b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
345da6c28aaSamw 
3468b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_is_stream_name(name)) {
3478b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
3488b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
349*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_stream_parse_name(name, fname, sname);
350da6c28aaSamw 
351*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_create_stream(sr, cr, dnode,
352*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		    fname, sname, flags, attr, ret_snode, ret_attr);
353da6c28aaSamw 
354*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		kmem_free(fname, MAXNAMELEN);
355*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		kmem_free(sname, MAXNAMELEN);
356*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (rc);
357*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
358da6c28aaSamw 
359*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	/* Not a named stream */
360da6c28aaSamw 
361*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_maybe_mangled_name(name)) {
362*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
363*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
364*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		kmem_free(longname, MAXNAMELEN);
365da6c28aaSamw 
366*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (rc == 0)
367*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = EEXIST;
368*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (rc != ENOENT)
369da6c28aaSamw 			return (rc);
370*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
371da6c28aaSamw 
372*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_fsop_create_file(sr, cr, dnode, name, flags,
373*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	    attr, ret_snode, ret_attr);
374*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	return (rc);
3757b59d02dSjb 
376*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States }
3777b59d02dSjb 
3787b59d02dSjb 
379*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /*
380*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * smb_fsop_create_stream
381*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  *
382*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * Create NTFS named stream file (sname) on unnamed stream
383*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * file (fname), creating the unnamed stream file if it
384*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * doesn't exist.
385*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * If we created the unnamed stream file and then creation
386*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * of the named stream file fails, we delete the unnamed stream.
387*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * Since we use the real file name for the smb_vop_remove we
388*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * clear the SMB_IGNORE_CASE flag to ensure a case sensitive
389*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * match.
390*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  *
391*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * The second parameter of smb_vop_setattr() is set to
392*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * NULL, even though an unnamed stream exists.  This is
393*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * because we want to set the UID and GID on the named
394*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * stream in this case for consistency with the (unnamed
395*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * stream) file (see comments for smb_vop_setattr()).
396*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  */
397*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int
398*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_stream(smb_request_t *sr, cred_t *cr,
399*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *dnode, char *fname, char *sname, int flags,
400*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr)
401*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States {
402*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_node_t	*fnode;
403*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_attr_t	fattr;
404*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	vnode_t		*xattrdvp;
405*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	vnode_t		*vp;
406*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	int		rc = 0;
407*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	boolean_t	fcreate = B_FALSE;
4087b59d02dSjb 
409*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	/* Look up / create the unnamed stream, fname */
410*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
411*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	    sr->tid_tree->t_snode, dnode, fname,
412*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	    &fnode, &fattr);
413*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (rc == ENOENT) {
414*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		fcreate = B_TRUE;
415*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_create_file(sr, cr, dnode, fname, flags,
416*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		    attr, &fnode, &fattr);
417*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
418*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (rc != 0)
419*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (rc);
420da6c28aaSamw 
421*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	/* create the named stream, sname */
422*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp,
423*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	    &xattrdvp, flags, cr);
424*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (rc != 0) {
425*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (fcreate) {
426*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			flags &= ~SMB_IGNORE_CASE;
427*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			(void) smb_vop_remove(dnode->vp,
428*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			    fnode->od_name, flags, cr);
429*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		}
430da6c28aaSamw 		smb_node_release(fnode);
431*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (rc);
432*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
433da6c28aaSamw 
434*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	attr->sa_vattr.va_uid = fattr.sa_vattr.va_uid;
435*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	attr->sa_vattr.va_gid = fattr.sa_vattr.va_gid;
436*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	attr->sa_mask = SMB_AT_UID | SMB_AT_GID;
437da6c28aaSamw 
438*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_setattr(vp, NULL, attr, 0, kcred);
439*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (rc != 0) {
440*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_release(fnode);
4418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (rc);
4428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
443da6c28aaSamw 
444*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	*ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdvp,
445*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	    vp, sname, ret_attr);
4468b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
447*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_node_release(fnode);
448*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	VN_RELE(xattrdvp);
449*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	VN_RELE(vp);
450*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
451*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (*ret_snode == NULL)
452*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = ENOMEM;
453*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
454*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	return (rc);
455*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States }
456*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
457*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /*
458*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * smb_fsop_create_file
459*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  */
460*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int
461*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_file(smb_request_t *sr, cred_t *cr,
462*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *dnode, char *name, int flags,
463*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr)
464*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States {
465*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	open_param_t	*op = &sr->arg.open;
466*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	vnode_t		*vp;
467*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_fssd_t	fs_sd;
468*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	uint32_t	secinfo;
469*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	uint32_t	status;
470*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	int		rc = 0;
4718b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
4728b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (op->sd) {
4738b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		/*
4748b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * SD sent by client in Windows format. Needs to be
4758b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * converted to FS format. No inheritance.
4768b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 */
4778b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		secinfo = smb_sd_get_secinfo(op->sd);
4788b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_fssd_init(&fs_sd, secinfo, 0);
4798b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
4808b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		status = smb_sd_tofs(op->sd, &fs_sd);
4818b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (status == NT_STATUS_SUCCESS) {
482*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
4838b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			    name, attr, ret_snode, ret_attr, &fs_sd);
484da6c28aaSamw 		} else {
4858b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = EINVAL;
4868b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		}
4878b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_fssd_term(&fs_sd);
4888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	} else if (sr->tid_tree->t_acltype == ACE_T) {
4898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		/*
4908b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * No incoming SD and filesystem is ZFS
4918b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * Server applies Windows inheritance rules,
4928b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * see smb_fsop_sdinherit() comments as to why.
4938b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 */
4948b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0);
495*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
4968b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (rc == 0) {
497*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
4988b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			    name, attr, ret_snode, ret_attr, &fs_sd);
4998b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		}
500da6c28aaSamw 
5018b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_fssd_term(&fs_sd);
5028b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	} else {
5038b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		/*
5048b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * No incoming SD and filesystem is not ZFS
5058b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * let the filesystem handles the inheritance.
5068b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 */
507*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_create(dnode->vp, name, attr, &vp,
5088b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    flags, cr, NULL);
509da6c28aaSamw 
5108b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (rc == 0) {
5118b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			*ret_snode = smb_node_lookup(sr, op, cr, vp,
512*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			    name, dnode, NULL, ret_attr);
5137f667e74Sjose borrego 
5148b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			if (*ret_snode == NULL)
5158b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 				rc = ENOMEM;
516da6c28aaSamw 
5178b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			VN_RELE(vp);
518da6c28aaSamw 		}
5198b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
520da6c28aaSamw 	}
521da6c28aaSamw 	return (rc);
522da6c28aaSamw }
523da6c28aaSamw 
524da6c28aaSamw /*
525da6c28aaSamw  * smb_fsop_mkdir
526da6c28aaSamw  *
527da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
528da6c28aaSamw  * the the calls are performed with the appropriate credentials.
529da6c28aaSamw  * Please document any direct call to explain the reason
530da6c28aaSamw  * for avoiding this wrapper.
531da6c28aaSamw  *
532da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
533da6c28aaSamw  *
534da6c28aaSamw  * *ret_snode is returned with a reference upon success.  No reference is
535da6c28aaSamw  * taken if an error is returned.
536da6c28aaSamw  */
537da6c28aaSamw int
538da6c28aaSamw smb_fsop_mkdir(
539faa1795aSjb     smb_request_t *sr,
540da6c28aaSamw     cred_t *cr,
541*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *dnode,
542da6c28aaSamw     char *name,
543da6c28aaSamw     smb_attr_t *attr,
544da6c28aaSamw     smb_node_t **ret_snode,
545da6c28aaSamw     smb_attr_t *ret_attr)
546da6c28aaSamw {
547da6c28aaSamw 	struct open_param *op = &sr->arg.open;
548da6c28aaSamw 	char *longname;
549da6c28aaSamw 	vnode_t *vp;
550da6c28aaSamw 	int flags = 0;
551da6c28aaSamw 	smb_fssd_t fs_sd;
552da6c28aaSamw 	uint32_t secinfo;
553da6c28aaSamw 	uint32_t status;
554da6c28aaSamw 	int rc;
555da6c28aaSamw 	ASSERT(cr);
556*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
557*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
558*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
559da6c28aaSamw 
560da6c28aaSamw 	ASSERT(ret_snode);
561da6c28aaSamw 	*ret_snode = 0;
562da6c28aaSamw 
563da6c28aaSamw 	ASSERT(name);
564da6c28aaSamw 	if (*name == 0)
565da6c28aaSamw 		return (EINVAL);
566da6c28aaSamw 
567da6c28aaSamw 	ASSERT(sr);
568da6c28aaSamw 	ASSERT(sr->tid_tree);
569c8ec8eeaSjose borrego 
570*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
571c8ec8eeaSjose borrego 		return (EACCES);
572c8ec8eeaSjose borrego 
573c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
574da6c28aaSamw 		return (EROFS);
5758b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
5768b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
577da6c28aaSamw 
578da6c28aaSamw 	if (smb_maybe_mangled_name(name)) {
579da6c28aaSamw 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
580*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
581da6c28aaSamw 		kmem_free(longname, MAXNAMELEN);
582da6c28aaSamw 
583da6c28aaSamw 		/*
584da6c28aaSamw 		 * If the name passed in by the client has an unmangled
585da6c28aaSamw 		 * equivalent that is found in the specified directory,
586da6c28aaSamw 		 * then the mkdir cannot succeed.  Return EEXIST.
587da6c28aaSamw 		 *
588da6c28aaSamw 		 * Only if ENOENT is returned will a mkdir be attempted.
589da6c28aaSamw 		 */
590da6c28aaSamw 
591da6c28aaSamw 		if (rc == 0)
592da6c28aaSamw 			rc = EEXIST;
593da6c28aaSamw 
594da6c28aaSamw 		if (rc != ENOENT)
595da6c28aaSamw 			return (rc);
596da6c28aaSamw 	}
597da6c28aaSamw 
598c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
599da6c28aaSamw 		flags = SMB_IGNORE_CASE;
600da6c28aaSamw 
60155bf511dSas 	if (op->sd) {
602da6c28aaSamw 		/*
603da6c28aaSamw 		 * SD sent by client in Windows format. Needs to be
604da6c28aaSamw 		 * converted to FS format. No inheritance.
605da6c28aaSamw 		 */
60655bf511dSas 		secinfo = smb_sd_get_secinfo(op->sd);
60755bf511dSas 		smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR);
608da6c28aaSamw 
60955bf511dSas 		status = smb_sd_tofs(op->sd, &fs_sd);
610da6c28aaSamw 		if (status == NT_STATUS_SUCCESS) {
611*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
612da6c28aaSamw 			    name, attr, ret_snode, ret_attr, &fs_sd);
613da6c28aaSamw 		}
614da6c28aaSamw 		else
615da6c28aaSamw 			rc = EINVAL;
61655bf511dSas 		smb_fssd_term(&fs_sd);
617da6c28aaSamw 	} else if (sr->tid_tree->t_acltype == ACE_T) {
618da6c28aaSamw 		/*
619da6c28aaSamw 		 * No incoming SD and filesystem is ZFS
620da6c28aaSamw 		 * Server applies Windows inheritance rules,
621da6c28aaSamw 		 * see smb_fsop_sdinherit() comments as to why.
622da6c28aaSamw 		 */
62355bf511dSas 		smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR);
624*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
625da6c28aaSamw 		if (rc == 0) {
626*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
627da6c28aaSamw 			    name, attr, ret_snode, ret_attr, &fs_sd);
628da6c28aaSamw 		}
629da6c28aaSamw 
63055bf511dSas 		smb_fssd_term(&fs_sd);
631da6c28aaSamw 
632da6c28aaSamw 	} else {
633*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, flags, cr,
634dc20a302Sas 		    NULL);
635da6c28aaSamw 
636da6c28aaSamw 		if (rc == 0) {
637da6c28aaSamw 			*ret_snode = smb_node_lookup(sr, op, cr, vp, name,
638*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			    dnode, NULL, ret_attr);
639da6c28aaSamw 
6407f667e74Sjose borrego 			if (*ret_snode == NULL)
641da6c28aaSamw 				rc = ENOMEM;
6427f667e74Sjose borrego 
6437f667e74Sjose borrego 			VN_RELE(vp);
644da6c28aaSamw 		}
645da6c28aaSamw 	}
646da6c28aaSamw 
647da6c28aaSamw 	return (rc);
648da6c28aaSamw }
649da6c28aaSamw 
650da6c28aaSamw /*
651da6c28aaSamw  * smb_fsop_remove
652da6c28aaSamw  *
653da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
654da6c28aaSamw  * the the calls are performed with the appropriate credentials.
655da6c28aaSamw  * Please document any direct call to explain the reason
656da6c28aaSamw  * for avoiding this wrapper.
657da6c28aaSamw  *
658da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
659da6c28aaSamw  *
660da6c28aaSamw  * A null smb_request might be passed to this function.
661da6c28aaSamw  */
662da6c28aaSamw int
663da6c28aaSamw smb_fsop_remove(
664faa1795aSjb     smb_request_t	*sr,
665faa1795aSjb     cred_t		*cr,
666*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t		*dnode,
667faa1795aSjb     char		*name,
6688b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States     uint32_t		flags)
669da6c28aaSamw {
670faa1795aSjb 	smb_node_t	*fnode;
671faa1795aSjb 	smb_attr_t	file_attr;
672faa1795aSjb 	char		*longname;
673faa1795aSjb 	char		*fname;
674faa1795aSjb 	char		*sname;
675faa1795aSjb 	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 	 */
683*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
684*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
685da6c28aaSamw 
686*eb1d736bSafshin 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 
696*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (dnode->flags & NODE_XATTR_DIR) {
697*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_stream_remove(dnode->dir_snode->vp,
698cbfb650aScp 		    name, flags, cr);
699*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	} else if (smb_is_stream_name(name)) {
700*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_stream_parse_name(name, fname, sname);
7018d7e4166Sjose borrego 
702da6c28aaSamw 		/*
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,
709*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		    sr->tid_tree->t_snode, dnode, fname,
7108b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    &fnode, &file_attr);
711da6c28aaSamw 
712da6c28aaSamw 		if (rc != 0) {
713da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
714da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
715da6c28aaSamw 			return (rc);
716da6c28aaSamw 		}
717da6c28aaSamw 
718da6c28aaSamw 		/*
719da6c28aaSamw 		 * XXX
720da6c28aaSamw 		 * Need to find out what permission is required by NTFS
721da6c28aaSamw 		 * to remove a stream.
722da6c28aaSamw 		 */
723dc20a302Sas 		rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr);
724da6c28aaSamw 
725da6c28aaSamw 		smb_node_release(fnode);
726da6c28aaSamw 	} else {
727*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_remove(dnode->vp, name, flags, cr);
728da6c28aaSamw 
729da6c28aaSamw 		if (rc == ENOENT) {
730da6c28aaSamw 			if (smb_maybe_mangled_name(name) == 0) {
731da6c28aaSamw 				kmem_free(fname, MAXNAMELEN);
732da6c28aaSamw 				kmem_free(sname, MAXNAMELEN);
733da6c28aaSamw 				return (rc);
734da6c28aaSamw 			}
735da6c28aaSamw 			longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
736da6c28aaSamw 
737*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_unmangle_name(dnode, name,
7388b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			    longname, MAXNAMELEN);
739da6c28aaSamw 
740da6c28aaSamw 			if (rc == 0) {
741da6c28aaSamw 				/*
7428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 				 * longname is the real (case-sensitive)
7438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 				 * on-disk name.
744da6c28aaSamw 				 * We make sure we do a remove on this exact
745da6c28aaSamw 				 * name, as the name was mangled and denotes
746da6c28aaSamw 				 * a unique file.
747da6c28aaSamw 				 */
748da6c28aaSamw 				flags &= ~SMB_IGNORE_CASE;
749*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 				rc = smb_vop_remove(dnode->vp, longname,
750dc20a302Sas 				    flags, cr);
751da6c28aaSamw 			}
752da6c28aaSamw 
753da6c28aaSamw 			kmem_free(longname, MAXNAMELEN);
754da6c28aaSamw 		}
755da6c28aaSamw 	}
756da6c28aaSamw 
757da6c28aaSamw 	kmem_free(fname, MAXNAMELEN);
758da6c28aaSamw 	kmem_free(sname, MAXNAMELEN);
759da6c28aaSamw 	return (rc);
760da6c28aaSamw }
761da6c28aaSamw 
762da6c28aaSamw /*
763da6c28aaSamw  * smb_fsop_remove_streams
764da6c28aaSamw  *
765da6c28aaSamw  * This function removes a file's streams without removing the
766da6c28aaSamw  * file itself.
767da6c28aaSamw  *
7687f667e74Sjose borrego  * It is assumed that fnode is not a link.
769da6c28aaSamw  */
770da6c28aaSamw int
771faa1795aSjb smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode)
772da6c28aaSamw {
7737f667e74Sjose borrego 	int rc, flags = 0;
7747f667e74Sjose borrego 	uint16_t odid;
7757f667e74Sjose borrego 	smb_odir_t *od;
7767f667e74Sjose borrego 	smb_odirent_t *odirent;
7777f667e74Sjose borrego 	boolean_t eos;
778da6c28aaSamw 
779c8ec8eeaSjose borrego 	ASSERT(sr);
780da6c28aaSamw 	ASSERT(cr);
781da6c28aaSamw 	ASSERT(fnode);
782da6c28aaSamw 	ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
783da6c28aaSamw 	ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
784da6c28aaSamw 
785*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0) {
786*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, EACCES);
787*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
788*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
789da6c28aaSamw 
790*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_IS_READONLY(sr)) {
791*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, EROFS);
792*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
793*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
794da6c28aaSamw 
795c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
796da6c28aaSamw 		flags = SMB_IGNORE_CASE;
797*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
7988b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
7998b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
800da6c28aaSamw 
801*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if ((odid = smb_odir_openat(sr, fnode)) == 0) {
802*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, ENOENT);
803*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
804*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
805*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
806*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) {
807*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_errno(sr, ENOENT);
808*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
809*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
810da6c28aaSamw 
8117f667e74Sjose borrego 	odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
8127f667e74Sjose borrego 	for (;;) {
8137f667e74Sjose borrego 		rc = smb_odir_read(sr, od, odirent, &eos);
8147f667e74Sjose borrego 		if ((rc != 0) || (eos))
815da6c28aaSamw 			break;
8167f667e74Sjose borrego 		(void) smb_vop_remove(od->d_dnode->vp, odirent->od_name,
8177f667e74Sjose borrego 		    flags, cr);
818da6c28aaSamw 	}
8197f667e74Sjose borrego 	kmem_free(odirent, sizeof (smb_odirent_t));
8207f667e74Sjose borrego 
8217f667e74Sjose borrego 	smb_odir_release(od);
8227f667e74Sjose borrego 	smb_odir_close(od);
823da6c28aaSamw 	return (rc);
824da6c28aaSamw }
825da6c28aaSamw 
826da6c28aaSamw /*
827da6c28aaSamw  * smb_fsop_rmdir
828da6c28aaSamw  *
829da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
830da6c28aaSamw  * the the calls are performed with the appropriate credentials.
831da6c28aaSamw  * Please document any direct call to explain the reason
832da6c28aaSamw  * for avoiding this wrapper.
833da6c28aaSamw  *
834da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
835da6c28aaSamw  */
836da6c28aaSamw int
837da6c28aaSamw smb_fsop_rmdir(
838faa1795aSjb     smb_request_t	*sr,
839faa1795aSjb     cred_t		*cr,
840*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t		*dnode,
841faa1795aSjb     char		*name,
8428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States     uint32_t		flags)
843da6c28aaSamw {
844faa1795aSjb 	int		rc;
845faa1795aSjb 	char		*longname;
846da6c28aaSamw 
847da6c28aaSamw 	ASSERT(cr);
848da6c28aaSamw 	/*
849da6c28aaSamw 	 * The state of the node could be SMB_NODE_STATE_DESTROYING if this
850da6c28aaSamw 	 * function is called during the deletion of the node (because of
851da6c28aaSamw 	 * DELETE_ON_CLOSE).
852da6c28aaSamw 	 */
853*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
854*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
855da6c28aaSamw 
856*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 ||
857743a77edSAlan Wright 	    SMB_TREE_HAS_ACCESS(sr, ACE_DELETE_CHILD) == 0)
858da6c28aaSamw 		return (EACCES);
859da6c28aaSamw 
860c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
861da6c28aaSamw 		return (EROFS);
862da6c28aaSamw 
863*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_rmdir(dnode->vp, name, flags, cr);
864da6c28aaSamw 
865da6c28aaSamw 	if (rc == ENOENT) {
866da6c28aaSamw 		if (smb_maybe_mangled_name(name) == 0)
867da6c28aaSamw 			return (rc);
868da6c28aaSamw 
869da6c28aaSamw 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
870*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
871da6c28aaSamw 
872da6c28aaSamw 		if (rc == 0) {
873da6c28aaSamw 			/*
8748b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			 * longname is the real (case-sensitive)
8758b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			 * on-disk name.
876da6c28aaSamw 			 * We make sure we do a rmdir on this exact
877da6c28aaSamw 			 * name, as the name was mangled and denotes
878da6c28aaSamw 			 * a unique directory.
879da6c28aaSamw 			 */
880da6c28aaSamw 			flags &= ~SMB_IGNORE_CASE;
881*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_vop_rmdir(dnode->vp, longname, flags, cr);
882da6c28aaSamw 		}
883da6c28aaSamw 
884da6c28aaSamw 		kmem_free(longname, MAXNAMELEN);
885da6c28aaSamw 	}
886da6c28aaSamw 
887da6c28aaSamw 	return (rc);
888da6c28aaSamw }
889da6c28aaSamw 
890da6c28aaSamw /*
891da6c28aaSamw  * smb_fsop_getattr
892da6c28aaSamw  *
893da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
894da6c28aaSamw  * the the calls are performed with the appropriate credentials.
895da6c28aaSamw  * Please document any direct call to explain the reason
896da6c28aaSamw  * for avoiding this wrapper.
897da6c28aaSamw  *
898da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
899da6c28aaSamw  */
900da6c28aaSamw int
901faa1795aSjb smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
902da6c28aaSamw     smb_attr_t *attr)
903da6c28aaSamw {
904da6c28aaSamw 	smb_node_t *unnamed_node;
905da6c28aaSamw 	vnode_t *unnamed_vp = NULL;
906da6c28aaSamw 	uint32_t status;
907da6c28aaSamw 	uint32_t access = 0;
908da6c28aaSamw 	int flags = 0;
909dc20a302Sas 	int rc;
910da6c28aaSamw 
911da6c28aaSamw 	ASSERT(cr);
912da6c28aaSamw 	ASSERT(snode);
913da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
914da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
915da6c28aaSamw 
916743a77edSAlan Wright 	if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0 ||
917743a77edSAlan Wright 	    SMB_TREE_HAS_ACCESS(sr, ACE_READ_ATTRIBUTES) == 0)
918da6c28aaSamw 		return (EACCES);
919da6c28aaSamw 
920da6c28aaSamw 	if (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 
946dc20a302Sas 	rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr);
947dc20a302Sas 	if (rc == 0)
948dc20a302Sas 		snode->attr = *attr;
949dc20a302Sas 
950dc20a302Sas 	return (rc);
951da6c28aaSamw }
952da6c28aaSamw 
953da6c28aaSamw /*
954da6c28aaSamw  * smb_fsop_rename
955da6c28aaSamw  *
956da6c28aaSamw  * All SMB functions should use this smb_vop_rename wrapper to ensure that
957da6c28aaSamw  * the smb_vop_rename is performed with the appropriate credentials.
958da6c28aaSamw  * Please document any direct call to smb_vop_rename to explain the reason
959da6c28aaSamw  * for avoiding this wrapper.
960da6c28aaSamw  *
961*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * It is assumed that references exist on from_dnode and to_dnode coming
962da6c28aaSamw  * into this routine.
963da6c28aaSamw  */
964da6c28aaSamw int
965da6c28aaSamw smb_fsop_rename(
966faa1795aSjb     smb_request_t *sr,
967da6c28aaSamw     cred_t *cr,
968*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *from_dnode,
969da6c28aaSamw     char *from_name,
970*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t *to_dnode,
971da6c28aaSamw     char *to_name)
972da6c28aaSamw {
973da6c28aaSamw 	smb_node_t *from_snode;
974da6c28aaSamw 	smb_attr_t tmp_attr;
975da6c28aaSamw 	vnode_t *from_vp;
9768b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	int flags = 0, ret_flags;
977da6c28aaSamw 	int rc;
978743a77edSAlan Wright 	boolean_t isdir;
979da6c28aaSamw 
980da6c28aaSamw 	ASSERT(cr);
981*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(from_dnode);
982*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(from_dnode->n_magic == SMB_NODE_MAGIC);
983*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(from_dnode->n_state != SMB_NODE_STATE_DESTROYING);
984da6c28aaSamw 
985*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(to_dnode);
986*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC);
987*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING);
988da6c28aaSamw 
989*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, from_dnode) == 0)
990da6c28aaSamw 		return (EACCES);
991da6c28aaSamw 
992*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0)
993da6c28aaSamw 		return (EACCES);
994da6c28aaSamw 
995da6c28aaSamw 	ASSERT(sr);
996da6c28aaSamw 	ASSERT(sr->tid_tree);
997c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
998da6c28aaSamw 		return (EROFS);
999da6c28aaSamw 
1000da6c28aaSamw 	/*
1001c8ec8eeaSjose borrego 	 * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE
1002da6c28aaSamw 	 * here.
1003da6c28aaSamw 	 *
1004da6c28aaSamw 	 * A case-sensitive rename is always done in this routine
1005da6c28aaSamw 	 * because we are using the on-disk name from an earlier lookup.
1006da6c28aaSamw 	 * If a mangled name was passed in by the caller (denoting a
1007da6c28aaSamw 	 * deterministic lookup), then the exact file must be renamed
1008da6c28aaSamw 	 * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or
1009da6c28aaSamw 	 * else the underlying file system might return a "first-match"
1010da6c28aaSamw 	 * on this on-disk name, possibly resulting in the wrong file).
1011da6c28aaSamw 	 */
1012da6c28aaSamw 
10138b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
10148b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
10158b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
1016da6c28aaSamw 	/*
1017da6c28aaSamw 	 * XXX: Lock required through smb_node_release() below?
1018da6c28aaSamw 	 */
1019da6c28aaSamw 
1020*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_lookup(from_dnode->vp, from_name, &from_vp, NULL,
10218b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	    flags, &ret_flags, NULL, cr);
1022da6c28aaSamw 
1023da6c28aaSamw 	if (rc != 0)
1024da6c28aaSamw 		return (rc);
1025da6c28aaSamw 
1026743a77edSAlan Wright 	isdir = from_vp->v_type == VDIR;
1027743a77edSAlan Wright 
1028743a77edSAlan Wright 	if ((isdir && SMB_TREE_HAS_ACCESS(sr,
1029743a77edSAlan Wright 	    ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY) !=
1030743a77edSAlan Wright 	    (ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY)) ||
1031743a77edSAlan Wright 	    (!isdir && SMB_TREE_HAS_ACCESS(sr, ACE_DELETE | ACE_ADD_FILE) !=
1032743a77edSAlan Wright 	    (ACE_DELETE | ACE_ADD_FILE)))
1033743a77edSAlan Wright 		return (EACCES);
1034743a77edSAlan Wright 
1035*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_rename(from_dnode->vp, from_name, to_dnode->vp,
1036dc20a302Sas 	    to_name, flags, cr);
1037da6c28aaSamw 
1038da6c28aaSamw 	if (rc == 0) {
1039da6c28aaSamw 		from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name,
1040*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		    from_dnode, NULL, &tmp_attr);
1041da6c28aaSamw 
1042da6c28aaSamw 		if (from_snode == NULL) {
10437f667e74Sjose borrego 			rc = ENOMEM;
10447f667e74Sjose borrego 		} else {
1045*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_node_rename(from_dnode, from_snode,
1046*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			    to_dnode, to_name);
10477f667e74Sjose borrego 			smb_node_release(from_snode);
1048da6c28aaSamw 		}
1049da6c28aaSamw 	}
10507f667e74Sjose borrego 	VN_RELE(from_vp);
1051da6c28aaSamw 
1052da6c28aaSamw 	/* XXX: unlock */
1053da6c28aaSamw 
1054da6c28aaSamw 	return (rc);
1055da6c28aaSamw }
1056da6c28aaSamw 
1057da6c28aaSamw /*
1058da6c28aaSamw  * smb_fsop_setattr
1059da6c28aaSamw  *
1060da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
1061da6c28aaSamw  * the the calls are performed with the appropriate credentials.
1062da6c28aaSamw  * Please document any direct call to explain the reason
1063da6c28aaSamw  * for avoiding this wrapper.
1064da6c28aaSamw  *
1065da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
1066da6c28aaSamw  * A null smb_request might be passed to this function.
1067da6c28aaSamw  */
1068da6c28aaSamw int
1069da6c28aaSamw smb_fsop_setattr(
1070faa1795aSjb     smb_request_t	*sr,
1071faa1795aSjb     cred_t		*cr,
1072faa1795aSjb     smb_node_t		*snode,
1073faa1795aSjb     smb_attr_t		*set_attr,
1074faa1795aSjb     smb_attr_t		*ret_attr)
1075da6c28aaSamw {
1076da6c28aaSamw 	smb_node_t *unnamed_node;
1077da6c28aaSamw 	vnode_t *unnamed_vp = NULL;
1078da6c28aaSamw 	uint32_t status;
10792c1b14e5Sjose borrego 	uint32_t access;
1080da6c28aaSamw 	int rc = 0;
1081da6c28aaSamw 	int flags = 0;
10822c1b14e5Sjose borrego 	uint_t sa_mask;
1083da6c28aaSamw 
1084da6c28aaSamw 	ASSERT(cr);
1085da6c28aaSamw 	ASSERT(snode);
1086da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1087da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1088da6c28aaSamw 
1089c8ec8eeaSjose borrego 	if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0)
1090da6c28aaSamw 		return (EACCES);
1091da6c28aaSamw 
1092c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1093da6c28aaSamw 		return (EROFS);
1094da6c28aaSamw 
1095743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr,
1096743a77edSAlan Wright 	    ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0)
1097743a77edSAlan Wright 		return (EACCES);
1098743a77edSAlan Wright 
1099c8ec8eeaSjose borrego 	if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) {
1100c8ec8eeaSjose borrego 		if (sr->fid_ofile) {
1101c8ec8eeaSjose borrego 			if (SMB_OFILE_IS_READONLY(sr->fid_ofile))
1102c8ec8eeaSjose borrego 				return (EACCES);
1103c8ec8eeaSjose borrego 		} else {
1104c8ec8eeaSjose borrego 			if (SMB_PATHFILE_IS_READONLY(sr, snode))
1105c8ec8eeaSjose borrego 				return (EACCES);
1106c8ec8eeaSjose borrego 		}
1107c8ec8eeaSjose borrego 	}
1108c8ec8eeaSjose borrego 
1109da6c28aaSamw 	/* sr could be NULL in some cases */
1110da6c28aaSamw 	if (sr && sr->fid_ofile) {
11112c1b14e5Sjose borrego 		sa_mask = set_attr->sa_mask;
11122c1b14e5Sjose borrego 		access = 0;
1113c8ec8eeaSjose borrego 
11142c1b14e5Sjose borrego 		if (sa_mask & SMB_AT_SIZE) {
11152c1b14e5Sjose borrego 			access |= FILE_WRITE_DATA;
11162c1b14e5Sjose borrego 			sa_mask &= ~SMB_AT_SIZE;
11172c1b14e5Sjose borrego 		}
11182c1b14e5Sjose borrego 
11192c1b14e5Sjose borrego 		if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) {
1120da6c28aaSamw 			access |= WRITE_OWNER;
11212c1b14e5Sjose borrego 			sa_mask &= ~(SMB_AT_UID|SMB_AT_GID);
11222c1b14e5Sjose borrego 		}
1123da6c28aaSamw 
11242c1b14e5Sjose borrego 		if (sa_mask)
1125da6c28aaSamw 			access |= FILE_WRITE_ATTRIBUTES;
1126da6c28aaSamw 
1127da6c28aaSamw 		status = smb_ofile_access(sr->fid_ofile, cr, access);
1128da6c28aaSamw 		if (status != NT_STATUS_SUCCESS)
1129da6c28aaSamw 			return (EACCES);
1130da6c28aaSamw 
1131c8ec8eeaSjose borrego 		if (smb_tree_has_feature(sr->tid_tree,
1132c8ec8eeaSjose borrego 		    SMB_TREE_ACEMASKONACCESS))
1133da6c28aaSamw 			flags = ATTR_NOACLCHECK;
1134da6c28aaSamw 	}
1135da6c28aaSamw 
1136da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1137da6c28aaSamw 
1138da6c28aaSamw 	if (unnamed_node) {
1139da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1140da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1141da6c28aaSamw 		unnamed_vp = unnamed_node->vp;
1142da6c28aaSamw 	}
1143da6c28aaSamw 
11449660e5cbSJanice Chang 	rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr);
1145da6c28aaSamw 
1146da6c28aaSamw 	if ((rc == 0) && ret_attr) {
1147da6c28aaSamw 		/*
1148dc20a302Sas 		 * Use kcred to update the node attr because this
1149dc20a302Sas 		 * call is not being made on behalf of the user.
1150da6c28aaSamw 		 */
1151da6c28aaSamw 		ret_attr->sa_mask = SMB_AT_ALL;
1152c8ec8eeaSjose borrego 		rc = smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, flags,
1153c8ec8eeaSjose borrego 		    kcred);
1154dc20a302Sas 		if (rc == 0)
1155dc20a302Sas 			snode->attr = *ret_attr;
1156da6c28aaSamw 	}
1157da6c28aaSamw 
1158da6c28aaSamw 	return (rc);
1159da6c28aaSamw }
1160da6c28aaSamw 
1161da6c28aaSamw /*
1162da6c28aaSamw  * smb_fsop_read
1163da6c28aaSamw  *
1164da6c28aaSamw  * All SMB functions should use this wrapper to ensure that
1165da6c28aaSamw  * the the calls are performed with the appropriate credentials.
1166da6c28aaSamw  * Please document any direct call to explain the reason
1167da6c28aaSamw  * for avoiding this wrapper.
1168da6c28aaSamw  *
1169da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
1170da6c28aaSamw  */
1171da6c28aaSamw int
1172da6c28aaSamw smb_fsop_read(
1173da6c28aaSamw     struct smb_request *sr,
1174da6c28aaSamw     cred_t *cr,
1175da6c28aaSamw     smb_node_t *snode,
1176da6c28aaSamw     uio_t *uio,
1177da6c28aaSamw     smb_attr_t *ret_attr)
1178da6c28aaSamw {
1179da6c28aaSamw 	smb_node_t *unnamed_node;
1180da6c28aaSamw 	vnode_t *unnamed_vp = NULL;
1181c8ec8eeaSjose borrego 	caller_context_t ct;
1182dc20a302Sas 	int svmand;
1183da6c28aaSamw 	int rc;
1184da6c28aaSamw 
1185da6c28aaSamw 	ASSERT(cr);
1186da6c28aaSamw 	ASSERT(snode);
1187da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1188da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1189da6c28aaSamw 
1190da6c28aaSamw 	ASSERT(sr);
1191da6c28aaSamw 	ASSERT(sr->fid_ofile);
1192da6c28aaSamw 
1193743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_DATA) == 0)
1194743a77edSAlan Wright 		return (EACCES);
1195743a77edSAlan Wright 
1196da6c28aaSamw 	rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA);
1197da6c28aaSamw 	if (rc != NT_STATUS_SUCCESS) {
1198da6c28aaSamw 		rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE);
1199da6c28aaSamw 		if (rc != NT_STATUS_SUCCESS)
1200da6c28aaSamw 			return (EACCES);
1201da6c28aaSamw 	}
1202da6c28aaSamw 
1203da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1204da6c28aaSamw 	if (unnamed_node) {
1205da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1206da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1207da6c28aaSamw 		unnamed_vp = unnamed_node->vp;
1208da6c28aaSamw 		/*
1209da6c28aaSamw 		 * Streams permission are checked against the unnamed stream,
1210da6c28aaSamw 		 * but in FS level they have their own permissions. To avoid
1211da6c28aaSamw 		 * rejection by FS due to lack of permission on the actual
1212da6c28aaSamw 		 * extended attr kcred is passed for streams.
1213da6c28aaSamw 		 */
1214da6c28aaSamw 		cr = kcred;
1215da6c28aaSamw 	}
1216da6c28aaSamw 
1217dc20a302Sas 	smb_node_start_crit(snode, RW_READER);
1218c8ec8eeaSjose borrego 	rc = nbl_svmand(snode->vp, kcred, &svmand);
1219dc20a302Sas 	if (rc) {
1220dc20a302Sas 		smb_node_end_crit(snode);
1221dc20a302Sas 		return (rc);
1222dc20a302Sas 	}
1223dc20a302Sas 
1224c8ec8eeaSjose borrego 	ct = smb_ct;
1225c8ec8eeaSjose borrego 	ct.cc_pid = sr->fid_ofile->f_uniqid;
1226dc20a302Sas 	rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset,
1227c8ec8eeaSjose borrego 	    uio->uio_iov->iov_len, svmand, &ct);
1228da6c28aaSamw 
1229dc20a302Sas 	if (rc) {
1230dc20a302Sas 		smb_node_end_crit(snode);
12316537f381Sas 		return (ERANGE);
1232dc20a302Sas 	}
1233dc20a302Sas 	rc = smb_vop_read(snode->vp, uio, cr);
1234dc20a302Sas 
1235dc20a302Sas 	if (rc == 0 && ret_attr) {
1236da6c28aaSamw 		/*
1237dc20a302Sas 		 * Use kcred to update the node attr because this
1238dc20a302Sas 		 * call is not being made on behalf of the user.
1239da6c28aaSamw 		 */
1240da6c28aaSamw 		ret_attr->sa_mask = SMB_AT_ALL;
1241dc20a302Sas 		if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0,
1242dc20a302Sas 		    kcred) == 0) {
1243dc20a302Sas 			snode->attr = *ret_attr;
1244dc20a302Sas 		}
1245da6c28aaSamw 	}
1246da6c28aaSamw 
1247dc20a302Sas 	smb_node_end_crit(snode);
1248dc20a302Sas 
1249da6c28aaSamw 	return (rc);
1250da6c28aaSamw }
1251da6c28aaSamw 
1252da6c28aaSamw /*
1253da6c28aaSamw  * smb_fsop_write
1254da6c28aaSamw  *
1255da6c28aaSamw  * This is a wrapper function used for smb_write and smb_write_raw operations.
1256da6c28aaSamw  *
1257da6c28aaSamw  * It is assumed that a reference exists on snode coming into this routine.
1258da6c28aaSamw  */
1259da6c28aaSamw int
1260da6c28aaSamw smb_fsop_write(
1261faa1795aSjb     smb_request_t *sr,
1262da6c28aaSamw     cred_t *cr,
1263da6c28aaSamw     smb_node_t *snode,
1264da6c28aaSamw     uio_t *uio,
1265da6c28aaSamw     uint32_t *lcount,
1266da6c28aaSamw     smb_attr_t *ret_attr,
12673db3f65cSamw     int ioflag)
1268da6c28aaSamw {
1269da6c28aaSamw 	smb_node_t *unnamed_node;
1270da6c28aaSamw 	vnode_t *unnamed_vp = NULL;
1271c8ec8eeaSjose borrego 	caller_context_t ct;
1272dc20a302Sas 	int svmand;
1273da6c28aaSamw 	int rc;
1274da6c28aaSamw 
1275da6c28aaSamw 	ASSERT(cr);
1276da6c28aaSamw 	ASSERT(snode);
1277da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1278da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1279da6c28aaSamw 
1280da6c28aaSamw 	ASSERT(sr);
1281da6c28aaSamw 	ASSERT(sr->tid_tree);
1282da6c28aaSamw 	ASSERT(sr->fid_ofile);
1283da6c28aaSamw 
1284c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1285da6c28aaSamw 		return (EROFS);
1286da6c28aaSamw 
1287743a77edSAlan Wright 	if (SMB_OFILE_IS_READONLY(sr->fid_ofile) ||
1288743a77edSAlan Wright 	    SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_DATA | ACE_APPEND_DATA) == 0)
1289c8ec8eeaSjose borrego 		return (EACCES);
1290c8ec8eeaSjose borrego 
1291dc20a302Sas 	rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA);
1292dc20a302Sas 	if (rc != NT_STATUS_SUCCESS) {
1293dc20a302Sas 		rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA);
1294dc20a302Sas 		if (rc != NT_STATUS_SUCCESS)
1295dc20a302Sas 			return (EACCES);
1296dc20a302Sas 	}
1297da6c28aaSamw 
1298da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1299da6c28aaSamw 
1300da6c28aaSamw 	if (unnamed_node) {
1301da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1302da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1303da6c28aaSamw 		unnamed_vp = unnamed_node->vp;
1304da6c28aaSamw 		/*
1305da6c28aaSamw 		 * Streams permission are checked against the unnamed stream,
1306da6c28aaSamw 		 * but in FS level they have their own permissions. To avoid
1307da6c28aaSamw 		 * rejection by FS due to lack of permission on the actual
1308da6c28aaSamw 		 * extended attr kcred is passed for streams.
1309da6c28aaSamw 		 */
1310da6c28aaSamw 		cr = kcred;
1311da6c28aaSamw 	}
1312da6c28aaSamw 
1313dc20a302Sas 	smb_node_start_crit(snode, RW_READER);
1314c8ec8eeaSjose borrego 	rc = nbl_svmand(snode->vp, kcred, &svmand);
1315dc20a302Sas 	if (rc) {
1316dc20a302Sas 		smb_node_end_crit(snode);
1317dc20a302Sas 		return (rc);
1318dc20a302Sas 	}
1319c8ec8eeaSjose borrego 
1320c8ec8eeaSjose borrego 	ct = smb_ct;
1321c8ec8eeaSjose borrego 	ct.cc_pid = sr->fid_ofile->f_uniqid;
1322dc20a302Sas 	rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset,
1323c8ec8eeaSjose borrego 	    uio->uio_iov->iov_len, svmand, &ct);
1324da6c28aaSamw 
1325dc20a302Sas 	if (rc) {
1326dc20a302Sas 		smb_node_end_crit(snode);
13276537f381Sas 		return (ERANGE);
1328dc20a302Sas 	}
13293db3f65cSamw 	rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr);
1330dc20a302Sas 
1331dc20a302Sas 	if (rc == 0 && ret_attr) {
1332da6c28aaSamw 		/*
1333dc20a302Sas 		 * Use kcred to update the node attr because this
1334dc20a302Sas 		 * call is not being made on behalf of the user.
1335da6c28aaSamw 		 */
1336da6c28aaSamw 		ret_attr->sa_mask = SMB_AT_ALL;
1337dc20a302Sas 		if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0,
1338dc20a302Sas 		    kcred) == 0) {
1339dc20a302Sas 			snode->attr = *ret_attr;
1340dc20a302Sas 		}
1341da6c28aaSamw 	}
1342da6c28aaSamw 
1343dc20a302Sas 	smb_node_end_crit(snode);
1344dc20a302Sas 
1345da6c28aaSamw 	return (rc);
1346da6c28aaSamw }
1347da6c28aaSamw 
1348da6c28aaSamw /*
1349da6c28aaSamw  * smb_fsop_statfs
1350da6c28aaSamw  *
1351da6c28aaSamw  * This is a wrapper function used for stat operations.
1352da6c28aaSamw  */
1353da6c28aaSamw int
1354da6c28aaSamw smb_fsop_statfs(
1355da6c28aaSamw     cred_t *cr,
1356da6c28aaSamw     smb_node_t *snode,
1357da6c28aaSamw     struct statvfs64 *statp)
1358da6c28aaSamw {
1359da6c28aaSamw 	ASSERT(cr);
1360da6c28aaSamw 	ASSERT(snode);
1361da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1362da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1363da6c28aaSamw 
1364da6c28aaSamw 	return (smb_vop_statfs(snode->vp, statp, cr));
1365da6c28aaSamw }
1366da6c28aaSamw 
1367da6c28aaSamw /*
1368da6c28aaSamw  * smb_fsop_access
1369ee60c47bSjm  *
1370ee60c47bSjm  * Named streams do not have separate permissions from the associated
1371ee60c47bSjm  * unnamed stream.  Thus, if node is a named stream, the permissions
1372ee60c47bSjm  * check will be performed on the associated unnamed stream.
1373ee60c47bSjm  *
1374ee60c47bSjm  * However, our named streams do have their own quarantine attribute,
1375ee60c47bSjm  * separate from that on the unnamed stream. If READ or EXECUTE
1376ee60c47bSjm  * access has been requested on a named stream, an additional access
1377ee60c47bSjm  * check is performed on the named stream in case it has been
1378ee60c47bSjm  * quarantined.  kcred is used to avoid issues with the permissions
1379ee60c47bSjm  * set on the extended attribute file representing the named stream.
1380da6c28aaSamw  */
1381da6c28aaSamw int
1382da6c28aaSamw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1383da6c28aaSamw     uint32_t faccess)
1384da6c28aaSamw {
1385da6c28aaSamw 	int access = 0;
1386da6c28aaSamw 	int error;
1387da6c28aaSamw 	vnode_t *dir_vp;
1388da6c28aaSamw 	boolean_t acl_check = B_TRUE;
1389da6c28aaSamw 	smb_node_t *unnamed_node;
1390da6c28aaSamw 
1391c8ec8eeaSjose borrego 	ASSERT(sr);
1392da6c28aaSamw 	ASSERT(cr);
1393da6c28aaSamw 	ASSERT(snode);
1394da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1395da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1396da6c28aaSamw 
1397da6c28aaSamw 	if (faccess == 0)
1398da6c28aaSamw 		return (NT_STATUS_SUCCESS);
1399da6c28aaSamw 
1400c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr)) {
1401da6c28aaSamw 		if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA|
1402da6c28aaSamw 		    FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES|
1403da6c28aaSamw 		    DELETE|WRITE_DAC|WRITE_OWNER)) {
1404da6c28aaSamw 			return (NT_STATUS_ACCESS_DENIED);
1405da6c28aaSamw 		}
1406da6c28aaSamw 	}
1407da6c28aaSamw 
1408da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1409da6c28aaSamw 	if (unnamed_node) {
1410da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1411da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1412ee60c47bSjm 
1413ee60c47bSjm 		/*
1414ee60c47bSjm 		 * Perform VREAD access check on the named stream in case it
1415ee60c47bSjm 		 * is quarantined. kcred is passed to smb_vop_access so it
1416ee60c47bSjm 		 * doesn't fail due to lack of permission.
1417ee60c47bSjm 		 */
1418ee60c47bSjm 		if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) {
1419ee60c47bSjm 			error = smb_vop_access(snode->vp, VREAD,
1420ee60c47bSjm 			    0, NULL, kcred);
1421ee60c47bSjm 			if (error)
1422ee60c47bSjm 				return (NT_STATUS_ACCESS_DENIED);
1423ee60c47bSjm 		}
1424ee60c47bSjm 
1425da6c28aaSamw 		/*
1426da6c28aaSamw 		 * Streams authorization should be performed against the
1427da6c28aaSamw 		 * unnamed stream.
1428da6c28aaSamw 		 */
1429da6c28aaSamw 		snode = unnamed_node;
1430da6c28aaSamw 	}
1431da6c28aaSamw 
1432da6c28aaSamw 	if (faccess & ACCESS_SYSTEM_SECURITY) {
1433da6c28aaSamw 		/*
1434da6c28aaSamw 		 * This permission is required for reading/writing SACL and
1435da6c28aaSamw 		 * it's not part of DACL. It's only granted via proper
1436da6c28aaSamw 		 * privileges.
1437da6c28aaSamw 		 */
1438da6c28aaSamw 		if ((sr->uid_user->u_privileges &
1439da6c28aaSamw 		    (SMB_USER_PRIV_BACKUP |
1440da6c28aaSamw 		    SMB_USER_PRIV_RESTORE |
1441da6c28aaSamw 		    SMB_USER_PRIV_SECURITY)) == 0)
1442da6c28aaSamw 			return (NT_STATUS_PRIVILEGE_NOT_HELD);
1443da6c28aaSamw 
1444da6c28aaSamw 		faccess &= ~ACCESS_SYSTEM_SECURITY;
1445da6c28aaSamw 	}
1446da6c28aaSamw 
1447da6c28aaSamw 	/* Links don't have ACL */
1448c8ec8eeaSjose borrego 	if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) ||
1449da6c28aaSamw 	    (snode->attr.sa_vattr.va_type == VLNK))
1450da6c28aaSamw 		acl_check = B_FALSE;
1451da6c28aaSamw 
1452743a77edSAlan Wright 	/*
1453743a77edSAlan Wright 	 * Use the most restrictive parts of both faccess and the
1454743a77edSAlan Wright 	 * share access.  An AND of the two value masks gives us that
1455743a77edSAlan Wright 	 * since we've already converted to a mask of what we "can"
1456743a77edSAlan Wright 	 * do.
1457743a77edSAlan Wright 	 */
1458743a77edSAlan Wright 	faccess &= sr->tid_tree->t_access;
1459743a77edSAlan Wright 
1460da6c28aaSamw 	if (acl_check) {
1461da6c28aaSamw 		dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL;
1462da6c28aaSamw 		error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp,
1463da6c28aaSamw 		    cr);
1464da6c28aaSamw 	} else {
1465da6c28aaSamw 		/*
1466da6c28aaSamw 		 * FS doesn't understand 32-bit mask, need to map
1467da6c28aaSamw 		 */
1468da6c28aaSamw 		if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))
1469da6c28aaSamw 			access |= VWRITE;
1470da6c28aaSamw 
1471da6c28aaSamw 		if (faccess & FILE_READ_DATA)
1472da6c28aaSamw 			access |= VREAD;
1473da6c28aaSamw 
1474da6c28aaSamw 		if (faccess & FILE_EXECUTE)
1475da6c28aaSamw 			access |= VEXEC;
1476da6c28aaSamw 
1477da6c28aaSamw 		error = smb_vop_access(snode->vp, access, 0, NULL, cr);
1478da6c28aaSamw 	}
1479da6c28aaSamw 
1480da6c28aaSamw 	return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS);
1481da6c28aaSamw }
1482da6c28aaSamw 
1483da6c28aaSamw /*
1484da6c28aaSamw  * smb_fsop_lookup_name()
1485da6c28aaSamw  *
1486b89a8333Snatalie li - Sun Microsystems - Irvine United States  * If name indicates that the file is a stream file, perform
1487b89a8333Snatalie li - Sun Microsystems - Irvine United States  * stream specific lookup, otherwise call smb_fsop_lookup.
1488da6c28aaSamw  *
1489b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Return an error if the looked-up file is in outside the tree.
1490b89a8333Snatalie li - Sun Microsystems - Irvine United States  * (Required when invoked from open path.)
1491da6c28aaSamw  */
1492da6c28aaSamw 
1493da6c28aaSamw int
1494da6c28aaSamw smb_fsop_lookup_name(
1495faa1795aSjb     smb_request_t *sr,
1496da6c28aaSamw     cred_t	*cr,
1497da6c28aaSamw     int		flags,
1498da6c28aaSamw     smb_node_t	*root_node,
1499*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t	*dnode,
1500da6c28aaSamw     char	*name,
1501da6c28aaSamw     smb_node_t	**ret_snode,
1502da6c28aaSamw     smb_attr_t	*ret_attr)
1503da6c28aaSamw {
1504faa1795aSjb 	smb_node_t	*fnode;
1505faa1795aSjb 	smb_attr_t	file_attr;
1506faa1795aSjb 	vnode_t		*xattrdirvp;
1507faa1795aSjb 	vnode_t		*vp;
1508faa1795aSjb 	char		*od_name;
1509faa1795aSjb 	char		*fname;
1510faa1795aSjb 	char		*sname;
1511faa1795aSjb 	int		rc;
1512da6c28aaSamw 
1513da6c28aaSamw 	ASSERT(cr);
1514*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
1515*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
1516*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
1517da6c28aaSamw 
1518da6c28aaSamw 	/*
1519da6c28aaSamw 	 * The following check is required for streams processing, below
1520da6c28aaSamw 	 */
1521da6c28aaSamw 
1522c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1523da6c28aaSamw 		flags |= SMB_IGNORE_CASE;
1524da6c28aaSamw 
1525da6c28aaSamw 	fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1526da6c28aaSamw 	sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1527da6c28aaSamw 
1528*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_is_stream_name(name)) {
1529*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_stream_parse_name(name, fname, sname);
15308d7e4166Sjose borrego 
1531da6c28aaSamw 		/*
1532da6c28aaSamw 		 * Look up the unnamed stream (i.e. fname).
1533da6c28aaSamw 		 * Unmangle processing will be done on fname
1534da6c28aaSamw 		 * as well as any link target.
1535da6c28aaSamw 		 */
1536*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, fname,
15378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    &fnode, &file_attr);
1538da6c28aaSamw 
1539da6c28aaSamw 		if (rc != 0) {
1540da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
1541da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
1542da6c28aaSamw 			return (rc);
1543da6c28aaSamw 		}
1544da6c28aaSamw 
1545da6c28aaSamw 		od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1546da6c28aaSamw 
1547da6c28aaSamw 		/*
1548da6c28aaSamw 		 * od_name is the on-disk name of the stream, except
1549da6c28aaSamw 		 * without the prepended stream prefix (SMB_STREAM_PREFIX)
1550da6c28aaSamw 		 */
1551da6c28aaSamw 
1552da6c28aaSamw 		/*
1553da6c28aaSamw 		 * XXX
1554da6c28aaSamw 		 * What permissions NTFS requires for stream lookup if any?
1555da6c28aaSamw 		 */
1556da6c28aaSamw 		rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name,
1557dc20a302Sas 		    &xattrdirvp, flags, root_node->vp, cr);
1558da6c28aaSamw 
1559da6c28aaSamw 		if (rc != 0) {
1560da6c28aaSamw 			smb_node_release(fnode);
1561da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
1562da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
1563da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1564da6c28aaSamw 			return (rc);
1565da6c28aaSamw 		}
1566da6c28aaSamw 
1567da6c28aaSamw 		*ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
1568da6c28aaSamw 		    vp, od_name, ret_attr);
1569da6c28aaSamw 
1570da6c28aaSamw 		kmem_free(od_name, MAXNAMELEN);
1571da6c28aaSamw 		smb_node_release(fnode);
15727f667e74Sjose borrego 		VN_RELE(xattrdirvp);
15737f667e74Sjose borrego 		VN_RELE(vp);
1574da6c28aaSamw 
1575da6c28aaSamw 		if (*ret_snode == NULL) {
1576da6c28aaSamw 			kmem_free(fname, MAXNAMELEN);
1577da6c28aaSamw 			kmem_free(sname, MAXNAMELEN);
1578da6c28aaSamw 			return (ENOMEM);
1579da6c28aaSamw 		}
1580da6c28aaSamw 	} else {
1581*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, name,
15828b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    ret_snode, ret_attr);
1583da6c28aaSamw 	}
1584da6c28aaSamw 
1585da6c28aaSamw 	if (rc == 0) {
1586da6c28aaSamw 		ASSERT(ret_snode);
1587c8ec8eeaSjose borrego 		if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) {
1588da6c28aaSamw 			smb_node_release(*ret_snode);
1589da6c28aaSamw 			*ret_snode = NULL;
1590da6c28aaSamw 			rc = EACCES;
1591da6c28aaSamw 		}
1592da6c28aaSamw 	}
1593da6c28aaSamw 
1594da6c28aaSamw 	kmem_free(fname, MAXNAMELEN);
1595da6c28aaSamw 	kmem_free(sname, MAXNAMELEN);
1596da6c28aaSamw 
1597da6c28aaSamw 	return (rc);
1598da6c28aaSamw }
1599da6c28aaSamw 
1600da6c28aaSamw /*
1601da6c28aaSamw  * smb_fsop_lookup
1602da6c28aaSamw  *
1603da6c28aaSamw  * All SMB functions should use this smb_vop_lookup wrapper to ensure that
1604da6c28aaSamw  * the smb_vop_lookup is performed with the appropriate credentials and using
1605da6c28aaSamw  * case insensitive compares. Please document any direct call to smb_vop_lookup
1606da6c28aaSamw  * to explain the reason for avoiding this wrapper.
1607da6c28aaSamw  *
1608*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * It is assumed that a reference exists on dnode coming into this routine
1609da6c28aaSamw  * (and that it is safe from deallocation).
1610da6c28aaSamw  *
1611da6c28aaSamw  * Same with the root_node.
1612da6c28aaSamw  *
1613da6c28aaSamw  * *ret_snode is returned with a reference upon success.  No reference is
1614da6c28aaSamw  * taken if an error is returned.
1615da6c28aaSamw  *
1616da6c28aaSamw  * Note: The returned ret_snode may be in a child mount.  This is ok for
16177f667e74Sjose borrego  * readdir.
1618da6c28aaSamw  *
1619c8ec8eeaSjose borrego  * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent
1620da6c28aaSamw  * operations on files not in the parent mount.
1621da6c28aaSamw  */
1622da6c28aaSamw int
1623da6c28aaSamw smb_fsop_lookup(
1624faa1795aSjb     smb_request_t *sr,
1625da6c28aaSamw     cred_t	*cr,
1626da6c28aaSamw     int		flags,
1627da6c28aaSamw     smb_node_t	*root_node,
1628*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_node_t	*dnode,
1629da6c28aaSamw     char	*name,
1630da6c28aaSamw     smb_node_t	**ret_snode,
16318b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States     smb_attr_t	*ret_attr)
1632da6c28aaSamw {
1633da6c28aaSamw 	smb_node_t *lnk_target_node;
1634da6c28aaSamw 	smb_node_t *lnk_dnode;
1635da6c28aaSamw 	char *longname;
1636da6c28aaSamw 	char *od_name;
1637da6c28aaSamw 	vnode_t *vp;
1638da6c28aaSamw 	int rc;
16398b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	int ret_flags;
1640da6c28aaSamw 
1641da6c28aaSamw 	ASSERT(cr);
1642*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode);
1643*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
1644*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
1645da6c28aaSamw 
1646da6c28aaSamw 	if (name == NULL)
1647da6c28aaSamw 		return (EINVAL);
1648da6c28aaSamw 
1649*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
1650da6c28aaSamw 		return (EACCES);
1651da6c28aaSamw 
1652c8ec8eeaSjose borrego 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1653da6c28aaSamw 		flags |= SMB_IGNORE_CASE;
16548b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
16558b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
1656da6c28aaSamw 
1657da6c28aaSamw 	od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1658da6c28aaSamw 
1659*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_vop_lookup(dnode->vp, name, &vp, od_name, flags,
16608b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	    &ret_flags, root_node ? root_node->vp : NULL, cr);
1661da6c28aaSamw 
1662da6c28aaSamw 	if (rc != 0) {
1663da6c28aaSamw 		if (smb_maybe_mangled_name(name) == 0) {
1664da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1665da6c28aaSamw 			return (rc);
1666da6c28aaSamw 		}
1667da6c28aaSamw 
1668da6c28aaSamw 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1669*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
1670da6c28aaSamw 		if (rc != 0) {
1671da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1672da6c28aaSamw 			kmem_free(longname, MAXNAMELEN);
1673da6c28aaSamw 			return (rc);
1674da6c28aaSamw 		}
1675da6c28aaSamw 
1676da6c28aaSamw 		/*
16778b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * longname is the real (case-sensitive)
16788b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * on-disk name.
1679da6c28aaSamw 		 * We make sure we do a lookup on this exact
1680da6c28aaSamw 		 * name, as the name was mangled and denotes
1681da6c28aaSamw 		 * a unique file.
1682da6c28aaSamw 		 */
1683da6c28aaSamw 
1684da6c28aaSamw 		if (flags & SMB_IGNORE_CASE)
1685da6c28aaSamw 			flags &= ~SMB_IGNORE_CASE;
1686da6c28aaSamw 
1687*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_vop_lookup(dnode->vp, longname, &vp, od_name,
16888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    flags, &ret_flags, root_node ? root_node->vp : NULL, cr);
1689da6c28aaSamw 
1690da6c28aaSamw 		kmem_free(longname, MAXNAMELEN);
1691da6c28aaSamw 
1692da6c28aaSamw 		if (rc != 0) {
1693da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1694da6c28aaSamw 			return (rc);
1695da6c28aaSamw 		}
1696da6c28aaSamw 	}
1697da6c28aaSamw 
1698da6c28aaSamw 	if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) {
1699da6c28aaSamw 
1700*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_pathname(sr, od_name, FOLLOW, root_node, dnode,
1701da6c28aaSamw 		    &lnk_dnode, &lnk_target_node, cr);
1702da6c28aaSamw 
1703da6c28aaSamw 		if (rc != 0) {
1704da6c28aaSamw 			/*
1705da6c28aaSamw 			 * The link is assumed to be for the last component
1706da6c28aaSamw 			 * of a path.  Hence any ENOTDIR error will be returned
1707da6c28aaSamw 			 * as ENOENT.
1708da6c28aaSamw 			 */
1709da6c28aaSamw 			if (rc == ENOTDIR)
1710da6c28aaSamw 				rc = ENOENT;
1711da6c28aaSamw 
1712da6c28aaSamw 			VN_RELE(vp);
1713da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1714da6c28aaSamw 			return (rc);
1715da6c28aaSamw 		}
1716da6c28aaSamw 
1717da6c28aaSamw 		/*
1718da6c28aaSamw 		 * Release the original VLNK vnode
1719da6c28aaSamw 		 */
1720da6c28aaSamw 
1721da6c28aaSamw 		VN_RELE(vp);
1722da6c28aaSamw 		vp = lnk_target_node->vp;
1723da6c28aaSamw 
1724da6c28aaSamw 		rc = smb_vop_traverse_check(&vp);
1725da6c28aaSamw 
1726da6c28aaSamw 		if (rc != 0) {
1727da6c28aaSamw 			smb_node_release(lnk_dnode);
1728da6c28aaSamw 			smb_node_release(lnk_target_node);
1729da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1730da6c28aaSamw 			return (rc);
1731da6c28aaSamw 		}
1732da6c28aaSamw 
1733da6c28aaSamw 		/*
1734da6c28aaSamw 		 * smb_vop_traverse_check() may have returned a different vnode
1735da6c28aaSamw 		 */
1736da6c28aaSamw 
1737da6c28aaSamw 		if (lnk_target_node->vp == vp) {
1738da6c28aaSamw 			*ret_snode = lnk_target_node;
1739da6c28aaSamw 			*ret_attr = (*ret_snode)->attr;
1740da6c28aaSamw 		} else {
1741da6c28aaSamw 			*ret_snode = smb_node_lookup(sr, NULL, cr, vp,
1742da6c28aaSamw 			    lnk_target_node->od_name, lnk_dnode, NULL,
1743da6c28aaSamw 			    ret_attr);
17447f667e74Sjose borrego 			VN_RELE(vp);
1745da6c28aaSamw 
17467f667e74Sjose borrego 			if (*ret_snode == NULL)
1747da6c28aaSamw 				rc = ENOMEM;
1748da6c28aaSamw 			smb_node_release(lnk_target_node);
1749da6c28aaSamw 		}
1750da6c28aaSamw 
1751da6c28aaSamw 		smb_node_release(lnk_dnode);
1752da6c28aaSamw 
1753da6c28aaSamw 	} else {
1754da6c28aaSamw 
1755da6c28aaSamw 		rc = smb_vop_traverse_check(&vp);
1756da6c28aaSamw 		if (rc) {
1757da6c28aaSamw 			VN_RELE(vp);
1758da6c28aaSamw 			kmem_free(od_name, MAXNAMELEN);
1759da6c28aaSamw 			return (rc);
1760da6c28aaSamw 		}
1761da6c28aaSamw 
1762da6c28aaSamw 		*ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name,
1763*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		    dnode, NULL, ret_attr);
17647f667e74Sjose borrego 		VN_RELE(vp);
1765da6c28aaSamw 
17667f667e74Sjose borrego 		if (*ret_snode == NULL)
1767da6c28aaSamw 			rc = ENOMEM;
1768da6c28aaSamw 	}
1769da6c28aaSamw 
1770da6c28aaSamw 	kmem_free(od_name, MAXNAMELEN);
1771da6c28aaSamw 	return (rc);
1772da6c28aaSamw }
1773da6c28aaSamw 
1774da6c28aaSamw int /*ARGSUSED*/
1775da6c28aaSamw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode)
1776da6c28aaSamw {
1777da6c28aaSamw 	ASSERT(cr);
1778da6c28aaSamw 	ASSERT(snode);
1779da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1780da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1781da6c28aaSamw 
1782da6c28aaSamw 	ASSERT(sr);
1783da6c28aaSamw 	ASSERT(sr->tid_tree);
1784c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1785da6c28aaSamw 		return (EROFS);
1786da6c28aaSamw 
1787dc20a302Sas 	return (smb_vop_commit(snode->vp, cr));
1788da6c28aaSamw }
1789da6c28aaSamw 
1790da6c28aaSamw /*
1791da6c28aaSamw  * smb_fsop_aclread
1792da6c28aaSamw  *
1793da6c28aaSamw  * Retrieve filesystem ACL. Depends on requested ACLs in
1794da6c28aaSamw  * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in
1795da6c28aaSamw  * fs_sd. Note that requesting a DACL/SACL doesn't mean that
1796da6c28aaSamw  * the corresponding field in fs_sd should be non-NULL upon
1797da6c28aaSamw  * return, since the target ACL might not contain that type of
1798da6c28aaSamw  * entries.
1799da6c28aaSamw  *
1800da6c28aaSamw  * Returned ACL is always in ACE_T (aka ZFS) format.
1801da6c28aaSamw  * If successful the allocated memory for the ACL should be freed
180255bf511dSas  * using smb_fsacl_free() or smb_fssd_term()
1803da6c28aaSamw  */
1804da6c28aaSamw int
1805da6c28aaSamw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1806da6c28aaSamw     smb_fssd_t *fs_sd)
1807da6c28aaSamw {
1808da6c28aaSamw 	int error = 0;
1809da6c28aaSamw 	int flags = 0;
1810da6c28aaSamw 	int access = 0;
1811da6c28aaSamw 	acl_t *acl;
1812da6c28aaSamw 	smb_node_t *unnamed_node;
1813da6c28aaSamw 
1814da6c28aaSamw 	ASSERT(cr);
1815da6c28aaSamw 
1816743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0)
1817743a77edSAlan Wright 		return (EACCES);
1818743a77edSAlan Wright 
1819da6c28aaSamw 	if (sr->fid_ofile) {
1820da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
1821da6c28aaSamw 			access = READ_CONTROL;
1822da6c28aaSamw 
1823da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
1824da6c28aaSamw 			access |= ACCESS_SYSTEM_SECURITY;
1825da6c28aaSamw 
1826da6c28aaSamw 		error = smb_ofile_access(sr->fid_ofile, cr, access);
1827da6c28aaSamw 		if (error != NT_STATUS_SUCCESS) {
1828da6c28aaSamw 			return (EACCES);
1829da6c28aaSamw 		}
1830da6c28aaSamw 	}
1831da6c28aaSamw 
1832da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1833da6c28aaSamw 	if (unnamed_node) {
1834da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1835da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1836da6c28aaSamw 		/*
1837da6c28aaSamw 		 * Streams don't have ACL, any read ACL attempt on a stream
1838da6c28aaSamw 		 * should be performed on the unnamed stream.
1839da6c28aaSamw 		 */
1840da6c28aaSamw 		snode = unnamed_node;
1841da6c28aaSamw 	}
1842da6c28aaSamw 
1843c8ec8eeaSjose borrego 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS))
1844da6c28aaSamw 		flags = ATTR_NOACLCHECK;
1845da6c28aaSamw 
1846da6c28aaSamw 	error = smb_vop_acl_read(snode->vp, &acl, flags,
1847dc20a302Sas 	    sr->tid_tree->t_acltype, cr);
1848da6c28aaSamw 	if (error != 0) {
1849da6c28aaSamw 		return (error);
1850da6c28aaSamw 	}
1851da6c28aaSamw 
1852da6c28aaSamw 	error = acl_translate(acl, _ACL_ACE_ENABLED,
1853da6c28aaSamw 	    (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid);
1854da6c28aaSamw 
1855da6c28aaSamw 	if (error == 0) {
185655bf511dSas 		smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl,
1857da6c28aaSamw 		    fs_sd->sd_secinfo);
1858da6c28aaSamw 	}
1859da6c28aaSamw 
1860da6c28aaSamw 	acl_free(acl);
1861da6c28aaSamw 	return (error);
1862da6c28aaSamw }
1863da6c28aaSamw 
1864da6c28aaSamw /*
1865da6c28aaSamw  * smb_fsop_aclwrite
1866da6c28aaSamw  *
1867da6c28aaSamw  * Stores the filesystem ACL provided in fs_sd->sd_acl.
1868da6c28aaSamw  */
1869da6c28aaSamw int
1870da6c28aaSamw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1871da6c28aaSamw     smb_fssd_t *fs_sd)
1872da6c28aaSamw {
1873da6c28aaSamw 	int target_flavor;
1874da6c28aaSamw 	int error = 0;
1875da6c28aaSamw 	int flags = 0;
1876da6c28aaSamw 	int access = 0;
1877da6c28aaSamw 	acl_t *acl, *dacl, *sacl;
1878da6c28aaSamw 	smb_node_t *unnamed_node;
1879da6c28aaSamw 
1880da6c28aaSamw 	ASSERT(cr);
1881da6c28aaSamw 
1882da6c28aaSamw 	ASSERT(sr);
1883da6c28aaSamw 	ASSERT(sr->tid_tree);
1884c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
1885da6c28aaSamw 		return (EROFS);
1886da6c28aaSamw 
1887743a77edSAlan Wright 	if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0)
1888743a77edSAlan Wright 		return (EACCES);
1889743a77edSAlan Wright 
1890da6c28aaSamw 	if (sr->fid_ofile) {
1891da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
1892da6c28aaSamw 			access = WRITE_DAC;
1893da6c28aaSamw 
1894da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
1895da6c28aaSamw 			access |= ACCESS_SYSTEM_SECURITY;
1896da6c28aaSamw 
1897da6c28aaSamw 		error = smb_ofile_access(sr->fid_ofile, cr, access);
1898da6c28aaSamw 		if (error != NT_STATUS_SUCCESS)
1899da6c28aaSamw 			return (EACCES);
1900da6c28aaSamw 	}
1901da6c28aaSamw 
1902da6c28aaSamw 	switch (sr->tid_tree->t_acltype) {
1903da6c28aaSamw 	case ACLENT_T:
1904da6c28aaSamw 		target_flavor = _ACL_ACLENT_ENABLED;
1905da6c28aaSamw 		break;
1906da6c28aaSamw 
1907da6c28aaSamw 	case ACE_T:
1908da6c28aaSamw 		target_flavor = _ACL_ACE_ENABLED;
1909da6c28aaSamw 		break;
1910da6c28aaSamw 	default:
1911da6c28aaSamw 		return (EINVAL);
1912da6c28aaSamw 	}
1913da6c28aaSamw 
1914da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
1915da6c28aaSamw 	if (unnamed_node) {
1916da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1917da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1918da6c28aaSamw 		/*
1919da6c28aaSamw 		 * Streams don't have ACL, any write ACL attempt on a stream
1920da6c28aaSamw 		 * should be performed on the unnamed stream.
1921da6c28aaSamw 		 */
1922da6c28aaSamw 		snode = unnamed_node;
1923da6c28aaSamw 	}
1924da6c28aaSamw 
1925da6c28aaSamw 	dacl = fs_sd->sd_zdacl;
1926da6c28aaSamw 	sacl = fs_sd->sd_zsacl;
1927da6c28aaSamw 
1928da6c28aaSamw 	ASSERT(dacl || sacl);
1929da6c28aaSamw 	if ((dacl == NULL) && (sacl == NULL))
1930da6c28aaSamw 		return (EINVAL);
1931da6c28aaSamw 
1932da6c28aaSamw 	if (dacl && sacl)
193355bf511dSas 		acl = smb_fsacl_merge(dacl, sacl);
1934da6c28aaSamw 	else if (dacl)
1935da6c28aaSamw 		acl = dacl;
1936da6c28aaSamw 	else
1937da6c28aaSamw 		acl = sacl;
1938da6c28aaSamw 
1939da6c28aaSamw 	error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR),
1940da6c28aaSamw 	    fs_sd->sd_uid, fs_sd->sd_gid);
1941da6c28aaSamw 	if (error == 0) {
1942c8ec8eeaSjose borrego 		if (smb_tree_has_feature(sr->tid_tree,
1943c8ec8eeaSjose borrego 		    SMB_TREE_ACEMASKONACCESS))
1944da6c28aaSamw 			flags = ATTR_NOACLCHECK;
1945da6c28aaSamw 
1946dc20a302Sas 		error = smb_vop_acl_write(snode->vp, acl, flags, cr);
1947da6c28aaSamw 	}
1948da6c28aaSamw 
1949da6c28aaSamw 	if (dacl && sacl)
1950da6c28aaSamw 		acl_free(acl);
1951da6c28aaSamw 
1952da6c28aaSamw 	return (error);
1953da6c28aaSamw }
1954da6c28aaSamw 
1955da6c28aaSamw acl_type_t
1956da6c28aaSamw smb_fsop_acltype(smb_node_t *snode)
1957da6c28aaSamw {
1958da6c28aaSamw 	return (smb_vop_acl_type(snode->vp));
1959da6c28aaSamw }
1960da6c28aaSamw 
1961da6c28aaSamw /*
1962da6c28aaSamw  * smb_fsop_sdread
1963da6c28aaSamw  *
1964da6c28aaSamw  * Read the requested security descriptor items from filesystem.
1965da6c28aaSamw  * The items are specified in fs_sd->sd_secinfo.
1966da6c28aaSamw  */
1967da6c28aaSamw int
1968da6c28aaSamw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1969da6c28aaSamw     smb_fssd_t *fs_sd)
1970da6c28aaSamw {
1971da6c28aaSamw 	int error = 0;
1972da6c28aaSamw 	int getowner = 0;
1973da6c28aaSamw 	cred_t *ga_cred;
1974da6c28aaSamw 	smb_attr_t attr;
1975da6c28aaSamw 
1976da6c28aaSamw 	ASSERT(cr);
1977da6c28aaSamw 	ASSERT(fs_sd);
1978da6c28aaSamw 
1979da6c28aaSamw 	/*
1980da6c28aaSamw 	 * File's uid/gid is fetched in two cases:
1981da6c28aaSamw 	 *
1982da6c28aaSamw 	 * 1. it's explicitly requested
1983da6c28aaSamw 	 *
1984da6c28aaSamw 	 * 2. target ACL is ACE_T (ZFS ACL). They're needed for
1985da6c28aaSamw 	 *    owner@/group@ entries. In this case kcred should be used
1986da6c28aaSamw 	 *    because uid/gid are fetched on behalf of smb server.
1987da6c28aaSamw 	 */
1988da6c28aaSamw 	if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) {
1989da6c28aaSamw 		getowner = 1;
1990da6c28aaSamw 		ga_cred = cr;
1991da6c28aaSamw 	} else if (sr->tid_tree->t_acltype == ACE_T) {
1992da6c28aaSamw 		getowner = 1;
1993da6c28aaSamw 		ga_cred = kcred;
1994da6c28aaSamw 	}
1995da6c28aaSamw 
1996da6c28aaSamw 	if (getowner) {
1997da6c28aaSamw 		/*
1998da6c28aaSamw 		 * Windows require READ_CONTROL to read owner/group SID since
1999da6c28aaSamw 		 * they're part of Security Descriptor.
2000da6c28aaSamw 		 * ZFS only requires read_attribute. Need to have a explicit
2001da6c28aaSamw 		 * access check here.
2002da6c28aaSamw 		 */
2003da6c28aaSamw 		if (sr->fid_ofile == NULL) {
2004da6c28aaSamw 			error = smb_fsop_access(sr, ga_cred, snode,
2005da6c28aaSamw 			    READ_CONTROL);
2006da6c28aaSamw 			if (error)
2007da6c28aaSamw 				return (error);
2008da6c28aaSamw 		}
2009da6c28aaSamw 
2010da6c28aaSamw 		attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
2011da6c28aaSamw 		error = smb_fsop_getattr(sr, ga_cred, snode, &attr);
2012da6c28aaSamw 		if (error == 0) {
2013da6c28aaSamw 			fs_sd->sd_uid = attr.sa_vattr.va_uid;
2014da6c28aaSamw 			fs_sd->sd_gid = attr.sa_vattr.va_gid;
2015da6c28aaSamw 		} else {
2016da6c28aaSamw 			return (error);
2017da6c28aaSamw 		}
2018da6c28aaSamw 	}
2019da6c28aaSamw 
2020da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2021da6c28aaSamw 		error = smb_fsop_aclread(sr, cr, snode, fs_sd);
2022da6c28aaSamw 	}
2023da6c28aaSamw 
2024da6c28aaSamw 	return (error);
2025da6c28aaSamw }
2026da6c28aaSamw 
2027da6c28aaSamw /*
2028da6c28aaSamw  * smb_fsop_sdmerge
2029da6c28aaSamw  *
2030da6c28aaSamw  * From SMB point of view DACL and SACL are two separate list
2031da6c28aaSamw  * which can be manipulated independently without one affecting
2032da6c28aaSamw  * the other, but entries for both DACL and SACL will end up
2033da6c28aaSamw  * in the same ACL if target filesystem supports ACE_T ACLs.
2034da6c28aaSamw  *
2035da6c28aaSamw  * So, if either DACL or SACL is present in the client set request
2036da6c28aaSamw  * the entries corresponding to the non-present ACL shouldn't
2037da6c28aaSamw  * be touched in the FS ACL.
2038da6c28aaSamw  *
2039da6c28aaSamw  * fs_sd parameter contains DACL and SACL specified by SMB
2040da6c28aaSamw  * client to be set on a file/directory. The client could
2041da6c28aaSamw  * specify both or one of these ACLs (if none is specified
2042da6c28aaSamw  * we don't get this far). When both DACL and SACL are given
2043da6c28aaSamw  * by client the existing ACL should be overwritten. If only
2044da6c28aaSamw  * one of them is specified the entries corresponding to the other
2045da6c28aaSamw  * ACL should not be touched. For example, if only DACL
2046da6c28aaSamw  * is specified in input fs_sd, the function reads audit entries
2047da6c28aaSamw  * of the existing ACL of the file and point fs_sd->sd_zsdacl
2048da6c28aaSamw  * pointer to the fetched SACL, this way when smb_fsop_sdwrite()
2049da6c28aaSamw  * function is called the passed fs_sd would point to the specified
2050da6c28aaSamw  * DACL by client and fetched SACL from filesystem, so the file
2051da6c28aaSamw  * will end up with correct ACL.
2052da6c28aaSamw  */
2053da6c28aaSamw static int
2054da6c28aaSamw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd)
2055da6c28aaSamw {
2056da6c28aaSamw 	smb_fssd_t cur_sd;
2057da6c28aaSamw 	int error = 0;
2058da6c28aaSamw 
2059da6c28aaSamw 	if (sr->tid_tree->t_acltype != ACE_T)
2060da6c28aaSamw 		/* Don't bother if target FS doesn't support ACE_T */
2061da6c28aaSamw 		return (0);
2062da6c28aaSamw 
2063da6c28aaSamw 	if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) {
2064da6c28aaSamw 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
2065da6c28aaSamw 			/*
2066da6c28aaSamw 			 * Don't overwrite existing audit entries
2067da6c28aaSamw 			 */
206855bf511dSas 			smb_fssd_init(&cur_sd, SMB_SACL_SECINFO,
2069da6c28aaSamw 			    fs_sd->sd_flags);
2070da6c28aaSamw 
2071da6c28aaSamw 			error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
2072da6c28aaSamw 			if (error == 0) {
2073da6c28aaSamw 				ASSERT(fs_sd->sd_zsacl == NULL);
2074da6c28aaSamw 				fs_sd->sd_zsacl = cur_sd.sd_zsacl;
2075da6c28aaSamw 				if (fs_sd->sd_zsacl && fs_sd->sd_zdacl)
2076da6c28aaSamw 					fs_sd->sd_zsacl->acl_flags =
2077da6c28aaSamw 					    fs_sd->sd_zdacl->acl_flags;
2078da6c28aaSamw 			}
2079da6c28aaSamw 		} else {
2080da6c28aaSamw 			/*
2081da6c28aaSamw 			 * Don't overwrite existing access entries
2082da6c28aaSamw 			 */
208355bf511dSas 			smb_fssd_init(&cur_sd, SMB_DACL_SECINFO,
2084da6c28aaSamw 			    fs_sd->sd_flags);
2085da6c28aaSamw 
2086da6c28aaSamw 			error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
2087da6c28aaSamw 			if (error == 0) {
2088da6c28aaSamw 				ASSERT(fs_sd->sd_zdacl == NULL);
2089da6c28aaSamw 				fs_sd->sd_zdacl = cur_sd.sd_zdacl;
2090da6c28aaSamw 				if (fs_sd->sd_zdacl && fs_sd->sd_zsacl)
2091da6c28aaSamw 					fs_sd->sd_zdacl->acl_flags =
2092da6c28aaSamw 					    fs_sd->sd_zsacl->acl_flags;
2093da6c28aaSamw 			}
2094da6c28aaSamw 		}
2095da6c28aaSamw 
2096da6c28aaSamw 		if (error)
209755bf511dSas 			smb_fssd_term(&cur_sd);
2098da6c28aaSamw 	}
2099da6c28aaSamw 
2100da6c28aaSamw 	return (error);
2101da6c28aaSamw }
2102da6c28aaSamw 
2103da6c28aaSamw /*
2104da6c28aaSamw  * smb_fsop_sdwrite
2105da6c28aaSamw  *
2106da6c28aaSamw  * Stores the given uid, gid and acl in filesystem.
2107da6c28aaSamw  * Provided items in fs_sd are specified by fs_sd->sd_secinfo.
2108da6c28aaSamw  *
2109da6c28aaSamw  * A SMB security descriptor could contain owner, primary group,
2110da6c28aaSamw  * DACL and SACL. Setting an SD should be atomic but here it has to
2111da6c28aaSamw  * be done via two separate FS operations: VOP_SETATTR and
2112da6c28aaSamw  * VOP_SETSECATTR. Therefore, this function has to simulate the
2113da6c28aaSamw  * atomicity as well as it can.
21142c1b14e5Sjose borrego  *
21152c1b14e5Sjose borrego  * Get the current uid, gid before setting the new uid/gid
21162c1b14e5Sjose borrego  * so if smb_fsop_aclwrite fails they can be restored. root cred is
21172c1b14e5Sjose borrego  * used to get currend uid/gid since this operation is performed on
21182c1b14e5Sjose borrego  * behalf of the server not the user.
21192c1b14e5Sjose borrego  *
21202c1b14e5Sjose borrego  * If setting uid/gid fails with EPERM it means that and invalid
21212c1b14e5Sjose borrego  * owner has been specified. Callers should translate this to
21222c1b14e5Sjose borrego  * STATUS_INVALID_OWNER which is not the normal mapping for EPERM
21232c1b14e5Sjose borrego  * in upper layers, so EPERM is mapped to EBADE.
2124da6c28aaSamw  */
2125da6c28aaSamw int
2126da6c28aaSamw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2127da6c28aaSamw     smb_fssd_t *fs_sd, int overwrite)
2128da6c28aaSamw {
2129da6c28aaSamw 	int error = 0;
2130da6c28aaSamw 	int access = 0;
2131da6c28aaSamw 	smb_attr_t set_attr;
2132da6c28aaSamw 	smb_attr_t orig_attr;
2133da6c28aaSamw 
2134da6c28aaSamw 	ASSERT(cr);
2135da6c28aaSamw 	ASSERT(fs_sd);
2136da6c28aaSamw 
2137da6c28aaSamw 	ASSERT(sr);
2138da6c28aaSamw 	ASSERT(sr->tid_tree);
2139c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr))
2140da6c28aaSamw 		return (EROFS);
2141da6c28aaSamw 
2142da6c28aaSamw 	bzero(&set_attr, sizeof (smb_attr_t));
2143da6c28aaSamw 
2144da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
2145da6c28aaSamw 		set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
2146da6c28aaSamw 		set_attr.sa_mask |= SMB_AT_UID;
21472c1b14e5Sjose borrego 		access |= WRITE_OWNER;
2148da6c28aaSamw 	}
2149da6c28aaSamw 
2150da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
2151da6c28aaSamw 		set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
2152da6c28aaSamw 		set_attr.sa_mask |= SMB_AT_GID;
21532c1b14e5Sjose borrego 		access |= WRITE_OWNER;
2154da6c28aaSamw 	}
2155da6c28aaSamw 
2156da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
2157da6c28aaSamw 		access |= WRITE_DAC;
2158da6c28aaSamw 
2159da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
2160da6c28aaSamw 		access |= ACCESS_SYSTEM_SECURITY;
2161da6c28aaSamw 
2162da6c28aaSamw 	if (sr->fid_ofile)
2163da6c28aaSamw 		error = smb_ofile_access(sr->fid_ofile, cr, access);
2164da6c28aaSamw 	else
2165da6c28aaSamw 		error = smb_fsop_access(sr, cr, snode, access);
2166da6c28aaSamw 
2167da6c28aaSamw 	if (error)
2168da6c28aaSamw 		return (EACCES);
2169da6c28aaSamw 
2170da6c28aaSamw 	if (set_attr.sa_mask) {
2171da6c28aaSamw 		orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
2172da6c28aaSamw 		error = smb_fsop_getattr(sr, kcred, snode, &orig_attr);
21732c1b14e5Sjose borrego 		if (error == 0) {
2174da6c28aaSamw 			error = smb_fsop_setattr(sr, cr, snode, &set_attr,
2175da6c28aaSamw 			    NULL);
21762c1b14e5Sjose borrego 			if (error == EPERM)
21772c1b14e5Sjose borrego 				error = EBADE;
21782c1b14e5Sjose borrego 		}
2179da6c28aaSamw 
2180da6c28aaSamw 		if (error)
2181da6c28aaSamw 			return (error);
2182da6c28aaSamw 	}
2183da6c28aaSamw 
2184da6c28aaSamw 	if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2185da6c28aaSamw 		if (overwrite == 0) {
2186da6c28aaSamw 			error = smb_fsop_sdmerge(sr, snode, fs_sd);
2187da6c28aaSamw 			if (error)
2188da6c28aaSamw 				return (error);
2189da6c28aaSamw 		}
2190da6c28aaSamw 
2191da6c28aaSamw 		error = smb_fsop_aclwrite(sr, cr, snode, fs_sd);
2192da6c28aaSamw 		if (error) {
2193da6c28aaSamw 			/*
2194da6c28aaSamw 			 * Revert uid/gid changes if required.
2195da6c28aaSamw 			 */
2196da6c28aaSamw 			if (set_attr.sa_mask) {
2197da6c28aaSamw 				orig_attr.sa_mask = set_attr.sa_mask;
2198da6c28aaSamw 				(void) smb_fsop_setattr(sr, kcred, snode,
2199da6c28aaSamw 				    &orig_attr, NULL);
2200da6c28aaSamw 			}
2201da6c28aaSamw 		}
2202da6c28aaSamw 	}
2203da6c28aaSamw 
2204da6c28aaSamw 	return (error);
2205da6c28aaSamw }
2206da6c28aaSamw 
2207da6c28aaSamw /*
2208da6c28aaSamw  * smb_fsop_sdinherit
2209da6c28aaSamw  *
2210da6c28aaSamw  * Inherit the security descriptor from the parent container.
2211da6c28aaSamw  * This function is called after FS has created the file/folder
2212da6c28aaSamw  * so if this doesn't do anything it means FS inheritance is
2213da6c28aaSamw  * in place.
2214da6c28aaSamw  *
2215da6c28aaSamw  * Do inheritance for ZFS internally.
2216da6c28aaSamw  *
2217da6c28aaSamw  * If we want to let ZFS does the inheritance the
2218da6c28aaSamw  * following setting should be true:
2219da6c28aaSamw  *
2220da6c28aaSamw  *  - aclinherit = passthrough
2221da6c28aaSamw  *  - aclmode = passthrough
2222da6c28aaSamw  *  - smbd umask = 0777
2223da6c28aaSamw  *
2224da6c28aaSamw  * This will result in right effective permissions but
2225da6c28aaSamw  * ZFS will always add 6 ACEs for owner, owning group
2226da6c28aaSamw  * and others to be POSIX compliant. This is not what
2227da6c28aaSamw  * Windows clients/users expect, so we decided that CIFS
2228da6c28aaSamw  * implements Windows rules and overwrite whatever ZFS
2229da6c28aaSamw  * comes up with. This way we also don't have to care
2230da6c28aaSamw  * about ZFS aclinherit and aclmode settings.
2231da6c28aaSamw  */
2232da6c28aaSamw static int
2233da6c28aaSamw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd)
2234da6c28aaSamw {
2235da6c28aaSamw 	int is_dir;
223655bf511dSas 	acl_t *dacl = NULL;
223755bf511dSas 	acl_t *sacl = NULL;
2238da6c28aaSamw 	ksid_t *owner_sid;
2239da6c28aaSamw 	int error;
2240da6c28aaSamw 
2241da6c28aaSamw 	ASSERT(fs_sd);
2242da6c28aaSamw 
2243da6c28aaSamw 	if (sr->tid_tree->t_acltype != ACE_T) {
2244da6c28aaSamw 		/*
2245da6c28aaSamw 		 * No forced inheritance for non-ZFS filesystems.
2246da6c28aaSamw 		 */
2247da6c28aaSamw 		fs_sd->sd_secinfo = 0;
2248da6c28aaSamw 		return (0);
2249da6c28aaSamw 	}
2250da6c28aaSamw 
2251da6c28aaSamw 
2252da6c28aaSamw 	/* Fetch parent directory's ACL */
2253da6c28aaSamw 	error = smb_fsop_sdread(sr, kcred, dnode, fs_sd);
2254da6c28aaSamw 	if (error) {
2255da6c28aaSamw 		return (error);
2256da6c28aaSamw 	}
2257da6c28aaSamw 
2258da6c28aaSamw 	is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR);
2259da6c28aaSamw 	owner_sid = crgetsid(sr->user_cr, KSID_OWNER);
2260da6c28aaSamw 	ASSERT(owner_sid);
226155bf511dSas 	dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO,
2262da6c28aaSamw 	    owner_sid->ks_id);
226355bf511dSas 	sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO,
2264da6c28aaSamw 	    (uid_t)-1);
2265da6c28aaSamw 
226655bf511dSas 	if (sacl == NULL)
226755bf511dSas 		fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO;
226855bf511dSas 
226955bf511dSas 	smb_fsacl_free(fs_sd->sd_zdacl);
227055bf511dSas 	smb_fsacl_free(fs_sd->sd_zsacl);
2271da6c28aaSamw 
2272da6c28aaSamw 	fs_sd->sd_zdacl = dacl;
2273da6c28aaSamw 	fs_sd->sd_zsacl = sacl;
2274da6c28aaSamw 
2275da6c28aaSamw 	return (0);
2276da6c28aaSamw }
2277da6c28aaSamw 
2278da6c28aaSamw /*
2279da6c28aaSamw  * smb_fsop_eaccess
2280da6c28aaSamw  *
2281da6c28aaSamw  * Returns the effective permission of the given credential for the
2282da6c28aaSamw  * specified object.
2283da6c28aaSamw  *
2284da6c28aaSamw  * This is just a workaround. We need VFS/FS support for this.
2285da6c28aaSamw  */
2286da6c28aaSamw void
2287da6c28aaSamw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2288da6c28aaSamw     uint32_t *eaccess)
2289da6c28aaSamw {
2290da6c28aaSamw 	int access = 0;
2291da6c28aaSamw 	vnode_t *dir_vp;
2292da6c28aaSamw 	smb_node_t *unnamed_node;
2293da6c28aaSamw 
2294da6c28aaSamw 	ASSERT(cr);
2295da6c28aaSamw 	ASSERT(snode);
2296da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
2297da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
2298da6c28aaSamw 
2299da6c28aaSamw 	unnamed_node = SMB_IS_STREAM(snode);
2300da6c28aaSamw 	if (unnamed_node) {
2301da6c28aaSamw 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
2302da6c28aaSamw 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
2303da6c28aaSamw 		/*
2304da6c28aaSamw 		 * Streams authorization should be performed against the
2305da6c28aaSamw 		 * unnamed stream.
2306da6c28aaSamw 		 */
2307da6c28aaSamw 		snode = unnamed_node;
2308da6c28aaSamw 	}
2309da6c28aaSamw 
2310c8ec8eeaSjose borrego 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) {
2311da6c28aaSamw 		dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL;
2312da6c28aaSamw 		smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp,
2313da6c28aaSamw 		    cr);
2314da6c28aaSamw 		return;
2315da6c28aaSamw 	}
2316da6c28aaSamw 
2317da6c28aaSamw 	/*
2318da6c28aaSamw 	 * FS doesn't understand 32-bit mask
2319da6c28aaSamw 	 */
2320da6c28aaSamw 	smb_vop_eaccess(snode->vp, &access, 0, NULL, cr);
2321743a77edSAlan Wright 	access &= sr->tid_tree->t_access;
2322da6c28aaSamw 
2323da6c28aaSamw 	*eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES;
2324da6c28aaSamw 
2325da6c28aaSamw 	if (access & VREAD)
2326da6c28aaSamw 		*eaccess |= FILE_READ_DATA;
2327da6c28aaSamw 
2328da6c28aaSamw 	if (access & VEXEC)
2329da6c28aaSamw 		*eaccess |= FILE_EXECUTE;
2330da6c28aaSamw 
2331da6c28aaSamw 	if (access & VWRITE)
2332da6c28aaSamw 		*eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
2333da6c28aaSamw 		    FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
2334da6c28aaSamw }
233555bf511dSas 
2336dc20a302Sas /*
2337dc20a302Sas  * smb_fsop_shrlock
2338dc20a302Sas  *
2339dc20a302Sas  * For the current open request, check file sharing rules
2340dc20a302Sas  * against existing opens.
2341dc20a302Sas  *
2342dc20a302Sas  * Returns NT_STATUS_SHARING_VIOLATION if there is any
2343dc20a302Sas  * sharing conflict.  Returns NT_STATUS_SUCCESS otherwise.
2344dc20a302Sas  *
2345dc20a302Sas  * Full system-wide share reservation synchronization is available
2346dc20a302Sas  * when the nbmand (non-blocking mandatory) mount option is set
2347dc20a302Sas  * (i.e. nbl_need_crit() is true) and nbmand critical regions are used.
2348dc20a302Sas  * This provides synchronization with NFS and local processes.  The
2349dc20a302Sas  * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called
2350dc20a302Sas  * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well
2351dc20a302Sas  * as the CIFS rename and delete paths.
2352dc20a302Sas  *
2353dc20a302Sas  * The CIFS server will also enter the nbl critical region in the open,
2354dc20a302Sas  * rename, and delete paths when nbmand is not set.  There is limited
2355dc20a302Sas  * coordination with local and VFS share reservations in this case.
2356dc20a302Sas  * Note that when the nbmand mount option is not set, the VFS layer
2357dc20a302Sas  * only processes advisory reservations and the delete mode is not checked.
2358dc20a302Sas  *
2359dc20a302Sas  * Whether or not the nbmand mount option is set, intra-CIFS share
2360dc20a302Sas  * checking is done in the open, delete, and rename paths using a CIFS
2361dc20a302Sas  * critical region (node->n_share_lock).
2362dc20a302Sas  */
2363dc20a302Sas 
2364dc20a302Sas uint32_t
2365faa1795aSjb smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid,
2366dc20a302Sas     uint32_t desired_access, uint32_t share_access)
2367dc20a302Sas {
2368dc20a302Sas 	int rc;
2369dc20a302Sas 
2370dc20a302Sas 	if (node->attr.sa_vattr.va_type == VDIR)
2371dc20a302Sas 		return (NT_STATUS_SUCCESS);
2372dc20a302Sas 
2373dc20a302Sas 	/* Allow access if the request is just for meta data */
2374dc20a302Sas 	if ((desired_access & FILE_DATA_ALL) == 0)
2375dc20a302Sas 		return (NT_STATUS_SUCCESS);
2376dc20a302Sas 
2377dc20a302Sas 	rc = smb_node_open_check(node, cr, desired_access, share_access);
2378dc20a302Sas 	if (rc)
2379dc20a302Sas 		return (NT_STATUS_SHARING_VIOLATION);
2380dc20a302Sas 
2381dc20a302Sas 	rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access,
2382dc20a302Sas 	    cr);
2383dc20a302Sas 	if (rc)
2384dc20a302Sas 		return (NT_STATUS_SHARING_VIOLATION);
2385dc20a302Sas 
2386dc20a302Sas 	return (NT_STATUS_SUCCESS);
2387dc20a302Sas }
2388dc20a302Sas 
238955bf511dSas void
2390dc20a302Sas smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid)
2391dc20a302Sas {
2392dc20a302Sas 	if (node->attr.sa_vattr.va_type == VDIR)
2393dc20a302Sas 		return;
2394dc20a302Sas 
2395dc20a302Sas 	(void) smb_vop_unshrlock(node->vp, uniq_fid, cr);
2396dc20a302Sas }
23978c10a865Sas 
23988c10a865Sas int
23998c10a865Sas smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock,
24008c10a865Sas     cred_t *cr)
24018c10a865Sas {
24028c10a865Sas 	flock64_t bf;
24038c10a865Sas 	int flag = F_REMOTELOCK;
24048c10a865Sas 
24053ad684d6Sjb 	/*
24063ad684d6Sjb 	 * VOP_FRLOCK() will not be called if:
24073ad684d6Sjb 	 *
24083ad684d6Sjb 	 * 1) The lock has a range of zero bytes. The semantics of Windows and
24093ad684d6Sjb 	 *    POSIX are different. In the case of POSIX it asks for the locking
24103ad684d6Sjb 	 *    of all the bytes from the offset provided until the end of the
24113ad684d6Sjb 	 *    file. In the case of Windows a range of zero locks nothing and
24123ad684d6Sjb 	 *    doesn't conflict with any other lock.
24133ad684d6Sjb 	 *
24143ad684d6Sjb 	 * 2) The lock rolls over (start + lenght < start). Solaris will assert
24153ad684d6Sjb 	 *    if such a request is submitted. This will not create
24163ad684d6Sjb 	 *    incompatibilities between POSIX and Windows. In the Windows world,
24173ad684d6Sjb 	 *    if a client submits such a lock, the server will not lock any
24183ad684d6Sjb 	 *    bytes. Interestingly if the same lock (same offset and length) is
24193ad684d6Sjb 	 *    resubmitted Windows will consider that there is an overlap and
24203ad684d6Sjb 	 *    the granting rules will then apply.
24213ad684d6Sjb 	 */
24223ad684d6Sjb 	if ((lock->l_length == 0) ||
24233ad684d6Sjb 	    ((lock->l_start + lock->l_length - 1) < lock->l_start))
24243ad684d6Sjb 		return (0);
24253ad684d6Sjb 
24268c10a865Sas 	bzero(&bf, sizeof (bf));
24278c10a865Sas 
24288c10a865Sas 	if (unlock) {
24298c10a865Sas 		bf.l_type = F_UNLCK;
24308c10a865Sas 	} else if (lock->l_type == SMB_LOCK_TYPE_READONLY) {
24318c10a865Sas 		bf.l_type = F_RDLCK;
24328c10a865Sas 		flag |= FREAD;
24338c10a865Sas 	} else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) {
24348c10a865Sas 		bf.l_type = F_WRLCK;
24358c10a865Sas 		flag |= FWRITE;
24368c10a865Sas 	}
24378c10a865Sas 
24388c10a865Sas 	bf.l_start = lock->l_start;
24398c10a865Sas 	bf.l_len = lock->l_length;
2440c8ec8eeaSjose borrego 	bf.l_pid = lock->l_file->f_uniqid;
24418c10a865Sas 	bf.l_sysid = smb_ct.cc_sysid;
24428c10a865Sas 
24438c10a865Sas 	return (smb_vop_frlock(node->vp, cr, flag, &bf));
24448c10a865Sas }
2445