xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_tree.c (revision 56e2cc86321ec889bf83a888d902c60d6fb2ef8d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * General Structures Layout
28  * -------------------------
29  *
30  * This is a simplified diagram showing the relationship between most of the
31  * main structures.
32  *
33  * +-------------------+
34  * |     SMB_INFO      |
35  * +-------------------+
36  *          |
37  *          |
38  *          v
39  * +-------------------+       +-------------------+      +-------------------+
40  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
41  * +-------------------+       +-------------------+      +-------------------+
42  *          |
43  *          |
44  *          v
45  * +-------------------+       +-------------------+      +-------------------+
46  * |       USER        |<----->|       USER        |......|       USER        |
47  * +-------------------+       +-------------------+      +-------------------+
48  *          |
49  *          |
50  *          v
51  * +-------------------+       +-------------------+      +-------------------+
52  * |       TREE        |<----->|       TREE        |......|       TREE        |
53  * +-------------------+       +-------------------+      +-------------------+
54  *      |         |
55  *      |         |
56  *      |         v
57  *      |     +-------+       +-------+      +-------+
58  *      |     | OFILE |<----->| OFILE |......| OFILE |
59  *      |     +-------+       +-------+      +-------+
60  *      |
61  *      |
62  *      v
63  *  +-------+       +------+      +------+
64  *  | ODIR  |<----->| ODIR |......| ODIR |
65  *  +-------+       +------+      +------+
66  *
67  *
68  * Tree State Machine
69  * ------------------
70  *
71  *    +-----------------------------+	 T0
72  *    |  SMB_TREE_STATE_CONNECTED   |<----------- Creation/Allocation
73  *    +-----------------------------+
74  *		    |
75  *		    | T1
76  *		    |
77  *		    v
78  *    +------------------------------+
79  *    | SMB_TREE_STATE_DISCONNECTING |
80  *    +------------------------------+
81  *		    |
82  *		    | T2
83  *		    |
84  *		    v
85  *    +-----------------------------+    T3
86  *    | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free
87  *    +-----------------------------+
88  *
89  * SMB_TREE_STATE_CONNECTED
90  *
91  *    While in this state:
92  *      - The tree is queued in the list of trees of its user.
93  *      - References will be given out if the tree is looked up.
94  *      - Files under that tree can be accessed.
95  *
96  * SMB_TREE_STATE_DISCONNECTING
97  *
98  *    While in this state:
99  *      - The tree is queued in the list of trees of its user.
100  *      - References will not be given out if the tree is looked up.
101  *      - The files and directories open under the tree are being closed.
102  *      - The resources associated with the tree remain.
103  *
104  * SMB_TREE_STATE_DISCONNECTED
105  *
106  *    While in this state:
107  *      - The tree is queued in the list of trees of its user.
108  *      - References will not be given out if the tree is looked up.
109  *      - The tree has no more files and directories opened.
110  *      - The resources associated with the tree remain.
111  *
112  * Transition T0
113  *
114  *    This transition occurs in smb_tree_connect(). A new tree is created and
115  *    added to the list of trees of a user.
116  *
117  * Transition T1
118  *
119  *    This transition occurs in smb_tree_disconnect().
120  *
121  * Transition T2
122  *
123  *    This transition occurs in smb_tree_release(). The resources associated
124  *    with the tree are freed as well as the tree structure. For the transition
125  *    to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED state and
126  *    the reference count be zero.
127  *
128  * Comments
129  * --------
130  *
131  *    The state machine of the tree structures is controlled by 3 elements:
132  *      - The list of trees of the user it belongs to.
133  *      - The mutex embedded in the structure itself.
134  *      - The reference count.
135  *
136  *    There's a mutex embedded in the tree structure used to protect its fields
137  *    and there's a lock embedded in the list of trees of a user. To
138  *    increment or to decrement the reference count the mutex must be entered.
139  *    To insert the tree into the list of trees of the user and to remove
140  *    the tree from it, the lock must be entered in RW_WRITER mode.
141  *
142  *    Rules of access to a tree structure:
143  *
144  *    1) In order to avoid deadlocks, when both (mutex and lock of the user
145  *       list) have to be entered, the lock must be entered first.
146  *
147  *    2) All actions applied to a tree require a reference count.
148  *
149  *    3) There are 2 ways of getting a reference count: when a tree is
150  *       connected and when a tree is looked up.
151  *
152  *    It should be noted that the reference count of a tree registers the
153  *    number of references to the tree in other structures (such as an smb
154  *    request). The reference count is not incremented in these 2 instances:
155  *
156  *    1) The tree is connected. An tree is anchored by his state. If there's
157  *       no activity involving a tree currently connected, the reference
158  *       count of that tree is zero.
159  *
160  *    2) The tree is queued in the list of trees of the user. The fact of
161  *       being queued in that list is NOT registered by incrementing the
162  *       reference count.
163  */
164 #include <sys/types.h>
165 #include <sys/refstr_impl.h>
166 #include <sys/feature_tests.h>
167 #include <sys/sunddi.h>
168 #include <sys/fsid.h>
169 #include <sys/vfs.h>
170 #include <sys/stat.h>
171 #include <sys/varargs.h>
172 #include <smbsrv/smb_incl.h>
173 #include <smbsrv/lmerr.h>
174 #include <smbsrv/smb_fsops.h>
175 #include <smbsrv/smb_door_svc.h>
176 #include <smbsrv/smb_share.h>
177 #include <sys/pathname.h>
178 
179 int smb_tcon_mute = 0;
180 
181 static smb_tree_t *smb_tree_connect_disk(smb_request_t *, const char *);
182 static smb_tree_t *smb_tree_connect_ipc(smb_request_t *, const char *);
183 static smb_tree_t *smb_tree_alloc(smb_user_t *, const smb_share_t *,
184     int32_t, smb_node_t *, uint32_t);
185 static void smb_tree_dealloc(smb_tree_t *);
186 static boolean_t smb_tree_is_connected_locked(smb_tree_t *);
187 static boolean_t smb_tree_is_disconnected(smb_tree_t *);
188 static const char *smb_tree_get_sharename(const char *);
189 static int smb_tree_get_stype(const char *, const char *, int32_t *);
190 static int smb_tree_getattr(const smb_share_t *, smb_node_t *, smb_tree_t *);
191 static void smb_tree_get_volname(vfs_t *, smb_tree_t *);
192 static void smb_tree_get_flags(const smb_share_t *, vfs_t *, smb_tree_t *);
193 static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
194 static void smb_tree_close_odirs(smb_tree_t *, uint16_t);
195 static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *);
196 
197 /*
198  * Extract the share name and share type and connect as appropriate.
199  * Share names are case insensitive so we map the share name to
200  * lower-case as a convenience for internal processing.
201  */
202 smb_tree_t *
203 smb_tree_connect(smb_request_t *sr)
204 {
205 	char *unc_path = sr->arg.tcon.path;
206 	char *service = sr->arg.tcon.service;
207 	smb_tree_t *tree = NULL;
208 	const char *name;
209 	int32_t stype;
210 
211 	(void) utf8_strlwr(unc_path);
212 
213 	if ((name = smb_tree_get_sharename(unc_path)) == NULL) {
214 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
215 		return (NULL);
216 	}
217 
218 	if (smb_tree_get_stype(name, service, &stype) != 0) {
219 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
220 		    ERRDOS, ERROR_BAD_DEV_TYPE);
221 		return (NULL);
222 	}
223 
224 	switch (stype & STYPE_MASK) {
225 	case STYPE_DISKTREE:
226 		tree = smb_tree_connect_disk(sr, name);
227 		break;
228 
229 	case STYPE_IPC:
230 		tree = smb_tree_connect_ipc(sr, name);
231 		break;
232 
233 	default:
234 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
235 		    ERRDOS, ERROR_BAD_DEV_TYPE);
236 		break;
237 	}
238 
239 	return (tree);
240 }
241 
242 /*
243  * Disconnect a tree.
244  */
245 void
246 smb_tree_disconnect(
247     smb_tree_t	*tree)
248 {
249 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
250 
251 	mutex_enter(&tree->t_mutex);
252 	ASSERT(tree->t_refcnt);
253 
254 	if (smb_tree_is_connected_locked(tree)) {
255 		/*
256 		 * Indicate that the disconnect process has started.
257 		 */
258 		tree->t_state = SMB_TREE_STATE_DISCONNECTING;
259 		mutex_exit(&tree->t_mutex);
260 		atomic_dec_32(&tree->t_server->sv_open_trees);
261 
262 		/*
263 		 * The files opened under this tree are closed.
264 		 */
265 		smb_ofile_close_all(tree);
266 		/*
267 		 * The directories opened under this tree are closed.
268 		 */
269 		smb_tree_close_odirs(tree, 0);
270 		mutex_enter(&tree->t_mutex);
271 		tree->t_state = SMB_TREE_STATE_DISCONNECTED;
272 	}
273 
274 	mutex_exit(&tree->t_mutex);
275 }
276 
277 /*
278  * Take a reference on a tree.
279  */
280 boolean_t
281 smb_tree_hold(
282     smb_tree_t		*tree)
283 {
284 	ASSERT(tree);
285 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
286 
287 	mutex_enter(&tree->t_mutex);
288 
289 	if (smb_tree_is_connected_locked(tree)) {
290 		tree->t_refcnt++;
291 		mutex_exit(&tree->t_mutex);
292 		return (B_TRUE);
293 	}
294 
295 	mutex_exit(&tree->t_mutex);
296 	return (B_FALSE);
297 }
298 
299 /*
300  * Release a reference on a tree.  If the tree is disconnected and the
301  * reference count falls to zero, the tree will be deallocated.
302  */
303 void
304 smb_tree_release(
305     smb_tree_t		*tree)
306 {
307 	ASSERT(tree);
308 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
309 
310 	mutex_enter(&tree->t_mutex);
311 	ASSERT(tree->t_refcnt);
312 	tree->t_refcnt--;
313 
314 	if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0)) {
315 		mutex_exit(&tree->t_mutex);
316 		smb_tree_dealloc(tree);
317 		return;
318 	}
319 
320 	mutex_exit(&tree->t_mutex);
321 }
322 
323 /*
324  * Close ofiles and odirs that match pid.
325  */
326 void
327 smb_tree_close_pid(
328     smb_tree_t		*tree,
329     uint16_t		pid)
330 {
331 	ASSERT(tree);
332 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
333 
334 	smb_ofile_close_all_by_pid(tree, pid);
335 	smb_tree_close_odirs(tree, pid);
336 }
337 
338 /*
339  * Check whether or not a tree supports the features identified by flags.
340  */
341 boolean_t
342 smb_tree_has_feature(smb_tree_t *tree, uint32_t flags)
343 {
344 	ASSERT(tree);
345 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
346 
347 	return ((tree->t_flags & flags) == flags);
348 }
349 
350 
351 /* *************************** Static Functions ***************************** */
352 #define	SHARES_DIR	".zfs/shares/"
353 static void
354 smb_tree_acl_access(cred_t *cred, const char *sharename, vnode_t *pathvp,
355 		    uint32_t *access)
356 {
357 	int rc;
358 	vfs_t *vfsp;
359 	vnode_t *root = NULL;
360 	vnode_t *sharevp = NULL;
361 	char *sharepath;
362 	struct pathname pnp;
363 	size_t size;
364 
365 	*access = ACE_ALL_PERMS; /* default to full "UNIX" access */
366 
367 	/*
368 	 * Using the vnode of the share path, we then find the root
369 	 * directory of the mounted file system. We will then look to
370 	 * see if there is a .zfs/shares directory and if there is,
371 	 * get the access information from the ACL/ACES values and
372 	 * check against the cred.
373 	 */
374 	vfsp = pathvp->v_vfsp;
375 	if (vfsp != NULL)
376 		rc = VFS_ROOT(vfsp, &root);
377 	else
378 		rc = ENOENT;
379 
380 	if (rc != 0)
381 		return;
382 
383 
384 	/*
385 	 * Find the share object, if there is one. Need to construct
386 	 * the path to the .zfs/shares/<sharename> object and look it
387 	 * up.  root is called held but will be released by
388 	 * lookuppnvp().
389 	 */
390 
391 	size = sizeof (SHARES_DIR) + strlen(sharename) + 1;
392 	sharepath = kmem_alloc(size, KM_SLEEP);
393 	(void) sprintf(sharepath, "%s%s", SHARES_DIR, sharename);
394 
395 	pn_alloc(&pnp);
396 	(void) pn_set(&pnp, sharepath);
397 	rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL,
398 	    &sharevp, rootdir, root, kcred);
399 	pn_free(&pnp);
400 
401 	kmem_free(sharepath, size);
402 
403 	/*
404 	 * Now get the effective access value based on cred and ACL
405 	 * values.
406 	 */
407 
408 	if (rc == 0)
409 		smb_vop_eaccess(sharevp, (int *)access, V_ACE_MASK, NULL, cred);
410 
411 }
412 
413 /*
414  * Connect a share for use with files and directories.
415  */
416 
417 static smb_tree_t *
418 smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
419 {
420 	smb_user_t		*user = sr->uid_user;
421 	smb_node_t		*dir_snode = NULL;
422 	smb_node_t		*snode = NULL;
423 	char			last_component[MAXNAMELEN];
424 	smb_tree_t		*tree;
425 	smb_share_t 		*si;
426 	smb_attr_t		attr;
427 	cred_t			*u_cred;
428 	int			rc;
429 	uint32_t		access = 0; /* read/write is assumed */
430 	uint32_t		hostaccess = ACE_ALL_PERMS;
431 	uint32_t		aclaccess;
432 
433 	ASSERT(user);
434 	u_cred = user->u_cred;
435 	ASSERT(u_cred);
436 
437 	if (user->u_flags & SMB_USER_FLAG_IPC) {
438 		smb_tree_log(sr, sharename, "access denied: IPC only");
439 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
440 		return (NULL);
441 	}
442 
443 	si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP);
444 
445 	if (smb_kshare_getinfo(sr->sr_server->sv_lmshrd, (char *)sharename, si,
446 	    &sr->session->ipaddr) != NERR_Success) {
447 		smb_tree_log(sr, sharename, "share not found");
448 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
449 		kmem_free(si, sizeof (smb_share_t));
450 		return (NULL);
451 	}
452 
453 	/*
454 	 * Handle the default administration shares: C$, D$ etc.
455 	 * Only a user with admin rights is allowed to map these
456 	 * shares.
457 	 */
458 	if (si->shr_flags & SMB_SHRF_ADMIN) {
459 		if (!smb_user_is_admin(user)) {
460 			smb_tree_log(sr, sharename, "access denied: not admin");
461 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
462 			    ERRSRV, ERRaccess);
463 			kmem_free(si, sizeof (smb_share_t));
464 			return (NULL);
465 		}
466 	}
467 
468 	/*
469 	 * Set up the OptionalSupport for this share.
470 	 */
471 	sr->arg.tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
472 
473 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
474 	case SMB_SHRF_CSC_DISABLED:
475 		sr->arg.tcon.optional_support |= SMB_CSC_CACHE_NONE;
476 		break;
477 	case SMB_SHRF_CSC_AUTO:
478 		sr->arg.tcon.optional_support |= SMB_CSC_CACHE_AUTO_REINT;
479 		break;
480 	case SMB_SHRF_CSC_VDO:
481 		sr->arg.tcon.optional_support |= SMB_CSC_CACHE_VDO;
482 		break;
483 	case SMB_SHRF_CSC_MANUAL:
484 	default:
485 		/*
486 		 * Default to SMB_CSC_CACHE_MANUAL_REINT.
487 		 */
488 		break;
489 	}
490 
491 	access = si->shr_access_value & SMB_SHRF_ACC_ALL;
492 
493 	if (access == SMB_SHRF_ACC_RO) {
494 		hostaccess &= ~ACE_ALL_WRITE_PERMS;
495 	} else if (access == SMB_SHRF_ACC_NONE) {
496 		kmem_free(si, sizeof (smb_share_t));
497 		smb_tree_log(sr, sharename, "access denied: host access");
498 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
499 		return (NULL);
500 	}
501 
502 	/*
503 	 * Check that the shared directory exists.
504 	 */
505 	rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dir_snode,
506 	    last_component);
507 
508 	if (rc == 0) {
509 		rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS,
510 		    sr->sr_server->si_root_smb_node, dir_snode, last_component,
511 		    &snode, &attr);
512 
513 		smb_node_release(dir_snode);
514 	}
515 
516 	if (rc) {
517 		if (snode)
518 			smb_node_release(snode);
519 
520 		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
521 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
522 		kmem_free(si, sizeof (smb_share_t));
523 		return (NULL);
524 	}
525 
526 	/*
527 	 * Find share level ACL if it exists in the designated
528 	 * location. Needs to be done after finding a valid path but
529 	 * before the tree is allocated.
530 	 */
531 	smb_tree_acl_access(u_cred, sharename, snode->vp, &aclaccess);
532 	/* if an error, then no share file -- default to no ACL */
533 	if (rc == 0) {
534 		/*
535 		 * There need to be some permissions in order to have
536 		 * any access.
537 		 */
538 		if ((aclaccess & ACE_ALL_PERMS) == 0) {
539 			smb_tree_log(sr, sharename, "access denied: share ACL");
540 			smbsr_error(sr, 0, ERRSRV, ERRaccess);
541 			kmem_free(si, sizeof (smb_share_t));
542 			smb_node_release(snode);
543 			return (NULL);
544 		}
545 	}
546 
547 	/*
548 	 * Set tree ACL access to the minimum ACL permissions based on
549 	 * hostaccess (those allowed by host based access) and
550 	 * aclaccess (those from the ACL object for the share). This
551 	 * is done during the alloc.
552 	 */
553 
554 	(void) strlcpy(si->shr_name, sharename, MAXNAMELEN);
555 	tree = smb_tree_alloc(user, si, STYPE_DISKTREE, snode,
556 	    hostaccess & aclaccess);
557 
558 	if (tree == NULL)
559 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
560 
561 	smb_node_release(snode);
562 	kmem_free(si, sizeof (smb_share_t));
563 	return (tree);
564 }
565 
566 /*
567  * Connect an IPC share for use with named pipes.
568  */
569 static smb_tree_t *
570 smb_tree_connect_ipc(smb_request_t *sr, const char *name)
571 {
572 	smb_user_t	*user = sr->uid_user;
573 	smb_tree_t	*tree;
574 	smb_share_t	*si;
575 
576 	ASSERT(user);
577 
578 	if ((user->u_flags & SMB_USER_FLAG_IPC) &&
579 	    sr->sr_cfg->skc_restrict_anon) {
580 		smb_tree_log(sr, name, "access denied: restrict anonymous");
581 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
582 		return (NULL);
583 	}
584 
585 	sr->arg.tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
586 
587 	si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP);
588 	(void) strlcpy(si->shr_name, name, MAXNAMELEN);
589 	(void) strlcpy(si->shr_path, name, MAXPATHLEN);
590 	si->shr_type = STYPE_IPC | STYPE_SPECIAL;
591 
592 	tree = smb_tree_alloc(user, si, STYPE_IPC, NULL, ACE_ALL_PERMS);
593 	if (tree == NULL) {
594 		smb_tree_log(sr, name, "access denied");
595 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
596 	}
597 
598 	kmem_free(si, sizeof (smb_share_t));
599 	return (tree);
600 }
601 
602 /*
603  * Allocate a tree.
604  */
605 static smb_tree_t *
606 smb_tree_alloc(
607     smb_user_t		*user,
608     const smb_share_t	*si,
609     int32_t		stype,
610     smb_node_t		*snode,
611     uint32_t access)
612 {
613 	smb_tree_t	*tree;
614 	uint16_t	tid;
615 
616 	if (smb_idpool_alloc(&user->u_tid_pool, &tid))
617 		return (NULL);
618 
619 	tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP);
620 	bzero(tree, sizeof (smb_tree_t));
621 
622 	if (STYPE_ISDSK(stype)) {
623 		if (smb_tree_getattr(si, snode, tree) != 0) {
624 			smb_idpool_free(&user->u_tid_pool, tid);
625 			kmem_cache_free(user->u_server->si_cache_tree, tree);
626 			return (NULL);
627 		}
628 	}
629 
630 	if (smb_idpool_constructor(&tree->t_fid_pool)) {
631 		smb_idpool_free(&user->u_tid_pool, tid);
632 		kmem_cache_free(user->u_server->si_cache_tree, tree);
633 		return (NULL);
634 	}
635 
636 	if (smb_idpool_constructor(&tree->t_odid_pool)) {
637 		smb_idpool_destructor(&tree->t_fid_pool);
638 		smb_idpool_free(&user->u_tid_pool, tid);
639 		kmem_cache_free(user->u_server->si_cache_tree, tree);
640 		return (NULL);
641 	}
642 
643 	smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
644 	    offsetof(smb_ofile_t, f_lnd));
645 
646 	smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
647 	    offsetof(smb_odir_t, d_lnd));
648 
649 	(void) strlcpy(tree->t_sharename, si->shr_name,
650 	    sizeof (tree->t_sharename));
651 	(void) strlcpy(tree->t_resource, si->shr_path,
652 	    sizeof (tree->t_resource));
653 
654 	mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
655 
656 	tree->t_user = user;
657 	tree->t_session = user->u_session;
658 	tree->t_server = user->u_server;
659 	tree->t_refcnt = 1;
660 	tree->t_tid = tid;
661 	tree->t_res_type = stype;
662 	tree->t_state = SMB_TREE_STATE_CONNECTED;
663 	tree->t_magic = SMB_TREE_MAGIC;
664 	tree->t_access = access;
665 
666 	/* if FS is readonly, enforce that here */
667 	if (tree->t_flags & SMB_TREE_READONLY)
668 		tree->t_access &= ~ACE_ALL_WRITE_PERMS;
669 
670 	if (STYPE_ISDSK(stype)) {
671 		smb_node_ref(snode);
672 		tree->t_snode = snode;
673 		tree->t_acltype = smb_fsop_acltype(snode);
674 	}
675 
676 	smb_llist_enter(&user->u_tree_list, RW_WRITER);
677 	smb_llist_insert_head(&user->u_tree_list, tree);
678 	smb_llist_exit(&user->u_tree_list);
679 	atomic_inc_32(&user->u_session->s_tree_cnt);
680 	atomic_inc_32(&user->u_server->sv_open_trees);
681 
682 	return (tree);
683 }
684 
685 /*
686  * Deallocate a tree: release all resources associated with a tree and
687  * remove the tree from the user's tree list.
688  *
689  * The tree being destroyed must be in the "destroying" state and the
690  * reference count must be zero. This function assumes it's single threaded
691  * i.e. only one thread will attempt to destroy a specific tree, which
692  * should be the case if the tree is in disconnected and has a reference
693  * count of zero.
694  */
695 static void
696 smb_tree_dealloc(smb_tree_t *tree)
697 {
698 	ASSERT(tree);
699 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
700 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
701 	ASSERT(tree->t_refcnt == 0);
702 
703 	/*
704 	 * Remove the tree from the user's tree list.  This must be done
705 	 * before any resources associated with the tree are released.
706 	 */
707 	smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER);
708 	smb_llist_remove(&tree->t_user->u_tree_list, tree);
709 	smb_llist_exit(&tree->t_user->u_tree_list);
710 
711 	tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
712 	smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid);
713 	atomic_dec_32(&tree->t_session->s_tree_cnt);
714 
715 	if (tree->t_snode)
716 		smb_node_release(tree->t_snode);
717 
718 	mutex_destroy(&tree->t_mutex);
719 
720 	/*
721 	 * The list of open files and open directories should be empty.
722 	 */
723 	smb_llist_destructor(&tree->t_ofile_list);
724 	smb_llist_destructor(&tree->t_odir_list);
725 	smb_idpool_destructor(&tree->t_fid_pool);
726 	smb_idpool_destructor(&tree->t_odid_pool);
727 	kmem_cache_free(tree->t_server->si_cache_tree, tree);
728 }
729 
730 /*
731  * Determine whether or not a tree is connected.
732  * This function must be called with the tree mutex held.
733  */
734 static boolean_t
735 smb_tree_is_connected_locked(smb_tree_t *tree)
736 {
737 	switch (tree->t_state) {
738 	case SMB_TREE_STATE_CONNECTED:
739 		return (B_TRUE);
740 
741 	case SMB_TREE_STATE_DISCONNECTING:
742 	case SMB_TREE_STATE_DISCONNECTED:
743 		/*
744 		 * The tree exists but being diconnected or destroyed.
745 		 */
746 		return (B_FALSE);
747 
748 	default:
749 		ASSERT(0);
750 		return (B_FALSE);
751 	}
752 }
753 
754 /*
755  * Determine whether or not a tree is disconnected.
756  * This function must be called with the tree mutex held.
757  */
758 static boolean_t
759 smb_tree_is_disconnected(smb_tree_t *tree)
760 {
761 	switch (tree->t_state) {
762 	case SMB_TREE_STATE_DISCONNECTED:
763 		return (B_TRUE);
764 
765 	case SMB_TREE_STATE_CONNECTED:
766 	case SMB_TREE_STATE_DISCONNECTING:
767 		return (B_FALSE);
768 
769 	default:
770 		ASSERT(0);
771 		return (B_FALSE);
772 	}
773 }
774 
775 /*
776  * Return a pointer to the share name within a share resource path.
777  *
778  * The share path may be a Uniform Naming Convention (UNC) string
779  * (\\server\share) or simply the share name.  We validate the UNC
780  * format but we don't look at the server name.
781  */
782 static const char *
783 smb_tree_get_sharename(const char *unc_path)
784 {
785 	const char *sharename = unc_path;
786 
787 	if (sharename[0] == '\\') {
788 		/*
789 		 * Looks like a UNC path, validate the format.
790 		 */
791 		if (sharename[1] != '\\')
792 			return (NULL);
793 
794 		if ((sharename = strchr(sharename+2, '\\')) == NULL)
795 			return (NULL);
796 
797 		++sharename;
798 	} else if (strchr(sharename, '\\') != NULL) {
799 		/*
800 		 * This should be a share name (no embedded \'s).
801 		 */
802 		return (NULL);
803 	}
804 
805 	return (sharename);
806 }
807 
808 /*
809  * Map the service to a resource type.  Valid values for service are:
810  *
811  *	A:      Disk share
812  *	LPT1:   Printer
813  *	IPC     Named pipe
814  *	COMM    Communications device
815  *	?????   Any type of device (wildcard)
816  *
817  * We support IPC and disk shares; anything else is currently treated
818  * as an error.  IPC$ is reserved as the named pipe share.
819  */
820 static int
821 smb_tree_get_stype(const char *sharename, const char *service,
822     int32_t *stype_ret)
823 {
824 	const char *any = "?????";
825 
826 	if ((strcmp(service, any) == 0) || (strcasecmp(service, "IPC") == 0)) {
827 		if (strcasecmp(sharename, "IPC$") == 0) {
828 			*stype_ret = STYPE_IPC;
829 			return (0);
830 		}
831 	}
832 
833 	if ((strcmp(service, any) == 0) || (strcasecmp(service, "A:") == 0)) {
834 		if (strcasecmp(sharename, "IPC$") == 0)
835 			return (-1);
836 
837 		*stype_ret = STYPE_DISKTREE;
838 		return (0);
839 	}
840 
841 	return (-1);
842 }
843 
844 /*
845  * Obtain the tree attributes: volume name, typename and flags.
846  */
847 static int
848 smb_tree_getattr(const smb_share_t *si, smb_node_t *node, smb_tree_t *tree)
849 {
850 	vfs_t *vfsp = SMB_NODE_VFS(node);
851 
852 	ASSERT(vfsp);
853 
854 	if (getvfs(&vfsp->vfs_fsid) != vfsp)
855 		return (ESTALE);
856 
857 	smb_tree_get_volname(vfsp, tree);
858 	smb_tree_get_flags(si, vfsp, tree);
859 
860 	VFS_RELE(vfsp);
861 	return (0);
862 }
863 
864 /*
865  * Extract the volume name.
866  */
867 static void
868 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
869 {
870 	refstr_t *vfs_mntpoint;
871 	const char *s;
872 	char *name;
873 
874 	vfs_mntpoint = vfs_getmntpoint(vfsp);
875 
876 	s = vfs_mntpoint->rs_string;
877 	s += strspn(s, "/");
878 	(void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
879 
880 	refstr_rele(vfs_mntpoint);
881 
882 	name = tree->t_volume;
883 	(void) strsep((char **)&name, "/");
884 }
885 
886 /*
887  * Always set ACL support because the VFS will fake ACLs for file systems
888  * that don't support them.
889  *
890  * Some flags are dependent on the typename, which is also set up here.
891  * File system types are hardcoded in uts/common/os/vfs_conf.c.
892  */
893 static void
894 smb_tree_get_flags(const smb_share_t *si, vfs_t *vfsp, smb_tree_t *tree)
895 {
896 	typedef struct smb_mtype {
897 		char		*mt_name;
898 		size_t		mt_namelen;
899 		uint32_t	mt_flags;
900 	} smb_mtype_t;
901 
902 	static smb_mtype_t smb_mtype[] = {
903 		{ "zfs",	3,	SMB_TREE_UNICODE_ON_DISK },
904 		{ "ufs",	3,	SMB_TREE_UNICODE_ON_DISK },
905 		{ "nfs",	3,	SMB_TREE_NFS_MOUNTED },
906 		{ "tmpfs",	5,	SMB_TREE_NO_EXPORT }
907 	};
908 	smb_mtype_t	*mtype;
909 	char		*name;
910 	uint32_t	flags = SMB_TREE_SUPPORTS_ACLS;
911 	int		i;
912 
913 	if (si->shr_flags & SMB_SHRF_CATIA)
914 		flags |= SMB_TREE_CATIA;
915 
916 	if (vfsp->vfs_flag & VFS_RDONLY)
917 		flags |= SMB_TREE_READONLY;
918 
919 	if (vfsp->vfs_flag & VFS_XATTR)
920 		flags |= SMB_TREE_STREAMS;
921 
922 	if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL))
923 		flags |= SMB_TREE_NO_ATIME;
924 
925 	name = vfssw[vfsp->vfs_fstype].vsw_name;
926 
927 	for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
928 		mtype = &smb_mtype[i];
929 		if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
930 			flags |= mtype->mt_flags;
931 	}
932 
933 	(void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
934 	(void) utf8_strupr((char *)tree->t_typename);
935 
936 	if (vfs_has_feature(vfsp, VFSFT_XVATTR))
937 		flags |= SMB_TREE_XVATTR;
938 
939 	if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
940 		flags |= SMB_TREE_CASEINSENSITIVE;
941 
942 	if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
943 		flags |= SMB_TREE_NO_CASESENSITIVE;
944 
945 	if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
946 		flags |= SMB_TREE_DIRENTFLAGS;
947 
948 	if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
949 		flags |= SMB_TREE_ACLONCREATE;
950 
951 	if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
952 		flags |= SMB_TREE_ACEMASKONACCESS;
953 
954 	DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);
955 
956 
957 	tree->t_flags = flags;
958 }
959 
960 /*
961  * Report share access result to syslog.
962  */
963 static void
964 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
965 {
966 	va_list ap;
967 	char buf[128];
968 	smb_user_t *user = sr->uid_user;
969 
970 	ASSERT(user);
971 
972 	if (smb_tcon_mute)
973 		return;
974 
975 	if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
976 		/*
977 		 * Only report normal users, i.e. ignore W2K misuse
978 		 * of the IPC connection by filtering out internal
979 		 * names such as nobody and root.
980 		 */
981 		if ((strcmp(user->u_name, "root") == 0) ||
982 		    (strcmp(user->u_name, "nobody") == 0)) {
983 			return;
984 		}
985 	}
986 
987 	va_start(ap, fmt);
988 	(void) vsnprintf(buf, 128, fmt, ap);
989 	va_end(ap);
990 
991 	cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
992 	    user->u_domain, user->u_name, sharename, buf);
993 }
994 
995 /*
996  * smb_tree_lookup_odir
997  *
998  * Find the specified odir in the tree's list of odirs, and
999  * attempt to obtain a hold on the odir.
1000  *
1001  * Returns NULL if odir not found or a hold cannot be obtained.
1002  */
1003 smb_odir_t *
1004 smb_tree_lookup_odir(smb_tree_t *tree, uint16_t odid)
1005 {
1006 	smb_odir_t	*od;
1007 	smb_llist_t	*od_list;
1008 
1009 	ASSERT(tree);
1010 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1011 
1012 	od_list = &tree->t_odir_list;
1013 	smb_llist_enter(od_list, RW_READER);
1014 
1015 	od = smb_llist_head(od_list);
1016 	while (od) {
1017 		if (od->d_odid == odid) {
1018 			if (!smb_odir_hold(od))
1019 				od = NULL;
1020 			break;
1021 		}
1022 		od = smb_llist_next(od_list, od);
1023 	}
1024 
1025 	smb_llist_exit(od_list);
1026 	return (od);
1027 }
1028 
1029 boolean_t
1030 smb_tree_is_connected(smb_tree_t *tree)
1031 {
1032 	boolean_t	rb;
1033 
1034 	mutex_enter(&tree->t_mutex);
1035 	rb = smb_tree_is_connected_locked(tree);
1036 	mutex_exit(&tree->t_mutex);
1037 	return (rb);
1038 }
1039 
1040 /*
1041  * smb_tree_get_odir
1042  *
1043  * Find the next odir in the tree's list of odirs, and obtain a
1044  * hold on it.
1045  * If the specified odir is NULL the search starts at the beginning
1046  * of the tree's odir list, otherwise the search starts after the
1047  * specified odir.
1048  */
1049 static smb_odir_t *
1050 smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od)
1051 {
1052 	smb_llist_t *od_list;
1053 
1054 	ASSERT(tree);
1055 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1056 
1057 	od_list = &tree->t_odir_list;
1058 	smb_llist_enter(od_list, RW_READER);
1059 
1060 	if (od) {
1061 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1062 		od = smb_llist_next(od_list, od);
1063 	} else {
1064 		od = smb_llist_head(od_list);
1065 	}
1066 
1067 	while (od) {
1068 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1069 
1070 		if (smb_odir_hold(od))
1071 			break;
1072 		od = smb_llist_next(od_list, od);
1073 	}
1074 
1075 	smb_llist_exit(od_list);
1076 	return (od);
1077 }
1078 
1079 /*
1080  * smb_tree_close_odirs
1081  *
1082  * Close all open odirs in the tree's list which were opened by
1083  * the process identified by pid.
1084  * If pid is zero, close all open odirs in the tree's list.
1085  */
1086 static void
1087 smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid)
1088 {
1089 	smb_odir_t *od, *next_od;
1090 
1091 	ASSERT(tree);
1092 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1093 
1094 	od = smb_tree_get_odir(tree, NULL);
1095 	while (od) {
1096 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1097 		ASSERT(od->d_tree == tree);
1098 
1099 		next_od = smb_tree_get_odir(tree, od);
1100 		if ((pid == 0) || (od->d_opened_by_pid == pid))
1101 				smb_odir_close(od);
1102 		smb_odir_release(od);
1103 
1104 		od = next_od;
1105 	}
1106 }
1107