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