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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "@(#)smb_tree.c 1.5 08/08/07 SMI" 27 28 /* 29 * General Structures Layout 30 * ------------------------- 31 * 32 * This is a simplified diagram showing the relationship between most of the 33 * main structures. 34 * 35 * +-------------------+ 36 * | SMB_INFO | 37 * +-------------------+ 38 * | 39 * | 40 * v 41 * +-------------------+ +-------------------+ +-------------------+ 42 * | SESSION |<----->| SESSION |......| SESSION | 43 * +-------------------+ +-------------------+ +-------------------+ 44 * | 45 * | 46 * v 47 * +-------------------+ +-------------------+ +-------------------+ 48 * | USER |<----->| USER |......| USER | 49 * +-------------------+ +-------------------+ +-------------------+ 50 * | 51 * | 52 * v 53 * +-------------------+ +-------------------+ +-------------------+ 54 * | TREE |<----->| TREE |......| TREE | 55 * +-------------------+ +-------------------+ +-------------------+ 56 * | | 57 * | | 58 * | v 59 * | +-------+ +-------+ +-------+ 60 * | | OFILE |<----->| OFILE |......| OFILE | 61 * | +-------+ +-------+ +-------+ 62 * | 63 * | 64 * v 65 * +-------+ +------+ +------+ 66 * | ODIR |<----->| ODIR |......| ODIR | 67 * +-------+ +------+ +------+ 68 * 69 * 70 * Tree State Machine 71 * ------------------ 72 * 73 * +-----------------------------+ T0 74 * | SMB_TREE_STATE_CONNECTED |<----------- Creation/Allocation 75 * +-----------------------------+ 76 * | 77 * | T1 78 * | 79 * v 80 * +------------------------------+ 81 * | SMB_TREE_STATE_DISCONNECTING | 82 * +------------------------------+ 83 * | 84 * | T2 85 * | 86 * v 87 * +-----------------------------+ T3 88 * | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free 89 * +-----------------------------+ 90 * 91 * SMB_TREE_STATE_CONNECTED 92 * 93 * While in this state: 94 * - The tree is queued in the list of trees of its user. 95 * - References will be given out if the tree is looked up. 96 * - Files under that tree can be accessed. 97 * 98 * SMB_TREE_STATE_DISCONNECTING 99 * 100 * While in this state: 101 * - The tree is queued in the list of trees of its user. 102 * - References will not be given out if the tree is looked up. 103 * - The files and directories open under the tree are being closed. 104 * - The resources associated with the tree remain. 105 * 106 * SMB_TREE_STATE_DISCONNECTED 107 * 108 * While in this state: 109 * - The tree is queued in the list of trees of its user. 110 * - References will not be given out if the tree is looked up. 111 * - The tree has no more files and directories opened. 112 * - The resources associated with the tree remain. 113 * 114 * Transition T0 115 * 116 * This transition occurs in smb_tree_connect(). A new tree is created and 117 * added to the list of trees of a user. 118 * 119 * Transition T1 120 * 121 * This transition occurs in smb_tree_disconnect(). 122 * 123 * Transition T2 124 * 125 * This transition occurs in smb_tree_release(). The resources associated 126 * with the tree are freed as well as the tree structure. For the transition 127 * to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED state and 128 * the reference count be zero. 129 * 130 * Comments 131 * -------- 132 * 133 * The state machine of the tree structures is controlled by 3 elements: 134 * - The list of trees of the user it belongs to. 135 * - The mutex embedded in the structure itself. 136 * - The reference count. 137 * 138 * There's a mutex embedded in the tree structure used to protect its fields 139 * and there's a lock embedded in the list of trees of a user. To 140 * increment or to decrement the reference count the mutex must be entered. 141 * To insert the tree into the list of trees of the user and to remove 142 * the tree from it, the lock must be entered in RW_WRITER mode. 143 * 144 * Rules of access to a tree structure: 145 * 146 * 1) In order to avoid deadlocks, when both (mutex and lock of the user 147 * list) have to be entered, the lock must be entered first. 148 * 149 * 2) All actions applied to a tree require a reference count. 150 * 151 * 3) There are 2 ways of getting a reference count: when a tree is 152 * connected and when a tree is looked up. 153 * 154 * It should be noted that the reference count of a tree registers the 155 * number of references to the tree in other structures (such as an smb 156 * request). The reference count is not incremented in these 2 instances: 157 * 158 * 1) The tree is connected. An tree is anchored by his 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 #include <sys/types.h> 167 #include <sys/refstr_impl.h> 168 #include <sys/feature_tests.h> 169 #include <sys/sunddi.h> 170 #include <sys/fsid.h> 171 #include <sys/vfs.h> 172 #include <sys/stat.h> 173 #include <sys/varargs.h> 174 #include <smbsrv/smb_incl.h> 175 #include <smbsrv/lmerr.h> 176 #include <smbsrv/mlsvc.h> 177 #include <smbsrv/smb_fsops.h> 178 #include <smbsrv/smb_door_svc.h> 179 #include <smbsrv/smb_share.h> 180 181 int smb_tcon_mute = 0; 182 183 static smb_tree_t *smb_tree_connect_disk(smb_request_t *, const char *); 184 static smb_tree_t *smb_tree_connect_ipc(smb_request_t *, const char *); 185 static smb_tree_t *smb_tree_alloc(smb_user_t *, const char *, const char *, 186 int32_t, smb_node_t *); 187 static void smb_tree_dealloc(smb_tree_t *); 188 static boolean_t smb_tree_is_connected(smb_tree_t *); 189 static boolean_t smb_tree_is_disconnected(smb_tree_t *); 190 static const char *smb_tree_get_sharename(const char *); 191 static int smb_tree_get_stype(const char *, const char *, int32_t *); 192 static int smb_tree_getattr(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(vfs_t *, smb_tree_t *); 195 static void smb_tree_log(smb_request_t *, const char *, const char *, ...); 196 197 /* 198 * Extract the share name and share type and connect as appropriate. 199 * Share names are case insensitive so we map the share name to 200 * lower-case as a convenience for internal processing. 201 */ 202 smb_tree_t * 203 smb_tree_connect(smb_request_t *sr) 204 { 205 char *unc_path = sr->arg.tcon.path; 206 char *service = sr->arg.tcon.service; 207 smb_tree_t *tree = NULL; 208 const char *name; 209 int32_t stype; 210 211 (void) utf8_strlwr(unc_path); 212 213 if ((name = smb_tree_get_sharename(unc_path)) == NULL) { 214 smbsr_error(sr, 0, ERRSRV, ERRinvnetname); 215 return (NULL); 216 } 217 218 if (smb_tree_get_stype(name, service, &stype) != 0) { 219 smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE, 220 ERRDOS, ERROR_BAD_DEV_TYPE); 221 return (NULL); 222 } 223 224 switch (stype & STYPE_MASK) { 225 case STYPE_DISKTREE: 226 tree = smb_tree_connect_disk(sr, name); 227 break; 228 229 case STYPE_IPC: 230 tree = smb_tree_connect_ipc(sr, name); 231 break; 232 233 default: 234 smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE, 235 ERRDOS, ERROR_BAD_DEV_TYPE); 236 break; 237 } 238 239 return (tree); 240 } 241 242 /* 243 * Disconnect a tree. 244 */ 245 void 246 smb_tree_disconnect( 247 smb_tree_t *tree) 248 { 249 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 250 251 mutex_enter(&tree->t_mutex); 252 ASSERT(tree->t_refcnt); 253 254 if (smb_tree_is_connected(tree)) { 255 /* 256 * Indicate that the disconnect process has started. 257 */ 258 tree->t_state = SMB_TREE_STATE_DISCONNECTING; 259 mutex_exit(&tree->t_mutex); 260 atomic_dec_32(&tree->t_server->sv_open_trees); 261 262 /* 263 * The files opened under this tree are closed. 264 */ 265 smb_ofile_close_all(tree); 266 /* 267 * The directories opened under this tree are closed. 268 */ 269 smb_odir_close_all(tree); 270 mutex_enter(&tree->t_mutex); 271 tree->t_state = SMB_TREE_STATE_DISCONNECTED; 272 } 273 274 mutex_exit(&tree->t_mutex); 275 } 276 277 /* 278 * Take a reference on a tree. 279 */ 280 boolean_t 281 smb_tree_hold( 282 smb_tree_t *tree) 283 { 284 ASSERT(tree); 285 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 286 287 mutex_enter(&tree->t_mutex); 288 289 if (smb_tree_is_connected(tree)) { 290 tree->t_refcnt++; 291 mutex_exit(&tree->t_mutex); 292 return (B_TRUE); 293 } 294 295 mutex_exit(&tree->t_mutex); 296 return (B_FALSE); 297 } 298 299 /* 300 * Release a reference on a tree. If the tree is disconnected and the 301 * reference count falls to zero, the tree will be deallocated. 302 */ 303 void 304 smb_tree_release( 305 smb_tree_t *tree) 306 { 307 ASSERT(tree); 308 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 309 310 mutex_enter(&tree->t_mutex); 311 ASSERT(tree->t_refcnt); 312 tree->t_refcnt--; 313 314 if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0)) { 315 mutex_exit(&tree->t_mutex); 316 smb_tree_dealloc(tree); 317 return; 318 } 319 320 mutex_exit(&tree->t_mutex); 321 } 322 323 /* 324 * Close ofiles and odirs that match pid. 325 */ 326 void 327 smb_tree_close_pid( 328 smb_tree_t *tree, 329 uint16_t pid) 330 { 331 ASSERT(tree); 332 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 333 334 smb_ofile_close_all_by_pid(tree, pid); 335 smb_odir_close_all_by_pid(tree, pid); 336 } 337 338 /* 339 * Check whether or not a tree supports the features identified by flags. 340 */ 341 boolean_t 342 smb_tree_has_feature(smb_tree_t *tree, uint32_t flags) 343 { 344 ASSERT(tree); 345 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 346 347 return ((tree->t_flags & flags) == flags); 348 } 349 350 /* *************************** Static Functions ***************************** */ 351 352 /* 353 * Connect a share for use with files and directories. 354 */ 355 static smb_tree_t * 356 smb_tree_connect_disk(smb_request_t *sr, const char *sharename) 357 { 358 smb_user_t *user = sr->uid_user; 359 smb_node_t *dir_snode = NULL; 360 smb_node_t *snode = NULL; 361 char last_component[MAXNAMELEN]; 362 smb_tree_t *tree; 363 smb_share_t *si; 364 smb_attr_t attr; 365 cred_t *u_cred; 366 int rc; 367 uint32_t access = 0; /* read/write is assumed */ 368 uint32_t hostaccess; 369 370 ASSERT(user); 371 u_cred = user->u_cred; 372 ASSERT(u_cred); 373 374 if (user->u_flags & SMB_USER_FLAG_IPC) { 375 smb_tree_log(sr, sharename, "access denied: IPC only"); 376 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 377 return (NULL); 378 } 379 380 si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP); 381 382 if (smb_kshare_getinfo(sr->sr_server->sv_lmshrd, (char *)sharename, si, 383 sr->session->ipaddr) != NERR_Success) { 384 smb_tree_log(sr, sharename, "share not found"); 385 smbsr_error(sr, 0, ERRSRV, ERRinvnetname); 386 kmem_free(si, sizeof (smb_share_t)); 387 return (NULL); 388 } 389 390 /* 391 * Handle the default administration shares: C$, D$ etc. 392 * Only a user with admin rights is allowed to map these 393 * shares. 394 */ 395 if (si->shr_flags & SMB_SHRF_ADMIN) { 396 if (!smb_user_is_admin(user)) { 397 smb_tree_log(sr, sharename, "access denied: not admin"); 398 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 399 ERRSRV, ERRaccess); 400 kmem_free(si, sizeof (smb_share_t)); 401 return (NULL); 402 } 403 } 404 405 hostaccess = si->shr_access_value & SMB_SHRF_ACC_ALL; 406 407 if (hostaccess == SMB_SHRF_ACC_RO) { 408 access = SMB_TREE_READONLY; 409 } else if (hostaccess == SMB_SHRF_ACC_NONE) { 410 kmem_free(si, sizeof (smb_share_t)); 411 smb_tree_log(sr, sharename, "access denied: host access"); 412 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 413 return (NULL); 414 } 415 416 /* 417 * Check that the shared directory exists. 418 */ 419 rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dir_snode, 420 last_component); 421 422 if (rc == 0) { 423 rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS, 0, 424 dir_snode, last_component, &snode, &attr, 0, 0); 425 426 smb_node_release(dir_snode); 427 } 428 429 if (rc) { 430 if (snode) 431 smb_node_release(snode); 432 433 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path); 434 smbsr_error(sr, 0, ERRSRV, ERRinvnetname); 435 kmem_free(si, sizeof (smb_share_t)); 436 return (NULL); 437 } 438 439 tree = smb_tree_alloc(user, sharename, si->shr_path, STYPE_DISKTREE, 440 snode); 441 442 if (tree == NULL) 443 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 444 else 445 tree->t_flags |= access; 446 447 smb_node_release(snode); 448 kmem_free(si, sizeof (smb_share_t)); 449 return (tree); 450 } 451 452 /* 453 * Connect an IPC share for use with named pipes. 454 */ 455 static smb_tree_t * 456 smb_tree_connect_ipc(smb_request_t *sr, const char *name) 457 { 458 smb_user_t *user = sr->uid_user; 459 smb_tree_t *tree; 460 461 ASSERT(user); 462 463 if ((user->u_flags & SMB_USER_FLAG_IPC) && 464 sr->sr_cfg->skc_restrict_anon) { 465 smb_tree_log(sr, name, "access denied: restrict anonymous"); 466 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 467 return (NULL); 468 } 469 470 tree = smb_tree_alloc(user, name, name, STYPE_IPC, NULL); 471 if (tree == NULL) { 472 smb_tree_log(sr, name, "access denied"); 473 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 474 } 475 476 return (tree); 477 } 478 479 /* 480 * Allocate a tree. 481 */ 482 static smb_tree_t * 483 smb_tree_alloc( 484 smb_user_t *user, 485 const char *sharename, 486 const char *resource, 487 int32_t stype, 488 smb_node_t *snode) 489 { 490 smb_tree_t *tree; 491 uint16_t tid; 492 493 if (smb_idpool_alloc(&user->u_tid_pool, &tid)) 494 return (NULL); 495 496 tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP); 497 bzero(tree, sizeof (smb_tree_t)); 498 499 if (STYPE_ISDSK(stype)) { 500 if (smb_tree_getattr(snode, tree) != 0) { 501 smb_idpool_free(&user->u_tid_pool, tid); 502 kmem_cache_free(user->u_server->si_cache_tree, tree); 503 return (NULL); 504 } 505 } 506 507 if (smb_idpool_constructor(&tree->t_fid_pool)) { 508 smb_idpool_free(&user->u_tid_pool, tid); 509 kmem_cache_free(user->u_server->si_cache_tree, tree); 510 return (NULL); 511 } 512 513 if (smb_idpool_constructor(&tree->t_sid_pool)) { 514 smb_idpool_destructor(&tree->t_fid_pool); 515 smb_idpool_free(&user->u_tid_pool, tid); 516 kmem_cache_free(user->u_server->si_cache_tree, tree); 517 return (NULL); 518 } 519 520 smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t), 521 offsetof(smb_ofile_t, f_lnd)); 522 523 smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t), 524 offsetof(smb_odir_t, d_lnd)); 525 526 (void) strlcpy(tree->t_sharename, sharename, 527 sizeof (tree->t_sharename)); 528 (void) strlcpy(tree->t_resource, resource, sizeof (tree->t_resource)); 529 530 mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL); 531 532 tree->t_user = user; 533 tree->t_session = user->u_session; 534 tree->t_server = user->u_server; 535 tree->t_refcnt = 1; 536 tree->t_tid = tid; 537 tree->t_res_type = stype; 538 tree->t_state = SMB_TREE_STATE_CONNECTED; 539 tree->t_magic = SMB_TREE_MAGIC; 540 541 if (STYPE_ISDSK(stype)) { 542 smb_node_ref(snode); 543 tree->t_snode = snode; 544 tree->t_acltype = smb_fsop_acltype(snode); 545 } 546 547 smb_llist_enter(&user->u_tree_list, RW_WRITER); 548 smb_llist_insert_head(&user->u_tree_list, tree); 549 smb_llist_exit(&user->u_tree_list); 550 atomic_inc_32(&user->u_session->s_tree_cnt); 551 atomic_inc_32(&user->u_server->sv_open_trees); 552 553 return (tree); 554 } 555 556 /* 557 * Deallocate a tree: release all resources associated with a tree and 558 * remove the tree from the user's tree list. 559 * 560 * The tree being destroyed must be in the "destroying" state and the 561 * reference count must be zero. This function assumes it's single threaded 562 * i.e. only one thread will attempt to destroy a specific tree, which 563 * should be the case if the tree is in disconnected and has a reference 564 * count of zero. 565 */ 566 static void 567 smb_tree_dealloc(smb_tree_t *tree) 568 { 569 ASSERT(tree); 570 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 571 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); 572 ASSERT(tree->t_refcnt == 0); 573 574 /* 575 * Remove the tree from the user's tree list. This must be done 576 * before any resources associated with the tree are released. 577 */ 578 smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER); 579 smb_llist_remove(&tree->t_user->u_tree_list, tree); 580 smb_llist_exit(&tree->t_user->u_tree_list); 581 582 tree->t_magic = (uint32_t)~SMB_TREE_MAGIC; 583 smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid); 584 atomic_dec_32(&tree->t_session->s_tree_cnt); 585 586 if (tree->t_snode) 587 smb_node_release(tree->t_snode); 588 589 mutex_destroy(&tree->t_mutex); 590 591 /* 592 * The list of open files and open directories should be empty. 593 */ 594 smb_llist_destructor(&tree->t_ofile_list); 595 smb_llist_destructor(&tree->t_odir_list); 596 smb_idpool_destructor(&tree->t_fid_pool); 597 smb_idpool_destructor(&tree->t_sid_pool); 598 kmem_cache_free(tree->t_server->si_cache_tree, tree); 599 } 600 601 /* 602 * Determine whether or not a tree is connected. 603 * This function must be called with the tree mutex held. 604 */ 605 static boolean_t 606 smb_tree_is_connected(smb_tree_t *tree) 607 { 608 switch (tree->t_state) { 609 case SMB_TREE_STATE_CONNECTED: 610 return (B_TRUE); 611 612 case SMB_TREE_STATE_DISCONNECTING: 613 case SMB_TREE_STATE_DISCONNECTED: 614 /* 615 * The tree exists but being diconnected or destroyed. 616 */ 617 return (B_FALSE); 618 619 default: 620 ASSERT(0); 621 return (B_FALSE); 622 } 623 } 624 625 /* 626 * Determine whether or not a tree is disconnected. 627 * This function must be called with the tree mutex held. 628 */ 629 static boolean_t 630 smb_tree_is_disconnected(smb_tree_t *tree) 631 { 632 switch (tree->t_state) { 633 case SMB_TREE_STATE_DISCONNECTED: 634 return (B_TRUE); 635 636 case SMB_TREE_STATE_CONNECTED: 637 case SMB_TREE_STATE_DISCONNECTING: 638 return (B_FALSE); 639 640 default: 641 ASSERT(0); 642 return (B_FALSE); 643 } 644 } 645 646 /* 647 * Return a pointer to the share name within a share resource path. 648 * 649 * The share path may be a Uniform Naming Convention (UNC) string 650 * (\\server\share) or simply the share name. We validate the UNC 651 * format but we don't look at the server name. 652 */ 653 static const char * 654 smb_tree_get_sharename(const char *unc_path) 655 { 656 const char *sharename = unc_path; 657 658 if (sharename[0] == '\\') { 659 /* 660 * Looks like a UNC path, validate the format. 661 */ 662 if (sharename[1] != '\\') 663 return (NULL); 664 665 if ((sharename = strchr(sharename+2, '\\')) == NULL) 666 return (NULL); 667 668 ++sharename; 669 } else if (strchr(sharename, '\\') != NULL) { 670 /* 671 * This should be a share name (no embedded \'s). 672 */ 673 return (NULL); 674 } 675 676 return (sharename); 677 } 678 679 /* 680 * Map the service to a resource type. Valid values for service are: 681 * 682 * A: Disk share 683 * LPT1: Printer 684 * IPC Named pipe 685 * COMM Communications device 686 * ????? Any type of device (wildcard) 687 * 688 * We support IPC and disk shares; anything else is currently treated 689 * as an error. IPC$ is reserved as the named pipe share. 690 */ 691 static int 692 smb_tree_get_stype(const char *sharename, const char *service, 693 int32_t *stype_ret) 694 { 695 const char *any = "?????"; 696 697 if ((strcmp(service, any) == 0) || (strcasecmp(service, "IPC") == 0)) { 698 if (strcasecmp(sharename, "IPC$") == 0) { 699 *stype_ret = STYPE_IPC; 700 return (0); 701 } 702 } 703 704 if ((strcmp(service, any) == 0) || (strcasecmp(service, "A:") == 0)) { 705 if (strcasecmp(sharename, "IPC$") == 0) 706 return (-1); 707 708 *stype_ret = STYPE_DISKTREE; 709 return (0); 710 } 711 712 return (-1); 713 } 714 715 /* 716 * Obtain the tree attributes: volume name, typename and flags. 717 */ 718 static int 719 smb_tree_getattr(smb_node_t *node, smb_tree_t *tree) 720 { 721 vfs_t *vfsp = SMB_NODE_VFS(node); 722 723 ASSERT(vfsp); 724 725 if (getvfs(&vfsp->vfs_fsid) != vfsp) 726 return (ESTALE); 727 728 smb_tree_get_volname(vfsp, tree); 729 smb_tree_get_flags(vfsp, tree); 730 731 VFS_RELE(vfsp); 732 return (0); 733 } 734 735 /* 736 * Extract the volume name. 737 */ 738 static void 739 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree) 740 { 741 refstr_t *vfs_mntpoint; 742 const char *s; 743 char *name; 744 745 vfs_mntpoint = vfs_getmntpoint(vfsp); 746 747 s = vfs_mntpoint->rs_string; 748 s += strspn(s, "/"); 749 (void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN); 750 751 refstr_rele(vfs_mntpoint); 752 753 name = tree->t_volume; 754 (void) strsep((char **)&name, "/"); 755 } 756 757 /* 758 * Always set ACL support because the VFS will fake ACLs for file systems 759 * that don't support them. 760 * 761 * Some flags are dependent on the typename, which is also set up here. 762 * File system types are hardcoded in uts/common/os/vfs_conf.c. 763 */ 764 static void 765 smb_tree_get_flags(vfs_t *vfsp, smb_tree_t *tree) 766 { 767 uint32_t flags = SMB_TREE_SUPPORTS_ACLS; 768 char *name; 769 770 if (vfsp->vfs_flag & VFS_RDONLY) 771 flags |= SMB_TREE_READONLY; 772 773 if (vfsp->vfs_flag & VFS_XATTR) 774 flags |= SMB_TREE_STREAMS; 775 776 if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL)) 777 flags |= SMB_TREE_NO_ATIME; 778 779 name = vfssw[vfsp->vfs_fstype].vsw_name; 780 781 if (strcmp(name, "tmpfs") == 0) 782 flags |= SMB_TREE_NO_EXPORT; 783 784 if (strncasecmp(name, NFS, sizeof (NFS)) == 0) 785 flags |= SMB_TREE_NFS_MOUNTED; 786 787 (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN); 788 (void) utf8_strupr((char *)tree->t_typename); 789 790 if (vfs_has_feature(vfsp, VFSFT_XVATTR)) 791 flags |= SMB_TREE_XVATTR; 792 793 if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE)) 794 flags |= SMB_TREE_CASEINSENSITIVE; 795 796 if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE)) 797 flags |= SMB_TREE_NO_CASESENSITIVE; 798 799 if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS)) 800 flags |= SMB_TREE_DIRENTFLAGS; 801 802 if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE)) 803 flags |= SMB_TREE_ACLONCREATE; 804 805 if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS)) 806 flags |= SMB_TREE_ACEMASKONACCESS; 807 808 DTRACE_PROBE1(smb__tree__flags, uint32_t, flags); 809 810 tree->t_flags = flags; 811 } 812 813 /* 814 * Report share access result to syslog. 815 */ 816 static void 817 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...) 818 { 819 va_list ap; 820 char buf[128]; 821 smb_user_t *user = sr->uid_user; 822 823 ASSERT(user); 824 825 if (smb_tcon_mute) 826 return; 827 828 if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) { 829 /* 830 * Only report normal users, i.e. ignore W2K misuse 831 * of the IPC connection by filtering out internal 832 * names such as nobody and root. 833 */ 834 if ((strcmp(user->u_name, "root") == 0) || 835 (strcmp(user->u_name, "nobody") == 0)) { 836 return; 837 } 838 } 839 840 va_start(ap, fmt); 841 (void) vsnprintf(buf, 128, fmt, ap); 842 va_end(ap); 843 844 cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s", 845 user->u_domain, user->u_name, sharename, buf); 846 } 847