The branch, master has been updated
       via  f14a7065690 smbd: move access override for previous versions to the 
SMB layer
       via  fd4e41144a8 smbd: check for previous versions in 
check_any_access_fsp()
       via  02ed99343d1 smbd: use check_any_access_fsp() for all access checks
       via  995a31c8d4c smbd: replace CHECK_WRITE() macro with calls to 
check_any_access_fsp()
       via  ee3035218df smbd: set fsp->fsp_flags.can_write to false for access 
to previous-versions
       via  a0ae45be770 smbd: return correct error when trying to create a 
hardlink to a VSS file
       via  bf497819e61 smbd: fix check_any_access_fsp() for non-fsa fsps
       via  96b577c380f smbd: rename check_access_fsp() to 
check_any_access_fsp()
       via  76c8fe16bff smbd: set fsp_flags.is_fsa to true on printer file 
handles
       via  276c5bd851a smbd: return the correct error in can_rename()
       via  537eedfe2a7 smbtorture: expand smb2.twrp.write test
       via  c62484bc2c6 s4/libcli/raw: implemement 
RAW_SFILEINFO_LINK_INFORMATION
       via  78119edba01 selftest: remove error_inject from shadow_write share
      from  1047abf3aa3 selftest: let list_servers.NT1 really use NT1 protocol

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit f14a7065690b00e3c6af2c1f0b0aec51c1e0b372
Author: Ralph Boehme <s...@samba.org>
Date:   Fri Dec 15 11:59:36 2023 +0100

    smbd: move access override for previous versions to the SMB layer
    
    Doing the previous version access checks and semantics at the SMB
    layer means we can simplify the shadow_copy2 and remove the kludge.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>
    
    Autobuild-User(master): Ralph Böhme <s...@samba.org>
    Autobuild-Date(master): Mon Jan  8 16:58:26 UTC 2024 on atb-devel-224

commit fd4e41144a819b4403340e4a28664ac586722b41
Author: Ralph Boehme <s...@samba.org>
Date:   Wed Dec 20 15:09:59 2023 +0100

    smbd: check for previous versions in check_any_access_fsp()
    
    Now that check_any_access_fsp() is broadly used consistently to
    restrict access for all modifying operations, we can add a check for
    previous versions to check_any_access_fsp() and it gets enforced
    consistently.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 02ed99343d19fd0845531ad99a46b1dd5b8a7a4f
Author: Ralph Boehme <s...@samba.org>
Date:   Wed Dec 20 18:01:57 2023 +0100

    smbd: use check_any_access_fsp() for all access checks
    
    Replaces the direct access to fsp->access_mask with a call to
    check_any_access_fsp() which allows doing additional checks if needed.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 995a31c8d4c1789c16bae6b8196f2565d4b1dfdb
Author: Ralph Boehme <s...@samba.org>
Date:   Wed Dec 20 18:32:25 2023 +0100

    smbd: replace CHECK_WRITE() macro with calls to check_any_access_fsp()
    
    The additional check if fd underlying fd is valid and not -1 should not be 
done
    at this place. I actually would prefer an write to fail with EBADF if this
    happens, as it's likely easier to debug why this happened. These days we 
should
    always have a valid fd.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit ee3035218df4cfd68b6aab6825c78f2b85234c6c
Author: Ralph Boehme <s...@samba.org>
Date:   Wed Dec 20 18:03:22 2023 +0100

    smbd: set fsp->fsp_flags.can_write to false for access to previous-versions
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit a0ae45be770a13373c148a689b9761f14c4f942c
Author: Ralph Boehme <s...@samba.org>
Date:   Fri Dec 22 11:19:38 2023 +0100

    smbd: return correct error when trying to create a hardlink to a VSS file
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit bf497819e61131cfa6469971596af3aa9bd4bb49
Author: Ralph Boehme <s...@samba.org>
Date:   Thu Dec 21 10:58:09 2023 +0100

    smbd: fix check_any_access_fsp() for non-fsa fsps
    
    smbd_check_access_rights_fsp() requires *all* rights in access_mask to
    be granted by the underlying ACL, but the semantics of this function
    is supposed to grant access if any one of the rights in
    access_requested is allowed.
    
    Fix this by looping over the requested access mask. If
    smbd_check_access_rights_fsp() returns sucess, mask will be non-null
    and when assigned to access_granted, the subsequent check will pass,
    fail otherwise.
    
    I'm not doing an early exit on purpose because a subsequent commit
    adds additional security checks that are done in the subsequent code
    path common for fsa and non-fsa fsps.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 96b577c380fa914eb1ffa95849c82bdb88aa1ec6
Author: Ralph Boehme <s...@samba.org>
Date:   Thu Dec 21 10:58:09 2023 +0100

    smbd: rename check_access_fsp() to check_any_access_fsp()
    
    The semantics of the access check in check_access_fsp() itself is to
    allow access if *at least* one or more rights of the rights in
    access_mask are allowed. The name check_any_access_fsp() better
    reflects this.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 76c8fe16bff36a29fa326355256b50737d04bd85
Author: Ralph Boehme <s...@samba.org>
Date:   Thu Dec 21 16:27:42 2023 +0100

    smbd: set fsp_flags.is_fsa to true on printer file handles
    
    Printer file handles went through SMB_VFS_CREATE_FILE() and are network
    callable, so it makes sense to set this on them.
    
    This ensures that check_access_fsp() doesn't take the codepath calling
    smbd_check_access_rights_fsp(), but just checks the request rights from
    fsp->access_mask.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 276c5bd851ab6ab818a49d9c47f6b96de8024778
Author: Ralph Boehme <s...@samba.org>
Date:   Tue Dec 19 13:06:55 2023 +0100

    smbd: return the correct error in can_rename()
    
    This is what Windows returns for this case.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 537eedfe2a79fba2e1f062f14ba7a0c5f8f70a88
Author: Ralph Boehme <s...@samba.org>
Date:   Fri Dec 15 19:55:23 2023 +0100

    smbtorture: expand smb2.twrp.write test
    
    Test more modifying operations are blocked and access masks are correct.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit c62484bc2c60ebac42635793d94cb8e62629acbf
Author: Ralph Boehme <s...@samba.org>
Date:   Fri Dec 22 10:40:39 2023 +0100

    s4/libcli/raw: implemement RAW_SFILEINFO_LINK_INFORMATION
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 78119edba013583555069271bb61134c12c2c135
Author: Ralph Boehme <s...@samba.org>
Date:   Thu Dec 21 19:40:21 2023 +0100

    selftest: remove error_inject from shadow_write share
    
    Frankly, I can't remember why I added this as part of bug 13688. The
    goal of the corresponding test is to verify a write on a read-only
    file handle fails. As the file is opened O_RDONLY, the write will fail
    anyway and there's no need to inject the error.
    
    To make things worse, having the error injected meant we didn't notice
    when the underlying logic of forcing the open to be done with O_RDONLY
    was done as O_RDWR, resulting in the write on the handle to succeed.
    
    This happened when we introduced reopen_from_fsp(): the initial
    pathref open of a path with a twrp value was correctly detected and
    handled by shadow_copy2_openat(). However, when converting the pathref
    open to a real one via reopen_from_fsp(), shadow_copy2_openat() only
    sees the magic /proc/fd path and has no way of inferring that this was
    originating from a prevous version open with a twrp value.
    
    Tl;dr: we can just remove this error injection, it is not needed, the
    correct fix is to implement this in the SMB layer which is done in the
    subsequent commits.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688
    
    Signed-off-by: Ralph Boehme <s...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

-----------------------------------------------------------------------

Summary of changes:
 selftest/target/Samba3.pm           |   4 +-
 source3/include/smb_macros.h        |   5 -
 source3/modules/offload_token.c     |   7 +-
 source3/modules/vfs_acl_common.c    |   7 +-
 source3/modules/vfs_nfs4acl_xattr.c |   7 +-
 source3/modules/vfs_shadow_copy2.c  |  30 +----
 source3/printing/printspoolss.c     |   1 +
 source3/smbd/dir.c                  |   5 +-
 source3/smbd/dosmode.c              |  20 +--
 source3/smbd/file_access.c          |  10 +-
 source3/smbd/files.c                |   3 +
 source3/smbd/notify.c               |   5 +-
 source3/smbd/open.c                 |  43 ++++++-
 source3/smbd/proto.h                |   4 +-
 source3/smbd/smb1_reply.c           |  37 +++---
 source3/smbd/smb2_flush.c           |   7 +-
 source3/smbd/smb2_getinfo.c         |   8 +-
 source3/smbd/smb2_ioctl_filesys.c   |   6 +-
 source3/smbd/smb2_nttrans.c         |  45 ++++---
 source3/smbd/smb2_reply.c           |  15 ++-
 source3/smbd/smb2_trans2.c          |  80 +++++++++---
 source3/smbd/smb2_write.c           |   6 +-
 source4/libcli/raw/rawsetfileinfo.c |  14 +++
 source4/torture/smb2/create.c       | 245 +++++++++++++++++++++++++++++++++++-
 24 files changed, 489 insertions(+), 125 deletions(-)


Changeset truncated at 500 lines:

diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 0375e913a9d..bfa9fad5ffe 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -3447,9 +3447,7 @@ sub provision($$)
 [shadow_write]
        path = $shadow_tstdir
        comment = previous versions snapshots under mount point
-       vfs objects = shadow_copy2 streams_xattr error_inject
-       aio write size = 0
-       error_inject:pwrite = EBADF
+       vfs objects = shadow_copy2 streams_xattr
        shadow:mountpoint = $shadow_tstdir
        shadow:fixinodes = yes
        smbd async dosmode = yes
diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h
index 3a942f9df11..4b3989dce93 100644
--- a/source3/include/smb_macros.h
+++ b/source3/include/smb_macros.h
@@ -67,11 +67,6 @@
         (fsp_get_io_fd(fsp) != -1) && \
         (((fsp)->fsp_flags.can_read)))
 
-#define CHECK_WRITE(fsp) \
-       ((fsp)->fsp_flags.can_write && \
-       (!(fsp)->fsp_flags.is_pathref) && \
-        (fsp_get_io_fd(fsp) != -1))
-
 #define ERROR_WAS_LOCK_DENIED(status) (NT_STATUS_EQUAL((status), 
NT_STATUS_LOCK_NOT_GRANTED) || \
                                NT_STATUS_EQUAL((status), 
NT_STATUS_FILE_LOCK_CONFLICT) )
 
diff --git a/source3/modules/offload_token.c b/source3/modules/offload_token.c
index 901991daf28..3b71a0028fb 100644
--- a/source3/modules/offload_token.c
+++ b/source3/modules/offload_token.c
@@ -259,6 +259,8 @@ NTSTATUS vfs_offload_token_check_handles(uint32_t fsctl,
                                         files_struct *src_fsp,
                                         files_struct *dst_fsp)
 {
+       NTSTATUS status;
+
        if (src_fsp->vuid != dst_fsp->vuid) {
                DBG_INFO("copy chunk handles not in the same session.\n");
                return NT_STATUS_ACCESS_DENIED;
@@ -317,10 +319,11 @@ NTSTATUS vfs_offload_token_check_handles(uint32_t fsctl,
         *
         * A non writable dst handle also doesn't make sense for other fsctls.
         */
-       if (!CHECK_WRITE(dst_fsp)) {
+       status = check_any_access_fsp(dst_fsp, 
FILE_WRITE_DATA|FILE_APPEND_DATA);
+       if (!NT_STATUS_IS_OK(status)) {
                DBG_INFO("dest handle not writable (%s).\n",
                        smb_fname_str_dbg(dst_fsp->fsp_name));
-               return NT_STATUS_ACCESS_DENIED;
+               return status;
        }
        /*
         * - The Open.GrantedAccess of the destination file does not include
diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c
index 692e776d10c..314fc79a3a6 100644
--- a/source3/modules/vfs_acl_common.c
+++ b/source3/modules/vfs_acl_common.c
@@ -738,10 +738,13 @@ static NTSTATUS set_underlying_acl(vfs_handle_struct 
*handle, files_struct *fsp,
        /* We got access denied here. If we're already root,
           or we didn't need to do a chown, or the fsp isn't
           open with WRITE_OWNER access, just return. */
-       if (get_current_uid(handle->conn) == 0 || !chown_needed ||
-           !(fsp->access_mask & SEC_STD_WRITE_OWNER)) {
+       if (get_current_uid(handle->conn) == 0 || !chown_needed) {
                return NT_STATUS_ACCESS_DENIED;
        }
+       status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
        /*
         * Only allow take-ownership, not give-ownership. That's the way Windows
diff --git a/source3/modules/vfs_nfs4acl_xattr.c 
b/source3/modules/vfs_nfs4acl_xattr.c
index cecafcf50b8..1fd3519ca02 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -368,11 +368,14 @@ static NTSTATUS 
nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
        }
 
        if (get_current_uid(handle->conn) == 0 ||
-           chown_needed == false ||
-           !(fsp->access_mask & SEC_STD_WRITE_OWNER))
+           chown_needed == false)
        {
                return NT_STATUS_ACCESS_DENIED;
        }
+       status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
        /*
         * Only allow take-ownership, not give-ownership. That's the way Windows
diff --git a/source3/modules/vfs_shadow_copy2.c 
b/source3/modules/vfs_shadow_copy2.c
index ac87ddac46f..47b0edc72c3 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -1556,7 +1556,6 @@ static int shadow_copy2_openat(vfs_handle_struct *handle,
        struct smb_filename *smb_fname = NULL;
        time_t timestamp = 0;
        char *stripped = NULL;
-       bool is_converted = false;
        int saved_errno = 0;
        int ret;
        bool ok;
@@ -1573,12 +1572,11 @@ static int shadow_copy2_openat(vfs_handle_struct 
*handle,
                return -1;
        }
 
-       ok = shadow_copy2_strip_snapshot_converted(talloc_tos(),
-                                                  handle,
-                                                  smb_fname,
-                                                  &timestamp,
-                                                  &stripped,
-                                                  &is_converted);
+       ok = shadow_copy2_strip_snapshot(talloc_tos(),
+                                        handle,
+                                        smb_fname,
+                                        &timestamp,
+                                        &stripped);
        if (!ok) {
                TALLOC_FREE(smb_fname);
                return -1;
@@ -1586,16 +1584,6 @@ static int shadow_copy2_openat(vfs_handle_struct *handle,
        if (timestamp == 0) {
                TALLOC_FREE(stripped);
                TALLOC_FREE(smb_fname);
-               if (is_converted) {
-                       /*
-                        * Just pave over the user requested mode and use
-                        * O_RDONLY. Later attempts by the client to write on
-                        * the handle will fail in the pwrite() syscall with
-                        * EINVAL which we carefully map to EROFS. In sum, this
-                        * matches Windows behaviour.
-                        */
-                       how.flags &= ~(O_WRONLY | O_RDWR | O_CREAT);
-               }
                return SMB_VFS_NEXT_OPENAT(handle,
                                           dirfsp,
                                           smb_fname_in,
@@ -1616,14 +1604,6 @@ static int shadow_copy2_openat(vfs_handle_struct *handle,
        }
        TALLOC_FREE(stripped);
 
-       /*
-        * Just pave over the user requested mode and use O_RDONLY. Later
-        * attempts by the client to write on the handle will fail in the
-        * pwrite() syscall with EINVAL which we carefully map to EROFS. In sum,
-        * this matches Windows behaviour.
-        */
-       how.flags &= ~(O_WRONLY | O_RDWR | O_CREAT);
-
        ret = SMB_VFS_NEXT_OPENAT(handle,
                                  dirfsp,
                                  smb_fname,
diff --git a/source3/printing/printspoolss.c b/source3/printing/printspoolss.c
index 31117a4b743..94404f7682a 100644
--- a/source3/printing/printspoolss.c
+++ b/source3/printing/printspoolss.c
@@ -244,6 +244,7 @@ NTSTATUS print_spool_open(files_struct *fsp,
        fsp->sent_oplock_break = NO_BREAK_SENT;
        fsp->fsp_flags.is_directory = false;
        fsp->fsp_flags.delete_on_close = false;
+       fsp->fsp_flags.is_fsa = true;
 
        fsp->print_file = pf;
 
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
index 800b7221cfd..49c37cbb4d9 100644
--- a/source3/smbd/dir.c
+++ b/source3/smbd/dir.c
@@ -218,11 +218,12 @@ NTSTATUS dptr_create(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if (!(fsp->access_mask & SEC_DIR_LIST)) {
+       status = check_any_access_fsp(fsp, SEC_DIR_LIST);
+       if (!NT_STATUS_IS_OK(status)) {
                DBG_INFO("dptr_create: directory %s "
                        "not open for LIST access\n",
                        fsp_str_dbg(fsp));
-               return NT_STATUS_ACCESS_DENIED;
+               return status;
        }
        status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd);
        if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index 6fbcac40d2e..1472af7d059 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -1076,15 +1076,17 @@ NTSTATUS file_set_sparse(connection_struct *conn,
         * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
         * following access flags are granted.
         */
-       if ((fsp->access_mask & (FILE_WRITE_DATA
-                               | FILE_WRITE_ATTRIBUTES
-                               | SEC_FILE_APPEND_DATA)) == 0) {
-               DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
-                       "access_mask[0x%08X] - access denied\n",
-                       smb_fname_str_dbg(fsp->fsp_name),
-                       sparse,
-                       fsp->access_mask));
-               return NT_STATUS_ACCESS_DENIED;
+       status = check_any_access_fsp(fsp,
+                                 FILE_WRITE_DATA
+                                 | FILE_WRITE_ATTRIBUTES
+                                 | SEC_FILE_APPEND_DATA);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_DEBUG("fname[%s] set[%u] "
+                         "access_mask[0x%08X] - access denied\n",
+                         smb_fname_str_dbg(fsp->fsp_name),
+                         sparse,
+                         fsp->access_mask);
+               return status;
        }
 
        if (fsp->fsp_flags.is_directory) {
diff --git a/source3/smbd/file_access.c b/source3/smbd/file_access.c
index 9ad9173e49c..9928eb99750 100644
--- a/source3/smbd/file_access.c
+++ b/source3/smbd/file_access.c
@@ -192,6 +192,7 @@ bool directory_has_default_acl_fsp(struct files_struct *fsp)
 
 NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32_t dosmode)
 {
+       NTSTATUS status;
        /*
         * Only allow delete on close for writable files.
         */
@@ -220,11 +221,12 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, 
uint32_t dosmode)
         * intent.
         */
 
-       if (!(fsp->access_mask & DELETE_ACCESS)) {
-               DEBUG(10,("can_set_delete_on_close: file %s delete on "
+       status = check_any_access_fsp(fsp, DELETE_ACCESS);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_DEBUG("file %s delete on "
                          "close flag set but delete access denied.\n",
-                         fsp_str_dbg(fsp)));
-               return NT_STATUS_ACCESS_DENIED;
+                         fsp_str_dbg(fsp));
+               return status;
        }
 
        /* Don't allow delete on close for non-empty directories. */
diff --git a/source3/smbd/files.c b/source3/smbd/files.c
index 48b78dc32c0..6aad76a8a5c 100644
--- a/source3/smbd/files.c
+++ b/source3/smbd/files.c
@@ -2448,6 +2448,9 @@ NTSTATUS dup_file_fsp(
        to->fsp_flags.can_write =
                CAN_WRITE(from->conn) &&
                ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
+       if (from->fsp_name->twrp != 0) {
+               to->fsp_flags.can_write = false;
+       }
        to->fsp_flags.modified = from->fsp_flags.modified;
        to->fsp_flags.is_directory = from->fsp_flags.is_directory;
        to->fsp_flags.aio_write_behind = from->fsp_flags.aio_write_behind;
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index 399d7800249..156fbf700c3 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -295,8 +295,9 @@ NTSTATUS change_notify_create(struct files_struct *fsp,
         * Setting a changenotify needs READ/LIST access
         * on the directory handle.
         */
-       if (!(fsp->access_mask & SEC_DIR_LIST)) {
-               return NT_STATUS_ACCESS_DENIED;
+       status = check_any_access_fsp(fsp, SEC_DIR_LIST);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        if (fsp->notify != NULL) {
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index d34d0354ff7..da809196fa4 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1635,6 +1635,9 @@ static NTSTATUS open_file(
        fsp->fsp_flags.can_write =
                CAN_WRITE(conn) &&
                ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
+       if (fsp->fsp_name->twrp != 0) {
+               fsp->fsp_flags.can_write = false;
+       }
        fsp->print_file = NULL;
        fsp->fsp_flags.modified = false;
        fsp->sent_oplock_break = NO_BREAK_SENT;
@@ -3626,7 +3629,8 @@ static int disposition_to_open_flags(uint32_t 
create_disposition)
 }
 
 static int calculate_open_access_flags(uint32_t access_mask,
-                                      uint32_t private_flags)
+                                      uint32_t private_flags,
+                                      NTTIME twrp)
 {
        bool need_write, need_read;
 
@@ -3635,6 +3639,15 @@ static int calculate_open_access_flags(uint32_t 
access_mask,
         * mean the same thing under DOS and Unix.
         */
 
+       if (twrp != 0) {
+               /*
+                * Pave over the user requested mode and force O_RDONLY for the
+                * file handle. Windows allows opening a VSS file with O_RDWR,
+                * even though actual writes on the handle will fail.
+                */
+               return O_RDONLY;
+       }
+
        need_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA));
        if (!need_write) {
                return O_RDONLY;
@@ -3800,6 +3813,7 @@ static NTSTATUS open_file_ntcreate(connection_struct 
*conn,
        bool posix_open = False;
        bool new_file_created = False;
        bool first_open_attempt = true;
+       bool is_twrp = (smb_fname_atname->twrp != 0);
        NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED;
        mode_t new_unx_mode = (mode_t)0;
        mode_t unx_mode = (mode_t)0;
@@ -3959,6 +3973,9 @@ static NTSTATUS open_file_ntcreate(connection_struct 
*conn,
                                         smb_fname_str_dbg(smb_fname) ));
                                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
                        }
+                       if (is_twrp) {
+                               return NT_STATUS_MEDIA_WRITE_PROTECTED;
+                       }
                        break;
 
                case FILE_CREATE:
@@ -3974,11 +3991,24 @@ static NTSTATUS open_file_ntcreate(connection_struct 
*conn,
                                }
                                return NT_STATUS_OBJECT_NAME_COLLISION;
                        }
+                       if (is_twrp) {
+                               return NT_STATUS_MEDIA_WRITE_PROTECTED;
+                       }
                        break;
 
                case FILE_SUPERSEDE:
                case FILE_OVERWRITE_IF:
+                       if (is_twrp) {
+                               return NT_STATUS_MEDIA_WRITE_PROTECTED;
+                       }
+                       break;
                case FILE_OPEN_IF:
+                       if (is_twrp) {
+                               if (!file_existed) {
+                                       return NT_STATUS_MEDIA_WRITE_PROTECTED;
+                               }
+                               create_disposition = FILE_OPEN;
+                       }
                        break;
                default:
                        return NT_STATUS_INVALID_PARAMETER;
@@ -4051,7 +4081,9 @@ static NTSTATUS open_file_ntcreate(connection_struct 
*conn,
         * mean the same thing under DOS and Unix.
         */
 
-       flags |= calculate_open_access_flags(access_mask, private_flags);
+       flags |= calculate_open_access_flags(access_mask,
+                                            private_flags,
+                                            smb_fname->twrp);
 
        /*
         * Currently we only look at FILE_WRITE_THROUGH for create options.
@@ -4782,6 +4814,10 @@ static NTSTATUS open_directory(connection_struct *conn,
                                return status;
                        }
 
+                       if (smb_fname_atname->twrp != 0) {
+                               return NT_STATUS_MEDIA_WRITE_PROTECTED;
+                       }
+
                        status = mkdir_internal(conn,
                                                parent_dir_fname,
                                                smb_fname_atname,
@@ -4810,6 +4846,9 @@ static NTSTATUS open_directory(connection_struct *conn,
                                status = NT_STATUS_OK;
                                info = FILE_WAS_OPENED;
                        } else {
+                               if (smb_fname_atname->twrp != 0) {
+                                       return NT_STATUS_MEDIA_WRITE_PROTECTED;
+                               }
                                status = mkdir_internal(conn,
                                                        parent_dir_fname,
                                                        smb_fname_atname,
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 2875fcf562b..d18afe3e996 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -1060,8 +1060,8 @@ NTSTATUS smb_set_file_disposition_info(connection_struct 
*conn,
                                       files_struct *fsp,
                                       struct smb_filename *smb_fname);
 NTSTATUS refuse_symlink_fsp(const struct files_struct *fsp);
-NTSTATUS check_access_fsp(struct files_struct *fsp,
-                         uint32_t access_mask);
+NTSTATUS check_any_access_fsp(struct files_struct *fsp,
+                             uint32_t access_requested);
 uint64_t smb_roundup(connection_struct *conn, uint64_t val);
 bool samba_private_attr_name(const char *unix_ea_name);
 NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx,
diff --git a/source3/smbd/smb1_reply.c b/source3/smbd/smb1_reply.c
index cc1b1311cf1..b2f317a1db9 100644
--- a/source3/smbd/smb1_reply.c
+++ b/source3/smbd/smb1_reply.c
@@ -3928,8 +3928,9 @@ void reply_writebraw(struct smb_request *req)
                return;
        }
 
-       if (!CHECK_WRITE(fsp)) {
-               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+       status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
                error_to_writebrawerr(req);
                END_PROFILE(SMBwritebraw);
                return;
@@ -4159,8 +4160,9 @@ void reply_writeunlock(struct smb_request *req)
                return;
        }
 
-       if (!CHECK_WRITE(fsp)) {
-               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+       status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
                END_PROFILE(SMBwriteunlock);
                return;
        }
@@ -4294,8 +4296,9 @@ void reply_write(struct smb_request *req)
                return;
        }
 
-       if (!CHECK_WRITE(fsp)) {
-               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+       status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
                END_PROFILE(SMBwrite);
                return;
        }
@@ -4573,8 +4576,9 @@ void reply_write_and_X(struct smb_request *req)
                goto out;
        }
 
-       if (!CHECK_WRITE(fsp)) {
-               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+       status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
                goto out;
        }
 
@@ -5285,6 +5289,7 @@ void reply_writeclose(struct smb_request *req)
        struct timespec mtime;
        files_struct *fsp;
        struct lock_struct lock;
+       NTSTATUS status;
 
        START_PROFILE(SMBwriteclose);
 
@@ -5300,8 +5305,9 @@ void reply_writeclose(struct smb_request *req)
                END_PROFILE(SMBwriteclose);
                return;
        }
-       if (!CHECK_WRITE(fsp)) {
-               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+       status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
                END_PROFILE(SMBwriteclose);
                return;
        }
@@ -6091,6 +6097,7 @@ void reply_printwrite(struct smb_request *req)
        int numtowrite;
        const char *data;
        files_struct *fsp;
+       NTSTATUS status;
 
        START_PROFILE(SMBsplwr);
 
@@ -6113,8 +6120,9 @@ void reply_printwrite(struct smb_request *req)
                return;
        }
 
-       if (!CHECK_WRITE(fsp)) {
-               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+       status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
+       if (!NT_STATUS_IS_OK(status)) {


-- 
Samba Shared Repository

Reply via email to