xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_fsops.c (revision dd72704bd9e794056c558153663c739e2012d721)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2012-2022 Tintri by DDN, Inc. All rights reserved.
24  * Copyright 2022 RackTop Systems, Inc.
25  */
26 
27 #include <sys/sid.h>
28 #include <sys/nbmlock.h>
29 #include <smbsrv/smb_fsops.h>
30 #include <smbsrv/smb_kproto.h>
31 #include <acl/acl_common.h>
32 #include <sys/fcntl.h>
33 #include <sys/filio.h>
34 #include <sys/flock.h>
35 #include <fs/fs_subr.h>
36 
37 extern caller_context_t smb_ct;
38 
39 static int smb_fsop_create_file_with_stream(smb_request_t *, cred_t *,
40     smb_node_t *, char *, char *, int, smb_attr_t *, smb_node_t **);
41 
42 static int smb_fsop_create_file(smb_request_t *, cred_t *, smb_node_t *,
43     char *, int, smb_attr_t *, smb_node_t **);
44 
45 #ifdef	_KERNEL
46 static int smb_fsop_create_with_sd(smb_request_t *, cred_t *, smb_node_t *,
47     char *, smb_attr_t *, smb_node_t **, smb_fssd_t *);
48 static int smb_fsop_sdinherit(smb_request_t *, smb_node_t *, smb_fssd_t *);
49 #endif	/* _KERNEL */
50 
51 /*
52  * The smb_fsop_* functions have knowledge of CIFS semantics.
53  *
54  * The smb_vop_* functions have minimal knowledge of CIFS semantics and
55  * serve as an interface to the VFS layer.
56  *
57  * Hence, smb_request_t and smb_node_t structures should not be passed
58  * from the smb_fsop_* layer to the smb_vop_* layer.
59  *
60  * In general, CIFS service code should only ever call smb_fsop_*
61  * functions directly, and never smb_vop_* functions directly.
62  *
63  * smb_fsop_* functions should call smb_vop_* functions where possible, instead
64  * of their smb_fsop_* counterparts.  However, there are times when
65  * this cannot be avoided.
66  */
67 
68 /*
69  * Note: Stream names cannot be mangled.
70  */
71 
72 /*
73  * smb_fsop_amask_to_omode
74  *
75  * Convert the access mask to the open mode (for use
76  * with the VOP_OPEN call).
77  *
78  * Note that opening a file for attribute only access
79  * will also translate into an FREAD or FWRITE open mode
80  * (i.e., it's not just for data).
81  *
82  * This is needed so that opens are tracked appropriately
83  * for oplock processing.
84  */
85 
86 int
87 smb_fsop_amask_to_omode(uint32_t access)
88 {
89 	int mode = 0;
90 
91 	if (access & (FILE_READ_DATA | FILE_EXECUTE |
92 	    FILE_READ_ATTRIBUTES | FILE_READ_EA))
93 		mode |= FREAD;
94 
95 	if (access & (FILE_WRITE_DATA | FILE_APPEND_DATA |
96 	    FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))
97 		mode |= FWRITE;
98 
99 	if (access & FILE_APPEND_DATA)
100 		mode |= FAPPEND;
101 
102 	return (mode);
103 }
104 
105 int
106 smb_fsop_open(smb_node_t *node, int mode, cred_t *cred)
107 {
108 	/*
109 	 * Assuming that the same vnode is returned as we had before.
110 	 * (I.e., with certain types of files or file systems, a
111 	 * different vnode might be returned by VOP_OPEN)
112 	 */
113 	return (smb_vop_open(&node->vp, mode, cred));
114 }
115 
116 void
117 smb_fsop_close(smb_node_t *node, int mode, cred_t *cred)
118 {
119 	smb_vop_close(node->vp, mode, cred);
120 }
121 
122 #ifdef	_KERNEL
123 static int
124 smb_fsop_create_with_sd(smb_request_t *sr, cred_t *cr,
125     smb_node_t *dnode, char *name,
126     smb_attr_t *attr, smb_node_t **ret_snode, smb_fssd_t *fs_sd)
127 {
128 	vsecattr_t *vsap;
129 	vsecattr_t vsecattr;
130 	smb_attr_t set_attr;
131 	acl_t *acl, *dacl, *sacl;
132 	vnode_t *vp;
133 	cred_t *kcr = zone_kcred();
134 	int aclbsize = 0;	/* size of acl list in bytes */
135 	int flags = 0;
136 	int rc;
137 	boolean_t is_dir;
138 
139 	ASSERT(fs_sd);
140 	ASSERT(ret_snode != NULL);
141 
142 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
143 		flags = SMB_IGNORE_CASE;
144 	if (SMB_TREE_SUPPORTS_CATIA(sr))
145 		flags |= SMB_CATIA;
146 
147 	ASSERT(cr);
148 
149 	is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0);
150 
151 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) {
152 		dacl = fs_sd->sd_zdacl;
153 		sacl = fs_sd->sd_zsacl;
154 		if (dacl != NULL || sacl != NULL) {
155 			if (dacl && sacl) {
156 				acl = smb_fsacl_merge(dacl, sacl);
157 			} else if (dacl) {
158 				acl = dacl;
159 			} else {
160 				acl = sacl;
161 			}
162 
163 			rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize);
164 
165 			if (dacl && sacl)
166 				acl_free(acl);
167 
168 			if (rc != 0)
169 				return (rc);
170 
171 			vsap = &vsecattr;
172 		} else {
173 			vsap = NULL;
174 		}
175 
176 		/* The tree ACEs may prevent a create */
177 		rc = EACCES;
178 		if (is_dir) {
179 			if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_SUBDIRECTORY) != 0)
180 				rc = smb_vop_mkdir(dnode->vp, name, attr,
181 				    &vp, flags, cr, vsap);
182 		} else {
183 			if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_FILE) != 0)
184 				rc = smb_vop_create(dnode->vp, name, attr,
185 				    &vp, flags, cr, vsap);
186 		}
187 
188 		if (vsap != NULL)
189 			kmem_free(vsap->vsa_aclentp, aclbsize);
190 
191 		if (rc != 0)
192 			return (rc);
193 
194 		set_attr.sa_mask = 0;
195 
196 		/*
197 		 * Ideally we should be able to specify the owner and owning
198 		 * group at create time along with the ACL. Since we cannot
199 		 * do that right now, kcred is passed to smb_vop_setattr so it
200 		 * doesn't fail due to lack of permission.
201 		 */
202 		if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
203 			set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
204 			set_attr.sa_mask |= SMB_AT_UID;
205 		}
206 
207 		if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
208 			set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
209 			set_attr.sa_mask |= SMB_AT_GID;
210 		}
211 
212 		if (set_attr.sa_mask)
213 			rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcr);
214 
215 		if (rc == 0) {
216 			*ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
217 			    name, dnode, NULL);
218 
219 			if (*ret_snode == NULL)
220 				rc = ENOMEM;
221 
222 			VN_RELE(vp);
223 		}
224 	} else {
225 		/*
226 		 * For filesystems that don't support ACL-on-create, try
227 		 * to set the specified SD after create, which could actually
228 		 * fail because of conflicts between inherited security
229 		 * attributes upon creation and the specified SD.
230 		 *
231 		 * Passing kcred to smb_fsop_sdwrite() to overcome this issue.
232 		 */
233 
234 		if (is_dir) {
235 			rc = smb_vop_mkdir(dnode->vp, name, attr, &vp,
236 			    flags, cr, NULL);
237 		} else {
238 			rc = smb_vop_create(dnode->vp, name, attr, &vp,
239 			    flags, cr, NULL);
240 		}
241 
242 		if (rc != 0)
243 			return (rc);
244 
245 		*ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
246 		    name, dnode, NULL);
247 
248 		if (*ret_snode != NULL) {
249 			if (!smb_tree_has_feature(sr->tid_tree,
250 			    SMB_TREE_NFS_MOUNTED))
251 				rc = smb_fsop_sdwrite(sr, kcr, *ret_snode,
252 				    fs_sd, 1);
253 		} else {
254 			rc = ENOMEM;
255 		}
256 
257 		VN_RELE(vp);
258 	}
259 
260 	if (rc != 0) {
261 		if (is_dir)
262 			(void) smb_vop_rmdir(dnode->vp, name, flags, cr);
263 		else
264 			(void) smb_vop_remove(dnode->vp, name, flags, cr);
265 	}
266 
267 	return (rc);
268 }
269 #endif	/* _KERNEL */
270 
271 /*
272  * smb_fsop_create
273  *
274  * All SMB functions should use this wrapper to ensure that
275  * all the smb_vop_creates are performed with the appropriate credentials.
276  * Please document any direct calls to explain the reason for avoiding
277  * this wrapper.
278  *
279  * *ret_snode is returned with a reference upon success.  No reference is
280  * taken if an error is returned.
281  */
282 int
283 smb_fsop_create(smb_request_t *sr, cred_t *cr, smb_node_t *dnode,
284     char *name, smb_attr_t *attr, smb_node_t **ret_snode)
285 {
286 	int	rc = 0;
287 	int	flags = 0;
288 	char	*fname, *sname;
289 	char	*longname = NULL;
290 
291 	ASSERT(cr);
292 	ASSERT(dnode);
293 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
294 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
295 
296 	ASSERT(ret_snode);
297 	*ret_snode = 0;
298 
299 	ASSERT(name);
300 	if (*name == 0)
301 		return (EINVAL);
302 
303 	ASSERT(sr);
304 	ASSERT(sr->tid_tree);
305 
306 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
307 		return (EACCES);
308 
309 	if (SMB_TREE_IS_READONLY(sr))
310 		return (EROFS);
311 
312 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
313 		flags = SMB_IGNORE_CASE;
314 	if (SMB_TREE_SUPPORTS_CATIA(sr))
315 		flags |= SMB_CATIA;
316 	if (SMB_TREE_SUPPORTS_ABE(sr))
317 		flags |= SMB_ABE;
318 
319 	if (smb_is_stream_name(name)) {
320 		fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
321 		sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
322 		smb_stream_parse_name(name, fname, sname);
323 
324 		rc = smb_fsop_create_file_with_stream(sr, cr, dnode,
325 		    fname, sname, flags, attr, ret_snode);
326 
327 		kmem_free(fname, MAXNAMELEN);
328 		kmem_free(sname, MAXNAMELEN);
329 		return (rc);
330 	}
331 
332 	/* Not a named stream */
333 
334 	if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(name)) {
335 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
336 		rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
337 		kmem_free(longname, MAXNAMELEN);
338 
339 		if (rc == 0)
340 			rc = EEXIST;
341 		if (rc != ENOENT)
342 			return (rc);
343 	}
344 
345 	rc = smb_fsop_create_file(sr, cr, dnode, name, flags,
346 	    attr, ret_snode);
347 	return (rc);
348 
349 }
350 
351 
352 /*
353  * smb_fsop_create_file_with_stream
354  *
355  * Create named stream (sname) on file (fname), creating the file if it
356  * doesn't exist.
357  * If we created the file and then creation of the named stream fails,
358  * we delete the file.
359  * Since we use the real file name for the smb_vop_remove we
360  * clear the SMB_IGNORE_CASE flag to ensure a case sensitive
361  * match.
362  *
363  * Note that some stream "types" are "restricted" and only
364  * internal callers (cr == kcred) can create those.
365  */
366 static int
367 smb_fsop_create_file_with_stream(smb_request_t *sr, cred_t *cr,
368     smb_node_t *dnode, char *fname, char *sname, int flags,
369     smb_attr_t *attr, smb_node_t **ret_snode)
370 {
371 	smb_node_t	*fnode;
372 	cred_t		*kcr = zone_kcred();
373 	int		rc = 0;
374 	boolean_t	fcreate = B_FALSE;
375 
376 	ASSERT(ret_snode != NULL);
377 
378 	if (cr != kcr && smb_strname_restricted(sname))
379 		return (EACCES);
380 
381 	/* Look up / create the unnamed stream, fname */
382 	rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
383 	    sr->tid_tree->t_snode, dnode, fname, &fnode);
384 	if (rc == 0) {
385 		if (smb_fsop_access(sr, sr->user_cr, fnode,
386 		    sr->sr_open.desired_access) != 0) {
387 			smb_node_release(fnode);
388 			rc = EACCES;
389 		}
390 	} else if (rc == ENOENT) {
391 		fcreate = B_TRUE;
392 		rc = smb_fsop_create_file(sr, cr, dnode, fname, flags,
393 		    attr, &fnode);
394 	}
395 	if (rc != 0)
396 		return (rc);
397 
398 	rc = smb_fsop_create_stream(sr, cr, dnode, fnode, sname, flags, attr,
399 	    ret_snode);
400 
401 	if (rc != 0) {
402 		if (fcreate) {
403 			flags &= ~SMB_IGNORE_CASE;
404 			(void) smb_vop_remove(dnode->vp,
405 			    fnode->od_name, flags, cr);
406 		}
407 	}
408 
409 	smb_node_release(fnode);
410 	return (rc);
411 }
412 
413 /*
414  * smb_fsop_create_stream
415  *
416  * Create named stream (sname) on existing file (fnode).
417  *
418  * The second parameter of smb_vop_setattr() is set to
419  * NULL, even though an unnamed stream exists.  This is
420  * because we want to set the UID and GID on the named
421  * stream in this case for consistency with the (unnamed
422  * stream) file (see comments for smb_vop_setattr()).
423  *
424  * Note that some stream "types" are "restricted" and only
425  * internal callers (cr == kcred) can create those.
426  */
427 int
428 smb_fsop_create_stream(smb_request_t *sr, cred_t *cr,
429     smb_node_t *dnode, smb_node_t *fnode, char *sname, int flags,
430     smb_attr_t *attr, smb_node_t **ret_snode)
431 {
432 	smb_attr_t	fattr;
433 	vnode_t		*xattrdvp;
434 	vnode_t		*vp;
435 	cred_t		*kcr = zone_kcred();
436 	int		rc = 0;
437 
438 	ASSERT(ret_snode != NULL);
439 
440 	if (cr != kcr && smb_strname_restricted(sname))
441 		return (EACCES);
442 
443 	bzero(&fattr, sizeof (fattr));
444 	fattr.sa_mask = SMB_AT_UID | SMB_AT_GID;
445 	rc = smb_vop_getattr(fnode->vp, NULL, &fattr, 0, kcr);
446 
447 	if (rc == 0) {
448 		/* create the named stream, sname */
449 		rc = smb_vop_stream_create(fnode->vp, sname,
450 		    attr, &vp, &xattrdvp, flags, cr);
451 	}
452 	if (rc != 0)
453 		return (rc);
454 
455 	attr->sa_vattr.va_uid = fattr.sa_vattr.va_uid;
456 	attr->sa_vattr.va_gid = fattr.sa_vattr.va_gid;
457 	attr->sa_mask = SMB_AT_UID | SMB_AT_GID;
458 
459 	rc = smb_vop_setattr(vp, NULL, attr, 0, kcr);
460 	if (rc != 0) {
461 		VN_RELE(xattrdvp);
462 		VN_RELE(vp);
463 		return (rc);
464 	}
465 
466 	*ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdvp,
467 	    vp, sname);
468 
469 	VN_RELE(xattrdvp);
470 	VN_RELE(vp);
471 
472 	if (*ret_snode == NULL)
473 		rc = ENOMEM;
474 
475 	/* notify change to the unnamed stream */
476 	if (rc == 0)
477 		smb_node_notify_change(dnode,
478 		    FILE_ACTION_ADDED_STREAM, fnode->od_name);
479 
480 	return (rc);
481 }
482 
483 /*
484  * smb_fsop_create_file
485  */
486 static int
487 smb_fsop_create_file(smb_request_t *sr, cred_t *cr,
488     smb_node_t *dnode, char *name, int flags,
489     smb_attr_t *attr, smb_node_t **ret_snode)
490 {
491 	smb_arg_open_t	*op = &sr->sr_open;
492 	vnode_t		*vp;
493 	int		rc;
494 
495 	ASSERT(ret_snode != NULL);
496 
497 #ifdef	_KERNEL
498 	smb_fssd_t	fs_sd;
499 	uint32_t	secinfo;
500 	uint32_t	status;
501 
502 	if (op->sd) {
503 		/*
504 		 * SD sent by client in Windows format. Needs to be
505 		 * converted to FS format. Inherit DACL/SACL if they're not
506 		 * specified.
507 		 */
508 		secinfo = smb_sd_get_secinfo(op->sd);
509 
510 		if ((secinfo & SMB_SACL_SECINFO) != 0 &&
511 		    !smb_user_has_security_priv(sr->uid_user, cr))
512 			return (EPERM);
513 
514 		smb_fssd_init(&fs_sd, secinfo, 0);
515 
516 		status = smb_sd_tofs(op->sd, &fs_sd);
517 		if (status == NT_STATUS_SUCCESS) {
518 			rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
519 			if (rc == 0)
520 				rc = smb_fsop_create_with_sd(sr, cr, dnode,
521 				    name, attr, ret_snode, &fs_sd);
522 
523 		} else {
524 			rc = EINVAL;
525 		}
526 		smb_fssd_term(&fs_sd);
527 	} else if (sr->tid_tree->t_acltype == ACE_T) {
528 		/*
529 		 * No incoming SD and filesystem is ZFS
530 		 * Server applies Windows inheritance rules,
531 		 * see smb_fsop_sdinherit() comments as to why.
532 		 */
533 		smb_fssd_init(&fs_sd, 0, 0);
534 		rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
535 		if (rc == 0) {
536 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
537 			    name, attr, ret_snode, &fs_sd);
538 		}
539 
540 		smb_fssd_term(&fs_sd);
541 	} else
542 #endif	/* _KERNEL */
543 	{
544 		/*
545 		 * No incoming SD and filesystem is not ZFS
546 		 * let the filesystem handles the inheritance.
547 		 */
548 		rc = smb_vop_create(dnode->vp, name, attr, &vp,
549 		    flags, cr, NULL);
550 
551 		if (rc == 0) {
552 			*ret_snode = smb_node_lookup(sr, op, cr, vp,
553 			    name, dnode, NULL);
554 
555 			if (*ret_snode == NULL)
556 				rc = ENOMEM;
557 
558 			VN_RELE(vp);
559 		}
560 
561 	}
562 
563 	if (rc == 0)
564 		smb_node_notify_change(dnode, FILE_ACTION_ADDED, name);
565 
566 	return (rc);
567 }
568 
569 /*
570  * smb_fsop_mkdir
571  *
572  * All SMB functions should use this wrapper to ensure that
573  * the the calls are performed with the appropriate credentials.
574  * Please document any direct call to explain the reason
575  * for avoiding this wrapper.
576  *
577  * It is assumed that a reference exists on snode coming into this routine.
578  *
579  * *ret_snode is returned with a reference upon success.  No reference is
580  * taken if an error is returned.
581  */
582 int
583 smb_fsop_mkdir(
584     smb_request_t *sr,
585     cred_t *cr,
586     smb_node_t *dnode,
587     char *name,
588     smb_attr_t *attr,
589     smb_node_t **ret_snode)
590 {
591 	struct open_param *op = &sr->arg.open;
592 	char *longname;
593 	vnode_t *vp;
594 	int flags = 0;
595 	int rc;
596 
597 #ifdef	_KERNEL
598 	smb_fssd_t fs_sd;
599 	uint32_t secinfo;
600 	uint32_t status;
601 #endif	/* _KERNEL */
602 
603 	ASSERT(cr);
604 	ASSERT(dnode);
605 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
606 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
607 
608 	ASSERT(ret_snode);
609 	*ret_snode = 0;
610 
611 	ASSERT(name);
612 	if (*name == 0)
613 		return (EINVAL);
614 
615 	ASSERT(sr);
616 	ASSERT(sr->tid_tree);
617 
618 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
619 		return (EACCES);
620 
621 	if (SMB_TREE_IS_READONLY(sr))
622 		return (EROFS);
623 	if (SMB_TREE_SUPPORTS_CATIA(sr))
624 		flags |= SMB_CATIA;
625 	if (SMB_TREE_SUPPORTS_ABE(sr))
626 		flags |= SMB_ABE;
627 
628 	if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(name)) {
629 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
630 		rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
631 		kmem_free(longname, MAXNAMELEN);
632 
633 		/*
634 		 * If the name passed in by the client has an unmangled
635 		 * equivalent that is found in the specified directory,
636 		 * then the mkdir cannot succeed.  Return EEXIST.
637 		 *
638 		 * Only if ENOENT is returned will a mkdir be attempted.
639 		 */
640 
641 		if (rc == 0)
642 			rc = EEXIST;
643 
644 		if (rc != ENOENT)
645 			return (rc);
646 	}
647 
648 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
649 		flags = SMB_IGNORE_CASE;
650 
651 #ifdef	_KERNEL
652 	if (op->sd) {
653 		/*
654 		 * SD sent by client in Windows format. Needs to be
655 		 * converted to FS format. Inherit DACL/SACL if they're not
656 		 * specified.
657 		 */
658 		secinfo = smb_sd_get_secinfo(op->sd);
659 
660 		if ((secinfo & SMB_SACL_SECINFO) != 0 &&
661 		    !smb_user_has_security_priv(sr->uid_user, cr))
662 			return (EPERM);
663 
664 		smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR);
665 
666 		status = smb_sd_tofs(op->sd, &fs_sd);
667 		if (status == NT_STATUS_SUCCESS) {
668 			rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
669 			if (rc == 0)
670 				rc = smb_fsop_create_with_sd(sr, cr, dnode,
671 				    name, attr, ret_snode, &fs_sd);
672 		}
673 		else
674 			rc = EINVAL;
675 		smb_fssd_term(&fs_sd);
676 	} else if (sr->tid_tree->t_acltype == ACE_T) {
677 		/*
678 		 * No incoming SD and filesystem is ZFS
679 		 * Server applies Windows inheritance rules,
680 		 * see smb_fsop_sdinherit() comments as to why.
681 		 */
682 		smb_fssd_init(&fs_sd, 0, SMB_FSSD_FLAGS_DIR);
683 		rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
684 		if (rc == 0) {
685 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
686 			    name, attr, ret_snode, &fs_sd);
687 		}
688 
689 		smb_fssd_term(&fs_sd);
690 
691 	} else
692 #endif	/* _KERNEL */
693 	{
694 		rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, flags, cr,
695 		    NULL);
696 
697 		if (rc == 0) {
698 			*ret_snode = smb_node_lookup(sr, op, cr, vp, name,
699 			    dnode, NULL);
700 
701 			if (*ret_snode == NULL)
702 				rc = ENOMEM;
703 
704 			VN_RELE(vp);
705 		}
706 	}
707 
708 	if (rc == 0)
709 		smb_node_notify_change(dnode, FILE_ACTION_ADDED, name);
710 
711 	return (rc);
712 }
713 
714 /*
715  * smb_fsop_remove
716  *
717  * All SMB functions should use this wrapper to ensure that
718  * the the calls are performed with the appropriate credentials.
719  * Please document any direct call to explain the reason
720  * for avoiding this wrapper.
721  *
722  * It is assumed that a reference exists on snode coming into this routine.
723  *
724  * A null smb_request might be passed to this function.
725  *
726  * Note that some stream "types" are "restricted" and only
727  * internal callers (cr == kcred) can remove those.
728  */
729 int
730 smb_fsop_remove(
731     smb_request_t	*sr,
732     cred_t		*cr,
733     smb_node_t		*dnode,
734     char		*name,
735     uint32_t		flags)
736 {
737 	smb_node_t	*fnode;
738 	char		*longname;
739 	char		*fname;
740 	char		*sname;
741 	int		rc;
742 
743 	ASSERT(cr);
744 	/*
745 	 * The state of the node could be SMB_NODE_STATE_DESTROYING if this
746 	 * function is called during the deletion of the node (because of
747 	 * DELETE_ON_CLOSE).
748 	 */
749 	ASSERT(dnode);
750 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
751 
752 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 ||
753 	    SMB_TREE_HAS_ACCESS(sr, ACE_DELETE) == 0)
754 		return (EACCES);
755 
756 	if (SMB_TREE_IS_READONLY(sr))
757 		return (EROFS);
758 
759 	fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
760 	sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
761 
762 	if (dnode->flags & NODE_XATTR_DIR) {
763 		if (cr != zone_kcred() && smb_strname_restricted(name)) {
764 			rc = EACCES;
765 			goto out;
766 		}
767 
768 		fnode = dnode->n_dnode;
769 		rc = smb_vop_stream_remove(fnode->vp, name, flags, cr);
770 
771 		/* notify change to the unnamed stream */
772 		if ((rc == 0) && fnode->n_dnode) {
773 			smb_node_notify_change(fnode->n_dnode,
774 			    FILE_ACTION_REMOVED_STREAM, fnode->od_name);
775 		}
776 	} else if (smb_is_stream_name(name)) {
777 		smb_stream_parse_name(name, fname, sname);
778 
779 		if (cr != zone_kcred() && smb_strname_restricted(sname)) {
780 			rc = EACCES;
781 			goto out;
782 		}
783 
784 		/*
785 		 * Look up the unnamed stream (i.e. fname).
786 		 * Unmangle processing will be done on fname
787 		 * as well as any link target.
788 		 */
789 
790 		rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
791 		    sr->tid_tree->t_snode, dnode, fname, &fnode);
792 
793 		if (rc != 0) {
794 			goto out;
795 		}
796 
797 		/*
798 		 * XXX
799 		 * Need to find out what permission is required by NTFS
800 		 * to remove a stream.
801 		 */
802 		rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr);
803 
804 		smb_node_release(fnode);
805 
806 		/* notify change to the unnamed stream */
807 		if (rc == 0) {
808 			smb_node_notify_change(dnode,
809 			    FILE_ACTION_REMOVED_STREAM, fname);
810 		}
811 	} else {
812 		rc = smb_vop_remove(dnode->vp, name, flags, cr);
813 
814 		if (rc == ENOENT) {
815 			if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
816 			    !smb_maybe_mangled(name)) {
817 				goto out;
818 			}
819 			longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
820 
821 			if (SMB_TREE_SUPPORTS_ABE(sr))
822 				flags |= SMB_ABE;
823 
824 			rc = smb_unmangle(dnode, name, longname, MAXNAMELEN,
825 			    flags);
826 
827 			if (rc == 0) {
828 				/*
829 				 * longname is the real (case-sensitive)
830 				 * on-disk name.
831 				 * We make sure we do a remove on this exact
832 				 * name, as the name was mangled and denotes
833 				 * a unique file.
834 				 */
835 				flags &= ~SMB_IGNORE_CASE;
836 				rc = smb_vop_remove(dnode->vp, longname,
837 				    flags, cr);
838 			}
839 			kmem_free(longname, MAXNAMELEN);
840 		}
841 		if (rc == 0) {
842 			smb_node_notify_change(dnode,
843 			    FILE_ACTION_REMOVED, name);
844 		}
845 	}
846 
847 out:
848 	kmem_free(fname, MAXNAMELEN);
849 	kmem_free(sname, MAXNAMELEN);
850 
851 	return (rc);
852 }
853 
854 /*
855  * smb_fsop_remove_streams
856  *
857  * This function removes a file's streams without removing the
858  * file itself.
859  *
860  * It is assumed that fnode is not a link.
861  */
862 uint32_t
863 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode)
864 {
865 	int rc, flags = 0;
866 	smb_odir_t *od;
867 	smb_odirent_t *odirent;
868 	uint32_t status;
869 	boolean_t eos;
870 
871 	ASSERT(sr);
872 	ASSERT(cr);
873 	ASSERT(fnode);
874 	ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
875 	ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
876 
877 	if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0)
878 		return (NT_STATUS_ACCESS_DENIED);
879 
880 	if (SMB_TREE_IS_READONLY(sr))
881 		return (NT_STATUS_ACCESS_DENIED);
882 
883 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
884 		flags = SMB_IGNORE_CASE;
885 
886 	if (SMB_TREE_SUPPORTS_CATIA(sr))
887 		flags |= SMB_CATIA;
888 
889 	/*
890 	 * NB: There aren't currently any restricted streams that could be
891 	 * removed by this function. If there ever are, be careful to exclude
892 	 * any restricted streams that we DON'T want to remove.
893 	 */
894 	status = smb_odir_openat(sr, fnode, &od, B_FALSE);
895 	switch (status) {
896 	case 0:
897 		break;
898 	case NT_STATUS_OBJECT_NAME_NOT_FOUND:
899 	case NT_STATUS_NO_SUCH_FILE:
900 	case NT_STATUS_NOT_SUPPORTED:
901 		/* No streams to remove. */
902 		return (0);
903 	default:
904 		return (status);
905 	}
906 
907 	odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
908 	for (;;) {
909 		rc = smb_odir_read(sr, od, odirent, &eos);
910 		if ((rc != 0) || (eos))
911 			break;
912 		(void) smb_vop_remove(od->d_dnode->vp, odirent->od_name,
913 		    flags, cr);
914 	}
915 	kmem_free(odirent, sizeof (smb_odirent_t));
916 	if (eos && rc == ENOENT)
917 		rc = 0;
918 
919 	smb_odir_close(od);
920 	smb_odir_release(od);
921 	if (rc)
922 		status = smb_errno2status(rc);
923 	return (status);
924 }
925 
926 /*
927  * smb_fsop_rmdir
928  *
929  * All SMB functions should use this wrapper to ensure that
930  * the the calls are performed with the appropriate credentials.
931  * Please document any direct call to explain the reason
932  * for avoiding this wrapper.
933  *
934  * It is assumed that a reference exists on snode coming into this routine.
935  */
936 int
937 smb_fsop_rmdir(
938     smb_request_t	*sr,
939     cred_t		*cr,
940     smb_node_t		*dnode,
941     char		*name,
942     uint32_t		flags)
943 {
944 	int		rc;
945 	char		*longname;
946 
947 	ASSERT(cr);
948 	/*
949 	 * The state of the node could be SMB_NODE_STATE_DESTROYING if this
950 	 * function is called during the deletion of the node (because of
951 	 * DELETE_ON_CLOSE).
952 	 */
953 	ASSERT(dnode);
954 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
955 
956 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 ||
957 	    SMB_TREE_HAS_ACCESS(sr, ACE_DELETE_CHILD) == 0)
958 		return (EACCES);
959 
960 	if (SMB_TREE_IS_READONLY(sr))
961 		return (EROFS);
962 
963 	rc = smb_vop_rmdir(dnode->vp, name, flags, cr);
964 
965 	if (rc == ENOENT) {
966 		if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
967 		    !smb_maybe_mangled(name)) {
968 			return (rc);
969 		}
970 
971 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
972 
973 		if (SMB_TREE_SUPPORTS_ABE(sr))
974 			flags |= SMB_ABE;
975 		rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
976 
977 		if (rc == 0) {
978 			/*
979 			 * longname is the real (case-sensitive)
980 			 * on-disk name.
981 			 * We make sure we do a rmdir on this exact
982 			 * name, as the name was mangled and denotes
983 			 * a unique directory.
984 			 */
985 			flags &= ~SMB_IGNORE_CASE;
986 			rc = smb_vop_rmdir(dnode->vp, longname, flags, cr);
987 		}
988 
989 		kmem_free(longname, MAXNAMELEN);
990 	}
991 
992 	if (rc == 0)
993 		smb_node_notify_change(dnode, FILE_ACTION_REMOVED, name);
994 
995 	return (rc);
996 }
997 
998 /*
999  * smb_fsop_getattr
1000  *
1001  * All SMB functions should use this wrapper to ensure that
1002  * the the calls are performed with the appropriate credentials.
1003  * Please document any direct call to explain the reason
1004  * for avoiding this wrapper.
1005  *
1006  * It is assumed that a reference exists on snode coming into this routine.
1007  */
1008 int
1009 smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1010     smb_attr_t *attr)
1011 {
1012 	smb_node_t *unnamed_node;
1013 	vnode_t *unnamed_vp = NULL;
1014 	uint32_t status;
1015 	uint32_t access = 0;
1016 	int flags = 0;
1017 	int rc;
1018 
1019 	ASSERT(cr);
1020 	ASSERT(snode);
1021 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1022 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1023 
1024 	if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0 ||
1025 	    SMB_TREE_HAS_ACCESS(sr, ACE_READ_ATTRIBUTES) == 0)
1026 		return (EACCES);
1027 
1028 	/* sr could be NULL in some cases */
1029 	if (sr && sr->fid_ofile) {
1030 		/* if uid and/or gid is requested */
1031 		if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID))
1032 			access |= READ_CONTROL;
1033 
1034 		/* if anything else is also requested */
1035 		if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID))
1036 			access |= FILE_READ_ATTRIBUTES;
1037 
1038 		status = smb_ofile_access(sr->fid_ofile, cr, access);
1039 		if (status != NT_STATUS_SUCCESS)
1040 			return (EACCES);
1041 
1042 		if (smb_tree_has_feature(sr->tid_tree,
1043 		    SMB_TREE_ACEMASKONACCESS))
1044 			flags = ATTR_NOACLCHECK;
1045 	}
1046 
1047 	unnamed_node = SMB_IS_STREAM(snode);
1048 
1049 	if (unnamed_node) {
1050 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1051 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1052 		unnamed_vp = unnamed_node->vp;
1053 	}
1054 
1055 	rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr);
1056 
1057 	if ((rc == 0) && smb_node_is_dfslink(snode)) {
1058 		/* a DFS link should be treated as a directory */
1059 		attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
1060 	}
1061 
1062 	return (rc);
1063 }
1064 
1065 /*
1066  * smb_fsop_link
1067  *
1068  * All SMB functions should use this smb_vop_link wrapper to ensure that
1069  * the smb_vop_link is performed with the appropriate credentials.
1070  * Please document any direct call to smb_vop_link to explain the reason
1071  * for avoiding this wrapper.
1072  *
1073  * It is assumed that references exist on from_dnode and to_dnode coming
1074  * into this routine.
1075  */
1076 int
1077 smb_fsop_link(smb_request_t *sr, cred_t *cr, smb_node_t *from_fnode,
1078     smb_node_t *to_dnode, char *to_name)
1079 {
1080 	char	*longname = NULL;
1081 	int	flags = 0;
1082 	int	rc;
1083 
1084 	ASSERT(sr);
1085 	ASSERT(sr->tid_tree);
1086 	ASSERT(cr);
1087 	ASSERT(to_dnode);
1088 	ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC);
1089 	ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1090 	ASSERT(from_fnode);
1091 	ASSERT(from_fnode->n_magic == SMB_NODE_MAGIC);
1092 	ASSERT(from_fnode->n_state != SMB_NODE_STATE_DESTROYING);
1093 
1094 	if (SMB_TREE_CONTAINS_NODE(sr, from_fnode) == 0)
1095 		return (EACCES);
1096 
1097 	if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0)
1098 		return (EACCES);
1099 
1100 	if (SMB_TREE_IS_READONLY(sr))
1101 		return (EROFS);
1102 
1103 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1104 		flags = SMB_IGNORE_CASE;
1105 	if (SMB_TREE_SUPPORTS_CATIA(sr))
1106 		flags |= SMB_CATIA;
1107 	if (SMB_TREE_SUPPORTS_ABE(sr))
1108 		flags |= SMB_ABE;
1109 
1110 	if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(to_name)) {
1111 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1112 		rc = smb_unmangle(to_dnode, to_name, longname,
1113 		    MAXNAMELEN, flags);
1114 		kmem_free(longname, MAXNAMELEN);
1115 
1116 		if (rc == 0)
1117 			rc = EEXIST;
1118 		if (rc != ENOENT)
1119 			return (rc);
1120 	}
1121 
1122 	rc = smb_vop_link(to_dnode->vp, from_fnode->vp, to_name, flags, cr);
1123 
1124 	if (rc == 0)
1125 		smb_node_notify_change(to_dnode, FILE_ACTION_ADDED, to_name);
1126 
1127 	return (rc);
1128 }
1129 
1130 /*
1131  * smb_fsop_rename
1132  *
1133  * All SMB functions should use this smb_vop_rename wrapper to ensure that
1134  * the smb_vop_rename is performed with the appropriate credentials.
1135  * Please document any direct call to smb_vop_rename to explain the reason
1136  * for avoiding this wrapper.
1137  *
1138  * It is assumed that references exist on from_dnode and to_dnode coming
1139  * into this routine.
1140  */
1141 int
1142 smb_fsop_rename(
1143     smb_request_t *sr,
1144     cred_t *cr,
1145     smb_node_t *from_dnode,
1146     char *from_name,
1147     smb_node_t *to_dnode,
1148     char *to_name)
1149 {
1150 	smb_node_t *from_snode;
1151 	smb_attr_t from_attr;
1152 	vnode_t *from_vp;
1153 	int flags = 0, ret_flags;
1154 	int rc;
1155 	boolean_t isdir;
1156 
1157 	ASSERT(cr);
1158 	ASSERT(from_dnode);
1159 	ASSERT(from_dnode->n_magic == SMB_NODE_MAGIC);
1160 	ASSERT(from_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1161 
1162 	ASSERT(to_dnode);
1163 	ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC);
1164 	ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1165 
1166 	if (SMB_TREE_CONTAINS_NODE(sr, from_dnode) == 0)
1167 		return (EACCES);
1168 
1169 	if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0)
1170 		return (EACCES);
1171 
1172 	ASSERT(sr);
1173 	ASSERT(sr->tid_tree);
1174 	if (SMB_TREE_IS_READONLY(sr))
1175 		return (EROFS);
1176 
1177 	/*
1178 	 * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE
1179 	 * here.
1180 	 *
1181 	 * A case-sensitive rename is always done in this routine
1182 	 * because we are using the on-disk name from an earlier lookup.
1183 	 * If a mangled name was passed in by the caller (denoting a
1184 	 * deterministic lookup), then the exact file must be renamed
1185 	 * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or
1186 	 * else the underlying file system might return a "first-match"
1187 	 * on this on-disk name, possibly resulting in the wrong file).
1188 	 */
1189 
1190 	if (SMB_TREE_SUPPORTS_CATIA(sr))
1191 		flags |= SMB_CATIA;
1192 
1193 	/*
1194 	 * XXX: Lock required through smb_node_release() below?
1195 	 */
1196 
1197 	rc = smb_vop_lookup(from_dnode->vp, from_name, &from_vp, NULL,
1198 	    flags, &ret_flags, NULL, &from_attr, cr);
1199 
1200 	if (rc != 0)
1201 		return (rc);
1202 
1203 	/*
1204 	 * Make sure "from" vp is not a mount point.
1205 	 */
1206 	if (from_vp->v_type == VDIR && vn_ismntpt(from_vp)) {
1207 		VN_RELE(from_vp);
1208 		return (EACCES);
1209 	}
1210 
1211 	if (from_attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) {
1212 		VN_RELE(from_vp);
1213 		return (EACCES);
1214 	}
1215 
1216 	isdir = ((from_attr.sa_dosattr & FILE_ATTRIBUTE_DIRECTORY) != 0);
1217 
1218 	if ((isdir && SMB_TREE_HAS_ACCESS(sr,
1219 	    ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY) !=
1220 	    (ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY)) ||
1221 	    (!isdir && SMB_TREE_HAS_ACCESS(sr, ACE_DELETE | ACE_ADD_FILE) !=
1222 	    (ACE_DELETE | ACE_ADD_FILE))) {
1223 		VN_RELE(from_vp);
1224 		return (EACCES);
1225 	}
1226 
1227 	/*
1228 	 * SMB checks access on open and retains an access granted
1229 	 * mask for use while the file is open.  ACL changes should
1230 	 * not affect access to an open file.
1231 	 *
1232 	 * If the rename is being performed on an ofile:
1233 	 * - Check the ofile's access granted mask to see if the
1234 	 *   rename is permitted - requires DELETE access.
1235 	 * - If the file system does access checking, set the
1236 	 *   ATTR_NOACLCHECK flag to ensure that the file system
1237 	 *   does not check permissions on subsequent calls.
1238 	 */
1239 	if (sr && sr->fid_ofile) {
1240 		rc = smb_ofile_access(sr->fid_ofile, cr, DELETE);
1241 		if (rc != NT_STATUS_SUCCESS) {
1242 			VN_RELE(from_vp);
1243 			return (EACCES);
1244 		}
1245 
1246 		/*
1247 		 * TODO: avoid ACL check for source file.
1248 		 * smb_vop_rename() passes its own flags to VOP_RENAME,
1249 		 * and ZFS doesn't pass it on to zfs_zaccess_rename().
1250 		 */
1251 	}
1252 
1253 	rc = smb_vop_rename(from_dnode->vp, from_name, to_dnode->vp,
1254 	    to_name, flags, cr);
1255 
1256 	if (rc == 0) {
1257 		from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name,
1258 		    from_dnode, NULL);
1259 
1260 		if (from_snode == NULL) {
1261 			rc = ENOMEM;
1262 		} else {
1263 			smb_node_rename(from_dnode, from_snode,
1264 			    to_dnode, to_name);
1265 			smb_node_release(from_snode);
1266 		}
1267 	}
1268 	VN_RELE(from_vp);
1269 
1270 	if (rc == 0) {
1271 		if (from_dnode == to_dnode) {
1272 			smb_node_notify_change(from_dnode,
1273 			    FILE_ACTION_RENAMED_OLD_NAME, from_name);
1274 			smb_node_notify_change(to_dnode,
1275 			    FILE_ACTION_RENAMED_NEW_NAME, to_name);
1276 		} else {
1277 			smb_node_notify_change(from_dnode,
1278 			    FILE_ACTION_REMOVED, from_name);
1279 			smb_node_notify_change(to_dnode,
1280 			    FILE_ACTION_ADDED, to_name);
1281 		}
1282 	}
1283 
1284 	/* XXX: unlock */
1285 
1286 	return (rc);
1287 }
1288 
1289 /*
1290  * smb_fsop_setattr
1291  *
1292  * All SMB functions should use this wrapper to ensure that
1293  * the the calls are performed with the appropriate credentials.
1294  * Please document any direct call to explain the reason
1295  * for avoiding this wrapper.
1296  *
1297  * It is assumed that a reference exists on snode coming into
1298  * this function.
1299  * A null smb_request might be passed to this function.
1300  */
1301 int
1302 smb_fsop_setattr(
1303     smb_request_t	*sr,
1304     cred_t		*cr,
1305     smb_node_t		*snode,
1306     smb_attr_t		*set_attr)
1307 {
1308 	smb_node_t *unnamed_node;
1309 	vnode_t *unnamed_vp = NULL;
1310 	uint32_t status;
1311 	uint32_t access;
1312 	int rc = 0;
1313 	int flags = 0;
1314 	uint_t sa_mask;
1315 
1316 	ASSERT(cr);
1317 	ASSERT(snode);
1318 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1319 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1320 
1321 	if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0)
1322 		return (EACCES);
1323 
1324 	if (SMB_TREE_IS_READONLY(sr))
1325 		return (EROFS);
1326 
1327 	if (SMB_TREE_HAS_ACCESS(sr,
1328 	    ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0)
1329 		return (EACCES);
1330 
1331 	/*
1332 	 * SMB checks access on open and retains an access granted
1333 	 * mask for use while the file is open.  ACL changes should
1334 	 * not affect access to an open file.
1335 	 *
1336 	 * If the setattr is being performed on an ofile:
1337 	 * - Check the ofile's access granted mask to see if the
1338 	 *   setattr is permitted.
1339 	 *   UID, GID - require WRITE_OWNER
1340 	 *   SIZE, ALLOCSZ - require FILE_WRITE_DATA
1341 	 *   all other attributes require FILE_WRITE_ATTRIBUTES
1342 	 *
1343 	 * - If the file system does access checking, set the
1344 	 *   ATTR_NOACLCHECK flag to ensure that the file system
1345 	 *   does not check permissions on subsequent calls.
1346 	 */
1347 	if (sr && sr->fid_ofile) {
1348 		sa_mask = set_attr->sa_mask;
1349 		access = 0;
1350 
1351 		if (sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ)) {
1352 			access |= FILE_WRITE_DATA;
1353 			sa_mask &= ~(SMB_AT_SIZE | SMB_AT_ALLOCSZ);
1354 		}
1355 
1356 		if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) {
1357 			access |= WRITE_OWNER;
1358 			sa_mask &= ~(SMB_AT_UID|SMB_AT_GID);
1359 		}
1360 
1361 		if (sa_mask)
1362 			access |= FILE_WRITE_ATTRIBUTES;
1363 
1364 		status = smb_ofile_access(sr->fid_ofile, cr, access);
1365 		if (status != NT_STATUS_SUCCESS)
1366 			return (EACCES);
1367 
1368 		if (smb_tree_has_feature(sr->tid_tree,
1369 		    SMB_TREE_ACEMASKONACCESS))
1370 			flags = ATTR_NOACLCHECK;
1371 	}
1372 
1373 	unnamed_node = SMB_IS_STREAM(snode);
1374 
1375 	if (unnamed_node) {
1376 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1377 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1378 		unnamed_vp = unnamed_node->vp;
1379 	}
1380 
1381 	rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr);
1382 	return (rc);
1383 }
1384 
1385 /*
1386  * Support for SMB2 setinfo FileValidDataLengthInformation.
1387  * Free (zero out) data in the range off, off+len
1388  */
1389 int
1390 smb_fsop_freesp(
1391     smb_request_t	*sr,
1392     cred_t		*cr,
1393     smb_ofile_t		*ofile,
1394     off64_t		off,
1395     off64_t		len)
1396 {
1397 	flock64_t flk;
1398 	smb_node_t *node = ofile->f_node;
1399 	uint32_t status;
1400 	uint32_t access = FILE_WRITE_DATA;
1401 	int rc;
1402 
1403 	ASSERT(cr);
1404 	ASSERT(node);
1405 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
1406 	ASSERT(node->n_state != SMB_NODE_STATE_DESTROYING);
1407 
1408 	if (SMB_TREE_CONTAINS_NODE(sr, node) == 0)
1409 		return (EACCES);
1410 
1411 	if (SMB_TREE_IS_READONLY(sr))
1412 		return (EROFS);
1413 
1414 	if (SMB_TREE_HAS_ACCESS(sr, access) == 0)
1415 		return (EACCES);
1416 
1417 	/*
1418 	 * SMB checks access on open and retains an access granted
1419 	 * mask for use while the file is open.  ACL changes should
1420 	 * not affect access to an open file.
1421 	 *
1422 	 * If the setattr is being performed on an ofile:
1423 	 * - Check the ofile's access granted mask to see if this
1424 	 *   modification should be permitted (FILE_WRITE_DATA)
1425 	 */
1426 	status = smb_ofile_access(sr->fid_ofile, cr, access);
1427 	if (status != NT_STATUS_SUCCESS)
1428 		return (EACCES);
1429 
1430 	bzero(&flk, sizeof (flk));
1431 	flk.l_start = off;
1432 	flk.l_len = len;
1433 
1434 	rc = smb_vop_space(node->vp, F_FREESP, &flk, FWRITE, 0LL, cr);
1435 	return (rc);
1436 }
1437 
1438 /*
1439  * smb_fsop_read
1440  *
1441  * All SMB functions should use this wrapper to ensure that
1442  * the the calls are performed with the appropriate credentials.
1443  * Please document any direct call to explain the reason
1444  * for avoiding this wrapper.
1445  *
1446  * It is assumed that a reference exists on snode coming into this routine.
1447  * Note that ofile may be different from sr->fid_ofile, or may be NULL.
1448  */
1449 int
1450 smb_fsop_read(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1451     smb_ofile_t *ofile, uio_t *uio, int ioflag)
1452 {
1453 	caller_context_t ct;
1454 	cred_t *kcr = zone_kcred();
1455 	uint32_t amask;
1456 	int svmand;
1457 	int rc;
1458 
1459 	ASSERT(cr);
1460 	ASSERT(snode);
1461 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1462 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1463 
1464 	ASSERT(sr);
1465 
1466 	if (ofile != NULL) {
1467 		/*
1468 		 * Check tree access.  Not SMB_TREE_HAS_ACCESS
1469 		 * because we need to use ofile->f_tree
1470 		 */
1471 		if ((ofile->f_tree->t_access & ACE_READ_DATA) == 0)
1472 			return (EACCES);
1473 
1474 		/*
1475 		 * Check ofile access.  Use in-line smb_ofile_access
1476 		 * so we can check both amask bits at the same time.
1477 		 * If any bit in amask is granted, allow this read.
1478 		 */
1479 		amask = FILE_READ_DATA;
1480 		if (sr->smb_flg2 & SMB_FLAGS2_READ_IF_EXECUTE)
1481 			amask |= FILE_EXECUTE;
1482 		if (cr != kcr && (ofile->f_granted_access & amask) == 0)
1483 			return (EACCES);
1484 	}
1485 
1486 	/*
1487 	 * Streams permission are checked against the unnamed stream,
1488 	 * but in FS level they have their own permissions. To avoid
1489 	 * rejection by FS due to lack of permission on the actual
1490 	 * extended attr kcred is passed for streams.
1491 	 */
1492 	if (SMB_IS_STREAM(snode))
1493 		cr = kcr;
1494 
1495 	smb_node_start_crit(snode, RW_READER);
1496 	rc = nbl_svmand(snode->vp, kcr, &svmand);
1497 	if (rc) {
1498 		smb_node_end_crit(snode);
1499 		return (rc);
1500 	}
1501 
1502 	/*
1503 	 * Note: SMB allows a zero-byte read, which should not
1504 	 * conflict with any locks.  However nbl_lock_conflict
1505 	 * takes a zero-byte length as lock to EOF, so we must
1506 	 * special case that here.
1507 	 */
1508 	if (uio->uio_resid > 0) {
1509 		ct = smb_ct;
1510 		if (ofile != NULL)
1511 			ct.cc_pid = ofile->f_uniqid;
1512 		rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset,
1513 		    uio->uio_resid, svmand, &ct);
1514 		if (rc != 0) {
1515 			smb_node_end_crit(snode);
1516 			return (ERANGE);
1517 		}
1518 	}
1519 
1520 	rc = smb_vop_read(snode->vp, uio, ioflag, cr);
1521 	smb_node_end_crit(snode);
1522 
1523 	return (rc);
1524 }
1525 
1526 /*
1527  * smb_fsop_write
1528  *
1529  * It is assumed that a reference exists on snode coming into this routine.
1530  * Note that ofile may be different from sr->fid_ofile, or may be NULL.
1531  */
1532 int
1533 smb_fsop_write(
1534     smb_request_t *sr,
1535     cred_t *cr,
1536     smb_node_t *snode,
1537     smb_ofile_t *ofile,
1538     uio_t *uio,
1539     uint32_t *lcount,
1540     int ioflag)
1541 {
1542 	caller_context_t ct;
1543 	smb_attr_t attr;
1544 	cred_t *kcr = zone_kcred();
1545 	smb_node_t *u_node;
1546 	vnode_t *u_vp = NULL;
1547 	vnode_t *vp;
1548 	uint32_t amask;
1549 	int svmand;
1550 	int rc;
1551 
1552 	ASSERT(cr);
1553 	ASSERT(snode);
1554 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1555 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1556 
1557 	ASSERT(sr);
1558 	vp = snode->vp;
1559 
1560 	if (ofile != NULL) {
1561 		amask = FILE_WRITE_DATA | FILE_APPEND_DATA;
1562 
1563 		/* Check tree access. */
1564 		if ((ofile->f_tree->t_access & amask) == 0)
1565 			return (EROFS);
1566 
1567 		/*
1568 		 * Check ofile access.  Use in-line smb_ofile_access
1569 		 * so we can check both amask bits at the same time.
1570 		 * If any bit in amask is granted, allow this write.
1571 		 */
1572 		if (cr != kcr && (ofile->f_granted_access & amask) == 0)
1573 			return (EACCES);
1574 	}
1575 
1576 	/*
1577 	 * Streams permission are checked against the unnamed stream,
1578 	 * but in FS level they have their own permissions. To avoid
1579 	 * rejection by FS due to lack of permission on the actual
1580 	 * extended attr kcred is passed for streams.
1581 	 */
1582 	u_node = SMB_IS_STREAM(snode);
1583 	if (u_node != NULL) {
1584 		ASSERT(u_node->n_magic == SMB_NODE_MAGIC);
1585 		ASSERT(u_node->n_state != SMB_NODE_STATE_DESTROYING);
1586 		u_vp = u_node->vp;
1587 		cr = kcr;
1588 	}
1589 
1590 	smb_node_start_crit(snode, RW_READER);
1591 	rc = nbl_svmand(vp, kcr, &svmand);
1592 	if (rc) {
1593 		smb_node_end_crit(snode);
1594 		return (rc);
1595 	}
1596 
1597 	/*
1598 	 * Note: SMB allows a zero-byte write, which should not
1599 	 * conflict with any locks.  However nbl_lock_conflict
1600 	 * takes a zero-byte length as lock to EOF, so we must
1601 	 * special case that here.
1602 	 */
1603 	if (uio->uio_resid > 0) {
1604 		ct = smb_ct;
1605 		if (ofile != NULL)
1606 			ct.cc_pid = ofile->f_uniqid;
1607 		rc = nbl_lock_conflict(vp, NBL_WRITE, uio->uio_loffset,
1608 		    uio->uio_resid, svmand, &ct);
1609 		if (rc != 0) {
1610 			smb_node_end_crit(snode);
1611 			return (ERANGE);
1612 		}
1613 	}
1614 
1615 	rc = smb_vop_write(vp, uio, ioflag, lcount, cr);
1616 
1617 	/*
1618 	 * Once the mtime has been set via this ofile, the
1619 	 * automatic mtime changes from writes via this ofile
1620 	 * should cease, preserving the mtime that was set.
1621 	 * See: [MS-FSA] 2.1.5.14 and smb_node_setattr.
1622 	 *
1623 	 * The VFS interface does not offer a way to ask it to
1624 	 * skip the mtime updates, so we simulate the desired
1625 	 * behavior by re-setting the mtime after writes on a
1626 	 * handle where the mtime has been set.
1627 	 */
1628 	if (ofile != NULL &&
1629 	    (ofile->f_pending_attr.sa_mask & SMB_AT_MTIME) != 0) {
1630 		bcopy(&ofile->f_pending_attr, &attr, sizeof (attr));
1631 		attr.sa_mask = SMB_AT_MTIME;
1632 		(void) smb_vop_setattr(vp, u_vp, &attr, 0, kcr);
1633 	}
1634 
1635 	smb_node_end_crit(snode);
1636 
1637 	return (rc);
1638 }
1639 
1640 /*
1641  * Find the next allocated range starting at or after
1642  * the offset (*datap), returning the start/end of
1643  * that range in (*datap, *holep)
1644  */
1645 int
1646 smb_fsop_next_alloc_range(
1647     cred_t *cr,
1648     smb_node_t *node,
1649     off64_t *datap,
1650     off64_t *holep)
1651 {
1652 	int err;
1653 
1654 	err = smb_vop_ioctl(node->vp, _FIO_SEEK_DATA, datap, cr);
1655 	if (err != 0)
1656 		return (err);
1657 
1658 	*holep = *datap;
1659 	err = smb_vop_ioctl(node->vp, _FIO_SEEK_HOLE, holep, cr);
1660 
1661 	return (err);
1662 }
1663 
1664 /*
1665  * smb_fsop_statfs
1666  *
1667  * This is a wrapper function used for stat operations.
1668  */
1669 int
1670 smb_fsop_statfs(
1671     cred_t *cr,
1672     smb_node_t *snode,
1673     struct statvfs64 *statp)
1674 {
1675 	ASSERT(cr);
1676 	ASSERT(snode);
1677 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1678 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1679 
1680 	return (smb_vop_statfs(snode->vp, statp, cr));
1681 }
1682 
1683 /*
1684  * smb_fsop_access
1685  *
1686  * Named streams do not have separate permissions from the associated
1687  * unnamed stream.  Thus, if node is a named stream, the permissions
1688  * check will be performed on the associated unnamed stream.
1689  *
1690  * However, our named streams do have their own quarantine attribute,
1691  * separate from that on the unnamed stream. If READ or EXECUTE
1692  * access has been requested on a named stream, an additional access
1693  * check is performed on the named stream in case it has been
1694  * quarantined.  kcred is used to avoid issues with the permissions
1695  * set on the extended attribute file representing the named stream.
1696  *
1697  * Note that some stream "types" are "restricted" and only
1698  * internal callers (cr == kcred) can access those.
1699  */
1700 int
1701 smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1702     uint32_t faccess)
1703 {
1704 	int access = 0;
1705 	int error;
1706 	vnode_t *dir_vp;
1707 	boolean_t acl_check = B_TRUE;
1708 	smb_node_t *unnamed_node;
1709 
1710 	ASSERT(sr);
1711 	ASSERT(cr);
1712 	ASSERT(snode);
1713 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1714 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1715 
1716 	if (SMB_TREE_IS_READONLY(sr)) {
1717 		if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA|
1718 		    FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES|
1719 		    DELETE|WRITE_DAC|WRITE_OWNER)) {
1720 			return (NT_STATUS_ACCESS_DENIED);
1721 		}
1722 	}
1723 
1724 	if (smb_node_is_reparse(snode) && (faccess & DELETE))
1725 		return (NT_STATUS_ACCESS_DENIED);
1726 
1727 	unnamed_node = SMB_IS_STREAM(snode);
1728 	if (unnamed_node) {
1729 		cred_t *kcr = zone_kcred();
1730 
1731 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1732 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1733 
1734 		if (cr != kcr && smb_strname_restricted(snode->od_name))
1735 			return (NT_STATUS_ACCESS_DENIED);
1736 
1737 		/*
1738 		 * Perform VREAD access check on the named stream in case it
1739 		 * is quarantined. kcred is passed to smb_vop_access so it
1740 		 * doesn't fail due to lack of permission.
1741 		 */
1742 		if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) {
1743 			error = smb_vop_access(snode->vp, VREAD,
1744 			    0, NULL, kcr);
1745 			if (error)
1746 				return (NT_STATUS_ACCESS_DENIED);
1747 		}
1748 
1749 		/*
1750 		 * Streams authorization should be performed against the
1751 		 * unnamed stream.
1752 		 */
1753 		snode = unnamed_node;
1754 	}
1755 
1756 	if (faccess & ACCESS_SYSTEM_SECURITY) {
1757 		/*
1758 		 * This permission is required for reading/writing SACL and
1759 		 * it's not part of DACL. It's only granted via proper
1760 		 * privileges.
1761 		 */
1762 		if (!smb_user_has_security_priv(sr->uid_user, cr))
1763 			return (NT_STATUS_PRIVILEGE_NOT_HELD);
1764 
1765 		faccess &= ~ACCESS_SYSTEM_SECURITY;
1766 	}
1767 
1768 	/* Links don't have ACL */
1769 	if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) ||
1770 	    smb_node_is_symlink(snode))
1771 		acl_check = B_FALSE;
1772 
1773 	/* Deny access based on the share access mask */
1774 
1775 	if ((faccess & ~sr->tid_tree->t_access) != 0)
1776 		return (NT_STATUS_ACCESS_DENIED);
1777 
1778 	if (acl_check) {
1779 		dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
1780 		error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp,
1781 		    cr);
1782 	} else {
1783 		/*
1784 		 * FS doesn't understand 32-bit mask, need to map
1785 		 */
1786 		if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))
1787 			access |= VWRITE;
1788 
1789 		if (faccess & FILE_READ_DATA)
1790 			access |= VREAD;
1791 
1792 		if (faccess & FILE_EXECUTE)
1793 			access |= VEXEC;
1794 
1795 		error = smb_vop_access(snode->vp, access, 0, NULL, cr);
1796 	}
1797 
1798 	return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS);
1799 }
1800 
1801 /*
1802  * smb_fsop_lookup_name()
1803  *
1804  * Lookup both the file and stream specified in 'name'.
1805  * If name indicates that the file is a stream file, perform
1806  * stream specific lookup, otherwise call smb_fsop_lookup.
1807  *
1808  * On success, returns the found node in *ret_snode. This will be either a named
1809  * or unnamed stream node, depending on the name specified.
1810  *
1811  * Return an error if the looked-up file is in outside the tree.
1812  * (Required when invoked from open path.)
1813  *
1814  * Case sensitivity flags (SMB_IGNORE_CASE, SMB_CASE_SENSITIVE):
1815  * if SMB_CASE_SENSITIVE is set, the SMB_IGNORE_CASE flag will NOT be set
1816  * based on the tree's case sensitivity. However, if the SMB_IGNORE_CASE
1817  * flag is set in the flags value passed as a parameter, a case insensitive
1818  * lookup WILL be done (regardless of whether SMB_CASE_SENSITIVE is set
1819  * or not).
1820  */
1821 
1822 int
1823 smb_fsop_lookup_name(
1824     smb_request_t *sr,
1825     cred_t	*cr,
1826     int		flags,
1827     smb_node_t	*root_node,
1828     smb_node_t	*dnode,
1829     char	*name,
1830     smb_node_t	**ret_snode)
1831 {
1832 	char *sname = NULL;
1833 	int rc;
1834 	smb_node_t *tmp_node;
1835 
1836 	ASSERT(ret_snode != NULL);
1837 
1838 	rc = smb_fsop_lookup_file(sr, cr, flags, root_node, dnode, name,
1839 	    &sname, ret_snode);
1840 
1841 	if (rc != 0 || sname == NULL)
1842 		return (rc);
1843 
1844 	tmp_node = *ret_snode;
1845 	rc = smb_fsop_lookup_stream(sr, cr, flags, root_node, tmp_node, sname,
1846 	    ret_snode);
1847 	kmem_free(sname, MAXNAMELEN);
1848 	smb_node_release(tmp_node);
1849 
1850 	return (rc);
1851 }
1852 
1853 /*
1854  * smb_fsop_lookup_file()
1855  *
1856  * Look up of the file portion of 'name'. If a Stream is specified,
1857  * return the stream name in 'sname', which this allocates.
1858  * The caller must free 'sname'.
1859  *
1860  * Return an error if the looked-up file is outside the tree.
1861  * (Required when invoked from open path.)
1862  *
1863  * Case sensitivity flags (SMB_IGNORE_CASE, SMB_CASE_SENSITIVE):
1864  * if SMB_CASE_SENSITIVE is set, the SMB_IGNORE_CASE flag will NOT be set
1865  * based on the tree's case sensitivity. However, if the SMB_IGNORE_CASE
1866  * flag is set in the flags value passed as a parameter, a case insensitive
1867  * lookup WILL be done (regardless of whether SMB_CASE_SENSITIVE is set
1868  * or not).
1869  */
1870 
1871 int
1872 smb_fsop_lookup_file(
1873     smb_request_t *sr,
1874     cred_t	*cr,
1875     int		flags,
1876     smb_node_t	*root_node,
1877     smb_node_t	*dnode,
1878     char	*name,
1879     char	**sname,
1880     smb_node_t	**ret_snode)
1881 {
1882 	char		*fname;
1883 	int		rc;
1884 
1885 	ASSERT(cr);
1886 	ASSERT(dnode);
1887 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
1888 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
1889 	ASSERT(ret_snode != NULL);
1890 
1891 	/*
1892 	 * The following check is required for streams processing, below
1893 	 */
1894 
1895 	if (!(flags & SMB_CASE_SENSITIVE)) {
1896 		if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1897 			flags |= SMB_IGNORE_CASE;
1898 	}
1899 
1900 	*sname = NULL;
1901 	if (smb_is_stream_name(name)) {
1902 		*sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1903 		fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1904 		smb_stream_parse_name(name, fname, *sname);
1905 
1906 		/*
1907 		 * Look up the unnamed stream (i.e. fname).
1908 		 * Unmangle processing will be done on fname
1909 		 * as well as any link target.
1910 		 */
1911 		rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode,
1912 		    fname, ret_snode);
1913 		kmem_free(fname, MAXNAMELEN);
1914 	} else {
1915 		rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, name,
1916 		    ret_snode);
1917 	}
1918 
1919 	if (rc == 0) {
1920 		ASSERT(ret_snode);
1921 		if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) {
1922 			smb_node_release(*ret_snode);
1923 			*ret_snode = NULL;
1924 			rc = EACCES;
1925 		}
1926 	}
1927 
1928 	if (rc != 0 && *sname != NULL) {
1929 		kmem_free(*sname, MAXNAMELEN);
1930 		*sname = NULL;
1931 	}
1932 	return (rc);
1933 }
1934 
1935 /*
1936  * smb_fsop_lookup_stream
1937  *
1938  * The file exists, see if the stream exists.
1939  */
1940 int
1941 smb_fsop_lookup_stream(
1942     smb_request_t *sr,
1943     cred_t *cr,
1944     int flags,
1945     smb_node_t *root_node,
1946     smb_node_t *fnode,
1947     char *sname,
1948     smb_node_t **ret_snode)
1949 {
1950 	char		*od_name;
1951 	vnode_t		*xattrdirvp;
1952 	vnode_t		*vp;
1953 	int rc;
1954 
1955 	/*
1956 	 * The following check is required for streams processing, below
1957 	 */
1958 
1959 	if (!(flags & SMB_CASE_SENSITIVE)) {
1960 		if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1961 			flags |= SMB_IGNORE_CASE;
1962 	}
1963 
1964 	od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1965 
1966 	/*
1967 	 * od_name is the on-disk name of the stream, except
1968 	 * without the prepended stream prefix (SMB_STREAM_PREFIX)
1969 	 */
1970 
1971 	rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name,
1972 	    &xattrdirvp, flags, root_node->vp, cr);
1973 
1974 	if (rc != 0) {
1975 		kmem_free(od_name, MAXNAMELEN);
1976 		return (rc);
1977 	}
1978 
1979 	*ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
1980 	    vp, od_name);
1981 
1982 	kmem_free(od_name, MAXNAMELEN);
1983 	VN_RELE(xattrdirvp);
1984 	VN_RELE(vp);
1985 
1986 	if (*ret_snode == NULL)
1987 		return (ENOMEM);
1988 
1989 	return (rc);
1990 }
1991 
1992 /*
1993  * smb_fsop_lookup
1994  *
1995  * All SMB functions should use this smb_vop_lookup wrapper to ensure that
1996  * the smb_vop_lookup is performed with the appropriate credentials and using
1997  * case insensitive compares. Please document any direct call to smb_vop_lookup
1998  * to explain the reason for avoiding this wrapper.
1999  *
2000  * It is assumed that a reference exists on dnode coming into this routine
2001  * (and that it is safe from deallocation).
2002  *
2003  * Same with the root_node.
2004  *
2005  * *ret_snode is returned with a reference upon success.  No reference is
2006  * taken if an error is returned.
2007  *
2008  * Note: The returned ret_snode may be in a child mount.  This is ok for
2009  * readdir.
2010  *
2011  * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent
2012  * operations on files not in the parent mount.
2013  *
2014  * Case sensitivity flags (SMB_IGNORE_CASE, SMB_CASE_SENSITIVE):
2015  * if SMB_CASE_SENSITIVE is set, the SMB_IGNORE_CASE flag will NOT be set
2016  * based on the tree's case sensitivity. However, if the SMB_IGNORE_CASE
2017  * flag is set in the flags value passed as a parameter, a case insensitive
2018  * lookup WILL be done (regardless of whether SMB_CASE_SENSITIVE is set
2019  * or not).
2020  */
2021 int
2022 smb_fsop_lookup(
2023     smb_request_t *sr,
2024     cred_t	*cr,
2025     int		flags,
2026     smb_node_t	*root_node,
2027     smb_node_t	*dnode,
2028     char	*name,
2029     smb_node_t	**ret_snode)
2030 {
2031 	smb_node_t *lnk_target_node;
2032 	smb_node_t *lnk_dnode;
2033 	char *longname;
2034 	char *od_name;
2035 	vnode_t *vp;
2036 	int rc;
2037 	int ret_flags;
2038 	smb_attr_t attr;
2039 
2040 	ASSERT(cr);
2041 	ASSERT(dnode);
2042 	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
2043 	ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
2044 
2045 	if (name == NULL)
2046 		return (EINVAL);
2047 
2048 	if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
2049 		return (EACCES);
2050 
2051 	if (!(flags & SMB_CASE_SENSITIVE)) {
2052 		if (SMB_TREE_IS_CASEINSENSITIVE(sr))
2053 			flags |= SMB_IGNORE_CASE;
2054 	}
2055 	if (SMB_TREE_SUPPORTS_CATIA(sr))
2056 		flags |= SMB_CATIA;
2057 	if (SMB_TREE_SUPPORTS_ABE(sr))
2058 		flags |= SMB_ABE;
2059 
2060 	/*
2061 	 * Can have "" or "." when opening named streams on a directory.
2062 	 */
2063 	if (name[0] == '\0' || (name[0] == '.' && name[1] == '\0')) {
2064 		smb_node_ref(dnode);
2065 		*ret_snode = dnode;
2066 		return (0);
2067 	}
2068 
2069 	od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2070 
2071 	rc = smb_vop_lookup(dnode->vp, name, &vp, od_name, flags,
2072 	    &ret_flags, root_node ? root_node->vp : NULL, &attr, cr);
2073 
2074 	if (rc != 0) {
2075 		if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
2076 		    !smb_maybe_mangled(name)) {
2077 			kmem_free(od_name, MAXNAMELEN);
2078 			return (rc);
2079 		}
2080 
2081 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2082 		rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
2083 		if (rc != 0) {
2084 			kmem_free(od_name, MAXNAMELEN);
2085 			kmem_free(longname, MAXNAMELEN);
2086 			return (rc);
2087 		}
2088 
2089 		/*
2090 		 * longname is the real (case-sensitive)
2091 		 * on-disk name.
2092 		 * We make sure we do a lookup on this exact
2093 		 * name, as the name was mangled and denotes
2094 		 * a unique file.
2095 		 */
2096 
2097 		if (flags & SMB_IGNORE_CASE)
2098 			flags &= ~SMB_IGNORE_CASE;
2099 
2100 		rc = smb_vop_lookup(dnode->vp, longname, &vp, od_name,
2101 		    flags, &ret_flags, root_node ? root_node->vp : NULL, &attr,
2102 		    cr);
2103 
2104 		kmem_free(longname, MAXNAMELEN);
2105 
2106 		if (rc != 0) {
2107 			kmem_free(od_name, MAXNAMELEN);
2108 			return (rc);
2109 		}
2110 	}
2111 
2112 	if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK) &&
2113 	    ((attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)) {
2114 		rc = smb_pathname(sr, od_name, FOLLOW, root_node, dnode,
2115 		    &lnk_dnode, &lnk_target_node, cr, NULL);
2116 
2117 		if (rc != 0) {
2118 			/*
2119 			 * The link is assumed to be for the last component
2120 			 * of a path.  Hence any ENOTDIR error will be returned
2121 			 * as ENOENT.
2122 			 */
2123 			if (rc == ENOTDIR)
2124 				rc = ENOENT;
2125 
2126 			VN_RELE(vp);
2127 			kmem_free(od_name, MAXNAMELEN);
2128 			return (rc);
2129 		}
2130 
2131 		/*
2132 		 * Release the original VLNK vnode
2133 		 */
2134 
2135 		VN_RELE(vp);
2136 		vp = lnk_target_node->vp;
2137 
2138 		rc = smb_vop_traverse_check(&vp);
2139 
2140 		if (rc != 0) {
2141 			smb_node_release(lnk_dnode);
2142 			smb_node_release(lnk_target_node);
2143 			kmem_free(od_name, MAXNAMELEN);
2144 			return (rc);
2145 		}
2146 
2147 		/*
2148 		 * smb_vop_traverse_check() may have returned a different vnode
2149 		 */
2150 
2151 		if (lnk_target_node->vp == vp) {
2152 			*ret_snode = lnk_target_node;
2153 		} else {
2154 			*ret_snode = smb_node_lookup(sr, NULL, cr, vp,
2155 			    lnk_target_node->od_name, lnk_dnode, NULL);
2156 			VN_RELE(vp);
2157 
2158 			if (*ret_snode == NULL)
2159 				rc = ENOMEM;
2160 			smb_node_release(lnk_target_node);
2161 		}
2162 
2163 		smb_node_release(lnk_dnode);
2164 
2165 	} else {
2166 
2167 		rc = smb_vop_traverse_check(&vp);
2168 		if (rc) {
2169 			VN_RELE(vp);
2170 			kmem_free(od_name, MAXNAMELEN);
2171 			return (rc);
2172 		}
2173 
2174 		*ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name,
2175 		    dnode, NULL);
2176 		VN_RELE(vp);
2177 
2178 		if (*ret_snode == NULL)
2179 			rc = ENOMEM;
2180 	}
2181 
2182 	kmem_free(od_name, MAXNAMELEN);
2183 	return (rc);
2184 }
2185 
2186 int /*ARGSUSED*/
2187 smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode)
2188 {
2189 	ASSERT(cr);
2190 	ASSERT(snode);
2191 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
2192 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
2193 
2194 	ASSERT(sr);
2195 	ASSERT(sr->tid_tree);
2196 	if (SMB_TREE_IS_READONLY(sr))
2197 		return (EROFS);
2198 
2199 	return (smb_vop_commit(snode->vp, cr));
2200 }
2201 
2202 /*
2203  * smb_fsop_aclread
2204  *
2205  * Retrieve filesystem ACL. Depends on requested ACLs in
2206  * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in
2207  * fs_sd. Note that requesting a DACL/SACL doesn't mean that
2208  * the corresponding field in fs_sd should be non-NULL upon
2209  * return, since the target ACL might not contain that type of
2210  * entries.
2211  *
2212  * Returned ACL is always in ACE_T (aka ZFS) format.
2213  * If successful the allocated memory for the ACL should be freed
2214  * using smb_fsacl_free() or smb_fssd_term()
2215  */
2216 int
2217 smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2218     smb_fssd_t *fs_sd)
2219 {
2220 	int error = 0;
2221 	int flags = 0;
2222 	int access = 0;
2223 	acl_t *acl;
2224 
2225 	ASSERT(cr);
2226 
2227 	/* Can't query security on named streams */
2228 	if (SMB_IS_STREAM(snode) != NULL)
2229 		return (EINVAL);
2230 
2231 	if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0)
2232 		return (EACCES);
2233 
2234 	if (sr->fid_ofile) {
2235 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
2236 			access = READ_CONTROL;
2237 
2238 		if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
2239 			access |= ACCESS_SYSTEM_SECURITY;
2240 
2241 		error = smb_ofile_access(sr->fid_ofile, cr, access);
2242 		if (error != NT_STATUS_SUCCESS) {
2243 			return (EACCES);
2244 		}
2245 	}
2246 
2247 
2248 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS))
2249 		flags = ATTR_NOACLCHECK;
2250 
2251 	error = smb_vop_acl_read(snode->vp, &acl, flags,
2252 	    sr->tid_tree->t_acltype, cr);
2253 	if (error != 0) {
2254 		return (error);
2255 	}
2256 
2257 	error = acl_translate(acl, _ACL_ACE_ENABLED,
2258 	    smb_node_is_dir(snode), fs_sd->sd_uid, fs_sd->sd_gid);
2259 
2260 	if (error == 0) {
2261 		smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl,
2262 		    fs_sd->sd_secinfo);
2263 	}
2264 
2265 	acl_free(acl);
2266 	return (error);
2267 }
2268 
2269 /*
2270  * smb_fsop_aclwrite
2271  *
2272  * Stores the filesystem ACL provided in fs_sd->sd_acl.
2273  */
2274 int
2275 smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2276     smb_fssd_t *fs_sd)
2277 {
2278 	int target_flavor;
2279 	int error = 0;
2280 	int flags = 0;
2281 	int access = 0;
2282 	acl_t *acl, *dacl, *sacl;
2283 
2284 	ASSERT(cr);
2285 
2286 	ASSERT(sr);
2287 	ASSERT(sr->tid_tree);
2288 	if (SMB_TREE_IS_READONLY(sr))
2289 		return (EROFS);
2290 
2291 	/* Can't set security on named streams */
2292 	if (SMB_IS_STREAM(snode) != NULL)
2293 		return (EINVAL);
2294 
2295 	if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0)
2296 		return (EACCES);
2297 
2298 	if (sr->fid_ofile) {
2299 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
2300 			access = WRITE_DAC;
2301 
2302 		if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
2303 			access |= ACCESS_SYSTEM_SECURITY;
2304 
2305 		error = smb_ofile_access(sr->fid_ofile, cr, access);
2306 		if (error != NT_STATUS_SUCCESS)
2307 			return (EACCES);
2308 	}
2309 
2310 	switch (sr->tid_tree->t_acltype) {
2311 	case ACLENT_T:
2312 		target_flavor = _ACL_ACLENT_ENABLED;
2313 		break;
2314 
2315 	case ACE_T:
2316 		target_flavor = _ACL_ACE_ENABLED;
2317 		break;
2318 	default:
2319 		return (EINVAL);
2320 	}
2321 
2322 	dacl = fs_sd->sd_zdacl;
2323 	sacl = fs_sd->sd_zsacl;
2324 
2325 	ASSERT(dacl || sacl);
2326 	if ((dacl == NULL) && (sacl == NULL))
2327 		return (EINVAL);
2328 
2329 	if (dacl && sacl)
2330 		acl = smb_fsacl_merge(dacl, sacl);
2331 	else if (dacl)
2332 		acl = dacl;
2333 	else
2334 		acl = sacl;
2335 
2336 	error = acl_translate(acl, target_flavor, smb_node_is_dir(snode),
2337 	    fs_sd->sd_uid, fs_sd->sd_gid);
2338 	if (error == 0) {
2339 		if (smb_tree_has_feature(sr->tid_tree,
2340 		    SMB_TREE_ACEMASKONACCESS))
2341 			flags = ATTR_NOACLCHECK;
2342 
2343 		error = smb_vop_acl_write(snode->vp, acl, flags, cr);
2344 		if (error == 0 && snode->n_dnode != NULL) {
2345 			// FILE_NOTIFY_CHANGE_SECURITY
2346 			smb_node_notify_change(snode->n_dnode,
2347 			    FILE_ACTION_MODIFIED, snode->od_name);
2348 		}
2349 	}
2350 
2351 	if (dacl && sacl)
2352 		acl_free(acl);
2353 
2354 	return (error);
2355 }
2356 
2357 acl_type_t
2358 smb_fsop_acltype(smb_node_t *snode)
2359 {
2360 	return (smb_vop_acl_type(snode->vp));
2361 }
2362 
2363 /*
2364  * smb_fsop_sdread
2365  *
2366  * Read the requested security descriptor items from filesystem.
2367  * The items are specified in fs_sd->sd_secinfo.
2368  */
2369 int
2370 smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2371     smb_fssd_t *fs_sd)
2372 {
2373 	int error = 0;
2374 	int getowner = 0;
2375 	cred_t *ga_cred;
2376 	smb_attr_t attr;
2377 
2378 	ASSERT(cr);
2379 	ASSERT(fs_sd);
2380 
2381 	/* Can't query security on named streams */
2382 	if (SMB_IS_STREAM(snode) != NULL)
2383 		return (EINVAL);
2384 
2385 	/*
2386 	 * File's uid/gid is fetched in two cases:
2387 	 *
2388 	 * 1. it's explicitly requested
2389 	 *
2390 	 * 2. target ACL is ACE_T (ZFS ACL). They're needed for
2391 	 *    owner@/group@ entries. In this case kcred should be used
2392 	 *    because uid/gid are fetched on behalf of smb server.
2393 	 */
2394 	if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) {
2395 		getowner = 1;
2396 		ga_cred = cr;
2397 	} else if (sr->tid_tree->t_acltype == ACE_T) {
2398 		getowner = 1;
2399 		ga_cred = zone_kcred();
2400 	}
2401 
2402 	if (getowner) {
2403 		/*
2404 		 * Windows require READ_CONTROL to read owner/group SID since
2405 		 * they're part of Security Descriptor.
2406 		 * ZFS only requires read_attribute. Need to have a explicit
2407 		 * access check here.
2408 		 */
2409 		if (sr->fid_ofile == NULL) {
2410 			error = smb_fsop_access(sr, ga_cred, snode,
2411 			    READ_CONTROL);
2412 			if (error)
2413 				return (EACCES);
2414 		}
2415 
2416 		attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
2417 		error = smb_fsop_getattr(sr, ga_cred, snode, &attr);
2418 		if (error == 0) {
2419 			fs_sd->sd_uid = attr.sa_vattr.va_uid;
2420 			fs_sd->sd_gid = attr.sa_vattr.va_gid;
2421 		} else {
2422 			return (error);
2423 		}
2424 	}
2425 
2426 	if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2427 		error = smb_fsop_aclread(sr, cr, snode, fs_sd);
2428 	}
2429 
2430 	return (error);
2431 }
2432 
2433 /*
2434  * smb_fsop_sdmerge
2435  *
2436  * From SMB point of view DACL and SACL are two separate list
2437  * which can be manipulated independently without one affecting
2438  * the other, but entries for both DACL and SACL will end up
2439  * in the same ACL if target filesystem supports ACE_T ACLs.
2440  *
2441  * So, if either DACL or SACL is present in the client set request
2442  * the entries corresponding to the non-present ACL shouldn't
2443  * be touched in the FS ACL.
2444  *
2445  * fs_sd parameter contains DACL and SACL specified by SMB
2446  * client to be set on a file/directory. The client could
2447  * specify both or one of these ACLs (if none is specified
2448  * we don't get this far). When both DACL and SACL are given
2449  * by client the existing ACL should be overwritten. If only
2450  * one of them is specified the entries corresponding to the other
2451  * ACL should not be touched. For example, if only DACL
2452  * is specified in input fs_sd, the function reads audit entries
2453  * of the existing ACL of the file and point fs_sd->sd_zsdacl
2454  * pointer to the fetched SACL, this way when smb_fsop_sdwrite()
2455  * function is called the passed fs_sd would point to the specified
2456  * DACL by client and fetched SACL from filesystem, so the file
2457  * will end up with correct ACL.
2458  */
2459 static int
2460 smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd)
2461 {
2462 	smb_fssd_t cur_sd;
2463 	cred_t *kcr = zone_kcred();
2464 	int error = 0;
2465 
2466 	if (sr->tid_tree->t_acltype != ACE_T)
2467 		/* Don't bother if target FS doesn't support ACE_T */
2468 		return (0);
2469 
2470 	if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) {
2471 		if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
2472 			/*
2473 			 * Don't overwrite existing audit entries
2474 			 */
2475 			smb_fssd_init(&cur_sd, SMB_SACL_SECINFO,
2476 			    fs_sd->sd_flags);
2477 
2478 			error = smb_fsop_sdread(sr, kcr, snode, &cur_sd);
2479 			if (error == 0) {
2480 				ASSERT(fs_sd->sd_zsacl == NULL);
2481 				fs_sd->sd_zsacl = cur_sd.sd_zsacl;
2482 				if (fs_sd->sd_zsacl && fs_sd->sd_zdacl)
2483 					fs_sd->sd_zsacl->acl_flags =
2484 					    fs_sd->sd_zdacl->acl_flags;
2485 			}
2486 		} else {
2487 			/*
2488 			 * Don't overwrite existing access entries
2489 			 */
2490 			smb_fssd_init(&cur_sd, SMB_DACL_SECINFO,
2491 			    fs_sd->sd_flags);
2492 
2493 			error = smb_fsop_sdread(sr, kcr, snode, &cur_sd);
2494 			if (error == 0) {
2495 				ASSERT(fs_sd->sd_zdacl == NULL);
2496 				fs_sd->sd_zdacl = cur_sd.sd_zdacl;
2497 				if (fs_sd->sd_zdacl && fs_sd->sd_zsacl)
2498 					fs_sd->sd_zdacl->acl_flags =
2499 					    fs_sd->sd_zsacl->acl_flags;
2500 			}
2501 		}
2502 
2503 		if (error)
2504 			smb_fssd_term(&cur_sd);
2505 	}
2506 
2507 	return (error);
2508 }
2509 
2510 /*
2511  * smb_fsop_sdwrite
2512  *
2513  * Stores the given uid, gid and acl in filesystem.
2514  * Provided items in fs_sd are specified by fs_sd->sd_secinfo.
2515  *
2516  * A SMB security descriptor could contain owner, primary group,
2517  * DACL and SACL. Setting an SD should be atomic but here it has to
2518  * be done via two separate FS operations: VOP_SETATTR and
2519  * VOP_SETSECATTR. Therefore, this function has to simulate the
2520  * atomicity as well as it can.
2521  *
2522  * Get the current uid, gid before setting the new uid/gid
2523  * so if smb_fsop_aclwrite fails they can be restored. root cred is
2524  * used to get currend uid/gid since this operation is performed on
2525  * behalf of the server not the user.
2526  *
2527  * If setting uid/gid fails with EPERM it means that and invalid
2528  * owner has been specified. Callers should translate this to
2529  * STATUS_INVALID_OWNER which is not the normal mapping for EPERM
2530  * in upper layers, so EPERM is mapped to EBADE.
2531  *
2532  * If 'overwrite' is non-zero, then the existing ACL is ignored.
2533  */
2534 int
2535 smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2536     smb_fssd_t *fs_sd, int overwrite)
2537 {
2538 	smb_attr_t set_attr;
2539 	smb_attr_t orig_attr;
2540 	cred_t *kcr = zone_kcred();
2541 	int error = 0;
2542 	int access = 0;
2543 
2544 	ASSERT(cr);
2545 	ASSERT(fs_sd);
2546 
2547 	ASSERT(sr);
2548 	ASSERT(sr->tid_tree);
2549 	if (SMB_TREE_IS_READONLY(sr))
2550 		return (EROFS);
2551 
2552 	/* Can't set security on named streams */
2553 	if (SMB_IS_STREAM(snode) != NULL)
2554 		return (EINVAL);
2555 
2556 	bzero(&set_attr, sizeof (smb_attr_t));
2557 
2558 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
2559 		set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
2560 		set_attr.sa_mask |= SMB_AT_UID;
2561 		access |= WRITE_OWNER;
2562 	}
2563 
2564 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
2565 		set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
2566 		set_attr.sa_mask |= SMB_AT_GID;
2567 		access |= WRITE_OWNER;
2568 	}
2569 
2570 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
2571 		access |= WRITE_DAC;
2572 
2573 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
2574 		access |= ACCESS_SYSTEM_SECURITY;
2575 
2576 	if (sr->fid_ofile)
2577 		error = smb_ofile_access(sr->fid_ofile, cr, access);
2578 	else
2579 		error = smb_fsop_access(sr, cr, snode, access);
2580 
2581 	if (error)
2582 		return (EACCES);
2583 
2584 	if (set_attr.sa_mask) {
2585 		orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
2586 		error = smb_fsop_getattr(sr, kcr, snode, &orig_attr);
2587 		if (error == 0) {
2588 			error = smb_fsop_setattr(sr, cr, snode, &set_attr);
2589 			if (error == EPERM)
2590 				error = EBADE;
2591 		}
2592 
2593 		if (error)
2594 			return (error);
2595 	}
2596 
2597 	if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2598 		if (overwrite == 0)
2599 			error = smb_fsop_sdmerge(sr, snode, fs_sd);
2600 
2601 		if (error == 0)
2602 			error = smb_fsop_aclwrite(sr, cr, snode, fs_sd);
2603 
2604 		if (error != 0) {
2605 			/*
2606 			 * Revert uid/gid changes if required.
2607 			 */
2608 			if (set_attr.sa_mask) {
2609 				orig_attr.sa_mask = set_attr.sa_mask;
2610 				(void) smb_fsop_setattr(sr, kcr, snode,
2611 				    &orig_attr);
2612 			}
2613 		}
2614 	}
2615 
2616 	return (error);
2617 }
2618 
2619 #ifdef	_KERNEL
2620 /*
2621  * smb_fsop_sdinherit
2622  *
2623  * Inherit the security descriptor from the parent container.
2624  * This function is called after FS has created the file/folder
2625  * so if this doesn't do anything it means FS inheritance is
2626  * in place.
2627  *
2628  * Do inheritance for ZFS internally.
2629  *
2630  * If we want to let ZFS does the inheritance the
2631  * following setting should be true:
2632  *
2633  *  - aclinherit = passthrough
2634  *  - aclmode = passthrough
2635  *  - smbd umask = 0777
2636  *
2637  * This will result in right effective permissions but
2638  * ZFS will always add 6 ACEs for owner, owning group
2639  * and others to be POSIX compliant. This is not what
2640  * Windows clients/users expect, so we decided that CIFS
2641  * implements Windows rules and overwrite whatever ZFS
2642  * comes up with. This way we also don't have to care
2643  * about ZFS aclinherit and aclmode settings.
2644  */
2645 static int
2646 smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd)
2647 {
2648 	acl_t *dacl = NULL;
2649 	acl_t *sacl = NULL;
2650 	int is_dir;
2651 	int error;
2652 	uint32_t secinfo;
2653 	smb_fssd_t pfs_sd;
2654 
2655 	ASSERT(fs_sd);
2656 
2657 	secinfo = fs_sd->sd_secinfo;
2658 
2659 	/* Anything to do? */
2660 	if ((secinfo & SMB_ACL_SECINFO) == SMB_ACL_SECINFO)
2661 		return (0);
2662 
2663 	/*
2664 	 * No forced inheritance for non-ZFS filesystems.
2665 	 */
2666 	if (sr->tid_tree->t_acltype != ACE_T)
2667 		return (0);
2668 
2669 	smb_fssd_init(&pfs_sd, SMB_ACL_SECINFO, fs_sd->sd_flags);
2670 
2671 	/* Fetch parent directory's ACL */
2672 	error = smb_fsop_sdread(sr, zone_kcred(), dnode, &pfs_sd);
2673 	if (error) {
2674 		return (error);
2675 	}
2676 
2677 	is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR);
2678 	if ((secinfo & SMB_DACL_SECINFO) == 0) {
2679 		dacl = smb_fsacl_inherit(pfs_sd.sd_zdacl, is_dir,
2680 		    SMB_DACL_SECINFO, sr->user_cr);
2681 		fs_sd->sd_zdacl = dacl;
2682 	}
2683 
2684 	if ((secinfo & SMB_SACL_SECINFO) == 0) {
2685 		sacl = smb_fsacl_inherit(pfs_sd.sd_zsacl, is_dir,
2686 		    SMB_SACL_SECINFO, sr->user_cr);
2687 		fs_sd->sd_zsacl = sacl;
2688 	}
2689 
2690 	smb_fsacl_free(pfs_sd.sd_zdacl);
2691 	smb_fsacl_free(pfs_sd.sd_zsacl);
2692 	return (0);
2693 }
2694 #endif	/* _KERNEL */
2695 
2696 /*
2697  * smb_fsop_eaccess
2698  *
2699  * Returns the effective permission of the given credential for the
2700  * specified object.
2701  *
2702  * This is just a workaround. We need VFS/FS support for this.
2703  */
2704 void
2705 smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2706     uint32_t *eaccess)
2707 {
2708 	int access = 0;
2709 	vnode_t *dir_vp;
2710 	smb_node_t *unnamed_node;
2711 
2712 	ASSERT(cr);
2713 	ASSERT(snode);
2714 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
2715 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
2716 
2717 	unnamed_node = SMB_IS_STREAM(snode);
2718 	if (unnamed_node) {
2719 		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
2720 		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
2721 		/*
2722 		 * Streams authorization should be performed against the
2723 		 * unnamed stream.
2724 		 */
2725 		snode = unnamed_node;
2726 	}
2727 
2728 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) {
2729 		dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
2730 		smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp,
2731 		    cr);
2732 		return;
2733 	}
2734 
2735 	/*
2736 	 * FS doesn't understand 32-bit mask
2737 	 */
2738 	smb_vop_eaccess(snode->vp, &access, 0, NULL, cr);
2739 	access &= sr->tid_tree->t_access;
2740 
2741 	*eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES;
2742 
2743 	if (access & VREAD)
2744 		*eaccess |= FILE_READ_DATA;
2745 
2746 	if (access & VEXEC)
2747 		*eaccess |= FILE_EXECUTE;
2748 
2749 	if (access & VWRITE)
2750 		*eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
2751 		    FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
2752 
2753 	if (access & (VREAD | VWRITE))
2754 		*eaccess |= SYNCHRONIZE;
2755 
2756 #ifdef	_FAKE_KERNEL
2757 	/* Should be: if (we are the owner)... */
2758 	if (access & VWRITE)
2759 		*eaccess |= DELETE | WRITE_DAC | WRITE_OWNER;
2760 #endif
2761 }
2762 
2763 /*
2764  * smb_fsop_shrlock
2765  *
2766  * For the current open request, check file sharing rules
2767  * against existing opens.
2768  *
2769  * Returns NT_STATUS_SHARING_VIOLATION if there is any
2770  * sharing conflict.  Returns NT_STATUS_SUCCESS otherwise.
2771  *
2772  * Full system-wide share reservation synchronization is available
2773  * when the nbmand (non-blocking mandatory) mount option is set
2774  * (i.e. nbl_need_crit() is true) and nbmand critical regions are used.
2775  * This provides synchronization with NFS and local processes.  The
2776  * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called
2777  * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well
2778  * as the CIFS rename and delete paths.
2779  *
2780  * The CIFS server will also enter the nbl critical region in the open,
2781  * rename, and delete paths when nbmand is not set.  There is limited
2782  * coordination with local and VFS share reservations in this case.
2783  * Note that when the nbmand mount option is not set, the VFS layer
2784  * only processes advisory reservations and the delete mode is not checked.
2785  *
2786  * Whether or not the nbmand mount option is set, intra-CIFS share
2787  * checking is done in the open, delete, and rename paths using a CIFS
2788  * critical region (node->n_share_lock).
2789  */
2790 uint32_t
2791 smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid,
2792     uint32_t desired_access, uint32_t share_access)
2793 {
2794 	int rc;
2795 
2796 	/* Allow access if the request is just for meta data */
2797 	if ((desired_access & FILE_DATA_ALL) == 0)
2798 		return (NT_STATUS_SUCCESS);
2799 
2800 	rc = smb_node_open_check(node, desired_access, share_access);
2801 	if (rc)
2802 		return (NT_STATUS_SHARING_VIOLATION);
2803 
2804 	rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access,
2805 	    cr);
2806 	if (rc)
2807 		return (NT_STATUS_SHARING_VIOLATION);
2808 
2809 	return (NT_STATUS_SUCCESS);
2810 }
2811 
2812 void
2813 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid)
2814 {
2815 	(void) smb_vop_unshrlock(node->vp, uniq_fid, cr);
2816 }
2817 
2818 int
2819 smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock,
2820     cred_t *cr)
2821 {
2822 	flock64_t bf;
2823 	int flag = F_REMOTELOCK;
2824 
2825 	/*
2826 	 * VOP_FRLOCK() will not be called if:
2827 	 *
2828 	 * 1) The lock has a range of zero bytes. The semantics of Windows and
2829 	 *    POSIX are different. In the case of POSIX it asks for the locking
2830 	 *    of all the bytes from the offset provided until the end of the
2831 	 *    file. In the case of Windows a range of zero locks nothing and
2832 	 *    doesn't conflict with any other lock.
2833 	 *
2834 	 * 2) The lock rolls over (start + lenght < start). Solaris will assert
2835 	 *    if such a request is submitted. This will not create
2836 	 *    incompatibilities between POSIX and Windows. In the Windows world,
2837 	 *    if a client submits such a lock, the server will not lock any
2838 	 *    bytes. Interestingly if the same lock (same offset and length) is
2839 	 *    resubmitted Windows will consider that there is an overlap and
2840 	 *    the granting rules will then apply.
2841 	 *
2842 	 * 3) The SMB-level process IDs (smb_pid) are not passed down to the
2843 	 *    POSIX level in l_pid because (a) the rules about lock PIDs are
2844 	 *    different in SMB, and (b) we're putting our ofile f_uniqid in
2845 	 *    the POSIX l_pid field to segregate locks per SMB ofile.
2846 	 *    (We're also using a "remote" system ID in l_sysid.)
2847 	 *    All SMB locking PIDs are handled at the SMB level and
2848 	 *    not exposed in POSIX locking.
2849 	 */
2850 	if ((lock->l_length == 0) ||
2851 	    ((lock->l_start + lock->l_length - 1) < lock->l_start))
2852 		return (0);
2853 
2854 	bzero(&bf, sizeof (bf));
2855 
2856 	if (unlock) {
2857 		bf.l_type = F_UNLCK;
2858 	} else if (lock->l_type == SMB_LOCK_TYPE_READONLY) {
2859 		bf.l_type = F_RDLCK;
2860 		flag |= FREAD;
2861 	} else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) {
2862 		bf.l_type = F_WRLCK;
2863 		flag |= FWRITE;
2864 	}
2865 
2866 	bf.l_start = lock->l_start;
2867 	bf.l_len = lock->l_length;
2868 	bf.l_pid = lock->l_file->f_uniqid;
2869 	bf.l_sysid = smb_ct.cc_sysid;
2870 
2871 	return (smb_vop_frlock(node->vp, cr, flag, &bf));
2872 }
2873