]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
smbd: make the replay cache record an index on the global open table
authorRalph Boehme <slow@samba.org>
Thu, 10 Jul 2025 14:31:16 +0000 (16:31 +0200)
committerRalph Boehme <slow@samba.org>
Tue, 5 Aug 2025 14:52:34 +0000 (14:52 +0000)
Store only the open_global record key as is in the replay-cache record, making
it an index into the global open table. Then in the replay code, use the new
function smbXsrv_open_global_lookup() to get at the open records.

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/librpc/idl/smbXsrv.idl
source3/smbd/smbXsrv_open.c

index ee0a90fe46132a0bfee576c9b7e01ad76553b281..140f6089fc424d3a8feeaf72d1d3de1a72a4924a 100644 (file)
@@ -493,9 +493,7 @@ interface smbXsrv
                [switch_is(version)] smbXsrv_openU      info;
        } smbXsrv_openB;
 
-       const uint32 SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE = 12;
        typedef [public] struct {
-               NTTIME                                  idle_time;
-               uint32                                  local_id;
+               DATA_BLOB                               open_global_key;
        } smbXsrv_open_replay_cache;
 }
index 272ce54365f529dc84cf05cf8523adf32f8ac020..f52f7cf2efb4c345ace650e1dc1a7390ecbbd6a6 100644 (file)
@@ -296,6 +296,58 @@ static NTSTATUS smbXsrv_open_global_verify_record(
        return NT_STATUS_FATAL_APP_EXIT;
 }
 
+struct smbXsrv_open_global_lookup_state {
+       TALLOC_CTX *mem_ctx;
+       struct smbXsrv_open_global0 *global;
+       NTSTATUS status;
+};
+
+static void smbXsrv_open_global_lookup_fn(struct db_record *rec,
+                                         TDB_DATA val,
+                                         void *private_data)
+{
+       struct smbXsrv_open_global_lookup_state *state = private_data;
+       TDB_DATA key = dbwrap_record_get_key(rec);
+
+       state->status = smbXsrv_open_global_parse_record(state->mem_ctx,
+                                                        key,
+                                                        val,
+                                                        &state->global);
+       if (!NT_STATUS_IS_OK(state->status)) {
+               return;
+       }
+       return;
+}
+
+static NTSTATUS smbXsrv_open_global_lookup(
+                       struct smbXsrv_open_table *table,
+                       TALLOC_CTX *mem_ctx,
+                       uint32_t open_global_id,
+                       const struct smbXsrv_open_global0 **_global)
+{
+       struct smbXsrv_open_global_key_buf key_buf;
+       TDB_DATA key = smbXsrv_open_global_id_to_key(open_global_id, &key_buf);
+       struct smbXsrv_open_global_lookup_state state = {
+               .mem_ctx = mem_ctx,
+       };
+       NTSTATUS status;
+
+       status = dbwrap_do_locked(table->global.db_ctx,
+                                 key,
+                                 smbXsrv_open_global_lookup_fn,
+                                 &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("dbwrap_do_locked failed\n");
+               return status;
+       }
+       if (!NT_STATUS_IS_OK(state.status)) {
+               DBG_ERR("smbXsrv_open_global_lookup_fn failed\n");
+               return state.status;
+       }
+       *_global = state.global;
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS smbXsrv_open_global_store(
        struct db_record *rec,
        TDB_DATA key,
@@ -618,13 +670,7 @@ static NTSTATUS smbXsrv_open_set_replay_cache(struct smbXsrv_open *op)
        struct GUID_txt_buf buf;
        char *guid_string;
        struct db_context *db = op->table->local.replay_cache_db_ctx;
-       struct smbXsrv_open_replay_cache rc = {
-               .idle_time = op->idle_time,
-               .local_id = op->local_id,
-       };
-       uint8_t data[SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE] = { 0 };
-       DATA_BLOB blob = { .data = data, .length = sizeof(data), };
-       enum ndr_err_code ndr_err;
+       struct smbXsrv_open_global_key_buf open_key_buf;
        NTSTATUS status;
        TDB_DATA val;
 
@@ -639,19 +685,11 @@ static NTSTATUS smbXsrv_open_set_replay_cache(struct smbXsrv_open *op)
        create_guid = &op->global->create_guid;
        guid_string = GUID_buf_string(create_guid, &buf);
 
-       ndr_err = ndr_push_struct_into_fixed_blob(&blob, &rc,
-               (ndr_push_flags_fn_t)ndr_push_smbXsrv_open_replay_cache);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               status = ndr_map_error2ntstatus(ndr_err);
-               return status;
-       }
+       val = smbXsrv_open_global_id_to_key(op->global->open_global_id,
+                                           &open_key_buf);
 
        DBG_DEBUG("Replay Cache: store create_guid [%s]\n",
                  GUID_buf_string(&op->global->create_guid, &buf));
-       if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
-               NDR_PRINT_DEBUG(smbXsrv_open_replay_cache, &rc);
-       }
-       val = make_tdb_data(blob.data, blob.length);
 
        status = dbwrap_store_bystring(db, guid_string, val, TDB_REPLACE);
 
@@ -1039,13 +1077,10 @@ NTSTATUS smb2srv_open_lookup_replay_cache(struct smbXsrv_connection *conn,
        const char *create_guid_str = GUID_buf_string(&create_guid, &_create_guid_buf);
        TDB_DATA create_guid_key = string_term_tdb_data(create_guid_str);
        struct db_record *db_rec = NULL;
+       const struct smbXsrv_open_global0 *global = NULL;
        struct smbXsrv_open *op = NULL;
-       struct smbXsrv_open_replay_cache rc = {
-               .idle_time = now,
-               .local_id = 0,
-       };
-       enum ndr_err_code ndr_err;
-       DATA_BLOB blob = data_blob_null;
+       uint32_t open_global_id;
+
        TDB_DATA val;
 
        *_open = NULL;
@@ -1058,23 +1093,11 @@ NTSTATUS smb2srv_open_lookup_replay_cache(struct smbXsrv_connection *conn,
 
        val = dbwrap_record_get_value(db_rec);
        if (val.dsize == 0) {
-               uint8_t data[SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE];
+               struct smbXsrv_open_global_key_buf open_key_buf;
 
                DBG_DEBUG("Fresh replay-cache record\n");
-               if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
-                       NDR_PRINT_DEBUG(smbXsrv_open_replay_cache, &rc);
-               }
-
-               blob = data_blob_const(data, ARRAY_SIZE(data));
-               ndr_err = ndr_push_struct_into_fixed_blob(&blob, &rc,
-                       (ndr_push_flags_fn_t)ndr_push_smbXsrv_open_replay_cache);
-               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-                       status = ndr_map_error2ntstatus(ndr_err);
-                       TALLOC_FREE(frame);
-                       return status;
-               }
 
-               val = make_tdb_data(blob.data, blob.length);
+               val = smbXsrv_open_global_id_to_key(0, &open_key_buf);
                status = dbwrap_record_store(db_rec, val, TDB_REPLACE);
                if (!NT_STATUS_IS_OK(status)) {
                        TALLOC_FREE(frame);
@@ -1089,26 +1112,21 @@ NTSTATUS smb2srv_open_lookup_replay_cache(struct smbXsrv_connection *conn,
                return NT_STATUS_FWP_RESERVED;
        }
 
-       if (val.dsize != SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE) {
+       /*
+        * For now we expect the size of the record containing the global
+        * key to be the size of an uint32_t. If we ever change this, this
+        * will needs revisiting.
+        */
+       if (val.dsize != sizeof(uint32_t)) {
                TALLOC_FREE(frame);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
+       open_global_id = PULL_BE_U32(val.dptr, 0);
 
-       blob = data_blob_const(val.dptr, val.dsize);
-       ndr_err = ndr_pull_struct_blob_all_noalloc(&blob, &rc,
-                       (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_open_replay_cache);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               status = ndr_map_error2ntstatus(ndr_err);
-               TALLOC_FREE(frame);
-               return status;
-       }
+       DBG_DEBUG("Found replay cache record open_global_id [%"PRIx32"]\n",
+                 open_global_id);
 
-       DBG_DEBUG("Found smbXsrv_open_replay_cache record\n");
-       if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
-               NDR_PRINT_DEBUG(smbXsrv_open_replay_cache, &rc);
-       }
-
-       if (rc.local_id == 0) {
+       if (open_global_id == 0) {
                /*
                 * The original request (or a former replay) is still
                 * pending, ask the client to retry by sending
@@ -1119,31 +1137,43 @@ NTSTATUS smb2srv_open_lookup_replay_cache(struct smbXsrv_connection *conn,
                return NT_STATUS_FILE_NOT_AVAILABLE;
        }
 
-       DBG_DEBUG("Found replay-cache record with local_id\n");
+       TALLOC_FREE(db_rec);
+       status = smbXsrv_open_global_lookup(table,
+                                           frame,
+                                           open_global_id,
+                                           &global);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_DEBUG("Global open not found for create "
+                         "[0x%"PRIx32"] [%s] [%s]\n",
+                         open_global_id, create_guid_str, name);
+               TALLOC_FREE(frame);
+               return status;
+       }
+
+       if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
+               NDR_PRINT_DEBUG(smbXsrv_open_global0, global);
+       }
 
        status = smbXsrv_open_local_lookup(table,
-                                          rc.local_id,
-                                          0, /* global_id */
+                                          global->open_volatile_id,
+                                          global->open_persistent_id,
                                           now,
                                           &op);
-       if (!NT_STATUS_IS_OK(status)) {
-               DBG_ERR("stale local_id %u for create %s [%s] - %s\n",
-                       (unsigned)rc.local_id,
-                       create_guid_str,
-                       name,
-                       nt_errstr(status));
+       if (NT_STATUS_IS_OK(status)) {
+               DBG_DEBUG("Found local open\n");
 
+               /*
+                * We found an open the caller can reuse.
+                */
+               SMB_ASSERT(op != NULL);
+               *_open = op;
                TALLOC_FREE(frame);
-               return status;
+               return NT_STATUS_OK;
        }
 
-       /*
-        * We found an open the caller can reuse.
-        */
-       SMB_ASSERT(op != NULL);
-       *_open = op;
+       DBG_DEBUG("No local open\n");
        TALLOC_FREE(frame);
-       return NT_STATUS_OK;
+       return status;
 }
 
 struct smb2srv_open_recreate_state {