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 * | |
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 }
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);
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.
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 {
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;
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
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
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;
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
|
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 * | |
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 }
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);
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.
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 {
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;
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
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
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;
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
|