diff options
author | Stefan Metzmacher <metze@samba.org> | 2020-06-22 17:30:28 +0200 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2020-07-08 15:54:39 +0000 |
commit | 3d7f81979c2db790930b369671e8346f0bb25331 (patch) | |
tree | 7e9ca88b3b5f5b7de16312b6e0978f45a0a557db /source4 | |
parent | 68a351b7620a87fc8191666e49058cbfdee62e67 (diff) | |
download | samba-3d7f81979c2db790930b369671e8346f0bb25331.tar.gz |
s4:torture/smb2: move smb2_transport blocking to the generic block.[ch]
We may want to use this in other places too, not only multichannel.c
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11897
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Günther Deschner <gd@samba.org>
Diffstat (limited to 'source4')
-rw-r--r-- | source4/torture/smb2/block.c | 214 | ||||
-rw-r--r-- | source4/torture/smb2/block.h | 11 | ||||
-rw-r--r-- | source4/torture/smb2/multichannel.c | 236 |
3 files changed, 236 insertions, 225 deletions
diff --git a/source4/torture/smb2/block.c b/source4/torture/smb2/block.c index d0cb934adf9..b9982b0574d 100644 --- a/source4/torture/smb2/block.c +++ b/source4/torture/smb2/block.c @@ -27,6 +27,9 @@ #include "lib/util/util_net.h" #include "torture/smb2/block.h" #include "libcli/smb/smbXcli_base.h" +#include "lib/util/tevent_ntstatus.h" +#include "oplock_break_handler.h" +#include "lease_break_handler.h" /* * OUTPUT @@ -230,3 +233,214 @@ bool torture_unblock_tcp_output_cleanup(struct torture_context *tctx) { return iptables_setup_chain(tctx, "OUTPUT", "SMBTORTURE_OUTPUT", true); } + +/* + * Use iptables to block channels + */ +static bool test_block_smb2_transport_iptables(struct torture_context *tctx, + struct smb2_transport *transport, + const char *name) +{ + uint16_t local_port; + bool ret; + + local_port = torture_get_local_port_from_transport(transport); + torture_comment(tctx, "transport[%s] uses tcp port: %d\n", name, local_port); + ret = torture_block_tcp_output_port(tctx, name, local_port); + torture_assert(tctx, ret, "we could not block tcp transport"); + + return ret; +} + +static bool test_unblock_smb2_transport_iptables(struct torture_context *tctx, + struct smb2_transport *transport, + const char *name) +{ + uint16_t local_port; + bool ret; + + local_port = torture_get_local_port_from_transport(transport); + torture_comment(tctx, "transport[%s] uses tcp port: %d\n", name, local_port); + ret = torture_unblock_tcp_output_port(tctx, name, local_port); + torture_assert(tctx, ret, "we could not block tcp transport"); + + 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; +} + +bool _test_block_smb2_transport(struct torture_context *tctx, + struct smb2_transport *transport, + const char *name) +{ + bool use_iptables = torture_setting_bool(tctx, + "use_iptables", false); + + if (use_iptables) { + return test_block_smb2_transport_iptables(tctx, transport, name); + } else { + return test_block_smb2_transport_fsctl_smbtorture(tctx, transport, name); + } +} + +bool _test_unblock_smb2_transport(struct torture_context *tctx, + struct smb2_transport *transport, + const char *name) +{ + bool use_iptables = torture_setting_bool(tctx, + "use_iptables", false); + + if (use_iptables) { + return test_unblock_smb2_transport_iptables(tctx, transport, name); + } else { + return true; + } +} + +bool test_setup_blocked_transports(struct torture_context *tctx) +{ + bool use_iptables = torture_setting_bool(tctx, + "use_iptables", false); + + if (use_iptables) { + return torture_block_tcp_output_setup(tctx); + } + + return true; +} + +void test_cleanup_blocked_transports(struct torture_context *tctx) +{ + bool use_iptables = torture_setting_bool(tctx, + "use_iptables", false); + + if (use_iptables) { + torture_unblock_tcp_output_cleanup(tctx); + } +} diff --git a/source4/torture/smb2/block.h b/source4/torture/smb2/block.h index 7f36b89a693..6a6370a1ab5 100644 --- a/source4/torture/smb2/block.h +++ b/source4/torture/smb2/block.h @@ -30,3 +30,14 @@ bool torture_unblock_tcp_output_port(struct torture_context *tctx, bool torture_block_tcp_output_setup(struct torture_context *tctx); bool torture_unblock_tcp_output_cleanup(struct torture_context *tctx); +bool test_setup_blocked_transports(struct torture_context *tctx); +void test_cleanup_blocked_transports(struct torture_context *tctx); + +#define test_block_smb2_transport(_tctx, _t) _test_block_smb2_transport(_tctx, _t, #_t) +bool _test_block_smb2_transport(struct torture_context *tctx, + struct smb2_transport *transport, + const char *name); +#define test_unblock_smb2_transport(_tctx, _t) _test_unblock_smb2_transport(_tctx, _t, #_t) +bool _test_unblock_smb2_transport(struct torture_context *tctx, + struct smb2_transport *transport, + const char *name); diff --git a/source4/torture/smb2/multichannel.c b/source4/torture/smb2/multichannel.c index 3742cb8bac8..3e29c7d02a9 100644 --- a/source4/torture/smb2/multichannel.c +++ b/source4/torture/smb2/multichannel.c @@ -36,7 +36,6 @@ #include "oplock_break_handler.h" #include "lease_break_handler.h" #include "torture/smb2/block.h" -#include "lib/util/tevent_ntstatus.h" #define BASEDIR "multichanneltestdir" @@ -367,219 +366,6 @@ static void test_multichannel_init_smb_create(struct smb2_create *io) /* windows 2016 returns 300000 0x493E0 */ } -/* - * Use iptables to block channels - */ -static bool test_iptables_block_channel(struct torture_context *tctx, - struct smb2_transport *transport, - const char *name) -{ - uint16_t local_port; - bool ret; - - local_port = torture_get_local_port_from_transport(transport); - torture_comment(tctx, "transport[%s] uses tcp port: %d\n", name, local_port); - ret = torture_block_tcp_output_port(tctx, name, local_port); - torture_assert(tctx, ret, "we could not block tcp transport"); - - return ret; -} - -static bool test_iptables_unblock_channel(struct torture_context *tctx, - struct smb2_transport *transport, - const char *name) -{ - uint16_t local_port; - bool ret; - - local_port = torture_get_local_port_from_transport(transport); - torture_comment(tctx, "transport[%s] uses tcp port: %d\n", name, local_port); - ret = torture_unblock_tcp_output_port(tctx, name, local_port); - torture_assert(tctx, ret, "we could not block tcp transport"); - - 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, - const char *name) -{ - bool use_iptables = torture_setting_bool(tctx, - "use_iptables", false); - - if (use_iptables) { - return test_iptables_block_channel(tctx, transport, name); - } else { - return test_block_smb2_transport_fsctl_smbtorture(tctx, transport, name); - } -} - -#define test_unblock_channel(_tctx, _t) _test_unblock_channel(_tctx, _t, #_t) -static bool _test_unblock_channel(struct torture_context *tctx, - struct smb2_transport *transport, - const char *name) -{ - bool use_iptables = torture_setting_bool(tctx, - "use_iptables", false); - - if (use_iptables) { - return test_iptables_unblock_channel(tctx, transport, name); - } else { - return true; - } -} - -static bool test_setup_blocked_channels(struct torture_context *tctx) -{ - bool use_iptables = torture_setting_bool(tctx, - "use_iptables", false); - - if (use_iptables) { - return torture_block_tcp_output_setup(tctx); - } - - return true; -} - -static void test_cleanup_blocked_channels(struct torture_context *tctx) -{ - bool use_iptables = torture_setting_bool(tctx, - "use_iptables", false); - - if (use_iptables) { - torture_unblock_tcp_output_cleanup(tctx); - } -} - /* Timer handler function notifies the registering function that time is up */ static void timeout_cb(struct tevent_context *ev, struct tevent_timer *te, @@ -899,11 +685,11 @@ static bool test_multichannel_oplock_break_test2(struct torture_context *tctx, transport2 = break_info.received_transport; torture_reset_break_info(tctx, &break_info); - block_setup = test_setup_blocked_channels(tctx); - torture_assert(tctx, block_setup, "test_setup_blocked_channels"); + block_setup = test_setup_blocked_transports(tctx); + torture_assert(tctx, block_setup, "test_setup_blocked_transports"); /* block channel */ - block_ok = test_block_channel(tctx, transport2); + block_ok = test_block_smb2_transport(tctx, transport2); torture_comment(tctx, "client1 opens fname2 via session 1\n"); io2.in.oplock_level = smb2_util_oplock_level("b"); @@ -987,9 +773,9 @@ static bool test_multichannel_oplock_break_test2(struct torture_context *tctx, done: if (block_ok && !unblock_ok) { - test_unblock_channel(tctx, transport2); + test_unblock_smb2_transport(tctx, transport2); } - test_cleanup_blocked_channels(tctx); + test_cleanup_blocked_transports(tctx); tree1->session = session1; @@ -1355,12 +1141,12 @@ static bool test_multichannel_lease_break_test2(struct torture_context *tctx, CHECK_VAL(io2.out.durable_open, false); CHECK_VAL(lease_break_info.count, 0); - block_setup = test_setup_blocked_channels(tctx); - torture_assert(tctx, block_setup, "test_setup_blocked_channels"); + block_setup = test_setup_blocked_transports(tctx); + torture_assert(tctx, block_setup, "test_setup_blocked_transports"); torture_comment(tctx, "Blocking 2A\n"); /* Block 2A */ - block_ok = test_block_channel(tctx, transport2A); + block_ok = test_block_smb2_transport(tctx, transport2A); torture_assert(tctx, block_ok, "we could not block tcp transport"); /* 1 opens file2 */ @@ -1414,7 +1200,7 @@ static bool test_multichannel_lease_break_test2(struct torture_context *tctx, /* Unblock 2A */ torture_comment(tctx, "Unblocking 2A\n"); - unblock_ok = test_unblock_channel(tctx, transport2A); + unblock_ok = test_unblock_smb2_transport(tctx, transport2A); torture_assert(tctx, unblock_ok, "we could not unblock tcp transport"); /* 1 opens file1 */ @@ -1508,10 +1294,10 @@ static bool test_multichannel_lease_break_test2(struct torture_context *tctx, done: if (block_ok && !unblock_ok) { - test_unblock_channel(tctx, transport2A); + test_unblock_smb2_transport(tctx, transport2A); } if (block_setup) { - test_cleanup_blocked_channels(tctx); + test_cleanup_blocked_transports(tctx); } tree1->session = session1; |