xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_tree.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
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 2011 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_user_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 	if ((si = smb_kshare_lookup(name)) == NULL) {
241 		smb_tree_log(sr, name, "share not found");
242 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
243 		return (NULL);
244 	}
245 
246 	if (!strcasecmp(SMB_SHARE_PRINT, name)) {
247 		smb_kshare_release(si);
248 		smb_tree_log(sr, name, "access not permitted");
249 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
250 		return (NULL);
251 	}
252 
253 	sr->sr_tcon.si = si;
254 
255 	switch (si->shr_type & STYPE_MASK) {
256 	case STYPE_DISKTREE:
257 		tree = smb_tree_connect_disk(sr, name);
258 		break;
259 	case STYPE_IPC:
260 		tree = smb_tree_connect_ipc(sr, name);
261 		break;
262 	case STYPE_PRINTQ:
263 		tree = smb_tree_connect_printq(sr, name);
264 		break;
265 	default:
266 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
267 		    ERRDOS, ERROR_BAD_DEV_TYPE);
268 		break;
269 	}
270 
271 	smb_kshare_release(si);
272 	return (tree);
273 }
274 
275 /*
276  * Disconnect a tree.
277  */
278 void
279 smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec)
280 {
281 	smb_shr_execinfo_t execinfo;
282 
283 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
284 
285 	mutex_enter(&tree->t_mutex);
286 	ASSERT(tree->t_refcnt);
287 
288 	if (smb_tree_is_connected_locked(tree)) {
289 		/*
290 		 * Indicate that the disconnect process has started.
291 		 */
292 		tree->t_state = SMB_TREE_STATE_DISCONNECTING;
293 		mutex_exit(&tree->t_mutex);
294 
295 		if (do_exec) {
296 			/*
297 			 * The files opened under this tree are closed.
298 			 */
299 			smb_ofile_close_all(tree);
300 			/*
301 			 * The directories opened under this tree are closed.
302 			 */
303 			smb_tree_close_odirs(tree, 0);
304 		}
305 
306 		mutex_enter(&tree->t_mutex);
307 		tree->t_state = SMB_TREE_STATE_DISCONNECTED;
308 		smb_server_dec_trees(tree->t_server);
309 	}
310 
311 	mutex_exit(&tree->t_mutex);
312 
313 	if (do_exec && (tree->t_state == SMB_TREE_STATE_DISCONNECTED) &&
314 	    (tree->t_execflags & SMB_EXEC_UNMAP)) {
315 
316 		smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_UNMAP);
317 		(void) smb_kshare_exec(&execinfo);
318 	}
319 }
320 
321 /*
322  * Take a reference on a tree.
323  */
324 boolean_t
325 smb_tree_hold(
326     smb_tree_t		*tree)
327 {
328 	ASSERT(tree);
329 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
330 
331 	mutex_enter(&tree->t_mutex);
332 
333 	if (smb_tree_is_connected_locked(tree)) {
334 		tree->t_refcnt++;
335 		mutex_exit(&tree->t_mutex);
336 		return (B_TRUE);
337 	}
338 
339 	mutex_exit(&tree->t_mutex);
340 	return (B_FALSE);
341 }
342 
343 /*
344  * Release a reference on a tree.  If the tree is disconnected and the
345  * reference count falls to zero, post the object for deletion.
346  * Object deletion is deferred to avoid modifying a list while an
347  * iteration may be in progress.
348  */
349 void
350 smb_tree_release(
351     smb_tree_t		*tree)
352 {
353 	SMB_TREE_VALID(tree);
354 
355 	mutex_enter(&tree->t_mutex);
356 	ASSERT(tree->t_refcnt);
357 	tree->t_refcnt--;
358 
359 	/* flush the ofile and odir lists' delete queues */
360 	smb_llist_flush(&tree->t_ofile_list);
361 	smb_llist_flush(&tree->t_odir_list);
362 
363 	if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0))
364 		smb_user_post_tree(tree->t_user, tree);
365 
366 	mutex_exit(&tree->t_mutex);
367 }
368 
369 void
370 smb_tree_post_ofile(smb_tree_t *tree, smb_ofile_t *of)
371 {
372 	SMB_TREE_VALID(tree);
373 	SMB_OFILE_VALID(of);
374 	ASSERT(of->f_refcnt == 0);
375 	ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED);
376 	ASSERT(of->f_tree == tree);
377 
378 	smb_llist_post(&tree->t_ofile_list, of, smb_ofile_delete);
379 }
380 
381 void
382 smb_tree_post_odir(smb_tree_t *tree, smb_odir_t *od)
383 {
384 	SMB_TREE_VALID(tree);
385 	SMB_ODIR_VALID(od);
386 	ASSERT(od->d_refcnt == 0);
387 	ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED);
388 	ASSERT(od->d_tree == tree);
389 
390 	smb_llist_post(&tree->t_odir_list, od, smb_odir_delete);
391 }
392 
393 /*
394  * Close ofiles and odirs that match pid.
395  */
396 void
397 smb_tree_close_pid(
398     smb_tree_t		*tree,
399     uint16_t		pid)
400 {
401 	ASSERT(tree);
402 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
403 
404 	smb_ofile_close_all_by_pid(tree, pid);
405 	smb_tree_close_odirs(tree, pid);
406 }
407 
408 /*
409  * Check whether or not a tree supports the features identified by flags.
410  */
411 boolean_t
412 smb_tree_has_feature(smb_tree_t *tree, uint32_t flags)
413 {
414 	ASSERT(tree);
415 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
416 
417 	return ((tree->t_flags & flags) == flags);
418 }
419 
420 /*
421  * If the enumeration request is for tree data, handle the request
422  * here.  Otherwise, pass it on to the ofiles.
423  *
424  * This function should be called with a hold on the tree.
425  */
426 int
427 smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum)
428 {
429 	smb_ofile_t	*of;
430 	smb_ofile_t	*next;
431 	int		rc;
432 
433 	ASSERT(tree);
434 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
435 
436 	if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE)
437 		return (smb_tree_enum_private(tree, svcenum));
438 
439 	of = smb_tree_get_ofile(tree, NULL);
440 	while (of) {
441 		ASSERT(of->f_tree == tree);
442 
443 		rc = smb_ofile_enum(of, svcenum);
444 		if (rc != 0) {
445 			smb_ofile_release(of);
446 			break;
447 		}
448 
449 		next = smb_tree_get_ofile(tree, of);
450 		smb_ofile_release(of);
451 		of = next;
452 	}
453 
454 	return (rc);
455 }
456 
457 /*
458  * Close a file by its unique id.
459  */
460 int
461 smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid)
462 {
463 	smb_ofile_t	*of;
464 
465 	ASSERT(tree);
466 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
467 
468 	if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL)
469 		return (ENOENT);
470 
471 	if (smb_ofile_disallow_fclose(of)) {
472 		smb_ofile_release(of);
473 		return (EACCES);
474 	}
475 
476 	smb_ofile_close(of, 0);
477 	smb_ofile_release(of);
478 	return (0);
479 }
480 
481 /* *************************** Static Functions ***************************** */
482 
483 #define	SHARES_DIR	".zfs/shares/"
484 
485 /*
486  * Calculates permissions given by the share's ACL to the
487  * user in the passed request.  The default is full access.
488  * If any error occurs, full access is granted.
489  *
490  * Using the vnode of the share path find the root directory
491  * of the mounted file system. Then look to see if there is a
492  * .zfs/shares directory and if there is, lookup the file with
493  * the same name as the share name in it. The ACL set for this
494  * file is the share's ACL which is used for access check here.
495  */
496 static uint32_t
497 smb_tree_acl_access(smb_request_t *sr, const smb_kshare_t *si, vnode_t *pathvp)
498 {
499 	smb_user_t	*user;
500 	cred_t		*cred;
501 	int		rc;
502 	vfs_t		*vfsp;
503 	vnode_t		*root = NULL;
504 	vnode_t		*sharevp = NULL;
505 	char		*sharepath;
506 	struct pathname	pnp;
507 	size_t		size;
508 	uint32_t	access;
509 
510 	user = sr->uid_user;
511 	cred = user->u_cred;
512 	access = ACE_ALL_PERMS;
513 
514 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
515 		/*
516 		 * An autohome share owner gets full access to the share.
517 		 * Everyone else is denied access.
518 		 */
519 		if (si->shr_uid != crgetuid(cred))
520 			access = 0;
521 
522 		return (access);
523 	}
524 
525 	/*
526 	 * The hold on 'root' is released by the lookuppnvp() that follows
527 	 */
528 	vfsp = pathvp->v_vfsp;
529 	if (vfsp != NULL)
530 		rc = VFS_ROOT(vfsp, &root);
531 	else
532 		rc = ENOENT;
533 
534 	if (rc != 0)
535 		return (access);
536 
537 
538 	size = sizeof (SHARES_DIR) + strlen(si->shr_name) + 1;
539 	sharepath = smb_srm_alloc(sr, size);
540 	(void) sprintf(sharepath, "%s%s", SHARES_DIR, si->shr_name);
541 
542 	pn_alloc(&pnp);
543 	(void) pn_set(&pnp, sharepath);
544 	rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL, &sharevp, rootdir, root,
545 	    kcred);
546 	pn_free(&pnp);
547 
548 	/*
549 	 * Now get the effective access value based on cred and ACL values.
550 	 */
551 	if (rc == 0) {
552 		smb_vop_eaccess(sharevp, (int *)&access, V_ACE_MASK, NULL,
553 		    cred);
554 		VN_RELE(sharevp);
555 	}
556 
557 	return (access);
558 }
559 
560 /*
561  * Performs the following access checks for a disk share:
562  *
563  *  - No IPC/anonymous user is allowed
564  *
565  *  - If user is Guest, guestok property of the share should be
566  *    enabled
567  *
568  *  - If this is an Admin share, the user should have administrative
569  *    privileges
570  *
571  *  - Host based access control lists
572  *
573  *  - Share ACL
574  *
575  *  Returns the access allowed or 0 if access is denied.
576  */
577 static uint32_t
578 smb_tree_chkaccess(smb_request_t *sr, smb_kshare_t *shr, vnode_t *vp)
579 {
580 	smb_user_t *user = sr->uid_user;
581 	char *sharename = shr->shr_name;
582 	uint32_t host_access;
583 	uint32_t acl_access;
584 	uint32_t access;
585 
586 	if (user->u_flags & SMB_USER_FLAG_IPC) {
587 		smb_tree_log(sr, sharename, "access denied: IPC only");
588 		return (0);
589 	}
590 
591 	if ((user->u_flags & SMB_USER_FLAG_GUEST) &&
592 	    ((shr->shr_flags & SMB_SHRF_GUEST_OK) == 0)) {
593 		smb_tree_log(sr, sharename, "access denied: guest disabled");
594 		return (0);
595 	}
596 
597 	if ((shr->shr_flags & SMB_SHRF_ADMIN) && !smb_user_is_admin(user)) {
598 		smb_tree_log(sr, sharename, "access denied: not admin");
599 		return (0);
600 	}
601 
602 	host_access = smb_kshare_hostaccess(shr, &sr->session->ipaddr);
603 	if ((host_access & ACE_ALL_PERMS) == 0) {
604 		smb_tree_log(sr, sharename, "access denied: host access");
605 		return (0);
606 	}
607 
608 	acl_access = smb_tree_acl_access(sr, shr, vp);
609 	if ((acl_access & ACE_ALL_PERMS) == 0) {
610 		smb_tree_log(sr, sharename, "access denied: share ACL");
611 		return (0);
612 	}
613 
614 	access = host_access & acl_access;
615 	if ((access & ACE_ALL_PERMS) == 0) {
616 		smb_tree_log(sr, sharename, "access denied");
617 		return (0);
618 	}
619 
620 	return (access);
621 }
622 
623 /*
624  * Connect a share for use with files and directories.
625  */
626 static smb_tree_t *
627 smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
628 {
629 	const char		*any = "?????";
630 	smb_user_t		*user = sr->uid_user;
631 	smb_node_t		*dnode = NULL;
632 	smb_node_t		*snode = NULL;
633 	smb_kshare_t 		*si = sr->sr_tcon.si;
634 	char			*service = sr->sr_tcon.service;
635 	char			last_component[MAXNAMELEN];
636 	smb_tree_t		*tree;
637 	int			rc;
638 	uint32_t		access;
639 	smb_shr_execinfo_t	execinfo;
640 
641 	ASSERT(user);
642 	ASSERT(user->u_cred);
643 
644 	if ((strcmp(service, any) != 0) && (strcasecmp(service, "A:") != 0)) {
645 		smb_tree_log(sr, sharename, "invalid service (%s)", service);
646 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
647 		    ERRDOS, ERROR_BAD_DEV_TYPE);
648 		return (NULL);
649 	}
650 
651 	/*
652 	 * Check that the shared directory exists.
653 	 */
654 	rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
655 	    last_component);
656 
657 	if (rc == 0) {
658 		rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
659 		    sr->sr_server->si_root_smb_node, dnode, last_component,
660 		    &snode);
661 
662 		smb_node_release(dnode);
663 	}
664 
665 	if (rc) {
666 		if (snode)
667 			smb_node_release(snode);
668 
669 		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
670 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
671 		return (NULL);
672 	}
673 
674 	if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
675 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
676 		smb_node_release(snode);
677 		return (NULL);
678 	}
679 
680 	/*
681 	 * Set up the OptionalSupport for this share.
682 	 */
683 	sr->sr_tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
684 
685 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
686 	case SMB_SHRF_CSC_DISABLED:
687 		sr->sr_tcon.optional_support |= SMB_CSC_CACHE_NONE;
688 		break;
689 	case SMB_SHRF_CSC_AUTO:
690 		sr->sr_tcon.optional_support |= SMB_CSC_CACHE_AUTO_REINT;
691 		break;
692 	case SMB_SHRF_CSC_VDO:
693 		sr->sr_tcon.optional_support |= SMB_CSC_CACHE_VDO;
694 		break;
695 	case SMB_SHRF_CSC_MANUAL:
696 	default:
697 		/*
698 		 * Default to SMB_CSC_CACHE_MANUAL_REINT.
699 		 */
700 		break;
701 	}
702 
703 	/* ABE support */
704 	if (si->shr_flags & SMB_SHRF_ABE)
705 		sr->sr_tcon.optional_support |=
706 		    SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
707 
708 	if (si->shr_flags & SMB_SHRF_DFSROOT)
709 		sr->sr_tcon.optional_support |= SMB_SHARE_IS_IN_DFS;
710 
711 	/* if 'smb' zfs property: shortnames=disabled */
712 	if (!smb_shortnames)
713 		sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME;
714 
715 	tree = smb_tree_alloc(user, si, snode, access,
716 	    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(&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(user, si, snode, access,
809 	    sr->sr_cfg->skc_execflags);
810 
811 	smb_node_release(snode);
812 
813 	if (tree == NULL)
814 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
815 
816 	return (tree);
817 }
818 
819 /*
820  * Connect an IPC share for use with named pipes.
821  */
822 static smb_tree_t *
823 smb_tree_connect_ipc(smb_request_t *sr, const char *name)
824 {
825 	const char	*any = "?????";
826 	smb_user_t	*user = sr->uid_user;
827 	smb_tree_t	*tree;
828 	smb_kshare_t	*si = sr->sr_tcon.si;
829 	char		*service = sr->sr_tcon.service;
830 
831 	ASSERT(user);
832 
833 	if ((user->u_flags & SMB_USER_FLAG_IPC) &&
834 	    sr->sr_cfg->skc_restrict_anon) {
835 		smb_tree_log(sr, name, "access denied: restrict anonymous");
836 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
837 		return (NULL);
838 	}
839 
840 	if ((strcmp(service, any) != 0) && (strcasecmp(service, "IPC") != 0)) {
841 		smb_tree_log(sr, name, "invalid service (%s)", service);
842 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
843 		    ERRDOS, ERROR_BAD_DEV_TYPE);
844 		return (NULL);
845 	}
846 
847 	sr->sr_tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
848 
849 	tree = smb_tree_alloc(user, si, NULL, ACE_ALL_PERMS, 0);
850 	if (tree == NULL) {
851 		smb_tree_log(sr, name, "access denied");
852 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
853 	}
854 
855 	return (tree);
856 }
857 
858 /*
859  * Allocate a tree.
860  */
861 static smb_tree_t *
862 smb_tree_alloc(smb_user_t *user, const smb_kshare_t *si, smb_node_t *snode,
863     uint32_t access, uint32_t execflags)
864 {
865 	smb_tree_t	*tree;
866 	uint32_t	stype = si->shr_type;
867 	uint16_t	tid;
868 
869 	if (smb_idpool_alloc(&user->u_tid_pool, &tid))
870 		return (NULL);
871 
872 	tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP);
873 	bzero(tree, sizeof (smb_tree_t));
874 
875 	tree->t_user = user;
876 	tree->t_session = user->u_session;
877 	tree->t_server = user->u_server;
878 
879 	if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
880 		if (smb_tree_getattr(si, snode, tree) != 0) {
881 			smb_idpool_free(&user->u_tid_pool, tid);
882 			kmem_cache_free(user->u_server->si_cache_tree, tree);
883 			return (NULL);
884 		}
885 	}
886 
887 	if (smb_idpool_constructor(&tree->t_fid_pool)) {
888 		smb_idpool_free(&user->u_tid_pool, tid);
889 		kmem_cache_free(user->u_server->si_cache_tree, tree);
890 		return (NULL);
891 	}
892 
893 	if (smb_idpool_constructor(&tree->t_odid_pool)) {
894 		smb_idpool_destructor(&tree->t_fid_pool);
895 		smb_idpool_free(&user->u_tid_pool, tid);
896 		kmem_cache_free(user->u_server->si_cache_tree, tree);
897 		return (NULL);
898 	}
899 
900 	smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
901 	    offsetof(smb_ofile_t, f_lnd));
902 
903 	smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
904 	    offsetof(smb_odir_t, d_lnd));
905 
906 	(void) strlcpy(tree->t_sharename, si->shr_name,
907 	    sizeof (tree->t_sharename));
908 	(void) strlcpy(tree->t_resource, si->shr_path,
909 	    sizeof (tree->t_resource));
910 
911 	mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
912 
913 	tree->t_refcnt = 1;
914 	tree->t_tid = tid;
915 	tree->t_res_type = stype;
916 	tree->t_state = SMB_TREE_STATE_CONNECTED;
917 	tree->t_magic = SMB_TREE_MAGIC;
918 	tree->t_access = access;
919 	tree->t_connect_time = gethrestime_sec();
920 	tree->t_execflags = execflags;
921 
922 	/* if FS is readonly, enforce that here */
923 	if (tree->t_flags & SMB_TREE_READONLY)
924 		tree->t_access &= ~ACE_ALL_WRITE_PERMS;
925 
926 	if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
927 		smb_node_ref(snode);
928 		tree->t_snode = snode;
929 		tree->t_acltype = smb_fsop_acltype(snode);
930 	}
931 
932 	smb_llist_enter(&user->u_tree_list, RW_WRITER);
933 	smb_llist_insert_head(&user->u_tree_list, tree);
934 	smb_llist_exit(&user->u_tree_list);
935 	atomic_inc_32(&user->u_session->s_tree_cnt);
936 	smb_server_inc_trees(user->u_server);
937 	return (tree);
938 }
939 
940 /*
941  * Deallocate a tree.  The open file and open directory lists should be
942  * empty.
943  *
944  * Remove the tree from the user's tree list before freeing resources
945  * associated with the tree.
946  */
947 void
948 smb_tree_dealloc(void *arg)
949 {
950 	smb_user_t	*user;
951 	smb_tree_t	*tree = (smb_tree_t *)arg;
952 
953 	SMB_TREE_VALID(tree);
954 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
955 	ASSERT(tree->t_refcnt == 0);
956 
957 	user = tree->t_user;
958 	smb_llist_enter(&user->u_tree_list, RW_WRITER);
959 	smb_llist_remove(&user->u_tree_list, tree);
960 	smb_idpool_free(&user->u_tid_pool, tree->t_tid);
961 	atomic_dec_32(&tree->t_session->s_tree_cnt);
962 	smb_llist_exit(&user->u_tree_list);
963 
964 	mutex_enter(&tree->t_mutex);
965 	mutex_exit(&tree->t_mutex);
966 
967 	tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
968 
969 	if (tree->t_snode)
970 		smb_node_release(tree->t_snode);
971 
972 	mutex_destroy(&tree->t_mutex);
973 	smb_llist_destructor(&tree->t_ofile_list);
974 	smb_llist_destructor(&tree->t_odir_list);
975 	smb_idpool_destructor(&tree->t_fid_pool);
976 	smb_idpool_destructor(&tree->t_odid_pool);
977 	kmem_cache_free(tree->t_server->si_cache_tree, tree);
978 }
979 
980 /*
981  * Determine whether or not a tree is connected.
982  * This function must be called with the tree mutex held.
983  */
984 static boolean_t
985 smb_tree_is_connected_locked(smb_tree_t *tree)
986 {
987 	switch (tree->t_state) {
988 	case SMB_TREE_STATE_CONNECTED:
989 		return (B_TRUE);
990 
991 	case SMB_TREE_STATE_DISCONNECTING:
992 	case SMB_TREE_STATE_DISCONNECTED:
993 		/*
994 		 * The tree exists but being diconnected or destroyed.
995 		 */
996 		return (B_FALSE);
997 
998 	default:
999 		ASSERT(0);
1000 		return (B_FALSE);
1001 	}
1002 }
1003 
1004 /*
1005  * Determine whether or not a tree is disconnected.
1006  * This function must be called with the tree mutex held.
1007  */
1008 static boolean_t
1009 smb_tree_is_disconnected(smb_tree_t *tree)
1010 {
1011 	switch (tree->t_state) {
1012 	case SMB_TREE_STATE_DISCONNECTED:
1013 		return (B_TRUE);
1014 
1015 	case SMB_TREE_STATE_CONNECTED:
1016 	case SMB_TREE_STATE_DISCONNECTING:
1017 		return (B_FALSE);
1018 
1019 	default:
1020 		ASSERT(0);
1021 		return (B_FALSE);
1022 	}
1023 }
1024 
1025 /*
1026  * Return a pointer to the share name within a share resource path.
1027  *
1028  * The share path may be a Uniform Naming Convention (UNC) string
1029  * (\\server\share) or simply the share name.  We validate the UNC
1030  * format but we don't look at the server name.
1031  */
1032 static const char *
1033 smb_tree_get_sharename(const char *unc_path)
1034 {
1035 	const char *sharename = unc_path;
1036 
1037 	if (sharename[0] == '\\') {
1038 		/*
1039 		 * Looks like a UNC path, validate the format.
1040 		 */
1041 		if (sharename[1] != '\\')
1042 			return (NULL);
1043 
1044 		if ((sharename = strchr(sharename+2, '\\')) == NULL)
1045 			return (NULL);
1046 
1047 		++sharename;
1048 	} else if (strchr(sharename, '\\') != NULL) {
1049 		/*
1050 		 * This should be a share name (no embedded \'s).
1051 		 */
1052 		return (NULL);
1053 	}
1054 
1055 	return (sharename);
1056 }
1057 
1058 /*
1059  * Obtain the tree attributes: volume name, typename and flags.
1060  */
1061 static int
1062 smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree)
1063 {
1064 	vfs_t *vfsp = SMB_NODE_VFS(node);
1065 
1066 	ASSERT(vfsp);
1067 
1068 	if (getvfs(&vfsp->vfs_fsid) != vfsp)
1069 		return (ESTALE);
1070 
1071 	smb_tree_get_volname(vfsp, tree);
1072 	smb_tree_get_flags(si, vfsp, tree);
1073 
1074 	VFS_RELE(vfsp);
1075 	return (0);
1076 }
1077 
1078 /*
1079  * Extract the volume name.
1080  */
1081 static void
1082 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
1083 {
1084 	refstr_t *vfs_mntpoint;
1085 	const char *s;
1086 	char *name;
1087 
1088 	vfs_mntpoint = vfs_getmntpoint(vfsp);
1089 
1090 	s = vfs_mntpoint->rs_string;
1091 	s += strspn(s, "/");
1092 	(void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
1093 
1094 	refstr_rele(vfs_mntpoint);
1095 
1096 	name = tree->t_volume;
1097 	(void) strsep((char **)&name, "/");
1098 }
1099 
1100 /*
1101  * Always set ACL support because the VFS will fake ACLs for file systems
1102  * that don't support them.
1103  *
1104  * Some flags are dependent on the typename, which is also set up here.
1105  * File system types are hardcoded in uts/common/os/vfs_conf.c.
1106  */
1107 static void
1108 smb_tree_get_flags(const smb_kshare_t *si, vfs_t *vfsp, smb_tree_t *tree)
1109 {
1110 	smb_session_t *ssn = tree->t_session;
1111 
1112 	typedef struct smb_mtype {
1113 		char		*mt_name;
1114 		size_t		mt_namelen;
1115 		uint32_t	mt_flags;
1116 	} smb_mtype_t;
1117 
1118 	static smb_mtype_t smb_mtype[] = {
1119 		{ "zfs",    3,	SMB_TREE_UNICODE_ON_DISK |
1120 		    SMB_TREE_QUOTA | SMB_TREE_SPARSE},
1121 		{ "ufs",    3,	SMB_TREE_UNICODE_ON_DISK },
1122 		{ "nfs",    3,	SMB_TREE_NFS_MOUNTED },
1123 		{ "tmpfs",  5,	SMB_TREE_NO_EXPORT }
1124 	};
1125 	smb_mtype_t	*mtype;
1126 	char		*name;
1127 	uint32_t	flags = SMB_TREE_SUPPORTS_ACLS;
1128 	int		i;
1129 
1130 	if (si->shr_flags & SMB_SHRF_DFSROOT)
1131 		flags |= SMB_TREE_DFSROOT;
1132 
1133 	if (si->shr_flags & SMB_SHRF_CATIA)
1134 		flags |= SMB_TREE_CATIA;
1135 
1136 	if (si->shr_flags & SMB_SHRF_ABE)
1137 		flags |= SMB_TREE_ABE;
1138 
1139 	if (ssn->s_cfg.skc_oplock_enable) {
1140 		/* if 'smb' zfs property: oplocks=enabled */
1141 		flags |= SMB_TREE_OPLOCKS;
1142 	}
1143 
1144 	/* Global config option for now.  Later make per-share. */
1145 	if (ssn->s_cfg.skc_traverse_mounts)
1146 		flags |= SMB_TREE_TRAVERSE_MOUNTS;
1147 
1148 	/* if 'smb' zfs property: shortnames=enabled */
1149 	if (smb_shortnames)
1150 		flags |= SMB_TREE_SHORTNAMES;
1151 
1152 	if (vfsp->vfs_flag & VFS_RDONLY)
1153 		flags |= SMB_TREE_READONLY;
1154 
1155 	if (vfsp->vfs_flag & VFS_XATTR)
1156 		flags |= SMB_TREE_STREAMS;
1157 
1158 	name = vfssw[vfsp->vfs_fstype].vsw_name;
1159 
1160 	for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
1161 		mtype = &smb_mtype[i];
1162 		if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
1163 			flags |= mtype->mt_flags;
1164 	}
1165 
1166 	(void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
1167 	(void) smb_strupr((char *)tree->t_typename);
1168 
1169 	if (vfs_has_feature(vfsp, VFSFT_XVATTR))
1170 		flags |= SMB_TREE_XVATTR;
1171 
1172 	if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
1173 		flags |= SMB_TREE_CASEINSENSITIVE;
1174 
1175 	if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
1176 		flags |= SMB_TREE_NO_CASESENSITIVE;
1177 
1178 	if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
1179 		flags |= SMB_TREE_DIRENTFLAGS;
1180 
1181 	if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
1182 		flags |= SMB_TREE_ACLONCREATE;
1183 
1184 	if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
1185 		flags |= SMB_TREE_ACEMASKONACCESS;
1186 
1187 	DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);
1188 
1189 
1190 	tree->t_flags = flags;
1191 }
1192 
1193 /*
1194  * Report share access result to syslog.
1195  */
1196 static void
1197 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
1198 {
1199 	va_list ap;
1200 	char buf[128];
1201 	smb_user_t *user = sr->uid_user;
1202 
1203 	ASSERT(user);
1204 
1205 	if (smb_tcon_mute)
1206 		return;
1207 
1208 	if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
1209 		/*
1210 		 * Only report normal users, i.e. ignore W2K misuse
1211 		 * of the IPC connection by filtering out internal
1212 		 * names such as nobody and root.
1213 		 */
1214 		if ((strcmp(user->u_name, "root") == 0) ||
1215 		    (strcmp(user->u_name, "nobody") == 0)) {
1216 			return;
1217 		}
1218 	}
1219 
1220 	va_start(ap, fmt);
1221 	(void) vsnprintf(buf, 128, fmt, ap);
1222 	va_end(ap);
1223 
1224 	cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
1225 	    user->u_domain, user->u_name, sharename, buf);
1226 }
1227 
1228 /*
1229  * smb_tree_lookup_odir
1230  *
1231  * Find the specified odir in the tree's list of odirs, and
1232  * attempt to obtain a hold on the odir.
1233  *
1234  * Returns NULL if odir not found or a hold cannot be obtained.
1235  */
1236 smb_odir_t *
1237 smb_tree_lookup_odir(smb_tree_t *tree, uint16_t odid)
1238 {
1239 	smb_odir_t	*od;
1240 	smb_llist_t	*od_list;
1241 
1242 	ASSERT(tree);
1243 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1244 
1245 	od_list = &tree->t_odir_list;
1246 	smb_llist_enter(od_list, RW_READER);
1247 
1248 	od = smb_llist_head(od_list);
1249 	while (od) {
1250 		if (od->d_odid == odid) {
1251 			if (!smb_odir_hold(od))
1252 				od = NULL;
1253 			break;
1254 		}
1255 		od = smb_llist_next(od_list, od);
1256 	}
1257 
1258 	smb_llist_exit(od_list);
1259 	return (od);
1260 }
1261 
1262 boolean_t
1263 smb_tree_is_connected(smb_tree_t *tree)
1264 {
1265 	boolean_t	rb;
1266 
1267 	mutex_enter(&tree->t_mutex);
1268 	rb = smb_tree_is_connected_locked(tree);
1269 	mutex_exit(&tree->t_mutex);
1270 	return (rb);
1271 }
1272 
1273 /*
1274  * Get the next open ofile in the list.  A reference is taken on
1275  * the ofile, which can be released later with smb_ofile_release().
1276  *
1277  * If the specified ofile is NULL, search from the beginning of the
1278  * list.  Otherwise, the search starts just after that ofile.
1279  *
1280  * Returns NULL if there are no open files in the list.
1281  */
1282 static smb_ofile_t *
1283 smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of)
1284 {
1285 	smb_llist_t *ofile_list;
1286 
1287 	ASSERT(tree);
1288 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1289 
1290 	ofile_list = &tree->t_ofile_list;
1291 	smb_llist_enter(ofile_list, RW_READER);
1292 
1293 	if (of) {
1294 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
1295 		of = smb_llist_next(ofile_list, of);
1296 	} else {
1297 		of = smb_llist_head(ofile_list);
1298 	}
1299 
1300 	while (of) {
1301 		if (smb_ofile_hold(of))
1302 			break;
1303 
1304 		of = smb_llist_next(ofile_list, of);
1305 	}
1306 
1307 	smb_llist_exit(ofile_list);
1308 	return (of);
1309 }
1310 
1311 /*
1312  * smb_tree_get_odir
1313  *
1314  * Find the next odir in the tree's list of odirs, and obtain a
1315  * hold on it.
1316  * If the specified odir is NULL the search starts at the beginning
1317  * of the tree's odir list, otherwise the search starts after the
1318  * specified odir.
1319  */
1320 static smb_odir_t *
1321 smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od)
1322 {
1323 	smb_llist_t *od_list;
1324 
1325 	ASSERT(tree);
1326 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1327 
1328 	od_list = &tree->t_odir_list;
1329 	smb_llist_enter(od_list, RW_READER);
1330 
1331 	if (od) {
1332 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1333 		od = smb_llist_next(od_list, od);
1334 	} else {
1335 		od = smb_llist_head(od_list);
1336 	}
1337 
1338 	while (od) {
1339 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1340 
1341 		if (smb_odir_hold(od))
1342 			break;
1343 		od = smb_llist_next(od_list, od);
1344 	}
1345 
1346 	smb_llist_exit(od_list);
1347 	return (od);
1348 }
1349 
1350 /*
1351  * smb_tree_close_odirs
1352  *
1353  * Close all open odirs in the tree's list which were opened by
1354  * the process identified by pid.
1355  * If pid is zero, close all open odirs in the tree's list.
1356  */
1357 static void
1358 smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid)
1359 {
1360 	smb_odir_t *od, *next_od;
1361 
1362 	ASSERT(tree);
1363 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1364 
1365 	od = smb_tree_get_odir(tree, NULL);
1366 	while (od) {
1367 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1368 		ASSERT(od->d_tree == tree);
1369 
1370 		next_od = smb_tree_get_odir(tree, od);
1371 		if ((pid == 0) || (od->d_opened_by_pid == pid))
1372 			smb_odir_close(od);
1373 		smb_odir_release(od);
1374 
1375 		od = next_od;
1376 	}
1377 }
1378 
1379 static void
1380 smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec, int exec_type)
1381 {
1382 	exec->e_sharename = tree->t_sharename;
1383 	exec->e_winname = tree->t_user->u_name;
1384 	exec->e_userdom = tree->t_user->u_domain;
1385 	exec->e_srv_ipaddr = tree->t_session->local_ipaddr;
1386 	exec->e_cli_ipaddr = tree->t_session->ipaddr;
1387 	exec->e_cli_netbiosname = tree->t_session->workstation;
1388 	exec->e_uid = crgetuid(tree->t_user->u_cred);
1389 	exec->e_type = exec_type;
1390 }
1391 
1392 /*
1393  * Private function to support smb_tree_enum.
1394  */
1395 static int
1396 smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum)
1397 {
1398 	uint8_t *pb;
1399 	uint_t nbytes;
1400 	int rc;
1401 
1402 	if (svcenum->se_nskip > 0) {
1403 		svcenum->se_nskip--;
1404 		return (0);
1405 	}
1406 
1407 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
1408 		svcenum->se_nitems = svcenum->se_nlimit;
1409 		return (0);
1410 	}
1411 
1412 	pb = &svcenum->se_buf[svcenum->se_bused];
1413 	rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes);
1414 	if (rc == 0) {
1415 		svcenum->se_bavail -= nbytes;
1416 		svcenum->se_bused += nbytes;
1417 		svcenum->se_nitems++;
1418 	}
1419 
1420 	return (rc);
1421 }
1422 
1423 /*
1424  * Encode connection information into a buffer: connection information
1425  * needed in user space to support RPC requests.
1426  */
1427 static int
1428 smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
1429     uint32_t *nbytes)
1430 {
1431 	smb_netconnectinfo_t	info;
1432 	int			rc;
1433 
1434 	smb_tree_netinfo_init(tree, &info);
1435 	rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes);
1436 	smb_tree_netinfo_fini(&info);
1437 
1438 	return (rc);
1439 }
1440 
1441 /*
1442  * Note: ci_numusers should be the number of users connected to
1443  * the share rather than the number of references on the tree but
1444  * we don't have a mechanism to track users/share in smbsrv yet.
1445  */
1446 static void
1447 smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
1448 {
1449 	smb_user_t	*user;
1450 
1451 	ASSERT(tree);
1452 
1453 	info->ci_id = tree->t_tid;
1454 	info->ci_type = tree->t_res_type;
1455 	info->ci_numopens = tree->t_open_files;
1456 	info->ci_numusers = tree->t_refcnt;
1457 	info->ci_time = gethrestime_sec() - tree->t_connect_time;
1458 
1459 	info->ci_sharelen = strlen(tree->t_sharename) + 1;
1460 	info->ci_share = smb_mem_strdup(tree->t_sharename);
1461 
1462 	user = tree->t_user;
1463 	ASSERT(user);
1464 
1465 	info->ci_namelen = user->u_domain_len + user->u_name_len + 2;
1466 	info->ci_username = kmem_alloc(info->ci_namelen, KM_SLEEP);
1467 	(void) snprintf(info->ci_username, info->ci_namelen, "%s\\%s",
1468 	    user->u_domain, user->u_name);
1469 }
1470 
1471 static void
1472 smb_tree_netinfo_fini(smb_netconnectinfo_t *info)
1473 {
1474 	if (info == NULL)
1475 		return;
1476 
1477 	if (info->ci_username)
1478 		kmem_free(info->ci_username, info->ci_namelen);
1479 	if (info->ci_share)
1480 		smb_mem_free(info->ci_share);
1481 
1482 	bzero(info, sizeof (smb_netconnectinfo_t));
1483 }
1484