From: Ralph Boehme Date: Fri, 15 Dec 2023 10:59:36 +0000 (+0100) Subject: smbd: move access override for previous versions to the SMB layer X-Git-Tag: samba-4.18.10~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee2df0bbb3429ca2bece2b651e00182453d1b089;p=thirdparty%2Fsamba.git 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 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 (backported from commit f14a7065690b00e3c6af2c1f0b0aec51c1e0b372) [slow@samba.org: vfs_shadow_copy2.c: no TALLOC_FREE() in context] [slow@samba.org: open.c: assign result from calculate_open_access_flags()] Autobuild-User(v4-18-test): Jule Anger Autobuild-Date(v4-18-test): Tue Jan 16 10:05:29 UTC 2024 on atb-devel-224 --- diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index a2c9d3ce4c9..5bd5b87fb23 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, - ×tamp, - &stripped, - &is_converted); + ok = shadow_copy2_strip_snapshot(talloc_tos(), + handle, + smb_fname, + ×tamp, + &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/smbd/open.c b/source3/smbd/open.c index e804d096907..edc72bb03f0 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3672,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; @@ -3681,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; @@ -3811,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; @@ -3968,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: @@ -3983,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; @@ -4060,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. @@ -4788,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, @@ -4816,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,