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