2 Unix SMB/CIFS implementation.
4 test SMB2 multichannel operations
6 Copyright (C) Guenther Deschner, 2016
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28 #include "libcli/security/security.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "librpc/gen_ndr/ndr_ioctl.h"
31 #include "../libcli/smb/smbXcli_base.h"
32 #include "lib/cmdline/popt_common.h"
33 #include "auth/credentials/credentials.h"
34 #include "libcli/security/security.h"
35 #include "libcli/resolve/resolve.h"
36 #include "lib/param/param.h"
37 #include "lib/events/events.h"
38 #include "oplock_break_handler.h"
39 #include "system/network.h"
40 #include "lib/util/util_net.h"
41 #include "torture/smb2/block.h"
42 #include "lease_break_handler.h"
44 #define BASEDIR "multichanneltestdir"
46 extern struct break_info break_info;
47 extern struct lease_break_info lease_break_info;
49 #define CHECK_STATUS(status, correct) \
50 torture_assert_ntstatus_equal_goto(tctx, status, correct, ret, done, "");
52 #define CHECK_VAL(v, correct) do { \
53 if ((v) != (correct)) { \
54 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
55 __location__, #v, (int)v, (int)correct); \
60 #define CHECK_CREATED(__io, __created, __attribute) \
62 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
63 CHECK_VAL((__io)->out.alloc_size, 0); \
64 CHECK_VAL((__io)->out.size, 0); \
65 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
66 CHECK_VAL((__io)->out.reserved2, 0); \
69 #define CHECK_PTR(ptr, correct) do { \
70 if ((ptr) != (correct)) { \
71 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%p - should be 0x%p\n", \
72 __location__, #ptr, ptr, correct); \
77 #define CHECK_LEASE(__io, __state, __oplevel, __key, __flags) \
79 CHECK_VAL((__io)->out.lease_response.lease_version, 1); \
81 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
82 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], (__key)); \
83 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], ~(__key)); \
84 CHECK_VAL((__io)->out.lease_response.lease_state, smb2_util_lease_state(__state)); \
86 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
87 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], 0); \
88 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], 0); \
89 CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
92 CHECK_VAL((__io)->out.lease_response.lease_flags, (__flags)); \
93 CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
94 CHECK_VAL((__io)->out.lease_response.lease_epoch, 0); \
97 static bool retrieve_ipv4_address_from_net_interface_info(struct torture_context *tctx,
98 struct fsctl_net_iface_info *info,
101 if (info->sockaddr.family != FSCTL_NET_IFACE_AF_INET) {
105 *ipv4 = talloc_strdup(tctx, info->sockaddr.saddr.saddr_in.ipv4);
111 static bool retrieve_ipv6_address_from_net_interface_info(struct torture_context *tctx,
112 struct fsctl_net_iface_info *info,
115 if (info->sockaddr.family != FSCTL_NET_IFACE_AF_INET6) {
119 *ipv6 = talloc_strdup(tctx, info->sockaddr.saddr.saddr_in6.ipv6);
125 static bool test_ioctl_network_interface_info(struct torture_context *tctx,
126 struct smb2_tree *tree,
127 struct fsctl_net_iface_info *info)
129 union smb_ioctl ioctl;
130 struct smb2_handle fh;
133 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
134 if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
135 torture_skip(tctx, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
140 ioctl.smb2.level = RAW_IOCTL_SMB2;
142 fh.data[0] = UINT64_MAX;
143 fh.data[1] = UINT64_MAX;
145 ioctl.smb2.in.file.handle = fh;
146 ioctl.smb2.in.function = FSCTL_QUERY_NETWORK_INTERFACE_INFO;
147 ioctl.smb2.in.max_response_size = 0x10000; /* Windows client sets this to 64KiB */
148 ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
150 torture_assert_ntstatus_ok(tctx,
151 smb2_ioctl(tree, tctx, &ioctl.smb2),
152 "FSCTL_QUERY_NETWORK_INTERFACE_INFO failed");
155 (ioctl.smb2.out.out.length != 0),
156 "no interface info returned???");
158 torture_assert_ndr_success(tctx,
159 ndr_pull_struct_blob(&ioctl.smb2.out.out, tctx, info,
160 (ndr_pull_flags_fn_t)ndr_pull_fsctl_net_iface_info),
161 "failed to ndr pull");
163 /* NDR_PRINT_DEBUG(fsctl_net_iface_info, info); */
168 static bool test_session_bind_multiple_nics(struct torture_context *tctx,
169 struct smb2_tree *tree)
171 //const char *host = torture_setting_string(tctx, "host", NULL);
172 //const char *share = torture_setting_string(tctx, "share", NULL);
173 struct smb2_transport *transport1 = tree->session->transport;
174 //struct cli_credentials *credentials = popt_get_cmdline_credentials();
175 //struct smb2_tree *tree2 = NULL;
178 struct fsctl_net_iface_info info;
179 const struct sockaddr_storage *remote_ss;
180 char addr[INET6_ADDRSTRLEN];
183 caps = smb2cli_conn_server_capabilities(transport1->conn);
184 if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
185 torture_skip(tctx, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
189 test_ioctl_network_interface_info(tctx, tree, &info),
190 "failed to retrieve network interface info");
192 remote_ss = smbXcli_conn_remote_sockaddr(transport1->conn);
194 print_sockaddr(addr, sizeof(addr), remote_ss);
197 retrieve_ipv4_address_from_net_interface_info(tctx, &info, &addr2),
198 "failed to retrieve ipv4 address");
200 torture_comment(tctx, "interface 1: %s\n", addr2);
202 if (strequal(addr, addr2)) {
204 retrieve_ipv4_address_from_net_interface_info(tctx, info.next, &addr2),
205 "failed to retrieve ipv4 address");
206 torture_comment(tctx, "interface 2: %s\n", addr2);
209 if (strequal(addr, addr2)) {
210 torture_fail(tctx, talloc_asprintf(tctx, "cannot proceed as %s and %s are equal",
214 torture_comment(tctx,
215 "currently connected to %s\n", addr);
217 torture_comment(tctx,
218 "adding another interface %s\n", addr2);
220 compare transport1->conn->remote_ss (struct sockaddr_storage)
222 struct fsctl_sockaddr_storage sockaddr;
224 /* check if interface info has another interface */
226 status = smb2_connect(tctx,
228 lpcfg_smb_ports(tctx->lp_ctx),
230 lpcfg_resolve_context(tctx->lp_ctx),
234 &transport1->options,
235 lpcfg_socket_options(tctx->lp_ctx),
236 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
238 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
239 "smb2_connect failed");
248 static bool test_multichannel_interface_info(struct torture_context *tctx,
249 struct smb2_tree *tree)
251 struct fsctl_net_iface_info info;
252 return test_ioctl_network_interface_info(tctx, tree, &info);
255 static struct smb2_tree *test_multichannel_create_channel(
256 struct torture_context *tctx,
259 struct cli_credentials *credentials,
260 struct smbcli_options *transport2_options,
261 struct smb2_tree *parent_tree
265 struct smb2_transport *transport;
266 struct smb2_session *session;
268 struct smb2_tree *tree;
270 status = smb2_connect(tctx,
272 lpcfg_smb_ports(tctx->lp_ctx),
274 lpcfg_resolve_context(tctx->lp_ctx),
279 lpcfg_socket_options(tctx->lp_ctx),
280 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
282 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
283 "smb2_connect failed");
284 transport = tree->session->transport;
285 transport->oplock.handler = torture_oplock_ack_handler;
286 transport->oplock.private_data = tree;
287 transport->lease.handler = torture_lease_handler;
288 transport->lease.private_data = tree;
289 torture_comment(tctx, "established transport [%p]\n", transport);
292 * If parent tree is set, bind the session to the parent transport
295 session = smb2_session_channel(transport,
296 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
297 parent_tree, parent_tree->session);
298 torture_assert_goto(tctx, session != NULL, ret, done,
299 "smb2_session_channel failed");
301 tree->smbXcli = parent_tree->smbXcli;
302 tree->session = session;
303 status = smb2_session_setup_spnego(session,
305 0 /* previous_session_id */);
306 CHECK_STATUS(status, NT_STATUS_OK);
307 torture_comment(tctx, "bound new session to parent\n");
310 * We absolutely need to make sure to send something over this
311 * connection to register the oplock break handler with the smb client
312 * connection. If we do not send something (at least a keepalive), we
313 * will *NEVER* receive anything over this transport.
315 smb2_keepalive(transport);
319 /* Check below placed to avoid compilation warnings */
326 static int test_multichannel_create_channels2(
327 struct torture_context *tctx,
330 struct cli_credentials *credentials,
331 struct smbcli_options *transport2_options,
332 struct smb2_tree **tree2A,
333 struct smb2_tree **tree2B,
334 struct smb2_tree **tree2C
337 struct smb2_tree *tree;
338 struct smb2_transport *transport2A;
339 struct smb2_transport *transport2B;
340 struct smb2_transport *transport2C;
341 uint16_t local_port = 0;
343 transport2_options->client_guid = GUID_random();
346 torture_comment(tctx, "Setting up connection 2A\n");
347 tree = test_multichannel_create_channel(tctx, host, share,
348 credentials, transport2_options, NULL);
353 transport2A = tree->session->transport;
354 local_port = torture_get_local_port_from_transport(transport2A);
355 torture_comment(tctx, "transport2A uses tcp port: %d\n", local_port);
359 torture_comment(tctx, "Setting up connection 2B\n");
360 tree = test_multichannel_create_channel(tctx, host, share,
361 credentials, transport2_options, *tree2A);
366 transport2B = tree->session->transport;
367 local_port = torture_get_local_port_from_transport(transport2B);
368 torture_comment(tctx, "transport2B uses tcp port: %d\n",
374 torture_comment(tctx, "Setting up connection 2C\n");
375 tree = test_multichannel_create_channel(tctx, host, share,
376 credentials, transport2_options, *tree2A);
381 transport2C = tree->session->transport;
382 local_port = torture_get_local_port_from_transport(transport2C);
383 torture_comment(tctx, "transport2C uses tcp port: %d\n",
392 static void test_multichannel_free_channels2(struct smb2_tree *tree2A,
393 struct smb2_tree *tree2B,
394 struct smb2_tree *tree2C)
401 static bool test_multichannel_initial_checks(struct torture_context *tctx,
402 struct smb2_tree *tree1)
404 struct smb2_transport *transport1 = tree1->session->transport;
405 uint32_t server_capabilities;
406 struct fsctl_net_iface_info info;
408 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
409 torture_skip_goto(tctx, fail,
410 "SMB 3.X Dialect family required for "
411 "Multichannel tests\n");
414 server_capabilities = smb2cli_conn_server_capabilities(
415 tree1->session->transport->conn);
416 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
417 torture_skip_goto(tctx, fail,
418 "Server does not support multichannel.");
421 torture_comment(tctx, "Testing Oplock Break on multiple channels\n");
424 test_ioctl_network_interface_info(tctx, tree1, &info),
425 "failed to retrieve network interface info");
432 static void test_multichannel_init_smb_create(struct smb2_create *io)
434 io->in.durable_open = false;
435 io->in.durable_open_v2 = true;
436 io->in.persistent_open = false;
437 io->in.create_guid = GUID_random();
438 io->in.timeout = 0x493E0; /* 300000 */
439 /* windows 2016 returns 300000 0x493E0 */
443 * Test Oplock Break with Multi Channel
445 static bool test_multichannel_oplock_break(struct torture_context *tctx,
446 struct smb2_tree *tree1)
448 const char *host = torture_setting_string(tctx, "host", NULL);
449 const char *share = torture_setting_string(tctx, "share", NULL);
450 struct cli_credentials *credentials = popt_get_cmdline_credentials();
452 TALLOC_CTX *mem_ctx = talloc_new(tctx);
453 struct smb2_handle _h;
454 struct smb2_handle *h = NULL;
455 struct smb2_handle h_client1_file1 = { 0 };
456 struct smb2_handle h_client1_file2 = { 0 };
457 struct smb2_handle h_client1_file3 = { 0 };
458 struct smb2_handle h_client2_file1 = { 0 };
459 struct smb2_handle h_client2_file2 = { 0 };
460 struct smb2_handle h_client2_file3 = { 0 };
461 struct smb2_create io1, io2, io3;
464 const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
465 const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
466 const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
467 struct smb2_tree *tree2A = NULL;
468 struct smb2_tree *tree2B = NULL;
469 struct smb2_tree *tree2C = NULL;
470 struct smb2_transport *transport1 = tree1->session->transport;
471 struct smb2_transport *transport2B = NULL;
472 struct smb2_transport *transport2C = NULL;
473 struct smbcli_options transport2_options;
474 struct smb2_session *session1 = tree1->session;
475 uint16_t local_port = 0;
476 bool block_ok = false;
477 bool unblock_ok = false;
480 if (!test_multichannel_initial_checks(tctx, tree1))
483 torture_reset_break_info(tctx, &break_info);
485 transport1->oplock.handler = torture_oplock_ack_handler;
486 transport1->oplock.private_data = tree1;
487 torture_comment(tctx, "transport1 [%p]\n", transport1);
488 local_port = torture_get_local_port_from_transport(transport1);
489 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
491 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
492 CHECK_STATUS(status, NT_STATUS_OK);
493 smb2_util_close(tree1, _h);
494 smb2_util_unlink(tree1, fname1);
495 smb2_util_unlink(tree1, fname2);
496 smb2_util_unlink(tree1, fname3);
497 CHECK_VAL(break_info.count, 0);
499 smb2_oplock_create_share(&io1, fname1,
500 smb2_util_share_access("RWD"),
501 smb2_util_oplock_level("b"));
502 test_multichannel_init_smb_create(&io1);
504 smb2_oplock_create_share(&io2, fname2,
505 smb2_util_share_access("RWD"),
506 smb2_util_oplock_level("b"));
507 test_multichannel_init_smb_create(&io2);
509 smb2_oplock_create_share(&io3, fname3,
510 smb2_util_share_access("RWD"),
511 smb2_util_oplock_level("b"));
512 test_multichannel_init_smb_create(&io3);
514 transport2_options = transport1->options;
515 rval = test_multichannel_create_channels2(tctx, host, share,
518 &tree2A, &tree2B, NULL);
520 transport2B = tree2B->session->transport;
522 /* now the real test starts with opening files */
524 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
528 status = smb2_create(tree2A, mem_ctx, &io1);
529 CHECK_STATUS(status, NT_STATUS_OK);
530 h_client2_file1 = io1.out.file.handle;
531 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
532 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
533 CHECK_VAL(io1.out.durable_open_v2, true);
534 CHECK_VAL(io1.out.timeout, io1.in.timeout);
535 CHECK_VAL(io1.out.durable_open, false);
536 torture_wait_for_oplock_break(tctx);
537 CHECK_VAL(break_info.count, 0);
539 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
542 status = smb2_create(tree2B, mem_ctx, &io2);
543 CHECK_STATUS(status, NT_STATUS_OK);
544 h_client2_file2 = io2.out.file.handle;
545 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
546 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
547 CHECK_VAL(io2.out.durable_open_v2, true);
548 CHECK_VAL(io2.out.timeout, io2.in.timeout);
549 CHECK_VAL(io2.out.durable_open, false);
550 torture_wait_for_oplock_break(tctx);
551 CHECK_VAL(break_info.count, 0);
559 torture_comment(tctx, "client1 opens fname1 via session 1\n");
561 io1.in.oplock_level = smb2_util_oplock_level("b");
562 status = smb2_create(tree1, mem_ctx, &io1);
563 CHECK_STATUS(status, NT_STATUS_OK);
564 h_client1_file1 = io1.out.file.handle;
565 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
566 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
567 CHECK_VAL(io1.out.durable_open_v2, false);
568 CHECK_VAL(io1.out.timeout, 0);
569 CHECK_VAL(io1.out.durable_open, false);
570 torture_wait_for_oplock_break(tctx);
571 CHECK_VAL(break_info.count, 1);
572 CHECK_PTR(break_info.received_transport, transport2B);
574 torture_reset_break_info(tctx, &break_info);
581 torture_comment(tctx, "client1 opens fname2 via session 1\n");
583 io2.in.oplock_level = smb2_util_oplock_level("b");
584 status = smb2_create(tree1, mem_ctx, &io2);
585 CHECK_STATUS(status, NT_STATUS_OK);
586 h_client1_file2 = io2.out.file.handle;
587 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
588 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
589 CHECK_VAL(io2.out.durable_open_v2, false);
590 CHECK_VAL(io2.out.timeout, 0);
591 CHECK_VAL(io2.out.durable_open, false);
592 torture_wait_for_oplock_break(tctx);
593 CHECK_VAL(break_info.count, 1);
594 CHECK_PTR(break_info.received_transport, transport2B);
596 /* cleanup everything */
597 torture_reset_break_info(tctx, &break_info);
599 smb2_util_close(tree1, h_client1_file1);
600 smb2_util_close(tree1, h_client1_file2);
601 smb2_util_close(tree1, h_client1_file3);
602 smb2_util_close(tree2A, h_client2_file1);
603 smb2_util_close(tree2A, h_client2_file2);
604 smb2_util_close(tree2A, h_client2_file3);
606 smb2_util_unlink(tree1, fname1);
607 smb2_util_unlink(tree1, fname2);
608 smb2_util_unlink(tree1, fname3);
609 CHECK_VAL(break_info.count, 0);
610 test_multichannel_free_channels2(tree2A, tree2B, tree2C);
611 tree2A = tree2B = tree2C = NULL;
613 /* now repeat the test with the third channel */
614 rval = test_multichannel_create_channels2(tctx, host, share,
617 &tree2A, &tree2B, &tree2C);
619 transport2B = tree2B->session->transport;
620 transport2C = tree2C->session->transport;
622 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
623 io1.in.oplock_level = smb2_util_oplock_level("b");
624 status = smb2_create(tree2A, mem_ctx, &io1);
625 CHECK_STATUS(status, NT_STATUS_OK);
626 h_client2_file1 = io1.out.file.handle;
627 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
628 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
629 CHECK_VAL(io1.out.durable_open_v2, true);
630 CHECK_VAL(io1.out.timeout, io1.in.timeout);
631 CHECK_VAL(io1.out.durable_open, false);
632 torture_wait_for_oplock_break(tctx);
633 CHECK_VAL(break_info.count, 0);
636 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
639 io2.in.oplock_level = smb2_util_oplock_level("b");
640 status = smb2_create(tree2B, mem_ctx, &io2);
641 CHECK_STATUS(status, NT_STATUS_OK);
642 h_client2_file2 = io2.out.file.handle;
643 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
644 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
645 CHECK_VAL(io2.out.durable_open_v2, true);
646 CHECK_VAL(io2.out.timeout, io2.in.timeout);
647 CHECK_VAL(io2.out.durable_open, false);
648 torture_wait_for_oplock_break(tctx);
649 CHECK_VAL(break_info.count, 0);
657 torture_comment(tctx, "client1 opens fname1 via session 1\n");
659 io1.in.oplock_level = smb2_util_oplock_level("b");
660 status = smb2_create(tree1, mem_ctx, &io1);
661 CHECK_STATUS(status, NT_STATUS_OK);
662 h_client1_file1 = io1.out.file.handle;
663 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
664 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
665 CHECK_VAL(io1.out.durable_open_v2, false);
666 CHECK_VAL(io1.out.timeout, 0);
667 CHECK_VAL(io1.out.durable_open, false);
668 torture_wait_for_oplock_break(tctx);
669 CHECK_VAL(break_info.count, 1);
670 CHECK_PTR(break_info.received_transport, transport2C);
672 torture_reset_break_info(tctx, &break_info);
674 /* block tcp connection of transport2C */
675 block_ok = torture_block_tcp_transport(tctx, transport2C);
676 torture_assert(tctx, block_ok, "we could not block tcp transport");
683 torture_comment(tctx, "client1 opens fname2 via session 1\n");
685 io2.in.oplock_level = smb2_util_oplock_level("b");
686 status = smb2_create(tree1, mem_ctx, &io2);
687 CHECK_STATUS(status, NT_STATUS_OK);
688 h_client1_file2 = io2.out.file.handle;
689 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
690 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
691 CHECK_VAL(io2.out.durable_open_v2, false);
692 CHECK_VAL(io2.out.timeout, 0);
693 CHECK_VAL(io2.out.durable_open, false);
696 * Important: when filtered, Windows will really let the open succeed
697 * and *NOT* send a new oplock break over the remaining channels, thus
698 * the break info count stays at one.
701 torture_wait_for_oplock_break(tctx);
702 CHECK_VAL(break_info.count, 0);
704 torture_reset_break_info(tctx, &break_info);
706 blob = data_blob_string_const("Here I am");
708 torture_comment(tctx, "Trying write to file2 on tree2B\n");
710 status = smb2_util_write(tree2B,
715 torture_assert_ntstatus_ok(tctx, status,
716 "failed to write file2 via channel 2B");
718 smb2_util_close(tree1, h_client1_file2);
720 torture_comment(tctx, "client1 opens fname2 via session 1 again\n");
722 io2.in.oplock_level = smb2_util_oplock_level("b");
723 status = smb2_create(tree1, mem_ctx, &io2);
724 CHECK_STATUS(status, NT_STATUS_OK);
725 h_client1_file2 = io2.out.file.handle;
726 io2.out.alloc_size = 0;
728 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
729 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
730 CHECK_VAL(io2.out.durable_open_v2, false);
731 CHECK_VAL(io2.out.timeout, 0);
732 CHECK_VAL(io2.out.durable_open, false);
733 torture_wait_for_oplock_break(tctx);
734 CHECK_VAL(break_info.count, 1);
735 CHECK_PTR(break_info.received_transport, transport1);
737 unblock_ok = torture_unblock_tcp_transport(tctx, transport2C);
738 torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
740 /* next test: disconnect 2C and trigger break */
742 torture_reset_break_info(tctx, &break_info);
745 * now add a third channel and repeat the test, we need to reestablish
746 * transport2C because the remote end has invalidated our connection
748 torture_comment(tctx, "Reconnecting session 2C\n");
750 tree2C = test_multichannel_create_channel(tctx, host, share,
751 credentials, &transport2_options, tree2A);
754 transport2C = tree2C->session->transport;
756 torture_comment(tctx, "client 2 opening fname3 over newly established transport2C\n");
758 status = smb2_create(tree2C, mem_ctx, &io3);
759 CHECK_STATUS(status, NT_STATUS_OK);
760 h_client2_file3 = io3.out.file.handle;
761 CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
762 CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("b"));
763 CHECK_VAL(io3.out.durable_open_v2, true);
764 CHECK_VAL(io3.out.timeout, io3.in.timeout);
765 CHECK_VAL(io3.out.durable_open, false);
766 torture_wait_for_oplock_break(tctx);
767 CHECK_VAL(break_info.count, 0);
769 torture_comment(tctx, "explicit disconnect of transport2C\n");
770 smbXcli_conn_disconnect(transport2C->conn, NT_STATUS_FOOBAR);
772 torture_comment(tctx, "client1 opens fname3 via session 1\n");
774 status = smb2_create(tree1, mem_ctx, &io3);
775 CHECK_STATUS(status, NT_STATUS_OK);
776 h_client1_file3 = io3.out.file.handle;
777 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
778 CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
779 CHECK_VAL(io3.out.durable_open_v2, false);
780 CHECK_VAL(io3.out.timeout, 0);
781 CHECK_VAL(io3.out.durable_open, false);
782 torture_wait_for_oplock_break(tctx);
783 CHECK_VAL(break_info.count, 1);
784 CHECK_PTR(break_info.received_transport, transport2B);
787 smb2_util_close(tree1, *h);
792 if (block_ok && !unblock_ok) {
793 /* unblock tcp connection of transport2C */
794 unblock_ok = torture_unblock_tcp_transport(tctx, transport2C);
797 tree1->session = session1;
799 smb2_util_close(tree1, h_client1_file1);
800 smb2_util_close(tree1, h_client1_file2);
801 smb2_util_close(tree1, h_client1_file3);
802 if (tree2A != NULL) {
803 smb2_util_close(tree2A, h_client2_file1);
804 smb2_util_close(tree2A, h_client2_file2);
805 smb2_util_close(tree2A, h_client2_file3);
809 smb2_util_close(tree1, *h);
812 smb2_util_unlink(tree1, fname1);
813 smb2_util_unlink(tree1, fname2);
814 smb2_util_unlink(tree1, fname3);
815 smb2_deltree(tree1, BASEDIR);
817 test_multichannel_free_channels2(tree2A, tree2B, tree2C);
819 talloc_free(mem_ctx);
824 static const uint64_t LEASE1F1 = 0xBADC0FFEE0DDF00Dull;
825 static const uint64_t LEASE1F2 = 0xBADC0FFEE0DDD00Dull;
826 static const uint64_t LEASE1F3 = 0xDADC0FFEE0DDD00Dull;
827 static const uint64_t LEASE2F1 = 0xDEADBEEFFEEDBEADull;
828 static const uint64_t LEASE2F2 = 0xDAD0FFEDD00DF00Dull;
829 static const uint64_t LEASE2F3 = 0xBAD0FFEDD00DF00Dull;
833 * open file1 in session 2A
834 * open file2 in session 2B
835 * open file3 in session 2C
836 * open file1 in session 1
837 * lease break sent to 2A
838 * open file2 in session 1
839 * lease break sent to 2A
840 * open file3 in session 1
841 * lease break sent to 2A
843 static bool test_multichannel_lease_break_test1(struct torture_context *tctx,
844 struct smb2_tree *tree1)
846 const char *host = torture_setting_string(tctx, "host", NULL);
847 const char *share = torture_setting_string(tctx, "share", NULL);
848 struct cli_credentials *credentials = popt_get_cmdline_credentials();
850 TALLOC_CTX *mem_ctx = talloc_new(tctx);
851 struct smb2_handle _h;
852 struct smb2_handle *h = NULL;
853 struct smb2_handle h_client1_file1 = { 0 };
854 struct smb2_handle h_client1_file2 = { 0 };
855 struct smb2_handle h_client1_file3 = { 0 };
856 struct smb2_handle h_client2_file1 = { 0 };
857 struct smb2_handle h_client2_file2 = { 0 };
858 struct smb2_handle h_client2_file3 = { 0 };
859 struct smb2_create io1, io2, io3;
862 const char *fname1 = BASEDIR "\\lease_break_test1.dat";
863 const char *fname2 = BASEDIR "\\lease_break_test2.dat";
864 const char *fname3 = BASEDIR "\\lease_break_test3.dat";
865 struct smb2_tree *tree2A = NULL;
866 struct smb2_tree *tree2B = NULL;
867 struct smb2_tree *tree2C = NULL;
868 struct smb2_transport *transport1 = tree1->session->transport;
869 struct smb2_transport *transport2A = NULL;
870 struct smb2_transport *transport2B = NULL;
871 struct smb2_transport *transport2C = NULL;
872 struct smbcli_options transport2_options;
873 struct smb2_session *session1 = tree1->session;
874 uint16_t local_port = 0;
875 bool block_ok = false;
876 bool unblock_ok = false;
877 struct smb2_lease ls1;
878 struct smb2_lease ls2;
879 struct smb2_lease ls3;
881 if (!test_multichannel_initial_checks(tctx, tree1))
884 torture_reset_lease_break_info(tctx, &lease_break_info);
886 transport1->lease.handler = torture_lease_handler;
887 transport1->lease.private_data = tree1;
888 torture_comment(tctx, "transport1 [%p]\n", transport1);
889 local_port = torture_get_local_port_from_transport(transport1);
890 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
892 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
893 CHECK_STATUS(status, NT_STATUS_OK);
894 smb2_util_close(tree1, _h);
895 smb2_util_unlink(tree1, fname1);
896 smb2_util_unlink(tree1, fname2);
897 smb2_util_unlink(tree1, fname3);
898 CHECK_VAL(lease_break_info.count, 0);
900 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
901 smb2_util_lease_state("RHW"));
902 test_multichannel_init_smb_create(&io1);
904 smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
905 smb2_util_lease_state("RHW"));
906 test_multichannel_init_smb_create(&io2);
908 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
909 smb2_util_lease_state("RHW"));
910 test_multichannel_init_smb_create(&io3);
912 transport2_options = transport1->options;
914 torture_comment(tctx, "Test 1 start \n");
916 rval = test_multichannel_create_channels2(tctx, host, share,
919 &tree2A, &tree2B, &tree2C);
921 transport2A = tree2A->session->transport;
922 transport2B = tree2B->session->transport;
923 transport2C = tree2C->session->transport;
927 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
928 status = smb2_create(tree2A, mem_ctx, &io1);
929 CHECK_STATUS(status, NT_STATUS_OK);
930 h_client2_file1 = io1.out.file.handle;
931 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
932 CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
933 CHECK_VAL(io1.out.durable_open_v2, true);
934 CHECK_VAL(io1.out.timeout, io1.in.timeout);
935 CHECK_VAL(io1.out.durable_open, false);
936 CHECK_VAL(lease_break_info.count, 0);
939 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
940 status = smb2_create(tree2B, mem_ctx, &io2);
941 CHECK_STATUS(status, NT_STATUS_OK);
942 h_client2_file2 = io2.out.file.handle;
943 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
944 CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
945 CHECK_VAL(io2.out.durable_open_v2, true);
946 CHECK_VAL(io2.out.timeout, io2.in.timeout);
947 CHECK_VAL(io2.out.durable_open, false);
948 CHECK_VAL(lease_break_info.count, 0);
951 torture_comment(tctx, "client2 opens fname3 via session 2C\n");
952 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
953 smb2_util_lease_state("RHW"));
954 status = smb2_create(tree2C, mem_ctx, &io3);
955 CHECK_STATUS(status, NT_STATUS_OK);
956 h_client2_file3 = io3.out.file.handle;
957 CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
958 CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
959 CHECK_VAL(io3.out.durable_open_v2, false);
960 CHECK_VAL(io3.out.timeout, io3.in.timeout);
961 CHECK_VAL(io3.out.durable_open, false);
962 CHECK_VAL(lease_break_info.count, 0);
969 torture_comment(tctx, "client1 opens fname1 via session 1\n");
970 smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
971 smb2_util_lease_state("RHW"));
972 status = smb2_create(tree1, mem_ctx, &io1);
973 CHECK_STATUS(status, NT_STATUS_OK);
974 h_client1_file1 = io1.out.file.handle;
975 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
976 CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
977 CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
978 CHECK_VAL(io1.out.durable_open_v2, false);
979 CHECK_VAL(io1.out.timeout, 0);
980 CHECK_VAL(io1.out.durable_open, false);
981 CHECK_VAL(lease_break_info.count, 1);
982 CHECK_PTR(lease_break_info.lease_transport, transport2A);
984 torture_reset_lease_break_info(tctx, &lease_break_info);
991 torture_comment(tctx, "client1 opens fname2 via session 1\n");
992 smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
993 smb2_util_lease_state("RHW"));
994 status = smb2_create(tree1, mem_ctx, &io2);
995 CHECK_STATUS(status, NT_STATUS_OK);
996 h_client1_file2 = io2.out.file.handle;
997 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
998 CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
999 CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
1000 CHECK_VAL(io2.out.durable_open_v2, false);
1001 CHECK_VAL(io2.out.timeout, 0);
1002 CHECK_VAL(io2.out.durable_open, false);
1003 CHECK_VAL(lease_break_info.count, 1);
1004 CHECK_PTR(lease_break_info.lease_transport, transport2A);
1006 torture_reset_lease_break_info(tctx, &lease_break_info);
1013 torture_comment(tctx, "client1 opens fname3 via session 1\n");
1014 smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
1015 smb2_util_lease_state("RHW"));
1016 status = smb2_create(tree1, mem_ctx, &io3);
1017 CHECK_STATUS(status, NT_STATUS_OK);
1018 h_client1_file3 = io3.out.file.handle;
1019 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1020 CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
1021 CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
1022 CHECK_VAL(io3.out.durable_open_v2, false);
1023 CHECK_VAL(io3.out.timeout, 0);
1024 CHECK_VAL(io3.out.durable_open, false);
1025 CHECK_VAL(lease_break_info.count, 1);
1026 CHECK_PTR(lease_break_info.lease_transport, transport2A);
1029 /* cleanup everything */
1030 torture_reset_lease_break_info(tctx, &lease_break_info);
1032 smb2_util_close(tree1, h_client1_file1);
1033 smb2_util_close(tree1, h_client1_file2);
1034 smb2_util_close(tree1, h_client1_file3);
1035 smb2_util_close(tree2A, h_client2_file1);
1036 smb2_util_close(tree2A, h_client2_file2);
1037 smb2_util_close(tree2A, h_client2_file3);
1039 smb2_util_unlink(tree1, fname1);
1040 smb2_util_unlink(tree1, fname2);
1041 smb2_util_unlink(tree1, fname3);
1042 CHECK_VAL(lease_break_info.count, 0);
1043 test_multichannel_free_channels2(tree2A, tree2B, tree2C);
1044 tree2A = tree2B = tree2C = NULL;
1046 if (block_ok && !unblock_ok) {
1047 /* unblock tcp connection of transport2C */
1048 unblock_ok = torture_unblock_tcp_transport(tctx, transport2C);
1049 unblock_ok = torture_unblock_tcp_transport(tctx, transport2A);
1050 unblock_ok = torture_unblock_tcp_transport(tctx, transport2B);
1053 tree1->session = session1;
1055 smb2_util_close(tree1, h_client1_file1);
1056 smb2_util_close(tree1, h_client1_file2);
1057 smb2_util_close(tree1, h_client1_file3);
1058 if (tree2A != NULL) {
1059 smb2_util_close(tree2A, h_client2_file1);
1060 smb2_util_close(tree2A, h_client2_file2);
1061 smb2_util_close(tree2A, h_client2_file3);
1065 smb2_util_close(tree1, *h);
1068 smb2_util_unlink(tree1, fname1);
1069 smb2_util_unlink(tree1, fname2);
1070 smb2_util_unlink(tree1, fname3);
1071 smb2_deltree(tree1, BASEDIR);
1073 test_multichannel_free_channels2(tree2A, tree2B, tree2C);
1075 talloc_free(mem_ctx);
1080 static bool test_multichannel_lease_break(struct torture_context *tctx,
1081 struct smb2_tree *tree1)
1084 const char *host = torture_setting_string(tctx, "host", NULL);
1085 const char *share = torture_setting_string(tctx, "share", NULL);
1086 struct cli_credentials *credentials = popt_get_cmdline_credentials();
1088 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1089 struct smb2_handle _h;
1090 struct smb2_handle *h = NULL;
1091 struct smb2_handle h_client1_file1 = { 0 };
1092 struct smb2_handle h_client1_file2 = { 0 };
1093 struct smb2_handle h_client1_file3 = { 0 };
1094 struct smb2_handle h_client2_file1 = { 0 };
1095 struct smb2_handle h_client2_file2 = { 0 };
1096 struct smb2_handle h_client2_file3 = { 0 };
1097 struct smb2_create io1, io2, io3;
1100 const char *fname1 = BASEDIR "\\lease_break_test1.dat";
1101 const char *fname2 = BASEDIR "\\lease_break_test2.dat";
1102 const char *fname3 = BASEDIR "\\lease_break_test3.dat";
1103 struct smb2_tree *tree2A = NULL;
1104 struct smb2_tree *tree2B = NULL;
1105 struct smb2_tree *tree2C = NULL;
1106 struct smb2_transport *transport1 = tree1->session->transport;
1107 struct smb2_transport *transport2A = NULL;
1108 struct smb2_transport *transport2B = NULL;
1109 struct smb2_transport *transport2C = NULL;
1110 struct smbcli_options transport2_options;
1111 struct smb2_session *session1 = tree1->session;
1112 uint16_t local_port = 0;
1113 bool block_ok = false;
1114 bool unblock_ok = false;
1115 struct smb2_lease ls1;
1116 struct smb2_lease ls2;
1117 struct smb2_lease ls3;
1120 if (!test_multichannel_initial_checks(tctx, tree1))
1123 torture_reset_lease_break_info(tctx, &lease_break_info);
1125 transport1->lease.handler = torture_lease_handler;
1126 transport1->lease.private_data = tree1;
1127 torture_comment(tctx, "transport1 [%p]\n", transport1);
1128 local_port = torture_get_local_port_from_transport(transport1);
1129 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
1131 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
1132 CHECK_STATUS(status, NT_STATUS_OK);
1133 smb2_util_close(tree1, _h);
1134 smb2_util_unlink(tree1, fname1);
1135 smb2_util_unlink(tree1, fname2);
1136 smb2_util_unlink(tree1, fname3);
1137 CHECK_VAL(lease_break_info.count, 0);
1139 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1140 smb2_util_lease_state("RHW"));
1141 test_multichannel_init_smb_create(&io1);
1143 smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
1144 smb2_util_lease_state("RHW"));
1145 test_multichannel_init_smb_create(&io2);
1147 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
1148 smb2_util_lease_state("RHW"));
1149 test_multichannel_init_smb_create(&io3);
1151 transport2_options = transport1->options;
1155 * open file1 in session 2A
1156 * open file2 in session 2B
1157 * open file3 in session 2C
1158 * open file1 in session 1
1159 * lease break sent to 2A
1160 * open file2 in session 2
1161 * lease break sent to 2B
1163 torture_comment(tctx, "Test 2 start \n");
1165 transport2_options = transport1->options;
1166 rval = test_multichannel_create_channels2(tctx, host, share,
1168 &transport2_options,
1169 &tree2A, &tree2B, &tree2C);
1171 transport2A = tree2A->session->transport;
1172 transport2B = tree2B->session->transport;
1173 transport2C = tree2C->session->transport;
1175 /* 2a opens file1 */
1176 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
1177 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1178 smb2_util_lease_state("RHW"));
1179 status = smb2_create(tree2A, mem_ctx, &io1);
1180 CHECK_STATUS(status, NT_STATUS_OK);
1181 h_client2_file1 = io1.out.file.handle;
1182 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1183 CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
1184 CHECK_VAL(io1.out.durable_open_v2, false);
1185 CHECK_VAL(io1.out.timeout, io1.in.timeout);
1186 CHECK_VAL(io1.out.durable_open, false);
1187 CHECK_VAL(lease_break_info.count, 0);
1189 /* 2b opens file2 */
1190 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
1191 smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
1192 smb2_util_lease_state("RHW"));
1193 status = smb2_create(tree2B, mem_ctx, &io2);
1194 CHECK_STATUS(status, NT_STATUS_OK);
1195 h_client2_file2 = io2.out.file.handle;
1196 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1197 CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
1198 CHECK_VAL(io2.out.durable_open_v2, false);
1199 CHECK_VAL(io2.out.timeout, io2.in.timeout);
1200 CHECK_VAL(io2.out.durable_open, false);
1201 CHECK_VAL(lease_break_info.count, 0);
1203 /* 2c opens file3 */
1204 torture_comment(tctx, "client2 opens fname3 via session 2C\n");
1205 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
1206 smb2_util_lease_state("RHW"));
1207 status = smb2_create(tree2C, mem_ctx, &io3);
1208 CHECK_STATUS(status, NT_STATUS_OK);
1209 h_client2_file3 = io3.out.file.handle;
1210 CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1211 CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
1212 CHECK_VAL(io3.out.durable_open_v2, false);
1213 CHECK_VAL(io3.out.timeout, io2.in.timeout);
1214 CHECK_VAL(io3.out.durable_open, false);
1215 CHECK_VAL(lease_break_info.count, 0);
1222 torture_comment(tctx, "client1 opens fname1 via session 1\n");
1223 smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
1224 smb2_util_lease_state("RHW"));
1225 status = smb2_create(tree1, mem_ctx, &io1);
1226 CHECK_STATUS(status, NT_STATUS_OK);
1227 h_client1_file1 = io1.out.file.handle;
1228 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1229 CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
1230 CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
1231 CHECK_VAL(io1.out.durable_open_v2, false);
1232 CHECK_VAL(io1.out.timeout, 0);
1233 CHECK_VAL(io1.out.durable_open, false);
1234 CHECK_VAL(lease_break_info.count, 1);
1235 CHECK_PTR(lease_break_info.lease_transport, transport2A);
1237 torture_reset_lease_break_info(tctx, &lease_break_info);
1244 torture_comment(tctx, "client1 opens fname2 via session 1\n");
1245 smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
1246 smb2_util_lease_state("RHW"));
1247 status = smb2_create(tree1, mem_ctx, &io2);
1248 CHECK_STATUS(status, NT_STATUS_OK);
1249 h_client1_file2 = io2.out.file.handle;
1250 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1251 CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
1252 CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
1253 CHECK_VAL(io2.out.durable_open_v2, false);
1254 CHECK_VAL(io2.out.timeout, 0);
1255 CHECK_VAL(io2.out.durable_open, false);
1256 CHECK_VAL(lease_break_info.count, 1);
1257 CHECK_PTR(lease_break_info.lease_transport, transport2A);
1259 /* cleanup everything */
1260 torture_reset_lease_break_info(tctx, &lease_break_info);
1262 smb2_util_close(tree1, h_client1_file1);
1263 smb2_util_close(tree1, h_client1_file2);
1264 smb2_util_close(tree1, h_client1_file3);
1265 smb2_util_close(tree2A, h_client2_file1);
1266 smb2_util_close(tree2A, h_client2_file2);
1267 smb2_util_close(tree2A, h_client2_file3);
1269 smb2_util_unlink(tree1, fname1);
1270 smb2_util_unlink(tree1, fname2);
1271 smb2_util_unlink(tree1, fname3);
1272 CHECK_VAL(lease_break_info.count, 0);
1273 test_multichannel_free_channels2(tree2A, tree2B, tree2C);
1274 tree2A = tree2B = tree2C = NULL;
1278 * open file1 in session 2A
1279 * open file2 in session 2B
1280 * open file3 in session 2C
1282 * open file2 in session 1
1283 * lease break reaches through session 2A
1284 * server allows session 1 to open file1
1285 * unblock 2B 2C, send keep alive
1286 * open file1 in session 1
1287 * lease break sent to 2A
1289 torture_comment(tctx, "Test 3 start \n");
1291 rval = test_multichannel_create_channels2(tctx, host, share,
1293 &transport2_options,
1294 &tree2A, &tree2B, &tree2C);
1296 transport2A = tree2A->session->transport;
1297 transport2B = tree2B->session->transport;
1298 transport2C = tree2C->session->transport;
1300 /* 2a opens file1 */
1301 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
1302 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1303 smb2_util_lease_state("RHW"));
1304 status = smb2_create(tree2A, mem_ctx, &io1);
1305 CHECK_STATUS(status, NT_STATUS_OK);
1306 h_client2_file1 = io1.out.file.handle;
1307 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1308 CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
1309 CHECK_VAL(io1.out.durable_open_v2, false); //true);
1310 CHECK_VAL(io1.out.timeout, io1.in.timeout);
1311 CHECK_VAL(io1.out.durable_open, false);
1312 CHECK_VAL(lease_break_info.count, 0);
1314 /* 2b opens file2 */
1315 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
1316 smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
1317 smb2_util_lease_state("RHW"));
1318 status = smb2_create(tree2B, mem_ctx, &io2);
1319 CHECK_STATUS(status, NT_STATUS_OK);
1320 h_client2_file2 = io2.out.file.handle;
1321 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1322 CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
1323 CHECK_VAL(io2.out.durable_open_v2, false); //true);
1324 CHECK_VAL(io2.out.timeout, io2.in.timeout);
1325 CHECK_VAL(io2.out.durable_open, false);
1326 CHECK_VAL(lease_break_info.count, 0);
1329 torture_comment(tctx, "Blocking 2B and 2C\n");
1330 /* Block 2B and 2C */
1331 block_ok = torture_block_tcp_transport(tctx, transport2B);
1332 block_ok |= torture_block_tcp_transport(tctx, transport2C);
1333 torture_assert(tctx, block_ok, "we could not block tcp transport");
1337 * batchoplock break?
1340 torture_comment(tctx, "Client opens fname2 with session 1 with 2B and 2C blocked\n");
1341 smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
1342 smb2_util_lease_state("RHW"));
1343 status = smb2_create(tree1, mem_ctx, &io2);
1344 CHECK_STATUS(status, NT_STATUS_OK);
1345 h_client1_file2 = io2.out.file.handle;
1346 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1347 CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
1348 CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
1349 CHECK_VAL(io2.out.durable_open_v2, false);
1350 CHECK_VAL(io2.out.timeout, 0);
1351 CHECK_VAL(io2.out.durable_open, false);
1353 CHECK_VAL(lease_break_info.count, 1);
1354 torture_reset_lease_break_info(tctx, &lease_break_info);
1356 /* Unblock 2B and 2C */
1357 torture_comment(tctx, "Unblocking 2B and 2C\n");
1358 unblock_ok = torture_unblock_tcp_transport(tctx, transport2B);
1359 unblock_ok |= torture_unblock_tcp_transport(tctx, transport2C);
1360 torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
1361 torture_unblock_cleanup(tctx);
1363 /* Will this trigger pending break? */
1364 smb2_keepalive(transport2B);
1365 smb2_keepalive(transport2C);
1366 CHECK_VAL(lease_break_info.count, 0);
1374 torture_comment(tctx, "client opens fname1 via session 1\n");
1376 smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
1377 smb2_util_lease_state("RHW"));
1378 status = smb2_create(tree1, mem_ctx, &io1);
1379 CHECK_STATUS(status, NT_STATUS_OK);
1380 h_client1_file1 = io1.out.file.handle;
1381 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1382 CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
1383 CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
1384 CHECK_VAL(io1.out.durable_open_v2, false);
1385 CHECK_VAL(io1.out.timeout, 0);
1386 CHECK_VAL(io1.out.durable_open, false);
1387 CHECK_VAL(lease_break_info.count, 1);
1389 torture_comment(tctx, "client closes fname1 via session 2A\n");
1390 status = smb2_util_close(tree2A, h_client2_file1);
1391 CHECK_STATUS(status, NT_STATUS_OK);
1393 torture_reset_lease_break_info(tctx, &lease_break_info);
1394 smb2_util_close(tree1, h_client1_file1);
1395 smb2_util_close(tree1, h_client1_file2);
1396 smb2_util_close(tree1, h_client1_file3);
1397 smb2_util_close(tree2A, h_client2_file1);
1398 smb2_util_close(tree2A, h_client2_file2);
1399 smb2_util_close(tree2A, h_client2_file3);
1401 smb2_util_unlink(tree1, fname1);
1402 smb2_util_unlink(tree1, fname2);
1403 smb2_util_unlink(tree1, fname3);
1404 CHECK_VAL(lease_break_info.count, 0);
1405 test_multichannel_free_channels2(tree2A, tree2B, tree2C);
1406 tree2A = tree2B = tree2C = NULL;
1410 * open file1 in session 2A
1411 * open file2 in session 2B
1412 * open file3 in session 2C
1414 * open file3 in session 1
1416 * server allows session 1 to open file1
1418 * open file2 in session 1
1419 * no oplock break because 2B blocked.
1420 * session 1 allowed to open file2
1421 * 2A writes "Here I am to file 2"
1422 * Recieve break on 1 drop oplock.
1424 torture_comment(tctx, "Test 4 start \n");
1426 rval = test_multichannel_create_channels2(tctx, host, share,
1428 &transport2_options,
1429 &tree2A, &tree2B, &tree2C);
1431 transport2A = tree2A->session->transport;
1432 transport2B = tree2B->session->transport;
1433 transport2C = tree2C->session->transport;
1435 /* 2a opens file1 */
1436 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
1437 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1438 smb2_util_lease_state("RHW"));
1439 status = smb2_create(tree2A, mem_ctx, &io1);
1440 CHECK_STATUS(status, NT_STATUS_OK);
1441 h_client2_file1 = io1.out.file.handle;
1442 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1443 CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
1444 CHECK_VAL(io1.out.durable_open_v2, false); //true);
1445 CHECK_VAL(io1.out.timeout, io1.in.timeout);
1446 CHECK_VAL(io1.out.durable_open, false);
1447 CHECK_VAL(lease_break_info.count, 0);
1449 /* 2b opens file2 */
1450 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
1451 smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
1452 smb2_util_lease_state("RHW"));
1453 status = smb2_create(tree2B, mem_ctx, &io2);
1454 CHECK_STATUS(status, NT_STATUS_OK);
1455 h_client2_file2 = io2.out.file.handle;
1456 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1457 CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
1458 CHECK_VAL(io2.out.durable_open_v2, false); //true);
1459 CHECK_VAL(io2.out.timeout, io2.in.timeout);
1460 CHECK_VAL(io2.out.durable_open, false);
1461 CHECK_VAL(lease_break_info.count, 0);
1463 /* 2c opens file3 */
1464 torture_comment(tctx, "client2 opens fname3 via session 2C\n");
1465 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
1466 smb2_util_lease_state("RHW"));
1467 status = smb2_create(tree2C, mem_ctx, &io3);
1468 CHECK_STATUS(status, NT_STATUS_OK);
1469 h_client2_file3 = io3.out.file.handle;
1470 CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1471 CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
1472 CHECK_VAL(io3.out.durable_open_v2, false);
1473 CHECK_VAL(io3.out.timeout, io2.in.timeout);
1474 CHECK_VAL(io3.out.durable_open, false);
1475 CHECK_VAL(lease_break_info.count, 0);
1478 torture_comment(tctx, "Disconnect 2C\n");
1479 torture_comment(tctx, "explicit disconnect of transport2C\n");
1480 smbXcli_conn_disconnect(transport2C->conn, NT_STATUS_FOOBAR);
1484 * batchoplock break?
1486 torture_comment(tctx, "Client opens fname3 with session 1\n");
1487 smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
1488 smb2_util_lease_state("RHW"));
1489 status = smb2_create(tree1, mem_ctx, &io3);
1490 CHECK_STATUS(status, NT_STATUS_OK);
1491 h_client1_file3 = io3.out.file.handle;
1492 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1493 CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
1494 CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
1495 CHECK_VAL(io1.out.durable_open_v2, false);
1496 CHECK_VAL(io1.out.timeout, 0);
1497 CHECK_VAL(io1.out.durable_open, false);
1498 CHECK_VAL(lease_break_info.count, 1);
1500 torture_reset_lease_break_info(tctx, &lease_break_info);
1503 block_ok = torture_block_tcp_transport(tctx, transport2B);
1504 torture_assert(tctx, block_ok, "we could not block tcp transport");
1508 * batchoplock break?
1510 torture_comment(tctx, "client opens fname2 via session 1\n");
1511 smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
1512 smb2_util_lease_state("RHW"));
1513 status = smb2_create(tree1, mem_ctx, &io2);
1514 CHECK_STATUS(status, NT_STATUS_OK);
1515 h_client1_file2 = io2.out.file.handle;
1516 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1517 CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
1518 CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
1519 CHECK_VAL(io2.out.durable_open_v2, false);
1520 CHECK_VAL(io2.out.timeout, 0);
1521 CHECK_VAL(io2.out.durable_open, false);
1522 CHECK_VAL(lease_break_info.count, 1);
1524 /* 2A writes "Here I am to file 2" */
1526 torture_comment(tctx, "Trying write to file2 on tree2A\n");
1527 blob = data_blob_string_const("Here I am");
1528 status = smb2_util_write(tree2A,
1533 torture_assert_ntstatus_ok(tctx, status,
1534 "failed to write file2 via channel 2A");
1537 unblock_ok = torture_unblock_tcp_transport(tctx, transport2B);
1538 torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
1540 torture_reset_lease_break_info(tctx, &lease_break_info);
1541 smb2_util_close(tree1, h_client1_file1);
1542 smb2_util_close(tree1, h_client1_file2);
1543 smb2_util_close(tree1, h_client1_file3);
1544 smb2_util_close(tree2A, h_client2_file1);
1545 smb2_util_close(tree2A, h_client2_file2);
1546 smb2_util_close(tree2A, h_client2_file3);
1548 smb2_util_unlink(tree1, fname1);
1549 smb2_util_unlink(tree1, fname2);
1550 smb2_util_unlink(tree1, fname3);
1551 CHECK_VAL(lease_break_info.count, 0);
1552 test_multichannel_free_channels2(tree2A, tree2B, tree2C);
1553 tree2A = tree2B = tree2C = NULL;
1556 if (block_ok && !unblock_ok) {
1557 /* unblock tcp connection of transport2C */
1558 unblock_ok = torture_unblock_tcp_transport(tctx, transport2C);
1559 unblock_ok = torture_unblock_tcp_transport(tctx, transport2A);
1560 unblock_ok = torture_unblock_tcp_transport(tctx, transport2B);
1563 tree1->session = session1;
1565 smb2_util_close(tree1, h_client1_file1);
1566 smb2_util_close(tree1, h_client1_file2);
1567 smb2_util_close(tree1, h_client1_file3);
1568 if (tree2A != NULL) {
1569 smb2_util_close(tree2A, h_client2_file1);
1570 smb2_util_close(tree2A, h_client2_file2);
1571 smb2_util_close(tree2A, h_client2_file3);
1575 smb2_util_close(tree1, *h);
1578 smb2_util_unlink(tree1, fname1);
1579 smb2_util_unlink(tree1, fname2);
1580 smb2_util_unlink(tree1, fname3);
1581 smb2_deltree(tree1, BASEDIR);
1583 test_multichannel_free_channels2(tree2A, tree2B, tree2C);
1585 talloc_free(mem_ctx);
1591 * Test limits of channels
1593 static bool test_multichannel_num_channels(struct torture_context *tctx,
1594 struct smb2_tree *tree1)
1596 const char *host = torture_setting_string(tctx, "host", NULL);
1597 const char *share = torture_setting_string(tctx, "share", NULL);
1598 struct cli_credentials *credentials = popt_get_cmdline_credentials();
1599 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1601 struct smb2_tree **tree2 = NULL;
1602 struct smb2_transport *transport1 = tree1->session->transport;
1603 struct smb2_transport **transport2 = NULL;
1604 struct smbcli_options transport2_options;
1605 struct smb2_session **session2 = NULL;
1606 uint32_t server_capabilities;
1608 int max_channels = 33; /* 32 is the W2K12R2 and W2K16 limit */
1610 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
1611 torture_fail(tctx, "SMB 3.X Dialect family required for "
1612 "Multichannel tests\n");
1615 server_capabilities = smb2cli_conn_server_capabilities(
1616 tree1->session->transport->conn);
1617 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
1619 "Server does not support multichannel.");
1622 torture_comment(tctx, "Testing max. number of channels\n");
1624 transport2_options = transport1->options;
1625 transport2_options.client_guid = GUID_random();
1627 tree2 = talloc_zero_array(mem_ctx, struct smb2_tree *, max_channels);
1628 transport2 = talloc_zero_array(mem_ctx, struct smb2_transport *, max_channels);
1629 session2 = talloc_zero_array(mem_ctx, struct smb2_session *, max_channels);
1630 if (tree2 == NULL || transport2 == NULL || session2 == NULL) {
1631 torture_fail(tctx, "out of memory");
1634 for (i = 0; i < max_channels; i++) {
1636 NTSTATUS expected_status;
1638 torture_assert_ntstatus_ok_goto(tctx,
1641 lpcfg_smb_ports(tctx->lp_ctx),
1643 lpcfg_resolve_context(tctx->lp_ctx),
1647 &transport2_options,
1648 lpcfg_socket_options(tctx->lp_ctx),
1649 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
1651 ret, done, "smb2_connect failed");
1653 transport2[i] = tree2[i]->session->transport;
1656 /* done for the 1st channel */
1661 * Now bind the session2[i] to the transport2
1663 session2[i] = smb2_session_channel(transport2[i],
1664 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
1668 torture_assert(tctx, session2[i] != NULL, "smb2_session_channel failed");
1670 torture_comment(tctx, "established transport2 [#%d]\n", i);
1673 expected_status = NT_STATUS_INSUFFICIENT_RESOURCES;
1675 expected_status = NT_STATUS_OK;
1678 torture_assert_ntstatus_equal_goto(tctx,
1679 smb2_session_setup_spnego(session2[i],
1680 popt_get_cmdline_credentials(),
1681 0 /* previous_session_id */),
1684 talloc_asprintf(tctx, "failed to establish session setup for channel #%d", i));
1686 torture_comment(tctx, "bound session2 [#%d] to session2 [0]\n", i);
1690 talloc_free(mem_ctx);
1695 struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
1697 struct torture_suite *suite = torture_suite_create(ctx, "multichannel");
1699 torture_suite_add_1smb2_test(suite, "session_bind_multiple_nics", test_session_bind_multiple_nics);
1700 torture_suite_add_1smb2_test(suite, "interface_info", test_multichannel_interface_info);
1701 torture_suite_add_1smb2_test(suite, "oplock_break", test_multichannel_oplock_break);
1702 torture_suite_add_1smb2_test(suite, "lease_break", test_multichannel_lease_break);
1703 torture_suite_add_1smb2_test(suite, "lease_break_test1", test_multichannel_lease_break_test1);
1704 torture_suite_add_1smb2_test(suite, "num_channels", test_multichannel_num_channels);
1706 suite->description = talloc_strdup(suite, "SMB2 Multichannel tests");