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 /*
22148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
2356a2adb6SPrashanth Badari * Copyright 2012-2022 Tintri by DDN, Inc. All rights reserved.
2448f31ae7SGordon Ross * Copyright 2022 RackTop Systems, Inc.
25da6c28aaSamw */
26da6c28aaSamw
27da6c28aaSamw #include <sys/sid.h>
28dc20a302Sas200622 #include <sys/nbmlock.h>
29da6c28aaSamw #include <smbsrv/smb_fsops.h>
3055bf511dSas200622 #include <smbsrv/smb_kproto.h>
31da6c28aaSamw #include <acl/acl_common.h>
32dc20a302Sas200622 #include <sys/fcntl.h>
3355f0a249SGordon Ross #include <sys/filio.h>
34dc20a302Sas200622 #include <sys/flock.h>
35dc20a302Sas200622 #include <fs/fs_subr.h>
36da6c28aaSamw
37faa1795aSjb150015 extern caller_context_t smb_ct;
38faa1795aSjb150015
390a73e6f9SMatt Barden static int smb_fsop_create_file_with_stream(smb_request_t *, cred_t *,
400a73e6f9SMatt Barden smb_node_t *, char *, char *, int, smb_attr_t *, smb_node_t **);
41eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
42eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_file(smb_request_t *, cred_t *, smb_node_t *,
43037cac00Sjoyce mcintosh char *, int, smb_attr_t *, smb_node_t **);
44eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
45b819cea2SGordon Ross #ifdef _KERNEL
46eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_with_sd(smb_request_t *, cred_t *, smb_node_t *,
47037cac00Sjoyce mcintosh char *, smb_attr_t *, smb_node_t **, smb_fssd_t *);
48eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_sdinherit(smb_request_t *, smb_node_t *, smb_fssd_t *);
49b819cea2SGordon Ross #endif /* _KERNEL */
50da6c28aaSamw
51da6c28aaSamw /*
52da6c28aaSamw * The smb_fsop_* functions have knowledge of CIFS semantics.
53da6c28aaSamw *
54da6c28aaSamw * The smb_vop_* functions have minimal knowledge of CIFS semantics and
55da6c28aaSamw * serve as an interface to the VFS layer.
56da6c28aaSamw *
57da6c28aaSamw * Hence, smb_request_t and smb_node_t structures should not be passed
58da6c28aaSamw * from the smb_fsop_* layer to the smb_vop_* layer.
59da6c28aaSamw *
60da6c28aaSamw * In general, CIFS service code should only ever call smb_fsop_*
61da6c28aaSamw * functions directly, and never smb_vop_* functions directly.
62da6c28aaSamw *
63da6c28aaSamw * smb_fsop_* functions should call smb_vop_* functions where possible, instead
64da6c28aaSamw * of their smb_fsop_* counterparts. However, there are times when
65da6c28aaSamw * this cannot be avoided.
66da6c28aaSamw */
67da6c28aaSamw
68da6c28aaSamw /*
69da6c28aaSamw * Note: Stream names cannot be mangled.
70da6c28aaSamw */
71da6c28aaSamw
72da6c28aaSamw /*
738c10a865Sas200622 * smb_fsop_amask_to_omode
748c10a865Sas200622 *
758c10a865Sas200622 * Convert the access mask to the open mode (for use
768c10a865Sas200622 * with the VOP_OPEN call).
778c10a865Sas200622 *
788c10a865Sas200622 * Note that opening a file for attribute only access
798c10a865Sas200622 * will also translate into an FREAD or FWRITE open mode
808c10a865Sas200622 * (i.e., it's not just for data).
818c10a865Sas200622 *
828c10a865Sas200622 * This is needed so that opens are tracked appropriately
838c10a865Sas200622 * for oplock processing.
84da6c28aaSamw */
85da6c28aaSamw
86da6c28aaSamw int
smb_fsop_amask_to_omode(uint32_t access)878c10a865Sas200622 smb_fsop_amask_to_omode(uint32_t access)
88da6c28aaSamw {
89da6c28aaSamw int mode = 0;
90da6c28aaSamw
918c10a865Sas200622 if (access & (FILE_READ_DATA | FILE_EXECUTE |
928c10a865Sas200622 FILE_READ_ATTRIBUTES | FILE_READ_EA))
93da6c28aaSamw mode |= FREAD;
94da6c28aaSamw
958c10a865Sas200622 if (access & (FILE_WRITE_DATA | FILE_APPEND_DATA |
968c10a865Sas200622 FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))
97da6c28aaSamw mode |= FWRITE;
98da6c28aaSamw
998c10a865Sas200622 if (access & FILE_APPEND_DATA)
100da6c28aaSamw mode |= FAPPEND;
101da6c28aaSamw
102da6c28aaSamw return (mode);
103da6c28aaSamw }
104da6c28aaSamw
1058c10a865Sas200622 int
smb_fsop_open(smb_node_t * node,int mode,cred_t * cred)1068c10a865Sas200622 smb_fsop_open(smb_node_t *node, int mode, cred_t *cred)
1078c10a865Sas200622 {
1088c10a865Sas200622 /*
1098c10a865Sas200622 * Assuming that the same vnode is returned as we had before.
1108c10a865Sas200622 * (I.e., with certain types of files or file systems, a
1118c10a865Sas200622 * different vnode might be returned by VOP_OPEN)
1128c10a865Sas200622 */
1138c10a865Sas200622 return (smb_vop_open(&node->vp, mode, cred));
1148c10a865Sas200622 }
1158c10a865Sas200622
116c8ec8eeaSjose borrego void
smb_fsop_close(smb_node_t * node,int mode,cred_t * cred)1178c10a865Sas200622 smb_fsop_close(smb_node_t *node, int mode, cred_t *cred)
1188c10a865Sas200622 {
119c8ec8eeaSjose borrego smb_vop_close(node->vp, mode, cred);
1208c10a865Sas200622 }
1218c10a865Sas200622
122b819cea2SGordon Ross #ifdef _KERNEL
123da6c28aaSamw static int
smb_fsop_create_with_sd(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,smb_attr_t * attr,smb_node_t ** ret_snode,smb_fssd_t * fs_sd)124eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_with_sd(smb_request_t *sr, cred_t *cr,
125eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode, char *name,
126037cac00Sjoyce mcintosh smb_attr_t *attr, smb_node_t **ret_snode, smb_fssd_t *fs_sd)
127da6c28aaSamw {
128da6c28aaSamw vsecattr_t *vsap;
129da6c28aaSamw vsecattr_t vsecattr;
130da6c28aaSamw smb_attr_t set_attr;
1318622ec45SGordon Ross acl_t *acl, *dacl, *sacl;
132da6c28aaSamw vnode_t *vp;
1338622ec45SGordon Ross cred_t *kcr = zone_kcred();
134da6c28aaSamw int aclbsize = 0; /* size of acl list in bytes */
135da6c28aaSamw int flags = 0;
136da6c28aaSamw int rc;
1372c1b14e5Sjose borrego boolean_t is_dir;
138da6c28aaSamw
139da6c28aaSamw ASSERT(fs_sd);
1400a73e6f9SMatt Barden ASSERT(ret_snode != NULL);
141da6c28aaSamw
142c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr))
143da6c28aaSamw flags = SMB_IGNORE_CASE;
1448b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr))
1458b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA;
146da6c28aaSamw
147da6c28aaSamw ASSERT(cr);
148da6c28aaSamw
149da6c28aaSamw is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0);
150da6c28aaSamw
151c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) {
152da6c28aaSamw dacl = fs_sd->sd_zdacl;
153da6c28aaSamw sacl = fs_sd->sd_zsacl;
154d11e14a7SMatt Barden if (dacl != NULL || sacl != NULL) {
155da6c28aaSamw if (dacl && sacl) {
15655bf511dSas200622 acl = smb_fsacl_merge(dacl, sacl);
157da6c28aaSamw } else if (dacl) {
158da6c28aaSamw acl = dacl;
159da6c28aaSamw } else {
160da6c28aaSamw acl = sacl;
161da6c28aaSamw }
162da6c28aaSamw
16355bf511dSas200622 rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize);
164da6c28aaSamw
165da6c28aaSamw if (dacl && sacl)
166da6c28aaSamw acl_free(acl);
167da6c28aaSamw
1682c1b14e5Sjose borrego if (rc != 0)
169da6c28aaSamw return (rc);
170da6c28aaSamw
171da6c28aaSamw vsap = &vsecattr;
1722c1b14e5Sjose borrego } else {
173da6c28aaSamw vsap = NULL;
1742c1b14e5Sjose borrego }
175da6c28aaSamw
176743a77edSAlan Wright /* The tree ACEs may prevent a create */
177743a77edSAlan Wright rc = EACCES;
178da6c28aaSamw if (is_dir) {
179743a77edSAlan Wright if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_SUBDIRECTORY) != 0)
180eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_mkdir(dnode->vp, name, attr,
181743a77edSAlan Wright &vp, flags, cr, vsap);
182da6c28aaSamw } else {
183743a77edSAlan Wright if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_FILE) != 0)
184eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_create(dnode->vp, name, attr,
185743a77edSAlan Wright &vp, flags, cr, vsap);
186da6c28aaSamw }
187da6c28aaSamw
188da6c28aaSamw if (vsap != NULL)
189da6c28aaSamw kmem_free(vsap->vsa_aclentp, aclbsize);
190da6c28aaSamw
191da6c28aaSamw if (rc != 0)
192da6c28aaSamw return (rc);
193da6c28aaSamw
194da6c28aaSamw set_attr.sa_mask = 0;
195da6c28aaSamw
196da6c28aaSamw /*
197da6c28aaSamw * Ideally we should be able to specify the owner and owning
198da6c28aaSamw * group at create time along with the ACL. Since we cannot
199da6c28aaSamw * do that right now, kcred is passed to smb_vop_setattr so it
200da6c28aaSamw * doesn't fail due to lack of permission.
201da6c28aaSamw */
202da6c28aaSamw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
203da6c28aaSamw set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
204da6c28aaSamw set_attr.sa_mask |= SMB_AT_UID;
205da6c28aaSamw }
206da6c28aaSamw
207da6c28aaSamw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
208da6c28aaSamw set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
209da6c28aaSamw set_attr.sa_mask |= SMB_AT_GID;
210da6c28aaSamw }
211da6c28aaSamw
2129660e5cbSJanice Chang if (set_attr.sa_mask)
2138622ec45SGordon Ross rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcr);
214da6c28aaSamw
2152c1b14e5Sjose borrego if (rc == 0) {
2162c1b14e5Sjose borrego *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
217037cac00Sjoyce mcintosh name, dnode, NULL);
2182c1b14e5Sjose borrego
2197f667e74Sjose borrego if (*ret_snode == NULL)
2202c1b14e5Sjose borrego rc = ENOMEM;
2217f667e74Sjose borrego
2227f667e74Sjose borrego VN_RELE(vp);
2232c1b14e5Sjose borrego }
224da6c28aaSamw } else {
225da6c28aaSamw /*
226da6c28aaSamw * For filesystems that don't support ACL-on-create, try
227da6c28aaSamw * to set the specified SD after create, which could actually
228da6c28aaSamw * fail because of conflicts between inherited security
229da6c28aaSamw * attributes upon creation and the specified SD.
230da6c28aaSamw *
231da6c28aaSamw * Passing kcred to smb_fsop_sdwrite() to overcome this issue.
232da6c28aaSamw */
233da6c28aaSamw
234da6c28aaSamw if (is_dir) {
235eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_mkdir(dnode->vp, name, attr, &vp,
2362c1b14e5Sjose borrego flags, cr, NULL);
237da6c28aaSamw } else {
238eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_create(dnode->vp, name, attr, &vp,
2392c1b14e5Sjose borrego flags, cr, NULL);
240da6c28aaSamw }
241da6c28aaSamw
24255bf511dSas200622 if (rc != 0)
24355bf511dSas200622 return (rc);
24455bf511dSas200622
2452c1b14e5Sjose borrego *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
246037cac00Sjoyce mcintosh name, dnode, NULL);
247da6c28aaSamw
2482c1b14e5Sjose borrego if (*ret_snode != NULL) {
2492c1b14e5Sjose borrego if (!smb_tree_has_feature(sr->tid_tree,
2502c1b14e5Sjose borrego SMB_TREE_NFS_MOUNTED))
2518622ec45SGordon Ross rc = smb_fsop_sdwrite(sr, kcr, *ret_snode,
2522c1b14e5Sjose borrego fs_sd, 1);
2532c1b14e5Sjose borrego } else {
254da6c28aaSamw rc = ENOMEM;
255da6c28aaSamw }
2567f667e74Sjose borrego
2577f667e74Sjose borrego VN_RELE(vp);
258da6c28aaSamw }
259da6c28aaSamw
26055bf511dSas200622 if (rc != 0) {
2612c1b14e5Sjose borrego if (is_dir)
262eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_vop_rmdir(dnode->vp, name, flags, cr);
2632c1b14e5Sjose borrego else
264eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_vop_remove(dnode->vp, name, flags, cr);
26555bf511dSas200622 }
26655bf511dSas200622
267da6c28aaSamw return (rc);
268da6c28aaSamw }
269b819cea2SGordon Ross #endif /* _KERNEL */
270da6c28aaSamw
271da6c28aaSamw /*
272da6c28aaSamw * smb_fsop_create
273da6c28aaSamw *
274da6c28aaSamw * All SMB functions should use this wrapper to ensure that
275da6c28aaSamw * all the smb_vop_creates are performed with the appropriate credentials.
276eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * Please document any direct calls to explain the reason for avoiding
277eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * this wrapper.
278da6c28aaSamw *
279da6c28aaSamw * *ret_snode is returned with a reference upon success. No reference is
280da6c28aaSamw * taken if an error is returned.
281da6c28aaSamw */
282da6c28aaSamw int
smb_fsop_create(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,smb_attr_t * attr,smb_node_t ** ret_snode)283037cac00Sjoyce mcintosh smb_fsop_create(smb_request_t *sr, cred_t *cr, smb_node_t *dnode,
284037cac00Sjoyce mcintosh char *name, smb_attr_t *attr, smb_node_t **ret_snode)
285da6c28aaSamw {
286da6c28aaSamw int rc = 0;
287eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States int flags = 0;
288eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States char *fname, *sname;
289eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States char *longname = NULL;
290da6c28aaSamw
291da6c28aaSamw ASSERT(cr);
292eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode);
293eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
294eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
295da6c28aaSamw
296da6c28aaSamw ASSERT(ret_snode);
297da6c28aaSamw *ret_snode = 0;
298da6c28aaSamw
299da6c28aaSamw ASSERT(name);
300da6c28aaSamw if (*name == 0)
301da6c28aaSamw return (EINVAL);
302da6c28aaSamw
303da6c28aaSamw ASSERT(sr);
304da6c28aaSamw ASSERT(sr->tid_tree);
305c8ec8eeaSjose borrego
306eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
307c8ec8eeaSjose borrego return (EACCES);
308c8ec8eeaSjose borrego
309c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr))
310da6c28aaSamw return (EROFS);
311da6c28aaSamw
312c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr))
313da6c28aaSamw flags = SMB_IGNORE_CASE;
3148b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr))
3158b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA;
316e3f2c991SKeyur Desai if (SMB_TREE_SUPPORTS_ABE(sr))
317e3f2c991SKeyur Desai flags |= SMB_ABE;
318da6c28aaSamw
3198b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (smb_is_stream_name(name)) {
320da6c28aaSamw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
321da6c28aaSamw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
322eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_stream_parse_name(name, fname, sname);
323da6c28aaSamw
3240a73e6f9SMatt Barden rc = smb_fsop_create_file_with_stream(sr, cr, dnode,
325037cac00Sjoyce mcintosh fname, sname, flags, attr, ret_snode);
3268b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
327da6c28aaSamw kmem_free(fname, MAXNAMELEN);
328da6c28aaSamw kmem_free(sname, MAXNAMELEN);
3298b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc);
330da6c28aaSamw }
3318b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
3328b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /* Not a named stream */
333eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
334cb174861Sjoyce mcintosh if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(name)) {
3358b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
336148c5f43SAlan Wright rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
3378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States kmem_free(longname, MAXNAMELEN);
3388b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
3398b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (rc == 0)
3408b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States rc = EEXIST;
3418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (rc != ENOENT)
3428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc);
3438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
3448b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
345eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_file(sr, cr, dnode, name, flags,
346037cac00Sjoyce mcintosh attr, ret_snode);
347eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc);
348eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
349eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States }
350eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
351eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
352eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /*
3530a73e6f9SMatt Barden * smb_fsop_create_file_with_stream
354eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States *
3550a73e6f9SMatt Barden * Create named stream (sname) on file (fname), creating the file if it
356eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * doesn't exist.
3570a73e6f9SMatt Barden * If we created the file and then creation of the named stream fails,
3580a73e6f9SMatt Barden * we delete the file.
359eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * Since we use the real file name for the smb_vop_remove we
360eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * clear the SMB_IGNORE_CASE flag to ensure a case sensitive
361eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * match.
362eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States *
3630a73e6f9SMatt Barden * Note that some stream "types" are "restricted" and only
3640a73e6f9SMatt Barden * internal callers (cr == kcred) can create those.
3650a73e6f9SMatt Barden */
3660a73e6f9SMatt Barden static int
smb_fsop_create_file_with_stream(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * fname,char * sname,int flags,smb_attr_t * attr,smb_node_t ** ret_snode)3670a73e6f9SMatt Barden smb_fsop_create_file_with_stream(smb_request_t *sr, cred_t *cr,
3680a73e6f9SMatt Barden smb_node_t *dnode, char *fname, char *sname, int flags,
3690a73e6f9SMatt Barden smb_attr_t *attr, smb_node_t **ret_snode)
3700a73e6f9SMatt Barden {
3710a73e6f9SMatt Barden smb_node_t *fnode;
3720a73e6f9SMatt Barden cred_t *kcr = zone_kcred();
3730a73e6f9SMatt Barden int rc = 0;
3740a73e6f9SMatt Barden boolean_t fcreate = B_FALSE;
3750a73e6f9SMatt Barden
3760a73e6f9SMatt Barden ASSERT(ret_snode != NULL);
3770a73e6f9SMatt Barden
3780a73e6f9SMatt Barden if (cr != kcr && smb_strname_restricted(sname))
3790a73e6f9SMatt Barden return (EACCES);
3800a73e6f9SMatt Barden
3810a73e6f9SMatt Barden /* Look up / create the unnamed stream, fname */
3820a73e6f9SMatt Barden rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
3830a73e6f9SMatt Barden sr->tid_tree->t_snode, dnode, fname, &fnode);
3840a73e6f9SMatt Barden if (rc == 0) {
3850a73e6f9SMatt Barden if (smb_fsop_access(sr, sr->user_cr, fnode,
3860a73e6f9SMatt Barden sr->sr_open.desired_access) != 0) {
3870a73e6f9SMatt Barden smb_node_release(fnode);
3880a73e6f9SMatt Barden rc = EACCES;
3890a73e6f9SMatt Barden }
3900a73e6f9SMatt Barden } else if (rc == ENOENT) {
3910a73e6f9SMatt Barden fcreate = B_TRUE;
3920a73e6f9SMatt Barden rc = smb_fsop_create_file(sr, cr, dnode, fname, flags,
3930a73e6f9SMatt Barden attr, &fnode);
3940a73e6f9SMatt Barden }
3950a73e6f9SMatt Barden if (rc != 0)
3960a73e6f9SMatt Barden return (rc);
3970a73e6f9SMatt Barden
3980a73e6f9SMatt Barden rc = smb_fsop_create_stream(sr, cr, dnode, fnode, sname, flags, attr,
3990a73e6f9SMatt Barden ret_snode);
4000a73e6f9SMatt Barden
4010a73e6f9SMatt Barden if (rc != 0) {
4020a73e6f9SMatt Barden if (fcreate) {
4030a73e6f9SMatt Barden flags &= ~SMB_IGNORE_CASE;
4040a73e6f9SMatt Barden (void) smb_vop_remove(dnode->vp,
4050a73e6f9SMatt Barden fnode->od_name, flags, cr);
4060a73e6f9SMatt Barden }
4070a73e6f9SMatt Barden }
4080a73e6f9SMatt Barden
4090a73e6f9SMatt Barden smb_node_release(fnode);
4100a73e6f9SMatt Barden return (rc);
4110a73e6f9SMatt Barden }
4120a73e6f9SMatt Barden
4130a73e6f9SMatt Barden /*
4140a73e6f9SMatt Barden * smb_fsop_create_stream
4150a73e6f9SMatt Barden *
4160a73e6f9SMatt Barden * Create named stream (sname) on existing file (fnode).
4170a73e6f9SMatt Barden *
418eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * The second parameter of smb_vop_setattr() is set to
419eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * NULL, even though an unnamed stream exists. This is
420eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * because we want to set the UID and GID on the named
421eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * stream in this case for consistency with the (unnamed
422eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * stream) file (see comments for smb_vop_setattr()).
4238d94f651SGordon Ross *
4248d94f651SGordon Ross * Note that some stream "types" are "restricted" and only
4258d94f651SGordon Ross * internal callers (cr == kcred) can create those.
426eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States */
4270a73e6f9SMatt Barden int
smb_fsop_create_stream(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,smb_node_t * fnode,char * sname,int flags,smb_attr_t * attr,smb_node_t ** ret_snode)428eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_stream(smb_request_t *sr, cred_t *cr,
4290a73e6f9SMatt Barden smb_node_t *dnode, smb_node_t *fnode, char *sname, int flags,
430037cac00Sjoyce mcintosh smb_attr_t *attr, smb_node_t **ret_snode)
431eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States {
432eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_attr_t fattr;
433eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States vnode_t *xattrdvp;
434eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States vnode_t *vp;
4358622ec45SGordon Ross cred_t *kcr = zone_kcred();
436eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States int rc = 0;
4370a73e6f9SMatt Barden
4380a73e6f9SMatt Barden ASSERT(ret_snode != NULL);
439eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
4408d94f651SGordon Ross if (cr != kcr && smb_strname_restricted(sname))
4418d94f651SGordon Ross return (EACCES);
4428d94f651SGordon Ross
4430a73e6f9SMatt Barden bzero(&fattr, sizeof (fattr));
444037cac00Sjoyce mcintosh fattr.sa_mask = SMB_AT_UID | SMB_AT_GID;
4458622ec45SGordon Ross rc = smb_vop_getattr(fnode->vp, NULL, &fattr, 0, kcr);
446037cac00Sjoyce mcintosh
447037cac00Sjoyce mcintosh if (rc == 0) {
448eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /* create the named stream, sname */
4490a73e6f9SMatt Barden rc = smb_vop_stream_create(fnode->vp, sname,
4500a73e6f9SMatt Barden attr, &vp, &xattrdvp, flags, cr);
451037cac00Sjoyce mcintosh }
4520a73e6f9SMatt Barden if (rc != 0)
453eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc);
454eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
455eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States attr->sa_vattr.va_uid = fattr.sa_vattr.va_uid;
456eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States attr->sa_vattr.va_gid = fattr.sa_vattr.va_gid;
457eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States attr->sa_mask = SMB_AT_UID | SMB_AT_GID;
458eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
4598622ec45SGordon Ross rc = smb_vop_setattr(vp, NULL, attr, 0, kcr);
460eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (rc != 0) {
4610a73e6f9SMatt Barden VN_RELE(xattrdvp);
4620a73e6f9SMatt Barden VN_RELE(vp);
463eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc);
464eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States }
465eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
466eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdvp,
467037cac00Sjoyce mcintosh vp, sname);
468eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
469eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(xattrdvp);
470eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(vp);
471eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
472eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (*ret_snode == NULL)
473eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = ENOMEM;
474eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
4759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* notify change to the unnamed stream */
4769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (rc == 0)
477ccc71be5SGordon Ross smb_node_notify_change(dnode,
4780a73e6f9SMatt Barden FILE_ACTION_ADDED_STREAM, fnode->od_name);
4799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
480eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc);
481eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States }
482eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
483eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /*
484eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * smb_fsop_create_file
485eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States */
486eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int
smb_fsop_create_file(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,int flags,smb_attr_t * attr,smb_node_t ** ret_snode)487eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_file(smb_request_t *sr, cred_t *cr,
488eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode, char *name, int flags,
489037cac00Sjoyce mcintosh smb_attr_t *attr, smb_node_t **ret_snode)
490eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States {
491148c5f43SAlan Wright smb_arg_open_t *op = &sr->sr_open;
492eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States vnode_t *vp;
493b819cea2SGordon Ross int rc;
494b819cea2SGordon Ross
4950a73e6f9SMatt Barden ASSERT(ret_snode != NULL);
4960a73e6f9SMatt Barden
497b819cea2SGordon Ross #ifdef _KERNEL
498eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fssd_t fs_sd;
499eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States uint32_t secinfo;
500eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States uint32_t status;
501eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
50255bf511dSas200622 if (op->sd) {
503da6c28aaSamw /*
504da6c28aaSamw * SD sent by client in Windows format. Needs to be
505d11e14a7SMatt Barden * converted to FS format. Inherit DACL/SACL if they're not
506d11e14a7SMatt Barden * specified.
507da6c28aaSamw */
50855bf511dSas200622 secinfo = smb_sd_get_secinfo(op->sd);
509d11e14a7SMatt Barden
5109e3ab9e9SMatt Barden if ((secinfo & SMB_SACL_SECINFO) != 0 &&
5119e3ab9e9SMatt Barden !smb_user_has_security_priv(sr->uid_user, cr))
5129e3ab9e9SMatt Barden return (EPERM);
5139e3ab9e9SMatt Barden
51455bf511dSas200622 smb_fssd_init(&fs_sd, secinfo, 0);
515da6c28aaSamw
51655bf511dSas200622 status = smb_sd_tofs(op->sd, &fs_sd);
517da6c28aaSamw if (status == NT_STATUS_SUCCESS) {
518d11e14a7SMatt Barden rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
519d11e14a7SMatt Barden if (rc == 0)
520eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_with_sd(sr, cr, dnode,
521037cac00Sjoyce mcintosh name, attr, ret_snode, &fs_sd);
522d11e14a7SMatt Barden
5238b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } else {
524da6c28aaSamw rc = EINVAL;
5258b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
52655bf511dSas200622 smb_fssd_term(&fs_sd);
527da6c28aaSamw } else if (sr->tid_tree->t_acltype == ACE_T) {
528da6c28aaSamw /*
529da6c28aaSamw * No incoming SD and filesystem is ZFS
530da6c28aaSamw * Server applies Windows inheritance rules,
531da6c28aaSamw * see smb_fsop_sdinherit() comments as to why.
532da6c28aaSamw */
533d11e14a7SMatt Barden smb_fssd_init(&fs_sd, 0, 0);
534eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
535da6c28aaSamw if (rc == 0) {
536eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_with_sd(sr, cr, dnode,
537037cac00Sjoyce mcintosh name, attr, ret_snode, &fs_sd);
538da6c28aaSamw }
539da6c28aaSamw
54055bf511dSas200622 smb_fssd_term(&fs_sd);
541b819cea2SGordon Ross } else
542b819cea2SGordon Ross #endif /* _KERNEL */
543b819cea2SGordon Ross {
544da6c28aaSamw /*
545da6c28aaSamw * No incoming SD and filesystem is not ZFS
546da6c28aaSamw * let the filesystem handles the inheritance.
547da6c28aaSamw */
548eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_create(dnode->vp, name, attr, &vp,
549dc20a302Sas200622 flags, cr, NULL);
550da6c28aaSamw
551da6c28aaSamw if (rc == 0) {
552da6c28aaSamw *ret_snode = smb_node_lookup(sr, op, cr, vp,
553037cac00Sjoyce mcintosh name, dnode, NULL);
554da6c28aaSamw
5557f667e74Sjose borrego if (*ret_snode == NULL)
556da6c28aaSamw rc = ENOMEM;
5577f667e74Sjose borrego
5587f667e74Sjose borrego VN_RELE(vp);
559da6c28aaSamw }
560da6c28aaSamw
561da6c28aaSamw }
5629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
5639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (rc == 0)
564b819cea2SGordon Ross smb_node_notify_change(dnode, FILE_ACTION_ADDED, name);
5659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
566da6c28aaSamw return (rc);
567da6c28aaSamw }
568da6c28aaSamw
569da6c28aaSamw /*
570da6c28aaSamw * smb_fsop_mkdir
571da6c28aaSamw *
572da6c28aaSamw * All SMB functions should use this wrapper to ensure that
573da6c28aaSamw * the the calls are performed with the appropriate credentials.
574da6c28aaSamw * Please document any direct call to explain the reason
575da6c28aaSamw * for avoiding this wrapper.
576da6c28aaSamw *
577da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine.
578da6c28aaSamw *
579da6c28aaSamw * *ret_snode is returned with a reference upon success. No reference is
580da6c28aaSamw * taken if an error is returned.
581da6c28aaSamw */
582da6c28aaSamw int
smb_fsop_mkdir(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,smb_attr_t * attr,smb_node_t ** ret_snode)583da6c28aaSamw smb_fsop_mkdir(
584faa1795aSjb150015 smb_request_t *sr,
585da6c28aaSamw cred_t *cr,
586eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode,
587da6c28aaSamw char *name,
588da6c28aaSamw smb_attr_t *attr,
589037cac00Sjoyce mcintosh smb_node_t **ret_snode)
590da6c28aaSamw {
591da6c28aaSamw struct open_param *op = &sr->arg.open;
592da6c28aaSamw char *longname;
593da6c28aaSamw vnode_t *vp;
594da6c28aaSamw int flags = 0;
595b819cea2SGordon Ross int rc;
596b819cea2SGordon Ross
597b819cea2SGordon Ross #ifdef _KERNEL
598da6c28aaSamw smb_fssd_t fs_sd;
599da6c28aaSamw uint32_t secinfo;
600da6c28aaSamw uint32_t status;
601b819cea2SGordon Ross #endif /* _KERNEL */
602b819cea2SGordon Ross
603da6c28aaSamw ASSERT(cr);
604eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode);
605eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
606eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
607da6c28aaSamw
608da6c28aaSamw ASSERT(ret_snode);
609da6c28aaSamw *ret_snode = 0;
610da6c28aaSamw
611da6c28aaSamw ASSERT(name);
612da6c28aaSamw if (*name == 0)
613da6c28aaSamw return (EINVAL);
614da6c28aaSamw
615da6c28aaSamw ASSERT(sr);
616da6c28aaSamw ASSERT(sr->tid_tree);
617c8ec8eeaSjose borrego
618eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
619c8ec8eeaSjose borrego return (EACCES);
620c8ec8eeaSjose borrego
621c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr))
622da6c28aaSamw return (EROFS);
6238b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr))
6248b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA;
625e3f2c991SKeyur Desai if (SMB_TREE_SUPPORTS_ABE(sr))
626e3f2c991SKeyur Desai flags |= SMB_ABE;
627da6c28aaSamw
628cb174861Sjoyce mcintosh if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(name)) {
629da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
630148c5f43SAlan Wright rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
631da6c28aaSamw kmem_free(longname, MAXNAMELEN);
632da6c28aaSamw
633da6c28aaSamw /*
634da6c28aaSamw * If the name passed in by the client has an unmangled
635da6c28aaSamw * equivalent that is found in the specified directory,
636da6c28aaSamw * then the mkdir cannot succeed. Return EEXIST.
637da6c28aaSamw *
638da6c28aaSamw * Only if ENOENT is returned will a mkdir be attempted.
639da6c28aaSamw */
640da6c28aaSamw
641da6c28aaSamw if (rc == 0)
642da6c28aaSamw rc = EEXIST;
643da6c28aaSamw
644da6c28aaSamw if (rc != ENOENT)
645da6c28aaSamw return (rc);
646da6c28aaSamw }
647da6c28aaSamw
648c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr))
649da6c28aaSamw flags = SMB_IGNORE_CASE;
650da6c28aaSamw
651b819cea2SGordon Ross #ifdef _KERNEL
65255bf511dSas200622 if (op->sd) {
653da6c28aaSamw /*
654da6c28aaSamw * SD sent by client in Windows format. Needs to be
655d11e14a7SMatt Barden * converted to FS format. Inherit DACL/SACL if they're not
656d11e14a7SMatt Barden * specified.
657da6c28aaSamw */
65855bf511dSas200622 secinfo = smb_sd_get_secinfo(op->sd);
659d11e14a7SMatt Barden
6609e3ab9e9SMatt Barden if ((secinfo & SMB_SACL_SECINFO) != 0 &&
6619e3ab9e9SMatt Barden !smb_user_has_security_priv(sr->uid_user, cr))
6629e3ab9e9SMatt Barden return (EPERM);
6639e3ab9e9SMatt Barden
66455bf511dSas200622 smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR);
665da6c28aaSamw
66655bf511dSas200622 status = smb_sd_tofs(op->sd, &fs_sd);
667da6c28aaSamw if (status == NT_STATUS_SUCCESS) {
668d11e14a7SMatt Barden rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
669d11e14a7SMatt Barden if (rc == 0)
670eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_with_sd(sr, cr, dnode,
671037cac00Sjoyce mcintosh name, attr, ret_snode, &fs_sd);
672da6c28aaSamw }
673da6c28aaSamw else
674da6c28aaSamw rc = EINVAL;
67555bf511dSas200622 smb_fssd_term(&fs_sd);
676da6c28aaSamw } else if (sr->tid_tree->t_acltype == ACE_T) {
677da6c28aaSamw /*
678da6c28aaSamw * No incoming SD and filesystem is ZFS
679da6c28aaSamw * Server applies Windows inheritance rules,
680da6c28aaSamw * see smb_fsop_sdinherit() comments as to why.
681da6c28aaSamw */
682d11e14a7SMatt Barden smb_fssd_init(&fs_sd, 0, SMB_FSSD_FLAGS_DIR);
683eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
684da6c28aaSamw if (rc == 0) {
685eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_with_sd(sr, cr, dnode,
686037cac00Sjoyce mcintosh name, attr, ret_snode, &fs_sd);
687da6c28aaSamw }
688da6c28aaSamw
68955bf511dSas200622 smb_fssd_term(&fs_sd);
690da6c28aaSamw
691b819cea2SGordon Ross } else
692b819cea2SGordon Ross #endif /* _KERNEL */
693b819cea2SGordon Ross {
694eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, flags, cr,
695dc20a302Sas200622 NULL);
696da6c28aaSamw
697da6c28aaSamw if (rc == 0) {
698da6c28aaSamw *ret_snode = smb_node_lookup(sr, op, cr, vp, name,
699037cac00Sjoyce mcintosh dnode, NULL);
700da6c28aaSamw
7017f667e74Sjose borrego if (*ret_snode == NULL)
702da6c28aaSamw rc = ENOMEM;
7037f667e74Sjose borrego
7047f667e74Sjose borrego VN_RELE(vp);
705da6c28aaSamw }
706da6c28aaSamw }
707da6c28aaSamw
7089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (rc == 0)
709b819cea2SGordon Ross smb_node_notify_change(dnode, FILE_ACTION_ADDED, name);
7109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
711da6c28aaSamw return (rc);
712da6c28aaSamw }
713da6c28aaSamw
714da6c28aaSamw /*
715da6c28aaSamw * smb_fsop_remove
716da6c28aaSamw *
717da6c28aaSamw * All SMB functions should use this wrapper to ensure that
718da6c28aaSamw * the the calls are performed with the appropriate credentials.
719da6c28aaSamw * Please document any direct call to explain the reason
720da6c28aaSamw * for avoiding this wrapper.
721da6c28aaSamw *
722da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine.
723da6c28aaSamw *
724da6c28aaSamw * A null smb_request might be passed to this function.
7258d94f651SGordon Ross *
7268d94f651SGordon Ross * Note that some stream "types" are "restricted" and only
7278d94f651SGordon Ross * internal callers (cr == kcred) can remove those.
728da6c28aaSamw */
729da6c28aaSamw int
smb_fsop_remove(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,uint32_t flags)730da6c28aaSamw smb_fsop_remove(
731faa1795aSjb150015 smb_request_t *sr,
732da6c28aaSamw cred_t *cr,
733eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode,
734da6c28aaSamw char *name,
7358b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States uint32_t flags)
736da6c28aaSamw {
737da6c28aaSamw smb_node_t *fnode;
738da6c28aaSamw char *longname;
739da6c28aaSamw char *fname;
740da6c28aaSamw char *sname;
741da6c28aaSamw int rc;
742da6c28aaSamw
743da6c28aaSamw ASSERT(cr);
744da6c28aaSamw /*
745da6c28aaSamw * The state of the node could be SMB_NODE_STATE_DESTROYING if this
746da6c28aaSamw * function is called during the deletion of the node (because of
747da6c28aaSamw * DELETE_ON_CLOSE).
748da6c28aaSamw */
749eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode);
750eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
751da6c28aaSamw
752eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 ||
753743a77edSAlan Wright SMB_TREE_HAS_ACCESS(sr, ACE_DELETE) == 0)
754da6c28aaSamw return (EACCES);
755da6c28aaSamw
756c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr))
757da6c28aaSamw return (EROFS);
758da6c28aaSamw
759da6c28aaSamw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
760da6c28aaSamw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
761da6c28aaSamw
762eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (dnode->flags & NODE_XATTR_DIR) {
7638d94f651SGordon Ross if (cr != zone_kcred() && smb_strname_restricted(name)) {
7648d94f651SGordon Ross rc = EACCES;
7658d94f651SGordon Ross goto out;
7668d94f651SGordon Ross }
7678d94f651SGordon Ross
7689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States fnode = dnode->n_dnode;
7699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_stream_remove(fnode->vp, name, flags, cr);
7709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
7719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* notify change to the unnamed stream */
772ccc71be5SGordon Ross if ((rc == 0) && fnode->n_dnode) {
773ccc71be5SGordon Ross smb_node_notify_change(fnode->n_dnode,
774ccc71be5SGordon Ross FILE_ACTION_REMOVED_STREAM, fnode->od_name);
775ccc71be5SGordon Ross }
776eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } else if (smb_is_stream_name(name)) {
777eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_stream_parse_name(name, fname, sname);
7788d7e4166Sjose borrego
7798d94f651SGordon Ross if (cr != zone_kcred() && smb_strname_restricted(sname)) {
7808d94f651SGordon Ross rc = EACCES;
7818d94f651SGordon Ross goto out;
7828d94f651SGordon Ross }
7838d94f651SGordon Ross
784cbfb650aScp160787 /*
785da6c28aaSamw * Look up the unnamed stream (i.e. fname).
786da6c28aaSamw * Unmangle processing will be done on fname
787da6c28aaSamw * as well as any link target.
788da6c28aaSamw */
789da6c28aaSamw
790da6c28aaSamw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
791037cac00Sjoyce mcintosh sr->tid_tree->t_snode, dnode, fname, &fnode);
792da6c28aaSamw
793da6c28aaSamw if (rc != 0) {
7948d94f651SGordon Ross goto out;
795da6c28aaSamw }
796da6c28aaSamw
797da6c28aaSamw /*
798da6c28aaSamw * XXX
799da6c28aaSamw * Need to find out what permission is required by NTFS
800da6c28aaSamw * to remove a stream.
801da6c28aaSamw */
802dc20a302Sas200622 rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr);
803da6c28aaSamw
804da6c28aaSamw smb_node_release(fnode);
8059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
8069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* notify change to the unnamed stream */
807ccc71be5SGordon Ross if (rc == 0) {
808ccc71be5SGordon Ross smb_node_notify_change(dnode,
809ccc71be5SGordon Ross FILE_ACTION_REMOVED_STREAM, fname);
810ccc71be5SGordon Ross }
811da6c28aaSamw } else {
812eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_remove(dnode->vp, name, flags, cr);
813da6c28aaSamw
814da6c28aaSamw if (rc == ENOENT) {
815cb174861Sjoyce mcintosh if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
816cb174861Sjoyce mcintosh !smb_maybe_mangled(name)) {
8178d94f651SGordon Ross goto out;
818da6c28aaSamw }
819da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
820da6c28aaSamw
821e3f2c991SKeyur Desai if (SMB_TREE_SUPPORTS_ABE(sr))
822e3f2c991SKeyur Desai flags |= SMB_ABE;
823e3f2c991SKeyur Desai
824148c5f43SAlan Wright rc = smb_unmangle(dnode, name, longname, MAXNAMELEN,
825148c5f43SAlan Wright flags);
826da6c28aaSamw
827da6c28aaSamw if (rc == 0) {
828da6c28aaSamw /*
8298b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * longname is the real (case-sensitive)
8308b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * on-disk name.
831da6c28aaSamw * We make sure we do a remove on this exact
832da6c28aaSamw * name, as the name was mangled and denotes
833da6c28aaSamw * a unique file.
834da6c28aaSamw */
835da6c28aaSamw flags &= ~SMB_IGNORE_CASE;
836eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_remove(dnode->vp, longname,
837dc20a302Sas200622 flags, cr);
838da6c28aaSamw }
839da6c28aaSamw kmem_free(longname, MAXNAMELEN);
840da6c28aaSamw }
841b819cea2SGordon Ross if (rc == 0) {
842b819cea2SGordon Ross smb_node_notify_change(dnode,
843b819cea2SGordon Ross FILE_ACTION_REMOVED, name);
844b819cea2SGordon Ross }
845da6c28aaSamw }
846da6c28aaSamw
8478d94f651SGordon Ross out:
848da6c28aaSamw kmem_free(fname, MAXNAMELEN);
849da6c28aaSamw kmem_free(sname, MAXNAMELEN);
8509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
851da6c28aaSamw return (rc);
852da6c28aaSamw }
853da6c28aaSamw
854da6c28aaSamw /*
855da6c28aaSamw * smb_fsop_remove_streams
856da6c28aaSamw *
857da6c28aaSamw * This function removes a file's streams without removing the
858da6c28aaSamw * file itself.
859da6c28aaSamw *
8607f667e74Sjose borrego * It is assumed that fnode is not a link.
861da6c28aaSamw */
862a90cf9f2SGordon Ross uint32_t
smb_fsop_remove_streams(smb_request_t * sr,cred_t * cr,smb_node_t * fnode)863faa1795aSjb150015 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode)
864da6c28aaSamw {
8657f667e74Sjose borrego int rc, flags = 0;
8667f667e74Sjose borrego smb_odir_t *od;
8677f667e74Sjose borrego smb_odirent_t *odirent;
868a90cf9f2SGordon Ross uint32_t status;
8697f667e74Sjose borrego boolean_t eos;
870da6c28aaSamw
871c8ec8eeaSjose borrego ASSERT(sr);
872da6c28aaSamw ASSERT(cr);
873da6c28aaSamw ASSERT(fnode);
874da6c28aaSamw ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
875da6c28aaSamw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
876da6c28aaSamw
877a90cf9f2SGordon Ross if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0)
878a90cf9f2SGordon Ross return (NT_STATUS_ACCESS_DENIED);
879da6c28aaSamw
880a90cf9f2SGordon Ross if (SMB_TREE_IS_READONLY(sr))
881a90cf9f2SGordon Ross return (NT_STATUS_ACCESS_DENIED);
882da6c28aaSamw
883c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr))
884da6c28aaSamw flags = SMB_IGNORE_CASE;
885eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
8868b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr))
8878b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA;
888da6c28aaSamw
88956a2adb6SPrashanth Badari /*
89056a2adb6SPrashanth Badari * NB: There aren't currently any restricted streams that could be
89156a2adb6SPrashanth Badari * removed by this function. If there ever are, be careful to exclude
89256a2adb6SPrashanth Badari * any restricted streams that we DON'T want to remove.
89356a2adb6SPrashanth Badari */
89456a2adb6SPrashanth Badari status = smb_odir_openat(sr, fnode, &od, B_FALSE);
895a90cf9f2SGordon Ross switch (status) {
896a90cf9f2SGordon Ross case 0:
897a90cf9f2SGordon Ross break;
898d2488fe8SGordon Ross case NT_STATUS_OBJECT_NAME_NOT_FOUND:
899a90cf9f2SGordon Ross case NT_STATUS_NO_SUCH_FILE:
900a90cf9f2SGordon Ross case NT_STATUS_NOT_SUPPORTED:
901a90cf9f2SGordon Ross /* No streams to remove. */
902a90cf9f2SGordon Ross return (0);
903a90cf9f2SGordon Ross default:
904a90cf9f2SGordon Ross return (status);
905eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States }
9067f667e74Sjose borrego
9077f667e74Sjose borrego odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
908da6c28aaSamw for (;;) {
9097f667e74Sjose borrego rc = smb_odir_read(sr, od, odirent, &eos);
9107f667e74Sjose borrego if ((rc != 0) || (eos))
911da6c28aaSamw break;
9127f667e74Sjose borrego (void) smb_vop_remove(od->d_dnode->vp, odirent->od_name,
9137f667e74Sjose borrego flags, cr);
914da6c28aaSamw }
9157f667e74Sjose borrego kmem_free(odirent, sizeof (smb_odirent_t));
916a90cf9f2SGordon Ross if (eos && rc == ENOENT)
917a90cf9f2SGordon Ross rc = 0;
9187f667e74Sjose borrego
9197f667e74Sjose borrego smb_odir_close(od);
920a1511e6bSjoyce mcintosh smb_odir_release(od);
921a90cf9f2SGordon Ross if (rc)
922a90cf9f2SGordon Ross status = smb_errno2status(rc);
923a90cf9f2SGordon Ross return (status);
924da6c28aaSamw }
925da6c28aaSamw
926da6c28aaSamw /*
927da6c28aaSamw * smb_fsop_rmdir
928da6c28aaSamw *
929da6c28aaSamw * All SMB functions should use this wrapper to ensure that
930da6c28aaSamw * the the calls are performed with the appropriate credentials.
931da6c28aaSamw * Please document any direct call to explain the reason
932da6c28aaSamw * for avoiding this wrapper.
933da6c28aaSamw *
934da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine.
935da6c28aaSamw */
936da6c28aaSamw int
smb_fsop_rmdir(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,uint32_t flags)937da6c28aaSamw smb_fsop_rmdir(
938faa1795aSjb150015 smb_request_t *sr,
939da6c28aaSamw cred_t *cr,
940eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode,
941da6c28aaSamw char *name,
9428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States uint32_t flags)
943da6c28aaSamw {
944da6c28aaSamw int rc;
945da6c28aaSamw char *longname;
946da6c28aaSamw
947da6c28aaSamw ASSERT(cr);
948da6c28aaSamw /*
949da6c28aaSamw * The state of the node could be SMB_NODE_STATE_DESTROYING if this
950da6c28aaSamw * function is called during the deletion of the node (because of
951da6c28aaSamw * DELETE_ON_CLOSE).
952da6c28aaSamw */
953eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode);
954eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
955da6c28aaSamw
956eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 ||
957743a77edSAlan Wright SMB_TREE_HAS_ACCESS(sr, ACE_DELETE_CHILD) == 0)
958da6c28aaSamw return (EACCES);
959da6c28aaSamw
960c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr))
961da6c28aaSamw return (EROFS);
962da6c28aaSamw
963eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_rmdir(dnode->vp, name, flags, cr);
964da6c28aaSamw
965da6c28aaSamw if (rc == ENOENT) {
966cb174861Sjoyce mcintosh if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
967cb174861Sjoyce mcintosh !smb_maybe_mangled(name)) {
968da6c28aaSamw return (rc);
969cb174861Sjoyce mcintosh }
970da6c28aaSamw
971da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
972e3f2c991SKeyur Desai
973e3f2c991SKeyur Desai if (SMB_TREE_SUPPORTS_ABE(sr))
974e3f2c991SKeyur Desai flags |= SMB_ABE;
975148c5f43SAlan Wright rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
976da6c28aaSamw
977da6c28aaSamw if (rc == 0) {
978da6c28aaSamw /*
9798b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * longname is the real (case-sensitive)
9808b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * on-disk name.
981da6c28aaSamw * We make sure we do a rmdir on this exact
982da6c28aaSamw * name, as the name was mangled and denotes
983da6c28aaSamw * a unique directory.
984da6c28aaSamw */
985da6c28aaSamw flags &= ~SMB_IGNORE_CASE;
986eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_rmdir(dnode->vp, longname, flags, cr);
987da6c28aaSamw }
988da6c28aaSamw
989da6c28aaSamw kmem_free(longname, MAXNAMELEN);
990da6c28aaSamw }
991da6c28aaSamw
9929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (rc == 0)
993b819cea2SGordon Ross smb_node_notify_change(dnode, FILE_ACTION_REMOVED, name);
9949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
995da6c28aaSamw return (rc);
996da6c28aaSamw }
997da6c28aaSamw
998da6c28aaSamw /*
999da6c28aaSamw * smb_fsop_getattr
1000da6c28aaSamw *
1001da6c28aaSamw * All SMB functions should use this wrapper to ensure that
1002da6c28aaSamw * the the calls are performed with the appropriate credentials.
1003da6c28aaSamw * Please document any direct call to explain the reason
1004da6c28aaSamw * for avoiding this wrapper.
1005da6c28aaSamw *
1006da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine.
1007da6c28aaSamw */
1008da6c28aaSamw int
smb_fsop_getattr(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_attr_t * attr)1009faa1795aSjb150015 smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1010da6c28aaSamw smb_attr_t *attr)
1011da6c28aaSamw {
1012da6c28aaSamw smb_node_t *unnamed_node;
1013da6c28aaSamw vnode_t *unnamed_vp = NULL;
1014da6c28aaSamw uint32_t status;
1015da6c28aaSamw uint32_t access = 0;
1016da6c28aaSamw int flags = 0;
1017dc20a302Sas200622 int rc;
1018da6c28aaSamw
1019da6c28aaSamw ASSERT(cr);
1020da6c28aaSamw ASSERT(snode);
1021da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1022da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1023da6c28aaSamw
1024743a77edSAlan Wright if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0 ||
1025743a77edSAlan Wright SMB_TREE_HAS_ACCESS(sr, ACE_READ_ATTRIBUTES) == 0)
1026da6c28aaSamw return (EACCES);
1027da6c28aaSamw
1028037cac00Sjoyce mcintosh /* sr could be NULL in some cases */
1029037cac00Sjoyce mcintosh if (sr && sr->fid_ofile) {
1030da6c28aaSamw /* if uid and/or gid is requested */
1031da6c28aaSamw if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID))
1032da6c28aaSamw access |= READ_CONTROL;
1033da6c28aaSamw
1034da6c28aaSamw /* if anything else is also requested */
1035da6c28aaSamw if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID))
1036da6c28aaSamw access |= FILE_READ_ATTRIBUTES;
1037da6c28aaSamw
1038da6c28aaSamw status = smb_ofile_access(sr->fid_ofile, cr, access);
1039da6c28aaSamw if (status != NT_STATUS_SUCCESS)
1040da6c28aaSamw return (EACCES);
1041da6c28aaSamw
1042c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree,
1043c8ec8eeaSjose borrego SMB_TREE_ACEMASKONACCESS))
1044da6c28aaSamw flags = ATTR_NOACLCHECK;
1045da6c28aaSamw }
1046da6c28aaSamw
1047da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode);
1048da6c28aaSamw
1049da6c28aaSamw if (unnamed_node) {
1050da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1051da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1052da6c28aaSamw unnamed_vp = unnamed_node->vp;
1053da6c28aaSamw }
1054da6c28aaSamw
1055dc20a302Sas200622 rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr);
10569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
10579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((rc == 0) && smb_node_is_dfslink(snode)) {
10589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* a DFS link should be treated as a directory */
10599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
10609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
10619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
1062dc20a302Sas200622 return (rc);
1063da6c28aaSamw }
1064da6c28aaSamw
1065da6c28aaSamw /*
1066b1352070SAlan Wright * smb_fsop_link
1067b1352070SAlan Wright *
1068b1352070SAlan Wright * All SMB functions should use this smb_vop_link wrapper to ensure that
1069b1352070SAlan Wright * the smb_vop_link is performed with the appropriate credentials.
1070b1352070SAlan Wright * Please document any direct call to smb_vop_link to explain the reason
1071b1352070SAlan Wright * for avoiding this wrapper.
1072b1352070SAlan Wright *
1073b1352070SAlan Wright * It is assumed that references exist on from_dnode and to_dnode coming
1074b1352070SAlan Wright * into this routine.
1075b1352070SAlan Wright */
1076b1352070SAlan Wright int
smb_fsop_link(smb_request_t * sr,cred_t * cr,smb_node_t * from_fnode,smb_node_t * to_dnode,char * to_name)1077bbf6f00cSJordan Brown smb_fsop_link(smb_request_t *sr, cred_t *cr, smb_node_t *from_fnode,
1078bbf6f00cSJordan Brown smb_node_t *to_dnode, char *to_name)
1079b1352070SAlan Wright {
1080b1352070SAlan Wright char *longname = NULL;
1081b1352070SAlan Wright int flags = 0;
1082b1352070SAlan Wright int rc;
1083b1352070SAlan Wright
1084b1352070SAlan Wright ASSERT(sr);
1085b1352070SAlan Wright ASSERT(sr->tid_tree);
1086b1352070SAlan Wright ASSERT(cr);
1087b1352070SAlan Wright ASSERT(to_dnode);
1088b1352070SAlan Wright ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC);
1089b1352070SAlan Wright ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1090b1352070SAlan Wright ASSERT(from_fnode);
1091b1352070SAlan Wright ASSERT(from_fnode->n_magic == SMB_NODE_MAGIC);
1092b1352070SAlan Wright ASSERT(from_fnode->n_state != SMB_NODE_STATE_DESTROYING);
1093b1352070SAlan Wright
1094b1352070SAlan Wright if (SMB_TREE_CONTAINS_NODE(sr, from_fnode) == 0)
1095b1352070SAlan Wright return (EACCES);
1096b1352070SAlan Wright
1097b1352070SAlan Wright if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0)
1098b1352070SAlan Wright return (EACCES);
1099b1352070SAlan Wright
1100b1352070SAlan Wright if (SMB_TREE_IS_READONLY(sr))
1101b1352070SAlan Wright return (EROFS);
1102b1352070SAlan Wright
1103b1352070SAlan Wright if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1104b1352070SAlan Wright flags = SMB_IGNORE_CASE;
1105b1352070SAlan Wright if (SMB_TREE_SUPPORTS_CATIA(sr))
1106b1352070SAlan Wright flags |= SMB_CATIA;
1107e3f2c991SKeyur Desai if (SMB_TREE_SUPPORTS_ABE(sr))
1108e3f2c991SKeyur Desai flags |= SMB_ABE;
1109b1352070SAlan Wright
1110cb174861Sjoyce mcintosh if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(to_name)) {
1111b1352070SAlan Wright longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1112148c5f43SAlan Wright rc = smb_unmangle(to_dnode, to_name, longname,
1113148c5f43SAlan Wright MAXNAMELEN, flags);
1114b1352070SAlan Wright kmem_free(longname, MAXNAMELEN);
1115b1352070SAlan Wright
1116b1352070SAlan Wright if (rc == 0)
1117b1352070SAlan Wright rc = EEXIST;
1118b1352070SAlan Wright if (rc != ENOENT)
1119b1352070SAlan Wright return (rc);
1120b1352070SAlan Wright }
1121b1352070SAlan Wright
1122b1352070SAlan Wright rc = smb_vop_link(to_dnode->vp, from_fnode->vp, to_name, flags, cr);
11239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
1124b819cea2SGordon Ross if (rc == 0)
1125b819cea2SGordon Ross smb_node_notify_change(to_dnode, FILE_ACTION_ADDED, to_name);
11269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
1127b1352070SAlan Wright return (rc);
1128b1352070SAlan Wright }
1129b1352070SAlan Wright
1130b1352070SAlan Wright /*
1131da6c28aaSamw * smb_fsop_rename
1132da6c28aaSamw *
1133da6c28aaSamw * All SMB functions should use this smb_vop_rename wrapper to ensure that
1134da6c28aaSamw * the smb_vop_rename is performed with the appropriate credentials.
1135da6c28aaSamw * Please document any direct call to smb_vop_rename to explain the reason
1136da6c28aaSamw * for avoiding this wrapper.
1137da6c28aaSamw *
1138eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * It is assumed that references exist on from_dnode and to_dnode coming
1139da6c28aaSamw * into this routine.
1140da6c28aaSamw */
1141da6c28aaSamw int
smb_fsop_rename(smb_request_t * sr,cred_t * cr,smb_node_t * from_dnode,char * from_name,smb_node_t * to_dnode,char * to_name)1142da6c28aaSamw smb_fsop_rename(
1143faa1795aSjb150015 smb_request_t *sr,
1144da6c28aaSamw cred_t *cr,
1145eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *from_dnode,
1146da6c28aaSamw char *from_name,
1147eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *to_dnode,
1148da6c28aaSamw char *to_name)
1149da6c28aaSamw {
1150da6c28aaSamw smb_node_t *from_snode;
11519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_attr_t from_attr;
1152da6c28aaSamw vnode_t *from_vp;
11538b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States int flags = 0, ret_flags;
1154da6c28aaSamw int rc;
1155743a77edSAlan Wright boolean_t isdir;
1156da6c28aaSamw
1157da6c28aaSamw ASSERT(cr);
1158eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(from_dnode);
1159eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(from_dnode->n_magic == SMB_NODE_MAGIC);
1160eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(from_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1161da6c28aaSamw
1162eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(to_dnode);
1163eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC);
1164eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1165da6c28aaSamw
1166eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, from_dnode) == 0)
1167da6c28aaSamw return (EACCES);
1168da6c28aaSamw
1169eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0)
1170da6c28aaSamw return (EACCES);
1171da6c28aaSamw
1172da6c28aaSamw ASSERT(sr);
1173da6c28aaSamw ASSERT(sr->tid_tree);
1174c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr))
1175da6c28aaSamw return (EROFS);
1176da6c28aaSamw
1177da6c28aaSamw /*
1178c8ec8eeaSjose borrego * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE
1179da6c28aaSamw * here.
1180da6c28aaSamw *
1181da6c28aaSamw * A case-sensitive rename is always done in this routine
1182da6c28aaSamw * because we are using the on-disk name from an earlier lookup.
1183da6c28aaSamw * If a mangled name was passed in by the caller (denoting a
1184da6c28aaSamw * deterministic lookup), then the exact file must be renamed
1185da6c28aaSamw * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or
1186da6c28aaSamw * else the underlying file system might return a "first-match"
1187da6c28aaSamw * on this on-disk name, possibly resulting in the wrong file).
1188da6c28aaSamw */
1189da6c28aaSamw
11908b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr))
11918b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA;
11928b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
1193da6c28aaSamw /*
1194da6c28aaSamw * XXX: Lock required through smb_node_release() below?
1195da6c28aaSamw */
1196da6c28aaSamw
1197eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_lookup(from_dnode->vp, from_name, &from_vp, NULL,
11989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States flags, &ret_flags, NULL, &from_attr, cr);
1199da6c28aaSamw
1200da6c28aaSamw if (rc != 0)
1201da6c28aaSamw return (rc);
1202da6c28aaSamw
1203663b59f4SAlexander Stetsenko /*
1204663b59f4SAlexander Stetsenko * Make sure "from" vp is not a mount point.
1205663b59f4SAlexander Stetsenko */
1206663b59f4SAlexander Stetsenko if (from_vp->v_type == VDIR && vn_ismntpt(from_vp)) {
1207663b59f4SAlexander Stetsenko VN_RELE(from_vp);
1208663b59f4SAlexander Stetsenko return (EACCES);
1209663b59f4SAlexander Stetsenko }
1210663b59f4SAlexander Stetsenko
12119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (from_attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) {
12129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(from_vp);
12139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (EACCES);
12149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
12159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
12169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States isdir = ((from_attr.sa_dosattr & FILE_ATTRIBUTE_DIRECTORY) != 0);
1217743a77edSAlan Wright
1218743a77edSAlan Wright if ((isdir && SMB_TREE_HAS_ACCESS(sr,
1219743a77edSAlan Wright ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY) !=
1220743a77edSAlan Wright (ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY)) ||
1221743a77edSAlan Wright (!isdir && SMB_TREE_HAS_ACCESS(sr, ACE_DELETE | ACE_ADD_FILE) !=
12229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (ACE_DELETE | ACE_ADD_FILE))) {
12239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(from_vp);
1224743a77edSAlan Wright return (EACCES);
12259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
1226743a77edSAlan Wright
1227bbf6f00cSJordan Brown /*
1228bbf6f00cSJordan Brown * SMB checks access on open and retains an access granted
1229bbf6f00cSJordan Brown * mask for use while the file is open. ACL changes should
1230bbf6f00cSJordan Brown * not affect access to an open file.
1231bbf6f00cSJordan Brown *
1232bbf6f00cSJordan Brown * If the rename is being performed on an ofile:
1233bbf6f00cSJordan Brown * - Check the ofile's access granted mask to see if the
1234bbf6f00cSJordan Brown * rename is permitted - requires DELETE access.
1235bbf6f00cSJordan Brown * - If the file system does access checking, set the
1236bbf6f00cSJordan Brown * ATTR_NOACLCHECK flag to ensure that the file system
1237bbf6f00cSJordan Brown * does not check permissions on subsequent calls.
1238bbf6f00cSJordan Brown */
1239bbf6f00cSJordan Brown if (sr && sr->fid_ofile) {
1240bbf6f00cSJordan Brown rc = smb_ofile_access(sr->fid_ofile, cr, DELETE);
12419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (rc != NT_STATUS_SUCCESS) {
12429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(from_vp);
1243bbf6f00cSJordan Brown return (EACCES);
12449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
1245bbf6f00cSJordan Brown
1246f4048769SMatt Barden /*
1247f4048769SMatt Barden * TODO: avoid ACL check for source file.
1248f4048769SMatt Barden * smb_vop_rename() passes its own flags to VOP_RENAME,
1249f4048769SMatt Barden * and ZFS doesn't pass it on to zfs_zaccess_rename().
1250f4048769SMatt Barden */
1251bbf6f00cSJordan Brown }
1252bbf6f00cSJordan Brown
1253eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_rename(from_dnode->vp, from_name, to_dnode->vp,
1254dc20a302Sas200622 to_name, flags, cr);
1255da6c28aaSamw
1256da6c28aaSamw if (rc == 0) {
1257da6c28aaSamw from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name,
1258037cac00Sjoyce mcintosh from_dnode, NULL);
1259da6c28aaSamw
1260da6c28aaSamw if (from_snode == NULL) {
12617f667e74Sjose borrego rc = ENOMEM;
1262da6c28aaSamw } else {
1263eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_rename(from_dnode, from_snode,
1264eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States to_dnode, to_name);
12657f667e74Sjose borrego smb_node_release(from_snode);
1266da6c28aaSamw }
12677f667e74Sjose borrego }
12687f667e74Sjose borrego VN_RELE(from_vp);
1269da6c28aaSamw
1270b819cea2SGordon Ross if (rc == 0) {
1271b819cea2SGordon Ross if (from_dnode == to_dnode) {
1272b819cea2SGordon Ross smb_node_notify_change(from_dnode,
1273b819cea2SGordon Ross FILE_ACTION_RENAMED_OLD_NAME, from_name);
1274b819cea2SGordon Ross smb_node_notify_change(to_dnode,
1275b819cea2SGordon Ross FILE_ACTION_RENAMED_NEW_NAME, to_name);
1276b819cea2SGordon Ross } else {
1277b819cea2SGordon Ross smb_node_notify_change(from_dnode,
1278b819cea2SGordon Ross FILE_ACTION_REMOVED, from_name);
1279b819cea2SGordon Ross smb_node_notify_change(to_dnode,
1280b819cea2SGordon Ross FILE_ACTION_ADDED, to_name);
1281b819cea2SGordon Ross }
1282b819cea2SGordon Ross }
12839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
1284da6c28aaSamw /* XXX: unlock */
1285da6c28aaSamw
1286da6c28aaSamw return (rc);
1287da6c28aaSamw }
1288da6c28aaSamw
1289da6c28aaSamw /*
1290da6c28aaSamw * smb_fsop_setattr
1291da6c28aaSamw *
1292da6c28aaSamw * All SMB functions should use this wrapper to ensure that
1293da6c28aaSamw * the the calls are performed with the appropriate credentials.
1294da6c28aaSamw * Please document any direct call to explain the reason
1295da6c28aaSamw * for avoiding this wrapper.
1296da6c28aaSamw *
1297e3f2c991SKeyur Desai * It is assumed that a reference exists on snode coming into
1298e3f2c991SKeyur Desai * this function.
1299da6c28aaSamw * A null smb_request might be passed to this function.
1300da6c28aaSamw */
1301da6c28aaSamw int
smb_fsop_setattr(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_attr_t * set_attr)1302da6c28aaSamw smb_fsop_setattr(
1303da6c28aaSamw smb_request_t *sr,
1304da6c28aaSamw cred_t *cr,
1305da6c28aaSamw smb_node_t *snode,
1306037cac00Sjoyce mcintosh smb_attr_t *set_attr)
1307da6c28aaSamw {
1308da6c28aaSamw smb_node_t *unnamed_node;
1309da6c28aaSamw vnode_t *unnamed_vp = NULL;
1310da6c28aaSamw uint32_t status;
13112c1b14e5Sjose borrego uint32_t access;
1312da6c28aaSamw int rc = 0;
1313da6c28aaSamw int flags = 0;
13142c1b14e5Sjose borrego uint_t sa_mask;
1315da6c28aaSamw
1316da6c28aaSamw ASSERT(cr);
1317da6c28aaSamw ASSERT(snode);
1318da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1319da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1320da6c28aaSamw
1321c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0)
1322da6c28aaSamw return (EACCES);
1323da6c28aaSamw
1324c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr))
1325da6c28aaSamw return (EROFS);
1326da6c28aaSamw
1327743a77edSAlan Wright if (SMB_TREE_HAS_ACCESS(sr,
1328743a77edSAlan Wright ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0)
1329743a77edSAlan Wright return (EACCES);
1330743a77edSAlan Wright
1331e3f2c991SKeyur Desai /*
1332e3f2c991SKeyur Desai * SMB checks access on open and retains an access granted
1333e3f2c991SKeyur Desai * mask for use while the file is open. ACL changes should
1334e3f2c991SKeyur Desai * not affect access to an open file.
1335e3f2c991SKeyur Desai *
1336e3f2c991SKeyur Desai * If the setattr is being performed on an ofile:
1337e3f2c991SKeyur Desai * - Check the ofile's access granted mask to see if the
1338e3f2c991SKeyur Desai * setattr is permitted.
1339e3f2c991SKeyur Desai * UID, GID - require WRITE_OWNER
1340e3f2c991SKeyur Desai * SIZE, ALLOCSZ - require FILE_WRITE_DATA
1341e3f2c991SKeyur Desai * all other attributes require FILE_WRITE_ATTRIBUTES
1342e3f2c991SKeyur Desai *
1343e3f2c991SKeyur Desai * - If the file system does access checking, set the
1344e3f2c991SKeyur Desai * ATTR_NOACLCHECK flag to ensure that the file system
1345e3f2c991SKeyur Desai * does not check permissions on subsequent calls.
1346e3f2c991SKeyur Desai */
1347da6c28aaSamw if (sr && sr->fid_ofile) {
13482c1b14e5Sjose borrego sa_mask = set_attr->sa_mask;
13492c1b14e5Sjose borrego access = 0;
1350c8ec8eeaSjose borrego
1351e3f2c991SKeyur Desai if (sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ)) {
13522c1b14e5Sjose borrego access |= FILE_WRITE_DATA;
1353e3f2c991SKeyur Desai sa_mask &= ~(SMB_AT_SIZE | SMB_AT_ALLOCSZ);
13542c1b14e5Sjose borrego }
13552c1b14e5Sjose borrego
13562c1b14e5Sjose borrego if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) {
1357da6c28aaSamw access |= WRITE_OWNER;
13582c1b14e5Sjose borrego sa_mask &= ~(SMB_AT_UID|SMB_AT_GID);
13592c1b14e5Sjose borrego }
1360da6c28aaSamw
13612c1b14e5Sjose borrego if (sa_mask)
1362da6c28aaSamw access |= FILE_WRITE_ATTRIBUTES;
1363da6c28aaSamw
1364da6c28aaSamw status = smb_ofile_access(sr->fid_ofile, cr, access);
1365da6c28aaSamw if (status != NT_STATUS_SUCCESS)
1366da6c28aaSamw return (EACCES);
1367da6c28aaSamw
1368c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree,
1369c8ec8eeaSjose borrego SMB_TREE_ACEMASKONACCESS))
1370da6c28aaSamw flags = ATTR_NOACLCHECK;
1371da6c28aaSamw }
1372da6c28aaSamw
1373da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode);
1374da6c28aaSamw
1375da6c28aaSamw if (unnamed_node) {
1376da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1377da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1378da6c28aaSamw unnamed_vp = unnamed_node->vp;
1379da6c28aaSamw }
1380da6c28aaSamw
13819660e5cbSJanice Chang rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr);
1382da6c28aaSamw return (rc);
1383da6c28aaSamw }
1384da6c28aaSamw
1385da6c28aaSamw /*
1386a90cf9f2SGordon Ross * Support for SMB2 setinfo FileValidDataLengthInformation.
138755f0a249SGordon Ross * Free (zero out) data in the range off, off+len
1388a90cf9f2SGordon Ross */
1389a90cf9f2SGordon Ross int
smb_fsop_freesp(smb_request_t * sr,cred_t * cr,smb_ofile_t * ofile,off64_t off,off64_t len)139055f0a249SGordon Ross smb_fsop_freesp(
1391a90cf9f2SGordon Ross smb_request_t *sr,
1392a90cf9f2SGordon Ross cred_t *cr,
139355f0a249SGordon Ross smb_ofile_t *ofile,
139455f0a249SGordon Ross off64_t off,
139555f0a249SGordon Ross off64_t len)
1396a90cf9f2SGordon Ross {
1397a90cf9f2SGordon Ross flock64_t flk;
139855f0a249SGordon Ross smb_node_t *node = ofile->f_node;
1399a90cf9f2SGordon Ross uint32_t status;
1400a90cf9f2SGordon Ross uint32_t access = FILE_WRITE_DATA;
1401a90cf9f2SGordon Ross int rc;
1402a90cf9f2SGordon Ross
1403a90cf9f2SGordon Ross ASSERT(cr);
1404a90cf9f2SGordon Ross ASSERT(node);
1405a90cf9f2SGordon Ross ASSERT(node->n_magic == SMB_NODE_MAGIC);
1406a90cf9f2SGordon Ross ASSERT(node->n_state != SMB_NODE_STATE_DESTROYING);
1407a90cf9f2SGordon Ross
1408a90cf9f2SGordon Ross if (SMB_TREE_CONTAINS_NODE(sr, node) == 0)
1409a90cf9f2SGordon Ross return (EACCES);
1410a90cf9f2SGordon Ross
1411a90cf9f2SGordon Ross if (SMB_TREE_IS_READONLY(sr))
1412a90cf9f2SGordon Ross return (EROFS);
1413a90cf9f2SGordon Ross
1414a90cf9f2SGordon Ross if (SMB_TREE_HAS_ACCESS(sr, access) == 0)
1415a90cf9f2SGordon Ross return (EACCES);
1416a90cf9f2SGordon Ross
1417a90cf9f2SGordon Ross /*
1418a90cf9f2SGordon Ross * SMB checks access on open and retains an access granted
1419a90cf9f2SGordon Ross * mask for use while the file is open. ACL changes should
1420a90cf9f2SGordon Ross * not affect access to an open file.
1421a90cf9f2SGordon Ross *
1422a90cf9f2SGordon Ross * If the setattr is being performed on an ofile:
1423a90cf9f2SGordon Ross * - Check the ofile's access granted mask to see if this
1424a90cf9f2SGordon Ross * modification should be permitted (FILE_WRITE_DATA)
1425a90cf9f2SGordon Ross */
1426a90cf9f2SGordon Ross status = smb_ofile_access(sr->fid_ofile, cr, access);
1427a90cf9f2SGordon Ross if (status != NT_STATUS_SUCCESS)
1428a90cf9f2SGordon Ross return (EACCES);
1429a90cf9f2SGordon Ross
1430a90cf9f2SGordon Ross bzero(&flk, sizeof (flk));
143155f0a249SGordon Ross flk.l_start = off;
143255f0a249SGordon Ross flk.l_len = len;
1433a90cf9f2SGordon Ross
1434a90cf9f2SGordon Ross rc = smb_vop_space(node->vp, F_FREESP, &flk, FWRITE, 0LL, cr);
1435a90cf9f2SGordon Ross return (rc);
1436a90cf9f2SGordon Ross }
1437a90cf9f2SGordon Ross
1438a90cf9f2SGordon Ross /*
1439da6c28aaSamw * smb_fsop_read
1440da6c28aaSamw *
1441da6c28aaSamw * All SMB functions should use this wrapper to ensure that
1442da6c28aaSamw * the the calls are performed with the appropriate credentials.
1443da6c28aaSamw * Please document any direct call to explain the reason
1444da6c28aaSamw * for avoiding this wrapper.
1445da6c28aaSamw *
1446da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine.
144755f0a249SGordon Ross * Note that ofile may be different from sr->fid_ofile, or may be NULL.
1448da6c28aaSamw */
1449da6c28aaSamw int
smb_fsop_read(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_ofile_t * ofile,uio_t * uio,int ioflag)145055f0a249SGordon Ross smb_fsop_read(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1451dfa42fabSMatt Barden smb_ofile_t *ofile, uio_t *uio, int ioflag)
1452da6c28aaSamw {
1453c8ec8eeaSjose borrego caller_context_t ct;
14548622ec45SGordon Ross cred_t *kcr = zone_kcred();
145555f0a249SGordon Ross uint32_t amask;
1456dc20a302Sas200622 int svmand;
1457da6c28aaSamw int rc;
1458da6c28aaSamw
1459da6c28aaSamw ASSERT(cr);
1460da6c28aaSamw ASSERT(snode);
1461da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1462da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1463da6c28aaSamw
1464da6c28aaSamw ASSERT(sr);
1465da6c28aaSamw
146655f0a249SGordon Ross if (ofile != NULL) {
146755f0a249SGordon Ross /*
146855f0a249SGordon Ross * Check tree access. Not SMB_TREE_HAS_ACCESS
146955f0a249SGordon Ross * because we need to use ofile->f_tree
147055f0a249SGordon Ross */
147155f0a249SGordon Ross if ((ofile->f_tree->t_access & ACE_READ_DATA) == 0)
1472743a77edSAlan Wright return (EACCES);
1473743a77edSAlan Wright
147455f0a249SGordon Ross /*
147555f0a249SGordon Ross * Check ofile access. Use in-line smb_ofile_access
147655f0a249SGordon Ross * so we can check both amask bits at the same time.
147755f0a249SGordon Ross * If any bit in amask is granted, allow this read.
147855f0a249SGordon Ross */
147955f0a249SGordon Ross amask = FILE_READ_DATA;
148055f0a249SGordon Ross if (sr->smb_flg2 & SMB_FLAGS2_READ_IF_EXECUTE)
148155f0a249SGordon Ross amask |= FILE_EXECUTE;
148255f0a249SGordon Ross if (cr != kcr && (ofile->f_granted_access & amask) == 0)
1483da6c28aaSamw return (EACCES);
148455f0a249SGordon Ross }
1485da6c28aaSamw
1486da6c28aaSamw /*
1487da6c28aaSamw * Streams permission are checked against the unnamed stream,
1488da6c28aaSamw * but in FS level they have their own permissions. To avoid
1489da6c28aaSamw * rejection by FS due to lack of permission on the actual
1490da6c28aaSamw * extended attr kcred is passed for streams.
1491da6c28aaSamw */
1492037cac00Sjoyce mcintosh if (SMB_IS_STREAM(snode))
14938622ec45SGordon Ross cr = kcr;
1494da6c28aaSamw
1495dc20a302Sas200622 smb_node_start_crit(snode, RW_READER);
14968622ec45SGordon Ross rc = nbl_svmand(snode->vp, kcr, &svmand);
1497dc20a302Sas200622 if (rc) {
1498dc20a302Sas200622 smb_node_end_crit(snode);
1499dc20a302Sas200622 return (rc);
1500dc20a302Sas200622 }
1501da6c28aaSamw
15020897f7fbSGordon Ross /*
15030897f7fbSGordon Ross * Note: SMB allows a zero-byte read, which should not
15040897f7fbSGordon Ross * conflict with any locks. However nbl_lock_conflict
15050897f7fbSGordon Ross * takes a zero-byte length as lock to EOF, so we must
15060897f7fbSGordon Ross * special case that here.
15070897f7fbSGordon Ross */
15080897f7fbSGordon Ross if (uio->uio_resid > 0) {
1509c8ec8eeaSjose borrego ct = smb_ct;
151055f0a249SGordon Ross if (ofile != NULL)
151155f0a249SGordon Ross ct.cc_pid = ofile->f_uniqid;
1512dc20a302Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset,
15130897f7fbSGordon Ross uio->uio_resid, svmand, &ct);
15140897f7fbSGordon Ross if (rc != 0) {
1515dc20a302Sas200622 smb_node_end_crit(snode);
15166537f381Sas200622 return (ERANGE);
1517dc20a302Sas200622 }
15180897f7fbSGordon Ross }
1519037cac00Sjoyce mcintosh
1520dfa42fabSMatt Barden rc = smb_vop_read(snode->vp, uio, ioflag, cr);
1521dc20a302Sas200622 smb_node_end_crit(snode);
1522da6c28aaSamw
1523da6c28aaSamw return (rc);
1524da6c28aaSamw }
1525da6c28aaSamw
1526da6c28aaSamw /*
1527da6c28aaSamw * smb_fsop_write
1528da6c28aaSamw *
1529da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine.
153055f0a249SGordon Ross * Note that ofile may be different from sr->fid_ofile, or may be NULL.
1531da6c28aaSamw */
1532da6c28aaSamw int
smb_fsop_write(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_ofile_t * ofile,uio_t * uio,uint32_t * lcount,int ioflag)1533da6c28aaSamw smb_fsop_write(
1534faa1795aSjb150015 smb_request_t *sr,
1535da6c28aaSamw cred_t *cr,
1536da6c28aaSamw smb_node_t *snode,
153755f0a249SGordon Ross smb_ofile_t *ofile,
1538da6c28aaSamw uio_t *uio,
1539da6c28aaSamw uint32_t *lcount,
15403db3f65cSamw int ioflag)
1541da6c28aaSamw {
1542c8ec8eeaSjose borrego caller_context_t ct;
15435fd03bc0SGordon Ross smb_attr_t attr;
154455f0a249SGordon Ross cred_t *kcr = zone_kcred();
15455fd03bc0SGordon Ross smb_node_t *u_node;
15465fd03bc0SGordon Ross vnode_t *u_vp = NULL;
15475fd03bc0SGordon Ross vnode_t *vp;
154855f0a249SGordon Ross uint32_t amask;
1549dc20a302Sas200622 int svmand;
1550da6c28aaSamw int rc;
1551da6c28aaSamw
1552da6c28aaSamw ASSERT(cr);
1553da6c28aaSamw ASSERT(snode);
1554da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1555da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1556da6c28aaSamw
1557da6c28aaSamw ASSERT(sr);
15585fd03bc0SGordon Ross vp = snode->vp;
1559da6c28aaSamw
156055f0a249SGordon Ross if (ofile != NULL) {
156155f0a249SGordon Ross amask = FILE_WRITE_DATA | FILE_APPEND_DATA;
156255f0a249SGordon Ross
156355f0a249SGordon Ross /* Check tree access. */
156455f0a249SGordon Ross if ((ofile->f_tree->t_access & amask) == 0)
1565da6c28aaSamw return (EROFS);
1566dc20a302Sas200622
156755f0a249SGordon Ross /*
156855f0a249SGordon Ross * Check ofile access. Use in-line smb_ofile_access
156955f0a249SGordon Ross * so we can check both amask bits at the same time.
157055f0a249SGordon Ross * If any bit in amask is granted, allow this write.
157155f0a249SGordon Ross */
157255f0a249SGordon Ross if (cr != kcr && (ofile->f_granted_access & amask) == 0)
1573da6c28aaSamw return (EACCES);
1574dc20a302Sas200622 }
1575da6c28aaSamw
1576da6c28aaSamw /*
1577da6c28aaSamw * Streams permission are checked against the unnamed stream,
1578da6c28aaSamw * but in FS level they have their own permissions. To avoid
1579da6c28aaSamw * rejection by FS due to lack of permission on the actual
1580da6c28aaSamw * extended attr kcred is passed for streams.
1581da6c28aaSamw */
15825fd03bc0SGordon Ross u_node = SMB_IS_STREAM(snode);
15835fd03bc0SGordon Ross if (u_node != NULL) {
15845fd03bc0SGordon Ross ASSERT(u_node->n_magic == SMB_NODE_MAGIC);
15855fd03bc0SGordon Ross ASSERT(u_node->n_state != SMB_NODE_STATE_DESTROYING);
15865fd03bc0SGordon Ross u_vp = u_node->vp;
15878622ec45SGordon Ross cr = kcr;
15885fd03bc0SGordon Ross }
1589da6c28aaSamw
1590f74a127fSGordon Ross smb_node_start_crit(snode, RW_READER);
15918622ec45SGordon Ross rc = nbl_svmand(vp, kcr, &svmand);
1592dc20a302Sas200622 if (rc) {
1593dc20a302Sas200622 smb_node_end_crit(snode);
1594dc20a302Sas200622 return (rc);
1595dc20a302Sas200622 }
1596c8ec8eeaSjose borrego
15970897f7fbSGordon Ross /*
15980897f7fbSGordon Ross * Note: SMB allows a zero-byte write, which should not
15990897f7fbSGordon Ross * conflict with any locks. However nbl_lock_conflict
16000897f7fbSGordon Ross * takes a zero-byte length as lock to EOF, so we must
16010897f7fbSGordon Ross * special case that here.
16020897f7fbSGordon Ross */
16030897f7fbSGordon Ross if (uio->uio_resid > 0) {
1604c8ec8eeaSjose borrego ct = smb_ct;
160555f0a249SGordon Ross if (ofile != NULL)
160655f0a249SGordon Ross ct.cc_pid = ofile->f_uniqid;
16075fd03bc0SGordon Ross rc = nbl_lock_conflict(vp, NBL_WRITE, uio->uio_loffset,
16080897f7fbSGordon Ross uio->uio_resid, svmand, &ct);
16090897f7fbSGordon Ross if (rc != 0) {
1610dc20a302Sas200622 smb_node_end_crit(snode);
16116537f381Sas200622 return (ERANGE);
1612dc20a302Sas200622 }
16130897f7fbSGordon Ross }
1614037cac00Sjoyce mcintosh
16155fd03bc0SGordon Ross rc = smb_vop_write(vp, uio, ioflag, lcount, cr);
16165fd03bc0SGordon Ross
16175fd03bc0SGordon Ross /*
16185fd03bc0SGordon Ross * Once the mtime has been set via this ofile, the
16195fd03bc0SGordon Ross * automatic mtime changes from writes via this ofile
16205fd03bc0SGordon Ross * should cease, preserving the mtime that was set.
16215fd03bc0SGordon Ross * See: [MS-FSA] 2.1.5.14 and smb_node_setattr.
16225fd03bc0SGordon Ross *
16235fd03bc0SGordon Ross * The VFS interface does not offer a way to ask it to
16245fd03bc0SGordon Ross * skip the mtime updates, so we simulate the desired
16255fd03bc0SGordon Ross * behavior by re-setting the mtime after writes on a
16265fd03bc0SGordon Ross * handle where the mtime has been set.
16275fd03bc0SGordon Ross */
162855f0a249SGordon Ross if (ofile != NULL &&
162955f0a249SGordon Ross (ofile->f_pending_attr.sa_mask & SMB_AT_MTIME) != 0) {
163055f0a249SGordon Ross bcopy(&ofile->f_pending_attr, &attr, sizeof (attr));
16315fd03bc0SGordon Ross attr.sa_mask = SMB_AT_MTIME;
16328622ec45SGordon Ross (void) smb_vop_setattr(vp, u_vp, &attr, 0, kcr);
16335fd03bc0SGordon Ross }
16345fd03bc0SGordon Ross
1635dc20a302Sas200622 smb_node_end_crit(snode);
1636da6c28aaSamw
1637da6c28aaSamw return (rc);
1638da6c28aaSamw }
1639da6c28aaSamw
1640*8b01ef7eSGordon Ross
1641*8b01ef7eSGordon Ross /*
1642*8b01ef7eSGordon Ross * Support for zero-copy read/write
1643*8b01ef7eSGordon Ross * Request buffers and return them.
1644*8b01ef7eSGordon Ross *
1645*8b01ef7eSGordon Ross * Unlike other fsop functions, these two do NOT include the SR
1646*8b01ef7eSGordon Ross * because the lifetime of the loaned buffers could eventually
1647*8b01ef7eSGordon Ross * extend beyond the life of the smb_request_t that used them.
1648*8b01ef7eSGordon Ross */
1649*8b01ef7eSGordon Ross int
smb_fsop_reqzcbuf(smb_node_t * node,xuio_t * xuio,int ioflag,cred_t * cr)1650*8b01ef7eSGordon Ross smb_fsop_reqzcbuf(smb_node_t *node, xuio_t *xuio, int ioflag, cred_t *cr)
1651*8b01ef7eSGordon Ross {
1652*8b01ef7eSGordon Ross return (smb_vop_reqzcbuf(node->vp, ioflag, xuio, cr));
1653*8b01ef7eSGordon Ross }
1654*8b01ef7eSGordon Ross
1655*8b01ef7eSGordon Ross int
smb_fsop_retzcbuf(smb_node_t * node,xuio_t * xuio,cred_t * cr)1656*8b01ef7eSGordon Ross smb_fsop_retzcbuf(smb_node_t *node, xuio_t *xuio, cred_t *cr)
1657*8b01ef7eSGordon Ross {
1658*8b01ef7eSGordon Ross return (smb_vop_retzcbuf(node->vp, xuio, cr));
1659*8b01ef7eSGordon Ross }
1660*8b01ef7eSGordon Ross
1661da6c28aaSamw /*
166255f0a249SGordon Ross * Find the next allocated range starting at or after
166355f0a249SGordon Ross * the offset (*datap), returning the start/end of
166455f0a249SGordon Ross * that range in (*datap, *holep)
166555f0a249SGordon Ross */
166655f0a249SGordon Ross int
smb_fsop_next_alloc_range(cred_t * cr,smb_node_t * node,off64_t * datap,off64_t * holep)166755f0a249SGordon Ross smb_fsop_next_alloc_range(
166855f0a249SGordon Ross cred_t *cr,
166955f0a249SGordon Ross smb_node_t *node,
167055f0a249SGordon Ross off64_t *datap,
167155f0a249SGordon Ross off64_t *holep)
167255f0a249SGordon Ross {
167355f0a249SGordon Ross int err;
167455f0a249SGordon Ross
167555f0a249SGordon Ross err = smb_vop_ioctl(node->vp, _FIO_SEEK_DATA, datap, cr);
167655f0a249SGordon Ross if (err != 0)
167755f0a249SGordon Ross return (err);
167855f0a249SGordon Ross
167955f0a249SGordon Ross *holep = *datap;
168055f0a249SGordon Ross err = smb_vop_ioctl(node->vp, _FIO_SEEK_HOLE, holep, cr);
168155f0a249SGordon Ross
168255f0a249SGordon Ross return (err);
168355f0a249SGordon Ross }
168455f0a249SGordon Ross
168555f0a249SGordon Ross /*
1686da6c28aaSamw * smb_fsop_statfs
1687da6c28aaSamw *
1688da6c28aaSamw * This is a wrapper function used for stat operations.
1689da6c28aaSamw */
1690da6c28aaSamw int
smb_fsop_statfs(cred_t * cr,smb_node_t * snode,struct statvfs64 * statp)1691da6c28aaSamw smb_fsop_statfs(
1692da6c28aaSamw cred_t *cr,
1693da6c28aaSamw smb_node_t *snode,
1694da6c28aaSamw struct statvfs64 *statp)
1695da6c28aaSamw {
1696da6c28aaSamw ASSERT(cr);
1697da6c28aaSamw ASSERT(snode);
1698da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1699da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1700da6c28aaSamw
1701da6c28aaSamw return (smb_vop_statfs(snode->vp, statp, cr));
1702da6c28aaSamw }
1703da6c28aaSamw
1704da6c28aaSamw /*
1705da6c28aaSamw * smb_fsop_access
1706ee60c47bSjm199354 *
1707ee60c47bSjm199354 * Named streams do not have separate permissions from the associated
1708ee60c47bSjm199354 * unnamed stream. Thus, if node is a named stream, the permissions
1709ee60c47bSjm199354 * check will be performed on the associated unnamed stream.
1710ee60c47bSjm199354 *
1711ee60c47bSjm199354 * However, our named streams do have their own quarantine attribute,
1712ee60c47bSjm199354 * separate from that on the unnamed stream. If READ or EXECUTE
1713ee60c47bSjm199354 * access has been requested on a named stream, an additional access
1714ee60c47bSjm199354 * check is performed on the named stream in case it has been
1715ee60c47bSjm199354 * quarantined. kcred is used to avoid issues with the permissions
1716ee60c47bSjm199354 * set on the extended attribute file representing the named stream.
17178d94f651SGordon Ross *
17188d94f651SGordon Ross * Note that some stream "types" are "restricted" and only
17198d94f651SGordon Ross * internal callers (cr == kcred) can access those.
1720da6c28aaSamw */
1721da6c28aaSamw int
smb_fsop_access(smb_request_t * sr,cred_t * cr,smb_node_t * snode,uint32_t faccess)1722da6c28aaSamw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1723da6c28aaSamw uint32_t faccess)
1724da6c28aaSamw {
1725da6c28aaSamw int access = 0;
1726da6c28aaSamw int error;
1727da6c28aaSamw vnode_t *dir_vp;
1728da6c28aaSamw boolean_t acl_check = B_TRUE;
1729da6c28aaSamw smb_node_t *unnamed_node;
1730da6c28aaSamw
1731c8ec8eeaSjose borrego ASSERT(sr);
1732da6c28aaSamw ASSERT(cr);
1733da6c28aaSamw ASSERT(snode);
1734da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1735da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1736da6c28aaSamw
1737c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) {
1738da6c28aaSamw if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA|
1739da6c28aaSamw FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES|
1740da6c28aaSamw DELETE|WRITE_DAC|WRITE_OWNER)) {
1741da6c28aaSamw return (NT_STATUS_ACCESS_DENIED);
1742da6c28aaSamw }
1743da6c28aaSamw }
1744da6c28aaSamw
17459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_node_is_reparse(snode) && (faccess & DELETE))
17469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (NT_STATUS_ACCESS_DENIED);
17479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
1748da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode);
1749da6c28aaSamw if (unnamed_node) {
17508d94f651SGordon Ross cred_t *kcr = zone_kcred();
17518d94f651SGordon Ross
1752da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1753da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1754ee60c47bSjm199354
17558d94f651SGordon Ross if (cr != kcr && smb_strname_restricted(snode->od_name))
17568d94f651SGordon Ross return (NT_STATUS_ACCESS_DENIED);
17578d94f651SGordon Ross
1758ee60c47bSjm199354 /*
1759ee60c47bSjm199354 * Perform VREAD access check on the named stream in case it
1760ee60c47bSjm199354 * is quarantined. kcred is passed to smb_vop_access so it
1761ee60c47bSjm199354 * doesn't fail due to lack of permission.
1762ee60c47bSjm199354 */
1763ee60c47bSjm199354 if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) {
1764ee60c47bSjm199354 error = smb_vop_access(snode->vp, VREAD,
17658d94f651SGordon Ross 0, NULL, kcr);
1766ee60c47bSjm199354 if (error)
1767ee60c47bSjm199354 return (NT_STATUS_ACCESS_DENIED);
1768ee60c47bSjm199354 }
1769ee60c47bSjm199354
1770da6c28aaSamw /*
1771da6c28aaSamw * Streams authorization should be performed against the
1772da6c28aaSamw * unnamed stream.
1773da6c28aaSamw */
1774da6c28aaSamw snode = unnamed_node;
1775da6c28aaSamw }
1776da6c28aaSamw
1777da6c28aaSamw if (faccess & ACCESS_SYSTEM_SECURITY) {
1778da6c28aaSamw /*
1779da6c28aaSamw * This permission is required for reading/writing SACL and
1780da6c28aaSamw * it's not part of DACL. It's only granted via proper
1781da6c28aaSamw * privileges.
1782da6c28aaSamw */
17839e3ab9e9SMatt Barden if (!smb_user_has_security_priv(sr->uid_user, cr))
1784da6c28aaSamw return (NT_STATUS_PRIVILEGE_NOT_HELD);
1785da6c28aaSamw
1786da6c28aaSamw faccess &= ~ACCESS_SYSTEM_SECURITY;
1787da6c28aaSamw }
1788da6c28aaSamw
1789da6c28aaSamw /* Links don't have ACL */
1790c8ec8eeaSjose borrego if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) ||
17919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_symlink(snode))
1792da6c28aaSamw acl_check = B_FALSE;
1793da6c28aaSamw
1794cb174861Sjoyce mcintosh /* Deny access based on the share access mask */
1795cb174861Sjoyce mcintosh
1796cb174861Sjoyce mcintosh if ((faccess & ~sr->tid_tree->t_access) != 0)
1797cb174861Sjoyce mcintosh return (NT_STATUS_ACCESS_DENIED);
1798743a77edSAlan Wright
1799da6c28aaSamw if (acl_check) {
18001fcced4cSJordan Brown dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
1801da6c28aaSamw error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp,
1802da6c28aaSamw cr);
1803da6c28aaSamw } else {
1804da6c28aaSamw /*
1805da6c28aaSamw * FS doesn't understand 32-bit mask, need to map
1806da6c28aaSamw */
1807da6c28aaSamw if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))
1808da6c28aaSamw access |= VWRITE;
1809da6c28aaSamw
1810da6c28aaSamw if (faccess & FILE_READ_DATA)
1811da6c28aaSamw access |= VREAD;
1812da6c28aaSamw
1813da6c28aaSamw if (faccess & FILE_EXECUTE)
1814da6c28aaSamw access |= VEXEC;
1815da6c28aaSamw
1816da6c28aaSamw error = smb_vop_access(snode->vp, access, 0, NULL, cr);
1817da6c28aaSamw }
1818da6c28aaSamw
1819da6c28aaSamw return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS);
1820da6c28aaSamw }
1821da6c28aaSamw
1822da6c28aaSamw /*
1823da6c28aaSamw * smb_fsop_lookup_name()
1824da6c28aaSamw *
18250a73e6f9SMatt Barden * Lookup both the file and stream specified in 'name'.
1826b89a8333Snatalie li - Sun Microsystems - Irvine United States * If name indicates that the file is a stream file, perform
1827b89a8333Snatalie li - Sun Microsystems - Irvine United States * stream specific lookup, otherwise call smb_fsop_lookup.
1828da6c28aaSamw *
18290a73e6f9SMatt Barden * On success, returns the found node in *ret_snode. This will be either a named
18300a73e6f9SMatt Barden * or unnamed stream node, depending on the name specified.
18310a73e6f9SMatt Barden *
1832b89a8333Snatalie li - Sun Microsystems - Irvine United States * Return an error if the looked-up file is in outside the tree.
1833b89a8333Snatalie li - Sun Microsystems - Irvine United States * (Required when invoked from open path.)
1834148c5f43SAlan Wright *
1835148c5f43SAlan Wright * Case sensitivity flags (SMB_IGNORE_CASE, SMB_CASE_SENSITIVE):
1836148c5f43SAlan Wright * if SMB_CASE_SENSITIVE is set, the SMB_IGNORE_CASE flag will NOT be set
1837148c5f43SAlan Wright * based on the tree's case sensitivity. However, if the SMB_IGNORE_CASE
1838148c5f43SAlan Wright * flag is set in the flags value passed as a parameter, a case insensitive
1839148c5f43SAlan Wright * lookup WILL be done (regardless of whether SMB_CASE_SENSITIVE is set
1840148c5f43SAlan Wright * or not).
1841da6c28aaSamw */
1842da6c28aaSamw
1843da6c28aaSamw int
smb_fsop_lookup_name(smb_request_t * sr,cred_t * cr,int flags,smb_node_t * root_node,smb_node_t * dnode,char * name,smb_node_t ** ret_snode)1844da6c28aaSamw smb_fsop_lookup_name(
1845faa1795aSjb150015 smb_request_t *sr,
1846da6c28aaSamw cred_t *cr,
1847da6c28aaSamw int flags,
1848da6c28aaSamw smb_node_t *root_node,
1849eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode,
1850da6c28aaSamw char *name,
1851037cac00Sjoyce mcintosh smb_node_t **ret_snode)
1852da6c28aaSamw {
18530a73e6f9SMatt Barden char *sname = NULL;
18540a73e6f9SMatt Barden int rc;
18550a73e6f9SMatt Barden smb_node_t *tmp_node;
18560a73e6f9SMatt Barden
18570a73e6f9SMatt Barden ASSERT(ret_snode != NULL);
18580a73e6f9SMatt Barden
18590a73e6f9SMatt Barden rc = smb_fsop_lookup_file(sr, cr, flags, root_node, dnode, name,
18600a73e6f9SMatt Barden &sname, ret_snode);
18610a73e6f9SMatt Barden
18620a73e6f9SMatt Barden if (rc != 0 || sname == NULL)
18630a73e6f9SMatt Barden return (rc);
18640a73e6f9SMatt Barden
18650a73e6f9SMatt Barden tmp_node = *ret_snode;
18660a73e6f9SMatt Barden rc = smb_fsop_lookup_stream(sr, cr, flags, root_node, tmp_node, sname,
18670a73e6f9SMatt Barden ret_snode);
18680a73e6f9SMatt Barden kmem_free(sname, MAXNAMELEN);
18690a73e6f9SMatt Barden smb_node_release(tmp_node);
18700a73e6f9SMatt Barden
18710a73e6f9SMatt Barden return (rc);
18720a73e6f9SMatt Barden }
18730a73e6f9SMatt Barden
18740a73e6f9SMatt Barden /*
18750a73e6f9SMatt Barden * smb_fsop_lookup_file()
18760a73e6f9SMatt Barden *
18770a73e6f9SMatt Barden * Look up of the file portion of 'name'. If a Stream is specified,
18780a73e6f9SMatt Barden * return the stream name in 'sname', which this allocates.
18790a73e6f9SMatt Barden * The caller must free 'sname'.
18800a73e6f9SMatt Barden *
18810a73e6f9SMatt Barden * Return an error if the looked-up file is outside the tree.
18820a73e6f9SMatt Barden * (Required when invoked from open path.)
18830a73e6f9SMatt Barden *
18840a73e6f9SMatt Barden * Case sensitivity flags (SMB_IGNORE_CASE, SMB_CASE_SENSITIVE):
18850a73e6f9SMatt Barden * if SMB_CASE_SENSITIVE is set, the SMB_IGNORE_CASE flag will NOT be set
18860a73e6f9SMatt Barden * based on the tree's case sensitivity. However, if the SMB_IGNORE_CASE
18870a73e6f9SMatt Barden * flag is set in the flags value passed as a parameter, a case insensitive
18880a73e6f9SMatt Barden * lookup WILL be done (regardless of whether SMB_CASE_SENSITIVE is set
18890a73e6f9SMatt Barden * or not).
18900a73e6f9SMatt Barden */
18910a73e6f9SMatt Barden
18920a73e6f9SMatt Barden int
smb_fsop_lookup_file(smb_request_t * sr,cred_t * cr,int flags,smb_node_t * root_node,smb_node_t * dnode,char * name,char ** sname,smb_node_t ** ret_snode)18930a73e6f9SMatt Barden smb_fsop_lookup_file(
18940a73e6f9SMatt Barden smb_request_t *sr,
18950a73e6f9SMatt Barden cred_t *cr,
18960a73e6f9SMatt Barden int flags,
18970a73e6f9SMatt Barden smb_node_t *root_node,
18980a73e6f9SMatt Barden smb_node_t *dnode,
18990a73e6f9SMatt Barden char *name,
19000a73e6f9SMatt Barden char **sname,
19010a73e6f9SMatt Barden smb_node_t **ret_snode)
19020a73e6f9SMatt Barden {
1903da6c28aaSamw char *fname;
1904da6c28aaSamw int rc;
1905da6c28aaSamw
1906da6c28aaSamw ASSERT(cr);
1907eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode);
1908eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
1909eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
19100a73e6f9SMatt Barden ASSERT(ret_snode != NULL);
1911da6c28aaSamw
1912da6c28aaSamw /*
1913da6c28aaSamw * The following check is required for streams processing, below
1914da6c28aaSamw */
1915da6c28aaSamw
1916148c5f43SAlan Wright if (!(flags & SMB_CASE_SENSITIVE)) {
1917c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1918da6c28aaSamw flags |= SMB_IGNORE_CASE;
1919148c5f43SAlan Wright }
1920da6c28aaSamw
19210a73e6f9SMatt Barden *sname = NULL;
1922eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (smb_is_stream_name(name)) {
19230a73e6f9SMatt Barden *sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
19240a73e6f9SMatt Barden fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
19250a73e6f9SMatt Barden smb_stream_parse_name(name, fname, *sname);
19268d7e4166Sjose borrego
1927da6c28aaSamw /*
1928da6c28aaSamw * Look up the unnamed stream (i.e. fname).
1929da6c28aaSamw * Unmangle processing will be done on fname
1930da6c28aaSamw * as well as any link target.
1931da6c28aaSamw */
1932037cac00Sjoyce mcintosh rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode,
19330a73e6f9SMatt Barden fname, ret_snode);
1934da6c28aaSamw kmem_free(fname, MAXNAMELEN);
1935da6c28aaSamw } else {
1936eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, name,
1937037cac00Sjoyce mcintosh ret_snode);
1938da6c28aaSamw }
1939da6c28aaSamw
1940da6c28aaSamw if (rc == 0) {
1941da6c28aaSamw ASSERT(ret_snode);
1942c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) {
1943da6c28aaSamw smb_node_release(*ret_snode);
1944da6c28aaSamw *ret_snode = NULL;
1945da6c28aaSamw rc = EACCES;
1946da6c28aaSamw }
1947da6c28aaSamw }
1948da6c28aaSamw
19490a73e6f9SMatt Barden if (rc != 0 && *sname != NULL) {
19500a73e6f9SMatt Barden kmem_free(*sname, MAXNAMELEN);
19510a73e6f9SMatt Barden *sname = NULL;
19520a73e6f9SMatt Barden }
19530a73e6f9SMatt Barden return (rc);
19540a73e6f9SMatt Barden }
19550a73e6f9SMatt Barden
19560a73e6f9SMatt Barden /*
19570a73e6f9SMatt Barden * smb_fsop_lookup_stream
19580a73e6f9SMatt Barden *
19590a73e6f9SMatt Barden * The file exists, see if the stream exists.
19600a73e6f9SMatt Barden */
19610a73e6f9SMatt Barden int
smb_fsop_lookup_stream(smb_request_t * sr,cred_t * cr,int flags,smb_node_t * root_node,smb_node_t * fnode,char * sname,smb_node_t ** ret_snode)19620a73e6f9SMatt Barden smb_fsop_lookup_stream(
19630a73e6f9SMatt Barden smb_request_t *sr,
19640a73e6f9SMatt Barden cred_t *cr,
19650a73e6f9SMatt Barden int flags,
19660a73e6f9SMatt Barden smb_node_t *root_node,
19670a73e6f9SMatt Barden smb_node_t *fnode,
19680a73e6f9SMatt Barden char *sname,
19690a73e6f9SMatt Barden smb_node_t **ret_snode)
19700a73e6f9SMatt Barden {
19710a73e6f9SMatt Barden char *od_name;
19720a73e6f9SMatt Barden vnode_t *xattrdirvp;
19730a73e6f9SMatt Barden vnode_t *vp;
19740a73e6f9SMatt Barden int rc;
19750a73e6f9SMatt Barden
19760a73e6f9SMatt Barden /*
19770a73e6f9SMatt Barden * The following check is required for streams processing, below
19780a73e6f9SMatt Barden */
19790a73e6f9SMatt Barden
19800a73e6f9SMatt Barden if (!(flags & SMB_CASE_SENSITIVE)) {
19810a73e6f9SMatt Barden if (SMB_TREE_IS_CASEINSENSITIVE(sr))
19820a73e6f9SMatt Barden flags |= SMB_IGNORE_CASE;
19830a73e6f9SMatt Barden }
19840a73e6f9SMatt Barden
19850a73e6f9SMatt Barden od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
19860a73e6f9SMatt Barden
19870a73e6f9SMatt Barden /*
19880a73e6f9SMatt Barden * od_name is the on-disk name of the stream, except
19890a73e6f9SMatt Barden * without the prepended stream prefix (SMB_STREAM_PREFIX)
19900a73e6f9SMatt Barden */
19910a73e6f9SMatt Barden
19920a73e6f9SMatt Barden rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name,
19930a73e6f9SMatt Barden &xattrdirvp, flags, root_node->vp, cr);
19940a73e6f9SMatt Barden
19950a73e6f9SMatt Barden if (rc != 0) {
19960a73e6f9SMatt Barden kmem_free(od_name, MAXNAMELEN);
19970a73e6f9SMatt Barden return (rc);
19980a73e6f9SMatt Barden }
19990a73e6f9SMatt Barden
20000a73e6f9SMatt Barden *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
20010a73e6f9SMatt Barden vp, od_name);
20020a73e6f9SMatt Barden
20030a73e6f9SMatt Barden kmem_free(od_name, MAXNAMELEN);
20040a73e6f9SMatt Barden VN_RELE(xattrdirvp);
20050a73e6f9SMatt Barden VN_RELE(vp);
20060a73e6f9SMatt Barden
20070a73e6f9SMatt Barden if (*ret_snode == NULL)
20080a73e6f9SMatt Barden return (ENOMEM);
2009da6c28aaSamw
2010da6c28aaSamw return (rc);
2011da6c28aaSamw }
2012da6c28aaSamw
2013da6c28aaSamw /*
2014da6c28aaSamw * smb_fsop_lookup
2015da6c28aaSamw *
2016da6c28aaSamw * All SMB functions should use this smb_vop_lookup wrapper to ensure that
2017da6c28aaSamw * the smb_vop_lookup is performed with the appropriate credentials and using
2018da6c28aaSamw * case insensitive compares. Please document any direct call to smb_vop_lookup
2019da6c28aaSamw * to explain the reason for avoiding this wrapper.
2020da6c28aaSamw *
2021eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * It is assumed that a reference exists on dnode coming into this routine
2022da6c28aaSamw * (and that it is safe from deallocation).
2023da6c28aaSamw *
2024da6c28aaSamw * Same with the root_node.
2025da6c28aaSamw *
2026da6c28aaSamw * *ret_snode is returned with a reference upon success. No reference is
2027da6c28aaSamw * taken if an error is returned.
2028da6c28aaSamw *
2029da6c28aaSamw * Note: The returned ret_snode may be in a child mount. This is ok for
20307f667e74Sjose borrego * readdir.
2031da6c28aaSamw *
2032c8ec8eeaSjose borrego * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent
2033da6c28aaSamw * operations on files not in the parent mount.
2034bbf6f00cSJordan Brown *
2035bbf6f00cSJordan Brown * Case sensitivity flags (SMB_IGNORE_CASE, SMB_CASE_SENSITIVE):
2036bbf6f00cSJordan Brown * if SMB_CASE_SENSITIVE is set, the SMB_IGNORE_CASE flag will NOT be set
2037bbf6f00cSJordan Brown * based on the tree's case sensitivity. However, if the SMB_IGNORE_CASE
2038bbf6f00cSJordan Brown * flag is set in the flags value passed as a parameter, a case insensitive
2039bbf6f00cSJordan Brown * lookup WILL be done (regardless of whether SMB_CASE_SENSITIVE is set
2040bbf6f00cSJordan Brown * or not).
2041da6c28aaSamw */
2042da6c28aaSamw int
smb_fsop_lookup(smb_request_t * sr,cred_t * cr,int flags,smb_node_t * root_node,smb_node_t * dnode,char * name,smb_node_t ** ret_snode)2043da6c28aaSamw smb_fsop_lookup(
2044faa1795aSjb150015 smb_request_t *sr,
2045da6c28aaSamw cred_t *cr,
2046da6c28aaSamw int flags,
2047da6c28aaSamw smb_node_t *root_node,
2048eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode,
2049da6c28aaSamw char *name,
2050037cac00Sjoyce mcintosh smb_node_t **ret_snode)
2051da6c28aaSamw {
2052da6c28aaSamw smb_node_t *lnk_target_node;
2053da6c28aaSamw smb_node_t *lnk_dnode;
2054da6c28aaSamw char *longname;
2055da6c28aaSamw char *od_name;
2056da6c28aaSamw vnode_t *vp;
2057da6c28aaSamw int rc;
20588b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States int ret_flags;
20599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_attr_t attr;
2060da6c28aaSamw
2061da6c28aaSamw ASSERT(cr);
2062eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode);
2063eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
2064eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
2065da6c28aaSamw
2066da6c28aaSamw if (name == NULL)
2067da6c28aaSamw return (EINVAL);
2068da6c28aaSamw
2069eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
2070da6c28aaSamw return (EACCES);
2071da6c28aaSamw
2072bbf6f00cSJordan Brown if (!(flags & SMB_CASE_SENSITIVE)) {
2073c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr))
2074da6c28aaSamw flags |= SMB_IGNORE_CASE;
2075bbf6f00cSJordan Brown }
20768b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr))
20778b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA;
2078e3f2c991SKeyur Desai if (SMB_TREE_SUPPORTS_ABE(sr))
2079e3f2c991SKeyur Desai flags |= SMB_ABE;
2080da6c28aaSamw
2081d082c877SGordon Ross /*
2082d082c877SGordon Ross * Can have "" or "." when opening named streams on a directory.
2083d082c877SGordon Ross */
2084d082c877SGordon Ross if (name[0] == '\0' || (name[0] == '.' && name[1] == '\0')) {
2085d082c877SGordon Ross smb_node_ref(dnode);
2086d082c877SGordon Ross *ret_snode = dnode;
2087d082c877SGordon Ross return (0);
2088d082c877SGordon Ross }
2089d082c877SGordon Ross
2090da6c28aaSamw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2091da6c28aaSamw
2092eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_lookup(dnode->vp, name, &vp, od_name, flags,
20939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States &ret_flags, root_node ? root_node->vp : NULL, &attr, cr);
2094da6c28aaSamw
2095da6c28aaSamw if (rc != 0) {
2096cb174861Sjoyce mcintosh if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
2097cb174861Sjoyce mcintosh !smb_maybe_mangled(name)) {
2098da6c28aaSamw kmem_free(od_name, MAXNAMELEN);
2099da6c28aaSamw return (rc);
2100da6c28aaSamw }
2101da6c28aaSamw
2102da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2103148c5f43SAlan Wright rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
2104da6c28aaSamw if (rc != 0) {
2105da6c28aaSamw kmem_free(od_name, MAXNAMELEN);
2106da6c28aaSamw kmem_free(longname, MAXNAMELEN);
2107da6c28aaSamw return (rc);
2108da6c28aaSamw }
2109da6c28aaSamw
2110da6c28aaSamw /*
21118b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * longname is the real (case-sensitive)
21128b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * on-disk name.
2113da6c28aaSamw * We make sure we do a lookup on this exact
2114da6c28aaSamw * name, as the name was mangled and denotes
2115da6c28aaSamw * a unique file.
2116da6c28aaSamw */
2117da6c28aaSamw
2118da6c28aaSamw if (flags & SMB_IGNORE_CASE)
2119da6c28aaSamw flags &= ~SMB_IGNORE_CASE;
2120da6c28aaSamw
2121eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_lookup(dnode->vp, longname, &vp, od_name,
21229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States flags, &ret_flags, root_node ? root_node->vp : NULL, &attr,
21239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States cr);
2124da6c28aaSamw
2125da6c28aaSamw kmem_free(longname, MAXNAMELEN);
2126da6c28aaSamw
2127da6c28aaSamw if (rc != 0) {
2128da6c28aaSamw kmem_free(od_name, MAXNAMELEN);
2129da6c28aaSamw return (rc);
2130da6c28aaSamw }
2131da6c28aaSamw }
2132da6c28aaSamw
21339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK) &&
21349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ((attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)) {
2135eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_pathname(sr, od_name, FOLLOW, root_node, dnode,
21361bc6aeeeSMatt Barden &lnk_dnode, &lnk_target_node, cr, NULL);
2137da6c28aaSamw
2138da6c28aaSamw if (rc != 0) {
2139da6c28aaSamw /*
2140da6c28aaSamw * The link is assumed to be for the last component
2141da6c28aaSamw * of a path. Hence any ENOTDIR error will be returned
2142da6c28aaSamw * as ENOENT.
2143da6c28aaSamw */
2144da6c28aaSamw if (rc == ENOTDIR)
2145da6c28aaSamw rc = ENOENT;
2146da6c28aaSamw
2147da6c28aaSamw VN_RELE(vp);
2148da6c28aaSamw kmem_free(od_name, MAXNAMELEN);
2149da6c28aaSamw return (rc);
2150da6c28aaSamw }
2151da6c28aaSamw
2152da6c28aaSamw /*
2153da6c28aaSamw * Release the original VLNK vnode
2154da6c28aaSamw */
2155da6c28aaSamw
2156da6c28aaSamw VN_RELE(vp);
2157da6c28aaSamw vp = lnk_target_node->vp;
2158da6c28aaSamw
2159da6c28aaSamw rc = smb_vop_traverse_check(&vp);
2160da6c28aaSamw
2161da6c28aaSamw if (rc != 0) {
2162da6c28aaSamw smb_node_release(lnk_dnode);
2163da6c28aaSamw smb_node_release(lnk_target_node);
2164da6c28aaSamw kmem_free(od_name, MAXNAMELEN);
2165da6c28aaSamw return (rc);
2166da6c28aaSamw }
2167da6c28aaSamw
2168da6c28aaSamw /*
2169da6c28aaSamw * smb_vop_traverse_check() may have returned a different vnode
2170da6c28aaSamw */
2171da6c28aaSamw
2172da6c28aaSamw if (lnk_target_node->vp == vp) {
2173da6c28aaSamw *ret_snode = lnk_target_node;
2174da6c28aaSamw } else {
2175da6c28aaSamw *ret_snode = smb_node_lookup(sr, NULL, cr, vp,
2176037cac00Sjoyce mcintosh lnk_target_node->od_name, lnk_dnode, NULL);
2177da6c28aaSamw VN_RELE(vp);
21787f667e74Sjose borrego
21797f667e74Sjose borrego if (*ret_snode == NULL)
2180da6c28aaSamw rc = ENOMEM;
2181da6c28aaSamw smb_node_release(lnk_target_node);
2182da6c28aaSamw }
2183da6c28aaSamw
2184da6c28aaSamw smb_node_release(lnk_dnode);
2185da6c28aaSamw
2186da6c28aaSamw } else {
2187da6c28aaSamw
2188da6c28aaSamw rc = smb_vop_traverse_check(&vp);
2189da6c28aaSamw if (rc) {
2190da6c28aaSamw VN_RELE(vp);
2191da6c28aaSamw kmem_free(od_name, MAXNAMELEN);
2192da6c28aaSamw return (rc);
2193da6c28aaSamw }
2194da6c28aaSamw
2195da6c28aaSamw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name,
2196037cac00Sjoyce mcintosh dnode, NULL);
2197da6c28aaSamw VN_RELE(vp);
21987f667e74Sjose borrego
21997f667e74Sjose borrego if (*ret_snode == NULL)
2200da6c28aaSamw rc = ENOMEM;
2201da6c28aaSamw }
2202da6c28aaSamw
2203da6c28aaSamw kmem_free(od_name, MAXNAMELEN);
2204da6c28aaSamw return (rc);
2205da6c28aaSamw }
2206da6c28aaSamw
2207da6c28aaSamw int /*ARGSUSED*/
smb_fsop_commit(smb_request_t * sr,cred_t * cr,smb_node_t * snode)2208da6c28aaSamw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode)
2209da6c28aaSamw {
2210da6c28aaSamw ASSERT(cr);
2211da6c28aaSamw ASSERT(snode);
2212da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC);
2213da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
2214da6c28aaSamw
2215da6c28aaSamw ASSERT(sr);
2216da6c28aaSamw ASSERT(sr->tid_tree);
2217c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr))
2218da6c28aaSamw return (EROFS);
2219da6c28aaSamw
2220dc20a302Sas200622 return (smb_vop_commit(snode->vp, cr));
2221da6c28aaSamw }
2222da6c28aaSamw
2223da6c28aaSamw /*
2224da6c28aaSamw * smb_fsop_aclread
2225da6c28aaSamw *
2226da6c28aaSamw * Retrieve filesystem ACL. Depends on requested ACLs in
2227da6c28aaSamw * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in
2228da6c28aaSamw * fs_sd. Note that requesting a DACL/SACL doesn't mean that
2229da6c28aaSamw * the corresponding field in fs_sd should be non-NULL upon
2230da6c28aaSamw * return, since the target ACL might not contain that type of
2231da6c28aaSamw * entries.
2232da6c28aaSamw *
2233da6c28aaSamw * Returned ACL is always in ACE_T (aka ZFS) format.
2234da6c28aaSamw * If successful the allocated memory for the ACL should be freed
223555bf511dSas200622 * using smb_fsacl_free() or smb_fssd_term()
2236da6c28aaSamw */
2237da6c28aaSamw int
smb_fsop_aclread(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_fssd_t * fs_sd)2238da6c28aaSamw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2239da6c28aaSamw smb_fssd_t *fs_sd)
2240da6c28aaSamw {
2241da6c28aaSamw int error = 0;
2242da6c28aaSamw int flags = 0;
2243da6c28aaSamw int access = 0;
2244da6c28aaSamw acl_t *acl;
2245da6c28aaSamw
2246da6c28aaSamw ASSERT(cr);
2247da6c28aaSamw
2248245d1332SMatt Barden /* Can't query security on named streams */
2249245d1332SMatt Barden if (SMB_IS_STREAM(snode) != NULL)
2250245d1332SMatt Barden return (EINVAL);
2251245d1332SMatt Barden
2252743a77edSAlan Wright if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0)
2253743a77edSAlan Wright return (EACCES);
2254743a77edSAlan Wright
2255da6c28aaSamw if (sr->fid_ofile) {
2256da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
2257da6c28aaSamw access = READ_CONTROL;
2258da6c28aaSamw
2259da6c28aaSamw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
2260da6c28aaSamw access |= ACCESS_SYSTEM_SECURITY;
2261da6c28aaSamw
2262da6c28aaSamw error = smb_ofile_access(sr->fid_ofile, cr, access);
2263da6c28aaSamw if (error != NT_STATUS_SUCCESS) {
2264da6c28aaSamw return (EACCES);
2265da6c28aaSamw }
2266da6c28aaSamw }
2267da6c28aaSamw
2268da6c28aaSamw
2269c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS))
2270da6c28aaSamw flags = ATTR_NOACLCHECK;
2271da6c28aaSamw
2272da6c28aaSamw error = smb_vop_acl_read(snode->vp, &acl, flags,
2273dc20a302Sas200622 sr->tid_tree->t_acltype, cr);
2274da6c28aaSamw if (error != 0) {
2275da6c28aaSamw return (error);
2276da6c28aaSamw }
2277da6c28aaSamw
2278da6c28aaSamw error = acl_translate(acl, _ACL_ACE_ENABLED,
22799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_dir(snode), fs_sd->sd_uid, fs_sd->sd_gid);
2280da6c28aaSamw
2281da6c28aaSamw if (error == 0) {
228255bf511dSas200622 smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl,
2283da6c28aaSamw fs_sd->sd_secinfo);
2284da6c28aaSamw }
2285da6c28aaSamw
2286da6c28aaSamw acl_free(acl);
2287da6c28aaSamw return (error);
2288da6c28aaSamw }
2289da6c28aaSamw
2290da6c28aaSamw /*
2291da6c28aaSamw * smb_fsop_aclwrite
2292da6c28aaSamw *
2293da6c28aaSamw * Stores the filesystem ACL provided in fs_sd->sd_acl.
2294da6c28aaSamw */
2295da6c28aaSamw int
smb_fsop_aclwrite(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_fssd_t * fs_sd)2296da6c28aaSamw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2297da6c28aaSamw smb_fssd_t *fs_sd)
2298da6c28aaSamw {
2299da6c28aaSamw int target_flavor;
2300da6c28aaSamw int error = 0;
2301da6c28aaSamw int flags = 0;
2302da6c28aaSamw int access = 0;
2303da6c28aaSamw acl_t *acl, *dacl, *sacl;
2304da6c28aaSamw
2305da6c28aaSamw ASSERT(cr);
2306da6c28aaSamw
2307da6c28aaSamw ASSERT(sr);
2308da6c28aaSamw ASSERT(sr->tid_tree);
2309c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr))
2310da6c28aaSamw return (EROFS);
2311da6c28aaSamw
2312245d1332SMatt Barden /* Can't set security on named streams */
2313245d1332SMatt Barden if (SMB_IS_STREAM(snode) != NULL)
2314245d1332SMatt Barden return (EINVAL);
2315245d1332SMatt Barden
2316743a77edSAlan Wright if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0)
2317743a77edSAlan Wright return (EACCES);
2318743a77edSAlan Wright
2319da6c28aaSamw if (sr->fid_ofile) {
2320da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
2321da6c28aaSamw access = WRITE_DAC;
2322da6c28aaSamw
2323da6c28aaSamw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
2324da6c28aaSamw access |= ACCESS_SYSTEM_SECURITY;
2325da6c28aaSamw
2326da6c28aaSamw error = smb_ofile_access(sr->fid_ofile, cr, access);
2327da6c28aaSamw if (error != NT_STATUS_SUCCESS)
2328da6c28aaSamw return (EACCES);
2329da6c28aaSamw }
2330da6c28aaSamw
2331da6c28aaSamw switch (sr->tid_tree->t_acltype) {
2332da6c28aaSamw case ACLENT_T:
2333da6c28aaSamw target_flavor = _ACL_ACLENT_ENABLED;
2334da6c28aaSamw break;
2335da6c28aaSamw
2336da6c28aaSamw case ACE_T:
2337da6c28aaSamw target_flavor = _ACL_ACE_ENABLED;
2338da6c28aaSamw break;
2339da6c28aaSamw default:
2340da6c28aaSamw return (EINVAL);
2341da6c28aaSamw }
2342da6c28aaSamw
2343da6c28aaSamw dacl = fs_sd->sd_zdacl;
2344da6c28aaSamw sacl = fs_sd->sd_zsacl;
2345da6c28aaSamw
2346da6c28aaSamw ASSERT(dacl || sacl);
2347da6c28aaSamw if ((dacl == NULL) && (sacl == NULL))
2348da6c28aaSamw return (EINVAL);
2349da6c28aaSamw
2350da6c28aaSamw if (dacl && sacl)
235155bf511dSas200622 acl = smb_fsacl_merge(dacl, sacl);
2352da6c28aaSamw else if (dacl)
2353da6c28aaSamw acl = dacl;
2354da6c28aaSamw else
2355da6c28aaSamw acl = sacl;
2356da6c28aaSamw
23579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States error = acl_translate(acl, target_flavor, smb_node_is_dir(snode),
2358da6c28aaSamw fs_sd->sd_uid, fs_sd->sd_gid);
2359da6c28aaSamw if (error == 0) {
2360c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree,
2361c8ec8eeaSjose borrego SMB_TREE_ACEMASKONACCESS))
2362da6c28aaSamw flags = ATTR_NOACLCHECK;
2363da6c28aaSamw
2364dc20a302Sas200622 error = smb_vop_acl_write(snode->vp, acl, flags, cr);
236548f31ae7SGordon Ross if (error == 0 && snode->n_dnode != NULL) {
236648f31ae7SGordon Ross // FILE_NOTIFY_CHANGE_SECURITY
236748f31ae7SGordon Ross smb_node_notify_change(snode->n_dnode,
236848f31ae7SGordon Ross FILE_ACTION_MODIFIED, snode->od_name);
236948f31ae7SGordon Ross }
2370da6c28aaSamw }
2371da6c28aaSamw
2372da6c28aaSamw if (dacl && sacl)
2373da6c28aaSamw acl_free(acl);
2374da6c28aaSamw
2375da6c28aaSamw return (error);
2376da6c28aaSamw }
2377da6c28aaSamw
2378da6c28aaSamw acl_type_t
smb_fsop_acltype(smb_node_t * snode)2379da6c28aaSamw smb_fsop_acltype(smb_node_t *snode)
2380da6c28aaSamw {
2381da6c28aaSamw return (smb_vop_acl_type(snode->vp));
2382da6c28aaSamw }
2383da6c28aaSamw
2384da6c28aaSamw /*
2385da6c28aaSamw * smb_fsop_sdread
2386da6c28aaSamw *
2387da6c28aaSamw * Read the requested security descriptor items from filesystem.
2388da6c28aaSamw * The items are specified in fs_sd->sd_secinfo.
2389da6c28aaSamw */
2390da6c28aaSamw int
smb_fsop_sdread(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_fssd_t * fs_sd)2391da6c28aaSamw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2392da6c28aaSamw smb_fssd_t *fs_sd)
2393da6c28aaSamw {
2394da6c28aaSamw int error = 0;
2395da6c28aaSamw int getowner = 0;
2396da6c28aaSamw cred_t *ga_cred;
2397da6c28aaSamw smb_attr_t attr;
2398da6c28aaSamw
2399da6c28aaSamw ASSERT(cr);
2400da6c28aaSamw ASSERT(fs_sd);
2401da6c28aaSamw
2402245d1332SMatt Barden /* Can't query security on named streams */
2403245d1332SMatt Barden if (SMB_IS_STREAM(snode) != NULL)
2404245d1332SMatt Barden return (EINVAL);
2405245d1332SMatt Barden
2406da6c28aaSamw /*
2407da6c28aaSamw * File's uid/gid is fetched in two cases:
2408da6c28aaSamw *
2409da6c28aaSamw * 1. it's explicitly requested
2410da6c28aaSamw *
2411da6c28aaSamw * 2. target ACL is ACE_T (ZFS ACL). They're needed for
2412da6c28aaSamw * owner@/group@ entries. In this case kcred should be used
2413da6c28aaSamw * because uid/gid are fetched on behalf of smb server.
2414da6c28aaSamw */
2415da6c28aaSamw if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) {
2416da6c28aaSamw getowner = 1;
2417da6c28aaSamw ga_cred = cr;
2418da6c28aaSamw } else if (sr->tid_tree->t_acltype == ACE_T) {
2419da6c28aaSamw getowner = 1;
24208622ec45SGordon Ross ga_cred = zone_kcred();
2421da6c28aaSamw }
2422da6c28aaSamw
2423da6c28aaSamw if (getowner) {
2424da6c28aaSamw /*
2425da6c28aaSamw * Windows require READ_CONTROL to read owner/group SID since
2426da6c28aaSamw * they're part of Security Descriptor.
2427da6c28aaSamw * ZFS only requires read_attribute. Need to have a explicit
2428da6c28aaSamw * access check here.
2429da6c28aaSamw */
2430da6c28aaSamw if (sr->fid_ofile == NULL) {
2431da6c28aaSamw error = smb_fsop_access(sr, ga_cred, snode,
2432da6c28aaSamw READ_CONTROL);
2433da6c28aaSamw if (error)
2434b1352070SAlan Wright return (EACCES);
2435da6c28aaSamw }
2436da6c28aaSamw
2437da6c28aaSamw attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
2438da6c28aaSamw error = smb_fsop_getattr(sr, ga_cred, snode, &attr);
2439da6c28aaSamw if (error == 0) {
2440da6c28aaSamw fs_sd->sd_uid = attr.sa_vattr.va_uid;
2441da6c28aaSamw fs_sd->sd_gid = attr.sa_vattr.va_gid;
2442da6c28aaSamw } else {
2443da6c28aaSamw return (error);
2444da6c28aaSamw }
2445da6c28aaSamw }
2446da6c28aaSamw
2447da6c28aaSamw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2448da6c28aaSamw error = smb_fsop_aclread(sr, cr, snode, fs_sd);
2449da6c28aaSamw }
2450da6c28aaSamw
2451da6c28aaSamw return (error);
2452da6c28aaSamw }
2453da6c28aaSamw
2454da6c28aaSamw /*
2455da6c28aaSamw * smb_fsop_sdmerge
2456da6c28aaSamw *
2457da6c28aaSamw * From SMB point of view DACL and SACL are two separate list
2458da6c28aaSamw * which can be manipulated independently without one affecting
2459da6c28aaSamw * the other, but entries for both DACL and SACL will end up
2460da6c28aaSamw * in the same ACL if target filesystem supports ACE_T ACLs.
2461da6c28aaSamw *
2462da6c28aaSamw * So, if either DACL or SACL is present in the client set request
2463da6c28aaSamw * the entries corresponding to the non-present ACL shouldn't
2464da6c28aaSamw * be touched in the FS ACL.
2465da6c28aaSamw *
2466da6c28aaSamw * fs_sd parameter contains DACL and SACL specified by SMB
2467da6c28aaSamw * client to be set on a file/directory. The client could
2468da6c28aaSamw * specify both or one of these ACLs (if none is specified
2469da6c28aaSamw * we don't get this far). When both DACL and SACL are given
2470da6c28aaSamw * by client the existing ACL should be overwritten. If only
2471da6c28aaSamw * one of them is specified the entries corresponding to the other
2472da6c28aaSamw * ACL should not be touched. For example, if only DACL
2473da6c28aaSamw * is specified in input fs_sd, the function reads audit entries
2474da6c28aaSamw * of the existing ACL of the file and point fs_sd->sd_zsdacl
2475da6c28aaSamw * pointer to the fetched SACL, this way when smb_fsop_sdwrite()
2476da6c28aaSamw * function is called the passed fs_sd would point to the specified
2477da6c28aaSamw * DACL by client and fetched SACL from filesystem, so the file
2478da6c28aaSamw * will end up with correct ACL.
2479da6c28aaSamw */
2480da6c28aaSamw static int
smb_fsop_sdmerge(smb_request_t * sr,smb_node_t * snode,smb_fssd_t * fs_sd)2481da6c28aaSamw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd)
2482da6c28aaSamw {
2483da6c28aaSamw smb_fssd_t cur_sd;
24848622ec45SGordon Ross cred_t *kcr = zone_kcred();
2485da6c28aaSamw int error = 0;
2486da6c28aaSamw
2487da6c28aaSamw if (sr->tid_tree->t_acltype != ACE_T)
2488da6c28aaSamw /* Don't bother if target FS doesn't support ACE_T */
2489da6c28aaSamw return (0);
2490da6c28aaSamw
2491da6c28aaSamw if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) {
2492da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
2493da6c28aaSamw /*
2494da6c28aaSamw * Don't overwrite existing audit entries
2495da6c28aaSamw */
249655bf511dSas200622 smb_fssd_init(&cur_sd, SMB_SACL_SECINFO,
2497da6c28aaSamw fs_sd->sd_flags);
2498da6c28aaSamw
24998622ec45SGordon Ross error = smb_fsop_sdread(sr, kcr, snode, &cur_sd);
2500da6c28aaSamw if (error == 0) {
2501da6c28aaSamw ASSERT(fs_sd->sd_zsacl == NULL);
2502da6c28aaSamw fs_sd->sd_zsacl = cur_sd.sd_zsacl;
2503da6c28aaSamw if (fs_sd->sd_zsacl && fs_sd->sd_zdacl)
2504da6c28aaSamw fs_sd->sd_zsacl->acl_flags =
2505da6c28aaSamw fs_sd->sd_zdacl->acl_flags;
2506da6c28aaSamw }
2507da6c28aaSamw } else {
2508da6c28aaSamw /*
2509da6c28aaSamw * Don't overwrite existing access entries
2510da6c28aaSamw */
251155bf511dSas200622 smb_fssd_init(&cur_sd, SMB_DACL_SECINFO,
2512da6c28aaSamw fs_sd->sd_flags);
2513da6c28aaSamw
25148622ec45SGordon Ross error = smb_fsop_sdread(sr, kcr, snode, &cur_sd);
2515da6c28aaSamw if (error == 0) {
2516da6c28aaSamw ASSERT(fs_sd->sd_zdacl == NULL);
2517da6c28aaSamw fs_sd->sd_zdacl = cur_sd.sd_zdacl;
2518da6c28aaSamw if (fs_sd->sd_zdacl && fs_sd->sd_zsacl)
2519da6c28aaSamw fs_sd->sd_zdacl->acl_flags =
2520da6c28aaSamw fs_sd->sd_zsacl->acl_flags;
2521da6c28aaSamw }
2522da6c28aaSamw }
2523da6c28aaSamw
2524da6c28aaSamw if (error)
252555bf511dSas200622 smb_fssd_term(&cur_sd);
2526da6c28aaSamw }
2527da6c28aaSamw
2528da6c28aaSamw return (error);
2529da6c28aaSamw }
2530da6c28aaSamw
2531da6c28aaSamw /*
2532da6c28aaSamw * smb_fsop_sdwrite
2533da6c28aaSamw *
2534da6c28aaSamw * Stores the given uid, gid and acl in filesystem.
2535da6c28aaSamw * Provided items in fs_sd are specified by fs_sd->sd_secinfo.
2536da6c28aaSamw *
2537da6c28aaSamw * A SMB security descriptor could contain owner, primary group,
2538da6c28aaSamw * DACL and SACL. Setting an SD should be atomic but here it has to
2539da6c28aaSamw * be done via two separate FS operations: VOP_SETATTR and
2540da6c28aaSamw * VOP_SETSECATTR. Therefore, this function has to simulate the
2541da6c28aaSamw * atomicity as well as it can.
25422c1b14e5Sjose borrego *
25432c1b14e5Sjose borrego * Get the current uid, gid before setting the new uid/gid
25442c1b14e5Sjose borrego * so if smb_fsop_aclwrite fails they can be restored. root cred is
25452c1b14e5Sjose borrego * used to get currend uid/gid since this operation is performed on
25462c1b14e5Sjose borrego * behalf of the server not the user.
25472c1b14e5Sjose borrego *
25482c1b14e5Sjose borrego * If setting uid/gid fails with EPERM it means that and invalid
25492c1b14e5Sjose borrego * owner has been specified. Callers should translate this to
25502c1b14e5Sjose borrego * STATUS_INVALID_OWNER which is not the normal mapping for EPERM
25512c1b14e5Sjose borrego * in upper layers, so EPERM is mapped to EBADE.
2552d11e14a7SMatt Barden *
2553d11e14a7SMatt Barden * If 'overwrite' is non-zero, then the existing ACL is ignored.
2554da6c28aaSamw */
2555da6c28aaSamw int
smb_fsop_sdwrite(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_fssd_t * fs_sd,int overwrite)2556da6c28aaSamw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2557da6c28aaSamw smb_fssd_t *fs_sd, int overwrite)
2558da6c28aaSamw {
2559da6c28aaSamw smb_attr_t set_attr;
2560da6c28aaSamw smb_attr_t orig_attr;
25618622ec45SGordon Ross cred_t *kcr = zone_kcred();
25628622ec45SGordon Ross int error = 0;
25638622ec45SGordon Ross int access = 0;
2564da6c28aaSamw
2565da6c28aaSamw ASSERT(cr);
2566da6c28aaSamw ASSERT(fs_sd);
2567da6c28aaSamw
2568da6c28aaSamw ASSERT(sr);
2569da6c28aaSamw ASSERT(sr->tid_tree);
2570c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr))
2571da6c28aaSamw return (EROFS);
2572da6c28aaSamw
2573245d1332SMatt Barden /* Can't set security on named streams */
2574245d1332SMatt Barden if (SMB_IS_STREAM(snode) != NULL)
2575245d1332SMatt Barden return (EINVAL);
2576245d1332SMatt Barden
2577da6c28aaSamw bzero(&set_attr, sizeof (smb_attr_t));
2578da6c28aaSamw
2579da6c28aaSamw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
2580da6c28aaSamw set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
2581da6c28aaSamw set_attr.sa_mask |= SMB_AT_UID;
25822c1b14e5Sjose borrego access |= WRITE_OWNER;
2583da6c28aaSamw }
2584da6c28aaSamw
2585da6c28aaSamw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
2586da6c28aaSamw set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
2587da6c28aaSamw set_attr.sa_mask |= SMB_AT_GID;
25882c1b14e5Sjose borrego access |= WRITE_OWNER;
2589da6c28aaSamw }
2590da6c28aaSamw
2591da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
2592da6c28aaSamw access |= WRITE_DAC;
2593da6c28aaSamw
2594da6c28aaSamw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
2595da6c28aaSamw access |= ACCESS_SYSTEM_SECURITY;
2596da6c28aaSamw
2597da6c28aaSamw if (sr->fid_ofile)
2598da6c28aaSamw error = smb_ofile_access(sr->fid_ofile, cr, access);
2599da6c28aaSamw else
2600da6c28aaSamw error = smb_fsop_access(sr, cr, snode, access);
2601da6c28aaSamw
2602da6c28aaSamw if (error)
2603da6c28aaSamw return (EACCES);
2604da6c28aaSamw
2605da6c28aaSamw if (set_attr.sa_mask) {
2606da6c28aaSamw orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
26078622ec45SGordon Ross error = smb_fsop_getattr(sr, kcr, snode, &orig_attr);
26082c1b14e5Sjose borrego if (error == 0) {
2609037cac00Sjoyce mcintosh error = smb_fsop_setattr(sr, cr, snode, &set_attr);
26102c1b14e5Sjose borrego if (error == EPERM)
26112c1b14e5Sjose borrego error = EBADE;
26122c1b14e5Sjose borrego }
2613da6c28aaSamw
2614da6c28aaSamw if (error)
2615da6c28aaSamw return (error);
2616da6c28aaSamw }
2617da6c28aaSamw
2618da6c28aaSamw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2619d11e14a7SMatt Barden if (overwrite == 0)
2620da6c28aaSamw error = smb_fsop_sdmerge(sr, snode, fs_sd);
2621da6c28aaSamw
2622d11e14a7SMatt Barden if (error == 0)
2623da6c28aaSamw error = smb_fsop_aclwrite(sr, cr, snode, fs_sd);
2624d11e14a7SMatt Barden
2625d11e14a7SMatt Barden if (error != 0) {
2626da6c28aaSamw /*
2627da6c28aaSamw * Revert uid/gid changes if required.
2628da6c28aaSamw */
2629da6c28aaSamw if (set_attr.sa_mask) {
2630da6c28aaSamw orig_attr.sa_mask = set_attr.sa_mask;
26318622ec45SGordon Ross (void) smb_fsop_setattr(sr, kcr, snode,
2632037cac00Sjoyce mcintosh &orig_attr);
2633da6c28aaSamw }
2634da6c28aaSamw }
2635da6c28aaSamw }
2636da6c28aaSamw
2637da6c28aaSamw return (error);
2638da6c28aaSamw }
2639da6c28aaSamw
2640b819cea2SGordon Ross #ifdef _KERNEL
2641da6c28aaSamw /*
2642da6c28aaSamw * smb_fsop_sdinherit
2643da6c28aaSamw *
2644da6c28aaSamw * Inherit the security descriptor from the parent container.
2645da6c28aaSamw * This function is called after FS has created the file/folder
2646da6c28aaSamw * so if this doesn't do anything it means FS inheritance is
2647da6c28aaSamw * in place.
2648da6c28aaSamw *
2649da6c28aaSamw * Do inheritance for ZFS internally.
2650da6c28aaSamw *
2651da6c28aaSamw * If we want to let ZFS does the inheritance the
2652da6c28aaSamw * following setting should be true:
2653da6c28aaSamw *
2654da6c28aaSamw * - aclinherit = passthrough
2655da6c28aaSamw * - aclmode = passthrough
2656da6c28aaSamw * - smbd umask = 0777
2657da6c28aaSamw *
2658da6c28aaSamw * This will result in right effective permissions but
2659da6c28aaSamw * ZFS will always add 6 ACEs for owner, owning group
2660da6c28aaSamw * and others to be POSIX compliant. This is not what
2661da6c28aaSamw * Windows clients/users expect, so we decided that CIFS
2662da6c28aaSamw * implements Windows rules and overwrite whatever ZFS
2663da6c28aaSamw * comes up with. This way we also don't have to care
2664da6c28aaSamw * about ZFS aclinherit and aclmode settings.
2665da6c28aaSamw */
2666da6c28aaSamw static int
smb_fsop_sdinherit(smb_request_t * sr,smb_node_t * dnode,smb_fssd_t * fs_sd)2667da6c28aaSamw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd)
2668da6c28aaSamw {
266955bf511dSas200622 acl_t *dacl = NULL;
267055bf511dSas200622 acl_t *sacl = NULL;
26719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States int is_dir;
2672da6c28aaSamw int error;
2673d11e14a7SMatt Barden uint32_t secinfo;
2674d11e14a7SMatt Barden smb_fssd_t pfs_sd;
2675da6c28aaSamw
2676da6c28aaSamw ASSERT(fs_sd);
2677da6c28aaSamw
2678d11e14a7SMatt Barden secinfo = fs_sd->sd_secinfo;
2679d11e14a7SMatt Barden
2680d11e14a7SMatt Barden /* Anything to do? */
2681d11e14a7SMatt Barden if ((secinfo & SMB_ACL_SECINFO) == SMB_ACL_SECINFO)
2682d11e14a7SMatt Barden return (0);
2683d11e14a7SMatt Barden
2684da6c28aaSamw /*
2685da6c28aaSamw * No forced inheritance for non-ZFS filesystems.
2686da6c28aaSamw */
2687d11e14a7SMatt Barden if (sr->tid_tree->t_acltype != ACE_T)
2688da6c28aaSamw return (0);
2689da6c28aaSamw
2690d11e14a7SMatt Barden smb_fssd_init(&pfs_sd, SMB_ACL_SECINFO, fs_sd->sd_flags);
2691da6c28aaSamw
2692da6c28aaSamw /* Fetch parent directory's ACL */
2693d11e14a7SMatt Barden error = smb_fsop_sdread(sr, zone_kcred(), dnode, &pfs_sd);
2694da6c28aaSamw if (error) {
2695da6c28aaSamw return (error);
2696da6c28aaSamw }
2697da6c28aaSamw
2698da6c28aaSamw is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR);
2699d11e14a7SMatt Barden if ((secinfo & SMB_DACL_SECINFO) == 0) {
2700d11e14a7SMatt Barden dacl = smb_fsacl_inherit(pfs_sd.sd_zdacl, is_dir,
2701d11e14a7SMatt Barden SMB_DACL_SECINFO, sr->user_cr);
2702da6c28aaSamw fs_sd->sd_zdacl = dacl;
2703d11e14a7SMatt Barden }
2704da6c28aaSamw
2705d11e14a7SMatt Barden if ((secinfo & SMB_SACL_SECINFO) == 0) {
2706d11e14a7SMatt Barden sacl = smb_fsacl_inherit(pfs_sd.sd_zsacl, is_dir,
2707d11e14a7SMatt Barden SMB_SACL_SECINFO, sr->user_cr);
2708d11e14a7SMatt Barden fs_sd->sd_zsacl = sacl;
2709d11e14a7SMatt Barden }
2710d11e14a7SMatt Barden
2711d11e14a7SMatt Barden smb_fsacl_free(pfs_sd.sd_zdacl);
2712d11e14a7SMatt Barden smb_fsacl_free(pfs_sd.sd_zsacl);
2713da6c28aaSamw return (0);
2714da6c28aaSamw }
2715b819cea2SGordon Ross #endif /* _KERNEL */
2716da6c28aaSamw
2717da6c28aaSamw /*
2718da6c28aaSamw * smb_fsop_eaccess
2719da6c28aaSamw *
2720da6c28aaSamw * Returns the effective permission of the given credential for the
2721da6c28aaSamw * specified object.
2722da6c28aaSamw *
2723da6c28aaSamw * This is just a workaround. We need VFS/FS support for this.
2724da6c28aaSamw */
2725da6c28aaSamw void
smb_fsop_eaccess(smb_request_t * sr,cred_t * cr,smb_node_t * snode,uint32_t * eaccess)2726da6c28aaSamw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2727da6c28aaSamw uint32_t *eaccess)
2728da6c28aaSamw {
2729da6c28aaSamw int access = 0;
2730da6c28aaSamw vnode_t *dir_vp;
2731da6c28aaSamw smb_node_t *unnamed_node;
2732da6c28aaSamw
2733da6c28aaSamw ASSERT(cr);
2734da6c28aaSamw ASSERT(snode);
2735da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC);
2736da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
2737da6c28aaSamw
2738da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode);
2739da6c28aaSamw if (unnamed_node) {
2740da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
2741da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
2742da6c28aaSamw /*
2743da6c28aaSamw * Streams authorization should be performed against the
2744da6c28aaSamw * unnamed stream.
2745da6c28aaSamw */
2746da6c28aaSamw snode = unnamed_node;
2747da6c28aaSamw }
2748da6c28aaSamw
2749c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) {
27501fcced4cSJordan Brown dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
2751da6c28aaSamw smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp,
2752da6c28aaSamw cr);
2753da6c28aaSamw return;
2754da6c28aaSamw }
2755da6c28aaSamw
2756da6c28aaSamw /*
2757da6c28aaSamw * FS doesn't understand 32-bit mask
2758da6c28aaSamw */
2759da6c28aaSamw smb_vop_eaccess(snode->vp, &access, 0, NULL, cr);
2760743a77edSAlan Wright access &= sr->tid_tree->t_access;
2761da6c28aaSamw
2762da6c28aaSamw *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES;
2763da6c28aaSamw
2764da6c28aaSamw if (access & VREAD)
2765da6c28aaSamw *eaccess |= FILE_READ_DATA;
2766da6c28aaSamw
2767da6c28aaSamw if (access & VEXEC)
2768da6c28aaSamw *eaccess |= FILE_EXECUTE;
2769da6c28aaSamw
2770da6c28aaSamw if (access & VWRITE)
2771da6c28aaSamw *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
2772da6c28aaSamw FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
2773d2488fe8SGordon Ross
2774d2488fe8SGordon Ross if (access & (VREAD | VWRITE))
2775d2488fe8SGordon Ross *eaccess |= SYNCHRONIZE;
2776d2488fe8SGordon Ross
2777d2488fe8SGordon Ross #ifdef _FAKE_KERNEL
2778d2488fe8SGordon Ross /* Should be: if (we are the owner)... */
2779d2488fe8SGordon Ross if (access & VWRITE)
2780d2488fe8SGordon Ross *eaccess |= DELETE | WRITE_DAC | WRITE_OWNER;
2781d2488fe8SGordon Ross #endif
2782da6c28aaSamw }
278355bf511dSas200622
2784dc20a302Sas200622 /*
2785dc20a302Sas200622 * smb_fsop_shrlock
2786dc20a302Sas200622 *
2787dc20a302Sas200622 * For the current open request, check file sharing rules
2788dc20a302Sas200622 * against existing opens.
2789dc20a302Sas200622 *
2790dc20a302Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any
2791dc20a302Sas200622 * sharing conflict. Returns NT_STATUS_SUCCESS otherwise.
2792dc20a302Sas200622 *
2793dc20a302Sas200622 * Full system-wide share reservation synchronization is available
2794dc20a302Sas200622 * when the nbmand (non-blocking mandatory) mount option is set
2795dc20a302Sas200622 * (i.e. nbl_need_crit() is true) and nbmand critical regions are used.
2796dc20a302Sas200622 * This provides synchronization with NFS and local processes. The
2797dc20a302Sas200622 * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called
2798dc20a302Sas200622 * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well
2799dc20a302Sas200622 * as the CIFS rename and delete paths.
2800dc20a302Sas200622 *
2801dc20a302Sas200622 * The CIFS server will also enter the nbl critical region in the open,
2802dc20a302Sas200622 * rename, and delete paths when nbmand is not set. There is limited
2803dc20a302Sas200622 * coordination with local and VFS share reservations in this case.
2804dc20a302Sas200622 * Note that when the nbmand mount option is not set, the VFS layer
2805dc20a302Sas200622 * only processes advisory reservations and the delete mode is not checked.
2806dc20a302Sas200622 *
2807dc20a302Sas200622 * Whether or not the nbmand mount option is set, intra-CIFS share
2808dc20a302Sas200622 * checking is done in the open, delete, and rename paths using a CIFS
2809dc20a302Sas200622 * critical region (node->n_share_lock).
2810dc20a302Sas200622 */
2811dc20a302Sas200622 uint32_t
smb_fsop_shrlock(cred_t * cr,smb_node_t * node,uint32_t uniq_fid,uint32_t desired_access,uint32_t share_access)2812faa1795aSjb150015 smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid,
2813dc20a302Sas200622 uint32_t desired_access, uint32_t share_access)
281455bf511dSas200622 {
2815dc20a302Sas200622 int rc;
2816dc20a302Sas200622
2817dc20a302Sas200622 /* Allow access if the request is just for meta data */
2818dc20a302Sas200622 if ((desired_access & FILE_DATA_ALL) == 0)
2819dc20a302Sas200622 return (NT_STATUS_SUCCESS);
2820dc20a302Sas200622
28219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_node_open_check(node, desired_access, share_access);
2822dc20a302Sas200622 if (rc)
2823dc20a302Sas200622 return (NT_STATUS_SHARING_VIOLATION);
2824dc20a302Sas200622
2825dc20a302Sas200622 rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access,
2826dc20a302Sas200622 cr);
2827dc20a302Sas200622 if (rc)
2828dc20a302Sas200622 return (NT_STATUS_SHARING_VIOLATION);
2829dc20a302Sas200622
2830dc20a302Sas200622 return (NT_STATUS_SUCCESS);
2831dc20a302Sas200622 }
2832dc20a302Sas200622
2833dc20a302Sas200622 void
smb_fsop_unshrlock(cred_t * cr,smb_node_t * node,uint32_t uniq_fid)2834dc20a302Sas200622 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid)
2835dc20a302Sas200622 {
2836dc20a302Sas200622 (void) smb_vop_unshrlock(node->vp, uniq_fid, cr);
2837dc20a302Sas200622 }
28388c10a865Sas200622
28398c10a865Sas200622 int
smb_fsop_frlock(smb_node_t * node,smb_lock_t * lock,boolean_t unlock,cred_t * cr)28408c10a865Sas200622 smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock,
28418c10a865Sas200622 cred_t *cr)
28428c10a865Sas200622 {
28438c10a865Sas200622 flock64_t bf;
28448c10a865Sas200622 int flag = F_REMOTELOCK;
28458c10a865Sas200622
28463ad684d6Sjb150015 /*
28473ad684d6Sjb150015 * VOP_FRLOCK() will not be called if:
28483ad684d6Sjb150015 *
28493ad684d6Sjb150015 * 1) The lock has a range of zero bytes. The semantics of Windows and
28503ad684d6Sjb150015 * POSIX are different. In the case of POSIX it asks for the locking
28513ad684d6Sjb150015 * of all the bytes from the offset provided until the end of the
28523ad684d6Sjb150015 * file. In the case of Windows a range of zero locks nothing and
28533ad684d6Sjb150015 * doesn't conflict with any other lock.
28543ad684d6Sjb150015 *
28553ad684d6Sjb150015 * 2) The lock rolls over (start + lenght < start). Solaris will assert
28563ad684d6Sjb150015 * if such a request is submitted. This will not create
28573ad684d6Sjb150015 * incompatibilities between POSIX and Windows. In the Windows world,
28583ad684d6Sjb150015 * if a client submits such a lock, the server will not lock any
28593ad684d6Sjb150015 * bytes. Interestingly if the same lock (same offset and length) is
28603ad684d6Sjb150015 * resubmitted Windows will consider that there is an overlap and
28613ad684d6Sjb150015 * the granting rules will then apply.
28620897f7fbSGordon Ross *
28630897f7fbSGordon Ross * 3) The SMB-level process IDs (smb_pid) are not passed down to the
28640897f7fbSGordon Ross * POSIX level in l_pid because (a) the rules about lock PIDs are
28650897f7fbSGordon Ross * different in SMB, and (b) we're putting our ofile f_uniqid in
28660897f7fbSGordon Ross * the POSIX l_pid field to segregate locks per SMB ofile.
28670897f7fbSGordon Ross * (We're also using a "remote" system ID in l_sysid.)
28680897f7fbSGordon Ross * All SMB locking PIDs are handled at the SMB level and
28690897f7fbSGordon Ross * not exposed in POSIX locking.
28703ad684d6Sjb150015 */
28713ad684d6Sjb150015 if ((lock->l_length == 0) ||
28723ad684d6Sjb150015 ((lock->l_start + lock->l_length - 1) < lock->l_start))
28733ad684d6Sjb150015 return (0);
28743ad684d6Sjb150015
28758c10a865Sas200622 bzero(&bf, sizeof (bf));
28768c10a865Sas200622
28778c10a865Sas200622 if (unlock) {
28788c10a865Sas200622 bf.l_type = F_UNLCK;
28798c10a865Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READONLY) {
28808c10a865Sas200622 bf.l_type = F_RDLCK;
28818c10a865Sas200622 flag |= FREAD;
28828c10a865Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) {
28838c10a865Sas200622 bf.l_type = F_WRLCK;
28848c10a865Sas200622 flag |= FWRITE;
28858c10a865Sas200622 }
28868c10a865Sas200622
28878c10a865Sas200622 bf.l_start = lock->l_start;
28888c10a865Sas200622 bf.l_len = lock->l_length;
2889c8ec8eeaSjose borrego bf.l_pid = lock->l_file->f_uniqid;
28908c10a865Sas200622 bf.l_sysid = smb_ct.cc_sysid;
28918c10a865Sas200622
28928c10a865Sas200622 return (smb_vop_frlock(node->vp, cr, flag, &bf));
28938c10a865Sas200622 }
2894