Changeset 988 for vendor/current/source3/smbd/dosmode.c
- Timestamp:
- Nov 24, 2016, 1:14:11 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/source3/smbd/dosmode.c
r860 r988 22 22 #include "system/filesys.h" 23 23 #include "librpc/gen_ndr/ndr_xattr.h" 24 #include "librpc/gen_ndr/ioctl.h" 24 25 #include "../libcli/security/security.h" 25 26 #include "smbd/smbd.h" 27 #include "lib/param/loadparm.h" 28 29 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn, 30 struct smb_filename *smb_fname, 31 files_struct **ret_fsp, 32 bool *need_close); 33 34 static void dos_mode_debug_print(const char *func, uint32_t mode) 35 { 36 fstring modestr; 37 38 if (DEBUGLEVEL < DBGLVL_INFO) { 39 return; 40 } 41 42 modestr[0] = '\0'; 43 44 if (mode & FILE_ATTRIBUTE_HIDDEN) { 45 fstrcat(modestr, "h"); 46 } 47 if (mode & FILE_ATTRIBUTE_READONLY) { 48 fstrcat(modestr, "r"); 49 } 50 if (mode & FILE_ATTRIBUTE_SYSTEM) { 51 fstrcat(modestr, "s"); 52 } 53 if (mode & FILE_ATTRIBUTE_DIRECTORY) { 54 fstrcat(modestr, "d"); 55 } 56 if (mode & FILE_ATTRIBUTE_ARCHIVE) { 57 fstrcat(modestr, "a"); 58 } 59 if (mode & FILE_ATTRIBUTE_SPARSE) { 60 fstrcat(modestr, "[sparse]"); 61 } 62 if (mode & FILE_ATTRIBUTE_OFFLINE) { 63 fstrcat(modestr, "[offline]"); 64 } 65 if (mode & FILE_ATTRIBUTE_COMPRESSED) { 66 fstrcat(modestr, "[compressed]"); 67 } 68 69 DBG_INFO("%s returning (0x%x): \"%s\"\n", func, (unsigned)mode, 70 modestr); 71 } 26 72 27 73 static uint32_t filter_mode_by_protocol(uint32_t mode) … … 83 129 } 84 130 85 if ((inherit_from_dir != NULL) && lp_inherit_perms(SNUM(conn))) { 86 struct smb_filename *smb_fname_parent = NULL; 87 NTSTATUS status; 131 if ((inherit_from_dir != NULL) && lp_inherit_permissions(SNUM(conn))) { 132 struct smb_filename *smb_fname_parent; 88 133 89 134 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", … … 91 136 inherit_from_dir)); 92 137 93 status = create_synthetic_smb_fname(talloc_tos(), 94 inherit_from_dir, NULL, 95 NULL, &smb_fname_parent); 96 if (!NT_STATUS_IS_OK(status)) { 97 DEBUG(1,("unix_mode(%s) failed, [dir %s]: %s\n", 138 smb_fname_parent = synthetic_smb_fname( 139 talloc_tos(), inherit_from_dir, NULL, NULL); 140 if (smb_fname_parent == NULL) { 141 DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n", 98 142 smb_fname_str_dbg(smb_fname), 99 inherit_from_dir , nt_errstr(status)));143 inherit_from_dir)); 100 144 return(0); 101 145 } … … 131 175 132 176 /* Apply directory mask */ 133 result &= lp_dir _mask(SNUM(conn));177 result &= lp_directory_mask(SNUM(conn)); 134 178 /* Add in force bits */ 135 result |= lp_force_dir _mode(SNUM(conn));179 result |= lp_force_directory_mode(SNUM(conn)); 136 180 } 137 181 } else { … … 156 200 } 157 201 158 DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname), 159 (int)result)); 202 DBG_INFO("unix_mode(%s) returning 0%o\n", 203 smb_fname_str_dbg(smb_fname), (int)result); 204 160 205 return(result); 161 206 } … … 165 210 ****************************************************************************/ 166 211 167 static uint32 dos_mode_from_sbuf(connection_struct *conn,212 static uint32_t dos_mode_from_sbuf(connection_struct *conn, 168 213 const struct smb_filename *smb_fname) 169 214 { … … 171 216 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn)); 172 217 218 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE) 219 /* if we can find out if a file is immutable we should report it r/o */ 220 if (smb_fname->st.st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) { 221 result |= FILE_ATTRIBUTE_READONLY; 222 } 223 #endif 173 224 if (ro_opts == MAP_READONLY_YES) { 174 225 /* Original Samba method - map inverse of user "w" bit. */ … … 197 248 result |= set_link_read_only_flag(&smb_fname->st); 198 249 199 DEBUG(8,("dos_mode_from_sbuf returning ")); 200 201 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h")); 202 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r")); 203 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s")); 204 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d")); 205 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a")); 206 207 DEBUG(8,("\n")); 250 dos_mode_debug_print(__func__, result); 251 208 252 return result; 209 253 } … … 216 260 static bool get_ea_dos_attribute(connection_struct *conn, 217 261 struct smb_filename *smb_fname, 218 uint32 *pattr)262 uint32_t *pattr) 219 263 { 220 264 struct xattr_DOSATTRIB dosattrib; … … 236 280 sizeof(attrstr)); 237 281 if (sizeret == -1) { 238 if (errno == ENOSYS 239 #if defined(ENOTSUP) 240 || errno == ENOTSUP) { 241 #else 242 ) { 243 #endif 244 DEBUG(1,("get_ea_dos_attribute: Cannot get attribute " 245 "from EA on file %s: Error = %s\n", 246 smb_fname_str_dbg(smb_fname), 247 strerror(errno))); 248 set_store_dos_attributes(SNUM(conn), False); 249 } 282 DBG_INFO("Cannot get attribute " 283 "from EA on file %s: Error = %s\n", 284 smb_fname_str_dbg(smb_fname), strerror(errno)); 250 285 return False; 251 286 } … … 277 312 struct timespec create_time = 278 313 nt_time_to_unix_timespec( 279 &dosattrib.info.info1.create_time);314 dosattrib.info.info1.create_time); 280 315 281 316 update_stat_ex_create_time(&smb_fname->st, … … 299 334 struct timespec create_time = 300 335 nt_time_to_unix_timespec( 301 &dosattrib.info.info3.create_time);336 dosattrib.info.info3.create_time); 302 337 303 338 update_stat_ex_create_time(&smb_fname->st, … … 322 357 } 323 358 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */ 324 *pattr = (uint32)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE)); 325 326 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr)); 327 328 if (dosattr & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h")); 329 if (dosattr & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r")); 330 if (dosattr & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s")); 331 if (dosattr & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d")); 332 if (dosattr & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a")); 333 334 DEBUG(8,("\n")); 359 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE)); 360 361 dos_mode_debug_print(__func__, *pattr); 335 362 336 363 return True; … … 344 371 static bool set_ea_dos_attribute(connection_struct *conn, 345 372 struct smb_filename *smb_fname, 346 uint32 dosmode)373 uint32_t dosmode) 347 374 { 348 375 struct xattr_DOSATTRIB dosattrib; 349 376 enum ndr_err_code ndr_err; 350 377 DATA_BLOB blob; 351 352 if (!lp_store_dos_attributes(SNUM(conn))) {353 return False;354 }355 378 356 379 ZERO_STRUCT(dosattrib); … … 361 384 XATTR_DOSINFO_CREATE_TIME; 362 385 dosattrib.info.info3.attrib = dosmode; 363 unix_timespec_to_nt_time(&dosattrib.info.info3.create_time,386 dosattrib.info.info3.create_time = unix_timespec_to_nt_time( 364 387 smb_fname->st.st_ex_btime); 365 388 … … 387 410 0) == -1) { 388 411 bool ret = false; 412 bool need_close = false; 389 413 files_struct *fsp = NULL; 390 414 391 415 if((errno != EPERM) && (errno != EACCES)) { 392 if (errno == ENOSYS 393 #if defined(ENOTSUP) 394 || errno == ENOTSUP) { 395 #else 396 ) { 397 #endif 398 DEBUG(1,("set_ea_dos_attributes: Cannot set " 399 "attribute EA on file %s: Error = %s\n", 400 smb_fname_str_dbg(smb_fname), 401 strerror(errno) )); 402 set_store_dos_attributes(SNUM(conn), False); 403 } 416 DBG_INFO("Cannot set " 417 "attribute EA on file %s: Error = %s\n", 418 smb_fname_str_dbg(smb_fname), strerror(errno)); 404 419 return false; 405 420 } … … 413 428 return false; 414 429 430 if (!can_write_to_file(conn, smb_fname)) { 431 return false; 432 } 433 415 434 /* 416 * We need to open the file with write access whilst 417 * still in our current user context. This ensures we 418 * are not violating security in doing the setxattr. 435 * We need to get an open file handle to do the 436 * metadata operation under root. 419 437 */ 420 438 421 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname, 422 &fsp))) 439 if (!NT_STATUS_IS_OK(get_file_handle_for_metadata(conn, 440 smb_fname, 441 &fsp, 442 &need_close))) { 423 443 return false; 444 } 445 424 446 become_root(); 425 447 if (SMB_VFS_FSETXATTR(fsp, … … 429 451 } 430 452 unbecome_root(); 431 close_file(NULL, fsp, NORMAL_CLOSE); 453 if (need_close) { 454 close_file(NULL, fsp, NORMAL_CLOSE); 455 } 432 456 return ret; 433 457 } … … 442 466 ****************************************************************************/ 443 467 444 uint32 dos_mode_msdfs(connection_struct *conn,468 uint32_t dos_mode_msdfs(connection_struct *conn, 445 469 const struct smb_filename *smb_fname) 446 470 { 447 uint32 result = 0;471 uint32_t result = 0; 448 472 449 473 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname))); … … 490 514 result |= FILE_ATTRIBUTE_REPARSE_POINT; 491 515 492 DEBUG(8,("dos_mode_msdfs returning ")); 493 494 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h")); 495 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r")); 496 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s")); 497 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d")); 498 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a")); 499 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]")); 500 501 DEBUG(8,("\n")); 516 dos_mode_debug_print(__func__, result); 502 517 503 518 return(result); 504 519 } 505 520 506 #ifdef HAVE_STAT_DOS_FLAGS 507 /**************************************************************************** 508 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*) 509 ****************************************************************************/ 510 511 int dos_attributes_to_stat_dos_flags(uint32_t dosmode) 512 { 513 uint32_t dos_stat_flags = 0; 514 515 if (dosmode & FILE_ATTRIBUTE_ARCHIVE) 516 dos_stat_flags |= UF_DOS_ARCHIVE; 517 if (dosmode & FILE_ATTRIBUTE_HIDDEN) 518 dos_stat_flags |= UF_DOS_HIDDEN; 519 if (dosmode & FILE_ATTRIBUTE_READONLY) 520 dos_stat_flags |= UF_DOS_RO; 521 if (dosmode & FILE_ATTRIBUTE_SYSTEM) 522 dos_stat_flags |= UF_DOS_SYSTEM; 523 if (dosmode & FILE_ATTRIBUTE_NONINDEXED) 524 dos_stat_flags |= UF_DOS_NOINDEX; 525 526 return dos_stat_flags; 527 } 528 529 /**************************************************************************** 530 Gets DOS attributes, accessed via st_ex_flags in the stat struct. 531 ****************************************************************************/ 532 533 static bool get_stat_dos_flags(connection_struct *conn, 534 const struct smb_filename *smb_fname, 535 uint32_t *dosmode) 536 { 537 SMB_ASSERT(VALID_STAT(smb_fname->st)); 538 SMB_ASSERT(dosmode); 539 540 if (!lp_store_dos_attributes(SNUM(conn))) { 541 return false; 542 } 543 544 DEBUG(5, ("Getting stat dos attributes for %s.\n", 545 smb_fname_str_dbg(smb_fname))); 546 547 if (smb_fname->st.st_ex_flags & UF_DOS_ARCHIVE) 548 *dosmode |= FILE_ATTRIBUTE_ARCHIVE; 549 if (smb_fname->st.st_ex_flags & UF_DOS_HIDDEN) 550 *dosmode |= FILE_ATTRIBUTE_HIDDEN; 551 if (smb_fname->st.st_ex_flags & UF_DOS_RO) 552 *dosmode |= FILE_ATTRIBUTE_READONLY; 553 if (smb_fname->st.st_ex_flags & UF_DOS_SYSTEM) 554 *dosmode |= FILE_ATTRIBUTE_SYSTEM; 555 if (smb_fname->st.st_ex_flags & UF_DOS_NOINDEX) 556 *dosmode |= FILE_ATTRIBUTE_NONINDEXED; 557 if (smb_fname->st.st_ex_flags & FILE_ATTRIBUTE_SPARSE) 558 *dosmode |= FILE_ATTRIBUTE_SPARSE; 559 if (S_ISDIR(smb_fname->st.st_ex_mode)) 560 *dosmode |= FILE_ATTRIBUTE_DIRECTORY; 561 562 *dosmode |= set_link_read_only_flag(&smb_fname->st); 563 564 return true; 565 } 566 567 /**************************************************************************** 568 Sets DOS attributes, stored in st_ex_flags of the inode. 569 ****************************************************************************/ 570 571 static bool set_stat_dos_flags(connection_struct *conn, 572 const struct smb_filename *smb_fname, 573 uint32_t dosmode, 574 bool *attributes_changed) 575 { 576 uint32_t new_flags = 0; 577 int error = 0; 578 579 SMB_ASSERT(VALID_STAT(smb_fname->st)); 580 SMB_ASSERT(attributes_changed); 581 582 *attributes_changed = false; 583 584 if (!lp_store_dos_attributes(SNUM(conn))) { 585 return false; 586 } 587 588 DEBUG(5, ("Setting stat dos attributes for %s.\n", 589 smb_fname_str_dbg(smb_fname))); 590 591 new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) | 592 dos_attributes_to_stat_dos_flags(dosmode); 593 594 /* Return early if no flags changed. */ 595 if (new_flags == smb_fname->st.st_ex_flags) 596 return true; 597 598 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags, 599 smb_fname->st.st_ex_flags)); 600 601 /* Set new flags with chflags. */ 602 error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags); 603 if (error) { 604 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on " 605 "file %s! errno=%d\n", new_flags, 606 smb_fname_str_dbg(smb_fname), errno)); 607 return false; 608 } 609 610 *attributes_changed = true; 611 return true; 612 } 613 #endif /* HAVE_STAT_DOS_FLAGS */ 521 /* 522 * check whether a file or directory is flagged as compressed. 523 */ 524 static NTSTATUS dos_mode_check_compressed(connection_struct *conn, 525 struct smb_filename *smb_fname, 526 bool *is_compressed) 527 { 528 NTSTATUS status; 529 uint16_t compression_fmt; 530 TALLOC_CTX *tmp_ctx = talloc_new(NULL); 531 if (tmp_ctx == NULL) { 532 status = NT_STATUS_NO_MEMORY; 533 goto err_out; 534 } 535 536 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname, 537 &compression_fmt); 538 if (!NT_STATUS_IS_OK(status)) { 539 goto err_ctx_free; 540 } 541 542 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) { 543 *is_compressed = true; 544 } else { 545 *is_compressed = false; 546 } 547 status = NT_STATUS_OK; 548 549 err_ctx_free: 550 talloc_free(tmp_ctx); 551 err_out: 552 return status; 553 } 614 554 615 555 /**************************************************************************** … … 619 559 ****************************************************************************/ 620 560 621 uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname)622 { 623 uint32 result = 0;624 bool offline , used_stat_dos_flags = false;561 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname) 562 { 563 uint32_t result = 0; 564 bool offline; 625 565 626 566 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname))); … … 647 587 } 648 588 649 #ifdef HAVE_STAT_DOS_FLAGS 650 used_stat_dos_flags = get_stat_dos_flags(conn, smb_fname, &result); 651 #endif 652 if (!used_stat_dos_flags) { 653 /* Get the DOS attributes from an EA by preference. */ 654 if (!get_ea_dos_attribute(conn, smb_fname, &result)) { 655 result |= dos_mode_from_sbuf(conn, smb_fname); 656 } 589 /* Get the DOS attributes from an EA by preference. */ 590 if (!get_ea_dos_attribute(conn, smb_fname, &result)) { 591 result |= dos_mode_from_sbuf(conn, smb_fname); 657 592 } 658 593 … … 660 595 if (S_ISREG(smb_fname->st.st_ex_mode) && offline) { 661 596 result |= FILE_ATTRIBUTE_OFFLINE; 597 } 598 599 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) { 600 bool compressed = false; 601 NTSTATUS status = dos_mode_check_compressed(conn, smb_fname, 602 &compressed); 603 if (NT_STATUS_IS_OK(status) && compressed) { 604 result |= FILE_ATTRIBUTE_COMPRESSED; 605 } 662 606 } 663 607 … … 675 619 result = filter_mode_by_protocol(result); 676 620 677 DEBUG(8,("dos_mode returning ")); 678 679 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h")); 680 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r")); 681 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s")); 682 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d")); 683 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a")); 684 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]")); 685 686 DEBUG(8,("\n")); 687 688 return(result); 621 dos_mode_debug_print(__func__, result); 622 623 return result; 689 624 } 690 625 … … 697 632 698 633 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, 699 uint32 dosmode, const char *parent_dir, bool newfile)634 uint32_t dosmode, const char *parent_dir, bool newfile) 700 635 { 701 636 int mask=0; … … 705 640 uint32_t old_mode; 706 641 struct timespec new_create_timespec; 642 files_struct *fsp = NULL; 643 bool need_close = false; 644 NTSTATUS status; 645 646 if (!CAN_WRITE(conn)) { 647 errno = EROFS; 648 return -1; 649 } 707 650 708 651 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */ … … 726 669 old_mode = dos_mode(conn, smb_fname); 727 670 728 if (dosmode & FILE_ATTRIBUTE_OFFLINE) { 729 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) { 730 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname); 731 if (lret == -1) { 732 DEBUG(0, ("set_dos_mode: client has asked to " 733 "set FILE_ATTRIBUTE_OFFLINE to " 734 "%s/%s but there was an error while " 735 "setting it or it is not " 736 "supported.\n", parent_dir, 737 smb_fname_str_dbg(smb_fname))); 671 if ((dosmode & FILE_ATTRIBUTE_OFFLINE) && 672 !(old_mode & FILE_ATTRIBUTE_OFFLINE)) { 673 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname); 674 if (lret == -1) { 675 if (errno == ENOTSUP) { 676 DEBUG(10, ("Setting FILE_ATTRIBUTE_OFFLINE for " 677 "%s/%s is not supported.\n", 678 parent_dir, 679 smb_fname_str_dbg(smb_fname))); 680 } else { 681 DEBUG(0, ("An error occurred while setting " 682 "FILE_ATTRIBUTE_OFFLINE for " 683 "%s/%s: %s", parent_dir, 684 smb_fname_str_dbg(smb_fname), 685 strerror(errno))); 738 686 } 739 687 } … … 745 693 smb_fname->st.st_ex_btime = new_create_timespec; 746 694 747 #ifdef HAVE_STAT_DOS_FLAGS748 {749 bool attributes_changed;750 751 if (set_stat_dos_flags(conn, smb_fname, dosmode,752 &attributes_changed))753 {754 if (!newfile && attributes_changed) {755 notify_fname(conn, NOTIFY_ACTION_MODIFIED,756 FILE_NOTIFY_CHANGE_ATTRIBUTES,757 smb_fname->base_name);758 }759 smb_fname->st.st_ex_mode = unixmode;760 return 0;761 }762 }763 #endif764 695 /* Store the DOS attributes in an EA by preference. */ 765 if (set_ea_dos_attribute(conn, smb_fname, dosmode)) { 696 if (lp_store_dos_attributes(SNUM(conn))) { 697 /* 698 * Don't fall back to using UNIX modes. Finally 699 * follow the smb.conf manpage. 700 */ 701 if (!set_ea_dos_attribute(conn, smb_fname, dosmode)) { 702 return -1; 703 } 766 704 if (!newfile) { 767 705 notify_fname(conn, NOTIFY_ACTION_MODIFIED, … … 774 712 775 713 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir); 714 715 /* preserve the file type bits */ 716 mask |= S_IFMT; 776 717 777 718 /* preserve the s bits */ … … 847 788 */ 848 789 849 /* Check if we have write access. */ 850 if (CAN_WRITE(conn)) { 851 /* 852 * We need to open the file with write access whilst 853 * still in our current user context. This ensures we 854 * are not violating security in doing the fchmod. 855 */ 856 files_struct *fsp; 857 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname, 858 &fsp))) 859 return -1; 860 become_root(); 861 ret = SMB_VFS_FCHMOD(fsp, unixmode); 862 unbecome_root(); 790 if (!can_write_to_file(conn, smb_fname)) { 791 errno = EACCES; 792 return -1; 793 } 794 795 /* 796 * We need to get an open file handle to do the 797 * metadata operation under root. 798 */ 799 800 status = get_file_handle_for_metadata(conn, 801 smb_fname, 802 &fsp, 803 &need_close); 804 if (!NT_STATUS_IS_OK(status)) { 805 errno = map_errno_from_nt_status(status); 806 return -1; 807 } 808 809 become_root(); 810 ret = SMB_VFS_FCHMOD(fsp, unixmode); 811 unbecome_root(); 812 if (need_close) { 863 813 close_file(NULL, fsp, NORMAL_CLOSE); 864 if (!newfile) {865 notify_fname(conn, NOTIFY_ACTION_MODIFIED,866 FILE_NOTIFY_CHANGE_ATTRIBUTES,867 smb_fname->base_name);868 }869 if (ret == 0) {870 smb_fname->st.st_ex_mode = unixmode;871 }814 } 815 if (!newfile) { 816 notify_fname(conn, NOTIFY_ACTION_MODIFIED, 817 FILE_NOTIFY_CHANGE_ATTRIBUTES, 818 smb_fname->base_name); 819 } 820 if (ret == 0) { 821 smb_fname->st.st_ex_mode = unixmode; 872 822 } 873 823 … … 889 839 smb_fname_str_dbg(fsp->fsp_name), 890 840 sparse, 891 lp_servicename( SNUM(conn))));841 lp_servicename(talloc_tos(), SNUM(conn)))); 892 842 return NT_STATUS_MEDIA_WRITE_PROTECTED; 893 843 } 894 844 895 if (!(fsp->access_mask & FILE_WRITE_DATA) && 896 !(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) { 845 /* 846 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the 847 * following access flags are granted. 848 */ 849 if ((fsp->access_mask & (FILE_WRITE_DATA 850 | FILE_WRITE_ATTRIBUTES 851 | SEC_FILE_APPEND_DATA)) == 0) { 897 852 DEBUG(9,("file_set_sparse: fname[%s] set[%u] " 898 853 "access_mask[0x%08X] - access denied\n", … … 901 856 fsp->access_mask)); 902 857 return NT_STATUS_ACCESS_DENIED; 858 } 859 860 if (fsp->is_directory) { 861 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n", 862 (sparse ? "set" : "clear"), 863 smb_fname_str_dbg(fsp->fsp_name))); 864 return NT_STATUS_INVALID_PARAMETER; 865 } 866 867 if (IS_IPC(conn) || IS_PRINT(conn)) { 868 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n", 869 (sparse ? "set" : "clear"))); 870 return NT_STATUS_INVALID_PARAMETER; 903 871 } 904 872 … … 1047 1015 struct timespec create_time) 1048 1016 { 1049 NTSTATUS status; 1050 struct smb_filename *smb_fname = NULL; 1017 struct smb_filename *smb_fname; 1051 1018 uint32_t dosmode; 1052 1019 int ret; … … 1056 1023 } 1057 1024 1058 status = create_synthetic_smb_fname(talloc_tos(), 1059 psmb_fname->base_name, 1060 NULL, &psmb_fname->st, 1061 &smb_fname); 1062 1063 if (!NT_STATUS_IS_OK(status)) { 1064 return status; 1025 smb_fname = synthetic_smb_fname(talloc_tos(), psmb_fname->base_name, 1026 NULL, &psmb_fname->st); 1027 1028 if (smb_fname == NULL) { 1029 return NT_STATUS_NO_MEMORY; 1065 1030 } 1066 1031 … … 1101 1066 return smb_fname->st.st_ex_mtime; 1102 1067 } 1068 1069 /**************************************************************************** 1070 Get a real open file handle we can do meta-data operations on. As it's 1071 going to be used under root access only on meta-data we should look for 1072 any existing open file handle first, and use that in preference (also to 1073 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle. 1074 ****************************************************************************/ 1075 1076 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn, 1077 struct smb_filename *smb_fname, 1078 files_struct **ret_fsp, 1079 bool *need_close) 1080 { 1081 NTSTATUS status; 1082 files_struct *fsp; 1083 struct file_id file_id; 1084 1085 *need_close = false; 1086 1087 if (!VALID_STAT(smb_fname->st)) { 1088 return NT_STATUS_INVALID_PARAMETER; 1089 } 1090 1091 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st); 1092 1093 for(fsp = file_find_di_first(conn->sconn, file_id); 1094 fsp; 1095 fsp = file_find_di_next(fsp)) { 1096 if (fsp->fh->fd != -1) { 1097 *ret_fsp = fsp; 1098 return NT_STATUS_OK; 1099 } 1100 } 1101 1102 /* Opens an INTERNAL_OPEN_ONLY write handle. */ 1103 status = SMB_VFS_CREATE_FILE( 1104 conn, /* conn */ 1105 NULL, /* req */ 1106 0, /* root_dir_fid */ 1107 smb_fname, /* fname */ 1108 FILE_WRITE_DATA, /* access_mask */ 1109 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ 1110 FILE_SHARE_DELETE), 1111 FILE_OPEN, /* create_disposition*/ 1112 0, /* create_options */ 1113 0, /* file_attributes */ 1114 INTERNAL_OPEN_ONLY, /* oplock_request */ 1115 NULL, /* lease */ 1116 0, /* allocation_size */ 1117 0, /* private_flags */ 1118 NULL, /* sd */ 1119 NULL, /* ea_list */ 1120 ret_fsp, /* result */ 1121 NULL, /* pinfo */ 1122 NULL, NULL); /* create context */ 1123 1124 if (NT_STATUS_IS_OK(status)) { 1125 *need_close = true; 1126 } 1127 return status; 1128 }
Note:
See TracChangeset
for help on using the changeset viewer.