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