From: Stefan Metzmacher Date: Mon, 8 Jun 2020 14:33:45 +0000 (+0200) Subject: s4:torture/smb2: make use of FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT X-Git-Tag: samba-4.13.0rc1~37 X-Git-Url: http://git.samba.org/?a=commitdiff_plain;h=68a351b7620a87fc8191666e49058cbfdee62e67;p=samba.git s4:torture/smb2: make use of FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT This is a way to test without being able to use iptables. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11897 Signed-off-by: Stefan Metzmacher Reviewed-by: Günther Deschner --- diff --git a/source4/torture/smb2/multichannel.c b/source4/torture/smb2/multichannel.c index 7cf39dadbe3..3742cb8bac8 100644 --- a/source4/torture/smb2/multichannel.c +++ b/source4/torture/smb2/multichannel.c @@ -36,6 +36,7 @@ #include "oplock_break_handler.h" #include "lease_break_handler.h" #include "torture/smb2/block.h" +#include "lib/util/tevent_ntstatus.h" #define BASEDIR "multichanneltestdir" @@ -366,28 +367,6 @@ static void test_multichannel_init_smb_create(struct smb2_create *io) /* windows 2016 returns 300000 0x493E0 */ } -/* - * We simulate blocking incoming oplock break requests by simply ignoring - * the incoming break requests. - */ -static bool test_set_ignore_break_handler(struct torture_context *tctx, - struct smb2_transport *transport) -{ - transport->oplock.handler = torture_oplock_ignore_handler; - transport->lease.handler = torture_lease_ignore_handler; - - return true; -} - -static bool test_reset_break_handler(struct torture_context *tctx, - struct smb2_transport *transport) -{ - transport->oplock.handler = torture_oplock_ack_handler; - transport->lease.handler = torture_lease_handler; - - return true; -} - /* * Use iptables to block channels */ @@ -421,6 +400,134 @@ static bool test_iptables_unblock_channel(struct torture_context *tctx, return ret; } +static bool torture_blocked_lease_handler(struct smb2_transport *transport, + const struct smb2_lease_break *lb, + void *private_data) +{ + struct smb2_transport *transport_copy = + talloc_get_type_abort(private_data, + struct smb2_transport); + bool lease_skip_ack = lease_break_info.lease_skip_ack; + bool ok; + + lease_break_info.lease_skip_ack = true; + ok = transport_copy->lease.handler(transport, + lb, + transport_copy->lease.private_data); + lease_break_info.lease_skip_ack = lease_skip_ack; + + if (!ok) { + return false; + } + + if (lease_break_info.lease_skip_ack) { + return true; + } + + if (lb->break_flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) { + lease_break_info.failures++; + } + + return true; +} + +static bool torture_blocked_oplock_handler(struct smb2_transport *transport, + const struct smb2_handle *handle, + uint8_t level, + void *private_data) +{ + struct smb2_transport *transport_copy = + talloc_get_type_abort(private_data, + struct smb2_transport); + bool oplock_skip_ack = break_info.oplock_skip_ack; + bool ok; + + break_info.oplock_skip_ack = true; + ok = transport_copy->oplock.handler(transport, + handle, + level, + transport_copy->oplock.private_data); + break_info.oplock_skip_ack = oplock_skip_ack; + + if (!ok) { + return false; + } + + if (break_info.oplock_skip_ack) { + return true; + } + + break_info.failures++; + break_info.failure_status = NT_STATUS_CONNECTION_DISCONNECTED; + + return true; +} + +static bool test_block_smb2_transport_fsctl_smbtorture(struct torture_context *tctx, + struct smb2_transport *transport, + const char *name) +{ + struct smb2_transport *transport_copy = NULL; + DATA_BLOB in_input_buffer = data_blob_null; + DATA_BLOB in_output_buffer = data_blob_null; + DATA_BLOB out_input_buffer = data_blob_null; + DATA_BLOB out_output_buffer = data_blob_null; + struct tevent_req *req = NULL; + uint16_t local_port; + NTSTATUS status; + bool ok; + + transport_copy = talloc_zero(transport, struct smb2_transport); + torture_assert(tctx, transport_copy, "talloc transport_copy"); + transport_copy->lease = transport->lease; + transport_copy->oplock = transport->oplock; + + local_port = torture_get_local_port_from_transport(transport); + torture_comment(tctx, "transport[%s] uses tcp port: %d\n", name, local_port); + req = smb2cli_ioctl_send(tctx, + tctx->ev, + transport->conn, + 1000, /* timeout_msec */ + NULL, /* session */ + NULL, /* tcon */ + UINT64_MAX, /* in_fid_persistent */ + UINT64_MAX, /* in_fid_volatile */ + FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT, + 0, /* in_max_input_length */ + &in_input_buffer, + 0, /* in_max_output_length */ + &in_output_buffer, + SMB2_IOCTL_FLAG_IS_FSCTL); + torture_assert(tctx, req != NULL, "smb2cli_ioctl_send() failed"); + ok = tevent_req_poll_ntstatus(req, tctx->ev, &status); + if (ok) { + status = NT_STATUS_OK; + } + torture_assert_ntstatus_ok(tctx, status, "tevent_req_poll_ntstatus() failed"); + status = smb2cli_ioctl_recv(req, tctx, + &out_input_buffer, + &out_output_buffer); + torture_assert_ntstatus_ok(tctx, status, + "FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT failed\n\n" + "On a Samba server 'smbd:FSCTL_SMBTORTURE = yes' is needed!\n\n" + "Otherwise you may need to use iptables like this:\n" + "--option='torture:use_iptables=yes'\n" + "And maybe something like this in addition:\n" + "--option='torture:iptables_command=sudo /sbin/iptables'\n\n"); + TALLOC_FREE(req); + + if (transport->lease.handler != NULL) { + transport->lease.handler = torture_blocked_lease_handler; + transport->lease.private_data = transport_copy; + } + if (transport->oplock.handler != NULL) { + transport->oplock.handler = torture_blocked_oplock_handler; + transport->oplock.private_data = transport_copy; + } + + return true; +} + #define test_block_channel(_tctx, _t) _test_block_channel(_tctx, _t, #_t) static bool _test_block_channel(struct torture_context *tctx, struct smb2_transport *transport, @@ -432,7 +539,7 @@ static bool _test_block_channel(struct torture_context *tctx, if (use_iptables) { return test_iptables_block_channel(tctx, transport, name); } else { - return test_set_ignore_break_handler(tctx, transport); + return test_block_smb2_transport_fsctl_smbtorture(tctx, transport, name); } } @@ -447,7 +554,7 @@ static bool _test_unblock_channel(struct torture_context *tctx, if (use_iptables) { return test_iptables_unblock_channel(tctx, transport, name); } else { - return test_reset_break_handler(tctx, transport); + return true; } }