smbd: move access override for previous versions to the SMB layer
authorRalph Boehme <slow@samba.org>
Fri, 15 Dec 2023 10:59:36 +0000 (11:59 +0100)
committerJule Anger <janger@samba.org>
Tue, 16 Jan 2024 10:05:29 +0000 (10:05 +0000)
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@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
Autobuild-User(master): Ralph Böhme <slow@samba.org>
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 <janger@samba.org>
Autobuild-Date(v4-18-test): Tue Jan 16 10:05:29 UTC 2024 on atb-devel-224

source3/modules/vfs_shadow_copy2.c
source3/smbd/open.c

index a2c9d3ce4c98df834aecb110d6b75f7e5238e71d..5bd5b87fb235413e35a0cfef0584960daa50556f 100644 (file)
@@ -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,
index e804d096907776a68c015c905328be7b5d0ee298..edc72bb03f0717422b3384a74b47a0c286c3a93f 100644 (file)
@@ -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,