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 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
26 */
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 its 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
167 #include <sys/refstr_impl.h>
168 #include <smbsrv/smb_kproto.h>
169 #include <smbsrv/smb_ktypes.h>
170 #include <smbsrv/smb_fsops.h>
171 #include <smbsrv/smb_share.h>
172
173 int smb_tcon_mute = 0;
174
175 uint32_t smb_tree_connect_core(smb_request_t *);
176 uint32_t smb_tree_connect_disk(smb_request_t *, smb_arg_tcon_t *);
177 uint32_t smb_tree_connect_printq(smb_request_t *, smb_arg_tcon_t *);
178 uint32_t smb_tree_connect_ipc(smb_request_t *, smb_arg_tcon_t *);
179 static smb_tree_t *smb_tree_alloc(smb_request_t *, const smb_kshare_t *,
180 smb_node_t *, uint32_t, uint32_t);
181 static boolean_t smb_tree_is_connected_locked(smb_tree_t *);
182 static boolean_t smb_tree_is_disconnected(smb_tree_t *);
183 static char *smb_tree_get_sharename(char *);
184 static int smb_tree_getattr(const smb_kshare_t *, smb_node_t *, smb_tree_t *);
185 static void smb_tree_get_volname(vfs_t *, smb_tree_t *);
186 static void smb_tree_get_flags(const smb_kshare_t *, vfs_t *, smb_tree_t *);
187 static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
188 static void smb_tree_close_odirs(smb_tree_t *, uint16_t);
189 static smb_ofile_t *smb_tree_get_ofile(smb_tree_t *, smb_ofile_t *);
190 static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *);
191 static void smb_tree_set_execinfo(smb_tree_t *, smb_shr_execinfo_t *, int);
192 static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *);
193 static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *);
194 static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *);
195 static void smb_tree_netinfo_fini(smb_netconnectinfo_t *);
196
197 uint32_t
198 smb_tree_connect(smb_request_t *sr)
199 {
200 smb_server_t *sv = sr->sr_server;
201 uint32_t status;
202
203 if (smb_threshold_enter(&sv->sv_tcon_ct) != 0) {
204 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
205 }
206
207 status = smb_tree_connect_core(sr);
208 smb_threshold_exit(&sv->sv_tcon_ct);
209 return (status);
210 }
211
212 /*
213 * Lookup the share name dispatch the appropriate stype handler.
214 * Share names are case insensitive so we map the share name to
215 * lower-case as a convenience for internal processing.
216 *
217 * Valid service values are:
218 * A: Disk share
219 * LPT1: Printer
220 * IPC Named pipe (IPC$ is reserved as the named pipe share).
221 * COMM Communications device
222 * ????? Any type of device (wildcard)
223 */
224 uint32_t
225 smb_tree_connect_core(smb_request_t *sr)
226 {
227 smb_arg_tcon_t *tcon = &sr->sr_tcon;
228 smb_kshare_t *si;
229 char *name;
230 uint32_t status;
231
232 (void) smb_strlwr(tcon->path);
233
234 if ((name = smb_tree_get_sharename(tcon->path)) == NULL) {
235 smb_tree_log(sr, tcon->path, "invalid UNC path");
236 return (NT_STATUS_BAD_NETWORK_NAME);
237 }
238
239 si = smb_kshare_lookup(sr->sr_server, name);
240 if (si == NULL) {
241 smb_tree_log(sr, name, "share not found");
242 return (NT_STATUS_BAD_NETWORK_NAME);
243 }
244
245 if (!strcasecmp(SMB_SHARE_PRINT, name)) {
246 smb_kshare_release(sr->sr_server, si);
247 smb_tree_log(sr, name, "access not permitted");
248 return (NT_STATUS_ACCESS_DENIED);
249 }
250
251 /* NB: name points into tcon->path - don't free it. */
252 tcon->name = name;
253 sr->sr_tcon.si = si;
254
255 switch (si->shr_type & STYPE_MASK) {
256 case STYPE_DISKTREE:
257 status = smb_tree_connect_disk(sr, &sr->sr_tcon);
258 break;
259 case STYPE_IPC:
260 status = smb_tree_connect_ipc(sr, &sr->sr_tcon);
261 break;
262 case STYPE_PRINTQ:
263 status = smb_tree_connect_printq(sr, &sr->sr_tcon);
264 break;
265 default:
266 status = NT_STATUS_BAD_DEVICE_TYPE;
267 break;
268 }
269
270 smb_kshare_release(sr->sr_server, si);
271 sr->sr_tcon.si = NULL;
272
273 return (status);
274 }
275
276 /*
277 * Disconnect a tree.
278 */
279 void
280 smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec)
281 {
282 smb_shr_execinfo_t execinfo;
283
284 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
285
286 mutex_enter(&tree->t_mutex);
287 ASSERT(tree->t_refcnt);
288
289 if (smb_tree_is_connected_locked(tree)) {
290 /*
291 * Indicate that the disconnect process has started.
292 */
293 tree->t_state = SMB_TREE_STATE_DISCONNECTING;
294 mutex_exit(&tree->t_mutex);
295
296 if (do_exec) {
297 /*
298 * The files opened under this tree are closed.
299 */
300 smb_ofile_close_all(tree);
301 /*
302 * The directories opened under this tree are closed.
303 */
304 smb_tree_close_odirs(tree, 0);
305 }
306
307 mutex_enter(&tree->t_mutex);
308 tree->t_state = SMB_TREE_STATE_DISCONNECTED;
309 smb_server_dec_trees(tree->t_server);
310 }
311
312 mutex_exit(&tree->t_mutex);
313
314 if (do_exec && (tree->t_state == SMB_TREE_STATE_DISCONNECTED) &&
315 (tree->t_execflags & SMB_EXEC_UNMAP)) {
316
317 smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_UNMAP);
318 (void) smb_kshare_exec(tree->t_server, &execinfo);
319 }
320 }
321
322 /*
323 * Take a reference on a tree.
324 */
325 boolean_t
326 smb_tree_hold(
327 smb_tree_t *tree)
328 {
329 SMB_TREE_VALID(tree);
330
331 mutex_enter(&tree->t_mutex);
332
333 if (smb_tree_is_connected_locked(tree)) {
334 tree->t_refcnt++;
335 mutex_exit(&tree->t_mutex);
336 return (B_TRUE);
337 }
338
339 mutex_exit(&tree->t_mutex);
340 return (B_FALSE);
341 }
342
343 /*
344 * Bump the hold count regardless of the tree state. This is used in
345 * some internal code paths where we've already checked that we had a
346 * valid tree connection, and don't want to deal with the possiblity
347 * that the tree state might have changed to disconnecting after our
348 * original hold was taken. It's correct to continue processing a
349 * request even when new requests cannot lookup that tree anymore.
350 */
351 void
352 smb_tree_hold_internal(
353 smb_tree_t *tree)
354 {
355 SMB_TREE_VALID(tree);
356
357 mutex_enter(&tree->t_mutex);
358 tree->t_refcnt++;
359 mutex_exit(&tree->t_mutex);
360 }
361
362 /*
363 * Release a reference on a tree. If the tree is disconnected and the
364 * reference count falls to zero, post the object for deletion.
365 * Object deletion is deferred to avoid modifying a list while an
366 * iteration may be in progress.
367 */
368 void
369 smb_tree_release(
370 smb_tree_t *tree)
371 {
372 SMB_TREE_VALID(tree);
373
374 mutex_enter(&tree->t_mutex);
375 ASSERT(tree->t_refcnt);
376 tree->t_refcnt--;
377
378 /* flush the ofile and odir lists' delete queues */
379 smb_llist_flush(&tree->t_ofile_list);
380 smb_llist_flush(&tree->t_odir_list);
381
382 if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0))
383 smb_session_post_tree(tree->t_session, tree);
384
385 mutex_exit(&tree->t_mutex);
386 }
387
388 void
389 smb_tree_post_ofile(smb_tree_t *tree, smb_ofile_t *of)
390 {
391 SMB_TREE_VALID(tree);
392 SMB_OFILE_VALID(of);
393 ASSERT(of->f_refcnt == 0);
394 ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED);
395 ASSERT(of->f_tree == tree);
396
397 smb_llist_post(&tree->t_ofile_list, of, smb_ofile_delete);
398 }
399
400 void
401 smb_tree_post_odir(smb_tree_t *tree, smb_odir_t *od)
402 {
403 SMB_TREE_VALID(tree);
404 SMB_ODIR_VALID(od);
405 ASSERT(od->d_refcnt == 0);
406 ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED);
407 ASSERT(od->d_tree == tree);
408
409 smb_llist_post(&tree->t_odir_list, od, smb_odir_delete);
410 }
411
412 /*
413 * Close ofiles and odirs that match pid.
414 */
415 void
416 smb_tree_close_pid(
417 smb_tree_t *tree,
418 uint32_t pid)
419 {
420 ASSERT(tree);
421 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
422
423 smb_ofile_close_all_by_pid(tree, pid);
424 smb_tree_close_odirs(tree, pid);
425 }
426
427 /*
428 * Check whether or not a tree supports the features identified by flags.
429 */
430 boolean_t
431 smb_tree_has_feature(smb_tree_t *tree, uint32_t flags)
432 {
433 ASSERT(tree);
434 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
435
436 return ((tree->t_flags & flags) == flags);
437 }
438
439 /*
440 * If the enumeration request is for tree data, handle the request
441 * here. Otherwise, pass it on to the ofiles.
442 *
443 * This function should be called with a hold on the tree.
444 */
445 int
446 smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum)
447 {
448 smb_ofile_t *of;
449 smb_ofile_t *next;
450 int rc = 0;
451
452 ASSERT(tree);
453 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
454
455 if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE)
456 return (smb_tree_enum_private(tree, svcenum));
457
458 of = smb_tree_get_ofile(tree, NULL);
459 while (of) {
460 ASSERT(of->f_tree == tree);
461
462 rc = smb_ofile_enum(of, svcenum);
463 if (rc != 0) {
464 smb_ofile_release(of);
465 break;
466 }
467
468 next = smb_tree_get_ofile(tree, of);
469 smb_ofile_release(of);
470 of = next;
471 }
472
473 return (rc);
474 }
475
476 /*
477 * Close a file by its unique id.
478 */
479 int
480 smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid)
481 {
482 smb_ofile_t *of;
483
484 ASSERT(tree);
485 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
486
487 if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL)
488 return (ENOENT);
489
490 if (smb_ofile_disallow_fclose(of)) {
491 smb_ofile_release(of);
492 return (EACCES);
493 }
494
495 smb_ofile_close(of, 0);
496 smb_ofile_release(of);
497 return (0);
498 }
499
500 /* *************************** Static Functions ***************************** */
501
502 #define SHARES_DIR ".zfs/shares/"
503
504 /*
505 * Calculates permissions given by the share's ACL to the
506 * user in the passed request. The default is full access.
507 * If any error occurs, full access is granted.
508 *
509 * Using the vnode of the share path find the root directory
510 * of the mounted file system. Then look to see if there is a
511 * .zfs/shares directory and if there is, lookup the file with
512 * the same name as the share name in it. The ACL set for this
513 * file is the share's ACL which is used for access check here.
514 */
515 static uint32_t
516 smb_tree_acl_access(smb_request_t *sr, const smb_kshare_t *si, vnode_t *pathvp)
517 {
518 smb_user_t *user;
519 cred_t *cred;
520 int rc;
521 vfs_t *vfsp;
522 vnode_t *root = NULL;
523 vnode_t *sharevp = NULL;
524 char *sharepath;
525 struct pathname pnp;
526 size_t size;
527 uint32_t access;
528
529 user = sr->uid_user;
530 cred = user->u_cred;
531 access = ACE_ALL_PERMS;
532
533 if (si->shr_flags & SMB_SHRF_AUTOHOME) {
534 /*
535 * An autohome share owner gets full access to the share.
536 * Everyone else is denied access.
537 */
538 if (si->shr_uid != crgetuid(cred))
539 access = 0;
540
541 return (access);
542 }
543
544 /*
545 * The hold on 'root' is released by the lookuppnvp() that follows
546 */
547 vfsp = pathvp->v_vfsp;
548 if (vfsp != NULL)
549 rc = VFS_ROOT(vfsp, &root);
550 else
551 rc = ENOENT;
552
553 if (rc != 0)
554 return (access);
555
556
557 size = sizeof (SHARES_DIR) + strlen(si->shr_name) + 1;
558 sharepath = smb_srm_alloc(sr, size);
559 (void) snprintf(sharepath, size, "%s%s", SHARES_DIR, si->shr_name);
560
561 pn_alloc(&pnp);
562 (void) pn_set(&pnp, sharepath);
563 rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL, &sharevp, rootdir, root,
564 zone_kcred());
565 pn_free(&pnp);
566
567 /*
568 * Now get the effective access value based on cred and ACL values.
569 */
570 if (rc == 0) {
571 smb_vop_eaccess(sharevp, (int *)&access, V_ACE_MASK, NULL,
572 cred);
573 VN_RELE(sharevp);
574 }
575
576 return (access);
577 }
578
579 /*
580 * Performs the following access checks for a disk share:
581 *
582 * - No IPC/anonymous user is allowed
583 *
584 * - If user is Guest, guestok property of the share should be
585 * enabled
586 *
587 * - If this is an Admin share, the user should have administrative
588 * privileges
589 *
590 * - Host based access control lists
591 *
592 * - Share ACL
593 *
594 * Returns the access allowed or 0 if access is denied.
595 */
596 static uint32_t
597 smb_tree_chkaccess(smb_request_t *sr, smb_kshare_t *shr, vnode_t *vp)
598 {
599 smb_user_t *user = sr->uid_user;
600 char *sharename = shr->shr_name;
601 uint32_t host_access;
602 uint32_t acl_access;
603 uint32_t access;
604
605 if (user->u_flags & SMB_USER_FLAG_ANON) {
606 smb_tree_log(sr, sharename, "access denied: IPC only");
607 return (0);
608 }
609
610 if ((user->u_flags & SMB_USER_FLAG_GUEST) &&
611 ((shr->shr_flags & SMB_SHRF_GUEST_OK) == 0)) {
612 smb_tree_log(sr, sharename, "access denied: guest disabled");
613 return (0);
614 }
615
616 if ((shr->shr_flags & SMB_SHRF_ADMIN) && !smb_user_is_admin(user)) {
617 smb_tree_log(sr, sharename, "access denied: not admin");
618 return (0);
619 }
620
621 host_access = smb_kshare_hostaccess(shr, sr->session);
622 if ((host_access & ACE_ALL_PERMS) == 0) {
623 smb_tree_log(sr, sharename, "access denied: host access");
624 return (0);
625 }
626
627 acl_access = smb_tree_acl_access(sr, shr, vp);
628 if ((acl_access & ACE_ALL_PERMS) == 0) {
629 smb_tree_log(sr, sharename, "access denied: share ACL");
630 return (0);
631 }
632
633 access = host_access & acl_access;
634 if ((access & ACE_ALL_PERMS) == 0) {
635 smb_tree_log(sr, sharename, "access denied");
636 return (0);
637 }
638
639 return (access);
640 }
641
642 /*
643 * Connect a share for use with files and directories.
644 */
645 uint32_t
646 smb_tree_connect_disk(smb_request_t *sr, smb_arg_tcon_t *tcon)
647 {
648 char *sharename = tcon->path;
649 const char *any = "?????";
650 smb_user_t *user = sr->uid_user;
651 smb_node_t *dnode = NULL;
652 smb_node_t *snode = NULL;
653 smb_kshare_t *si = tcon->si;
654 char *service = tcon->service;
655 char last_component[MAXNAMELEN];
656 smb_tree_t *tree;
657 int rc;
658 uint32_t access;
659 smb_shr_execinfo_t execinfo;
660
661 ASSERT(user);
662 ASSERT(user->u_cred);
663
664 if (service != NULL &&
665 strcmp(service, any) != 0 &&
666 strcasecmp(service, "A:") != 0) {
667 smb_tree_log(sr, sharename, "invalid service (%s)", service);
668 return (NT_STATUS_BAD_DEVICE_TYPE);
669 }
670
671 /*
672 * Check that the shared directory exists.
673 */
674 rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
675 last_component);
676 if (rc == 0) {
677 rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
678 sr->sr_server->si_root_smb_node, dnode, last_component,
679 &snode);
680
681 smb_node_release(dnode);
682 }
683
684 if (rc) {
685 if (snode)
686 smb_node_release(snode);
687
688 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
689 return (NT_STATUS_BAD_NETWORK_NAME);
690 }
691
692 if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
693 smb_node_release(snode);
694 return (NT_STATUS_ACCESS_DENIED);
695 }
696
697 /*
698 * Set up the OptionalSupport for this share.
699 */
700 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
701
702 switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
703 case SMB_SHRF_CSC_DISABLED:
704 tcon->optional_support |= SMB_CSC_CACHE_NONE;
705 break;
706 case SMB_SHRF_CSC_AUTO:
707 tcon->optional_support |= SMB_CSC_CACHE_AUTO_REINT;
708 break;
709 case SMB_SHRF_CSC_VDO:
710 tcon->optional_support |= SMB_CSC_CACHE_VDO;
711 break;
712 case SMB_SHRF_CSC_MANUAL:
713 default:
714 /*
715 * Default to SMB_CSC_CACHE_MANUAL_REINT.
716 */
717 break;
718 }
719
720 /* ABE support */
721 if (si->shr_flags & SMB_SHRF_ABE)
722 tcon->optional_support |=
723 SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
724
725 if (si->shr_flags & SMB_SHRF_DFSROOT)
726 tcon->optional_support |= SMB_SHARE_IS_IN_DFS;
727
728 /* if 'smb' zfs property: shortnames=disabled */
729 if (!smb_shortnames)
730 sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME;
731
732 tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
733
734 smb_node_release(snode);
735
736 if (tree == NULL)
737 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
738
739 if (tree->t_execflags & SMB_EXEC_MAP) {
740 smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_MAP);
741
742 rc = smb_kshare_exec(tree->t_server, &execinfo);
743
744 if ((rc != 0) && (tree->t_execflags & SMB_EXEC_TERM)) {
745 smb_tree_disconnect(tree, B_FALSE);
746 smb_tree_release(tree);
747 return (NT_STATUS_ACCESS_DENIED);
748 }
749 }
750
751 sr->tid_tree = tree;
752 sr->smb_tid = tree->t_tid;
753
754 return (0);
755 }
756
757 /*
758 * Shares have both a share and host based access control. The access
759 * granted will be minimum permissions based on both hostaccess
760 * (permissions allowed by host based access) and aclaccess (from the
761 * share ACL).
762 */
763 uint32_t
764 smb_tree_connect_printq(smb_request_t *sr, smb_arg_tcon_t *tcon)
765 {
766 char *sharename = tcon->path;
767 const char *any = "?????";
768 smb_user_t *user = sr->uid_user;
769 smb_node_t *dnode = NULL;
770 smb_node_t *snode = NULL;
771 smb_kshare_t *si = tcon->si;
772 char *service = tcon->service;
773 char last_component[MAXNAMELEN];
774 smb_tree_t *tree;
775 int rc;
776 uint32_t access;
777
778 ASSERT(user);
779 ASSERT(user->u_cred);
780
781 if (sr->sr_server->sv_cfg.skc_print_enable == 0) {
782 smb_tree_log(sr, sharename, "printing disabled");
783 return (NT_STATUS_BAD_NETWORK_NAME);
784 }
785
786 if (service != NULL &&
787 strcmp(service, any) != 0 &&
788 strcasecmp(service, "LPT1:") != 0) {
789 smb_tree_log(sr, sharename, "invalid service (%s)", service);
790 return (NT_STATUS_BAD_DEVICE_TYPE);
791 }
792
793 /*
794 * Check that the shared directory exists.
795 */
796 rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
797 last_component);
798 if (rc == 0) {
799 rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
800 sr->sr_server->si_root_smb_node, dnode, last_component,
801 &snode);
802
803 smb_node_release(dnode);
804 }
805
806 if (rc) {
807 if (snode)
808 smb_node_release(snode);
809
810 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
811 return (NT_STATUS_BAD_NETWORK_NAME);
812 }
813
814 if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
815 smb_node_release(snode);
816 return (NT_STATUS_ACCESS_DENIED);
817 }
818
819 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
820
821 tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
822
823 smb_node_release(snode);
824
825 if (tree == NULL)
826 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
827
828 sr->tid_tree = tree;
829 sr->smb_tid = tree->t_tid;
830
831 return (0);
832 }
833
834 /*
835 * Connect an IPC share for use with named pipes.
836 */
837 uint32_t
838 smb_tree_connect_ipc(smb_request_t *sr, smb_arg_tcon_t *tcon)
839 {
840 char *name = tcon->path;
841 const char *any = "?????";
842 smb_user_t *user = sr->uid_user;
843 smb_tree_t *tree;
844 smb_kshare_t *si = tcon->si;
845 char *service = tcon->service;
846
847 ASSERT(user);
848
849 if (service != NULL &&
850 strcmp(service, any) != 0 &&
851 strcasecmp(service, "IPC") != 0) {
852 smb_tree_log(sr, name, "invalid service (%s)", service);
853 return (NT_STATUS_BAD_DEVICE_TYPE);
854 }
855
856 if ((user->u_flags & SMB_USER_FLAG_ANON) &&
857 sr->sr_cfg->skc_restrict_anon) {
858 smb_tree_log(sr, name, "access denied: restrict anonymous");
859 return (NT_STATUS_ACCESS_DENIED);
860 }
861
862 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
863
864 tree = smb_tree_alloc(sr, si, NULL, ACE_ALL_PERMS, 0);
865 if (tree == NULL)
866 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
867
868 sr->tid_tree = tree;
869 sr->smb_tid = tree->t_tid;
870
871 return (0);
872 }
873
874 /*
875 * Allocate a tree.
876 */
877 static smb_tree_t *
878 smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si,
879 smb_node_t *snode, uint32_t access, uint32_t execflags)
880 {
881 smb_session_t *session = sr->session;
882 smb_tree_t *tree;
883 uint32_t stype = si->shr_type;
884 uint16_t tid;
885
886 if (smb_idpool_alloc(&session->s_tid_pool, &tid))
887 return (NULL);
888
889 tree = kmem_cache_alloc(smb_cache_tree, KM_SLEEP);
890 bzero(tree, sizeof (smb_tree_t));
891
892 tree->t_session = session;
893 tree->t_server = session->s_server;
894
895 /* grab a ref for tree->t_owner */
896 smb_user_hold_internal(sr->uid_user);
897 tree->t_owner = sr->uid_user;
898
899 if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
900 if (smb_tree_getattr(si, snode, tree) != 0) {
901 smb_idpool_free(&session->s_tid_pool, tid);
902 kmem_cache_free(smb_cache_tree, tree);
903 return (NULL);
904 }
905 }
906
907 if (smb_idpool_constructor(&tree->t_fid_pool)) {
908 smb_idpool_free(&session->s_tid_pool, tid);
909 kmem_cache_free(smb_cache_tree, tree);
910 return (NULL);
911 }
912
913 if (smb_idpool_constructor(&tree->t_odid_pool)) {
914 smb_idpool_destructor(&tree->t_fid_pool);
915 smb_idpool_free(&session->s_tid_pool, tid);
916 kmem_cache_free(smb_cache_tree, tree);
917 return (NULL);
918 }
919
920 smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
921 offsetof(smb_ofile_t, f_lnd));
922
923 smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
924 offsetof(smb_odir_t, d_lnd));
925
926 (void) strlcpy(tree->t_sharename, si->shr_name,
927 sizeof (tree->t_sharename));
928 (void) strlcpy(tree->t_resource, si->shr_path,
929 sizeof (tree->t_resource));
930
931 mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
932
933 tree->t_refcnt = 1;
934 tree->t_tid = tid;
935 tree->t_res_type = stype;
936 tree->t_state = SMB_TREE_STATE_CONNECTED;
937 tree->t_magic = SMB_TREE_MAGIC;
938 tree->t_access = access;
939 tree->t_connect_time = gethrestime_sec();
940 tree->t_execflags = execflags;
941
942 /* if FS is readonly, enforce that here */
943 if (tree->t_flags & SMB_TREE_READONLY)
944 tree->t_access &= ~ACE_ALL_WRITE_PERMS;
945
946 if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
947 smb_node_ref(snode);
948 tree->t_snode = snode;
949 tree->t_acltype = smb_fsop_acltype(snode);
950 }
951
952 smb_llist_enter(&session->s_tree_list, RW_WRITER);
953 smb_llist_insert_head(&session->s_tree_list, tree);
954 smb_llist_exit(&session->s_tree_list);
955 atomic_inc_32(&session->s_tree_cnt);
956 smb_server_inc_trees(session->s_server);
957 return (tree);
958 }
959
960 /*
961 * Deallocate a tree. The open file and open directory lists should be
962 * empty.
963 *
964 * Remove the tree from the user's tree list before freeing resources
965 * associated with the tree.
966 */
967 void
968 smb_tree_dealloc(void *arg)
969 {
970 smb_session_t *session;
971 smb_tree_t *tree = (smb_tree_t *)arg;
972
973 SMB_TREE_VALID(tree);
974 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
975 ASSERT(tree->t_refcnt == 0);
976
977 session = tree->t_session;
978 smb_llist_enter(&session->s_tree_list, RW_WRITER);
979 smb_llist_remove(&session->s_tree_list, tree);
980 smb_idpool_free(&session->s_tid_pool, tree->t_tid);
981 atomic_dec_32(&session->s_tree_cnt);
982 smb_llist_exit(&session->s_tree_list);
983
984 mutex_enter(&tree->t_mutex);
985 mutex_exit(&tree->t_mutex);
986
987 tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
988
989 if (tree->t_snode)
990 smb_node_release(tree->t_snode);
991
992 mutex_destroy(&tree->t_mutex);
993 smb_llist_destructor(&tree->t_ofile_list);
994 smb_llist_destructor(&tree->t_odir_list);
995 smb_idpool_destructor(&tree->t_fid_pool);
996 smb_idpool_destructor(&tree->t_odid_pool);
997
998 SMB_USER_VALID(tree->t_owner);
999 smb_user_release(tree->t_owner);
1000
1001 kmem_cache_free(smb_cache_tree, tree);
1002 }
1003
1004 /*
1005 * Determine whether or not a tree is connected.
1006 * This function must be called with the tree mutex held.
1007 */
1008 static boolean_t
1009 smb_tree_is_connected_locked(smb_tree_t *tree)
1010 {
1011 switch (tree->t_state) {
1012 case SMB_TREE_STATE_CONNECTED:
1013 return (B_TRUE);
1014
1015 case SMB_TREE_STATE_DISCONNECTING:
1016 case SMB_TREE_STATE_DISCONNECTED:
1017 /*
1018 * The tree exists but being diconnected or destroyed.
1019 */
1020 return (B_FALSE);
1021
1022 default:
1023 ASSERT(0);
1024 return (B_FALSE);
1025 }
1026 }
1027
1028 /*
1029 * Determine whether or not a tree is disconnected.
1030 * This function must be called with the tree mutex held.
1031 */
1032 static boolean_t
1033 smb_tree_is_disconnected(smb_tree_t *tree)
1034 {
1035 switch (tree->t_state) {
1036 case SMB_TREE_STATE_DISCONNECTED:
1037 return (B_TRUE);
1038
1039 case SMB_TREE_STATE_CONNECTED:
1040 case SMB_TREE_STATE_DISCONNECTING:
1041 return (B_FALSE);
1042
1043 default:
1044 ASSERT(0);
1045 return (B_FALSE);
1046 }
1047 }
1048
1049 /*
1050 * Return a pointer to the share name within a share resource path.
1051 *
1052 * The share path may be a Uniform Naming Convention (UNC) string
1053 * (\\server\share) or simply the share name. We validate the UNC
1054 * format but we don't look at the server name.
1055 */
1056 static char *
1057 smb_tree_get_sharename(char *unc_path)
1058 {
1059 char *sharename = unc_path;
1060
1061 if (sharename[0] == '\\') {
1062 /*
1063 * Looks like a UNC path, validate the format.
1064 */
1065 if (sharename[1] != '\\')
1066 return (NULL);
1067
1068 if ((sharename = strchr(sharename+2, '\\')) == NULL)
1069 return (NULL);
1070
1071 ++sharename;
1072 } else if (strchr(sharename, '\\') != NULL) {
1073 /*
1074 * This should be a share name (no embedded \'s).
1075 */
1076 return (NULL);
1077 }
1078
1079 return (sharename);
1080 }
1081
1082 /*
1083 * Obtain the tree attributes: volume name, typename and flags.
1084 */
1085 static int
1086 smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree)
1087 {
1088 vfs_t *vfsp = SMB_NODE_VFS(node);
1089
1090 ASSERT(vfsp);
1091
1092 if (getvfs(&vfsp->vfs_fsid) != vfsp)
1093 return (ESTALE);
1094
1095 smb_tree_get_volname(vfsp, tree);
1096 smb_tree_get_flags(si, vfsp, tree);
1097
1098 VFS_RELE(vfsp);
1099 return (0);
1100 }
1101
1102 /*
1103 * Extract the volume name.
1104 */
1105 static void
1106 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
1107 {
1108 #ifdef _FAKE_KERNEL
1109 _NOTE(ARGUNUSED(vfsp))
1110 (void) strlcpy(tree->t_volume, "fake", SMB_VOLNAMELEN);
1111 #else /* _FAKE_KERNEL */
1112 refstr_t *vfs_mntpoint;
1113 const char *s;
1114 char *name;
1115
1116 vfs_mntpoint = vfs_getmntpoint(vfsp);
1117
1118 s = refstr_value(vfs_mntpoint);
1119 s += strspn(s, "/");
1120 (void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
1121
1122 refstr_rele(vfs_mntpoint);
1123
1124 name = tree->t_volume;
1125 (void) strsep((char **)&name, "/");
1126 #endif /* _FAKE_KERNEL */
1127 }
1128
1129 /*
1130 * Always set "unicode on disk" because we always use utf8 names locally.
1131 * Always set ACL support because the VFS will fake ACLs for file systems
1132 * that don't support them.
1133 *
1134 * Some flags are dependent on the typename, which is also set up here.
1135 * File system types are hardcoded in uts/common/os/vfs_conf.c.
1136 */
1137 static void
1138 smb_tree_get_flags(const smb_kshare_t *si, vfs_t *vfsp, smb_tree_t *tree)
1139 {
1140 smb_session_t *ssn = tree->t_session;
1141 struct vfssw *vswp;
1142
1143 typedef struct smb_mtype {
1144 char *mt_name;
1145 size_t mt_namelen;
1146 uint32_t mt_flags;
1147 } smb_mtype_t;
1148
1149 static smb_mtype_t smb_mtype[] = {
1150 { "zfs", 3, SMB_TREE_QUOTA | SMB_TREE_SPARSE},
1151 { "ufs", 3, 0 },
1152 { "nfs", 3, SMB_TREE_NFS_MOUNTED },
1153 { "tmpfs", 5, SMB_TREE_NO_EXPORT }
1154 };
1155 smb_mtype_t *mtype;
1156 char *name;
1157 uint32_t flags =
1158 SMB_TREE_SUPPORTS_ACLS |
1159 SMB_TREE_UNICODE_ON_DISK;
1160 int i;
1161
1162 if (si->shr_flags & SMB_SHRF_DFSROOT)
1163 flags |= SMB_TREE_DFSROOT;
1164
1165 if (si->shr_flags & SMB_SHRF_CATIA)
1166 flags |= SMB_TREE_CATIA;
1167
1168 if (si->shr_flags & SMB_SHRF_ABE)
1169 flags |= SMB_TREE_ABE;
1170
1171 if (ssn->s_cfg.skc_oplock_enable) {
1172 /* if 'smb' zfs property: oplocks=enabled */
1173 flags |= SMB_TREE_OPLOCKS;
1174 }
1175
1176 /* Global config option for now. Later make per-share. */
1177 if (ssn->s_cfg.skc_traverse_mounts)
1178 flags |= SMB_TREE_TRAVERSE_MOUNTS;
1179
1180 /* if 'smb' zfs property: shortnames=enabled */
1181 if (smb_shortnames)
1182 flags |= SMB_TREE_SHORTNAMES;
1183
1184 if (vfsp->vfs_flag & VFS_RDONLY)
1185 flags |= SMB_TREE_READONLY;
1186
1187 if (vfsp->vfs_flag & VFS_XATTR)
1188 flags |= SMB_TREE_STREAMS;
1189
1190 vswp = vfs_getvfsswbyvfsops(vfs_getops(vfsp));
1191 if (vswp != NULL) {
1192 name = vswp->vsw_name;
1193 vfs_unrefvfssw(vswp);
1194 } else {
1195 name = "?";
1196 }
1197
1198 for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
1199 mtype = &smb_mtype[i];
1200 if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
1201 flags |= mtype->mt_flags;
1202 }
1203
1204 (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
1205 (void) smb_strupr((char *)tree->t_typename);
1206
1207 if (vfs_has_feature(vfsp, VFSFT_XVATTR))
1208 flags |= SMB_TREE_XVATTR;
1209
1210 if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
1211 flags |= SMB_TREE_CASEINSENSITIVE;
1212
1213 if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
1214 flags |= SMB_TREE_NO_CASESENSITIVE;
1215
1216 if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
1217 flags |= SMB_TREE_DIRENTFLAGS;
1218
1219 if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
1220 flags |= SMB_TREE_ACLONCREATE;
1221
1222 if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
1223 flags |= SMB_TREE_ACEMASKONACCESS;
1224
1225 DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);
1226
1227
1228 tree->t_flags = flags;
1229 }
1230
1231 /*
1232 * Report share access result to syslog.
1233 */
1234 static void
1235 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
1236 {
1237 va_list ap;
1238 char buf[128];
1239 smb_user_t *user = sr->uid_user;
1240
1241 ASSERT(user);
1242
1243 if (smb_tcon_mute)
1244 return;
1245
1246 if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
1247 /*
1248 * Only report normal users, i.e. ignore W2K misuse
1249 * of the IPC connection by filtering out internal
1250 * names such as nobody and root.
1251 */
1252 if ((strcmp(user->u_name, "root") == 0) ||
1253 (strcmp(user->u_name, "nobody") == 0)) {
1254 return;
1255 }
1256 }
1257
1258 va_start(ap, fmt);
1259 (void) vsnprintf(buf, 128, fmt, ap);
1260 va_end(ap);
1261
1262 cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
1263 user->u_domain, user->u_name, sharename, buf);
1264 }
1265
1266 /*
1267 * smb_tree_lookup_odir
1268 *
1269 * Find the specified odir in the tree's list of odirs, and
1270 * attempt to obtain a hold on the odir.
1271 *
1272 * Returns NULL if odir not found or a hold cannot be obtained.
1273 */
1274 smb_odir_t *
1275 smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid)
1276 {
1277 smb_odir_t *od;
1278 smb_llist_t *od_list;
1279 smb_tree_t *tree = sr->tid_tree;
1280
1281 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1282
1283 od_list = &tree->t_odir_list;
1284
1285 smb_llist_enter(od_list, RW_READER);
1286 od = smb_llist_head(od_list);
1287 while (od) {
1288 if (od->d_odid == odid)
1289 break;
1290 od = smb_llist_next(od_list, od);
1291 }
1292 if (od == NULL)
1293 goto out;
1294
1295 /*
1296 * Only allow use of a given Search ID with the same UID that
1297 * was used to create it. MS-CIFS 3.3.5.14
1298 */
1299 if (od->d_user != sr->uid_user) {
1300 od = NULL;
1301 goto out;
1302 }
1303 if (!smb_odir_hold(od))
1304 od = NULL;
1305
1306 out:
1307 smb_llist_exit(od_list);
1308 return (od);
1309 }
1310
1311 boolean_t
1312 smb_tree_is_connected(smb_tree_t *tree)
1313 {
1314 boolean_t rb;
1315
1316 mutex_enter(&tree->t_mutex);
1317 rb = smb_tree_is_connected_locked(tree);
1318 mutex_exit(&tree->t_mutex);
1319 return (rb);
1320 }
1321
1322 /*
1323 * Get the next open ofile in the list. A reference is taken on
1324 * the ofile, which can be released later with smb_ofile_release().
1325 *
1326 * If the specified ofile is NULL, search from the beginning of the
1327 * list. Otherwise, the search starts just after that ofile.
1328 *
1329 * Returns NULL if there are no open files in the list.
1330 */
1331 static smb_ofile_t *
1332 smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of)
1333 {
1334 smb_llist_t *ofile_list;
1335
1336 ASSERT(tree);
1337 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1338
1339 ofile_list = &tree->t_ofile_list;
1340 smb_llist_enter(ofile_list, RW_READER);
1341
1342 if (of) {
1343 ASSERT(of->f_magic == SMB_OFILE_MAGIC);
1344 of = smb_llist_next(ofile_list, of);
1345 } else {
1346 of = smb_llist_head(ofile_list);
1347 }
1348
1349 while (of) {
1350 if (smb_ofile_hold(of))
1351 break;
1352
1353 of = smb_llist_next(ofile_list, of);
1354 }
1355
1356 smb_llist_exit(ofile_list);
1357 return (of);
1358 }
1359
1360 /*
1361 * smb_tree_get_odir
1362 *
1363 * Find the next odir in the tree's list of odirs, and obtain a
1364 * hold on it.
1365 * If the specified odir is NULL the search starts at the beginning
1366 * of the tree's odir list, otherwise the search starts after the
1367 * specified odir.
1368 */
1369 static smb_odir_t *
1370 smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od)
1371 {
1372 smb_llist_t *od_list;
1373
1374 ASSERT(tree);
1375 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1376
1377 od_list = &tree->t_odir_list;
1378 smb_llist_enter(od_list, RW_READER);
1379
1380 if (od) {
1381 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1382 od = smb_llist_next(od_list, od);
1383 } else {
1384 od = smb_llist_head(od_list);
1385 }
1386
1387 while (od) {
1388 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1389
1390 if (smb_odir_hold(od))
1391 break;
1392 od = smb_llist_next(od_list, od);
1393 }
1394
1395 smb_llist_exit(od_list);
1396 return (od);
1397 }
1398
1399 /*
1400 * smb_tree_close_odirs
1401 *
1402 * Close all open odirs in the tree's list which were opened by
1403 * the process identified by pid.
1404 * If pid is zero, close all open odirs in the tree's list.
1405 */
1406 static void
1407 smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid)
1408 {
1409 smb_odir_t *od, *next_od;
1410
1411 ASSERT(tree);
1412 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1413
1414 od = smb_tree_get_odir(tree, NULL);
1415 while (od) {
1416 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1417 ASSERT(od->d_tree == tree);
1418
1419 next_od = smb_tree_get_odir(tree, od);
1420 if ((pid == 0) || (od->d_opened_by_pid == pid))
1421 smb_odir_close(od);
1422 smb_odir_release(od);
1423
1424 od = next_od;
1425 }
1426 }
1427
1428 static void
1429 smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec,
1430 int exec_type)
1431 {
1432 exec->e_sharename = tree->t_sharename;
1433 exec->e_winname = tree->t_owner->u_name;
1434 exec->e_userdom = tree->t_owner->u_domain;
1435 exec->e_srv_ipaddr = tree->t_session->local_ipaddr;
1436 exec->e_cli_ipaddr = tree->t_session->ipaddr;
1437 exec->e_cli_netbiosname = tree->t_session->workstation;
1438 exec->e_uid = crgetuid(tree->t_owner->u_cred);
1439 exec->e_type = exec_type;
1440 }
1441
1442 /*
1443 * Private function to support smb_tree_enum.
1444 */
1445 static int
1446 smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum)
1447 {
1448 uint8_t *pb;
1449 uint_t nbytes;
1450 int rc;
1451
1452 if (svcenum->se_nskip > 0) {
1453 svcenum->se_nskip--;
1454 return (0);
1455 }
1456
1457 if (svcenum->se_nitems >= svcenum->se_nlimit) {
1458 svcenum->se_nitems = svcenum->se_nlimit;
1459 return (0);
1460 }
1461
1462 pb = &svcenum->se_buf[svcenum->se_bused];
1463 rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes);
1464 if (rc == 0) {
1465 svcenum->se_bavail -= nbytes;
1466 svcenum->se_bused += nbytes;
1467 svcenum->se_nitems++;
1468 }
1469
1470 return (rc);
1471 }
1472
1473 /*
1474 * Encode connection information into a buffer: connection information
1475 * needed in user space to support RPC requests.
1476 */
1477 static int
1478 smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
1479 uint32_t *nbytes)
1480 {
1481 smb_netconnectinfo_t info;
1482 int rc;
1483
1484 smb_tree_netinfo_init(tree, &info);
1485 rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes);
1486 smb_tree_netinfo_fini(&info);
1487
1488 return (rc);
1489 }
1490
1491 static void
1492 smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen)
1493 {
1494 smb_user_t *user = tree->t_owner;
1495
1496 /*
1497 * u_domain_len and u_name_len include the '\0' in their
1498 * lengths, hence the sum of the two lengths gives us room
1499 * for both the '\\' and '\0' chars.
1500 */
1501 ASSERT(namestr);
1502 ASSERT(namelen);
1503 ASSERT(user->u_domain_len > 0);
1504 ASSERT(user->u_name_len > 0);
1505 *namelen = user->u_domain_len + user->u_name_len;
1506 *namestr = kmem_alloc(*namelen, KM_SLEEP);
1507 (void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain,
1508 user->u_name);
1509 }
1510
1511 /*
1512 * Note: ci_numusers should be the number of users connected to
1513 * the share rather than the number of references on the tree but
1514 * we don't have a mechanism to track users/share in smbsrv yet.
1515 */
1516 static void
1517 smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
1518 {
1519 ASSERT(tree);
1520
1521 info->ci_id = tree->t_tid;
1522 info->ci_type = tree->t_res_type;
1523 info->ci_numopens = tree->t_open_files;
1524 info->ci_numusers = tree->t_refcnt;
1525 info->ci_time = gethrestime_sec() - tree->t_connect_time;
1526
1527 info->ci_sharelen = strlen(tree->t_sharename) + 1;
1528 info->ci_share = smb_mem_strdup(tree->t_sharename);
1529
1530 smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen);
1531 }
1532
1533 static void
1534 smb_tree_netinfo_fini(smb_netconnectinfo_t *info)
1535 {
1536 if (info == NULL)
1537 return;
1538
1539 if (info->ci_username)
1540 kmem_free(info->ci_username, info->ci_namelen);
1541 if (info->ci_share)
1542 smb_mem_free(info->ci_share);
1543
1544 bzero(info, sizeof (smb_netconnectinfo_t));
1545 }