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