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