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