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