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/>.
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25 #include "torture/torture.h"
26 #include "torture/smb2/proto.h"
27 #include "libcli/security/security.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "librpc/gen_ndr/ndr_ioctl.h"
30 #include "../libcli/smb/smbXcli_base.h"
31 #include "lib/cmdline/popt_common.h"
32 #include "libcli/security/security.h"
33 #include "libcli/resolve/resolve.h"
34 #include "lib/param/param.h"
35 #include "lib/events/events.h"
36 #include "oplock_break_handler.h"
37 #include "lease_break_handler.h"
38 #include "torture/smb2/block.h"
40 #define BASEDIR "multichanneltestdir"
42 #define CHECK_STATUS(status, correct) \
43 torture_assert_ntstatus_equal_goto(tctx, status, correct,\
46 #define CHECK_VAL(v, correct) do { \
47 if ((v) != (correct)) { \
48 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s" \
49 " got 0x%x - should be 0x%x\n", \
50 __location__, #v, (int)v, (int)correct); \
55 #define CHECK_VAL_GREATER_THAN(v, gt_val) do { \
56 if ((v) <= (gt_val)) { \
57 torture_result(tctx, TORTURE_FAIL, \
58 "(%s): wrong value for %s got 0x%x - " \
59 "should be greater than 0x%x\n", \
60 __location__, #v, (int)v, (int)gt_val); \
65 #define CHECK_CREATED(__io, __created, __attribute) \
67 CHECK_VAL((__io)->out.create_action, \
68 NTCREATEX_ACTION_ ## __created); \
69 CHECK_VAL((__io)->out.alloc_size, 0); \
70 CHECK_VAL((__io)->out.size, 0); \
71 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
72 CHECK_VAL((__io)->out.reserved2, 0); \
75 #define CHECK_PTR(ptr, correct) do { \
76 if ((ptr) != (correct)) { \
77 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
78 "got 0x%p - should be 0x%p\n", \
79 __location__, #ptr, ptr, correct); \
84 #define CHECK_LEASE(__io, __state, __oplevel, __key, __flags) \
86 CHECK_VAL((__io)->out.lease_response.lease_version, 1); \
88 CHECK_VAL((__io)->out.oplock_level, \
89 SMB2_OPLOCK_LEVEL_LEASE); \
90 CHECK_VAL((__io)->out.lease_response.lease_key.data[0],\
92 CHECK_VAL((__io)->out.lease_response.lease_key.data[1],\
94 CHECK_VAL((__io)->out.lease_response.lease_state,\
95 smb2_util_lease_state(__state)); \
97 CHECK_VAL((__io)->out.oplock_level,\
98 SMB2_OPLOCK_LEVEL_NONE); \
99 CHECK_VAL((__io)->out.lease_response.lease_key.data[0],\
101 CHECK_VAL((__io)->out.lease_response.lease_key.data[1],\
103 CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
106 CHECK_VAL((__io)->out.lease_response.lease_flags, (__flags)); \
107 CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
108 CHECK_VAL((__io)->out.lease_response.lease_epoch, 0); \
111 static bool test_ioctl_network_interface_info(struct torture_context *tctx,
112 struct smb2_tree *tree,
113 struct fsctl_net_iface_info *info)
115 union smb_ioctl ioctl;
116 struct smb2_handle fh;
119 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
120 if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
122 "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
127 ioctl.smb2.level = RAW_IOCTL_SMB2;
129 fh.data[0] = UINT64_MAX;
130 fh.data[1] = UINT64_MAX;
132 ioctl.smb2.in.file.handle = fh;
133 ioctl.smb2.in.function = FSCTL_QUERY_NETWORK_INTERFACE_INFO;
134 /* Windows client sets this to 64KiB */
135 ioctl.smb2.in.max_output_response = 0x10000;
136 ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
138 torture_assert_ntstatus_ok(tctx,
139 smb2_ioctl(tree, tctx, &ioctl.smb2),
140 "FSCTL_QUERY_NETWORK_INTERFACE_INFO failed");
143 (ioctl.smb2.out.out.length != 0),
144 "no interface info returned???");
146 torture_assert_ndr_success(tctx,
147 ndr_pull_struct_blob(&ioctl.smb2.out.out, tctx, info,
148 (ndr_pull_flags_fn_t)ndr_pull_fsctl_net_iface_info),
149 "failed to ndr pull");
152 NDR_PRINT_DEBUG(fsctl_net_iface_info, info);
158 static bool test_multichannel_interface_info(struct torture_context *tctx,
159 struct smb2_tree *tree)
161 struct fsctl_net_iface_info info;
163 return test_ioctl_network_interface_info(tctx, tree, &info);
166 static struct smb2_tree *test_multichannel_create_channel(
167 struct torture_context *tctx,
170 struct cli_credentials *credentials,
171 struct smbcli_options *transport_options,
172 struct smb2_tree *parent_tree
176 struct smb2_transport *transport;
177 struct smb2_session *session;
179 struct smb2_tree *tree;
181 status = smb2_connect(tctx,
183 lpcfg_smb_ports(tctx->lp_ctx),
185 lpcfg_resolve_context(tctx->lp_ctx),
190 lpcfg_socket_options(tctx->lp_ctx),
191 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
193 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
194 "smb2_connect failed");
195 transport = tree->session->transport;
196 transport->oplock.handler = torture_oplock_ack_handler;
197 transport->oplock.private_data = tree;
198 transport->lease.handler = torture_lease_handler;
199 transport->lease.private_data = tree;
200 torture_comment(tctx, "established transport [%p]\n", transport);
203 * If parent tree is set, bind the session to the parent transport
206 session = smb2_session_channel(transport,
207 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
208 parent_tree, parent_tree->session);
209 torture_assert_goto(tctx, session != NULL, ret, done,
210 "smb2_session_channel failed");
212 tree->smbXcli = parent_tree->smbXcli;
213 tree->session = session;
214 status = smb2_session_setup_spnego(session,
216 0 /* previous_session_id */);
217 CHECK_STATUS(status, NT_STATUS_OK);
218 torture_comment(tctx, "bound new session to parent\n");
221 * We absolutely need to make sure to send something over this
222 * connection to register the oplock break handler with the smb client
223 * connection. If we do not send something (at least a keepalive), we
224 * will *NEVER* receive anything over this transport.
226 smb2_keepalive(transport);
236 bool test_multichannel_create_channels(
237 struct torture_context *tctx,
240 struct cli_credentials *credentials,
241 struct smbcli_options *transport_options,
242 struct smb2_tree **tree2A,
243 struct smb2_tree **tree2B,
244 struct smb2_tree **tree2C
247 struct smb2_tree *tree;
248 struct smb2_transport *transport2A;
249 struct smb2_transport *transport2B;
250 struct smb2_transport *transport2C;
251 uint16_t local_port = 0;
253 transport_options->client_guid = GUID_random();
256 torture_comment(tctx, "Setting up connection 2A\n");
257 tree = test_multichannel_create_channel(tctx, host, share,
258 credentials, transport_options, NULL);
263 transport2A = tree->session->transport;
264 local_port = torture_get_local_port_from_transport(transport2A);
265 torture_comment(tctx, "transport2A uses tcp port: %d\n", local_port);
269 torture_comment(tctx, "Setting up connection 2B\n");
270 tree = test_multichannel_create_channel(tctx, host, share,
271 credentials, transport_options, *tree2A);
276 transport2B = tree->session->transport;
277 local_port = torture_get_local_port_from_transport(transport2B);
278 torture_comment(tctx, "transport2B uses tcp port: %d\n",
284 torture_comment(tctx, "Setting up connection 2C\n");
285 tree = test_multichannel_create_channel(tctx, host, share,
286 credentials, transport_options, *tree2A);
291 transport2C = tree->session->transport;
292 local_port = torture_get_local_port_from_transport(transport2C);
293 torture_comment(tctx, "transport2C uses tcp port: %d\n",
302 static void test_multichannel_free_channels(struct smb2_tree *tree2A,
303 struct smb2_tree *tree2B,
304 struct smb2_tree *tree2C)
311 static bool test_multichannel_initial_checks(struct torture_context *tctx,
312 struct smb2_tree *tree1)
314 struct smb2_transport *transport1 = tree1->session->transport;
315 uint32_t server_capabilities;
316 struct fsctl_net_iface_info info;
318 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
319 torture_skip_goto(tctx, fail,
320 "SMB 3.X Dialect family required for "
321 "Multichannel tests\n");
324 server_capabilities = smb2cli_conn_server_capabilities(
325 tree1->session->transport->conn);
326 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
327 torture_skip_goto(tctx, fail,
328 "Server does not support multichannel.");
332 test_ioctl_network_interface_info(tctx, tree1, &info),
333 "failed to retrieve network interface info");
340 static void test_multichannel_init_smb_create(struct smb2_create *io)
342 io->in.durable_open = false;
343 io->in.durable_open_v2 = true;
344 io->in.persistent_open = false;
345 io->in.create_guid = GUID_random();
346 io->in.timeout = 0x493E0; /* 300000 */
347 /* windows 2016 returns 300000 0x493E0 */
351 * We simulate blocking incoming oplock break requests by simply ignoring
352 * the incoming break requests.
354 static bool test_set_ignore_break_handler(struct torture_context *tctx,
355 struct smb2_transport *transport)
357 transport->oplock.handler = torture_oplock_ignore_handler;
358 transport->lease.handler = torture_lease_ignore_handler;
363 static bool test_reset_break_handler(struct torture_context *tctx,
364 struct smb2_transport *transport)
366 transport->oplock.handler = torture_oplock_ack_handler;
367 transport->lease.handler = torture_lease_handler;
373 * Use iptables to block channels
375 static bool test_iptables_block_channel(struct torture_context *tctx,
376 struct smb2_transport *transport,
382 local_port = torture_get_local_port_from_transport(transport);
383 torture_comment(tctx, "transport uses tcp port: %d\n", local_port);
384 ret = torture_block_tcp_transport_name(tctx, transport, name);
385 torture_assert(tctx, ret, "we could not block tcp transport");
390 static bool test_iptables_unblock_channel(struct torture_context *tctx,
391 struct smb2_transport *transport,
397 local_port = torture_get_local_port_from_transport(transport);
398 torture_comment(tctx, "transport uses tcp port: %d\n", local_port);
399 ret = torture_unblock_tcp_transport_name(tctx, transport, name);
400 torture_assert(tctx, ret, "we could not block tcp transport");
405 #define test_block_channel(_tctx, _t) _test_block_channel(_tctx, _t, #_t)
406 static bool _test_block_channel(struct torture_context *tctx,
407 struct smb2_transport *transport,
410 bool use_iptables = torture_setting_bool(tctx,
411 "use_iptables", false);
414 return test_iptables_block_channel(tctx, transport, name);
416 return test_set_ignore_break_handler(tctx, transport);
420 #define test_unblock_channel(_tctx, _t) _test_unblock_channel(_tctx, _t, #_t)
421 static bool _test_unblock_channel(struct torture_context *tctx,
422 struct smb2_transport *transport,
425 bool use_iptables = torture_setting_bool(tctx,
426 "use_iptables", false);
429 return test_iptables_unblock_channel(tctx, transport, name);
431 return test_reset_break_handler(tctx, transport);
435 static void test_cleanup_blocked_channels(struct torture_context *tctx)
437 bool use_iptables = torture_setting_bool(tctx,
438 "use_iptables", false);
441 torture_unblock_cleanup(tctx);
446 * Oplock break - Test 1
447 * Test to confirm that server sends oplock breaks as expected.
448 * open file1 in session 2A
449 * open file2 in session 2B
450 * open file1 in session 1
451 * oplock break received
452 * open file1 in session 1
453 * oplock break received
456 static bool test_multichannel_oplock_break_test1(struct torture_context *tctx,
457 struct smb2_tree *tree1)
459 const char *host = torture_setting_string(tctx, "host", NULL);
460 const char *share = torture_setting_string(tctx, "share", NULL);
461 struct cli_credentials *credentials = popt_get_cmdline_credentials();
463 TALLOC_CTX *mem_ctx = talloc_new(tctx);
464 struct smb2_handle _h;
465 struct smb2_handle h_client1_file1 = {{0}};
466 struct smb2_handle h_client1_file2 = {{0}};
467 struct smb2_handle h_client1_file3 = {{0}};
468 struct smb2_handle h_client2_file1 = {{0}};
469 struct smb2_handle h_client2_file2 = {{0}};
470 struct smb2_handle h_client2_file3 = {{0}};
471 struct smb2_create io1, io2, io3;
473 const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
474 const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
475 const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
476 struct smb2_tree *tree2A = NULL;
477 struct smb2_tree *tree2B = NULL;
478 struct smb2_tree *tree2C = NULL;
479 struct smb2_transport *transport1 = tree1->session->transport;
480 struct smbcli_options transport2_options;
481 struct smb2_session *session1 = tree1->session;
482 uint16_t local_port = 0;
484 if (!test_multichannel_initial_checks(tctx, tree1)) {
488 torture_comment(tctx, "Oplock break retry: Test1\n");
490 torture_reset_break_info(tctx, &break_info);
492 transport1->oplock.handler = torture_oplock_ack_handler;
493 transport1->oplock.private_data = tree1;
494 torture_comment(tctx, "transport1 [%p]\n", transport1);
495 local_port = torture_get_local_port_from_transport(transport1);
496 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
498 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
499 CHECK_STATUS(status, NT_STATUS_OK);
500 smb2_util_close(tree1, _h);
501 smb2_util_unlink(tree1, fname1);
502 smb2_util_unlink(tree1, fname2);
503 smb2_util_unlink(tree1, fname3);
504 CHECK_VAL(break_info.count, 0);
506 smb2_oplock_create_share(&io1, fname1,
507 smb2_util_share_access("RWD"),
508 smb2_util_oplock_level("b"));
509 test_multichannel_init_smb_create(&io1);
511 smb2_oplock_create_share(&io2, fname2,
512 smb2_util_share_access("RWD"),
513 smb2_util_oplock_level("b"));
514 test_multichannel_init_smb_create(&io2);
516 smb2_oplock_create_share(&io3, fname3,
517 smb2_util_share_access("RWD"),
518 smb2_util_oplock_level("b"));
519 test_multichannel_init_smb_create(&io3);
521 transport2_options = transport1->options;
523 ret = test_multichannel_create_channels(tctx, host, share,
526 &tree2A, &tree2B, NULL);
527 torture_assert(tctx, ret, "Could not create channels.\n");
530 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
531 status = smb2_create(tree2A, mem_ctx, &io1);
532 CHECK_STATUS(status, NT_STATUS_OK);
533 h_client2_file1 = io1.out.file.handle;
534 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
535 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
536 torture_wait_for_oplock_break(tctx);
537 CHECK_VAL(break_info.count, 0);
540 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
541 status = smb2_create(tree2B, mem_ctx, &io2);
542 CHECK_STATUS(status, NT_STATUS_OK);
543 h_client2_file2 = io2.out.file.handle;
544 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
545 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
546 torture_wait_for_oplock_break(tctx);
547 CHECK_VAL(break_info.count, 0);
550 /* 1 opens file1 - batchoplock break? */
551 torture_comment(tctx, "client1 opens fname1 via session 1\n");
552 io1.in.oplock_level = smb2_util_oplock_level("b");
553 status = smb2_create(tree1, mem_ctx, &io1);
554 CHECK_STATUS(status, NT_STATUS_OK);
555 h_client1_file1 = io1.out.file.handle;
556 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
557 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
558 torture_wait_for_oplock_break(tctx);
559 CHECK_VAL(break_info.count, 1);
561 torture_reset_break_info(tctx, &break_info);
563 /* 1 opens file2 - batchoplock break? */
564 torture_comment(tctx, "client1 opens fname2 via session 1\n");
565 io2.in.oplock_level = smb2_util_oplock_level("b");
566 status = smb2_create(tree1, mem_ctx, &io2);
567 CHECK_STATUS(status, NT_STATUS_OK);
568 h_client1_file2 = io2.out.file.handle;
569 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
570 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
571 torture_wait_for_oplock_break(tctx);
572 CHECK_VAL(break_info.count, 1);
574 /* cleanup everything */
575 torture_reset_break_info(tctx, &break_info);
577 smb2_util_close(tree1, h_client1_file1);
578 smb2_util_close(tree1, h_client1_file2);
579 smb2_util_close(tree1, h_client1_file3);
580 smb2_util_close(tree2A, h_client2_file1);
581 smb2_util_close(tree2A, h_client2_file2);
582 smb2_util_close(tree2A, h_client2_file3);
584 smb2_util_unlink(tree1, fname1);
585 smb2_util_unlink(tree1, fname2);
586 smb2_util_unlink(tree1, fname3);
587 CHECK_VAL(break_info.count, 0);
588 test_multichannel_free_channels(tree2A, tree2B, tree2C);
589 tree2A = tree2B = tree2C = NULL;
591 tree1->session = session1;
593 smb2_util_close(tree1, h_client1_file1);
594 smb2_util_close(tree1, h_client1_file2);
595 smb2_util_close(tree1, h_client1_file3);
596 if (tree2A != NULL) {
597 smb2_util_close(tree2A, h_client2_file1);
598 smb2_util_close(tree2A, h_client2_file2);
599 smb2_util_close(tree2A, h_client2_file3);
602 smb2_util_unlink(tree1, fname1);
603 smb2_util_unlink(tree1, fname2);
604 smb2_util_unlink(tree1, fname3);
605 smb2_deltree(tree1, BASEDIR);
607 test_multichannel_free_channels(tree2A, tree2B, tree2C);
609 talloc_free(mem_ctx);
615 * Oplock Break Test 2
616 * Test to see if oplock break retries are sent by the server.
617 * Also checks to see if new channels can be created and used
618 * after an oplock break retry.
621 * open file1 in session 1
622 * oplock break received
623 * block channel on which oplock break received
624 * open file2 in session 1
625 * oplock break not received. Retry received.
627 * write to file2 on 2B
628 * Break sent to session 1(which has file2 open)
629 * Break sent to session 2A(which has read oplock)
630 * close file1 in session 1
631 * open file1 with session 1
632 * unblock blocked channel
633 * disconnect blocked channel
636 * open file3 in session 1
639 static bool test_multichannel_oplock_break_test2(struct torture_context *tctx,
640 struct smb2_tree *tree1)
642 const char *host = torture_setting_string(tctx, "host", NULL);
643 const char *share = torture_setting_string(tctx, "share", NULL);
644 struct cli_credentials *credentials = popt_get_cmdline_credentials();
646 TALLOC_CTX *mem_ctx = talloc_new(tctx);
647 struct smb2_handle _h;
648 struct smb2_handle h_client1_file1 = {{0}};
649 struct smb2_handle h_client1_file2 = {{0}};
650 struct smb2_handle h_client1_file3 = {{0}};
651 struct smb2_handle h_client2_file1 = {{0}};
652 struct smb2_handle h_client2_file2 = {{0}};
653 struct smb2_handle h_client2_file3 = {{0}};
654 struct smb2_create io1, io2, io3;
656 const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
657 const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
658 const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
659 struct smb2_tree *tree2A = NULL;
660 struct smb2_tree *tree2B = NULL;
661 struct smb2_tree *tree2C = NULL;
662 struct smb2_tree *tree2D = NULL;
663 struct smb2_transport *transport1 = tree1->session->transport;
664 struct smb2_transport *transport2 = NULL;
665 struct smbcli_options transport2_options;
666 struct smb2_session *session1 = tree1->session;
667 uint16_t local_port = 0;
669 bool block_ok = false;
670 bool unblock_ok = false;
672 if (!test_multichannel_initial_checks(tctx, tree1)) {
676 torture_comment(tctx, "Oplock break retry: Test2\n");
678 torture_reset_break_info(tctx, &break_info);
680 transport1->oplock.handler = torture_oplock_ack_handler;
681 transport1->oplock.private_data = tree1;
682 torture_comment(tctx, "transport1 [%p]\n", transport1);
683 local_port = torture_get_local_port_from_transport(transport1);
684 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
686 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
687 CHECK_STATUS(status, NT_STATUS_OK);
688 smb2_util_close(tree1, _h);
689 smb2_util_unlink(tree1, fname1);
690 smb2_util_unlink(tree1, fname2);
691 smb2_util_unlink(tree1, fname3);
692 CHECK_VAL(break_info.count, 0);
694 smb2_oplock_create_share(&io1, fname1,
695 smb2_util_share_access("RWD"),
696 smb2_util_oplock_level("b"));
697 test_multichannel_init_smb_create(&io1);
699 smb2_oplock_create_share(&io2, fname2,
700 smb2_util_share_access("RWD"),
701 smb2_util_oplock_level("b"));
702 test_multichannel_init_smb_create(&io2);
704 smb2_oplock_create_share(&io3, fname3,
705 smb2_util_share_access("RWD"),
706 smb2_util_oplock_level("b"));
707 test_multichannel_init_smb_create(&io3);
709 transport2_options = transport1->options;
711 ret = test_multichannel_create_channels(tctx, host, share,
714 &tree2A, &tree2B, &tree2C);
715 torture_assert(tctx, ret, "Could not create channels.\n")
717 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
718 io1.in.oplock_level = smb2_util_oplock_level("b");
719 status = smb2_create(tree2A, mem_ctx, &io1);
720 CHECK_STATUS(status, NT_STATUS_OK);
721 h_client2_file1 = io1.out.file.handle;
722 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
723 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
724 torture_wait_for_oplock_break(tctx);
725 CHECK_VAL(break_info.count, 0);
728 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
729 io2.in.oplock_level = smb2_util_oplock_level("b");
730 status = smb2_create(tree2B, mem_ctx, &io2);
731 CHECK_STATUS(status, NT_STATUS_OK);
732 h_client2_file2 = io2.out.file.handle;
733 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
734 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
735 torture_wait_for_oplock_break(tctx);
736 CHECK_VAL(break_info.count, 0);
739 torture_comment(tctx, "client1 opens fname1 via session 1\n");
740 io1.in.oplock_level = smb2_util_oplock_level("b");
741 status = smb2_create(tree1, mem_ctx, &io1);
742 CHECK_STATUS(status, NT_STATUS_OK);
743 h_client1_file1 = io1.out.file.handle;
744 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
745 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
746 torture_wait_for_oplock_break(tctx);
747 CHECK_VAL(break_info.count, 1);
749 /* We use the transport over which this oplock break was received */
750 transport2 = break_info.received_transport;
751 torture_reset_break_info(tctx, &break_info);
754 block_ok = test_block_channel(tctx, transport2);
756 torture_comment(tctx, "client1 opens fname2 via session 1\n");
757 io2.in.oplock_level = smb2_util_oplock_level("b");
758 status = smb2_create(tree1, mem_ctx, &io2);
759 CHECK_STATUS(status, NT_STATUS_OK);
760 h_client1_file2 = io2.out.file.handle;
761 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
762 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
765 * Samba downgrades oplock to a level 2 oplock.
766 * Windows 2016 revokes oplock
768 torture_wait_for_oplock_break(tctx);
769 CHECK_VAL(break_info.count, 1);
770 torture_reset_break_info(tctx, &break_info);
772 torture_comment(tctx, "Trying write to file2 on tree2B\n");
774 blob = data_blob_string_const("Here I am");
775 status = smb2_util_write(tree2B,
780 torture_assert_ntstatus_ok(tctx, status,
781 "failed to write file2 via channel 2B");
784 * Samba: Write triggers 2 oplock breaks
785 * for session 1 which has file2 open
786 * for session 2 which has type 2 oplock
787 * Windows 2016: Only one oplock break for session 1
789 torture_wait_for_oplock_break(tctx);
790 CHECK_VAL_GREATER_THAN(break_info.count, 0);
791 torture_reset_break_info(tctx, &break_info);
793 torture_comment(tctx, "client1 closes fname2 via session 1\n");
794 smb2_util_close(tree1, h_client1_file2);
796 torture_comment(tctx, "client1 opens fname2 via session 1 again\n");
797 io2.in.oplock_level = smb2_util_oplock_level("b");
798 status = smb2_create(tree1, mem_ctx, &io2);
799 CHECK_STATUS(status, NT_STATUS_OK);
800 h_client1_file2 = io2.out.file.handle;
801 io2.out.alloc_size = 0;
803 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
804 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
807 * now add a fourth channel and repeat the test, we need to reestablish
808 * transport2 because the remote end has invalidated our connection
810 torture_comment(tctx, "Connecting session 2D\n");
811 tree2D = test_multichannel_create_channel(tctx, host, share,
812 credentials, &transport2_options, tree2B);
817 torture_reset_break_info(tctx, &break_info);
818 torture_comment(tctx, "client 2 opening fname3 over transport2D\n");
819 status = smb2_create(tree2D, mem_ctx, &io3);
820 CHECK_STATUS(status, NT_STATUS_OK);
821 h_client2_file3 = io3.out.file.handle;
822 CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
823 CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("b"));
824 torture_wait_for_oplock_break(tctx);
825 CHECK_VAL(break_info.count, 0);
827 torture_comment(tctx, "client1 opens fname3 via session 1\n");
828 status = smb2_create(tree1, mem_ctx, &io3);
829 CHECK_STATUS(status, NT_STATUS_OK);
830 h_client1_file3 = io3.out.file.handle;
831 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
832 CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
833 torture_wait_for_oplock_break(tctx);
834 CHECK_VAL(break_info.count, 1);
837 if (block_ok && !unblock_ok) {
838 test_unblock_channel(tctx, transport2);
840 test_cleanup_blocked_channels(tctx);
842 tree1->session = session1;
844 smb2_util_close(tree1, h_client1_file1);
845 smb2_util_close(tree1, h_client1_file2);
846 smb2_util_close(tree1, h_client1_file3);
847 if (tree2B != NULL) {
848 smb2_util_close(tree2B, h_client2_file1);
849 smb2_util_close(tree2B, h_client2_file2);
850 smb2_util_close(tree2B, h_client2_file3);
853 smb2_util_unlink(tree1, fname1);
854 smb2_util_unlink(tree1, fname2);
855 smb2_util_unlink(tree1, fname3);
856 smb2_deltree(tree1, BASEDIR);
858 test_multichannel_free_channels(tree2A, tree2B, tree2C);
859 if (tree2D != NULL) {
863 talloc_free(mem_ctx);
868 static const uint64_t LEASE1F1 = 0xBADC0FFEE0DDF00Dull;
869 static const uint64_t LEASE1F2 = 0xBADC0FFEE0DDD00Dull;
870 static const uint64_t LEASE1F3 = 0xDADC0FFEE0DDD00Dull;
871 static const uint64_t LEASE2F1 = 0xDEADBEEFFEEDBEADull;
872 static const uint64_t LEASE2F2 = 0xDAD0FFEDD00DF00Dull;
873 static const uint64_t LEASE2F3 = 0xBAD0FFEDD00DF00Dull;
876 * Lease Break Test 1:
877 * Test to check if lease breaks are sent by the server as expected.
878 * open file1 in session 2A
879 * open file2 in session 2B
880 * open file3 in session 2C
881 * open file1 in session 1
883 * open file2 in session 1
885 * open file3 in session 1
888 static bool test_multichannel_lease_break_test1(struct torture_context *tctx,
889 struct smb2_tree *tree1)
891 const char *host = torture_setting_string(tctx, "host", NULL);
892 const char *share = torture_setting_string(tctx, "share", NULL);
893 struct cli_credentials *credentials = popt_get_cmdline_credentials();
895 TALLOC_CTX *mem_ctx = talloc_new(tctx);
896 struct smb2_handle _h;
897 struct smb2_handle *h = NULL;
898 struct smb2_handle h_client1_file1 = {{0}};
899 struct smb2_handle h_client1_file2 = {{0}};
900 struct smb2_handle h_client1_file3 = {{0}};
901 struct smb2_handle h_client2_file1 = {{0}};
902 struct smb2_handle h_client2_file2 = {{0}};
903 struct smb2_handle h_client2_file3 = {{0}};
904 struct smb2_create io1, io2, io3;
906 const char *fname1 = BASEDIR "\\lease_break_test1.dat";
907 const char *fname2 = BASEDIR "\\lease_break_test2.dat";
908 const char *fname3 = BASEDIR "\\lease_break_test3.dat";
909 struct smb2_tree *tree2A = NULL;
910 struct smb2_tree *tree2B = NULL;
911 struct smb2_tree *tree2C = NULL;
912 struct smb2_transport *transport1 = tree1->session->transport;
913 struct smbcli_options transport2_options;
914 struct smb2_session *session1 = tree1->session;
915 uint16_t local_port = 0;
916 struct smb2_lease ls1;
917 struct smb2_lease ls2;
918 struct smb2_lease ls3;
920 if (!test_multichannel_initial_checks(tctx, tree1)) {
924 torture_comment(tctx, "Lease break retry: Test1\n");
926 torture_reset_lease_break_info(tctx, &lease_break_info);
928 transport1->lease.handler = torture_lease_handler;
929 transport1->lease.private_data = tree1;
930 torture_comment(tctx, "transport1 [%p]\n", transport1);
931 local_port = torture_get_local_port_from_transport(transport1);
932 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
934 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
935 CHECK_STATUS(status, NT_STATUS_OK);
936 smb2_util_close(tree1, _h);
937 smb2_util_unlink(tree1, fname1);
938 smb2_util_unlink(tree1, fname2);
939 smb2_util_unlink(tree1, fname3);
940 CHECK_VAL(lease_break_info.count, 0);
942 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
943 smb2_util_lease_state("RHW"));
944 test_multichannel_init_smb_create(&io1);
946 smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
947 smb2_util_lease_state("RHW"));
948 test_multichannel_init_smb_create(&io2);
950 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
951 smb2_util_lease_state("RHW"));
952 test_multichannel_init_smb_create(&io3);
954 transport2_options = transport1->options;
956 ret = test_multichannel_create_channels(tctx, host, share,
959 &tree2A, &tree2B, &tree2C);
960 torture_assert(tctx, ret, "Could not create channels.\n");
963 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
964 status = smb2_create(tree2A, mem_ctx, &io1);
965 CHECK_STATUS(status, NT_STATUS_OK);
966 h_client2_file1 = io1.out.file.handle;
967 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
968 CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
969 CHECK_VAL(lease_break_info.count, 0);
972 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
973 status = smb2_create(tree2B, mem_ctx, &io2);
974 CHECK_STATUS(status, NT_STATUS_OK);
975 h_client2_file2 = io2.out.file.handle;
976 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
977 CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
978 CHECK_VAL(lease_break_info.count, 0);
981 torture_comment(tctx, "client2 opens fname3 via session 2C\n");
982 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
983 smb2_util_lease_state("RHW"));
984 status = smb2_create(tree2C, mem_ctx, &io3);
985 CHECK_STATUS(status, NT_STATUS_OK);
986 h_client2_file3 = io3.out.file.handle;
987 CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
988 CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
989 CHECK_VAL(lease_break_info.count, 0);
991 /* 1 opens file1 - lease break? */
992 torture_comment(tctx, "client1 opens fname1 via session 1\n");
993 smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
994 smb2_util_lease_state("RHW"));
995 status = smb2_create(tree1, mem_ctx, &io1);
996 CHECK_STATUS(status, NT_STATUS_OK);
997 h_client1_file1 = io1.out.file.handle;
998 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
999 CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
1000 CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
1001 CHECK_VAL(lease_break_info.count, 1);
1003 torture_reset_lease_break_info(tctx, &lease_break_info);
1005 /* 1 opens file2 - lease break? */
1006 torture_comment(tctx, "client1 opens fname2 via session 1\n");
1007 smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
1008 smb2_util_lease_state("RHW"));
1009 status = smb2_create(tree1, mem_ctx, &io2);
1010 CHECK_STATUS(status, NT_STATUS_OK);
1011 h_client1_file2 = io2.out.file.handle;
1012 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1013 CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
1014 CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
1015 CHECK_VAL(lease_break_info.count, 1);
1017 torture_reset_lease_break_info(tctx, &lease_break_info);
1019 /* 1 opens file3 - lease break? */
1020 torture_comment(tctx, "client1 opens fname3 via session 1\n");
1021 smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
1022 smb2_util_lease_state("RHW"));
1023 status = smb2_create(tree1, mem_ctx, &io3);
1024 CHECK_STATUS(status, NT_STATUS_OK);
1025 h_client1_file3 = io3.out.file.handle;
1026 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1027 CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
1028 CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
1029 CHECK_VAL(lease_break_info.count, 1);
1031 /* cleanup everything */
1032 torture_reset_lease_break_info(tctx, &lease_break_info);
1034 smb2_util_close(tree1, h_client1_file1);
1035 smb2_util_close(tree1, h_client1_file2);
1036 smb2_util_close(tree1, h_client1_file3);
1037 smb2_util_close(tree2A, h_client2_file1);
1038 smb2_util_close(tree2A, h_client2_file2);
1039 smb2_util_close(tree2A, h_client2_file3);
1041 smb2_util_unlink(tree1, fname1);
1042 smb2_util_unlink(tree1, fname2);
1043 smb2_util_unlink(tree1, fname3);
1044 CHECK_VAL(lease_break_info.count, 0);
1045 test_multichannel_free_channels(tree2A, tree2B, tree2C);
1046 tree2A = tree2B = tree2C = NULL;
1048 tree1->session = session1;
1050 smb2_util_close(tree1, h_client1_file1);
1051 smb2_util_close(tree1, h_client1_file2);
1052 smb2_util_close(tree1, h_client1_file3);
1053 if (tree2A != NULL) {
1054 smb2_util_close(tree2A, h_client2_file1);
1055 smb2_util_close(tree2A, h_client2_file2);
1056 smb2_util_close(tree2A, h_client2_file3);
1060 smb2_util_close(tree1, *h);
1063 smb2_util_unlink(tree1, fname1);
1064 smb2_util_unlink(tree1, fname2);
1065 smb2_util_unlink(tree1, fname3);
1066 smb2_deltree(tree1, BASEDIR);
1068 test_multichannel_free_channels(tree2A, tree2B, tree2C);
1070 talloc_free(mem_ctx);
1076 * Lease Break Test 2:
1077 * Test for lease break retries being sent by the server.
1079 * open file1 in session 2A
1080 * open file2 in session 2B
1082 * open file2 in session 1
1083 * lease break retry reaches the client?
1085 * open file3 in session 2C
1087 * open file1 in session 1
1088 * lease break reaches the client?
1089 * open file3 in session 1
1090 * lease break reached the client?
1092 * On deletion by 1, lease breaks sent for file1, file2 and file3
1094 * This changes RH lease to R for Session 2.
1095 * (This has been disabled while we add support for sending lease
1096 * break for handle leases.)
1098 static bool test_multichannel_lease_break_test2(struct torture_context *tctx,
1099 struct smb2_tree *tree1)
1101 const char *host = torture_setting_string(tctx, "host", NULL);
1102 const char *share = torture_setting_string(tctx, "share", NULL);
1103 struct cli_credentials *credentials = popt_get_cmdline_credentials();
1105 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1106 struct smb2_handle _h;
1107 struct smb2_handle *h = NULL;
1108 struct smb2_handle h_client1_file1 = {{0}};
1109 struct smb2_handle h_client1_file2 = {{0}};
1110 struct smb2_handle h_client1_file3 = {{0}};
1111 struct smb2_handle h_client2_file1 = {{0}};
1112 struct smb2_handle h_client2_file2 = {{0}};
1113 struct smb2_handle h_client2_file3 = {{0}};
1114 struct smb2_create io1, io2, io3;
1116 const char *fname1 = BASEDIR "\\lease_break_test1.dat";
1117 const char *fname2 = BASEDIR "\\lease_break_test2.dat";
1118 const char *fname3 = BASEDIR "\\lease_break_test3.dat";
1119 struct smb2_tree *tree2A = NULL;
1120 struct smb2_tree *tree2B = NULL;
1121 struct smb2_tree *tree2C = NULL;
1122 struct smb2_transport *transport1 = tree1->session->transport;
1123 struct smb2_transport *transport2A = NULL;
1124 struct smbcli_options transport2_options;
1125 struct smb2_session *session1 = tree1->session;
1126 uint16_t local_port = 0;
1127 struct smb2_lease ls1;
1128 struct smb2_lease ls2;
1129 struct smb2_lease ls3;
1130 bool block_ok = false;
1131 bool unblock_ok = false;
1134 if (!test_multichannel_initial_checks(tctx, tree1)) {
1138 torture_comment(tctx, "Lease break retry: Test2\n");
1140 torture_reset_lease_break_info(tctx, &lease_break_info);
1142 transport1->lease.handler = torture_lease_handler;
1143 transport1->lease.private_data = tree1;
1144 torture_comment(tctx, "transport1 [%p]\n", transport1);
1145 local_port = torture_get_local_port_from_transport(transport1);
1146 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
1148 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
1149 CHECK_STATUS(status, NT_STATUS_OK);
1150 smb2_util_close(tree1, _h);
1151 smb2_util_unlink(tree1, fname1);
1152 smb2_util_unlink(tree1, fname2);
1153 smb2_util_unlink(tree1, fname3);
1154 CHECK_VAL(lease_break_info.count, 0);
1156 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1157 smb2_util_lease_state("RHW"));
1158 test_multichannel_init_smb_create(&io1);
1160 smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
1161 smb2_util_lease_state("RHW"));
1162 test_multichannel_init_smb_create(&io2);
1164 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
1165 smb2_util_lease_state("RHW"));
1166 test_multichannel_init_smb_create(&io3);
1168 transport2_options = transport1->options;
1170 ret = test_multichannel_create_channels(tctx, host, share,
1172 &transport2_options,
1173 &tree2A, &tree2B, NULL);
1174 torture_assert(tctx, ret, "Could not create channels.\n");
1175 transport2A = tree2A->session->transport;
1177 /* 2a opens file1 */
1178 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
1179 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1180 smb2_util_lease_state("RHW"));
1181 status = smb2_create(tree2A, mem_ctx, &io1);
1182 CHECK_STATUS(status, NT_STATUS_OK);
1183 h_client2_file1 = io1.out.file.handle;
1184 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1185 CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
1186 CHECK_VAL(io1.out.durable_open_v2, false); //true);
1187 CHECK_VAL(io1.out.timeout, io1.in.timeout);
1188 CHECK_VAL(io1.out.durable_open, false);
1189 CHECK_VAL(lease_break_info.count, 0);
1191 /* 2b opens file2 */
1192 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
1193 smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
1194 smb2_util_lease_state("RHW"));
1195 status = smb2_create(tree2B, mem_ctx, &io2);
1196 CHECK_STATUS(status, NT_STATUS_OK);
1197 h_client2_file2 = io2.out.file.handle;
1198 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1199 CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
1200 CHECK_VAL(io2.out.durable_open_v2, false); //true);
1201 CHECK_VAL(io2.out.timeout, io2.in.timeout);
1202 CHECK_VAL(io2.out.durable_open, false);
1203 CHECK_VAL(lease_break_info.count, 0);
1206 torture_comment(tctx, "Blocking 2A\n");
1208 block_ok = test_block_channel(tctx, transport2A);
1209 torture_assert(tctx, block_ok, "we could not block tcp transport");
1212 torture_comment(tctx,
1213 "Client opens fname2 with session1 with 2A blocked\n");
1214 smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
1215 smb2_util_lease_state("RHW"));
1216 status = smb2_create(tree1, mem_ctx, &io2);
1217 CHECK_STATUS(status, NT_STATUS_OK);
1218 h_client1_file2 = io2.out.file.handle;
1219 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1220 CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
1221 CHECK_VAL(io2.out.durable_open_v2, false);
1222 CHECK_VAL(io2.out.timeout, 0);
1223 CHECK_VAL(io2.out.durable_open, false);
1225 if (lease_break_info.count == 0) {
1226 torture_comment(tctx,
1227 "Did not receive expected lease break!!\n");
1229 torture_comment(tctx, "Received %d lease break(s)!!\n",
1230 lease_break_info.count);
1233 CHECK_VAL(lease_break_info.count, 1);
1234 CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
1235 torture_reset_lease_break_info(tctx, &lease_break_info);
1238 torture_comment(tctx, "Connecting session 2C\n");
1239 talloc_free(tree2C);
1240 tree2C = test_multichannel_create_channel(tctx, host, share,
1241 credentials, &transport2_options, tree2A);
1246 /* 2c opens file3 */
1247 torture_comment(tctx, "client2 opens fname3 via session 2C\n");
1248 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
1249 smb2_util_lease_state("RHW"));
1250 status = smb2_create(tree2C, mem_ctx, &io3);
1251 CHECK_STATUS(status, NT_STATUS_OK);
1252 h_client2_file3 = io3.out.file.handle;
1253 CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1254 CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
1255 CHECK_VAL(io3.out.durable_open_v2, false);
1256 CHECK_VAL(io3.out.timeout, io2.in.timeout);
1257 CHECK_VAL(io3.out.durable_open, false);
1258 CHECK_VAL(lease_break_info.count, 0);
1261 torture_comment(tctx, "Unblocking 2A\n");
1262 unblock_ok = test_unblock_channel(tctx, transport2A);
1263 torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
1266 torture_comment(tctx, "Client opens fname1 with session 1\n");
1267 smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
1268 smb2_util_lease_state("RHW"));
1269 status = smb2_create(tree1, mem_ctx, &io1);
1270 CHECK_STATUS(status, NT_STATUS_OK);
1271 h_client1_file1 = io1.out.file.handle;
1272 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1273 CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
1275 if (lease_break_info.count == 0) {
1276 torture_comment(tctx,
1277 "Did not receive expected lease break!!\n");
1279 torture_comment(tctx,
1280 "Received %d lease break(s)!!\n",
1281 lease_break_info.count);
1283 CHECK_VAL(lease_break_info.count, 1);
1284 CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
1285 torture_reset_lease_break_info(tctx, &lease_break_info);
1288 torture_comment(tctx, "client opens fname3 via session 1\n");
1290 smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
1291 smb2_util_lease_state("RHW"));
1292 status = smb2_create(tree1, mem_ctx, &io3);
1293 CHECK_STATUS(status, NT_STATUS_OK);
1294 h_client1_file3 = io3.out.file.handle;
1295 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1296 CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
1298 if (lease_break_info.count == 0) {
1299 torture_comment(tctx,
1300 "Did not receive expected lease break!!\n");
1302 torture_comment(tctx,
1303 "Received %d lease break(s)!!\n",
1304 lease_break_info.count);
1306 CHECK_VAL(lease_break_info.count, 1);
1307 CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
1308 torture_reset_lease_break_info(tctx, &lease_break_info);
1310 smb2_util_close(tree1, h_client1_file1);
1311 smb2_util_close(tree1, h_client1_file2);
1312 smb2_util_close(tree1, h_client1_file3);
1315 * Session 2 still has RW lease on file 1. Deletion of this file by 1
1316 * leads to a lease break call to session 2 file1
1318 smb2_util_unlink(tree1, fname1);
1320 * Bug - Samba does not revoke Handle lease on unlink
1321 * CHECK_BREAK_INFO("RH", "R", LEASE2F1);
1323 torture_reset_lease_break_info(tctx, &lease_break_info);
1326 * Session 2 still has RW lease on file 2. Deletion of this file by 1
1327 * leads to a lease break call to session 2 file2
1329 smb2_util_unlink(tree1, fname2);
1331 * Bug - Samba does not revoke Handle lease on unlink
1332 * CHECK_BREAK_INFO("RH", "R", LEASE2F2);
1334 torture_reset_lease_break_info(tctx, &lease_break_info);
1337 * Session 2 still has RW lease on file 3. Deletion of this file by 1
1338 * leads to a lease break call to session 2 file3
1340 smb2_util_unlink(tree1, fname3);
1342 * Bug - Samba does not revoke Handle lease on unlink
1343 * CHECK_BREAK_INFO("RH", "R", LEASE2F3);
1345 torture_reset_lease_break_info(tctx, &lease_break_info);
1347 smb2_util_close(tree2C, h_client2_file1);
1348 smb2_util_close(tree2C, h_client2_file2);
1349 smb2_util_close(tree2C, h_client2_file3);
1351 test_multichannel_free_channels(tree2A, tree2B, tree2C);
1352 tree2A = tree2B = tree2C = NULL;
1355 if (block_ok && !unblock_ok) {
1356 test_unblock_channel(tctx, transport2A);
1358 test_cleanup_blocked_channels(tctx);
1360 tree1->session = session1;
1362 smb2_util_close(tree1, h_client1_file1);
1363 smb2_util_close(tree1, h_client1_file2);
1364 smb2_util_close(tree1, h_client1_file3);
1365 if (tree2A != NULL) {
1366 smb2_util_close(tree2A, h_client2_file1);
1367 smb2_util_close(tree2A, h_client2_file2);
1368 smb2_util_close(tree2A, h_client2_file3);
1372 smb2_util_close(tree1, *h);
1375 smb2_util_unlink(tree1, fname1);
1376 smb2_util_unlink(tree1, fname2);
1377 smb2_util_unlink(tree1, fname3);
1378 smb2_deltree(tree1, BASEDIR);
1380 test_multichannel_free_channels(tree2A, tree2B, tree2C);
1382 talloc_free(mem_ctx);
1387 struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
1389 struct torture_suite *suite = torture_suite_create(ctx, "multichannel");
1390 struct torture_suite *suite_generic = torture_suite_create(ctx,
1392 struct torture_suite *suite_oplocks = torture_suite_create(ctx,
1394 struct torture_suite *suite_leases = torture_suite_create(ctx,
1397 torture_suite_add_suite(suite, suite_generic);
1398 torture_suite_add_suite(suite, suite_oplocks);
1399 torture_suite_add_suite(suite, suite_leases);
1401 torture_suite_add_1smb2_test(suite, "interface_info",
1402 test_multichannel_interface_info);
1403 torture_suite_add_1smb2_test(suite_oplocks, "test1",
1404 test_multichannel_oplock_break_test1);
1405 torture_suite_add_1smb2_test(suite_oplocks, "test2",
1406 test_multichannel_oplock_break_test2);
1407 torture_suite_add_1smb2_test(suite_leases, "test1",
1408 test_multichannel_lease_break_test1);
1409 torture_suite_add_1smb2_test(suite_leases, "test2",
1410 test_multichannel_lease_break_test2);
1412 suite->description = talloc_strdup(suite, "SMB2 Multichannel tests");