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  */
21da6c28aaSamw /*
22faa1795aSjb  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26*c8ec8eeaSjose borrego #pragma ident	"@(#)smb_tree.c	1.5	08/08/07 SMI"
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  * +-------------------+       +-------------------+      +-------------------+
44da6c28aaSamw  *          |
45da6c28aaSamw  *          |
46da6c28aaSamw  *          v
47da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
48da6c28aaSamw  * |       USER        |<----->|       USER        |......|       USER        |
49da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
50da6c28aaSamw  *          |
51da6c28aaSamw  *          |
52da6c28aaSamw  *          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  *
125da6c28aaSamw  *    This transition occurs in smb_tree_release(). The resources associated
126da6c28aaSamw  *    with the tree are freed as well as the tree structure. For the transition
127da6c28aaSamw  *    to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED state and
128da6c28aaSamw  *    the reference count be zero.
129da6c28aaSamw  *
130da6c28aaSamw  * Comments
131da6c28aaSamw  * --------
132da6c28aaSamw  *
133da6c28aaSamw  *    The state machine of the tree structures is controlled by 3 elements:
134da6c28aaSamw  *      - The list of trees of the user it belongs to.
135da6c28aaSamw  *      - The mutex embedded in the structure itself.
136da6c28aaSamw  *      - The reference count.
137da6c28aaSamw  *
138da6c28aaSamw  *    There's a mutex embedded in the tree structure used to protect its fields
139da6c28aaSamw  *    and there's a lock embedded in the list of trees of a user. To
140da6c28aaSamw  *    increment or to decrement the reference count the mutex must be entered.
141da6c28aaSamw  *    To insert the tree into the list of trees of the user and to remove
142da6c28aaSamw  *    the tree from it, the lock must be entered in RW_WRITER mode.
143da6c28aaSamw  *
144da6c28aaSamw  *    Rules of access to a tree structure:
145da6c28aaSamw  *
146da6c28aaSamw  *    1) In order to avoid deadlocks, when both (mutex and lock of the user
147da6c28aaSamw  *       list) have to be entered, the lock must be entered first.
148da6c28aaSamw  *
149da6c28aaSamw  *    2) All actions applied to a tree require a reference count.
150da6c28aaSamw  *
151*c8ec8eeaSjose borrego  *    3) There are 2 ways of getting a reference count: when a tree is
152*c8ec8eeaSjose borrego  *       connected and when a tree is looked up.
153da6c28aaSamw  *
154da6c28aaSamw  *    It should be noted that the reference count of a tree registers the
155da6c28aaSamw  *    number of references to the tree in other structures (such as an smb
156da6c28aaSamw  *    request). The reference count is not incremented in these 2 instances:
157da6c28aaSamw  *
158da6c28aaSamw  *    1) The tree is connected. An tree is anchored by his state. If there's
159da6c28aaSamw  *       no activity involving a tree currently connected, the reference
160da6c28aaSamw  *       count of that tree is zero.
161da6c28aaSamw  *
162da6c28aaSamw  *    2) The tree is queued in the list of trees of the user. The fact of
163da6c28aaSamw  *       being queued in that list is NOT registered by incrementing the
164da6c28aaSamw  *       reference count.
165da6c28aaSamw  */
166*c8ec8eeaSjose borrego #include <sys/types.h>
167*c8ec8eeaSjose borrego #include <sys/refstr_impl.h>
168*c8ec8eeaSjose borrego #include <sys/feature_tests.h>
169*c8ec8eeaSjose borrego #include <sys/sunddi.h>
17055bf511dSas #include <sys/fsid.h>
171*c8ec8eeaSjose borrego #include <sys/vfs.h>
172*c8ec8eeaSjose borrego #include <sys/stat.h>
173*c8ec8eeaSjose borrego #include <sys/varargs.h>
174da6c28aaSamw #include <smbsrv/smb_incl.h>
175*c8ec8eeaSjose borrego #include <smbsrv/lmerr.h>
176*c8ec8eeaSjose borrego #include <smbsrv/mlsvc.h>
177da6c28aaSamw #include <smbsrv/smb_fsops.h>
178*c8ec8eeaSjose borrego #include <smbsrv/smb_door_svc.h>
179*c8ec8eeaSjose borrego #include <smbsrv/smb_share.h>
180*c8ec8eeaSjose borrego 
181*c8ec8eeaSjose borrego int smb_tcon_mute = 0;
182*c8ec8eeaSjose borrego 
183*c8ec8eeaSjose borrego static smb_tree_t *smb_tree_connect_disk(smb_request_t *, const char *);
184*c8ec8eeaSjose borrego static smb_tree_t *smb_tree_connect_ipc(smb_request_t *, const char *);
185*c8ec8eeaSjose borrego static smb_tree_t *smb_tree_alloc(smb_user_t *, const char *, const char *,
186*c8ec8eeaSjose borrego     int32_t, smb_node_t *);
187*c8ec8eeaSjose borrego static void smb_tree_dealloc(smb_tree_t *);
188*c8ec8eeaSjose borrego static boolean_t smb_tree_is_connected(smb_tree_t *);
189*c8ec8eeaSjose borrego static boolean_t smb_tree_is_disconnected(smb_tree_t *);
190*c8ec8eeaSjose borrego static const char *smb_tree_get_sharename(const char *);
191*c8ec8eeaSjose borrego static int smb_tree_get_stype(const char *, const char *, int32_t *);
192*c8ec8eeaSjose borrego static int smb_tree_getattr(smb_node_t *, smb_tree_t *);
193*c8ec8eeaSjose borrego static void smb_tree_get_volname(vfs_t *, smb_tree_t *);
194*c8ec8eeaSjose borrego static void smb_tree_get_flags(vfs_t *, smb_tree_t *);
195*c8ec8eeaSjose borrego static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
196da6c28aaSamw 
197da6c28aaSamw /*
198*c8ec8eeaSjose borrego  * Extract the share name and share type and connect as appropriate.
199*c8ec8eeaSjose borrego  * Share names are case insensitive so we map the share name to
200*c8ec8eeaSjose borrego  * lower-case as a convenience for internal processing.
201da6c28aaSamw  */
202da6c28aaSamw smb_tree_t *
203*c8ec8eeaSjose borrego smb_tree_connect(smb_request_t *sr)
204da6c28aaSamw {
205*c8ec8eeaSjose borrego 	char *unc_path = sr->arg.tcon.path;
206*c8ec8eeaSjose borrego 	char *service = sr->arg.tcon.service;
207*c8ec8eeaSjose borrego 	smb_tree_t *tree = NULL;
208*c8ec8eeaSjose borrego 	const char *name;
209*c8ec8eeaSjose borrego 	int32_t stype;
210da6c28aaSamw 
211*c8ec8eeaSjose borrego 	(void) utf8_strlwr(unc_path);
212da6c28aaSamw 
213*c8ec8eeaSjose borrego 	if ((name = smb_tree_get_sharename(unc_path)) == NULL) {
214*c8ec8eeaSjose borrego 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
215da6c28aaSamw 		return (NULL);
216da6c28aaSamw 	}
217da6c28aaSamw 
218*c8ec8eeaSjose borrego 	if (smb_tree_get_stype(name, service, &stype) != 0) {
219*c8ec8eeaSjose borrego 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
220*c8ec8eeaSjose borrego 		    ERRDOS, ERROR_BAD_DEV_TYPE);
221da6c28aaSamw 		return (NULL);
222da6c28aaSamw 	}
223da6c28aaSamw 
224da6c28aaSamw 	switch (stype & STYPE_MASK) {
225da6c28aaSamw 	case STYPE_DISKTREE:
226*c8ec8eeaSjose borrego 		tree = smb_tree_connect_disk(sr, name);
227da6c28aaSamw 		break;
228da6c28aaSamw 
229da6c28aaSamw 	case STYPE_IPC:
230*c8ec8eeaSjose borrego 		tree = smb_tree_connect_ipc(sr, name);
231*c8ec8eeaSjose borrego 		break;
232*c8ec8eeaSjose borrego 
233da6c28aaSamw 	default:
234*c8ec8eeaSjose borrego 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
235*c8ec8eeaSjose borrego 		    ERRDOS, ERROR_BAD_DEV_TYPE);
236da6c28aaSamw 		break;
237da6c28aaSamw 	}
238da6c28aaSamw 
239da6c28aaSamw 	return (tree);
240da6c28aaSamw }
241da6c28aaSamw 
242da6c28aaSamw /*
243*c8ec8eeaSjose borrego  * Disconnect a tree.
244da6c28aaSamw  */
245da6c28aaSamw void
246da6c28aaSamw smb_tree_disconnect(
247da6c28aaSamw     smb_tree_t	*tree)
248da6c28aaSamw {
249da6c28aaSamw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
250da6c28aaSamw 
251da6c28aaSamw 	mutex_enter(&tree->t_mutex);
252da6c28aaSamw 	ASSERT(tree->t_refcnt);
253*c8ec8eeaSjose borrego 
254*c8ec8eeaSjose borrego 	if (smb_tree_is_connected(tree)) {
255da6c28aaSamw 		/*
256*c8ec8eeaSjose borrego 		 * Indicate that the disconnect process has started.
257da6c28aaSamw 		 */
258da6c28aaSamw 		tree->t_state = SMB_TREE_STATE_DISCONNECTING;
259da6c28aaSamw 		mutex_exit(&tree->t_mutex);
260faa1795aSjb 		atomic_dec_32(&tree->t_server->sv_open_trees);
261*c8ec8eeaSjose borrego 
262da6c28aaSamw 		/*
263da6c28aaSamw 		 * The files opened under this tree are closed.
264da6c28aaSamw 		 */
265da6c28aaSamw 		smb_ofile_close_all(tree);
266da6c28aaSamw 		/*
267da6c28aaSamw 		 * The directories opened under this tree are closed.
268da6c28aaSamw 		 */
269da6c28aaSamw 		smb_odir_close_all(tree);
270da6c28aaSamw 		mutex_enter(&tree->t_mutex);
271da6c28aaSamw 		tree->t_state = SMB_TREE_STATE_DISCONNECTED;
272da6c28aaSamw 	}
273da6c28aaSamw 
274da6c28aaSamw 	mutex_exit(&tree->t_mutex);
275da6c28aaSamw }
276da6c28aaSamw 
277da6c28aaSamw /*
278*c8ec8eeaSjose borrego  * Take a reference on a tree.
279da6c28aaSamw  */
280*c8ec8eeaSjose borrego boolean_t
281*c8ec8eeaSjose borrego smb_tree_hold(
282*c8ec8eeaSjose borrego     smb_tree_t		*tree)
283da6c28aaSamw {
284*c8ec8eeaSjose borrego 	ASSERT(tree);
285*c8ec8eeaSjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
286da6c28aaSamw 
287*c8ec8eeaSjose borrego 	mutex_enter(&tree->t_mutex);
288*c8ec8eeaSjose borrego 
289*c8ec8eeaSjose borrego 	if (smb_tree_is_connected(tree)) {
290*c8ec8eeaSjose borrego 		tree->t_refcnt++;
291*c8ec8eeaSjose borrego 		mutex_exit(&tree->t_mutex);
292*c8ec8eeaSjose borrego 		return (B_TRUE);
293da6c28aaSamw 	}
294*c8ec8eeaSjose borrego 
295*c8ec8eeaSjose borrego 	mutex_exit(&tree->t_mutex);
296*c8ec8eeaSjose borrego 	return (B_FALSE);
297da6c28aaSamw }
298da6c28aaSamw 
299da6c28aaSamw /*
300*c8ec8eeaSjose borrego  * Release a reference on a tree.  If the tree is disconnected and the
301*c8ec8eeaSjose borrego  * reference count falls to zero, the tree will be deallocated.
302da6c28aaSamw  */
303da6c28aaSamw void
304*c8ec8eeaSjose borrego smb_tree_release(
305*c8ec8eeaSjose borrego     smb_tree_t		*tree)
306da6c28aaSamw {
307*c8ec8eeaSjose borrego 	ASSERT(tree);
308*c8ec8eeaSjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
309da6c28aaSamw 
310*c8ec8eeaSjose borrego 	mutex_enter(&tree->t_mutex);
311*c8ec8eeaSjose borrego 	ASSERT(tree->t_refcnt);
312*c8ec8eeaSjose borrego 	tree->t_refcnt--;
313*c8ec8eeaSjose borrego 
314*c8ec8eeaSjose borrego 	if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0)) {
315*c8ec8eeaSjose borrego 		mutex_exit(&tree->t_mutex);
316*c8ec8eeaSjose borrego 		smb_tree_dealloc(tree);
317*c8ec8eeaSjose borrego 		return;
318da6c28aaSamw 	}
319*c8ec8eeaSjose borrego 
320*c8ec8eeaSjose borrego 	mutex_exit(&tree->t_mutex);
321da6c28aaSamw }
322da6c28aaSamw 
323da6c28aaSamw /*
324*c8ec8eeaSjose borrego  * Close ofiles and odirs that match pid.
325da6c28aaSamw  */
326da6c28aaSamw void
327*c8ec8eeaSjose borrego smb_tree_close_pid(
328*c8ec8eeaSjose borrego     smb_tree_t		*tree,
329*c8ec8eeaSjose borrego     uint16_t		pid)
330da6c28aaSamw {
331da6c28aaSamw 	ASSERT(tree);
332da6c28aaSamw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
333da6c28aaSamw 
334*c8ec8eeaSjose borrego 	smb_ofile_close_all_by_pid(tree, pid);
335*c8ec8eeaSjose borrego 	smb_odir_close_all_by_pid(tree, pid);
336*c8ec8eeaSjose borrego }
337da6c28aaSamw 
338*c8ec8eeaSjose borrego /*
339*c8ec8eeaSjose borrego  * Check whether or not a tree supports the features identified by flags.
340*c8ec8eeaSjose borrego  */
341*c8ec8eeaSjose borrego boolean_t
342*c8ec8eeaSjose borrego smb_tree_has_feature(smb_tree_t *tree, uint32_t flags)
343*c8ec8eeaSjose borrego {
344*c8ec8eeaSjose borrego 	ASSERT(tree);
345*c8ec8eeaSjose borrego 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
346da6c28aaSamw 
347*c8ec8eeaSjose borrego 	return ((tree->t_flags & flags) == flags);
348da6c28aaSamw }
349da6c28aaSamw 
350*c8ec8eeaSjose borrego /* *************************** Static Functions ***************************** */
351*c8ec8eeaSjose borrego 
352da6c28aaSamw /*
353*c8ec8eeaSjose borrego  * Connect a share for use with files and directories.
354da6c28aaSamw  */
355*c8ec8eeaSjose borrego static smb_tree_t *
356*c8ec8eeaSjose borrego smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
357da6c28aaSamw {
358*c8ec8eeaSjose borrego 	smb_user_t		*user = sr->uid_user;
359*c8ec8eeaSjose borrego 	smb_node_t		*dir_snode = NULL;
360*c8ec8eeaSjose borrego 	smb_node_t		*snode = NULL;
361*c8ec8eeaSjose borrego 	char			last_component[MAXNAMELEN];
362*c8ec8eeaSjose borrego 	smb_tree_t		*tree;
363*c8ec8eeaSjose borrego 	smb_share_t 		si;
364*c8ec8eeaSjose borrego 	smb_attr_t		attr;
365*c8ec8eeaSjose borrego 	cred_t			*u_cred;
366*c8ec8eeaSjose borrego 	int			rc;
367da6c28aaSamw 
368da6c28aaSamw 	ASSERT(user);
369*c8ec8eeaSjose borrego 	u_cred = user->u_cred;
370*c8ec8eeaSjose borrego 	ASSERT(u_cred);
371*c8ec8eeaSjose borrego 
372*c8ec8eeaSjose borrego 	bzero(&si, sizeof (smb_share_t));
373*c8ec8eeaSjose borrego 
374*c8ec8eeaSjose borrego 	if (user->u_flags & SMB_USER_FLAG_IPC) {
375*c8ec8eeaSjose borrego 		smb_tree_log(sr, sharename, "access denied: IPC only");
376*c8ec8eeaSjose borrego 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
377*c8ec8eeaSjose borrego 		return (NULL);
378*c8ec8eeaSjose borrego 	}
379*c8ec8eeaSjose borrego 
380*c8ec8eeaSjose borrego 	if (smb_kshare_getinfo(sr->sr_server->sv_lmshrd, sharename, &si) !=
381*c8ec8eeaSjose borrego 	    NERR_Success) {
382*c8ec8eeaSjose borrego 		smb_tree_log(sr, sharename, "share not found");
383*c8ec8eeaSjose borrego 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
384*c8ec8eeaSjose borrego 		return (NULL);
385*c8ec8eeaSjose borrego 	}
386*c8ec8eeaSjose borrego 
387*c8ec8eeaSjose borrego 	/*
388*c8ec8eeaSjose borrego 	 * Handle the default administration shares: C$, D$ etc.
389*c8ec8eeaSjose borrego 	 * Only a user with admin rights is allowed to map these
390*c8ec8eeaSjose borrego 	 * shares.
391*c8ec8eeaSjose borrego 	 */
392*c8ec8eeaSjose borrego 	if (si.shr_flags & SMB_SHRF_ADMIN) {
393*c8ec8eeaSjose borrego 		if (!smb_user_is_admin(user)) {
394*c8ec8eeaSjose borrego 			smb_tree_log(sr, sharename, "access denied: not admin");
395*c8ec8eeaSjose borrego 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
396*c8ec8eeaSjose borrego 			    ERRSRV, ERRaccess);
397*c8ec8eeaSjose borrego 			return (NULL);
398da6c28aaSamw 		}
399da6c28aaSamw 	}
400*c8ec8eeaSjose borrego 
401*c8ec8eeaSjose borrego 	/*
402*c8ec8eeaSjose borrego 	 * Check that the shared directory exists.
403*c8ec8eeaSjose borrego 	 */
404*c8ec8eeaSjose borrego 	rc = smb_pathname_reduce(sr, u_cred, si.shr_path, 0, 0, &dir_snode,
405*c8ec8eeaSjose borrego 	    last_component);
406*c8ec8eeaSjose borrego 
407*c8ec8eeaSjose borrego 	if (rc == 0) {
408*c8ec8eeaSjose borrego 		rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS, 0,
409*c8ec8eeaSjose borrego 		    dir_snode, last_component, &snode, &attr, 0, 0);
410*c8ec8eeaSjose borrego 
411*c8ec8eeaSjose borrego 		smb_node_release(dir_snode);
412*c8ec8eeaSjose borrego 	}
413*c8ec8eeaSjose borrego 
414*c8ec8eeaSjose borrego 	if (rc) {
415*c8ec8eeaSjose borrego 		if (snode)
416*c8ec8eeaSjose borrego 			smb_node_release(snode);
417*c8ec8eeaSjose borrego 
418*c8ec8eeaSjose borrego 		smb_tree_log(sr, sharename, "bad path: %s", si.shr_path);
419*c8ec8eeaSjose borrego 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
420*c8ec8eeaSjose borrego 		return (NULL);
421*c8ec8eeaSjose borrego 	}
422*c8ec8eeaSjose borrego 
423*c8ec8eeaSjose borrego 	tree = smb_tree_alloc(user, sharename, si.shr_path, STYPE_DISKTREE,
424*c8ec8eeaSjose borrego 	    snode);
425*c8ec8eeaSjose borrego 	if (tree == NULL)
426*c8ec8eeaSjose borrego 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
427*c8ec8eeaSjose borrego 
428*c8ec8eeaSjose borrego 	smb_node_release(snode);
429*c8ec8eeaSjose borrego 	return (tree);
430da6c28aaSamw }
431da6c28aaSamw 
432da6c28aaSamw /*
433*c8ec8eeaSjose borrego  * Connect an IPC share for use with named pipes.
434da6c28aaSamw  */
435*c8ec8eeaSjose borrego static smb_tree_t *
436*c8ec8eeaSjose borrego smb_tree_connect_ipc(smb_request_t *sr, const char *name)
437da6c28aaSamw {
438*c8ec8eeaSjose borrego 	smb_user_t *user = sr->uid_user;
439*c8ec8eeaSjose borrego 	smb_tree_t *tree;
440da6c28aaSamw 
441*c8ec8eeaSjose borrego 	ASSERT(user);
442da6c28aaSamw 
443*c8ec8eeaSjose borrego 	if ((user->u_flags & SMB_USER_FLAG_IPC) &&
444*c8ec8eeaSjose borrego 	    sr->sr_cfg->skc_restrict_anon) {
445*c8ec8eeaSjose borrego 		smb_tree_log(sr, name, "access denied: restrict anonymous");
446*c8ec8eeaSjose borrego 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
447*c8ec8eeaSjose borrego 		return (NULL);
448da6c28aaSamw 	}
449da6c28aaSamw 
450*c8ec8eeaSjose borrego 	tree = smb_tree_alloc(user, name, name, STYPE_IPC, NULL);
451*c8ec8eeaSjose borrego 	if (tree == NULL) {
452*c8ec8eeaSjose borrego 		smb_tree_log(sr, name, "access denied");
453*c8ec8eeaSjose borrego 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
454da6c28aaSamw 	}
455*c8ec8eeaSjose borrego 
456*c8ec8eeaSjose borrego 	return (tree);
457da6c28aaSamw }
458da6c28aaSamw 
459da6c28aaSamw /*
460*c8ec8eeaSjose borrego  * Allocate a tree.
461da6c28aaSamw  */
462*c8ec8eeaSjose borrego static smb_tree_t *
463*c8ec8eeaSjose borrego smb_tree_alloc(
464da6c28aaSamw     smb_user_t		*user,
465*c8ec8eeaSjose borrego     const char		*sharename,
466*c8ec8eeaSjose borrego     const char		*resource,
467*c8ec8eeaSjose borrego     int32_t		stype,
468*c8ec8eeaSjose borrego     smb_node_t		*snode)
469da6c28aaSamw {
470*c8ec8eeaSjose borrego 	smb_tree_t	*tree;
471*c8ec8eeaSjose borrego 	uint16_t	tid;
472da6c28aaSamw 
473*c8ec8eeaSjose borrego 	if (smb_idpool_alloc(&user->u_tid_pool, &tid))
474*c8ec8eeaSjose borrego 		return (NULL);
475da6c28aaSamw 
476*c8ec8eeaSjose borrego 	tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP);
477*c8ec8eeaSjose borrego 	bzero(tree, sizeof (smb_tree_t));
478da6c28aaSamw 
479*c8ec8eeaSjose borrego 	if (STYPE_ISDSK(stype)) {
480*c8ec8eeaSjose borrego 		if (smb_tree_getattr(snode, tree) != 0) {
481*c8ec8eeaSjose borrego 			smb_idpool_free(&user->u_tid_pool, tid);
482*c8ec8eeaSjose borrego 			kmem_cache_free(user->u_server->si_cache_tree, tree);
483*c8ec8eeaSjose borrego 			return (NULL);
484da6c28aaSamw 		}
485da6c28aaSamw 	}
486*c8ec8eeaSjose borrego 
487*c8ec8eeaSjose borrego 	if (smb_idpool_constructor(&tree->t_fid_pool)) {
488*c8ec8eeaSjose borrego 		smb_idpool_free(&user->u_tid_pool, tid);
489*c8ec8eeaSjose borrego 		kmem_cache_free(user->u_server->si_cache_tree, tree);
490*c8ec8eeaSjose borrego 		return (NULL);
491*c8ec8eeaSjose borrego 	}
492*c8ec8eeaSjose borrego 
493*c8ec8eeaSjose borrego 	if (smb_idpool_constructor(&tree->t_sid_pool)) {
494*c8ec8eeaSjose borrego 		smb_idpool_destructor(&tree->t_fid_pool);
495*c8ec8eeaSjose borrego 		smb_idpool_free(&user->u_tid_pool, tid);
496*c8ec8eeaSjose borrego 		kmem_cache_free(user->u_server->si_cache_tree, tree);
497*c8ec8eeaSjose borrego 		return (NULL);
498*c8ec8eeaSjose borrego 	}
499*c8ec8eeaSjose borrego 
500*c8ec8eeaSjose borrego 	smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
501*c8ec8eeaSjose borrego 	    offsetof(smb_ofile_t, f_lnd));
502*c8ec8eeaSjose borrego 
503*c8ec8eeaSjose borrego 	smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
504*c8ec8eeaSjose borrego 	    offsetof(smb_odir_t, d_lnd));
505*c8ec8eeaSjose borrego 
506*c8ec8eeaSjose borrego 	(void) strlcpy(tree->t_sharename, sharename,
507*c8ec8eeaSjose borrego 	    sizeof (tree->t_sharename));
508*c8ec8eeaSjose borrego 	(void) strlcpy(tree->t_resource, resource, sizeof (tree->t_resource));
509*c8ec8eeaSjose borrego 
510*c8ec8eeaSjose borrego 	mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
511*c8ec8eeaSjose borrego 
512*c8ec8eeaSjose borrego 	tree->t_user = user;
513*c8ec8eeaSjose borrego 	tree->t_session = user->u_session;
514*c8ec8eeaSjose borrego 	tree->t_server = user->u_server;
515*c8ec8eeaSjose borrego 	tree->t_refcnt = 1;
516*c8ec8eeaSjose borrego 	tree->t_tid = tid;
517*c8ec8eeaSjose borrego 	tree->t_res_type = stype;
518*c8ec8eeaSjose borrego 	tree->t_state = SMB_TREE_STATE_CONNECTED;
519*c8ec8eeaSjose borrego 	tree->t_magic = SMB_TREE_MAGIC;
520*c8ec8eeaSjose borrego 
521*c8ec8eeaSjose borrego 	if (STYPE_ISDSK(stype)) {
522*c8ec8eeaSjose borrego 		smb_node_ref(snode);
523*c8ec8eeaSjose borrego 		tree->t_snode = snode;
524*c8ec8eeaSjose borrego 		tree->t_acltype = smb_fsop_acltype(snode);
525*c8ec8eeaSjose borrego 	}
526*c8ec8eeaSjose borrego 
527*c8ec8eeaSjose borrego 	smb_llist_enter(&user->u_tree_list, RW_WRITER);
528*c8ec8eeaSjose borrego 	smb_llist_insert_head(&user->u_tree_list, tree);
529da6c28aaSamw 	smb_llist_exit(&user->u_tree_list);
530*c8ec8eeaSjose borrego 	atomic_inc_32(&user->u_session->s_tree_cnt);
531*c8ec8eeaSjose borrego 	atomic_inc_32(&user->u_server->sv_open_trees);
532da6c28aaSamw 
533*c8ec8eeaSjose borrego 	return (tree);
534*c8ec8eeaSjose borrego }
535da6c28aaSamw 
536da6c28aaSamw /*
537*c8ec8eeaSjose borrego  * Deallocate a tree: release all resources associated with a tree and
538*c8ec8eeaSjose borrego  * remove the tree from the user's tree list.
539*c8ec8eeaSjose borrego  *
540*c8ec8eeaSjose borrego  * The tree being destroyed must be in the "destroying" state and the
541*c8ec8eeaSjose borrego  * reference count must be zero. This function assumes it's single threaded
542*c8ec8eeaSjose borrego  * i.e. only one thread will attempt to destroy a specific tree, which
543*c8ec8eeaSjose borrego  * should be the case if the tree is in disconnected and has a reference
544*c8ec8eeaSjose borrego  * count of zero.
545da6c28aaSamw  */
546da6c28aaSamw static void
547*c8ec8eeaSjose borrego smb_tree_dealloc(smb_tree_t *tree)
548da6c28aaSamw {
549da6c28aaSamw 	ASSERT(tree);
550da6c28aaSamw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
551da6c28aaSamw 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
552da6c28aaSamw 	ASSERT(tree->t_refcnt == 0);
553da6c28aaSamw 
554da6c28aaSamw 	/*
555*c8ec8eeaSjose borrego 	 * Remove the tree from the user's tree list.  This must be done
556*c8ec8eeaSjose borrego 	 * before any resources associated with the tree are released.
557da6c28aaSamw 	 */
558da6c28aaSamw 	smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER);
559da6c28aaSamw 	smb_llist_remove(&tree->t_user->u_tree_list, tree);
560da6c28aaSamw 	smb_llist_exit(&tree->t_user->u_tree_list);
561da6c28aaSamw 
562da6c28aaSamw 	tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
563da6c28aaSamw 	smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid);
564da6c28aaSamw 	atomic_dec_32(&tree->t_session->s_tree_cnt);
565da6c28aaSamw 
566*c8ec8eeaSjose borrego 	if (tree->t_snode)
567da6c28aaSamw 		smb_node_release(tree->t_snode);
568*c8ec8eeaSjose borrego 
569da6c28aaSamw 	mutex_destroy(&tree->t_mutex);
570*c8ec8eeaSjose borrego 
571da6c28aaSamw 	/*
572da6c28aaSamw 	 * The list of open files and open directories should be empty.
573da6c28aaSamw 	 */
574da6c28aaSamw 	smb_llist_destructor(&tree->t_ofile_list);
575da6c28aaSamw 	smb_llist_destructor(&tree->t_odir_list);
576da6c28aaSamw 	smb_idpool_destructor(&tree->t_fid_pool);
577da6c28aaSamw 	smb_idpool_destructor(&tree->t_sid_pool);
578faa1795aSjb 	kmem_cache_free(tree->t_server->si_cache_tree, tree);
579da6c28aaSamw }
580da6c28aaSamw 
581da6c28aaSamw /*
582*c8ec8eeaSjose borrego  * Determine whether or not a tree is connected.
583*c8ec8eeaSjose borrego  * This function must be called with the tree mutex held.
584*c8ec8eeaSjose borrego  */
585*c8ec8eeaSjose borrego static boolean_t
586*c8ec8eeaSjose borrego smb_tree_is_connected(smb_tree_t *tree)
587*c8ec8eeaSjose borrego {
588*c8ec8eeaSjose borrego 	switch (tree->t_state) {
589*c8ec8eeaSjose borrego 	case SMB_TREE_STATE_CONNECTED:
590*c8ec8eeaSjose borrego 		return (B_TRUE);
591*c8ec8eeaSjose borrego 
592*c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTING:
593*c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTED:
594*c8ec8eeaSjose borrego 		/*
595*c8ec8eeaSjose borrego 		 * The tree exists but being diconnected or destroyed.
596*c8ec8eeaSjose borrego 		 */
597*c8ec8eeaSjose borrego 		return (B_FALSE);
598*c8ec8eeaSjose borrego 
599*c8ec8eeaSjose borrego 	default:
600*c8ec8eeaSjose borrego 		ASSERT(0);
601*c8ec8eeaSjose borrego 		return (B_FALSE);
602*c8ec8eeaSjose borrego 	}
603*c8ec8eeaSjose borrego }
604*c8ec8eeaSjose borrego 
605*c8ec8eeaSjose borrego /*
606*c8ec8eeaSjose borrego  * Determine whether or not a tree is disconnected.
607*c8ec8eeaSjose borrego  * This function must be called with the tree mutex held.
608*c8ec8eeaSjose borrego  */
609*c8ec8eeaSjose borrego static boolean_t
610*c8ec8eeaSjose borrego smb_tree_is_disconnected(smb_tree_t *tree)
611*c8ec8eeaSjose borrego {
612*c8ec8eeaSjose borrego 	switch (tree->t_state) {
613*c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTED:
614*c8ec8eeaSjose borrego 		return (B_TRUE);
615*c8ec8eeaSjose borrego 
616*c8ec8eeaSjose borrego 	case SMB_TREE_STATE_CONNECTED:
617*c8ec8eeaSjose borrego 	case SMB_TREE_STATE_DISCONNECTING:
618*c8ec8eeaSjose borrego 		return (B_FALSE);
619*c8ec8eeaSjose borrego 
620*c8ec8eeaSjose borrego 	default:
621*c8ec8eeaSjose borrego 		ASSERT(0);
622*c8ec8eeaSjose borrego 		return (B_FALSE);
623*c8ec8eeaSjose borrego 	}
624*c8ec8eeaSjose borrego }
625*c8ec8eeaSjose borrego 
626*c8ec8eeaSjose borrego /*
627*c8ec8eeaSjose borrego  * Return a pointer to the share name within a share resource path.
628da6c28aaSamw  *
629*c8ec8eeaSjose borrego  * The share path may be a Uniform Naming Convention (UNC) string
630*c8ec8eeaSjose borrego  * (\\server\share) or simply the share name.  We validate the UNC
631*c8ec8eeaSjose borrego  * format but we don't look at the server name.
632*c8ec8eeaSjose borrego  */
633*c8ec8eeaSjose borrego static const char *
634*c8ec8eeaSjose borrego smb_tree_get_sharename(const char *unc_path)
635*c8ec8eeaSjose borrego {
636*c8ec8eeaSjose borrego 	const char *sharename = unc_path;
637*c8ec8eeaSjose borrego 
638*c8ec8eeaSjose borrego 	if (sharename[0] == '\\') {
639*c8ec8eeaSjose borrego 		/*
640*c8ec8eeaSjose borrego 		 * Looks like a UNC path, validate the format.
641*c8ec8eeaSjose borrego 		 */
642*c8ec8eeaSjose borrego 		if (sharename[1] != '\\')
643*c8ec8eeaSjose borrego 			return (NULL);
644*c8ec8eeaSjose borrego 
645*c8ec8eeaSjose borrego 		if ((sharename = strchr(sharename+2, '\\')) == NULL)
646*c8ec8eeaSjose borrego 			return (NULL);
647*c8ec8eeaSjose borrego 
648*c8ec8eeaSjose borrego 		++sharename;
649*c8ec8eeaSjose borrego 	} else if (strchr(sharename, '\\') != NULL) {
650*c8ec8eeaSjose borrego 		/*
651*c8ec8eeaSjose borrego 		 * This should be a share name (no embedded \'s).
652*c8ec8eeaSjose borrego 		 */
653*c8ec8eeaSjose borrego 		return (NULL);
654*c8ec8eeaSjose borrego 	}
655*c8ec8eeaSjose borrego 
656*c8ec8eeaSjose borrego 	return (sharename);
657*c8ec8eeaSjose borrego }
658*c8ec8eeaSjose borrego 
659*c8ec8eeaSjose borrego /*
660*c8ec8eeaSjose borrego  * Map the service to a resource type.  Valid values for service are:
661da6c28aaSamw  *
662*c8ec8eeaSjose borrego  *	A:      Disk share
663*c8ec8eeaSjose borrego  *	LPT1:   Printer
664*c8ec8eeaSjose borrego  *	IPC     Named pipe
665*c8ec8eeaSjose borrego  *	COMM    Communications device
666*c8ec8eeaSjose borrego  *	?????   Any type of device (wildcard)
667da6c28aaSamw  *
668*c8ec8eeaSjose borrego  * We support IPC and disk shares; anything else is currently treated
669*c8ec8eeaSjose borrego  * as an error.  IPC$ is reserved as the named pipe share.
670da6c28aaSamw  */
671*c8ec8eeaSjose borrego static int
672*c8ec8eeaSjose borrego smb_tree_get_stype(const char *sharename, const char *service,
673*c8ec8eeaSjose borrego     int32_t *stype_ret)
674da6c28aaSamw {
675*c8ec8eeaSjose borrego 	const char *any = "?????";
676da6c28aaSamw 
677*c8ec8eeaSjose borrego 	if ((strcmp(service, any) == 0) || (strcasecmp(service, "IPC") == 0)) {
678*c8ec8eeaSjose borrego 		if (strcasecmp(sharename, "IPC$") == 0) {
679*c8ec8eeaSjose borrego 			*stype_ret = STYPE_IPC;
680*c8ec8eeaSjose borrego 			return (0);
681da6c28aaSamw 		}
682da6c28aaSamw 	}
683da6c28aaSamw 
684*c8ec8eeaSjose borrego 	if ((strcmp(service, any) == 0) || (strcasecmp(service, "A:") == 0)) {
685*c8ec8eeaSjose borrego 		if (strcasecmp(sharename, "IPC$") == 0)
686*c8ec8eeaSjose borrego 			return (-1);
687*c8ec8eeaSjose borrego 
688*c8ec8eeaSjose borrego 		*stype_ret = STYPE_DISKTREE;
689*c8ec8eeaSjose borrego 		return (0);
690*c8ec8eeaSjose borrego 	}
691*c8ec8eeaSjose borrego 
692*c8ec8eeaSjose borrego 	return (-1);
693da6c28aaSamw }
694da6c28aaSamw 
695da6c28aaSamw /*
696*c8ec8eeaSjose borrego  * Obtain the tree attributes: volume name, typename and flags.
697*c8ec8eeaSjose borrego  */
698*c8ec8eeaSjose borrego static int
699*c8ec8eeaSjose borrego smb_tree_getattr(smb_node_t *node, smb_tree_t *tree)
700*c8ec8eeaSjose borrego {
701*c8ec8eeaSjose borrego 	vfs_t *vfsp = SMB_NODE_VFS(node);
702*c8ec8eeaSjose borrego 
703*c8ec8eeaSjose borrego 	ASSERT(vfsp);
704*c8ec8eeaSjose borrego 
705*c8ec8eeaSjose borrego 	if (getvfs(&vfsp->vfs_fsid) != vfsp)
706*c8ec8eeaSjose borrego 		return (ESTALE);
707*c8ec8eeaSjose borrego 
708*c8ec8eeaSjose borrego 	smb_tree_get_volname(vfsp, tree);
709*c8ec8eeaSjose borrego 	smb_tree_get_flags(vfsp, tree);
710*c8ec8eeaSjose borrego 
711*c8ec8eeaSjose borrego 	VFS_RELE(vfsp);
712*c8ec8eeaSjose borrego 	return (0);
713*c8ec8eeaSjose borrego }
714*c8ec8eeaSjose borrego 
715*c8ec8eeaSjose borrego /*
716*c8ec8eeaSjose borrego  * Extract the volume name.
717*c8ec8eeaSjose borrego  */
718*c8ec8eeaSjose borrego static void
719*c8ec8eeaSjose borrego smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
720*c8ec8eeaSjose borrego {
721*c8ec8eeaSjose borrego 	refstr_t *vfs_mntpoint;
722*c8ec8eeaSjose borrego 	const char *s;
723*c8ec8eeaSjose borrego 	char *name;
724*c8ec8eeaSjose borrego 
725*c8ec8eeaSjose borrego 	vfs_mntpoint = vfs_getmntpoint(vfsp);
726*c8ec8eeaSjose borrego 
727*c8ec8eeaSjose borrego 	s = vfs_mntpoint->rs_string;
728*c8ec8eeaSjose borrego 	s += strspn(s, "/");
729*c8ec8eeaSjose borrego 	(void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
730*c8ec8eeaSjose borrego 
731*c8ec8eeaSjose borrego 	refstr_rele(vfs_mntpoint);
732*c8ec8eeaSjose borrego 
733*c8ec8eeaSjose borrego 	name = tree->t_volume;
734*c8ec8eeaSjose borrego 	(void) strsep((char **)&name, "/");
735*c8ec8eeaSjose borrego }
736*c8ec8eeaSjose borrego 
737*c8ec8eeaSjose borrego /*
738*c8ec8eeaSjose borrego  * Always set ACL support because the VFS will fake ACLs for file systems
739*c8ec8eeaSjose borrego  * that don't support them.
740da6c28aaSamw  *
741*c8ec8eeaSjose borrego  * Some flags are dependent on the typename, which is also set up here.
742*c8ec8eeaSjose borrego  * File system types are hardcoded in uts/common/os/vfs_conf.c.
743da6c28aaSamw  */
744*c8ec8eeaSjose borrego static void
745*c8ec8eeaSjose borrego smb_tree_get_flags(vfs_t *vfsp, smb_tree_t *tree)
746da6c28aaSamw {
747*c8ec8eeaSjose borrego 	uint32_t flags = SMB_TREE_SUPPORTS_ACLS;
748*c8ec8eeaSjose borrego 	char *name;
749da6c28aaSamw 
750*c8ec8eeaSjose borrego 	if (vfsp->vfs_flag & VFS_RDONLY)
751*c8ec8eeaSjose borrego 		flags |= SMB_TREE_READONLY;
752*c8ec8eeaSjose borrego 
753*c8ec8eeaSjose borrego 	if (vfsp->vfs_flag & VFS_XATTR)
754*c8ec8eeaSjose borrego 		flags |= SMB_TREE_STREAMS;
755*c8ec8eeaSjose borrego 
756*c8ec8eeaSjose borrego 	if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL))
757*c8ec8eeaSjose borrego 		flags |= SMB_TREE_NO_ATIME;
758*c8ec8eeaSjose borrego 
759*c8ec8eeaSjose borrego 	name = vfssw[vfsp->vfs_fstype].vsw_name;
760*c8ec8eeaSjose borrego 
761*c8ec8eeaSjose borrego 	if (strcmp(name, "tmpfs") == 0)
762*c8ec8eeaSjose borrego 		flags |= SMB_TREE_NO_EXPORT;
763*c8ec8eeaSjose borrego 
764*c8ec8eeaSjose borrego 	if (strncasecmp(name, NFS, sizeof (NFS)) == 0)
765*c8ec8eeaSjose borrego 		flags |= SMB_TREE_NFS_MOUNTED;
766*c8ec8eeaSjose borrego 
767*c8ec8eeaSjose borrego 	if (strncasecmp(name, "UFS", sizeof ("UFS")) == 0)
768*c8ec8eeaSjose borrego 		flags |= SMB_TREE_UFS;
769*c8ec8eeaSjose borrego 
770*c8ec8eeaSjose borrego 	(void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
771*c8ec8eeaSjose borrego 	(void) utf8_strupr((char *)tree->t_typename);
772da6c28aaSamw 
773*c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_XVATTR))
774*c8ec8eeaSjose borrego 		flags |= SMB_TREE_XVATTR;
775*c8ec8eeaSjose borrego 
776*c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
777*c8ec8eeaSjose borrego 		flags |= SMB_TREE_CASEINSENSITIVE;
778*c8ec8eeaSjose borrego 
779*c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
780*c8ec8eeaSjose borrego 		flags |= SMB_TREE_NO_CASESENSITIVE;
781*c8ec8eeaSjose borrego 
782*c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
783*c8ec8eeaSjose borrego 		flags |= SMB_TREE_DIRENTFLAGS;
784*c8ec8eeaSjose borrego 
785*c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
786*c8ec8eeaSjose borrego 		flags |= SMB_TREE_ACLONCREATE;
787*c8ec8eeaSjose borrego 
788*c8ec8eeaSjose borrego 	if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
789*c8ec8eeaSjose borrego 		flags |= SMB_TREE_ACEMASKONACCESS;
790*c8ec8eeaSjose borrego 
791*c8ec8eeaSjose borrego 	DTRACE_PROBE1(smb__tree__flags, uint32_t, flags);
792*c8ec8eeaSjose borrego 
793*c8ec8eeaSjose borrego 	tree->t_flags = flags;
794*c8ec8eeaSjose borrego }
795*c8ec8eeaSjose borrego 
796*c8ec8eeaSjose borrego /*
797*c8ec8eeaSjose borrego  * Report share access result to syslog.
798*c8ec8eeaSjose borrego  */
799*c8ec8eeaSjose borrego static void
800*c8ec8eeaSjose borrego smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
801*c8ec8eeaSjose borrego {
802*c8ec8eeaSjose borrego 	va_list ap;
803*c8ec8eeaSjose borrego 	char buf[128];
804*c8ec8eeaSjose borrego 	smb_user_t *user = sr->uid_user;
805*c8ec8eeaSjose borrego 
806*c8ec8eeaSjose borrego 	ASSERT(user);
807*c8ec8eeaSjose borrego 
808*c8ec8eeaSjose borrego 	if (smb_tcon_mute)
809*c8ec8eeaSjose borrego 		return;
810*c8ec8eeaSjose borrego 
811*c8ec8eeaSjose borrego 	if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
812*c8ec8eeaSjose borrego 		/*
813*c8ec8eeaSjose borrego 		 * Only report normal users, i.e. ignore W2K misuse
814*c8ec8eeaSjose borrego 		 * of the IPC connection by filtering out internal
815*c8ec8eeaSjose borrego 		 * names such as nobody and root.
816*c8ec8eeaSjose borrego 		 */
817*c8ec8eeaSjose borrego 		if ((strcmp(user->u_name, "root") == 0) ||
818*c8ec8eeaSjose borrego 		    (strcmp(user->u_name, "nobody") == 0)) {
819*c8ec8eeaSjose borrego 			return;
820da6c28aaSamw 		}
821da6c28aaSamw 	}
822da6c28aaSamw 
823*c8ec8eeaSjose borrego 	va_start(ap, fmt);
824*c8ec8eeaSjose borrego 	(void) vsnprintf(buf, 128, fmt, ap);
825*c8ec8eeaSjose borrego 	va_end(ap);
826*c8ec8eeaSjose borrego 
827*c8ec8eeaSjose borrego 	cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
828*c8ec8eeaSjose borrego 	    user->u_domain, user->u_name, sharename, buf);
829da6c28aaSamw }
830