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