The branch, master has been updated via d41d9f8d29a docs: document serverid command via 3b954ccbaab net: add `net tdb smbXsrv wipedbs` alias for `net serverid wipedbs` via ebf53bcaa89 net: handle replay records in `net serverid wipedbs` via fdb3e0206f1 smbd: return replay-cache records in smbXsrv_open_global_traverse() via 6a8bf702bb0 smbd: reformat smbXsrv_open_global_traverse() function pointer args via 26ee6686079 smbd: also delete replay cache record in smbXsrv_open_cleanup() via 20c63692661 smbd: make create-replay cache disk backed via de1b2b0d07e libndr: add support for unions to ndr_pull_struct_blob_noalloc() and ndr_push_struct_into_fixed_blob() via 9b5b63870f7 smbd: implement session check from MS-SMB2 3.3.5.9 Receiving an SMB2 CREATE Request via 990322a48aa smbd: Add session_global_id and tcon_global_id to smbXsrv_open_global0 via 9f9409a80ac smbd: add smbXsrv_tcon to smbXsrv_open via e6134129791 smbd: add smbXsrv_session to smbXsrv_open via 3cd4018b7e4 smbd: add and use smbXsrv_open_replay_cache_key_buf via 7e8aa812a5d smbd: make the replay cache record an index on the global open table via 81fb4a77122 smbd: invert logic when handling pending create in smb2srv_open_lookup_replay_cache() via 09e859756bb smbd: move create_action to smbXsrv_open_global0 via f6e7d85e632 smbd: simplify create-replay via f149ab455d0 smbd: move DH2Q context processing to its own function via f97751a110e smbd: add some debugging to smbXsrv_open_[lookup|set]_replay_cache() via c63d63e36ab smbd: move create_action handling to smbd_smb2_create_after_exec() via 93c1f55917e smbd: simplify create_action handling via 45aa16a77a5 smbtorture: add test smb2.replay.replay-twice-durable via cd672d1e2b7 smbtorture: add test smb2.replay.durable-reconnect-replay3 via 8695f2af60f smbtorture: add test smb2.replay.durable-reconnect-replay2 via 12d5201d8ee smbtorture: add test smb2.replay.durable-reconnect-replay1 via 06d13da577a smbd: fix include order in smbXsrv_open.c via e5806227fd8 s3/dbwrap_watch: avoid leaking backend db handle in traverses from a4dff82e453 s3:utils: Allow ROLE_IPA_DC to allow to use Kerberos in gensec
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit d41d9f8d29ae66d90fab35b4f3f840cf0ea07d42 Author: Ralph Boehme <s...@samba.org> Date: Fri Jul 11 14:29:38 2025 +0200 docs: document serverid command Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> Autobuild-User(master): Ralph Böhme <s...@samba.org> Autobuild-Date(master): Tue Aug 5 16:03:56 UTC 2025 on atb-devel-224 commit 3b954ccbaab39f7ce3223eb6a28b0e9fde67d007 Author: Ralph Boehme <s...@samba.org> Date: Sun Jun 29 18:04:41 2025 +0200 net: add `net tdb smbXsrv wipedbs` alias for `net serverid wipedbs` `net serverid` is imho not the right place for the wipedbs functionality. Add it as an alias to `net tdb`. It works pretty opaque and unless you run # net tdb smbXsrv wipedbs --help Usage: net serverid wipedbs [--test] [--verbose] Example: net serverid wipedbs -v the use won't notice it is an alias. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit ebf53bcaa893914c49417d382a6b6384cbbaee50 Author: Ralph Boehme <s...@samba.org> Date: Sat Jul 26 15:27:41 2025 +0200 net: handle replay records in `net serverid wipedbs` Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit fdb3e0206f1a46a81ed93b91cdb8f51ec6ab1c63 Author: Ralph Boehme <s...@samba.org> Date: Fri Jul 11 06:30:15 2025 +0200 smbd: return replay-cache records in smbXsrv_open_global_traverse() Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 6a8bf702bb0bd63df18849545de88936db169989 Author: Ralph Boehme <s...@samba.org> Date: Tue Jun 17 16:13:52 2025 +0200 smbd: reformat smbXsrv_open_global_traverse() function pointer args Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 26ee66860795d2a9bdf0763517b84fba0bbe8c30 Author: Ralph Boehme <s...@samba.org> Date: Tue Jun 17 16:59:07 2025 +0200 smbd: also delete replay cache record in smbXsrv_open_cleanup() Add and use smbXsrv_replay_cleanup() to delete replay cache records. Another external caller comes later, hence adding this as a public function. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 20c636926617b7232464b1ddb29018dd637a8bd1 Author: Ralph Boehme <s...@samba.org> Date: Sat Jul 26 15:05:45 2025 +0200 smbd: make create-replay cache disk backed Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit de1b2b0d07ef32ff8b9ab4fbf2bec51b227256ec Author: Ralph Boehme <s...@samba.org> Date: Fri Jul 11 06:02:13 2025 +0200 libndr: add support for unions to ndr_pull_struct_blob_noalloc() and ndr_push_struct_into_fixed_blob() The union switch value is stored by ndr_token_store() which uses talloc to manage ndr.switch_list. Preallocate a ndr_token array and ndr_token_list on the stack of size ndr_token_list.fixed_alloc_count and optionally use that in ndr_token_store(). Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 9b5b63870f7f0e0a5f89f14515529a9fdbfdb879 Author: Ralph Boehme <s...@samba.org> Date: Thu Jul 10 16:48:22 2025 +0200 smbd: implement session check from MS-SMB2 3.3.5.9 Receiving an SMB2 CREATE Request If the server implements the SMB 3.x dialect family and all of the following conditions are TRUE, the server MUST look up an Open in GlobalOpenTable where Open.IsReplayEligible is TRUE and Open.CreateGuid matches the CreateGuid in the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 create context and Open.ClientGuid matches the ClientGuid of the connection that received this request: ... If an Open is found, the server MUST perform the following: ... If Open.Session.SessionId is not equal to the current Session.SessionId, the server MUST fail the request with STATUS_DUPLICATE_OBJECTID. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 990322a48aa7d25b3ee126273186dba54d05a85d Author: Ralph Boehme <s...@samba.org> Date: Thu Jul 10 13:10:42 2025 +0200 smbd: Add session_global_id and tcon_global_id to smbXsrv_open_global0 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 9f9409a80ac4acdccfef08b13cd59d0f5dc38f8f Author: Ralph Boehme <s...@samba.org> Date: Fri Jul 11 06:49:54 2025 +0200 smbd: add smbXsrv_tcon to smbXsrv_open Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit e61341297910f034c5fafa1662c2712147c737c2 Author: Ralph Boehme <s...@samba.org> Date: Sat Jun 28 08:55:25 2025 +0200 smbd: add smbXsrv_session to smbXsrv_open From "MS-SMB2 3.3.1.10 Per Open": Open.Session: A reference to the authenticated session, as specified in section 3.3.1.8, over which this open was performed. If the open is not attached to a session at this time, this value MUST be NULL. Needed to implement: 3.3.5.9 Receiving an SMB2 CREATE Request If the server implements the SMB 3.x dialect family and all of the following conditions are TRUE, the server MUST look up an Open in GlobalOpenTable where Open.IsReplayEligible is TRUE and Open.CreateGuid matches the CreateGuid in the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 create context and Open.ClientGuid matches the ClientGuid of the connection that received this request: ... If an Open is found, the server MUST perform the following: .. If Open.Session.SessionId is not equal to the current Session.SessionId, the server MUST fail the request with STATUS_DUPLICATE_OBJECTID. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 3cd4018b7e49201065f16a62568ea47849c3fc60 Author: Ralph Boehme <s...@samba.org> Date: Sat Jul 26 14:49:10 2025 +0200 smbd: add and use smbXsrv_open_replay_cache_key_buf No change in behaviour. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 7e8aa812a5deec7ef5afc5a457acdeb35a5f7dab Author: Ralph Boehme <s...@samba.org> Date: Thu Jul 10 16:31:16 2025 +0200 smbd: make the replay cache record an index on the global open table 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 <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 81fb4a7712203a63787ebad85002c7728708fda6 Author: Ralph Boehme <s...@samba.org> Date: Sat Jul 12 08:27:38 2025 +0200 smbd: invert logic when handling pending create in smb2srv_open_lookup_replay_cache() No change in behaviour. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 09e859756bb6fc9deee403212503fb4a567d1382 Author: Ralph Boehme <s...@samba.org> Date: Thu Jul 10 15:51:12 2025 +0200 smbd: move create_action to smbXsrv_open_global0 In preperation for making create replay disk backed. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit f6e7d85e632c7e5ef63cefe7dc3be2e83978e269 Author: Ralph Boehme <s...@samba.org> Date: Thu Jul 10 15:33:48 2025 +0200 smbd: simplify create-replay Just check state->open_was_deferred and skip calling smb2srv_open_lookup_replay_cache() if it is set. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit f149ab455d01ccdb7c29d58ce86a894db807d4c5 Author: Ralph Boehme <s...@samba.org> Date: Thu Jul 10 14:38:53 2025 +0200 smbd: move DH2Q context processing to its own function The DH2Q processing code is getting a bit bloated, move it to it's own function. This also simplifies a coming change where I'll add an early out. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit f97751a110e093e301d24e734d64a2a638dd7c8a Author: Ralph Boehme <s...@samba.org> Date: Sat Jun 14 19:13:44 2025 +0200 smbd: add some debugging to smbXsrv_open_[lookup|set]_replay_cache() Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit c63d63e36ab83be9a2d4a4df41f59bf7ae1af06a Author: Ralph Boehme <s...@samba.org> Date: Sat Jun 14 15:41:38 2025 +0200 smbd: move create_action handling to smbd_smb2_create_after_exec() This ensures op->create_action is set when we're calling smbXsrv_open_update() and fixes create_action handling for create replays. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 93c1f55917ee0500b3c9fc169063cb3a5a492983 Author: Ralph Boehme <s...@samba.org> Date: Tue Jul 8 14:47:24 2025 +0200 smbd: simplify create_action handling (state->info == FILE_WAS_OVERWRITTEN) can only happen when returning SMB_VFS_CREATE_FILE(), not for a Durable Handle reconnect or Replay, hence we can move the check and adjustment of state->info to smbd_smb2_create_send() after the call to SMB_VFS_CREATE_FILE(). This nicely simplifies the logic in smbd_smb2_create_finish() where we can now just set state->op->create_action and state->out_create_action to the value of state->info. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 45aa16a77a55600cf972dcc11f2f003cd991ed73 Author: Ralph Boehme <s...@samba.org> Date: Mon Jun 30 16:45:35 2025 +0200 smbtorture: add test smb2.replay.replay-twice-durable This verifies a second replay on a durable handle, after the handle has already been used, is "ignored" and handled as a normal open. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit cd672d1e2b7325a3734a69929f013adde46e7d2c Author: Ralph Boehme <s...@samba.org> Date: Mon Jun 30 12:17:24 2025 +0200 smbtorture: add test smb2.replay.durable-reconnect-replay3 This verifies a CREATE replay on a second connection with previous_session_id set is working correctly. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 8695f2af60fa2245a11e0efd69ca63b2e0cc7bd1 Author: Ralph Boehme <s...@samba.org> Date: Mon Jun 30 10:19:14 2025 +0200 smbtorture: add test smb2.replay.durable-reconnect-replay2 This verifies a replay on a new connection with a new sesssion fails with NT_STATUS_DUPLICATE_OBJECTID. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 12d5201d8eebf2d6834c7a36f5797ed9d5fce102 Author: Ralph Boehme <s...@samba.org> Date: Tue Jun 17 17:56:07 2025 +0200 smbtorture: add test smb2.replay.durable-reconnect-replay1 This verifies CREATE replay is working on a new connection. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 06d13da577ae95eada1e63eaa203a1a9394bd4d4 Author: Ralph Boehme <s...@samba.org> Date: Tue Jun 17 16:26:46 2025 +0200 smbd: fix include order in smbXsrv_open.c Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit e5806227fd8d2fabf203b6060bd9ad9bde7380e1 Author: Ralph Boehme <s...@samba.org> Date: Mon Jun 23 10:17:32 2025 +0200 s3/dbwrap_watch: avoid leaking backend db handle in traverses Currently in a traverse callback dbwrap_record_get_db() returns the backend db handle. Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> ----------------------------------------------------------------------- Summary of changes: docs-xml/manpages/net.8.xml | 36 +++ librpc/ndr/libndr.h | 1 + librpc/ndr/ndr.c | 26 ++- source3/lib/dbwrap/dbwrap_watch.c | 6 +- source3/librpc/idl/smbXsrv.idl | 17 +- source3/smbd/files.c | 3 +- source3/smbd/smb2_create.c | 272 +++++++++++++---------- source3/smbd/smbXsrv_open.c | 428 +++++++++++++++++++++++------------ source3/smbd/smbXsrv_open.h | 16 +- source3/utils/net_proto.h | 2 + source3/utils/net_serverid.c | 244 ++++++++++++++++++-- source3/utils/net_tdb.c | 24 ++ source4/torture/smb2/replay.c | 455 ++++++++++++++++++++++++++++++++++++++ 13 files changed, 1242 insertions(+), 288 deletions(-) Changeset truncated at 500 lines: diff --git a/docs-xml/manpages/net.8.xml b/docs-xml/manpages/net.8.xml index a2cdcac1e9c..d9293d0bb34 100644 --- a/docs-xml/manpages/net.8.xml +++ b/docs-xml/manpages/net.8.xml @@ -3141,6 +3141,13 @@ Dump the locking table of a certain global lock. </itemizedlist> </refsect3> + + <refsect3> + <title>tdb smbXsrv wipedbs</title> + <para>Clean stale entries from smbXsrv databases.</para> + <para>An alias for <command>net serverid wipedbs</command>. + </para> + </refsect3> </refsect2> <refsect2> @@ -3752,6 +3759,35 @@ net witness force-response Force an AsyncNotify response based on json input ( </refsect3> +</refsect2> + +<refsect2> + <title>serverid</title> + <para>Check existence of a serverid and clean stale entries from fileserver + state databases.</para> + <para>The following commands are implemented: + <simplelist> + <member>net serverid exists Check existence of a serverid</member> + <member>net serverid wipedbs Clean stale entries from fileserver state databases</member> + </simplelist> + </para> + +<refsect3> + <title>serverid exists <serverid></title> + <para>Checks if a serverid exits.</para> +</refsect3> + +<refsect3> + <title>serverid wipedbs</title> + <para>Clean stale entries from fileserver state databases</para> + <para>Options for wipedbs:</para> + <para> --test</para> + <para> Only check for stale entries and log them</para> + <para> --verbose</para> + <para> Produce verbose logging</para> +</refsect3> + + </refsect2> <refsect2> diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h index 344f08b20a1..7ee706c6085 100644 --- a/librpc/ndr/libndr.h +++ b/librpc/ndr/libndr.h @@ -44,6 +44,7 @@ struct ndr_token; struct ndr_token_list { struct ndr_token *tokens; uint32_t count; + uint32_t fixed_alloc_count; }; struct ndr_compression_state; diff --git a/librpc/ndr/ndr.c b/librpc/ndr/ndr.c index 082bacc2fa6..fc08b6661f8 100644 --- a/librpc/ndr/ndr.c +++ b/librpc/ndr/ndr.c @@ -48,6 +48,11 @@ */ #define NDR_TOKEN_MAX_LIST_SIZE 65535 +/* + * An arbitrary limit used by the fixed-size pull/push functions + */ +#define NDR_FIXED_SIZE_MARSHALL_MAX_TOKENS 10 + size_t ndr_token_max_list_size(void) { return NDR_TOKEN_MAX_LIST_SIZE; }; @@ -1081,6 +1086,12 @@ _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx, const void *key, uint32_t value) { + if (list->fixed_alloc_count != 0) { + if (list->count >= list->fixed_alloc_count) { + return NDR_ERR_RANGE; + } + goto store; + } if (list->tokens == NULL) { list->tokens = talloc_array(mem_ctx, struct ndr_token, 10); if (list->tokens == NULL) { @@ -1115,6 +1126,7 @@ _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx, list->tokens = new_tokens; } } +store: list->tokens[list->count].key = key; list->tokens[list->count].value = value; list->count++; @@ -1511,10 +1523,16 @@ _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_noalloc(const uint8_t *buf, * This allows us to keep the safety of the PIDL-generated * code without the talloc() overhead. */ + struct ndr_token tokens[NDR_FIXED_SIZE_MARSHALL_MAX_TOKENS]; + struct ndr_token_list switch_list = { + .tokens = tokens, + .fixed_alloc_count = ARRAY_SIZE(tokens), + }; struct ndr_pull ndr = { .data = discard_const_p(uint8_t, buf), .data_size = buflen, .current_mem_ctx = (void *)-1, + .switch_list = switch_list, }; NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p)); @@ -1632,10 +1650,16 @@ _PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem _PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob( DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn) { + struct ndr_token tokens[NDR_FIXED_SIZE_MARSHALL_MAX_TOKENS]; + struct ndr_token_list switch_list = { + .tokens = tokens, + .fixed_alloc_count = ARRAY_SIZE(tokens), + }; struct ndr_push ndr = { .data = blob->data, .alloc_size = blob->length, - .fixed_buf_size = true + .fixed_buf_size = true, + .switch_list = switch_list, }; NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p)); diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c index df931192c21..e62aba91090 100644 --- a/source3/lib/dbwrap/dbwrap_watch.c +++ b/source3/lib/dbwrap/dbwrap_watch.c @@ -653,6 +653,7 @@ static NTSTATUS dbwrap_watched_delete(struct db_record *rec) } struct dbwrap_watched_traverse_state { + struct db_context *db; int (*fn)(struct db_record *rec, void *private_data); void *private_data; }; @@ -672,6 +673,7 @@ static int dbwrap_watched_traverse_fn(struct db_record *rec, return 0; } prec.value_valid = true; + prec.db = state->db; return state->fn(&prec, state->private_data); } @@ -684,7 +686,7 @@ static int dbwrap_watched_traverse(struct db_context *db, struct db_watched_ctx *ctx = talloc_get_type_abort( db->private_data, struct db_watched_ctx); struct dbwrap_watched_traverse_state state = { - .fn = fn, .private_data = private_data }; + .db = db, .fn = fn, .private_data = private_data }; NTSTATUS status; int ret; @@ -704,7 +706,7 @@ static int dbwrap_watched_traverse_read(struct db_context *db, struct db_watched_ctx *ctx = talloc_get_type_abort( db->private_data, struct db_watched_ctx); struct dbwrap_watched_traverse_state state = { - .fn = fn, .private_data = private_data }; + .db = db, .fn = fn, .private_data = private_data }; NTSTATUS status; int ret; diff --git a/source3/librpc/idl/smbXsrv.idl b/source3/librpc/idl/smbXsrv.idl index 9aaa836cd7a..af7335e1d2a 100644 --- a/source3/librpc/idl/smbXsrv.idl +++ b/source3/librpc/idl/smbXsrv.idl @@ -422,6 +422,8 @@ interface smbXsrv typedef struct { server_id server_id; + hyper session_global_id; + uint32 tcon_global_id; uint32 open_global_id; hyper open_persistent_id; hyper open_volatile_id; @@ -430,6 +432,7 @@ interface smbXsrv GUID create_guid; GUID client_guid; GUID app_instance_id; + uint32 create_action; /* * TODO: for durable/resilient/persistent handles we need more * things here. See [MS-SMB2] 3.3.1.10 Per Open @@ -473,11 +476,12 @@ interface smbXsrv [ignore] smbXsrv_open_table *table; uint32 local_id; [ref] smbXsrv_open_global0 *global; + smbXsrv_session *session; + smbXsrv_tcon *tcon; NTSTATUS status; NTTIME idle_time; [ignore] files_struct *compat; smbXsrv_open_flags flags; - uint32 create_action; hyper request_count; hyper pre_request_count; } smbXsrv_open; @@ -493,10 +497,13 @@ interface smbXsrv [switch_is(version)] smbXsrv_openU info; } smbXsrv_openB; - const uint32 SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE = 28; + const uint32 SMBXSRV_OPEN_REPLAY_CACHE_KEY_FIXED_SIZE = 32; typedef [public] struct { - GUID holder_req_guid; - NTTIME idle_time; - uint32 local_id; + GUID client_guid; + GUID create_guid; + } smbXsrv_open_replay_cache_key; + + typedef [public] struct { + DATA_BLOB open_global_key; } smbXsrv_open_replay_cache; } diff --git a/source3/smbd/files.c b/source3/smbd/files.c index 73c20b68004..4cc203d8a1a 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -120,7 +120,8 @@ NTSTATUS fsp_bind_smb(struct files_struct *fsp, struct smb_request *req) now = timeval_to_nttime(&fsp->open_time); status = smbXsrv_open_create(req->xconn, - fsp->conn->session_info, + req->session, + fsp->conn->tcon, now, &op); if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index 12e87ec7b6f..f8f63e85287 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -682,6 +682,7 @@ struct smbd_smb2_create_state { struct deferred_open_record *open_rec; files_struct *result; bool replay_operation; + bool replay_reconnect; uint8_t in_oplock_level; uint32_t in_create_disposition; uint32_t in_create_options; @@ -1078,11 +1079,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, * there is nothing else to do), durable_reconnect or * new open. */ - if (state->replay_operation) { + if (state->replay_operation && !state->replay_reconnect) { + SMB_ASSERT(state->op != NULL); state->result = state->op->compat; state->result->op = state->op; state->update_open = false; - state->info = state->op->create_action; + state->info = state->op->global->create_action; smbd_smb2_create_after_exec(req); if (!tevent_req_is_in_progress(req)) { @@ -1093,16 +1095,23 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, return req; } - if (state->do_durable_reconnect) { + if (state->do_durable_reconnect || state->replay_reconnect) { DATA_BLOB new_cookie = data_blob_null; NTTIME now = timeval_to_nttime(&smb2req->request_time); const struct smb2_lease_key *lease_key = NULL; + /* + * Assert a replay on a multichannel connection doesn't end up + * here. + */ + SMB_ASSERT(state->op == NULL); + if (state->lease_ptr != NULL) { lease_key = &state->lease_ptr->lease_key; } status = smb2srv_open_recreate(smb2req->xconn, - smb1req->conn->session_info, + smb2req->session, + smb2req->tcon, state->persistent_id, state->create_guid, lease_key, @@ -1167,7 +1176,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, state->update_open = true; - state->info = FILE_WAS_OPENED; + if (!state->replay_reconnect) { + state->info = FILE_WAS_OPENED; + } else { + state->info = state->op->global->create_action; + } smbd_smb2_create_after_exec(req); if (!tevent_req_is_in_progress(req)) { @@ -1325,6 +1338,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, } state->op = state->result->op; + if ((state->in_create_disposition == FILE_SUPERSEDE) && + (state->info == FILE_WAS_OVERWRITTEN)) + { + state->info = FILE_WAS_SUPERSEDED; + } + smbd_smb2_create_after_exec(req); if (!tevent_req_is_in_progress(req)) { return tevent_req_post(req, state->ev); @@ -1359,6 +1378,135 @@ static void smbd_smb2_create_purge_replay_cache(struct tevent_req *req, state->purge_create_guid = NULL; } +static void smbd_smb2_cc_before_exec_dhc2q(struct tevent_req *req) +{ + struct smbd_smb2_create_state *state = tevent_req_data( + req, struct smbd_smb2_create_state); + struct smbd_smb2_request *smb2req = state->smb2req; + const uint8_t *p = state->dh2q->data.data; + NTTIME now = timeval_to_nttime(&smb2req->request_time); + uint32_t durable_v2_timeout = 0; + DATA_BLOB create_guid_blob; + const uint8_t *hdr = NULL; + uint32_t flags; + NTSTATUS status; + + if (state->dh2q->data.length != 32) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + if (state->dhnq != NULL) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + durable_v2_timeout = IVAL(p, 0); + create_guid_blob = data_blob_const(p + 16, 16); + + status = GUID_from_ndr_blob(&create_guid_blob, + &state->_create_guid); + if (tevent_req_nterror(req, status)) { + return; + } + state->create_guid = &state->_create_guid; + + /* + * we need to store the create_guid later + */ + state->update_open = true; + + /* + * And we need to create a cache for replaying the + * create. + */ + state->need_replay_cache = true; + + /* + * durable handle v2 request processed below + */ + state->durable_requested = true; + state->durable_timeout_msec = MIN(durable_v2_timeout, 300*1000); + if (state->durable_timeout_msec == 0) { + /* + * Set the timeout to 1 min as default. + * + * This matches Windows 2012. + */ + state->durable_timeout_msec = (60*1000); + } + + /* + * Check for replay operation. + * Only consider it when we have dh2q. + * If we do not have a replay operation, verify that + * the create_guid is not cached for replay. + */ + hdr = SMBD_SMB2_IN_HDR_PTR(smb2req); + flags = IVAL(hdr, SMB2_HDR_FLAGS); + state->replay_operation = flags & SMB2_HDR_FLAG_REPLAY_OPERATION; + + if (state->open_was_deferred) { + /* + * When processing a redispatched deferred open, we have the + * following state: + * - no OPEN record + * - RC record with global_file_id=0 (pending open state) + * + * We just skip calling smb2srv_open_lookup_replay_cache() as + * - we already have a RC record + * - it would fail with NT_STATUS_FILE_NOT_AVAILABLE which is + * not what we want in this "internal replay" case + * + * So we just set replay_operation to false and move on. + */ + state->replay_operation = false; + return; + } + + status = smb2srv_open_lookup_replay_cache(smb2req->xconn, + smb2req->session, + *state->create_guid, + state->fname, + now, + &state->persistent_id, + &state->op); + if (NT_STATUS_EQUAL(status, NT_STATUS_FWP_RESERVED)) { + /* + * We've reserved the replay_cache record + * for ourself, indicating we're still + * in progress. + * + * It means the smbd_smb2_create_cleanup() + * may need to call smbXsrv_open_purge_replay_cache() + * in order to cleanup. + */ + SMB_ASSERT(state->op == NULL); + state->_purge_create_guid = state->_create_guid; + state->purge_create_guid = &state->_purge_create_guid; + state->replay_operation = false; + } else if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_NOT_AVAILABLE)) { + tevent_req_nterror(req, status); + return; + } else if (NT_STATUS_EQUAL(status, NT_STATUS_HANDLE_NO_LONGER_VALID)) { + state->replay_reconnect = true; + } else if (tevent_req_nterror(req, status)) { + DBG_WARNING("smb2srv_open_lookup_replay_cache " + "failed: %s\n", nt_errstr(status)); + return; + } else if (!state->replay_operation) { + /* + * If a create without replay operation flag + * is sent but with a create_guid that is + * currently in the replay cache -- fail. + */ + (void)tevent_req_nterror(req, NT_STATUS_DUPLICATE_OBJECTID); + return; + } + + return; +} + static void smbd_smb2_create_before_exec(struct tevent_req *req) { struct smbd_smb2_create_state *state = tevent_req_data( @@ -1444,105 +1592,8 @@ static void smbd_smb2_create_before_exec(struct tevent_req *req) } if (state->dh2q != NULL) { - const uint8_t *p = state->dh2q->data.data; - NTTIME now = timeval_to_nttime(&smb2req->request_time); - uint32_t durable_v2_timeout = 0; - DATA_BLOB create_guid_blob; - const uint8_t *hdr; - uint32_t flags; - - if (state->dh2q->data.length != 32) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (state->dhnq != NULL) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - durable_v2_timeout = IVAL(p, 0); - create_guid_blob = data_blob_const(p + 16, 16); - - status = GUID_from_ndr_blob(&create_guid_blob, - &state->_create_guid); - if (tevent_req_nterror(req, status)) { - return; - } - state->create_guid = &state->_create_guid; - - /* - * we need to store the create_guid later - */ - state->update_open = true; - - /* - * And we need to create a cache for replaying the - * create. - */ - state->need_replay_cache = true; - -- Samba Shared Repository