summaryrefslogtreecommitdiff
path: root/source4/torture/smb2
diff options
context:
space:
mode:
authorGünther Deschner <gd@samba.org>2016-02-25 11:15:06 +0100
committerJeremy Allison <jra@samba.org>2016-03-22 00:23:21 +0100
commit2b799880b91f2ee44531644c62916f9a50531d04 (patch)
tree8f3ad644a5dbf4684de0666c1029a21773cbac24 /source4/torture/smb2
parentccda60ed9b33bb22ec2e162401a949aeaa631c8d (diff)
downloadsamba-2b799880b91f2ee44531644c62916f9a50531d04.tar.gz
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>
Diffstat (limited to 'source4/torture/smb2')
-rw-r--r--source4/torture/smb2/replay.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c
index c32533b1d69..8388837dde4 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);