xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_tree.c (revision e44e85a7f9935f0428e188393e3da61b17e83884)
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 
426 }
427 
428 /*
429  * Connect a share for use with files and directories.
430  */
431 
432 static smb_tree_t *
433 smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
434 {
435 	smb_user_t		*user = sr->uid_user;
436 	smb_node_t		*dir_snode = NULL;
437 	smb_node_t		*snode = NULL;
438 	char			last_component[MAXNAMELEN];
439 	smb_tree_t		*tree;
440 	smb_share_t 		*si;
441 	smb_attr_t		attr;
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, &attr);
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 an error, then no share file -- default to no ACL */
560 	if (rc == 0) {
561 		/*
562 		 * There need to be some permissions in order to have
563 		 * any access.
564 		 */
565 		if ((aclaccess & ACE_ALL_PERMS) == 0) {
566 			smb_tree_log(sr, sharename, "access denied: share ACL");
567 			smbsr_error(sr, 0, ERRSRV, ERRaccess);
568 			kmem_free(si, sizeof (smb_share_t));
569 			smb_node_release(snode);
570 			return (NULL);
571 		}
572 	}
573 
574 	/*
575 	 * Set tree ACL access to the minimum ACL permissions based on
576 	 * hostaccess (those allowed by host based access) and
577 	 * aclaccess (those from the ACL object for the share). This
578 	 * is done during the alloc.
579 	 */
580 
581 	(void) strlcpy(si->shr_name, sharename, MAXNAMELEN);
582 	tree = smb_tree_alloc(user, si, STYPE_DISKTREE, snode,
583 	    hostaccess & aclaccess);
584 
585 	smb_node_release(snode);
586 
587 	if (tree == NULL)
588 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
589 	else {
590 
591 		tree->t_shr_flags = si->shr_flags;
592 
593 		if (tree->t_shr_flags & SMB_SHRF_MAP) {
594 			(void) smb_tree_set_execsub_info(tree, &subs);
595 
596 			rc = smb_kshare_exec(sr->sr_server->sv_lmshrd,
597 			    (char *)sharename, &subs, SMB_SHR_MAP);
598 
599 			if (rc != 0 && tree->t_shr_flags & SMB_SHRF_DISP_TERM) {
600 				smb_tree_disconnect(tree, B_FALSE);
601 				smb_tree_release(tree);
602 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV,
603 				    ERRaccess);
604 				kmem_free(si, sizeof (smb_share_t));
605 				return (NULL);
606 			}
607 		}
608 	}
609 
610 	kmem_free(si, sizeof (smb_share_t));
611 
612 	return (tree);
613 }
614 
615 /*
616  * Connect an IPC share for use with named pipes.
617  */
618 static smb_tree_t *
619 smb_tree_connect_ipc(smb_request_t *sr, const char *name)
620 {
621 	smb_user_t	*user = sr->uid_user;
622 	smb_tree_t	*tree;
623 	smb_share_t	*si;
624 
625 	ASSERT(user);
626 
627 	if ((user->u_flags & SMB_USER_FLAG_IPC) &&
628 	    sr->sr_cfg->skc_restrict_anon) {
629 		smb_tree_log(sr, name, "access denied: restrict anonymous");
630 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
631 		return (NULL);
632 	}
633 
634 	sr->arg.tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
635 
636 	si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP);
637 	(void) strlcpy(si->shr_name, name, MAXNAMELEN);
638 	(void) strlcpy(si->shr_path, name, MAXPATHLEN);
639 	si->shr_type = STYPE_IPC | STYPE_SPECIAL;
640 
641 	tree = smb_tree_alloc(user, si, STYPE_IPC, NULL, ACE_ALL_PERMS);
642 	if (tree == NULL) {
643 		smb_tree_log(sr, name, "access denied");
644 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
645 	}
646 
647 	kmem_free(si, sizeof (smb_share_t));
648 	return (tree);
649 }
650 
651 /*
652  * Allocate a tree.
653  */
654 static smb_tree_t *
655 smb_tree_alloc(
656     smb_user_t		*user,
657     const smb_share_t	*si,
658     int32_t		stype,
659     smb_node_t		*snode,
660     uint32_t access)
661 {
662 	smb_tree_t	*tree;
663 	uint16_t	tid;
664 
665 	if (smb_idpool_alloc(&user->u_tid_pool, &tid))
666 		return (NULL);
667 
668 	tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP);
669 	bzero(tree, sizeof (smb_tree_t));
670 
671 	if (STYPE_ISDSK(stype)) {
672 		if (smb_tree_getattr(si, snode, tree) != 0) {
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 
679 	if (smb_idpool_constructor(&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 	if (smb_idpool_constructor(&tree->t_odid_pool)) {
686 		smb_idpool_destructor(&tree->t_fid_pool);
687 		smb_idpool_free(&user->u_tid_pool, tid);
688 		kmem_cache_free(user->u_server->si_cache_tree, tree);
689 		return (NULL);
690 	}
691 
692 	smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
693 	    offsetof(smb_ofile_t, f_lnd));
694 
695 	smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
696 	    offsetof(smb_odir_t, d_lnd));
697 
698 	(void) strlcpy(tree->t_sharename, si->shr_name,
699 	    sizeof (tree->t_sharename));
700 	(void) strlcpy(tree->t_resource, si->shr_path,
701 	    sizeof (tree->t_resource));
702 
703 	mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
704 
705 	tree->t_user = user;
706 	tree->t_session = user->u_session;
707 	tree->t_server = user->u_server;
708 	tree->t_refcnt = 1;
709 	tree->t_tid = tid;
710 	tree->t_res_type = stype;
711 	tree->t_state = SMB_TREE_STATE_CONNECTED;
712 	tree->t_magic = SMB_TREE_MAGIC;
713 	tree->t_access = access;
714 
715 	/* if FS is readonly, enforce that here */
716 	if (tree->t_flags & SMB_TREE_READONLY)
717 		tree->t_access &= ~ACE_ALL_WRITE_PERMS;
718 
719 	if (STYPE_ISDSK(stype)) {
720 		smb_node_ref(snode);
721 		tree->t_snode = snode;
722 		tree->t_acltype = smb_fsop_acltype(snode);
723 	}
724 
725 	smb_llist_enter(&user->u_tree_list, RW_WRITER);
726 	smb_llist_insert_head(&user->u_tree_list, tree);
727 	smb_llist_exit(&user->u_tree_list);
728 	atomic_inc_32(&user->u_session->s_tree_cnt);
729 	atomic_inc_32(&user->u_server->sv_open_trees);
730 
731 	return (tree);
732 }
733 
734 /*
735  * Deallocate a tree: release all resources associated with a tree and
736  * remove the tree from the user's tree list.
737  *
738  * The tree being destroyed must be in the "destroying" state and the
739  * reference count must be zero. This function assumes it's single threaded
740  * i.e. only one thread will attempt to destroy a specific tree, which
741  * should be the case if the tree is in disconnected and has a reference
742  * count of zero.
743  */
744 static void
745 smb_tree_dealloc(smb_tree_t *tree)
746 {
747 	ASSERT(tree);
748 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
749 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
750 	ASSERT(tree->t_refcnt == 0);
751 
752 	/*
753 	 * Remove the tree from the user's tree list.  This must be done
754 	 * before any resources associated with the tree are released.
755 	 */
756 	smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER);
757 	smb_llist_remove(&tree->t_user->u_tree_list, tree);
758 	smb_llist_exit(&tree->t_user->u_tree_list);
759 
760 	tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
761 	smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid);
762 	atomic_dec_32(&tree->t_session->s_tree_cnt);
763 
764 	if (tree->t_snode)
765 		smb_node_release(tree->t_snode);
766 
767 	mutex_destroy(&tree->t_mutex);
768 
769 	/*
770 	 * The list of open files and open directories should be empty.
771 	 */
772 	smb_llist_destructor(&tree->t_ofile_list);
773 	smb_llist_destructor(&tree->t_odir_list);
774 	smb_idpool_destructor(&tree->t_fid_pool);
775 	smb_idpool_destructor(&tree->t_odid_pool);
776 	kmem_cache_free(tree->t_server->si_cache_tree, tree);
777 }
778 
779 /*
780  * Determine whether or not a tree is connected.
781  * This function must be called with the tree mutex held.
782  */
783 static boolean_t
784 smb_tree_is_connected_locked(smb_tree_t *tree)
785 {
786 	switch (tree->t_state) {
787 	case SMB_TREE_STATE_CONNECTED:
788 		return (B_TRUE);
789 
790 	case SMB_TREE_STATE_DISCONNECTING:
791 	case SMB_TREE_STATE_DISCONNECTED:
792 		/*
793 		 * The tree exists but being diconnected or destroyed.
794 		 */
795 		return (B_FALSE);
796 
797 	default:
798 		ASSERT(0);
799 		return (B_FALSE);
800 	}
801 }
802 
803 /*
804  * Determine whether or not a tree is disconnected.
805  * This function must be called with the tree mutex held.
806  */
807 static boolean_t
808 smb_tree_is_disconnected(smb_tree_t *tree)
809 {
810 	switch (tree->t_state) {
811 	case SMB_TREE_STATE_DISCONNECTED:
812 		return (B_TRUE);
813 
814 	case SMB_TREE_STATE_CONNECTED:
815 	case SMB_TREE_STATE_DISCONNECTING:
816 		return (B_FALSE);
817 
818 	default:
819 		ASSERT(0);
820 		return (B_FALSE);
821 	}
822 }
823 
824 /*
825  * Return a pointer to the share name within a share resource path.
826  *
827  * The share path may be a Uniform Naming Convention (UNC) string
828  * (\\server\share) or simply the share name.  We validate the UNC
829  * format but we don't look at the server name.
830  */
831 static const char *
832 smb_tree_get_sharename(const char *unc_path)
833 {
834 	const char *sharename = unc_path;
835 
836 	if (sharename[0] == '\\') {
837 		/*
838 		 * Looks like a UNC path, validate the format.
839 		 */
840 		if (sharename[1] != '\\')
841 			return (NULL);
842 
843 		if ((sharename = strchr(sharename+2, '\\')) == NULL)
844 			return (NULL);
845 
846 		++sharename;
847 	} else if (strchr(sharename, '\\') != NULL) {
848 		/*
849 		 * This should be a share name (no embedded \'s).
850 		 */
851 		return (NULL);
852 	}
853 
854 	return (sharename);
855 }
856 
857 /*
858  * Map the service to a resource type.  Valid values for service are:
859  *
860  *	A:      Disk share
861  *	LPT1:   Printer
862  *	IPC     Named pipe
863  *	COMM    Communications device
864  *	?????   Any type of device (wildcard)
865  *
866  * We support IPC and disk shares; anything else is currently treated
867  * as an error.  IPC$ is reserved as the named pipe share.
868  */
869 static int
870 smb_tree_get_stype(const char *sharename, const char *service,
871     int32_t *stype_ret)
872 {
873 	const char *any = "?????";
874 
875 	if ((strcmp(service, any) == 0) || (strcasecmp(service, "IPC") == 0)) {
876 		if (strcasecmp(sharename, "IPC$") == 0) {
877 			*stype_ret = STYPE_IPC;
878 			return (0);
879 		}
880 	}
881 
882 	if ((strcmp(service, any) == 0) || (strcasecmp(service, "A:") == 0)) {
883 		if (strcasecmp(sharename, "IPC$") == 0)
884 			return (-1);
885 
886 		*stype_ret = STYPE_DISKTREE;
887 		return (0);
888 	}
889 
890 	return (-1);
891 }
892 
893 /*
894  * Obtain the tree attributes: volume name, typename and flags.
895  */
896 static int
897 smb_tree_getattr(const smb_share_t *si, smb_node_t *node, smb_tree_t *tree)
898 {
899 	vfs_t *vfsp = SMB_NODE_VFS(node);
900 
901 	ASSERT(vfsp);
902 
903 	if (getvfs(&vfsp->vfs_fsid) != vfsp)
904 		return (ESTALE);
905 
906 	smb_tree_get_volname(vfsp, tree);
907 	smb_tree_get_flags(si, vfsp, tree);
908 
909 	VFS_RELE(vfsp);
910 	return (0);
911 }
912 
913 /*
914  * Extract the volume name.
915  */
916 static void
917 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
918 {
919 	refstr_t *vfs_mntpoint;
920 	const char *s;
921 	char *name;
922 
923 	vfs_mntpoint = vfs_getmntpoint(vfsp);
924 
925 	s = vfs_mntpoint->rs_string;
926 	s += strspn(s, "/");
927 	(void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
928 
929 	refstr_rele(vfs_mntpoint);
930 
931 	name = tree->t_volume;
932 	(void) strsep((char **)&name, "/");
933 }
934 
935 /*
936  * Always set ACL support because the VFS will fake ACLs for file systems
937  * that don't support them.
938  *
939  * Some flags are dependent on the typename, which is also set up here.
940  * File system types are hardcoded in uts/common/os/vfs_conf.c.
941  */
942 static void
943 smb_tree_get_flags(const smb_share_t *si, vfs_t *vfsp, smb_tree_t *tree)
944 {
945 	typedef struct smb_mtype {
946 		char		*mt_name;
947 		size_t		mt_namelen;
948 		uint32_t	mt_flags;
949 	} smb_mtype_t;
950 
951 	static smb_mtype_t smb_mtype[] = {
952 		{ "zfs",	3,	SMB_TREE_UNICODE_ON_DISK },
953 		{ "ufs",	3,	SMB_TREE_UNICODE_ON_DISK },
954 		{ "nfs",	3,	SMB_TREE_NFS_MOUNTED },
955 		{ "tmpfs",	5,	SMB_TREE_NO_EXPORT }
956 	};
957 	smb_mtype_t	*mtype;
958 	char		*name;
959 	uint32_t	flags = SMB_TREE_SUPPORTS_ACLS;
960 	int		i;
961 
962 	if (si->shr_flags & SMB_SHRF_CATIA)
963 		flags |= SMB_TREE_CATIA;
964 
965 	if (vfsp->vfs_flag & VFS_RDONLY)
966 		flags |= SMB_TREE_READONLY;
967 
968 	if (vfsp->vfs_flag & VFS_XATTR)
969 		flags |= SMB_TREE_STREAMS;
970 
971 	if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL))
972 		flags |= SMB_TREE_NO_ATIME;
973 
974 	name = vfssw[vfsp->vfs_fstype].vsw_name;
975 
976 	for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
977 		mtype = &smb_mtype[i];
978 		if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
979 			flags |= mtype->mt_flags;
980 	}
981 
982 	(void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
983 	(void) utf8_strupr((char *)tree->t_typename);
984 
985 	if (vfs_has_feature(vfsp, VFSFT_XVATTR))
986 		flags |= SMB_TREE_XVATTR;
987 
988 	if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
989 		flags |= SMB_TREE_CASEINSENSITIVE;
990 
991 	if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
992 		flags |= SMB_TREE_NO_CASESENSITIVE;
993 
994 	if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
995 		flags |= SMB_TREE_DIRENTFLAGS;
996 
997 	if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
998 		flags |= SMB_TREE_ACLONCREATE;
999 
1000 	if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
1001 		flags |= SMB_TREE_ACEMASKONACCESS;
1002 
1003 	DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);
1004 
1005 
1006 	tree->t_flags = flags;
1007 }
1008 
1009 /*
1010  * Report share access result to syslog.
1011  */
1012 static void
1013 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
1014 {
1015 	va_list ap;
1016 	char buf[128];
1017 	smb_user_t *user = sr->uid_user;
1018 
1019 	ASSERT(user);
1020 
1021 	if (smb_tcon_mute)
1022 		return;
1023 
1024 	if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
1025 		/*
1026 		 * Only report normal users, i.e. ignore W2K misuse
1027 		 * of the IPC connection by filtering out internal
1028 		 * names such as nobody and root.
1029 		 */
1030 		if ((strcmp(user->u_name, "root") == 0) ||
1031 		    (strcmp(user->u_name, "nobody") == 0)) {
1032 			return;
1033 		}
1034 	}
1035 
1036 	va_start(ap, fmt);
1037 	(void) vsnprintf(buf, 128, fmt, ap);
1038 	va_end(ap);
1039 
1040 	cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
1041 	    user->u_domain, user->u_name, sharename, buf);
1042 }
1043 
1044 /*
1045  * smb_tree_lookup_odir
1046  *
1047  * Find the specified odir in the tree's list of odirs, and
1048  * attempt to obtain a hold on the odir.
1049  *
1050  * Returns NULL if odir not found or a hold cannot be obtained.
1051  */
1052 smb_odir_t *
1053 smb_tree_lookup_odir(smb_tree_t *tree, uint16_t odid)
1054 {
1055 	smb_odir_t	*od;
1056 	smb_llist_t	*od_list;
1057 
1058 	ASSERT(tree);
1059 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1060 
1061 	od_list = &tree->t_odir_list;
1062 	smb_llist_enter(od_list, RW_READER);
1063 
1064 	od = smb_llist_head(od_list);
1065 	while (od) {
1066 		if (od->d_odid == odid) {
1067 			if (!smb_odir_hold(od))
1068 				od = NULL;
1069 			break;
1070 		}
1071 		od = smb_llist_next(od_list, od);
1072 	}
1073 
1074 	smb_llist_exit(od_list);
1075 	return (od);
1076 }
1077 
1078 boolean_t
1079 smb_tree_is_connected(smb_tree_t *tree)
1080 {
1081 	boolean_t	rb;
1082 
1083 	mutex_enter(&tree->t_mutex);
1084 	rb = smb_tree_is_connected_locked(tree);
1085 	mutex_exit(&tree->t_mutex);
1086 	return (rb);
1087 }
1088 
1089 /*
1090  * smb_tree_get_odir
1091  *
1092  * Find the next odir in the tree's list of odirs, and obtain a
1093  * hold on it.
1094  * If the specified odir is NULL the search starts at the beginning
1095  * of the tree's odir list, otherwise the search starts after the
1096  * specified odir.
1097  */
1098 static smb_odir_t *
1099 smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od)
1100 {
1101 	smb_llist_t *od_list;
1102 
1103 	ASSERT(tree);
1104 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1105 
1106 	od_list = &tree->t_odir_list;
1107 	smb_llist_enter(od_list, RW_READER);
1108 
1109 	if (od) {
1110 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1111 		od = smb_llist_next(od_list, od);
1112 	} else {
1113 		od = smb_llist_head(od_list);
1114 	}
1115 
1116 	while (od) {
1117 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1118 
1119 		if (smb_odir_hold(od))
1120 			break;
1121 		od = smb_llist_next(od_list, od);
1122 	}
1123 
1124 	smb_llist_exit(od_list);
1125 	return (od);
1126 }
1127 
1128 /*
1129  * smb_tree_close_odirs
1130  *
1131  * Close all open odirs in the tree's list which were opened by
1132  * the process identified by pid.
1133  * If pid is zero, close all open odirs in the tree's list.
1134  */
1135 static void
1136 smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid)
1137 {
1138 	smb_odir_t *od, *next_od;
1139 
1140 	ASSERT(tree);
1141 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1142 
1143 	od = smb_tree_get_odir(tree, NULL);
1144 	while (od) {
1145 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1146 		ASSERT(od->d_tree == tree);
1147 
1148 		next_od = smb_tree_get_odir(tree, od);
1149 		if ((pid == 0) || (od->d_opened_by_pid == pid))
1150 				smb_odir_close(od);
1151 		smb_odir_release(od);
1152 
1153 		od = next_od;
1154 	}
1155 }
1156 
1157 static void
1158 smb_tree_set_execsub_info(smb_tree_t *tree, smb_execsub_info_t *subs)
1159 {
1160 		subs->e_winname = tree->t_user->u_name;
1161 		subs->e_userdom = tree->t_user->u_domain;
1162 		subs->e_srv_ipaddr = tree->t_session->local_ipaddr;
1163 		subs->e_cli_ipaddr = tree->t_session->ipaddr;
1164 		subs->e_cli_netbiosname = tree->t_session->workstation;
1165 		subs->e_uid = tree->t_user->u_cred->cr_uid;
1166 }
1167