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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% 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 * Ofile State Machine 71 * ------------------ 72 * 73 * +-------------------------+ T0 74 * | SMB_OFILE_STATE_OPEN |<----------- Creation/Allocation 75 * +-------------------------+ 76 * | 77 * | T1 78 * | 79 * v 80 * +-------------------------+ 81 * | SMB_OFILE_STATE_CLOSING | 82 * +-------------------------+ 83 * | 84 * | T2 85 * | 86 * v 87 * +-------------------------+ T3 88 * | SMB_OFILE_STATE_CLOSED |----------> Deletion/Free 89 * +-------------------------+ 90 * 91 * SMB_OFILE_STATE_OPEN 92 * 93 * While in this state: 94 * - The ofile is queued in the list of ofiles of its tree. 95 * - References will be given out if the ofile is looked up. 96 * 97 * SMB_OFILE_STATE_CLOSING 98 * 99 * While in this state: 100 * - The ofile is queued in the list of ofiles of its tree. 101 * - References will not be given out if the ofile is looked up. 102 * - The file is closed and the locks held are being released. 103 * - The resources associated with the ofile remain. 104 * 105 * SMB_OFILE_STATE_CLOSED 106 * 107 * While in this state: 108 * - The ofile is queued in the list of ofiles of its tree. 109 * - References will not be given out if the ofile is looked up. 110 * - The resources associated with the ofile remain. 111 * 112 * Transition T0 113 * 114 * This transition occurs in smb_ofile_open(). A new ofile is created and 115 * added to the list of ofiles of a tree. 116 * 117 * Transition T1 118 * 119 * This transition occurs in smb_ofile_close(). 120 * 121 * Transition T2 122 * 123 * This transition occurs in smb_ofile_release(). The resources associated 124 * with the ofile are freed as well as the ofile structure. For the 125 * transition to occur, the ofile must be in the SMB_OFILE_STATE_CLOSED 126 * state and the reference count be zero. 127 * 128 * Comments 129 * -------- 130 * 131 * The state machine of the ofile structures is controlled by 3 elements: 132 * - The list of ofiles of the tree it belongs to. 133 * - The mutex embedded in the structure itself. 134 * - The reference count. 135 * 136 * There's a mutex embedded in the ofile structure used to protect its fields 137 * and there's a lock embedded in the list of ofiles of a tree. To 138 * increment or to decrement the reference count the mutex must be entered. 139 * To insert the ofile into the list of ofiles of the tree and to remove 140 * the ofile from it, the lock must be entered in RW_WRITER mode. 141 * 142 * Rules of access to a ofile structure: 143 * 144 * 1) In order to avoid deadlocks, when both (mutex and lock of the ofile 145 * list) have to be entered, the lock must be entered first. 146 * 147 * 2) All actions applied to an ofile require a reference count. 148 * 149 * 3) There are 2 ways of getting a reference count. One is when the ofile 150 * is opened. The other one when the ofile is looked up. This translates 151 * into 2 functions: smb_ofile_open() and smb_ofile_lookup_by_fid(). 152 * 153 * It should be noted that the reference count of an ofile registers the 154 * number of references to the ofile in other structures (such as an smb 155 * request). The reference count is not incremented in these 2 instances: 156 * 157 * 1) The ofile is open. An ofile is anchored by his state. If there's 158 * no activity involving an ofile currently open, the reference count 159 * of that ofile is zero. 160 * 161 * 2) The ofile is queued in the list of ofiles of its tree. The fact of 162 * being queued in that list is NOT registered by incrementing the 163 * reference count. 164 */ 165 #include <smbsrv/smb_incl.h> 166 #include <smbsrv/smb_kproto.h> 167 #include <smbsrv/smb_fsops.h> 168 169 /* Static functions defined further down this file. */ 170 static void smb_ofile_delete(smb_ofile_t *of); 171 static smb_ofile_t *smb_ofile_close_and_next(smb_ofile_t *of); 172 173 /* 174 * smb_ofile_open 175 * 176 * 177 */ 178 smb_ofile_t * 179 smb_ofile_open( 180 smb_tree_t *tree, 181 smb_node_t *node, 182 uint16_t pid, 183 uint32_t access_granted, 184 uint32_t create_options, 185 uint32_t share_access, 186 uint16_t ftype, 187 char *pipe_name, 188 uint32_t rpc_fid, 189 smb_error_t *err) 190 { 191 smb_ofile_t *of; 192 uint16_t fid; 193 194 if (smb_idpool_alloc(&tree->t_fid_pool, &fid)) { 195 err->status = NT_STATUS_TOO_MANY_OPENED_FILES; 196 err->errcls = ERRDOS; 197 err->errcode = ERROR_TOO_MANY_OPEN_FILES; 198 return (NULL); 199 } 200 201 of = kmem_cache_alloc(smb_info.si_cache_ofile, KM_SLEEP); 202 bzero(of, sizeof (smb_ofile_t)); 203 of->f_magic = SMB_OFILE_MAGIC; 204 of->f_refcnt = 1; 205 of->f_fid = fid; 206 of->f_opened_by_pid = pid; 207 of->f_granted_access = access_granted; 208 of->f_share_access = share_access; 209 of->f_create_options = create_options; 210 of->f_cr = tree->t_user->u_cred; 211 crhold(of->f_cr); 212 of->f_ftype = ftype; 213 of->f_session = tree->t_user->u_session; 214 of->f_user = tree->t_user; 215 of->f_tree = tree; 216 of->f_node = node; 217 mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL); 218 of->f_state = SMB_OFILE_STATE_OPEN; 219 220 if (ftype == SMB_FTYPE_MESG_PIPE) { 221 of->f_pipe_info = kmem_alloc(sizeof (mlsvc_pipe_t), KM_SLEEP); 222 bzero(of->f_pipe_info, sizeof (mlsvc_pipe_t)); 223 of->f_pipe_info->pipe_name = pipe_name; 224 of->f_pipe_info->fid = rpc_fid; 225 mutex_init(&of->f_pipe_info->mutex, NULL, MUTEX_DEFAULT, NULL); 226 cv_init(&of->f_pipe_info->cv, NULL, CV_DEFAULT, NULL); 227 } else { 228 ASSERT(ftype == SMB_FTYPE_DISK); /* Regular file, not a pipe */ 229 ASSERT(node); 230 if (crgetuid(of->f_cr) == node->attr.sa_vattr.va_uid) { 231 /* 232 * Add this bit for the file's owner even if it's not 233 * specified in the request (Windows behavior). 234 */ 235 of->f_granted_access |= FILE_READ_ATTRIBUTES; 236 } 237 238 if ((node->vp->v_type == VREG) && (smb_fsop_open(of) != 0)) { 239 of->f_magic = 0; 240 mutex_destroy(&of->f_mutex); 241 crfree(of->f_cr); 242 smb_idpool_free(&tree->t_fid_pool, of->f_fid); 243 kmem_cache_free(smb_info.si_cache_ofile, of); 244 err->status = NT_STATUS_ACCESS_DENIED; 245 err->errcls = ERRDOS; 246 err->errcode = ERROR_ACCESS_DENIED; 247 return (NULL); 248 } 249 smb_llist_enter(&node->n_ofile_list, RW_WRITER); 250 smb_llist_insert_tail(&node->n_ofile_list, of); 251 smb_llist_exit(&node->n_ofile_list); 252 } 253 smb_llist_enter(&tree->t_ofile_list, RW_WRITER); 254 smb_llist_insert_tail(&tree->t_ofile_list, of); 255 smb_llist_exit(&tree->t_ofile_list); 256 atomic_inc_32(&smb_info.open_files); 257 atomic_inc_32(&of->f_session->s_file_cnt); 258 259 return (of); 260 } 261 262 /* 263 * smb_ofile_close 264 * 265 * 266 */ 267 int 268 smb_ofile_close( 269 smb_ofile_t *of, 270 uint32_t last_wtime) 271 { 272 int rc = 0; 273 274 275 ASSERT(of); 276 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 277 278 mutex_enter(&of->f_mutex); 279 ASSERT(of->f_refcnt); 280 switch (of->f_state) { 281 case SMB_OFILE_STATE_OPEN: { 282 283 of->f_state = SMB_OFILE_STATE_CLOSING; 284 mutex_exit(&of->f_mutex); 285 286 if (of->f_ftype == SMB_FTYPE_MESG_PIPE) { 287 smb_rpc_close(of); 288 } else { 289 if (of->f_node->vp->v_type == VREG) 290 (void) smb_fsop_close(of); 291 292 if (of->f_node->flags & NODE_CREATED_READONLY) { 293 smb_node_set_dosattr(of->f_node, 294 of->f_node->attr.sa_dosattr | 295 SMB_FA_READONLY); 296 of->f_node->flags &= ~NODE_CREATED_READONLY; 297 } 298 299 smb_ofile_close_timestamp_update(of, last_wtime); 300 rc = smb_sync_fsattr(NULL, of->f_cr, of->f_node); 301 smb_commit_delete_on_close(of); 302 smb_release_oplock(of, OPLOCK_RELEASE_FILE_CLOSED); 303 smb_commit_delete_on_close(of); 304 /* 305 * if there is any notify change request for 306 * this file then see if any of them is related 307 * to this open instance. If there is any then 308 * cancel them. 309 */ 310 if (of->f_node->flags & NODE_FLAGS_NOTIFY_CHANGE) 311 smb_process_file_notify_change_queue(of); 312 smb_node_destroy_lock_by_ofile(of->f_node, of); 313 } 314 atomic_dec_32(&smb_info.open_files); 315 316 mutex_enter(&of->f_mutex); 317 ASSERT(of->f_refcnt); 318 ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING); 319 of->f_state = SMB_OFILE_STATE_CLOSED; 320 mutex_exit(&of->f_mutex); 321 return (rc); 322 } 323 case SMB_OFILE_STATE_CLOSED: 324 case SMB_OFILE_STATE_CLOSING: 325 break; 326 327 default: 328 ASSERT(0); 329 break; 330 } 331 mutex_exit(&of->f_mutex); 332 return (rc); 333 } 334 335 /* 336 * smb_ofile_close_all 337 * 338 * 339 */ 340 void 341 smb_ofile_close_all( 342 smb_tree_t *tree) 343 { 344 smb_ofile_t *of; 345 346 ASSERT(tree); 347 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 348 349 smb_llist_enter(&tree->t_ofile_list, RW_READER); 350 of = smb_llist_head(&tree->t_ofile_list); 351 while (of) { 352 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 353 ASSERT(of->f_tree == tree); 354 of = smb_ofile_close_and_next(of); 355 } 356 smb_llist_exit(&tree->t_ofile_list); 357 } 358 359 /* 360 * smb_ofiles_close_by_pid 361 * 362 * 363 */ 364 void 365 smb_ofile_close_all_by_pid( 366 smb_tree_t *tree, 367 uint16_t pid) 368 { 369 smb_ofile_t *of; 370 371 ASSERT(tree); 372 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 373 374 smb_llist_enter(&tree->t_ofile_list, RW_READER); 375 of = smb_llist_head(&tree->t_ofile_list); 376 while (of) { 377 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 378 ASSERT(of->f_tree == tree); 379 if (of->f_opened_by_pid == pid) { 380 of = smb_ofile_close_and_next(of); 381 } else { 382 of = smb_llist_next(&tree->t_ofile_list, of); 383 } 384 } 385 smb_llist_exit(&tree->t_ofile_list); 386 } 387 388 /* 389 * smb_ofile_release 390 * 391 */ 392 void 393 smb_ofile_release( 394 smb_ofile_t *of) 395 { 396 ASSERT(of); 397 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 398 399 mutex_enter(&of->f_mutex); 400 ASSERT(of->f_refcnt); 401 of->f_refcnt--; 402 switch (of->f_state) { 403 case SMB_OFILE_STATE_OPEN: 404 case SMB_OFILE_STATE_CLOSING: 405 break; 406 407 case SMB_OFILE_STATE_CLOSED: 408 if (of->f_refcnt == 0) { 409 mutex_exit(&of->f_mutex); 410 smb_ofile_delete(of); 411 return; 412 } 413 break; 414 415 default: 416 ASSERT(0); 417 break; 418 } 419 mutex_exit(&of->f_mutex); 420 } 421 422 /* 423 * smb_ofile_lookup_by_fid 424 * 425 * Find the open file whose fid matches the one specified in the request. 426 * If we can't find the fid or the shares (trees) don't match, we have a 427 * bad fid. 428 */ 429 smb_ofile_t * 430 smb_ofile_lookup_by_fid( 431 smb_tree_t *tree, 432 uint16_t fid) 433 { 434 smb_llist_t *of_list; 435 smb_ofile_t *of; 436 437 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 438 439 of_list = &tree->t_ofile_list; 440 441 smb_llist_enter(of_list, RW_READER); 442 of = smb_llist_head(of_list); 443 while (of) { 444 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 445 ASSERT(of->f_tree == tree); 446 if (of->f_fid == fid) { 447 mutex_enter(&of->f_mutex); 448 if (of->f_state != SMB_OFILE_STATE_OPEN) { 449 mutex_exit(&of->f_mutex); 450 smb_llist_exit(of_list); 451 return (NULL); 452 } 453 of->f_refcnt++; 454 mutex_exit(&of->f_mutex); 455 break; 456 } 457 of = smb_llist_next(of_list, of); 458 } 459 smb_llist_exit(of_list); 460 return (of); 461 } 462 463 /* 464 * smb_ofile_set_flags 465 * 466 * Return value: 467 * 468 * Current flags value 469 * 470 */ 471 void 472 smb_ofile_set_flags( 473 smb_ofile_t *of, 474 uint32_t flags) 475 { 476 ASSERT(of); 477 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 478 ASSERT(of->f_refcnt); 479 480 mutex_enter(&of->f_mutex); 481 of->f_flags |= flags; 482 mutex_exit(&of->f_mutex); 483 } 484 /* 485 * smb_ofile_seek 486 * 487 * Return value: 488 * 489 * 0 Success 490 * EINVAL Unknown mode 491 * EOVERFLOW offset too big 492 * 493 */ 494 int 495 smb_ofile_seek( 496 smb_ofile_t *of, 497 ushort_t mode, 498 int32_t off, 499 uint32_t *retoff) 500 { 501 u_offset_t newoff = 0; 502 int rc = 0; 503 504 ASSERT(of); 505 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 506 ASSERT(of->f_refcnt); 507 508 mutex_enter(&of->f_mutex); 509 switch (mode) { 510 case SMB_SEEK_SET: 511 if (off < 0) 512 newoff = 0; 513 else 514 newoff = (u_offset_t)off; 515 break; 516 517 case SMB_SEEK_CUR: 518 if (off < 0 && (-off) > of->f_seek_pos) 519 newoff = 0; 520 else 521 newoff = of->f_seek_pos + (u_offset_t)off; 522 break; 523 524 case SMB_SEEK_END: 525 if (off < 0 && (-off) > of->f_node->attr.sa_vattr.va_size) 526 newoff = 0; 527 else 528 newoff = of->f_node->attr.sa_vattr.va_size + 529 (u_offset_t)off; 530 break; 531 532 default: 533 mutex_exit(&of->f_mutex); 534 return (EINVAL); 535 } 536 537 /* 538 * See comments at the beginning of smb_seek.c. 539 * If the offset is greater than UINT_MAX, we will return an error. 540 */ 541 542 if (newoff > UINT_MAX) { 543 rc = EOVERFLOW; 544 } else { 545 of->f_seek_pos = newoff; 546 *retoff = (uint32_t)newoff; 547 } 548 mutex_exit(&of->f_mutex); 549 return (rc); 550 } 551 552 /* 553 * smb_ofile_close_timestamp_update 554 * 555 * 556 */ 557 void 558 smb_ofile_close_timestamp_update( 559 smb_ofile_t *of, 560 uint32_t last_wtime) 561 { 562 smb_node_t *node; 563 timestruc_t mtime, atime; 564 unsigned int what = 0; 565 566 mtime.tv_sec = last_wtime; 567 mtime.tv_nsec = 0; 568 569 if (mtime.tv_sec != 0 && mtime.tv_sec != 0xFFFFFFFF) { 570 mtime.tv_sec = smb_local_time_to_gmt(mtime.tv_sec); 571 what |= SMB_AT_MTIME; 572 } 573 574 /* 575 * NODE_FLAGS_SYNCATIME is set whenever something is 576 * written to a file. Compliant volumes don't update 577 * atime upon write, so don't update the atime if the 578 * volume is compliant. 579 */ 580 node = of->f_node; 581 if (node->flags & NODE_FLAGS_SYNCATIME) { 582 node->flags &= ~NODE_FLAGS_SYNCATIME; 583 what |= SMB_AT_ATIME; 584 (void) microtime(&atime); 585 } 586 587 smb_node_set_time(node, 0, &mtime, &atime, 0, what); 588 } 589 590 /* 591 * smb_ofile_is_open 592 * 593 */ 594 boolean_t 595 smb_ofile_is_open( 596 smb_ofile_t *of) 597 { 598 boolean_t rc = B_FALSE; 599 600 ASSERT(of); 601 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 602 603 mutex_enter(&of->f_mutex); 604 if (of->f_state == SMB_OFILE_STATE_OPEN) { 605 rc = B_TRUE; 606 } 607 mutex_exit(&of->f_mutex); 608 return (rc); 609 } 610 611 /* *************************** Static Functions ***************************** */ 612 613 /* 614 * smb_ofile_close_and_next 615 * 616 * This function closes the file passed in (if appropriate) and returns the 617 * next open file in the list of open files of the tree of the open file passed 618 * in. It requires that the list of open files of the tree be entered in 619 * RW_READER mode before being called. 620 */ 621 static smb_ofile_t * 622 smb_ofile_close_and_next( 623 smb_ofile_t *of) 624 { 625 smb_ofile_t *next_of; 626 smb_tree_t *tree; 627 628 ASSERT(of); 629 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 630 631 mutex_enter(&of->f_mutex); 632 switch (of->f_state) { 633 case SMB_OFILE_STATE_OPEN: 634 /* The file is still open. */ 635 of->f_refcnt++; 636 ASSERT(of->f_refcnt); 637 tree = of->f_tree; 638 mutex_exit(&of->f_mutex); 639 smb_llist_exit(&of->f_tree->t_ofile_list); 640 (void) smb_ofile_close(of, 0); 641 smb_ofile_release(of); 642 smb_llist_enter(&tree->t_ofile_list, RW_READER); 643 next_of = smb_llist_head(&tree->t_ofile_list); 644 break; 645 case SMB_OFILE_STATE_CLOSING: 646 case SMB_OFILE_STATE_CLOSED: 647 /* 648 * The ofile exists but is closed or 649 * in the process being closed. 650 */ 651 mutex_exit(&of->f_mutex); 652 next_of = smb_llist_next(&of->f_tree->t_ofile_list, of); 653 break; 654 default: 655 ASSERT(0); 656 mutex_exit(&of->f_mutex); 657 next_of = smb_llist_next(&of->f_tree->t_ofile_list, of); 658 break; 659 } 660 return (next_of); 661 } 662 663 /* 664 * smb_ofile_delete 665 * 666 * 667 */ 668 static void 669 smb_ofile_delete( 670 smb_ofile_t *of) 671 { 672 ASSERT(of); 673 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 674 ASSERT(of->f_refcnt == 0); 675 ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED); 676 677 /* 678 * Let's remove the ofile from the list of ofiles of the tree. This has 679 * to be done before any resources associated with the ofile are 680 * released. 681 */ 682 smb_llist_enter(&of->f_tree->t_ofile_list, RW_WRITER); 683 smb_llist_remove(&of->f_tree->t_ofile_list, of); 684 smb_llist_exit(&of->f_tree->t_ofile_list); 685 atomic_dec_32(&of->f_session->s_file_cnt); 686 687 if (of->f_ftype == SMB_FTYPE_MESG_PIPE) { 688 kmem_free(of->f_pipe_info, sizeof (mlsvc_pipe_t)); 689 of->f_pipe_info = NULL; 690 } else { 691 ASSERT(of->f_ftype == SMB_FTYPE_DISK); 692 ASSERT(of->f_node != NULL); 693 smb_llist_enter(&of->f_node->n_ofile_list, RW_WRITER); 694 smb_llist_remove(&of->f_node->n_ofile_list, of); 695 smb_llist_exit(&of->f_node->n_ofile_list); 696 smb_node_release(of->f_node); 697 } 698 699 of->f_magic = (uint32_t)~SMB_OFILE_MAGIC; 700 mutex_destroy(&of->f_mutex); 701 crfree(of->f_cr); 702 smb_idpool_free(&of->f_tree->t_fid_pool, of->f_fid); 703 kmem_cache_free(smb_info.si_cache_ofile, of); 704 } 705 706 /* 707 * smb_ofile_access 708 * 709 * This function will check to see if the access requested is granted. 710 * Returns NT status codes. 711 */ 712 uint32_t 713 smb_ofile_access(smb_ofile_t *of, cred_t *cr, uint32_t access) 714 { 715 716 if ((of == NULL) || (cr == kcred)) 717 return (NT_STATUS_SUCCESS); 718 719 /* 720 * If the request is for something 721 * I don't grant it is an error 722 */ 723 if (~(of->f_granted_access) & access) { 724 if (!(of->f_granted_access & ACCESS_SYSTEM_SECURITY) && 725 (access & ACCESS_SYSTEM_SECURITY)) { 726 return (NT_STATUS_PRIVILEGE_NOT_HELD); 727 } 728 return (NT_STATUS_ACCESS_DENIED); 729 } 730 731 return (NT_STATUS_SUCCESS); 732 } 733