[SCM] Samba Shared Repository - branch v4-19-test updated

Jule Anger janger at samba.org
Tue Jan 9 13:18:01 UTC 2024


The branch, v4-19-test has been updated
       via  cfbaab5654c smbd: move access override for previous versions to the SMB layer
       via  0874d3ab3e1 smbd: check for previous versions in check_any_access_fsp()
       via  f5eb449cac8 smbd: use check_any_access_fsp() for all access checks
       via  44396d7bade smbd: replace CHECK_WRITE() macro with calls to check_any_access_fsp()
       via  bfa5f178099 smbd: set fsp->fsp_flags.can_write to false for access to previous-versions
       via  0352aae6ea1 smbd: return correct error when trying to create a hardlink to a VSS file
       via  8318428f3f8 smbd: fix check_any_access_fsp() for non-fsa fsps
       via  0f865a34f1a smbd: rename check_access_fsp() to check_any_access_fsp()
       via  9ee7991d97d smbd: set fsp_flags.is_fsa to true on printer file handles
       via  b8383780249 smbd: return the correct error in can_rename()
       via  a510fc46bcd smbtorture: expand smb2.twrp.write test
       via  bb9aea6a7e6 s4/libcli/raw: implemement RAW_SFILEINFO_LINK_INFORMATION
       via  b6c2c26e9ba selftest: remove error_inject from shadow_write share
      from  b9f60718ccd VERSION: Bump version up to Samba 4.19.5...

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-19-test


- Log -----------------------------------------------------------------
commit cfbaab5654cc40ef08ab09492d20aac2f33cbf0e
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    
    Autobuild-User(master): Ralph Böhme <slow at samba.org>
    Autobuild-Date(master): Mon Jan  8 16:58:26 UTC 2024 on atb-devel-224
    
    (backported from commit f14a7065690b00e3c6af2c1f0b0aec51c1e0b372)
    [slow at samba.org: vfs_shadow_copy2.c: no TALLOC_FREE() in context]
    [slow at samba.org: open.c: assign result from calculate_open_access_flags()]
    
    Autobuild-User(v4-19-test): Jule Anger <janger at samba.org>
    Autobuild-Date(v4-19-test): Tue Jan  9 13:17:12 UTC 2024 on atb-devel-224

commit 0874d3ab3e1cb7e42900da9543963799b864e485
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit fd4e41144a819b4403340e4a28664ac586722b41)

commit f5eb449cac82de61c4eadc1b134c92896f69aacf
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 02ed99343d19fd0845531ad99a46b1dd5b8a7a4f)

commit 44396d7bade98b41fb655e30d84195793684f593
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 995a31c8d4c1789c16bae6b8196f2565d4b1dfdb)

commit bfa5f1780990e4f763f0214fb660c64c53188e65
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit ee3035218df4cfd68b6aab6825c78f2b85234c6c)

commit 0352aae6ea1e8c38ca8ca091123ddde455c2e5ab
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit a0ae45be770a13373c148a689b9761f14c4f942c)

commit 8318428f3f8dbdbc7ff11f2755ae6b702049c72d
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit bf497819e61131cfa6469971596af3aa9bd4bb49)

commit 0f865a34f1a080e35ce6a4c19fec80a84c7b8dc9
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 96b577c380fa914eb1ffa95849c82bdb88aa1ec6)

commit 9ee7991d97dfc0aeaecc12816d6e7a34b74106e8
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 76c8fe16bff36a29fa326355256b50737d04bd85)

commit b838378024966ac75119d6426380178f8c482a16
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 276c5bd851ab6ab818a49d9c47f6b96de8024778)

commit a510fc46bcd0fc6e78d51eebdbbb7fbb44a134de
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 537eedfe2a79fba2e1f062f14ba7a0c5f8f70a88)

commit bb9aea6a7e69b92d76cc09812de8887e1ea6930c
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit c62484bc2c60ebac42635793d94cb8e62629acbf)

commit b6c2c26e9ba02b6b7b0843e8a01344c774974dee
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 78119edba013583555069271bb61134c12c2c135)

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

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 44ac4a5901a..b9990928f4b 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -3437,9 +3437,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 42ff9ffb0d4..1851709774a 100644
--- a/source3/include/smb_macros.h
+++ b/source3/include/smb_macros.h
@@ -74,11 +74,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 341806b09a4..8f611c485ae 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 8471d81c153..df9b2cefcfe 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,26 +1572,15 @@ 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) {
 		return -1;
 	}
 	if (timestamp == 0) {
-		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,
@@ -1613,14 +1601,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 59fbe548501..6cdbec19a54 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 18d2322cf0e..5402180cf26 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -1068,15 +1068,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 476aead590d..7c4c7156d24 100644
--- a/source3/smbd/file_access.c
+++ b/source3/smbd/file_access.c
@@ -191,6 +191,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.
 	 */
@@ -219,11 +220,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 b8640fd6677..02cfc424822 100644
--- a/source3/smbd/files.c
+++ b/source3/smbd/files.c
@@ -2148,6 +2148,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 3581c4b9173..a7759c349e4 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1678,6 +1678,9 @@ static NTSTATUS open_file(struct smb_request *req,
 	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;
@@ -3669,7 +3672,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;
 
@@ -3678,6 +3682,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;
@@ -3808,6 +3821,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;
@@ -3965,6 +3979,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:
@@ -3980,11 +3997,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;
@@ -4057,7 +4087,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.
@@ -4785,6 +4817,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,
@@ -4813,6 +4849,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 78e1b48be09..6e54e11486f 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -1108,8 +1108,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 63ff98fb22b..9fbfc39c69f 100644
--- a/source3/smbd/smb1_reply.c
+++ b/source3/smbd/smb1_reply.c
@@ -3926,8 +3926,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;
@@ -4157,8 +4158,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;
 	}
@@ -4292,8 +4294,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;
 	}
@@ -4571,8 +4574,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;
 	}
 
@@ -5283,6 +5287,7 @@ void reply_writeclose(struct smb_request *req)
 	struct timespec mtime;
 	files_struct *fsp;
 	struct lock_struct lock;
+	NTSTATUS status;
 
 	START_PROFILE(SMBwriteclose);
 
@@ -5298,8 +5303,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;
 	}
@@ -6086,6 +6092,7 @@ void reply_printwrite(struct smb_request *req)
 	int numtowrite;
 	const char *data;
 	files_struct *fsp;
+	NTSTATUS status;
 
 	START_PROFILE(SMBsplwr);
 
@@ -6108,8 +6115,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)) {
+		reply_nterror(req, status);
 		END_PROFILE(SMBsplwr);
 		return;


-- 
Samba Shared Repository



More information about the samba-cvs mailing list