xref: /titanic_51/usr/src/uts/common/fs/smbsrv/smb_tree.c (revision e085f1530a2b52c62d916408e99d66a557855d42)
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 <sys/cred_impl.h>
173 #include <smbsrv/smb_incl.h>
174 #include <smbsrv/lmerr.h>
175 #include <smbsrv/smb_fsops.h>
176 #include <smbsrv/smb_door_svc.h>
177 #include <smbsrv/smb_share.h>
178 #include <sys/pathname.h>
179 
180 int smb_tcon_mute = 0;
181 
182 static smb_tree_t *smb_tree_connect_disk(smb_request_t *, const char *);
183 static smb_tree_t *smb_tree_connect_ipc(smb_request_t *, const char *);
184 static smb_tree_t *smb_tree_alloc(smb_user_t *, const smb_share_t *,
185     int32_t, smb_node_t *, uint32_t);
186 static void smb_tree_dealloc(smb_tree_t *);
187 static boolean_t smb_tree_is_connected_locked(smb_tree_t *);
188 static boolean_t smb_tree_is_disconnected(smb_tree_t *);
189 static const char *smb_tree_get_sharename(const char *);
190 static int smb_tree_get_stype(const char *, const char *, int32_t *);
191 static int smb_tree_getattr(const smb_share_t *, smb_node_t *, smb_tree_t *);
192 static void smb_tree_get_volname(vfs_t *, smb_tree_t *);
193 static void smb_tree_get_flags(const smb_share_t *, vfs_t *, smb_tree_t *);
194 static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
195 static void smb_tree_close_odirs(smb_tree_t *, uint16_t);
196 static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *);
197 static void smb_tree_set_execsub_info(smb_tree_t *, smb_execsub_info_t *);
198 
199 /*
200  * Extract the share name and share type and connect as appropriate.
201  * Share names are case insensitive so we map the share name to
202  * lower-case as a convenience for internal processing.
203  */
204 smb_tree_t *
205 smb_tree_connect(smb_request_t *sr)
206 {
207 	char *unc_path = sr->arg.tcon.path;
208 	char *service = sr->arg.tcon.service;
209 	smb_tree_t *tree = NULL;
210 	const char *name;
211 	int32_t stype;
212 
213 	(void) utf8_strlwr(unc_path);
214 
215 	if ((name = smb_tree_get_sharename(unc_path)) == NULL) {
216 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
217 		return (NULL);
218 	}
219 
220 	if (smb_tree_get_stype(name, service, &stype) != 0) {
221 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
222 		    ERRDOS, ERROR_BAD_DEV_TYPE);
223 		return (NULL);
224 	}
225 
226 	switch (stype & STYPE_MASK) {
227 	case STYPE_DISKTREE:
228 		tree = smb_tree_connect_disk(sr, name);
229 		break;
230 
231 	case STYPE_IPC:
232 		tree = smb_tree_connect_ipc(sr, name);
233 		break;
234 
235 	default:
236 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
237 		    ERRDOS, ERROR_BAD_DEV_TYPE);
238 		break;
239 	}
240 
241 	return (tree);
242 }
243 
244 /*
245  * Disconnect a tree.
246  */
247 void
248 smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec)
249 {
250 	smb_execsub_info_t subs;
251 
252 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
253 
254 	mutex_enter(&tree->t_mutex);
255 	ASSERT(tree->t_refcnt);
256 
257 	if (smb_tree_is_connected_locked(tree)) {
258 		/*
259 		 * Indicate that the disconnect process has started.
260 		 */
261 		tree->t_state = SMB_TREE_STATE_DISCONNECTING;
262 		mutex_exit(&tree->t_mutex);
263 		atomic_dec_32(&tree->t_server->sv_open_trees);
264 
265 		if (do_exec) {
266 			/*
267 			 * The files opened under this tree are closed.
268 			 */
269 			smb_ofile_close_all(tree);
270 			/*
271 			 * The directories opened under this tree are closed.
272 			 */
273 			smb_tree_close_odirs(tree, 0);
274 		}
275 
276 		mutex_enter(&tree->t_mutex);
277 		tree->t_state = SMB_TREE_STATE_DISCONNECTED;
278 	}
279 
280 	mutex_exit(&tree->t_mutex);
281 
282 	if (do_exec && tree->t_state == SMB_TREE_STATE_DISCONNECTED &&
283 	    tree->t_shr_flags & SMB_SHRF_UNMAP) {
284 
285 		(void) smb_tree_set_execsub_info(tree, &subs);
286 
287 		(void) smb_kshare_exec(tree->t_server->sv_lmshrd,
288 		    (char *)tree->t_sharename, &subs, SMB_SHR_UNMAP);
289 	}
290 }
291 
292 /*
293  * Take a reference on a tree.
294  */
295 boolean_t
296 smb_tree_hold(
297     smb_tree_t		*tree)
298 {
299 	ASSERT(tree);
300 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
301 
302 	mutex_enter(&tree->t_mutex);
303 
304 	if (smb_tree_is_connected_locked(tree)) {
305 		tree->t_refcnt++;
306 		mutex_exit(&tree->t_mutex);
307 		return (B_TRUE);
308 	}
309 
310 	mutex_exit(&tree->t_mutex);
311 	return (B_FALSE);
312 }
313 
314 /*
315  * Release a reference on a tree.  If the tree is disconnected and the
316  * reference count falls to zero, the tree will be deallocated.
317  */
318 void
319 smb_tree_release(
320     smb_tree_t		*tree)
321 {
322 	ASSERT(tree);
323 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
324 
325 	mutex_enter(&tree->t_mutex);
326 	ASSERT(tree->t_refcnt);
327 	tree->t_refcnt--;
328 
329 	if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0)) {
330 		mutex_exit(&tree->t_mutex);
331 		smb_tree_dealloc(tree);
332 		return;
333 	}
334 
335 	mutex_exit(&tree->t_mutex);
336 }
337 
338 /*
339  * Close ofiles and odirs that match pid.
340  */
341 void
342 smb_tree_close_pid(
343     smb_tree_t		*tree,
344     uint16_t		pid)
345 {
346 	ASSERT(tree);
347 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
348 
349 	smb_ofile_close_all_by_pid(tree, pid);
350 	smb_tree_close_odirs(tree, pid);
351 }
352 
353 /*
354  * Check whether or not a tree supports the features identified by flags.
355  */
356 boolean_t
357 smb_tree_has_feature(smb_tree_t *tree, uint32_t flags)
358 {
359 	ASSERT(tree);
360 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
361 
362 	return ((tree->t_flags & flags) == flags);
363 }
364 
365 
366 /* *************************** Static Functions ***************************** */
367 #define	SHARES_DIR	".zfs/shares/"
368 static void
369 smb_tree_acl_access(cred_t *cred, const char *sharename, vnode_t *pathvp,
370 		    uint32_t *access)
371 {
372 	int rc;
373 	vfs_t *vfsp;
374 	vnode_t *root = NULL;
375 	vnode_t *sharevp = NULL;
376 	char *sharepath;
377 	struct pathname pnp;
378 	size_t size;
379 
380 	*access = ACE_ALL_PERMS; /* default to full "UNIX" access */
381 
382 	/*
383 	 * Using the vnode of the share path, we then find the root
384 	 * directory of the mounted file system. We will then look to
385 	 * see if there is a .zfs/shares directory and if there is,
386 	 * get the access information from the ACL/ACES values and
387 	 * check against the cred.
388 	 */
389 	vfsp = pathvp->v_vfsp;
390 	if (vfsp != NULL)
391 		rc = VFS_ROOT(vfsp, &root);
392 	else
393 		rc = ENOENT;
394 
395 	if (rc != 0)
396 		return;
397 
398 
399 	/*
400 	 * Find the share object, if there is one. Need to construct
401 	 * the path to the .zfs/shares/<sharename> object and look it
402 	 * up.  root is called held but will be released by
403 	 * lookuppnvp().
404 	 */
405 
406 	size = sizeof (SHARES_DIR) + strlen(sharename) + 1;
407 	sharepath = kmem_alloc(size, KM_SLEEP);
408 	(void) sprintf(sharepath, "%s%s", SHARES_DIR, sharename);
409 
410 	pn_alloc(&pnp);
411 	(void) pn_set(&pnp, sharepath);
412 	rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL,
413 	    &sharevp, rootdir, root, kcred);
414 	pn_free(&pnp);
415 
416 	kmem_free(sharepath, size);
417 
418 	/*
419 	 * Now get the effective access value based on cred and ACL
420 	 * values.
421 	 */
422 
423 	if (rc == 0) {
424 		smb_vop_eaccess(sharevp, (int *)access, V_ACE_MASK, NULL, cred);
425 		VN_RELE(sharevp);
426 	}
427 }
428 
429 /*
430  * Connect a share for use with files and directories.
431  */
432 
433 static smb_tree_t *
434 smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
435 {
436 	smb_user_t		*user = sr->uid_user;
437 	smb_node_t		*dir_snode = NULL;
438 	smb_node_t		*snode = NULL;
439 	char			last_component[MAXNAMELEN];
440 	smb_tree_t		*tree;
441 	smb_share_t 		*si;
442 	cred_t			*u_cred;
443 	int			rc;
444 	uint32_t		access = 0; /* read/write is assumed */
445 	uint32_t		hostaccess = ACE_ALL_PERMS;
446 	uint32_t		aclaccess;
447 	smb_execsub_info_t	subs;
448 
449 	ASSERT(user);
450 	u_cred = user->u_cred;
451 	ASSERT(u_cred);
452 
453 	if (user->u_flags & SMB_USER_FLAG_IPC) {
454 		smb_tree_log(sr, sharename, "access denied: IPC only");
455 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
456 		return (NULL);
457 	}
458 
459 	si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP);
460 
461 	if (smb_kshare_getinfo(sr->sr_server->sv_lmshrd, (char *)sharename, si,
462 	    &sr->session->ipaddr) != NERR_Success) {
463 		smb_tree_log(sr, sharename, "share not found");
464 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
465 		kmem_free(si, sizeof (smb_share_t));
466 		return (NULL);
467 	}
468 
469 	if (user->u_flags & SMB_USER_FLAG_GUEST) {
470 		if ((si->shr_flags & SMB_SHRF_GUEST_OK) == 0) {
471 			smb_tree_log(sr, sharename,
472 			    "access denied: guest disabled");
473 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV,
474 			    ERRaccess);
475 			kmem_free(si, sizeof (smb_share_t));
476 			return (NULL);
477 		}
478 	}
479 
480 	/*
481 	 * Handle the default administration shares: C$, D$ etc.
482 	 * Only a user with admin rights is allowed to map these
483 	 * shares.
484 	 */
485 	if (si->shr_flags & SMB_SHRF_ADMIN) {
486 		if (!smb_user_is_admin(user)) {
487 			smb_tree_log(sr, sharename, "access denied: not admin");
488 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
489 			    ERRSRV, ERRaccess);
490 			kmem_free(si, sizeof (smb_share_t));
491 			return (NULL);
492 		}
493 	}
494 
495 	/*
496 	 * Set up the OptionalSupport for this share.
497 	 */
498 	sr->arg.tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
499 
500 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
501 	case SMB_SHRF_CSC_DISABLED:
502 		sr->arg.tcon.optional_support |= SMB_CSC_CACHE_NONE;
503 		break;
504 	case SMB_SHRF_CSC_AUTO:
505 		sr->arg.tcon.optional_support |= SMB_CSC_CACHE_AUTO_REINT;
506 		break;
507 	case SMB_SHRF_CSC_VDO:
508 		sr->arg.tcon.optional_support |= SMB_CSC_CACHE_VDO;
509 		break;
510 	case SMB_SHRF_CSC_MANUAL:
511 	default:
512 		/*
513 		 * Default to SMB_CSC_CACHE_MANUAL_REINT.
514 		 */
515 		break;
516 	}
517 
518 	access = si->shr_access_value & SMB_SHRF_ACC_ALL;
519 
520 	if (access == SMB_SHRF_ACC_RO) {
521 		hostaccess &= ~ACE_ALL_WRITE_PERMS;
522 	} else if (access == SMB_SHRF_ACC_NONE) {
523 		kmem_free(si, sizeof (smb_share_t));
524 		smb_tree_log(sr, sharename, "access denied: host access");
525 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
526 		return (NULL);
527 	}
528 
529 	/*
530 	 * Check that the shared directory exists.
531 	 */
532 	rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dir_snode,
533 	    last_component);
534 
535 	if (rc == 0) {
536 		rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS,
537 		    sr->sr_server->si_root_smb_node, dir_snode, last_component,
538 		    &snode);
539 
540 		smb_node_release(dir_snode);
541 	}
542 
543 	if (rc) {
544 		if (snode)
545 			smb_node_release(snode);
546 
547 		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
548 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
549 		kmem_free(si, sizeof (smb_share_t));
550 		return (NULL);
551 	}
552 
553 	/*
554 	 * Find share level ACL if it exists in the designated
555 	 * location. Needs to be done after finding a valid path but
556 	 * before the tree is allocated.
557 	 */
558 	smb_tree_acl_access(u_cred, sharename, snode->vp, &aclaccess);
559 	if ((aclaccess & ACE_ALL_PERMS) == 0) {
560 		smb_tree_log(sr, sharename, "access denied: share ACL");
561 		smbsr_error(sr, 0, ERRSRV, ERRaccess);
562 		kmem_free(si, sizeof (smb_share_t));
563 		smb_node_release(snode);
564 		return (NULL);
565 	}
566 
567 	/*
568 	 * Set tree ACL access to the minimum ACL permissions based on
569 	 * hostaccess (those allowed by host based access) and
570 	 * aclaccess (those from the ACL object for the share). This
571 	 * is done during the alloc.
572 	 */
573 
574 	(void) strlcpy(si->shr_name, sharename, MAXNAMELEN);
575 	tree = smb_tree_alloc(user, si, STYPE_DISKTREE, snode,
576 	    hostaccess & aclaccess);
577 
578 	smb_node_release(snode);
579 
580 	if (tree == NULL)
581 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
582 	else {
583 
584 		tree->t_shr_flags = si->shr_flags;
585 
586 		if (tree->t_shr_flags & SMB_SHRF_MAP) {
587 			(void) smb_tree_set_execsub_info(tree, &subs);
588 
589 			rc = smb_kshare_exec(sr->sr_server->sv_lmshrd,
590 			    (char *)sharename, &subs, SMB_SHR_MAP);
591 
592 			if (rc != 0 && tree->t_shr_flags & SMB_SHRF_DISP_TERM) {
593 				smb_tree_disconnect(tree, B_FALSE);
594 				smb_tree_release(tree);
595 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV,
596 				    ERRaccess);
597 				kmem_free(si, sizeof (smb_share_t));
598 				return (NULL);
599 			}
600 		}
601 	}
602 
603 	kmem_free(si, sizeof (smb_share_t));
604 
605 	return (tree);
606 }
607 
608 /*
609  * Connect an IPC share for use with named pipes.
610  */
611 static smb_tree_t *
612 smb_tree_connect_ipc(smb_request_t *sr, const char *name)
613 {
614 	smb_user_t	*user = sr->uid_user;
615 	smb_tree_t	*tree;
616 	smb_share_t	*si;
617 
618 	ASSERT(user);
619 
620 	if ((user->u_flags & SMB_USER_FLAG_IPC) &&
621 	    sr->sr_cfg->skc_restrict_anon) {
622 		smb_tree_log(sr, name, "access denied: restrict anonymous");
623 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
624 		return (NULL);
625 	}
626 
627 	sr->arg.tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
628 
629 	si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP);
630 	(void) strlcpy(si->shr_name, name, MAXNAMELEN);
631 	(void) strlcpy(si->shr_path, name, MAXPATHLEN);
632 	si->shr_type = STYPE_IPC | STYPE_SPECIAL;
633 
634 	tree = smb_tree_alloc(user, si, STYPE_IPC, NULL, ACE_ALL_PERMS);
635 	if (tree == NULL) {
636 		smb_tree_log(sr, name, "access denied");
637 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
638 	}
639 
640 	kmem_free(si, sizeof (smb_share_t));
641 	return (tree);
642 }
643 
644 /*
645  * Allocate a tree.
646  */
647 static smb_tree_t *
648 smb_tree_alloc(
649     smb_user_t		*user,
650     const smb_share_t	*si,
651     int32_t		stype,
652     smb_node_t		*snode,
653     uint32_t access)
654 {
655 	smb_tree_t	*tree;
656 	uint16_t	tid;
657 
658 	if (smb_idpool_alloc(&user->u_tid_pool, &tid))
659 		return (NULL);
660 
661 	tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP);
662 	bzero(tree, sizeof (smb_tree_t));
663 
664 	if (STYPE_ISDSK(stype)) {
665 		if (smb_tree_getattr(si, snode, tree) != 0) {
666 			smb_idpool_free(&user->u_tid_pool, tid);
667 			kmem_cache_free(user->u_server->si_cache_tree, tree);
668 			return (NULL);
669 		}
670 	}
671 
672 	if (smb_idpool_constructor(&tree->t_fid_pool)) {
673 		smb_idpool_free(&user->u_tid_pool, tid);
674 		kmem_cache_free(user->u_server->si_cache_tree, tree);
675 		return (NULL);
676 	}
677 
678 	if (smb_idpool_constructor(&tree->t_odid_pool)) {
679 		smb_idpool_destructor(&tree->t_fid_pool);
680 		smb_idpool_free(&user->u_tid_pool, tid);
681 		kmem_cache_free(user->u_server->si_cache_tree, tree);
682 		return (NULL);
683 	}
684 
685 	smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
686 	    offsetof(smb_ofile_t, f_lnd));
687 
688 	smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
689 	    offsetof(smb_odir_t, d_lnd));
690 
691 	(void) strlcpy(tree->t_sharename, si->shr_name,
692 	    sizeof (tree->t_sharename));
693 	(void) strlcpy(tree->t_resource, si->shr_path,
694 	    sizeof (tree->t_resource));
695 
696 	mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
697 
698 	tree->t_user = user;
699 	tree->t_session = user->u_session;
700 	tree->t_server = user->u_server;
701 	tree->t_refcnt = 1;
702 	tree->t_tid = tid;
703 	tree->t_res_type = stype;
704 	tree->t_state = SMB_TREE_STATE_CONNECTED;
705 	tree->t_magic = SMB_TREE_MAGIC;
706 	tree->t_access = access;
707 
708 	/* if FS is readonly, enforce that here */
709 	if (tree->t_flags & SMB_TREE_READONLY)
710 		tree->t_access &= ~ACE_ALL_WRITE_PERMS;
711 
712 	if (STYPE_ISDSK(stype)) {
713 		smb_node_ref(snode);
714 		tree->t_snode = snode;
715 		tree->t_acltype = smb_fsop_acltype(snode);
716 	}
717 
718 	smb_llist_enter(&user->u_tree_list, RW_WRITER);
719 	smb_llist_insert_head(&user->u_tree_list, tree);
720 	smb_llist_exit(&user->u_tree_list);
721 	atomic_inc_32(&user->u_session->s_tree_cnt);
722 	atomic_inc_32(&user->u_server->sv_open_trees);
723 
724 	return (tree);
725 }
726 
727 /*
728  * Deallocate a tree: release all resources associated with a tree and
729  * remove the tree from the user's tree list.
730  *
731  * The tree being destroyed must be in the "destroying" state and the
732  * reference count must be zero. This function assumes it's single threaded
733  * i.e. only one thread will attempt to destroy a specific tree, which
734  * should be the case if the tree is in disconnected and has a reference
735  * count of zero.
736  */
737 static void
738 smb_tree_dealloc(smb_tree_t *tree)
739 {
740 	ASSERT(tree);
741 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
742 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
743 	ASSERT(tree->t_refcnt == 0);
744 
745 	/*
746 	 * Remove the tree from the user's tree list.  This must be done
747 	 * before any resources associated with the tree are released.
748 	 */
749 	smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER);
750 	smb_llist_remove(&tree->t_user->u_tree_list, tree);
751 	smb_llist_exit(&tree->t_user->u_tree_list);
752 
753 	tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
754 	smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid);
755 	atomic_dec_32(&tree->t_session->s_tree_cnt);
756 
757 	if (tree->t_snode)
758 		smb_node_release(tree->t_snode);
759 
760 	mutex_destroy(&tree->t_mutex);
761 
762 	/*
763 	 * The list of open files and open directories should be empty.
764 	 */
765 	smb_llist_destructor(&tree->t_ofile_list);
766 	smb_llist_destructor(&tree->t_odir_list);
767 	smb_idpool_destructor(&tree->t_fid_pool);
768 	smb_idpool_destructor(&tree->t_odid_pool);
769 	kmem_cache_free(tree->t_server->si_cache_tree, tree);
770 }
771 
772 /*
773  * Determine whether or not a tree is connected.
774  * This function must be called with the tree mutex held.
775  */
776 static boolean_t
777 smb_tree_is_connected_locked(smb_tree_t *tree)
778 {
779 	switch (tree->t_state) {
780 	case SMB_TREE_STATE_CONNECTED:
781 		return (B_TRUE);
782 
783 	case SMB_TREE_STATE_DISCONNECTING:
784 	case SMB_TREE_STATE_DISCONNECTED:
785 		/*
786 		 * The tree exists but being diconnected or destroyed.
787 		 */
788 		return (B_FALSE);
789 
790 	default:
791 		ASSERT(0);
792 		return (B_FALSE);
793 	}
794 }
795 
796 /*
797  * Determine whether or not a tree is disconnected.
798  * This function must be called with the tree mutex held.
799  */
800 static boolean_t
801 smb_tree_is_disconnected(smb_tree_t *tree)
802 {
803 	switch (tree->t_state) {
804 	case SMB_TREE_STATE_DISCONNECTED:
805 		return (B_TRUE);
806 
807 	case SMB_TREE_STATE_CONNECTED:
808 	case SMB_TREE_STATE_DISCONNECTING:
809 		return (B_FALSE);
810 
811 	default:
812 		ASSERT(0);
813 		return (B_FALSE);
814 	}
815 }
816 
817 /*
818  * Return a pointer to the share name within a share resource path.
819  *
820  * The share path may be a Uniform Naming Convention (UNC) string
821  * (\\server\share) or simply the share name.  We validate the UNC
822  * format but we don't look at the server name.
823  */
824 static const char *
825 smb_tree_get_sharename(const char *unc_path)
826 {
827 	const char *sharename = unc_path;
828 
829 	if (sharename[0] == '\\') {
830 		/*
831 		 * Looks like a UNC path, validate the format.
832 		 */
833 		if (sharename[1] != '\\')
834 			return (NULL);
835 
836 		if ((sharename = strchr(sharename+2, '\\')) == NULL)
837 			return (NULL);
838 
839 		++sharename;
840 	} else if (strchr(sharename, '\\') != NULL) {
841 		/*
842 		 * This should be a share name (no embedded \'s).
843 		 */
844 		return (NULL);
845 	}
846 
847 	return (sharename);
848 }
849 
850 /*
851  * Map the service to a resource type.  Valid values for service are:
852  *
853  *	A:      Disk share
854  *	LPT1:   Printer
855  *	IPC     Named pipe
856  *	COMM    Communications device
857  *	?????   Any type of device (wildcard)
858  *
859  * We support IPC and disk shares; anything else is currently treated
860  * as an error.  IPC$ is reserved as the named pipe share.
861  */
862 static int
863 smb_tree_get_stype(const char *sharename, const char *service,
864     int32_t *stype_ret)
865 {
866 	const char *any = "?????";
867 
868 	if ((strcmp(service, any) == 0) || (strcasecmp(service, "IPC") == 0)) {
869 		if (strcasecmp(sharename, "IPC$") == 0) {
870 			*stype_ret = STYPE_IPC;
871 			return (0);
872 		}
873 	}
874 
875 	if ((strcmp(service, any) == 0) || (strcasecmp(service, "A:") == 0)) {
876 		if (strcasecmp(sharename, "IPC$") == 0)
877 			return (-1);
878 
879 		*stype_ret = STYPE_DISKTREE;
880 		return (0);
881 	}
882 
883 	return (-1);
884 }
885 
886 /*
887  * Obtain the tree attributes: volume name, typename and flags.
888  */
889 static int
890 smb_tree_getattr(const smb_share_t *si, smb_node_t *node, smb_tree_t *tree)
891 {
892 	vfs_t *vfsp = SMB_NODE_VFS(node);
893 
894 	ASSERT(vfsp);
895 
896 	if (getvfs(&vfsp->vfs_fsid) != vfsp)
897 		return (ESTALE);
898 
899 	smb_tree_get_volname(vfsp, tree);
900 	smb_tree_get_flags(si, vfsp, tree);
901 
902 	VFS_RELE(vfsp);
903 	return (0);
904 }
905 
906 /*
907  * Extract the volume name.
908  */
909 static void
910 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
911 {
912 	refstr_t *vfs_mntpoint;
913 	const char *s;
914 	char *name;
915 
916 	vfs_mntpoint = vfs_getmntpoint(vfsp);
917 
918 	s = vfs_mntpoint->rs_string;
919 	s += strspn(s, "/");
920 	(void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
921 
922 	refstr_rele(vfs_mntpoint);
923 
924 	name = tree->t_volume;
925 	(void) strsep((char **)&name, "/");
926 }
927 
928 /*
929  * Always set ACL support because the VFS will fake ACLs for file systems
930  * that don't support them.
931  *
932  * Some flags are dependent on the typename, which is also set up here.
933  * File system types are hardcoded in uts/common/os/vfs_conf.c.
934  */
935 static void
936 smb_tree_get_flags(const smb_share_t *si, vfs_t *vfsp, smb_tree_t *tree)
937 {
938 	typedef struct smb_mtype {
939 		char		*mt_name;
940 		size_t		mt_namelen;
941 		uint32_t	mt_flags;
942 	} smb_mtype_t;
943 
944 	static smb_mtype_t smb_mtype[] = {
945 		{ "zfs",	3,	SMB_TREE_UNICODE_ON_DISK },
946 		{ "ufs",	3,	SMB_TREE_UNICODE_ON_DISK },
947 		{ "nfs",	3,	SMB_TREE_NFS_MOUNTED },
948 		{ "tmpfs",	5,	SMB_TREE_NO_EXPORT }
949 	};
950 	smb_mtype_t	*mtype;
951 	char		*name;
952 	uint32_t	flags = SMB_TREE_SUPPORTS_ACLS;
953 	int		i;
954 
955 	if (si->shr_flags & SMB_SHRF_CATIA)
956 		flags |= SMB_TREE_CATIA;
957 
958 	if (vfsp->vfs_flag & VFS_RDONLY)
959 		flags |= SMB_TREE_READONLY;
960 
961 	if (vfsp->vfs_flag & VFS_XATTR)
962 		flags |= SMB_TREE_STREAMS;
963 
964 	if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL))
965 		flags |= SMB_TREE_NO_ATIME;
966 
967 	name = vfssw[vfsp->vfs_fstype].vsw_name;
968 
969 	for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
970 		mtype = &smb_mtype[i];
971 		if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
972 			flags |= mtype->mt_flags;
973 	}
974 
975 	(void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
976 	(void) utf8_strupr((char *)tree->t_typename);
977 
978 	if (vfs_has_feature(vfsp, VFSFT_XVATTR))
979 		flags |= SMB_TREE_XVATTR;
980 
981 	if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
982 		flags |= SMB_TREE_CASEINSENSITIVE;
983 
984 	if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
985 		flags |= SMB_TREE_NO_CASESENSITIVE;
986 
987 	if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
988 		flags |= SMB_TREE_DIRENTFLAGS;
989 
990 	if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
991 		flags |= SMB_TREE_ACLONCREATE;
992 
993 	if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
994 		flags |= SMB_TREE_ACEMASKONACCESS;
995 
996 	DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);
997 
998 
999 	tree->t_flags = flags;
1000 }
1001 
1002 /*
1003  * Report share access result to syslog.
1004  */
1005 static void
1006 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
1007 {
1008 	va_list ap;
1009 	char buf[128];
1010 	smb_user_t *user = sr->uid_user;
1011 
1012 	ASSERT(user);
1013 
1014 	if (smb_tcon_mute)
1015 		return;
1016 
1017 	if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
1018 		/*
1019 		 * Only report normal users, i.e. ignore W2K misuse
1020 		 * of the IPC connection by filtering out internal
1021 		 * names such as nobody and root.
1022 		 */
1023 		if ((strcmp(user->u_name, "root") == 0) ||
1024 		    (strcmp(user->u_name, "nobody") == 0)) {
1025 			return;
1026 		}
1027 	}
1028 
1029 	va_start(ap, fmt);
1030 	(void) vsnprintf(buf, 128, fmt, ap);
1031 	va_end(ap);
1032 
1033 	cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
1034 	    user->u_domain, user->u_name, sharename, buf);
1035 }
1036 
1037 /*
1038  * smb_tree_lookup_odir
1039  *
1040  * Find the specified odir in the tree's list of odirs, and
1041  * attempt to obtain a hold on the odir.
1042  *
1043  * Returns NULL if odir not found or a hold cannot be obtained.
1044  */
1045 smb_odir_t *
1046 smb_tree_lookup_odir(smb_tree_t *tree, uint16_t odid)
1047 {
1048 	smb_odir_t	*od;
1049 	smb_llist_t	*od_list;
1050 
1051 	ASSERT(tree);
1052 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1053 
1054 	od_list = &tree->t_odir_list;
1055 	smb_llist_enter(od_list, RW_READER);
1056 
1057 	od = smb_llist_head(od_list);
1058 	while (od) {
1059 		if (od->d_odid == odid) {
1060 			if (!smb_odir_hold(od))
1061 				od = NULL;
1062 			break;
1063 		}
1064 		od = smb_llist_next(od_list, od);
1065 	}
1066 
1067 	smb_llist_exit(od_list);
1068 	return (od);
1069 }
1070 
1071 boolean_t
1072 smb_tree_is_connected(smb_tree_t *tree)
1073 {
1074 	boolean_t	rb;
1075 
1076 	mutex_enter(&tree->t_mutex);
1077 	rb = smb_tree_is_connected_locked(tree);
1078 	mutex_exit(&tree->t_mutex);
1079 	return (rb);
1080 }
1081 
1082 /*
1083  * smb_tree_get_odir
1084  *
1085  * Find the next odir in the tree's list of odirs, and obtain a
1086  * hold on it.
1087  * If the specified odir is NULL the search starts at the beginning
1088  * of the tree's odir list, otherwise the search starts after the
1089  * specified odir.
1090  */
1091 static smb_odir_t *
1092 smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od)
1093 {
1094 	smb_llist_t *od_list;
1095 
1096 	ASSERT(tree);
1097 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1098 
1099 	od_list = &tree->t_odir_list;
1100 	smb_llist_enter(od_list, RW_READER);
1101 
1102 	if (od) {
1103 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1104 		od = smb_llist_next(od_list, od);
1105 	} else {
1106 		od = smb_llist_head(od_list);
1107 	}
1108 
1109 	while (od) {
1110 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1111 
1112 		if (smb_odir_hold(od))
1113 			break;
1114 		od = smb_llist_next(od_list, od);
1115 	}
1116 
1117 	smb_llist_exit(od_list);
1118 	return (od);
1119 }
1120 
1121 /*
1122  * smb_tree_close_odirs
1123  *
1124  * Close all open odirs in the tree's list which were opened by
1125  * the process identified by pid.
1126  * If pid is zero, close all open odirs in the tree's list.
1127  */
1128 static void
1129 smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid)
1130 {
1131 	smb_odir_t *od, *next_od;
1132 
1133 	ASSERT(tree);
1134 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1135 
1136 	od = smb_tree_get_odir(tree, NULL);
1137 	while (od) {
1138 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1139 		ASSERT(od->d_tree == tree);
1140 
1141 		next_od = smb_tree_get_odir(tree, od);
1142 		if ((pid == 0) || (od->d_opened_by_pid == pid))
1143 				smb_odir_close(od);
1144 		smb_odir_release(od);
1145 
1146 		od = next_od;
1147 	}
1148 }
1149 
1150 static void
1151 smb_tree_set_execsub_info(smb_tree_t *tree, smb_execsub_info_t *subs)
1152 {
1153 		subs->e_winname = tree->t_user->u_name;
1154 		subs->e_userdom = tree->t_user->u_domain;
1155 		subs->e_srv_ipaddr = tree->t_session->local_ipaddr;
1156 		subs->e_cli_ipaddr = tree->t_session->ipaddr;
1157 		subs->e_cli_netbiosname = tree->t_session->workstation;
1158 		subs->e_uid = tree->t_user->u_cred->cr_uid;
1159 }
1160