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 (void) smb_sync_fsattr(NULL, of->f_cr, of->f_node); 306 smb_commit_delete_on_close(of); 307 smb_oplock_release(of->f_node, B_FALSE); 308 smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid); 309 smb_node_destroy_lock_by_ofile(of->f_node, of); 310 311 if (of->f_node->vp->v_type == VREG) 312 (void) smb_fsop_close(of->f_node, of->f_mode, 313 of->f_cr); 314 315 /* 316 * Cancel any notify change requests related 317 * to this open instance. 318 */ 319 if (of->f_node->flags & NODE_FLAGS_NOTIFY_CHANGE) 320 smb_process_file_notify_change_queue(of); 321 } 322 atomic_dec_32(&of->f_tree->t_server->sv_open_files); 323 324 mutex_enter(&of->f_mutex); 325 ASSERT(of->f_refcnt); 326 ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING); 327 of->f_state = SMB_OFILE_STATE_CLOSED; 328 mutex_exit(&of->f_mutex); 329 return; 330 } 331 case SMB_OFILE_STATE_CLOSED: 332 case SMB_OFILE_STATE_CLOSING: 333 break; 334 335 default: 336 ASSERT(0); 337 break; 338 } 339 mutex_exit(&of->f_mutex); 340 } 341 342 /* 343 * smb_ofile_close_all 344 * 345 * 346 */ 347 void 348 smb_ofile_close_all( 349 smb_tree_t *tree) 350 { 351 smb_ofile_t *of; 352 353 ASSERT(tree); 354 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 355 356 smb_llist_enter(&tree->t_ofile_list, RW_READER); 357 of = smb_llist_head(&tree->t_ofile_list); 358 while (of) { 359 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 360 ASSERT(of->f_tree == tree); 361 of = smb_ofile_close_and_next(of); 362 } 363 smb_llist_exit(&tree->t_ofile_list); 364 } 365 366 /* 367 * smb_ofiles_close_by_pid 368 * 369 * 370 */ 371 void 372 smb_ofile_close_all_by_pid( 373 smb_tree_t *tree, 374 uint16_t pid) 375 { 376 smb_ofile_t *of; 377 378 ASSERT(tree); 379 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 380 381 smb_llist_enter(&tree->t_ofile_list, RW_READER); 382 of = smb_llist_head(&tree->t_ofile_list); 383 while (of) { 384 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 385 ASSERT(of->f_tree == tree); 386 if (of->f_opened_by_pid == pid) { 387 of = smb_ofile_close_and_next(of); 388 } else { 389 of = smb_llist_next(&tree->t_ofile_list, of); 390 } 391 } 392 smb_llist_exit(&tree->t_ofile_list); 393 } 394 395 /* 396 * smb_ofile_release 397 * 398 */ 399 void 400 smb_ofile_release( 401 smb_ofile_t *of) 402 { 403 ASSERT(of); 404 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 405 406 mutex_enter(&of->f_mutex); 407 ASSERT(of->f_refcnt); 408 of->f_refcnt--; 409 switch (of->f_state) { 410 case SMB_OFILE_STATE_OPEN: 411 case SMB_OFILE_STATE_CLOSING: 412 break; 413 414 case SMB_OFILE_STATE_CLOSED: 415 if (of->f_refcnt == 0) { 416 mutex_exit(&of->f_mutex); 417 smb_ofile_delete(of); 418 return; 419 } 420 break; 421 422 default: 423 ASSERT(0); 424 break; 425 } 426 mutex_exit(&of->f_mutex); 427 } 428 429 /* 430 * smb_ofile_lookup_by_fid 431 * 432 * Find the open file whose fid matches the one specified in the request. 433 * If we can't find the fid or the shares (trees) don't match, we have a 434 * bad fid. 435 */ 436 smb_ofile_t * 437 smb_ofile_lookup_by_fid( 438 smb_tree_t *tree, 439 uint16_t fid) 440 { 441 smb_llist_t *of_list; 442 smb_ofile_t *of; 443 444 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 445 446 of_list = &tree->t_ofile_list; 447 448 smb_llist_enter(of_list, RW_READER); 449 of = smb_llist_head(of_list); 450 while (of) { 451 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 452 ASSERT(of->f_tree == tree); 453 if (of->f_fid == fid) { 454 mutex_enter(&of->f_mutex); 455 if (of->f_state != SMB_OFILE_STATE_OPEN) { 456 mutex_exit(&of->f_mutex); 457 smb_llist_exit(of_list); 458 return (NULL); 459 } 460 of->f_refcnt++; 461 mutex_exit(&of->f_mutex); 462 break; 463 } 464 of = smb_llist_next(of_list, of); 465 } 466 smb_llist_exit(of_list); 467 return (of); 468 } 469 470 /* 471 * smb_ofile_set_flags 472 * 473 * Return value: 474 * 475 * Current flags value 476 * 477 */ 478 void 479 smb_ofile_set_flags( 480 smb_ofile_t *of, 481 uint32_t flags) 482 { 483 ASSERT(of); 484 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 485 ASSERT(of->f_refcnt); 486 487 mutex_enter(&of->f_mutex); 488 of->f_flags |= flags; 489 mutex_exit(&of->f_mutex); 490 } 491 /* 492 * smb_ofile_seek 493 * 494 * Return value: 495 * 496 * 0 Success 497 * EINVAL Unknown mode 498 * EOVERFLOW offset too big 499 * 500 */ 501 int 502 smb_ofile_seek( 503 smb_ofile_t *of, 504 ushort_t mode, 505 int32_t off, 506 uint32_t *retoff) 507 { 508 u_offset_t newoff = 0; 509 int rc = 0; 510 511 ASSERT(of); 512 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 513 ASSERT(of->f_refcnt); 514 515 mutex_enter(&of->f_mutex); 516 switch (mode) { 517 case SMB_SEEK_SET: 518 if (off < 0) 519 newoff = 0; 520 else 521 newoff = (u_offset_t)off; 522 break; 523 524 case SMB_SEEK_CUR: 525 if (off < 0 && (-off) > of->f_seek_pos) 526 newoff = 0; 527 else 528 newoff = of->f_seek_pos + (u_offset_t)off; 529 break; 530 531 case SMB_SEEK_END: 532 if (off < 0 && (-off) > of->f_node->attr.sa_vattr.va_size) 533 newoff = 0; 534 else 535 newoff = of->f_node->attr.sa_vattr.va_size + 536 (u_offset_t)off; 537 break; 538 539 default: 540 mutex_exit(&of->f_mutex); 541 return (EINVAL); 542 } 543 544 /* 545 * See comments at the beginning of smb_seek.c. 546 * If the offset is greater than UINT_MAX, we will return an error. 547 */ 548 549 if (newoff > UINT_MAX) { 550 rc = EOVERFLOW; 551 } else { 552 of->f_seek_pos = newoff; 553 *retoff = (uint32_t)newoff; 554 } 555 mutex_exit(&of->f_mutex); 556 return (rc); 557 } 558 559 /* 560 * smb_ofile_close_timestamp_update 561 * 562 * The last_wtime is specified in the request received 563 * from the client. If it is neither 0 nor -1, this time 564 * should be used as the file's mtime. It must first be 565 * converted from the server's localtime (as received in 566 * the client's request) to GMT. 567 */ 568 void 569 smb_ofile_close_timestamp_update( 570 smb_ofile_t *of, 571 uint32_t last_wtime) 572 { 573 smb_node_t *node; 574 timestruc_t mtime, atime; 575 unsigned int what = 0; 576 577 mtime.tv_sec = 0; 578 mtime.tv_nsec = 0; 579 580 if (last_wtime != 0 && last_wtime != 0xFFFFFFFF) { 581 mtime.tv_sec = last_wtime + of->f_server->si_gmtoff; 582 what |= SMB_AT_MTIME; 583 } 584 585 /* 586 * NODE_FLAGS_SYNCATIME is set whenever something is 587 * written to a file. 588 */ 589 node = of->f_node; 590 if (node->flags & NODE_FLAGS_SYNCATIME) { 591 what |= SMB_AT_ATIME; 592 (void) microtime(&atime); 593 } 594 595 smb_node_set_time(node, 0, &mtime, &atime, 0, what); 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