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.
25814e0daaSGordon Ross  * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
262cf6b79fSGordon Ross  * Copyright 2022 RackTop Systems, Inc.
27da6c28aaSamw  */
28da6c28aaSamw 
29da6c28aaSamw /*
30da6c28aaSamw  * General Structures Layout
31da6c28aaSamw  * -------------------------
32da6c28aaSamw  *
33da6c28aaSamw  * This is a simplified diagram showing the relationship between most of the
34da6c28aaSamw  * main structures.
35da6c28aaSamw  *
36da6c28aaSamw  * +-------------------+
37da6c28aaSamw  * |     SMB_INFO      |
38da6c28aaSamw  * +-------------------+
39da6c28aaSamw  *          |
40da6c28aaSamw  *          |
41da6c28aaSamw  *          v
42da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
43da6c28aaSamw  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
44da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
453b13a1efSThomas Keiser  *   |          |
463b13a1efSThomas Keiser  *   |          |
473b13a1efSThomas Keiser  *   |          v
483b13a1efSThomas Keiser  *   |  +-------------------+     +-------------------+   +-------------------+
493b13a1efSThomas Keiser  *   |  |       USER        |<--->|       USER        |...|       USER        |
503b13a1efSThomas Keiser  *   |  +-------------------+     +-------------------+   +-------------------+
513b13a1efSThomas Keiser  *   |
523b13a1efSThomas Keiser  *   |
533b13a1efSThomas Keiser  *   v
54da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
55da6c28aaSamw  * |       TREE        |<----->|       TREE        |......|       TREE        |
56da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
57da6c28aaSamw  *      |         |
58da6c28aaSamw  *      |         |
59da6c28aaSamw  *      |         v
60da6c28aaSamw  *      |     +-------+       +-------+      +-------+
61da6c28aaSamw  *      |     | OFILE |<----->| OFILE |......| OFILE |
62da6c28aaSamw  *      |     +-------+       +-------+      +-------+
63da6c28aaSamw  *      |
64da6c28aaSamw  *      |
65da6c28aaSamw  *      v
66da6c28aaSamw  *  +-------+       +------+      +------+
67da6c28aaSamw  *  | ODIR  |<----->| ODIR |......| ODIR |
68da6c28aaSamw  *  +-------+       +------+      +------+
69da6c28aaSamw  *
70da6c28aaSamw  *
71da6c28aaSamw  * Tree State Machine
72da6c28aaSamw  * ------------------
73da6c28aaSamw  *
74da6c28aaSamw  *    +-----------------------------+	 T0
75da6c28aaSamw  *    |  SMB_TREE_STATE_CONNECTED   |<----------- Creation/Allocation
76da6c28aaSamw  *    +-----------------------------+
77da6c28aaSamw  *		    |
78da6c28aaSamw  *		    | T1
79da6c28aaSamw  *		    |
80da6c28aaSamw  *		    v
81da6c28aaSamw  *    +------------------------------+
82da6c28aaSamw  *    | SMB_TREE_STATE_DISCONNECTING |
83da6c28aaSamw  *    +------------------------------+
84da6c28aaSamw  *		    |
85da6c28aaSamw  *		    | T2
86da6c28aaSamw  *		    |
87da6c28aaSamw  *		    v
88da6c28aaSamw  *    +-----------------------------+    T3
89da6c28aaSamw  *    | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free
90da6c28aaSamw  *    +-----------------------------+
91da6c28aaSamw  *
92da6c28aaSamw  * SMB_TREE_STATE_CONNECTED
93da6c28aaSamw  *
94da6c28aaSamw  *    While in this state:
95da6c28aaSamw  *      - The tree is queued in the list of trees of its user.
96da6c28aaSamw  *      - References will be given out if the tree is looked up.
97da6c28aaSamw  *      - Files under that tree can be accessed.
98da6c28aaSamw  *
99da6c28aaSamw  * SMB_TREE_STATE_DISCONNECTING
100da6c28aaSamw  *
101da6c28aaSamw  *    While in this state:
102da6c28aaSamw  *      - The tree is queued in the list of trees of its user.
103da6c28aaSamw  *      - References will not be given out if the tree is looked up.
104da6c28aaSamw  *      - The files and directories open under the tree are being closed.
105da6c28aaSamw  *      - The resources associated with the tree remain.
106da6c28aaSamw  *
107da6c28aaSamw  * SMB_TREE_STATE_DISCONNECTED
108da6c28aaSamw  *
109da6c28aaSamw  *    While in this state:
110da6c28aaSamw  *      - The tree is queued in the list of trees of its user.
111da6c28aaSamw  *      - References will not be given out if the tree is looked up.
112da6c28aaSamw  *      - The tree has no more files and directories opened.
113da6c28aaSamw  *      - The resources associated with the tree remain.
114da6c28aaSamw  *
115da6c28aaSamw  * Transition T0
116da6c28aaSamw  *
117da6c28aaSamw  *    This transition occurs in smb_tree_connect(). A new tree is created and
118da6c28aaSamw  *    added to the list of trees of a user.
119da6c28aaSamw  *
120da6c28aaSamw  * Transition T1
121da6c28aaSamw  *
122da6c28aaSamw  *    This transition occurs in smb_tree_disconnect().
123da6c28aaSamw  *
124da6c28aaSamw  * Transition T2
125da6c28aaSamw  *
126811599a4SMatt Barden  *    This transition occurs in smb_tree_disconnect()
127811599a4SMatt Barden  *
128811599a4SMatt Barden  * Transition T3
129811599a4SMatt Barden  *
130da6c28aaSamw  *    This transition occurs in smb_tree_release(). The resources associated
131da6c28aaSamw  *    with the tree are freed as well as the tree structure. For the transition
132811599a4SMatt Barden  *    to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED and the
133811599a4SMatt Barden  *    reference count must be zero.
134da6c28aaSamw  *
135da6c28aaSamw  * Comments
136da6c28aaSamw  * --------
137da6c28aaSamw  *
138da6c28aaSamw  *    The state machine of the tree structures is controlled by 3 elements:
139da6c28aaSamw  *      - The list of trees of the user it belongs to.
140da6c28aaSamw  *      - The mutex embedded in the structure itself.
141da6c28aaSamw  *      - The reference count.
142da6c28aaSamw  *
143da6c28aaSamw  *    There's a mutex embedded in the tree structure used to protect its fields
144da6c28aaSamw  *    and there's a lock embedded in the list of trees of a user. To
145da6c28aaSamw  *    increment or to decrement the reference count the mutex must be entered.
146da6c28aaSamw  *    To insert the tree into the list of trees of the user and to remove
147da6c28aaSamw  *    the tree from it, the lock must be entered in RW_WRITER mode.
148da6c28aaSamw  *
149da6c28aaSamw  *    Rules of access to a tree structure:
150da6c28aaSamw  *
151da6c28aaSamw  *    1) In order to avoid deadlocks, when both (mutex and lock of the user
152811599a4SMatt Barden  *       list) have to be entered, the lock must be entered first. Additionally,
153811599a4SMatt Barden  *       when both the (mutex and lock of the ofile list) have to be entered,
154811599a4SMatt Barden  *       the mutex must be entered first. However, the ofile list lock must NOT
155811599a4SMatt Barden  *       be dropped while the mutex is held in such a way that the ofile deleteq
156811599a4SMatt Barden  *       is flushed.
157da6c28aaSamw  *
158da6c28aaSamw  *    2) All actions applied to a tree require a reference count.
159da6c28aaSamw  *
160c8ec8eeaSjose borrego  *    3) There are 2 ways of getting a reference count: when a tree is
161c8ec8eeaSjose borrego  *       connected and when a tree is looked up.
162da6c28aaSamw  *
163da6c28aaSamw  *    It should be noted that the reference count of a tree registers the
164da6c28aaSamw  *    number of references to the tree in other structures (such as an smb
165da6c28aaSamw  *    request). The reference count is not incremented in these 2 instances:
166da6c28aaSamw  *
16748bbca81SDaniel Hoffman  *    1) The tree is connected. An tree is anchored by its state. If there's
168da6c28aaSamw  *       no activity involving a tree currently connected, the reference
169da6c28aaSamw  *       count of that tree is zero.
170da6c28aaSamw  *
171da6c28aaSamw  *    2) The tree is queued in the list of trees of the user. The fact of
172da6c28aaSamw  *       being queued in that list is NOT registered by incrementing the
173da6c28aaSamw  *       reference count.
174da6c28aaSamw  */
175148c5f43SAlan Wright 
176c8ec8eeaSjose borrego #include <sys/refstr_impl.h>
177bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
178148c5f43SAlan Wright #include <smbsrv/smb_ktypes.h>
179da6c28aaSamw #include <smbsrv/smb_fsops.h>
180cb174861Sjoyce mcintosh #include <smbsrv/smb_share.h>
181c8ec8eeaSjose borrego 
18245f8fdd1SGordon Ross int smb_tcon_mute = 1;
183c8ec8eeaSjose borrego 
184a90cf9f2SGordon Ross uint32_t	smb_tree_connect_core(smb_request_t *);
185a90cf9f2SGordon Ross uint32_t	smb_tree_connect_disk(smb_request_t *, smb_arg_tcon_t *);
186a90cf9f2SGordon Ross uint32_t	smb_tree_connect_printq(smb_request_t *, smb_arg_tcon_t *);
187a90cf9f2SGordon Ross uint32_t	smb_tree_connect_ipc(smb_request_t *, smb_arg_tcon_t *);
188811599a4SMatt Barden static void smb_tree_dealloc(void *);
1898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States static boolean_t smb_tree_is_connected_locked(smb_tree_t *);
190a90cf9f2SGordon Ross static char *smb_tree_get_sharename(char *);
191148c5f43SAlan Wright static int smb_tree_getattr(const smb_kshare_t *, smb_node_t *, smb_tree_t *);
19225a9a7aaSGordon Ross static void smb_tree_get_creation(smb_node_t *, smb_tree_t *);
193c8ec8eeaSjose borrego static void smb_tree_get_volname(vfs_t *, smb_tree_t *);
194148c5f43SAlan Wright static void smb_tree_get_flags(const smb_kshare_t *, vfs_t *, smb_tree_t *);
195c8ec8eeaSjose borrego static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
1968d94f651SGordon Ross static void smb_tree_close_odirs(smb_tree_t *, uint32_t);
197148c5f43SAlan Wright static void smb_tree_set_execinfo(smb_tree_t *, smb_shr_execinfo_t *, int);
1981fcced4cSJordan Brown static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *);
1991fcced4cSJordan Brown static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *);
2001fcced4cSJordan Brown static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *);
2011fcced4cSJordan Brown static void smb_tree_netinfo_fini(smb_netconnectinfo_t *);
202da6c28aaSamw 
203a90cf9f2SGordon Ross uint32_t
smb_tree_connect(smb_request_t * sr)204cb174861Sjoyce mcintosh smb_tree_connect(smb_request_t *sr)
205cb174861Sjoyce mcintosh {
206cb174861Sjoyce mcintosh 	smb_server_t	*sv = sr->sr_server;
207a90cf9f2SGordon Ross 	uint32_t status;
208cb174861Sjoyce mcintosh 
209cb174861Sjoyce mcintosh 	if (smb_threshold_enter(&sv->sv_tcon_ct) != 0) {
210a90cf9f2SGordon Ross 		return (NT_STATUS_INSUFF_SERVER_RESOURCES);
211cb174861Sjoyce mcintosh 	}
212cb174861Sjoyce mcintosh 
213a90cf9f2SGordon Ross 	status = smb_tree_connect_core(sr);
214856399cfSGordon Ross 	smb_threshold_exit(&sv->sv_tcon_ct);
215a90cf9f2SGordon Ross 	return (status);
216cb174861Sjoyce mcintosh }
217cb174861Sjoyce mcintosh 
218da6c28aaSamw /*
219148c5f43SAlan Wright  * Lookup the share name dispatch the appropriate stype handler.
220c8ec8eeaSjose borrego  * Share names are case insensitive so we map the share name to
221c8ec8eeaSjose borrego  * lower-case as a convenience for internal processing.
222148c5f43SAlan Wright  *
223148c5f43SAlan Wright  * Valid service values are:
224148c5f43SAlan Wright  *	A:      Disk share
225148c5f43SAlan Wright  *	LPT1:   Printer
226148c5f43SAlan Wright  *	IPC     Named pipe (IPC$ is reserved as the named pipe share).
227148c5f43SAlan Wright  *	COMM    Communications device
228148c5f43SAlan Wright  *	?????   Any type of device (wildcard)
229da6c28aaSamw  */
230a90cf9f2SGordon Ross uint32_t
smb_tree_connect_core(smb_request_t * sr)231cb174861Sjoyce mcintosh smb_tree_connect_core(smb_request_t *sr)
232da6c28aaSamw {
233a90cf9f2SGordon Ross 	smb_arg_tcon_t	*tcon = &sr->sr_tcon;
234148c5f43SAlan Wright 	smb_kshare_t	*si;
235a90cf9f2SGordon Ross 	char		*name;
236a90cf9f2SGordon Ross 	uint32_t	status;
237da6c28aaSamw 
238a90cf9f2SGordon Ross 	(void) smb_strlwr(tcon->path);
239da6c28aaSamw 
240a90cf9f2SGordon Ross 	if ((name = smb_tree_get_sharename(tcon->path)) == NULL) {
241a90cf9f2SGordon Ross 		smb_tree_log(sr, tcon->path, "invalid UNC path");
242a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_NETWORK_NAME);
243da6c28aaSamw 	}
244da6c28aaSamw 
2458622ec45SGordon Ross 	si = smb_kshare_lookup(sr->sr_server, name);
2468622ec45SGordon Ross 	if (si == NULL) {
247148c5f43SAlan Wright 		smb_tree_log(sr, name, "share not found");
248a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_NETWORK_NAME);
249da6c28aaSamw 	}
250cb174861Sjoyce mcintosh 
251cb174861Sjoyce mcintosh 	if (!strcasecmp(SMB_SHARE_PRINT, name)) {
2528622ec45SGordon Ross 		smb_kshare_release(sr->sr_server, si);
253cb174861Sjoyce mcintosh 		smb_tree_log(sr, name, "access not permitted");
254a90cf9f2SGordon Ross 		return (NT_STATUS_ACCESS_DENIED);
255cb174861Sjoyce mcintosh 	}
256cb174861Sjoyce mcintosh 
257a90cf9f2SGordon Ross 	/* NB: name points into tcon->path - don't free it. */
258a90cf9f2SGordon Ross 	tcon->name = name;
259148c5f43SAlan Wright 	sr->sr_tcon.si = si;
260da6c28aaSamw 
2611160dcf7SMatt Barden 	/*
2621160dcf7SMatt Barden 	 * [MS-SMB2] 3.3.5.7 Receiving an SMB2 TREE_CONNECT Request
2631160dcf7SMatt Barden 	 *
2641160dcf7SMatt Barden 	 * If we support 3.x, RejectUnencryptedAccess is TRUE,
2651160dcf7SMatt Barden 	 * if Tcon.EncryptData is TRUE or global EncryptData is TRUE,
2661160dcf7SMatt Barden 	 * and the connection doesn't support encryption,
2671160dcf7SMatt Barden 	 * return ACCESS_DENIED.
2681160dcf7SMatt Barden 	 *
2691160dcf7SMatt Barden 	 * If RejectUnencryptedAccess is TRUE, we force max_protocol
2701160dcf7SMatt Barden 	 * to at least 3.0. Additionally, if the tree requires encryption,
2711160dcf7SMatt Barden 	 * we don't care what we support, we still enforce encryption.
2721160dcf7SMatt Barden 	 */
2731160dcf7SMatt Barden 	if ((sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED ||
2741160dcf7SMatt Barden 	    si->shr_encrypt == SMB_CONFIG_REQUIRED) &&
2751160dcf7SMatt Barden 	    (sr->session->srv_cap & SMB2_CAP_ENCRYPTION) == 0) {
2761160dcf7SMatt Barden 		status = NT_STATUS_ACCESS_DENIED;
2771160dcf7SMatt Barden 		goto out;
2781160dcf7SMatt Barden 	}
2791160dcf7SMatt Barden 
280148c5f43SAlan Wright 	switch (si->shr_type & STYPE_MASK) {
281da6c28aaSamw 	case STYPE_DISKTREE:
282a90cf9f2SGordon Ross 		status = smb_tree_connect_disk(sr, &sr->sr_tcon);
283da6c28aaSamw 		break;
284da6c28aaSamw 	case STYPE_IPC:
285a90cf9f2SGordon Ross 		status = smb_tree_connect_ipc(sr, &sr->sr_tcon);
286c8ec8eeaSjose borrego 		break;
287148c5f43SAlan Wright 	case STYPE_PRINTQ:
288a90cf9f2SGordon Ross 		status = smb_tree_connect_printq(sr, &sr->sr_tcon);
289148c5f43SAlan Wright 		break;
290da6c28aaSamw 	default:
291a90cf9f2SGordon Ross 		status = NT_STATUS_BAD_DEVICE_TYPE;
292da6c28aaSamw 		break;
293da6c28aaSamw 	}
294da6c28aaSamw 
2951160dcf7SMatt Barden out:
2968622ec45SGordon Ross 	smb_kshare_release(sr->sr_server, si);
297a90cf9f2SGordon Ross 	sr->sr_tcon.si = NULL;
298a90cf9f2SGordon Ross 
299a90cf9f2SGordon Ross 	return (status);
300da6c28aaSamw }
301da6c28aaSamw 
302da6c28aaSamw /*
303c8ec8eeaSjose borrego  * Disconnect a tree.
3048d94f651SGordon Ross  *
3058d94f651SGordon Ross  * The "do_exec" arg is obsolete and ignored.
306da6c28aaSamw  */
307da6c28aaSamw void
smb_tree_disconnect(smb_tree_t * tree,boolean_t do_exec)30829bd2886SAlan Wright smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec)
309da6c28aaSamw {
3108d94f651SGordon Ross 	_NOTE(ARGUNUSED(do_exec))
311148c5f43SAlan Wright 	smb_shr_execinfo_t execinfo;
31229bd2886SAlan Wright 
313da6c28aaSamw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
314da6c28aaSamw 
315da6c28aaSamw 	mutex_enter(&tree->t_mutex);
316da6c28aaSamw 	ASSERT(tree->t_refcnt);
317c8ec8eeaSjose borrego 
3188d94f651SGordon Ross 	if (!smb_tree_is_connected_locked(tree)) {
319da6c28aaSamw 		mutex_exit(&tree->t_mutex);
3208d94f651SGordon Ross 		return;
321da6c28aaSamw 	}
322da6c28aaSamw 
3238d94f651SGordon Ross 	/*
3248d94f651SGordon Ross 	 * Indicate that the disconnect process has started.
3258d94f651SGordon Ross 	 */
3268d94f651SGordon Ross 	tree->t_state = SMB_TREE_STATE_DISCONNECTING;
327da6c28aaSamw 	mutex_exit(&tree->t_mutex);
32829bd2886SAlan Wright 
3298d94f651SGordon Ross 	/*
3308d94f651SGordon Ross 	 * The files opened under this tree are closed.
3318d94f651SGordon Ross 	 */
3328d94f651SGordon Ross 	smb_ofile_close_all(tree, 0);
3338d94f651SGordon Ross 	/*
3348d94f651SGordon Ross 	 * The directories opened under this tree are closed.
3358d94f651SGordon Ross 	 */
3368d94f651SGordon Ross 	smb_tree_close_odirs(tree, 0);
33729bd2886SAlan Wright 
3388d94f651SGordon Ross 	if ((tree->t_execflags & SMB_EXEC_UNMAP) != 0) {
339148c5f43SAlan Wright 		smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_UNMAP);
3408622ec45SGordon Ross 		(void) smb_kshare_exec(tree->t_server, &execinfo);
34129bd2886SAlan Wright 	}
342da6c28aaSamw }
343da6c28aaSamw 
344da6c28aaSamw /*
345c8ec8eeaSjose borrego  * Take a reference on a tree.
346da6c28aaSamw  */
347c8ec8eeaSjose borrego boolean_t
smb_tree_hold(smb_tree_t * tree)348c8ec8eeaSjose borrego smb_tree_hold(
349c8ec8eeaSjose borrego     smb_tree_t		*tree)
350da6c28aaSamw {
351a90cf9f2SGordon Ross 	SMB_TREE_VALID(tree);
352da6c28aaSamw 
353c8ec8eeaSjose borrego 	mutex_enter(&tree->t_mutex);
354c8ec8eeaSjose borrego 
3558b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_tree_is_connected_locked(tree)) {
356c8ec8eeaSjose borrego 		tree->t_refcnt++;
357c8ec8eeaSjose borrego 		mutex_exit(&tree->t_mutex);
358c8ec8eeaSjose borrego 		return (B_TRUE);
359da6c28aaSamw 	}
360c8ec8eeaSjose borrego 
361c8ec8eeaSjose borrego 	mutex_exit(&tree->t_mutex);
362c8ec8eeaSjose borrego 	return (B_FALSE);
363da6c28aaSamw }
364da6c28aaSamw 
365a90cf9f2SGordon Ross /*
366a90cf9f2SGordon Ross  * Bump the hold count regardless of the tree state.  This is used in
367a90cf9f2SGordon Ross  * some internal code paths where we've already checked that we had a
368a90cf9f2SGordon Ross  * valid tree connection, and don't want to deal with the possiblity
369a90cf9f2SGordon Ross  * that the tree state might have changed to disconnecting after our
370a90cf9f2SGordon Ross  * original hold was taken.  It's correct to continue processing a
371a90cf9f2SGordon Ross  * request even when new requests cannot lookup that tree anymore.
372a90cf9f2SGordon Ross  */
373a90cf9f2SGordon Ross void
smb_tree_hold_internal(smb_tree_t * tree)374a90cf9f2SGordon Ross smb_tree_hold_internal(
375a90cf9f2SGordon Ross     smb_tree_t		*tree)
376a90cf9f2SGordon Ross {
377a90cf9f2SGordon Ross 	SMB_TREE_VALID(tree);
378a90cf9f2SGordon Ross 
379a90cf9f2SGordon Ross 	mutex_enter(&tree->t_mutex);
380a90cf9f2SGordon Ross 	tree->t_refcnt++;
381a90cf9f2SGordon Ross 	mutex_exit(&tree->t_mutex);
382a90cf9f2SGordon Ross }
383a90cf9f2SGordon Ross 
384da6c28aaSamw /*
385c8ec8eeaSjose borrego  * Release a reference on a tree.  If the tree is disconnected and the
3869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * reference count falls to zero, post the object for deletion.
3879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Object deletion is deferred to avoid modifying a list while an
3889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * iteration may be in progress.
389da6c28aaSamw  */
390da6c28aaSamw void
smb_tree_release(smb_tree_t * tree)391c8ec8eeaSjose borrego smb_tree_release(
392c8ec8eeaSjose borrego     smb_tree_t		*tree)
393da6c28aaSamw {
3949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_TREE_VALID(tree);
395da6c28aaSamw 
396c5866007SKeyur Desai 	/* flush the ofile and odir lists' delete queues */
3972cf6b79fSGordon Ross 	smb_lavl_flush(&tree->t_ofile_list);
398c5866007SKeyur Desai 	smb_llist_flush(&tree->t_odir_list);
399c5866007SKeyur Desai 
400811599a4SMatt Barden 	mutex_enter(&tree->t_mutex);
401811599a4SMatt Barden 	ASSERT(tree->t_refcnt);
402811599a4SMatt Barden 	tree->t_refcnt--;
4039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
404811599a4SMatt Barden 	switch (tree->t_state) {
4058d94f651SGordon Ross 	case SMB_TREE_STATE_DISCONNECTING:
406811599a4SMatt Barden 		if (tree->t_refcnt == 0) {
407811599a4SMatt Barden 			smb_session_t *ssn = tree->t_session;
408811599a4SMatt Barden 			tree->t_state = SMB_TREE_STATE_DISCONNECTED;
409811599a4SMatt Barden 			smb_llist_post(&ssn->s_tree_list, tree,
410811599a4SMatt Barden 			    smb_tree_dealloc);
411811599a4SMatt Barden 		}
412811599a4SMatt Barden 		break;
413811599a4SMatt Barden 	case SMB_TREE_STATE_CONNECTED:
414811599a4SMatt Barden 		break;
415811599a4SMatt Barden 	default:
416811599a4SMatt Barden 		ASSERT(0);
417811599a4SMatt Barden 		break;
418811599a4SMatt Barden 	}
4199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
420811599a4SMatt Barden 	mutex_exit(&tree->t_mutex);
4219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
4229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
423da6c28aaSamw /*
424c8ec8eeaSjose borrego  * Close ofiles and odirs that match pid.
425da6c28aaSamw  */
426da6c28aaSamw void
smb_tree_close_pid(smb_tree_t * tree,uint32_t pid)427c8ec8eeaSjose borrego smb_tree_close_pid(
428c8ec8eeaSjose borrego     smb_tree_t		*tree,
429a90cf9f2SGordon Ross     uint32_t		pid)
430da6c28aaSamw {
431da6c28aaSamw 	ASSERT(tree);
432da6c28aaSamw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
433da6c28aaSamw 
434811599a4SMatt Barden 	smb_ofile_close_all(tree, pid);
4357f667e74Sjose borrego 	smb_tree_close_odirs(tree, pid);
436c8ec8eeaSjose borrego }
437da6c28aaSamw 
438c8ec8eeaSjose borrego /*
439c8ec8eeaSjose borrego  * Check whether or not a tree supports the features identified by flags.
440c8ec8eeaSjose borrego  */
441c8ec8eeaSjose borrego boolean_t
smb_tree_has_feature(smb_tree_t * tree,uint32_t flags)442c8ec8eeaSjose borrego smb_tree_has_feature(smb_tree_t *tree, uint32_t flags)
443c8ec8eeaSjose borrego {
444c8ec8eeaSjose borrego 	ASSERT(tree);
445c8ec8eeaSjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
446da6c28aaSamw 
447c8ec8eeaSjose borrego 	return ((tree->t_flags & flags) == flags);
448da6c28aaSamw }
449da6c28aaSamw 
4501fcced4cSJordan Brown /*
4511fcced4cSJordan Brown  * If the enumeration request is for tree data, handle the request
4521fcced4cSJordan Brown  * here.  Otherwise, pass it on to the ofiles.
4531fcced4cSJordan Brown  *
4541fcced4cSJordan Brown  * This function should be called with a hold on the tree.
4551fcced4cSJordan Brown  */
4561fcced4cSJordan Brown int
smb_tree_enum(smb_tree_t * tree,smb_svcenum_t * svcenum)4571fcced4cSJordan Brown smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum)
4581fcced4cSJordan Brown {
4592cf6b79fSGordon Ross 	smb_lavl_t	*lavl;
4601fcced4cSJordan Brown 	smb_ofile_t	*of;
4613b13a1efSThomas Keiser 	int		rc = 0;
4621fcced4cSJordan Brown 
4631fcced4cSJordan Brown 	if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE)
4641fcced4cSJordan Brown 		return (smb_tree_enum_private(tree, svcenum));
4651fcced4cSJordan Brown 
4662cf6b79fSGordon Ross 	lavl = &tree->t_ofile_list;
4672cf6b79fSGordon Ross 	smb_lavl_enter(lavl, RW_READER);
4681fcced4cSJordan Brown 
4692cf6b79fSGordon Ross 	of = smb_lavl_first(lavl);
4708d94f651SGordon Ross 	while (of) {
4718d94f651SGordon Ross 		if (smb_ofile_hold(of)) {
4728d94f651SGordon Ross 			rc = smb_ofile_enum(of, svcenum);
4731fcced4cSJordan Brown 			smb_ofile_release(of);
4741fcced4cSJordan Brown 		}
4758d94f651SGordon Ross 		if (rc != 0)
4768d94f651SGordon Ross 			break;
4772cf6b79fSGordon Ross 		of = smb_lavl_next(lavl, of);
4781fcced4cSJordan Brown 	}
4791fcced4cSJordan Brown 
4802cf6b79fSGordon Ross 	smb_lavl_exit(lavl);
4818d94f651SGordon Ross 
4821fcced4cSJordan Brown 	return (rc);
4831fcced4cSJordan Brown }
4841fcced4cSJordan Brown 
4851fcced4cSJordan Brown /*
4861fcced4cSJordan Brown  * Close a file by its unique id.
4871fcced4cSJordan Brown  */
4881fcced4cSJordan Brown int
smb_tree_fclose(smb_tree_t * tree,uint32_t uniqid)4891fcced4cSJordan Brown smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid)
4901fcced4cSJordan Brown {
4911fcced4cSJordan Brown 	smb_ofile_t	*of;
4921fcced4cSJordan Brown 
4931fcced4cSJordan Brown 	ASSERT(tree);
4941fcced4cSJordan Brown 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
4951fcced4cSJordan Brown 
496811599a4SMatt Barden 	/*
497811599a4SMatt Barden 	 * Note that ORPHANED ofiles aren't fclosable, as they have
498811599a4SMatt Barden 	 * no session, user, or tree by which they might be found.
499811599a4SMatt Barden 	 * They will eventually expire.
500811599a4SMatt Barden 	 */
5011fcced4cSJordan Brown 	if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL)
5021fcced4cSJordan Brown 		return (ENOENT);
5031fcced4cSJordan Brown 
5041fcced4cSJordan Brown 	if (smb_ofile_disallow_fclose(of)) {
5051fcced4cSJordan Brown 		smb_ofile_release(of);
5061fcced4cSJordan Brown 		return (EACCES);
5071fcced4cSJordan Brown 	}
5081fcced4cSJordan Brown 
5091fcced4cSJordan Brown 	smb_ofile_close(of, 0);
5101fcced4cSJordan Brown 	smb_ofile_release(of);
5111fcced4cSJordan Brown 	return (0);
5121fcced4cSJordan Brown }
513743a77edSAlan Wright 
514c8ec8eeaSjose borrego /* *************************** Static Functions ***************************** */
5151fcced4cSJordan Brown 
516743a77edSAlan Wright #define	SHARES_DIR	".zfs/shares/"
517148c5f43SAlan Wright 
518148c5f43SAlan Wright /*
519148c5f43SAlan Wright  * Calculates permissions given by the share's ACL to the
520148c5f43SAlan Wright  * user in the passed request.  The default is full access.
521148c5f43SAlan Wright  * If any error occurs, full access is granted.
522148c5f43SAlan Wright  *
523148c5f43SAlan Wright  * Using the vnode of the share path find the root directory
524148c5f43SAlan Wright  * of the mounted file system. Then look to see if there is a
525148c5f43SAlan Wright  * .zfs/shares directory and if there is, lookup the file with
526148c5f43SAlan Wright  * the same name as the share name in it. The ACL set for this
527148c5f43SAlan Wright  * file is the share's ACL which is used for access check here.
528148c5f43SAlan Wright  */
529148c5f43SAlan Wright static uint32_t
smb_tree_acl_access(smb_request_t * sr,const smb_kshare_t * si,vnode_t * pathvp)530148c5f43SAlan Wright smb_tree_acl_access(smb_request_t *sr, const smb_kshare_t *si, vnode_t *pathvp)
531743a77edSAlan Wright {
532fe1c642dSBill Krier 	smb_user_t	*user;
533fe1c642dSBill Krier 	cred_t		*cred;
534fe1c642dSBill Krier 	int		rc;
535fe1c642dSBill Krier 	vfs_t		*vfsp;
536fe1c642dSBill Krier 	vnode_t		*root = NULL;
537fe1c642dSBill Krier 	vnode_t		*sharevp = NULL;
538fe1c642dSBill Krier 	char		*sharepath;
539fe1c642dSBill Krier 	struct pathname	pnp;
540fe1c642dSBill Krier 	size_t		size;
541148c5f43SAlan Wright 	uint32_t	access;
542fe1c642dSBill Krier 
543fe1c642dSBill Krier 	user = sr->uid_user;
544fe1c642dSBill Krier 	cred = user->u_cred;
545148c5f43SAlan Wright 	access = ACE_ALL_PERMS;
546743a77edSAlan Wright 
547fe1c642dSBill Krier 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
548fe1c642dSBill Krier 		/*
549fe1c642dSBill Krier 		 * An autohome share owner gets full access to the share.
550fe1c642dSBill Krier 		 * Everyone else is denied access.
551fe1c642dSBill Krier 		 */
552c5866007SKeyur Desai 		if (si->shr_uid != crgetuid(cred))
553148c5f43SAlan Wright 			access = 0;
554148c5f43SAlan Wright 
555148c5f43SAlan Wright 		return (access);
556fe1c642dSBill Krier 	}
557fe1c642dSBill Krier 
558743a77edSAlan Wright 	/*
559148c5f43SAlan Wright 	 * The hold on 'root' is released by the lookuppnvp() that follows
560743a77edSAlan Wright 	 */
561743a77edSAlan Wright 	vfsp = pathvp->v_vfsp;
562743a77edSAlan Wright 	if (vfsp != NULL)
563743a77edSAlan Wright 		rc = VFS_ROOT(vfsp, &root);
564743a77edSAlan Wright 	else
565743a77edSAlan Wright 		rc = ENOENT;
566743a77edSAlan Wright 
567743a77edSAlan Wright 	if (rc != 0)
568148c5f43SAlan Wright 		return (access);
569743a77edSAlan Wright 
570743a77edSAlan Wright 
571fe1c642dSBill Krier 	size = sizeof (SHARES_DIR) + strlen(si->shr_name) + 1;
572148c5f43SAlan Wright 	sharepath = smb_srm_alloc(sr, size);
573b819cea2SGordon Ross 	(void) snprintf(sharepath, size, "%s%s", SHARES_DIR, si->shr_name);
574743a77edSAlan Wright 
575743a77edSAlan Wright 	pn_alloc(&pnp);
576743a77edSAlan Wright 	(void) pn_set(&pnp, sharepath);
577148c5f43SAlan Wright 	rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL, &sharevp, rootdir, root,
5788622ec45SGordon Ross 	    zone_kcred());
579743a77edSAlan Wright 	pn_free(&pnp);
580743a77edSAlan Wright 
581743a77edSAlan Wright 	/*
582148c5f43SAlan Wright 	 * Now get the effective access value based on cred and ACL values.
583743a77edSAlan Wright 	 */
584037cac00Sjoyce mcintosh 	if (rc == 0) {
585148c5f43SAlan Wright 		smb_vop_eaccess(sharevp, (int *)&access, V_ACE_MASK, NULL,
586148c5f43SAlan Wright 		    cred);
587037cac00Sjoyce mcintosh 		VN_RELE(sharevp);
588037cac00Sjoyce mcintosh 	}
589148c5f43SAlan Wright 
590148c5f43SAlan Wright 	return (access);
591743a77edSAlan Wright }
592c8ec8eeaSjose borrego 
593da6c28aaSamw /*
594148c5f43SAlan Wright  * Performs the following access checks for a disk share:
595148c5f43SAlan Wright  *
596148c5f43SAlan Wright  *  - No IPC/anonymous user is allowed
597148c5f43SAlan Wright  *
598148c5f43SAlan Wright  *  - If user is Guest, guestok property of the share should be
599148c5f43SAlan Wright  *    enabled
600148c5f43SAlan Wright  *
601148c5f43SAlan Wright  *  - If this is an Admin share, the user should have administrative
602148c5f43SAlan Wright  *    privileges
603148c5f43SAlan Wright  *
604148c5f43SAlan Wright  *  - Host based access control lists
605148c5f43SAlan Wright  *
606148c5f43SAlan Wright  *  - Share ACL
607148c5f43SAlan Wright  *
608148c5f43SAlan Wright  *  Returns the access allowed or 0 if access is denied.
609da6c28aaSamw  */
610148c5f43SAlan Wright static uint32_t
smb_tree_chkaccess(smb_request_t * sr,smb_kshare_t * shr,vnode_t * vp)611148c5f43SAlan Wright smb_tree_chkaccess(smb_request_t *sr, smb_kshare_t *shr, vnode_t *vp)
612148c5f43SAlan Wright {
613148c5f43SAlan Wright 	smb_user_t *user = sr->uid_user;
614148c5f43SAlan Wright 	char *sharename = shr->shr_name;
615148c5f43SAlan Wright 	uint32_t host_access;
616148c5f43SAlan Wright 	uint32_t acl_access;
617148c5f43SAlan Wright 	uint32_t access;
618743a77edSAlan Wright 
619a90cf9f2SGordon Ross 	if (user->u_flags & SMB_USER_FLAG_ANON) {
620148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: IPC only");
621148c5f43SAlan Wright 		return (0);
622148c5f43SAlan Wright 	}
623148c5f43SAlan Wright 
624148c5f43SAlan Wright 	if ((user->u_flags & SMB_USER_FLAG_GUEST) &&
625148c5f43SAlan Wright 	    ((shr->shr_flags & SMB_SHRF_GUEST_OK) == 0)) {
626148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: guest disabled");
627148c5f43SAlan Wright 		return (0);
628148c5f43SAlan Wright 	}
629148c5f43SAlan Wright 
630*97264293SGordon Ross 	if ((shr->shr_flags & SMB_SHRF_ADMIN) && !SMB_USER_IS_ADMIN(user)) {
631148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: not admin");
632148c5f43SAlan Wright 		return (0);
633148c5f43SAlan Wright 	}
634148c5f43SAlan Wright 
6358622ec45SGordon Ross 	host_access = smb_kshare_hostaccess(shr, sr->session);
636148c5f43SAlan Wright 	if ((host_access & ACE_ALL_PERMS) == 0) {
637148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: host access");
638148c5f43SAlan Wright 		return (0);
639148c5f43SAlan Wright 	}
640148c5f43SAlan Wright 
641*97264293SGordon Ross 	/*
642*97264293SGordon Ross 	 * This checks the "share" ACL, which is normally "open"
643*97264293SGordon Ross 	 */
644148c5f43SAlan Wright 	acl_access = smb_tree_acl_access(sr, shr, vp);
645148c5f43SAlan Wright 	if ((acl_access & ACE_ALL_PERMS) == 0) {
646148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied: share ACL");
647148c5f43SAlan Wright 		return (0);
648148c5f43SAlan Wright 	}
649148c5f43SAlan Wright 
650148c5f43SAlan Wright 	access = host_access & acl_access;
651148c5f43SAlan Wright 	if ((access & ACE_ALL_PERMS) == 0) {
652148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "access denied");
653148c5f43SAlan Wright 		return (0);
654148c5f43SAlan Wright 	}
655148c5f43SAlan Wright 
656148c5f43SAlan Wright 	return (access);
657148c5f43SAlan Wright }
658148c5f43SAlan Wright 
6598d94f651SGordon Ross /* How long should tree connect wait for DH import to complete? */
6608d94f651SGordon Ross int smb_tcon_import_wait = 20; /* sec. */
6618d94f651SGordon Ross 
662148c5f43SAlan Wright /*
663148c5f43SAlan Wright  * Connect a share for use with files and directories.
664148c5f43SAlan Wright  */
665a90cf9f2SGordon Ross uint32_t
smb_tree_connect_disk(smb_request_t * sr,smb_arg_tcon_t * tcon)666a90cf9f2SGordon Ross smb_tree_connect_disk(smb_request_t *sr, smb_arg_tcon_t *tcon)
667da6c28aaSamw {
668a90cf9f2SGordon Ross 	char			*sharename = tcon->path;
669148c5f43SAlan Wright 	const char		*any = "?????";
670c8ec8eeaSjose borrego 	smb_user_t		*user = sr->uid_user;
671c8ec8eeaSjose borrego 	smb_node_t		*snode = NULL;
672811599a4SMatt Barden 	smb_kshare_t		*si = tcon->si;
673a90cf9f2SGordon Ross 	char			*service = tcon->service;
674c8ec8eeaSjose borrego 	smb_tree_t		*tree;
675c8ec8eeaSjose borrego 	int			rc;
676148c5f43SAlan Wright 	uint32_t		access;
677148c5f43SAlan Wright 	smb_shr_execinfo_t	execinfo;
6788d94f651SGordon Ross 	clock_t	time;
679da6c28aaSamw 
680da6c28aaSamw 	ASSERT(user);
681148c5f43SAlan Wright 	ASSERT(user->u_cred);
682c8ec8eeaSjose borrego 
683a90cf9f2SGordon Ross 	if (service != NULL &&
684a90cf9f2SGordon Ross 	    strcmp(service, any) != 0 &&
685a90cf9f2SGordon Ross 	    strcasecmp(service, "A:") != 0) {
686148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "invalid service (%s)", service);
687a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_DEVICE_TYPE);
688c8ec8eeaSjose borrego 	}
689c8ec8eeaSjose borrego 
690148c5f43SAlan Wright 	/*
691148c5f43SAlan Wright 	 * Check that the shared directory exists.
692148c5f43SAlan Wright 	 */
6938d94f651SGordon Ross 	snode = si->shr_root_node;
6948d94f651SGordon Ross 	if (snode == NULL) {
695148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
696a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_NETWORK_NAME);
69729bd2886SAlan Wright 	}
69829bd2886SAlan Wright 
699148c5f43SAlan Wright 	if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
700a90cf9f2SGordon Ross 		return (NT_STATUS_ACCESS_DENIED);
701da6c28aaSamw 	}
702c8ec8eeaSjose borrego 
7038d94f651SGordon Ross 	/*
7048d94f651SGordon Ross 	 * Wait for DH import of persistent handles to finish.
7058d94f651SGordon Ross 	 * If we timeout, it's not clear what status to return,
7068d94f651SGordon Ross 	 * but as the share is not really available yet, let's
7078d94f651SGordon Ross 	 * return the status for "no such share".
7088d94f651SGordon Ross 	 */
7098d94f651SGordon Ross 	time = SEC_TO_TICK(smb_tcon_import_wait) + ddi_get_lbolt();
7108d94f651SGordon Ross 	mutex_enter(&si->shr_mutex);
7118d94f651SGordon Ross 	while (si->shr_import_busy != NULL) {
7128d94f651SGordon Ross 		if (cv_timedwait(&si->shr_cv, &si->shr_mutex, time) < 0) {
7138d94f651SGordon Ross 			mutex_exit(&si->shr_mutex);
7148d94f651SGordon Ross 			return (NT_STATUS_BAD_NETWORK_NAME);
7158d94f651SGordon Ross 		}
7168d94f651SGordon Ross 	}
7178d94f651SGordon Ross 	mutex_exit(&si->shr_mutex);
7188d94f651SGordon Ross 
7198d7e4166Sjose borrego 	/*
7208d7e4166Sjose borrego 	 * Set up the OptionalSupport for this share.
7218d7e4166Sjose borrego 	 */
722a90cf9f2SGordon Ross 	tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
7238d7e4166Sjose borrego 
7248d7e4166Sjose borrego 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
7258d7e4166Sjose borrego 	case SMB_SHRF_CSC_DISABLED:
726a90cf9f2SGordon Ross 		tcon->optional_support |= SMB_CSC_CACHE_NONE;
7278d7e4166Sjose borrego 		break;
7288d7e4166Sjose borrego 	case SMB_SHRF_CSC_AUTO:
729a90cf9f2SGordon Ross 		tcon->optional_support |= SMB_CSC_CACHE_AUTO_REINT;
7308d7e4166Sjose borrego 		break;
7318d7e4166Sjose borrego 	case SMB_SHRF_CSC_VDO:
732a90cf9f2SGordon Ross 		tcon->optional_support |= SMB_CSC_CACHE_VDO;
7338d7e4166Sjose borrego 		break;
7348d7e4166Sjose borrego 	case SMB_SHRF_CSC_MANUAL:
7358d7e4166Sjose borrego 	default:
7368d7e4166Sjose borrego 		/*
7378d7e4166Sjose borrego 		 * Default to SMB_CSC_CACHE_MANUAL_REINT.
7388d7e4166Sjose borrego 		 */
7398d7e4166Sjose borrego 		break;
7408d7e4166Sjose borrego 	}
7418d7e4166Sjose borrego 
742e3f2c991SKeyur Desai 	/* ABE support */
743e3f2c991SKeyur Desai 	if (si->shr_flags & SMB_SHRF_ABE)
744a90cf9f2SGordon Ross 		tcon->optional_support |=
745e3f2c991SKeyur Desai 		    SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
746e3f2c991SKeyur Desai 
7479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (si->shr_flags & SMB_SHRF_DFSROOT)
748a90cf9f2SGordon Ross 		tcon->optional_support |= SMB_SHARE_IS_IN_DFS;
7499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
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 
755814e0daaSGordon Ross 	if (tree->t_flags & SMB_TREE_SHORTNAMES)
756814e0daaSGordon Ross 		tcon->optional_support |= SMB_UNIQUE_FILE_NAME;
757814e0daaSGordon Ross 
758a90cf9f2SGordon Ross 	if (tree->t_execflags & SMB_EXEC_MAP) {
759a90cf9f2SGordon Ross 		smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_MAP);
760148c5f43SAlan Wright 
761a90cf9f2SGordon Ross 		rc = smb_kshare_exec(tree->t_server, &execinfo);
762148c5f43SAlan Wright 
763a90cf9f2SGordon Ross 		if ((rc != 0) && (tree->t_execflags & SMB_EXEC_TERM)) {
7648d94f651SGordon Ross 			/*
7658d94f651SGordon Ross 			 * Inline parts of: smb_tree_disconnect()
7668d94f651SGordon Ross 			 * Not using smb_tree_disconnect() for cleanup
7678d94f651SGordon Ross 			 * here because: we don't want an exec up-call,
7688d94f651SGordon Ross 			 * and there can't be any opens as we never
7698d94f651SGordon Ross 			 * returned this TID to the client.
7708d94f651SGordon Ross 			 */
7718d94f651SGordon Ross 			mutex_enter(&tree->t_mutex);
7728d94f651SGordon Ross 			tree->t_state = SMB_TREE_STATE_DISCONNECTING;
7738d94f651SGordon Ross 			mutex_exit(&tree->t_mutex);
7748d94f651SGordon Ross 
775a90cf9f2SGordon Ross 			smb_tree_release(tree);
776a90cf9f2SGordon Ross 			return (NT_STATUS_ACCESS_DENIED);
777148c5f43SAlan Wright 		}
778148c5f43SAlan Wright 	}
779148c5f43SAlan Wright 
780a90cf9f2SGordon Ross 	sr->tid_tree = tree;
781a90cf9f2SGordon Ross 	sr->smb_tid  = tree->t_tid;
782a90cf9f2SGordon Ross 
783a90cf9f2SGordon Ross 	return (0);
784148c5f43SAlan Wright }
785148c5f43SAlan Wright 
786148c5f43SAlan Wright /*
787148c5f43SAlan Wright  * Shares have both a share and host based access control.  The access
788148c5f43SAlan Wright  * granted will be minimum permissions based on both hostaccess
789148c5f43SAlan Wright  * (permissions allowed by host based access) and aclaccess (from the
790148c5f43SAlan Wright  * share ACL).
791148c5f43SAlan Wright  */
792a90cf9f2SGordon Ross uint32_t
smb_tree_connect_printq(smb_request_t * sr,smb_arg_tcon_t * tcon)793a90cf9f2SGordon Ross smb_tree_connect_printq(smb_request_t *sr, smb_arg_tcon_t *tcon)
794148c5f43SAlan Wright {
795a90cf9f2SGordon Ross 	char			*sharename = tcon->path;
796148c5f43SAlan Wright 	const char		*any = "?????";
797148c5f43SAlan Wright 	smb_user_t		*user = sr->uid_user;
798148c5f43SAlan Wright 	smb_node_t		*dnode = NULL;
799148c5f43SAlan Wright 	smb_node_t		*snode = NULL;
800811599a4SMatt Barden 	smb_kshare_t		*si = tcon->si;
801a90cf9f2SGordon Ross 	char			*service = tcon->service;
802148c5f43SAlan Wright 	char			last_component[MAXNAMELEN];
803148c5f43SAlan Wright 	smb_tree_t		*tree;
804148c5f43SAlan Wright 	int			rc;
805148c5f43SAlan Wright 	uint32_t		access;
806148c5f43SAlan Wright 
807148c5f43SAlan Wright 	ASSERT(user);
808148c5f43SAlan Wright 	ASSERT(user->u_cred);
809148c5f43SAlan Wright 
810b7301bf5SGordon Ross 	if (sr->sr_server->sv_cfg.skc_print_enable == 0) {
811b7301bf5SGordon Ross 		smb_tree_log(sr, sharename, "printing disabled");
812a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_NETWORK_NAME);
813b7301bf5SGordon Ross 	}
814b7301bf5SGordon Ross 
815a90cf9f2SGordon Ross 	if (service != NULL &&
816a90cf9f2SGordon Ross 	    strcmp(service, any) != 0 &&
817a90cf9f2SGordon Ross 	    strcasecmp(service, "LPT1:") != 0) {
818148c5f43SAlan Wright 		smb_tree_log(sr, sharename, "invalid service (%s)", service);
819a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_DEVICE_TYPE);
820b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
821b89a8333Snatalie li - Sun Microsystems - Irvine United States 
822c8ec8eeaSjose borrego 	/*
823c8ec8eeaSjose borrego 	 * Check that the shared directory exists.
824c8ec8eeaSjose borrego 	 */
825148c5f43SAlan Wright 	rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
826c8ec8eeaSjose borrego 	    last_component);
827c8ec8eeaSjose borrego 	if (rc == 0) {
828148c5f43SAlan Wright 		rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
8291fcced4cSJordan Brown 		    sr->sr_server->si_root_smb_node, dnode, last_component,
830037cac00Sjoyce mcintosh 		    &snode);
831c8ec8eeaSjose borrego 
8321fcced4cSJordan Brown 		smb_node_release(dnode);
833c8ec8eeaSjose borrego 	}
834c8ec8eeaSjose borrego 
835c8ec8eeaSjose borrego 	if (rc) {
836c8ec8eeaSjose borrego 		if (snode)
837c8ec8eeaSjose borrego 			smb_node_release(snode);
838c8ec8eeaSjose borrego 
839b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
840a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_NETWORK_NAME);
841c8ec8eeaSjose borrego 	}
842c8ec8eeaSjose borrego 
843148c5f43SAlan Wright 	if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
844037cac00Sjoyce mcintosh 		smb_node_release(snode);
845a90cf9f2SGordon Ross 		return (NT_STATUS_ACCESS_DENIED);
846743a77edSAlan Wright 	}
847743a77edSAlan Wright 
848a90cf9f2SGordon Ross 	tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
8492c2961f8Sjose borrego 
8503b13a1efSThomas Keiser 	tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
851b89a8333Snatalie li - Sun Microsystems - Irvine United States 
85229bd2886SAlan Wright 	smb_node_release(snode);
85329bd2886SAlan Wright 
854c8ec8eeaSjose borrego 	if (tree == NULL)
855a90cf9f2SGordon Ross 		return (NT_STATUS_INSUFF_SERVER_RESOURCES);
85629bd2886SAlan Wright 
857a90cf9f2SGordon Ross 	sr->tid_tree = tree;
858a90cf9f2SGordon Ross 	sr->smb_tid  = tree->t_tid;
859a90cf9f2SGordon Ross 
860a90cf9f2SGordon Ross 	return (0);
861da6c28aaSamw }
862da6c28aaSamw 
863da6c28aaSamw /*
864c8ec8eeaSjose borrego  * Connect an IPC share for use with named pipes.
865da6c28aaSamw  */
866a90cf9f2SGordon Ross uint32_t
smb_tree_connect_ipc(smb_request_t * sr,smb_arg_tcon_t * tcon)867a90cf9f2SGordon Ross smb_tree_connect_ipc(smb_request_t *sr, smb_arg_tcon_t *tcon)
868da6c28aaSamw {
869a90cf9f2SGordon Ross 	char		*name = tcon->path;
870148c5f43SAlan Wright 	const char	*any = "?????";
8718b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_user_t	*user = sr->uid_user;
8728b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_tree_t	*tree;
873a90cf9f2SGordon Ross 	smb_kshare_t	*si = tcon->si;
874a90cf9f2SGordon Ross 	char		*service = tcon->service;
875da6c28aaSamw 
876c8ec8eeaSjose borrego 	ASSERT(user);
877da6c28aaSamw 
878a90cf9f2SGordon Ross 	if (service != NULL &&
879a90cf9f2SGordon Ross 	    strcmp(service, any) != 0 &&
880a90cf9f2SGordon Ross 	    strcasecmp(service, "IPC") != 0) {
881a90cf9f2SGordon Ross 		smb_tree_log(sr, name, "invalid service (%s)", service);
882a90cf9f2SGordon Ross 		return (NT_STATUS_BAD_DEVICE_TYPE);
883da6c28aaSamw 	}
884da6c28aaSamw 
885a90cf9f2SGordon Ross 	if ((user->u_flags & SMB_USER_FLAG_ANON) &&
886a90cf9f2SGordon Ross 	    sr->sr_cfg->skc_restrict_anon) {
887a90cf9f2SGordon Ross 		smb_tree_log(sr, name, "access denied: restrict anonymous");
888a90cf9f2SGordon Ross 		return (NT_STATUS_ACCESS_DENIED);
889148c5f43SAlan Wright 	}
8908d7e4166Sjose borrego 
891a90cf9f2SGordon Ross 	tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
8928b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
8933b13a1efSThomas Keiser 	tree = smb_tree_alloc(sr, si, NULL, ACE_ALL_PERMS, 0);
894a90cf9f2SGordon Ross 	if (tree == NULL)
895a90cf9f2SGordon Ross 		return (NT_STATUS_INSUFF_SERVER_RESOURCES);
896c8ec8eeaSjose borrego 
897a90cf9f2SGordon Ross 	sr->tid_tree = tree;
898a90cf9f2SGordon Ross 	sr->smb_tid  = tree->t_tid;
899a90cf9f2SGordon Ross 
900a90cf9f2SGordon Ross 	return (0);
901da6c28aaSamw }
902da6c28aaSamw 
903da6c28aaSamw /*
904c8ec8eeaSjose borrego  * Allocate a tree.
905da6c28aaSamw  */
9068d94f651SGordon Ross smb_tree_t *
smb_tree_alloc(smb_request_t * sr,const smb_kshare_t * si,smb_node_t * snode,uint32_t access,uint32_t execflags)9073b13a1efSThomas Keiser smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si,
9083b13a1efSThomas Keiser     smb_node_t *snode, uint32_t access, uint32_t execflags)
909da6c28aaSamw {
9103b13a1efSThomas Keiser 	smb_session_t	*session = sr->session;
911c8ec8eeaSjose borrego 	smb_tree_t	*tree;
912148c5f43SAlan Wright 	uint32_t	stype = si->shr_type;
913c8ec8eeaSjose borrego 	uint16_t	tid;
914da6c28aaSamw 
9153b13a1efSThomas Keiser 	if (smb_idpool_alloc(&session->s_tid_pool, &tid))
916c8ec8eeaSjose borrego 		return (NULL);
917da6c28aaSamw 
9188622ec45SGordon Ross 	tree = kmem_cache_alloc(smb_cache_tree, KM_SLEEP);
919c8ec8eeaSjose borrego 	bzero(tree, sizeof (smb_tree_t));
920da6c28aaSamw 
9213b13a1efSThomas Keiser 	tree->t_session = session;
9223b13a1efSThomas Keiser 	tree->t_server = session->s_server;
9233b13a1efSThomas Keiser 
924148c5f43SAlan Wright 	if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
9258b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (smb_tree_getattr(si, snode, tree) != 0) {
9263b13a1efSThomas Keiser 			smb_idpool_free(&session->s_tid_pool, tid);
9278622ec45SGordon Ross 			kmem_cache_free(smb_cache_tree, tree);
928c8ec8eeaSjose borrego 			return (NULL);
929da6c28aaSamw 		}
930da6c28aaSamw 	}
931c8ec8eeaSjose borrego 
932c8ec8eeaSjose borrego 	if (smb_idpool_constructor(&tree->t_fid_pool)) {
9333b13a1efSThomas Keiser 		smb_idpool_free(&session->s_tid_pool, tid);
9348622ec45SGordon Ross 		kmem_cache_free(smb_cache_tree, tree);
935c8ec8eeaSjose borrego 		return (NULL);
936c8ec8eeaSjose borrego 	}
937c8ec8eeaSjose borrego 
9387f667e74Sjose borrego 	if (smb_idpool_constructor(&tree->t_odid_pool)) {
939c8ec8eeaSjose borrego 		smb_idpool_destructor(&tree->t_fid_pool);
9403b13a1efSThomas Keiser 		smb_idpool_free(&session->s_tid_pool, tid);
9418622ec45SGordon Ross 		kmem_cache_free(smb_cache_tree, tree);
942c8ec8eeaSjose borrego 		return (NULL);
943c8ec8eeaSjose borrego 	}
944c8ec8eeaSjose borrego 
9452cf6b79fSGordon Ross 	smb_lavl_constructor(&tree->t_ofile_list,
9462cf6b79fSGordon Ross 	    smb_ofile_avl_compare,  sizeof (smb_ofile_t),
947811599a4SMatt Barden 	    offsetof(smb_ofile_t, f_tree_lnd));
948c8ec8eeaSjose borrego 
949c8ec8eeaSjose borrego 	smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
950c8ec8eeaSjose borrego 	    offsetof(smb_odir_t, d_lnd));
951c8ec8eeaSjose borrego 
9528b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	(void) strlcpy(tree->t_sharename, si->shr_name,
953c8ec8eeaSjose borrego 	    sizeof (tree->t_sharename));
9548b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	(void) strlcpy(tree->t_resource, si->shr_path,
9558b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	    sizeof (tree->t_resource));
956c8ec8eeaSjose borrego 
957c8ec8eeaSjose borrego 	mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
958c8ec8eeaSjose borrego 
959c8ec8eeaSjose borrego 	tree->t_refcnt = 1;
960c8ec8eeaSjose borrego 	tree->t_tid = tid;
961c8ec8eeaSjose borrego 	tree->t_res_type = stype;
962c8ec8eeaSjose borrego 	tree->t_state = SMB_TREE_STATE_CONNECTED;
963c8ec8eeaSjose borrego 	tree->t_magic = SMB_TREE_MAGIC;
964743a77edSAlan Wright 	tree->t_access = access;
9651fcced4cSJordan Brown 	tree->t_connect_time = gethrestime_sec();
966148c5f43SAlan Wright 	tree->t_execflags = execflags;
967743a77edSAlan Wright 
968af536d7dSGordon Ross 	/* grab a ref for tree->t_owner */
969af536d7dSGordon Ross 	smb_user_hold_internal(sr->uid_user);
9701baeef30SPrashanth Badari 	smb_user_inc_trees(sr->uid_user);
971af536d7dSGordon Ross 	tree->t_owner = sr->uid_user;
972af536d7dSGordon Ross 
973743a77edSAlan Wright 	/* if FS is readonly, enforce that here */
974743a77edSAlan Wright 	if (tree->t_flags & SMB_TREE_READONLY)
975743a77edSAlan Wright 		tree->t_access &= ~ACE_ALL_WRITE_PERMS;
976c8ec8eeaSjose borrego 
977148c5f43SAlan Wright 	if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
978c8ec8eeaSjose borrego 		smb_node_ref(snode);
979c8ec8eeaSjose borrego 		tree->t_snode = snode;
980c8ec8eeaSjose borrego 		tree->t_acltype = smb_fsop_acltype(snode);
981c8ec8eeaSjose borrego 	}
982c8ec8eeaSjose borrego 
9833b13a1efSThomas Keiser 	smb_llist_enter(&session->s_tree_list, RW_WRITER);
9843b13a1efSThomas Keiser 	smb_llist_insert_head(&session->s_tree_list, tree);
9853b13a1efSThomas Keiser 	smb_llist_exit(&session->s_tree_list);
9863b13a1efSThomas Keiser 	atomic_inc_32(&session->s_tree_cnt);
9873b13a1efSThomas Keiser 	smb_server_inc_trees(session->s_server);
988c8ec8eeaSjose borrego 	return (tree);
989c8ec8eeaSjose borrego }
990da6c28aaSamw 
991da6c28aaSamw /*
9929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Deallocate a tree.  The open file and open directory lists should be
9939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * empty.
994c8ec8eeaSjose borrego  *
9959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Remove the tree from the user's tree list before freeing resources
9969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * associated with the tree.
997da6c28aaSamw  */
998811599a4SMatt Barden static void
smb_tree_dealloc(void * arg)9999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_tree_dealloc(void *arg)
1000da6c28aaSamw {
10013b13a1efSThomas Keiser 	smb_session_t	*session;
10029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_tree_t	*tree = (smb_tree_t *)arg;
10039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
10049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_TREE_VALID(tree);
1005da6c28aaSamw 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
1006da6c28aaSamw 	ASSERT(tree->t_refcnt == 0);
1007da6c28aaSamw 
10088d94f651SGordon Ross 	smb_server_dec_trees(tree->t_server);
10098d94f651SGordon Ross 
10103b13a1efSThomas Keiser 	session = tree->t_session;
10113b13a1efSThomas Keiser 	smb_llist_enter(&session->s_tree_list, RW_WRITER);
10123b13a1efSThomas Keiser 	smb_llist_remove(&session->s_tree_list, tree);
10133b13a1efSThomas Keiser 	smb_idpool_free(&session->s_tid_pool, tree->t_tid);
10143b13a1efSThomas Keiser 	atomic_dec_32(&session->s_tree_cnt);
10153b13a1efSThomas Keiser 	smb_llist_exit(&session->s_tree_list);
10169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1017811599a4SMatt Barden 	/*
1018811599a4SMatt Barden 	 * This tree is no longer on s_tree_list, however...
1019811599a4SMatt Barden 	 *
1020811599a4SMatt Barden 	 * This is called via smb_llist_post, which means it may run
1021811599a4SMatt Barden 	 * BEFORE smb_tree_release drops t_mutex (if another thread
1022811599a4SMatt Barden 	 * flushes the delete queue before we do).  Synchronize.
1023811599a4SMatt Barden 	 */
10249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_enter(&tree->t_mutex);
10259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_exit(&tree->t_mutex);
1026da6c28aaSamw 
1027da6c28aaSamw 	tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
1028da6c28aaSamw 
1029c8ec8eeaSjose borrego 	if (tree->t_snode)
1030da6c28aaSamw 		smb_node_release(tree->t_snode);
1031c8ec8eeaSjose borrego 
1032da6c28aaSamw 	mutex_destroy(&tree->t_mutex);
10332cf6b79fSGordon Ross 	smb_lavl_destructor(&tree->t_ofile_list);
1034da6c28aaSamw 	smb_llist_destructor(&tree->t_odir_list);
1035da6c28aaSamw 	smb_idpool_destructor(&tree->t_fid_pool);
10367f667e74Sjose borrego 	smb_idpool_destructor(&tree->t_odid_pool);
10373b13a1efSThomas Keiser 
10383b13a1efSThomas Keiser 	SMB_USER_VALID(tree->t_owner);
10391baeef30SPrashanth Badari 	smb_user_dec_trees(tree->t_owner);
10403b13a1efSThomas Keiser 	smb_user_release(tree->t_owner);
10413b13a1efSThomas Keiser 
10428622ec45SGordon Ross 	kmem_cache_free(smb_cache_tree, tree);
1043da6c28aaSamw }
1044da6c28aaSamw 
1045da6c28aaSamw /*
1046c8ec8eeaSjose borrego  * Determine whether or not a tree is connected.
1047c8ec8eeaSjose borrego  * This function must be called with the tree mutex held.
1048c8ec8eeaSjose borrego  */
1049c8ec8eeaSjose borrego static boolean_t
smb_tree_is_connected_locked(smb_tree_t * tree)10508b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tree_is_connected_locked(smb_tree_t *tree)
1051c8ec8eeaSjose borrego {
1052c8ec8eeaSjose borrego 	switch (tree->t_state) {
1053c8ec8eeaSjose borrego 	case SMB_TREE_STATE_CONNECTED:
1054c8ec8eeaSjose borrego 		return (B_TRUE);
1055c8ec8eeaSjose borrego 
1056c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTING:
1057c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTED:
1058c8ec8eeaSjose borrego 		/*
1059811599a4SMatt Barden 		 * The tree exists but is being disconnected or destroyed.
1060c8ec8eeaSjose borrego 		 */
1061c8ec8eeaSjose borrego 		return (B_FALSE);
1062c8ec8eeaSjose borrego 
1063c8ec8eeaSjose borrego 	default:
1064c8ec8eeaSjose borrego 		ASSERT(0);
1065c8ec8eeaSjose borrego 		return (B_FALSE);
1066c8ec8eeaSjose borrego 	}
1067c8ec8eeaSjose borrego }
1068c8ec8eeaSjose borrego 
1069c8ec8eeaSjose borrego /*
1070c8ec8eeaSjose borrego  * Return a pointer to the share name within a share resource path.
1071da6c28aaSamw  *
1072c8ec8eeaSjose borrego  * The share path may be a Uniform Naming Convention (UNC) string
1073c8ec8eeaSjose borrego  * (\\server\share) or simply the share name.  We validate the UNC
1074c8ec8eeaSjose borrego  * format but we don't look at the server name.
1075c8ec8eeaSjose borrego  */
1076a90cf9f2SGordon Ross static char *
smb_tree_get_sharename(char * unc_path)1077a90cf9f2SGordon Ross smb_tree_get_sharename(char *unc_path)
1078c8ec8eeaSjose borrego {
1079a90cf9f2SGordon Ross 	char *sharename = unc_path;
1080c8ec8eeaSjose borrego 
1081c8ec8eeaSjose borrego 	if (sharename[0] == '\\') {
1082c8ec8eeaSjose borrego 		/*
1083c8ec8eeaSjose borrego 		 * Looks like a UNC path, validate the format.
1084c8ec8eeaSjose borrego 		 */
1085c8ec8eeaSjose borrego 		if (sharename[1] != '\\')
1086c8ec8eeaSjose borrego 			return (NULL);
1087c8ec8eeaSjose borrego 
1088c8ec8eeaSjose borrego 		if ((sharename = strchr(sharename+2, '\\')) == NULL)
1089c8ec8eeaSjose borrego 			return (NULL);
1090c8ec8eeaSjose borrego 
1091c8ec8eeaSjose borrego 		++sharename;
1092c8ec8eeaSjose borrego 	} else if (strchr(sharename, '\\') != NULL) {
1093c8ec8eeaSjose borrego 		/*
1094c8ec8eeaSjose borrego 		 * This should be a share name (no embedded \'s).
1095c8ec8eeaSjose borrego 		 */
1096c8ec8eeaSjose borrego 		return (NULL);
1097c8ec8eeaSjose borrego 	}
1098c8ec8eeaSjose borrego 
1099c8ec8eeaSjose borrego 	return (sharename);
1100c8ec8eeaSjose borrego }
1101c8ec8eeaSjose borrego 
1102da6c28aaSamw /*
1103c8ec8eeaSjose borrego  * Obtain the tree attributes: volume name, typename and flags.
1104814e0daaSGordon Ross  * Called only with DISK and PRINTQ shares.
1105c8ec8eeaSjose borrego  */
1106c8ec8eeaSjose borrego static int
smb_tree_getattr(const smb_kshare_t * si,smb_node_t * node,smb_tree_t * tree)1107148c5f43SAlan Wright smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree)
1108c8ec8eeaSjose borrego {
1109c8ec8eeaSjose borrego 	vfs_t *vfsp = SMB_NODE_VFS(node);
1110af536d7dSGordon Ross 	vfs_t *realvfsp;
1111c8ec8eeaSjose borrego 
1112c8ec8eeaSjose borrego 	ASSERT(vfsp);
1113c8ec8eeaSjose borrego 
111425a9a7aaSGordon Ross 	smb_tree_get_creation(node, tree);
1115c8ec8eeaSjose borrego 	smb_tree_get_volname(vfsp, tree);
1116af536d7dSGordon Ross 
1117af536d7dSGordon Ross 	/*
1118af536d7dSGordon Ross 	 * In the case of an lofs mount, we need to ask the (real)
1119af536d7dSGordon Ross 	 * underlying filesystem about capabilities, where the
1120af536d7dSGordon Ross 	 * passed in vfs_t will be from lofs.
1121af536d7dSGordon Ross 	 */
1122af536d7dSGordon Ross 	realvfsp = getvfs(&vfsp->vfs_fsid);
1123af536d7dSGordon Ross 	if (realvfsp != NULL) {
1124af536d7dSGordon Ross 		smb_tree_get_flags(si, realvfsp, tree);
1125af536d7dSGordon Ross 		VFS_RELE(realvfsp);
1126af536d7dSGordon Ross 	} else {
1127af536d7dSGordon Ross 		cmn_err(CE_NOTE, "Failed getting info for share: %s",
1128af536d7dSGordon Ross 		    si->shr_name);
1129af536d7dSGordon Ross 		/* do the best we can without realvfsp */
1130af536d7dSGordon Ross 		smb_tree_get_flags(si, vfsp, tree);
1131af536d7dSGordon Ross 	}
1132c8ec8eeaSjose borrego 
1133ab017dbaSGordon Ross 	if (tree->t_session->dialect >= SMB_VERS_3_0)
1134ab017dbaSGordon Ross 		tree->t_encrypt = si->shr_encrypt;
1135ab017dbaSGordon Ross 	else
11361160dcf7SMatt Barden 		tree->t_encrypt = SMB_CONFIG_DISABLED;
11371160dcf7SMatt Barden 
1138c8ec8eeaSjose borrego 	return (0);
1139c8ec8eeaSjose borrego }
1140c8ec8eeaSjose borrego 
114125a9a7aaSGordon Ross /*
114225a9a7aaSGordon Ross  * File volume creation time
114325a9a7aaSGordon Ross  */
114425a9a7aaSGordon Ross static void
smb_tree_get_creation(smb_node_t * node,smb_tree_t * tree)114525a9a7aaSGordon Ross smb_tree_get_creation(smb_node_t *node, smb_tree_t *tree)
114625a9a7aaSGordon Ross {
114725a9a7aaSGordon Ross 	smb_attr_t	attr;
114825a9a7aaSGordon Ross 	cred_t		*kcr = zone_kcred();
114925a9a7aaSGordon Ross 
115025a9a7aaSGordon Ross 	bzero(&attr, sizeof (attr));
115125a9a7aaSGordon Ross 	attr.sa_mask = SMB_AT_CRTIME;
115225a9a7aaSGordon Ross 	(void) smb_node_getattr(NULL, node, kcr, NULL, &attr);
115325a9a7aaSGordon Ross 	/* On failure we'll have time zero, which is OK */
115425a9a7aaSGordon Ross 
115525a9a7aaSGordon Ross 	tree->t_create_time = attr.sa_crtime;
115625a9a7aaSGordon Ross }
115725a9a7aaSGordon Ross 
1158c8ec8eeaSjose borrego /*
1159c8ec8eeaSjose borrego  * Extract the volume name.
1160c8ec8eeaSjose borrego  */
1161c8ec8eeaSjose borrego static void
smb_tree_get_volname(vfs_t * vfsp,smb_tree_t * tree)1162c8ec8eeaSjose borrego smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
1163c8ec8eeaSjose borrego {
1164a90cf9f2SGordon Ross #ifdef	_FAKE_KERNEL
1165a90cf9f2SGordon Ross 	_NOTE(ARGUNUSED(vfsp))
1166a90cf9f2SGordon Ross 	(void) strlcpy(tree->t_volume, "fake", SMB_VOLNAMELEN);
1167a90cf9f2SGordon Ross #else	/* _FAKE_KERNEL */
1168c8ec8eeaSjose borrego 	refstr_t *vfs_mntpoint;
1169c8ec8eeaSjose borrego 	const char *s;
1170c8ec8eeaSjose borrego 	char *name;
1171c8ec8eeaSjose borrego 
1172c8ec8eeaSjose borrego 	vfs_mntpoint = vfs_getmntpoint(vfsp);
1173c8ec8eeaSjose borrego 
1174b819cea2SGordon Ross 	s = refstr_value(vfs_mntpoint);
1175c8ec8eeaSjose borrego 	s += strspn(s, "/");
1176c8ec8eeaSjose borrego 	(void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
1177c8ec8eeaSjose borrego 
1178c8ec8eeaSjose borrego 	refstr_rele(vfs_mntpoint);
1179c8ec8eeaSjose borrego 
1180c8ec8eeaSjose borrego 	name = tree->t_volume;
1181c8ec8eeaSjose borrego 	(void) strsep((char **)&name, "/");
1182a90cf9f2SGordon Ross #endif	/* _FAKE_KERNEL */
1183c8ec8eeaSjose borrego }
1184c8ec8eeaSjose borrego 
1185c8ec8eeaSjose borrego /*
1186814e0daaSGordon Ross  * Get flags from the VFS (and other places) for a new tree.
1187814e0daaSGordon Ross  * Called only with DISK and PRINTQ shares.
1188814e0daaSGordon Ross  *
1189a90cf9f2SGordon Ross  * Always set "unicode on disk" because we always use utf8 names locally.
1190c8ec8eeaSjose borrego  * Always set ACL support because the VFS will fake ACLs for file systems
1191c8ec8eeaSjose borrego  * that don't support them.
1192da6c28aaSamw  *
1193c8ec8eeaSjose borrego  * Some flags are dependent on the typename, which is also set up here.
1194c8ec8eeaSjose borrego  * File system types are hardcoded in uts/common/os/vfs_conf.c.
1195da6c28aaSamw  */
1196c8ec8eeaSjose borrego static void
smb_tree_get_flags(const smb_kshare_t * si,vfs_t * vfsp,smb_tree_t * tree)1197148c5f43SAlan Wright smb_tree_get_flags(const smb_kshare_t *si, vfs_t *vfsp, smb_tree_t *tree)
1198da6c28aaSamw {
11995f1ef25cSAram Hăvărneanu 	smb_session_t *ssn = tree->t_session;
1200b819cea2SGordon Ross 	struct vfssw	*vswp;
12015f1ef25cSAram Hăvărneanu 
1202fc724630SAlan Wright 	typedef struct smb_mtype {
1203fc724630SAlan Wright 		char		*mt_name;
1204fc724630SAlan Wright 		size_t		mt_namelen;
1205fc724630SAlan Wright 		uint32_t	mt_flags;
1206fc724630SAlan Wright 	} smb_mtype_t;
1207fc724630SAlan Wright 
1208fc724630SAlan Wright 	static smb_mtype_t smb_mtype[] = {
120955f0a249SGordon Ross #ifdef	_FAKE_KERNEL
121055f0a249SGordon Ross 		/* See libfksmbsrv:fake_vfs.c */
121155f0a249SGordon Ross 		{ "fake",    3,	SMB_TREE_SPARSE},
121255f0a249SGordon Ross #endif	/* _FAKE_KERNEL */
1213a90cf9f2SGordon Ross 		{ "zfs",    3,	SMB_TREE_QUOTA | SMB_TREE_SPARSE},
1214a90cf9f2SGordon Ross 		{ "ufs",    3,	0 },
12159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		{ "nfs",    3,	SMB_TREE_NFS_MOUNTED },
12169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		{ "tmpfs",  5,	SMB_TREE_NO_EXPORT }
1217fc724630SAlan Wright 	};
1218fc724630SAlan Wright 	smb_mtype_t	*mtype;
1219fc724630SAlan Wright 	char		*name;
1220a90cf9f2SGordon Ross 	uint32_t	flags =
1221a90cf9f2SGordon Ross 	    SMB_TREE_SUPPORTS_ACLS |
1222a90cf9f2SGordon Ross 	    SMB_TREE_UNICODE_ON_DISK;
1223fc724630SAlan Wright 	int		i;
1224da6c28aaSamw 
12259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (si->shr_flags & SMB_SHRF_DFSROOT)
12269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_TREE_DFSROOT;
12279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12288b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (si->shr_flags & SMB_SHRF_CATIA)
12298b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_TREE_CATIA;
12308b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
1231e3f2c991SKeyur Desai 	if (si->shr_flags & SMB_SHRF_ABE)
1232e3f2c991SKeyur Desai 		flags |= SMB_TREE_ABE;
1233e3f2c991SKeyur Desai 
12348d94f651SGordon Ross 	if (si->shr_flags & SMB_SHRF_CA)
12358d94f651SGordon Ross 		flags |= SMB_TREE_CA;
12368d94f651SGordon Ross 
123794047d49SGordon Ross 	if (si->shr_flags & SMB_SHRF_FSO)
123894047d49SGordon Ross 		flags |= SMB_TREE_FORCE_L2_OPLOCK;
123994047d49SGordon Ross 
1240814e0daaSGordon Ross 	if (ssn->s_cfg.skc_oplock_enable)
1241cb174861Sjoyce mcintosh 		flags |= SMB_TREE_OPLOCKS;
1242cb174861Sjoyce mcintosh 
12435f1ef25cSAram Hăvărneanu 	if (ssn->s_cfg.skc_traverse_mounts)
12445f1ef25cSAram Hăvărneanu 		flags |= SMB_TREE_TRAVERSE_MOUNTS;
12455f1ef25cSAram Hăvărneanu 
1246814e0daaSGordon Ross 	if (ssn->s_cfg.skc_short_names)
1247cb174861Sjoyce mcintosh 		flags |= SMB_TREE_SHORTNAMES;
1248cb174861Sjoyce mcintosh 
1249c8ec8eeaSjose borrego 	if (vfsp->vfs_flag & VFS_RDONLY)
1250c8ec8eeaSjose borrego 		flags |= SMB_TREE_READONLY;
1251c8ec8eeaSjose borrego 
1252c8ec8eeaSjose borrego 	if (vfsp->vfs_flag & VFS_XATTR)
1253c8ec8eeaSjose borrego 		flags |= SMB_TREE_STREAMS;
1254c8ec8eeaSjose borrego 
1255b819cea2SGordon Ross 	vswp = vfs_getvfsswbyvfsops(vfs_getops(vfsp));
1256b819cea2SGordon Ross 	if (vswp != NULL) {
1257b819cea2SGordon Ross 		name = vswp->vsw_name;
1258b819cea2SGordon Ross 		vfs_unrefvfssw(vswp);
1259b819cea2SGordon Ross 	} else {
1260b819cea2SGordon Ross 		name = "?";
1261b819cea2SGordon Ross 	}
1262c8ec8eeaSjose borrego 
1263fc724630SAlan Wright 	for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
1264fc724630SAlan Wright 		mtype = &smb_mtype[i];
1265fc724630SAlan Wright 		if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
1266fc724630SAlan Wright 			flags |= mtype->mt_flags;
1267fc724630SAlan Wright 	}
1268c8ec8eeaSjose borrego 
1269ca5fb90aSGordon Ross 	/*
1270ca5fb90aSGordon Ross 	 * SMB_TREE_QUOTA will be on here if the FS is ZFS.  We want to
1271ca5fb90aSGordon Ross 	 * turn it OFF when the share property says false.
1272ca5fb90aSGordon Ross 	 */
1273ca5fb90aSGordon Ross 	if ((si->shr_flags & SMB_SHRF_QUOTAS) == 0)
1274ca5fb90aSGordon Ross 		flags &= ~SMB_TREE_QUOTA;
1275ca5fb90aSGordon Ross 
1276c8ec8eeaSjose borrego 	(void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
1277bbf6f00cSJordan Brown 	(void) smb_strupr((char *)tree->t_typename);
1278da6c28aaSamw 
1279c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_XVATTR))
1280c8ec8eeaSjose borrego 		flags |= SMB_TREE_XVATTR;
1281c8ec8eeaSjose borrego 
1282c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
1283c8ec8eeaSjose borrego 		flags |= SMB_TREE_CASEINSENSITIVE;
1284c8ec8eeaSjose borrego 
1285c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
1286c8ec8eeaSjose borrego 		flags |= SMB_TREE_NO_CASESENSITIVE;
1287c8ec8eeaSjose borrego 
1288c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
1289c8ec8eeaSjose borrego 		flags |= SMB_TREE_DIRENTFLAGS;
1290c8ec8eeaSjose borrego 
1291c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
1292c8ec8eeaSjose borrego 		flags |= SMB_TREE_ACLONCREATE;
1293c8ec8eeaSjose borrego 
1294c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
1295c8ec8eeaSjose borrego 		flags |= SMB_TREE_ACEMASKONACCESS;
1296c8ec8eeaSjose borrego 
1297fc724630SAlan Wright 	DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);
1298fc724630SAlan Wright 
1299c8ec8eeaSjose borrego 
1300c8ec8eeaSjose borrego 	tree->t_flags = flags;
1301c8ec8eeaSjose borrego }
1302c8ec8eeaSjose borrego 
1303c8ec8eeaSjose borrego /*
1304c8ec8eeaSjose borrego  * Report share access result to syslog.
1305c8ec8eeaSjose borrego  */
1306c8ec8eeaSjose borrego static void
smb_tree_log(smb_request_t * sr,const char * sharename,const char * fmt,...)1307c8ec8eeaSjose borrego smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
1308c8ec8eeaSjose borrego {
1309c8ec8eeaSjose borrego 	va_list ap;
1310c8ec8eeaSjose borrego 	char buf[128];
1311c8ec8eeaSjose borrego 	smb_user_t *user = sr->uid_user;
1312c8ec8eeaSjose borrego 
1313c8ec8eeaSjose borrego 	ASSERT(user);
1314c8ec8eeaSjose borrego 
1315c8ec8eeaSjose borrego 	if (smb_tcon_mute)
1316c8ec8eeaSjose borrego 		return;
1317c8ec8eeaSjose borrego 
1318c8ec8eeaSjose borrego 	if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
1319c8ec8eeaSjose borrego 		/*
1320c8ec8eeaSjose borrego 		 * Only report normal users, i.e. ignore W2K misuse
1321c8ec8eeaSjose borrego 		 * of the IPC connection by filtering out internal
1322c8ec8eeaSjose borrego 		 * names such as nobody and root.
1323c8ec8eeaSjose borrego 		 */
1324c8ec8eeaSjose borrego 		if ((strcmp(user->u_name, "root") == 0) ||
1325c8ec8eeaSjose borrego 		    (strcmp(user->u_name, "nobody") == 0)) {
1326c8ec8eeaSjose borrego 			return;
1327da6c28aaSamw 		}
1328da6c28aaSamw 	}
1329da6c28aaSamw 
1330c8ec8eeaSjose borrego 	va_start(ap, fmt);
1331c8ec8eeaSjose borrego 	(void) vsnprintf(buf, 128, fmt, ap);
1332c8ec8eeaSjose borrego 	va_end(ap);
1333c8ec8eeaSjose borrego 
1334c8ec8eeaSjose borrego 	cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
1335c8ec8eeaSjose borrego 	    user->u_domain, user->u_name, sharename, buf);
1336da6c28aaSamw }
13377f667e74Sjose borrego 
13387f667e74Sjose borrego /*
13397f667e74Sjose borrego  * smb_tree_lookup_odir
13407f667e74Sjose borrego  *
13417f667e74Sjose borrego  * Find the specified odir in the tree's list of odirs, and
13427f667e74Sjose borrego  * attempt to obtain a hold on the odir.
13437f667e74Sjose borrego  *
13447f667e74Sjose borrego  * Returns NULL if odir not found or a hold cannot be obtained.
13457f667e74Sjose borrego  */
13467f667e74Sjose borrego smb_odir_t *
smb_tree_lookup_odir(smb_request_t * sr,uint16_t odid)13473b13a1efSThomas Keiser smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid)
13487f667e74Sjose borrego {
13497f667e74Sjose borrego 	smb_odir_t	*od;
13507f667e74Sjose borrego 	smb_llist_t	*od_list;
13513b13a1efSThomas Keiser 	smb_tree_t	*tree = sr->tid_tree;
13527f667e74Sjose borrego 
13537f667e74Sjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
13547f667e74Sjose borrego 
13557f667e74Sjose borrego 	od_list = &tree->t_odir_list;
13567f667e74Sjose borrego 
13573b13a1efSThomas Keiser 	smb_llist_enter(od_list, RW_READER);
13587f667e74Sjose borrego 	od = smb_llist_head(od_list);
13597f667e74Sjose borrego 	while (od) {
13603b13a1efSThomas Keiser 		if (od->d_odid == odid)
13617f667e74Sjose borrego 			break;
13627f667e74Sjose borrego 		od = smb_llist_next(od_list, od);
13637f667e74Sjose borrego 	}
13643b13a1efSThomas Keiser 	if (od == NULL)
13653b13a1efSThomas Keiser 		goto out;
13663b13a1efSThomas Keiser 
13673b13a1efSThomas Keiser 	/*
13683b13a1efSThomas Keiser 	 * Only allow use of a given Search ID with the same UID that
13693b13a1efSThomas Keiser 	 * was used to create it.  MS-CIFS 3.3.5.14
13703b13a1efSThomas Keiser 	 */
13713b13a1efSThomas Keiser 	if (od->d_user != sr->uid_user) {
13723b13a1efSThomas Keiser 		od = NULL;
13733b13a1efSThomas Keiser 		goto out;
13743b13a1efSThomas Keiser 	}
13753b13a1efSThomas Keiser 	if (!smb_odir_hold(od))
13763b13a1efSThomas Keiser 		od = NULL;
13777f667e74Sjose borrego 
13783b13a1efSThomas Keiser out:
13797f667e74Sjose borrego 	smb_llist_exit(od_list);
13807f667e74Sjose borrego 	return (od);
13817f667e74Sjose borrego }
13827f667e74Sjose borrego 
13838b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States boolean_t
smb_tree_is_connected(smb_tree_t * tree)13848b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tree_is_connected(smb_tree_t *tree)
13858b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States {
13868b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	boolean_t	rb;
13878b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
13888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_enter(&tree->t_mutex);
13898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	rb = smb_tree_is_connected_locked(tree);
13908b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_exit(&tree->t_mutex);
13918b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	return (rb);
13928b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
13938b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
13947f667e74Sjose borrego /*
13957f667e74Sjose borrego  * smb_tree_close_odirs
13967f667e74Sjose borrego  *
13977f667e74Sjose borrego  * Close all open odirs in the tree's list which were opened by
13987f667e74Sjose borrego  * the process identified by pid.
13997f667e74Sjose borrego  * If pid is zero, close all open odirs in the tree's list.
14007f667e74Sjose borrego  */
14017f667e74Sjose borrego static void
smb_tree_close_odirs(smb_tree_t * tree,uint32_t pid)14028d94f651SGordon Ross smb_tree_close_odirs(smb_tree_t *tree, uint32_t pid)
14037f667e74Sjose borrego {
14048d94f651SGordon Ross 	smb_llist_t	*od_list;
14058d94f651SGordon Ross 	smb_odir_t	*od;
14067f667e74Sjose borrego 
14077f667e74Sjose borrego 	ASSERT(tree);
14087f667e74Sjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
14097f667e74Sjose borrego 
14108d94f651SGordon Ross 	od_list = &tree->t_odir_list;
14118d94f651SGordon Ross 	smb_llist_enter(od_list, RW_READER);
14128d94f651SGordon Ross 
14138d94f651SGordon Ross 	for (od = smb_llist_head(od_list);
14148d94f651SGordon Ross 	    od != NULL;
14158d94f651SGordon Ross 	    od = smb_llist_next(od_list, od)) {
14168d94f651SGordon Ross 
14177f667e74Sjose borrego 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
14187f667e74Sjose borrego 		ASSERT(od->d_tree == tree);
14197f667e74Sjose borrego 
14208d94f651SGordon Ross 		if (pid != 0 && od->d_opened_by_pid != pid)
14218d94f651SGordon Ross 			continue;
14227f667e74Sjose borrego 
14238d94f651SGordon Ross 		if (smb_odir_hold(od)) {
14248d94f651SGordon Ross 			smb_odir_close(od);
14258d94f651SGordon Ross 			smb_odir_release(od);
14268d94f651SGordon Ross 		}
14277f667e74Sjose borrego 	}
14288d94f651SGordon Ross 
14298d94f651SGordon Ross 	smb_llist_exit(od_list);
14307f667e74Sjose borrego }
143129bd2886SAlan Wright 
143229bd2886SAlan Wright static void
smb_tree_set_execinfo(smb_tree_t * tree,smb_shr_execinfo_t * exec,int exec_type)14333b13a1efSThomas Keiser smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec,
14343b13a1efSThomas Keiser     int exec_type)
143529bd2886SAlan Wright {
1436148c5f43SAlan Wright 	exec->e_sharename = tree->t_sharename;
14373b13a1efSThomas Keiser 	exec->e_winname = tree->t_owner->u_name;
14383b13a1efSThomas Keiser 	exec->e_userdom = tree->t_owner->u_domain;
1439148c5f43SAlan Wright 	exec->e_srv_ipaddr = tree->t_session->local_ipaddr;
1440148c5f43SAlan Wright 	exec->e_cli_ipaddr = tree->t_session->ipaddr;
1441148c5f43SAlan Wright 	exec->e_cli_netbiosname = tree->t_session->workstation;
14423b13a1efSThomas Keiser 	exec->e_uid = crgetuid(tree->t_owner->u_cred);
1443148c5f43SAlan Wright 	exec->e_type = exec_type;
144429bd2886SAlan Wright }
14451fcced4cSJordan Brown 
14461fcced4cSJordan Brown /*
14471fcced4cSJordan Brown  * Private function to support smb_tree_enum.
14481fcced4cSJordan Brown  */
14491fcced4cSJordan Brown static int
smb_tree_enum_private(smb_tree_t * tree,smb_svcenum_t * svcenum)14501fcced4cSJordan Brown smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum)
14511fcced4cSJordan Brown {
14521fcced4cSJordan Brown 	uint8_t *pb;
14531fcced4cSJordan Brown 	uint_t nbytes;
14541fcced4cSJordan Brown 	int rc;
14551fcced4cSJordan Brown 
14561fcced4cSJordan Brown 	if (svcenum->se_nskip > 0) {
14571fcced4cSJordan Brown 		svcenum->se_nskip--;
14581fcced4cSJordan Brown 		return (0);
14591fcced4cSJordan Brown 	}
14601fcced4cSJordan Brown 
14611fcced4cSJordan Brown 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
14621fcced4cSJordan Brown 		svcenum->se_nitems = svcenum->se_nlimit;
14631fcced4cSJordan Brown 		return (0);
14641fcced4cSJordan Brown 	}
14651fcced4cSJordan Brown 
14661fcced4cSJordan Brown 	pb = &svcenum->se_buf[svcenum->se_bused];
14671fcced4cSJordan Brown 	rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes);
14681fcced4cSJordan Brown 	if (rc == 0) {
14691fcced4cSJordan Brown 		svcenum->se_bavail -= nbytes;
14701fcced4cSJordan Brown 		svcenum->se_bused += nbytes;
14711fcced4cSJordan Brown 		svcenum->se_nitems++;
14721fcced4cSJordan Brown 	}
14731fcced4cSJordan Brown 
14741fcced4cSJordan Brown 	return (rc);
14751fcced4cSJordan Brown }
14761fcced4cSJordan Brown 
14771fcced4cSJordan Brown /*
14781fcced4cSJordan Brown  * Encode connection information into a buffer: connection information
14791fcced4cSJordan Brown  * needed in user space to support RPC requests.
14801fcced4cSJordan Brown  */
14811fcced4cSJordan Brown static int
smb_tree_netinfo_encode(smb_tree_t * tree,uint8_t * buf,size_t buflen,uint32_t * nbytes)14821fcced4cSJordan Brown smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
14831fcced4cSJordan Brown     uint32_t *nbytes)
14841fcced4cSJordan Brown {
14851fcced4cSJordan Brown 	smb_netconnectinfo_t	info;
14861fcced4cSJordan Brown 	int			rc;
14871fcced4cSJordan Brown 
14881fcced4cSJordan Brown 	smb_tree_netinfo_init(tree, &info);
14891fcced4cSJordan Brown 	rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes);
14901fcced4cSJordan Brown 	smb_tree_netinfo_fini(&info);
14911fcced4cSJordan Brown 
14921fcced4cSJordan Brown 	return (rc);
14931fcced4cSJordan Brown }
14941fcced4cSJordan Brown 
14953b13a1efSThomas Keiser static void
smb_tree_netinfo_username(smb_tree_t * tree,char ** namestr,uint32_t * namelen)14963b13a1efSThomas Keiser smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen)
14973b13a1efSThomas Keiser {
14983b13a1efSThomas Keiser 	smb_user_t		*user = tree->t_owner;
14993b13a1efSThomas Keiser 
15003b13a1efSThomas Keiser 	/*
15013b13a1efSThomas Keiser 	 * u_domain_len and u_name_len include the '\0' in their
15023b13a1efSThomas Keiser 	 * lengths, hence the sum of the two lengths gives us room
15033b13a1efSThomas Keiser 	 * for both the '\\' and '\0' chars.
15043b13a1efSThomas Keiser 	 */
15053b13a1efSThomas Keiser 	ASSERT(namestr);
15063b13a1efSThomas Keiser 	ASSERT(namelen);
15073b13a1efSThomas Keiser 	ASSERT(user->u_domain_len > 0);
15083b13a1efSThomas Keiser 	ASSERT(user->u_name_len > 0);
15093b13a1efSThomas Keiser 	*namelen = user->u_domain_len + user->u_name_len;
15103b13a1efSThomas Keiser 	*namestr = kmem_alloc(*namelen, KM_SLEEP);
15113b13a1efSThomas Keiser 	(void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain,
15123b13a1efSThomas Keiser 	    user->u_name);
15133b13a1efSThomas Keiser }
15143b13a1efSThomas Keiser 
15151fcced4cSJordan Brown /*
15161fcced4cSJordan Brown  * Note: ci_numusers should be the number of users connected to
15171fcced4cSJordan Brown  * the share rather than the number of references on the tree but
15181fcced4cSJordan Brown  * we don't have a mechanism to track users/share in smbsrv yet.
15191fcced4cSJordan Brown  */
15201fcced4cSJordan Brown static void
smb_tree_netinfo_init(smb_tree_t * tree,smb_netconnectinfo_t * info)15211fcced4cSJordan Brown smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
15221fcced4cSJordan Brown {
15231fcced4cSJordan Brown 	ASSERT(tree);
15241fcced4cSJordan Brown 
15251fcced4cSJordan Brown 	info->ci_id = tree->t_tid;
15261fcced4cSJordan Brown 	info->ci_type = tree->t_res_type;
15271fcced4cSJordan Brown 	info->ci_numopens = tree->t_open_files;
15281fcced4cSJordan Brown 	info->ci_numusers = tree->t_refcnt;
15291fcced4cSJordan Brown 	info->ci_time = gethrestime_sec() - tree->t_connect_time;
15301fcced4cSJordan Brown 
15311fcced4cSJordan Brown 	info->ci_sharelen = strlen(tree->t_sharename) + 1;
15329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	info->ci_share = smb_mem_strdup(tree->t_sharename);
15331fcced4cSJordan Brown 
15343b13a1efSThomas Keiser 	smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen);
15351fcced4cSJordan Brown }
15361fcced4cSJordan Brown 
15371fcced4cSJordan Brown static void
smb_tree_netinfo_fini(smb_netconnectinfo_t * info)15381fcced4cSJordan Brown smb_tree_netinfo_fini(smb_netconnectinfo_t *info)
15391fcced4cSJordan Brown {
15401fcced4cSJordan Brown 	if (info == NULL)
15411fcced4cSJordan Brown 		return;
15421fcced4cSJordan Brown 
15431fcced4cSJordan Brown 	if (info->ci_username)
15441fcced4cSJordan Brown 		kmem_free(info->ci_username, info->ci_namelen);
15451fcced4cSJordan Brown 	if (info->ci_share)
15469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smb_mem_free(info->ci_share);
15471fcced4cSJordan Brown 
15481fcced4cSJordan Brown 	bzero(info, sizeof (smb_netconnectinfo_t));
15491fcced4cSJordan Brown }
1550