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