The Samba-Bugzilla – Attachment 11935 Details for
Bug 11809
SMB3 multichannel implementation is missing channel sequence number verification
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
patch from master for v4-4-test
patch (text/plain), 63.75 KB, created by
Guenther Deschner
on 2016-03-24 11:19:52 UTC
(
hide
)
Description:
patch from master for v4-4-test
Filename:
MIME Type:
Creator:
Guenther Deschner
Created:
2016-03-24 11:19:52 UTC
Size:
63.75 KB
patch
obsolete
>From 31f33a3f3996a5fff9833540c8227600f4aa2a55 Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org> >Date: Wed, 27 Jan 2016 16:18:25 +0100 >Subject: [PATCH 01/20] s3:smbXsrv.idl: add 8 byte channel_sequence number and > request counters to IDL. > >Guenther > >Signed-off-by: Guenther Deschner <gd@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/librpc/idl/smbXsrv.idl | 3 +++ > 1 file changed, 3 insertions(+) > >diff --git a/source3/librpc/idl/smbXsrv.idl b/source3/librpc/idl/smbXsrv.idl >index 4c6895a..1bfa51e 100644 >--- a/source3/librpc/idl/smbXsrv.idl >+++ b/source3/librpc/idl/smbXsrv.idl >@@ -430,6 +430,7 @@ interface smbXsrv > uint32 durable_timeout_msec; > boolean8 durable; > DATA_BLOB backend_cookie; >+ hyper channel_sequence; > } smbXsrv_open_global0; > > typedef union { >@@ -470,6 +471,8 @@ interface smbXsrv > [ignore] files_struct *compat; > smbXsrv_open_flags flags; > uint32 create_action; >+ hyper request_count; >+ hyper pre_request_count; > } smbXsrv_open; > > typedef union { >-- >2.5.5 > > >From 088468195b7f7f04eab0ce6fb928bda1c703e2fa Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Wed, 24 Feb 2016 15:51:14 +0100 >Subject: [PATCH 02/20] smbd:smb2: add a modify flag to dispatch table > >This indicates that an operation is a modifying operation. >Some parts of the upcoming channel sequence number logic >only applies to modify operations. > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> > >Signed-off-by: Michael Adam <obnox@samba.org> >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_server.c | 4 ++++ > 1 file changed, 4 insertions(+) > >diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c >index 68d637e..7b6d8d6 100644 >--- a/source3/smbd/smb2_server.c >+++ b/source3/smbd/smb2_server.c >@@ -46,6 +46,7 @@ static const struct smbd_smb2_dispatch_table { > bool as_root; > uint16_t fileid_ofs; > bool allow_invalid_fileid; >+ bool modify; > } smbd_smb2_table[] = { > #define _OP(o) .opcode = o, .name = #o > { >@@ -98,6 +99,7 @@ static const struct smbd_smb2_dispatch_table { > .need_session = true, > .need_tcon = true, > .fileid_ofs = 0x10, >+ .modify = true, > },{ > _OP(SMB2_OP_LOCK), > .need_session = true, >@@ -109,6 +111,7 @@ static const struct smbd_smb2_dispatch_table { > .need_tcon = true, > .fileid_ofs = 0x08, > .allow_invalid_fileid = true, >+ .modify = true, > },{ > _OP(SMB2_OP_CANCEL), > .as_root = true, >@@ -135,6 +138,7 @@ static const struct smbd_smb2_dispatch_table { > .need_session = true, > .need_tcon = true, > .fileid_ofs = 0x10, >+ .modify = true, > },{ > _OP(SMB2_OP_BREAK), > .need_session = true, >-- >2.5.5 > > >From ae6967ea3e39a1a5401be4a4c969b467dd22dce4 Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Tue, 15 Mar 2016 12:36:59 +0100 >Subject: [PATCH 03/20] smbd:smb2: add request_counters_updated to the > smbd_smb2_request struct > >This will be used to keep track of whether the outstanding request >counters have been updated in the dispatch, so that the reply >code can act accordingly. > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/globals.h | 7 +++++++ > 1 file changed, 7 insertions(+) > >diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h >index c843f5a..4c02083 100644 >--- a/source3/smbd/globals.h >+++ b/source3/smbd/globals.h >@@ -720,6 +720,13 @@ struct smbd_smb2_request { > struct files_struct *compat_chain_fsp; > > /* >+ * Keep track of whether the outstanding request counters >+ * had been updated in dispatch, so that they need to be >+ * adapted again in reply. >+ */ >+ bool request_counters_updated; >+ >+ /* > * The sub request for async backend calls. > * This is used for SMB2 Cancel. > */ >-- >2.5.5 > > >From 71d2b190646bdf5fce65a776dfe6873da8d82479 Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Wed, 24 Feb 2016 15:54:41 +0100 >Subject: [PATCH 04/20] smbd:smb2: implement channel sequence checks and > request counters in dispatch > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> >Pair-Programmed-With: Guenther Deschner <gd@samba.org> > >Signed-off-by: Michael Adam <obnox@samba.org> >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Signed-off-by: Guenther Deschner <gd@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_server.c | 120 +++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 120 insertions(+) > >diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c >index 7b6d8d6..01892e1 100644 >--- a/source3/smbd/smb2_server.c >+++ b/source3/smbd/smb2_server.c >@@ -2111,6 +2111,121 @@ bool smbXsrv_is_partially_signed(uint8_t signing_flags) > (signing_flags & SMBXSRV_PROCESSED_SIGNED_PACKET)); > } > >+static NTSTATUS smbd_smb2_request_dispatch_update_counts( >+ struct smbd_smb2_request *req, >+ bool modify_call) >+{ >+ struct smbXsrv_connection *xconn = req->xconn; >+ const uint8_t *inhdr; >+ uint16_t channel_sequence; >+ uint32_t flags; >+ int cmp; >+ struct smbXsrv_open *op; >+ bool update_open = false; >+ NTSTATUS status = NT_STATUS_OK; >+ >+ req->request_counters_updated = false; >+ >+ if (xconn->protocol < PROTOCOL_SMB2_22) { >+ return NT_STATUS_OK; >+ } >+ >+ if (req->compat_chain_fsp == NULL) { >+ return NT_STATUS_OK; >+ } >+ >+ op = req->compat_chain_fsp->op; >+ if (op == NULL) { >+ return NT_STATUS_OK; >+ } >+ >+ inhdr = SMBD_SMB2_IN_HDR_PTR(req); >+ flags = IVAL(inhdr, SMB2_HDR_FLAGS); >+ channel_sequence = SVAL(inhdr, SMB2_HDR_CHANNEL_SEQUENCE); >+ >+ cmp = channel_sequence - op->global->channel_sequence; >+ >+ if (abs(cmp) > INT16_MAX) { >+ /* >+ * [MS-SMB2] 3.3.5.2.10 - Verifying the Channel Sequence Number: >+ * >+ * If the channel sequence number of the request and the one >+ * known to the server are not equal, the channel sequence >+ * number and outstanding request counts are only updated >+ * "... if the unsigned difference using 16-bit arithmetic >+ * between ChannelSequence and Open.ChannelSequence is less than >+ * or equal to 0x7FFF ...". >+ * Otherwise, an error is returned for the modifying >+ * calls write, set_info, and ioctl. >+ * >+ * There are currently two issues with the description: >+ * >+ * * For the other calls, the document seems to imply >+ * that processing continues without adapting the >+ * counters (if the sequence numbers are not equal). >+ * >+ * TODO: This needs clarification! >+ * >+ * * Also, the behaviour if the difference is larger >+ * than 0x7FFF is not clear. The document seems to >+ * imply that if such a difference is reached, >+ * the server starts to ignore the counters or >+ * in the case of the modifying calls, return errors. >+ * >+ * TODO: This needs clarification! >+ * >+ * At this point Samba tries to be a little more >+ * clever than the description in the MS-SMB2 document >+ * by heuristically detecting and properly treating >+ * a 16 bit overflow of the client-submitted sequence >+ * number: >+ * >+ * If the stored channel squence number is more than >+ * 0x7FFF larger than the one from the request, then >+ * the client-provided sequence number has likely >+ * overflown. We treat this case as valid instead >+ * of as failure. >+ * >+ * The MS-SMB2 behaviour would be setting cmp = -1. >+ */ >+ cmp *= -1; >+ } >+ >+ if (!(flags & SMB2_HDR_FLAG_REPLAY_OPERATION)) { >+ if (cmp == 0) { >+ op->request_count += 1; >+ req->request_counters_updated = true; >+ } else if (cmp > 0) { >+ op->pre_request_count += op->request_count; >+ op->request_count = 1; >+ op->global->channel_sequence = channel_sequence; >+ update_open = true; >+ req->request_counters_updated = true; >+ } else if (modify_call) { >+ return NT_STATUS_FILE_NOT_AVAILABLE; >+ } >+ } else { >+ if (cmp == 0 && op->pre_request_count == 0) { >+ op->request_count += 1; >+ req->request_counters_updated = true; >+ } else if (cmp > 0 && op->pre_request_count == 0) { >+ op->pre_request_count += op->request_count; >+ op->request_count = 1; >+ op->global->channel_sequence = channel_sequence; >+ update_open = true; >+ req->request_counters_updated = true; >+ } else if (modify_call) { >+ return NT_STATUS_FILE_NOT_AVAILABLE; >+ } >+ } >+ >+ if (update_open) { >+ status = smbXsrv_open_update(op); >+ } >+ >+ return status; >+} >+ > NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) > { > struct smbXsrv_connection *xconn = req->xconn; >@@ -2408,6 +2523,11 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) > } > } > >+ status = smbd_smb2_request_dispatch_update_counts(req, call->modify); >+ if (!NT_STATUS_IS_OK(status)) { >+ return smbd_smb2_request_error(req, status); >+ } >+ > if (call->as_root) { > SMB_ASSERT(call->fileid_ofs == 0); > /* This call needs to be run as root */ >-- >2.5.5 > > >From 7dbb1707d96e39bed8898db08339d3b2d768c87c Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Tue, 23 Feb 2016 20:54:34 +0100 >Subject: [PATCH 05/20] smbd:smb2: update outstanding request counters before > sending a reply > >This is part of the channel sequence number treatment of multi-channel. > >Pair-Programmed-With: Guenther Deschner <gd@samba.org> > >Signed-off-by: Michael Adam <obnox@samba.org> >Signed-off-by: Guenther Deschner <gd@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_server.c | 37 +++++++++++++++++++++++++++++++++++++ > 1 file changed, 37 insertions(+) > >diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c >index 01892e1..ae125df 100644 >--- a/source3/smbd/smb2_server.c >+++ b/source3/smbd/smb2_server.c >@@ -2676,6 +2676,40 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) > return return_value; > } > >+static void smbd_smb2_request_reply_update_counts(struct smbd_smb2_request *req) >+{ >+ struct smbXsrv_connection *xconn = req->xconn; >+ const uint8_t *inhdr; >+ uint16_t channel_sequence; >+ struct smbXsrv_open *op; >+ >+ if (!req->request_counters_updated) { >+ return; >+ } >+ >+ if (xconn->protocol < PROTOCOL_SMB2_22) { >+ return; >+ } >+ >+ if (req->compat_chain_fsp == NULL) { >+ return; >+ } >+ >+ op = req->compat_chain_fsp->op; >+ if (op == NULL) { >+ return; >+ } >+ >+ inhdr = SMBD_SMB2_IN_HDR_PTR(req); >+ channel_sequence = SVAL(inhdr, SMB2_HDR_CHANNEL_SEQUENCE); >+ >+ if (op->global->channel_sequence == channel_sequence) { >+ op->request_count -= 1; >+ } else { >+ op->pre_request_count -= 1; >+ } >+} >+ > static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) > { > struct smbXsrv_connection *xconn = req->xconn; >@@ -2689,6 +2723,9 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) > req->subreq = NULL; > TALLOC_FREE(req->async_te); > >+ /* MS-SMB2: 3.3.4.1 Sending Any Outgoing Message */ >+ smbd_smb2_request_reply_update_counts(req); >+ > if (req->do_encryption && > (firsttf->iov_len == 0) && > (req->first_key.length == 0) && >-- >2.5.5 > > >From f81f3a2d78832258b09bcc63d5cce2b4594cbbc8 Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Sat, 27 Feb 2016 14:02:02 +0100 >Subject: [PATCH 06/20] smbd:smb2: add some asserts before decrementing the > counters > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_server.c | 2 ++ > 1 file changed, 2 insertions(+) > >diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c >index ae125df..8a4aa96 100644 >--- a/source3/smbd/smb2_server.c >+++ b/source3/smbd/smb2_server.c >@@ -2704,8 +2704,10 @@ static void smbd_smb2_request_reply_update_counts(struct smbd_smb2_request *req) > channel_sequence = SVAL(inhdr, SMB2_HDR_CHANNEL_SEQUENCE); > > if (op->global->channel_sequence == channel_sequence) { >+ SMB_ASSERT(op->request_count > 0); > op->request_count -= 1; > } else { >+ SMB_ASSERT(op->pre_request_count > 0); > op->pre_request_count -= 1; > } > } >-- >2.5.5 > > >From ccda60ed9b33bb22ec2e162401a949aeaa631c8d Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org> >Date: Tue, 1 Mar 2016 15:15:10 +0100 >Subject: [PATCH 07/20] libcli:smb:smbXcli_base: add > smb2cli_session_current_channel_sequence() call. > >Guenther > >Signed-off-by: Guenther Deschner <gd@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > libcli/smb/smbXcli_base.c | 5 +++++ > libcli/smb/smbXcli_base.h | 1 + > 2 files changed, 6 insertions(+) > >diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c >index ad6a254..48388b6 100644 >--- a/libcli/smb/smbXcli_base.c >+++ b/libcli/smb/smbXcli_base.c >@@ -5486,6 +5486,11 @@ uint16_t smb2cli_session_reset_channel_sequence(struct smbXcli_session *session, > return prev_cs; > } > >+uint16_t smb2cli_session_current_channel_sequence(struct smbXcli_session *session) >+{ >+ return session->smb2->channel_sequence; >+} >+ > void smb2cli_session_start_replay(struct smbXcli_session *session) > { > session->smb2->replay_active = true; >diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h >index e4cfb10..ffccd7e 100644 >--- a/libcli/smb/smbXcli_base.h >+++ b/libcli/smb/smbXcli_base.h >@@ -410,6 +410,7 @@ void smb2cli_session_set_id_and_flags(struct smbXcli_session *session, > void smb2cli_session_increment_channel_sequence(struct smbXcli_session *session); > uint16_t smb2cli_session_reset_channel_sequence(struct smbXcli_session *session, > uint16_t channel_sequence); >+uint16_t smb2cli_session_current_channel_sequence(struct smbXcli_session *session); > void smb2cli_session_start_replay(struct smbXcli_session *session); > void smb2cli_session_stop_replay(struct smbXcli_session *session); > NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session, >-- >2.5.5 > > >From 2b799880b91f2ee44531644c62916f9a50531d04 Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org> >Date: Thu, 25 Feb 2016 11:15:06 +0100 >Subject: [PATCH 08/20] torture:smb2: add test for checking sequence number > wrap around. > >Guenther > >Signed-off-by: Guenther Deschner <gd@samba.org> >Reviewed-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > selftest/knownfail | 1 + > source4/torture/smb2/replay.c | 266 ++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 267 insertions(+) > >diff --git a/selftest/knownfail b/selftest/knownfail >index c15d263..0950ef0 100644 >--- a/selftest/knownfail >+++ b/selftest/knownfail >@@ -207,6 +207,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.channel-sequence > ^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 c32533b..8388837 100644 >--- a/source4/torture/smb2/replay.c >+++ b/source4/torture/smb2/replay.c >@@ -1428,6 +1428,271 @@ done: > return ret; > } > >+static bool test_channel_sequence_table(struct torture_context *tctx, >+ struct smb2_tree *tree, >+ bool do_replay, >+ uint16_t opcode) >+{ >+ NTSTATUS status; >+ TALLOC_CTX *mem_ctx = talloc_new(tctx); >+ struct smb2_handle handle; >+ struct smb2_handle *phandle = NULL; >+ struct smb2_create io; >+ struct GUID create_guid = GUID_random(); >+ bool ret = true; >+ const char *fname = BASEDIR "\\channel_sequence.dat"; >+ uint16_t csn = 0; >+ uint16_t limit = UINT16_MAX - 0x7fff; >+ int i; >+ struct { >+ uint16_t csn; >+ bool csn_rand_low; >+ bool csn_rand_high; >+ NTSTATUS expected_status; >+ } tests[] = { >+ { >+ .csn = 0, >+ .expected_status = NT_STATUS_OK, >+ },{ >+ .csn = 0x7fff + 1, >+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, >+ },{ >+ .csn = 0x7fff + 2, >+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, >+ },{ >+ .csn = -1, >+ .csn_rand_high = true, >+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, >+ },{ >+ .csn = 0xffff, >+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, >+ },{ >+ .csn = 0x7fff, >+ .expected_status = NT_STATUS_OK, >+ },{ >+ .csn = 0x7ffe, >+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, >+ },{ >+ .csn = 0, >+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, >+ },{ >+ .csn = -1, >+ .csn_rand_low = true, >+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, >+ },{ >+ .csn = 0x7fff + 1, >+ .expected_status = NT_STATUS_OK, >+ },{ >+ .csn = 0xffff, >+ .expected_status = NT_STATUS_OK, >+ },{ >+ .csn = 0, >+ .expected_status = NT_STATUS_OK, >+ },{ >+ .csn = 1, >+ .expected_status = NT_STATUS_OK, >+ },{ >+ .csn = 0, >+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, >+ },{ >+ .csn = 1, >+ .expected_status = NT_STATUS_OK, >+ },{ >+ .csn = 0xffff, >+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, >+ } >+ }; >+ >+ smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0); >+ >+ csn = smb2cli_session_current_channel_sequence(tree->session->smbXcli); >+ torture_comment(tctx, "Testing create with channel sequence number: 0x%04x\n", csn); >+ >+ 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.create_guid = create_guid; >+ io.in.timeout = UINT32_MAX; >+ >+ torture_assert_ntstatus_ok_goto(tctx, >+ smb2_create(tree, mem_ctx, &io), >+ ret, done, "failed to call smb2_create"); >+ >+ handle = io.out.file.handle; >+ phandle = &handle; >+ >+ for (i=0; i <ARRAY_SIZE(tests); i++) { >+ >+ const char *opstr = ""; >+ union smb_fileinfo qfinfo; >+ >+ csn = tests[i].csn; >+ >+ if (tests[i].csn_rand_low) { >+ csn = rand() % limit; >+ } else if (tests[i].csn_rand_high) { >+ csn = rand() % limit + 0x7fff; >+ } >+ >+ switch (opcode) { >+ case SMB2_OP_WRITE: >+ opstr = "write"; >+ break; >+ case SMB2_OP_IOCTL: >+ opstr = "ioctl"; >+ break; >+ case SMB2_OP_SETINFO: >+ opstr = "setinfo"; >+ break; >+ default: >+ break; >+ } >+ >+ smb2cli_session_reset_channel_sequence(tree->session->smbXcli, csn); >+ csn = smb2cli_session_current_channel_sequence(tree->session->smbXcli); >+ >+ torture_comment(tctx, "Testing %s (replay: %s) with CSN 0x%04x, expecting: %s\n", >+ opstr, do_replay ? "true" : "false", csn, >+ nt_errstr(tests[i].expected_status)); >+ >+ if (do_replay) { >+ smb2cli_session_start_replay(tree->session->smbXcli); >+ } >+ >+ switch (opcode) { >+ case SMB2_OP_WRITE: { >+ DATA_BLOB blob = data_blob_talloc(tctx, NULL, 255); >+ >+ generate_random_buffer(blob.data, blob.length); >+ >+ status = smb2_util_write(tree, handle, blob.data, 0, blob.length); >+ if (NT_STATUS_IS_OK(status)) { >+ struct smb2_read rd; >+ >+ rd = (struct smb2_read) { >+ .in.file.handle = handle, >+ .in.length = blob.length, >+ .in.offset = 0 >+ }; >+ >+ torture_assert_ntstatus_ok_goto(tctx, >+ smb2_read(tree, tree, &rd), >+ ret, done, "failed to read after write"); >+ >+ torture_assert_data_blob_equal(tctx, >+ rd.out.data, blob, >+ "read/write mismatch"); >+ } >+ break; >+ } >+ case SMB2_OP_IOCTL: { >+ union smb_ioctl ioctl; >+ ioctl = (union smb_ioctl) { >+ .smb2.level = RAW_IOCTL_SMB2, >+ .smb2.in.file.handle = handle, >+ .smb2.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID, >+ .smb2.in.max_response_size = 64, >+ .smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL >+ }; >+ status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2); >+ break; >+ } >+ case SMB2_OP_SETINFO: { >+ union smb_setfileinfo sfinfo; >+ ZERO_STRUCT(sfinfo); >+ sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION; >+ sfinfo.generic.in.file.handle = handle; >+ sfinfo.position_information.in.position = 0x1000; >+ status = smb2_setinfo_file(tree, &sfinfo); >+ break; >+ } >+ default: >+ break; >+ } >+ >+ qfinfo = (union smb_fileinfo) { >+ .generic.level = RAW_SFILEINFO_POSITION_INFORMATION, >+ .generic.in.file.handle = handle >+ }; >+ >+ torture_assert_ntstatus_ok_goto(tctx, >+ smb2_getinfo_file(tree, mem_ctx, &qfinfo), >+ ret, done, "failed to read after write"); >+ >+ if (do_replay) { >+ smb2cli_session_stop_replay(tree->session->smbXcli); >+ } >+ >+ torture_assert_ntstatus_equal_goto(tctx, >+ status, tests[i].expected_status, >+ ret, done, "got unexpected failure code"); >+ >+ } >+done: >+ if (phandle != NULL) { >+ smb2_util_close(tree, *phandle); >+ } >+ >+ smb2_util_unlink(tree, fname); >+ >+ return ret; >+} >+ >+static bool test_channel_sequence(struct torture_context *tctx, >+ struct smb2_tree *tree) >+{ >+ TALLOC_CTX *mem_ctx = talloc_new(tctx); >+ bool ret = true; >+ const char *fname = BASEDIR "\\channel_sequence.dat"; >+ struct smb2_transport *transport1 = tree->session->transport; >+ struct smb2_handle handle; >+ uint32_t server_capabilities; >+ uint16_t opcodes[] = { SMB2_OP_WRITE, SMB2_OP_IOCTL, SMB2_OP_SETINFO }; >+ int i; >+ >+ 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( >+ tree->session->transport->conn); >+ if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) { >+ torture_skip(tctx, >+ "Server does not support multi-channel."); >+ } >+ >+ torture_comment(tctx, "Testing channel sequence numbers\n"); >+ >+ torture_assert_ntstatus_ok_goto(tctx, >+ torture_smb2_testdir(tree, BASEDIR, &handle), >+ ret, done, "failed to setup test directory"); >+ >+ smb2_util_close(tree, handle); >+ smb2_util_unlink(tree, fname); >+ >+ for (i=0; i <ARRAY_SIZE(opcodes); i++) { >+ torture_assert(tctx, >+ test_channel_sequence_table(tctx, tree, false, opcodes[i]), >+ "failed to test CSN without replay flag"); >+ torture_assert(tctx, >+ test_channel_sequence_table(tctx, tree, true, opcodes[i]), >+ "failed to test CSN with replay flag"); >+ } >+ >+done: >+ >+ smb2_util_unlink(tree, fname); >+ smb2_deltree(tree, BASEDIR); >+ >+ talloc_free(tree); >+ talloc_free(mem_ctx); >+ >+ return ret; >+} >+ > /** > * Test Durablity V2 Create Replay Detection on Multi Channel > */ >@@ -1971,6 +2236,7 @@ struct torture_suite *torture_smb2_replay_init(void) > 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, "channel-sequence", test_channel_sequence); > 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.5 > > >From c5c3f91c6fd1ac3282d2fa27e262af097f0adfca Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org> >Date: Wed, 24 Feb 2016 19:23:21 +0100 >Subject: [PATCH 09/20] lib/torture: add torture_assert_u64_not_equal_goto > macro >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >Guenther > >Signed-off-by: Günther Deschner <gd@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > lib/torture/torture.h | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > >diff --git a/lib/torture/torture.h b/lib/torture/torture.h >index 356922a..e710873 100644 >--- a/lib/torture/torture.h >+++ b/lib/torture/torture.h >@@ -479,6 +479,18 @@ void torture_result(struct torture_context *test, > } \ > } while(0) > >+#define torture_assert_u64_not_equal_goto(torture_ctx,got,not_expected,ret,label,cmt)\ >+ do { uint64_t __got = (got), __not_expected = (not_expected); \ >+ if (__got == __not_expected) { \ >+ torture_result(torture_ctx, TORTURE_FAIL, \ >+ __location__": "#got" was %llu (0x%llX), expected a different number: %s", \ >+ (unsigned long long)__got, (unsigned long long)__got, \ >+ cmt); \ >+ ret = false; \ >+ goto label; \ >+ } \ >+ } while(0) >+ > #define torture_assert_errno_equal(torture_ctx,expected,cmt)\ > do { int __expected = (expected); \ > if (errno != __expected) { \ >-- >2.5.5 > > >From e095a61c4b36e71b03d8afc724da09c91603a29b Mon Sep 17 00:00:00 2001 >From: Anubhav Rakshit <anubhav.rakshit@gmail.com> >Date: Thu, 30 Oct 2014 13:20:57 +0530 >Subject: [PATCH 10/20] torture:smb2: Add test replay6 to verify Error Codes > for DurableHandleReqV2 replay > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> >Pair-Programmed-With: Guenther Deschner <gd@samba.org> >Pair-Programmed-With: Michael Adam <obnox@samba.org> > >Signed-off-by: Anubhav Rakshit <anubhav.rakshit@gmail.com> >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Signed-off-by: Guenther Deschner <gd@samba.org> >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source4/torture/smb2/replay.c | 211 +++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 209 insertions(+), 2 deletions(-) > >diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c >index 8388837..91bb568 100644 >--- a/source4/torture/smb2/replay.c >+++ b/source4/torture/smb2/replay.c >@@ -94,7 +94,7 @@ > > #define BASEDIR "replaytestdir" > >-static struct { >+struct break_info { > struct torture_context *tctx; > struct smb2_handle handle; > uint8_t level; >@@ -102,7 +102,16 @@ static struct { > int count; > int failures; > NTSTATUS failure_status; >-} break_info; >+}; >+ >+static struct break_info break_info; >+ >+static void torture_reset_break_info(struct torture_context *tctx, >+ struct break_info *r) >+{ >+ ZERO_STRUCTP(r); >+ r->tctx = tctx; >+} > > static void torture_oplock_ack_callback(struct smb2_request *req) > { >@@ -163,6 +172,61 @@ static bool torture_oplock_ack_handler(struct smb2_transport *transport, > } > > /** >+ * Timer handler function notifies the registering function that time is up >+ */ >+static void timeout_cb(struct tevent_context *ev, >+ struct tevent_timer *te, >+ struct timeval current_time, >+ void *private_data) >+{ >+ bool *timesup = (bool *)private_data; >+ *timesup = true; >+ return; >+} >+ >+/** >+ * Wait a short period of time to receive a single oplock break request >+ */ >+static void torture_wait_for_oplock_break(struct torture_context *tctx) >+{ >+ TALLOC_CTX *tmp_ctx = talloc_new(NULL); >+ struct tevent_timer *te = NULL; >+ struct timeval ne; >+ bool timesup = false; >+ int old_count = break_info.count; >+ >+ /* Wait .1 seconds for an oplock break */ >+ ne = tevent_timeval_current_ofs(0, 100000); >+ >+ te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, ×up); >+ if (te == NULL) { >+ torture_comment(tctx, "Failed to wait for an oplock break. " >+ "test results may not be accurate."); >+ goto done; >+ } >+ >+ while (!timesup && break_info.count < old_count + 1) { >+ if (tevent_loop_once(tctx->ev) != 0) { >+ torture_comment(tctx, "Failed to wait for an oplock " >+ "break. test results may not be " >+ "accurate."); >+ goto done; >+ } >+ } >+ >+done: >+ /* >+ * We don't know if the timed event fired and was freed, we received >+ * our oplock break, or some other event triggered the loop. Thus, >+ * we create a tmp_ctx to be able to safely free/remove the timed >+ * event in all 3 cases. >+ */ >+ talloc_free(tmp_ctx); >+ >+ return; >+} >+ >+/** > * 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. > */ >@@ -2221,6 +2285,148 @@ done: > return ret; > } > >+ >+/** >+ * Test Error Codes when a DurableHandleReqV2 with matching CreateGuid is >+ * re-sent with or without SMB2_FLAGS_REPLAY_OPERATION >+ */ >+static bool test_replay6(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; >+ union smb_fileinfo qfinfo; >+ struct GUID create_guid = GUID_random(); >+ bool ret = true; >+ const char *fname = BASEDIR "\\replay6.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"); >+ } >+ >+ torture_reset_break_info(tctx, &break_info); >+ tree->session->transport->oplock.handler = torture_oplock_ack_handler; >+ tree->session->transport->oplock.private_data = tree; >+ >+ torture_comment(tctx, "Error Codes for DurableHandleReqV2 Replay\n"); >+ smb2_util_unlink(tree, fname); >+ status = torture_smb2_testdir(tree, BASEDIR, &_h); >+ CHECK_STATUS(status, NT_STATUS_OK); >+ smb2_util_close(tree, _h); >+ torture_wait_for_oplock_break(tctx); >+ CHECK_VAL(break_info.count, 0); >+ torture_reset_break_info(tctx, &break_info); >+ >+ 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; >+ >+ 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.oplock_level, smb2_util_oplock_level("b")); >+ CHECK_VAL(io.out.durable_open, false); >+ CHECK_VAL(io.out.durable_open_v2, true); >+ >+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; >+ io.in.create_disposition = NTCREATEX_DISP_OPEN; >+ 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_OK); >+ CHECK_CREATE_OUT(&io, &ref1); >+ torture_wait_for_oplock_break(tctx); >+ CHECK_VAL(break_info.count, 0); >+ torture_reset_break_info(tctx, &break_info); >+ >+ qfinfo = (union smb_fileinfo) { >+ .generic.level = RAW_SFILEINFO_POSITION_INFORMATION, >+ .generic.in.file.handle = *h >+ }; >+ torture_comment(tctx, "Trying getinfo\n"); >+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); >+ CHECK_STATUS(status, NT_STATUS_OK); >+ CHECK_VAL(qfinfo.position_information.out.position, 0); >+ >+ 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_OK); >+ torture_assert_u64_not_equal_goto(tctx, >+ io.out.file.handle.data[0], >+ ref1.out.file.handle.data[0], >+ ret, done, "data 0"); >+ torture_assert_u64_not_equal_goto(tctx, >+ io.out.file.handle.data[1], >+ ref1.out.file.handle.data[1], >+ ret, done, "data 1"); >+ torture_wait_for_oplock_break(tctx); >+ CHECK_VAL(break_info.count, 1); >+ CHECK_VAL(break_info.level, smb2_util_oplock_level("s")); >+ torture_reset_break_info(tctx, &break_info); >+ >+ /* >+ * Resend the matching Durable V2 Create without >+ * SMB2_FLAGS_REPLAY_OPERATION. This triggers an oplock break and still >+ * gets NT_STATUS_DUPLICATE_OBJECTID >+ */ >+ status = smb2_create(tree, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_DUPLICATE_OBJECTID); >+ torture_wait_for_oplock_break(tctx); >+ CHECK_VAL(break_info.count, 0); >+ torture_reset_break_info(tctx, &break_info); >+ >+ /* >+ * According to MS-SMB2 3.3.5.9.10 if Durable V2 Create is replayed and >+ * FileAttributes or CreateDisposition do not match the earlier Create >+ * request the Server fails request with >+ * NT_STATUS_INVALID_PARAMETER. But through this test we see that server >+ * does not really care about changed FileAttributes or >+ * CreateDisposition. >+ */ >+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; >+ io.in.create_disposition = NTCREATEX_DISP_OPEN; >+ 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_OK); >+ torture_assert_u64_not_equal_goto(tctx, >+ io.out.file.handle.data[0], >+ ref1.out.file.handle.data[0], >+ ret, done, "data 0"); >+ torture_assert_u64_not_equal_goto(tctx, >+ io.out.file.handle.data[1], >+ ref1.out.file.handle.data[1], >+ ret, done, "data 1"); >+ torture_wait_for_oplock_break(tctx); >+ CHECK_VAL(break_info.count, 0); >+ >+done: >+ if (h != NULL) { >+ smb2_util_close(tree, *h); >+ } >+ >+ smb2_util_unlink(tree, fname); >+ smb2_deltree(tree, BASEDIR); >+ >+ talloc_free(tree); >+ talloc_free(mem_ctx); >+ >+ return ret; >+} >+ > struct torture_suite *torture_smb2_replay_init(void) > { > struct torture_suite *suite = >@@ -2240,6 +2446,7 @@ struct torture_suite *torture_smb2_replay_init(void) > 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); >+ torture_suite_add_1smb2_test(suite, "replay6", test_replay6); > > suite->description = talloc_strdup(suite, "SMB2 REPLAY tests"); > >-- >2.5.5 > > >From b7186a00bb985b5b878ccf2c47a1ac4e0c2a7c79 Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Tue, 15 Mar 2016 09:35:03 +0100 >Subject: [PATCH 11/20] torture:smb2: use assert, not warning in error case in > durable-open.reopen1a > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source4/torture/smb2/durable_open.c | 10 +++------- > 1 file changed, 3 insertions(+), 7 deletions(-) > >diff --git a/source4/torture/smb2/durable_open.c b/source4/torture/smb2/durable_open.c >index fe0a326..11388ef 100644 >--- a/source4/torture/smb2/durable_open.c >+++ b/source4/torture/smb2/durable_open.c >@@ -464,13 +464,9 @@ static bool test_durable_open_reopen1a(struct torture_context *tctx, > > previous_session_id = smb2cli_session_current_id(tree->session->smbXcli); > >- if (!torture_smb2_connection_ext(tctx, previous_session_id, >- &options, &tree2)) >- { >- torture_warning(tctx, "couldn't reconnect, bailing\n"); >- ret = false; >- goto done; >- } >+ ret = torture_smb2_connection_ext(tctx, previous_session_id, >+ &options, &tree2); >+ torture_assert_goto(tctx, ret, ret, done, "could not reconnect"); > > /* > * check that this has deleted the old session >-- >2.5.5 > > >From 37c05f4ade3a2d0e5076941095e7d5c09631ac1b Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Fri, 4 Mar 2016 22:55:40 +0100 >Subject: [PATCH 12/20] torture:smb2: fix crashes in smb2.durable-open.reopen1a > test > >If the test failed too early, we dereferenced tree2 which >was still NULL. > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source4/torture/smb2/durable_open.c | 18 ++++++++++++------ > 1 file changed, 12 insertions(+), 6 deletions(-) > >diff --git a/source4/torture/smb2/durable_open.c b/source4/torture/smb2/durable_open.c >index 11388ef..e8a82c0 100644 >--- a/source4/torture/smb2/durable_open.c >+++ b/source4/torture/smb2/durable_open.c >@@ -479,6 +479,8 @@ static bool test_durable_open_reopen1a(struct torture_context *tctx, > status = smb2_create(tree, mem_ctx, &io2); > CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); > >+ TALLOC_FREE(tree); >+ > /* > * but a durable reconnect on the new session succeeds: > */ >@@ -495,15 +497,19 @@ static bool test_durable_open_reopen1a(struct torture_context *tctx, > h = &_h; > > done: >- if (h != NULL) { >- smb2_util_close(tree2, *h); >+ if (tree == NULL) { >+ tree = tree2; > } > >- smb2_util_unlink(tree2, fname); >- >- talloc_free(tree2); >+ if (tree != NULL) { >+ if (h != NULL) { >+ smb2_util_close(tree, *h); >+ h = NULL; >+ } >+ smb2_util_unlink(tree, fname); > >- talloc_free(tree); >+ talloc_free(tree); >+ } > > talloc_free(mem_ctx); > >-- >2.5.5 > > >From 505546be57043c81e38ddcfe1b8bcdf0ad5963b0 Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Thu, 17 Mar 2016 02:45:16 +0100 >Subject: [PATCH 13/20] torture:smb2: durable-open.reopen1a only needs one io > struct > >Using two is confusing. > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source4/torture/smb2/durable_open.c | 38 ++++++++++++++++++------------------- > 1 file changed, 19 insertions(+), 19 deletions(-) > >diff --git a/source4/torture/smb2/durable_open.c b/source4/torture/smb2/durable_open.c >index e8a82c0..584f046 100644 >--- a/source4/torture/smb2/durable_open.c >+++ b/source4/torture/smb2/durable_open.c >@@ -431,7 +431,7 @@ static bool test_durable_open_reopen1a(struct torture_context *tctx, > char fname[256]; > struct smb2_handle _h; > struct smb2_handle *h = NULL; >- struct smb2_create io1, io2; >+ struct smb2_create io; > bool ret = true; > struct smb2_tree *tree2 = NULL; > uint64_t previous_session_id; >@@ -445,18 +445,18 @@ static bool test_durable_open_reopen1a(struct torture_context *tctx, > > smb2_util_unlink(tree, fname); > >- smb2_oplock_create_share(&io1, fname, >+ smb2_oplock_create_share(&io, fname, > smb2_util_share_access(""), > smb2_util_oplock_level("b")); >- io1.in.durable_open = true; >+ io.in.durable_open = true; > >- status = smb2_create(tree, mem_ctx, &io1); >+ status = smb2_create(tree, mem_ctx, &io); > CHECK_STATUS(status, NT_STATUS_OK); >- _h = io1.out.file.handle; >+ _h = io.out.file.handle; > h = &_h; >- CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); >- CHECK_VAL(io1.out.durable_open, true); >- CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b")); >+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); >+ CHECK_VAL(io.out.durable_open, true); >+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); > > /* > * a session reconnect on a second tcp connection >@@ -472,11 +472,11 @@ static bool test_durable_open_reopen1a(struct torture_context *tctx, > * check that this has deleted the old session > */ > >- ZERO_STRUCT(io2); >- io2.in.fname = fname; >- io2.in.durable_handle = h; >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle = h; > >- status = smb2_create(tree, mem_ctx, &io2); >+ status = smb2_create(tree, mem_ctx, &io); > CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); > > TALLOC_FREE(tree); >@@ -485,15 +485,15 @@ static bool test_durable_open_reopen1a(struct torture_context *tctx, > * but a durable reconnect on the new session succeeds: > */ > >- ZERO_STRUCT(io2); >- io2.in.fname = fname; >- io2.in.durable_handle = h; >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle = h; > >- status = smb2_create(tree2, mem_ctx, &io2); >+ status = smb2_create(tree2, mem_ctx, &io); > CHECK_STATUS(status, NT_STATUS_OK); >- CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE); >- CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b")); >- _h = io2.out.file.handle; >+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE); >+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); >+ _h = io.out.file.handle; > h = &_h; > > done: >-- >2.5.5 > > >From 7b557617e48e17c2f02801fcd089719f7994488b Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Tue, 15 Mar 2016 08:59:53 +0100 >Subject: [PATCH 14/20] torture:smb2: for oplocks, durable reconnect works with > different client guid > >in durabble-open.reopen1a test > >Try both original and a different client guid. > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source4/torture/smb2/durable_open.c | 51 +++++++++++++++++++++++++++++++++++++ > 1 file changed, 51 insertions(+) > >diff --git a/source4/torture/smb2/durable_open.c b/source4/torture/smb2/durable_open.c >index 584f046..b74b5c5 100644 >--- a/source4/torture/smb2/durable_open.c >+++ b/source4/torture/smb2/durable_open.c >@@ -434,10 +434,13 @@ static bool test_durable_open_reopen1a(struct torture_context *tctx, > struct smb2_create io; > bool ret = true; > struct smb2_tree *tree2 = NULL; >+ struct smb2_tree *tree3 = NULL; > uint64_t previous_session_id; > struct smbcli_options options; >+ struct GUID orig_client_guid; > > options = tree->session->transport->options; >+ orig_client_guid = options.client_guid; > > /* Choose a random name in case the state is left a little funky. */ > snprintf(fname, 256, "durable_open_reopen1a_%s.dat", >@@ -464,6 +467,9 @@ static bool test_durable_open_reopen1a(struct torture_context *tctx, > > previous_session_id = smb2cli_session_current_id(tree->session->smbXcli); > >+ /* for oplocks, the client guid can be different: */ >+ options.client_guid = GUID_random(); >+ > ret = torture_smb2_connection_ext(tctx, previous_session_id, > &options, &tree2); > torture_assert_goto(tctx, ret, ret, done, "could not reconnect"); >@@ -496,11 +502,56 @@ static bool test_durable_open_reopen1a(struct torture_context *tctx, > _h = io.out.file.handle; > h = &_h; > >+ /* >+ * a session reconnect on a second tcp connection >+ */ >+ >+ previous_session_id = smb2cli_session_current_id(tree2->session->smbXcli); >+ >+ /* the original client_guid works just the same */ >+ options.client_guid = orig_client_guid; >+ >+ ret = torture_smb2_connection_ext(tctx, previous_session_id, >+ &options, &tree3); >+ torture_assert_goto(tctx, ret, ret, done, "could not reconnect"); >+ >+ /* >+ * check that this has deleted the old session >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle = h; >+ >+ status = smb2_create(tree2, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); >+ >+ TALLOC_FREE(tree2); >+ >+ /* >+ * but a durable reconnect on the new session succeeds: >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle = h; >+ >+ status = smb2_create(tree3, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_OK); >+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE); >+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b")); >+ _h = io.out.file.handle; >+ h = &_h; >+ > done: > if (tree == NULL) { > tree = tree2; > } > >+ if (tree == NULL) { >+ tree = tree3; >+ } >+ > if (tree != NULL) { > if (h != NULL) { > smb2_util_close(tree, *h); >-- >2.5.5 > > >From 3e90abe6704a1af62ce22a6e62539a28a8abfe22 Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Tue, 15 Mar 2016 10:02:14 +0100 >Subject: [PATCH 15/20] torture:smb2: add durable-open.reopen1a-lease > >Lease variant of the reopen1a test which tests the >relevance of the client guid. > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > selftest/knownfail | 1 + > source4/torture/smb2/durable_open.c | 170 ++++++++++++++++++++++++++++++++++++ > 2 files changed, 171 insertions(+) > >diff --git a/selftest/knownfail b/selftest/knownfail >index 0950ef0..d223871 100644 >--- a/selftest/knownfail >+++ b/selftest/knownfail >@@ -193,6 +193,7 @@ > ^samba3.smb2.notify.rec > ^samba3.smb2.durable-open.delete_on_close2 > ^samba3.smb2.durable-v2-open.app-instance >+^samba3.smb2.durable-open.reopen1a-lease\(ad_dc\)$ > ^samba4.smb2.ioctl.req_resume_key\(ad_dc_ntvfs\) # not supported by s4 ntvfs server > ^samba4.smb2.ioctl.copy_chunk_\w*\(ad_dc_ntvfs\) # not supported by s4 ntvfs server > ^samba3.smb2.dir.one >diff --git a/source4/torture/smb2/durable_open.c b/source4/torture/smb2/durable_open.c >index b74b5c5..7b59566 100644 >--- a/source4/torture/smb2/durable_open.c >+++ b/source4/torture/smb2/durable_open.c >@@ -568,6 +568,175 @@ done: > } > > /** >+ * lease variant of reopen1a >+ * >+ * Basic test for doing a durable open and doing a session >+ * reconnect while the first session is still active and the >+ * handle is still open in the client. >+ * This closes the original session and a durable reconnect on >+ * the new session succeeds depending on the client guid: >+ * >+ * Durable reconnect on a session with a different client guid fails. >+ * Durable reconnect on a session with the original client guid succeeds. >+ */ >+bool test_durable_open_reopen1a_lease(struct torture_context *tctx, >+ struct smb2_tree *tree) >+{ >+ NTSTATUS status; >+ TALLOC_CTX *mem_ctx = talloc_new(tctx); >+ char fname[256]; >+ struct smb2_handle _h; >+ struct smb2_handle *h = NULL; >+ struct smb2_create io; >+ struct smb2_lease ls; >+ uint64_t lease_key; >+ bool ret = true; >+ struct smb2_tree *tree2 = NULL; >+ struct smb2_tree *tree3 = NULL; >+ uint64_t previous_session_id; >+ struct smbcli_options options; >+ struct GUID orig_client_guid; >+ >+ options = tree->session->transport->options; >+ orig_client_guid = options.client_guid; >+ >+ /* Choose a random name in case the state is left a little funky. */ >+ snprintf(fname, 256, "durable_v2_open_reopen1a_lease_%s.dat", >+ generate_random_str(tctx, 8)); >+ >+ smb2_util_unlink(tree, fname); >+ >+ lease_key = random(); >+ smb2_lease_create(&io, &ls, false /* dir */, fname, >+ lease_key, smb2_util_lease_state("RWH")); >+ io.in.durable_open = true; >+ >+ 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, true); >+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); >+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key); >+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key); >+ CHECK_VAL(io.out.lease_response.lease_state, >+ smb2_util_lease_state("RWH")); >+ CHECK_VAL(io.out.lease_response.lease_flags, 0); >+ CHECK_VAL(io.out.lease_response.lease_duration, 0); >+ >+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli); >+ >+ /* >+ * a session reconnect on a second tcp connection >+ * with a different client_guid does not allow >+ * the durable reconnect. >+ */ >+ >+ options.client_guid = GUID_random(); >+ >+ ret = torture_smb2_connection_ext(tctx, previous_session_id, >+ &options, &tree2); >+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect"); >+ >+ /* >+ * check that this has deleted the old session >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle = h; >+ io.in.lease_request = &ls; >+ status = smb2_create(tree, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); >+ TALLOC_FREE(tree); >+ >+ >+ /* >+ * but a durable reconnect on the new session with the wrong >+ * client guid fails >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle = h; >+ io.in.lease_request = &ls; >+ status = smb2_create(tree2, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); >+ >+ /* >+ * now a session reconnect on a second tcp connection >+ * with original client_guid allows the durable reconnect. >+ */ >+ >+ options.client_guid = orig_client_guid; >+ >+ ret = torture_smb2_connection_ext(tctx, previous_session_id, >+ &options, &tree3); >+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect"); >+ >+ /* >+ * check that this has deleted the old session >+ * In this case, a durable reconnect attempt with the >+ * correct client_guid yields a different error code. >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle = h; >+ io.in.lease_request = &ls; >+ status = smb2_create(tree2, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); >+ TALLOC_FREE(tree2); >+ >+ /* >+ * but a durable reconnect on the new session succeeds: >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle = h; >+ io.in.lease_request = &ls; >+ status = smb2_create(tree3, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_OK); >+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE); >+ CHECK_VAL(io.out.durable_open, false); /* no dh response context... */ >+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); >+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key); >+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key); >+ CHECK_VAL(io.out.lease_response.lease_state, >+ smb2_util_lease_state("RWH")); >+ CHECK_VAL(io.out.lease_response.lease_flags, 0); >+ CHECK_VAL(io.out.lease_response.lease_duration, 0); >+ _h = io.out.file.handle; >+ h = &_h; >+ >+done: >+ if (tree == NULL) { >+ tree = tree2; >+ } >+ >+ if (tree == NULL) { >+ tree = tree3; >+ } >+ >+ if (tree != NULL) { >+ if (h != NULL) { >+ smb2_util_close(tree, *h); >+ } >+ >+ smb2_util_unlink(tree, fname); >+ >+ talloc_free(tree); >+ } >+ >+ talloc_free(mem_ctx); >+ >+ return ret; >+} >+ >+ >+/** > * basic test for doing a durable open > * tcp disconnect, reconnect, do a durable reopen (succeeds) > */ >@@ -2589,6 +2758,7 @@ struct torture_suite *torture_smb2_durable_open_init(void) > torture_suite_add_1smb2_test(suite, "open-lease", test_durable_open_open_lease); > torture_suite_add_1smb2_test(suite, "reopen1", test_durable_open_reopen1); > torture_suite_add_1smb2_test(suite, "reopen1a", test_durable_open_reopen1a); >+ torture_suite_add_1smb2_test(suite, "reopen1a-lease", test_durable_open_reopen1a_lease); > torture_suite_add_1smb2_test(suite, "reopen2", test_durable_open_reopen2); > torture_suite_add_1smb2_test(suite, "reopen2-lease", test_durable_open_reopen2_lease); > torture_suite_add_1smb2_test(suite, "reopen2-lease-v2", test_durable_open_reopen2_lease_v2); >-- >2.5.5 > > >From 186cd708291641c507cda0c89cc9c24900634ed2 Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Tue, 15 Mar 2016 09:39:43 +0100 >Subject: [PATCH 16/20] torture:smb2: use assert, not warning in error case in > durable-v2-open.reopen1a > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source4/torture/smb2/durable_v2_open.c | 10 +++------- > 1 file changed, 3 insertions(+), 7 deletions(-) > >diff --git a/source4/torture/smb2/durable_v2_open.c b/source4/torture/smb2/durable_v2_open.c >index f3ec344..a80506a 100644 >--- a/source4/torture/smb2/durable_v2_open.c >+++ b/source4/torture/smb2/durable_v2_open.c >@@ -629,13 +629,9 @@ bool test_durable_v2_open_reopen1a(struct torture_context *tctx, > > previous_session_id = smb2cli_session_current_id(tree->session->smbXcli); > >- if (!torture_smb2_connection_ext(tctx, previous_session_id, >- &options, &tree2)) >- { >- torture_warning(tctx, "couldn't reconnect, bailing\n"); >- ret = false; >- goto done; >- } >+ ret = torture_smb2_connection_ext(tctx, previous_session_id, >+ &options, &tree2); >+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect"); > > /* > * check that this has deleted the old session >-- >2.5.5 > > >From b0f592d05f66114427b26cd4aeea918e41a2e952 Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Tue, 15 Mar 2016 09:44:06 +0100 >Subject: [PATCH 17/20] torture:smb2: fix crashes in > smb2.durable-v2-open.reopen1a test > >If the test failed too early, we dereferenced tree2 which >was still NULL. > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source4/torture/smb2/durable_v2_open.c | 16 ++++++++++++---- > 1 file changed, 12 insertions(+), 4 deletions(-) > >diff --git a/source4/torture/smb2/durable_v2_open.c b/source4/torture/smb2/durable_v2_open.c >index a80506a..de24c8f 100644 >--- a/source4/torture/smb2/durable_v2_open.c >+++ b/source4/torture/smb2/durable_v2_open.c >@@ -644,6 +644,8 @@ bool test_durable_v2_open_reopen1a(struct torture_context *tctx, > status = smb2_create(tree, mem_ctx, &io); > CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); > >+ TALLOC_FREE(tree); >+ > /* > * but a durable reconnect on the new session succeeds: > */ >@@ -664,13 +666,19 @@ bool test_durable_v2_open_reopen1a(struct torture_context *tctx, > h = &_h; > > done: >- if (h != NULL) { >- smb2_util_close(tree, *h); >+ if (tree == NULL) { >+ tree = tree2; > } > >- smb2_util_unlink(tree, fname); >+ if (tree != NULL) { >+ if (h != NULL) { >+ smb2_util_close(tree, *h); >+ } > >- talloc_free(tree); >+ smb2_util_unlink(tree, fname); >+ >+ talloc_free(tree); >+ } > > talloc_free(mem_ctx); > >-- >2.5.5 > > >From cd2298087583de8d6b352dbbbecb00b1dbffe25c Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Thu, 17 Mar 2016 02:35:35 +0100 >Subject: [PATCH 18/20] torture:smb2: get rid of supefluous io2 var in > durable-v2-open.reopen1a > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source4/torture/smb2/durable_v2_open.c | 26 +++++++++++++------------- > 1 file changed, 13 insertions(+), 13 deletions(-) > >diff --git a/source4/torture/smb2/durable_v2_open.c b/source4/torture/smb2/durable_v2_open.c >index de24c8f..2528187 100644 >--- a/source4/torture/smb2/durable_v2_open.c >+++ b/source4/torture/smb2/durable_v2_open.c >@@ -588,7 +588,7 @@ bool test_durable_v2_open_reopen1a(struct torture_context *tctx, > char fname[256]; > struct smb2_handle _h; > struct smb2_handle *h = NULL; >- struct smb2_create io, io2; >+ struct smb2_create io; > struct GUID create_guid = GUID_random(); > bool ret = true; > struct smb2_tree *tree2 = NULL; >@@ -650,19 +650,19 @@ bool test_durable_v2_open_reopen1a(struct torture_context *tctx, > * but a durable reconnect on the new session succeeds: > */ > >- ZERO_STRUCT(io2); >- io2.in.fname = ""; >- io2.in.durable_handle_v2 = h; >- io2.in.create_guid = create_guid; >- status = smb2_create(tree2, mem_ctx, &io2); >+ ZERO_STRUCT(io); >+ io.in.fname = ""; >+ io.in.durable_handle_v2 = h; >+ io.in.create_guid = create_guid; >+ status = smb2_create(tree2, mem_ctx, &io); > CHECK_STATUS(status, NT_STATUS_OK); >- CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE); >- CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b")); >- CHECK_VAL(io2.out.durable_open, false); >- CHECK_VAL(io2.out.durable_open_v2, false); /* no dh2q response blob */ >- CHECK_VAL(io2.out.persistent_open, false); >- CHECK_VAL(io2.out.timeout, io.in.timeout); >- _h = io2.out.file.handle; >+ CHECK_CREATED(&io, EXISTED, 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, false); /* no dh2q response blob */ >+ CHECK_VAL(io.out.persistent_open, false); >+ CHECK_VAL(io.out.timeout, io.in.timeout); >+ _h = io.out.file.handle; > h = &_h; > > done: >-- >2.5.5 > > >From b853040d5f27f0faf8d9a6071e6e6e6b2f840360 Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Tue, 15 Mar 2016 09:02:28 +0100 >Subject: [PATCH 19/20] torture:smb2: for oplocks, durable reconnect works with > different client-guid > >for durable-v2-open.reopen1a > >Try both different and original client guid. > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source4/torture/smb2/durable_v2_open.c | 54 ++++++++++++++++++++++++++++++++++ > 1 file changed, 54 insertions(+) > >diff --git a/source4/torture/smb2/durable_v2_open.c b/source4/torture/smb2/durable_v2_open.c >index 2528187..e48fb9b 100644 >--- a/source4/torture/smb2/durable_v2_open.c >+++ b/source4/torture/smb2/durable_v2_open.c >@@ -592,10 +592,13 @@ bool test_durable_v2_open_reopen1a(struct torture_context *tctx, > struct GUID create_guid = GUID_random(); > bool ret = true; > struct smb2_tree *tree2 = NULL; >+ struct smb2_tree *tree3 = NULL; > uint64_t previous_session_id; > struct smbcli_options options; >+ struct GUID orig_client_guid; > > options = tree->session->transport->options; >+ orig_client_guid = options.client_guid; > > /* Choose a random name in case the state is left a little funky. */ > snprintf(fname, 256, "durable_v2_open_reopen1a_%s.dat", >@@ -629,6 +632,9 @@ bool test_durable_v2_open_reopen1a(struct torture_context *tctx, > > previous_session_id = smb2cli_session_current_id(tree->session->smbXcli); > >+ /* for oplocks, the client guid can be different: */ >+ options.client_guid = GUID_random(); >+ > ret = torture_smb2_connection_ext(tctx, previous_session_id, > &options, &tree2); > torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect"); >@@ -665,11 +671,59 @@ bool test_durable_v2_open_reopen1a(struct torture_context *tctx, > _h = io.out.file.handle; > h = &_h; > >+ /* >+ * a session reconnect on a second tcp connection >+ */ >+ >+ previous_session_id = smb2cli_session_current_id(tree2->session->smbXcli); >+ >+ /* it works the same with the original guid */ >+ options.client_guid = orig_client_guid; >+ >+ ret = torture_smb2_connection_ext(tctx, previous_session_id, >+ &options, &tree3); >+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect"); >+ >+ /* >+ * check that this has deleted the old session >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = ""; >+ io.in.durable_handle_v2 = h; >+ io.in.create_guid = create_guid; >+ status = smb2_create(tree2, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); >+ TALLOC_FREE(tree2); >+ >+ /* >+ * but a durable reconnect on the new session succeeds: >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = ""; >+ io.in.durable_handle_v2 = h; >+ io.in.create_guid = create_guid; >+ status = smb2_create(tree3, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_OK); >+ CHECK_CREATED(&io, EXISTED, 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, false); /* no dh2q response blob */ >+ CHECK_VAL(io.out.persistent_open, false); >+ CHECK_VAL(io.out.timeout, io.in.timeout); >+ _h = io.out.file.handle; >+ h = &_h; >+ > done: > if (tree == NULL) { > tree = tree2; > } > >+ if (tree == NULL) { >+ tree = tree3; >+ } >+ > if (tree != NULL) { > if (h != NULL) { > smb2_util_close(tree, *h); >-- >2.5.5 > > >From e9586a653c62b996f1a183c897308ea0794c1cb7 Mon Sep 17 00:00:00 2001 >From: Michael Adam <obnox@samba.org> >Date: Tue, 15 Mar 2016 09:06:56 +0100 >Subject: [PATCH 20/20] torture:smb2: add durable-v2-open.reopen1a-lease > >Lease variant of the reopen1a test which tests the >relevance of the client guid. > >Signed-off-by: Michael Adam <obnox@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >Autobuild-User(master): Jeremy Allison <jra@samba.org> >Autobuild-Date(master): Tue Mar 22 03:47:02 CET 2016 on sn-devel-144 >--- > selftest/knownfail | 1 + > source4/torture/smb2/durable_v2_open.c | 183 +++++++++++++++++++++++++++++++++ > 2 files changed, 184 insertions(+) > >diff --git a/selftest/knownfail b/selftest/knownfail >index d223871..83cf2d6 100644 >--- a/selftest/knownfail >+++ b/selftest/knownfail >@@ -194,6 +194,7 @@ > ^samba3.smb2.durable-open.delete_on_close2 > ^samba3.smb2.durable-v2-open.app-instance > ^samba3.smb2.durable-open.reopen1a-lease\(ad_dc\)$ >+^samba3.smb2.durable-v2-open.reopen1a-lease\(ad_dc\)$ > ^samba4.smb2.ioctl.req_resume_key\(ad_dc_ntvfs\) # not supported by s4 ntvfs server > ^samba4.smb2.ioctl.copy_chunk_\w*\(ad_dc_ntvfs\) # not supported by s4 ntvfs server > ^samba3.smb2.dir.one >diff --git a/source4/torture/smb2/durable_v2_open.c b/source4/torture/smb2/durable_v2_open.c >index e48fb9b..b7d8920 100644 >--- a/source4/torture/smb2/durable_v2_open.c >+++ b/source4/torture/smb2/durable_v2_open.c >@@ -740,6 +740,188 @@ done: > } > > /** >+ * lease variant of reopen1a >+ * >+ * Basic test for doing a durable open and doing a session >+ * reconnect while the first session is still active and the >+ * handle is still open in the client. >+ * This closes the original session and a durable reconnect on >+ * the new session succeeds depending on the client guid: >+ * >+ * Durable reconnect on a session with a different client guid fails. >+ * Durable reconnect on a session with the original client guid succeeds. >+ */ >+bool test_durable_v2_open_reopen1a_lease(struct torture_context *tctx, >+ struct smb2_tree *tree) >+{ >+ NTSTATUS status; >+ TALLOC_CTX *mem_ctx = talloc_new(tctx); >+ char fname[256]; >+ struct smb2_handle _h; >+ struct smb2_handle *h = NULL; >+ struct smb2_create io; >+ struct GUID create_guid = GUID_random(); >+ struct smb2_lease ls; >+ uint64_t lease_key; >+ bool ret = true; >+ struct smb2_tree *tree2 = NULL; >+ struct smb2_tree *tree3 = NULL; >+ uint64_t previous_session_id; >+ struct smbcli_options options; >+ struct GUID orig_client_guid; >+ >+ options = tree->session->transport->options; >+ orig_client_guid = options.client_guid; >+ >+ /* Choose a random name in case the state is left a little funky. */ >+ snprintf(fname, 256, "durable_v2_open_reopen1a_lease_%s.dat", >+ generate_random_str(tctx, 8)); >+ >+ smb2_util_unlink(tree, fname); >+ >+ lease_key = random(); >+ smb2_lease_create(&io, &ls, false /* dir */, fname, >+ lease_key, smb2_util_lease_state("RWH")); >+ 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); >+ CHECK_VAL(io.out.durable_open_v2, true); >+ CHECK_VAL(io.out.persistent_open, false); >+ CHECK_VAL(io.out.timeout, io.in.timeout); >+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); >+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key); >+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key); >+ CHECK_VAL(io.out.lease_response.lease_state, >+ smb2_util_lease_state("RWH")); >+ CHECK_VAL(io.out.lease_response.lease_flags, 0); >+ CHECK_VAL(io.out.lease_response.lease_duration, 0); >+ >+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli); >+ >+ /* >+ * a session reconnect on a second tcp connection >+ * with a different client_guid does not allow >+ * the durable reconnect. >+ */ >+ >+ options.client_guid = GUID_random(); >+ >+ ret = torture_smb2_connection_ext(tctx, previous_session_id, >+ &options, &tree2); >+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect"); >+ >+ /* >+ * check that this has deleted the old session >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle_v2 = h; >+ io.in.create_guid = create_guid; >+ io.in.lease_request = &ls; >+ status = smb2_create(tree, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); >+ TALLOC_FREE(tree); >+ >+ /* >+ * but a durable reconnect on the new session with the wrong >+ * client guid fails >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle_v2 = h; >+ io.in.create_guid = create_guid; >+ io.in.lease_request = &ls; >+ status = smb2_create(tree2, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); >+ >+ >+ /* >+ * now a session reconnect on a second tcp connection >+ * with original client_guid allows the durable reconnect. >+ */ >+ >+ options.client_guid = orig_client_guid; >+ //options.client_guid = GUID_random(); >+ >+ ret = torture_smb2_connection_ext(tctx, previous_session_id, >+ &options, &tree3); >+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect"); >+ >+ /* >+ * check that this has deleted the old session >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle_v2 = h; >+ io.in.create_guid = create_guid; >+ io.in.lease_request = &ls; >+ status = smb2_create(tree2, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); >+ TALLOC_FREE(tree2); >+ >+ /* >+ * but a durable reconnect on the new session succeeds: >+ */ >+ >+ ZERO_STRUCT(io); >+ io.in.fname = fname; >+ io.in.durable_handle_v2 = h; >+ io.in.create_guid = create_guid; >+ io.in.lease_request = &ls; >+ status = smb2_create(tree3, mem_ctx, &io); >+ CHECK_STATUS(status, NT_STATUS_OK); >+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE); >+ CHECK_VAL(io.out.durable_open, false); >+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */ >+ CHECK_VAL(io.out.persistent_open, false); >+ CHECK_VAL(io.out.timeout, io.in.timeout); >+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); >+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key); >+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key); >+ CHECK_VAL(io.out.lease_response.lease_state, >+ smb2_util_lease_state("RWH")); >+ CHECK_VAL(io.out.lease_response.lease_flags, 0); >+ CHECK_VAL(io.out.lease_response.lease_duration, 0); >+ _h = io.out.file.handle; >+ h = &_h; >+ >+done: >+ if (tree == NULL) { >+ tree = tree2; >+ } >+ >+ if (tree == NULL) { >+ tree = tree3; >+ } >+ >+ if (tree != NULL) { >+ if (h != NULL) { >+ smb2_util_close(tree, *h); >+ } >+ >+ smb2_util_unlink(tree, fname); >+ >+ talloc_free(tree); >+ } >+ >+ talloc_free(mem_ctx); >+ >+ return ret; >+} >+ >+/** > * basic test for doing a durable open > * tcp disconnect, reconnect, do a durable reopen (succeeds) > */ >@@ -1832,6 +2014,7 @@ struct torture_suite *torture_smb2_durable_v2_open_init(void) > torture_suite_add_1smb2_test(suite, "open-lease", test_durable_v2_open_lease); > torture_suite_add_1smb2_test(suite, "reopen1", test_durable_v2_open_reopen1); > torture_suite_add_1smb2_test(suite, "reopen1a", test_durable_v2_open_reopen1a); >+ torture_suite_add_1smb2_test(suite, "reopen1a-lease", test_durable_v2_open_reopen1a_lease); > torture_suite_add_1smb2_test(suite, "reopen2", test_durable_v2_open_reopen2); > torture_suite_add_1smb2_test(suite, "reopen2b", test_durable_v2_open_reopen2b); > torture_suite_add_1smb2_test(suite, "reopen2c", test_durable_v2_open_reopen2c); >-- >2.5.5 > >From fb381d885b0367c0b6f163ce1661b4cc4ae5f5ed Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Tue, 22 Mar 2016 16:03:58 +0100 >Subject: [PATCH] torture: Fix the O3 developer build > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >Autobuild-User(master): Jeremy Allison <jra@samba.org> >Autobuild-Date(master): Tue Mar 22 22:48:52 CET 2016 on sn-devel-144 >--- > 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 91bb568..26b5583 100644 >--- a/source4/torture/smb2/replay.c >+++ b/source4/torture/smb2/replay.c >@@ -1497,7 +1497,7 @@ static bool test_channel_sequence_table(struct torture_context *tctx, > bool do_replay, > uint16_t opcode) > { >- NTSTATUS status; >+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL; > TALLOC_CTX *mem_ctx = talloc_new(tctx); > struct smb2_handle handle; > struct smb2_handle *phandle = NULL; >-- >2.5.5 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 11809
:
11935
|
12082