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