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_ofile.c 1.12 08/08/08 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 struct open_param *op, 184 uint16_t ftype, 185 uint32_t uniqid, 186 smb_error_t *err) 187 { 188 smb_ofile_t *of; 189 uint16_t fid; 190 191 if (smb_idpool_alloc(&tree->t_fid_pool, &fid)) { 192 err->status = NT_STATUS_TOO_MANY_OPENED_FILES; 193 err->errcls = ERRDOS; 194 err->errcode = ERROR_TOO_MANY_OPEN_FILES; 195 return (NULL); 196 } 197 198 of = kmem_cache_alloc(tree->t_server->si_cache_ofile, KM_SLEEP); 199 bzero(of, sizeof (smb_ofile_t)); 200 of->f_magic = SMB_OFILE_MAGIC; 201 of->f_refcnt = 1; 202 of->f_fid = fid; 203 of->f_uniqid = uniqid; 204 of->f_opened_by_pid = pid; 205 of->f_granted_access = op->desired_access; 206 of->f_share_access = op->share_access; 207 of->f_create_options = op->create_options; 208 of->f_cr = tree->t_user->u_cred; 209 crhold(of->f_cr); 210 of->f_ftype = ftype; 211 of->f_server = tree->t_server; 212 of->f_session = tree->t_user->u_session; 213 of->f_user = tree->t_user; 214 of->f_tree = tree; 215 of->f_node = node; 216 mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL); 217 of->f_state = SMB_OFILE_STATE_OPEN; 218 219 if (ftype == SMB_FTYPE_MESG_PIPE) { 220 of->f_pipe = kmem_zalloc(sizeof (smb_opipe_t), KM_SLEEP); 221 } else { 222 ASSERT(ftype == SMB_FTYPE_DISK); /* Regular file, not a pipe */ 223 ASSERT(node); 224 if (crgetuid(of->f_cr) == node->attr.sa_vattr.va_uid) { 225 /* 226 * Add this bit for the file's owner even if it's not 227 * specified in the request (Windows behavior). 228 */ 229 of->f_granted_access |= FILE_READ_ATTRIBUTES; 230 } 231 232 if (node->vp->v_type == VREG) { 233 of->f_mode = 234 smb_fsop_amask_to_omode(of->f_granted_access); 235 if (smb_fsop_open(node, of->f_mode, of->f_cr) != 0) { 236 of->f_magic = 0; 237 mutex_destroy(&of->f_mutex); 238 crfree(of->f_cr); 239 smb_idpool_free(&tree->t_fid_pool, of->f_fid); 240 kmem_cache_free(tree->t_server->si_cache_ofile, 241 of); 242 err->status = NT_STATUS_ACCESS_DENIED; 243 err->errcls = ERRDOS; 244 err->errcode = ERROR_ACCESS_DENIED; 245 return (NULL); 246 } 247 } 248 249 if (tree->t_flags & SMB_TREE_READONLY) 250 of->f_flags |= SMB_OFLAGS_READONLY; 251 252 if (op->created_readonly) 253 node->readonly_creator = of; 254 255 smb_llist_enter(&node->n_ofile_list, RW_WRITER); 256 smb_llist_insert_tail(&node->n_ofile_list, of); 257 smb_llist_exit(&node->n_ofile_list); 258 } 259 smb_llist_enter(&tree->t_ofile_list, RW_WRITER); 260 smb_llist_insert_tail(&tree->t_ofile_list, of); 261 smb_llist_exit(&tree->t_ofile_list); 262 atomic_inc_32(&tree->t_server->sv_open_files); 263 atomic_inc_32(&of->f_session->s_file_cnt); 264 265 return (of); 266 } 267 268 /* 269 * smb_ofile_close 270 * 271 * 272 */ 273 void 274 smb_ofile_close( 275 smb_ofile_t *of, 276 uint32_t last_wtime) 277 { 278 ASSERT(of); 279 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 280 281 mutex_enter(&of->f_mutex); 282 ASSERT(of->f_refcnt); 283 switch (of->f_state) { 284 case SMB_OFILE_STATE_OPEN: { 285 286 of->f_state = SMB_OFILE_STATE_CLOSING; 287 mutex_exit(&of->f_mutex); 288 289 if (of->f_ftype == SMB_FTYPE_MESG_PIPE) { 290 smb_opipe_close(of); 291 } else { 292 /* 293 * For files created readonly, propagate the readonly 294 * bit to the ofile now 295 */ 296 297 if (of->f_node->readonly_creator == of) { 298 of->f_node->attr.sa_dosattr |= 299 FILE_ATTRIBUTE_READONLY; 300 of->f_node->what |= SMB_AT_DOSATTR; 301 of->f_node->readonly_creator = NULL; 302 } 303 304 smb_ofile_close_timestamp_update(of, last_wtime); 305 smb_commit_delete_on_close(of); 306 smb_oplock_release(of->f_node, B_FALSE); 307 smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid); 308 smb_node_destroy_lock_by_ofile(of->f_node, of); 309 310 if (of->f_node->vp->v_type == VREG) 311 (void) smb_fsop_close(of->f_node, of->f_mode, 312 of->f_cr); 313 314 /* 315 * Cancel any notify change requests related 316 * to this open instance. 317 */ 318 if (of->f_node->flags & NODE_FLAGS_NOTIFY_CHANGE) 319 smb_process_file_notify_change_queue(of); 320 } 321 atomic_dec_32(&of->f_tree->t_server->sv_open_files); 322 323 mutex_enter(&of->f_mutex); 324 ASSERT(of->f_refcnt); 325 ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING); 326 of->f_state = SMB_OFILE_STATE_CLOSED; 327 mutex_exit(&of->f_mutex); 328 return; 329 } 330 case SMB_OFILE_STATE_CLOSED: 331 case SMB_OFILE_STATE_CLOSING: 332 break; 333 334 default: 335 ASSERT(0); 336 break; 337 } 338 mutex_exit(&of->f_mutex); 339 } 340 341 /* 342 * smb_ofile_close_all 343 * 344 * 345 */ 346 void 347 smb_ofile_close_all( 348 smb_tree_t *tree) 349 { 350 smb_ofile_t *of; 351 352 ASSERT(tree); 353 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 354 355 smb_llist_enter(&tree->t_ofile_list, RW_READER); 356 of = smb_llist_head(&tree->t_ofile_list); 357 while (of) { 358 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 359 ASSERT(of->f_tree == tree); 360 of = smb_ofile_close_and_next(of); 361 } 362 smb_llist_exit(&tree->t_ofile_list); 363 } 364 365 /* 366 * smb_ofiles_close_by_pid 367 * 368 * 369 */ 370 void 371 smb_ofile_close_all_by_pid( 372 smb_tree_t *tree, 373 uint16_t pid) 374 { 375 smb_ofile_t *of; 376 377 ASSERT(tree); 378 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 379 380 smb_llist_enter(&tree->t_ofile_list, RW_READER); 381 of = smb_llist_head(&tree->t_ofile_list); 382 while (of) { 383 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 384 ASSERT(of->f_tree == tree); 385 if (of->f_opened_by_pid == pid) { 386 of = smb_ofile_close_and_next(of); 387 } else { 388 of = smb_llist_next(&tree->t_ofile_list, of); 389 } 390 } 391 smb_llist_exit(&tree->t_ofile_list); 392 } 393 394 /* 395 * smb_ofile_release 396 * 397 */ 398 void 399 smb_ofile_release( 400 smb_ofile_t *of) 401 { 402 ASSERT(of); 403 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 404 405 mutex_enter(&of->f_mutex); 406 ASSERT(of->f_refcnt); 407 of->f_refcnt--; 408 switch (of->f_state) { 409 case SMB_OFILE_STATE_OPEN: 410 case SMB_OFILE_STATE_CLOSING: 411 break; 412 413 case SMB_OFILE_STATE_CLOSED: 414 if (of->f_refcnt == 0) { 415 mutex_exit(&of->f_mutex); 416 smb_ofile_delete(of); 417 return; 418 } 419 break; 420 421 default: 422 ASSERT(0); 423 break; 424 } 425 mutex_exit(&of->f_mutex); 426 } 427 428 /* 429 * smb_ofile_lookup_by_fid 430 * 431 * Find the open file whose fid matches the one specified in the request. 432 * If we can't find the fid or the shares (trees) don't match, we have a 433 * bad fid. 434 */ 435 smb_ofile_t * 436 smb_ofile_lookup_by_fid( 437 smb_tree_t *tree, 438 uint16_t fid) 439 { 440 smb_llist_t *of_list; 441 smb_ofile_t *of; 442 443 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 444 445 of_list = &tree->t_ofile_list; 446 447 smb_llist_enter(of_list, RW_READER); 448 of = smb_llist_head(of_list); 449 while (of) { 450 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 451 ASSERT(of->f_tree == tree); 452 if (of->f_fid == fid) { 453 mutex_enter(&of->f_mutex); 454 if (of->f_state != SMB_OFILE_STATE_OPEN) { 455 mutex_exit(&of->f_mutex); 456 smb_llist_exit(of_list); 457 return (NULL); 458 } 459 of->f_refcnt++; 460 mutex_exit(&of->f_mutex); 461 break; 462 } 463 of = smb_llist_next(of_list, of); 464 } 465 smb_llist_exit(of_list); 466 return (of); 467 } 468 469 /* 470 * smb_ofile_set_flags 471 * 472 * Return value: 473 * 474 * Current flags value 475 * 476 */ 477 void 478 smb_ofile_set_flags( 479 smb_ofile_t *of, 480 uint32_t flags) 481 { 482 ASSERT(of); 483 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 484 ASSERT(of->f_refcnt); 485 486 mutex_enter(&of->f_mutex); 487 of->f_flags |= flags; 488 mutex_exit(&of->f_mutex); 489 } 490 /* 491 * smb_ofile_seek 492 * 493 * Return value: 494 * 495 * 0 Success 496 * EINVAL Unknown mode 497 * EOVERFLOW offset too big 498 * 499 */ 500 int 501 smb_ofile_seek( 502 smb_ofile_t *of, 503 ushort_t mode, 504 int32_t off, 505 uint32_t *retoff) 506 { 507 u_offset_t newoff = 0; 508 int rc = 0; 509 510 ASSERT(of); 511 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 512 ASSERT(of->f_refcnt); 513 514 mutex_enter(&of->f_mutex); 515 switch (mode) { 516 case SMB_SEEK_SET: 517 if (off < 0) 518 newoff = 0; 519 else 520 newoff = (u_offset_t)off; 521 break; 522 523 case SMB_SEEK_CUR: 524 if (off < 0 && (-off) > of->f_seek_pos) 525 newoff = 0; 526 else 527 newoff = of->f_seek_pos + (u_offset_t)off; 528 break; 529 530 case SMB_SEEK_END: 531 if (off < 0 && (-off) > of->f_node->attr.sa_vattr.va_size) 532 newoff = 0; 533 else 534 newoff = of->f_node->attr.sa_vattr.va_size + 535 (u_offset_t)off; 536 break; 537 538 default: 539 mutex_exit(&of->f_mutex); 540 return (EINVAL); 541 } 542 543 /* 544 * See comments at the beginning of smb_seek.c. 545 * If the offset is greater than UINT_MAX, we will return an error. 546 */ 547 548 if (newoff > UINT_MAX) { 549 rc = EOVERFLOW; 550 } else { 551 of->f_seek_pos = newoff; 552 *retoff = (uint32_t)newoff; 553 } 554 mutex_exit(&of->f_mutex); 555 return (rc); 556 } 557 558 /* 559 * smb_ofile_close_timestamp_update 560 * 561 * The last_wtime is specified in the request received 562 * from the client. If it is neither 0 nor -1, this time 563 * should be used as the file's mtime. It must first be 564 * converted from the server's localtime (as received in 565 * the client's request) to GMT. 566 */ 567 void 568 smb_ofile_close_timestamp_update( 569 smb_ofile_t *of, 570 uint32_t last_wtime) 571 { 572 smb_node_t *node; 573 timestruc_t mtime, atime; 574 unsigned int what = 0; 575 576 mtime.tv_sec = 0; 577 mtime.tv_nsec = 0; 578 579 if (last_wtime != 0 && last_wtime != 0xFFFFFFFF) { 580 mtime.tv_sec = last_wtime + of->f_server->si_gmtoff; 581 what |= SMB_AT_MTIME; 582 } 583 584 /* 585 * NODE_FLAGS_SYNCATIME is set whenever something is 586 * written to a file. 587 */ 588 node = of->f_node; 589 if (node->flags & NODE_FLAGS_SYNCATIME) { 590 what |= SMB_AT_ATIME; 591 (void) microtime(&atime); 592 } 593 594 smb_node_set_time(node, 0, &mtime, &atime, 0, what); 595 (void) smb_sync_fsattr(NULL, of->f_cr, of->f_node); 596 } 597 598 /* 599 * smb_ofile_is_open 600 * 601 */ 602 boolean_t 603 smb_ofile_is_open( 604 smb_ofile_t *of) 605 { 606 boolean_t rc = B_FALSE; 607 608 ASSERT(of); 609 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 610 611 mutex_enter(&of->f_mutex); 612 if (of->f_state == SMB_OFILE_STATE_OPEN) { 613 rc = B_TRUE; 614 } 615 mutex_exit(&of->f_mutex); 616 return (rc); 617 } 618 619 /* *************************** Static Functions ***************************** */ 620 621 /* 622 * smb_ofile_close_and_next 623 * 624 * This function closes the file passed in (if appropriate) and returns the 625 * next open file in the list of open files of the tree of the open file passed 626 * in. It requires that the list of open files of the tree be entered in 627 * RW_READER mode before being called. 628 */ 629 static smb_ofile_t * 630 smb_ofile_close_and_next( 631 smb_ofile_t *of) 632 { 633 smb_ofile_t *next_of; 634 smb_tree_t *tree; 635 636 ASSERT(of); 637 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 638 639 mutex_enter(&of->f_mutex); 640 switch (of->f_state) { 641 case SMB_OFILE_STATE_OPEN: 642 /* The file is still open. */ 643 of->f_refcnt++; 644 ASSERT(of->f_refcnt); 645 tree = of->f_tree; 646 mutex_exit(&of->f_mutex); 647 smb_llist_exit(&of->f_tree->t_ofile_list); 648 smb_ofile_close(of, 0); 649 smb_ofile_release(of); 650 smb_llist_enter(&tree->t_ofile_list, RW_READER); 651 next_of = smb_llist_head(&tree->t_ofile_list); 652 break; 653 case SMB_OFILE_STATE_CLOSING: 654 case SMB_OFILE_STATE_CLOSED: 655 /* 656 * The ofile exists but is closed or 657 * in the process being closed. 658 */ 659 mutex_exit(&of->f_mutex); 660 next_of = smb_llist_next(&of->f_tree->t_ofile_list, of); 661 break; 662 default: 663 ASSERT(0); 664 mutex_exit(&of->f_mutex); 665 next_of = smb_llist_next(&of->f_tree->t_ofile_list, of); 666 break; 667 } 668 return (next_of); 669 } 670 671 /* 672 * smb_ofile_delete 673 * 674 * 675 */ 676 static void 677 smb_ofile_delete( 678 smb_ofile_t *of) 679 { 680 ASSERT(of); 681 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 682 ASSERT(of->f_refcnt == 0); 683 ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED); 684 685 /* 686 * Let's remove the ofile from the list of ofiles of the tree. This has 687 * to be done before any resources associated with the ofile are 688 * released. 689 */ 690 smb_llist_enter(&of->f_tree->t_ofile_list, RW_WRITER); 691 smb_llist_remove(&of->f_tree->t_ofile_list, of); 692 smb_llist_exit(&of->f_tree->t_ofile_list); 693 atomic_dec_32(&of->f_session->s_file_cnt); 694 695 if (of->f_ftype == SMB_FTYPE_MESG_PIPE) { 696 kmem_free(of->f_pipe, sizeof (smb_opipe_t)); 697 of->f_pipe = NULL; 698 } else { 699 ASSERT(of->f_ftype == SMB_FTYPE_DISK); 700 ASSERT(of->f_node != NULL); 701 smb_llist_enter(&of->f_node->n_ofile_list, RW_WRITER); 702 smb_llist_remove(&of->f_node->n_ofile_list, of); 703 smb_llist_exit(&of->f_node->n_ofile_list); 704 smb_node_release(of->f_node); 705 } 706 707 of->f_magic = (uint32_t)~SMB_OFILE_MAGIC; 708 mutex_destroy(&of->f_mutex); 709 crfree(of->f_cr); 710 smb_idpool_free(&of->f_tree->t_fid_pool, of->f_fid); 711 kmem_cache_free(of->f_tree->t_server->si_cache_ofile, of); 712 } 713 714 /* 715 * smb_ofile_access 716 * 717 * This function will check to see if the access requested is granted. 718 * Returns NT status codes. 719 */ 720 uint32_t 721 smb_ofile_access(smb_ofile_t *of, cred_t *cr, uint32_t access) 722 { 723 724 if ((of == NULL) || (cr == kcred)) 725 return (NT_STATUS_SUCCESS); 726 727 /* 728 * If the request is for something 729 * I don't grant it is an error 730 */ 731 if (~(of->f_granted_access) & access) { 732 if (!(of->f_granted_access & ACCESS_SYSTEM_SECURITY) && 733 (access & ACCESS_SYSTEM_SECURITY)) { 734 return (NT_STATUS_PRIVILEGE_NOT_HELD); 735 } 736 return (NT_STATUS_ACCESS_DENIED); 737 } 738 739 return (NT_STATUS_SUCCESS); 740 } 741 742 743 /* 744 * smb_ofile_open_check 745 * 746 * check file sharing rules for current open request 747 * against existing open instances of the same file 748 * 749 * Returns NT_STATUS_SHARING_VIOLATION if there is any 750 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 751 */ 752 uint32_t 753 smb_ofile_open_check( 754 smb_ofile_t *of, 755 cred_t *cr, 756 uint32_t desired_access, 757 uint32_t share_access) 758 { 759 smb_node_t *node; 760 761 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 762 763 node = of->f_node; 764 765 mutex_enter(&of->f_mutex); 766 767 if (of->f_state != SMB_OFILE_STATE_OPEN) { 768 mutex_exit(&of->f_mutex); 769 return (NT_STATUS_INVALID_HANDLE); 770 } 771 772 /* 773 * It appears that share modes are not relevant to 774 * directories, but this check will remain as it is not 775 * clear whether it was originally put here for a reason. 776 */ 777 if (node->attr.sa_vattr.va_type == VDIR) { 778 if (SMB_DENY_RW(of->f_share_access) && 779 (node->n_orig_uid != crgetuid(cr))) { 780 mutex_exit(&of->f_mutex); 781 return (NT_STATUS_SHARING_VIOLATION); 782 } 783 784 mutex_exit(&of->f_mutex); 785 return (NT_STATUS_SUCCESS); 786 } 787 788 /* if it's just meta data */ 789 if ((of->f_granted_access & FILE_DATA_ALL) == 0) { 790 mutex_exit(&of->f_mutex); 791 return (NT_STATUS_SUCCESS); 792 } 793 794 /* 795 * Check requested share access against the 796 * open granted (desired) access 797 */ 798 if (SMB_DENY_DELETE(share_access) && (of->f_granted_access & DELETE)) { 799 mutex_exit(&of->f_mutex); 800 return (NT_STATUS_SHARING_VIOLATION); 801 } 802 803 if (SMB_DENY_READ(share_access) && 804 (of->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE))) { 805 mutex_exit(&of->f_mutex); 806 return (NT_STATUS_SHARING_VIOLATION); 807 } 808 809 if (SMB_DENY_WRITE(share_access) && 810 (of->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) { 811 mutex_exit(&of->f_mutex); 812 return (NT_STATUS_SHARING_VIOLATION); 813 } 814 815 /* check requested desired access against the open share access */ 816 if (SMB_DENY_DELETE(of->f_share_access) && (desired_access & DELETE)) { 817 mutex_exit(&of->f_mutex); 818 return (NT_STATUS_SHARING_VIOLATION); 819 } 820 821 if (SMB_DENY_READ(of->f_share_access) && 822 (desired_access & (FILE_READ_DATA | FILE_EXECUTE))) { 823 mutex_exit(&of->f_mutex); 824 return (NT_STATUS_SHARING_VIOLATION); 825 } 826 827 if (SMB_DENY_WRITE(of->f_share_access) && 828 (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) { 829 mutex_exit(&of->f_mutex); 830 return (NT_STATUS_SHARING_VIOLATION); 831 } 832 833 mutex_exit(&of->f_mutex); 834 return (NT_STATUS_SUCCESS); 835 } 836 837 /* 838 * smb_ofile_rename_check 839 * 840 * An open file can be renamed if 841 * 842 * 1. isn't opened for data writing or deleting 843 * 844 * 2. Opened with "Deny Delete" share mode 845 * But not opened for data reading or executing 846 * (opened for accessing meta data) 847 */ 848 849 uint32_t 850 smb_ofile_rename_check(smb_ofile_t *of) 851 { 852 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 853 854 mutex_enter(&of->f_mutex); 855 856 if (of->f_state != SMB_OFILE_STATE_OPEN) { 857 mutex_exit(&of->f_mutex); 858 return (NT_STATUS_INVALID_HANDLE); 859 } 860 861 if (of->f_granted_access & 862 (FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE)) { 863 mutex_exit(&of->f_mutex); 864 return (NT_STATUS_SHARING_VIOLATION); 865 } 866 867 if ((of->f_share_access & FILE_SHARE_DELETE) == 0) { 868 if (of->f_granted_access & 869 (FILE_READ_DATA | FILE_EXECUTE)) { 870 mutex_exit(&of->f_mutex); 871 return (NT_STATUS_SHARING_VIOLATION); 872 } 873 } 874 875 mutex_exit(&of->f_mutex); 876 return (NT_STATUS_SUCCESS); 877 } 878 879 /* 880 * smb_ofile_delete_check 881 * 882 * An open file can be deleted only if opened for 883 * accessing meta data. Share modes aren't important 884 * in this case. 885 * 886 * NOTE: there is another mechanism for deleting an 887 * open file that NT clients usually use. 888 * That's setting "Delete on close" flag for an open 889 * file. In this way the file will be deleted after 890 * last close. This flag can be set by SmbTrans2SetFileInfo 891 * with FILE_DISPOSITION_INFO information level. 892 * For setting this flag, the file should be opened by 893 * DELETE access in the FID that is passed in the Trans2 894 * request. 895 */ 896 897 uint32_t 898 smb_ofile_delete_check(smb_ofile_t *of) 899 { 900 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 901 902 mutex_enter(&of->f_mutex); 903 904 if (of->f_state != SMB_OFILE_STATE_OPEN) { 905 mutex_exit(&of->f_mutex); 906 return (NT_STATUS_INVALID_HANDLE); 907 } 908 909 if (of->f_granted_access & 910 (FILE_READ_DATA | FILE_WRITE_DATA | 911 FILE_APPEND_DATA | FILE_EXECUTE | DELETE)) { 912 mutex_exit(&of->f_mutex); 913 return (NT_STATUS_SHARING_VIOLATION); 914 } 915 916 mutex_exit(&of->f_mutex); 917 return (NT_STATUS_SUCCESS); 918 } 919