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 "%Z%%M% %I% %E% SMI" 27 28 /* 29 * This module provides the common open functionality to the various 30 * open and create SMB interface functions. 31 */ 32 33 #include <smbsrv/smb_incl.h> 34 #include <smbsrv/smb_fsops.h> 35 #include <smbsrv/mlsvc.h> 36 #include <smbsrv/nterror.h> 37 #include <smbsrv/ntstatus.h> 38 #include <smbsrv/smbinfo.h> 39 #include <sys/fcntl.h> 40 #include <sys/nbmlock.h> 41 42 extern uint32_t smb_is_executable(char *path); 43 44 /* 45 * The default stability mode is to perform the write-through 46 * behaviour requested by the client. 47 */ 48 int smb_stable_mode = 0; 49 50 51 /* 52 * This macro is used to delete a newly created object 53 * if any error happens after creation of object. 54 */ 55 #define SMB_DEL_NEWOBJ(obj) \ 56 if (created) { \ 57 if (is_dir) \ 58 (void) smb_fsop_rmdir(sr, sr->user_cr, \ 59 obj.dir_snode, obj.last_comp, 0); \ 60 else \ 61 (void) smb_fsop_remove(sr, sr->user_cr, \ 62 obj.dir_snode, obj.last_comp, 0); \ 63 } 64 65 /* 66 * smb_set_stability 67 * 68 * Set the default stability mode. Normal (mode is zero) means perform 69 * the write-through behaviour requested by the client. Synchronous 70 * (mode is non-zero) means journal everything regardless of the write 71 * through behaviour requested by the client. 72 */ 73 void 74 smb_set_stability(int mode) 75 { 76 smb_stable_mode = mode; 77 } 78 79 /* 80 * smb_access_generic_to_file 81 * 82 * Search MSDN for IoCreateFile to see following mapping. 83 * 84 * GENERIC_READ STANDARD_RIGHTS_READ, FILE_READ_DATA, 85 * FILE_READ_ATTRIBUTES and FILE_READ_EA 86 * 87 * GENERIC_WRITE STANDARD_RIGHTS_WRITE, FILE_WRITE_DATA, 88 * FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA 89 * 90 * GENERIC_EXECUTE STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE. 91 */ 92 uint32_t 93 smb_access_generic_to_file(uint32_t desired_access) 94 { 95 uint32_t access = 0; 96 97 if (desired_access & GENERIC_ALL) 98 return (FILE_ALL_ACCESS & ~SYNCHRONIZE); 99 100 if (desired_access & GENERIC_EXECUTE) { 101 desired_access &= ~GENERIC_EXECUTE; 102 access |= (STANDARD_RIGHTS_EXECUTE | 103 SYNCHRONIZE | FILE_EXECUTE); 104 } 105 106 if (desired_access & GENERIC_WRITE) { 107 desired_access &= ~GENERIC_WRITE; 108 access |= (FILE_GENERIC_WRITE & ~SYNCHRONIZE); 109 } 110 111 if (desired_access & GENERIC_READ) { 112 desired_access &= ~GENERIC_READ; 113 access |= FILE_GENERIC_READ; 114 } 115 116 return (access | desired_access); 117 } 118 119 /* 120 * smb_omode_to_amask 121 * 122 * This function converts open modes used by Open and Open AndX 123 * commands to desired access bits used by NT Create AndX command. 124 */ 125 uint32_t 126 smb_omode_to_amask(uint32_t desired_access) 127 { 128 switch (desired_access & SMB_DA_ACCESS_MASK) { 129 case SMB_DA_ACCESS_READ: 130 return (FILE_GENERIC_READ); 131 132 case SMB_DA_ACCESS_WRITE: 133 return (FILE_GENERIC_WRITE); 134 135 case SMB_DA_ACCESS_READ_WRITE: 136 return (FILE_GENERIC_READ | FILE_GENERIC_WRITE); 137 138 case SMB_DA_ACCESS_EXECUTE: 139 return (FILE_GENERIC_EXECUTE); 140 } 141 142 /* invalid open mode */ 143 return ((uint32_t)SMB_INVALID_AMASK); 144 } 145 146 /* 147 * smb_denymode_to_sharemode 148 * 149 * This function converts deny modes used by Open and Open AndX 150 * commands to share access bits used by NT Create AndX command. 151 */ 152 uint32_t 153 smb_denymode_to_sharemode(uint32_t desired_access, char *fname) 154 { 155 switch (desired_access & SMB_DA_SHARE_MASK) { 156 case SMB_DA_SHARE_COMPATIBILITY: 157 if (smb_is_executable(fname)) 158 return (FILE_SHARE_READ | FILE_SHARE_WRITE); 159 else { 160 if ((desired_access & 161 SMB_DA_ACCESS_MASK) == SMB_DA_ACCESS_READ) 162 return (FILE_SHARE_READ); 163 else 164 return (FILE_SHARE_NONE); 165 } 166 167 case SMB_DA_SHARE_EXCLUSIVE: 168 return (FILE_SHARE_NONE); 169 170 case SMB_DA_SHARE_DENY_WRITE: 171 return (FILE_SHARE_READ); 172 173 case SMB_DA_SHARE_DENY_READ: 174 return (FILE_SHARE_WRITE); 175 176 case SMB_DA_SHARE_DENY_NONE: 177 return (FILE_SHARE_READ | FILE_SHARE_WRITE); 178 } 179 180 /* invalid deny mode */ 181 return ((uint32_t)SMB_INVALID_SHAREMODE); 182 } 183 184 /* 185 * smb_ofun_to_crdisposition 186 * 187 * This function converts open function values used by Open and Open AndX 188 * commands to create disposition values used by NT Create AndX command. 189 */ 190 uint32_t 191 smb_ofun_to_crdisposition(uint16_t ofun) 192 { 193 static int ofun_cr_map[3][2] = 194 { 195 { -1, FILE_CREATE }, 196 { FILE_OPEN, FILE_OPEN_IF }, 197 { FILE_OVERWRITE, FILE_OVERWRITE_IF } 198 }; 199 200 int row = ofun & SMB_OFUN_OPEN_MASK; 201 int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4; 202 203 if (row == 3) 204 return ((uint32_t)SMB_INVALID_CRDISPOSITION); 205 206 return (ofun_cr_map[row][col]); 207 } 208 209 /* 210 * smb_open_subr 211 * 212 * Notes on write-through behaviour. It looks like pre-LM0.12 versions 213 * of the protocol specify the write-through mode when a file is opened, 214 * (SmbOpen, SmbOpenAndX) so the write calls (SmbWrite, SmbWriteAndClose, 215 * SmbWriteAndUnlock) don't need to contain a write-through flag. 216 * 217 * With LM0.12, the open calls (SmbCreateAndX, SmbNtTransactCreate) 218 * don't indicate which write-through mode to use. Instead the write 219 * calls (SmbWriteAndX, SmbWriteRaw) specify the mode on a per call 220 * basis. 221 * 222 * We don't care which open call was used to get us here, we just need 223 * to ensure that the write-through mode flag is copied from the open 224 * parameters to the node. We test the omode write-through flag in all 225 * write functions. 226 * 227 * This function will return NT status codes but it also raises errors, 228 * in which case it won't return to the caller. Be careful how you 229 * handle things in here. 230 */ 231 232 uint32_t 233 smb_open_subr(struct smb_request *sr) 234 { 235 int created = 0; 236 struct smb_node *node = 0; 237 struct smb_node *dnode = 0; 238 struct smb_node *cur_node; 239 struct open_param *op = &sr->arg.open; 240 int rc; 241 struct smb_ofile *of; 242 smb_attr_t new_attr; 243 int pathlen; 244 int max_requested = 0; 245 uint32_t max_allowed; 246 unsigned int granted_oplock; 247 uint32_t status = NT_STATUS_SUCCESS; 248 int is_dir; 249 smb_error_t err; 250 int is_stream; 251 int lookup_flags = SMB_FOLLOW_LINKS; 252 uint32_t daccess; 253 uint32_t share_access = op->share_access; 254 uint32_t uniq_fid; 255 256 is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0; 257 258 if (is_dir) { 259 /* 260 * The file being created or opened is a directory file. 261 * With this flag, the Disposition parameter must be set to 262 * one of FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF 263 */ 264 if ((op->create_disposition != FILE_CREATE) && 265 (op->create_disposition != FILE_OPEN_IF) && 266 (op->create_disposition != FILE_OPEN)) { 267 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 268 ERRDOS, ERROR_INVALID_ACCESS); 269 /* invalid open mode */ 270 /* NOTREACHED */ 271 } 272 } 273 274 if (op->desired_access & MAXIMUM_ALLOWED) { 275 max_requested = 1; 276 op->desired_access &= ~MAXIMUM_ALLOWED; 277 } 278 op->desired_access = smb_access_generic_to_file(op->desired_access); 279 280 if (sr->session->s_file_cnt >= SMB_SESSION_OFILE_MAX) { 281 282 ASSERT(sr->uid_user); 283 cmn_err(CE_NOTE, "smbd[%s\\%s]: %s", sr->uid_user->u_domain, 284 sr->uid_user->u_name, 285 xlate_nt_status(NT_STATUS_TOO_MANY_OPENED_FILES)); 286 287 smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES, 288 ERRDOS, ERROR_TOO_MANY_OPEN_FILES); 289 /* NOTREACHED */ 290 } 291 292 /* This must be NULL at this point */ 293 sr->fid_ofile = NULL; 294 295 op->devstate = 0; 296 297 switch (sr->tid_tree->t_res_type & STYPE_MASK) { 298 case STYPE_DISKTREE: 299 break; 300 301 case STYPE_IPC: 302 /* 303 * No further processing for IPC, we need to either 304 * raise an exception or return success here. 305 */ 306 if ((rc = smb_rpc_open(sr)) != 0) { 307 smbsr_error(sr, rc, 0, 0); 308 /* NOTREACHED */ 309 } else { 310 return (NT_STATUS_SUCCESS); 311 } 312 break; 313 314 default: 315 smbsr_error(sr, 0, ERRSRV, ERRinvdevice); 316 /* NOTREACHED */ 317 break; 318 } 319 320 if ((pathlen = strlen(op->fqi.path)) >= MAXPATHLEN) { 321 smbsr_error(sr, 0, ERRSRV, ERRfilespecs); 322 /* NOTREACHED */ 323 } 324 325 /* 326 * Some clients pass null file names; NT interprets this as "\". 327 */ 328 if (pathlen == 0) { 329 op->fqi.path = "\\"; 330 pathlen = 1; 331 } 332 333 op->fqi.srch_attr = op->fqi.srch_attr; 334 335 if ((status = smb_validate_object_name(op->fqi.path, is_dir)) != 0) { 336 smbsr_error(sr, status, ERRDOS, ERROR_INVALID_NAME); 337 /* NOTREACHED */ 338 } 339 340 cur_node = op->fqi.dir_snode ? 341 op->fqi.dir_snode : sr->tid_tree->t_snode; 342 343 if (rc = smb_pathname_reduce(sr, sr->user_cr, op->fqi.path, 344 sr->tid_tree->t_snode, cur_node, &op->fqi.dir_snode, 345 op->fqi.last_comp)) { 346 smbsr_errno(sr, rc); 347 /* NOTREACHED */ 348 } 349 350 /* 351 * If the access mask has only DELETE set (ignore 352 * FILE_READ_ATTRIBUTES), then assume that this 353 * is a request to delete the link (if a link) 354 * and do not follow links. Otherwise, follow 355 * the link to the target. 356 */ 357 358 daccess = op->desired_access & ~FILE_READ_ATTRIBUTES; 359 360 if (daccess == DELETE) 361 lookup_flags &= ~SMB_FOLLOW_LINKS; 362 363 rc = smb_fsop_lookup_name(sr, kcred, lookup_flags, 364 sr->tid_tree->t_snode, op->fqi.dir_snode, op->fqi.last_comp, 365 &op->fqi.last_snode, &op->fqi.last_attr); 366 367 if (rc == 0) { 368 op->fqi.last_comp_was_found = 1; 369 (void) strcpy(op->fqi.last_comp_od, 370 op->fqi.last_snode->od_name); 371 } else if (rc == ENOENT) { 372 op->fqi.last_comp_was_found = 0; 373 op->fqi.last_snode = NULL; 374 rc = 0; 375 } else { 376 smb_node_release(op->fqi.dir_snode); 377 SMB_NULL_FQI_NODES(op->fqi); 378 smbsr_errno(sr, rc); 379 /* NOTREACHED */ 380 } 381 382 /* 383 * The uniq_fid is a CIFS-server-wide unique identifier for an ofile 384 * which is used to uniquely identify open instances for the 385 * VFS share reservation mechanism (accessed via smb_fsop_shrlock()). 386 */ 387 388 uniq_fid = SMB_UNIQ_FID(); 389 390 if (op->fqi.last_comp_was_found) { 391 node = op->fqi.last_snode; 392 dnode = op->fqi.dir_snode; 393 394 /* 395 * Enter critical region for share reservations. 396 * (See comments above smb_fsop_shrlock().) 397 */ 398 399 rw_enter(&node->n_share_lock, RW_WRITER); 400 401 /* 402 * Reject this request if the target is a directory 403 * and the client has specified that it must not be 404 * a directory (required by Lotus Notes). 405 */ 406 if ((op->create_options & FILE_NON_DIRECTORY_FILE) && 407 (op->fqi.last_attr.sa_vattr.va_type == VDIR)) { 408 rw_exit(&node->n_share_lock); 409 smb_node_release(node); 410 smb_node_release(dnode); 411 SMB_NULL_FQI_NODES(op->fqi); 412 smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY, 413 ERRDOS, ERROR_ACCESS_DENIED); 414 /* NOTREACHED */ 415 } 416 417 if (op->fqi.last_attr.sa_vattr.va_type == VDIR) { 418 if ((sr->smb_com == SMB_COM_OPEN_ANDX) || 419 (sr->smb_com == SMB_COM_OPEN)) { 420 /* 421 * Directories cannot be opened 422 * with the above commands 423 */ 424 rw_exit(&node->n_share_lock); 425 smb_node_release(node); 426 smb_node_release(dnode); 427 SMB_NULL_FQI_NODES(op->fqi); 428 smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY, 429 ERRDOS, ERROR_ACCESS_DENIED); 430 /* NOTREACHED */ 431 } 432 } else if (op->my_flags & MYF_MUST_BE_DIRECTORY) { 433 rw_exit(&node->n_share_lock); 434 smb_node_release(node); 435 smb_node_release(dnode); 436 SMB_NULL_FQI_NODES(op->fqi); 437 smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY, 438 ERRDOS, ERROR_DIRECTORY); 439 /* NOTREACHED */ 440 } 441 442 /* 443 * No more open should be accepted when "Delete on close" 444 * flag is set. 445 */ 446 if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 447 rw_exit(&node->n_share_lock); 448 smb_node_release(node); 449 smb_node_release(dnode); 450 SMB_NULL_FQI_NODES(op->fqi); 451 smbsr_error(sr, NT_STATUS_DELETE_PENDING, 452 ERRDOS, ERROR_ACCESS_DENIED); 453 /* NOTREACHED */ 454 } 455 456 /* 457 * Specified file already exists so the operation should fail. 458 */ 459 if (op->create_disposition == FILE_CREATE) { 460 rw_exit(&node->n_share_lock); 461 smb_node_release(node); 462 smb_node_release(dnode); 463 SMB_NULL_FQI_NODES(op->fqi); 464 smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION, 465 ERRDOS, ERROR_ALREADY_EXISTS); 466 /* NOTREACHED */ 467 } 468 469 /* 470 * Windows seems to check read-only access before file 471 * sharing check. 472 */ 473 if (NODE_IS_READONLY(node)) { 474 /* Files data only */ 475 if (node->attr.sa_vattr.va_type != VDIR) { 476 if (op->desired_access & (FILE_WRITE_DATA | 477 FILE_APPEND_DATA)) { 478 rw_exit(&node->n_share_lock); 479 smb_node_release(node); 480 smb_node_release(dnode); 481 SMB_NULL_FQI_NODES(op->fqi); 482 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 483 ERRDOS, ERRnoaccess); 484 /* NOTREACHED */ 485 } 486 } 487 } 488 489 /* 490 * The following check removes the need to check share 491 * reservations again when a truncate is done. 492 */ 493 494 if ((op->create_disposition == FILE_SUPERSEDE) || 495 (op->create_disposition == FILE_OVERWRITE_IF) || 496 (op->create_disposition == FILE_OVERWRITE)) { 497 498 if (!(op->desired_access & 499 (FILE_WRITE_DATA | FILE_APPEND_DATA))) { 500 rw_exit(&node->n_share_lock); 501 smb_node_release(node); 502 smb_node_release(dnode); 503 SMB_NULL_FQI_NODES(op->fqi); 504 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 505 ERRDOS, ERRnoaccess); 506 } 507 } 508 509 status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid, 510 op->desired_access, share_access); 511 512 if (status == NT_STATUS_SHARING_VIOLATION) { 513 rw_exit(&node->n_share_lock); 514 smb_node_release(node); 515 smb_node_release(dnode); 516 SMB_NULL_FQI_NODES(op->fqi); 517 return (status); 518 } 519 520 status = smb_fsop_access(sr, sr->user_cr, node, 521 op->desired_access); 522 523 if (status != NT_STATUS_SUCCESS) { 524 smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); 525 526 rw_exit(&node->n_share_lock); 527 smb_node_release(node); 528 smb_node_release(dnode); 529 SMB_NULL_FQI_NODES(op->fqi); 530 531 if (status == NT_STATUS_PRIVILEGE_NOT_HELD) { 532 smbsr_error(sr, status, 533 ERRDOS, ERROR_PRIVILEGE_NOT_HELD); 534 } else { 535 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 536 ERRDOS, ERROR_ACCESS_DENIED); 537 } 538 } 539 540 /* 541 * Break the oplock before share checks. If another client 542 * has the file open, this will force a flush or close, 543 * which may affect the outcome of any share checking. 544 */ 545 546 if (OPLOCKS_IN_FORCE(node)) { 547 status = smb_break_oplock(sr, node); 548 549 if (status != NT_STATUS_SUCCESS) { 550 rw_exit(&node->n_share_lock); 551 smb_node_release(node); 552 smb_node_release(dnode); 553 SMB_NULL_FQI_NODES(op->fqi); 554 smbsr_error(sr, status, 555 ERRDOS, ERROR_VC_DISCONNECTED); 556 /* NOTREACHED */ 557 } 558 } 559 560 switch (op->create_disposition) { 561 case FILE_SUPERSEDE: 562 case FILE_OVERWRITE_IF: 563 case FILE_OVERWRITE: 564 if (node->attr.sa_vattr.va_type == VDIR) { 565 smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); 566 rw_exit(&node->n_share_lock); 567 smb_node_release(node); 568 smb_node_release(dnode); 569 SMB_NULL_FQI_NODES(op->fqi); 570 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 571 ERRDOS, ERROR_ACCESS_DENIED); 572 /* NOTREACHED */ 573 } 574 575 if (node->attr.sa_vattr.va_size != op->dsize) { 576 node->flags &= ~NODE_FLAGS_SET_SIZE; 577 bzero(&new_attr, sizeof (new_attr)); 578 new_attr.sa_vattr.va_size = op->dsize; 579 new_attr.sa_mask = SMB_AT_SIZE; 580 581 rc = smb_fsop_setattr(sr, sr->user_cr, 582 node, &new_attr, &op->fqi.last_attr); 583 584 if (rc) { 585 smb_fsop_unshrlock(sr->user_cr, 586 node, uniq_fid); 587 rw_exit(&node->n_share_lock); 588 smb_node_release(node); 589 smb_node_release(dnode); 590 SMB_NULL_FQI_NODES(op->fqi); 591 smbsr_errno(sr, rc); 592 /* NOTREACHED */ 593 } 594 595 op->dsize = op->fqi.last_attr.sa_vattr.va_size; 596 } 597 598 /* 599 * If file is being replaced, 600 * we should remove existing streams 601 */ 602 if (SMB_IS_STREAM(node) == 0) 603 (void) smb_fsop_remove_streams(sr, sr->user_cr, 604 node); 605 606 op->action_taken = SMB_OACT_TRUNCATED; 607 break; 608 609 default: 610 /* 611 * FILE_OPEN or FILE_OPEN_IF. 612 */ 613 op->action_taken = SMB_OACT_OPENED; 614 break; 615 } 616 } else { 617 618 /* Last component was not found. */ 619 dnode = op->fqi.dir_snode; 620 621 if ((op->create_disposition == FILE_OPEN) || 622 (op->create_disposition == FILE_OVERWRITE)) { 623 smb_node_release(dnode); 624 SMB_NULL_FQI_NODES(op->fqi); 625 626 is_stream = smb_stream_parse_name(op->fqi.path, 627 NULL, NULL); 628 /* 629 * The requested file not found so the operation should 630 * fail with these two dispositions 631 */ 632 if (is_stream) 633 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 634 ERRDOS, ERROR_FILE_NOT_FOUND); 635 else 636 smbsr_error(sr, 0, ERRDOS, ERRbadfile); 637 /* NOTREACHED */ 638 } 639 640 /* 641 * lock the parent dir node in case another create 642 * request to the same parent directory comes in. 643 */ 644 smb_rwx_rwenter(&dnode->n_lock, RW_WRITER); 645 646 bzero(&new_attr, sizeof (new_attr)); 647 if (is_dir == 0) { 648 new_attr.sa_vattr.va_type = VREG; 649 new_attr.sa_vattr.va_mode = 0666; 650 new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE; 651 652 /* 653 * A problem with setting the readonly bit at 654 * create time is that this bit will prevent 655 * writes to the file from the same fid (which 656 * should be allowed). 657 * 658 * The solution is to set the bit at close time. 659 * Meanwhile, to prevent racing opens from being 660 * able to write to the file, the bit is set at 661 * create time until share reservations can be set 662 * to prevent write and delete access. At that point, 663 * the bit can be turned off until close (so as to 664 * allow writes from the same fid to the file). 665 */ 666 667 if (op->dattr & SMB_FA_READONLY) { 668 new_attr.sa_dosattr = FILE_ATTRIBUTE_READONLY; 669 new_attr.sa_mask |= SMB_AT_DOSATTR; 670 } 671 672 rc = smb_fsop_create(sr, sr->user_cr, dnode, 673 op->fqi.last_comp, &new_attr, 674 &op->fqi.last_snode, &op->fqi.last_attr); 675 676 if (rc != 0) { 677 smb_rwx_rwexit(&dnode->n_lock); 678 smb_node_release(dnode); 679 SMB_NULL_FQI_NODES(op->fqi); 680 smbsr_errno(sr, rc); 681 /* NOTREACHED */ 682 } 683 684 if (op->dattr & SMB_FA_READONLY) { 685 share_access &= ~(FILE_SHARE_WRITE | 686 FILE_SHARE_DELETE); 687 } 688 689 node = op->fqi.last_snode; 690 691 rw_enter(&node->n_share_lock, RW_WRITER); 692 693 status = smb_fsop_shrlock(sr->user_cr, node, 694 uniq_fid, op->desired_access, 695 share_access); 696 697 if (status == NT_STATUS_SHARING_VIOLATION) { 698 rw_exit(&node->n_share_lock); 699 smb_node_release(node); 700 smb_node_release(dnode); 701 SMB_NULL_FQI_NODES(op->fqi); 702 return (status); 703 } 704 705 new_attr = op->fqi.last_attr; 706 new_attr.sa_mask = 0; 707 708 if (op->dattr & SMB_FA_READONLY) { 709 new_attr.sa_dosattr &= ~FILE_ATTRIBUTE_READONLY; 710 new_attr.sa_mask |= SMB_AT_DOSATTR; 711 } 712 713 if (op->dsize) { 714 new_attr.sa_vattr.va_size = op->dsize; 715 new_attr.sa_mask |= SMB_AT_SIZE; 716 } 717 718 if (new_attr.sa_mask) { 719 node->attr = new_attr; 720 node->what = new_attr.sa_mask; 721 rc = smb_sync_fsattr(sr, sr->user_cr, node); 722 723 if (rc != 0) { 724 smb_fsop_unshrlock(sr->user_cr, node, 725 uniq_fid); 726 727 rw_exit(&node->n_share_lock); 728 smb_node_release(node); 729 (void) smb_fsop_remove(sr, sr->user_cr, 730 dnode, op->fqi.last_comp, 0); 731 smb_rwx_rwexit(&dnode->n_lock); 732 smb_node_release(dnode); 733 SMB_NULL_FQI_NODES(op->fqi); 734 smbsr_errno(sr, rc); 735 /* NOTREACHED */ 736 } else { 737 op->fqi.last_attr = node->attr; 738 } 739 } 740 741 } else { 742 op->dattr |= SMB_FA_DIRECTORY; 743 new_attr.sa_vattr.va_type = VDIR; 744 new_attr.sa_vattr.va_mode = 0777; 745 new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE; 746 rc = smb_fsop_mkdir(sr, sr->user_cr, dnode, 747 op->fqi.last_comp, &new_attr, 748 &op->fqi.last_snode, &op->fqi.last_attr); 749 if (rc != 0) { 750 smb_rwx_rwexit(&dnode->n_lock); 751 smb_node_release(dnode); 752 SMB_NULL_FQI_NODES(op->fqi); 753 smbsr_errno(sr, rc); 754 /* NOTREACHED */ 755 } 756 757 node = op->fqi.last_snode; 758 rw_enter(&node->n_share_lock, RW_WRITER); 759 } 760 761 created = 1; 762 op->action_taken = SMB_OACT_CREATED; 763 } 764 765 if ((op->fqi.last_attr.sa_vattr.va_type != VREG) && 766 (op->fqi.last_attr.sa_vattr.va_type != VDIR) && 767 (op->fqi.last_attr.sa_vattr.va_type != VLNK)) { 768 /* not allowed to do this */ 769 770 smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); 771 772 SMB_DEL_NEWOBJ(op->fqi); 773 rw_exit(&node->n_share_lock); 774 smb_node_release(node); 775 if (created) 776 smb_rwx_rwexit(&dnode->n_lock); 777 smb_node_release(dnode); 778 SMB_NULL_FQI_NODES(op->fqi); 779 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 780 /* NOTREACHED */ 781 } 782 783 if (max_requested) { 784 smb_fsop_eaccess(sr, sr->user_cr, node, &max_allowed); 785 op->desired_access |= max_allowed; 786 } 787 788 /* 789 * smb_ofile_open() will copy node to of->node. Hence 790 * the hold on node (i.e. op->fqi.last_snode) will be "transferred" 791 * to the "of" structure. 792 */ 793 794 of = smb_ofile_open(sr->tid_tree, node, sr->smb_pid, op->desired_access, 795 op->create_options, share_access, SMB_FTYPE_DISK, NULL, 0, 796 uniq_fid, &err); 797 798 if (of == NULL) { 799 smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); 800 801 SMB_DEL_NEWOBJ(op->fqi); 802 rw_exit(&node->n_share_lock); 803 smb_node_release(node); 804 if (created) 805 smb_rwx_rwexit(&dnode->n_lock); 806 smb_node_release(dnode); 807 SMB_NULL_FQI_NODES(op->fqi); 808 smbsr_error(sr, err.status, err.errcls, err.errcode); 809 /* NOTREACHED */ 810 } 811 812 /* 813 * Propagate the write-through mode from the open params 814 * to the node: see the notes in the function header. 815 * 816 * IR #102318 Mirroring may force synchronous 817 * writes regardless of what we specify here. 818 */ 819 if (smb_stable_mode || (op->create_options & FILE_WRITE_THROUGH)) 820 node->flags |= NODE_FLAGS_WRITE_THROUGH; 821 822 op->fileid = op->fqi.last_attr.sa_vattr.va_nodeid; 823 824 if (op->fqi.last_attr.sa_vattr.va_type == VDIR) { 825 /* We don't oplock directories */ 826 op->my_flags &= ~MYF_OPLOCK_MASK; 827 op->dsize = 0; 828 } else { 829 status = smb_acquire_oplock(sr, of, op->my_flags, 830 &granted_oplock); 831 op->my_flags &= ~MYF_OPLOCK_MASK; 832 833 if (status != NT_STATUS_SUCCESS) { 834 rw_exit(&node->n_share_lock); 835 /* 836 * smb_fsop_unshrlock() and smb_fsop_close() 837 * are called from smb_ofile_close() 838 */ 839 (void) smb_ofile_close(of, 0); 840 smb_ofile_release(of); 841 if (created) 842 smb_rwx_rwexit(&dnode->n_lock); 843 844 smb_node_release(dnode); 845 SMB_NULL_FQI_NODES(op->fqi); 846 847 smbsr_error(sr, status, 848 ERRDOS, ERROR_SHARING_VIOLATION); 849 /* NOTREACHED */ 850 } 851 852 op->my_flags |= granted_oplock; 853 op->dsize = op->fqi.last_attr.sa_vattr.va_size; 854 } 855 856 if (created) { 857 node->flags |= NODE_FLAGS_CREATED; 858 /* 859 * Clients may set the DOS readonly bit on create but they 860 * expect subsequent write operations on the open fid to 861 * succeed. Thus the DOS readonly bit is not set permanently 862 * until the file is closed. The NODE_CREATED_READONLY flag 863 * will act as the indicator to set the DOS readonly bit on 864 * close. 865 * Above, the readonly bit is set on create, share 866 * reservations are set, and then the bit is unset. 867 * These actions allow writes to the open fid to succeed 868 * until the file is closed while preventing write access 869 * from other opens while this fid is active. 870 */ 871 if (op->dattr & SMB_FA_READONLY) { 872 node->flags |= NODE_CREATED_READONLY; 873 op->dattr &= ~SMB_FA_READONLY; 874 } 875 smb_node_set_dosattr(node, op->dattr | SMB_FA_ARCHIVE); 876 if (op->utime.tv_sec == 0 || op->utime.tv_sec == UINT_MAX) 877 (void) microtime(&op->utime); 878 smb_node_set_time(node, NULL, &op->utime, 0, 0, SMB_AT_MTIME); 879 (void) smb_sync_fsattr(sr, sr->user_cr, node); 880 } else { 881 /* 882 * If we reach here, it means that file already exists 883 * and if create disposition is one of: FILE_SUPERSEDE, 884 * FILE_OVERWRITE_IF, or FILE_OVERWRITE it 885 * means that client wants to overwrite (or truncate) 886 * the existing file. So we should overwrite the dos 887 * attributes of destination file with the dos attributes 888 * of source file. 889 */ 890 891 switch (op->create_disposition) { 892 case FILE_SUPERSEDE: 893 case FILE_OVERWRITE_IF: 894 case FILE_OVERWRITE: 895 smb_node_set_dosattr(node, 896 op->dattr | SMB_FA_ARCHIVE); 897 (void) smb_sync_fsattr(sr, sr->user_cr, node); 898 } 899 op->utime = *smb_node_get_crtime(node); 900 op->dattr = smb_node_get_dosattr(node); 901 } 902 903 /* 904 * Set up the file type in open_param for the response 905 */ 906 op->ftype = SMB_FTYPE_DISK; 907 sr->smb_fid = of->f_fid; 908 sr->fid_ofile = of; 909 910 rw_exit(&node->n_share_lock); 911 912 if (created) 913 smb_rwx_rwexit(&dnode->n_lock); 914 915 smb_node_release(dnode); 916 SMB_NULL_FQI_NODES(op->fqi); 917 918 return (NT_STATUS_SUCCESS); 919 } 920 921 /* 922 * smb_validate_object_name 923 * 924 * Very basic file name validation. Directory validation is handed off 925 * to smb_validate_dirname. For filenames, we check for names of the 926 * form "AAAn:". Names that contain three characters, a single digit 927 * and a colon (:) are reserved as DOS device names, i.e. "COM1:". 928 * 929 * Returns NT status codes. 930 */ 931 uint32_t 932 smb_validate_object_name(char *path, unsigned int ftype) 933 { 934 char *filename; 935 936 if (path == 0) 937 return (0); 938 939 if (ftype) 940 return (smb_validate_dirname(path)); 941 942 /* 943 * Basename with backslashes. 944 */ 945 if ((filename = strrchr(path, '\\')) != 0) 946 ++filename; 947 else 948 filename = path; 949 950 if (strlen(filename) == 5 && 951 mts_isdigit(filename[3]) && 952 filename[4] == ':') { 953 return (NT_STATUS_OBJECT_NAME_INVALID); 954 } 955 956 return (0); 957 } 958 959 /* 960 * smb_preset_delete_on_close 961 * 962 * Set the DeleteOnClose flag on the smb file. When the file is closed, 963 * the flag will be transferred to the smb node, which will commit the 964 * delete operation and inhibit subsequent open requests. 965 * 966 * When DeleteOnClose is set on an smb_node, the common open code will 967 * reject subsequent open requests for the file. Observation of Windows 968 * 2000 indicates that subsequent opens should be allowed (assuming 969 * there would be no sharing violation) until the file is closed using 970 * the fid on which the DeleteOnClose was requested. 971 */ 972 void 973 smb_preset_delete_on_close(smb_ofile_t *file) 974 { 975 mutex_enter(&file->f_mutex); 976 file->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE; 977 mutex_exit(&file->f_mutex); 978 } 979