Ignore:
Timestamp:
Nov 24, 2016, 1:14:11 PM (9 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to version 4.4.3

File:
1 edited

Legend:

Unmodified
Added
Removed
  • vendor/current/source3/smbd/dosmode.c

    r860 r988  
    2222#include "system/filesys.h"
    2323#include "librpc/gen_ndr/ndr_xattr.h"
     24#include "librpc/gen_ndr/ioctl.h"
    2425#include "../libcli/security/security.h"
    2526#include "smbd/smbd.h"
     27#include "lib/param/loadparm.h"
     28
     29static 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
     34static 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}
    2672
    2773static uint32_t filter_mode_by_protocol(uint32_t mode)
     
    83129        }
    84130
    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;
    88133
    89134                DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
     
    91136                          inherit_from_dir));
    92137
    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",
    98142                                 smb_fname_str_dbg(smb_fname),
    99                                  inherit_from_dir, nt_errstr(status)));
     143                                 inherit_from_dir));
    100144                        return(0);
    101145                }
     
    131175
    132176                        /* Apply directory mask */
    133                         result &= lp_dir_mask(SNUM(conn));
     177                        result &= lp_directory_mask(SNUM(conn));
    134178                        /* Add in force bits */
    135                         result |= lp_force_dir_mode(SNUM(conn));
     179                        result |= lp_force_directory_mode(SNUM(conn));
    136180                }
    137181        } else {
     
    156200        }
    157201
    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
    160205        return(result);
    161206}
     
    165210****************************************************************************/
    166211
    167 static uint32 dos_mode_from_sbuf(connection_struct *conn,
     212static uint32_t dos_mode_from_sbuf(connection_struct *conn,
    168213                                 const struct smb_filename *smb_fname)
    169214{
     
    171216        enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
    172217
     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
    173224        if (ro_opts == MAP_READONLY_YES) {
    174225                /* Original Samba method - map inverse of user "w" bit. */
     
    197248        result |= set_link_read_only_flag(&smb_fname->st);
    198249
    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
    208252        return result;
    209253}
     
    216260static bool get_ea_dos_attribute(connection_struct *conn,
    217261                                 struct smb_filename *smb_fname,
    218                                  uint32 *pattr)
     262                                 uint32_t *pattr)
    219263{
    220264        struct xattr_DOSATTRIB dosattrib;
     
    236280                                   sizeof(attrstr));
    237281        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));
    250285                return False;
    251286        }
     
    277312                                struct timespec create_time =
    278313                                        nt_time_to_unix_timespec(
    279                                                 &dosattrib.info.info1.create_time);
     314                                                dosattrib.info.info1.create_time);
    280315
    281316                                update_stat_ex_create_time(&smb_fname->st,
     
    299334                                struct timespec create_time =
    300335                                        nt_time_to_unix_timespec(
    301                                                 &dosattrib.info.info3.create_time);
     336                                                dosattrib.info.info3.create_time);
    302337
    303338                                update_stat_ex_create_time(&smb_fname->st,
     
    322357        }
    323358        /* 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);
    335362
    336363        return True;
     
    344371static bool set_ea_dos_attribute(connection_struct *conn,
    345372                                 struct smb_filename *smb_fname,
    346                                  uint32 dosmode)
     373                                 uint32_t dosmode)
    347374{
    348375        struct xattr_DOSATTRIB dosattrib;
    349376        enum ndr_err_code ndr_err;
    350377        DATA_BLOB blob;
    351 
    352         if (!lp_store_dos_attributes(SNUM(conn))) {
    353                 return False;
    354         }
    355378
    356379        ZERO_STRUCT(dosattrib);
     
    361384                                        XATTR_DOSINFO_CREATE_TIME;
    362385        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(
    364387                                smb_fname->st.st_ex_btime);
    365388
     
    387410                             0) == -1) {
    388411                bool ret = false;
     412                bool need_close = false;
    389413                files_struct *fsp = NULL;
    390414
    391415                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));
    404419                        return false;
    405420                }
     
    413428                        return false;
    414429
     430                if (!can_write_to_file(conn, smb_fname)) {
     431                        return false;
     432                }
     433
    415434                /*
    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.
    419437                 */
    420438
    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))) {
    423443                        return false;
     444                }
     445
    424446                become_root();
    425447                if (SMB_VFS_FSETXATTR(fsp,
     
    429451                }
    430452                unbecome_root();
    431                 close_file(NULL, fsp, NORMAL_CLOSE);
     453                if (need_close) {
     454                        close_file(NULL, fsp, NORMAL_CLOSE);
     455                }
    432456                return ret;
    433457        }
     
    442466****************************************************************************/
    443467
    444 uint32 dos_mode_msdfs(connection_struct *conn,
     468uint32_t dos_mode_msdfs(connection_struct *conn,
    445469                      const struct smb_filename *smb_fname)
    446470{
    447         uint32 result = 0;
     471        uint32_t result = 0;
    448472
    449473        DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
     
    490514        result |= FILE_ATTRIBUTE_REPARSE_POINT;
    491515
    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);
    502517
    503518        return(result);
    504519}
    505520
    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 */
     524static 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
     549err_ctx_free:
     550        talloc_free(tmp_ctx);
     551err_out:
     552        return status;
     553}
    614554
    615555/****************************************************************************
     
    619559****************************************************************************/
    620560
    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;
     561uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
     562{
     563        uint32_t result = 0;
     564        bool offline;
    625565
    626566        DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
     
    647587        }
    648588
    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);
    657592        }
    658593
     
    660595        if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
    661596                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                }
    662606        }
    663607
     
    675619        result = filter_mode_by_protocol(result);
    676620
    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;
    689624}
    690625
     
    697632
    698633int 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)
    700635{
    701636        int mask=0;
     
    705640        uint32_t old_mode;
    706641        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        }
    707650
    708651        /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
     
    726669        old_mode = dos_mode(conn, smb_fname);
    727670
    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)));
    738686                        }
    739687                }
     
    745693        smb_fname->st.st_ex_btime = new_create_timespec;
    746694
    747 #ifdef HAVE_STAT_DOS_FLAGS
    748         {
    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 #endif
    764695        /* 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                }
    766704                if (!newfile) {
    767705                        notify_fname(conn, NOTIFY_ACTION_MODIFIED,
     
    774712
    775713        unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
     714
     715        /* preserve the file type bits */
     716        mask |= S_IFMT;
    776717
    777718        /* preserve the s bits */
     
    847788        */
    848789
    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) {
    863813                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;
    872822        }
    873823
     
    889839                        smb_fname_str_dbg(fsp->fsp_name),
    890840                        sparse,
    891                         lp_servicename(SNUM(conn))));
     841                        lp_servicename(talloc_tos(), SNUM(conn))));
    892842                return NT_STATUS_MEDIA_WRITE_PROTECTED;
    893843        }
    894844
    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) {
    897852                DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
    898853                        "access_mask[0x%08X] - access denied\n",
     
    901856                        fsp->access_mask));
    902857                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;
    903871        }
    904872
     
    10471015                                struct timespec create_time)
    10481016{
    1049         NTSTATUS status;
    1050         struct smb_filename *smb_fname = NULL;
     1017        struct smb_filename *smb_fname;
    10511018        uint32_t dosmode;
    10521019        int ret;
     
    10561023        }
    10571024
    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;
    10651030        }
    10661031
     
    11011066        return smb_fname->st.st_ex_mtime;
    11021067}
     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
     1076static 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.