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.
2448bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
25*af536d7dSGordon Ross  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
26da6c28aaSamw  */
27da6c28aaSamw 
28da6c28aaSamw /*
29da6c28aaSamw  * General Structures Layout
30da6c28aaSamw  * -------------------------
31da6c28aaSamw  *
32da6c28aaSamw  * This is a simplified diagram showing the relationship between most of the
33da6c28aaSamw  * main structures.
34da6c28aaSamw  *
35da6c28aaSamw  * +-------------------+
36da6c28aaSamw  * |     SMB_INFO      |
37da6c28aaSamw  * +-------------------+
38da6c28aaSamw  *          |
39da6c28aaSamw  *          |
40da6c28aaSamw  *          v
41da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
42da6c28aaSamw  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
43da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
443b13a1efSThomas Keiser  *   |          |
453b13a1efSThomas Keiser  *   |          |
463b13a1efSThomas Keiser  *   |          v
473b13a1efSThomas Keiser  *   |  +-------------------+     +-------------------+   +-------------------+
483b13a1efSThomas Keiser  *   |  |       USER        |<--->|       USER        |...|       USER        |
493b13a1efSThomas Keiser  *   |  +-------------------+     +-------------------+   +-------------------+
503b13a1efSThomas Keiser  *   |
513b13a1efSThomas Keiser  *   |
523b13a1efSThomas Keiser  *   v
53da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
54da6c28aaSamw  * |       TREE        |<----->|       TREE        |......|       TREE        |
55da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
56da6c28aaSamw  *      |         |
57da6c28aaSamw  *      |         |
58da6c28aaSamw  *      |         v
59da6c28aaSamw  *      |     +-------+       +-------+      +-------+
60da6c28aaSamw  *      |     | OFILE |<----->| OFILE |......| OFILE |
61da6c28aaSamw  *      |     +-------+       +-------+      +-------+
62da6c28aaSamw  *      |
63da6c28aaSamw  *      |
64da6c28aaSamw  *      v
65da6c28aaSamw  *  +-------+       +------+      +------+
66da6c28aaSamw  *  | ODIR  |<----->| ODIR |......| ODIR |
67da6c28aaSamw  *  +-------+       +------+      +------+
68da6c28aaSamw  *
69da6c28aaSamw  *
70da6c28aaSamw  * Tree State Machine
71da6c28aaSamw  * ------------------
72da6c28aaSamw  *
73da6c28aaSamw  *    +-----------------------------+	 T0
74da6c28aaSamw  *    |  SMB_TREE_STATE_CONNECTED   |<----------- Creation/Allocation
75da6c28aaSamw  *    +-----------------------------+
76da6c28aaSamw  *		    |
77da6c28aaSamw  *		    | T1
78da6c28aaSamw  *		    |
79da6c28aaSamw  *		    v
80da6c28aaSamw  *    +------------------------------+
81da6c28aaSamw  *    | SMB_TREE_STATE_DISCONNECTING |
82da6c28aaSamw  *    +------------------------------+
83da6c28aaSamw  *		    |
84da6c28aaSamw  *		    | T2
85da6c28aaSamw  *		    |
86da6c28aaSamw  *		    v
87da6c28aaSamw  *    +-----------------------------+    T3
88da6c28aaSamw  *    | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free
89da6c28aaSamw  *    +-----------------------------+
90da6c28aaSamw  *
91da6c28aaSamw  * SMB_TREE_STATE_CONNECTED
92da6c28aaSamw  *
93da6c28aaSamw  *    While in this state:
94da6c28aaSamw  *      - The tree is queued in the list of trees of its user.
95da6c28aaSamw  *      - References will be given out if the tree is looked up.
96da6c28aaSamw  *      - Files under that tree can be accessed.
97da6c28aaSamw  *
98da6c28aaSamw  * SMB_TREE_STATE_DISCONNECTING
99da6c28aaSamw  *
100da6c28aaSamw  *    While in this state:
101da6c28aaSamw  *      - The tree is queued in the list of trees of its user.
102da6c28aaSamw  *      - References will not be given out if the tree is looked up.
103da6c28aaSamw  *      - The files and directories open under the tree are being closed.
104da6c28aaSamw  *      - The resources associated with the tree remain.
105da6c28aaSamw  *
106da6c28aaSamw  * SMB_TREE_STATE_DISCONNECTED
107da6c28aaSamw  *
108da6c28aaSamw  *    While in this state:
109da6c28aaSamw  *      - The tree is queued in the list of trees of its user.
110da6c28aaSamw  *      - References will not be given out if the tree is looked up.
111da6c28aaSamw  *      - The tree has no more files and directories opened.
112da6c28aaSamw  *      - The resources associated with the tree remain.
113da6c28aaSamw  *
114da6c28aaSamw  * Transition T0
115da6c28aaSamw  *
116da6c28aaSamw  *    This transition occurs in smb_tree_connect(). A new tree is created and
117da6c28aaSamw  *    added to the list of trees of a user.
118da6c28aaSamw  *
119da6c28aaSamw  * Transition T1
120da6c28aaSamw  *
121da6c28aaSamw  *    This transition occurs in smb_tree_disconnect().
122da6c28aaSamw  *
123da6c28aaSamw  * Transition T2
124da6c28aaSamw  *
125811599a4SMatt Barden  *    This transition occurs in smb_tree_disconnect()
126811599a4SMatt Barden  *
127811599a4SMatt Barden  * Transition T3
128811599a4SMatt Barden  *
129da6c28aaSamw  *    This transition occurs in smb_tree_release(). The resources associated
130da6c28aaSamw  *    with the tree are freed as well as the tree structure. For the transition
131811599a4SMatt Barden  *    to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED and the
132811599a4SMatt Barden  *    reference count must be zero.
133da6c28aaSamw  *
134da6c28aaSamw  * Comments
135da6c28aaSamw  * --------
136da6c28aaSamw  *
137da6c28aaSamw  *    The state machine of the tree structures is controlled by 3 elements:
138da6c28aaSamw  *      - The list of trees of the user it belongs to.
139da6c28aaSamw  *      - The mutex embedded in the structure itself.
140da6c28aaSamw  *      - The reference count.
141da6c28aaSamw  *
142da6c28aaSamw  *    There's a mutex embedded in the tree structure used to protect its fields
143da6c28aaSamw  *    and there's a lock embedded in the list of trees of a user. To
144da6c28aaSamw  *    increment or to decrement the reference count the mutex must be entered.
145da6c28aaSamw  *    To insert the tree into the list of trees of the user and to remove
146da6c28aaSamw  *    the tree from it, the lock must be entered in RW_WRITER mode.
147da6c28aaSamw  *
148da6c28aaSamw  *    Rules of access to a tree structure:
149da6c28aaSamw  *
150da6c28aaSamw  *    1) In order to avoid deadlocks, when both (mutex and lock of the user
151811599a4SMatt Barden  *       list) have to be entered, the lock must be entered first. Additionally,
152811599a4SMatt Barden  *       when both the (mutex and lock of the ofile list) have to be entered,
153811599a4SMatt Barden  *       the mutex must be entered first. However, the ofile list lock must NOT
154811599a4SMatt Barden  *       be dropped while the mutex is held in such a way that the ofile deleteq
155811599a4SMatt Barden  *       is flushed.
156da6c28aaSamw  *
157da6c28aaSamw  *    2) All actions applied to a tree require a reference count.
158da6c28aaSamw  *
159c8ec8eeaSjose borrego  *    3) There are 2 ways of getting a reference count: when a tree is
160c8ec8eeaSjose borrego  *       connected and when a tree is looked up.
161da6c28aaSamw  *
162da6c28aaSamw  *    It should be noted that the reference count of a tree registers the
163da6c28aaSamw  *    number of references to the tree in other structures (such as an smb
164da6c28aaSamw  *    request). The reference count is not incremented in these 2 instances:
165da6c28aaSamw  *
16648bbca81SDaniel Hoffman  *    1) The tree is connected. An tree is anchored by its state. If there's
167da6c28aaSamw  *       no activity involving a tree currently connected, the reference
168da6c28aaSamw  *       count of that tree is zero.
169da6c28aaSamw  *
170da6c28aaSamw  *    2) The tree is queued in the list of trees of the user. The fact of
171da6c28aaSamw  *       being queued in that list is NOT registered by incrementing the
172da6c28aaSamw  *       reference count.
173da6c28aaSamw  */
174148c5f43SAlan Wright 
175c8ec8eeaSjose borrego #include <sys/refstr_impl.h>
176bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
177148c5f43SAlan Wright #include <smbsrv/smb_ktypes.h>
178da6c28aaSamw #include <smbsrv/smb_fsops.h>
179cb174861Sjoyce mcintosh #include <smbsrv/smb_share.h>
180c8ec8eeaSjose borrego 
181c8ec8eeaSjose borrego int smb_tcon_mute = 0;
182c8ec8eeaSjose borrego 
183a90cf9f2SGordon Ross uint32_t	smb_tree_connect_core(smb_request_t *);
184a90cf9f2SGordon Ross uint32_t	smb_tree_connect_disk(smb_request_t *, smb_arg_tcon_t *);
185a90cf9f2SGordon Ross uint32_t	smb_tree_connect_printq(smb_request_t *, smb_arg_tcon_t *);
186a90cf9f2SGordon Ross uint32_t	smb_tree_connect_ipc(smb_request_t *, smb_arg_tcon_t *);
187811599a4SMatt Barden static void smb_tree_dealloc(void *);
1888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States static boolean_t smb_tree_is_connected_locked(smb_tree_t *);
189a90cf9f2SGordon Ross static char *smb_tree_get_sharename(char *);
190148c5f43SAlan Wright static int smb_tree_getattr(const smb_kshare_t *, smb_node_t *, smb_tree_t *);
19125a9a7aaSGordon Ross static void smb_tree_get_creation(smb_node_t *, smb_tree_t *);
192c8ec8eeaSjose borrego static void smb_tree_get_volname(vfs_t *, smb_tree_t *);
193148c5f43SAlan Wright static void smb_tree_get_flags(const smb_kshare_t *, vfs_t *, smb_tree_t *);
194c8ec8eeaSjose borrego static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
1958d94f651SGordon Ross static void smb_tree_close_odirs(smb_tree_t *, uint32_t);
196148c5f43SAlan Wright static void smb_tree_set_execinfo(smb_tree_t *, smb_shr_execinfo_t *, int);
1971fcced4cSJordan Brown static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *);
1981fcced4cSJordan Brown static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *);
1991fcced4cSJordan Brown static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *);
2001fcced4cSJordan Brown static void smb_tree_netinfo_fini(smb_netconnectinfo_t *);
201da6c28aaSamw 
202a90cf9f2SGordon Ross uint32_t
203cb174861Sjoyce mcintosh smb_tree_connect(smb_request_t *sr)
204cb174861Sjoyce mcintosh {
205cb174861Sjoyce mcintosh 	smb_server_t	*sv = sr->sr_server;
206a90cf9f2SGordon Ross 	uint32_t status;
207cb174861Sjoyce mcintosh 
208cb174861Sjoyce mcintosh 	if (smb_threshold_enter(&sv->sv_tcon_ct) != 0) {
209a90cf9f2SGordon Ross 		return (NT_STATUS_INSUFF_SERVER_RESOURCES);
210cb174861Sjoyce mcintosh 	}
211cb174861Sjoyce mcintosh 
212a90cf9f2SGordon Ross 	status = smb_tree_connect_core(sr);
213856399cfSGordon Ross 	smb_threshold_exit(&sv->sv_tcon_ct);
214a90cf9f2SGordon Ross 	return (status);
215cb174861Sjoyce mcintosh }
216cb174861Sjoyce mcintosh 
217da6c28aaSamw /*
218148c5f43SAlan Wright  * Lookup the share name dispatch the appropriate stype handler.
219c8ec8eeaSjose borrego  * Share names are case insensitive so we map the share name to
220c8ec8eeaSjose borrego  * lower-case as a convenience for internal processing.
221148c5f43SAlan Wright  *
222148c5f43SAlan Wright  * Valid service values are:
223148c5f43SAlan Wright  *	A:      Disk share
224148c5f43SAlan Wright  *	LPT1:   Printer
225148c5f43SAlan Wright  *	IPC     Named pipe (IPC$ is reserved as the named pipe share).
226148c5f43SAlan Wright  *	COMM    Communications device
227148c5f43SAlan Wright  *	?????   Any type of device (wildcard)
228da6c28aaSamw  */
229a90cf9f2SGordon Ross uint32_t
230cb174861Sjoyce mcintosh smb_tree_connect_core(smb_request_t *sr)
231da6c28aaSamw {
232a90cf9f2SGordon Ross 	smb_arg_tcon_t	*tcon = &sr->sr_tcon;
233148c5f43SAlan Wright 	smb_kshare_t	*si;
234a90cf9f2SGordon Ross 	char		*name;
235a90cf9f2SGordon Ross 	uint32_t	status;
236da6c28aaSamw 
237a90cf9f2SGordon Ross 	(void) smb_strlwr(tcon->path);
238da6c28aaSamw 
239a90cf9f2SGordon Ross 	if ((name = smb_tree_get_sharename(tcon->path)) == NULL) {
240a90cf9f2SGordon Ross 		smb_tree_log(sr, tcon->path, "invalid UNC path");
241a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_NETWORK_NAME);
242da6c28aaSamw 	}
243da6c28aaSamw 
2448622ec45SGordon Ross 	si = smb_kshare_lookup(sr->sr_server, name);
2458622ec45SGordon Ross 	if (si == NULL) {
246148c5f43SAlan Wright 		smb_tree_log(sr, name, "share not found");
247a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_NETWORK_NAME);
248da6c28aaSamw 	}
249cb174861Sjoyce mcintosh 
250cb174861Sjoyce mcintosh 	if (!strcasecmp(SMB_SHARE_PRINT, name)) {
2518622ec45SGordon Ross 		smb_kshare_release(sr->sr_server, si);
252cb174861Sjoyce mcintosh 		smb_tree_log(sr, name, "access not permitted");
253a90cf9f2SGordon Ross 		return (NT_STATUS_ACCESS_DENIED);
254cb174861Sjoyce mcintosh 	}
255cb174861Sjoyce mcintosh 
256a90cf9f2SGordon Ross 	/* NB: name points into tcon->path - don't free it. */
257a90cf9f2SGordon Ross 	tcon->name = name;
258148c5f43SAlan Wright 	sr->sr_tcon.si = si;
259da6c28aaSamw 
2601160dcf7SMatt Barden 	/*
2611160dcf7SMatt Barden 	 * [MS-SMB2] 3.3.5.7 Receiving an SMB2 TREE_CONNECT Request
2621160dcf7SMatt Barden 	 *
2631160dcf7SMatt Barden 	 * If we support 3.x, RejectUnencryptedAccess is TRUE,
2641160dcf7SMatt Barden 	 * if Tcon.EncryptData is TRUE or global EncryptData is TRUE,
2651160dcf7SMatt Barden 	 * and the connection doesn't support encryption,
2661160dcf7SMatt Barden 	 * return ACCESS_DENIED.
2671160dcf7SMatt Barden 	 *
2681160dcf7SMatt Barden 	 * If RejectUnencryptedAccess is TRUE, we force max_protocol
2691160dcf7SMatt Barden 	 * to at least 3.0. Additionally, if the tree requires encryption,
2701160dcf7SMatt Barden 	 * we don't care what we support, we still enforce encryption.
2711160dcf7SMatt Barden 	 */
2721160dcf7SMatt Barden 	if ((sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED ||
2731160dcf7SMatt Barden 	    si->shr_encrypt == SMB_CONFIG_REQUIRED) &&
2741160dcf7SMatt Barden 	    (sr->session->srv_cap & SMB2_CAP_ENCRYPTION) == 0) {
2751160dcf7SMatt Barden 		status = NT_STATUS_ACCESS_DENIED;
2761160dcf7SMatt Barden 		goto out;
2771160dcf7SMatt Barden 	}
2781160dcf7SMatt Barden 
279148c5f43SAlan Wright 	switch (si->shr_type & STYPE_MASK) {
280da6c28aaSamw 	case STYPE_DISKTREE:
281a90cf9f2SGordon Ross 		status = smb_tree_connect_disk(sr, &sr->sr_tcon);
282da6c28aaSamw 		break;
283da6c28aaSamw 	case STYPE_IPC:
284a90cf9f2SGordon Ross 		status = smb_tree_connect_ipc(sr, &sr->sr_tcon);
285c8ec8eeaSjose borrego 		break;
286148c5f43SAlan Wright 	case STYPE_PRINTQ:
287a90cf9f2SGordon Ross 		status = smb_tree_connect_printq(sr, &sr->sr_tcon);
288148c5f43SAlan Wright 		break;
289da6c28aaSamw 	default:
290a90cf9f2SGordon Ross 		status = NT_STATUS_BAD_DEVICE_TYPE;
291da6c28aaSamw 		break;
292da6c28aaSamw 	}
293da6c28aaSamw 
2941160dcf7SMatt Barden out:
2958622ec45SGordon Ross 	smb_kshare_release(sr->sr_server, si);
296a90cf9f2SGordon Ross 	sr->sr_tcon.si = NULL;
297a90cf9f2SGordon Ross 
298a90cf9f2SGordon Ross 	return (status);
299da6c28aaSamw }
300da6c28aaSamw 
301da6c28aaSamw /*
302c8ec8eeaSjose borrego  * Disconnect a tree.
3038d94f651SGordon Ross  *
3048d94f651SGordon Ross  * The "do_exec" arg is obsolete and ignored.
305da6c28aaSamw  */
306da6c28aaSamw void
30729bd2886SAlan Wright smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec)
308da6c28aaSamw {
3098d94f651SGordon Ross 	_NOTE(ARGUNUSED(do_exec))
310148c5f43SAlan Wright 	smb_shr_execinfo_t execinfo;
31129bd2886SAlan Wright 
312da6c28aaSamw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
313da6c28aaSamw 
314da6c28aaSamw 	mutex_enter(&tree->t_mutex);
315da6c28aaSamw 	ASSERT(tree->t_refcnt);
316c8ec8eeaSjose borrego 
3178d94f651SGordon Ross 	if (!smb_tree_is_connected_locked(tree)) {
318da6c28aaSamw 		mutex_exit(&tree->t_mutex);
3198d94f651SGordon Ross 		return;
320da6c28aaSamw 	}
321da6c28aaSamw 
3228d94f651SGordon Ross 	/*
3238d94f651SGordon Ross 	 * Indicate that the disconnect process has started.
3248d94f651SGordon Ross 	 */
3258d94f651SGordon Ross 	tree->t_state = SMB_TREE_STATE_DISCONNECTING;
326da6c28aaSamw 	mutex_exit(&tree->t_mutex);
32729bd2886SAlan Wright 
3288d94f651SGordon Ross 	/*
3298d94f651SGordon Ross 	 * The files opened under this tree are closed.
3308d94f651SGordon Ross 	 */
3318d94f651SGordon Ross 	smb_ofile_close_all(tree, 0);
3328d94f651SGordon Ross 	/*
3338d94f651SGordon Ross 	 * The directories opened under this tree are closed.
3348d94f651SGordon Ross 	 */
3358d94f651SGordon Ross 	smb_tree_close_odirs(tree, 0);
33629bd2886SAlan Wright 
3378d94f651SGordon Ross 	if ((tree->t_execflags & SMB_EXEC_UNMAP) != 0) {
338148c5f43SAlan Wright 		smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_UNMAP);
3398622ec45SGordon Ross 		(void) smb_kshare_exec(tree->t_server, &execinfo);
34029bd2886SAlan Wright 	}
341da6c28aaSamw }
342da6c28aaSamw 
343da6c28aaSamw /*
344c8ec8eeaSjose borrego  * Take a reference on a tree.
345da6c28aaSamw  */
346c8ec8eeaSjose borrego boolean_t
347c8ec8eeaSjose borrego smb_tree_hold(
348c8ec8eeaSjose borrego     smb_tree_t		*tree)
349da6c28aaSamw {
350a90cf9f2SGordon Ross 	SMB_TREE_VALID(tree);
351da6c28aaSamw 
352c8ec8eeaSjose borrego 	mutex_enter(&tree->t_mutex);
353c8ec8eeaSjose borrego 
3548b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_tree_is_connected_locked(tree)) {
355c8ec8eeaSjose borrego 		tree->t_refcnt++;
356c8ec8eeaSjose borrego 		mutex_exit(&tree->t_mutex);
357c8ec8eeaSjose borrego 		return (B_TRUE);
358da6c28aaSamw 	}
359c8ec8eeaSjose borrego 
360c8ec8eeaSjose borrego 	mutex_exit(&tree->t_mutex);
361c8ec8eeaSjose borrego 	return (B_FALSE);
362da6c28aaSamw }
363da6c28aaSamw 
364a90cf9f2SGordon Ross /*
365a90cf9f2SGordon Ross  * Bump the hold count regardless of the tree state.  This is used in
366a90cf9f2SGordon Ross  * some internal code paths where we've already checked that we had a
367a90cf9f2SGordon Ross  * valid tree connection, and don't want to deal with the possiblity
368a90cf9f2SGordon Ross  * that the tree state might have changed to disconnecting after our
369a90cf9f2SGordon Ross  * original hold was taken.  It's correct to continue processing a
370a90cf9f2SGordon Ross  * request even when new requests cannot lookup that tree anymore.
371a90cf9f2SGordon Ross  */
372a90cf9f2SGordon Ross void
373a90cf9f2SGordon Ross smb_tree_hold_internal(
374a90cf9f2SGordon Ross     smb_tree_t		*tree)
375a90cf9f2SGordon Ross {
376a90cf9f2SGordon Ross 	SMB_TREE_VALID(tree);
377a90cf9f2SGordon Ross 
378a90cf9f2SGordon Ross 	mutex_enter(&tree->t_mutex);
379a90cf9f2SGordon Ross 	tree->t_refcnt++;
380a90cf9f2SGordon Ross 	mutex_exit(&tree->t_mutex);
381a90cf9f2SGordon Ross }
382a90cf9f2SGordon Ross 
383da6c28aaSamw /*
384c8ec8eeaSjose borrego  * Release a reference on a tree.  If the tree is disconnected and the
3859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * reference count falls to zero, post the object for deletion.
3869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Object deletion is deferred to avoid modifying a list while an
3879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * iteration may be in progress.
388da6c28aaSamw  */
389da6c28aaSamw void
390c8ec8eeaSjose borrego smb_tree_release(
391c8ec8eeaSjose borrego     smb_tree_t		*tree)
392da6c28aaSamw {
3939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_TREE_VALID(tree);
394da6c28aaSamw 
395c5866007SKeyur Desai 	/* flush the ofile and odir lists' delete queues */
396c5866007SKeyur Desai 	smb_llist_flush(&tree->t_ofile_list);
397c5866007SKeyur Desai 	smb_llist_flush(&tree->t_odir_list);
398c5866007SKeyur Desai 
399811599a4SMatt Barden 	mutex_enter(&tree->t_mutex);
400811599a4SMatt Barden 	ASSERT(tree->t_refcnt);
401811599a4SMatt Barden 	tree->t_refcnt--;
4029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
403811599a4SMatt Barden 	switch (tree->t_state) {
4048d94f651SGordon Ross 	case SMB_TREE_STATE_DISCONNECTING:
405811599a4SMatt Barden 		if (tree->t_refcnt == 0) {
406811599a4SMatt Barden 			smb_session_t *ssn = tree->t_session;
407811599a4SMatt Barden 			tree->t_state = SMB_TREE_STATE_DISCONNECTED;
408811599a4SMatt Barden 			smb_llist_post(&ssn->s_tree_list, tree,
409811599a4SMatt Barden 			    smb_tree_dealloc);
410811599a4SMatt Barden 		}
411811599a4SMatt Barden 		break;
412811599a4SMatt Barden 	case SMB_TREE_STATE_CONNECTED:
413811599a4SMatt Barden 		break;
414811599a4SMatt Barden 	default:
415811599a4SMatt Barden 		ASSERT(0);
416811599a4SMatt Barden 		break;
417811599a4SMatt Barden 	}
4189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
419811599a4SMatt Barden 	mutex_exit(&tree->t_mutex);
4209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
4219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
422da6c28aaSamw /*
423c8ec8eeaSjose borrego  * Close ofiles and odirs that match pid.
424da6c28aaSamw  */
425da6c28aaSamw void
426c8ec8eeaSjose borrego smb_tree_close_pid(
427c8ec8eeaSjose borrego     smb_tree_t		*tree,
428a90cf9f2SGordon Ross     uint32_t		pid)
429da6c28aaSamw {
430da6c28aaSamw 	ASSERT(tree);
431da6c28aaSamw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
432da6c28aaSamw 
433811599a4SMatt Barden 	smb_ofile_close_all(tree, pid);
4347f667e74Sjose borrego 	smb_tree_close_odirs(tree, pid);
435c8ec8eeaSjose borrego }
436da6c28aaSamw 
437c8ec8eeaSjose borrego /*
438c8ec8eeaSjose borrego  * Check whether or not a tree supports the features identified by flags.
439c8ec8eeaSjose borrego  */
440c8ec8eeaSjose borrego boolean_t
441c8ec8eeaSjose borrego smb_tree_has_feature(smb_tree_t *tree, uint32_t flags)
442c8ec8eeaSjose borrego {
443c8ec8eeaSjose borrego 	ASSERT(tree);
444c8ec8eeaSjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
445da6c28aaSamw 
446c8ec8eeaSjose borrego 	return ((tree->t_flags & flags) == flags);
447da6c28aaSamw }
448da6c28aaSamw 
4491fcced4cSJordan Brown /*
4501fcced4cSJordan Brown  * If the enumeration request is for tree data, handle the request
4511fcced4cSJordan Brown  * here.  Otherwise, pass it on to the ofiles.
4521fcced4cSJordan Brown  *
4531fcced4cSJordan Brown  * This function should be called with a hold on the tree.
4541fcced4cSJordan Brown  */
4551fcced4cSJordan Brown int
4561fcced4cSJordan Brown smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum)
4571fcced4cSJordan Brown {
4588d94f651SGordon Ross 	smb_llist_t	*of_list;
4591fcced4cSJordan Brown 	smb_ofile_t	*of;
4603b13a1efSThomas Keiser 	int		rc = 0;
4611fcced4cSJordan Brown 
4621fcced4cSJordan Brown 	if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE)
4631fcced4cSJordan Brown 		return (smb_tree_enum_private(tree, svcenum));
4641fcced4cSJordan Brown 
4658d94f651SGordon Ross 	of_list = &tree->t_ofile_list;
4668d94f651SGordon Ross 	smb_llist_enter(of_list, RW_READER);
4671fcced4cSJordan Brown 
4688d94f651SGordon Ross 	of = smb_llist_head(of_list);
4698d94f651SGordon Ross 	while (of) {
4708d94f651SGordon Ross 		if (smb_ofile_hold(of)) {
4718d94f651SGordon Ross 			rc = smb_ofile_enum(of, svcenum);
4721fcced4cSJordan Brown 			smb_ofile_release(of);
4731fcced4cSJordan Brown 		}
4748d94f651SGordon Ross 		if (rc != 0)
4758d94f651SGordon Ross 			break;
4768d94f651SGordon Ross 		of = smb_llist_next(of_list, of);
4771fcced4cSJordan Brown 	}
4781fcced4cSJordan Brown 
4798d94f651SGordon Ross 	smb_llist_exit(of_list);
4808d94f651SGordon Ross 
4811fcced4cSJordan Brown 	return (rc);
4821fcced4cSJordan Brown }
4831fcced4cSJordan Brown 
4841fcced4cSJordan Brown /*
4851fcced4cSJordan Brown  * Close a file by its unique id.
4861fcced4cSJordan Brown  */
4871fcced4cSJordan Brown int
4881fcced4cSJordan Brown smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid)
4891fcced4cSJordan Brown {
4901fcced4cSJordan Brown 	smb_ofile_t	*of;
4911fcced4cSJordan Brown 
4921fcced4cSJordan Brown 	ASSERT(tree);
4931fcced4cSJordan Brown 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
4941fcced4cSJordan Brown 
495811599a4SMatt Barden 	/*
496811599a4SMatt Barden 	 * Note that ORPHANED ofiles aren't fclosable, as they have
497811599a4SMatt Barden 	 * no session, user, or tree by which they might be found.
498811599a4SMatt Barden 	 * They will eventually expire.
499811599a4SMatt Barden 	 */
5001fcced4cSJordan Brown 	if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL)
5011fcced4cSJordan Brown 		return (ENOENT);
5021fcced4cSJordan Brown 
5031fcced4cSJordan Brown 	if (smb_ofile_disallow_fclose(of)) {
5041fcced4cSJordan Brown 		smb_ofile_release(of);
5051fcced4cSJordan Brown 		return (EACCES);
5061fcced4cSJordan Brown 	}
5071fcced4cSJordan Brown 
5081fcced4cSJordan Brown 	smb_ofile_close(of, 0);
5091fcced4cSJordan Brown 	smb_ofile_release(of);
5101fcced4cSJordan Brown 	return (0);
5111fcced4cSJordan Brown }
512743a77edSAlan Wright 
513c8ec8eeaSjose borrego /* *************************** Static Functions ***************************** */
5141fcced4cSJordan Brown 
515743a77edSAlan Wright #define	SHARES_DIR	".zfs/shares/"
516148c5f43SAlan Wright 
517148c5f43SAlan Wright /*
518148c5f43SAlan Wright  * Calculates permissions given by the share's ACL to the
519148c5f43SAlan Wright  * user in the passed request.  The default is full access.
520148c5f43SAlan Wright  * If any error occurs, full access is granted.
521148c5f43SAlan Wright  *
522148c5f43SAlan Wright  * Using the vnode of the share path find the root directory
523148c5f43SAlan Wright  * of the mounted file system. Then look to see if there is a
524148c5f43SAlan Wright  * .zfs/shares directory and if there is, lookup the file with
525148c5f43SAlan Wright  * the same name as the share name in it. The ACL set for this
526148c5f43SAlan Wright  * file is the share's ACL which is used for access check here.
527148c5f43SAlan Wright  */
528148c5f43SAlan Wright static uint32_t
529148c5f43SAlan Wright smb_tree_acl_access(smb_request_t *sr, const smb_kshare_t *si, vnode_t *pathvp)
530743a77edSAlan Wright {
531fe1c642dSBill Krier 	smb_user_t	*user;
532fe1c642dSBill Krier 	cred_t		*cred;
533fe1c642dSBill Krier 	int		rc;
534fe1c642dSBill Krier 	vfs_t		*vfsp;
535fe1c642dSBill Krier 	vnode_t		*root = NULL;
536fe1c642dSBill Krier 	vnode_t		*sharevp = NULL;
537fe1c642dSBill Krier 	char		*sharepath;
538fe1c642dSBill Krier 	struct pathname	pnp;
539fe1c642dSBill Krier 	size_t		size;
540148c5f43SAlan Wright 	uint32_t	access;
541fe1c642dSBill Krier 
542fe1c642dSBill Krier 	user = sr->uid_user;
543fe1c642dSBill Krier 	cred = user->u_cred;
544148c5f43SAlan Wright 	access = ACE_ALL_PERMS;
545743a77edSAlan Wright 
546fe1c642dSBill Krier 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
547fe1c642dSBill Krier 		/*
548fe1c642dSBill Krier 		 * An autohome share owner gets full access to the share.
549fe1c642dSBill Krier 		 * Everyone else is denied access.
550fe1c642dSBill Krier 		 */
551c5866007SKeyur Desai 		if (si->shr_uid != crgetuid(cred))
552148c5f43SAlan Wright 			access = 0;
553148c5f43SAlan Wright 
554148c5f43SAlan Wright 		return (access);
555fe1c642dSBill Krier 	}
556fe1c642dSBill Krier 
557743a77edSAlan Wright 	/*
558148c5f43SAlan Wright 	 * The hold on 'root' is released by the lookuppnvp() that follows
559743a77edSAlan Wright 	 */
560743a77edSAlan Wright 	vfsp = pathvp->v_vfsp;
561743a77edSAlan Wright 	if (vfsp != NULL)
562743a77edSAlan Wright 		rc = VFS_ROOT(vfsp, &root);
563743a77edSAlan Wright 	else
564743a77edSAlan Wright 		rc = ENOENT;
565743a77edSAlan Wright 
566743a77edSAlan Wright 	if (rc != 0)
567148c5f43SAlan Wright 		return (access);
568743a77edSAlan Wright 
569743a77edSAlan Wright 
570fe1c642dSBill Krier 	size = sizeof (SHARES_DIR) + strlen(si->shr_name) + 1;
571148c5f43SAlan Wright 	sharepath = smb_srm_alloc(sr, size);
572b819cea2SGordon Ross 	(void) snprintf(sharepath, size, "%s%s", SHARES_DIR, si->shr_name);
573743a77edSAlan Wright 
574743a77edSAlan Wright 	pn_alloc(&pnp);
575743a77edSAlan Wright 	(void) pn_set(&pnp, sharepath);
576148c5f43SAlan Wright 	rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL, &sharevp, rootdir, root,
5778622ec45SGordon Ross 	    zone_kcred());
578743a77edSAlan Wright 	pn_free(&pnp);
579743a77edSAlan Wright 
580743a77edSAlan Wright 	/*
581148c5f43SAlan Wright 	 * Now get the effective access value based on cred and ACL values.
582743a77edSAlan Wright 	 */
583037cac00Sjoyce mcintosh 	if (rc == 0) {
584148c5f43SAlan Wright 		smb_vop_eaccess(sharevp, (int *)&access, V_ACE_MASK, NULL,
585148c5f43SAlan Wright 		    cred);
586037cac00Sjoyce mcintosh 		VN_RELE(sharevp);
587037cac00Sjoyce mcintosh 	}
588148c5f43SAlan Wright 
589148c5f43SAlan Wright 	return (access);
590743a77edSAlan Wright }
591c8ec8eeaSjose borrego 
592da6c28aaSamw /*
593148c5f43SAlan Wright  * Performs the following access checks for a disk share:
594148c5f43SAlan Wright  *
595148c5f43SAlan Wright  *  - No IPC/anonymous user is allowed
596148c5f43SAlan Wright  *
597148c5f43SAlan Wright  *  - If user is Guest, guestok property of the share should be
598148c5f43SAlan Wright  *    enabled
599148c5f43SAlan Wright  *
600148c5f43SAlan Wright  *  - If this is an Admin share, the user should have administrative
601148c5f43SAlan Wright  *    privileges
602148c5f43SAlan Wright  *
603148c5f43SAlan Wright  *  - Host based access control lists
604148c5f43SAlan Wright  *
605148c5f43SAlan Wright  *  - Share ACL
606148c5f43SAlan Wright  *
607148c5f43SAlan Wright  *  Returns the access allowed or 0 if access is denied.
608da6c28aaSamw  */
609148c5f43SAlan Wright static uint32_t
610148c5f43SAlan Wright smb_tree_chkaccess(smb_request_t *sr, smb_kshare_t *shr, vnode_t *vp)
611148c5f43SAlan Wright {
612148c5f43SAlan Wright 	smb_user_t *user = sr->uid_user;
613148c5f43SAlan Wright 	char *sharename = shr->shr_name;
614148c5f43SAlan Wright 	uint32_t host_access;
615148c5f43SAlan Wright 	uint32_t acl_access;
616148c5f43SAlan Wright 	uint32_t access;
617743a77edSAlan Wright 
618a90cf9f2SGordon Ross 	if (user->u_flags & SMB_USER_FLAG_ANON) {
619148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: IPC only");
620148c5f43SAlan Wright 		return (0);
621148c5f43SAlan Wright 	}
622148c5f43SAlan Wright 
623148c5f43SAlan Wright 	if ((user->u_flags & SMB_USER_FLAG_GUEST) &&
624148c5f43SAlan Wright 	    ((shr->shr_flags & SMB_SHRF_GUEST_OK) == 0)) {
625148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: guest disabled");
626148c5f43SAlan Wright 		return (0);
627148c5f43SAlan Wright 	}
628148c5f43SAlan Wright 
629148c5f43SAlan Wright 	if ((shr->shr_flags & SMB_SHRF_ADMIN) && !smb_user_is_admin(user)) {
630148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: not admin");
631148c5f43SAlan Wright 		return (0);
632148c5f43SAlan Wright 	}
633148c5f43SAlan Wright 
6348622ec45SGordon Ross 	host_access = smb_kshare_hostaccess(shr, sr->session);
635148c5f43SAlan Wright 	if ((host_access & ACE_ALL_PERMS) == 0) {
636148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: host access");
637148c5f43SAlan Wright 		return (0);
638148c5f43SAlan Wright 	}
639148c5f43SAlan Wright 
640148c5f43SAlan Wright 	acl_access = smb_tree_acl_access(sr, shr, vp);
641148c5f43SAlan Wright 	if ((acl_access & ACE_ALL_PERMS) == 0) {
642148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: share ACL");
643148c5f43SAlan Wright 		return (0);
644148c5f43SAlan Wright 	}
645148c5f43SAlan Wright 
646148c5f43SAlan Wright 	access = host_access & acl_access;
647148c5f43SAlan Wright 	if ((access & ACE_ALL_PERMS) == 0) {
648148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied");
649148c5f43SAlan Wright 		return (0);
650148c5f43SAlan Wright 	}
651148c5f43SAlan Wright 
652148c5f43SAlan Wright 	return (access);
653148c5f43SAlan Wright }
654148c5f43SAlan Wright 
6558d94f651SGordon Ross /* How long should tree connect wait for DH import to complete? */
6568d94f651SGordon Ross int smb_tcon_import_wait = 20; /* sec. */
6578d94f651SGordon Ross 
658148c5f43SAlan Wright /*
659148c5f43SAlan Wright  * Connect a share for use with files and directories.
660148c5f43SAlan Wright  */
661a90cf9f2SGordon Ross uint32_t
662a90cf9f2SGordon Ross smb_tree_connect_disk(smb_request_t *sr, smb_arg_tcon_t *tcon)
663da6c28aaSamw {
664a90cf9f2SGordon Ross 	char			*sharename = tcon->path;
665148c5f43SAlan Wright 	const char		*any = "?????";
666c8ec8eeaSjose borrego 	smb_user_t		*user = sr->uid_user;
667c8ec8eeaSjose borrego 	smb_node_t		*snode = NULL;
668811599a4SMatt Barden 	smb_kshare_t		*si = tcon->si;
669a90cf9f2SGordon Ross 	char			*service = tcon->service;
670c8ec8eeaSjose borrego 	smb_tree_t		*tree;
671c8ec8eeaSjose borrego 	int			rc;
672148c5f43SAlan Wright 	uint32_t		access;
673148c5f43SAlan Wright 	smb_shr_execinfo_t	execinfo;
6748d94f651SGordon Ross 	clock_t	time;
675da6c28aaSamw 
676da6c28aaSamw 	ASSERT(user);
677148c5f43SAlan Wright 	ASSERT(user->u_cred);
678c8ec8eeaSjose borrego 
679a90cf9f2SGordon Ross 	if (service != NULL &&
680a90cf9f2SGordon Ross 	    strcmp(service, any) != 0 &&
681a90cf9f2SGordon Ross 	    strcasecmp(service, "A:") != 0) {
682148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "invalid service (%s)", service);
683a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_DEVICE_TYPE);
684c8ec8eeaSjose borrego 	}
685c8ec8eeaSjose borrego 
686148c5f43SAlan Wright 	/*
687148c5f43SAlan Wright 	 * Check that the shared directory exists.
688148c5f43SAlan Wright 	 */
6898d94f651SGordon Ross 	snode = si->shr_root_node;
6908d94f651SGordon Ross 	if (snode == NULL) {
691148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
692a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_NETWORK_NAME);
69329bd2886SAlan Wright 	}
69429bd2886SAlan Wright 
695148c5f43SAlan Wright 	if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
696a90cf9f2SGordon Ross 		return (NT_STATUS_ACCESS_DENIED);
697da6c28aaSamw 	}
698c8ec8eeaSjose borrego 
6998d94f651SGordon Ross 	/*
7008d94f651SGordon Ross 	 * Wait for DH import of persistent handles to finish.
7018d94f651SGordon Ross 	 * If we timeout, it's not clear what status to return,
7028d94f651SGordon Ross 	 * but as the share is not really available yet, let's
7038d94f651SGordon Ross 	 * return the status for "no such share".
7048d94f651SGordon Ross 	 */
7058d94f651SGordon Ross 	time = SEC_TO_TICK(smb_tcon_import_wait) + ddi_get_lbolt();
7068d94f651SGordon Ross 	mutex_enter(&si->shr_mutex);
7078d94f651SGordon Ross 	while (si->shr_import_busy != NULL) {
7088d94f651SGordon Ross 		if (cv_timedwait(&si->shr_cv, &si->shr_mutex, time) < 0) {
7098d94f651SGordon Ross 			mutex_exit(&si->shr_mutex);
7108d94f651SGordon Ross 			return (NT_STATUS_BAD_NETWORK_NAME);
7118d94f651SGordon Ross 		}
7128d94f651SGordon Ross 	}
7138d94f651SGordon Ross 	mutex_exit(&si->shr_mutex);
7148d94f651SGordon Ross 
7158d7e4166Sjose borrego 	/*
7168d7e4166Sjose borrego 	 * Set up the OptionalSupport for this share.
7178d7e4166Sjose borrego 	 */
718a90cf9f2SGordon Ross 	tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
7198d7e4166Sjose borrego 
7208d7e4166Sjose borrego 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
7218d7e4166Sjose borrego 	case SMB_SHRF_CSC_DISABLED:
722a90cf9f2SGordon Ross 		tcon->optional_support |= SMB_CSC_CACHE_NONE;
7238d7e4166Sjose borrego 		break;
7248d7e4166Sjose borrego 	case SMB_SHRF_CSC_AUTO:
725a90cf9f2SGordon Ross 		tcon->optional_support |= SMB_CSC_CACHE_AUTO_REINT;
7268d7e4166Sjose borrego 		break;
7278d7e4166Sjose borrego 	case SMB_SHRF_CSC_VDO:
728a90cf9f2SGordon Ross 		tcon->optional_support |= SMB_CSC_CACHE_VDO;
7298d7e4166Sjose borrego 		break;
7308d7e4166Sjose borrego 	case SMB_SHRF_CSC_MANUAL:
7318d7e4166Sjose borrego 	default:
7328d7e4166Sjose borrego 		/*
7338d7e4166Sjose borrego 		 * Default to SMB_CSC_CACHE_MANUAL_REINT.
7348d7e4166Sjose borrego 		 */
7358d7e4166Sjose borrego 		break;
7368d7e4166Sjose borrego 	}
7378d7e4166Sjose borrego 
738e3f2c991SKeyur Desai 	/* ABE support */
739e3f2c991SKeyur Desai 	if (si->shr_flags & SMB_SHRF_ABE)
740a90cf9f2SGordon Ross 		tcon->optional_support |=
741e3f2c991SKeyur Desai 		    SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
742e3f2c991SKeyur Desai 
7439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (si->shr_flags & SMB_SHRF_DFSROOT)
744a90cf9f2SGordon Ross 		tcon->optional_support |= SMB_SHARE_IS_IN_DFS;
7459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
746cb174861Sjoyce mcintosh 	/* if 'smb' zfs property: shortnames=disabled */
747cb174861Sjoyce mcintosh 	if (!smb_shortnames)
748cb174861Sjoyce mcintosh 		sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME;
749cb174861Sjoyce mcintosh 
7503b13a1efSThomas Keiser 	tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
751b89a8333Snatalie li - Sun Microsystems - Irvine United States 
752a90cf9f2SGordon Ross 	if (tree == NULL)
753a90cf9f2SGordon Ross 		return (NT_STATUS_INSUFF_SERVER_RESOURCES);
754a90cf9f2SGordon Ross 
755a90cf9f2SGordon Ross 	if (tree->t_execflags & SMB_EXEC_MAP) {
756a90cf9f2SGordon Ross 		smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_MAP);
757148c5f43SAlan Wright 
758a90cf9f2SGordon Ross 		rc = smb_kshare_exec(tree->t_server, &execinfo);
759148c5f43SAlan Wright 
760a90cf9f2SGordon Ross 		if ((rc != 0) && (tree->t_execflags & SMB_EXEC_TERM)) {
7618d94f651SGordon Ross 			/*
7628d94f651SGordon Ross 			 * Inline parts of: smb_tree_disconnect()
7638d94f651SGordon Ross 			 * Not using smb_tree_disconnect() for cleanup
7648d94f651SGordon Ross 			 * here because: we don't want an exec up-call,
7658d94f651SGordon Ross 			 * and there can't be any opens as we never
7668d94f651SGordon Ross 			 * returned this TID to the client.
7678d94f651SGordon Ross 			 */
7688d94f651SGordon Ross 			mutex_enter(&tree->t_mutex);
7698d94f651SGordon Ross 			tree->t_state = SMB_TREE_STATE_DISCONNECTING;
7708d94f651SGordon Ross 			mutex_exit(&tree->t_mutex);
7718d94f651SGordon Ross 
772a90cf9f2SGordon Ross 			smb_tree_release(tree);
773a90cf9f2SGordon Ross 			return (NT_STATUS_ACCESS_DENIED);
774148c5f43SAlan Wright 		}
775148c5f43SAlan Wright 	}
776148c5f43SAlan Wright 
777a90cf9f2SGordon Ross 	sr->tid_tree = tree;
778a90cf9f2SGordon Ross 	sr->smb_tid  = tree->t_tid;
779a90cf9f2SGordon Ross 
780a90cf9f2SGordon Ross 	return (0);
781148c5f43SAlan Wright }
782148c5f43SAlan Wright 
783148c5f43SAlan Wright /*
784148c5f43SAlan Wright  * Shares have both a share and host based access control.  The access
785148c5f43SAlan Wright  * granted will be minimum permissions based on both hostaccess
786148c5f43SAlan Wright  * (permissions allowed by host based access) and aclaccess (from the
787148c5f43SAlan Wright  * share ACL).
788148c5f43SAlan Wright  */
789a90cf9f2SGordon Ross uint32_t
790a90cf9f2SGordon Ross smb_tree_connect_printq(smb_request_t *sr, smb_arg_tcon_t *tcon)
791148c5f43SAlan Wright {
792a90cf9f2SGordon Ross 	char			*sharename = tcon->path;
793148c5f43SAlan Wright 	const char		*any = "?????";
794148c5f43SAlan Wright 	smb_user_t		*user = sr->uid_user;
795148c5f43SAlan Wright 	smb_node_t		*dnode = NULL;
796148c5f43SAlan Wright 	smb_node_t		*snode = NULL;
797811599a4SMatt Barden 	smb_kshare_t		*si = tcon->si;
798a90cf9f2SGordon Ross 	char			*service = tcon->service;
799148c5f43SAlan Wright 	char			last_component[MAXNAMELEN];
800148c5f43SAlan Wright 	smb_tree_t		*tree;
801148c5f43SAlan Wright 	int			rc;
802148c5f43SAlan Wright 	uint32_t		access;
803148c5f43SAlan Wright 
804148c5f43SAlan Wright 	ASSERT(user);
805148c5f43SAlan Wright 	ASSERT(user->u_cred);
806148c5f43SAlan Wright 
807b7301bf5SGordon Ross 	if (sr->sr_server->sv_cfg.skc_print_enable == 0) {
808b7301bf5SGordon Ross 		smb_tree_log(sr, sharename, "printing disabled");
809a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_NETWORK_NAME);
810b7301bf5SGordon Ross 	}
811b7301bf5SGordon Ross 
812a90cf9f2SGordon Ross 	if (service != NULL &&
813a90cf9f2SGordon Ross 	    strcmp(service, any) != 0 &&
814a90cf9f2SGordon Ross 	    strcasecmp(service, "LPT1:") != 0) {
815148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "invalid service (%s)", service);
816a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_DEVICE_TYPE);
817b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
818b89a8333Snatalie li - Sun Microsystems - Irvine United States 
819c8ec8eeaSjose borrego 	/*
820c8ec8eeaSjose borrego 	 * Check that the shared directory exists.
821c8ec8eeaSjose borrego 	 */
822148c5f43SAlan Wright 	rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
823c8ec8eeaSjose borrego 	    last_component);
824c8ec8eeaSjose borrego 	if (rc == 0) {
825148c5f43SAlan Wright 		rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
8261fcced4cSJordan Brown 		    sr->sr_server->si_root_smb_node, dnode, last_component,
827037cac00Sjoyce mcintosh 		    &snode);
828c8ec8eeaSjose borrego 
8291fcced4cSJordan Brown 		smb_node_release(dnode);
830c8ec8eeaSjose borrego 	}
831c8ec8eeaSjose borrego 
832c8ec8eeaSjose borrego 	if (rc) {
833c8ec8eeaSjose borrego 		if (snode)
834c8ec8eeaSjose borrego 			smb_node_release(snode);
835c8ec8eeaSjose borrego 
836b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
837a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_NETWORK_NAME);
838c8ec8eeaSjose borrego 	}
839c8ec8eeaSjose borrego 
840148c5f43SAlan Wright 	if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
841037cac00Sjoyce mcintosh 		smb_node_release(snode);
842a90cf9f2SGordon Ross 		return (NT_STATUS_ACCESS_DENIED);
843743a77edSAlan Wright 	}
844743a77edSAlan Wright 
845a90cf9f2SGordon Ross 	tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
8462c2961f8Sjose borrego 
8473b13a1efSThomas Keiser 	tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
848b89a8333Snatalie li - Sun Microsystems - Irvine United States 
84929bd2886SAlan Wright 	smb_node_release(snode);
85029bd2886SAlan Wright 
851c8ec8eeaSjose borrego 	if (tree == NULL)
852a90cf9f2SGordon Ross 		return (NT_STATUS_INSUFF_SERVER_RESOURCES);
85329bd2886SAlan Wright 
854a90cf9f2SGordon Ross 	sr->tid_tree = tree;
855a90cf9f2SGordon Ross 	sr->smb_tid  = tree->t_tid;
856a90cf9f2SGordon Ross 
857a90cf9f2SGordon Ross 	return (0);
858da6c28aaSamw }
859da6c28aaSamw 
860da6c28aaSamw /*
861c8ec8eeaSjose borrego  * Connect an IPC share for use with named pipes.
862da6c28aaSamw  */
863a90cf9f2SGordon Ross uint32_t
864a90cf9f2SGordon Ross smb_tree_connect_ipc(smb_request_t *sr, smb_arg_tcon_t *tcon)
865da6c28aaSamw {
866a90cf9f2SGordon Ross 	char		*name = tcon->path;
867148c5f43SAlan Wright 	const char	*any = "?????";
8688b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_user_t	*user = sr->uid_user;
8698b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_tree_t	*tree;
870a90cf9f2SGordon Ross 	smb_kshare_t	*si = tcon->si;
871a90cf9f2SGordon Ross 	char		*service = tcon->service;
872da6c28aaSamw 
873c8ec8eeaSjose borrego 	ASSERT(user);
874da6c28aaSamw 
875a90cf9f2SGordon Ross 	if (service != NULL &&
876a90cf9f2SGordon Ross 	    strcmp(service, any) != 0 &&
877a90cf9f2SGordon Ross 	    strcasecmp(service, "IPC") != 0) {
878a90cf9f2SGordon Ross 		smb_tree_log(sr, name, "invalid service (%s)", service);
879a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_DEVICE_TYPE);
880da6c28aaSamw 	}
881da6c28aaSamw 
882a90cf9f2SGordon Ross 	if ((user->u_flags & SMB_USER_FLAG_ANON) &&
883a90cf9f2SGordon Ross 	    sr->sr_cfg->skc_restrict_anon) {
884a90cf9f2SGordon Ross 		smb_tree_log(sr, name, "access denied: restrict anonymous");
885a90cf9f2SGordon Ross 		return (NT_STATUS_ACCESS_DENIED);
886148c5f43SAlan Wright 	}
8878d7e4166Sjose borrego 
888a90cf9f2SGordon Ross 	tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
8898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
8903b13a1efSThomas Keiser 	tree = smb_tree_alloc(sr, si, NULL, ACE_ALL_PERMS, 0);
891a90cf9f2SGordon Ross 	if (tree == NULL)
892a90cf9f2SGordon Ross 		return (NT_STATUS_INSUFF_SERVER_RESOURCES);
893c8ec8eeaSjose borrego 
894a90cf9f2SGordon Ross 	sr->tid_tree = tree;
895a90cf9f2SGordon Ross 	sr->smb_tid  = tree->t_tid;
896a90cf9f2SGordon Ross 
897a90cf9f2SGordon Ross 	return (0);
898da6c28aaSamw }
899da6c28aaSamw 
900da6c28aaSamw /*
901c8ec8eeaSjose borrego  * Allocate a tree.
902da6c28aaSamw  */
9038d94f651SGordon Ross smb_tree_t *
9043b13a1efSThomas Keiser smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si,
9053b13a1efSThomas Keiser     smb_node_t *snode, uint32_t access, uint32_t execflags)
906da6c28aaSamw {
9073b13a1efSThomas Keiser 	smb_session_t	*session = sr->session;
908c8ec8eeaSjose borrego 	smb_tree_t	*tree;
909148c5f43SAlan Wright 	uint32_t	stype = si->shr_type;
910c8ec8eeaSjose borrego 	uint16_t	tid;
911da6c28aaSamw 
9123b13a1efSThomas Keiser 	if (smb_idpool_alloc(&session->s_tid_pool, &tid))
913c8ec8eeaSjose borrego 		return (NULL);
914da6c28aaSamw 
9158622ec45SGordon Ross 	tree = kmem_cache_alloc(smb_cache_tree, KM_SLEEP);
916c8ec8eeaSjose borrego 	bzero(tree, sizeof (smb_tree_t));
917da6c28aaSamw 
9183b13a1efSThomas Keiser 	tree->t_session = session;
9193b13a1efSThomas Keiser 	tree->t_server = session->s_server;
9203b13a1efSThomas Keiser 
921148c5f43SAlan Wright 	if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
9228b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (smb_tree_getattr(si, snode, tree) != 0) {
9233b13a1efSThomas Keiser 			smb_idpool_free(&session->s_tid_pool, tid);
9248622ec45SGordon Ross 			kmem_cache_free(smb_cache_tree, tree);
925c8ec8eeaSjose borrego 			return (NULL);
926da6c28aaSamw 		}
927da6c28aaSamw 	}
928c8ec8eeaSjose borrego 
929c8ec8eeaSjose borrego 	if (smb_idpool_constructor(&tree->t_fid_pool)) {
9303b13a1efSThomas Keiser 		smb_idpool_free(&session->s_tid_pool, tid);
9318622ec45SGordon Ross 		kmem_cache_free(smb_cache_tree, tree);
932c8ec8eeaSjose borrego 		return (NULL);
933c8ec8eeaSjose borrego 	}
934c8ec8eeaSjose borrego 
9357f667e74Sjose borrego 	if (smb_idpool_constructor(&tree->t_odid_pool)) {
936c8ec8eeaSjose borrego 		smb_idpool_destructor(&tree->t_fid_pool);
9373b13a1efSThomas Keiser 		smb_idpool_free(&session->s_tid_pool, tid);
9388622ec45SGordon Ross 		kmem_cache_free(smb_cache_tree, tree);
939c8ec8eeaSjose borrego 		return (NULL);
940c8ec8eeaSjose borrego 	}
941c8ec8eeaSjose borrego 
942c8ec8eeaSjose borrego 	smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
943811599a4SMatt Barden 	    offsetof(smb_ofile_t, f_tree_lnd));
944c8ec8eeaSjose borrego 
945c8ec8eeaSjose borrego 	smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
946c8ec8eeaSjose borrego 	    offsetof(smb_odir_t, d_lnd));
947c8ec8eeaSjose borrego 
9488b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	(void) strlcpy(tree->t_sharename, si->shr_name,
949c8ec8eeaSjose borrego 	    sizeof (tree->t_sharename));
9508b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	(void) strlcpy(tree->t_resource, si->shr_path,
9518b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	    sizeof (tree->t_resource));
952c8ec8eeaSjose borrego 
953c8ec8eeaSjose borrego 	mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
954c8ec8eeaSjose borrego 
955c8ec8eeaSjose borrego 	tree->t_refcnt = 1;
956c8ec8eeaSjose borrego 	tree->t_tid = tid;
957c8ec8eeaSjose borrego 	tree->t_res_type = stype;
958c8ec8eeaSjose borrego 	tree->t_state = SMB_TREE_STATE_CONNECTED;
959c8ec8eeaSjose borrego 	tree->t_magic = SMB_TREE_MAGIC;
960743a77edSAlan Wright 	tree->t_access = access;
9611fcced4cSJordan Brown 	tree->t_connect_time = gethrestime_sec();
962148c5f43SAlan Wright 	tree->t_execflags = execflags;
963743a77edSAlan Wright 
964*af536d7dSGordon Ross 	/* grab a ref for tree->t_owner */
965*af536d7dSGordon Ross 	smb_user_hold_internal(sr->uid_user);
966*af536d7dSGordon Ross 	tree->t_owner = sr->uid_user;
967*af536d7dSGordon Ross 
968743a77edSAlan Wright 	/* if FS is readonly, enforce that here */
969743a77edSAlan Wright 	if (tree->t_flags & SMB_TREE_READONLY)
970743a77edSAlan Wright 		tree->t_access &= ~ACE_ALL_WRITE_PERMS;
971c8ec8eeaSjose borrego 
972148c5f43SAlan Wright 	if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
973c8ec8eeaSjose borrego 		smb_node_ref(snode);
974c8ec8eeaSjose borrego 		tree->t_snode = snode;
975c8ec8eeaSjose borrego 		tree->t_acltype = smb_fsop_acltype(snode);
976c8ec8eeaSjose borrego 	}
977c8ec8eeaSjose borrego 
9783b13a1efSThomas Keiser 	smb_llist_enter(&session->s_tree_list, RW_WRITER);
9793b13a1efSThomas Keiser 	smb_llist_insert_head(&session->s_tree_list, tree);
9803b13a1efSThomas Keiser 	smb_llist_exit(&session->s_tree_list);
9813b13a1efSThomas Keiser 	atomic_inc_32(&session->s_tree_cnt);
9823b13a1efSThomas Keiser 	smb_server_inc_trees(session->s_server);
983c8ec8eeaSjose borrego 	return (tree);
984c8ec8eeaSjose borrego }
985da6c28aaSamw 
986da6c28aaSamw /*
9879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Deallocate a tree.  The open file and open directory lists should be
9889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * empty.
989c8ec8eeaSjose borrego  *
9909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Remove the tree from the user's tree list before freeing resources
9919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * associated with the tree.
992da6c28aaSamw  */
993811599a4SMatt Barden static void
9949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_tree_dealloc(void *arg)
995da6c28aaSamw {
9963b13a1efSThomas Keiser 	smb_session_t	*session;
9979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_tree_t	*tree = (smb_tree_t *)arg;
9989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
9999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_TREE_VALID(tree);
1000da6c28aaSamw 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
1001da6c28aaSamw 	ASSERT(tree->t_refcnt == 0);
1002da6c28aaSamw 
10038d94f651SGordon Ross 	smb_server_dec_trees(tree->t_server);
10048d94f651SGordon Ross 
10053b13a1efSThomas Keiser 	session = tree->t_session;
10063b13a1efSThomas Keiser 	smb_llist_enter(&session->s_tree_list, RW_WRITER);
10073b13a1efSThomas Keiser 	smb_llist_remove(&session->s_tree_list, tree);
10083b13a1efSThomas Keiser 	smb_idpool_free(&session->s_tid_pool, tree->t_tid);
10093b13a1efSThomas Keiser 	atomic_dec_32(&session->s_tree_cnt);
10103b13a1efSThomas Keiser 	smb_llist_exit(&session->s_tree_list);
10119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1012811599a4SMatt Barden 	/*
1013811599a4SMatt Barden 	 * This tree is no longer on s_tree_list, however...
1014811599a4SMatt Barden 	 *
1015811599a4SMatt Barden 	 * This is called via smb_llist_post, which means it may run
1016811599a4SMatt Barden 	 * BEFORE smb_tree_release drops t_mutex (if another thread
1017811599a4SMatt Barden 	 * flushes the delete queue before we do).  Synchronize.
1018811599a4SMatt Barden 	 */
10199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_enter(&tree->t_mutex);
10209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_exit(&tree->t_mutex);
1021da6c28aaSamw 
1022da6c28aaSamw 	tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
1023da6c28aaSamw 
1024c8ec8eeaSjose borrego 	if (tree->t_snode)
1025da6c28aaSamw 		smb_node_release(tree->t_snode);
1026c8ec8eeaSjose borrego 
1027da6c28aaSamw 	mutex_destroy(&tree->t_mutex);
1028da6c28aaSamw 	smb_llist_destructor(&tree->t_ofile_list);
1029da6c28aaSamw 	smb_llist_destructor(&tree->t_odir_list);
1030da6c28aaSamw 	smb_idpool_destructor(&tree->t_fid_pool);
10317f667e74Sjose borrego 	smb_idpool_destructor(&tree->t_odid_pool);
10323b13a1efSThomas Keiser 
10333b13a1efSThomas Keiser 	SMB_USER_VALID(tree->t_owner);
10343b13a1efSThomas Keiser 	smb_user_release(tree->t_owner);
10353b13a1efSThomas Keiser 
10368622ec45SGordon Ross 	kmem_cache_free(smb_cache_tree, tree);
1037da6c28aaSamw }
1038da6c28aaSamw 
1039da6c28aaSamw /*
1040c8ec8eeaSjose borrego  * Determine whether or not a tree is connected.
1041c8ec8eeaSjose borrego  * This function must be called with the tree mutex held.
1042c8ec8eeaSjose borrego  */
1043c8ec8eeaSjose borrego static boolean_t
10448b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tree_is_connected_locked(smb_tree_t *tree)
1045c8ec8eeaSjose borrego {
1046c8ec8eeaSjose borrego 	switch (tree->t_state) {
1047c8ec8eeaSjose borrego 	case SMB_TREE_STATE_CONNECTED:
1048c8ec8eeaSjose borrego 		return (B_TRUE);
1049c8ec8eeaSjose borrego 
1050c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTING:
1051c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTED:
1052c8ec8eeaSjose borrego 		/*
1053811599a4SMatt Barden 		 * The tree exists but is being disconnected or destroyed.
1054c8ec8eeaSjose borrego 		 */
1055c8ec8eeaSjose borrego 		return (B_FALSE);
1056c8ec8eeaSjose borrego 
1057c8ec8eeaSjose borrego 	default:
1058c8ec8eeaSjose borrego 		ASSERT(0);
1059c8ec8eeaSjose borrego 		return (B_FALSE);
1060c8ec8eeaSjose borrego 	}
1061c8ec8eeaSjose borrego }
1062c8ec8eeaSjose borrego 
1063c8ec8eeaSjose borrego /*
1064c8ec8eeaSjose borrego  * Return a pointer to the share name within a share resource path.
1065da6c28aaSamw  *
1066c8ec8eeaSjose borrego  * The share path may be a Uniform Naming Convention (UNC) string
1067c8ec8eeaSjose borrego  * (\\server\share) or simply the share name.  We validate the UNC
1068c8ec8eeaSjose borrego  * format but we don't look at the server name.
1069c8ec8eeaSjose borrego  */
1070a90cf9f2SGordon Ross static char *
1071a90cf9f2SGordon Ross smb_tree_get_sharename(char *unc_path)
1072c8ec8eeaSjose borrego {
1073a90cf9f2SGordon Ross 	char *sharename = unc_path;
1074c8ec8eeaSjose borrego 
1075c8ec8eeaSjose borrego 	if (sharename[0] == '\\') {
1076c8ec8eeaSjose borrego 		/*
1077c8ec8eeaSjose borrego 		 * Looks like a UNC path, validate the format.
1078c8ec8eeaSjose borrego 		 */
1079c8ec8eeaSjose borrego 		if (sharename[1] != '\\')
1080c8ec8eeaSjose borrego 			return (NULL);
1081c8ec8eeaSjose borrego 
1082c8ec8eeaSjose borrego 		if ((sharename = strchr(sharename+2, '\\')) == NULL)
1083c8ec8eeaSjose borrego 			return (NULL);
1084c8ec8eeaSjose borrego 
1085c8ec8eeaSjose borrego 		++sharename;
1086c8ec8eeaSjose borrego 	} else if (strchr(sharename, '\\') != NULL) {
1087c8ec8eeaSjose borrego 		/*
1088c8ec8eeaSjose borrego 		 * This should be a share name (no embedded \'s).
1089c8ec8eeaSjose borrego 		 */
1090c8ec8eeaSjose borrego 		return (NULL);
1091c8ec8eeaSjose borrego 	}
1092c8ec8eeaSjose borrego 
1093c8ec8eeaSjose borrego 	return (sharename);
1094c8ec8eeaSjose borrego }
1095c8ec8eeaSjose borrego 
1096da6c28aaSamw /*
1097c8ec8eeaSjose borrego  * Obtain the tree attributes: volume name, typename and flags.
1098c8ec8eeaSjose borrego  */
1099c8ec8eeaSjose borrego static int
1100148c5f43SAlan Wright smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree)
1101c8ec8eeaSjose borrego {
1102c8ec8eeaSjose borrego 	vfs_t *vfsp = SMB_NODE_VFS(node);
1103*af536d7dSGordon Ross 	vfs_t *realvfsp;
11041160dcf7SMatt Barden 	smb_cfg_val_t srv_encrypt;
1105c8ec8eeaSjose borrego 
1106c8ec8eeaSjose borrego 	ASSERT(vfsp);
1107c8ec8eeaSjose borrego 
110825a9a7aaSGordon Ross 	smb_tree_get_creation(node, tree);
1109c8ec8eeaSjose borrego 	smb_tree_get_volname(vfsp, tree);
1110*af536d7dSGordon Ross 
1111*af536d7dSGordon Ross 	/*
1112*af536d7dSGordon Ross 	 * In the case of an lofs mount, we need to ask the (real)
1113*af536d7dSGordon Ross 	 * underlying filesystem about capabilities, where the
1114*af536d7dSGordon Ross 	 * passed in vfs_t will be from lofs.
1115*af536d7dSGordon Ross 	 */
1116*af536d7dSGordon Ross 	realvfsp = getvfs(&vfsp->vfs_fsid);
1117*af536d7dSGordon Ross 	if (realvfsp != NULL) {
1118*af536d7dSGordon Ross 		smb_tree_get_flags(si, realvfsp, tree);
1119*af536d7dSGordon Ross 		VFS_RELE(realvfsp);
1120*af536d7dSGordon Ross 	} else {
1121*af536d7dSGordon Ross 		cmn_err(CE_NOTE, "Failed getting info for share: %s",
1122*af536d7dSGordon Ross 		    si->shr_name);
1123*af536d7dSGordon Ross 		/* do the best we can without realvfsp */
1124*af536d7dSGordon Ross 		smb_tree_get_flags(si, vfsp, tree);
1125*af536d7dSGordon Ross 	}
1126c8ec8eeaSjose borrego 
11271160dcf7SMatt Barden 	srv_encrypt = tree->t_session->s_server->sv_cfg.skc_encrypt;
11281160dcf7SMatt Barden 	if (tree->t_session->dialect >= SMB_VERS_3_0) {
11291160dcf7SMatt Barden 		if (si->shr_encrypt == SMB_CONFIG_REQUIRED ||
11301160dcf7SMatt Barden 		    srv_encrypt == SMB_CONFIG_REQUIRED)
11311160dcf7SMatt Barden 			tree->t_encrypt = SMB_CONFIG_REQUIRED;
11321160dcf7SMatt Barden 		else if (si->shr_encrypt == SMB_CONFIG_ENABLED ||
11331160dcf7SMatt Barden 		    srv_encrypt == SMB_CONFIG_ENABLED)
11341160dcf7SMatt Barden 			tree->t_encrypt = SMB_CONFIG_ENABLED;
11351160dcf7SMatt Barden 		else
11361160dcf7SMatt Barden 			tree->t_encrypt = SMB_CONFIG_DISABLED;
11371160dcf7SMatt Barden 	} else
11381160dcf7SMatt Barden 		tree->t_encrypt = SMB_CONFIG_DISABLED;
11391160dcf7SMatt Barden 
1140c8ec8eeaSjose borrego 	return (0);
1141c8ec8eeaSjose borrego }
1142c8ec8eeaSjose borrego 
114325a9a7aaSGordon Ross /*
114425a9a7aaSGordon Ross  * File volume creation time
114525a9a7aaSGordon Ross  */
114625a9a7aaSGordon Ross static void
114725a9a7aaSGordon Ross smb_tree_get_creation(smb_node_t *node, smb_tree_t *tree)
114825a9a7aaSGordon Ross {
114925a9a7aaSGordon Ross 	smb_attr_t	attr;
115025a9a7aaSGordon Ross 	cred_t		*kcr = zone_kcred();
115125a9a7aaSGordon Ross 
115225a9a7aaSGordon Ross 	bzero(&attr, sizeof (attr));
115325a9a7aaSGordon Ross 	attr.sa_mask = SMB_AT_CRTIME;
115425a9a7aaSGordon Ross 	(void) smb_node_getattr(NULL, node, kcr, NULL, &attr);
115525a9a7aaSGordon Ross 	/* On failure we'll have time zero, which is OK */
115625a9a7aaSGordon Ross 
115725a9a7aaSGordon Ross 	tree->t_create_time = attr.sa_crtime;
115825a9a7aaSGordon Ross }
115925a9a7aaSGordon Ross 
1160c8ec8eeaSjose borrego /*
1161c8ec8eeaSjose borrego  * Extract the volume name.
1162c8ec8eeaSjose borrego  */
1163c8ec8eeaSjose borrego static void
1164c8ec8eeaSjose borrego smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
1165c8ec8eeaSjose borrego {
1166a90cf9f2SGordon Ross #ifdef	_FAKE_KERNEL
1167a90cf9f2SGordon Ross 	_NOTE(ARGUNUSED(vfsp))
1168a90cf9f2SGordon Ross 	(void) strlcpy(tree->t_volume, "fake", SMB_VOLNAMELEN);
1169a90cf9f2SGordon Ross #else	/* _FAKE_KERNEL */
1170c8ec8eeaSjose borrego 	refstr_t *vfs_mntpoint;
1171c8ec8eeaSjose borrego 	const char *s;
1172c8ec8eeaSjose borrego 	char *name;
1173c8ec8eeaSjose borrego 
1174c8ec8eeaSjose borrego 	vfs_mntpoint = vfs_getmntpoint(vfsp);
1175c8ec8eeaSjose borrego 
1176b819cea2SGordon Ross 	s = refstr_value(vfs_mntpoint);
1177c8ec8eeaSjose borrego 	s += strspn(s, "/");
1178c8ec8eeaSjose borrego 	(void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
1179c8ec8eeaSjose borrego 
1180c8ec8eeaSjose borrego 	refstr_rele(vfs_mntpoint);
1181c8ec8eeaSjose borrego 
1182c8ec8eeaSjose borrego 	name = tree->t_volume;
1183c8ec8eeaSjose borrego 	(void) strsep((char **)&name, "/");
1184a90cf9f2SGordon Ross #endif	/* _FAKE_KERNEL */
1185c8ec8eeaSjose borrego }
1186c8ec8eeaSjose borrego 
1187c8ec8eeaSjose borrego /*
1188a90cf9f2SGordon Ross  * Always set "unicode on disk" because we always use utf8 names locally.
1189c8ec8eeaSjose borrego  * Always set ACL support because the VFS will fake ACLs for file systems
1190c8ec8eeaSjose borrego  * that don't support them.
1191da6c28aaSamw  *
1192c8ec8eeaSjose borrego  * Some flags are dependent on the typename, which is also set up here.
1193c8ec8eeaSjose borrego  * File system types are hardcoded in uts/common/os/vfs_conf.c.
1194da6c28aaSamw  */
1195c8ec8eeaSjose borrego static void
1196148c5f43SAlan Wright smb_tree_get_flags(const smb_kshare_t *si, vfs_t *vfsp, smb_tree_t *tree)
1197da6c28aaSamw {
11985f1ef25cSAram Hăvărneanu 	smb_session_t *ssn = tree->t_session;
1199b819cea2SGordon Ross 	struct vfssw	*vswp;
12005f1ef25cSAram Hăvărneanu 
1201fc724630SAlan Wright 	typedef struct smb_mtype {
1202fc724630SAlan Wright 		char		*mt_name;
1203fc724630SAlan Wright 		size_t		mt_namelen;
1204fc724630SAlan Wright 		uint32_t	mt_flags;
1205fc724630SAlan Wright 	} smb_mtype_t;
1206fc724630SAlan Wright 
1207fc724630SAlan Wright 	static smb_mtype_t smb_mtype[] = {
120855f0a249SGordon Ross #ifdef	_FAKE_KERNEL
120955f0a249SGordon Ross 		/* See libfksmbsrv:fake_vfs.c */
121055f0a249SGordon Ross 		{ "fake",    3,	SMB_TREE_SPARSE},
121155f0a249SGordon Ross #endif	/* _FAKE_KERNEL */
1212a90cf9f2SGordon Ross 		{ "zfs",    3,	SMB_TREE_QUOTA | SMB_TREE_SPARSE},
1213a90cf9f2SGordon Ross 		{ "ufs",    3,	0 },
12149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		{ "nfs",    3,	SMB_TREE_NFS_MOUNTED },
12159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		{ "tmpfs",  5,	SMB_TREE_NO_EXPORT }
1216fc724630SAlan Wright 	};
1217fc724630SAlan Wright 	smb_mtype_t	*mtype;
1218fc724630SAlan Wright 	char		*name;
1219a90cf9f2SGordon Ross 	uint32_t	flags =
1220a90cf9f2SGordon Ross 	    SMB_TREE_SUPPORTS_ACLS |
1221a90cf9f2SGordon Ross 	    SMB_TREE_UNICODE_ON_DISK;
1222fc724630SAlan Wright 	int		i;
1223da6c28aaSamw 
12249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (si->shr_flags & SMB_SHRF_DFSROOT)
12259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_TREE_DFSROOT;
12269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12278b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (si->shr_flags & SMB_SHRF_CATIA)
12288b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_TREE_CATIA;
12298b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
1230e3f2c991SKeyur Desai 	if (si->shr_flags & SMB_SHRF_ABE)
1231e3f2c991SKeyur Desai 		flags |= SMB_TREE_ABE;
1232e3f2c991SKeyur Desai 
12338d94f651SGordon Ross 	if (si->shr_flags & SMB_SHRF_CA)
12348d94f651SGordon Ross 		flags |= SMB_TREE_CA;
12358d94f651SGordon Ross 
123694047d49SGordon Ross 	if (si->shr_flags & SMB_SHRF_FSO)
123794047d49SGordon Ross 		flags |= SMB_TREE_FORCE_L2_OPLOCK;
123894047d49SGordon Ross 
12395f1ef25cSAram Hăvărneanu 	if (ssn->s_cfg.skc_oplock_enable) {
1240cb174861Sjoyce mcintosh 		/* if 'smb' zfs property: oplocks=enabled */
1241cb174861Sjoyce mcintosh 		flags |= SMB_TREE_OPLOCKS;
1242cb174861Sjoyce mcintosh 	}
1243cb174861Sjoyce mcintosh 
12445f1ef25cSAram Hăvărneanu 	/* Global config option for now.  Later make per-share. */
12455f1ef25cSAram Hăvărneanu 	if (ssn->s_cfg.skc_traverse_mounts)
12465f1ef25cSAram Hăvărneanu 		flags |= SMB_TREE_TRAVERSE_MOUNTS;
12475f1ef25cSAram Hăvărneanu 
1248cb174861Sjoyce mcintosh 	/* if 'smb' zfs property: shortnames=enabled */
1249cb174861Sjoyce mcintosh 	if (smb_shortnames)
1250cb174861Sjoyce mcintosh 		flags |= SMB_TREE_SHORTNAMES;
1251cb174861Sjoyce mcintosh 
1252c8ec8eeaSjose borrego 	if (vfsp->vfs_flag & VFS_RDONLY)
1253c8ec8eeaSjose borrego 		flags |= SMB_TREE_READONLY;
1254c8ec8eeaSjose borrego 
1255c8ec8eeaSjose borrego 	if (vfsp->vfs_flag & VFS_XATTR)
1256c8ec8eeaSjose borrego 		flags |= SMB_TREE_STREAMS;
1257c8ec8eeaSjose borrego 
1258b819cea2SGordon Ross 	vswp = vfs_getvfsswbyvfsops(vfs_getops(vfsp));
1259b819cea2SGordon Ross 	if (vswp != NULL) {
1260b819cea2SGordon Ross 		name = vswp->vsw_name;
1261b819cea2SGordon Ross 		vfs_unrefvfssw(vswp);
1262b819cea2SGordon Ross 	} else {
1263b819cea2SGordon Ross 		name = "?";
1264b819cea2SGordon Ross 	}
1265c8ec8eeaSjose borrego 
1266fc724630SAlan Wright 	for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
1267fc724630SAlan Wright 		mtype = &smb_mtype[i];
1268fc724630SAlan Wright 		if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
1269fc724630SAlan Wright 			flags |= mtype->mt_flags;
1270fc724630SAlan Wright 	}
1271c8ec8eeaSjose borrego 
1272ca5fb90aSGordon Ross 	/*
1273ca5fb90aSGordon Ross 	 * SMB_TREE_QUOTA will be on here if the FS is ZFS.  We want to
1274ca5fb90aSGordon Ross 	 * turn it OFF when the share property says false.
1275ca5fb90aSGordon Ross 	 */
1276ca5fb90aSGordon Ross 	if ((si->shr_flags & SMB_SHRF_QUOTAS) == 0)
1277ca5fb90aSGordon Ross 		flags &= ~SMB_TREE_QUOTA;
1278ca5fb90aSGordon Ross 
1279c8ec8eeaSjose borrego 	(void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
1280bbf6f00cSJordan Brown 	(void) smb_strupr((char *)tree->t_typename);
1281da6c28aaSamw 
1282c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_XVATTR))
1283c8ec8eeaSjose borrego 		flags |= SMB_TREE_XVATTR;
1284c8ec8eeaSjose borrego 
1285c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
1286c8ec8eeaSjose borrego 		flags |= SMB_TREE_CASEINSENSITIVE;
1287c8ec8eeaSjose borrego 
1288c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
1289c8ec8eeaSjose borrego 		flags |= SMB_TREE_NO_CASESENSITIVE;
1290c8ec8eeaSjose borrego 
1291c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
1292c8ec8eeaSjose borrego 		flags |= SMB_TREE_DIRENTFLAGS;
1293c8ec8eeaSjose borrego 
1294c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
1295c8ec8eeaSjose borrego 		flags |= SMB_TREE_ACLONCREATE;
1296c8ec8eeaSjose borrego 
1297c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
1298c8ec8eeaSjose borrego 		flags |= SMB_TREE_ACEMASKONACCESS;
1299c8ec8eeaSjose borrego 
1300fc724630SAlan Wright 	DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);
1301fc724630SAlan Wright 
1302c8ec8eeaSjose borrego 
1303c8ec8eeaSjose borrego 	tree->t_flags = flags;
1304c8ec8eeaSjose borrego }
1305c8ec8eeaSjose borrego 
1306c8ec8eeaSjose borrego /*
1307c8ec8eeaSjose borrego  * Report share access result to syslog.
1308c8ec8eeaSjose borrego  */
1309c8ec8eeaSjose borrego static void
1310c8ec8eeaSjose borrego smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
1311c8ec8eeaSjose borrego {
1312c8ec8eeaSjose borrego 	va_list ap;
1313c8ec8eeaSjose borrego 	char buf[128];
1314c8ec8eeaSjose borrego 	smb_user_t *user = sr->uid_user;
1315c8ec8eeaSjose borrego 
1316c8ec8eeaSjose borrego 	ASSERT(user);
1317c8ec8eeaSjose borrego 
1318c8ec8eeaSjose borrego 	if (smb_tcon_mute)
1319c8ec8eeaSjose borrego 		return;
1320c8ec8eeaSjose borrego 
1321c8ec8eeaSjose borrego 	if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
1322c8ec8eeaSjose borrego 		/*
1323c8ec8eeaSjose borrego 		 * Only report normal users, i.e. ignore W2K misuse
1324c8ec8eeaSjose borrego 		 * of the IPC connection by filtering out internal
1325c8ec8eeaSjose borrego 		 * names such as nobody and root.
1326c8ec8eeaSjose borrego 		 */
1327c8ec8eeaSjose borrego 		if ((strcmp(user->u_name, "root") == 0) ||
1328c8ec8eeaSjose borrego 		    (strcmp(user->u_name, "nobody") == 0)) {
1329c8ec8eeaSjose borrego 			return;
1330da6c28aaSamw 		}
1331da6c28aaSamw 	}
1332da6c28aaSamw 
1333c8ec8eeaSjose borrego 	va_start(ap, fmt);
1334c8ec8eeaSjose borrego 	(void) vsnprintf(buf, 128, fmt, ap);
1335c8ec8eeaSjose borrego 	va_end(ap);
1336c8ec8eeaSjose borrego 
1337c8ec8eeaSjose borrego 	cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
1338c8ec8eeaSjose borrego 	    user->u_domain, user->u_name, sharename, buf);
1339da6c28aaSamw }
13407f667e74Sjose borrego 
13417f667e74Sjose borrego /*
13427f667e74Sjose borrego  * smb_tree_lookup_odir
13437f667e74Sjose borrego  *
13447f667e74Sjose borrego  * Find the specified odir in the tree's list of odirs, and
13457f667e74Sjose borrego  * attempt to obtain a hold on the odir.
13467f667e74Sjose borrego  *
13477f667e74Sjose borrego  * Returns NULL if odir not found or a hold cannot be obtained.
13487f667e74Sjose borrego  */
13497f667e74Sjose borrego smb_odir_t *
13503b13a1efSThomas Keiser smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid)
13517f667e74Sjose borrego {
13527f667e74Sjose borrego 	smb_odir_t	*od;
13537f667e74Sjose borrego 	smb_llist_t	*od_list;
13543b13a1efSThomas Keiser 	smb_tree_t	*tree = sr->tid_tree;
13557f667e74Sjose borrego 
13567f667e74Sjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
13577f667e74Sjose borrego 
13587f667e74Sjose borrego 	od_list = &tree->t_odir_list;
13597f667e74Sjose borrego 
13603b13a1efSThomas Keiser 	smb_llist_enter(od_list, RW_READER);
13617f667e74Sjose borrego 	od = smb_llist_head(od_list);
13627f667e74Sjose borrego 	while (od) {
13633b13a1efSThomas Keiser 		if (od->d_odid == odid)
13647f667e74Sjose borrego 			break;
13657f667e74Sjose borrego 		od = smb_llist_next(od_list, od);
13667f667e74Sjose borrego 	}
13673b13a1efSThomas Keiser 	if (od == NULL)
13683b13a1efSThomas Keiser 		goto out;
13693b13a1efSThomas Keiser 
13703b13a1efSThomas Keiser 	/*
13713b13a1efSThomas Keiser 	 * Only allow use of a given Search ID with the same UID that
13723b13a1efSThomas Keiser 	 * was used to create it.  MS-CIFS 3.3.5.14
13733b13a1efSThomas Keiser 	 */
13743b13a1efSThomas Keiser 	if (od->d_user != sr->uid_user) {
13753b13a1efSThomas Keiser 		od = NULL;
13763b13a1efSThomas Keiser 		goto out;
13773b13a1efSThomas Keiser 	}
13783b13a1efSThomas Keiser 	if (!smb_odir_hold(od))
13793b13a1efSThomas Keiser 		od = NULL;
13807f667e74Sjose borrego 
13813b13a1efSThomas Keiser out:
13827f667e74Sjose borrego 	smb_llist_exit(od_list);
13837f667e74Sjose borrego 	return (od);
13847f667e74Sjose borrego }
13857f667e74Sjose borrego 
13868b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States boolean_t
13878b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tree_is_connected(smb_tree_t *tree)
13888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States {
13898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	boolean_t	rb;
13908b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
13918b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_enter(&tree->t_mutex);
13928b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	rb = smb_tree_is_connected_locked(tree);
13938b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_exit(&tree->t_mutex);
13948b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	return (rb);
13958b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
13968b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
13977f667e74Sjose borrego /*
13987f667e74Sjose borrego  * smb_tree_close_odirs
13997f667e74Sjose borrego  *
14007f667e74Sjose borrego  * Close all open odirs in the tree's list which were opened by
14017f667e74Sjose borrego  * the process identified by pid.
14027f667e74Sjose borrego  * If pid is zero, close all open odirs in the tree's list.
14037f667e74Sjose borrego  */
14047f667e74Sjose borrego static void
14058d94f651SGordon Ross smb_tree_close_odirs(smb_tree_t *tree, uint32_t pid)
14067f667e74Sjose borrego {
14078d94f651SGordon Ross 	smb_llist_t	*od_list;
14088d94f651SGordon Ross 	smb_odir_t	*od;
14097f667e74Sjose borrego 
14107f667e74Sjose borrego 	ASSERT(tree);
14117f667e74Sjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
14127f667e74Sjose borrego 
14138d94f651SGordon Ross 	od_list = &tree->t_odir_list;
14148d94f651SGordon Ross 	smb_llist_enter(od_list, RW_READER);
14158d94f651SGordon Ross 
14168d94f651SGordon Ross 	for (od = smb_llist_head(od_list);
14178d94f651SGordon Ross 	    od != NULL;
14188d94f651SGordon Ross 	    od = smb_llist_next(od_list, od)) {
14198d94f651SGordon Ross 
14207f667e74Sjose borrego 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
14217f667e74Sjose borrego 		ASSERT(od->d_tree == tree);
14227f667e74Sjose borrego 
14238d94f651SGordon Ross 		if (pid != 0 && od->d_opened_by_pid != pid)
14248d94f651SGordon Ross 			continue;
14257f667e74Sjose borrego 
14268d94f651SGordon Ross 		if (smb_odir_hold(od)) {
14278d94f651SGordon Ross 			smb_odir_close(od);
14288d94f651SGordon Ross 			smb_odir_release(od);
14298d94f651SGordon Ross 		}
14307f667e74Sjose borrego 	}
14318d94f651SGordon Ross 
14328d94f651SGordon Ross 	smb_llist_exit(od_list);
14337f667e74Sjose borrego }
143429bd2886SAlan Wright 
143529bd2886SAlan Wright static void
14363b13a1efSThomas Keiser smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec,
14373b13a1efSThomas Keiser     int exec_type)
143829bd2886SAlan Wright {
1439148c5f43SAlan Wright 	exec->e_sharename = tree->t_sharename;
14403b13a1efSThomas Keiser 	exec->e_winname = tree->t_owner->u_name;
14413b13a1efSThomas Keiser 	exec->e_userdom = tree->t_owner->u_domain;
1442148c5f43SAlan Wright 	exec->e_srv_ipaddr = tree->t_session->local_ipaddr;
1443148c5f43SAlan Wright 	exec->e_cli_ipaddr = tree->t_session->ipaddr;
1444148c5f43SAlan Wright 	exec->e_cli_netbiosname = tree->t_session->workstation;
14453b13a1efSThomas Keiser 	exec->e_uid = crgetuid(tree->t_owner->u_cred);
1446148c5f43SAlan Wright 	exec->e_type = exec_type;
144729bd2886SAlan Wright }
14481fcced4cSJordan Brown 
14491fcced4cSJordan Brown /*
14501fcced4cSJordan Brown  * Private function to support smb_tree_enum.
14511fcced4cSJordan Brown  */
14521fcced4cSJordan Brown static int
14531fcced4cSJordan Brown smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum)
14541fcced4cSJordan Brown {
14551fcced4cSJordan Brown 	uint8_t *pb;
14561fcced4cSJordan Brown 	uint_t nbytes;
14571fcced4cSJordan Brown 	int rc;
14581fcced4cSJordan Brown 
14591fcced4cSJordan Brown 	if (svcenum->se_nskip > 0) {
14601fcced4cSJordan Brown 		svcenum->se_nskip--;
14611fcced4cSJordan Brown 		return (0);
14621fcced4cSJordan Brown 	}
14631fcced4cSJordan Brown 
14641fcced4cSJordan Brown 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
14651fcced4cSJordan Brown 		svcenum->se_nitems = svcenum->se_nlimit;
14661fcced4cSJordan Brown 		return (0);
14671fcced4cSJordan Brown 	}
14681fcced4cSJordan Brown 
14691fcced4cSJordan Brown 	pb = &svcenum->se_buf[svcenum->se_bused];
14701fcced4cSJordan Brown 	rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes);
14711fcced4cSJordan Brown 	if (rc == 0) {
14721fcced4cSJordan Brown 		svcenum->se_bavail -= nbytes;
14731fcced4cSJordan Brown 		svcenum->se_bused += nbytes;
14741fcced4cSJordan Brown 		svcenum->se_nitems++;
14751fcced4cSJordan Brown 	}
14761fcced4cSJordan Brown 
14771fcced4cSJordan Brown 	return (rc);
14781fcced4cSJordan Brown }
14791fcced4cSJordan Brown 
14801fcced4cSJordan Brown /*
14811fcced4cSJordan Brown  * Encode connection information into a buffer: connection information
14821fcced4cSJordan Brown  * needed in user space to support RPC requests.
14831fcced4cSJordan Brown  */
14841fcced4cSJordan Brown static int
14851fcced4cSJordan Brown smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
14861fcced4cSJordan Brown     uint32_t *nbytes)
14871fcced4cSJordan Brown {
14881fcced4cSJordan Brown 	smb_netconnectinfo_t	info;
14891fcced4cSJordan Brown 	int			rc;
14901fcced4cSJordan Brown 
14911fcced4cSJordan Brown 	smb_tree_netinfo_init(tree, &info);
14921fcced4cSJordan Brown 	rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes);
14931fcced4cSJordan Brown 	smb_tree_netinfo_fini(&info);
14941fcced4cSJordan Brown 
14951fcced4cSJordan Brown 	return (rc);
14961fcced4cSJordan Brown }
14971fcced4cSJordan Brown 
14983b13a1efSThomas Keiser static void
14993b13a1efSThomas Keiser smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen)
15003b13a1efSThomas Keiser {
15013b13a1efSThomas Keiser 	smb_user_t		*user = tree->t_owner;
15023b13a1efSThomas Keiser 
15033b13a1efSThomas Keiser 	/*
15043b13a1efSThomas Keiser 	 * u_domain_len and u_name_len include the '\0' in their
15053b13a1efSThomas Keiser 	 * lengths, hence the sum of the two lengths gives us room
15063b13a1efSThomas Keiser 	 * for both the '\\' and '\0' chars.
15073b13a1efSThomas Keiser 	 */
15083b13a1efSThomas Keiser 	ASSERT(namestr);
15093b13a1efSThomas Keiser 	ASSERT(namelen);
15103b13a1efSThomas Keiser 	ASSERT(user->u_domain_len > 0);
15113b13a1efSThomas Keiser 	ASSERT(user->u_name_len > 0);
15123b13a1efSThomas Keiser 	*namelen = user->u_domain_len + user->u_name_len;
15133b13a1efSThomas Keiser 	*namestr = kmem_alloc(*namelen, KM_SLEEP);
15143b13a1efSThomas Keiser 	(void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain,
15153b13a1efSThomas Keiser 	    user->u_name);
15163b13a1efSThomas Keiser }
15173b13a1efSThomas Keiser 
15181fcced4cSJordan Brown /*
15191fcced4cSJordan Brown  * Note: ci_numusers should be the number of users connected to
15201fcced4cSJordan Brown  * the share rather than the number of references on the tree but
15211fcced4cSJordan Brown  * we don't have a mechanism to track users/share in smbsrv yet.
15221fcced4cSJordan Brown  */
15231fcced4cSJordan Brown static void
15241fcced4cSJordan Brown smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
15251fcced4cSJordan Brown {
15261fcced4cSJordan Brown 	ASSERT(tree);
15271fcced4cSJordan Brown 
15281fcced4cSJordan Brown 	info->ci_id = tree->t_tid;
15291fcced4cSJordan Brown 	info->ci_type = tree->t_res_type;
15301fcced4cSJordan Brown 	info->ci_numopens = tree->t_open_files;
15311fcced4cSJordan Brown 	info->ci_numusers = tree->t_refcnt;
15321fcced4cSJordan Brown 	info->ci_time = gethrestime_sec() - tree->t_connect_time;
15331fcced4cSJordan Brown 
15341fcced4cSJordan Brown 	info->ci_sharelen = strlen(tree->t_sharename) + 1;
15359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	info->ci_share = smb_mem_strdup(tree->t_sharename);
15361fcced4cSJordan Brown 
15373b13a1efSThomas Keiser 	smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen);
15381fcced4cSJordan Brown }
15391fcced4cSJordan Brown 
15401fcced4cSJordan Brown static void
15411fcced4cSJordan Brown smb_tree_netinfo_fini(smb_netconnectinfo_t *info)
15421fcced4cSJordan Brown {
15431fcced4cSJordan Brown 	if (info == NULL)
15441fcced4cSJordan Brown 		return;
15451fcced4cSJordan Brown 
15461fcced4cSJordan Brown 	if (info->ci_username)
15471fcced4cSJordan Brown 		kmem_free(info->ci_username, info->ci_namelen);
15481fcced4cSJordan Brown 	if (info->ci_share)
15499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smb_mem_free(info->ci_share);
15501fcced4cSJordan Brown 
15511fcced4cSJordan Brown 	bzero(info, sizeof (smb_netconnectinfo_t));
15521fcced4cSJordan Brown }
1553