From f14a7065690b00e3c6af2c1f0b0aec51c1e0b372 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 15 Dec 2023 11:59:36 +0100 Subject: [PATCH] smbd: move access override for previous versions to the SMB layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Stefan Metzmacher Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Mon Jan 8 16:58:26 UTC 2024 on atb-devel-224 --- source3/modules/vfs_shadow_copy2.c | 30 ++++------------------ source3/smbd/open.c | 40 ++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 27 deletions(-) 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, - ×tamp, - &stripped, - &is_converted); + ok = shadow_copy2_strip_snapshot(talloc_tos(), + handle, + smb_fname, + ×tamp, + &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/smbd/open.c b/source3/smbd/open.c index 3872403dd56..da809196fa4 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3629,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; @@ -3638,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; @@ -3803,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; @@ -3962,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: @@ -3977,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; @@ -4054,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. @@ -4785,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, @@ -4813,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,