xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_tree.c (revision 6fa29843813e354e472ca1ef80590ab80e2362b7)
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 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2016 by Delphix. All rights reserved.
25  * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
26  * Copyright 2022 RackTop Systems, Inc.
27  */
28 
29 /*
30  * General Structures Layout
31  * -------------------------
32  *
33  * This is a simplified diagram showing the relationship between most of the
34  * main structures.
35  *
36  * +-------------------+
37  * |     SMB_INFO      |
38  * +-------------------+
39  *          |
40  *          |
41  *          v
42  * +-------------------+       +-------------------+      +-------------------+
43  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
44  * +-------------------+       +-------------------+      +-------------------+
45  *   |          |
46  *   |          |
47  *   |          v
48  *   |  +-------------------+     +-------------------+   +-------------------+
49  *   |  |       USER        |<--->|       USER        |...|       USER        |
50  *   |  +-------------------+     +-------------------+   +-------------------+
51  *   |
52  *   |
53  *   v
54  * +-------------------+       +-------------------+      +-------------------+
55  * |       TREE        |<----->|       TREE        |......|       TREE        |
56  * +-------------------+       +-------------------+      +-------------------+
57  *      |         |
58  *      |         |
59  *      |         v
60  *      |     +-------+       +-------+      +-------+
61  *      |     | OFILE |<----->| OFILE |......| OFILE |
62  *      |     +-------+       +-------+      +-------+
63  *      |
64  *      |
65  *      v
66  *  +-------+       +------+      +------+
67  *  | ODIR  |<----->| ODIR |......| ODIR |
68  *  +-------+       +------+      +------+
69  *
70  *
71  * Tree State Machine
72  * ------------------
73  *
74  *    +-----------------------------+	 T0
75  *    |  SMB_TREE_STATE_CONNECTED   |<----------- Creation/Allocation
76  *    +-----------------------------+
77  *		    |
78  *		    | T1
79  *		    |
80  *		    v
81  *    +------------------------------+
82  *    | SMB_TREE_STATE_DISCONNECTING |
83  *    +------------------------------+
84  *		    |
85  *		    | T2
86  *		    |
87  *		    v
88  *    +-----------------------------+    T3
89  *    | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free
90  *    +-----------------------------+
91  *
92  * SMB_TREE_STATE_CONNECTED
93  *
94  *    While in this state:
95  *      - The tree is queued in the list of trees of its user.
96  *      - References will be given out if the tree is looked up.
97  *      - Files under that tree can be accessed.
98  *
99  * SMB_TREE_STATE_DISCONNECTING
100  *
101  *    While in this state:
102  *      - The tree is queued in the list of trees of its user.
103  *      - References will not be given out if the tree is looked up.
104  *      - The files and directories open under the tree are being closed.
105  *      - The resources associated with the tree remain.
106  *
107  * SMB_TREE_STATE_DISCONNECTED
108  *
109  *    While in this state:
110  *      - The tree is queued in the list of trees of its user.
111  *      - References will not be given out if the tree is looked up.
112  *      - The tree has no more files and directories opened.
113  *      - The resources associated with the tree remain.
114  *
115  * Transition T0
116  *
117  *    This transition occurs in smb_tree_connect(). A new tree is created and
118  *    added to the list of trees of a user.
119  *
120  * Transition T1
121  *
122  *    This transition occurs in smb_tree_disconnect().
123  *
124  * Transition T2
125  *
126  *    This transition occurs in smb_tree_disconnect()
127  *
128  * Transition T3
129  *
130  *    This transition occurs in smb_tree_release(). The resources associated
131  *    with the tree are freed as well as the tree structure. For the transition
132  *    to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED and the
133  *    reference count must be zero.
134  *
135  * Comments
136  * --------
137  *
138  *    The state machine of the tree structures is controlled by 3 elements:
139  *      - The list of trees of the user it belongs to.
140  *      - The mutex embedded in the structure itself.
141  *      - The reference count.
142  *
143  *    There's a mutex embedded in the tree structure used to protect its fields
144  *    and there's a lock embedded in the list of trees of a user. To
145  *    increment or to decrement the reference count the mutex must be entered.
146  *    To insert the tree into the list of trees of the user and to remove
147  *    the tree from it, the lock must be entered in RW_WRITER mode.
148  *
149  *    Rules of access to a tree structure:
150  *
151  *    1) In order to avoid deadlocks, when both (mutex and lock of the user
152  *       list) have to be entered, the lock must be entered first. Additionally,
153  *       when both the (mutex and lock of the ofile list) have to be entered,
154  *       the mutex must be entered first. However, the ofile list lock must NOT
155  *       be dropped while the mutex is held in such a way that the ofile deleteq
156  *       is flushed.
157  *
158  *    2) All actions applied to a tree require a reference count.
159  *
160  *    3) There are 2 ways of getting a reference count: when a tree is
161  *       connected and when a tree is looked up.
162  *
163  *    It should be noted that the reference count of a tree registers the
164  *    number of references to the tree in other structures (such as an smb
165  *    request). The reference count is not incremented in these 2 instances:
166  *
167  *    1) The tree is connected. An tree is anchored by its state. If there's
168  *       no activity involving a tree currently connected, the reference
169  *       count of that tree is zero.
170  *
171  *    2) The tree is queued in the list of trees of the user. The fact of
172  *       being queued in that list is NOT registered by incrementing the
173  *       reference count.
174  */
175 
176 #include <sys/refstr_impl.h>
177 #include <smbsrv/smb_kproto.h>
178 #include <smbsrv/smb_ktypes.h>
179 #include <smbsrv/smb_fsops.h>
180 #include <smbsrv/smb_share.h>
181 
182 int smb_tcon_mute = 1;
183 
184 uint32_t	smb_tree_connect_core(smb_request_t *);
185 uint32_t	smb_tree_connect_disk(smb_request_t *, smb_arg_tcon_t *);
186 uint32_t	smb_tree_connect_printq(smb_request_t *, smb_arg_tcon_t *);
187 uint32_t	smb_tree_connect_ipc(smb_request_t *, smb_arg_tcon_t *);
188 static void smb_tree_dealloc(void *);
189 static boolean_t smb_tree_is_connected_locked(smb_tree_t *);
190 static char *smb_tree_get_sharename(char *);
191 static int smb_tree_getattr(const smb_kshare_t *, smb_node_t *, smb_tree_t *);
192 static void smb_tree_get_creation(smb_node_t *, smb_tree_t *);
193 static void smb_tree_get_volname(vfs_t *, smb_tree_t *);
194 static void smb_tree_get_flags(const smb_kshare_t *, vfs_t *, smb_tree_t *);
195 static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
196 static void smb_tree_close_odirs(smb_tree_t *, uint32_t);
197 static void smb_tree_set_execinfo(smb_tree_t *, smb_shr_execinfo_t *, int);
198 static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *);
199 static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *);
200 static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *);
201 static void smb_tree_netinfo_fini(smb_netconnectinfo_t *);
202 
203 uint32_t
204 smb_tree_connect(smb_request_t *sr)
205 {
206 	smb_server_t	*sv = sr->sr_server;
207 	uint32_t status;
208 
209 	if (smb_threshold_enter(&sv->sv_tcon_ct) != 0) {
210 		return (NT_STATUS_INSUFF_SERVER_RESOURCES);
211 	}
212 
213 	status = smb_tree_connect_core(sr);
214 	smb_threshold_exit(&sv->sv_tcon_ct);
215 	return (status);
216 }
217 
218 /*
219  * Lookup the share name dispatch the appropriate stype handler.
220  * Share names are case insensitive so we map the share name to
221  * lower-case as a convenience for internal processing.
222  *
223  * Valid service values are:
224  *	A:      Disk share
225  *	LPT1:   Printer
226  *	IPC     Named pipe (IPC$ is reserved as the named pipe share).
227  *	COMM    Communications device
228  *	?????   Any type of device (wildcard)
229  */
230 uint32_t
231 smb_tree_connect_core(smb_request_t *sr)
232 {
233 	smb_arg_tcon_t	*tcon = &sr->sr_tcon;
234 	smb_kshare_t	*si;
235 	char		*name;
236 	uint32_t	status;
237 
238 	(void) smb_strlwr(tcon->path);
239 
240 	if ((name = smb_tree_get_sharename(tcon->path)) == NULL) {
241 		smb_tree_log(sr, tcon->path, "invalid UNC path");
242 		return (NT_STATUS_BAD_NETWORK_NAME);
243 	}
244 
245 	si = smb_kshare_lookup(sr->sr_server, name);
246 	if (si == NULL) {
247 		smb_tree_log(sr, name, "share not found");
248 		return (NT_STATUS_BAD_NETWORK_NAME);
249 	}
250 
251 	if (!strcasecmp(SMB_SHARE_PRINT, name)) {
252 		smb_kshare_release(sr->sr_server, si);
253 		smb_tree_log(sr, name, "access not permitted");
254 		return (NT_STATUS_ACCESS_DENIED);
255 	}
256 
257 	/* NB: name points into tcon->path - don't free it. */
258 	tcon->name = name;
259 	sr->sr_tcon.si = si;
260 
261 	/*
262 	 * [MS-SMB2] 3.3.5.7 Receiving an SMB2 TREE_CONNECT Request
263 	 *
264 	 * If we support 3.x, RejectUnencryptedAccess is TRUE,
265 	 * if Tcon.EncryptData is TRUE or global EncryptData is TRUE,
266 	 * and the connection doesn't support encryption,
267 	 * return ACCESS_DENIED.
268 	 *
269 	 * If RejectUnencryptedAccess is TRUE, we force max_protocol
270 	 * to at least 3.0. Additionally, if the tree requires encryption,
271 	 * we don't care what we support, we still enforce encryption.
272 	 */
273 	if ((sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED ||
274 	    si->shr_encrypt == SMB_CONFIG_REQUIRED) &&
275 	    (sr->session->srv_cap & SMB2_CAP_ENCRYPTION) == 0) {
276 		status = NT_STATUS_ACCESS_DENIED;
277 		goto out;
278 	}
279 
280 	switch (si->shr_type & STYPE_MASK) {
281 	case STYPE_DISKTREE:
282 		status = smb_tree_connect_disk(sr, &sr->sr_tcon);
283 		break;
284 	case STYPE_IPC:
285 		status = smb_tree_connect_ipc(sr, &sr->sr_tcon);
286 		break;
287 	case STYPE_PRINTQ:
288 		status = smb_tree_connect_printq(sr, &sr->sr_tcon);
289 		break;
290 	default:
291 		status = NT_STATUS_BAD_DEVICE_TYPE;
292 		break;
293 	}
294 
295 out:
296 	smb_kshare_release(sr->sr_server, si);
297 	sr->sr_tcon.si = NULL;
298 
299 	return (status);
300 }
301 
302 /*
303  * Disconnect a tree.
304  *
305  * The "do_exec" arg is obsolete and ignored.
306  */
307 void
308 smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec)
309 {
310 	_NOTE(ARGUNUSED(do_exec))
311 	smb_shr_execinfo_t execinfo;
312 
313 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
314 
315 	mutex_enter(&tree->t_mutex);
316 	ASSERT(tree->t_refcnt);
317 
318 	if (!smb_tree_is_connected_locked(tree)) {
319 		mutex_exit(&tree->t_mutex);
320 		return;
321 	}
322 
323 	/*
324 	 * Indicate that the disconnect process has started.
325 	 */
326 	tree->t_state = SMB_TREE_STATE_DISCONNECTING;
327 	mutex_exit(&tree->t_mutex);
328 
329 	/*
330 	 * The files opened under this tree are closed.
331 	 */
332 	smb_ofile_close_all(tree, 0);
333 	/*
334 	 * The directories opened under this tree are closed.
335 	 */
336 	smb_tree_close_odirs(tree, 0);
337 
338 	if ((tree->t_execflags & SMB_EXEC_UNMAP) != 0) {
339 		smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_UNMAP);
340 		(void) smb_kshare_exec(tree->t_server, &execinfo);
341 	}
342 }
343 
344 /*
345  * Take a reference on a tree.
346  */
347 boolean_t
348 smb_tree_hold(
349     smb_tree_t		*tree)
350 {
351 	SMB_TREE_VALID(tree);
352 
353 	mutex_enter(&tree->t_mutex);
354 
355 	if (smb_tree_is_connected_locked(tree)) {
356 		tree->t_refcnt++;
357 		mutex_exit(&tree->t_mutex);
358 		return (B_TRUE);
359 	}
360 
361 	mutex_exit(&tree->t_mutex);
362 	return (B_FALSE);
363 }
364 
365 /*
366  * Bump the hold count regardless of the tree state.  This is used in
367  * some internal code paths where we've already checked that we had a
368  * valid tree connection, and don't want to deal with the possiblity
369  * that the tree state might have changed to disconnecting after our
370  * original hold was taken.  It's correct to continue processing a
371  * request even when new requests cannot lookup that tree anymore.
372  */
373 void
374 smb_tree_hold_internal(
375     smb_tree_t		*tree)
376 {
377 	SMB_TREE_VALID(tree);
378 
379 	mutex_enter(&tree->t_mutex);
380 	tree->t_refcnt++;
381 	mutex_exit(&tree->t_mutex);
382 }
383 
384 /*
385  * Release a reference on a tree.  If the tree is disconnected and the
386  * reference count falls to zero, post the object for deletion.
387  * Object deletion is deferred to avoid modifying a list while an
388  * iteration may be in progress.
389  */
390 void
391 smb_tree_release(
392     smb_tree_t		*tree)
393 {
394 	SMB_TREE_VALID(tree);
395 
396 	/* flush the ofile and odir lists' delete queues */
397 	smb_lavl_flush(&tree->t_ofile_list);
398 	smb_llist_flush(&tree->t_odir_list);
399 
400 	mutex_enter(&tree->t_mutex);
401 	ASSERT(tree->t_refcnt);
402 	tree->t_refcnt--;
403 
404 	switch (tree->t_state) {
405 	case SMB_TREE_STATE_DISCONNECTING:
406 		if (tree->t_refcnt == 0) {
407 			smb_session_t *ssn = tree->t_session;
408 			tree->t_state = SMB_TREE_STATE_DISCONNECTED;
409 			smb_llist_post(&ssn->s_tree_list, tree,
410 			    smb_tree_dealloc);
411 		}
412 		break;
413 	case SMB_TREE_STATE_CONNECTED:
414 		break;
415 	default:
416 		ASSERT(0);
417 		break;
418 	}
419 
420 	mutex_exit(&tree->t_mutex);
421 }
422 
423 /*
424  * Close ofiles and odirs that match pid.
425  */
426 void
427 smb_tree_close_pid(
428     smb_tree_t		*tree,
429     uint32_t		pid)
430 {
431 	ASSERT(tree);
432 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
433 
434 	smb_ofile_close_all(tree, pid);
435 	smb_tree_close_odirs(tree, pid);
436 }
437 
438 /*
439  * Check whether or not a tree supports the features identified by flags.
440  */
441 boolean_t
442 smb_tree_has_feature(smb_tree_t *tree, uint32_t flags)
443 {
444 	ASSERT(tree);
445 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
446 
447 	return ((tree->t_flags & flags) == flags);
448 }
449 
450 /*
451  * If the enumeration request is for tree data, handle the request
452  * here.  Otherwise, pass it on to the ofiles.
453  *
454  * This function should be called with a hold on the tree.
455  */
456 int
457 smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum)
458 {
459 	smb_lavl_t	*lavl;
460 	smb_ofile_t	*of;
461 	int		rc = 0;
462 
463 	if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE)
464 		return (smb_tree_enum_private(tree, svcenum));
465 
466 	lavl = &tree->t_ofile_list;
467 	smb_lavl_enter(lavl, RW_READER);
468 
469 	of = smb_lavl_first(lavl);
470 	while (of) {
471 		if (smb_ofile_hold(of)) {
472 			rc = smb_ofile_enum(of, svcenum);
473 			smb_ofile_release(of);
474 		}
475 		if (rc != 0)
476 			break;
477 		of = smb_lavl_next(lavl, of);
478 	}
479 
480 	smb_lavl_exit(lavl);
481 
482 	return (rc);
483 }
484 
485 /*
486  * Close a file by its unique id.
487  */
488 int
489 smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid)
490 {
491 	smb_ofile_t	*of;
492 
493 	ASSERT(tree);
494 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
495 
496 	/*
497 	 * Note that ORPHANED ofiles aren't fclosable, as they have
498 	 * no session, user, or tree by which they might be found.
499 	 * They will eventually expire.
500 	 */
501 	if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL)
502 		return (ENOENT);
503 
504 	if (smb_ofile_disallow_fclose(of)) {
505 		smb_ofile_release(of);
506 		return (EACCES);
507 	}
508 
509 	smb_ofile_close(of, 0);
510 	smb_ofile_release(of);
511 	return (0);
512 }
513 
514 /* *************************** Static Functions ***************************** */
515 
516 #define	SHARES_DIR	".zfs/shares/"
517 
518 /*
519  * Calculates permissions given by the share's ACL to the
520  * user in the passed request.  The default is full access.
521  * If any error occurs, full access is granted.
522  *
523  * Using the vnode of the share path find the root directory
524  * of the mounted file system. Then look to see if there is a
525  * .zfs/shares directory and if there is, lookup the file with
526  * the same name as the share name in it. The ACL set for this
527  * file is the share's ACL which is used for access check here.
528  */
529 static uint32_t
530 smb_tree_acl_access(smb_request_t *sr, const smb_kshare_t *si, vnode_t *pathvp)
531 {
532 	smb_user_t	*user;
533 	cred_t		*cred;
534 	int		rc;
535 	vfs_t		*vfsp;
536 	vnode_t		*root = NULL;
537 	vnode_t		*sharevp = NULL;
538 	char		*sharepath;
539 	struct pathname	pnp;
540 	size_t		size;
541 	uint32_t	access;
542 
543 	user = sr->uid_user;
544 	cred = user->u_cred;
545 	access = ACE_ALL_PERMS;
546 
547 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
548 		/*
549 		 * An autohome share owner gets full access to the share.
550 		 * Everyone else is denied access.
551 		 */
552 		if (si->shr_uid != crgetuid(cred))
553 			access = 0;
554 
555 		return (access);
556 	}
557 
558 	/*
559 	 * The hold on 'root' is released by the lookuppnvp() that follows
560 	 */
561 	vfsp = pathvp->v_vfsp;
562 	if (vfsp != NULL)
563 		rc = VFS_ROOT(vfsp, &root);
564 	else
565 		rc = ENOENT;
566 
567 	if (rc != 0)
568 		return (access);
569 
570 
571 	size = sizeof (SHARES_DIR) + strlen(si->shr_name) + 1;
572 	sharepath = smb_srm_alloc(sr, size);
573 	(void) snprintf(sharepath, size, "%s%s", SHARES_DIR, si->shr_name);
574 
575 	pn_alloc(&pnp);
576 	(void) pn_set(&pnp, sharepath);
577 	rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL, &sharevp, rootdir, root,
578 	    zone_kcred());
579 	pn_free(&pnp);
580 
581 	/*
582 	 * Now get the effective access value based on cred and ACL values.
583 	 */
584 	if (rc == 0) {
585 		smb_vop_eaccess(sharevp, (int *)&access, V_ACE_MASK, NULL,
586 		    cred);
587 		VN_RELE(sharevp);
588 	}
589 
590 	return (access);
591 }
592 
593 /*
594  * Performs the following access checks for a disk share:
595  *
596  *  - No IPC/anonymous user is allowed
597  *
598  *  - If user is Guest, guestok property of the share should be
599  *    enabled
600  *
601  *  - If this is an Admin share, the user should have administrative
602  *    privileges
603  *
604  *  - Host based access control lists
605  *
606  *  - Share ACL
607  *
608  *  Returns the access allowed or 0 if access is denied.
609  */
610 static uint32_t
611 smb_tree_chkaccess(smb_request_t *sr, smb_kshare_t *shr, vnode_t *vp)
612 {
613 	smb_user_t *user = sr->uid_user;
614 	char *sharename = shr->shr_name;
615 	uint32_t host_access;
616 	uint32_t acl_access;
617 	uint32_t access;
618 
619 	if (user->u_flags & SMB_USER_FLAG_ANON) {
620 		smb_tree_log(sr, sharename, "access denied: IPC only");
621 		return (0);
622 	}
623 
624 	if ((user->u_flags & SMB_USER_FLAG_GUEST) &&
625 	    ((shr->shr_flags & SMB_SHRF_GUEST_OK) == 0)) {
626 		smb_tree_log(sr, sharename, "access denied: guest disabled");
627 		return (0);
628 	}
629 
630 	if ((shr->shr_flags & SMB_SHRF_ADMIN) && !SMB_USER_IS_ADMIN(user)) {
631 		smb_tree_log(sr, sharename, "access denied: not admin");
632 		return (0);
633 	}
634 
635 	host_access = smb_kshare_hostaccess(shr, sr->session);
636 	if ((host_access & ACE_ALL_PERMS) == 0) {
637 		smb_tree_log(sr, sharename, "access denied: host access");
638 		return (0);
639 	}
640 
641 	/*
642 	 * This checks the "share" ACL, which is normally "open"
643 	 */
644 	acl_access = smb_tree_acl_access(sr, shr, vp);
645 	if ((acl_access & ACE_ALL_PERMS) == 0) {
646 		smb_tree_log(sr, sharename, "access denied: share ACL");
647 		return (0);
648 	}
649 
650 	access = host_access & acl_access;
651 	if ((access & ACE_ALL_PERMS) == 0) {
652 		smb_tree_log(sr, sharename, "access denied");
653 		return (0);
654 	}
655 
656 	return (access);
657 }
658 
659 /* How long should tree connect wait for DH import to complete? */
660 int smb_tcon_import_wait = 20; /* sec. */
661 
662 /*
663  * Connect a share for use with files and directories.
664  */
665 uint32_t
666 smb_tree_connect_disk(smb_request_t *sr, smb_arg_tcon_t *tcon)
667 {
668 	char			*sharename = tcon->path;
669 	const char		*any = "?????";
670 	smb_user_t		*user = sr->uid_user;
671 	smb_node_t		*snode = NULL;
672 	smb_kshare_t		*si = tcon->si;
673 	char			*service = tcon->service;
674 	smb_tree_t		*tree;
675 	int			rc;
676 	uint32_t		access;
677 	smb_shr_execinfo_t	execinfo;
678 	clock_t	time;
679 
680 	ASSERT(user);
681 	ASSERT(user->u_cred);
682 
683 	if (service != NULL &&
684 	    strcmp(service, any) != 0 &&
685 	    strcasecmp(service, "A:") != 0) {
686 		smb_tree_log(sr, sharename, "invalid service (%s)", service);
687 		return (NT_STATUS_BAD_DEVICE_TYPE);
688 	}
689 
690 	/*
691 	 * Check that the shared directory exists.
692 	 */
693 	snode = si->shr_root_node;
694 	if (snode == NULL) {
695 		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
696 		return (NT_STATUS_BAD_NETWORK_NAME);
697 	}
698 
699 	if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
700 		return (NT_STATUS_ACCESS_DENIED);
701 	}
702 
703 	/*
704 	 * Wait for DH import of persistent handles to finish.
705 	 * If we timeout, it's not clear what status to return,
706 	 * but as the share is not really available yet, let's
707 	 * return the status for "no such share".
708 	 */
709 	time = SEC_TO_TICK(smb_tcon_import_wait) + ddi_get_lbolt();
710 	mutex_enter(&si->shr_mutex);
711 	while (si->shr_import_busy != NULL) {
712 		if (cv_timedwait(&si->shr_cv, &si->shr_mutex, time) < 0) {
713 			mutex_exit(&si->shr_mutex);
714 			return (NT_STATUS_BAD_NETWORK_NAME);
715 		}
716 	}
717 	mutex_exit(&si->shr_mutex);
718 
719 	/*
720 	 * Set up the OptionalSupport for this share.
721 	 */
722 	tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
723 
724 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
725 	case SMB_SHRF_CSC_DISABLED:
726 		tcon->optional_support |= SMB_CSC_CACHE_NONE;
727 		break;
728 	case SMB_SHRF_CSC_AUTO:
729 		tcon->optional_support |= SMB_CSC_CACHE_AUTO_REINT;
730 		break;
731 	case SMB_SHRF_CSC_VDO:
732 		tcon->optional_support |= SMB_CSC_CACHE_VDO;
733 		break;
734 	case SMB_SHRF_CSC_MANUAL:
735 	default:
736 		/*
737 		 * Default to SMB_CSC_CACHE_MANUAL_REINT.
738 		 */
739 		break;
740 	}
741 
742 	/* ABE support */
743 	if (si->shr_flags & SMB_SHRF_ABE)
744 		tcon->optional_support |=
745 		    SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
746 
747 	if (si->shr_flags & SMB_SHRF_DFSROOT)
748 		tcon->optional_support |= SMB_SHARE_IS_IN_DFS;
749 
750 	tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
751 
752 	if (tree == NULL)
753 		return (NT_STATUS_INSUFF_SERVER_RESOURCES);
754 
755 	if (tree->t_flags & SMB_TREE_SHORTNAMES)
756 		tcon->optional_support |= SMB_UNIQUE_FILE_NAME;
757 
758 	if (tree->t_execflags & SMB_EXEC_MAP) {
759 		smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_MAP);
760 
761 		rc = smb_kshare_exec(tree->t_server, &execinfo);
762 
763 		if ((rc != 0) && (tree->t_execflags & SMB_EXEC_TERM)) {
764 			/*
765 			 * Inline parts of: smb_tree_disconnect()
766 			 * Not using smb_tree_disconnect() for cleanup
767 			 * here because: we don't want an exec up-call,
768 			 * and there can't be any opens as we never
769 			 * returned this TID to the client.
770 			 */
771 			mutex_enter(&tree->t_mutex);
772 			tree->t_state = SMB_TREE_STATE_DISCONNECTING;
773 			mutex_exit(&tree->t_mutex);
774 
775 			smb_tree_release(tree);
776 			return (NT_STATUS_ACCESS_DENIED);
777 		}
778 	}
779 
780 	sr->tid_tree = tree;
781 	sr->smb_tid  = tree->t_tid;
782 
783 	return (0);
784 }
785 
786 /*
787  * Shares have both a share and host based access control.  The access
788  * granted will be minimum permissions based on both hostaccess
789  * (permissions allowed by host based access) and aclaccess (from the
790  * share ACL).
791  */
792 uint32_t
793 smb_tree_connect_printq(smb_request_t *sr, smb_arg_tcon_t *tcon)
794 {
795 	char			*sharename = tcon->path;
796 	const char		*any = "?????";
797 	smb_user_t		*user = sr->uid_user;
798 	smb_node_t		*dnode = NULL;
799 	smb_node_t		*snode = NULL;
800 	smb_kshare_t		*si = tcon->si;
801 	char			*service = tcon->service;
802 	char			last_component[MAXNAMELEN];
803 	smb_tree_t		*tree;
804 	int			rc;
805 	uint32_t		access;
806 
807 	ASSERT(user);
808 	ASSERT(user->u_cred);
809 
810 	if (sr->sr_server->sv_cfg.skc_print_enable == 0) {
811 		smb_tree_log(sr, sharename, "printing disabled");
812 		return (NT_STATUS_BAD_NETWORK_NAME);
813 	}
814 
815 	if (service != NULL &&
816 	    strcmp(service, any) != 0 &&
817 	    strcasecmp(service, "LPT1:") != 0) {
818 		smb_tree_log(sr, sharename, "invalid service (%s)", service);
819 		return (NT_STATUS_BAD_DEVICE_TYPE);
820 	}
821 
822 	/*
823 	 * Check that the shared directory exists.
824 	 */
825 	rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
826 	    last_component);
827 	if (rc == 0) {
828 		rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
829 		    sr->sr_server->si_root_smb_node, dnode, last_component,
830 		    &snode);
831 
832 		smb_node_release(dnode);
833 	}
834 
835 	if (rc) {
836 		if (snode)
837 			smb_node_release(snode);
838 
839 		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
840 		return (NT_STATUS_BAD_NETWORK_NAME);
841 	}
842 
843 	if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
844 		smb_node_release(snode);
845 		return (NT_STATUS_ACCESS_DENIED);
846 	}
847 
848 	tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
849 
850 	tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
851 
852 	smb_node_release(snode);
853 
854 	if (tree == NULL)
855 		return (NT_STATUS_INSUFF_SERVER_RESOURCES);
856 
857 	sr->tid_tree = tree;
858 	sr->smb_tid  = tree->t_tid;
859 
860 	return (0);
861 }
862 
863 /*
864  * Connect an IPC share for use with named pipes.
865  */
866 uint32_t
867 smb_tree_connect_ipc(smb_request_t *sr, smb_arg_tcon_t *tcon)
868 {
869 	char		*name = tcon->path;
870 	const char	*any = "?????";
871 	smb_user_t	*user = sr->uid_user;
872 	smb_tree_t	*tree;
873 	smb_kshare_t	*si = tcon->si;
874 	char		*service = tcon->service;
875 
876 	ASSERT(user);
877 
878 	if (service != NULL &&
879 	    strcmp(service, any) != 0 &&
880 	    strcasecmp(service, "IPC") != 0) {
881 		smb_tree_log(sr, name, "invalid service (%s)", service);
882 		return (NT_STATUS_BAD_DEVICE_TYPE);
883 	}
884 
885 	if ((user->u_flags & SMB_USER_FLAG_ANON) &&
886 	    sr->sr_cfg->skc_restrict_anon) {
887 		smb_tree_log(sr, name, "access denied: restrict anonymous");
888 		return (NT_STATUS_ACCESS_DENIED);
889 	}
890 
891 	tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
892 
893 	tree = smb_tree_alloc(sr, si, NULL, ACE_ALL_PERMS, 0);
894 	if (tree == NULL)
895 		return (NT_STATUS_INSUFF_SERVER_RESOURCES);
896 
897 	sr->tid_tree = tree;
898 	sr->smb_tid  = tree->t_tid;
899 
900 	return (0);
901 }
902 
903 /*
904  * Allocate a tree.
905  */
906 smb_tree_t *
907 smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si,
908     smb_node_t *snode, uint32_t access, uint32_t execflags)
909 {
910 	smb_session_t	*session = sr->session;
911 	smb_tree_t	*tree;
912 	uint32_t	stype = si->shr_type;
913 	uint16_t	tid;
914 
915 	if (smb_idpool_alloc(&session->s_tid_pool, &tid))
916 		return (NULL);
917 
918 	tree = kmem_cache_alloc(smb_cache_tree, KM_SLEEP);
919 	bzero(tree, sizeof (smb_tree_t));
920 
921 	tree->t_session = session;
922 	tree->t_server = session->s_server;
923 
924 	if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
925 		if (smb_tree_getattr(si, snode, tree) != 0) {
926 			smb_idpool_free(&session->s_tid_pool, tid);
927 			kmem_cache_free(smb_cache_tree, tree);
928 			return (NULL);
929 		}
930 	}
931 
932 	if (smb_idpool_constructor(&tree->t_fid_pool)) {
933 		smb_idpool_free(&session->s_tid_pool, tid);
934 		kmem_cache_free(smb_cache_tree, tree);
935 		return (NULL);
936 	}
937 
938 	if (smb_idpool_constructor(&tree->t_odid_pool)) {
939 		smb_idpool_destructor(&tree->t_fid_pool);
940 		smb_idpool_free(&session->s_tid_pool, tid);
941 		kmem_cache_free(smb_cache_tree, tree);
942 		return (NULL);
943 	}
944 
945 	smb_lavl_constructor(&tree->t_ofile_list,
946 	    smb_ofile_avl_compare,  sizeof (smb_ofile_t),
947 	    offsetof(smb_ofile_t, f_tree_lnd));
948 
949 	smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
950 	    offsetof(smb_odir_t, d_lnd));
951 
952 	(void) strlcpy(tree->t_sharename, si->shr_name,
953 	    sizeof (tree->t_sharename));
954 	(void) strlcpy(tree->t_resource, si->shr_path,
955 	    sizeof (tree->t_resource));
956 
957 	mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
958 
959 	tree->t_refcnt = 1;
960 	tree->t_tid = tid;
961 	tree->t_res_type = stype;
962 	tree->t_state = SMB_TREE_STATE_CONNECTED;
963 	tree->t_magic = SMB_TREE_MAGIC;
964 	tree->t_access = access;
965 	tree->t_connect_time = gethrestime_sec();
966 	tree->t_execflags = execflags;
967 
968 	/* grab a ref for tree->t_owner */
969 	smb_user_hold_internal(sr->uid_user);
970 	smb_user_inc_trees(sr->uid_user);
971 	tree->t_owner = sr->uid_user;
972 
973 	/* if FS is readonly, enforce that here */
974 	if (tree->t_flags & SMB_TREE_READONLY)
975 		tree->t_access &= ~ACE_ALL_WRITE_PERMS;
976 
977 	if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
978 		smb_node_ref(snode);
979 		tree->t_snode = snode;
980 		tree->t_acltype = smb_fsop_acltype(snode);
981 	}
982 
983 	smb_llist_enter(&session->s_tree_list, RW_WRITER);
984 	smb_llist_insert_head(&session->s_tree_list, tree);
985 	smb_llist_exit(&session->s_tree_list);
986 	atomic_inc_32(&session->s_tree_cnt);
987 	smb_server_inc_trees(session->s_server);
988 	return (tree);
989 }
990 
991 /*
992  * Deallocate a tree.  The open file and open directory lists should be
993  * empty.
994  *
995  * Remove the tree from the user's tree list before freeing resources
996  * associated with the tree.
997  */
998 static void
999 smb_tree_dealloc(void *arg)
1000 {
1001 	smb_session_t	*session;
1002 	smb_tree_t	*tree = (smb_tree_t *)arg;
1003 
1004 	SMB_TREE_VALID(tree);
1005 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
1006 	ASSERT(tree->t_refcnt == 0);
1007 
1008 	smb_server_dec_trees(tree->t_server);
1009 
1010 	session = tree->t_session;
1011 	smb_llist_enter(&session->s_tree_list, RW_WRITER);
1012 	smb_llist_remove(&session->s_tree_list, tree);
1013 	smb_idpool_free(&session->s_tid_pool, tree->t_tid);
1014 	atomic_dec_32(&session->s_tree_cnt);
1015 	smb_llist_exit(&session->s_tree_list);
1016 
1017 	/*
1018 	 * This tree is no longer on s_tree_list, however...
1019 	 *
1020 	 * This is called via smb_llist_post, which means it may run
1021 	 * BEFORE smb_tree_release drops t_mutex (if another thread
1022 	 * flushes the delete queue before we do).  Synchronize.
1023 	 */
1024 	mutex_enter(&tree->t_mutex);
1025 	mutex_exit(&tree->t_mutex);
1026 
1027 	tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
1028 
1029 	if (tree->t_snode)
1030 		smb_node_release(tree->t_snode);
1031 
1032 	mutex_destroy(&tree->t_mutex);
1033 	smb_lavl_destructor(&tree->t_ofile_list);
1034 	smb_llist_destructor(&tree->t_odir_list);
1035 	smb_idpool_destructor(&tree->t_fid_pool);
1036 	smb_idpool_destructor(&tree->t_odid_pool);
1037 
1038 	SMB_USER_VALID(tree->t_owner);
1039 	smb_user_dec_trees(tree->t_owner);
1040 	smb_user_release(tree->t_owner);
1041 
1042 	kmem_cache_free(smb_cache_tree, tree);
1043 }
1044 
1045 /*
1046  * Determine whether or not a tree is connected.
1047  * This function must be called with the tree mutex held.
1048  */
1049 static boolean_t
1050 smb_tree_is_connected_locked(smb_tree_t *tree)
1051 {
1052 	switch (tree->t_state) {
1053 	case SMB_TREE_STATE_CONNECTED:
1054 		return (B_TRUE);
1055 
1056 	case SMB_TREE_STATE_DISCONNECTING:
1057 	case SMB_TREE_STATE_DISCONNECTED:
1058 		/*
1059 		 * The tree exists but is being disconnected or destroyed.
1060 		 */
1061 		return (B_FALSE);
1062 
1063 	default:
1064 		ASSERT(0);
1065 		return (B_FALSE);
1066 	}
1067 }
1068 
1069 /*
1070  * Return a pointer to the share name within a share resource path.
1071  *
1072  * The share path may be a Uniform Naming Convention (UNC) string
1073  * (\\server\share) or simply the share name.  We validate the UNC
1074  * format but we don't look at the server name.
1075  */
1076 static char *
1077 smb_tree_get_sharename(char *unc_path)
1078 {
1079 	char *sharename = unc_path;
1080 
1081 	if (sharename[0] == '\\') {
1082 		/*
1083 		 * Looks like a UNC path, validate the format.
1084 		 */
1085 		if (sharename[1] != '\\')
1086 			return (NULL);
1087 
1088 		if ((sharename = strchr(sharename+2, '\\')) == NULL)
1089 			return (NULL);
1090 
1091 		++sharename;
1092 	} else if (strchr(sharename, '\\') != NULL) {
1093 		/*
1094 		 * This should be a share name (no embedded \'s).
1095 		 */
1096 		return (NULL);
1097 	}
1098 
1099 	return (sharename);
1100 }
1101 
1102 /*
1103  * Obtain the tree attributes: volume name, typename and flags.
1104  * Called only with DISK and PRINTQ shares.
1105  */
1106 static int
1107 smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree)
1108 {
1109 	vfs_t *vfsp = SMB_NODE_VFS(node);
1110 	vfs_t *realvfsp;
1111 
1112 	ASSERT(vfsp);
1113 
1114 	smb_tree_get_creation(node, tree);
1115 	smb_tree_get_volname(vfsp, tree);
1116 
1117 	/*
1118 	 * In the case of an lofs mount, we need to ask the (real)
1119 	 * underlying filesystem about capabilities, where the
1120 	 * passed in vfs_t will be from lofs.
1121 	 */
1122 	realvfsp = getvfs(&vfsp->vfs_fsid);
1123 	if (realvfsp != NULL) {
1124 		smb_tree_get_flags(si, realvfsp, tree);
1125 		VFS_RELE(realvfsp);
1126 	} else {
1127 		cmn_err(CE_NOTE, "Failed getting info for share: %s",
1128 		    si->shr_name);
1129 		/* do the best we can without realvfsp */
1130 		smb_tree_get_flags(si, vfsp, tree);
1131 	}
1132 
1133 	if (tree->t_session->dialect >= SMB_VERS_3_0)
1134 		tree->t_encrypt = si->shr_encrypt;
1135 	else
1136 		tree->t_encrypt = SMB_CONFIG_DISABLED;
1137 
1138 	return (0);
1139 }
1140 
1141 /*
1142  * File volume creation time
1143  */
1144 static void
1145 smb_tree_get_creation(smb_node_t *node, smb_tree_t *tree)
1146 {
1147 	smb_attr_t	attr;
1148 	cred_t		*kcr = zone_kcred();
1149 
1150 	bzero(&attr, sizeof (attr));
1151 	attr.sa_mask = SMB_AT_CRTIME;
1152 	(void) smb_node_getattr(NULL, node, kcr, NULL, &attr);
1153 	/* On failure we'll have time zero, which is OK */
1154 
1155 	tree->t_create_time = attr.sa_crtime;
1156 }
1157 
1158 /*
1159  * Extract the volume name.
1160  */
1161 static void
1162 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
1163 {
1164 #ifdef	_FAKE_KERNEL
1165 	_NOTE(ARGUNUSED(vfsp))
1166 	(void) strlcpy(tree->t_volume, "fake", SMB_VOLNAMELEN);
1167 #else	/* _FAKE_KERNEL */
1168 	refstr_t *vfs_mntpoint;
1169 	const char *s;
1170 	char *name;
1171 
1172 	vfs_mntpoint = vfs_getmntpoint(vfsp);
1173 
1174 	s = refstr_value(vfs_mntpoint);
1175 	s += strspn(s, "/");
1176 	(void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
1177 
1178 	refstr_rele(vfs_mntpoint);
1179 
1180 	name = tree->t_volume;
1181 	(void) strsep((char **)&name, "/");
1182 #endif	/* _FAKE_KERNEL */
1183 }
1184 
1185 /*
1186  * Get flags from the VFS (and other places) for a new tree.
1187  * Called only with DISK and PRINTQ shares.
1188  *
1189  * Always set "unicode on disk" because we always use utf8 names locally.
1190  * Always set ACL support because the VFS will fake ACLs for file systems
1191  * that don't support them.
1192  *
1193  * Some flags are dependent on the typename, which is also set up here.
1194  * File system types are hardcoded in uts/common/os/vfs_conf.c.
1195  */
1196 static void
1197 smb_tree_get_flags(const smb_kshare_t *si, vfs_t *vfsp, smb_tree_t *tree)
1198 {
1199 	smb_session_t *ssn = tree->t_session;
1200 	struct vfssw	*vswp;
1201 
1202 	typedef struct smb_mtype {
1203 		char		*mt_name;
1204 		size_t		mt_namelen;
1205 		uint32_t	mt_flags;
1206 	} smb_mtype_t;
1207 
1208 	static smb_mtype_t smb_mtype[] = {
1209 #ifdef	_FAKE_KERNEL
1210 		/* See libfksmbsrv:fake_vfs.c */
1211 		{ "fake",    3,	SMB_TREE_SPARSE},
1212 #endif	/* _FAKE_KERNEL */
1213 		{ "zfs",    3,	SMB_TREE_QUOTA | SMB_TREE_SPARSE},
1214 		{ "ufs",    3,	0 },
1215 		{ "nfs",    3,	SMB_TREE_NFS_MOUNTED },
1216 		{ "tmpfs",  5,	SMB_TREE_NO_EXPORT }
1217 	};
1218 	smb_mtype_t	*mtype;
1219 	char		*name;
1220 	uint32_t	flags =
1221 	    SMB_TREE_SUPPORTS_ACLS |
1222 	    SMB_TREE_UNICODE_ON_DISK;
1223 	int		i;
1224 
1225 	if (si->shr_flags & SMB_SHRF_DFSROOT)
1226 		flags |= SMB_TREE_DFSROOT;
1227 
1228 	if (si->shr_flags & SMB_SHRF_CATIA)
1229 		flags |= SMB_TREE_CATIA;
1230 
1231 	if (si->shr_flags & SMB_SHRF_ABE)
1232 		flags |= SMB_TREE_ABE;
1233 
1234 	if (si->shr_flags & SMB_SHRF_CA)
1235 		flags |= SMB_TREE_CA;
1236 
1237 	if (si->shr_flags & SMB_SHRF_FSO)
1238 		flags |= SMB_TREE_FORCE_L2_OPLOCK;
1239 
1240 	if (ssn->s_cfg.skc_oplock_enable)
1241 		flags |= SMB_TREE_OPLOCKS;
1242 
1243 	if (ssn->s_cfg.skc_traverse_mounts)
1244 		flags |= SMB_TREE_TRAVERSE_MOUNTS;
1245 
1246 	if (ssn->s_cfg.skc_short_names)
1247 		flags |= SMB_TREE_SHORTNAMES;
1248 
1249 	if (vfsp->vfs_flag & VFS_RDONLY)
1250 		flags |= SMB_TREE_READONLY;
1251 
1252 	if (vfsp->vfs_flag & VFS_XATTR)
1253 		flags |= SMB_TREE_STREAMS;
1254 
1255 	vswp = vfs_getvfsswbyvfsops(vfs_getops(vfsp));
1256 	if (vswp != NULL) {
1257 		name = vswp->vsw_name;
1258 		vfs_unrefvfssw(vswp);
1259 	} else {
1260 		name = "?";
1261 	}
1262 
1263 	for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
1264 		mtype = &smb_mtype[i];
1265 		if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
1266 			flags |= mtype->mt_flags;
1267 	}
1268 
1269 	/*
1270 	 * SMB_TREE_QUOTA will be on here if the FS is ZFS.  We want to
1271 	 * turn it OFF when the share property says false.
1272 	 */
1273 	if ((si->shr_flags & SMB_SHRF_QUOTAS) == 0)
1274 		flags &= ~SMB_TREE_QUOTA;
1275 
1276 	(void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
1277 	(void) smb_strupr((char *)tree->t_typename);
1278 
1279 	if (vfs_has_feature(vfsp, VFSFT_XVATTR))
1280 		flags |= SMB_TREE_XVATTR;
1281 
1282 	if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
1283 		flags |= SMB_TREE_CASEINSENSITIVE;
1284 
1285 	if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
1286 		flags |= SMB_TREE_NO_CASESENSITIVE;
1287 
1288 	if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
1289 		flags |= SMB_TREE_DIRENTFLAGS;
1290 
1291 	if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
1292 		flags |= SMB_TREE_ACLONCREATE;
1293 
1294 	if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
1295 		flags |= SMB_TREE_ACEMASKONACCESS;
1296 
1297 	DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);
1298 
1299 
1300 	tree->t_flags = flags;
1301 }
1302 
1303 /*
1304  * Report share access result to syslog.
1305  */
1306 static void
1307 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
1308 {
1309 	va_list ap;
1310 	char buf[128];
1311 	smb_user_t *user = sr->uid_user;
1312 
1313 	ASSERT(user);
1314 
1315 	if (smb_tcon_mute)
1316 		return;
1317 
1318 	if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
1319 		/*
1320 		 * Only report normal users, i.e. ignore W2K misuse
1321 		 * of the IPC connection by filtering out internal
1322 		 * names such as nobody and root.
1323 		 */
1324 		if ((strcmp(user->u_name, "root") == 0) ||
1325 		    (strcmp(user->u_name, "nobody") == 0)) {
1326 			return;
1327 		}
1328 	}
1329 
1330 	va_start(ap, fmt);
1331 	(void) vsnprintf(buf, 128, fmt, ap);
1332 	va_end(ap);
1333 
1334 	cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
1335 	    user->u_domain, user->u_name, sharename, buf);
1336 }
1337 
1338 /*
1339  * smb_tree_lookup_odir
1340  *
1341  * Find the specified odir in the tree's list of odirs, and
1342  * attempt to obtain a hold on the odir.
1343  *
1344  * Returns NULL if odir not found or a hold cannot be obtained.
1345  */
1346 smb_odir_t *
1347 smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid)
1348 {
1349 	smb_odir_t	*od;
1350 	smb_llist_t	*od_list;
1351 	smb_tree_t	*tree = sr->tid_tree;
1352 
1353 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1354 
1355 	od_list = &tree->t_odir_list;
1356 
1357 	smb_llist_enter(od_list, RW_READER);
1358 	od = smb_llist_head(od_list);
1359 	while (od) {
1360 		if (od->d_odid == odid)
1361 			break;
1362 		od = smb_llist_next(od_list, od);
1363 	}
1364 	if (od == NULL)
1365 		goto out;
1366 
1367 	/*
1368 	 * Only allow use of a given Search ID with the same UID that
1369 	 * was used to create it.  MS-CIFS 3.3.5.14
1370 	 */
1371 	if (od->d_user != sr->uid_user) {
1372 		od = NULL;
1373 		goto out;
1374 	}
1375 	if (!smb_odir_hold(od))
1376 		od = NULL;
1377 
1378 out:
1379 	smb_llist_exit(od_list);
1380 	return (od);
1381 }
1382 
1383 boolean_t
1384 smb_tree_is_connected(smb_tree_t *tree)
1385 {
1386 	boolean_t	rb;
1387 
1388 	mutex_enter(&tree->t_mutex);
1389 	rb = smb_tree_is_connected_locked(tree);
1390 	mutex_exit(&tree->t_mutex);
1391 	return (rb);
1392 }
1393 
1394 /*
1395  * smb_tree_close_odirs
1396  *
1397  * Close all open odirs in the tree's list which were opened by
1398  * the process identified by pid.
1399  * If pid is zero, close all open odirs in the tree's list.
1400  */
1401 static void
1402 smb_tree_close_odirs(smb_tree_t *tree, uint32_t pid)
1403 {
1404 	smb_llist_t	*od_list;
1405 	smb_odir_t	*od;
1406 
1407 	ASSERT(tree);
1408 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1409 
1410 	od_list = &tree->t_odir_list;
1411 	smb_llist_enter(od_list, RW_READER);
1412 
1413 	for (od = smb_llist_head(od_list);
1414 	    od != NULL;
1415 	    od = smb_llist_next(od_list, od)) {
1416 
1417 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1418 		ASSERT(od->d_tree == tree);
1419 
1420 		if (pid != 0 && od->d_opened_by_pid != pid)
1421 			continue;
1422 
1423 		if (smb_odir_hold(od)) {
1424 			smb_odir_close(od);
1425 			smb_odir_release(od);
1426 		}
1427 	}
1428 
1429 	smb_llist_exit(od_list);
1430 }
1431 
1432 static void
1433 smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec,
1434     int exec_type)
1435 {
1436 	exec->e_sharename = tree->t_sharename;
1437 	exec->e_winname = tree->t_owner->u_name;
1438 	exec->e_userdom = tree->t_owner->u_domain;
1439 	exec->e_srv_ipaddr = tree->t_session->local_ipaddr;
1440 	exec->e_cli_ipaddr = tree->t_session->ipaddr;
1441 	exec->e_cli_netbiosname = tree->t_session->workstation;
1442 	exec->e_uid = crgetuid(tree->t_owner->u_cred);
1443 	exec->e_type = exec_type;
1444 }
1445 
1446 /*
1447  * Private function to support smb_tree_enum.
1448  */
1449 static int
1450 smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum)
1451 {
1452 	uint8_t *pb;
1453 	uint_t nbytes;
1454 	int rc;
1455 
1456 	if (svcenum->se_nskip > 0) {
1457 		svcenum->se_nskip--;
1458 		return (0);
1459 	}
1460 
1461 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
1462 		svcenum->se_nitems = svcenum->se_nlimit;
1463 		return (0);
1464 	}
1465 
1466 	pb = &svcenum->se_buf[svcenum->se_bused];
1467 	rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes);
1468 	if (rc == 0) {
1469 		svcenum->se_bavail -= nbytes;
1470 		svcenum->se_bused += nbytes;
1471 		svcenum->se_nitems++;
1472 	}
1473 
1474 	return (rc);
1475 }
1476 
1477 /*
1478  * Encode connection information into a buffer: connection information
1479  * needed in user space to support RPC requests.
1480  */
1481 static int
1482 smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
1483     uint32_t *nbytes)
1484 {
1485 	smb_netconnectinfo_t	info;
1486 	int			rc;
1487 
1488 	smb_tree_netinfo_init(tree, &info);
1489 	rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes);
1490 	smb_tree_netinfo_fini(&info);
1491 
1492 	return (rc);
1493 }
1494 
1495 static void
1496 smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen)
1497 {
1498 	smb_user_t		*user = tree->t_owner;
1499 
1500 	/*
1501 	 * u_domain_len and u_name_len include the '\0' in their
1502 	 * lengths, hence the sum of the two lengths gives us room
1503 	 * for both the '\\' and '\0' chars.
1504 	 */
1505 	ASSERT(namestr);
1506 	ASSERT(namelen);
1507 	ASSERT(user->u_domain_len > 0);
1508 	ASSERT(user->u_name_len > 0);
1509 	*namelen = user->u_domain_len + user->u_name_len;
1510 	*namestr = kmem_alloc(*namelen, KM_SLEEP);
1511 	(void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain,
1512 	    user->u_name);
1513 }
1514 
1515 /*
1516  * Note: ci_numusers should be the number of users connected to
1517  * the share rather than the number of references on the tree but
1518  * we don't have a mechanism to track users/share in smbsrv yet.
1519  */
1520 static void
1521 smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
1522 {
1523 	ASSERT(tree);
1524 
1525 	info->ci_id = tree->t_tid;
1526 	info->ci_type = tree->t_res_type;
1527 	info->ci_numopens = tree->t_open_files;
1528 	info->ci_numusers = tree->t_refcnt;
1529 	info->ci_time = gethrestime_sec() - tree->t_connect_time;
1530 
1531 	info->ci_sharelen = strlen(tree->t_sharename) + 1;
1532 	info->ci_share = smb_mem_strdup(tree->t_sharename);
1533 
1534 	smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen);
1535 }
1536 
1537 static void
1538 smb_tree_netinfo_fini(smb_netconnectinfo_t *info)
1539 {
1540 	if (info == NULL)
1541 		return;
1542 
1543 	if (info->ci_username)
1544 		kmem_free(info->ci_username, info->ci_namelen);
1545 	if (info->ci_share)
1546 		smb_mem_free(info->ci_share);
1547 
1548 	bzero(info, sizeof (smb_netconnectinfo_t));
1549 }
1550