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