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