The branch, master has been updated
       via  ff9178b6b4a smbd: return EACCESS when Durable Handle is reconnected 
with different user
       via  0ad4cb03936 smbtorture: DH reconnect with different user must fail 
with NT_STATUS_ACCESS_DENIED
       via  ff9bb28eeb8 s3/scavenger: call smbXsrv_open_cleanup() before 
share_mode_cleanup_disconnected()
       via  aa52db96cee smbtorture: add test 
smb2.durable-v2-open.reconnect-twice
       via  6f7a4a87feb smbd: DH reconnect hardening
       via  f23e94a885b smbd: compare Open.ClientGuid against Client.ClientGuid 
in DH reconnect
       via  c98e5f8a2ad smbd: only call scavenger_schedule_disconnected() if 
smbXsrv_open_close() succeeded
       via  15c6b767f93 smbd: free smbXsrv_open if SMB_VFS_DURABLE_RECONNECT() 
failed
       via  8ff9000d646 smbtorture: add a DH reconnect test that demonstrates 
the open record clobbering problem
       via  028a583920f s3/scavenger: raise debug level to 1 for cleanup 
failures
       via  095b5aca3d1 s3/scavenger: support more then one Durable Handle per 
file
       via  9e03f1d13b1 smbd: NDR_PRINT_DEBUG the vfs_default_durable_cookie in 
all relevant places
      from  dfd0ea70b9e third_party/waf: Explicit standard GNU directory 
command line options are not honoured

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


- Log -----------------------------------------------------------------
commit ff9178b6b4ad2aff651e7897aed5cf4fe7e37c20
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 8 08:38:05 2024 +0100

    smbd: return EACCESS when Durable Handle is reconnected with different user
    
    MS-SMB2 3.3.5.9.7 Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create 
Context
    
    10.  If the user represented by Session.SecurityContext is not the same user
    denoted by Open.DurableOwner, the server MUST fail the request with
    STATUS_ACCESS_DENIED and proceed as specified in "Failed Open Handling"
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11122
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>
    
    Autobuild-User(master): Ralph Böhme <[email protected]>
    Autobuild-Date(master): Fri Jun  6 17:15:45 UTC 2025 on atb-devel-224

commit 0ad4cb039364b8754b5b26f97f9364693ec1b1c4
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 8 11:25:21 2024 +0100

    smbtorture: DH reconnect with different user must fail with 
NT_STATUS_ACCESS_DENIED
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11122
    
    Pair-Programmed-With: Stefan Metzmacher <[email protected]>
    Signed-off-by: Ralph Boehme <[email protected]>
    Signed-off-by: Stefan Metzmacher <[email protected]>

commit ff9bb28eeb8534ddae138030e1df3f3059f9063f
Author: Ralph Boehme <[email protected]>
Date:   Mon Mar 25 15:53:15 2024 +0100

    s3/scavenger: call smbXsrv_open_cleanup() before 
share_mode_cleanup_disconnected()
    
    This ensures smbXsrv_open_cleanup(), which checks durable_timeout_msec, 
will detect
    a repeated DH disconnect that has reset the durable_timeout_msec.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15750
    
    Pair-Programmed-With: Stefan Metzmacher <[email protected]>
    Signed-off-by: Ralph Boehme <[email protected]>
    Signed-off-by: Stefan Metzmacher <[email protected]>

commit aa52db96ceeb0fa2dfbbdc2eafa6b50e32a6d18a
Author: Ralph Boehme <[email protected]>
Date:   Mon Mar 25 16:01:55 2024 +0100

    smbtorture: add test smb2.durable-v2-open.reconnect-twice
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15750
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>

commit 6f7a4a87feb3dd324ce6aa65b5451ef102032c00
Author: Ralph Boehme <[email protected]>
Date:   Tue Nov 19 17:45:35 2024 +0100

    smbd: DH reconnect hardening
    
    Verify the smbXsrv_open_global0 is marked as disconnected. This is 
similarily
    checked in SMB_VFS_RECONNECT() for the share_mode_entry and that catches the
    problem most of the times. But to be consistent we need this check also in
    smb2srv_open_recreate_fn().
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>

commit f23e94a885b746266e217a0410a3ef088520f0c8
Author: Ralph Boehme <[email protected]>
Date:   Wed Feb 26 15:28:53 2025 +0100

    smbd: compare Open.ClientGuid against Client.ClientGuid in DH reconnect
    
    This implements the check from MS-SMB2 3.3.5.9.7 "Handling the
    SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context".
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>

commit c98e5f8a2addaabcd6cbfce94a87e30590e6198f
Author: Ralph Boehme <[email protected]>
Date:   Tue Nov 19 20:00:49 2024 +0100

    smbd: only call scavenger_schedule_disconnected() if smbXsrv_open_close() 
succeeded
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>

commit 15c6b767f937867957c15790ff3fda886f1b347c
Author: Ralph Boehme <[email protected]>
Date:   Wed Feb 26 16:29:18 2025 +0100

    smbd: free smbXsrv_open if SMB_VFS_DURABLE_RECONNECT() failed
    
    Otherwise we leave "op" around which ultimately leads to 
smbXsrv_open_close()
    being called from its destructor smbXsrv_open_destructor() that is triggerd 
by
    its tree disconnect (or logoff, or ...) and this would clobber the open 
record.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>

commit 8ff9000d64647348e89375e1f071e7ac3c4092dd
Author: Ralph Boehme <[email protected]>
Date:   Mon Nov 18 18:16:59 2024 +0100

    smbtorture: add a DH reconnect test that demonstrates the open record 
clobbering problem
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>

commit 028a583920fe417919f97c236b5bd8508cc719b1
Author: Ralph Boehme <[email protected]>
Date:   Fri Jun 6 15:45:43 2025 +0200

    s3/scavenger: raise debug level to 1 for cleanup failures
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>

commit 095b5aca3d1678ce1229a2905a78250eed3cfb7b
Author: Ralph Boehme <[email protected]>
Date:   Thu Nov 7 15:41:18 2024 +0100

    s3/scavenger: support more then one Durable Handle per file
    
    Best viewed with git show --patience.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Pair-Programmed-With: Stefan Metzmacher <[email protected]>
    Signed-off-by: Ralph Boehme <[email protected]>
    Signed-off-by: Stefan Metzmacher <[email protected]>

commit 9e03f1d13b184b73d323355889be82ae545c0496
Author: Ralph Boehme <[email protected]>
Date:   Fri Jun 6 17:01:22 2025 +0200

    smbd: NDR_PRINT_DEBUG the vfs_default_durable_cookie in all relevant places
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>

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

Summary of changes:
 source3/selftest/tests.py              |   3 +-
 source3/smbd/close.c                   |   2 +-
 source3/smbd/durable.c                 |  20 +++
 source3/smbd/scavenger.c               | 150 +++++++----------------
 source3/smbd/smb2_create.c             |   6 +
 source3/smbd/smbXsrv_open.c            |  32 +++--
 source3/smbd/smbXsrv_open.h            |   2 +
 source4/torture/smb2/durable_open.c    | 217 +++++++++++++++++++++++++++++++++
 source4/torture/smb2/durable_v2_open.c | 110 +++++++++++++++++
 9 files changed, 429 insertions(+), 113 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index cedcf97e994..008c444681c 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -1239,7 +1239,8 @@ for t in tests:
     elif t == "rpc.mdssvc":
         plansmbtorture4testsuite(t, "fileserver", '//$SERVER_IP/tmp 
-U$USERNAME%$PASSWORD')
     elif t == "smb2.durable-open" or t == "smb2.durable-v2-open" or t == 
"smb2.replay" or t == "smb2.durable-v2-delay":
-        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/durable 
-U$USERNAME%$PASSWORD')
+        creds = " --option=torture:user2name=user1 
--option=torture:user2password=$PASSWORD"
+        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/durable 
-U$USERNAME%$PASSWORD' + creds)
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER_IP/durable 
-U$USERNAME%$PASSWORD')
     elif t == "base.rw1":
         plansmbtorture4testsuite(t, "nt4_dc_smb1", '//$SERVER_IP/tmp 
-U$USERNAME%$PASSWORD')
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index e0fc4618209..ce04056fc34 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -892,7 +892,6 @@ static NTSTATUS close_normal_file(struct smb_request *req, 
files_struct *fsp,
                                          "proceeding with normal close\n",
                                          fsp_str_dbg(fsp), nt_errstr(tmp)));
                        }
-                       scavenger_schedule_disconnected(fsp);
                } else {
                        DEBUG(1, ("Failed to disconnect durable handle for "
                                  "file %s: %s - proceeding with normal "
@@ -912,6 +911,7 @@ static NTSTATUS close_normal_file(struct smb_request *req, 
files_struct *fsp,
                DEBUG(10, ("%s disconnected durable handle for file %s\n",
                           conn->session_info->unix_info->unix_name,
                           fsp_str_dbg(fsp)));
+               scavenger_schedule_disconnected(fsp);
                return NT_STATUS_OK;
        }
 
diff --git a/source3/smbd/durable.c b/source3/smbd/durable.c
index 8e35e32538d..c13c8382f0f 100644
--- a/source3/smbd/durable.c
+++ b/source3/smbd/durable.c
@@ -117,6 +117,11 @@ NTSTATUS vfs_default_durable_cookie(struct files_struct 
*fsp,
        cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
        cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
 
+       if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
+               DBG_DEBUG("Fresh cookie\n");
+               NDR_PRINT_DEBUG(vfs_default_durable_cookie, &cookie);
+       }
+
        ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
                        
(ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
@@ -182,6 +187,11 @@ NTSTATUS vfs_default_durable_disconnect(struct 
files_struct *fsp,
                return status;
        }
 
+       if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
+               DBG_DEBUG("Old cookie\n");
+               NDR_PRINT_DEBUG(vfs_default_durable_cookie, &cookie);
+       }
+
        if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
                return NT_STATUS_INVALID_PARAMETER;
        }
@@ -279,6 +289,11 @@ NTSTATUS vfs_default_durable_disconnect(struct 
files_struct *fsp,
                return status;
        }
 
+       if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
+               DBG_DEBUG("New cookie\n");
+               NDR_PRINT_DEBUG(vfs_default_durable_cookie, &cookie);
+       }
+
        status = fd_close(fsp);
        if (!NT_STATUS_IS_OK(status)) {
                data_blob_free(&new_cookie_blob);
@@ -817,6 +832,11 @@ NTSTATUS vfs_default_durable_reconnect(struct 
connection_struct *conn,
                return status;
        }
 
+       if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
+               DBG_DEBUG("Cookie:\n");
+               NDR_PRINT_DEBUG(vfs_default_durable_cookie, &state.cookie);
+       }
+
        if (strcmp(state.cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
                return NT_STATUS_INVALID_PARAMETER;
        }
diff --git a/source3/smbd/scavenger.c b/source3/smbd/scavenger.c
index 40b2fe55dcc..2e04df662ef 100644
--- a/source3/smbd/scavenger.c
+++ b/source3/smbd/scavenger.c
@@ -472,27 +472,10 @@ struct cleanup_disconnected_state {
        struct file_id fid;
        struct share_mode_lock *lck;
        uint64_t open_persistent_id;
-       size_t num_disconnected;
-       bool found_connected;
+       struct share_mode_entry e;
 };
 
-static bool cleanup_disconnected_lease(struct share_mode_entry *e,
-                                      void *private_data)
-{
-       struct cleanup_disconnected_state *state = private_data;
-       NTSTATUS status;
-
-       status = leases_db_del(&e->client_guid, &e->lease_key, &state->fid);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               DBG_DEBUG("leases_db_del failed: %s\n",
-                         nt_errstr(status));
-       }
-
-       return false;
-}
-
-static bool share_mode_find_connected_fn(
+static bool cleanup_disconnected_share_mode_entry_fn(
        struct share_mode_entry *e,
        bool *modified,
        void *private_data)
@@ -500,53 +483,10 @@ static bool share_mode_find_connected_fn(
        struct cleanup_disconnected_state *state = private_data;
        bool disconnected;
 
-       disconnected = server_id_is_disconnected(&e->pid);
-       if (!disconnected) {
-               char *name = share_mode_filename(talloc_tos(), state->lck);
-               struct file_id_buf tmp1;
-               struct server_id_buf tmp2;
-               DBG_INFO("file (file-id='%s', servicepath='%s', name='%s') "
-                        "is used by server %s ==> do not cleanup\n",
-                        file_id_str_buf(state->fid, &tmp1),
-                        share_mode_servicepath(state->lck),
-                        name,
-                        server_id_str_buf(e->pid, &tmp2));
-               TALLOC_FREE(name);
-               state->found_connected = true;
-               return true;
-       }
-
-       if (state->open_persistent_id != e->share_file_id) {
-               char *name = share_mode_filename(talloc_tos(), state->lck);
-               struct file_id_buf tmp;
-               DBG_INFO("entry for file "
-                        "(file-id='%s', servicepath='%s', name='%s') "
-                        "has share_file_id %"PRIu64" but expected "
-                        "%"PRIu64"==> do not cleanup\n",
-                        file_id_str_buf(state->fid, &tmp),
-                        share_mode_servicepath(state->lck),
-                        name,
-                        e->share_file_id,
-                        state->open_persistent_id);
-               TALLOC_FREE(name);
-               state->found_connected = true;
-               return true;
+       if (e->share_file_id != state->open_persistent_id) {
+               return false;
        }
 
-       state->num_disconnected += 1;
-
-       return false;
-}
-
-static bool cleanup_disconnected_share_mode_entry_fn(
-       struct share_mode_entry *e,
-       bool *modified,
-       void *private_data)
-{
-       struct cleanup_disconnected_state *state = private_data;
-
-       bool disconnected;
-
        disconnected = server_id_is_disconnected(&e->pid);
        if (!disconnected) {
                char *name = share_mode_filename(talloc_tos(), state->lck);
@@ -567,7 +507,9 @@ static bool cleanup_disconnected_share_mode_entry_fn(
         * the indication to delete the entry.
         */
        e->stale = true;
-       return false;
+       state->e = *e;
+
+       return true;
 }
 
 static bool share_mode_cleanup_disconnected(
@@ -581,44 +523,20 @@ static bool share_mode_cleanup_disconnected(
        TALLOC_CTX *frame = talloc_stackframe();
        char *name = NULL;
        struct file_id_buf idbuf;
+       NTSTATUS status;
        bool ok;
 
        state.lck = get_existing_share_mode_lock(frame, fid);
        if (state.lck == NULL) {
-               DBG_INFO("Could not fetch share mode entry for %s\n",
+               DBG_WARNING("Could not fetch share mode entry for %s\n",
                         file_id_str_buf(fid, &idbuf));
                goto done;
        }
        name = share_mode_filename(frame, state.lck);
 
-       ok = share_mode_forall_entries(
-               state.lck, share_mode_find_connected_fn, &state);
-       if (!ok) {
-               DBG_DEBUG("share_mode_forall_entries failed\n");
-               goto done;
-       }
-       if (state.found_connected) {
-               DBG_DEBUG("Found connected entry\n");
-               goto done;
-       }
-
-       ok = share_mode_forall_leases(
-               state.lck, cleanup_disconnected_lease, &state);
-       if (!ok) {
-               DBG_DEBUG("failed to clean up leases associated "
-                         "with file (file-id='%s', servicepath='%s', "
-                         "name='%s') and open_persistent_id %"PRIu64" "
-                         "==> do not cleanup\n",
-                         file_id_str_buf(fid, &idbuf),
-                         share_mode_servicepath(state.lck),
-                         name,
-                         open_persistent_id);
-               goto done;
-       }
-
        ok = brl_cleanup_disconnected(fid, open_persistent_id);
        if (!ok) {
-               DBG_DEBUG("failed to clean up byte range locks associated "
+               DBG_WARNING("failed to clean up byte range locks associated "
                          "with file (file-id='%s', servicepath='%s', "
                          "name='%s') and open_persistent_id %"PRIu64" "
                          "==> do not cleanup\n",
@@ -629,10 +547,9 @@ static bool share_mode_cleanup_disconnected(
                goto done;
        }
 
-       DBG_DEBUG("cleaning up %zu entries for file "
+       DBG_DEBUG("cleaning up entry for file "
                  "(file-id='%s', servicepath='%s', name='%s') "
                  "from open_persistent_id %"PRIu64"\n",
-                 state.num_disconnected,
                  file_id_str_buf(fid, &idbuf),
                  share_mode_servicepath(state.lck),
                  name,
@@ -641,11 +558,10 @@ static bool share_mode_cleanup_disconnected(
        ok = share_mode_forall_entries(
                state.lck, cleanup_disconnected_share_mode_entry_fn, &state);
        if (!ok) {
-               DBG_DEBUG("failed to clean up %zu entries associated "
+               DBG_WARNING("failed to clean up entry associated "
                          "with file (file-id='%s', servicepath='%s', "
                          "name='%s') and open_persistent_id %"PRIu64" "
                          "==> do not cleanup\n",
-                         state.num_disconnected,
                          file_id_str_buf(fid, &idbuf),
                          share_mode_servicepath(state.lck),
                          name,
@@ -653,6 +569,30 @@ static bool share_mode_cleanup_disconnected(
                goto done;
        }
 
+       if (state.e.stale && (state.e.op_type == LEASE_OPLOCK)) {
+               status = remove_lease_if_stale(state.lck,
+                                              &state.e.client_guid,
+                                              &state.e.lease_key);
+               if (!NT_STATUS_IS_OK(status)) {
+                       struct GUID_txt_buf gbuf;
+
+                       DBG_WARNING("Failed to clean up lease associated "
+                                   "with file (file-id='%s', servicepath='%s', 
"
+                                   "name='%s', open_persistent_id=%" PRIu64
+                                   "client_guid=%s, "
+                                   "lease_key=%"PRIx64"/%"PRIx64"): %s\n",
+                                   file_id_str_buf(fid, &idbuf),
+                                   share_mode_servicepath(state.lck),
+                                   name,
+                                   open_persistent_id,
+                                   GUID_buf_string(&state.e.client_guid, 
&gbuf),
+                                   state.e.lease_key.data[0],
+                                   state.e.lease_key.data[1],
+                                   nt_errstr(status));
+                       goto done;
+               }
+       }
+
        ret = true;
 done:
        talloc_free(frame);
@@ -673,6 +613,16 @@ static void scavenger_timer(struct tevent_context *ev,
                  file_id_str_buf(ctx->msg.file_id, &idbuf),
                  timeval_string(talloc_tos(), &t, true));
 
+       status = smbXsrv_open_cleanup(ctx->msg.open_persistent_id);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_WARNING("Failed to cleanup open global for file %s open "
+                           "%"PRIu64": %s\n",
+                           file_id_str_buf(ctx->msg.file_id, &idbuf),
+                           ctx->msg.open_persistent_id,
+                           nt_errstr(status));
+               return;
+       }
+
        ok = share_mode_cleanup_disconnected(ctx->msg.file_id,
                                             ctx->msg.open_persistent_id);
        if (!ok) {
@@ -682,14 +632,6 @@ static void scavenger_timer(struct tevent_context *ev,
                            ctx->msg.open_persistent_id);
        }
 
-       status = smbXsrv_open_cleanup(ctx->msg.open_persistent_id);
-       if (!NT_STATUS_IS_OK(status)) {
-               DBG_WARNING("Failed to cleanup open global for file %s open "
-                           "%"PRIu64": %s\n",
-                           file_id_str_buf(ctx->msg.file_id, &idbuf),
-                           ctx->msg.open_persistent_id,
-                           nt_errstr(status));
-       }
 }
 
 static void scavenger_add_timer(struct smbd_scavenger_state *state,
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 78da998e169..6f4f3ed47de 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -1096,11 +1096,16 @@ static struct tevent_req 
*smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
        if (state->do_durable_reconnect) {
                DATA_BLOB new_cookie = data_blob_null;
                NTTIME now = timeval_to_nttime(&smb2req->request_time);
+               const struct smb2_lease_key *lease_key = NULL;
 
+               if (state->lease_ptr != NULL) {
+                       lease_key = &state->lease_ptr->lease_key;
+               }
                status = smb2srv_open_recreate(smb2req->xconn,
                                               smb1req->conn->session_info,
                                               state->persistent_id,
                                               state->create_guid,
+                                              lease_key,
                                               now,
                                               &state->op);
                if (tevent_req_nterror(req, status)) {
@@ -1135,6 +1140,7 @@ static struct tevent_req 
*smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                   nt_errstr(status),
                                   nt_errstr(return_status));
 
+                       TALLOC_FREE(state->op);
                        tevent_req_nterror(req, return_status);
                        return tevent_req_post(req, state->ev);
                }
diff --git a/source3/smbd/smbXsrv_open.c b/source3/smbd/smbXsrv_open.c
index 6fd64a028c9..c939bbd39c3 100644
--- a/source3/smbd/smbXsrv_open.c
+++ b/source3/smbd/smbXsrv_open.c
@@ -35,6 +35,7 @@
 #include "source3/include/util_tdb.h"
 #include "lib/util/idtree_random.h"
 #include "lib/util/time_basic.h"
+#include "../librpc/gen_ndr/ndr_smb2_lease_struct.h"
 
 struct smbXsrv_open_table {
        struct {
@@ -282,10 +283,10 @@ static NTSTATUS smbXsrv_open_global_verify_record(
        *_global0 = global0;
 
        if (server_id_is_disconnected(&global0->server_id)) {
-               return NT_STATUS_OK;
+               return NT_STATUS_REMOTE_DISCONNECT;
        }
        if (serverid_exists(&global0->server_id)) {
-               return NT_STATUS_OK;
+               return NT_STATUS_OBJECTID_EXISTS;
        }
 
        DBG_WARNING("smbd %s did not clean up record %s\n",
@@ -367,7 +368,7 @@ static void smbXsrv_open_global_allocate_fn(
        state->status = smbXsrv_open_global_verify_record(
                key, oldval, talloc_tos(), &tmp_global0);
 
-       if (NT_STATUS_IS_OK(state->status)) {
+       if (!NT_STATUS_EQUAL(state->status, NT_STATUS_NOT_FOUND)) {
                /*
                 * Found an existing record
                 */
@@ -1159,7 +1160,9 @@ NTSTATUS smb2srv_open_lookup_replay_cache(struct 
smbXsrv_connection *conn,
 
 struct smb2srv_open_recreate_state {
        struct smbXsrv_open *op;
+       const struct GUID *client_guid;
        const struct GUID *create_guid;
+       const struct smb2_lease_key *lease_key;
        struct security_token *current_token;
        struct server_id me;
 
@@ -1172,10 +1175,11 @@ static void smb2srv_open_recreate_fn(
        struct smb2srv_open_recreate_state *state = private_data;
        TDB_DATA key = dbwrap_record_get_key(rec);
        struct smbXsrv_open_global0 *global = NULL;
+       struct GUID_txt_buf buf1, buf2;
 
        state->status = smbXsrv_open_global_verify_record(
                key, oldval, state->op, &state->op->global);
-       if (!NT_STATUS_IS_OK(state->status)) {
+       if (!NT_STATUS_EQUAL(state->status, NT_STATUS_REMOTE_DISCONNECT)) {
                DBG_WARNING("smbXsrv_open_global_verify_record for %s "
                            "failed: %s\n",
                            tdb_data_dbg(key),
@@ -1184,6 +1188,16 @@ static void smb2srv_open_recreate_fn(
        }
        global = state->op->global;
 
+       if (state->lease_key != NULL &&
+           !GUID_equal(&global->client_guid, state->client_guid))
+       {
+               DBG_NOTICE("client guid: %s != %s in %s\n",
+                          GUID_buf_string(&global->client_guid, &buf1),
+                          GUID_buf_string(state->client_guid, &buf2),
+                          tdb_data_dbg(key));
+               goto not_found;
+       }
+
        /*
         * If the provided create_guid is NULL, this means that
         * the reconnect request was a v1 request. In that case
@@ -1192,7 +1206,6 @@ static void smb2srv_open_recreate_fn(
         */
        if ((state->create_guid != NULL) &&
            !GUID_equal(&global->create_guid, state->create_guid)) {
-               struct GUID_txt_buf buf1, buf2;
                DBG_NOTICE("%s != %s in %s\n",
                           GUID_buf_string(&global->create_guid, &buf1),
                           GUID_buf_string(state->create_guid, &buf2),
@@ -1206,7 +1219,8 @@ static void smb2srv_open_recreate_fn(
                DBG_NOTICE("global owner %s not in our token in %s\n",
                           dom_sid_str_buf(&global->open_owner, &buf),
                           tdb_data_dbg(key));
-               goto not_found;
+               state->status = NT_STATUS_ACCESS_DENIED;
+               return;
        }
 
        if (!global->durable) {
@@ -1237,12 +1251,15 @@ NTSTATUS smb2srv_open_recreate(struct 
smbXsrv_connection *conn,
                               struct auth_session_info *session_info,
                               uint64_t persistent_id,
                               const struct GUID *create_guid,
+                              const struct smb2_lease_key *lease_key,
                               NTTIME now,
                               struct smbXsrv_open **_open)
 {
        struct smbXsrv_open_table *table = conn->client->open_table;
        struct smb2srv_open_recreate_state state = {
+               .client_guid = &conn->client->global->client_guid,
                .create_guid = create_guid,
+               .lease_key = lease_key,
                .me = messaging_server_id(conn->client->msg_ctx),
        };
        struct smbXsrv_open_global_key_buf key_buf;
@@ -1459,7 +1476,7 @@ static void smbXsrv_open_cleanup_fn(
        }
 
        if (!delete_open) {
-               state->status = NT_STATUS_OK;
+               state->status = NT_STATUS_CANNOT_DELETE;
                return;
        }
 do_delete:
@@ -1478,6 +1495,7 @@ do_delete:
                  "deleted record from %s\n",
                  state->global_id,
                  dbwrap_name(dbwrap_record_get_db(rec)));
+       state->status = NT_STATUS_OK;
 }
 
 NTSTATUS smbXsrv_open_cleanup(uint64_t persistent_id)
diff --git a/source3/smbd/smbXsrv_open.h b/source3/smbd/smbXsrv_open.h
index 02576501237..58e585888e2 100644
--- a/source3/smbd/smbXsrv_open.h
+++ b/source3/smbd/smbXsrv_open.h
@@ -58,10 +58,12 @@ NTSTATUS smb2srv_open_lookup_replay_cache(struct 
smbXsrv_connection *conn,
                                          const char *name,
                                          NTTIME now,
                                          struct smbXsrv_open **_open);
+struct smb2_lease_key;
 NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn,
                               struct auth_session_info *session_info,
                               uint64_t persistent_id,
                               const struct GUID *create_guid,
+                              const struct smb2_lease_key *lease_key,
                               NTTIME now,
                               struct smbXsrv_open **_open);
 
diff --git a/source4/torture/smb2/durable_open.c 
b/source4/torture/smb2/durable_open.c
index b730fab3c29..2c5bc2224e6 100644
--- a/source4/torture/smb2/durable_open.c
+++ b/source4/torture/smb2/durable_open.c
@@ -26,7 +26,11 @@
 #include "../libcli/smb/smbXcli_base.h"


-- 
Samba Shared Repository

Reply via email to