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