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