xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_tree.c (revision 8622ec4569457733001d4982ef7f5b44427069be)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21148c5f43SAlan Wright 
22da6c28aaSamw /*
23c5866007SKeyur Desai  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
243b13a1efSThomas Keiser  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw /*
28da6c28aaSamw  * General Structures Layout
29da6c28aaSamw  * -------------------------
30da6c28aaSamw  *
31da6c28aaSamw  * This is a simplified diagram showing the relationship between most of the
32da6c28aaSamw  * main structures.
33da6c28aaSamw  *
34da6c28aaSamw  * +-------------------+
35da6c28aaSamw  * |     SMB_INFO      |
36da6c28aaSamw  * +-------------------+
37da6c28aaSamw  *          |
38da6c28aaSamw  *          |
39da6c28aaSamw  *          v
40da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
41da6c28aaSamw  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
42da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
433b13a1efSThomas Keiser  *   |          |
443b13a1efSThomas Keiser  *   |          |
453b13a1efSThomas Keiser  *   |          v
463b13a1efSThomas Keiser  *   |  +-------------------+     +-------------------+   +-------------------+
473b13a1efSThomas Keiser  *   |  |       USER        |<--->|       USER        |...|       USER        |
483b13a1efSThomas Keiser  *   |  +-------------------+     +-------------------+   +-------------------+
49da6c28aaSamw  *   |
50da6c28aaSamw  *   |
51da6c28aaSamw  *   v
52da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
53da6c28aaSamw  * |       TREE        |<----->|       TREE        |......|       TREE        |
54da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
55da6c28aaSamw  *      |         |
56da6c28aaSamw  *      |         |
57da6c28aaSamw  *      |         v
58da6c28aaSamw  *      |     +-------+       +-------+      +-------+
59da6c28aaSamw  *      |     | OFILE |<----->| OFILE |......| OFILE |
60da6c28aaSamw  *      |     +-------+       +-------+      +-------+
61da6c28aaSamw  *      |
62da6c28aaSamw  *      |
63da6c28aaSamw  *      v
64da6c28aaSamw  *  +-------+       +------+      +------+
65da6c28aaSamw  *  | ODIR  |<----->| ODIR |......| ODIR |
66da6c28aaSamw  *  +-------+       +------+      +------+
67da6c28aaSamw  *
68da6c28aaSamw  *
69da6c28aaSamw  * Tree State Machine
70da6c28aaSamw  * ------------------
71da6c28aaSamw  *
72da6c28aaSamw  *    +-----------------------------+	 T0
73da6c28aaSamw  *    |  SMB_TREE_STATE_CONNECTED   |<----------- Creation/Allocation
74da6c28aaSamw  *    +-----------------------------+
75da6c28aaSamw  *		    |
76da6c28aaSamw  *		    | T1
77da6c28aaSamw  *		    |
78da6c28aaSamw  *		    v
79da6c28aaSamw  *    +------------------------------+
80da6c28aaSamw  *    | SMB_TREE_STATE_DISCONNECTING |
81da6c28aaSamw  *    +------------------------------+
82da6c28aaSamw  *		    |
83da6c28aaSamw  *		    | T2
84da6c28aaSamw  *		    |
85da6c28aaSamw  *		    v
86da6c28aaSamw  *    +-----------------------------+    T3
87da6c28aaSamw  *    | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free
88da6c28aaSamw  *    +-----------------------------+
89da6c28aaSamw  *
90da6c28aaSamw  * SMB_TREE_STATE_CONNECTED
91da6c28aaSamw  *
92da6c28aaSamw  *    While in this state:
93da6c28aaSamw  *      - The tree is queued in the list of trees of its user.
94da6c28aaSamw  *      - References will be given out if the tree is looked up.
95da6c28aaSamw  *      - Files under that tree can be accessed.
96da6c28aaSamw  *
97da6c28aaSamw  * SMB_TREE_STATE_DISCONNECTING
98da6c28aaSamw  *
99da6c28aaSamw  *    While in this state:
100da6c28aaSamw  *      - The tree is queued in the list of trees of its user.
101da6c28aaSamw  *      - References will not be given out if the tree is looked up.
102da6c28aaSamw  *      - The files and directories open under the tree are being closed.
103da6c28aaSamw  *      - The resources associated with the tree remain.
104da6c28aaSamw  *
105da6c28aaSamw  * SMB_TREE_STATE_DISCONNECTED
106da6c28aaSamw  *
107da6c28aaSamw  *    While in this state:
108da6c28aaSamw  *      - The tree is queued in the list of trees of its user.
109da6c28aaSamw  *      - References will not be given out if the tree is looked up.
110da6c28aaSamw  *      - The tree has no more files and directories opened.
111da6c28aaSamw  *      - The resources associated with the tree remain.
112da6c28aaSamw  *
113da6c28aaSamw  * Transition T0
114da6c28aaSamw  *
115da6c28aaSamw  *    This transition occurs in smb_tree_connect(). A new tree is created and
116da6c28aaSamw  *    added to the list of trees of a user.
117da6c28aaSamw  *
118da6c28aaSamw  * Transition T1
119da6c28aaSamw  *
120da6c28aaSamw  *    This transition occurs in smb_tree_disconnect().
121da6c28aaSamw  *
122da6c28aaSamw  * Transition T2
123da6c28aaSamw  *
124da6c28aaSamw  *    This transition occurs in smb_tree_release(). The resources associated
125da6c28aaSamw  *    with the tree are freed as well as the tree structure. For the transition
126da6c28aaSamw  *    to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED state and
127da6c28aaSamw  *    the reference count be zero.
128da6c28aaSamw  *
129da6c28aaSamw  * Comments
130da6c28aaSamw  * --------
131da6c28aaSamw  *
132da6c28aaSamw  *    The state machine of the tree structures is controlled by 3 elements:
133da6c28aaSamw  *      - The list of trees of the user it belongs to.
134da6c28aaSamw  *      - The mutex embedded in the structure itself.
135da6c28aaSamw  *      - The reference count.
136da6c28aaSamw  *
137da6c28aaSamw  *    There's a mutex embedded in the tree structure used to protect its fields
138da6c28aaSamw  *    and there's a lock embedded in the list of trees of a user. To
139da6c28aaSamw  *    increment or to decrement the reference count the mutex must be entered.
140da6c28aaSamw  *    To insert the tree into the list of trees of the user and to remove
141da6c28aaSamw  *    the tree from it, the lock must be entered in RW_WRITER mode.
142da6c28aaSamw  *
143da6c28aaSamw  *    Rules of access to a tree structure:
144da6c28aaSamw  *
145da6c28aaSamw  *    1) In order to avoid deadlocks, when both (mutex and lock of the user
146da6c28aaSamw  *       list) have to be entered, the lock must be entered first.
147da6c28aaSamw  *
148da6c28aaSamw  *    2) All actions applied to a tree require a reference count.
149da6c28aaSamw  *
150c8ec8eeaSjose borrego  *    3) There are 2 ways of getting a reference count: when a tree is
151c8ec8eeaSjose borrego  *       connected and when a tree is looked up.
152da6c28aaSamw  *
153da6c28aaSamw  *    It should be noted that the reference count of a tree registers the
154da6c28aaSamw  *    number of references to the tree in other structures (such as an smb
155da6c28aaSamw  *    request). The reference count is not incremented in these 2 instances:
156da6c28aaSamw  *
157da6c28aaSamw  *    1) The tree is connected. An tree is anchored by his state. If there's
158da6c28aaSamw  *       no activity involving a tree currently connected, the reference
159da6c28aaSamw  *       count of that tree is zero.
160da6c28aaSamw  *
161da6c28aaSamw  *    2) The tree is queued in the list of trees of the user. The fact of
162da6c28aaSamw  *       being queued in that list is NOT registered by incrementing the
163da6c28aaSamw  *       reference count.
164da6c28aaSamw  */
165148c5f43SAlan Wright 
166c8ec8eeaSjose borrego #include <sys/refstr_impl.h>
167bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
168148c5f43SAlan Wright #include <smbsrv/smb_ktypes.h>
169da6c28aaSamw #include <smbsrv/smb_fsops.h>
170cb174861Sjoyce mcintosh #include <smbsrv/smb_share.h>
171da6c28aaSamw 
172c8ec8eeaSjose borrego int smb_tcon_mute = 0;
173c8ec8eeaSjose borrego 
174cb174861Sjoyce mcintosh static smb_tree_t *smb_tree_connect_core(smb_request_t *);
175c8ec8eeaSjose borrego static smb_tree_t *smb_tree_connect_disk(smb_request_t *, const char *);
176148c5f43SAlan Wright static smb_tree_t *smb_tree_connect_printq(smb_request_t *, const char *);
177c8ec8eeaSjose borrego static smb_tree_t *smb_tree_connect_ipc(smb_request_t *, const char *);
1783b13a1efSThomas Keiser static smb_tree_t *smb_tree_alloc(smb_request_t *, const smb_kshare_t *,
179148c5f43SAlan Wright     smb_node_t *, uint32_t, uint32_t);
1808b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States static boolean_t smb_tree_is_connected_locked(smb_tree_t *);
181c8ec8eeaSjose borrego static boolean_t smb_tree_is_disconnected(smb_tree_t *);
182c8ec8eeaSjose borrego static const char *smb_tree_get_sharename(const char *);
183148c5f43SAlan Wright static int smb_tree_getattr(const smb_kshare_t *, smb_node_t *, smb_tree_t *);
184c8ec8eeaSjose borrego static void smb_tree_get_volname(vfs_t *, smb_tree_t *);
185148c5f43SAlan Wright static void smb_tree_get_flags(const smb_kshare_t *, vfs_t *, smb_tree_t *);
186c8ec8eeaSjose borrego static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
1877f667e74Sjose borrego static void smb_tree_close_odirs(smb_tree_t *, uint16_t);
1881fcced4cSJordan Brown static smb_ofile_t *smb_tree_get_ofile(smb_tree_t *, smb_ofile_t *);
1897f667e74Sjose borrego static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *);
190148c5f43SAlan Wright static void smb_tree_set_execinfo(smb_tree_t *, smb_shr_execinfo_t *, int);
1911fcced4cSJordan Brown static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *);
1921fcced4cSJordan Brown static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *);
1931fcced4cSJordan Brown static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *);
1941fcced4cSJordan Brown static void smb_tree_netinfo_fini(smb_netconnectinfo_t *);
195da6c28aaSamw 
196cb174861Sjoyce mcintosh smb_tree_t *
197cb174861Sjoyce mcintosh smb_tree_connect(smb_request_t *sr)
198cb174861Sjoyce mcintosh {
199cb174861Sjoyce mcintosh 	smb_tree_t	*tree;
200cb174861Sjoyce mcintosh 	smb_server_t	*sv = sr->sr_server;
201cb174861Sjoyce mcintosh 
202cb174861Sjoyce mcintosh 	if (smb_threshold_enter(&sv->sv_tcon_ct) != 0) {
203cb174861Sjoyce mcintosh 		smbsr_error(sr, RPC_NT_SERVER_TOO_BUSY, 0, 0);
204cb174861Sjoyce mcintosh 		return (NULL);
205cb174861Sjoyce mcintosh 	}
206cb174861Sjoyce mcintosh 
207cb174861Sjoyce mcintosh 	tree = smb_tree_connect_core(sr);
208cb174861Sjoyce mcintosh 	smb_threshold_exit(&sv->sv_tcon_ct, sv);
209cb174861Sjoyce mcintosh 	return (tree);
210cb174861Sjoyce mcintosh }
211cb174861Sjoyce mcintosh 
212da6c28aaSamw /*
213148c5f43SAlan Wright  * Lookup the share name dispatch the appropriate stype handler.
214c8ec8eeaSjose borrego  * Share names are case insensitive so we map the share name to
215c8ec8eeaSjose borrego  * lower-case as a convenience for internal processing.
216148c5f43SAlan Wright  *
217148c5f43SAlan Wright  * Valid service values are:
218148c5f43SAlan Wright  *	A:      Disk share
219148c5f43SAlan Wright  *	LPT1:   Printer
220148c5f43SAlan Wright  *	IPC     Named pipe (IPC$ is reserved as the named pipe share).
221148c5f43SAlan Wright  *	COMM    Communications device
222148c5f43SAlan Wright  *	?????   Any type of device (wildcard)
223da6c28aaSamw  */
224cb174861Sjoyce mcintosh static smb_tree_t *
225cb174861Sjoyce mcintosh smb_tree_connect_core(smb_request_t *sr)
226c8ec8eeaSjose borrego {
227148c5f43SAlan Wright 	char		*unc_path = sr->sr_tcon.path;
228c8ec8eeaSjose borrego 	smb_tree_t	*tree = NULL;
229148c5f43SAlan Wright 	smb_kshare_t	*si;
230c8ec8eeaSjose borrego 	const char	*name;
231c8ec8eeaSjose borrego 
232bbf6f00cSJordan Brown 	(void) smb_strlwr(unc_path);
233c8ec8eeaSjose borrego 
234c8ec8eeaSjose borrego 	if ((name = smb_tree_get_sharename(unc_path)) == NULL) {
235488bda50SGordon Ross 		smb_tree_log(sr, unc_path, "invalid UNC path");
236c8ec8eeaSjose borrego 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
237c8ec8eeaSjose borrego 		return (NULL);
238c8ec8eeaSjose borrego 	}
239c8ec8eeaSjose borrego 
240*8622ec45SGordon Ross 	si = smb_kshare_lookup(sr->sr_server, name);
241*8622ec45SGordon Ross 	if (si == NULL) {
242148c5f43SAlan Wright 		smb_tree_log(sr, name, "share not found");
243148c5f43SAlan Wright 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
244c8ec8eeaSjose borrego 		return (NULL);
245c8ec8eeaSjose borrego 	}
246cb174861Sjoyce mcintosh 
247cb174861Sjoyce mcintosh 	if (!strcasecmp(SMB_SHARE_PRINT, name)) {
248*8622ec45SGordon Ross 		smb_kshare_release(sr->sr_server, si);
249cb174861Sjoyce mcintosh 		smb_tree_log(sr, name, "access not permitted");
250cb174861Sjoyce mcintosh 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
251cb174861Sjoyce mcintosh 		return (NULL);
252cb174861Sjoyce mcintosh 	}
253cb174861Sjoyce mcintosh 
254148c5f43SAlan Wright 	sr->sr_tcon.si = si;
255c8ec8eeaSjose borrego 
256148c5f43SAlan Wright 	switch (si->shr_type & STYPE_MASK) {
257c8ec8eeaSjose borrego 	case STYPE_DISKTREE:
258c8ec8eeaSjose borrego 		tree = smb_tree_connect_disk(sr, name);
259c8ec8eeaSjose borrego 		break;
260c8ec8eeaSjose borrego 	case STYPE_IPC:
261c8ec8eeaSjose borrego 		tree = smb_tree_connect_ipc(sr, name);
262c8ec8eeaSjose borrego 		break;
263148c5f43SAlan Wright 	case STYPE_PRINTQ:
264148c5f43SAlan Wright 		tree = smb_tree_connect_printq(sr, name);
265148c5f43SAlan Wright 		break;
266c8ec8eeaSjose borrego 	default:
267c8ec8eeaSjose borrego 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
268c8ec8eeaSjose borrego 		    ERRDOS, ERROR_BAD_DEV_TYPE);
269c8ec8eeaSjose borrego 		break;
270c8ec8eeaSjose borrego 	}
271c8ec8eeaSjose borrego 
272*8622ec45SGordon Ross 	smb_kshare_release(sr->sr_server, si);
273c8ec8eeaSjose borrego 	return (tree);
274c8ec8eeaSjose borrego }
275c8ec8eeaSjose borrego 
276c8ec8eeaSjose borrego /*
277c8ec8eeaSjose borrego  * Disconnect a tree.
278c8ec8eeaSjose borrego  */
279c8ec8eeaSjose borrego void
28029bd2886SAlan Wright smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec)
281c8ec8eeaSjose borrego {
282148c5f43SAlan Wright 	smb_shr_execinfo_t execinfo;
28329bd2886SAlan Wright 
284c8ec8eeaSjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
285c8ec8eeaSjose borrego 
286c8ec8eeaSjose borrego 	mutex_enter(&tree->t_mutex);
287c8ec8eeaSjose borrego 	ASSERT(tree->t_refcnt);
288c8ec8eeaSjose borrego 
2898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_tree_is_connected_locked(tree)) {
290c8ec8eeaSjose borrego 		/*
291c8ec8eeaSjose borrego 		 * Indicate that the disconnect process has started.
292c8ec8eeaSjose borrego 		 */
293c8ec8eeaSjose borrego 		tree->t_state = SMB_TREE_STATE_DISCONNECTING;
294c8ec8eeaSjose borrego 		mutex_exit(&tree->t_mutex);
295c8ec8eeaSjose borrego 
29629bd2886SAlan Wright 		if (do_exec) {
297c8ec8eeaSjose borrego 			/*
298c8ec8eeaSjose borrego 			 * The files opened under this tree are closed.
299c8ec8eeaSjose borrego 			 */
300c8ec8eeaSjose borrego 			smb_ofile_close_all(tree);
301c8ec8eeaSjose borrego 			/*
302c8ec8eeaSjose borrego 			 * The directories opened under this tree are closed.
303c8ec8eeaSjose borrego 			 */
3047f667e74Sjose borrego 			smb_tree_close_odirs(tree, 0);
30529bd2886SAlan Wright 		}
30629bd2886SAlan Wright 
307c8ec8eeaSjose borrego 		mutex_enter(&tree->t_mutex);
308c8ec8eeaSjose borrego 		tree->t_state = SMB_TREE_STATE_DISCONNECTED;
309148c5f43SAlan Wright 		smb_server_dec_trees(tree->t_server);
310c8ec8eeaSjose borrego 	}
311c8ec8eeaSjose borrego 
312c8ec8eeaSjose borrego 	mutex_exit(&tree->t_mutex);
31329bd2886SAlan Wright 
314148c5f43SAlan Wright 	if (do_exec && (tree->t_state == SMB_TREE_STATE_DISCONNECTED) &&
315148c5f43SAlan Wright 	    (tree->t_execflags & SMB_EXEC_UNMAP)) {
31629bd2886SAlan Wright 
317148c5f43SAlan Wright 		smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_UNMAP);
318*8622ec45SGordon Ross 		(void) smb_kshare_exec(tree->t_server, &execinfo);
31929bd2886SAlan Wright 	}
320c8ec8eeaSjose borrego }
321c8ec8eeaSjose borrego 
322c8ec8eeaSjose borrego /*
323c8ec8eeaSjose borrego  * Take a reference on a tree.
324c8ec8eeaSjose borrego  */
325c8ec8eeaSjose borrego boolean_t
326c8ec8eeaSjose borrego smb_tree_hold(
327c8ec8eeaSjose borrego     smb_tree_t		*tree)
328c8ec8eeaSjose borrego {
329c8ec8eeaSjose borrego 	ASSERT(tree);
330c8ec8eeaSjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
331c8ec8eeaSjose borrego 
332c8ec8eeaSjose borrego 	mutex_enter(&tree->t_mutex);
333c8ec8eeaSjose borrego 
3348b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_tree_is_connected_locked(tree)) {
335c8ec8eeaSjose borrego 		tree->t_refcnt++;
336c8ec8eeaSjose borrego 		mutex_exit(&tree->t_mutex);
337c8ec8eeaSjose borrego 		return (B_TRUE);
338c8ec8eeaSjose borrego 	}
339c8ec8eeaSjose borrego 
340c8ec8eeaSjose borrego 	mutex_exit(&tree->t_mutex);
341c8ec8eeaSjose borrego 	return (B_FALSE);
342c8ec8eeaSjose borrego }
343c8ec8eeaSjose borrego 
344c8ec8eeaSjose borrego /*
345c8ec8eeaSjose borrego  * Release a reference on a tree.  If the tree is disconnected and the
3469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * reference count falls to zero, post the object for deletion.
3479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Object deletion is deferred to avoid modifying a list while an
3489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * iteration may be in progress.
349c8ec8eeaSjose borrego  */
350c8ec8eeaSjose borrego void
351c8ec8eeaSjose borrego smb_tree_release(
352c8ec8eeaSjose borrego     smb_tree_t		*tree)
353c8ec8eeaSjose borrego {
3549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_TREE_VALID(tree);
355c8ec8eeaSjose borrego 
356c8ec8eeaSjose borrego 	mutex_enter(&tree->t_mutex);
357c8ec8eeaSjose borrego 	ASSERT(tree->t_refcnt);
358c8ec8eeaSjose borrego 	tree->t_refcnt--;
359c8ec8eeaSjose borrego 
360c5866007SKeyur Desai 	/* flush the ofile and odir lists' delete queues */
361c5866007SKeyur Desai 	smb_llist_flush(&tree->t_ofile_list);
362c5866007SKeyur Desai 	smb_llist_flush(&tree->t_odir_list);
363c5866007SKeyur Desai 
3649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0))
3653b13a1efSThomas Keiser 		smb_session_post_tree(tree->t_session, tree);
366c8ec8eeaSjose borrego 
367c8ec8eeaSjose borrego 	mutex_exit(&tree->t_mutex);
368c8ec8eeaSjose borrego }
369c8ec8eeaSjose borrego 
3709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
3719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_tree_post_ofile(smb_tree_t *tree, smb_ofile_t *of)
3729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
3739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_TREE_VALID(tree);
3749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OFILE_VALID(of);
3759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(of->f_refcnt == 0);
3769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED);
3779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(of->f_tree == tree);
3789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
3799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_post(&tree->t_ofile_list, of, smb_ofile_delete);
3809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
3819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
3829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
3839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_tree_post_odir(smb_tree_t *tree, smb_odir_t *od)
3849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
3859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_TREE_VALID(tree);
3869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_ODIR_VALID(od);
3879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(od->d_refcnt == 0);
3889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED);
3899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(od->d_tree == tree);
3909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
3919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_post(&tree->t_odir_list, od, smb_odir_delete);
3929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
3939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
394c8ec8eeaSjose borrego /*
395c8ec8eeaSjose borrego  * Close ofiles and odirs that match pid.
396c8ec8eeaSjose borrego  */
397c8ec8eeaSjose borrego void
398c8ec8eeaSjose borrego smb_tree_close_pid(
399c8ec8eeaSjose borrego     smb_tree_t		*tree,
400c8ec8eeaSjose borrego     uint16_t		pid)
401c8ec8eeaSjose borrego {
402c8ec8eeaSjose borrego 	ASSERT(tree);
403c8ec8eeaSjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
404c8ec8eeaSjose borrego 
405c8ec8eeaSjose borrego 	smb_ofile_close_all_by_pid(tree, pid);
4067f667e74Sjose borrego 	smb_tree_close_odirs(tree, pid);
407c8ec8eeaSjose borrego }
408c8ec8eeaSjose borrego 
409c8ec8eeaSjose borrego /*
410c8ec8eeaSjose borrego  * Check whether or not a tree supports the features identified by flags.
411c8ec8eeaSjose borrego  */
412c8ec8eeaSjose borrego boolean_t
413c8ec8eeaSjose borrego smb_tree_has_feature(smb_tree_t *tree, uint32_t flags)
414c8ec8eeaSjose borrego {
415c8ec8eeaSjose borrego 	ASSERT(tree);
416c8ec8eeaSjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
417c8ec8eeaSjose borrego 
418c8ec8eeaSjose borrego 	return ((tree->t_flags & flags) == flags);
419c8ec8eeaSjose borrego }
420c8ec8eeaSjose borrego 
4211fcced4cSJordan Brown /*
4221fcced4cSJordan Brown  * If the enumeration request is for tree data, handle the request
4231fcced4cSJordan Brown  * here.  Otherwise, pass it on to the ofiles.
4241fcced4cSJordan Brown  *
4251fcced4cSJordan Brown  * This function should be called with a hold on the tree.
4261fcced4cSJordan Brown  */
4271fcced4cSJordan Brown int
4281fcced4cSJordan Brown smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum)
4291fcced4cSJordan Brown {
4301fcced4cSJordan Brown 	smb_ofile_t	*of;
4311fcced4cSJordan Brown 	smb_ofile_t	*next;
4323b13a1efSThomas Keiser 	int		rc = 0;
4331fcced4cSJordan Brown 
4341fcced4cSJordan Brown 	ASSERT(tree);
4351fcced4cSJordan Brown 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
4361fcced4cSJordan Brown 
4371fcced4cSJordan Brown 	if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE)
4381fcced4cSJordan Brown 		return (smb_tree_enum_private(tree, svcenum));
4391fcced4cSJordan Brown 
4401fcced4cSJordan Brown 	of = smb_tree_get_ofile(tree, NULL);
4411fcced4cSJordan Brown 	while (of) {
4421fcced4cSJordan Brown 		ASSERT(of->f_tree == tree);
4431fcced4cSJordan Brown 
4441fcced4cSJordan Brown 		rc = smb_ofile_enum(of, svcenum);
4451fcced4cSJordan Brown 		if (rc != 0) {
4461fcced4cSJordan Brown 			smb_ofile_release(of);
4471fcced4cSJordan Brown 			break;
4481fcced4cSJordan Brown 		}
4491fcced4cSJordan Brown 
4501fcced4cSJordan Brown 		next = smb_tree_get_ofile(tree, of);
4511fcced4cSJordan Brown 		smb_ofile_release(of);
4521fcced4cSJordan Brown 		of = next;
4531fcced4cSJordan Brown 	}
4541fcced4cSJordan Brown 
4551fcced4cSJordan Brown 	return (rc);
4561fcced4cSJordan Brown }
4571fcced4cSJordan Brown 
4581fcced4cSJordan Brown /*
4591fcced4cSJordan Brown  * Close a file by its unique id.
4601fcced4cSJordan Brown  */
4611fcced4cSJordan Brown int
4621fcced4cSJordan Brown smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid)
4631fcced4cSJordan Brown {
4641fcced4cSJordan Brown 	smb_ofile_t	*of;
4651fcced4cSJordan Brown 
4661fcced4cSJordan Brown 	ASSERT(tree);
4671fcced4cSJordan Brown 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
4681fcced4cSJordan Brown 
4691fcced4cSJordan Brown 	if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL)
4701fcced4cSJordan Brown 		return (ENOENT);
4711fcced4cSJordan Brown 
4721fcced4cSJordan Brown 	if (smb_ofile_disallow_fclose(of)) {
4731fcced4cSJordan Brown 		smb_ofile_release(of);
4741fcced4cSJordan Brown 		return (EACCES);
4751fcced4cSJordan Brown 	}
4761fcced4cSJordan Brown 
4771fcced4cSJordan Brown 	smb_ofile_close(of, 0);
4781fcced4cSJordan Brown 	smb_ofile_release(of);
4791fcced4cSJordan Brown 	return (0);
4801fcced4cSJordan Brown }
481743a77edSAlan Wright 
482c8ec8eeaSjose borrego /* *************************** Static Functions ***************************** */
4831fcced4cSJordan Brown 
484743a77edSAlan Wright #define	SHARES_DIR	".zfs/shares/"
485148c5f43SAlan Wright 
486148c5f43SAlan Wright /*
487148c5f43SAlan Wright  * Calculates permissions given by the share's ACL to the
488148c5f43SAlan Wright  * user in the passed request.  The default is full access.
489148c5f43SAlan Wright  * If any error occurs, full access is granted.
490148c5f43SAlan Wright  *
491148c5f43SAlan Wright  * Using the vnode of the share path find the root directory
492148c5f43SAlan Wright  * of the mounted file system. Then look to see if there is a
493148c5f43SAlan Wright  * .zfs/shares directory and if there is, lookup the file with
494148c5f43SAlan Wright  * the same name as the share name in it. The ACL set for this
495148c5f43SAlan Wright  * file is the share's ACL which is used for access check here.
496148c5f43SAlan Wright  */
497148c5f43SAlan Wright static uint32_t
498148c5f43SAlan Wright smb_tree_acl_access(smb_request_t *sr, const smb_kshare_t *si, vnode_t *pathvp)
499743a77edSAlan Wright {
500fe1c642dSBill Krier 	smb_user_t	*user;
501fe1c642dSBill Krier 	cred_t		*cred;
502743a77edSAlan Wright 	int		rc;
503743a77edSAlan Wright 	vfs_t		*vfsp;
504743a77edSAlan Wright 	vnode_t		*root = NULL;
505743a77edSAlan Wright 	vnode_t		*sharevp = NULL;
506743a77edSAlan Wright 	char		*sharepath;
507743a77edSAlan Wright 	struct pathname	pnp;
508743a77edSAlan Wright 	size_t		size;
509148c5f43SAlan Wright 	uint32_t	access;
510743a77edSAlan Wright 
511fe1c642dSBill Krier 	user = sr->uid_user;
512fe1c642dSBill Krier 	cred = user->u_cred;
513148c5f43SAlan Wright 	access = ACE_ALL_PERMS;
514743a77edSAlan Wright 
515fe1c642dSBill Krier 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
516fe1c642dSBill Krier 		/*
517fe1c642dSBill Krier 		 * An autohome share owner gets full access to the share.
518fe1c642dSBill Krier 		 * Everyone else is denied access.
519fe1c642dSBill Krier 		 */
520c5866007SKeyur Desai 		if (si->shr_uid != crgetuid(cred))
521148c5f43SAlan Wright 			access = 0;
522148c5f43SAlan Wright 
523148c5f43SAlan Wright 		return (access);
524fe1c642dSBill Krier 	}
525fe1c642dSBill Krier 
526743a77edSAlan Wright 	/*
527148c5f43SAlan Wright 	 * The hold on 'root' is released by the lookuppnvp() that follows
528743a77edSAlan Wright 	 */
529743a77edSAlan Wright 	vfsp = pathvp->v_vfsp;
530743a77edSAlan Wright 	if (vfsp != NULL)
531743a77edSAlan Wright 		rc = VFS_ROOT(vfsp, &root);
532743a77edSAlan Wright 	else
533743a77edSAlan Wright 		rc = ENOENT;
534743a77edSAlan Wright 
535743a77edSAlan Wright 	if (rc != 0)
536148c5f43SAlan Wright 		return (access);
537743a77edSAlan Wright 
538743a77edSAlan Wright 
539fe1c642dSBill Krier 	size = sizeof (SHARES_DIR) + strlen(si->shr_name) + 1;
540148c5f43SAlan Wright 	sharepath = smb_srm_alloc(sr, size);
541fe1c642dSBill Krier 	(void) sprintf(sharepath, "%s%s", SHARES_DIR, si->shr_name);
542743a77edSAlan Wright 
543743a77edSAlan Wright 	pn_alloc(&pnp);
544743a77edSAlan Wright 	(void) pn_set(&pnp, sharepath);
545148c5f43SAlan Wright 	rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL, &sharevp, rootdir, root,
546*8622ec45SGordon Ross 	    zone_kcred());
547743a77edSAlan Wright 	pn_free(&pnp);
548743a77edSAlan Wright 
549743a77edSAlan Wright 	/*
550148c5f43SAlan Wright 	 * Now get the effective access value based on cred and ACL values.
551743a77edSAlan Wright 	 */
552037cac00Sjoyce mcintosh 	if (rc == 0) {
553148c5f43SAlan Wright 		smb_vop_eaccess(sharevp, (int *)&access, V_ACE_MASK, NULL,
554148c5f43SAlan Wright 		    cred);
555037cac00Sjoyce mcintosh 		VN_RELE(sharevp);
556037cac00Sjoyce mcintosh 	}
557148c5f43SAlan Wright 
558148c5f43SAlan Wright 	return (access);
559148c5f43SAlan Wright }
560148c5f43SAlan Wright 
561148c5f43SAlan Wright /*
562148c5f43SAlan Wright  * Performs the following access checks for a disk share:
563148c5f43SAlan Wright  *
564148c5f43SAlan Wright  *  - No IPC/anonymous user is allowed
565148c5f43SAlan Wright  *
566148c5f43SAlan Wright  *  - If user is Guest, guestok property of the share should be
567148c5f43SAlan Wright  *    enabled
568148c5f43SAlan Wright  *
569148c5f43SAlan Wright  *  - If this is an Admin share, the user should have administrative
570148c5f43SAlan Wright  *    privileges
571148c5f43SAlan Wright  *
572148c5f43SAlan Wright  *  - Host based access control lists
573148c5f43SAlan Wright  *
574148c5f43SAlan Wright  *  - Share ACL
575148c5f43SAlan Wright  *
576148c5f43SAlan Wright  *  Returns the access allowed or 0 if access is denied.
577148c5f43SAlan Wright  */
578148c5f43SAlan Wright static uint32_t
579148c5f43SAlan Wright smb_tree_chkaccess(smb_request_t *sr, smb_kshare_t *shr, vnode_t *vp)
580148c5f43SAlan Wright {
581148c5f43SAlan Wright 	smb_user_t *user = sr->uid_user;
582148c5f43SAlan Wright 	char *sharename = shr->shr_name;
583148c5f43SAlan Wright 	uint32_t host_access;
584148c5f43SAlan Wright 	uint32_t acl_access;
585148c5f43SAlan Wright 	uint32_t access;
586148c5f43SAlan Wright 
587148c5f43SAlan Wright 	if (user->u_flags & SMB_USER_FLAG_IPC) {
588148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: IPC only");
589148c5f43SAlan Wright 		return (0);
590148c5f43SAlan Wright 	}
591148c5f43SAlan Wright 
592148c5f43SAlan Wright 	if ((user->u_flags & SMB_USER_FLAG_GUEST) &&
593148c5f43SAlan Wright 	    ((shr->shr_flags & SMB_SHRF_GUEST_OK) == 0)) {
594148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: guest disabled");
595148c5f43SAlan Wright 		return (0);
596148c5f43SAlan Wright 	}
597148c5f43SAlan Wright 
598148c5f43SAlan Wright 	if ((shr->shr_flags & SMB_SHRF_ADMIN) && !smb_user_is_admin(user)) {
599148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: not admin");
600148c5f43SAlan Wright 		return (0);
601148c5f43SAlan Wright 	}
602148c5f43SAlan Wright 
603*8622ec45SGordon Ross 	host_access = smb_kshare_hostaccess(shr, sr->session);
604148c5f43SAlan Wright 	if ((host_access & ACE_ALL_PERMS) == 0) {
605148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: host access");
606148c5f43SAlan Wright 		return (0);
607148c5f43SAlan Wright 	}
608148c5f43SAlan Wright 
609148c5f43SAlan Wright 	acl_access = smb_tree_acl_access(sr, shr, vp);
610148c5f43SAlan Wright 	if ((acl_access & ACE_ALL_PERMS) == 0) {
611148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: share ACL");
612148c5f43SAlan Wright 		return (0);
613148c5f43SAlan Wright 	}
614148c5f43SAlan Wright 
615148c5f43SAlan Wright 	access = host_access & acl_access;
616148c5f43SAlan Wright 	if ((access & ACE_ALL_PERMS) == 0) {
617148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied");
618148c5f43SAlan Wright 		return (0);
619148c5f43SAlan Wright 	}
620148c5f43SAlan Wright 
621148c5f43SAlan Wright 	return (access);
622743a77edSAlan Wright }
623c8ec8eeaSjose borrego 
624c8ec8eeaSjose borrego /*
625c8ec8eeaSjose borrego  * Connect a share for use with files and directories.
626c8ec8eeaSjose borrego  */
627c8ec8eeaSjose borrego static smb_tree_t *
628c8ec8eeaSjose borrego smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
629c8ec8eeaSjose borrego {
630148c5f43SAlan Wright 	const char		*any = "?????";
631c8ec8eeaSjose borrego 	smb_user_t		*user = sr->uid_user;
6321fcced4cSJordan Brown 	smb_node_t		*dnode = NULL;
633c8ec8eeaSjose borrego 	smb_node_t		*snode = NULL;
634148c5f43SAlan Wright 	smb_kshare_t 		*si = sr->sr_tcon.si;
635148c5f43SAlan Wright 	char			*service = sr->sr_tcon.service;
636c8ec8eeaSjose borrego 	char			last_component[MAXNAMELEN];
637c8ec8eeaSjose borrego 	smb_tree_t		*tree;
638c8ec8eeaSjose borrego 	int			rc;
639148c5f43SAlan Wright 	uint32_t		access;
640148c5f43SAlan Wright 	smb_shr_execinfo_t	execinfo;
641c8ec8eeaSjose borrego 
642c8ec8eeaSjose borrego 	ASSERT(user);
643148c5f43SAlan Wright 	ASSERT(user->u_cred);
644c8ec8eeaSjose borrego 
645148c5f43SAlan Wright 	if ((strcmp(service, any) != 0) && (strcasecmp(service, "A:") != 0)) {
646148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "invalid service (%s)", service);
647148c5f43SAlan Wright 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
648148c5f43SAlan Wright 		    ERRDOS, ERROR_BAD_DEV_TYPE);
649b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
650b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
651b89a8333Snatalie li - Sun Microsystems - Irvine United States 
652c8ec8eeaSjose borrego 	/*
653c8ec8eeaSjose borrego 	 * Check that the shared directory exists.
654c8ec8eeaSjose borrego 	 */
655148c5f43SAlan Wright 	rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
656c8ec8eeaSjose borrego 	    last_component);
657c8ec8eeaSjose borrego 
658c8ec8eeaSjose borrego 	if (rc == 0) {
659148c5f43SAlan Wright 		rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
6601fcced4cSJordan Brown 		    sr->sr_server->si_root_smb_node, dnode, last_component,
661037cac00Sjoyce mcintosh 		    &snode);
662c8ec8eeaSjose borrego 
6631fcced4cSJordan Brown 		smb_node_release(dnode);
664c8ec8eeaSjose borrego 	}
665c8ec8eeaSjose borrego 
666c8ec8eeaSjose borrego 	if (rc) {
667c8ec8eeaSjose borrego 		if (snode)
668c8ec8eeaSjose borrego 			smb_node_release(snode);
669c8ec8eeaSjose borrego 
670b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
671c8ec8eeaSjose borrego 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
672c8ec8eeaSjose borrego 		return (NULL);
673c8ec8eeaSjose borrego 	}
674c8ec8eeaSjose borrego 
675148c5f43SAlan Wright 	if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
676148c5f43SAlan Wright 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
677743a77edSAlan Wright 		smb_node_release(snode);
678743a77edSAlan Wright 		return (NULL);
679743a77edSAlan Wright 	}
680743a77edSAlan Wright 
681743a77edSAlan Wright 	/*
682148c5f43SAlan Wright 	 * Set up the OptionalSupport for this share.
683743a77edSAlan Wright 	 */
684148c5f43SAlan Wright 	sr->sr_tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
6852c2961f8Sjose borrego 
686148c5f43SAlan Wright 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
687148c5f43SAlan Wright 	case SMB_SHRF_CSC_DISABLED:
688148c5f43SAlan Wright 		sr->sr_tcon.optional_support |= SMB_CSC_CACHE_NONE;
689148c5f43SAlan Wright 		break;
690148c5f43SAlan Wright 	case SMB_SHRF_CSC_AUTO:
691148c5f43SAlan Wright 		sr->sr_tcon.optional_support |= SMB_CSC_CACHE_AUTO_REINT;
692148c5f43SAlan Wright 		break;
693148c5f43SAlan Wright 	case SMB_SHRF_CSC_VDO:
694148c5f43SAlan Wright 		sr->sr_tcon.optional_support |= SMB_CSC_CACHE_VDO;
695148c5f43SAlan Wright 		break;
696148c5f43SAlan Wright 	case SMB_SHRF_CSC_MANUAL:
697148c5f43SAlan Wright 	default:
698148c5f43SAlan Wright 		/*
699148c5f43SAlan Wright 		 * Default to SMB_CSC_CACHE_MANUAL_REINT.
700148c5f43SAlan Wright 		 */
701148c5f43SAlan Wright 		break;
702148c5f43SAlan Wright 	}
703148c5f43SAlan Wright 
704148c5f43SAlan Wright 	/* ABE support */
705148c5f43SAlan Wright 	if (si->shr_flags & SMB_SHRF_ABE)
706148c5f43SAlan Wright 		sr->sr_tcon.optional_support |=
707148c5f43SAlan Wright 		    SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
708148c5f43SAlan Wright 
709148c5f43SAlan Wright 	if (si->shr_flags & SMB_SHRF_DFSROOT)
710148c5f43SAlan Wright 		sr->sr_tcon.optional_support |= SMB_SHARE_IS_IN_DFS;
711148c5f43SAlan Wright 
712cb174861Sjoyce mcintosh 	/* if 'smb' zfs property: shortnames=disabled */
713cb174861Sjoyce mcintosh 	if (!smb_shortnames)
714cb174861Sjoyce mcintosh 		sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME;
715cb174861Sjoyce mcintosh 
7163b13a1efSThomas Keiser 	tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
717148c5f43SAlan Wright 
718148c5f43SAlan Wright 	smb_node_release(snode);
719148c5f43SAlan Wright 
720148c5f43SAlan Wright 	if (tree) {
721148c5f43SAlan Wright 		if (tree->t_execflags & SMB_EXEC_MAP) {
722148c5f43SAlan Wright 			smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_MAP);
723148c5f43SAlan Wright 
724*8622ec45SGordon Ross 			rc = smb_kshare_exec(tree->t_server, &execinfo);
725148c5f43SAlan Wright 
726148c5f43SAlan Wright 			if ((rc != 0) && (tree->t_execflags & SMB_EXEC_TERM)) {
727148c5f43SAlan Wright 				smb_tree_disconnect(tree, B_FALSE);
728148c5f43SAlan Wright 				smb_tree_release(tree);
729148c5f43SAlan Wright 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV,
730148c5f43SAlan Wright 				    ERRaccess);
731148c5f43SAlan Wright 				return (NULL);
732148c5f43SAlan Wright 			}
733148c5f43SAlan Wright 		}
734148c5f43SAlan Wright 	} else {
735148c5f43SAlan Wright 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
736148c5f43SAlan Wright 	}
737148c5f43SAlan Wright 
738148c5f43SAlan Wright 	return (tree);
739148c5f43SAlan Wright }
740148c5f43SAlan Wright 
741148c5f43SAlan Wright /*
742148c5f43SAlan Wright  * Shares have both a share and host based access control.  The access
743148c5f43SAlan Wright  * granted will be minimum permissions based on both hostaccess
744148c5f43SAlan Wright  * (permissions allowed by host based access) and aclaccess (from the
745148c5f43SAlan Wright  * share ACL).
746148c5f43SAlan Wright  */
747148c5f43SAlan Wright static smb_tree_t *
748148c5f43SAlan Wright smb_tree_connect_printq(smb_request_t *sr, const char *sharename)
749148c5f43SAlan Wright {
750148c5f43SAlan Wright 	const char		*any = "?????";
751148c5f43SAlan Wright 	smb_user_t		*user = sr->uid_user;
752148c5f43SAlan Wright 	smb_node_t		*dnode = NULL;
753148c5f43SAlan Wright 	smb_node_t		*snode = NULL;
754148c5f43SAlan Wright 	smb_kshare_t 		*si = sr->sr_tcon.si;
755148c5f43SAlan Wright 	char			*service = sr->sr_tcon.service;
756148c5f43SAlan Wright 	char			last_component[MAXNAMELEN];
757148c5f43SAlan Wright 	smb_tree_t		*tree;
758148c5f43SAlan Wright 	int			rc;
759148c5f43SAlan Wright 	uint32_t		access;
760148c5f43SAlan Wright 
761148c5f43SAlan Wright 	ASSERT(user);
762148c5f43SAlan Wright 	ASSERT(user->u_cred);
763148c5f43SAlan Wright 
764b7301bf5SGordon Ross 	if (sr->sr_server->sv_cfg.skc_print_enable == 0) {
765b7301bf5SGordon Ross 		smb_tree_log(sr, sharename, "printing disabled");
766b7301bf5SGordon Ross 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
767b7301bf5SGordon Ross 		return (NULL);
768b7301bf5SGordon Ross 	}
769b7301bf5SGordon Ross 
770148c5f43SAlan Wright 	if ((strcmp(service, any) != 0) &&
771148c5f43SAlan Wright 	    (strcasecmp(service, "LPT1:") != 0)) {
772148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "invalid service (%s)", service);
773148c5f43SAlan Wright 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
774148c5f43SAlan Wright 		    ERRDOS, ERROR_BAD_DEV_TYPE);
775148c5f43SAlan Wright 		return (NULL);
776148c5f43SAlan Wright 	}
777148c5f43SAlan Wright 
778148c5f43SAlan Wright 	/*
779148c5f43SAlan Wright 	 * Check that the shared directory exists.
780148c5f43SAlan Wright 	 */
781148c5f43SAlan Wright 	rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
782148c5f43SAlan Wright 	    last_component);
783148c5f43SAlan Wright 	if (rc == 0) {
784148c5f43SAlan Wright 		rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
785148c5f43SAlan Wright 		    sr->sr_server->si_root_smb_node, dnode, last_component,
786148c5f43SAlan Wright 		    &snode);
787148c5f43SAlan Wright 
788148c5f43SAlan Wright 		smb_node_release(dnode);
789148c5f43SAlan Wright 	}
790148c5f43SAlan Wright 
791148c5f43SAlan Wright 	if (rc) {
792148c5f43SAlan Wright 		if (snode)
793148c5f43SAlan Wright 			smb_node_release(snode);
794148c5f43SAlan Wright 
795148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
796148c5f43SAlan Wright 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
797148c5f43SAlan Wright 		return (NULL);
798148c5f43SAlan Wright 	}
799148c5f43SAlan Wright 
800148c5f43SAlan Wright 	if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
801148c5f43SAlan Wright 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
802148c5f43SAlan Wright 		smb_node_release(snode);
803148c5f43SAlan Wright 		return (NULL);
804148c5f43SAlan Wright 	}
805148c5f43SAlan Wright 
806148c5f43SAlan Wright 	sr->sr_tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
807148c5f43SAlan Wright 
8083b13a1efSThomas Keiser 	tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
809b89a8333Snatalie li - Sun Microsystems - Irvine United States 
81029bd2886SAlan Wright 	smb_node_release(snode);
81129bd2886SAlan Wright 
812c8ec8eeaSjose borrego 	if (tree == NULL)
813c8ec8eeaSjose borrego 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
81429bd2886SAlan Wright 
815c8ec8eeaSjose borrego 	return (tree);
816c8ec8eeaSjose borrego }
817c8ec8eeaSjose borrego 
818c8ec8eeaSjose borrego /*
819c8ec8eeaSjose borrego  * Connect an IPC share for use with named pipes.
820c8ec8eeaSjose borrego  */
821c8ec8eeaSjose borrego static smb_tree_t *
822c8ec8eeaSjose borrego smb_tree_connect_ipc(smb_request_t *sr, const char *name)
823c8ec8eeaSjose borrego {
824148c5f43SAlan Wright 	const char	*any = "?????";
825c8ec8eeaSjose borrego 	smb_user_t	*user = sr->uid_user;
826c8ec8eeaSjose borrego 	smb_tree_t	*tree;
827148c5f43SAlan Wright 	smb_kshare_t	*si = sr->sr_tcon.si;
828148c5f43SAlan Wright 	char		*service = sr->sr_tcon.service;
829c8ec8eeaSjose borrego 
830c8ec8eeaSjose borrego 	ASSERT(user);
831c8ec8eeaSjose borrego 
832c8ec8eeaSjose borrego 	if ((user->u_flags & SMB_USER_FLAG_IPC) &&
833c8ec8eeaSjose borrego 	    sr->sr_cfg->skc_restrict_anon) {
834c8ec8eeaSjose borrego 		smb_tree_log(sr, name, "access denied: restrict anonymous");
835c8ec8eeaSjose borrego 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
836c8ec8eeaSjose borrego 		return (NULL);
837c8ec8eeaSjose borrego 	}
838c8ec8eeaSjose borrego 
839148c5f43SAlan Wright 	if ((strcmp(service, any) != 0) && (strcasecmp(service, "IPC") != 0)) {
840148c5f43SAlan Wright 		smb_tree_log(sr, name, "invalid service (%s)", service);
841148c5f43SAlan Wright 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
842148c5f43SAlan Wright 		    ERRDOS, ERROR_BAD_DEV_TYPE);
843148c5f43SAlan Wright 		return (NULL);
844148c5f43SAlan Wright 	}
8458d7e4166Sjose borrego 
846148c5f43SAlan Wright 	sr->sr_tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
8478b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
8483b13a1efSThomas Keiser 	tree = smb_tree_alloc(sr, si, NULL, ACE_ALL_PERMS, 0);
849c8ec8eeaSjose borrego 	if (tree == NULL) {
850c8ec8eeaSjose borrego 		smb_tree_log(sr, name, "access denied");
851c8ec8eeaSjose borrego 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
852c8ec8eeaSjose borrego 	}
853c8ec8eeaSjose borrego 
854c8ec8eeaSjose borrego 	return (tree);
855c8ec8eeaSjose borrego }
856c8ec8eeaSjose borrego 
857c8ec8eeaSjose borrego /*
858c8ec8eeaSjose borrego  * Allocate a tree.
859c8ec8eeaSjose borrego  */
860c8ec8eeaSjose borrego static smb_tree_t *
8613b13a1efSThomas Keiser smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si,
8623b13a1efSThomas Keiser     smb_node_t *snode, uint32_t access, uint32_t execflags)
863da6c28aaSamw {
8643b13a1efSThomas Keiser 	smb_session_t	*session = sr->session;
865da6c28aaSamw 	smb_tree_t	*tree;
866148c5f43SAlan Wright 	uint32_t	stype = si->shr_type;
867da6c28aaSamw 	uint16_t	tid;
868da6c28aaSamw 
8693b13a1efSThomas Keiser 	if (smb_idpool_alloc(&session->s_tid_pool, &tid))
870da6c28aaSamw 		return (NULL);
871da6c28aaSamw 
872*8622ec45SGordon Ross 	tree = kmem_cache_alloc(smb_cache_tree, KM_SLEEP);
873da6c28aaSamw 	bzero(tree, sizeof (smb_tree_t));
874da6c28aaSamw 
8753b13a1efSThomas Keiser 	tree->t_session = session;
8763b13a1efSThomas Keiser 	tree->t_server = session->s_server;
8773b13a1efSThomas Keiser 
8783b13a1efSThomas Keiser 	/* grab a ref for tree->t_owner */
8793b13a1efSThomas Keiser 	smb_user_hold_internal(sr->uid_user);
8803b13a1efSThomas Keiser 	tree->t_owner = sr->uid_user;
881cb174861Sjoyce mcintosh 
882148c5f43SAlan Wright 	if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
8838b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (smb_tree_getattr(si, snode, tree) != 0) {
8843b13a1efSThomas Keiser 			smb_idpool_free(&session->s_tid_pool, tid);
885*8622ec45SGordon Ross 			kmem_cache_free(smb_cache_tree, tree);
886c8ec8eeaSjose borrego 			return (NULL);
887c8ec8eeaSjose borrego 		}
888c8ec8eeaSjose borrego 	}
889c8ec8eeaSjose borrego 
890da6c28aaSamw 	if (smb_idpool_constructor(&tree->t_fid_pool)) {
8913b13a1efSThomas Keiser 		smb_idpool_free(&session->s_tid_pool, tid);
892*8622ec45SGordon Ross 		kmem_cache_free(smb_cache_tree, tree);
893da6c28aaSamw 		return (NULL);
894da6c28aaSamw 	}
895da6c28aaSamw 
8967f667e74Sjose borrego 	if (smb_idpool_constructor(&tree->t_odid_pool)) {
897da6c28aaSamw 		smb_idpool_destructor(&tree->t_fid_pool);
8983b13a1efSThomas Keiser 		smb_idpool_free(&session->s_tid_pool, tid);
899*8622ec45SGordon Ross 		kmem_cache_free(smb_cache_tree, tree);
900da6c28aaSamw 		return (NULL);
901da6c28aaSamw 	}
902da6c28aaSamw 
903da6c28aaSamw 	smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
904da6c28aaSamw 	    offsetof(smb_ofile_t, f_lnd));
905da6c28aaSamw 
906da6c28aaSamw 	smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
907da6c28aaSamw 	    offsetof(smb_odir_t, d_lnd));
908da6c28aaSamw 
9098b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	(void) strlcpy(tree->t_sharename, si->shr_name,
910da6c28aaSamw 	    sizeof (tree->t_sharename));
9118b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	(void) strlcpy(tree->t_resource, si->shr_path,
9128b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	    sizeof (tree->t_resource));
913da6c28aaSamw 
914da6c28aaSamw 	mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
915da6c28aaSamw 
916da6c28aaSamw 	tree->t_refcnt = 1;
917da6c28aaSamw 	tree->t_tid = tid;
918da6c28aaSamw 	tree->t_res_type = stype;
919da6c28aaSamw 	tree->t_state = SMB_TREE_STATE_CONNECTED;
920da6c28aaSamw 	tree->t_magic = SMB_TREE_MAGIC;
921743a77edSAlan Wright 	tree->t_access = access;
9221fcced4cSJordan Brown 	tree->t_connect_time = gethrestime_sec();
923148c5f43SAlan Wright 	tree->t_execflags = execflags;
924743a77edSAlan Wright 
925743a77edSAlan Wright 	/* if FS is readonly, enforce that here */
926743a77edSAlan Wright 	if (tree->t_flags & SMB_TREE_READONLY)
927743a77edSAlan Wright 		tree->t_access &= ~ACE_ALL_WRITE_PERMS;
928da6c28aaSamw 
929148c5f43SAlan Wright 	if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
930c8ec8eeaSjose borrego 		smb_node_ref(snode);
931c8ec8eeaSjose borrego 		tree->t_snode = snode;
932da6c28aaSamw 		tree->t_acltype = smb_fsop_acltype(snode);
933da6c28aaSamw 	}
934da6c28aaSamw 
9353b13a1efSThomas Keiser 	smb_llist_enter(&session->s_tree_list, RW_WRITER);
9363b13a1efSThomas Keiser 	smb_llist_insert_head(&session->s_tree_list, tree);
9373b13a1efSThomas Keiser 	smb_llist_exit(&session->s_tree_list);
9383b13a1efSThomas Keiser 	atomic_inc_32(&session->s_tree_cnt);
9393b13a1efSThomas Keiser 	smb_server_inc_trees(session->s_server);
940da6c28aaSamw 	return (tree);
941da6c28aaSamw }
942da6c28aaSamw 
943da6c28aaSamw /*
9449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Deallocate a tree.  The open file and open directory lists should be
9459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * empty.
946da6c28aaSamw  *
9479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Remove the tree from the user's tree list before freeing resources
9489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * associated with the tree.
949da6c28aaSamw  */
9509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
9519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_tree_dealloc(void *arg)
952da6c28aaSamw {
9533b13a1efSThomas Keiser 	smb_session_t	*session;
9549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_tree_t	*tree = (smb_tree_t *)arg;
9559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
9569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_TREE_VALID(tree);
957da6c28aaSamw 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
958da6c28aaSamw 	ASSERT(tree->t_refcnt == 0);
959da6c28aaSamw 
9603b13a1efSThomas Keiser 	session = tree->t_session;
9613b13a1efSThomas Keiser 	smb_llist_enter(&session->s_tree_list, RW_WRITER);
9623b13a1efSThomas Keiser 	smb_llist_remove(&session->s_tree_list, tree);
9633b13a1efSThomas Keiser 	smb_idpool_free(&session->s_tid_pool, tree->t_tid);
9643b13a1efSThomas Keiser 	atomic_dec_32(&session->s_tree_cnt);
9653b13a1efSThomas Keiser 	smb_llist_exit(&session->s_tree_list);
9669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
9679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_enter(&tree->t_mutex);
9689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_exit(&tree->t_mutex);
969da6c28aaSamw 
970da6c28aaSamw 	tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
971da6c28aaSamw 
972c8ec8eeaSjose borrego 	if (tree->t_snode)
973da6c28aaSamw 		smb_node_release(tree->t_snode);
974c8ec8eeaSjose borrego 
975da6c28aaSamw 	mutex_destroy(&tree->t_mutex);
976da6c28aaSamw 	smb_llist_destructor(&tree->t_ofile_list);
977da6c28aaSamw 	smb_llist_destructor(&tree->t_odir_list);
978da6c28aaSamw 	smb_idpool_destructor(&tree->t_fid_pool);
9797f667e74Sjose borrego 	smb_idpool_destructor(&tree->t_odid_pool);
9803b13a1efSThomas Keiser 
9813b13a1efSThomas Keiser 	SMB_USER_VALID(tree->t_owner);
9823b13a1efSThomas Keiser 	smb_user_release(tree->t_owner);
9833b13a1efSThomas Keiser 
984*8622ec45SGordon Ross 	kmem_cache_free(smb_cache_tree, tree);
985da6c28aaSamw }
986da6c28aaSamw 
987da6c28aaSamw /*
988c8ec8eeaSjose borrego  * Determine whether or not a tree is connected.
989c8ec8eeaSjose borrego  * This function must be called with the tree mutex held.
990da6c28aaSamw  */
991c8ec8eeaSjose borrego static boolean_t
9928b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tree_is_connected_locked(smb_tree_t *tree)
993da6c28aaSamw {
994c8ec8eeaSjose borrego 	switch (tree->t_state) {
995c8ec8eeaSjose borrego 	case SMB_TREE_STATE_CONNECTED:
996c8ec8eeaSjose borrego 		return (B_TRUE);
997da6c28aaSamw 
998c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTING:
999c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTED:
1000c8ec8eeaSjose borrego 		/*
1001c8ec8eeaSjose borrego 		 * The tree exists but being diconnected or destroyed.
1002c8ec8eeaSjose borrego 		 */
1003c8ec8eeaSjose borrego 		return (B_FALSE);
1004c8ec8eeaSjose borrego 
1005c8ec8eeaSjose borrego 	default:
1006da6c28aaSamw 		ASSERT(0);
1007c8ec8eeaSjose borrego 		return (B_FALSE);
1008da6c28aaSamw 	}
1009da6c28aaSamw }
1010da6c28aaSamw 
1011da6c28aaSamw /*
1012c8ec8eeaSjose borrego  * Determine whether or not a tree is disconnected.
1013c8ec8eeaSjose borrego  * This function must be called with the tree mutex held.
1014da6c28aaSamw  */
1015c8ec8eeaSjose borrego static boolean_t
1016c8ec8eeaSjose borrego smb_tree_is_disconnected(smb_tree_t *tree)
1017da6c28aaSamw {
1018c8ec8eeaSjose borrego 	switch (tree->t_state) {
1019c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTED:
1020c8ec8eeaSjose borrego 		return (B_TRUE);
1021da6c28aaSamw 
1022c8ec8eeaSjose borrego 	case SMB_TREE_STATE_CONNECTED:
1023c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTING:
1024c8ec8eeaSjose borrego 		return (B_FALSE);
1025da6c28aaSamw 
1026c8ec8eeaSjose borrego 	default:
1027da6c28aaSamw 		ASSERT(0);
1028c8ec8eeaSjose borrego 		return (B_FALSE);
1029da6c28aaSamw 	}
1030da6c28aaSamw }
1031da6c28aaSamw 
1032c8ec8eeaSjose borrego /*
1033c8ec8eeaSjose borrego  * Return a pointer to the share name within a share resource path.
1034c8ec8eeaSjose borrego  *
1035c8ec8eeaSjose borrego  * The share path may be a Uniform Naming Convention (UNC) string
1036c8ec8eeaSjose borrego  * (\\server\share) or simply the share name.  We validate the UNC
1037c8ec8eeaSjose borrego  * format but we don't look at the server name.
1038c8ec8eeaSjose borrego  */
1039c8ec8eeaSjose borrego static const char *
1040c8ec8eeaSjose borrego smb_tree_get_sharename(const char *unc_path)
1041c8ec8eeaSjose borrego {
1042c8ec8eeaSjose borrego 	const char *sharename = unc_path;
1043c8ec8eeaSjose borrego 
1044c8ec8eeaSjose borrego 	if (sharename[0] == '\\') {
1045c8ec8eeaSjose borrego 		/*
1046c8ec8eeaSjose borrego 		 * Looks like a UNC path, validate the format.
1047c8ec8eeaSjose borrego 		 */
1048c8ec8eeaSjose borrego 		if (sharename[1] != '\\')
1049c8ec8eeaSjose borrego 			return (NULL);
1050c8ec8eeaSjose borrego 
1051c8ec8eeaSjose borrego 		if ((sharename = strchr(sharename+2, '\\')) == NULL)
1052c8ec8eeaSjose borrego 			return (NULL);
1053c8ec8eeaSjose borrego 
1054c8ec8eeaSjose borrego 		++sharename;
1055c8ec8eeaSjose borrego 	} else if (strchr(sharename, '\\') != NULL) {
1056c8ec8eeaSjose borrego 		/*
1057c8ec8eeaSjose borrego 		 * This should be a share name (no embedded \'s).
1058c8ec8eeaSjose borrego 		 */
1059c8ec8eeaSjose borrego 		return (NULL);
1060c8ec8eeaSjose borrego 	}
1061c8ec8eeaSjose borrego 
1062c8ec8eeaSjose borrego 	return (sharename);
1063c8ec8eeaSjose borrego }
1064c8ec8eeaSjose borrego 
1065c8ec8eeaSjose borrego /*
1066c8ec8eeaSjose borrego  * Obtain the tree attributes: volume name, typename and flags.
1067c8ec8eeaSjose borrego  */
1068c8ec8eeaSjose borrego static int
1069148c5f43SAlan Wright smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree)
1070c8ec8eeaSjose borrego {
1071c8ec8eeaSjose borrego 	vfs_t *vfsp = SMB_NODE_VFS(node);
1072c8ec8eeaSjose borrego 
1073c8ec8eeaSjose borrego 	ASSERT(vfsp);
1074c8ec8eeaSjose borrego 
1075c8ec8eeaSjose borrego 	if (getvfs(&vfsp->vfs_fsid) != vfsp)
1076c8ec8eeaSjose borrego 		return (ESTALE);
1077c8ec8eeaSjose borrego 
1078c8ec8eeaSjose borrego 	smb_tree_get_volname(vfsp, tree);
10798b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_tree_get_flags(si, vfsp, tree);
1080c8ec8eeaSjose borrego 
1081c8ec8eeaSjose borrego 	VFS_RELE(vfsp);
1082c8ec8eeaSjose borrego 	return (0);
1083c8ec8eeaSjose borrego }
1084c8ec8eeaSjose borrego 
1085c8ec8eeaSjose borrego /*
1086c8ec8eeaSjose borrego  * Extract the volume name.
1087c8ec8eeaSjose borrego  */
1088c8ec8eeaSjose borrego static void
1089c8ec8eeaSjose borrego smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
1090c8ec8eeaSjose borrego {
1091c8ec8eeaSjose borrego 	refstr_t *vfs_mntpoint;
1092c8ec8eeaSjose borrego 	const char *s;
1093c8ec8eeaSjose borrego 	char *name;
1094c8ec8eeaSjose borrego 
1095c8ec8eeaSjose borrego 	vfs_mntpoint = vfs_getmntpoint(vfsp);
1096c8ec8eeaSjose borrego 
1097c8ec8eeaSjose borrego 	s = vfs_mntpoint->rs_string;
1098c8ec8eeaSjose borrego 	s += strspn(s, "/");
1099c8ec8eeaSjose borrego 	(void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
1100c8ec8eeaSjose borrego 
1101c8ec8eeaSjose borrego 	refstr_rele(vfs_mntpoint);
1102c8ec8eeaSjose borrego 
1103c8ec8eeaSjose borrego 	name = tree->t_volume;
1104c8ec8eeaSjose borrego 	(void) strsep((char **)&name, "/");
1105c8ec8eeaSjose borrego }
1106c8ec8eeaSjose borrego 
1107c8ec8eeaSjose borrego /*
1108c8ec8eeaSjose borrego  * Always set ACL support because the VFS will fake ACLs for file systems
1109c8ec8eeaSjose borrego  * that don't support them.
1110c8ec8eeaSjose borrego  *
1111c8ec8eeaSjose borrego  * Some flags are dependent on the typename, which is also set up here.
1112c8ec8eeaSjose borrego  * File system types are hardcoded in uts/common/os/vfs_conf.c.
1113c8ec8eeaSjose borrego  */
1114c8ec8eeaSjose borrego static void
1115148c5f43SAlan Wright smb_tree_get_flags(const smb_kshare_t *si, vfs_t *vfsp, smb_tree_t *tree)
1116c8ec8eeaSjose borrego {
11175f1ef25cSAram Hăvărneanu 	smb_session_t *ssn = tree->t_session;
11185f1ef25cSAram Hăvărneanu 
1119fc724630SAlan Wright 	typedef struct smb_mtype {
1120fc724630SAlan Wright 		char		*mt_name;
1121fc724630SAlan Wright 		size_t		mt_namelen;
1122fc724630SAlan Wright 		uint32_t	mt_flags;
1123fc724630SAlan Wright 	} smb_mtype_t;
1124fc724630SAlan Wright 
1125fc724630SAlan Wright 	static smb_mtype_t smb_mtype[] = {
1126fd9ee8b5Sjoyce mcintosh 		{ "zfs",    3,	SMB_TREE_UNICODE_ON_DISK |
1127fd9ee8b5Sjoyce mcintosh 		    SMB_TREE_QUOTA | SMB_TREE_SPARSE},
1128fc724630SAlan Wright 		{ "ufs",    3,	SMB_TREE_UNICODE_ON_DISK },
1129fc724630SAlan Wright 		{ "nfs",    3,	SMB_TREE_NFS_MOUNTED },
1130fc724630SAlan Wright 		{ "tmpfs",  5,	SMB_TREE_NO_EXPORT }
1131fc724630SAlan Wright 	};
1132fc724630SAlan Wright 	smb_mtype_t	*mtype;
1133c8ec8eeaSjose borrego 	char		*name;
1134fc724630SAlan Wright 	uint32_t	flags = SMB_TREE_SUPPORTS_ACLS;
1135fc724630SAlan Wright 	int		i;
1136c8ec8eeaSjose borrego 
11379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (si->shr_flags & SMB_SHRF_DFSROOT)
11389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_TREE_DFSROOT;
11399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11408b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (si->shr_flags & SMB_SHRF_CATIA)
11418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_TREE_CATIA;
11428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
1143e3f2c991SKeyur Desai 	if (si->shr_flags & SMB_SHRF_ABE)
1144e3f2c991SKeyur Desai 		flags |= SMB_TREE_ABE;
1145e3f2c991SKeyur Desai 
11465f1ef25cSAram Hăvărneanu 	if (ssn->s_cfg.skc_oplock_enable) {
1147cb174861Sjoyce mcintosh 		/* if 'smb' zfs property: oplocks=enabled */
1148cb174861Sjoyce mcintosh 		flags |= SMB_TREE_OPLOCKS;
1149cb174861Sjoyce mcintosh 	}
1150cb174861Sjoyce mcintosh 
11515f1ef25cSAram Hăvărneanu 	/* Global config option for now.  Later make per-share. */
11525f1ef25cSAram Hăvărneanu 	if (ssn->s_cfg.skc_traverse_mounts)
11535f1ef25cSAram Hăvărneanu 		flags |= SMB_TREE_TRAVERSE_MOUNTS;
11545f1ef25cSAram Hăvărneanu 
1155cb174861Sjoyce mcintosh 	/* if 'smb' zfs property: shortnames=enabled */
1156cb174861Sjoyce mcintosh 	if (smb_shortnames)
1157cb174861Sjoyce mcintosh 		flags |= SMB_TREE_SHORTNAMES;
1158cb174861Sjoyce mcintosh 
1159c8ec8eeaSjose borrego 	if (vfsp->vfs_flag & VFS_RDONLY)
1160c8ec8eeaSjose borrego 		flags |= SMB_TREE_READONLY;
1161c8ec8eeaSjose borrego 
1162c8ec8eeaSjose borrego 	if (vfsp->vfs_flag & VFS_XATTR)
1163c8ec8eeaSjose borrego 		flags |= SMB_TREE_STREAMS;
1164c8ec8eeaSjose borrego 
1165c8ec8eeaSjose borrego 	name = vfssw[vfsp->vfs_fstype].vsw_name;
1166c8ec8eeaSjose borrego 
1167fc724630SAlan Wright 	for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
1168fc724630SAlan Wright 		mtype = &smb_mtype[i];
1169fc724630SAlan Wright 		if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
1170fc724630SAlan Wright 			flags |= mtype->mt_flags;
1171fc724630SAlan Wright 	}
1172c8ec8eeaSjose borrego 
1173c8ec8eeaSjose borrego 	(void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
1174bbf6f00cSJordan Brown 	(void) smb_strupr((char *)tree->t_typename);
1175c8ec8eeaSjose borrego 
1176c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_XVATTR))
1177c8ec8eeaSjose borrego 		flags |= SMB_TREE_XVATTR;
1178c8ec8eeaSjose borrego 
1179c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
1180c8ec8eeaSjose borrego 		flags |= SMB_TREE_CASEINSENSITIVE;
1181c8ec8eeaSjose borrego 
1182c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
1183c8ec8eeaSjose borrego 		flags |= SMB_TREE_NO_CASESENSITIVE;
1184c8ec8eeaSjose borrego 
1185c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
1186c8ec8eeaSjose borrego 		flags |= SMB_TREE_DIRENTFLAGS;
1187c8ec8eeaSjose borrego 
1188c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
1189c8ec8eeaSjose borrego 		flags |= SMB_TREE_ACLONCREATE;
1190c8ec8eeaSjose borrego 
1191c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
1192c8ec8eeaSjose borrego 		flags |= SMB_TREE_ACEMASKONACCESS;
1193c8ec8eeaSjose borrego 
1194fc724630SAlan Wright 	DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);
1195fc724630SAlan Wright 
1196c8ec8eeaSjose borrego 
1197c8ec8eeaSjose borrego 	tree->t_flags = flags;
1198c8ec8eeaSjose borrego }
1199c8ec8eeaSjose borrego 
1200c8ec8eeaSjose borrego /*
1201c8ec8eeaSjose borrego  * Report share access result to syslog.
1202c8ec8eeaSjose borrego  */
1203c8ec8eeaSjose borrego static void
1204c8ec8eeaSjose borrego smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
1205c8ec8eeaSjose borrego {
1206c8ec8eeaSjose borrego 	va_list ap;
1207c8ec8eeaSjose borrego 	char buf[128];
1208c8ec8eeaSjose borrego 	smb_user_t *user = sr->uid_user;
1209c8ec8eeaSjose borrego 
1210c8ec8eeaSjose borrego 	ASSERT(user);
1211c8ec8eeaSjose borrego 
1212c8ec8eeaSjose borrego 	if (smb_tcon_mute)
1213c8ec8eeaSjose borrego 		return;
1214c8ec8eeaSjose borrego 
1215c8ec8eeaSjose borrego 	if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
1216c8ec8eeaSjose borrego 		/*
1217c8ec8eeaSjose borrego 		 * Only report normal users, i.e. ignore W2K misuse
1218c8ec8eeaSjose borrego 		 * of the IPC connection by filtering out internal
1219c8ec8eeaSjose borrego 		 * names such as nobody and root.
1220c8ec8eeaSjose borrego 		 */
1221c8ec8eeaSjose borrego 		if ((strcmp(user->u_name, "root") == 0) ||
1222c8ec8eeaSjose borrego 		    (strcmp(user->u_name, "nobody") == 0)) {
1223c8ec8eeaSjose borrego 			return;
1224c8ec8eeaSjose borrego 		}
1225c8ec8eeaSjose borrego 	}
1226c8ec8eeaSjose borrego 
1227c8ec8eeaSjose borrego 	va_start(ap, fmt);
1228c8ec8eeaSjose borrego 	(void) vsnprintf(buf, 128, fmt, ap);
1229c8ec8eeaSjose borrego 	va_end(ap);
1230c8ec8eeaSjose borrego 
1231c8ec8eeaSjose borrego 	cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
1232c8ec8eeaSjose borrego 	    user->u_domain, user->u_name, sharename, buf);
1233da6c28aaSamw }
12347f667e74Sjose borrego 
12357f667e74Sjose borrego /*
12367f667e74Sjose borrego  * smb_tree_lookup_odir
12377f667e74Sjose borrego  *
12387f667e74Sjose borrego  * Find the specified odir in the tree's list of odirs, and
12397f667e74Sjose borrego  * attempt to obtain a hold on the odir.
12407f667e74Sjose borrego  *
12417f667e74Sjose borrego  * Returns NULL if odir not found or a hold cannot be obtained.
12427f667e74Sjose borrego  */
12437f667e74Sjose borrego smb_odir_t *
12443b13a1efSThomas Keiser smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid)
12457f667e74Sjose borrego {
12467f667e74Sjose borrego 	smb_odir_t	*od;
12477f667e74Sjose borrego 	smb_llist_t	*od_list;
12483b13a1efSThomas Keiser 	smb_tree_t	*tree = sr->tid_tree;
12497f667e74Sjose borrego 
12507f667e74Sjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
12517f667e74Sjose borrego 
12527f667e74Sjose borrego 	od_list = &tree->t_odir_list;
12537f667e74Sjose borrego 
12543b13a1efSThomas Keiser 	smb_llist_enter(od_list, RW_READER);
12557f667e74Sjose borrego 	od = smb_llist_head(od_list);
12567f667e74Sjose borrego 	while (od) {
12573b13a1efSThomas Keiser 		if (od->d_odid == odid)
12587f667e74Sjose borrego 			break;
12597f667e74Sjose borrego 		od = smb_llist_next(od_list, od);
12607f667e74Sjose borrego 	}
12613b13a1efSThomas Keiser 	if (od == NULL)
12623b13a1efSThomas Keiser 		goto out;
12637f667e74Sjose borrego 
12643b13a1efSThomas Keiser 	/*
12653b13a1efSThomas Keiser 	 * Only allow use of a given Search ID with the same UID that
12663b13a1efSThomas Keiser 	 * was used to create it.  MS-CIFS 3.3.5.14
12673b13a1efSThomas Keiser 	 */
12683b13a1efSThomas Keiser 	if (od->d_user != sr->uid_user) {
12693b13a1efSThomas Keiser 		od = NULL;
12703b13a1efSThomas Keiser 		goto out;
12713b13a1efSThomas Keiser 	}
12723b13a1efSThomas Keiser 	if (!smb_odir_hold(od))
12733b13a1efSThomas Keiser 		od = NULL;
12743b13a1efSThomas Keiser 
12753b13a1efSThomas Keiser out:
12767f667e74Sjose borrego 	smb_llist_exit(od_list);
12777f667e74Sjose borrego 	return (od);
12787f667e74Sjose borrego }
12797f667e74Sjose borrego 
12808b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States boolean_t
12818b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tree_is_connected(smb_tree_t *tree)
12828b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States {
12838b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	boolean_t	rb;
12848b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
12858b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_enter(&tree->t_mutex);
12868b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	rb = smb_tree_is_connected_locked(tree);
12878b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_exit(&tree->t_mutex);
12888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	return (rb);
12898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
12908b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
12917f667e74Sjose borrego /*
12921fcced4cSJordan Brown  * Get the next open ofile in the list.  A reference is taken on
12931fcced4cSJordan Brown  * the ofile, which can be released later with smb_ofile_release().
12941fcced4cSJordan Brown  *
12951fcced4cSJordan Brown  * If the specified ofile is NULL, search from the beginning of the
12961fcced4cSJordan Brown  * list.  Otherwise, the search starts just after that ofile.
12971fcced4cSJordan Brown  *
12981fcced4cSJordan Brown  * Returns NULL if there are no open files in the list.
12991fcced4cSJordan Brown  */
13001fcced4cSJordan Brown static smb_ofile_t *
13011fcced4cSJordan Brown smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of)
13021fcced4cSJordan Brown {
13031fcced4cSJordan Brown 	smb_llist_t *ofile_list;
13041fcced4cSJordan Brown 
13051fcced4cSJordan Brown 	ASSERT(tree);
13061fcced4cSJordan Brown 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
13071fcced4cSJordan Brown 
13081fcced4cSJordan Brown 	ofile_list = &tree->t_ofile_list;
13091fcced4cSJordan Brown 	smb_llist_enter(ofile_list, RW_READER);
13101fcced4cSJordan Brown 
13111fcced4cSJordan Brown 	if (of) {
13121fcced4cSJordan Brown 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
13131fcced4cSJordan Brown 		of = smb_llist_next(ofile_list, of);
13141fcced4cSJordan Brown 	} else {
13151fcced4cSJordan Brown 		of = smb_llist_head(ofile_list);
13161fcced4cSJordan Brown 	}
13171fcced4cSJordan Brown 
13181fcced4cSJordan Brown 	while (of) {
13191fcced4cSJordan Brown 		if (smb_ofile_hold(of))
13201fcced4cSJordan Brown 			break;
13211fcced4cSJordan Brown 
13221fcced4cSJordan Brown 		of = smb_llist_next(ofile_list, of);
13231fcced4cSJordan Brown 	}
13241fcced4cSJordan Brown 
13251fcced4cSJordan Brown 	smb_llist_exit(ofile_list);
13261fcced4cSJordan Brown 	return (of);
13271fcced4cSJordan Brown }
13281fcced4cSJordan Brown 
13291fcced4cSJordan Brown /*
13307f667e74Sjose borrego  * smb_tree_get_odir
13317f667e74Sjose borrego  *
1332a1511e6bSjoyce mcintosh  * Find the next odir in the tree's list of odirs, and obtain a
1333a1511e6bSjoyce mcintosh  * hold on it.
13347f667e74Sjose borrego  * If the specified odir is NULL the search starts at the beginning
13357f667e74Sjose borrego  * of the tree's odir list, otherwise the search starts after the
13367f667e74Sjose borrego  * specified odir.
13377f667e74Sjose borrego  */
13387f667e74Sjose borrego static smb_odir_t *
13397f667e74Sjose borrego smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od)
13407f667e74Sjose borrego {
13417f667e74Sjose borrego 	smb_llist_t *od_list;
13427f667e74Sjose borrego 
13437f667e74Sjose borrego 	ASSERT(tree);
13447f667e74Sjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
13457f667e74Sjose borrego 
13467f667e74Sjose borrego 	od_list = &tree->t_odir_list;
13477f667e74Sjose borrego 	smb_llist_enter(od_list, RW_READER);
13487f667e74Sjose borrego 
13497f667e74Sjose borrego 	if (od) {
13507f667e74Sjose borrego 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
13517f667e74Sjose borrego 		od = smb_llist_next(od_list, od);
13527f667e74Sjose borrego 	} else {
13537f667e74Sjose borrego 		od = smb_llist_head(od_list);
13547f667e74Sjose borrego 	}
13557f667e74Sjose borrego 
13567f667e74Sjose borrego 	while (od) {
13577f667e74Sjose borrego 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
13587f667e74Sjose borrego 
13597f667e74Sjose borrego 		if (smb_odir_hold(od))
13607f667e74Sjose borrego 			break;
13617f667e74Sjose borrego 		od = smb_llist_next(od_list, od);
13627f667e74Sjose borrego 	}
13637f667e74Sjose borrego 
13647f667e74Sjose borrego 	smb_llist_exit(od_list);
13657f667e74Sjose borrego 	return (od);
13667f667e74Sjose borrego }
13677f667e74Sjose borrego 
13687f667e74Sjose borrego /*
13697f667e74Sjose borrego  * smb_tree_close_odirs
13707f667e74Sjose borrego  *
13717f667e74Sjose borrego  * Close all open odirs in the tree's list which were opened by
13727f667e74Sjose borrego  * the process identified by pid.
13737f667e74Sjose borrego  * If pid is zero, close all open odirs in the tree's list.
13747f667e74Sjose borrego  */
13757f667e74Sjose borrego static void
13767f667e74Sjose borrego smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid)
13777f667e74Sjose borrego {
13787f667e74Sjose borrego 	smb_odir_t *od, *next_od;
13797f667e74Sjose borrego 
13807f667e74Sjose borrego 	ASSERT(tree);
13817f667e74Sjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
13827f667e74Sjose borrego 
13837f667e74Sjose borrego 	od = smb_tree_get_odir(tree, NULL);
13847f667e74Sjose borrego 	while (od) {
13857f667e74Sjose borrego 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
13867f667e74Sjose borrego 		ASSERT(od->d_tree == tree);
13877f667e74Sjose borrego 
13887f667e74Sjose borrego 		next_od = smb_tree_get_odir(tree, od);
13897f667e74Sjose borrego 		if ((pid == 0) || (od->d_opened_by_pid == pid))
13907f667e74Sjose borrego 			smb_odir_close(od);
13917f667e74Sjose borrego 		smb_odir_release(od);
13927f667e74Sjose borrego 
13937f667e74Sjose borrego 		od = next_od;
13947f667e74Sjose borrego 	}
13957f667e74Sjose borrego }
139629bd2886SAlan Wright 
139729bd2886SAlan Wright static void
13983b13a1efSThomas Keiser smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec,
13993b13a1efSThomas Keiser     int exec_type)
140029bd2886SAlan Wright {
1401148c5f43SAlan Wright 	exec->e_sharename = tree->t_sharename;
14023b13a1efSThomas Keiser 	exec->e_winname = tree->t_owner->u_name;
14033b13a1efSThomas Keiser 	exec->e_userdom = tree->t_owner->u_domain;
1404148c5f43SAlan Wright 	exec->e_srv_ipaddr = tree->t_session->local_ipaddr;
1405148c5f43SAlan Wright 	exec->e_cli_ipaddr = tree->t_session->ipaddr;
1406148c5f43SAlan Wright 	exec->e_cli_netbiosname = tree->t_session->workstation;
14073b13a1efSThomas Keiser 	exec->e_uid = crgetuid(tree->t_owner->u_cred);
1408148c5f43SAlan Wright 	exec->e_type = exec_type;
140929bd2886SAlan Wright }
14101fcced4cSJordan Brown 
14111fcced4cSJordan Brown /*
14121fcced4cSJordan Brown  * Private function to support smb_tree_enum.
14131fcced4cSJordan Brown  */
14141fcced4cSJordan Brown static int
14151fcced4cSJordan Brown smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum)
14161fcced4cSJordan Brown {
14171fcced4cSJordan Brown 	uint8_t *pb;
14181fcced4cSJordan Brown 	uint_t nbytes;
14191fcced4cSJordan Brown 	int rc;
14201fcced4cSJordan Brown 
14211fcced4cSJordan Brown 	if (svcenum->se_nskip > 0) {
14221fcced4cSJordan Brown 		svcenum->se_nskip--;
14231fcced4cSJordan Brown 		return (0);
14241fcced4cSJordan Brown 	}
14251fcced4cSJordan Brown 
14261fcced4cSJordan Brown 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
14271fcced4cSJordan Brown 		svcenum->se_nitems = svcenum->se_nlimit;
14281fcced4cSJordan Brown 		return (0);
14291fcced4cSJordan Brown 	}
14301fcced4cSJordan Brown 
14311fcced4cSJordan Brown 	pb = &svcenum->se_buf[svcenum->se_bused];
14321fcced4cSJordan Brown 	rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes);
14331fcced4cSJordan Brown 	if (rc == 0) {
14341fcced4cSJordan Brown 		svcenum->se_bavail -= nbytes;
14351fcced4cSJordan Brown 		svcenum->se_bused += nbytes;
14361fcced4cSJordan Brown 		svcenum->se_nitems++;
14371fcced4cSJordan Brown 	}
14381fcced4cSJordan Brown 
14391fcced4cSJordan Brown 	return (rc);
14401fcced4cSJordan Brown }
14411fcced4cSJordan Brown 
14421fcced4cSJordan Brown /*
14431fcced4cSJordan Brown  * Encode connection information into a buffer: connection information
14441fcced4cSJordan Brown  * needed in user space to support RPC requests.
14451fcced4cSJordan Brown  */
14461fcced4cSJordan Brown static int
14471fcced4cSJordan Brown smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
14481fcced4cSJordan Brown     uint32_t *nbytes)
14491fcced4cSJordan Brown {
14501fcced4cSJordan Brown 	smb_netconnectinfo_t	info;
14511fcced4cSJordan Brown 	int			rc;
14521fcced4cSJordan Brown 
14531fcced4cSJordan Brown 	smb_tree_netinfo_init(tree, &info);
14541fcced4cSJordan Brown 	rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes);
14551fcced4cSJordan Brown 	smb_tree_netinfo_fini(&info);
14561fcced4cSJordan Brown 
14571fcced4cSJordan Brown 	return (rc);
14581fcced4cSJordan Brown }
14591fcced4cSJordan Brown 
14603b13a1efSThomas Keiser static void
14613b13a1efSThomas Keiser smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen)
14623b13a1efSThomas Keiser {
14633b13a1efSThomas Keiser 	smb_user_t		*user = tree->t_owner;
14643b13a1efSThomas Keiser 
14653b13a1efSThomas Keiser 	/*
14663b13a1efSThomas Keiser 	 * u_domain_len and u_name_len include the '\0' in their
14673b13a1efSThomas Keiser 	 * lengths, hence the sum of the two lengths gives us room
14683b13a1efSThomas Keiser 	 * for both the '\\' and '\0' chars.
14693b13a1efSThomas Keiser 	 */
14703b13a1efSThomas Keiser 	ASSERT(namestr);
14713b13a1efSThomas Keiser 	ASSERT(namelen);
14723b13a1efSThomas Keiser 	ASSERT(user->u_domain_len > 0);
14733b13a1efSThomas Keiser 	ASSERT(user->u_name_len > 0);
14743b13a1efSThomas Keiser 	*namelen = user->u_domain_len + user->u_name_len;
14753b13a1efSThomas Keiser 	*namestr = kmem_alloc(*namelen, KM_SLEEP);
14763b13a1efSThomas Keiser 	(void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain,
14773b13a1efSThomas Keiser 	    user->u_name);
14783b13a1efSThomas Keiser }
14793b13a1efSThomas Keiser 
14801fcced4cSJordan Brown /*
14811fcced4cSJordan Brown  * Note: ci_numusers should be the number of users connected to
14821fcced4cSJordan Brown  * the share rather than the number of references on the tree but
14831fcced4cSJordan Brown  * we don't have a mechanism to track users/share in smbsrv yet.
14841fcced4cSJordan Brown  */
14851fcced4cSJordan Brown static void
14861fcced4cSJordan Brown smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
14871fcced4cSJordan Brown {
14881fcced4cSJordan Brown 	ASSERT(tree);
14891fcced4cSJordan Brown 
14901fcced4cSJordan Brown 	info->ci_id = tree->t_tid;
14911fcced4cSJordan Brown 	info->ci_type = tree->t_res_type;
14921fcced4cSJordan Brown 	info->ci_numopens = tree->t_open_files;
14931fcced4cSJordan Brown 	info->ci_numusers = tree->t_refcnt;
14941fcced4cSJordan Brown 	info->ci_time = gethrestime_sec() - tree->t_connect_time;
14951fcced4cSJordan Brown 
14961fcced4cSJordan Brown 	info->ci_sharelen = strlen(tree->t_sharename) + 1;
14979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	info->ci_share = smb_mem_strdup(tree->t_sharename);
14981fcced4cSJordan Brown 
14993b13a1efSThomas Keiser 	smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen);
15001fcced4cSJordan Brown }
15011fcced4cSJordan Brown 
15021fcced4cSJordan Brown static void
15031fcced4cSJordan Brown smb_tree_netinfo_fini(smb_netconnectinfo_t *info)
15041fcced4cSJordan Brown {
15051fcced4cSJordan Brown 	if (info == NULL)
15061fcced4cSJordan Brown 		return;
15071fcced4cSJordan Brown 
15081fcced4cSJordan Brown 	if (info->ci_username)
15091fcced4cSJordan Brown 		kmem_free(info->ci_username, info->ci_namelen);
15101fcced4cSJordan Brown 	if (info->ci_share)
15119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smb_mem_free(info->ci_share);
15121fcced4cSJordan Brown 
15131fcced4cSJordan Brown 	bzero(info, sizeof (smb_netconnectinfo_t));
15141fcced4cSJordan Brown }
1515