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