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