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