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