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 <[email protected]>
Date: Fri Jul 11 14:29:38 2025 +0200
docs: document serverid command
Signed-off-by: Ralph Boehme <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
Autobuild-User(master): Ralph Böhme <[email protected]>
Autobuild-Date(master): Tue Aug 5 16:03:56 UTC 2025 on atb-devel-224
commit 3b954ccbaab39f7ce3223eb6a28b0e9fde67d007
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit ebf53bcaa893914c49417d382a6b6384cbbaee50
Author: Ralph Boehme <[email protected]>
Date: Sat Jul 26 15:27:41 2025 +0200
net: handle replay records in `net serverid wipedbs`
Signed-off-by: Ralph Boehme <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit fdb3e0206f1a46a81ed93b91cdb8f51ec6ab1c63
Author: Ralph Boehme <[email protected]>
Date: Fri Jul 11 06:30:15 2025 +0200
smbd: return replay-cache records in smbXsrv_open_global_traverse()
Signed-off-by: Ralph Boehme <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 6a8bf702bb0bd63df18849545de88936db169989
Author: Ralph Boehme <[email protected]>
Date: Tue Jun 17 16:13:52 2025 +0200
smbd: reformat smbXsrv_open_global_traverse() function pointer args
Signed-off-by: Ralph Boehme <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 26ee66860795d2a9bdf0763517b84fba0bbe8c30
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 20c636926617b7232464b1ddb29018dd637a8bd1
Author: Ralph Boehme <[email protected]>
Date: Sat Jul 26 15:05:45 2025 +0200
smbd: make create-replay cache disk backed
Signed-off-by: Ralph Boehme <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit de1b2b0d07ef32ff8b9ab4fbf2bec51b227256ec
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 9b5b63870f7f0e0a5f89f14515529a9fdbfdb879
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 990322a48aa7d25b3ee126273186dba54d05a85d
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 9f9409a80ac4acdccfef08b13cd59d0f5dc38f8f
Author: Ralph Boehme <[email protected]>
Date: Fri Jul 11 06:49:54 2025 +0200
smbd: add smbXsrv_tcon to smbXsrv_open
Signed-off-by: Ralph Boehme <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit e61341297910f034c5fafa1662c2712147c737c2
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 3cd4018b7e49201065f16a62568ea47849c3fc60
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 7e8aa812a5deec7ef5afc5a457acdeb35a5f7dab
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 81fb4a7712203a63787ebad85002c7728708fda6
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 09e859756bb6fc9deee403212503fb4a567d1382
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit f6e7d85e632c7e5ef63cefe7dc3be2e83978e269
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit f149ab455d01ccdb7c29d58ce86a894db807d4c5
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit f97751a110e093e301d24e734d64a2a638dd7c8a
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit c63d63e36ab83be9a2d4a4df41f59bf7ae1af06a
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 93c1f55917ee0500b3c9fc169063cb3a5a492983
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 45aa16a77a55600cf972dcc11f2f003cd991ed73
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit cd672d1e2b7325a3734a69929f013adde46e7d2c
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 8695f2af60fa2245a11e0efd69ca63b2e0cc7bd1
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 12d5201d8eebf2d6834c7a36f5797ed9d5fce102
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit 06d13da577ae95eada1e63eaa203a1a9394bd4d4
Author: Ralph Boehme <[email protected]>
Date: Tue Jun 17 16:26:46 2025 +0200
smbd: fix include order in smbXsrv_open.c
Signed-off-by: Ralph Boehme <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
commit e5806227fd8d2fabf203b6060bd9ad9bde7380e1
Author: Ralph Boehme <[email protected]>
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 <[email protected]>
Reviewed-by: Stefan Metzmacher <[email protected]>
-----------------------------------------------------------------------
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