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 const struct smbcli_options *_transport_options,
172 struct smb2_tree *parent_tree
175 struct smbcli_options transport_options = *_transport_options;
177 struct smb2_transport *transport;
178 struct smb2_session *session;
180 struct smb2_tree *tree;
183 transport_options.only_negprot = true;
186 status = smb2_connect(tctx,
188 lpcfg_smb_ports(tctx->lp_ctx),
190 lpcfg_resolve_context(tctx->lp_ctx),
195 lpcfg_socket_options(tctx->lp_ctx),
196 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
198 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
199 "smb2_connect failed");
200 transport = tree->session->transport;
201 transport->oplock.handler = torture_oplock_ack_handler;
202 transport->oplock.private_data = tree;
203 transport->lease.handler = torture_lease_handler;
204 transport->lease.private_data = tree;
205 torture_comment(tctx, "established transport [%p]\n", transport);
208 * If parent tree is set, bind the session to the parent transport
211 session = smb2_session_channel(transport,
212 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
213 parent_tree, parent_tree->session);
214 torture_assert_goto(tctx, session != NULL, ret, done,
215 "smb2_session_channel failed");
217 tree->smbXcli = parent_tree->smbXcli;
218 tree->session = session;
219 status = smb2_session_setup_spnego(session,
221 0 /* previous_session_id */);
222 CHECK_STATUS(status, NT_STATUS_OK);
223 torture_comment(tctx, "bound new session to parent\n");
226 * We absolutely need to make sure to send something over this
227 * connection to register the oplock break handler with the smb client
228 * connection. If we do not send something (at least a keepalive), we
229 * will *NEVER* receive anything over this transport.
231 smb2_keepalive(transport);
241 bool test_multichannel_create_channel_array(
242 struct torture_context *tctx,
245 struct cli_credentials *credentials,
246 struct smbcli_options *transport_options,
248 struct smb2_tree **trees)
252 transport_options->client_guid = GUID_random();
254 for (i = 0; i < num_trees; i++) {
255 struct smb2_tree *parent_tree = NULL;
256 struct smb2_tree *tree = NULL;
257 struct smb2_transport *transport = NULL;
258 uint16_t local_port = 0;
261 parent_tree = trees[0];
264 torture_comment(tctx, "Setting up connection %d\n", i);
265 tree = test_multichannel_create_channel(tctx, host, share,
266 credentials, transport_options,
268 torture_assert(tctx, tree, "failed to created new channel");
271 transport = tree->session->transport;
272 local_port = torture_get_local_port_from_transport(transport);
273 torture_comment(tctx, "transport[%d] uses tcp port: %d\n",
280 bool test_multichannel_create_channels(
281 struct torture_context *tctx,
284 struct cli_credentials *credentials,
285 struct smbcli_options *transport_options,
286 struct smb2_tree **tree2A,
287 struct smb2_tree **tree2B,
288 struct smb2_tree **tree2C
291 struct smb2_tree **trees = NULL;
292 size_t num_trees = 0;
295 torture_assert(tctx, tree2A, "tree2A required!");
297 torture_assert(tctx, tree2B, "tree2B required!");
299 if (tree2C != NULL) {
302 trees = talloc_zero_array(tctx, struct smb2_tree *, num_trees);
303 torture_assert(tctx, trees, "out of memory");
305 ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
314 if (tree2C != NULL) {
321 static void test_multichannel_free_channels(struct smb2_tree *tree2A,
322 struct smb2_tree *tree2B,
323 struct smb2_tree *tree2C)
330 static bool test_multichannel_initial_checks(struct torture_context *tctx,
331 struct smb2_tree *tree1)
333 struct smb2_transport *transport1 = tree1->session->transport;
334 uint32_t server_capabilities;
335 struct fsctl_net_iface_info info;
337 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
338 torture_skip_goto(tctx, fail,
339 "SMB 3.X Dialect family required for "
340 "Multichannel tests\n");
343 server_capabilities = smb2cli_conn_server_capabilities(
344 tree1->session->transport->conn);
345 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
346 torture_skip_goto(tctx, fail,
347 "Server does not support multichannel.");
351 test_ioctl_network_interface_info(tctx, tree1, &info),
352 "failed to retrieve network interface info");
359 static void test_multichannel_init_smb_create(struct smb2_create *io)
361 io->in.durable_open = false;
362 io->in.durable_open_v2 = true;
363 io->in.persistent_open = false;
364 io->in.create_guid = GUID_random();
365 io->in.timeout = 0x493E0; /* 300000 */
366 /* windows 2016 returns 300000 0x493E0 */
369 /* Timer handler function notifies the registering function that time is up */
370 static void timeout_cb(struct tevent_context *ev,
371 struct tevent_timer *te,
372 struct timeval current_time,
375 bool *timesup = (bool *)private_data;
380 * Oplock break - Test 1
381 * Test to confirm that server sends oplock breaks as expected.
382 * open file1 in session 2A
383 * open file2 in session 2B
384 * open file1 in session 1
385 * oplock break received
386 * open file1 in session 1
387 * oplock break received
390 static bool test_multichannel_oplock_break_test1(struct torture_context *tctx,
391 struct smb2_tree *tree1)
393 const char *host = torture_setting_string(tctx, "host", NULL);
394 const char *share = torture_setting_string(tctx, "share", NULL);
395 struct cli_credentials *credentials = popt_get_cmdline_credentials();
397 TALLOC_CTX *mem_ctx = talloc_new(tctx);
398 struct smb2_handle _h;
399 struct smb2_handle h_client1_file1 = {{0}};
400 struct smb2_handle h_client1_file2 = {{0}};
401 struct smb2_handle h_client1_file3 = {{0}};
402 struct smb2_handle h_client2_file1 = {{0}};
403 struct smb2_handle h_client2_file2 = {{0}};
404 struct smb2_handle h_client2_file3 = {{0}};
405 struct smb2_create io1, io2, io3;
407 const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
408 const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
409 const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
410 struct smb2_tree *tree2A = NULL;
411 struct smb2_tree *tree2B = NULL;
412 struct smb2_tree *tree2C = NULL;
413 struct smb2_transport *transport1 = tree1->session->transport;
414 struct smbcli_options transport2_options;
415 struct smb2_session *session1 = tree1->session;
416 uint16_t local_port = 0;
418 if (!test_multichannel_initial_checks(tctx, tree1)) {
422 torture_comment(tctx, "Oplock break retry: Test1\n");
424 torture_reset_break_info(tctx, &break_info);
426 transport1->oplock.handler = torture_oplock_ack_handler;
427 transport1->oplock.private_data = tree1;
428 torture_comment(tctx, "transport1 [%p]\n", transport1);
429 local_port = torture_get_local_port_from_transport(transport1);
430 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
432 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
433 CHECK_STATUS(status, NT_STATUS_OK);
434 smb2_util_close(tree1, _h);
435 smb2_util_unlink(tree1, fname1);
436 smb2_util_unlink(tree1, fname2);
437 smb2_util_unlink(tree1, fname3);
438 CHECK_VAL(break_info.count, 0);
440 smb2_oplock_create_share(&io1, fname1,
441 smb2_util_share_access("RWD"),
442 smb2_util_oplock_level("b"));
443 test_multichannel_init_smb_create(&io1);
445 smb2_oplock_create_share(&io2, fname2,
446 smb2_util_share_access("RWD"),
447 smb2_util_oplock_level("b"));
448 test_multichannel_init_smb_create(&io2);
450 smb2_oplock_create_share(&io3, fname3,
451 smb2_util_share_access("RWD"),
452 smb2_util_oplock_level("b"));
453 test_multichannel_init_smb_create(&io3);
455 transport2_options = transport1->options;
457 ret = test_multichannel_create_channels(tctx, host, share,
460 &tree2A, &tree2B, NULL);
461 torture_assert(tctx, ret, "Could not create channels.\n");
464 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
465 status = smb2_create(tree2A, mem_ctx, &io1);
466 CHECK_STATUS(status, NT_STATUS_OK);
467 h_client2_file1 = io1.out.file.handle;
468 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
469 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
470 torture_wait_for_oplock_break(tctx);
471 CHECK_VAL(break_info.count, 0);
474 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
475 status = smb2_create(tree2B, mem_ctx, &io2);
476 CHECK_STATUS(status, NT_STATUS_OK);
477 h_client2_file2 = io2.out.file.handle;
478 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
479 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
480 torture_wait_for_oplock_break(tctx);
481 CHECK_VAL(break_info.count, 0);
484 /* 1 opens file1 - batchoplock break? */
485 torture_comment(tctx, "client1 opens fname1 via session 1\n");
486 io1.in.oplock_level = smb2_util_oplock_level("b");
487 status = smb2_create(tree1, mem_ctx, &io1);
488 CHECK_STATUS(status, NT_STATUS_OK);
489 h_client1_file1 = io1.out.file.handle;
490 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
491 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
492 torture_wait_for_oplock_break(tctx);
493 CHECK_VAL(break_info.count, 1);
495 torture_reset_break_info(tctx, &break_info);
497 /* 1 opens file2 - batchoplock break? */
498 torture_comment(tctx, "client1 opens fname2 via session 1\n");
499 io2.in.oplock_level = smb2_util_oplock_level("b");
500 status = smb2_create(tree1, mem_ctx, &io2);
501 CHECK_STATUS(status, NT_STATUS_OK);
502 h_client1_file2 = io2.out.file.handle;
503 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
504 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
505 torture_wait_for_oplock_break(tctx);
506 CHECK_VAL(break_info.count, 1);
508 /* cleanup everything */
509 torture_reset_break_info(tctx, &break_info);
511 smb2_util_close(tree1, h_client1_file1);
512 smb2_util_close(tree1, h_client1_file2);
513 smb2_util_close(tree1, h_client1_file3);
514 smb2_util_close(tree2A, h_client2_file1);
515 smb2_util_close(tree2A, h_client2_file2);
516 smb2_util_close(tree2A, h_client2_file3);
518 smb2_util_unlink(tree1, fname1);
519 smb2_util_unlink(tree1, fname2);
520 smb2_util_unlink(tree1, fname3);
521 CHECK_VAL(break_info.count, 0);
522 test_multichannel_free_channels(tree2A, tree2B, tree2C);
523 tree2A = tree2B = tree2C = NULL;
525 tree1->session = session1;
527 smb2_util_close(tree1, h_client1_file1);
528 smb2_util_close(tree1, h_client1_file2);
529 smb2_util_close(tree1, h_client1_file3);
530 if (tree2A != NULL) {
531 smb2_util_close(tree2A, h_client2_file1);
532 smb2_util_close(tree2A, h_client2_file2);
533 smb2_util_close(tree2A, h_client2_file3);
536 smb2_util_unlink(tree1, fname1);
537 smb2_util_unlink(tree1, fname2);
538 smb2_util_unlink(tree1, fname3);
539 smb2_deltree(tree1, BASEDIR);
541 test_multichannel_free_channels(tree2A, tree2B, tree2C);
543 talloc_free(mem_ctx);
549 * Oplock Break Test 2
550 * Test to see if oplock break retries are sent by the server.
551 * Also checks to see if new channels can be created and used
552 * after an oplock break retry.
555 * open file1 in session 1
556 * oplock break received
557 * block channel on which oplock break received
558 * open file2 in session 1
559 * oplock break not received. Retry received.
561 * write to file2 on 2B
562 * Break sent to session 1(which has file2 open)
563 * Break sent to session 2A(which has read oplock)
564 * close file1 in session 1
565 * open file1 with session 1
566 * unblock blocked channel
567 * disconnect blocked channel
570 * open file3 in session 1
573 static bool test_multichannel_oplock_break_test2(struct torture_context *tctx,
574 struct smb2_tree *tree1)
576 const char *host = torture_setting_string(tctx, "host", NULL);
577 const char *share = torture_setting_string(tctx, "share", NULL);
578 struct cli_credentials *credentials = popt_get_cmdline_credentials();
580 TALLOC_CTX *mem_ctx = talloc_new(tctx);
581 struct smb2_handle _h;
582 struct smb2_handle h_client1_file1 = {{0}};
583 struct smb2_handle h_client1_file2 = {{0}};
584 struct smb2_handle h_client1_file3 = {{0}};
585 struct smb2_handle h_client2_file1 = {{0}};
586 struct smb2_handle h_client2_file2 = {{0}};
587 struct smb2_handle h_client2_file3 = {{0}};
588 struct smb2_create io1, io2, io3;
590 const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
591 const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
592 const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
593 struct smb2_tree *tree2A = NULL;
594 struct smb2_tree *tree2B = NULL;
595 struct smb2_tree *tree2C = NULL;
596 struct smb2_tree *tree2D = NULL;
597 struct smb2_transport *transport1 = tree1->session->transport;
598 struct smb2_transport *transport2 = NULL;
599 struct smbcli_options transport2_options;
600 struct smb2_session *session1 = tree1->session;
601 uint16_t local_port = 0;
603 bool block_setup = false;
604 bool block_ok = false;
605 bool unblock_ok = false;
607 if (!test_multichannel_initial_checks(tctx, tree1)) {
611 torture_comment(tctx, "Oplock break retry: Test2\n");
613 torture_reset_break_info(tctx, &break_info);
615 transport1->oplock.handler = torture_oplock_ack_handler;
616 transport1->oplock.private_data = tree1;
617 torture_comment(tctx, "transport1 [%p]\n", transport1);
618 local_port = torture_get_local_port_from_transport(transport1);
619 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
621 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
622 CHECK_STATUS(status, NT_STATUS_OK);
623 smb2_util_close(tree1, _h);
624 smb2_util_unlink(tree1, fname1);
625 smb2_util_unlink(tree1, fname2);
626 smb2_util_unlink(tree1, fname3);
627 CHECK_VAL(break_info.count, 0);
629 smb2_oplock_create_share(&io1, fname1,
630 smb2_util_share_access("RWD"),
631 smb2_util_oplock_level("b"));
632 test_multichannel_init_smb_create(&io1);
634 smb2_oplock_create_share(&io2, fname2,
635 smb2_util_share_access("RWD"),
636 smb2_util_oplock_level("b"));
637 test_multichannel_init_smb_create(&io2);
639 smb2_oplock_create_share(&io3, fname3,
640 smb2_util_share_access("RWD"),
641 smb2_util_oplock_level("b"));
642 test_multichannel_init_smb_create(&io3);
644 transport2_options = transport1->options;
646 ret = test_multichannel_create_channels(tctx, host, share,
649 &tree2A, &tree2B, &tree2C);
650 torture_assert(tctx, ret, "Could not create channels.\n");
652 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
653 io1.in.oplock_level = smb2_util_oplock_level("b");
654 status = smb2_create(tree2A, mem_ctx, &io1);
655 CHECK_STATUS(status, NT_STATUS_OK);
656 h_client2_file1 = io1.out.file.handle;
657 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
658 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
659 torture_wait_for_oplock_break(tctx);
660 CHECK_VAL(break_info.count, 0);
663 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
664 io2.in.oplock_level = smb2_util_oplock_level("b");
665 status = smb2_create(tree2B, mem_ctx, &io2);
666 CHECK_STATUS(status, NT_STATUS_OK);
667 h_client2_file2 = io2.out.file.handle;
668 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
669 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
670 torture_wait_for_oplock_break(tctx);
671 CHECK_VAL(break_info.count, 0);
674 torture_comment(tctx, "client1 opens fname1 via session 1\n");
675 io1.in.oplock_level = smb2_util_oplock_level("b");
676 status = smb2_create(tree1, mem_ctx, &io1);
677 CHECK_STATUS(status, NT_STATUS_OK);
678 h_client1_file1 = io1.out.file.handle;
679 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
680 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
681 torture_wait_for_oplock_break(tctx);
682 CHECK_VAL(break_info.count, 1);
684 /* We use the transport over which this oplock break was received */
685 transport2 = break_info.received_transport;
686 torture_reset_break_info(tctx, &break_info);
688 block_setup = test_setup_blocked_transports(tctx);
689 torture_assert(tctx, block_setup, "test_setup_blocked_transports");
692 block_ok = test_block_smb2_transport(tctx, transport2);
694 torture_comment(tctx, "client1 opens fname2 via session 1\n");
695 io2.in.oplock_level = smb2_util_oplock_level("b");
696 status = smb2_create(tree1, mem_ctx, &io2);
697 CHECK_STATUS(status, NT_STATUS_OK);
698 h_client1_file2 = io2.out.file.handle;
699 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
700 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
703 * Samba downgrades oplock to a level 2 oplock.
704 * Windows 2016 revokes oplock
706 torture_wait_for_oplock_break(tctx);
707 CHECK_VAL(break_info.count, 1);
708 torture_reset_break_info(tctx, &break_info);
710 torture_comment(tctx, "Trying write to file2 on tree2B\n");
712 blob = data_blob_string_const("Here I am");
713 status = smb2_util_write(tree2B,
718 torture_assert_ntstatus_ok(tctx, status,
719 "failed to write file2 via channel 2B");
722 * Samba: Write triggers 2 oplock breaks
723 * for session 1 which has file2 open
724 * for session 2 which has type 2 oplock
725 * Windows 2016: Only one oplock break for session 1
727 torture_wait_for_oplock_break(tctx);
728 CHECK_VAL_GREATER_THAN(break_info.count, 0);
729 torture_reset_break_info(tctx, &break_info);
731 torture_comment(tctx, "client1 closes fname2 via session 1\n");
732 smb2_util_close(tree1, h_client1_file2);
734 torture_comment(tctx, "client1 opens fname2 via session 1 again\n");
735 io2.in.oplock_level = smb2_util_oplock_level("b");
736 status = smb2_create(tree1, mem_ctx, &io2);
737 CHECK_STATUS(status, NT_STATUS_OK);
738 h_client1_file2 = io2.out.file.handle;
739 io2.out.alloc_size = 0;
741 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
742 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
745 * now add a fourth channel and repeat the test, we need to reestablish
746 * transport2 because the remote end has invalidated our connection
748 torture_comment(tctx, "Connecting session 2D\n");
749 tree2D = test_multichannel_create_channel(tctx, host, share,
750 credentials, &transport2_options, tree2B);
755 torture_reset_break_info(tctx, &break_info);
756 torture_comment(tctx, "client 2 opening fname3 over transport2D\n");
757 status = smb2_create(tree2D, mem_ctx, &io3);
758 CHECK_STATUS(status, NT_STATUS_OK);
759 h_client2_file3 = io3.out.file.handle;
760 CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
761 CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("b"));
762 torture_wait_for_oplock_break(tctx);
763 CHECK_VAL(break_info.count, 0);
765 torture_comment(tctx, "client1 opens fname3 via session 1\n");
766 status = smb2_create(tree1, mem_ctx, &io3);
767 CHECK_STATUS(status, NT_STATUS_OK);
768 h_client1_file3 = io3.out.file.handle;
769 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
770 CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
771 torture_wait_for_oplock_break(tctx);
772 CHECK_VAL(break_info.count, 1);
775 if (block_ok && !unblock_ok) {
776 test_unblock_smb2_transport(tctx, transport2);
778 test_cleanup_blocked_transports(tctx);
780 tree1->session = session1;
782 smb2_util_close(tree1, h_client1_file1);
783 smb2_util_close(tree1, h_client1_file2);
784 smb2_util_close(tree1, h_client1_file3);
785 if (tree2B != NULL) {
786 smb2_util_close(tree2B, h_client2_file1);
787 smb2_util_close(tree2B, h_client2_file2);
788 smb2_util_close(tree2B, h_client2_file3);
791 smb2_util_unlink(tree1, fname1);
792 smb2_util_unlink(tree1, fname2);
793 smb2_util_unlink(tree1, fname3);
794 smb2_deltree(tree1, BASEDIR);
796 test_multichannel_free_channels(tree2A, tree2B, tree2C);
797 if (tree2D != NULL) {
801 talloc_free(mem_ctx);
806 static const uint64_t LEASE1F1 = 0xBADC0FFEE0DDF00Dull;
807 static const uint64_t LEASE1F2 = 0xBADC0FFEE0DDD00Dull;
808 static const uint64_t LEASE1F3 = 0xDADC0FFEE0DDD00Dull;
809 static const uint64_t LEASE2F1 = 0xDEADBEEFFEEDBEADull;
810 static const uint64_t LEASE2F2 = 0xDAD0FFEDD00DF00Dull;
811 static const uint64_t LEASE2F3 = 0xBAD0FFEDD00DF00Dull;
814 * Lease Break Test 1:
815 * Test to check if lease breaks are sent by the server as expected.
816 * open file1 in session 2A
817 * open file2 in session 2B
818 * open file3 in session 2C
819 * open file1 in session 1
821 * open file2 in session 1
823 * open file3 in session 1
826 static bool test_multichannel_lease_break_test1(struct torture_context *tctx,
827 struct smb2_tree *tree1)
829 const char *host = torture_setting_string(tctx, "host", NULL);
830 const char *share = torture_setting_string(tctx, "share", NULL);
831 struct cli_credentials *credentials = popt_get_cmdline_credentials();
833 TALLOC_CTX *mem_ctx = talloc_new(tctx);
834 struct smb2_handle _h;
835 struct smb2_handle *h = NULL;
836 struct smb2_handle h_client1_file1 = {{0}};
837 struct smb2_handle h_client1_file2 = {{0}};
838 struct smb2_handle h_client1_file3 = {{0}};
839 struct smb2_handle h_client2_file1 = {{0}};
840 struct smb2_handle h_client2_file2 = {{0}};
841 struct smb2_handle h_client2_file3 = {{0}};
842 struct smb2_create io1, io2, io3;
844 const char *fname1 = BASEDIR "\\lease_break_test1.dat";
845 const char *fname2 = BASEDIR "\\lease_break_test2.dat";
846 const char *fname3 = BASEDIR "\\lease_break_test3.dat";
847 struct smb2_tree *tree2A = NULL;
848 struct smb2_tree *tree2B = NULL;
849 struct smb2_tree *tree2C = NULL;
850 struct smb2_transport *transport1 = tree1->session->transport;
851 struct smbcli_options transport2_options;
852 struct smb2_session *session1 = tree1->session;
853 uint16_t local_port = 0;
854 struct smb2_lease ls1;
855 struct smb2_lease ls2;
856 struct smb2_lease ls3;
858 if (!test_multichannel_initial_checks(tctx, tree1)) {
862 torture_comment(tctx, "Lease break retry: Test1\n");
864 torture_reset_lease_break_info(tctx, &lease_break_info);
866 transport1->lease.handler = torture_lease_handler;
867 transport1->lease.private_data = tree1;
868 torture_comment(tctx, "transport1 [%p]\n", transport1);
869 local_port = torture_get_local_port_from_transport(transport1);
870 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
872 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
873 CHECK_STATUS(status, NT_STATUS_OK);
874 smb2_util_close(tree1, _h);
875 smb2_util_unlink(tree1, fname1);
876 smb2_util_unlink(tree1, fname2);
877 smb2_util_unlink(tree1, fname3);
878 CHECK_VAL(lease_break_info.count, 0);
880 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
881 smb2_util_lease_state("RHW"));
882 test_multichannel_init_smb_create(&io1);
884 smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
885 smb2_util_lease_state("RHW"));
886 test_multichannel_init_smb_create(&io2);
888 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
889 smb2_util_lease_state("RHW"));
890 test_multichannel_init_smb_create(&io3);
892 transport2_options = transport1->options;
894 ret = test_multichannel_create_channels(tctx, host, share,
897 &tree2A, &tree2B, &tree2C);
898 torture_assert(tctx, ret, "Could not create channels.\n");
901 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
902 status = smb2_create(tree2A, mem_ctx, &io1);
903 CHECK_STATUS(status, NT_STATUS_OK);
904 h_client2_file1 = io1.out.file.handle;
905 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
906 CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
907 CHECK_VAL(lease_break_info.count, 0);
910 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
911 status = smb2_create(tree2B, mem_ctx, &io2);
912 CHECK_STATUS(status, NT_STATUS_OK);
913 h_client2_file2 = io2.out.file.handle;
914 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
915 CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
916 CHECK_VAL(lease_break_info.count, 0);
919 torture_comment(tctx, "client2 opens fname3 via session 2C\n");
920 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
921 smb2_util_lease_state("RHW"));
922 status = smb2_create(tree2C, mem_ctx, &io3);
923 CHECK_STATUS(status, NT_STATUS_OK);
924 h_client2_file3 = io3.out.file.handle;
925 CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
926 CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
927 CHECK_VAL(lease_break_info.count, 0);
929 /* 1 opens file1 - lease break? */
930 torture_comment(tctx, "client1 opens fname1 via session 1\n");
931 smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
932 smb2_util_lease_state("RHW"));
933 status = smb2_create(tree1, mem_ctx, &io1);
934 CHECK_STATUS(status, NT_STATUS_OK);
935 h_client1_file1 = io1.out.file.handle;
936 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
937 CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
938 CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
939 CHECK_VAL(lease_break_info.count, 1);
941 torture_reset_lease_break_info(tctx, &lease_break_info);
943 /* 1 opens file2 - lease break? */
944 torture_comment(tctx, "client1 opens fname2 via session 1\n");
945 smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
946 smb2_util_lease_state("RHW"));
947 status = smb2_create(tree1, mem_ctx, &io2);
948 CHECK_STATUS(status, NT_STATUS_OK);
949 h_client1_file2 = io2.out.file.handle;
950 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
951 CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
952 CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
953 CHECK_VAL(lease_break_info.count, 1);
955 torture_reset_lease_break_info(tctx, &lease_break_info);
957 /* 1 opens file3 - lease break? */
958 torture_comment(tctx, "client1 opens fname3 via session 1\n");
959 smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
960 smb2_util_lease_state("RHW"));
961 status = smb2_create(tree1, mem_ctx, &io3);
962 CHECK_STATUS(status, NT_STATUS_OK);
963 h_client1_file3 = io3.out.file.handle;
964 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
965 CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
966 CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
967 CHECK_VAL(lease_break_info.count, 1);
969 /* cleanup everything */
970 torture_reset_lease_break_info(tctx, &lease_break_info);
972 smb2_util_close(tree1, h_client1_file1);
973 smb2_util_close(tree1, h_client1_file2);
974 smb2_util_close(tree1, h_client1_file3);
975 smb2_util_close(tree2A, h_client2_file1);
976 smb2_util_close(tree2A, h_client2_file2);
977 smb2_util_close(tree2A, h_client2_file3);
979 smb2_util_unlink(tree1, fname1);
980 smb2_util_unlink(tree1, fname2);
981 smb2_util_unlink(tree1, fname3);
982 CHECK_VAL(lease_break_info.count, 0);
983 test_multichannel_free_channels(tree2A, tree2B, tree2C);
984 tree2A = tree2B = tree2C = NULL;
986 tree1->session = session1;
988 smb2_util_close(tree1, h_client1_file1);
989 smb2_util_close(tree1, h_client1_file2);
990 smb2_util_close(tree1, h_client1_file3);
991 if (tree2A != NULL) {
992 smb2_util_close(tree2A, h_client2_file1);
993 smb2_util_close(tree2A, h_client2_file2);
994 smb2_util_close(tree2A, h_client2_file3);
998 smb2_util_close(tree1, *h);
1001 smb2_util_unlink(tree1, fname1);
1002 smb2_util_unlink(tree1, fname2);
1003 smb2_util_unlink(tree1, fname3);
1004 smb2_deltree(tree1, BASEDIR);
1006 test_multichannel_free_channels(tree2A, tree2B, tree2C);
1008 talloc_free(mem_ctx);
1014 * Lease Break Test 2:
1015 * Test for lease break retries being sent by the server.
1017 * open file1 in session 2A
1018 * open file2 in session 2B
1020 * open file2 in session 1
1021 * lease break retry reaches the client?
1023 * open file3 in session 2C
1025 * open file1 in session 1
1026 * lease break reaches the client?
1027 * open file3 in session 1
1028 * lease break reached the client?
1030 * On deletion by 1, lease breaks sent for file1, file2 and file3
1032 * This changes RH lease to R for Session 2.
1033 * (This has been disabled while we add support for sending lease
1034 * break for handle leases.)
1036 static bool test_multichannel_lease_break_test2(struct torture_context *tctx,
1037 struct smb2_tree *tree1)
1039 const char *host = torture_setting_string(tctx, "host", NULL);
1040 const char *share = torture_setting_string(tctx, "share", NULL);
1041 struct cli_credentials *credentials = popt_get_cmdline_credentials();
1043 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1044 struct smb2_handle _h;
1045 struct smb2_handle *h = NULL;
1046 struct smb2_handle h_client1_file1 = {{0}};
1047 struct smb2_handle h_client1_file2 = {{0}};
1048 struct smb2_handle h_client1_file3 = {{0}};
1049 struct smb2_handle h_client2_file1 = {{0}};
1050 struct smb2_handle h_client2_file2 = {{0}};
1051 struct smb2_handle h_client2_file3 = {{0}};
1052 struct smb2_create io1, io2, io3;
1054 const char *fname1 = BASEDIR "\\lease_break_test1.dat";
1055 const char *fname2 = BASEDIR "\\lease_break_test2.dat";
1056 const char *fname3 = BASEDIR "\\lease_break_test3.dat";
1057 struct smb2_tree *tree2A = NULL;
1058 struct smb2_tree *tree2B = NULL;
1059 struct smb2_tree *tree2C = NULL;
1060 struct smb2_transport *transport1 = tree1->session->transport;
1061 struct smb2_transport *transport2A = NULL;
1062 struct smbcli_options transport2_options;
1063 struct smb2_session *session1 = tree1->session;
1064 uint16_t local_port = 0;
1065 struct smb2_lease ls1;
1066 struct smb2_lease ls2;
1067 struct smb2_lease ls3;
1068 bool block_setup = false;
1069 bool block_ok = false;
1070 bool unblock_ok = false;
1073 if (!test_multichannel_initial_checks(tctx, tree1)) {
1077 torture_comment(tctx, "Lease break retry: Test2\n");
1079 torture_reset_lease_break_info(tctx, &lease_break_info);
1081 transport1->lease.handler = torture_lease_handler;
1082 transport1->lease.private_data = tree1;
1083 torture_comment(tctx, "transport1 [%p]\n", transport1);
1084 local_port = torture_get_local_port_from_transport(transport1);
1085 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
1087 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
1088 CHECK_STATUS(status, NT_STATUS_OK);
1089 smb2_util_close(tree1, _h);
1090 smb2_util_unlink(tree1, fname1);
1091 smb2_util_unlink(tree1, fname2);
1092 smb2_util_unlink(tree1, fname3);
1093 CHECK_VAL(lease_break_info.count, 0);
1095 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1096 smb2_util_lease_state("RHW"));
1097 test_multichannel_init_smb_create(&io1);
1099 smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
1100 smb2_util_lease_state("RHW"));
1101 test_multichannel_init_smb_create(&io2);
1103 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
1104 smb2_util_lease_state("RHW"));
1105 test_multichannel_init_smb_create(&io3);
1107 transport2_options = transport1->options;
1109 ret = test_multichannel_create_channels(tctx, host, share,
1111 &transport2_options,
1112 &tree2A, &tree2B, NULL);
1113 torture_assert(tctx, ret, "Could not create channels.\n");
1114 transport2A = tree2A->session->transport;
1116 /* 2a opens file1 */
1117 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
1118 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1119 smb2_util_lease_state("RHW"));
1120 status = smb2_create(tree2A, mem_ctx, &io1);
1121 CHECK_STATUS(status, NT_STATUS_OK);
1122 h_client2_file1 = io1.out.file.handle;
1123 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1124 CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
1125 CHECK_VAL(io1.out.durable_open_v2, false); //true);
1126 CHECK_VAL(io1.out.timeout, io1.in.timeout);
1127 CHECK_VAL(io1.out.durable_open, false);
1128 CHECK_VAL(lease_break_info.count, 0);
1130 /* 2b opens file2 */
1131 torture_comment(tctx, "client2 opens fname2 via session 2B\n");
1132 smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
1133 smb2_util_lease_state("RHW"));
1134 status = smb2_create(tree2B, mem_ctx, &io2);
1135 CHECK_STATUS(status, NT_STATUS_OK);
1136 h_client2_file2 = io2.out.file.handle;
1137 CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1138 CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
1139 CHECK_VAL(io2.out.durable_open_v2, false); //true);
1140 CHECK_VAL(io2.out.timeout, io2.in.timeout);
1141 CHECK_VAL(io2.out.durable_open, false);
1142 CHECK_VAL(lease_break_info.count, 0);
1144 block_setup = test_setup_blocked_transports(tctx);
1145 torture_assert(tctx, block_setup, "test_setup_blocked_transports");
1147 torture_comment(tctx, "Blocking 2A\n");
1149 block_ok = test_block_smb2_transport(tctx, transport2A);
1150 torture_assert(tctx, block_ok, "we could not block tcp transport");
1152 torture_wait_for_lease_break(tctx);
1153 CHECK_VAL(lease_break_info.count, 0);
1156 torture_comment(tctx,
1157 "Client opens fname2 with session1 with 2A blocked\n");
1158 smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
1159 smb2_util_lease_state("RHW"));
1160 status = smb2_create(tree1, mem_ctx, &io2);
1161 CHECK_STATUS(status, NT_STATUS_OK);
1162 h_client1_file2 = io2.out.file.handle;
1163 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1164 CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
1165 CHECK_VAL(io2.out.durable_open_v2, false);
1166 CHECK_VAL(io2.out.timeout, 0);
1167 CHECK_VAL(io2.out.durable_open, false);
1169 if (lease_break_info.count == 0) {
1170 torture_comment(tctx,
1171 "Did not receive expected lease break!!\n");
1173 torture_comment(tctx, "Received %d lease break(s)!!\n",
1174 lease_break_info.count);
1178 * We got breaks on both channels
1179 * (one failed on the blocked connection)
1181 CHECK_VAL(lease_break_info.count, 2);
1182 lease_break_info.count -= 1;
1183 CHECK_VAL(lease_break_info.failures, 1);
1184 lease_break_info.failures -= 1;
1185 CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
1186 torture_reset_lease_break_info(tctx, &lease_break_info);
1189 torture_comment(tctx, "Connecting session 2C\n");
1190 talloc_free(tree2C);
1191 tree2C = test_multichannel_create_channel(tctx, host, share,
1192 credentials, &transport2_options, tree2A);
1197 /* 2c opens file3 */
1198 torture_comment(tctx, "client2 opens fname3 via session 2C\n");
1199 smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
1200 smb2_util_lease_state("RHW"));
1201 status = smb2_create(tree2C, mem_ctx, &io3);
1202 CHECK_STATUS(status, NT_STATUS_OK);
1203 h_client2_file3 = io3.out.file.handle;
1204 CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1205 CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
1206 CHECK_VAL(io3.out.durable_open_v2, false);
1207 CHECK_VAL(io3.out.timeout, io2.in.timeout);
1208 CHECK_VAL(io3.out.durable_open, false);
1209 CHECK_VAL(lease_break_info.count, 0);
1212 torture_comment(tctx, "Unblocking 2A\n");
1213 unblock_ok = test_unblock_smb2_transport(tctx, transport2A);
1214 torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
1217 torture_comment(tctx, "Client opens fname1 with session 1\n");
1218 smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
1219 smb2_util_lease_state("RHW"));
1220 status = smb2_create(tree1, mem_ctx, &io1);
1221 CHECK_STATUS(status, NT_STATUS_OK);
1222 h_client1_file1 = io1.out.file.handle;
1223 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1224 CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
1226 if (lease_break_info.count == 0) {
1227 torture_comment(tctx,
1228 "Did not receive expected lease break!!\n");
1230 torture_comment(tctx,
1231 "Received %d lease break(s)!!\n",
1232 lease_break_info.count);
1234 CHECK_VAL(lease_break_info.count, 1);
1235 CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
1236 torture_reset_lease_break_info(tctx, &lease_break_info);
1239 torture_comment(tctx, "client opens fname3 via session 1\n");
1241 smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
1242 smb2_util_lease_state("RHW"));
1243 status = smb2_create(tree1, mem_ctx, &io3);
1244 CHECK_STATUS(status, NT_STATUS_OK);
1245 h_client1_file3 = io3.out.file.handle;
1246 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1247 CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
1249 if (lease_break_info.count == 0) {
1250 torture_comment(tctx,
1251 "Did not receive expected lease break!!\n");
1253 torture_comment(tctx,
1254 "Received %d lease break(s)!!\n",
1255 lease_break_info.count);
1257 CHECK_VAL(lease_break_info.count, 1);
1258 CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
1259 torture_reset_lease_break_info(tctx, &lease_break_info);
1261 smb2_util_close(tree1, h_client1_file1);
1262 smb2_util_close(tree1, h_client1_file2);
1263 smb2_util_close(tree1, h_client1_file3);
1266 * Session 2 still has RW lease on file 1. Deletion of this file by 1
1267 * leads to a lease break call to session 2 file1
1269 smb2_util_unlink(tree1, fname1);
1271 * Bug - Samba does not revoke Handle lease on unlink
1272 * CHECK_BREAK_INFO("RH", "R", LEASE2F1);
1274 torture_reset_lease_break_info(tctx, &lease_break_info);
1277 * Session 2 still has RW lease on file 2. Deletion of this file by 1
1278 * leads to a lease break call to session 2 file2
1280 smb2_util_unlink(tree1, fname2);
1282 * Bug - Samba does not revoke Handle lease on unlink
1283 * CHECK_BREAK_INFO("RH", "R", LEASE2F2);
1285 torture_reset_lease_break_info(tctx, &lease_break_info);
1288 * Session 2 still has RW lease on file 3. Deletion of this file by 1
1289 * leads to a lease break call to session 2 file3
1291 smb2_util_unlink(tree1, fname3);
1293 * Bug - Samba does not revoke Handle lease on unlink
1294 * CHECK_BREAK_INFO("RH", "R", LEASE2F3);
1296 torture_reset_lease_break_info(tctx, &lease_break_info);
1298 smb2_util_close(tree2C, h_client2_file1);
1299 smb2_util_close(tree2C, h_client2_file2);
1300 smb2_util_close(tree2C, h_client2_file3);
1302 test_multichannel_free_channels(tree2A, tree2B, tree2C);
1303 tree2A = tree2B = tree2C = NULL;
1306 if (block_ok && !unblock_ok) {
1307 test_unblock_smb2_transport(tctx, transport2A);
1310 test_cleanup_blocked_transports(tctx);
1313 tree1->session = session1;
1315 smb2_util_close(tree1, h_client1_file1);
1316 smb2_util_close(tree1, h_client1_file2);
1317 smb2_util_close(tree1, h_client1_file3);
1318 if (tree2A != NULL) {
1319 smb2_util_close(tree2A, h_client2_file1);
1320 smb2_util_close(tree2A, h_client2_file2);
1321 smb2_util_close(tree2A, h_client2_file3);
1325 smb2_util_close(tree1, *h);
1328 smb2_util_unlink(tree1, fname1);
1329 smb2_util_unlink(tree1, fname2);
1330 smb2_util_unlink(tree1, fname3);
1331 smb2_deltree(tree1, BASEDIR);
1333 test_multichannel_free_channels(tree2A, tree2B, tree2C);
1335 talloc_free(mem_ctx);
1341 * Test 3: Check to see how the server behaves if lease break
1342 * response is sent over a different channel to one over which
1343 * the break is received.
1345 * open file1 in session 2A
1346 * open file1 in session 1
1347 * Lease break sent to 2A
1348 * 2B sends back lease break reply.
1349 * session 1 allowed to open file
1351 static bool test_multichannel_lease_break_test3(struct torture_context *tctx,
1352 struct smb2_tree *tree1)
1354 const char *host = torture_setting_string(tctx, "host", NULL);
1355 const char *share = torture_setting_string(tctx, "share", NULL);
1356 struct cli_credentials *credentials = popt_get_cmdline_credentials();
1358 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1359 struct smb2_handle _h;
1360 struct smb2_handle *h = NULL;
1361 struct smb2_handle h_client1_file1 = {{0}};
1362 struct smb2_handle h_client2_file1 = {{0}};
1363 struct smb2_create io1;
1365 const char *fname1 = BASEDIR "\\lease_break_test1.dat";
1366 struct smb2_tree *tree2A = NULL;
1367 struct smb2_tree *tree2B = NULL;
1368 struct smb2_transport *transport1 = tree1->session->transport;
1369 struct smb2_transport *transport2A = NULL;
1370 struct smbcli_options transport2_options;
1371 uint16_t local_port = 0;
1372 struct smb2_lease ls1;
1373 struct tevent_timer *te = NULL;
1375 bool timesup = false;
1376 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
1378 if (!test_multichannel_initial_checks(tctx, tree1)) {
1382 torture_comment(tctx, "Lease break retry: Test3\n");
1384 torture_reset_lease_break_info(tctx, &lease_break_info);
1386 transport1->lease.handler = torture_lease_handler;
1387 transport1->lease.private_data = tree1;
1388 torture_comment(tctx, "transport1 [%p]\n", transport1);
1389 local_port = torture_get_local_port_from_transport(transport1);
1390 torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
1392 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
1393 CHECK_STATUS(status, NT_STATUS_OK);
1394 smb2_util_close(tree1, _h);
1395 smb2_util_unlink(tree1, fname1);
1396 CHECK_VAL(lease_break_info.count, 0);
1398 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1399 smb2_util_lease_state("RHW"));
1400 test_multichannel_init_smb_create(&io1);
1402 transport2_options = transport1->options;
1404 ret = test_multichannel_create_channels(tctx, host, share,
1406 &transport2_options,
1407 &tree2A, &tree2B, NULL);
1408 torture_assert(tctx, ret, "Could not create channels.\n");
1409 transport2A = tree2A->session->transport;
1410 transport2A->lease.private_data = tree2B;
1412 /* 2a opens file1 */
1413 torture_comment(tctx, "client2 opens fname1 via session 2A\n");
1414 smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1415 smb2_util_lease_state("RHW"));
1416 status = smb2_create(tree2A, mem_ctx, &io1);
1417 CHECK_STATUS(status, NT_STATUS_OK);
1418 h_client2_file1 = io1.out.file.handle;
1419 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1420 CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
1421 CHECK_VAL(io1.out.durable_open_v2, false); //true);
1422 CHECK_VAL(io1.out.timeout, io1.in.timeout);
1423 CHECK_VAL(io1.out.durable_open, false);
1424 CHECK_VAL(lease_break_info.count, 0);
1426 /* Set a timeout for 5 seconds for session 1 to open file1 */
1427 ne = tevent_timeval_current_ofs(0, 5000000);
1428 te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, ×up);
1430 torture_comment(tctx, "Failed to add timer.");
1435 torture_comment(tctx, "Client opens fname1 with session 1\n");
1436 smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
1437 smb2_util_lease_state("RHW"));
1438 status = smb2_create(tree1, mem_ctx, &io1);
1439 CHECK_STATUS(status, NT_STATUS_OK);
1440 h_client1_file1 = io1.out.file.handle;
1441 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1442 CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
1443 CHECK_VAL(io1.out.durable_open_v2, false);
1444 CHECK_VAL(io1.out.timeout, 0);
1445 CHECK_VAL(io1.out.durable_open, false);
1447 CHECK_VAL(lease_break_info.count, 1);
1448 CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
1451 * Check if timeout handler was fired. This would indicate
1452 * that the server didn't receive a reply for the oplock break
1453 * from the client and the server let session 1 open the file
1454 * only after the oplock break timeout.
1456 CHECK_VAL(timesup, false);
1459 smb2_util_close(tree1, h_client1_file1);
1460 if (tree2A != NULL) {
1461 smb2_util_close(tree2A, h_client2_file1);
1465 smb2_util_close(tree1, *h);
1468 smb2_util_unlink(tree1, fname1);
1469 smb2_deltree(tree1, BASEDIR);
1471 test_multichannel_free_channels(tree2A, tree2B, NULL);
1473 talloc_free(mem_ctx);
1479 * Test limits of channels
1481 static bool test_multichannel_num_channels(struct torture_context *tctx,
1482 struct smb2_tree *tree1)
1484 const char *host = torture_setting_string(tctx, "host", NULL);
1485 const char *share = torture_setting_string(tctx, "share", NULL);
1486 struct cli_credentials *credentials = popt_get_cmdline_credentials();
1487 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1489 struct smb2_tree **tree2 = NULL;
1490 struct smb2_transport *transport1 = tree1->session->transport;
1491 struct smb2_transport **transport2 = NULL;
1492 struct smbcli_options transport2_options;
1493 struct smb2_session **session2 = NULL;
1494 uint32_t server_capabilities;
1496 int max_channels = 33; /* 32 is the W2K12R2 and W2K16 limit */
1498 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
1500 "SMB 3.X Dialect family required for Multichannel"
1504 server_capabilities = smb2cli_conn_server_capabilities(
1505 tree1->session->transport->conn);
1506 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
1508 "Server does not support multichannel.");
1511 torture_comment(tctx, "Testing max. number of channels\n");
1513 transport2_options = transport1->options;
1514 transport2_options.client_guid = GUID_random();
1516 tree2 = talloc_zero_array(mem_ctx, struct smb2_tree *,
1518 transport2 = talloc_zero_array(mem_ctx, struct smb2_transport *,
1520 session2 = talloc_zero_array(mem_ctx, struct smb2_session *,
1522 if (tree2 == NULL || transport2 == NULL || session2 == NULL) {
1523 torture_fail(tctx, "out of memory");
1526 for (i = 0; i < max_channels; i++) {
1528 NTSTATUS expected_status;
1530 torture_assert_ntstatus_ok_goto(tctx,
1533 lpcfg_smb_ports(tctx->lp_ctx),
1535 lpcfg_resolve_context(tctx->lp_ctx),
1539 &transport2_options,
1540 lpcfg_socket_options(tctx->lp_ctx),
1541 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
1543 ret, done, "smb2_connect failed");
1545 transport2[i] = tree2[i]->session->transport;
1549 * done for the 1st channel
1551 * For all remaining channels we do the
1552 * session setup on our own.
1554 transport2_options.only_negprot = true;
1559 * Now bind the session2[i] to the transport2
1561 session2[i] = smb2_session_channel(transport2[i],
1562 lpcfg_gensec_settings(tctx,
1567 torture_assert(tctx, session2[i] != NULL,
1568 "smb2_session_channel failed");
1570 torture_comment(tctx, "established transport2 [#%d]\n", i);
1573 expected_status = NT_STATUS_INSUFFICIENT_RESOURCES;
1575 expected_status = NT_STATUS_OK;
1578 torture_assert_ntstatus_equal_goto(tctx,
1579 smb2_session_setup_spnego(session2[i],
1580 popt_get_cmdline_credentials(),
1581 0 /* previous_session_id */),
1584 talloc_asprintf(tctx, "failed to establish session "
1585 "setup for channel #%d", i));
1587 torture_comment(tctx, "bound session2 [#%d] to session2 [0]\n",
1592 talloc_free(mem_ctx);
1597 struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
1599 struct torture_suite *suite = torture_suite_create(ctx, "multichannel");
1600 struct torture_suite *suite_generic = torture_suite_create(ctx,
1602 struct torture_suite *suite_oplocks = torture_suite_create(ctx,
1604 struct torture_suite *suite_leases = torture_suite_create(ctx,
1607 torture_suite_add_suite(suite, suite_generic);
1608 torture_suite_add_suite(suite, suite_oplocks);
1609 torture_suite_add_suite(suite, suite_leases);
1611 torture_suite_add_1smb2_test(suite_generic, "interface_info",
1612 test_multichannel_interface_info);
1613 torture_suite_add_1smb2_test(suite_generic, "num_channels",
1614 test_multichannel_num_channels);
1615 torture_suite_add_1smb2_test(suite_oplocks, "test1",
1616 test_multichannel_oplock_break_test1);
1617 torture_suite_add_1smb2_test(suite_oplocks, "test2",
1618 test_multichannel_oplock_break_test2);
1619 torture_suite_add_1smb2_test(suite_leases, "test1",
1620 test_multichannel_lease_break_test1);
1621 torture_suite_add_1smb2_test(suite_leases, "test2",
1622 test_multichannel_lease_break_test2);
1623 torture_suite_add_1smb2_test(suite_leases, "test3",
1624 test_multichannel_lease_break_test3);
1626 suite->description = talloc_strdup(suite, "SMB2 Multichannel tests");