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