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