From c70da3a0fba246bedbb7aa49bf448db4352e2c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Fri, 15 Jan 2016 18:07:31 +0100 Subject: [PATCH 01/40] s4-torture: let smb2.replay.replay2 test deal with scale out shares. Guenther Signed-off-by: Guenther Deschner Reviewed-by: Jeremy Allison --- source4/torture/smb2/replay.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 57b14f1..83d36a3 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -302,12 +302,17 @@ static bool test_replay2(struct torture_context *tctx, struct smb2_tree *tree) bool ret = true; const char *fname = BASEDIR "\\replay2.dat"; struct smb2_transport *transport = tree->session->transport; + uint32_t share_capabilities; + bool share_is_so; if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "SMB 3.X Dialect family required for " "replay tests\n"); } + share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli); + share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; + ZERO_STRUCT(break_info); break_info.tctx = tctx; tree->session->transport->oplock.handler = torture_oplock_ack_handler; @@ -336,10 +341,16 @@ static bool test_replay2(struct torture_context *tctx, struct smb2_tree *tree) _h = io.out.file.handle; h = &_h; CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); - CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); CHECK_VAL(io.out.durable_open, false); - CHECK_VAL(io.out.durable_open_v2, true); - CHECK_VAL(io.out.timeout, io.in.timeout); + if (share_is_so) { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s")); + CHECK_VAL(io.out.durable_open_v2, false); + CHECK_VAL(io.out.timeout, 0); + } else { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); + CHECK_VAL(io.out.durable_open_v2, true); + CHECK_VAL(io.out.timeout, io.in.timeout); + } /* * Replay Durable V2 Create on single channel @@ -392,10 +403,13 @@ static bool test_replay2(struct torture_context *tctx, struct smb2_tree *tree) io.in.durable_open_v2 = false; status = smb2_create(tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); - CHECK_VAL(break_info.count, 1); - CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle); - CHECK_VAL(break_info.level, smb2_util_oplock_level("s")); - ZERO_STRUCT(break_info); + + if (!share_is_so) { + CHECK_VAL(break_info.count, 1); + CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle); + CHECK_VAL(break_info.level, smb2_util_oplock_level("s")); + ZERO_STRUCT(break_info); + } smb2_util_close(tree, *h); h = NULL; -- 2.5.0 From 884d04b941c08f261028a857b1b51168d068b8c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Fri, 15 Jan 2016 18:24:08 +0100 Subject: [PATCH 02/40] s4-torture: let smb2.replay.replay3 test deal with scale out shares. Guenther Signed-off-by: Guenther Deschner Reviewed-by: Jeremy Allison --- source4/torture/smb2/replay.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 83d36a3..f045e17 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -485,12 +485,17 @@ static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1) struct smb2_transport *transport2 = NULL; struct smb2_session *session1_1 = tree1->session; struct smb2_session *session1_2 = NULL; + uint32_t share_capabilities; + bool share_is_so; if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "SMB 3.X Dialect family required for " "Replay tests\n"); } + share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli); + share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; + ZERO_STRUCT(break_info); break_info.tctx = tctx; transport1->oplock.handler = torture_oplock_ack_handler; @@ -522,10 +527,16 @@ static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1) _h = io.out.file.handle; h = &_h; CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); - CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); + if (share_is_so) { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s")); + CHECK_VAL(io.out.durable_open_v2, false); + CHECK_VAL(io.out.timeout, 0); + } else { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); + CHECK_VAL(io.out.durable_open_v2, true); + CHECK_VAL(io.out.timeout, io.in.timeout); + } CHECK_VAL(io.out.durable_open, false); - CHECK_VAL(io.out.durable_open_v2, true); - CHECK_VAL(io.out.timeout, io.in.timeout); CHECK_VAL(break_info.count, 0); status = smb2_connect(tctx, @@ -571,10 +582,16 @@ static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1) _h = io.out.file.handle; h = &_h; CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); - CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); + if (share_is_so) { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s")); + CHECK_VAL(io.out.durable_open_v2, false); + CHECK_VAL(io.out.timeout, 0); + } else { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); + CHECK_VAL(io.out.durable_open_v2, true); + CHECK_VAL(io.out.timeout, io.in.timeout); + } CHECK_VAL(io.out.durable_open, false); - CHECK_VAL(io.out.durable_open_v2, true); - CHECK_VAL(io.out.timeout, io.in.timeout); CHECK_VAL(break_info.count, 0); tree1->session = session1_1; -- 2.5.0 From d134d40ff346a884baa3d780e0d07bd86933ace0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Fri, 15 Jan 2016 18:30:15 +0100 Subject: [PATCH 03/40] s4-torture: let smb2.replay.replay4 test deal with scale out shares. Guenther Signed-off-by: Guenther Deschner Reviewed-by: Jeremy Allison --- source4/torture/smb2/replay.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index f045e17..4b3f569 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -640,12 +640,17 @@ static bool test_replay4(struct torture_context *tctx, struct smb2_tree *tree1) struct smb2_session *session1_1 = tree1->session; struct smb2_session *session1_2 = NULL; uint16_t curr_cs; + uint32_t share_capabilities; + bool share_is_so; if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "SMB 3.X Dialect family required for " "Replay tests\n"); } + share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli); + share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; + ZERO_STRUCT(break_info); break_info.tctx = tctx; transport1->oplock.handler = torture_oplock_ack_handler; @@ -677,10 +682,16 @@ static bool test_replay4(struct torture_context *tctx, struct smb2_tree *tree1) _h1 = io.out.file.handle; h1 = &_h1; CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); - CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); + if (share_is_so) { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s")); + CHECK_VAL(io.out.durable_open_v2, false); + CHECK_VAL(io.out.timeout, 0); + } else { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); + CHECK_VAL(io.out.durable_open_v2, true); + CHECK_VAL(io.out.timeout, io.in.timeout); + } CHECK_VAL(io.out.durable_open, false); - CHECK_VAL(io.out.durable_open_v2, true); - CHECK_VAL(io.out.timeout, io.in.timeout); CHECK_VAL(break_info.count, 0); status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf)); @@ -821,7 +832,11 @@ static bool test_replay4(struct torture_context *tctx, struct smb2_tree *tree1) smb2_util_close(tree1, *h1); h1 = NULL; - CHECK_VAL(break_info.count, 0); + if (share_is_so) { + CHECK_VAL(break_info.count, 1); + } else { + CHECK_VAL(break_info.count, 0); + } done: talloc_free(tree2); tree1->session = session1_1; -- 2.5.0 From 15bafd790990774edf0fd81aaaabab142a99f24c Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 22 Feb 2016 14:32:44 +0100 Subject: [PATCH 04/40] torture:smb2: rewrite connect test to use torture_asserts Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source4/torture/smb2/connect.c | 63 ++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 43 deletions(-) diff --git a/source4/torture/smb2/connect.c b/source4/torture/smb2/connect.c index 0067de0..6fd331a 100644 --- a/source4/torture/smb2/connect.c +++ b/source4/torture/smb2/connect.c @@ -194,74 +194,51 @@ bool torture_smb2_connect(struct torture_context *torture) struct smb2_request *req; struct smb2_handle h1, h2; NTSTATUS status; + bool ok; - if (!torture_smb2_connection(torture, &tree)) { - return false; - } + ok = torture_smb2_connection(torture, &tree); + torture_assert(torture, ok, "torture_smb2_connection failed"); smb2_util_unlink(tree, "test9.dat"); h1 = torture_smb2_createfile(tree, "test9.dat"); h2 = torture_smb2_createfile(tree, "test9.dat"); + status = torture_smb2_write(torture, tree, h1); - if (!NT_STATUS_IS_OK(status)) { - printf("Write failed - %s\n", nt_errstr(status)); - return false; - } + torture_assert_ntstatus_ok(torture, status, "write failed"); + status = torture_smb2_close(tree, h1); - if (!NT_STATUS_IS_OK(status)) { - printf("Close failed - %s\n", nt_errstr(status)); - return false; - } + torture_assert_ntstatus_ok(torture, status, "close failed"); + status = torture_smb2_close(tree, h2); - if (!NT_STATUS_IS_OK(status)) { - printf("Close failed - %s\n", nt_errstr(status)); - return false; - } + torture_assert_ntstatus_ok(torture, status, "close failed"); status = smb2_util_close(tree, h1); - if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED)) { - printf("close should have closed the handle - %s\n", nt_errstr(status)); - return false; - } + torture_assert_ntstatus_equal(torture, status, NT_STATUS_FILE_CLOSED, + "close should have closed the handle"); status = smb2_tdis(tree); - if (!NT_STATUS_IS_OK(status)) { - printf("tdis failed - %s\n", nt_errstr(status)); - return false; - } + torture_assert_ntstatus_ok(torture, status, "tdis failed"); status = smb2_tdis(tree); - if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) { - printf("tdis should have disabled session - %s\n", nt_errstr(status)); - return false; - } + torture_assert_ntstatus_equal(torture, status, + NT_STATUS_NETWORK_NAME_DELETED, + "tdis should have closed the tcon"); status = smb2_logoff(tree->session); - if (!NT_STATUS_IS_OK(status)) { - printf("Logoff failed - %s\n", nt_errstr(status)); - return false; - } + torture_assert_ntstatus_ok(torture, status, "logoff failed"); req = smb2_logoff_send(tree->session); - if (!req) { - printf("smb2_logoff_send() failed\n"); - return false; - } + torture_assert_not_null(torture, req, "smb2_logoff_send failed"); req->session = NULL; status = smb2_logoff_recv(req); - if (!NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) { - printf("Logoff should have disabled session - %s\n", nt_errstr(status)); - return false; - } + torture_assert_ntstatus_equal(torture, status, NT_STATUS_USER_SESSION_DELETED, + "logoff should have disabled session"); status = smb2_keepalive(tree->session->transport); - if (!NT_STATUS_IS_OK(status)) { - printf("keepalive failed? - %s\n", nt_errstr(status)); - return false; - } + torture_assert_ntstatus_ok(torture, status, "keepalive failed"); talloc_free(mem_ctx); -- 2.5.0 From c4c70b038913ae988ccda1aa26d4d772d85aec5c Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 22 Feb 2016 16:22:14 +0100 Subject: [PATCH 05/40] torture:smb2: rewrite connect test to use torture_asserts for create errors let torture_smb2_createfile propagate errors Signed-off-by: Michael Adam --- source4/torture/smb2/connect.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/source4/torture/smb2/connect.c b/source4/torture/smb2/connect.c index 6fd331a..f68c34f 100644 --- a/source4/torture/smb2/connect.c +++ b/source4/torture/smb2/connect.c @@ -137,8 +137,9 @@ static NTSTATUS torture_smb2_write(struct torture_context *tctx, struct smb2_tre /* send a create */ -static struct smb2_handle torture_smb2_createfile(struct smb2_tree *tree, - const char *fname) +static NTSTATUS torture_smb2_createfile(struct smb2_tree *tree, + const char *fname, + struct smb2_handle *handle) { struct smb2_create io; NTSTATUS status; @@ -158,8 +159,7 @@ static struct smb2_handle torture_smb2_createfile(struct smb2_tree *tree, status = smb2_create(tree, tmp_ctx, &io); if (!NT_STATUS_IS_OK(status)) { - printf("create1 failed - %s\n", nt_errstr(status)); - return io.out.file.handle; + return status; } if (DEBUGLVL(1)) { @@ -179,8 +179,10 @@ static struct smb2_handle torture_smb2_createfile(struct smb2_tree *tree, } talloc_free(tmp_ctx); - - return io.out.file.handle; + + *handle = io.out.file.handle; + + return NT_STATUS_OK; } @@ -201,8 +203,11 @@ bool torture_smb2_connect(struct torture_context *torture) smb2_util_unlink(tree, "test9.dat"); - h1 = torture_smb2_createfile(tree, "test9.dat"); - h2 = torture_smb2_createfile(tree, "test9.dat"); + status = torture_smb2_createfile(tree, "test9.dat", &h1); + torture_assert_ntstatus_ok(torture, status, "create failed"); + + status = torture_smb2_createfile(tree, "test9.dat", &h2); + torture_assert_ntstatus_ok(torture, status, "create failed"); status = torture_smb2_write(torture, tree, h1); torture_assert_ntstatus_ok(torture, status, "write failed"); -- 2.5.0 From 88d25932f65bc33f79c42ba2afee4ebe5a5c8354 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 22 Feb 2016 23:23:13 +0100 Subject: [PATCH 06/40] torture:smb2: fix memory leak in connect test. Signed-off-by: Michael Adam --- source4/torture/smb2/connect.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source4/torture/smb2/connect.c b/source4/torture/smb2/connect.c index f68c34f..e3716be 100644 --- a/source4/torture/smb2/connect.c +++ b/source4/torture/smb2/connect.c @@ -159,6 +159,7 @@ static NTSTATUS torture_smb2_createfile(struct smb2_tree *tree, status = smb2_create(tree, tmp_ctx, &io); if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(tmp_ctx); return status; } -- 2.5.0 From 2d7db94a1e26900b526b5bac3e23d68c31d2b39c Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 23 Feb 2016 00:27:11 +0100 Subject: [PATCH 07/40] torture:smb2: improve torture_comments in connect test Signed-off-by: Michael Adam Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Tue Feb 23 04:50:53 CET 2016 on sn-devel-144 --- source4/torture/smb2/connect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source4/torture/smb2/connect.c b/source4/torture/smb2/connect.c index e3716be..6340430 100644 --- a/source4/torture/smb2/connect.c +++ b/source4/torture/smb2/connect.c @@ -90,7 +90,7 @@ static NTSTATUS torture_smb2_write(struct torture_context *tctx, struct smb2_tre status = smb2_write(tree, &w); if (!NT_STATUS_IS_OK(status)) { - printf("write failed - %s\n", nt_errstr(status)); + printf("write 1 failed - %s\n", nt_errstr(status)); return status; } @@ -98,7 +98,7 @@ static NTSTATUS torture_smb2_write(struct torture_context *tctx, struct smb2_tre status = smb2_write(tree, &w); if (!NT_STATUS_IS_OK(status)) { - printf("write failed - %s\n", nt_errstr(status)); + printf("write 2 failed - %s\n", nt_errstr(status)); return status; } -- 2.5.0 From 5196d6ec3e0c04ce7a50f966b7409f49f696e365 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 26 Feb 2016 00:41:24 +0100 Subject: [PATCH 08/40] smbXsrv_open: factor fetch-locking of global record into function smbXsrv_open_global_fetch_locked() Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source3/smbd/smbXsrv_open.c | 85 +++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 49 deletions(-) diff --git a/source3/smbd/smbXsrv_open.c b/source3/smbd/smbXsrv_open.c index 1fe8b1b..737b2b9 100644 --- a/source3/smbd/smbXsrv_open.c +++ b/source3/smbd/smbXsrv_open.c @@ -151,6 +151,27 @@ static NTSTATUS smbXsrv_open_local_key_to_id(TDB_DATA key, uint32_t *id) return NT_STATUS_OK; } +static struct db_record *smbXsrv_open_global_fetch_locked( + struct db_context *db, + uint32_t id, + TALLOC_CTX *mem_ctx) +{ + TDB_DATA key; + uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE]; + struct db_record *rec = NULL; + + key = smbXsrv_open_global_id_to_key(id, key_buf); + + rec = dbwrap_fetch_locked(db, mem_ctx, key); + + if (rec == NULL) { + DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id, + hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); + } + + return rec; +} + static NTSTATUS smbXsrv_open_table_init(struct smbXsrv_connection *conn, uint32_t lowest_id, uint32_t highest_id, @@ -494,8 +515,6 @@ static NTSTATUS smbXsrv_open_global_allocate(struct db_context *db, bool is_free = false; bool was_free = false; uint32_t id; - uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; if (i >= min_tries && last_free != 0) { id = last_free; @@ -509,9 +528,7 @@ static NTSTATUS smbXsrv_open_global_allocate(struct db_context *db, id--; } - key = smbXsrv_open_global_id_to_key(id, key_buf); - - global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key); + global->db_rec = smbXsrv_open_global_fetch_locked(db, id, mem_ctx); if (global->db_rec == NULL) { talloc_free(global); return NT_STATUS_INSUFFICIENT_RESOURCES; @@ -717,8 +734,6 @@ static NTSTATUS smbXsrv_open_global_lookup(struct smbXsrv_open_table *table, TALLOC_CTX *mem_ctx, struct smbXsrv_open_global0 **_global) { - TDB_DATA key; - uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE]; struct db_record *global_rec = NULL; bool is_free = false; @@ -728,15 +743,10 @@ static NTSTATUS smbXsrv_open_global_lookup(struct smbXsrv_open_table *table, return NT_STATUS_INTERNAL_ERROR; } - key = smbXsrv_open_global_id_to_key(open_global_id, key_buf); - - global_rec = dbwrap_fetch_locked(table->global.db_ctx, mem_ctx, key); + global_rec = smbXsrv_open_global_fetch_locked(table->global.db_ctx, + open_global_id, + mem_ctx); if (global_rec == NULL) { - DEBUG(0, ("smbXsrv_open_global_lookup(0x%08x): " - "Failed to lock global key '%s'\n", - open_global_id, - hex_encode_talloc(talloc_tos(), key.dptr, - key.dsize))); return NT_STATUS_INTERNAL_DB_ERROR; } @@ -909,8 +919,6 @@ NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op) { struct smbXsrv_open_table *table = op->table; NTSTATUS status; - uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; if (op->global->db_rec != NULL) { DEBUG(0, ("smbXsrv_open_update(0x%08x): " @@ -919,17 +927,11 @@ NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op) return NT_STATUS_INTERNAL_ERROR; } - key = smbXsrv_open_global_id_to_key(op->global->open_global_id, - key_buf); - - op->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx, - op->global, key); + op->global->db_rec = smbXsrv_open_global_fetch_locked( + table->global.db_ctx, + op->global->open_global_id, + op->global /* TALLOC_CTX */); if (op->global->db_rec == NULL) { - DEBUG(0, ("smbXsrv_open_update(0x%08x): " - "Failed to lock global key '%s'\n", - op->global->open_global_id, - hex_encode_talloc(talloc_tos(), key.dptr, - key.dsize))); return NT_STATUS_INTERNAL_DB_ERROR; } @@ -979,21 +981,11 @@ NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now) global_rec = op->global->db_rec; op->global->db_rec = NULL; if (global_rec == NULL) { - uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; - - key = smbXsrv_open_global_id_to_key( - op->global->open_global_id, - key_buf); - - global_rec = dbwrap_fetch_locked(table->global.db_ctx, - op->global, key); + global_rec = smbXsrv_open_global_fetch_locked( + table->global.db_ctx, + op->global->open_global_id, + op->global /* TALLOC_CTX */); if (global_rec == NULL) { - DEBUG(0, ("smbXsrv_open_close(0x%08x): " - "Failed to lock global key '%s'\n", - op->global->open_global_id, - hex_encode_talloc(global_rec, key.dptr, - key.dsize))); error = NT_STATUS_INTERNAL_ERROR; } } @@ -1403,21 +1395,16 @@ NTSTATUS smbXsrv_open_cleanup(uint64_t persistent_id) NTSTATUS status = NT_STATUS_OK; TALLOC_CTX *frame = talloc_stackframe(); struct smbXsrv_open_global0 *op = NULL; - uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; TDB_DATA val; struct db_record *rec; bool delete_open = false; uint32_t global_id = persistent_id & UINT32_MAX; - key = smbXsrv_open_global_id_to_key(global_id, key_buf); - rec = dbwrap_fetch_locked(smbXsrv_open_global_db_ctx, frame, key); + rec = smbXsrv_open_global_fetch_locked(smbXsrv_open_global_db_ctx, + global_id, + frame); if (rec == NULL) { status = NT_STATUS_NOT_FOUND; - DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] " - "failed to fetch record from %s - %s\n", - global_id, dbwrap_name(smbXsrv_open_global_db_ctx), - nt_errstr(status))); goto done; } -- 2.5.0 From 17fa947e108f63152d464e25cd81e6710eeba28b Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 26 Feb 2016 00:53:22 +0100 Subject: [PATCH 09/40] smbXsrv_open: factor fetch-locking of local record into function smbXsrv_open_local_fetch_locked() Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Fri Feb 26 22:35:28 CET 2016 on sn-devel-144 --- source3/smbd/smbXsrv_open.c | 48 ++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/source3/smbd/smbXsrv_open.c b/source3/smbd/smbXsrv_open.c index 737b2b9..ee35f2d 100644 --- a/source3/smbd/smbXsrv_open.c +++ b/source3/smbd/smbXsrv_open.c @@ -172,6 +172,27 @@ static struct db_record *smbXsrv_open_global_fetch_locked( return rec; } +static struct db_record *smbXsrv_open_local_fetch_locked( + struct db_context *db, + uint32_t id, + TALLOC_CTX *mem_ctx) +{ + TDB_DATA key; + uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE]; + struct db_record *rec = NULL; + + key = smbXsrv_open_local_id_to_key(id, key_buf); + + rec = dbwrap_fetch_locked(db, mem_ctx, key); + + if (rec == NULL) { + DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id, + hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); + } + + return rec; +} + static NTSTATUS smbXsrv_open_table_init(struct smbXsrv_connection *conn, uint32_t lowest_id, uint32_t highest_id, @@ -296,8 +317,6 @@ static NTSTATUS smbXsrv_open_local_allocate_id(struct db_context *db, for (i = 0; i < (range / 2); i++) { uint32_t id; - uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE]; - TDB_DATA key; TDB_DATA val; struct db_record *rec = NULL; @@ -311,9 +330,7 @@ static NTSTATUS smbXsrv_open_local_allocate_id(struct db_context *db, id = highest_id; } - key = smbXsrv_open_local_id_to_key(id, key_buf); - - rec = dbwrap_fetch_locked(db, mem_ctx, key); + rec = smbXsrv_open_local_fetch_locked(db, id, mem_ctx); if (rec == NULL) { return NT_STATUS_INSUFFICIENT_RESOURCES; } @@ -363,16 +380,12 @@ static NTSTATUS smbXsrv_open_local_allocate_id(struct db_context *db, if (NT_STATUS_IS_OK(state.status)) { uint32_t id; - uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE]; - TDB_DATA key; TDB_DATA val; struct db_record *rec = NULL; id = state.useable_id; - key = smbXsrv_open_local_id_to_key(id, key_buf); - - rec = dbwrap_fetch_locked(db, mem_ctx, key); + rec = smbXsrv_open_local_fetch_locked(db, id, mem_ctx); if (rec == NULL) { return NT_STATUS_INSUFFICIENT_RESOURCES; } @@ -1044,19 +1057,10 @@ NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now) local_rec = op->db_rec; if (local_rec == NULL) { - uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE]; - TDB_DATA key; - - key = smbXsrv_open_local_id_to_key(op->local_id, key_buf); - - local_rec = dbwrap_fetch_locked(table->local.db_ctx, - op, key); + local_rec = smbXsrv_open_local_fetch_locked(table->local.db_ctx, + op->local_id, + op /* TALLOC_CTX*/); if (local_rec == NULL) { - DEBUG(0, ("smbXsrv_open_close(0x%08x): " - "Failed to lock local key '%s'\n", - op->global->open_global_id, - hex_encode_talloc(local_rec, key.dptr, - key.dsize))); error = NT_STATUS_INTERNAL_ERROR; } } -- 2.5.0 From 58007fc7c2ca8cb56d7fd1d4a3aedffa43d7a358 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Sat, 27 Feb 2016 00:52:59 +0100 Subject: [PATCH 10/40] smbXsrv_tcon: factor fetch-locking of global record into function Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source3/smbd/smbXsrv_tcon.c | 61 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/source3/smbd/smbXsrv_tcon.c b/source3/smbd/smbXsrv_tcon.c index 1d2a141..5f10c49 100644 --- a/source3/smbd/smbXsrv_tcon.c +++ b/source3/smbd/smbXsrv_tcon.c @@ -150,6 +150,27 @@ static NTSTATUS smbXsrv_tcon_local_key_to_id(TDB_DATA key, uint32_t *id) return NT_STATUS_OK; } +static struct db_record *smbXsrv_tcon_global_fetch_locked( + struct db_context *db, + uint32_t id, + TALLOC_CTX *mem_ctx) +{ + TDB_DATA key; + uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE]; + struct db_record *rec = NULL; + + key = smbXsrv_tcon_global_id_to_key(id, key_buf); + + rec = dbwrap_fetch_locked(db, mem_ctx, key); + + if (rec == NULL) { + DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id, + hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); + } + + return rec; +} + static NTSTATUS smbXsrv_tcon_table_init(TALLOC_CTX *mem_ctx, struct smbXsrv_tcon_table *table, uint32_t lowest_id, @@ -473,8 +494,6 @@ static NTSTATUS smbXsrv_tcon_global_allocate(struct db_context *db, bool is_free = false; bool was_free = false; uint32_t id; - uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; if (i >= min_tries && last_free != 0) { id = last_free; @@ -488,9 +507,8 @@ static NTSTATUS smbXsrv_tcon_global_allocate(struct db_context *db, id--; } - key = smbXsrv_tcon_global_id_to_key(id, key_buf); - - global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key); + global->db_rec = smbXsrv_tcon_global_fetch_locked(db, id, + mem_ctx); if (global->db_rec == NULL) { talloc_free(global); return NT_STATUS_INSUFFICIENT_RESOURCES; @@ -820,8 +838,6 @@ NTSTATUS smbXsrv_tcon_update(struct smbXsrv_tcon *tcon) { struct smbXsrv_tcon_table *table = tcon->table; NTSTATUS status; - uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; if (tcon->global->db_rec != NULL) { DEBUG(0, ("smbXsrv_tcon_update(0x%08x): " @@ -830,17 +846,11 @@ NTSTATUS smbXsrv_tcon_update(struct smbXsrv_tcon *tcon) return NT_STATUS_INTERNAL_ERROR; } - key = smbXsrv_tcon_global_id_to_key(tcon->global->tcon_global_id, - key_buf); - - tcon->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx, - tcon->global, key); + tcon->global->db_rec = smbXsrv_tcon_global_fetch_locked( + table->global.db_ctx, + tcon->global->tcon_global_id, + tcon->global /* TALLOC_CTX */); if (tcon->global->db_rec == NULL) { - DEBUG(0, ("smbXsrv_tcon_update(0x%08x): " - "Failed to lock global key '%s'\n", - tcon->global->tcon_global_id, - hex_encode_talloc(talloc_tos(), key.dptr, - key.dsize))); return NT_STATUS_INTERNAL_DB_ERROR; } @@ -888,22 +898,11 @@ NTSTATUS smbXsrv_tcon_disconnect(struct smbXsrv_tcon *tcon, uint64_t vuid) global_rec = tcon->global->db_rec; tcon->global->db_rec = NULL; if (global_rec == NULL) { - uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; - - key = smbXsrv_tcon_global_id_to_key( + global_rec = smbXsrv_tcon_global_fetch_locked( + table->global.db_ctx, tcon->global->tcon_global_id, - key_buf); - - global_rec = dbwrap_fetch_locked(table->global.db_ctx, - tcon->global, key); + tcon->global /* TALLOC_CTX */); if (global_rec == NULL) { - DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): " - "Failed to lock global key '%s'\n", - tcon->global->tcon_global_id, - tcon->global->share_name, - hex_encode_talloc(global_rec, key.dptr, - key.dsize))); error = NT_STATUS_INTERNAL_ERROR; } } -- 2.5.0 From b91b26247900fdb752cecb63ab729cdc4b7da6dd Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Sat, 27 Feb 2016 01:06:13 +0100 Subject: [PATCH 11/40] smbXsrv_tcon: factor fetch-locking of local record into function Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source3/smbd/smbXsrv_tcon.c | 58 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/source3/smbd/smbXsrv_tcon.c b/source3/smbd/smbXsrv_tcon.c index 5f10c49..ddd03f6 100644 --- a/source3/smbd/smbXsrv_tcon.c +++ b/source3/smbd/smbXsrv_tcon.c @@ -171,6 +171,27 @@ static struct db_record *smbXsrv_tcon_global_fetch_locked( return rec; } +static struct db_record *smbXsrv_tcon_local_fetch_locked( + struct db_context *db, + uint32_t id, + TALLOC_CTX *mem_ctx) +{ + TDB_DATA key; + uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE]; + struct db_record *rec = NULL; + + key = smbXsrv_tcon_local_id_to_key(id, key_buf); + + rec = dbwrap_fetch_locked(db, mem_ctx, key); + + if (rec == NULL) { + DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id, + hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); + } + + return rec; +} + static NTSTATUS smbXsrv_tcon_table_init(TALLOC_CTX *mem_ctx, struct smbXsrv_tcon_table *table, uint32_t lowest_id, @@ -287,8 +308,6 @@ static NTSTATUS smb1srv_tcon_local_allocate_id(struct db_context *db, for (i = 0; i < (range / 2); i++) { uint32_t id; - uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE]; - TDB_DATA key; TDB_DATA val; struct db_record *rec = NULL; @@ -302,9 +321,7 @@ static NTSTATUS smb1srv_tcon_local_allocate_id(struct db_context *db, id = highest_id; } - key = smbXsrv_tcon_local_id_to_key(id, key_buf); - - rec = dbwrap_fetch_locked(db, mem_ctx, key); + rec = smbXsrv_tcon_local_fetch_locked(db, id, mem_ctx); if (rec == NULL) { return NT_STATUS_INSUFFICIENT_RESOURCES; } @@ -354,16 +371,12 @@ static NTSTATUS smb1srv_tcon_local_allocate_id(struct db_context *db, if (NT_STATUS_IS_OK(state.status)) { uint32_t id; - uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE]; - TDB_DATA key; TDB_DATA val; struct db_record *rec = NULL; id = state.useable_id; - key = smbXsrv_tcon_local_id_to_key(id, key_buf); - - rec = dbwrap_fetch_locked(db, mem_ctx, key); + rec = smbXsrv_tcon_local_fetch_locked(db, id, mem_ctx); if (rec == NULL) { return NT_STATUS_INSUFFICIENT_RESOURCES; } @@ -755,17 +768,14 @@ static NTSTATUS smbXsrv_tcon_create(struct smbXsrv_tcon_table *table, if (protocol >= PROTOCOL_SMB2_02) { uint64_t id = global->tcon_global_id; - uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE]; - TDB_DATA key; global->tcon_wire_id = id; tcon->local_id = global->tcon_global_id; - key = smbXsrv_tcon_local_id_to_key(tcon->local_id, key_buf); - - local_rec = dbwrap_fetch_locked(table->local.db_ctx, - tcon, key); + local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx, + tcon->local_id, + tcon /* TALLOC_CTX */); if (local_rec == NULL) { TALLOC_FREE(tcon); return NT_STATUS_NO_MEMORY; @@ -926,20 +936,10 @@ NTSTATUS smbXsrv_tcon_disconnect(struct smbXsrv_tcon *tcon, uint64_t vuid) local_rec = tcon->db_rec; if (local_rec == NULL) { - uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE]; - TDB_DATA key; - - key = smbXsrv_tcon_local_id_to_key(tcon->local_id, key_buf); - - local_rec = dbwrap_fetch_locked(table->local.db_ctx, - tcon, key); + local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx, + tcon->local_id, + tcon /* TALLOC_CTX */); if (local_rec == NULL) { - DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): " - "Failed to lock local key '%s'\n", - tcon->global->tcon_global_id, - tcon->global->share_name, - hex_encode_talloc(local_rec, key.dptr, - key.dsize))); error = NT_STATUS_INTERNAL_ERROR; } } -- 2.5.0 From 61ac25c7deb9c0fdeea85259893a54e3e618741f Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Sat, 27 Feb 2016 01:26:16 +0100 Subject: [PATCH 12/40] smbXsrv_session: factor fetch-locking of global record into function Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source3/smbd/smbXsrv_session.c | 69 ++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c index 732388b..f7cc629 100644 --- a/source3/smbd/smbXsrv_session.c +++ b/source3/smbd/smbXsrv_session.c @@ -161,6 +161,27 @@ static NTSTATUS smbXsrv_session_local_key_to_id(TDB_DATA key, uint32_t *id) return NT_STATUS_OK; } +static struct db_record *smbXsrv_session_global_fetch_locked( + struct db_context *db, + uint32_t id, + TALLOC_CTX *mem_ctx) +{ + TDB_DATA key; + uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE]; + struct db_record *rec = NULL; + + key = smbXsrv_session_global_id_to_key(id, key_buf); + + rec = dbwrap_fetch_locked(db, mem_ctx, key); + + if (rec == NULL) { + DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id, + hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); + } + + return rec; +} + static void smbXsrv_session_close_loop(struct tevent_req *subreq); static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn, @@ -693,8 +714,6 @@ static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db, bool is_free = false; bool was_free = false; uint32_t id; - uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; if (i >= min_tries && last_free != 0) { id = last_free; @@ -708,9 +727,8 @@ static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db, id--; } - key = smbXsrv_session_global_id_to_key(id, key_buf); - - global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key); + global->db_rec = smbXsrv_session_global_fetch_locked(db, id, + mem_ctx); if (global->db_rec == NULL) { talloc_free(global); return NT_STATUS_INSUFFICIENT_RESOURCES; @@ -931,8 +949,6 @@ struct tevent_req *smb2srv_session_close_previous_send(TALLOC_CTX *mem_ctx, uint64_t global_zeros = previous_session_id & 0xFFFFFFFF00000000LLU; struct smbXsrv_session_table *table = conn->client->session_table; struct security_token *current_token = NULL; - uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; req = tevent_req_create(mem_ctx, &state, struct smb2srv_session_close_previous_state); @@ -969,10 +985,10 @@ struct tevent_req *smb2srv_session_close_previous_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - key = smbXsrv_session_global_id_to_key(global_id, key_buf); - - state->db_rec = dbwrap_fetch_locked(table->global.db_ctx, - state, key); + state->db_rec = smbXsrv_session_global_fetch_locked( + table->global.db_ctx, + global_id, + state /* TALLOC_CTX */); if (state->db_rec == NULL) { tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL); return tevent_req_post(req, ev); @@ -1336,8 +1352,6 @@ NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session) { struct smbXsrv_session_table *table = session->table; NTSTATUS status; - uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; if (session->global->db_rec != NULL) { DEBUG(0, ("smbXsrv_session_update(0x%08x): " @@ -1346,18 +1360,11 @@ NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session) return NT_STATUS_INTERNAL_ERROR; } - key = smbXsrv_session_global_id_to_key( + session->global->db_rec = smbXsrv_session_global_fetch_locked( + table->global.db_ctx, session->global->session_global_id, - key_buf); - - session->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx, - session->global, key); + session->global /* TALLOC_CTX */); if (session->global->db_rec == NULL) { - DEBUG(0, ("smbXsrv_session_update(0x%08x): " - "Failed to lock global key '%s'\n", - session->global->session_global_id, - hex_encode_talloc(talloc_tos(), key.dptr, - key.dsize))); return NT_STATUS_INTERNAL_DB_ERROR; } @@ -1621,21 +1628,11 @@ NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session) global_rec = session->global->db_rec; session->global->db_rec = NULL; if (global_rec == NULL) { - uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; - - key = smbXsrv_session_global_id_to_key( + global_rec = smbXsrv_session_global_fetch_locked( + table->global.db_ctx, session->global->session_global_id, - key_buf); - - global_rec = dbwrap_fetch_locked(table->global.db_ctx, - session->global, key); + session->global /* TALLOC_CTX */); if (global_rec == NULL) { - DEBUG(0, ("smbXsrv_session_logoff(0x%08x): " - "Failed to lock global key '%s'\n", - session->global->session_global_id, - hex_encode_talloc(global_rec, key.dptr, - key.dsize))); error = NT_STATUS_INTERNAL_ERROR; } } -- 2.5.0 From deaf3389eb0575018ad5919d900330c40c558455 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Sat, 27 Feb 2016 01:37:34 +0100 Subject: [PATCH 13/40] smbXsrv_session: factor fetch-locking of local record into function Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source3/smbd/smbXsrv_session.c | 60 ++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c index f7cc629..a5aee8c 100644 --- a/source3/smbd/smbXsrv_session.c +++ b/source3/smbd/smbXsrv_session.c @@ -182,6 +182,27 @@ static struct db_record *smbXsrv_session_global_fetch_locked( return rec; } +static struct db_record *smbXsrv_session_local_fetch_locked( + struct db_context *db, + uint32_t id, + TALLOC_CTX *mem_ctx) +{ + TDB_DATA key; + uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE]; + struct db_record *rec = NULL; + + key = smbXsrv_session_local_id_to_key(id, key_buf); + + rec = dbwrap_fetch_locked(db, mem_ctx, key); + + if (rec == NULL) { + DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id, + hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); + } + + return rec; +} + static void smbXsrv_session_close_loop(struct tevent_req *subreq); static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn, @@ -483,8 +504,6 @@ static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db, for (i = 0; i < (range / 2); i++) { uint32_t id; - uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE]; - TDB_DATA key; TDB_DATA val; struct db_record *rec = NULL; @@ -498,9 +517,7 @@ static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db, id = highest_id; } - key = smbXsrv_session_local_id_to_key(id, key_buf); - - rec = dbwrap_fetch_locked(db, mem_ctx, key); + rec = smbXsrv_session_local_fetch_locked(db, id, mem_ctx); if (rec == NULL) { return NT_STATUS_INSUFFICIENT_RESOURCES; } @@ -550,16 +567,12 @@ static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db, if (NT_STATUS_IS_OK(state.status)) { uint32_t id; - uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE]; - TDB_DATA key; TDB_DATA val; struct db_record *rec = NULL; id = state.useable_id; - key = smbXsrv_session_local_id_to_key(id, key_buf); - - rec = dbwrap_fetch_locked(db, mem_ctx, key); + rec = smbXsrv_session_local_fetch_locked(db, id, mem_ctx); if (rec == NULL) { return NT_STATUS_INSUFFICIENT_RESOURCES; } @@ -1206,8 +1219,6 @@ NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn, if (conn->protocol >= PROTOCOL_SMB2_02) { uint64_t id = global->session_global_id; - uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE]; - TDB_DATA key; global->connection_dialect = conn->smb2.server.dialect; @@ -1221,10 +1232,10 @@ NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn, session->local_id = global->session_global_id; - key = smbXsrv_session_local_id_to_key(session->local_id, key_buf); - - local_rec = dbwrap_fetch_locked(table->local.db_ctx, - session, key); + local_rec = smbXsrv_session_local_fetch_locked( + table->local.db_ctx, + session->local_id, + session /* TALLOC_CTX */); if (local_rec == NULL) { TALLOC_FREE(session); return NT_STATUS_NO_MEMORY; @@ -1655,20 +1666,11 @@ NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session) local_rec = session->db_rec; if (local_rec == NULL) { - uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE]; - TDB_DATA key; - - key = smbXsrv_session_local_id_to_key(session->local_id, - key_buf); - - local_rec = dbwrap_fetch_locked(table->local.db_ctx, - session, key); + local_rec = smbXsrv_session_local_fetch_locked( + table->local.db_ctx, + session->local_id, + session /* TALLOC_CTX */); if (local_rec == NULL) { - DEBUG(0, ("smbXsrv_session_logoff(0x%08x): " - "Failed to lock local key '%s'\n", - session->global->session_global_id, - hex_encode_talloc(local_rec, key.dptr, - key.dsize))); error = NT_STATUS_INTERNAL_ERROR; } } -- 2.5.0 From 4bcd267dba16b58e62846bc6f8b53355f3aa2c86 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Sat, 27 Feb 2016 01:58:45 +0100 Subject: [PATCH 14/40] smbXsrv_client: factor fetch-locking of global record into function Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source3/smbd/smbXsrv_client.c | 62 +++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/source3/smbd/smbXsrv_client.c b/source3/smbd/smbXsrv_client.c index 0e21fc6..2dd4cad 100644 --- a/source3/smbd/smbXsrv_client.c +++ b/source3/smbd/smbXsrv_client.c @@ -118,6 +118,28 @@ static TDB_DATA smbXsrv_client_global_id_to_key(const struct GUID *client_guid, return key; } +static struct db_record *smbXsrv_client_global_fetch_locked( + struct db_context *db, + const struct GUID *client_guid, + TALLOC_CTX *mem_ctx) +{ + TDB_DATA key; + uint8_t key_buf[SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE]; + struct db_record *rec = NULL; + + key = smbXsrv_client_global_id_to_key(client_guid, key_buf); + + rec = dbwrap_fetch_locked(db, mem_ctx, key); + + if (rec == NULL) { + DBG_DEBUG("Failed to lock guid [%s], key '%s'\n", + GUID_string(talloc_tos(), client_guid), + hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); + } + + return rec; +} + static NTSTATUS smbXsrv_client_table_create(TALLOC_CTX *mem_ctx, struct messaging_context *msg_ctx, uint32_t max_clients, @@ -252,18 +274,12 @@ NTSTATUS smb2srv_client_lookup_global(struct smbXsrv_client *client, struct smbXsrv_client_table *table = client->table; struct smbXsrv_client_global0 *global = NULL; bool is_free = false; - uint8_t key_buf[SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; struct db_record *db_rec; - key = smbXsrv_client_global_id_to_key(&client_guid, key_buf); - - db_rec = dbwrap_fetch_locked(table->global.db_ctx, - talloc_tos(), key); + db_rec = smbXsrv_client_global_fetch_locked(table->global.db_ctx, + &client_guid, + talloc_tos()); if (db_rec == NULL) { - DBG_ERR("guid [%s]: Failed to lock key '%s'\n", - GUID_string(talloc_tos(), &client_guid), - hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); return NT_STATUS_INTERNAL_DB_ERROR; } @@ -681,8 +697,6 @@ NTSTATUS smbXsrv_client_update(struct smbXsrv_client *client) { struct smbXsrv_client_table *table = client->table; NTSTATUS status; - uint8_t key_buf[SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; if (client->global->db_rec != NULL) { DBG_ERR("guid [%s]: Called with db_rec != NULL'\n", @@ -691,15 +705,11 @@ NTSTATUS smbXsrv_client_update(struct smbXsrv_client *client) return NT_STATUS_INTERNAL_ERROR; } - key = smbXsrv_client_global_id_to_key(&client->global->client_guid, - key_buf); - - client->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx, - client->global, key); + client->global->db_rec = smbXsrv_client_global_fetch_locked( + table->global.db_ctx, + &client->global->client_guid, + client->global /* TALLOC_CTX */); if (client->global->db_rec == NULL) { - DBG_ERR("guid [%s]: Failed to lock key '%s'\n", - GUID_string(talloc_tos(), &client->global->client_guid), - hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); return NT_STATUS_INTERNAL_DB_ERROR; } @@ -730,8 +740,6 @@ NTSTATUS smbXsrv_client_remove(struct smbXsrv_client *client) { struct smbXsrv_client_table *table = client->table; NTSTATUS status; - uint8_t key_buf[SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE]; - TDB_DATA key; if (client->global->db_rec != NULL) { DBG_ERR("client_guid[%s]: Called with db_rec != NULL'\n", @@ -743,15 +751,11 @@ NTSTATUS smbXsrv_client_remove(struct smbXsrv_client *client) return NT_STATUS_OK; } - key = smbXsrv_client_global_id_to_key(&client->global->client_guid, - key_buf); - - client->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx, - client->global, key); + client->global->db_rec = smbXsrv_client_global_fetch_locked( + table->global.db_ctx, + &client->global->client_guid, + client->global /* TALLOC_CTX */); if (client->global->db_rec == NULL) { - DBG_ERR("client_guid[%s]: Failed to lock key '%s'\n", - GUID_string(talloc_tos(), &client->global->client_guid), - hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); return NT_STATUS_INTERNAL_DB_ERROR; } -- 2.5.0 From 7608685a6c8a2efa6757df0323ff95084daad68b Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Sun, 28 Feb 2016 01:46:47 +0100 Subject: [PATCH 15/40] smbd:smb2_creat: remove outdated TODO comments Leases have meanwhile been implemented and the TODO has been taken care of. Signed-off-by: Michael Adam Reviewed-by: Jeremy Allson Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Sun Feb 28 08:16:26 CET 2016 on sn-devel-144 --- source3/smbd/smb2_create.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index 62948a0..7917d42 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -555,10 +555,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, * (Note that the cases of an additional dh2q or dh2c blob * which require a different error code, have been treated * above.) - * - * TODO: - * This is only true for the oplock case: - * For leases, lease request is required additionally. */ if (dhnq) { @@ -595,10 +591,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, * (Note that the cases of an additional dhnq, dhnc or dh2q * blob which require a different error code, have been * treated above.) - * - * TODO: - * This is only true for the oplock case: - * For leases, lease request is required additionally! */ num_blobs_allowed = 1; -- 2.5.0 From a8e27384697aaf0ecd6620424298dcaee38f7cf9 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 29 Feb 2016 01:51:23 +0100 Subject: [PATCH 16/40] torture:smb2: skip replay3 if server does not support Multi-Channel Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source4/torture/smb2/replay.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 4b3f569..71062c0 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -487,12 +487,20 @@ static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1) struct smb2_session *session1_2 = NULL; uint32_t share_capabilities; bool share_is_so; + uint32_t server_capabilities; if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "SMB 3.X Dialect family required for " "Replay tests\n"); } + server_capabilities = smb2cli_conn_server_capabilities( + tree1->session->transport->conn); + if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) { + torture_skip(tctx, + "Server does not support multi-channel."); + } + share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli); share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; -- 2.5.0 From 7d8eb63dba8895bf3568cc5d1b76f13c5f345ef3 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 29 Feb 2016 01:52:07 +0100 Subject: [PATCH 17/40] torture:smb2: skip replay5 test if server does not support persistent handles Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source4/torture/smb2/replay.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 71062c0..2b60cbf 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -877,6 +877,7 @@ static bool test_replay5(struct torture_context *tctx, struct smb2_tree *tree) uint32_t share_capabilities; bool share_is_ca; bool share_is_so; + uint32_t server_capabilities; const char *fname = BASEDIR "\\replay5.dat"; struct smb2_transport *transport = tree->session->transport; struct smbcli_options options = tree->session->transport->options; @@ -888,6 +889,13 @@ static bool test_replay5(struct torture_context *tctx, struct smb2_tree *tree) "Replay tests\n"); } + server_capabilities = smb2cli_conn_server_capabilities( + tree->session->transport->conn); + if (!(server_capabilities & SMB2_CAP_PERSISTENT_HANDLES)) { + torture_skip(tctx, + "Server does not support persistent handles."); + } + share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli); share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY; -- 2.5.0 From 18f61d0487f44225db6fc05bd0be5c7bc02653d6 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 29 Feb 2016 01:52:42 +0100 Subject: [PATCH 18/40] torture:smb2: fix skip message if share is not CA Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source4/torture/smb2/replay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 2b60cbf..26c32d1 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -900,7 +900,7 @@ static bool test_replay5(struct torture_context *tctx, struct smb2_tree *tree) share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY; if (!share_is_ca) { - torture_skip(tctx, "Persistent File Handles not supported"); + torture_skip(tctx, "Share is not continuously available."); } share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; -- 2.5.0 From bb53badd19ba48358a0543b0b9c23d16fe04c503 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 25 Feb 2016 16:02:36 +0100 Subject: [PATCH 19/40] dbwrap_util: improve a debug message in dbwrap_delete_action() Signed-off-by: Michael Adam Reviewed-by: Volker Lendecke --- lib/dbwrap/dbwrap_util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/dbwrap/dbwrap_util.c b/lib/dbwrap/dbwrap_util.c index 901ef56..5118fb7 100644 --- a/lib/dbwrap/dbwrap_util.c +++ b/lib/dbwrap/dbwrap_util.c @@ -412,7 +412,8 @@ static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data) status = dbwrap_record_delete(rec); if (!NT_STATUS_IS_OK(status)) { - DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status))); + DBG_INFO("dbwrap_record_delete returned %s\n", + nt_errstr(status)); } talloc_free(rec); -- 2.5.0 From d7e8b17debfa123b1a411c107b8e9dc87fc2f770 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 25 Feb 2016 00:56:14 +0100 Subject: [PATCH 20/40] dbwrap: add dbwrap_purge[_bystring] Variants of dbrwap_delete[_bysrting] that treats NOT FOUND as success. Signed-off-by: Michael Adam Reviewed-by: Volker Lendecke --- lib/dbwrap/dbwrap.h | 2 ++ lib/dbwrap/dbwrap_util.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/dbwrap/dbwrap.h b/lib/dbwrap/dbwrap.h index 5e13a59..2eded04 100644 --- a/lib/dbwrap/dbwrap.h +++ b/lib/dbwrap/dbwrap.h @@ -94,6 +94,8 @@ const char *dbwrap_name(struct db_context *db); /* The following definitions come from lib/dbwrap_util.c */ +NTSTATUS dbwrap_purge(struct db_context *db, TDB_DATA key); +NTSTATUS dbwrap_purge_bystring(struct db_context *db, const char *key); NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key); NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key, TDB_DATA data, int flags); diff --git a/lib/dbwrap/dbwrap_util.c b/lib/dbwrap/dbwrap_util.c index 5118fb7..22f910d 100644 --- a/lib/dbwrap/dbwrap_util.c +++ b/lib/dbwrap/dbwrap_util.c @@ -528,6 +528,23 @@ NTSTATUS dbwrap_trans_traverse(struct db_context *db, return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx); } +NTSTATUS dbwrap_purge(struct db_context *db, TDB_DATA key) +{ + NTSTATUS status; + + status = dbwrap_delete(db, key); + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + status = NT_STATUS_OK; + } + + return status; +} + +NTSTATUS dbwrap_purge_bystring(struct db_context *db, const char *key) +{ + return dbwrap_purge(db, string_term_tdb_data(key)); +} + NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key) { return dbwrap_delete(db, string_term_tdb_data(key)); -- 2.5.0 From ce5c0e3518d03e1f42d9d988fd70166b37b80ec9 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 25 Feb 2016 00:58:50 +0100 Subject: [PATCH 21/40] s3:registry: use dbwrap_purge_bystring instead of dbwrap_delete_bystring where appropriate Signed-off-by: Michael Adam Reviewed-by: Volker Lendecke --- source3/registry/reg_backend_db.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/source3/registry/reg_backend_db.c b/source3/registry/reg_backend_db.c index 7b3391d..bdfe7d2 100644 --- a/source3/registry/reg_backend_db.c +++ b/source3/registry/reg_backend_db.c @@ -966,12 +966,7 @@ static WERROR regdb_delete_key_with_prefix(struct db_context *db, goto done; } - werr = ntstatus_to_werror(dbwrap_delete_bystring(db, path)); - - /* treat "not found" as ok */ - if (W_ERROR_EQUAL(werr, WERR_NOT_FOUND)) { - werr = WERR_OK; - } + werr = ntstatus_to_werror(dbwrap_purge_bystring(db, path)); done: talloc_free(mem_ctx); -- 2.5.0 From 5716c46a677f37b7eb863bc40d901db5acce03b6 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 25 Feb 2016 16:15:04 +0100 Subject: [PATCH 22/40] netlogon_creds_cli: use dbwrap_purge instead of dbwrap_delete where appropriate Signed-off-by: Michael Adam Reviewed-by: Volker Lendecke --- libcli/auth/netlogon_creds_cli.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index 7c867cf..38b1351 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -1031,11 +1031,8 @@ struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx, return req; } - status = dbwrap_delete(state->context->db.ctx, - state->context->db.key_data); - if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { - status = NT_STATUS_OK; - } + status = dbwrap_purge(state->context->db.ctx, + state->context->db.key_data); if (tevent_req_nterror(req, status)) { return tevent_req_post(req, ev); } @@ -1065,11 +1062,8 @@ static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq) } state->locked_state->is_glocked = true; - status = dbwrap_delete(state->context->db.ctx, - state->context->db.key_data); - if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { - status = NT_STATUS_OK; - } + status = dbwrap_purge(state->context->db.ctx, + state->context->db.key_data); if (tevent_req_nterror(req, status)) { return; } -- 2.5.0 From fbf50a003467594c005ea82f0045efef74af9725 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 1 Mar 2016 20:40:47 +0100 Subject: [PATCH 23/40] smbd: fix crash in smbXsrv_client_global_remove() Probably copy-n-paste error. Uncovered by the multi-channel-related tests we're currently writing to exercise this code more. Pair-Programmed-With: Guenther Deschner Signed-off-by: Michael Adam Signed-off-by: Guenther Deschner Reviewed-by: Andreas Schneider --- source3/smbd/smbXsrv_client.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/source3/smbd/smbXsrv_client.c b/source3/smbd/smbXsrv_client.c index 2dd4cad..d8ba2f7 100644 --- a/source3/smbd/smbXsrv_client.c +++ b/source3/smbd/smbXsrv_client.c @@ -428,7 +428,6 @@ static NTSTATUS smbXsrv_client_global_store(struct smbXsrv_client_global0 *globa static NTSTATUS smbXsrv_client_global_remove(struct smbXsrv_client_global0 *global) { - struct smbXsrv_client_globalB global_blob; TDB_DATA key; NTSTATUS status; @@ -453,11 +452,8 @@ static NTSTATUS smbXsrv_client_global_remove(struct smbXsrv_client_global0 *glob return status; } global->stored = false; - if (DEBUGLVL(DBGLVL_DEBUG)) { - DBG_DEBUG("key '%s' delete\n", - hex_encode_talloc(global->db_rec, key.dptr, key.dsize)); - NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob); - } + DBG_DEBUG("key '%s' delete\n", + hex_encode_talloc(global->db_rec, key.dptr, key.dsize)); TALLOC_FREE(global->db_rec); -- 2.5.0 From 64e731a11d22965d5de52275260a208bf30a9a88 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 1 Mar 2016 23:07:06 +0100 Subject: [PATCH 24/40] torture:smb2: skip replay4 if server does not support multi-channel Signed-off-by: Michael Adam Reviewed-by: Andreas Schneider Autobuild-User(master): Michael Adam Autobuild-Date(master): Wed Mar 2 20:38:49 CET 2016 on sn-devel-144 --- source4/torture/smb2/replay.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 26c32d1..21f6f80 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -650,12 +650,20 @@ static bool test_replay4(struct torture_context *tctx, struct smb2_tree *tree1) uint16_t curr_cs; uint32_t share_capabilities; bool share_is_so; + uint32_t server_capabilities; if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "SMB 3.X Dialect family required for " "Replay tests\n"); } + server_capabilities = smb2cli_conn_server_capabilities( + tree1->session->transport->conn); + if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) { + torture_skip(tctx, + "Server does not support multi-channel."); + } + share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli); share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; -- 2.5.0 From 26be9597d7b74a1e8877ff32cde40b246c66fdc5 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 1 Mar 2016 01:14:48 +0100 Subject: [PATCH 25/40] torture:smb2: rename replay1 -> replay-commands Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- selftest/knownfail | 2 +- source4/torture/smb2/replay.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/selftest/knownfail b/selftest/knownfail index 04a0621..b1222f0 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -202,7 +202,7 @@ ^samba3.smb2.setinfo.setinfo ^samba3.smb2.session.*reauth5 # some special anonymous checks? ^samba3.smb2.compound.interim2 # wrong return code (STATUS_CANCELLED) -^samba3.smb2.replay.replay1 +^samba3.smb2.replay.replay-commands ^samba3.smb2.replay.replay2 ^samba3.smb2.replay.replay3 ^samba3.smb2.replay.replay4 diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 21f6f80..cef682a 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -161,7 +161,7 @@ static bool torture_oplock_ack_handler(struct smb2_transport *transport, * Test what happens when SMB2_FLAGS_REPLAY_OPERATION is enabled for various * commands. We want to verify if the server returns an error code or not. */ -static bool test_replay1(struct torture_context *tctx, struct smb2_tree *tree) +static bool test_replay_commands(struct torture_context *tctx, struct smb2_tree *tree) { bool ret = true; NTSTATUS status; @@ -175,7 +175,7 @@ static bool test_replay1(struct torture_context *tctx, struct smb2_tree *tree) struct smb2_lock_element el[2]; struct smb2_flush f; TALLOC_CTX *tmp_ctx = talloc_new(tree); - const char *fname = BASEDIR "\\replay1.dat"; + const char *fname = BASEDIR "\\replay_commands.dat"; struct smb2_transport *transport = tree->session->transport; if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) { @@ -997,7 +997,7 @@ struct torture_suite *torture_smb2_replay_init(void) struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "replay"); - torture_suite_add_1smb2_test(suite, "replay1", test_replay1); + torture_suite_add_1smb2_test(suite, "replay-commands", test_replay_commands); torture_suite_add_1smb2_test(suite, "replay2", test_replay2); torture_suite_add_1smb2_test(suite, "replay3", test_replay3); torture_suite_add_1smb2_test(suite, "replay4", test_replay4); -- 2.5.0 From 822540987c802d7ad8a2b8c8725188d8a8b23b7c Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 1 Mar 2016 01:18:03 +0100 Subject: [PATCH 26/40] torture:smb2: split rename2 into multiple tests and extend these - replay-regular - replay-dhv2-oplock1 - replay-dhv2-oplock2 - replay-dhv2-oplock3 Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- selftest/knownfail | 5 +- source4/torture/smb2/replay.c | 384 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 342 insertions(+), 47 deletions(-) diff --git a/selftest/knownfail b/selftest/knownfail index b1222f0..847415e 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -203,7 +203,10 @@ ^samba3.smb2.session.*reauth5 # some special anonymous checks? ^samba3.smb2.compound.interim2 # wrong return code (STATUS_CANCELLED) ^samba3.smb2.replay.replay-commands -^samba3.smb2.replay.replay2 +^samba3.smb2.replay.replay-regular +^samba3.smb2.replay.replay-dhv2-oplock1 +^samba3.smb2.replay.replay-dhv2-oplock2 +^samba3.smb2.replay.replay-dhv2-oplock3 ^samba3.smb2.replay.replay3 ^samba3.smb2.replay.replay4 ^samba3.smb2.lock.*replay diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index cef682a..561963a 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -287,20 +287,136 @@ done: } /** - * Test Durablity V2 Create Replay Detection on Single Channel. Also verify that - * regular creates can not be replayed. + * Test replay detection without create GUID on single channel. + * Regular creates can not be replayed. + * The return code is unaffected of the REPLAY_OPERATION flag. */ -static bool test_replay2(struct torture_context *tctx, struct smb2_tree *tree) +static bool test_replay_regular(struct torture_context *tctx, + struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); struct smb2_handle _h; struct smb2_handle *h = NULL; - struct smb2_create io, ref1, ref2; - struct GUID create_guid = GUID_random(); + struct smb2_create io; uint32_t perms = 0; bool ret = true; - const char *fname = BASEDIR "\\replay2.dat"; + const char *fname = BASEDIR "\\replay_regular.dat"; + struct smb2_transport *transport = tree->session->transport; + + if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) { + torture_skip(tctx, "SMB 3.X Dialect family required for " + "replay tests\n"); + } + + ZERO_STRUCT(break_info); + break_info.tctx = tctx; + tree->session->transport->oplock.handler = torture_oplock_ack_handler; + tree->session->transport->oplock.private_data = tree; + + smb2_util_unlink(tree, fname); + status = torture_smb2_testdir(tree, BASEDIR, &_h); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, _h); + CHECK_VAL(break_info.count, 0); + + torture_comment(tctx, "No replay detection for regular create\n"); + + perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE | + SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE | + SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA | + SEC_FILE_WRITE_DATA; + + io = (struct smb2_create) { + .in.desired_access = perms, + .in.file_attributes = 0, + .in.create_disposition = NTCREATEX_DISP_CREATE, + .in.share_access = NTCREATEX_SHARE_ACCESS_DELETE, + .in.create_options = 0x0, + .in.fname = fname + }; + + status = smb2_create(tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VAL(break_info.count, 0); + _h = io.out.file.handle; + h = &_h; + CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); + + smb2cli_session_start_replay(tree->session->smbXcli); + status = smb2_create(tree, tctx, &io); + smb2cli_session_stop_replay(tree->session->smbXcli); + CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION); + CHECK_VAL(break_info.count, 0); + + smb2_util_close(tree, *h); + h = NULL; + smb2_util_unlink(tree, fname); + + /* + * Same experiment with different create disposition. + */ + io.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + status = smb2_create(tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VAL(break_info.count, 0); + _h = io.out.file.handle; + h = &_h; + CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); + + smb2cli_session_start_replay(tree->session->smbXcli); + status = smb2_create(tree, tctx, &io); + smb2cli_session_stop_replay(tree->session->smbXcli); + CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); + CHECK_VAL(break_info.count, 0); + + smb2_util_close(tree, *h); + h = NULL; + smb2_util_unlink(tree, fname); + + /* + * Now with more generous share mode. + */ + io.in.share_access = smb2_util_share_access("RWD"); + status = smb2_create(tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VAL(break_info.count, 0); + _h = io.out.file.handle; + h = &_h; + CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); + + smb2cli_session_start_replay(tree->session->smbXcli); + status = smb2_create(tree, tctx, &io); + smb2cli_session_stop_replay(tree->session->smbXcli); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VAL(break_info.count, 0); + +done: + if (h != NULL) { + smb2_util_close(tree, *h); + } + smb2_deltree(tree, BASEDIR); + + talloc_free(tree); + talloc_free(mem_ctx); + + return ret; +} + +/** + * Test Durablity V2 Create Replay Detection on Single Channel. + */ +static bool test_replay_dhv2_oplock1(struct torture_context *tctx, + struct smb2_tree *tree) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle _h; + struct smb2_handle *h = NULL; + struct smb2_create io, ref1; + struct GUID create_guid = GUID_random(); + bool ret = true; + const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat"; struct smb2_transport *transport = tree->session->transport; uint32_t share_capabilities; bool share_is_so; @@ -362,14 +478,98 @@ static bool test_replay2(struct torture_context *tctx, struct smb2_tree *tree) CHECK_CREATE_OUT(&io, &ref1); CHECK_VAL(break_info.count, 0); +done: + if (h != NULL) { + smb2_util_close(tree, *h); + } + smb2_deltree(tree, BASEDIR); + + talloc_free(tree); + talloc_free(mem_ctx); + + return ret; +} + +/** + * Test Durablity V2 Create Replay Detection on Single Channel. + * Hand in a different oplock level in the replay. + * Server responds with the handed in oplock level and + * corresponding durable status, but does not change the + * oplock level or durable status of the opened file. + */ +static bool test_replay_dhv2_oplock2(struct torture_context *tctx, + struct smb2_tree *tree) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle _h; + struct smb2_handle *h = NULL; + struct smb2_create io, ref1, ref2; + struct GUID create_guid = GUID_random(); + bool ret = true; + const char *fname = BASEDIR "\\replay_dhv2_oplock2.dat"; + struct smb2_transport *transport = tree->session->transport; + uint32_t share_capabilities; + bool share_is_so; + + if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) { + torture_skip(tctx, "SMB 3.X Dialect family required for " + "replay tests\n"); + } + + share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli); + share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; + + ZERO_STRUCT(break_info); + break_info.tctx = tctx; + tree->session->transport->oplock.handler = torture_oplock_ack_handler; + tree->session->transport->oplock.private_data = tree; + + torture_comment(tctx, "Replay of DurableHandleReqV2 on Single " + "Channel\n"); + smb2_util_unlink(tree, fname); + status = torture_smb2_testdir(tree, BASEDIR, &_h); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, _h); + CHECK_VAL(break_info.count, 0); + + smb2_oplock_create_share(&io, fname, + smb2_util_share_access(""), + smb2_util_oplock_level("b")); + io.in.durable_open = false; + io.in.durable_open_v2 = true; + io.in.persistent_open = false; + io.in.create_guid = create_guid; + io.in.timeout = UINT32_MAX; + + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + ref1 = io; + _h = io.out.file.handle; + h = &_h; + CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); + CHECK_VAL(io.out.durable_open, false); + if (share_is_so) { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s")); + CHECK_VAL(io.out.durable_open_v2, false); + CHECK_VAL(io.out.timeout, 0); + } else { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); + CHECK_VAL(io.out.durable_open_v2, true); + CHECK_VAL(io.out.timeout, io.in.timeout); + } + /* - * See how server behaves if we change some of the Create params while - * Replaying. Change Share Access and Oplock Level. It seems the server - * does not care for change in these parameters. The server seems to - * only care for the File Name and GUID + * Replay durable v2 create on single channel: + * + * Replay the create with a different oplock (none). + * The server replies with the requested oplock level + * and also only replies with durable handle based + * on whether it could have been granted based on + * the requested oplock type. */ smb2_oplock_create_share(&io, fname, - smb2_util_share_access("RWD"), + smb2_util_share_access(""), smb2_util_oplock_level("")); io.in.durable_open = false; io.in.durable_open_v2 = true; @@ -378,9 +578,7 @@ static bool test_replay2(struct torture_context *tctx, struct smb2_tree *tree) io.in.timeout = UINT32_MAX; /* - * The output will just react on the - * input, but it doesn't change the oplock - * or share access values on the existing open + * Adapt the response to the exepected values */ ref2 = ref1; ref2.out.oplock_level = smb2_util_oplock_level(""); @@ -396,11 +594,17 @@ static bool test_replay2(struct torture_context *tctx, struct smb2_tree *tree) CHECK_VAL(break_info.count, 0); /* - * This is a normal open, which triggers an oplock - * break and still gets NT_STATUS_SHARING_VIOLATION + * Prove that the open file still has a batch oplock + * by breaking it with another open. */ - io = ref1; - io.in.durable_open_v2 = false; + smb2_oplock_create_share(&io, fname, + smb2_util_share_access(""), + smb2_util_oplock_level("b")); + io.in.durable_open = false; + io.in.durable_open_v2 = true; + io.in.persistent_open = false; + io.in.create_guid = GUID_random(); + io.in.timeout = UINT32_MAX; status = smb2_create(tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); @@ -411,48 +615,133 @@ static bool test_replay2(struct torture_context *tctx, struct smb2_tree *tree) ZERO_STRUCT(break_info); } - smb2_util_close(tree, *h); - h = NULL; - status = smb2_util_unlink(tree, fname); - CHECK_STATUS(status, NT_STATUS_OK); - CHECK_VAL(break_info.count, 0); +done: + if (h != NULL) { + smb2_util_close(tree, *h); + } + smb2_deltree(tree, BASEDIR); - /* - * No Replay detection for regular Creates - */ - perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE | - SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE | - SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA | - SEC_FILE_WRITE_DATA; + talloc_free(tree); + talloc_free(mem_ctx); - io = (struct smb2_create) { - .in.desired_access = perms, - .in.file_attributes = 0, - .in.create_disposition = NTCREATEX_DISP_CREATE, - .in.share_access = NTCREATEX_SHARE_ACCESS_DELETE, - .in.create_options = 0x0, - .in.fname = fname - }; + return ret; +} - status = smb2_create(tree, tctx, &io); +/** + * Test Durablity V2 Create Replay Detection on Single Channel. + * Replay with a different share mode. The share mode of + * the opened file is not changed by this. + */ +static bool test_replay_dhv2_oplock3(struct torture_context *tctx, + struct smb2_tree *tree) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle _h; + struct smb2_handle *h = NULL; + struct smb2_create io, ref1; + struct GUID create_guid = GUID_random(); + bool ret = true; + const char *fname = BASEDIR "\\replay_dhv2_oplock3.dat"; + struct smb2_transport *transport = tree->session->transport; + uint32_t share_capabilities; + bool share_is_so; + + if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) { + torture_skip(tctx, "SMB 3.X Dialect family required for " + "replay tests\n"); + } + + share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli); + share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; + + ZERO_STRUCT(break_info); + break_info.tctx = tctx; + tree->session->transport->oplock.handler = torture_oplock_ack_handler; + tree->session->transport->oplock.private_data = tree; + + torture_comment(tctx, "Replay of DurableHandleReqV2 on Single " + "Channel\n"); + smb2_util_unlink(tree, fname); + status = torture_smb2_testdir(tree, BASEDIR, &_h); CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, _h); CHECK_VAL(break_info.count, 0); + + smb2_oplock_create_share(&io, fname, + smb2_util_share_access(""), + smb2_util_oplock_level("b")); + io.in.durable_open = false; + io.in.durable_open_v2 = true; + io.in.persistent_open = false; + io.in.create_guid = create_guid; + io.in.timeout = UINT32_MAX; + + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + ref1 = io; _h = io.out.file.handle; h = &_h; CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); + CHECK_VAL(io.out.durable_open, false); + if (share_is_so) { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s")); + CHECK_VAL(io.out.durable_open_v2, false); + CHECK_VAL(io.out.timeout, 0); + } else { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); + CHECK_VAL(io.out.durable_open_v2, true); + CHECK_VAL(io.out.timeout, io.in.timeout); + } - torture_comment(tctx, "No Replay Detection for regular Create\n"); /* - * Now replay the same create + * Replay durable v2 create on single channel: + * + * Replay the create with a different share mode. + * The server replies with the requested share + * mode instead of that which is associated to + * the handle. */ + smb2_oplock_create_share(&io, fname, + smb2_util_share_access("RWD"), + smb2_util_oplock_level("b")); + io.in.durable_open = false; + io.in.durable_open_v2 = true; + io.in.persistent_open = false; + io.in.create_guid = create_guid; + io.in.timeout = UINT32_MAX; + smb2cli_session_start_replay(tree->session->smbXcli); - status = smb2_create(tree, tctx, &io); - CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION); + status = smb2_create(tree, mem_ctx, &io); + smb2cli_session_stop_replay(tree->session->smbXcli); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATE_OUT(&io, &ref1); CHECK_VAL(break_info.count, 0); -done: - smb2cli_session_stop_replay(tree->session->smbXcli); + /* + * In order to prove that the different share mode in the + * replayed create had no effect on the open file handle, + * show that a new create yields NT_STATUS_SHARING_VIOLATION. + */ + smb2_oplock_create_share(&io, fname, + smb2_util_share_access(""), + smb2_util_oplock_level("b")); + io.in.durable_open = false; + io.in.durable_open_v2 = true; + io.in.persistent_open = false; + io.in.create_guid = GUID_random(); + io.in.timeout = UINT32_MAX; + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); + if (!share_is_so) { + CHECK_VAL(break_info.count, 1); + CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle); + CHECK_VAL(break_info.level, smb2_util_oplock_level("s")); + ZERO_STRUCT(break_info); + } + +done: if (h != NULL) { smb2_util_close(tree, *h); } @@ -998,7 +1287,10 @@ struct torture_suite *torture_smb2_replay_init(void) torture_suite_create(talloc_autofree_context(), "replay"); torture_suite_add_1smb2_test(suite, "replay-commands", test_replay_commands); - torture_suite_add_1smb2_test(suite, "replay2", test_replay2); + torture_suite_add_1smb2_test(suite, "replay-regular", test_replay_regular); + torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock1", test_replay_dhv2_oplock1); + torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock2", test_replay_dhv2_oplock2); + torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock3", test_replay_dhv2_oplock3); torture_suite_add_1smb2_test(suite, "replay3", test_replay3); torture_suite_add_1smb2_test(suite, "replay4", test_replay4); torture_suite_add_1smb2_test(suite, "replay5", test_replay5); -- 2.5.0 From e570d4e830f67eb1665f473d87ccc9f846427dba Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 29 Feb 2016 19:00:42 +0100 Subject: [PATCH 27/40] torture:smb2:replay: extend CHECK_CREATE_OUT() to know leases Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source4/torture/smb2/replay.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 561963a..741fa4e 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -85,6 +85,11 @@ __IO_OUT_VAL(__io1, __io2, persistent_open); \ __IO_OUT_VAL(__io1, __io2, timeout); \ __IO_OUT_VAL(__io1, __io2, blobs.num_blobs); \ + if ((__io1)->out.oplock_level == SMB2_OPLOCK_LEVEL_LEASE) { \ + __IO_OUT_VAL(__io1, __io2, lease_response.lease_state);\ + __IO_OUT_VAL(__io1, __io2, lease_response.lease_key.data[0]);\ + __IO_OUT_VAL(__io1, __io2, lease_response.lease_key.data[1]);\ + } \ } while(0) #define BASEDIR "replaytestdir" -- 2.5.0 From 6dbed40f161539b8ef4a16271b4ec4507210d1a9 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 29 Feb 2016 18:23:04 +0100 Subject: [PATCH 28/40] torture:smb2: add smb2.replay.replay-dhv2-lease1 This is a variant of the replay-dhv2-oplock1 test for leases instead of for oplocks. Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- selftest/knownfail | 1 + source4/torture/smb2/replay.c | 139 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/selftest/knownfail b/selftest/knownfail index 847415e..3a61c1d 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -207,6 +207,7 @@ ^samba3.smb2.replay.replay-dhv2-oplock1 ^samba3.smb2.replay.replay-dhv2-oplock2 ^samba3.smb2.replay.replay-dhv2-oplock3 +^samba3.smb2.replay.replay-dhv2-lease1 ^samba3.smb2.replay.replay3 ^samba3.smb2.replay.replay4 ^samba3.smb2.lock.*replay diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 741fa4e..050398e 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -759,6 +759,144 @@ done: } /** + * Test durablity v2 create replay detection on single channel. + * Variant with leases instead of oplocks: + * - open a file with a rh lease + * - upgrade to a rwh lease with a second create + * - replay the first create. + * ==> it gets back the upgraded lease level + */ +static bool test_replay_dhv2_lease1(struct torture_context *tctx, + struct smb2_tree *tree) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle _h1; + struct smb2_handle *h1 = NULL; + struct smb2_handle _h2; + struct smb2_handle *h2 = NULL; + struct smb2_create io1, io2, ref1; + struct GUID create_guid = GUID_random(); + bool ret = true; + const char *fname = BASEDIR "\\replay2_lease1.dat"; + struct smb2_transport *transport = tree->session->transport; + uint32_t share_capabilities; + bool share_is_so; + uint32_t server_capabilities; + struct smb2_lease ls1, ls2; + uint64_t lease_key; + + if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) { + torture_skip(tctx, "SMB 3.X Dialect family required for " + "replay tests\n"); + } + + server_capabilities = smb2cli_conn_server_capabilities(transport->conn); + if (!(server_capabilities & SMB2_CAP_LEASING)) { + torture_skip(tctx, "leases are not supported"); + } + + share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli); + share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; + + ZERO_STRUCT(break_info); + break_info.tctx = tctx; + tree->session->transport->oplock.handler = torture_oplock_ack_handler; + tree->session->transport->oplock.private_data = tree; + + torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease " + "on Single Channel\n"); + smb2_util_unlink(tree, fname); + status = torture_smb2_testdir(tree, BASEDIR, &_h1); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, _h1); + CHECK_VAL(break_info.count, 0); + + lease_key = random(); + + smb2_lease_create(&io1, &ls1, false /* dir */, fname, + lease_key, smb2_util_lease_state("RH")); + io1.in.durable_open = false; + io1.in.durable_open_v2 = true; + io1.in.persistent_open = false; + io1.in.create_guid = create_guid; + io1.in.timeout = UINT32_MAX; + + status = smb2_create(tree, mem_ctx, &io1); + CHECK_STATUS(status, NT_STATUS_OK); + ref1 = io1; + _h1 = io1.out.file.handle; + h1 = &_h1; + CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); + CHECK_VAL(io1.out.durable_open, false); + CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); + CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key); + CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key); + if (share_is_so) { + CHECK_VAL(io1.out.lease_response.lease_state, + smb2_util_lease_state("R")); + CHECK_VAL(io1.out.durable_open_v2, false); + CHECK_VAL(io1.out.timeout, 0); + } else { + CHECK_VAL(io1.out.lease_response.lease_state, + smb2_util_lease_state("RH")); + CHECK_VAL(io1.out.durable_open_v2, true); + CHECK_VAL(io1.out.timeout, io1.in.timeout); + } + + /* + * Upgrade the lease to RWH + */ + smb2_lease_create(&io2, &ls2, false /* dir */, fname, + lease_key, smb2_util_lease_state("RHW")); + io2.in.durable_open = false; + io2.in.durable_open_v2 = true; + io2.in.persistent_open = false; + io2.in.create_guid = GUID_random(); /* new guid... */ + io2.in.timeout = UINT32_MAX; + + status = smb2_create(tree, mem_ctx, &io2); + CHECK_STATUS(status, NT_STATUS_OK); + _h2 = io2.out.file.handle; + h2 = &_h2; + + /* + * Replay Durable V2 Create on single channel. + * We get the io from open #1 but with the + * upgraded lease. + */ + + /* adapt expected lease in response */ + if (!share_is_so) { + ref1.out.lease_response.lease_state = + smb2_util_lease_state("RHW"); + } + + smb2cli_session_start_replay(tree->session->smbXcli); + status = smb2_create(tree, mem_ctx, &io1); + smb2cli_session_stop_replay(tree->session->smbXcli); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATE_OUT(&io1, &ref1); + CHECK_VAL(break_info.count, 0); + +done: + smb2cli_session_stop_replay(tree->session->smbXcli); + + if (h1 != NULL) { + smb2_util_close(tree, *h1); + } + if (h2 != NULL) { + smb2_util_close(tree, *h2); + } + smb2_deltree(tree, BASEDIR); + + talloc_free(tree); + talloc_free(mem_ctx); + + return ret; +} + +/** * Test Durablity V2 Create Replay Detection on Multi Channel */ static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1) @@ -1296,6 +1434,7 @@ struct torture_suite *torture_smb2_replay_init(void) torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock1", test_replay_dhv2_oplock1); torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock2", test_replay_dhv2_oplock2); torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock3", test_replay_dhv2_oplock3); + torture_suite_add_1smb2_test(suite, "replay-dhv2-lease1", test_replay_dhv2_lease1); torture_suite_add_1smb2_test(suite, "replay3", test_replay3); torture_suite_add_1smb2_test(suite, "replay4", test_replay4); torture_suite_add_1smb2_test(suite, "replay5", test_replay5); -- 2.5.0 From 0d632bbefe081a9a020d0d9951a5a261caac6f3f Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 29 Feb 2016 19:04:32 +0100 Subject: [PATCH 29/40] torture:smb2: add smb2.replay.replay-dhv2-lease2 Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- selftest/knownfail | 1 + source4/torture/smb2/replay.c | 152 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) diff --git a/selftest/knownfail b/selftest/knownfail index 3a61c1d..abca6a9 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -208,6 +208,7 @@ ^samba3.smb2.replay.replay-dhv2-oplock2 ^samba3.smb2.replay.replay-dhv2-oplock3 ^samba3.smb2.replay.replay-dhv2-lease1 +^samba3.smb2.replay.replay-dhv2-lease2 ^samba3.smb2.replay.replay3 ^samba3.smb2.replay.replay4 ^samba3.smb2.lock.*replay diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 050398e..600a8a6 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -897,6 +897,157 @@ done: } /** + * Test durablity v2 create replay detection on single channel. + * Variant with leases instead of oplocks, where the + * replay does not specify the original lease level but + * just a "R" lease. This still gives the upgraded lease + * level in the reply. + * - open a file with a rh lease + * - upgrade to a rwh lease with a second create + * - replay the first create. + * ==> it gets back the upgraded lease level + */ +static bool test_replay_dhv2_lease2(struct torture_context *tctx, + struct smb2_tree *tree) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle _h1; + struct smb2_handle *h1 = NULL; + struct smb2_handle _h2; + struct smb2_handle *h2 = NULL; + struct smb2_create io1, io2, ref1; + struct GUID create_guid = GUID_random(); + bool ret = true; + const char *fname = BASEDIR "\\replay2_lease2.dat"; + struct smb2_transport *transport = tree->session->transport; + uint32_t share_capabilities; + bool share_is_so; + uint32_t server_capabilities; + struct smb2_lease ls1, ls2; + uint64_t lease_key; + + if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) { + torture_skip(tctx, "SMB 3.X Dialect family required for " + "replay tests\n"); + } + + server_capabilities = smb2cli_conn_server_capabilities(transport->conn); + if (!(server_capabilities & SMB2_CAP_LEASING)) { + torture_skip(tctx, "leases are not supported"); + } + + share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli); + share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; + + ZERO_STRUCT(break_info); + break_info.tctx = tctx; + tree->session->transport->oplock.handler = torture_oplock_ack_handler; + tree->session->transport->oplock.private_data = tree; + + torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease " + "on Single Channel\n"); + smb2_util_unlink(tree, fname); + status = torture_smb2_testdir(tree, BASEDIR, &_h1); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, _h1); + CHECK_VAL(break_info.count, 0); + + lease_key = random(); + + smb2_lease_create(&io1, &ls1, false /* dir */, fname, + lease_key, smb2_util_lease_state("RH")); + io1.in.durable_open = false; + io1.in.durable_open_v2 = true; + io1.in.persistent_open = false; + io1.in.create_guid = create_guid; + io1.in.timeout = UINT32_MAX; + + status = smb2_create(tree, mem_ctx, &io1); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); + CHECK_VAL(io1.out.durable_open, false); + CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); + CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key); + CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key); + if (share_is_so) { + CHECK_VAL(io1.out.lease_response.lease_state, + smb2_util_lease_state("R")); + CHECK_VAL(io1.out.durable_open_v2, false); + CHECK_VAL(io1.out.timeout, 0); + } else { + CHECK_VAL(io1.out.lease_response.lease_state, + smb2_util_lease_state("RH")); + CHECK_VAL(io1.out.durable_open_v2, true); + CHECK_VAL(io1.out.timeout, io1.in.timeout); + } + ref1 = io1; + _h1 = io1.out.file.handle; + h1 = &_h1; + + /* + * Upgrade the lease to RWH + */ + smb2_lease_create(&io2, &ls2, false /* dir */, fname, + lease_key, smb2_util_lease_state("RHW")); + io2.in.durable_open = false; + io2.in.durable_open_v2 = true; + io2.in.persistent_open = false; + io2.in.create_guid = GUID_random(); /* new guid... */ + io2.in.timeout = UINT32_MAX; + + status = smb2_create(tree, mem_ctx, &io2); + CHECK_STATUS(status, NT_STATUS_OK); + _h2 = io2.out.file.handle; + h2 = &_h2; + + /* + * Replay Durable V2 Create on single channel. + * Changing the requested lease level to "R" + * does not change the response: + * We get the reply from open #1 but with the + * upgraded lease. + */ + + /* adapt the expected response */ + if (!share_is_so) { + ref1.out.lease_response.lease_state = + smb2_util_lease_state("RHW"); + } + + smb2_lease_create(&io1, &ls1, false /* dir */, fname, + lease_key, smb2_util_lease_state("R")); + io1.in.durable_open = false; + io1.in.durable_open_v2 = true; + io1.in.persistent_open = false; + io1.in.create_guid = create_guid; + io1.in.timeout = UINT32_MAX; + + smb2cli_session_start_replay(tree->session->smbXcli); + status = smb2_create(tree, mem_ctx, &io1); + smb2cli_session_stop_replay(tree->session->smbXcli); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATE_OUT(&io1, &ref1); + CHECK_VAL(break_info.count, 0); + +done: + smb2cli_session_stop_replay(tree->session->smbXcli); + + if (h1 != NULL) { + smb2_util_close(tree, *h1); + } + if (h2 != NULL) { + smb2_util_close(tree, *h2); + } + smb2_deltree(tree, BASEDIR); + + talloc_free(tree); + talloc_free(mem_ctx); + + return ret; +} + +/** * Test Durablity V2 Create Replay Detection on Multi Channel */ static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1) @@ -1435,6 +1586,7 @@ struct torture_suite *torture_smb2_replay_init(void) torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock2", test_replay_dhv2_oplock2); torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock3", test_replay_dhv2_oplock3); torture_suite_add_1smb2_test(suite, "replay-dhv2-lease1", test_replay_dhv2_lease1); + torture_suite_add_1smb2_test(suite, "replay-dhv2-lease2", test_replay_dhv2_lease2); torture_suite_add_1smb2_test(suite, "replay3", test_replay3); torture_suite_add_1smb2_test(suite, "replay4", test_replay4); torture_suite_add_1smb2_test(suite, "replay5", test_replay5); -- 2.5.0 From 440e8b97ce2f666bfdcb19b9d258884e10ffee28 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 1 Mar 2016 23:03:50 +0100 Subject: [PATCH 30/40] torture:smb2: add smb2.replay.replay-dhv2-lease-oplock Open with a lease and replay with an oplock. Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- selftest/knownfail | 1 + source4/torture/smb2/replay.c | 145 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) diff --git a/selftest/knownfail b/selftest/knownfail index abca6a9..dab4dbe 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -209,6 +209,7 @@ ^samba3.smb2.replay.replay-dhv2-oplock3 ^samba3.smb2.replay.replay-dhv2-lease1 ^samba3.smb2.replay.replay-dhv2-lease2 +^samba3.smb2.replay.replay-dhv2-lease-oplock ^samba3.smb2.replay.replay3 ^samba3.smb2.replay.replay4 ^samba3.smb2.lock.*replay diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 600a8a6..16d97bc 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -1048,6 +1048,150 @@ done: } /** + * Test durablity v2 create replay detection on single channel. + * Do the original create with a lease, and do the replay + * with an oplock. + */ +static bool test_replay_dhv2_lease_oplock(struct torture_context *tctx, + struct smb2_tree *tree) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle _h1; + struct smb2_handle *h1 = NULL; + struct smb2_handle _h2; + struct smb2_handle *h2 = NULL; + struct smb2_create io1, io2, ref1; + struct GUID create_guid = GUID_random(); + bool ret = true; + const char *fname = BASEDIR "\\replay2_lease1.dat"; + struct smb2_transport *transport = tree->session->transport; + uint32_t share_capabilities; + bool share_is_so; + uint32_t server_capabilities; + struct smb2_lease ls1, ls2; + uint64_t lease_key; + + if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) { + torture_skip(tctx, "SMB 3.X Dialect family required for " + "replay tests\n"); + } + + server_capabilities = smb2cli_conn_server_capabilities(transport->conn); + if (!(server_capabilities & SMB2_CAP_LEASING)) { + torture_skip(tctx, "leases are not supported"); + } + + share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli); + share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; + + ZERO_STRUCT(break_info); + break_info.tctx = tctx; + tree->session->transport->oplock.handler = torture_oplock_ack_handler; + tree->session->transport->oplock.private_data = tree; + + torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease " + "on Single Channel\n"); + smb2_util_unlink(tree, fname); + status = torture_smb2_testdir(tree, BASEDIR, &_h1); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, _h1); + CHECK_VAL(break_info.count, 0); + + lease_key = random(); + + smb2_lease_create(&io1, &ls1, false /* dir */, fname, + lease_key, smb2_util_lease_state("RH")); + io1.in.durable_open = false; + io1.in.durable_open_v2 = true; + io1.in.persistent_open = false; + io1.in.create_guid = create_guid; + io1.in.timeout = UINT32_MAX; + + status = smb2_create(tree, mem_ctx, &io1); + CHECK_STATUS(status, NT_STATUS_OK); + ref1 = io1; + _h1 = io1.out.file.handle; + h1 = &_h1; + CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); + CHECK_VAL(io1.out.durable_open, false); + CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); + CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key); + CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key); + if (share_is_so) { + CHECK_VAL(io1.out.lease_response.lease_state, + smb2_util_lease_state("R")); + CHECK_VAL(io1.out.durable_open_v2, false); + CHECK_VAL(io1.out.timeout, 0); + } else { + CHECK_VAL(io1.out.lease_response.lease_state, + smb2_util_lease_state("RH")); + CHECK_VAL(io1.out.durable_open_v2, true); + CHECK_VAL(io1.out.timeout, io1.in.timeout); + } + + /* + * Upgrade the lease to RWH + */ + smb2_lease_create(&io2, &ls2, false /* dir */, fname, + lease_key, smb2_util_lease_state("RHW")); + io2.in.durable_open = false; + io2.in.durable_open_v2 = true; + io2.in.persistent_open = false; + io2.in.create_guid = GUID_random(); /* new guid... */ + io2.in.timeout = UINT32_MAX; + + status = smb2_create(tree, mem_ctx, &io2); + CHECK_STATUS(status, NT_STATUS_OK); + _h2 = io2.out.file.handle; + h2 = &_h2; + + /* + * Replay Durable V2 Create on single channel. + * We get the io from open #1 but with the + * upgraded lease. + */ + + smb2_oplock_create_share(&io2, fname, + smb2_util_share_access(""), + smb2_util_oplock_level("b")); + io2.in.durable_open = false; + io2.in.durable_open_v2 = true; + io2.in.persistent_open = false; + io2.in.create_guid = create_guid; + io2.in.timeout = UINT32_MAX; + + /* adapt expected lease in response */ + if (!share_is_so) { + ref1.out.lease_response.lease_state = + smb2_util_lease_state("RHW"); + } + + smb2cli_session_start_replay(tree->session->smbXcli); + status = smb2_create(tree, mem_ctx, &io1); + smb2cli_session_stop_replay(tree->session->smbXcli); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATE_OUT(&io1, &ref1); + CHECK_VAL(break_info.count, 0); + +done: + smb2cli_session_stop_replay(tree->session->smbXcli); + + if (h1 != NULL) { + smb2_util_close(tree, *h1); + } + if (h2 != NULL) { + smb2_util_close(tree, *h2); + } + smb2_deltree(tree, BASEDIR); + + talloc_free(tree); + talloc_free(mem_ctx); + + return ret; +} + +/** * Test Durablity V2 Create Replay Detection on Multi Channel */ static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1) @@ -1587,6 +1731,7 @@ struct torture_suite *torture_smb2_replay_init(void) torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock3", test_replay_dhv2_oplock3); torture_suite_add_1smb2_test(suite, "replay-dhv2-lease1", test_replay_dhv2_lease1); torture_suite_add_1smb2_test(suite, "replay-dhv2-lease2", test_replay_dhv2_lease2); + torture_suite_add_1smb2_test(suite, "replay-dhv2-lease-oplock", test_replay_dhv2_lease_oplock); torture_suite_add_1smb2_test(suite, "replay3", test_replay3); torture_suite_add_1smb2_test(suite, "replay4", test_replay4); torture_suite_add_1smb2_test(suite, "replay5", test_replay5); -- 2.5.0 From c3a35e584a22195af0cf0f58b89807e2833d9cc8 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 2 Mar 2016 01:38:24 +0100 Subject: [PATCH 31/40] torture:smb2: add smb2.replay.replay-oplock-lease create with an oplock, and replay with a lease. Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- selftest/knownfail | 1 + source4/torture/smb2/replay.c | 105 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/selftest/knownfail b/selftest/knownfail index dab4dbe..3796ac4 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -207,6 +207,7 @@ ^samba3.smb2.replay.replay-dhv2-oplock1 ^samba3.smb2.replay.replay-dhv2-oplock2 ^samba3.smb2.replay.replay-dhv2-oplock3 +^samba3.smb2.replay.replay-dhv2-oplock-lease ^samba3.smb2.replay.replay-dhv2-lease1 ^samba3.smb2.replay.replay-dhv2-lease2 ^samba3.smb2.replay.replay-dhv2-lease-oplock diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index 16d97bc..d541f7a 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -759,6 +759,110 @@ done: } /** + * Test Durablity V2 Create Replay Detection on Single Channel. + * Create with an oplock, and replay with a lease. + */ +static bool test_replay_dhv2_oplock_lease(struct torture_context *tctx, + struct smb2_tree *tree) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle _h; + struct smb2_handle *h = NULL; + struct smb2_create io; + struct GUID create_guid = GUID_random(); + bool ret = true; + const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat"; + struct smb2_transport *transport = tree->session->transport; + uint32_t share_capabilities; + bool share_is_so; + uint32_t server_capabilities; + struct smb2_lease ls; + uint64_t lease_key; + + if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) { + torture_skip(tctx, "SMB 3.X Dialect family required for " + "replay tests\n"); + } + + server_capabilities = smb2cli_conn_server_capabilities(transport->conn); + if (!(server_capabilities & SMB2_CAP_LEASING)) { + torture_skip(tctx, "leases are not supported"); + } + + share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli); + share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; + + ZERO_STRUCT(break_info); + break_info.tctx = tctx; + tree->session->transport->oplock.handler = torture_oplock_ack_handler; + tree->session->transport->oplock.private_data = tree; + + torture_comment(tctx, "Replay of DurableHandleReqV2 on Single " + "Channel\n"); + smb2_util_unlink(tree, fname); + status = torture_smb2_testdir(tree, BASEDIR, &_h); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, _h); + CHECK_VAL(break_info.count, 0); + + smb2_oplock_create_share(&io, fname, + smb2_util_share_access(""), + smb2_util_oplock_level("b")); + io.in.durable_open = false; + io.in.durable_open_v2 = true; + io.in.persistent_open = false; + io.in.create_guid = create_guid; + io.in.timeout = UINT32_MAX; + + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + _h = io.out.file.handle; + h = &_h; + CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); + CHECK_VAL(io.out.durable_open, false); + if (share_is_so) { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s")); + CHECK_VAL(io.out.durable_open_v2, false); + CHECK_VAL(io.out.timeout, 0); + } else { + CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); + CHECK_VAL(io.out.durable_open_v2, true); + CHECK_VAL(io.out.timeout, io.in.timeout); + } + + /* + * Replay Durable V2 Create on single channel + * but replay it with a lease instead of an oplock. + */ + lease_key = random(); + smb2_lease_create(&io, &ls, false /* dir */, fname, + lease_key, smb2_util_lease_state("RH")); + io.in.durable_open = false; + io.in.durable_open_v2 = true; + io.in.persistent_open = false; + io.in.create_guid = create_guid; + io.in.timeout = UINT32_MAX; + + smb2cli_session_start_replay(tree->session->smbXcli); + status = smb2_create(tree, mem_ctx, &io); + smb2cli_session_stop_replay(tree->session->smbXcli); + CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); + +done: + if (h != NULL) { + smb2_util_close(tree, *h); + } + smb2_deltree(tree, BASEDIR); + + talloc_free(tree); + talloc_free(mem_ctx); + + return ret; +} + + +/** * Test durablity v2 create replay detection on single channel. * Variant with leases instead of oplocks: * - open a file with a rh lease @@ -1729,6 +1833,7 @@ struct torture_suite *torture_smb2_replay_init(void) torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock1", test_replay_dhv2_oplock1); torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock2", test_replay_dhv2_oplock2); torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock3", test_replay_dhv2_oplock3); + torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock-lease", test_replay_dhv2_oplock_lease); torture_suite_add_1smb2_test(suite, "replay-dhv2-lease1", test_replay_dhv2_lease1); torture_suite_add_1smb2_test(suite, "replay-dhv2-lease2", test_replay_dhv2_lease2); torture_suite_add_1smb2_test(suite, "replay-dhv2-lease-oplock", test_replay_dhv2_lease_oplock); -- 2.5.0 From 2fec45db158a8e2bd1795f4a519afcc13bd022ad Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 2 Mar 2016 20:45:16 +0100 Subject: [PATCH 32/40] torture:smb2: add smb2.replay.replay-dhv2-lease3 create with a lease, and replay with lease with a different lease key. Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- selftest/knownfail | 1 + source4/torture/smb2/replay.c | 134 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) diff --git a/selftest/knownfail b/selftest/knownfail index 3796ac4..34d1f2d 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -210,6 +210,7 @@ ^samba3.smb2.replay.replay-dhv2-oplock-lease ^samba3.smb2.replay.replay-dhv2-lease1 ^samba3.smb2.replay.replay-dhv2-lease2 +^samba3.smb2.replay.replay-dhv2-lease3 ^samba3.smb2.replay.replay-dhv2-lease-oplock ^samba3.smb2.replay.replay3 ^samba3.smb2.replay.replay4 diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index d541f7a..c32533b 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -1153,6 +1153,139 @@ done: /** * Test durablity v2 create replay detection on single channel. + * create with a lease, and replay with a different lease key + */ +static bool test_replay_dhv2_lease3(struct torture_context *tctx, + struct smb2_tree *tree) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle _h1; + struct smb2_handle *h1 = NULL; + struct smb2_handle _h2; + struct smb2_handle *h2 = NULL; + struct smb2_create io1, io2; + struct GUID create_guid = GUID_random(); + bool ret = true; + const char *fname = BASEDIR "\\replay2_lease2.dat"; + struct smb2_transport *transport = tree->session->transport; + uint32_t share_capabilities; + bool share_is_so; + uint32_t server_capabilities; + struct smb2_lease ls1, ls2; + uint64_t lease_key; + + if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) { + torture_skip(tctx, "SMB 3.X Dialect family required for " + "replay tests\n"); + } + + server_capabilities = smb2cli_conn_server_capabilities(transport->conn); + if (!(server_capabilities & SMB2_CAP_LEASING)) { + torture_skip(tctx, "leases are not supported"); + } + + share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli); + share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT; + + ZERO_STRUCT(break_info); + break_info.tctx = tctx; + tree->session->transport->oplock.handler = torture_oplock_ack_handler; + tree->session->transport->oplock.private_data = tree; + + torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease " + "on Single Channel\n"); + smb2_util_unlink(tree, fname); + status = torture_smb2_testdir(tree, BASEDIR, &_h1); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, _h1); + CHECK_VAL(break_info.count, 0); + + lease_key = random(); + + smb2_lease_create(&io1, &ls1, false /* dir */, fname, + lease_key, smb2_util_lease_state("RH")); + io1.in.durable_open = false; + io1.in.durable_open_v2 = true; + io1.in.persistent_open = false; + io1.in.create_guid = create_guid; + io1.in.timeout = UINT32_MAX; + + status = smb2_create(tree, mem_ctx, &io1); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); + CHECK_VAL(io1.out.durable_open, false); + CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); + CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key); + CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key); + if (share_is_so) { + CHECK_VAL(io1.out.lease_response.lease_state, + smb2_util_lease_state("R")); + CHECK_VAL(io1.out.durable_open_v2, false); + CHECK_VAL(io1.out.timeout, 0); + } else { + CHECK_VAL(io1.out.lease_response.lease_state, + smb2_util_lease_state("RH")); + CHECK_VAL(io1.out.durable_open_v2, true); + CHECK_VAL(io1.out.timeout, io1.in.timeout); + } + _h1 = io1.out.file.handle; + h1 = &_h1; + + /* + * Upgrade the lease to RWH + */ + smb2_lease_create(&io2, &ls2, false /* dir */, fname, + lease_key, smb2_util_lease_state("RHW")); + io2.in.durable_open = false; + io2.in.durable_open_v2 = true; + io2.in.persistent_open = false; + io2.in.create_guid = GUID_random(); /* new guid... */ + io2.in.timeout = UINT32_MAX; + + status = smb2_create(tree, mem_ctx, &io2); + CHECK_STATUS(status, NT_STATUS_OK); + _h2 = io2.out.file.handle; + h2 = &_h2; + + /* + * Replay Durable V2 Create on single channel. + * use a different lease key. + */ + + smb2_lease_create(&io1, &ls1, false /* dir */, fname, + random() /* lease key */, + smb2_util_lease_state("RH")); + io1.in.durable_open = false; + io1.in.durable_open_v2 = true; + io1.in.persistent_open = false; + io1.in.create_guid = create_guid; + io1.in.timeout = UINT32_MAX; + + smb2cli_session_start_replay(tree->session->smbXcli); + status = smb2_create(tree, mem_ctx, &io1); + smb2cli_session_stop_replay(tree->session->smbXcli); + CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); + +done: + smb2cli_session_stop_replay(tree->session->smbXcli); + + if (h1 != NULL) { + smb2_util_close(tree, *h1); + } + if (h2 != NULL) { + smb2_util_close(tree, *h2); + } + smb2_deltree(tree, BASEDIR); + + talloc_free(tree); + talloc_free(mem_ctx); + + return ret; +} + +/** + * Test durablity v2 create replay detection on single channel. * Do the original create with a lease, and do the replay * with an oplock. */ @@ -1836,6 +1969,7 @@ struct torture_suite *torture_smb2_replay_init(void) torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock-lease", test_replay_dhv2_oplock_lease); torture_suite_add_1smb2_test(suite, "replay-dhv2-lease1", test_replay_dhv2_lease1); torture_suite_add_1smb2_test(suite, "replay-dhv2-lease2", test_replay_dhv2_lease2); + torture_suite_add_1smb2_test(suite, "replay-dhv2-lease3", test_replay_dhv2_lease3); torture_suite_add_1smb2_test(suite, "replay-dhv2-lease-oplock", test_replay_dhv2_lease_oplock); torture_suite_add_1smb2_test(suite, "replay3", test_replay3); torture_suite_add_1smb2_test(suite, "replay4", test_replay4); -- 2.5.0 From 94df8f6f2761f3c47e1959ff8982a0d4336a2c79 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 24 Feb 2016 15:53:57 +0100 Subject: [PATCH 33/40] smbd:smb2: allow the REPLAY_OPERATION flag for SMB3+ requests Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Michael Adam Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- source3/smbd/smb2_server.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index ac922a1..68d637e 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -2225,6 +2225,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) if (opcode == SMB2_OP_CANCEL) { allowed_flags |= SMB2_HDR_FLAG_ASYNC; } + if (xconn->protocol >= PROTOCOL_SMB2_22) { + allowed_flags |= SMB2_HDR_FLAG_REPLAY_OPERATION; + } if ((flags & ~allowed_flags) != 0) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } -- 2.5.0 From 86c6d42c07f7754ccecdf2ded9423928df3292ef Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 26 Feb 2016 13:44:13 +0100 Subject: [PATCH 34/40] librpc:smbXsrv.idl: add flags to smbXsrv_open These flags reflect the need for and state of the replay cache. Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source3/librpc/idl/smbXsrv.idl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source3/librpc/idl/smbXsrv.idl b/source3/librpc/idl/smbXsrv.idl index fe86545..c55ca31 100644 --- a/source3/librpc/idl/smbXsrv.idl +++ b/source3/librpc/idl/smbXsrv.idl @@ -404,6 +404,11 @@ interface smbXsrv /* open files */ + typedef [public,bitmap8bit] bitmap { + SMBXSRV_OPEN_NEED_REPLAY_CACHE = 0x01, + SMBXSRV_OPEN_HAVE_REPLAY_CACHE = 0x02 + } smbXsrv_open_flags; + typedef struct { [ignore] db_record *db_rec; server_id server_id; @@ -463,6 +468,7 @@ interface smbXsrv NTSTATUS status; NTTIME idle_time; [ignore] files_struct *compat; + smbXsrv_open_flags flags; } smbXsrv_open; typedef union { -- 2.5.0 From 214cb28c074ea4471465d7f4a28a101bd6aff2f7 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 24 Feb 2016 00:23:15 +0100 Subject: [PATCH 35/40] smbXsrv:open: maintain a replay cache This caches a map create_guid -> file_id, so that a replayed create can find the already created open again. This is automatically deleted once the first use of the file handle is happening (triggered by the lookup for the file-id). Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source3/smbd/smbXsrv_open.c | 114 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) diff --git a/source3/smbd/smbXsrv_open.c b/source3/smbd/smbXsrv_open.c index ee35f2d..d020817 100644 --- a/source3/smbd/smbXsrv_open.c +++ b/source3/smbd/smbXsrv_open.c @@ -34,6 +34,7 @@ struct smbXsrv_open_table { struct { struct db_context *db_ctx; + struct db_context *replay_cache_db_ctx; uint32_t lowest_id; uint32_t highest_id; uint32_t max_opens; @@ -225,6 +226,11 @@ static NTSTATUS smbXsrv_open_table_init(struct smbXsrv_connection *conn, TALLOC_FREE(table); return NT_STATUS_NO_MEMORY; } + table->local.replay_cache_db_ctx = db_open_rbt(table); + if (table->local.replay_cache_db_ctx == NULL) { + TALLOC_FREE(table); + return NT_STATUS_NO_MEMORY; + } table->local.lowest_id = lowest_id; table->local.highest_id = highest_id; table->local.max_opens = max_opens; @@ -928,6 +934,79 @@ uint32_t smbXsrv_open_hash(struct smbXsrv_open *_open) return ret; } +static NTSTATUS smbXsrv_open_set_replay_cache(struct smbXsrv_open *op) +{ + struct GUID *create_guid; + struct GUID_txt_buf buf; + char *guid_string; + struct db_context *db = op->table->local.replay_cache_db_ctx; + NTSTATUS status; + + if (!(op->flags & SMBXSRV_OPEN_NEED_REPLAY_CACHE)) { + return NT_STATUS_OK; + } + + if (op->flags & SMBXSRV_OPEN_HAVE_REPLAY_CACHE) { + return NT_STATUS_OK; + } + + create_guid = &op->global->create_guid; + if (GUID_all_zero(create_guid)) { + return NT_STATUS_OK; + } + + guid_string = GUID_buf_string(create_guid, &buf); + if (guid_string == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = dbwrap_store_uint32_bystring(db, guid_string, op->local_id); + + if (NT_STATUS_IS_OK(status)) { + op->flags |= SMBXSRV_OPEN_HAVE_REPLAY_CACHE; + op->flags &= ~SMBXSRV_OPEN_NEED_REPLAY_CACHE; + } + + return status; +} + +static NTSTATUS smbXsrv_open_clear_replay_cache(struct smbXsrv_open *op) +{ + struct GUID *create_guid; + struct GUID_txt_buf buf; + char *guid_string; + struct db_context *db; + NTSTATUS status; + + if (op->table == NULL) { + return NT_STATUS_OK; + } + + db = op->table->local.replay_cache_db_ctx; + + if (!(op->flags & SMBXSRV_OPEN_HAVE_REPLAY_CACHE)) { + return NT_STATUS_OK; + } + + create_guid = &op->global->create_guid; + if (GUID_all_zero(create_guid)) { + return NT_STATUS_OK; + } + + guid_string = GUID_buf_string(create_guid, &buf); + if (guid_string == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = dbwrap_purge_bystring(db, guid_string); + + if (NT_STATUS_IS_OK(status)) { + op->flags &= ~SMBXSRV_OPEN_HAVE_REPLAY_CACHE; + } + + return status; +} + NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op) { struct smbXsrv_open_table *table = op->table; @@ -957,6 +1036,13 @@ NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op) return status; } + status = smbXsrv_open_set_replay_cache(op); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("smbXsrv_open_set_replay_cache failed: %s\n", + nt_errstr(status)); + return status; + } + if (CHECK_DEBUGLVL(10)) { struct smbXsrv_openB open_blob; @@ -980,8 +1066,14 @@ NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now) NTSTATUS status; NTSTATUS error = NT_STATUS_OK; + error = smbXsrv_open_clear_replay_cache(op); + if (!NT_STATUS_IS_OK(error)) { + DBG_ERR("smbXsrv_open_clear_replay_cache failed: %s\n", + nt_errstr(error)); + } + if (op->table == NULL) { - return NT_STATUS_OK; + return error; } table = op->table; @@ -1157,6 +1249,7 @@ NTSTATUS smb2srv_open_lookup(struct smbXsrv_connection *conn, uint64_t local_zeros = volatile_id & 0xFFFFFFFF00000000LLU; uint32_t global_id = persistent_id & UINT32_MAX; uint64_t global_zeros = persistent_id & 0xFFFFFFFF00000000LLU; + NTSTATUS status; if (local_zeros != 0) { return NT_STATUS_FILE_CLOSED; @@ -1170,7 +1263,24 @@ NTSTATUS smb2srv_open_lookup(struct smbXsrv_connection *conn, return NT_STATUS_FILE_CLOSED; } - return smbXsrv_open_local_lookup(table, local_id, global_id, now, _open); + status = smbXsrv_open_local_lookup(table, local_id, global_id, now, + _open); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* + * Clear the replay cache for this create_guid if it exists: + * This is based on the assumption that this lookup will be + * triggered by a client request using the file-id for lookup. + * Hence the client has proven that it has in fact seen the + * reply to its initial create call. So subsequent create replays + * should be treated as invalid. Hence the index for create_guid + * lookup needs to be removed. + */ + status = smbXsrv_open_clear_replay_cache(*_open); + + return status; } NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn, -- 2.5.0 From 76b93771cc08e8517569f0b4229083772dc3c20e Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 26 Feb 2016 13:53:25 +0100 Subject: [PATCH 36/40] smb2:create: create replay cache when request has a create_guid Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source3/smbd/smb2_create.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index 7917d42..6f01c39 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -668,6 +668,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, struct smb2_lease lease; struct smb2_lease *lease_ptr = NULL; ssize_t lease_len = -1; + bool need_replay_cache = false; #if 0 struct smb2_create_blob *svhdx = NULL; #endif @@ -804,6 +805,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, update_open = true; /* + * And we need to create a cache for replaying the + * create. + */ + need_replay_cache = true; + + /* * durable handle v2 request processed below */ durable_requested = true; @@ -1154,6 +1161,9 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, if (update_open) { op->global->create_guid = _create_guid; + if (need_replay_cache) { + op->flags |= SMBXSRV_OPEN_NEED_REPLAY_CACHE; + } status = smbXsrv_open_update(op); DEBUG(10, ("smb2_create_send: smbXsrv_open_update " -- 2.5.0 From 358beac011c007b070fe6b144c518bb4253283d2 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Sat, 27 Feb 2016 03:23:27 +0100 Subject: [PATCH 37/40] smbXsrv:open: add smb2srv_open_lookup_replay_cache() A function to find an open from the replay cache, based on the create_guid handed in. Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source3/smbd/globals.h | 4 ++++ source3/smbd/smbXsrv_open.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 1ca1389..c843f5a 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -641,6 +641,10 @@ NTSTATUS smb2srv_open_lookup(struct smbXsrv_connection *conn, uint64_t volatile_id, NTTIME now, struct smbXsrv_open **_open); +NTSTATUS smb2srv_open_lookup_replay_cache(struct smbXsrv_connection *conn, + const struct GUID *create_guid, + NTTIME now, + struct smbXsrv_open **_open); NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn, struct auth_session_info *session_info, uint64_t persistent_id, diff --git a/source3/smbd/smbXsrv_open.c b/source3/smbd/smbXsrv_open.c index d020817..a7cea18 100644 --- a/source3/smbd/smbXsrv_open.c +++ b/source3/smbd/smbXsrv_open.c @@ -1283,6 +1283,47 @@ NTSTATUS smb2srv_open_lookup(struct smbXsrv_connection *conn, return status; } +NTSTATUS smb2srv_open_lookup_replay_cache(struct smbXsrv_connection *conn, + const struct GUID *create_guid, + NTTIME now, /* TODO: needed ? */ + struct smbXsrv_open **_open) +{ + NTSTATUS status; + char *guid_string; + struct GUID_txt_buf buf; + uint32_t local_id = 0; + struct smbXsrv_open_table *table = conn->client->open_table; + struct db_context *db = table->local.replay_cache_db_ctx; + + if (GUID_all_zero(create_guid)) { + return NT_STATUS_NOT_FOUND; + } + + guid_string = GUID_buf_string(create_guid, &buf); + if (guid_string == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = dbwrap_fetch_uint32_bystring(db, guid_string, &local_id); + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + return status; + } + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("failed to fetch local_id from replay cache: %s\n", + nt_errstr(status)); + return status; + } + + status = smbXsrv_open_local_lookup(table, local_id, 0, /* global_id */ + now, _open); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("smbXsrv_open_local_lookup failed for local_id %u\n", + (unsigned)local_id); + } + + return status; +} + NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn, struct auth_session_info *session_info, uint64_t persistent_id, -- 2.5.0 From f6b22942f32dacfb030b5d3d1888705aee0f6f4e Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 29 Feb 2016 02:11:26 +0100 Subject: [PATCH 38/40] smbXsrv.idl: add create_action to smbXsrv_open Needed for create replay. Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- source3/librpc/idl/smbXsrv.idl | 1 + 1 file changed, 1 insertion(+) diff --git a/source3/librpc/idl/smbXsrv.idl b/source3/librpc/idl/smbXsrv.idl index c55ca31..4c6895a 100644 --- a/source3/librpc/idl/smbXsrv.idl +++ b/source3/librpc/idl/smbXsrv.idl @@ -469,6 +469,7 @@ interface smbXsrv NTTIME idle_time; [ignore] files_struct *compat; smbXsrv_open_flags flags; + uint32 create_action; } smbXsrv_open; typedef union { -- 2.5.0 From 2a484b972702b9b2e7d65b1a287acebaf53f9a2d Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Sun, 28 Feb 2016 02:32:36 +0100 Subject: [PATCH 39/40] smbd:smb2: implement create replay Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison --- selftest/knownfail | 10 ----- source3/smbd/smb2_create.c | 95 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 89 insertions(+), 16 deletions(-) diff --git a/selftest/knownfail b/selftest/knownfail index 34d1f2d..1ac99d4 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -202,16 +202,6 @@ ^samba3.smb2.setinfo.setinfo ^samba3.smb2.session.*reauth5 # some special anonymous checks? ^samba3.smb2.compound.interim2 # wrong return code (STATUS_CANCELLED) -^samba3.smb2.replay.replay-commands -^samba3.smb2.replay.replay-regular -^samba3.smb2.replay.replay-dhv2-oplock1 -^samba3.smb2.replay.replay-dhv2-oplock2 -^samba3.smb2.replay.replay-dhv2-oplock3 -^samba3.smb2.replay.replay-dhv2-oplock-lease -^samba3.smb2.replay.replay-dhv2-lease1 -^samba3.smb2.replay.replay-dhv2-lease2 -^samba3.smb2.replay.replay-dhv2-lease3 -^samba3.smb2.replay.replay-dhv2-lease-oplock ^samba3.smb2.replay.replay3 ^samba3.smb2.replay.replay4 ^samba3.smb2.lock.*replay diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index 6f01c39..d50b20c 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -475,6 +475,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, struct smb2_create_blob *dh2q = NULL; struct smb2_create_blob *rqls = NULL; struct smbXsrv_open *op = NULL; + bool replay_operation = false; if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) { requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; @@ -779,6 +780,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, const uint8_t *p = dh2q->data.data; uint32_t durable_v2_timeout = 0; DATA_BLOB create_guid_blob; + const uint8_t *hdr; + uint32_t flags; if (dh2q->data.length != 32) { tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -823,6 +826,38 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, */ 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); + replay_operation = + !!(flags & SMB2_HDR_FLAG_REPLAY_OPERATION); + + status = smb2srv_open_lookup_replay_cache( + smb2req->xconn, create_guid, + 0 /* now */, &op); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + replay_operation = false; + } else if (tevent_req_nterror(req, status)) { + DBG_WARNING("smb2srv_open_lookup_replay_cache " + "failed: %s\n", nt_errstr(status)); + return tevent_req_post(req, ev); + } else if (!replay_operation) { + /* + * If a create without replay operation flag + * is sent but with a create_guid that is + * currently in the replay cache -- fail. + */ + status = NT_STATUS_DUPLICATE_OBJECTID; + (void)tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } } if (dhnc) { @@ -918,6 +953,32 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, DEBUG(10, ("v2 lease key only for SMB3\n")); lease_ptr = NULL; } + + /* + * Replay with a lease is only allowed if the + * established open carries a lease with the + * same lease key. + */ + if (replay_operation) { + struct smb2_lease *op_ls = + &op->compat->lease->lease; + int op_oplock = op->compat->oplock_type; + + if (map_samba_oplock_levels_to_smb2(op_oplock) + != SMB2_OPLOCK_LEVEL_LEASE) + { + status = NT_STATUS_ACCESS_DENIED; + (void)tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + if (!smb2_lease_key_equal(&lease.lease_key, + &op_ls->lease_key)) + { + status = NT_STATUS_ACCESS_DENIED; + (void)tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + } } /* these are ignored for SMB2 */ @@ -930,9 +991,16 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, /* * For the backend file open procedure, there are - * two possible modes: durable_reconnect or not. + * three possible modes: replay operation (in which case + * there is nothing else to do), durable_reconnect or + * new open. */ - if (do_durable_reconnect) { + if (replay_operation) { + result = op->compat; + result->op = op; + update_open = false; + info = op->create_action; + } else if (do_durable_reconnect) { DATA_BLOB new_cookie = data_blob_null; NTTIME now = timeval_to_nttime(&smb2req->request_time); @@ -1142,7 +1210,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, } } - if (durable_requested && + if (!replay_operation && durable_requested && (fsp_lease_type(result) & SMB2_LEASE_HANDLE)) { status = SMB_VFS_DURABLE_COOKIE(result, @@ -1152,7 +1220,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, op->global->backend_cookie = data_blob_null; } } - if (op->global->backend_cookie.length > 0) { + if (!replay_operation && op->global->backend_cookie.length > 0) + { update_open = true; op->global->durable = true; @@ -1189,7 +1258,18 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, } } - if (dh2q && op->global->durable) { + if (dh2q && op->global->durable && + /* + * For replay operations, we return the dh2q blob + * in the case of oplocks not based on the state of + * the open, but on whether it could have been granted + * for the request data. In the case of leases instead, + * the state of the open is used... + */ + (!replay_operation || + in_oplock_level == SMB2_OPLOCK_LEVEL_BATCH || + in_oplock_level == SMB2_OPLOCK_LEVEL_LEASE)) + { uint8_t p[8] = { 0, }; DATA_BLOB blob = data_blob_const(p, sizeof(p)); uint32_t durable_v2_response_flags = 0; @@ -1261,7 +1341,9 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, smb2req->compat_chain_fsp = smb1req->chain_fsp; - if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) { + if (replay_operation) { + state->out_oplock_level = in_oplock_level; + } else if (lp_fake_oplocks(SNUM(smb2req->tcon->compat))) { state->out_oplock_level = in_oplock_level; } else { state->out_oplock_level = map_samba_oplock_levels_to_smb2(result->oplock_type); @@ -1273,6 +1355,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, } else { state->out_create_action = info; } + result->op->create_action = state->out_create_action; state->out_file_attributes = dos_mode(result->conn, result->fsp_name); -- 2.5.0 From 42423a0dde80f58062a41fec7f8386bf9a401972 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 3 Mar 2016 09:27:42 +0100 Subject: [PATCH 40/40] smbd:smb2: move op variable into scope of use in smb2_create_send Signed-off-by: Michael Adam Reviewed-by: Volker Lendecke --- source3/smbd/smb2_create.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index d50b20c..17bddc1 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -474,7 +474,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, struct smb2_create_blob *dhnq = NULL; struct smb2_create_blob *dh2q = NULL; struct smb2_create_blob *rqls = NULL; - struct smbXsrv_open *op = NULL; bool replay_operation = false; if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) { @@ -670,6 +669,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, struct smb2_lease *lease_ptr = NULL; ssize_t lease_len = -1; bool need_replay_cache = false; + struct smbXsrv_open *op = NULL; #if 0 struct smb2_create_blob *svhdx = NULL; #endif -- 2.5.0