LCOV - code coverage report
Current view: top level - source4/torture/smb2 - multichannel.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 23 1370 1.7 %
Date: 2024-06-13 04:01:37 Functions: 1 24 4.2 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  *
       4             :  * test SMB2 multichannel operations
       5             :  *
       6             :  * Copyright (C) Guenther Deschner, 2016
       7             :  *
       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.
      12             :  *
      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.
      17             :  *
      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/>.
      20             :  */
      21             : 
      22             : #include "includes.h"
      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/cmdline.h"
      32             : #include "libcli/security/security.h"
      33             : #include "libcli/resolve/resolve.h"
      34             : #include "lib/socket/socket.h"
      35             : #include "lib/param/param.h"
      36             : #include "lib/events/events.h"
      37             : #include "oplock_break_handler.h"
      38             : #include "lease_break_handler.h"
      39             : #include "torture/smb2/block.h"
      40             : 
      41             : #define BASEDIR "multichanneltestdir"
      42             : 
      43             : #define CHECK_STATUS(status, correct) \
      44             :         torture_assert_ntstatus_equal_goto(tctx, status, correct,\
      45             :                                            ret, done, "")
      46             : 
      47             : #define CHECK_VAL(v, correct) do { \
      48             :         if ((v) != (correct)) { \
      49             :                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s" \
      50             :                                 " got 0x%x - should be 0x%x\n", \
      51             :                                 __location__, #v, (int)v, (int)correct); \
      52             :                 ret = false; \
      53             :                 goto done; \
      54             :         } } while (0)
      55             : 
      56             : #define CHECK_VAL_GREATER_THAN(v, gt_val) do { \
      57             :         if ((v) <= (gt_val)) { \
      58             :                 torture_result(tctx, TORTURE_FAIL, \
      59             :                                 "(%s): wrong value for %s got 0x%x - " \
      60             :                                 "should be greater than 0x%x\n", \
      61             :                                 __location__, #v, (int)v, (int)gt_val); \
      62             :                 ret = false; \
      63             :                 goto done; \
      64             :         } } while (0)
      65             : 
      66             : #define CHECK_CREATED(__io, __created, __attribute)                     \
      67             :         do {                                                            \
      68             :                 CHECK_VAL((__io)->out.create_action,                 \
      69             :                                 NTCREATEX_ACTION_ ## __created);        \
      70             :                 CHECK_VAL((__io)->out.alloc_size, 0);                        \
      71             :                 CHECK_VAL((__io)->out.size, 0);                              \
      72             :                 CHECK_VAL((__io)->out.file_attr, (__attribute));     \
      73             :                 CHECK_VAL((__io)->out.reserved2, 0);                 \
      74             :         } while (0)
      75             : 
      76             : #define CHECK_PTR(ptr, correct) do { \
      77             :         if ((ptr) != (correct)) { \
      78             :                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
      79             :                                 "got 0x%p - should be 0x%p\n", \
      80             :                                 __location__, #ptr, ptr, correct); \
      81             :                 ret = false; \
      82             :                 goto done; \
      83             :         } } while (0)
      84             : 
      85             : #define CHECK_LEASE(__io, __state, __oplevel, __key, __flags)           \
      86             :         do {                                                            \
      87             :                 CHECK_VAL((__io)->out.lease_response.lease_version, 1); \
      88             :                 if (__oplevel) {                                        \
      89             :                         CHECK_VAL((__io)->out.oplock_level, \
      90             :                                         SMB2_OPLOCK_LEVEL_LEASE); \
      91             :                         CHECK_VAL((__io)->out.lease_response.lease_key.data[0],\
      92             :                                   (__key)); \
      93             :                         CHECK_VAL((__io)->out.lease_response.lease_key.data[1],\
      94             :                                   ~(__key)); \
      95             :                         CHECK_VAL((__io)->out.lease_response.lease_state,\
      96             :                                   smb2_util_lease_state(__state)); \
      97             :                 } else {                                                \
      98             :                         CHECK_VAL((__io)->out.oplock_level,\
      99             :                                   SMB2_OPLOCK_LEVEL_NONE); \
     100             :                         CHECK_VAL((__io)->out.lease_response.lease_key.data[0],\
     101             :                                   0); \
     102             :                         CHECK_VAL((__io)->out.lease_response.lease_key.data[1],\
     103             :                                   0); \
     104             :                         CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
     105             :                 }                                                       \
     106             :                                                                         \
     107             :                 CHECK_VAL((__io)->out.lease_response.lease_flags, (__flags)); \
     108             :                 CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
     109             :                 CHECK_VAL((__io)->out.lease_response.lease_epoch, 0); \
     110             :         } while (0)
     111             : 
     112             : #define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent, __epoch) \
     113             :         do {                                                            \
     114             :                 CHECK_VAL((__io)->out.lease_response_v2.lease_version, 2); \
     115             :                 if (__oplevel) {                                        \
     116             :                         CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
     117             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], (__key)); \
     118             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], ~(__key)); \
     119             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_state, smb2_util_lease_state(__state)); \
     120             :                 } else {                                                \
     121             :                         CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
     122             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], 0); \
     123             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], 0); \
     124             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_state, 0); \
     125             :                 }                                                       \
     126             :                                                                         \
     127             :                 CHECK_VAL((__io)->out.lease_response_v2.lease_flags, __flags); \
     128             :                 if (__flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET) { \
     129             :                         CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[0], (__parent)); \
     130             :                         CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[1], ~(__parent)); \
     131             :                 } \
     132             :                 CHECK_VAL((__io)->out.lease_response_v2.lease_duration, 0); \
     133             :                 CHECK_VAL((__io)->out.lease_response_v2.lease_epoch, (__epoch)); \
     134             :         } while(0)
     135             : 
     136             : #define CHECK_LEASE_BREAK_V2(__lb, __key, __from, __to, __break_flags, __new_epoch) \
     137             :         do {                                                            \
     138             :                 CHECK_VAL((__lb).current_lease.lease_key.data[0], (__key)); \
     139             :                 CHECK_VAL((__lb).current_lease.lease_key.data[1], ~(__key)); \
     140             :                 CHECK_VAL((__lb).current_lease.lease_state, smb2_util_lease_state(__from)); \
     141             :                 CHECK_VAL((__lb).new_epoch, (__new_epoch)); \
     142             :                 CHECK_VAL((__lb).break_flags, (__break_flags)); \
     143             :                 CHECK_VAL((__lb).new_lease_state, smb2_util_lease_state(__to)); \
     144             :         } while(0)
     145             : 
     146           0 : static bool test_ioctl_network_interface_info(struct torture_context *tctx,
     147             :                                               struct smb2_tree *tree,
     148             :                                               struct fsctl_net_iface_info *info)
     149             : {
     150             :         union smb_ioctl ioctl;
     151             :         struct smb2_handle fh;
     152             :         uint32_t caps;
     153             : 
     154           0 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
     155           0 :         if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
     156           0 :                 torture_skip(tctx,
     157             :                             "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
     158             :         }
     159             : 
     160           0 :         ZERO_STRUCT(ioctl);
     161             : 
     162           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
     163             : 
     164           0 :         fh.data[0] = UINT64_MAX;
     165           0 :         fh.data[1] = UINT64_MAX;
     166             : 
     167           0 :         ioctl.smb2.in.file.handle = fh;
     168           0 :         ioctl.smb2.in.function = FSCTL_QUERY_NETWORK_INTERFACE_INFO;
     169             :         /* Windows client sets this to 64KiB */
     170           0 :         ioctl.smb2.in.max_output_response = 0x10000;
     171           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
     172             : 
     173           0 :         torture_assert_ntstatus_ok(tctx,
     174             :                 smb2_ioctl(tree, tctx, &ioctl.smb2),
     175             :                 "FSCTL_QUERY_NETWORK_INTERFACE_INFO failed");
     176             : 
     177           0 :         torture_assert(tctx,
     178             :                 (ioctl.smb2.out.out.length != 0),
     179             :                 "no interface info returned???");
     180             : 
     181           0 :         torture_assert_ndr_success(tctx,
     182             :                 ndr_pull_struct_blob(&ioctl.smb2.out.out, tctx, info,
     183             :                         (ndr_pull_flags_fn_t)ndr_pull_fsctl_net_iface_info),
     184             :                 "failed to ndr pull");
     185             : 
     186           0 :         if (DEBUGLVL(1)) {
     187           0 :                 NDR_PRINT_DEBUG(fsctl_net_iface_info, info);
     188             :         }
     189             : 
     190           0 :         return true;
     191             : }
     192             : 
     193           0 : static bool test_multichannel_interface_info(struct torture_context *tctx,
     194             :                                              struct smb2_tree *tree)
     195             : {
     196             :         struct fsctl_net_iface_info info;
     197             : 
     198           0 :         return test_ioctl_network_interface_info(tctx, tree, &info);
     199             : }
     200             : 
     201           0 : static struct smb2_tree *test_multichannel_create_channel(
     202             :                                 struct torture_context *tctx,
     203             :                                 const char *host,
     204             :                                 const char *share,
     205             :                                 struct cli_credentials *credentials,
     206             :                                 const struct smbcli_options *_transport_options,
     207             :                                 struct smb2_tree *parent_tree
     208             :                                 )
     209             : {
     210           0 :         struct smbcli_options transport_options = *_transport_options;
     211             :         NTSTATUS status;
     212             :         struct smb2_transport *transport;
     213             :         struct smb2_session *session;
     214           0 :         bool ret = true;
     215             :         struct smb2_tree *tree;
     216             : 
     217           0 :         if (parent_tree) {
     218           0 :                 transport_options.only_negprot = true;
     219             :         }
     220             : 
     221           0 :         status = smb2_connect(tctx,
     222             :                         host,
     223             :                         lpcfg_smb_ports(tctx->lp_ctx),
     224             :                         share,
     225             :                         lpcfg_resolve_context(tctx->lp_ctx),
     226             :                         credentials,
     227             :                         &tree,
     228             :                         tctx->ev,
     229             :                         &transport_options,
     230             :                         lpcfg_socket_options(tctx->lp_ctx),
     231             :                         lpcfg_gensec_settings(tctx, tctx->lp_ctx)
     232             :                         );
     233           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     234             :                         "smb2_connect failed");
     235           0 :         transport = tree->session->transport;
     236           0 :         transport->oplock.handler = torture_oplock_ack_handler;
     237           0 :         transport->oplock.private_data = tree;
     238           0 :         transport->lease.handler = torture_lease_handler;
     239           0 :         transport->lease.private_data = tree;
     240           0 :         torture_comment(tctx, "established transport [%p]\n", transport);
     241             : 
     242             :         /*
     243             :          * If parent tree is set, bind the session to the parent transport
     244             :          */
     245           0 :         if (parent_tree) {
     246           0 :                 session = smb2_session_channel(transport,
     247             :                                 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
     248             :                                 parent_tree, parent_tree->session);
     249           0 :                 torture_assert_goto(tctx, session != NULL, ret, done,
     250             :                                 "smb2_session_channel failed");
     251             : 
     252           0 :                 tree->smbXcli = parent_tree->smbXcli;
     253           0 :                 tree->session = session;
     254           0 :                 status = smb2_session_setup_spnego(session,
     255             :                                                 credentials,
     256             :                                                 0 /* previous_session_id */);
     257           0 :                 CHECK_STATUS(status, NT_STATUS_OK);
     258           0 :                 torture_comment(tctx, "bound new session to parent\n");
     259             :         }
     260             :         /*
     261             :          * We absolutely need to make sure to send something over this
     262             :          * connection to register the oplock break handler with the smb client
     263             :          * connection. If we do not send something (at least a keepalive), we
     264             :          * will *NEVER* receive anything over this transport.
     265             :          */
     266           0 :         smb2_keepalive(transport);
     267             : 
     268           0 : done:
     269           0 :         if (ret) {
     270           0 :                 return tree;
     271             :         } else {
     272           0 :                 return NULL;
     273             :         }
     274             : }
     275             : 
     276           0 : bool test_multichannel_create_channel_array(
     277             :                                 struct torture_context *tctx,
     278             :                                 const char *host,
     279             :                                 const char *share,
     280             :                                 struct cli_credentials *credentials,
     281             :                                 struct smbcli_options *transport_options,
     282             :                                 uint8_t num_trees,
     283             :                                 struct smb2_tree **trees)
     284             : {
     285             :         uint8_t i;
     286             : 
     287           0 :         transport_options->client_guid = GUID_random();
     288             : 
     289           0 :         for (i = 0; i < num_trees; i++) {
     290           0 :                 struct smb2_tree *parent_tree = NULL;
     291           0 :                 struct smb2_tree *tree = NULL;
     292           0 :                 struct smb2_transport *transport = NULL;
     293           0 :                 uint16_t local_port = 0;
     294             : 
     295           0 :                 if (i > 0) {
     296           0 :                         parent_tree = trees[0];
     297             :                 }
     298             : 
     299           0 :                 torture_comment(tctx, "Setting up connection %d\n", i);
     300           0 :                 tree = test_multichannel_create_channel(tctx, host, share,
     301             :                                         credentials, transport_options,
     302             :                                         parent_tree);
     303           0 :                 torture_assert(tctx, tree, "failed to created new channel");
     304             : 
     305           0 :                 trees[i] = tree;
     306           0 :                 transport = tree->session->transport;
     307           0 :                 local_port = torture_get_local_port_from_transport(transport);
     308           0 :                 torture_comment(tctx, "transport[%d] uses tcp port: %d\n",
     309             :                                 i, local_port);
     310             :         }
     311             : 
     312           0 :         return true;
     313             : }
     314             : 
     315           0 : bool test_multichannel_create_channels(
     316             :                                 struct torture_context *tctx,
     317             :                                 const char *host,
     318             :                                 const char *share,
     319             :                                 struct cli_credentials *credentials,
     320             :                                 struct smbcli_options *transport_options,
     321             :                                 struct smb2_tree **tree2A,
     322             :                                 struct smb2_tree **tree2B,
     323             :                                 struct smb2_tree **tree2C
     324             :                                 )
     325             : {
     326           0 :         struct smb2_tree **trees = NULL;
     327           0 :         size_t num_trees = 0;
     328             :         bool ret;
     329             : 
     330           0 :         torture_assert(tctx, tree2A, "tree2A required!");
     331           0 :         num_trees += 1;
     332           0 :         torture_assert(tctx, tree2B, "tree2B required!");
     333           0 :         num_trees += 1;
     334           0 :         if (tree2C != NULL) {
     335           0 :                 num_trees += 1;
     336             :         }
     337           0 :         trees = talloc_zero_array(tctx, struct smb2_tree *, num_trees);
     338           0 :         torture_assert(tctx, trees, "out of memory");
     339             : 
     340           0 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
     341             :                                                      transport_options,
     342             :                                                      num_trees, trees);
     343           0 :         if (!ret) {
     344           0 :                 return false;
     345             :         }
     346             : 
     347           0 :         *tree2A = trees[0];
     348           0 :         *tree2B = trees[1];
     349           0 :         if (tree2C != NULL) {
     350           0 :                 *tree2C = trees[2];
     351             :         }
     352             : 
     353           0 :         return true;
     354             : }
     355             : 
     356           0 : static void test_multichannel_free_channels(struct smb2_tree *tree2A,
     357             :                                              struct smb2_tree *tree2B,
     358             :                                              struct smb2_tree *tree2C)
     359             : {
     360           0 :         TALLOC_FREE(tree2A);
     361           0 :         TALLOC_FREE(tree2B);
     362           0 :         TALLOC_FREE(tree2C);
     363           0 : }
     364             : 
     365           0 : static bool test_multichannel_initial_checks(struct torture_context *tctx,
     366             :                                              struct smb2_tree *tree1)
     367             : {
     368           0 :         struct smb2_transport *transport1 = tree1->session->transport;
     369             :         uint32_t server_capabilities;
     370             :         struct fsctl_net_iface_info info;
     371             : 
     372           0 :         if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
     373           0 :                 torture_skip_goto(tctx, fail,
     374             :                                   "SMB 3.X Dialect family required for "
     375             :                                   "Multichannel tests\n");
     376             :         }
     377             : 
     378           0 :         server_capabilities = smb2cli_conn_server_capabilities(
     379           0 :                                         tree1->session->transport->conn);
     380           0 :         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
     381           0 :                 torture_skip_goto(tctx, fail,
     382             :                              "Server does not support multichannel.");
     383             :         }
     384             : 
     385           0 :         torture_assert(tctx,
     386             :                 test_ioctl_network_interface_info(tctx, tree1, &info),
     387             :                 "failed to retrieve network interface info");
     388             : 
     389           0 :         return true;
     390           0 : fail:
     391           0 :         return false;
     392             : }
     393             : 
     394           0 : static void test_multichannel_init_smb_create(struct smb2_create *io)
     395             : {
     396           0 :         io->in.durable_open = false;
     397           0 :         io->in.durable_open_v2 = true;
     398           0 :         io->in.persistent_open = false;
     399           0 :         io->in.create_guid = GUID_random();
     400           0 :         io->in.timeout = 0x493E0; /* 300000 */
     401             :         /* windows 2016 returns 300000 0x493E0 */
     402           0 : }
     403             : 
     404             : /* Timer handler function notifies the registering function that time is up */
     405           0 : static void timeout_cb(struct tevent_context *ev,
     406             :                        struct tevent_timer *te,
     407             :                        struct timeval current_time,
     408             :                        void *private_data)
     409             : {
     410           0 :         bool *timesup = (bool *)private_data;
     411           0 :         *timesup = true;
     412           0 : }
     413             : 
     414             : /*
     415             :  * Oplock break - Test 1
     416             :  * Test to confirm that server sends oplock breaks as expected.
     417             :  * open file1 in session 2A
     418             :  * open file2 in session 2B
     419             :  * open file1 in session 1
     420             :  *      oplock break received
     421             :  * open file1 in session 1
     422             :  *      oplock break received
     423             :  * Cleanup
     424             :  */
     425           0 : static bool test_multichannel_oplock_break_test1(struct torture_context *tctx,
     426             :                                            struct smb2_tree *tree1)
     427             : {
     428           0 :         const char *host = torture_setting_string(tctx, "host", NULL);
     429           0 :         const char *share = torture_setting_string(tctx, "share", NULL);
     430           0 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
     431             :         NTSTATUS status;
     432           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     433             :         struct smb2_handle _h;
     434           0 :         struct smb2_handle h_client1_file1 = {{0}};
     435           0 :         struct smb2_handle h_client1_file2 = {{0}};
     436           0 :         struct smb2_handle h_client1_file3 = {{0}};
     437           0 :         struct smb2_handle h_client2_file1 = {{0}};
     438           0 :         struct smb2_handle h_client2_file2 = {{0}};
     439           0 :         struct smb2_handle h_client2_file3 = {{0}};
     440             :         struct smb2_create io1, io2, io3;
     441           0 :         bool ret = true;
     442           0 :         const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
     443           0 :         const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
     444           0 :         const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
     445           0 :         struct smb2_tree *tree2A = NULL;
     446           0 :         struct smb2_tree *tree2B = NULL;
     447           0 :         struct smb2_tree *tree2C = NULL;
     448           0 :         struct smb2_transport *transport1 = tree1->session->transport;
     449             :         struct smbcli_options transport2_options;
     450           0 :         struct smb2_session *session1 = tree1->session;
     451           0 :         uint16_t local_port = 0;
     452             : 
     453           0 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
     454           0 :                 return true;
     455             :         }
     456             : 
     457           0 :         torture_comment(tctx, "Oplock break retry: Test1\n");
     458             : 
     459           0 :         torture_reset_break_info(tctx, &break_info);
     460             : 
     461           0 :         transport1->oplock.handler = torture_oplock_ack_handler;
     462           0 :         transport1->oplock.private_data = tree1;
     463           0 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
     464           0 :         local_port = torture_get_local_port_from_transport(transport1);
     465           0 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
     466             : 
     467           0 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
     468           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     469           0 :         smb2_util_close(tree1, _h);
     470           0 :         smb2_util_unlink(tree1, fname1);
     471           0 :         smb2_util_unlink(tree1, fname2);
     472           0 :         smb2_util_unlink(tree1, fname3);
     473           0 :         CHECK_VAL(break_info.count, 0);
     474             : 
     475           0 :         smb2_oplock_create_share(&io1, fname1,
     476             :                         smb2_util_share_access("RWD"),
     477           0 :                         smb2_util_oplock_level("b"));
     478           0 :         test_multichannel_init_smb_create(&io1);
     479             : 
     480           0 :         smb2_oplock_create_share(&io2, fname2,
     481             :                         smb2_util_share_access("RWD"),
     482           0 :                         smb2_util_oplock_level("b"));
     483           0 :         test_multichannel_init_smb_create(&io2);
     484             : 
     485           0 :         smb2_oplock_create_share(&io3, fname3,
     486             :                         smb2_util_share_access("RWD"),
     487           0 :                         smb2_util_oplock_level("b"));
     488           0 :         test_multichannel_init_smb_create(&io3);
     489             : 
     490           0 :         transport2_options = transport1->options;
     491             : 
     492           0 :         ret = test_multichannel_create_channels(tctx, host, share,
     493             :                                                   credentials,
     494             :                                                   &transport2_options,
     495             :                                                   &tree2A, &tree2B, NULL);
     496           0 :         torture_assert(tctx, ret, "Could not create channels.\n");
     497             : 
     498             :         /* 2a opens file1 */
     499           0 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
     500           0 :         status = smb2_create(tree2A, mem_ctx, &io1);
     501           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     502           0 :         h_client2_file1 = io1.out.file.handle;
     503           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     504           0 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
     505           0 :         torture_wait_for_oplock_break(tctx);
     506           0 :         CHECK_VAL(break_info.count, 0);
     507             : 
     508             :         /* 2b opens file2 */
     509           0 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
     510           0 :         status = smb2_create(tree2B, mem_ctx, &io2);
     511           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     512           0 :         h_client2_file2 = io2.out.file.handle;
     513           0 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     514           0 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
     515           0 :         torture_wait_for_oplock_break(tctx);
     516           0 :         CHECK_VAL(break_info.count, 0);
     517             : 
     518             : 
     519             :         /* 1 opens file1 - batchoplock break? */
     520           0 :         torture_comment(tctx, "client1 opens fname1 via session 1\n");
     521           0 :         io1.in.oplock_level = smb2_util_oplock_level("b");
     522           0 :         status = smb2_create(tree1, mem_ctx, &io1);
     523           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     524           0 :         h_client1_file1 = io1.out.file.handle;
     525           0 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     526           0 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
     527           0 :         torture_wait_for_oplock_break(tctx);
     528           0 :         CHECK_VAL(break_info.count, 1);
     529             : 
     530           0 :         torture_reset_break_info(tctx, &break_info);
     531             : 
     532             :         /* 1 opens file2 - batchoplock break? */
     533           0 :         torture_comment(tctx, "client1 opens fname2 via session 1\n");
     534           0 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     535           0 :         status = smb2_create(tree1, mem_ctx, &io2);
     536           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     537           0 :         h_client1_file2 = io2.out.file.handle;
     538           0 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     539           0 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
     540           0 :         torture_wait_for_oplock_break(tctx);
     541           0 :         CHECK_VAL(break_info.count, 1);
     542             : 
     543             :         /* cleanup everything */
     544           0 :         torture_reset_break_info(tctx, &break_info);
     545             : 
     546           0 :         smb2_util_close(tree1, h_client1_file1);
     547           0 :         smb2_util_close(tree1, h_client1_file2);
     548           0 :         smb2_util_close(tree1, h_client1_file3);
     549           0 :         smb2_util_close(tree2A, h_client2_file1);
     550           0 :         smb2_util_close(tree2A, h_client2_file2);
     551           0 :         smb2_util_close(tree2A, h_client2_file3);
     552             : 
     553           0 :         smb2_util_unlink(tree1, fname1);
     554           0 :         smb2_util_unlink(tree1, fname2);
     555           0 :         smb2_util_unlink(tree1, fname3);
     556           0 :         CHECK_VAL(break_info.count, 0);
     557           0 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
     558           0 :         tree2A = tree2B = tree2C = NULL;
     559           0 : done:
     560           0 :         tree1->session = session1;
     561             : 
     562           0 :         smb2_util_close(tree1, h_client1_file1);
     563           0 :         smb2_util_close(tree1, h_client1_file2);
     564           0 :         smb2_util_close(tree1, h_client1_file3);
     565           0 :         if (tree2A != NULL) {
     566           0 :                 smb2_util_close(tree2A, h_client2_file1);
     567           0 :                 smb2_util_close(tree2A, h_client2_file2);
     568           0 :                 smb2_util_close(tree2A, h_client2_file3);
     569             :         }
     570             : 
     571           0 :         smb2_util_unlink(tree1, fname1);
     572           0 :         smb2_util_unlink(tree1, fname2);
     573           0 :         smb2_util_unlink(tree1, fname3);
     574           0 :         smb2_deltree(tree1, BASEDIR);
     575             : 
     576           0 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
     577           0 :         talloc_free(tree1);
     578           0 :         talloc_free(mem_ctx);
     579             : 
     580           0 :         return ret;
     581             : }
     582             : 
     583             : /*
     584             :  * Oplock Break Test 2
     585             :  * Test to see if oplock break retries are sent by the server.
     586             :  * Also checks to see if new channels can be created and used
     587             :  * after an oplock break retry.
     588             :  * open file1 in 2A
     589             :  * open file2 in 2B
     590             :  * open file1 in session 1
     591             :  *      oplock break received
     592             :  * block channel on which oplock break received
     593             :  * open file2 in session 1
     594             :  *      oplock break not received. Retry received.
     595             :  *      file opened
     596             :  * write to file2 on 2B
     597             :  *      Break sent to session 1(which has file2 open)
     598             :  *      Break sent to session 2A(which has read oplock)
     599             :  * close file1 in session 1
     600             :  * open file1 with session 1
     601             :  * unblock blocked channel
     602             :  * disconnect blocked channel
     603             :  * connect channel 2D
     604             :  * open file3 in 2D
     605             :  * open file3 in session 1
     606             :  *      receive break
     607             :  */
     608           0 : static bool test_multichannel_oplock_break_test2(struct torture_context *tctx,
     609             :                                            struct smb2_tree *tree1)
     610             : {
     611           0 :         const char *host = torture_setting_string(tctx, "host", NULL);
     612           0 :         const char *share = torture_setting_string(tctx, "share", NULL);
     613           0 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
     614             :         NTSTATUS status;
     615           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     616             :         struct smb2_handle _h;
     617           0 :         struct smb2_handle h_client1_file1 = {{0}};
     618           0 :         struct smb2_handle h_client1_file2 = {{0}};
     619           0 :         struct smb2_handle h_client1_file3 = {{0}};
     620           0 :         struct smb2_handle h_client2_file1 = {{0}};
     621           0 :         struct smb2_handle h_client2_file2 = {{0}};
     622           0 :         struct smb2_handle h_client2_file3 = {{0}};
     623             :         struct smb2_create io1, io2, io3;
     624           0 :         bool ret = true;
     625           0 :         const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
     626           0 :         const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
     627           0 :         const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
     628           0 :         struct smb2_tree *tree2A = NULL;
     629           0 :         struct smb2_tree *tree2B = NULL;
     630           0 :         struct smb2_tree *tree2C = NULL;
     631           0 :         struct smb2_tree *tree2D = NULL;
     632           0 :         struct smb2_transport *transport1 = tree1->session->transport;
     633           0 :         struct smb2_transport *transport2 = NULL;
     634             :         struct smbcli_options transport2_options;
     635           0 :         struct smb2_session *session1 = tree1->session;
     636           0 :         uint16_t local_port = 0;
     637             :         DATA_BLOB blob;
     638           0 :         bool block_setup = false;
     639           0 :         bool block_ok = false;
     640           0 :         bool unblock_ok = false;
     641             : 
     642           0 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
     643           0 :                 return true;
     644             :         }
     645             : 
     646           0 :         torture_comment(tctx, "Oplock break retry: Test2\n");
     647             : 
     648           0 :         torture_reset_break_info(tctx, &break_info);
     649             : 
     650           0 :         transport1->oplock.handler = torture_oplock_ack_handler;
     651           0 :         transport1->oplock.private_data = tree1;
     652           0 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
     653           0 :         local_port = torture_get_local_port_from_transport(transport1);
     654           0 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
     655             : 
     656           0 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
     657           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     658           0 :         smb2_util_close(tree1, _h);
     659           0 :         smb2_util_unlink(tree1, fname1);
     660           0 :         smb2_util_unlink(tree1, fname2);
     661           0 :         smb2_util_unlink(tree1, fname3);
     662           0 :         CHECK_VAL(break_info.count, 0);
     663             : 
     664           0 :         smb2_oplock_create_share(&io1, fname1,
     665             :                         smb2_util_share_access("RWD"),
     666           0 :                         smb2_util_oplock_level("b"));
     667           0 :         test_multichannel_init_smb_create(&io1);
     668             : 
     669           0 :         smb2_oplock_create_share(&io2, fname2,
     670             :                         smb2_util_share_access("RWD"),
     671           0 :                         smb2_util_oplock_level("b"));
     672           0 :         test_multichannel_init_smb_create(&io2);
     673             : 
     674           0 :         smb2_oplock_create_share(&io3, fname3,
     675             :                         smb2_util_share_access("RWD"),
     676           0 :                         smb2_util_oplock_level("b"));
     677           0 :         test_multichannel_init_smb_create(&io3);
     678             : 
     679           0 :         transport2_options = transport1->options;
     680             : 
     681           0 :         ret = test_multichannel_create_channels(tctx, host, share,
     682             :                                                   credentials,
     683             :                                                   &transport2_options,
     684             :                                                   &tree2A, &tree2B, &tree2C);
     685           0 :         torture_assert(tctx, ret, "Could not create channels.\n");
     686             : 
     687           0 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
     688           0 :         io1.in.oplock_level = smb2_util_oplock_level("b");
     689           0 :         status = smb2_create(tree2A, mem_ctx, &io1);
     690           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     691           0 :         h_client2_file1 = io1.out.file.handle;
     692           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     693           0 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
     694           0 :         torture_wait_for_oplock_break(tctx);
     695           0 :         CHECK_VAL(break_info.count, 0);
     696             : 
     697             : 
     698           0 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
     699           0 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     700           0 :         status = smb2_create(tree2B, mem_ctx, &io2);
     701           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     702           0 :         h_client2_file2 = io2.out.file.handle;
     703           0 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     704           0 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
     705           0 :         torture_wait_for_oplock_break(tctx);
     706           0 :         CHECK_VAL(break_info.count, 0);
     707             : 
     708             : 
     709           0 :         torture_comment(tctx, "client1 opens fname1 via session 1\n");
     710           0 :         io1.in.oplock_level = smb2_util_oplock_level("b");
     711           0 :         status = smb2_create(tree1, mem_ctx, &io1);
     712           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     713           0 :         h_client1_file1 = io1.out.file.handle;
     714           0 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     715           0 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
     716           0 :         torture_wait_for_oplock_break(tctx);
     717           0 :         CHECK_VAL(break_info.count, 1);
     718             : 
     719             :         /* We use the transport over which this oplock break was received */
     720           0 :         transport2 = break_info.received_transport;
     721           0 :         torture_reset_break_info(tctx, &break_info);
     722             : 
     723           0 :         block_setup = test_setup_blocked_transports(tctx);
     724           0 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
     725             : 
     726             :         /* block channel */
     727           0 :         block_ok = test_block_smb2_transport(tctx, transport2);
     728             : 
     729           0 :         torture_comment(tctx, "client1 opens fname2 via session 1\n");
     730           0 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     731           0 :         status = smb2_create(tree1, mem_ctx, &io2);
     732           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     733           0 :         h_client1_file2 = io2.out.file.handle;
     734           0 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     735           0 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
     736             : 
     737             :         /*
     738             :          * Samba downgrades oplock to a level 2 oplock.
     739             :          * Windows 2016 revokes oplock
     740             :          */
     741           0 :         torture_wait_for_oplock_break(tctx);
     742           0 :         CHECK_VAL(break_info.count, 1);
     743           0 :         torture_reset_break_info(tctx, &break_info);
     744             : 
     745           0 :         torture_comment(tctx, "Trying write to file2 on tree2B\n");
     746             : 
     747           0 :         blob = data_blob_string_const("Here I am");
     748           0 :         status = smb2_util_write(tree2B,
     749             :                                  h_client2_file2,
     750           0 :                                  blob.data,
     751             :                                  0,
     752             :                                  blob.length);
     753           0 :         torture_assert_ntstatus_ok(tctx, status,
     754             :                 "failed to write file2 via channel 2B");
     755             : 
     756             :         /*
     757             :          * Samba: Write triggers 2 oplock breaks
     758             :          *  for session 1 which has file2 open
     759             :          *  for session 2 which has type 2 oplock
     760             :          * Windows 2016: Only one oplock break for session 1
     761             :          */
     762           0 :         torture_wait_for_oplock_break(tctx);
     763           0 :         CHECK_VAL_GREATER_THAN(break_info.count, 0);
     764           0 :         torture_reset_break_info(tctx, &break_info);
     765             : 
     766           0 :         torture_comment(tctx, "client1 closes fname2 via session 1\n");
     767           0 :         smb2_util_close(tree1, h_client1_file2);
     768             : 
     769           0 :         torture_comment(tctx, "client1 opens fname2 via session 1 again\n");
     770           0 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     771           0 :         status = smb2_create(tree1, mem_ctx, &io2);
     772           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     773           0 :         h_client1_file2 = io2.out.file.handle;
     774           0 :         io2.out.alloc_size = 0;
     775           0 :         io2.out.size = 0;
     776           0 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     777           0 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
     778             : 
     779             :         /*
     780             :          * now add a fourth channel and repeat the test, we need to reestablish
     781             :          * transport2 because the remote end has invalidated our connection
     782             :          */
     783           0 :         torture_comment(tctx, "Connecting session 2D\n");
     784           0 :         tree2D = test_multichannel_create_channel(tctx, host, share,
     785             :                                      credentials, &transport2_options, tree2B);
     786           0 :         if (!tree2D) {
     787           0 :                 goto done;
     788             :         }
     789             : 
     790           0 :         torture_reset_break_info(tctx, &break_info);
     791           0 :         torture_comment(tctx, "client 2 opening fname3 over transport2D\n");
     792           0 :         status = smb2_create(tree2D, mem_ctx, &io3);
     793           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     794           0 :         h_client2_file3 = io3.out.file.handle;
     795           0 :         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     796           0 :         CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("b"));
     797           0 :         torture_wait_for_oplock_break(tctx);
     798           0 :         CHECK_VAL(break_info.count, 0);
     799             : 
     800           0 :         torture_comment(tctx, "client1 opens fname3 via session 1\n");
     801           0 :         status = smb2_create(tree1, mem_ctx, &io3);
     802           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     803           0 :         h_client1_file3 = io3.out.file.handle;
     804           0 :         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     805           0 :         CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
     806           0 :         torture_wait_for_oplock_break(tctx);
     807           0 :         CHECK_VAL(break_info.count, 1);
     808             : 
     809           0 : done:
     810           0 :         if (block_ok && !unblock_ok) {
     811           0 :                 test_unblock_smb2_transport(tctx, transport2);
     812             :         }
     813           0 :         test_cleanup_blocked_transports(tctx);
     814             : 
     815           0 :         tree1->session = session1;
     816             : 
     817           0 :         smb2_util_close(tree1, h_client1_file1);
     818           0 :         smb2_util_close(tree1, h_client1_file2);
     819           0 :         smb2_util_close(tree1, h_client1_file3);
     820           0 :         if (tree2B != NULL) {
     821           0 :                 smb2_util_close(tree2B, h_client2_file1);
     822           0 :                 smb2_util_close(tree2B, h_client2_file2);
     823           0 :                 smb2_util_close(tree2B, h_client2_file3);
     824             :         }
     825             : 
     826           0 :         smb2_util_unlink(tree1, fname1);
     827           0 :         smb2_util_unlink(tree1, fname2);
     828           0 :         smb2_util_unlink(tree1, fname3);
     829           0 :         smb2_deltree(tree1, BASEDIR);
     830             : 
     831           0 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
     832           0 :         if (tree2D != NULL) {
     833           0 :                 TALLOC_FREE(tree2D);
     834             :         }
     835           0 :         talloc_free(tree1);
     836           0 :         talloc_free(mem_ctx);
     837             : 
     838           0 :         return ret;
     839             : }
     840             : 
     841             : struct test_multichannel_oplock_break_state;
     842             : 
     843             : struct test_multichannel_oplock_break_channel {
     844             :         struct test_multichannel_oplock_break_state *state;
     845             :         size_t idx;
     846             :         char name[64];
     847             :         struct smb2_tree *tree;
     848             :         bool blocked;
     849             :         struct timeval break_time;
     850             :         double full_duration;
     851             :         double relative_duration;
     852             :         uint8_t level;
     853             :         size_t break_num;
     854             : };
     855             : 
     856             : struct test_multichannel_oplock_break_state {
     857             :         struct torture_context *tctx;
     858             :         struct timeval open_req_time;
     859             :         struct timeval open_rep_time;
     860             :         size_t num_breaks;
     861             :         struct timeval last_break_time;
     862             :         struct test_multichannel_oplock_break_channel channels[32];
     863             : };
     864             : 
     865           0 : static bool test_multichannel_oplock_break_handler(struct smb2_transport *transport,
     866             :                                                    const struct smb2_handle *handle,
     867             :                                                    uint8_t level,
     868             :                                                    void *private_data)
     869             : {
     870           0 :         struct test_multichannel_oplock_break_channel *c =
     871             :                 (struct test_multichannel_oplock_break_channel *)private_data;
     872           0 :         struct test_multichannel_oplock_break_state *state = c->state;
     873             : 
     874           0 :         c->break_time = timeval_current();
     875           0 :         c->full_duration = timeval_elapsed2(&state->open_req_time,
     876           0 :                                             &c->break_time);
     877           0 :         c->relative_duration = timeval_elapsed2(&state->last_break_time,
     878           0 :                                                 &c->break_time);
     879           0 :         state->last_break_time = c->break_time;
     880           0 :         c->level = level;
     881           0 :         c->break_num = ++state->num_breaks;
     882             : 
     883           0 :         torture_comment(state->tctx, "Got OPLOCK break %zu on %s after %f ( %f)\n",
     884           0 :                         c->break_num, c->name,
     885             :                         c->relative_duration,
     886             :                         c->full_duration);
     887             : 
     888           0 :         return torture_oplock_ack_handler(transport, handle, level, c->tree);
     889             : }
     890             : 
     891           0 : static bool test_multichannel_oplock_break_test3_windows(struct torture_context *tctx,
     892             :                                                          struct smb2_tree *tree1)
     893             : {
     894           0 :         const char *host = torture_setting_string(tctx, "host", NULL);
     895           0 :         const char *share = torture_setting_string(tctx, "share", NULL);
     896           0 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
     897             :         NTSTATUS status;
     898           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     899           0 :         struct test_multichannel_oplock_break_state state = {
     900             :                 .tctx = tctx,
     901             :         };
     902           0 :         struct test_multichannel_oplock_break_channel *open2_channel = NULL;
     903             :         struct smb2_handle _h;
     904           0 :         struct smb2_handle *h = NULL;
     905           0 :         struct smb2_handle h_client1_file1 = {{0}};
     906           0 :         struct smb2_handle h_client2_file1 = {{0}};
     907             :         struct smb2_create io1;
     908             :         struct smb2_create io2;
     909           0 :         bool ret = true;
     910           0 :         const char *fname1 = BASEDIR "\\oplock_break_test3w.dat";
     911           0 :         struct smb2_tree *trees2[32] = { NULL, };
     912             :         size_t i;
     913           0 :         struct smb2_transport *transport1 = tree1->session->transport;
     914             :         struct smbcli_options transport2_options;
     915           0 :         struct smb2_session *session1 = tree1->session;
     916           0 :         uint16_t local_port = 0;
     917           0 :         bool block_setup = false;
     918           0 :         bool block_ok = false;
     919             :         double open_duration;
     920             : 
     921           0 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
     922           0 :                 return true;
     923             :         }
     924             : 
     925           0 :         torture_comment(tctx, "Oplock break retry: Test3 (Windows behavior)\n");
     926             : 
     927           0 :         torture_reset_break_info(tctx, &break_info);
     928           0 :         break_info.oplock_skip_ack = true;
     929             : 
     930           0 :         transport1->oplock.handler = torture_oplock_ack_handler;
     931           0 :         transport1->oplock.private_data = tree1;
     932           0 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
     933           0 :         local_port = torture_get_local_port_from_transport(transport1);
     934           0 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
     935             : 
     936           0 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
     937           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     938           0 :         smb2_util_close(tree1, _h);
     939           0 :         smb2_util_unlink(tree1, fname1);
     940           0 :         CHECK_VAL(break_info.count, 0);
     941             : 
     942           0 :         smb2_oplock_create_share(&io2, fname1,
     943             :                         smb2_util_share_access("RWD"),
     944           0 :                         smb2_util_oplock_level("b"));
     945             : 
     946           0 :         transport2_options = transport1->options;
     947             : 
     948           0 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
     949             :                                                      &transport2_options,
     950             :                                                      ARRAY_SIZE(trees2), trees2);
     951           0 :         torture_assert(tctx, ret, "Could not create channels.\n");
     952             : 
     953           0 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
     954           0 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
     955           0 :                 struct smb2_transport *t = trees2[i]->session->transport;
     956             : 
     957           0 :                 c->state = &state;
     958           0 :                 c->idx = i+1;
     959           0 :                 c->tree = trees2[i];
     960           0 :                 snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
     961             : 
     962           0 :                 t->oplock.handler = test_multichannel_oplock_break_handler;
     963           0 :                 t->oplock.private_data = c;
     964             :         }
     965             : 
     966           0 :         open2_channel = &state.channels[0];
     967             : 
     968             :         /* 2a opens file1 */
     969           0 :         torture_comment(tctx, "client2 opens fname1 via %s\n",
     970           0 :                         open2_channel->name);
     971           0 :         status = smb2_create(open2_channel->tree, mem_ctx, &io2);
     972           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     973           0 :         h_client2_file1 = io2.out.file.handle;
     974           0 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     975           0 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
     976           0 :         CHECK_VAL(io2.out.durable_open_v2, false);
     977           0 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
     978           0 :         CHECK_VAL(io2.out.durable_open, false);
     979           0 :         CHECK_VAL(break_info.count, 0);
     980             : 
     981           0 :         block_setup = test_setup_blocked_transports(tctx);
     982           0 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
     983             : 
     984           0 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
     985           0 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
     986           0 :                 struct smb2_transport *t = c->tree->session->transport;
     987             : 
     988           0 :                 torture_comment(tctx, "Blocking %s\n", c->name);
     989           0 :                 block_ok = _test_block_smb2_transport(tctx, t, c->name);
     990           0 :                 torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
     991           0 :                 c->blocked = true;
     992             :         }
     993             : 
     994             :         /* 1 opens file2 */
     995           0 :         torture_comment(tctx,
     996             :                         "Client opens fname1 with session 1 with all %zu blocked\n",
     997             :                         ARRAY_SIZE(trees2));
     998           0 :         smb2_oplock_create_share(&io1, fname1,
     999             :                         smb2_util_share_access("RWD"),
    1000           0 :                         smb2_util_oplock_level("b"));
    1001           0 :         CHECK_VAL(lease_break_info.count, 0);
    1002           0 :         state.open_req_time = timeval_current();
    1003           0 :         state.last_break_time = state.open_req_time;
    1004           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    1005           0 :         state.open_rep_time = timeval_current();
    1006           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1007           0 :         h_client1_file1 = io1.out.file.handle;
    1008           0 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
    1009             : 
    1010           0 :         CHECK_VAL(break_info.count, 1);
    1011             : 
    1012           0 :         open_duration = timeval_elapsed2(&state.open_req_time,
    1013             :                                          &state.open_rep_time);
    1014           0 :         torture_comment(tctx, "open_duration: %f\n", open_duration);
    1015           0 :         CHECK_VAL_GREATER_THAN(open_duration, 35);
    1016             : 
    1017           0 :         if (break_info.count == 0) {
    1018           0 :                 torture_comment(tctx,
    1019             :                                 "Did not receive expected oplock break!!\n");
    1020             :         } else {
    1021           0 :                 torture_comment(tctx, "Received %d oplock break(s)!!\n",
    1022             :                                 break_info.count);
    1023             :         }
    1024             : 
    1025           0 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1026           0 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1027           0 :                 size_t expected_break_num = 0;
    1028             : 
    1029             :                 /*
    1030             :                  * Only the latest channel gets a break notification
    1031             :                  */
    1032           0 :                 if (i == (ARRAY_SIZE(state.channels) - 1)) {
    1033           0 :                         expected_break_num = 1;
    1034             :                 }
    1035             : 
    1036           0 :                 torture_comment(tctx, "Verify %s\n", c->name);
    1037           0 :                 torture_assert_int_equal(tctx, c->break_num, expected_break_num,
    1038             :                                          "Got oplock break on wrong channel");
    1039           0 :                 if (expected_break_num != 0) {
    1040           0 :                         CHECK_VAL(c->level, smb2_util_oplock_level("s"));
    1041             :                 }
    1042             :         }
    1043             : 
    1044           0 : done:
    1045           0 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1046           0 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1047           0 :                 struct smb2_transport *t = NULL;
    1048             : 
    1049           0 :                 if (!c->blocked) {
    1050           0 :                         continue;
    1051             :                 }
    1052             : 
    1053           0 :                 t = c->tree->session->transport;
    1054             : 
    1055           0 :                 torture_comment(tctx, "Unblocking %s\n", c->name);
    1056           0 :                 _test_unblock_smb2_transport(tctx, t, c->name);
    1057           0 :                 c->blocked = false;
    1058             :         }
    1059           0 :         if (block_setup) {
    1060           0 :                 test_cleanup_blocked_transports(tctx);
    1061             :         }
    1062             : 
    1063           0 :         tree1->session = session1;
    1064             : 
    1065           0 :         smb2_util_close(tree1, h_client1_file1);
    1066           0 :         if (trees2[0] != NULL) {
    1067           0 :                 smb2_util_close(trees2[0], h_client2_file1);
    1068             :         }
    1069             : 
    1070           0 :         if (h != NULL) {
    1071           0 :                 smb2_util_close(tree1, *h);
    1072             :         }
    1073             : 
    1074           0 :         smb2_util_unlink(tree1, fname1);
    1075           0 :         smb2_deltree(tree1, BASEDIR);
    1076             : 
    1077           0 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    1078           0 :                 if (trees2[i] == NULL) {
    1079           0 :                         continue;
    1080             :                 }
    1081           0 :                 TALLOC_FREE(trees2[i]);
    1082             :         }
    1083           0 :         talloc_free(tree1);
    1084           0 :         talloc_free(mem_ctx);
    1085             : 
    1086           0 :         return ret;
    1087             : }
    1088             : 
    1089           0 : static bool test_multichannel_oplock_break_test3_specification(struct torture_context *tctx,
    1090             :                                                                struct smb2_tree *tree1)
    1091             : {
    1092           0 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1093           0 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1094           0 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1095             :         NTSTATUS status;
    1096           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1097           0 :         struct test_multichannel_oplock_break_state state = {
    1098             :                 .tctx = tctx,
    1099             :         };
    1100           0 :         struct test_multichannel_oplock_break_channel *open2_channel = NULL;
    1101             :         struct smb2_handle _h;
    1102           0 :         struct smb2_handle *h = NULL;
    1103           0 :         struct smb2_handle h_client1_file1 = {{0}};
    1104           0 :         struct smb2_handle h_client2_file1 = {{0}};
    1105             :         struct smb2_create io1;
    1106             :         struct smb2_create io2;
    1107           0 :         bool ret = true;
    1108           0 :         const char *fname1 = BASEDIR "\\oplock_break_test3s.dat";
    1109           0 :         struct smb2_tree *trees2[32] = { NULL, };
    1110             :         size_t i;
    1111           0 :         struct smb2_transport *transport1 = tree1->session->transport;
    1112             :         struct smbcli_options transport2_options;
    1113           0 :         struct smb2_session *session1 = tree1->session;
    1114           0 :         uint16_t local_port = 0;
    1115           0 :         bool block_setup = false;
    1116           0 :         bool block_ok = false;
    1117             :         double open_duration;
    1118             : 
    1119           0 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1120           0 :                 return true;
    1121             :         }
    1122             : 
    1123           0 :         torture_comment(tctx, "Oplock break retry: Test3 (Specification behavior)\n");
    1124             : 
    1125           0 :         torture_reset_break_info(tctx, &break_info);
    1126           0 :         break_info.oplock_skip_ack = true;
    1127             : 
    1128           0 :         transport1->oplock.handler = torture_oplock_ack_handler;
    1129           0 :         transport1->oplock.private_data = tree1;
    1130           0 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1131           0 :         local_port = torture_get_local_port_from_transport(transport1);
    1132           0 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1133             : 
    1134           0 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1135           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1136           0 :         smb2_util_close(tree1, _h);
    1137           0 :         smb2_util_unlink(tree1, fname1);
    1138           0 :         CHECK_VAL(break_info.count, 0);
    1139             : 
    1140           0 :         smb2_oplock_create_share(&io2, fname1,
    1141             :                         smb2_util_share_access("RWD"),
    1142           0 :                         smb2_util_oplock_level("b"));
    1143             : 
    1144           0 :         transport2_options = transport1->options;
    1145             : 
    1146           0 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
    1147             :                                                      &transport2_options,
    1148             :                                                      ARRAY_SIZE(trees2), trees2);
    1149           0 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1150             : 
    1151           0 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    1152           0 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1153           0 :                 struct smb2_transport *t = trees2[i]->session->transport;
    1154             : 
    1155           0 :                 c->state = &state;
    1156           0 :                 c->idx = i+1;
    1157           0 :                 c->tree = trees2[i];
    1158           0 :                 snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
    1159             : 
    1160           0 :                 t->oplock.handler = test_multichannel_oplock_break_handler;
    1161           0 :                 t->oplock.private_data = c;
    1162             :         }
    1163             : 
    1164           0 :         open2_channel = &state.channels[0];
    1165             : 
    1166             :         /* 2a opens file1 */
    1167           0 :         torture_comment(tctx, "client2 opens fname1 via %s\n",
    1168           0 :                         open2_channel->name);
    1169           0 :         status = smb2_create(open2_channel->tree, mem_ctx, &io2);
    1170           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1171           0 :         h_client2_file1 = io2.out.file.handle;
    1172           0 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1173           0 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
    1174           0 :         CHECK_VAL(io2.out.durable_open_v2, false);
    1175           0 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
    1176           0 :         CHECK_VAL(io2.out.durable_open, false);
    1177           0 :         CHECK_VAL(break_info.count, 0);
    1178             : 
    1179           0 :         block_setup = test_setup_blocked_transports(tctx);
    1180           0 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
    1181             : 
    1182           0 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1183           0 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1184           0 :                 struct smb2_transport *t = c->tree->session->transport;
    1185             : 
    1186           0 :                 torture_comment(tctx, "Blocking %s\n", c->name);
    1187           0 :                 block_ok = _test_block_smb2_transport(tctx, t, c->name);
    1188           0 :                 torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
    1189           0 :                 c->blocked = true;
    1190             :         }
    1191             : 
    1192             :         /* 1 opens file2 */
    1193           0 :         torture_comment(tctx,
    1194             :                         "Client opens fname1 with session 1 with all %zu blocked\n",
    1195             :                         ARRAY_SIZE(trees2));
    1196           0 :         smb2_oplock_create_share(&io1, fname1,
    1197             :                         smb2_util_share_access("RWD"),
    1198           0 :                         smb2_util_oplock_level("b"));
    1199           0 :         CHECK_VAL(lease_break_info.count, 0);
    1200           0 :         state.open_req_time = timeval_current();
    1201           0 :         state.last_break_time = state.open_req_time;
    1202           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    1203           0 :         state.open_rep_time = timeval_current();
    1204           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1205           0 :         h_client1_file1 = io1.out.file.handle;
    1206             : 
    1207           0 :         CHECK_VAL_GREATER_THAN(break_info.count, 1);
    1208             : 
    1209           0 :         open_duration = timeval_elapsed2(&state.open_req_time,
    1210             :                                          &state.open_rep_time);
    1211           0 :         torture_comment(tctx, "open_duration: %f\n", open_duration);
    1212           0 :         if (break_info.count < ARRAY_SIZE(state.channels)) {
    1213           0 :                 CHECK_VAL_GREATER_THAN(open_duration, 35);
    1214           0 :                 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
    1215             :         } else {
    1216           0 :                 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
    1217             :         }
    1218             : 
    1219           0 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1220           0 :                 if (break_info.count >= ARRAY_SIZE(state.channels)) {
    1221           0 :                         break;
    1222             :                 }
    1223           0 :                 torture_comment(tctx, "Received %d oplock break(s) wait for more!!\n",
    1224             :                                 break_info.count);
    1225           0 :                 torture_wait_for_oplock_break(tctx);
    1226             :         }
    1227             : 
    1228           0 :         if (break_info.count == 0) {
    1229           0 :                 torture_comment(tctx,
    1230             :                                 "Did not receive expected oplock break!!\n");
    1231             :         } else {
    1232           0 :                 torture_comment(tctx, "Received %d oplock break(s)!!\n",
    1233             :                                 break_info.count);
    1234             :         }
    1235             : 
    1236           0 :         if (break_info.count < ARRAY_SIZE(state.channels)) {
    1237           0 :                 CHECK_VAL_GREATER_THAN(break_info.count, 3);
    1238             :         } else {
    1239           0 :                 CHECK_VAL(break_info.count, ARRAY_SIZE(state.channels));
    1240             :         }
    1241             : 
    1242           0 :         for (i = 0; i < break_info.count; i++) {
    1243           0 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1244             : 
    1245           0 :                 torture_comment(tctx, "Verify %s\n", c->name);
    1246           0 :                 torture_assert_int_equal(tctx, c->break_num, c->idx,
    1247             :                                          "Got oplock break on wrong channel");
    1248           0 :                 CHECK_VAL(c->level, smb2_util_oplock_level("s"));
    1249             :         }
    1250             : 
    1251           0 : done:
    1252           0 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1253           0 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1254           0 :                 struct smb2_transport *t = NULL;
    1255             : 
    1256           0 :                 if (!c->blocked) {
    1257           0 :                         continue;
    1258             :                 }
    1259             : 
    1260           0 :                 t = c->tree->session->transport;
    1261             : 
    1262           0 :                 torture_comment(tctx, "Unblocking %s\n", c->name);
    1263           0 :                 _test_unblock_smb2_transport(tctx, t, c->name);
    1264           0 :                 c->blocked = false;
    1265             :         }
    1266           0 :         if (block_setup) {
    1267           0 :                 test_cleanup_blocked_transports(tctx);
    1268             :         }
    1269             : 
    1270           0 :         tree1->session = session1;
    1271             : 
    1272           0 :         smb2_util_close(tree1, h_client1_file1);
    1273           0 :         if (trees2[0] != NULL) {
    1274           0 :                 smb2_util_close(trees2[0], h_client2_file1);
    1275             :         }
    1276             : 
    1277           0 :         if (h != NULL) {
    1278           0 :                 smb2_util_close(tree1, *h);
    1279             :         }
    1280             : 
    1281           0 :         smb2_util_unlink(tree1, fname1);
    1282           0 :         smb2_deltree(tree1, BASEDIR);
    1283             : 
    1284           0 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    1285           0 :                 if (trees2[i] == NULL) {
    1286           0 :                         continue;
    1287             :                 }
    1288           0 :                 TALLOC_FREE(trees2[i]);
    1289             :         }
    1290           0 :         talloc_free(tree1);
    1291           0 :         talloc_free(mem_ctx);
    1292             : 
    1293           0 :         return ret;
    1294             : }
    1295             : 
    1296             : static const uint64_t LEASE1F1 = 0xBADC0FFEE0DDF00Dull;
    1297             : static const uint64_t LEASE1F2 = 0xBADC0FFEE0DDD00Dull;
    1298             : static const uint64_t LEASE1F3 = 0xDADC0FFEE0DDD00Dull;
    1299             : static const uint64_t LEASE2F1 = 0xDEADBEEFFEEDBEADull;
    1300             : static const uint64_t LEASE2F2 = 0xDAD0FFEDD00DF00Dull;
    1301             : static const uint64_t LEASE2F3 = 0xBAD0FFEDD00DF00Dull;
    1302             : 
    1303             : /*
    1304             :  * Lease Break Test 1:
    1305             :  * Test to check if lease breaks are sent by the server as expected.
    1306             :  *      open file1 in session 2A
    1307             :  *      open file2 in session 2B
    1308             :  *      open file3 in session 2C
    1309             :  *      open file1 in session 1
    1310             :  *           lease break sent
    1311             :  *      open file2 in session 1
    1312             :  *           lease break sent
    1313             :  *      open file3 in session 1
    1314             :  *           lease break sent
    1315             :  */
    1316           0 : static bool test_multichannel_lease_break_test1(struct torture_context *tctx,
    1317             :                                                 struct smb2_tree *tree1)
    1318             : {
    1319           0 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1320           0 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1321           0 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1322             :         NTSTATUS status;
    1323           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1324             :         struct smb2_handle _h;
    1325           0 :         struct smb2_handle *h = NULL;
    1326           0 :         struct smb2_handle h_client1_file1 = {{0}};
    1327           0 :         struct smb2_handle h_client1_file2 = {{0}};
    1328           0 :         struct smb2_handle h_client1_file3 = {{0}};
    1329           0 :         struct smb2_handle h_client2_file1 = {{0}};
    1330           0 :         struct smb2_handle h_client2_file2 = {{0}};
    1331           0 :         struct smb2_handle h_client2_file3 = {{0}};
    1332             :         struct smb2_create io1, io2, io3;
    1333           0 :         bool ret = true;
    1334           0 :         const char *fname1 = BASEDIR "\\lease_break_test1.dat";
    1335           0 :         const char *fname2 = BASEDIR "\\lease_break_test2.dat";
    1336           0 :         const char *fname3 = BASEDIR "\\lease_break_test3.dat";
    1337           0 :         struct smb2_tree *tree2A = NULL;
    1338           0 :         struct smb2_tree *tree2B = NULL;
    1339           0 :         struct smb2_tree *tree2C = NULL;
    1340           0 :         struct smb2_transport *transport1 = tree1->session->transport;
    1341             :         struct smbcli_options transport2_options;
    1342           0 :         struct smb2_session *session1 = tree1->session;
    1343           0 :         uint16_t local_port = 0;
    1344             :         struct smb2_lease ls1;
    1345             :         struct smb2_lease ls2;
    1346             :         struct smb2_lease ls3;
    1347             : 
    1348           0 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1349           0 :                 return true;
    1350             :         }
    1351             : 
    1352           0 :         torture_comment(tctx, "Lease break retry: Test1\n");
    1353             : 
    1354           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1355             : 
    1356           0 :         transport1->lease.handler = torture_lease_handler;
    1357           0 :         transport1->lease.private_data = tree1;
    1358           0 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1359           0 :         local_port = torture_get_local_port_from_transport(transport1);
    1360           0 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1361             : 
    1362           0 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1363           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1364           0 :         smb2_util_close(tree1, _h);
    1365           0 :         smb2_util_unlink(tree1, fname1);
    1366           0 :         smb2_util_unlink(tree1, fname2);
    1367           0 :         smb2_util_unlink(tree1, fname3);
    1368           0 :         CHECK_VAL(lease_break_info.count, 0);
    1369             : 
    1370           0 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1371             :                           smb2_util_lease_state("RHW"));
    1372           0 :         test_multichannel_init_smb_create(&io1);
    1373             : 
    1374           0 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
    1375             :                           smb2_util_lease_state("RHW"));
    1376           0 :         test_multichannel_init_smb_create(&io2);
    1377             : 
    1378           0 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1379             :                           smb2_util_lease_state("RHW"));
    1380           0 :         test_multichannel_init_smb_create(&io3);
    1381             : 
    1382           0 :         transport2_options = transport1->options;
    1383             : 
    1384           0 :         ret = test_multichannel_create_channels(tctx, host, share,
    1385             :                                                   credentials,
    1386             :                                                   &transport2_options,
    1387             :                                                   &tree2A, &tree2B, &tree2C);
    1388           0 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1389             : 
    1390             :         /* 2a opens file1 */
    1391           0 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
    1392           0 :         status = smb2_create(tree2A, mem_ctx, &io1);
    1393           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1394           0 :         h_client2_file1 = io1.out.file.handle;
    1395           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1396           0 :         CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
    1397           0 :         CHECK_VAL(lease_break_info.count, 0);
    1398             : 
    1399             :         /* 2b opens file2 */
    1400           0 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
    1401           0 :         status = smb2_create(tree2B, mem_ctx, &io2);
    1402           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1403           0 :         h_client2_file2 = io2.out.file.handle;
    1404           0 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1405           0 :         CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
    1406           0 :         CHECK_VAL(lease_break_info.count, 0);
    1407             : 
    1408             :         /* 2c opens file3 */
    1409           0 :         torture_comment(tctx, "client2 opens fname3 via session 2C\n");
    1410           0 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1411             :                           smb2_util_lease_state("RHW"));
    1412           0 :         status = smb2_create(tree2C, mem_ctx, &io3);
    1413           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1414           0 :         h_client2_file3 = io3.out.file.handle;
    1415           0 :         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1416           0 :         CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
    1417           0 :         CHECK_VAL(lease_break_info.count, 0);
    1418             : 
    1419             :         /* 1 opens file1 - lease break? */
    1420           0 :         torture_comment(tctx, "client1 opens fname1 via session 1\n");
    1421           0 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
    1422             :                           smb2_util_lease_state("RHW"));
    1423           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    1424           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1425           0 :         h_client1_file1 = io1.out.file.handle;
    1426           0 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1427           0 :         CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
    1428           0 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
    1429           0 :         CHECK_VAL(lease_break_info.count, 1);
    1430             : 
    1431           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1432             : 
    1433             :         /* 1 opens file2 - lease break? */
    1434           0 :         torture_comment(tctx, "client1 opens fname2 via session 1\n");
    1435           0 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
    1436             :                           smb2_util_lease_state("RHW"));
    1437           0 :         status = smb2_create(tree1, mem_ctx, &io2);
    1438           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1439           0 :         h_client1_file2 = io2.out.file.handle;
    1440           0 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1441           0 :         CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
    1442           0 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
    1443           0 :         CHECK_VAL(lease_break_info.count, 1);
    1444             : 
    1445           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1446             : 
    1447             :         /* 1 opens file3 - lease break? */
    1448           0 :         torture_comment(tctx, "client1 opens fname3 via session 1\n");
    1449           0 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
    1450             :                           smb2_util_lease_state("RHW"));
    1451           0 :         status = smb2_create(tree1, mem_ctx, &io3);
    1452           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1453           0 :         h_client1_file3 = io3.out.file.handle;
    1454           0 :         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1455           0 :         CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
    1456           0 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
    1457           0 :         CHECK_VAL(lease_break_info.count, 1);
    1458             : 
    1459             :         /* cleanup everything */
    1460           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1461             : 
    1462           0 :         smb2_util_close(tree1, h_client1_file1);
    1463           0 :         smb2_util_close(tree1, h_client1_file2);
    1464           0 :         smb2_util_close(tree1, h_client1_file3);
    1465           0 :         smb2_util_close(tree2A, h_client2_file1);
    1466           0 :         smb2_util_close(tree2A, h_client2_file2);
    1467           0 :         smb2_util_close(tree2A, h_client2_file3);
    1468             : 
    1469           0 :         smb2_util_unlink(tree1, fname1);
    1470           0 :         smb2_util_unlink(tree1, fname2);
    1471           0 :         smb2_util_unlink(tree1, fname3);
    1472           0 :         CHECK_VAL(lease_break_info.count, 0);
    1473           0 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1474           0 :         tree2A = tree2B = tree2C = NULL;
    1475           0 : done:
    1476           0 :         tree1->session = session1;
    1477             : 
    1478           0 :         smb2_util_close(tree1, h_client1_file1);
    1479           0 :         smb2_util_close(tree1, h_client1_file2);
    1480           0 :         smb2_util_close(tree1, h_client1_file3);
    1481           0 :         if (tree2A != NULL) {
    1482           0 :                 smb2_util_close(tree2A, h_client2_file1);
    1483           0 :                 smb2_util_close(tree2A, h_client2_file2);
    1484           0 :                 smb2_util_close(tree2A, h_client2_file3);
    1485             :         }
    1486             : 
    1487           0 :         if (h != NULL) {
    1488           0 :                 smb2_util_close(tree1, *h);
    1489             :         }
    1490             : 
    1491           0 :         smb2_util_unlink(tree1, fname1);
    1492           0 :         smb2_util_unlink(tree1, fname2);
    1493           0 :         smb2_util_unlink(tree1, fname3);
    1494           0 :         smb2_deltree(tree1, BASEDIR);
    1495             : 
    1496           0 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1497           0 :         talloc_free(tree1);
    1498           0 :         talloc_free(mem_ctx);
    1499             : 
    1500           0 :         return ret;
    1501             : }
    1502             : 
    1503             : /*
    1504             :  * Lease Break Test 2:
    1505             :  * Test for lease break retries being sent by the server.
    1506             :  *      Connect 2A, 2B
    1507             :  *      open file1 in session 2A
    1508             :  *      open file2 in session 2B
    1509             :  *      block 2A
    1510             :  *      open file2 in session 1
    1511             :  *           lease break retry reaches the client?
    1512             :  *      Connect 2C
    1513             :  *      open file3 in session 2C
    1514             :  *      unblock 2A
    1515             :  *      open file1 in session 1
    1516             :  *           lease break reaches the client?
    1517             :  *      open file3 in session 1
    1518             :  *           lease break reached the client?
    1519             :  *      Cleanup
    1520             :  *           On deletion by 1, lease breaks sent for file1, file2 and file3
    1521             :  *           on 2B
    1522             :  *           This changes RH lease to R for Session 2.
    1523             :  *           (This has been disabled while we add support for sending lease
    1524             :  *            break for handle leases.)
    1525             :  */
    1526           0 : static bool test_multichannel_lease_break_test2(struct torture_context *tctx,
    1527             :                                                 struct smb2_tree *tree1)
    1528             : {
    1529           0 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1530           0 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1531           0 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1532             :         NTSTATUS status;
    1533           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1534             :         struct smb2_handle _h;
    1535           0 :         struct smb2_handle *h = NULL;
    1536           0 :         struct smb2_handle h_client1_file1 = {{0}};
    1537           0 :         struct smb2_handle h_client1_file2 = {{0}};
    1538           0 :         struct smb2_handle h_client1_file3 = {{0}};
    1539           0 :         struct smb2_handle h_client2_file1 = {{0}};
    1540           0 :         struct smb2_handle h_client2_file2 = {{0}};
    1541           0 :         struct smb2_handle h_client2_file3 = {{0}};
    1542             :         struct smb2_create io1, io2, io3;
    1543           0 :         bool ret = true;
    1544           0 :         const char *fname1 = BASEDIR "\\lease_break_test1.dat";
    1545           0 :         const char *fname2 = BASEDIR "\\lease_break_test2.dat";
    1546           0 :         const char *fname3 = BASEDIR "\\lease_break_test3.dat";
    1547           0 :         struct smb2_tree *tree2A = NULL;
    1548           0 :         struct smb2_tree *tree2B = NULL;
    1549           0 :         struct smb2_tree *tree2C = NULL;
    1550           0 :         struct smb2_transport *transport1 = tree1->session->transport;
    1551           0 :         struct smb2_transport *transport2A = NULL;
    1552             :         struct smbcli_options transport2_options;
    1553           0 :         struct smb2_session *session1 = tree1->session;
    1554           0 :         uint16_t local_port = 0;
    1555             :         struct smb2_lease ls1;
    1556             :         struct smb2_lease ls2;
    1557             :         struct smb2_lease ls3;
    1558           0 :         bool block_setup = false;
    1559           0 :         bool block_ok = false;
    1560           0 :         bool unblock_ok = false;
    1561             : 
    1562             : 
    1563           0 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1564           0 :                 return true;
    1565             :         }
    1566             : 
    1567           0 :         torture_comment(tctx, "Lease break retry: Test2\n");
    1568             : 
    1569           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1570             : 
    1571           0 :         transport1->lease.handler = torture_lease_handler;
    1572           0 :         transport1->lease.private_data = tree1;
    1573           0 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1574           0 :         local_port = torture_get_local_port_from_transport(transport1);
    1575           0 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1576             : 
    1577           0 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1578           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1579           0 :         smb2_util_close(tree1, _h);
    1580           0 :         smb2_util_unlink(tree1, fname1);
    1581           0 :         smb2_util_unlink(tree1, fname2);
    1582           0 :         smb2_util_unlink(tree1, fname3);
    1583           0 :         CHECK_VAL(lease_break_info.count, 0);
    1584             : 
    1585           0 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1586             :                           smb2_util_lease_state("RHW"));
    1587           0 :         test_multichannel_init_smb_create(&io1);
    1588             : 
    1589           0 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
    1590             :                           smb2_util_lease_state("RHW"));
    1591           0 :         test_multichannel_init_smb_create(&io2);
    1592             : 
    1593           0 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1594             :                           smb2_util_lease_state("RHW"));
    1595           0 :         test_multichannel_init_smb_create(&io3);
    1596             : 
    1597           0 :         transport2_options = transport1->options;
    1598             : 
    1599           0 :         ret = test_multichannel_create_channels(tctx, host, share,
    1600             :                                                   credentials,
    1601             :                                                   &transport2_options,
    1602             :                                                   &tree2A, &tree2B, NULL);
    1603           0 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1604           0 :         transport2A = tree2A->session->transport;
    1605             : 
    1606             :         /* 2a opens file1 */
    1607           0 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
    1608           0 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1609             :                           smb2_util_lease_state("RHW"));
    1610           0 :         status = smb2_create(tree2A, mem_ctx, &io1);
    1611           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1612           0 :         h_client2_file1 = io1.out.file.handle;
    1613           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1614           0 :         CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
    1615           0 :         CHECK_VAL(io1.out.durable_open_v2, false); //true);
    1616           0 :         CHECK_VAL(io1.out.timeout, io1.in.timeout);
    1617           0 :         CHECK_VAL(io1.out.durable_open, false);
    1618           0 :         CHECK_VAL(lease_break_info.count, 0);
    1619             : 
    1620             :         /* 2b opens file2 */
    1621           0 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
    1622           0 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
    1623             :                           smb2_util_lease_state("RHW"));
    1624           0 :         status = smb2_create(tree2B, mem_ctx, &io2);
    1625           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1626           0 :         h_client2_file2 = io2.out.file.handle;
    1627           0 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1628           0 :         CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
    1629           0 :         CHECK_VAL(io2.out.durable_open_v2, false); //true);
    1630           0 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
    1631           0 :         CHECK_VAL(io2.out.durable_open, false);
    1632           0 :         CHECK_VAL(lease_break_info.count, 0);
    1633             : 
    1634           0 :         block_setup = test_setup_blocked_transports(tctx);
    1635           0 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
    1636             : 
    1637           0 :         torture_comment(tctx, "Blocking 2A\n");
    1638             :         /* Block 2A */
    1639           0 :         block_ok = test_block_smb2_transport(tctx, transport2A);
    1640           0 :         torture_assert(tctx, block_ok, "we could not block tcp transport");
    1641             : 
    1642           0 :         torture_wait_for_lease_break(tctx);
    1643           0 :         CHECK_VAL(lease_break_info.count, 0);
    1644             : 
    1645             :         /* 1 opens file2 */
    1646           0 :         torture_comment(tctx,
    1647             :                         "Client opens fname2 with session1 with 2A blocked\n");
    1648           0 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
    1649             :                           smb2_util_lease_state("RHW"));
    1650           0 :         status = smb2_create(tree1, mem_ctx, &io2);
    1651           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1652           0 :         h_client1_file2 = io2.out.file.handle;
    1653           0 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1654           0 :         CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
    1655           0 :         CHECK_VAL(io2.out.durable_open_v2, false);
    1656           0 :         CHECK_VAL(io2.out.timeout, 0);
    1657           0 :         CHECK_VAL(io2.out.durable_open, false);
    1658             : 
    1659           0 :         if (lease_break_info.count == 0) {
    1660           0 :                 torture_comment(tctx,
    1661             :                                 "Did not receive expected lease break!!\n");
    1662             :         } else {
    1663           0 :                 torture_comment(tctx, "Received %d lease break(s)!!\n",
    1664             :                                 lease_break_info.count);
    1665             :         }
    1666             : 
    1667             :         /*
    1668             :          * We got breaks on both channels
    1669             :          * (one failed on the blocked connection)
    1670             :          */
    1671           0 :         CHECK_VAL(lease_break_info.count, 2);
    1672           0 :         lease_break_info.count -= 1;
    1673           0 :         CHECK_VAL(lease_break_info.failures, 1);
    1674           0 :         lease_break_info.failures -= 1;
    1675           0 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
    1676           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1677             : 
    1678             :         /* Connect 2C */
    1679           0 :         torture_comment(tctx, "Connecting session 2C\n");
    1680           0 :         talloc_free(tree2C);
    1681           0 :         tree2C = test_multichannel_create_channel(tctx, host, share,
    1682             :                                 credentials, &transport2_options, tree2A);
    1683           0 :         if (!tree2C) {
    1684           0 :                 goto done;
    1685             :         }
    1686             : 
    1687             :         /* 2c opens file3 */
    1688           0 :         torture_comment(tctx, "client2 opens fname3 via session 2C\n");
    1689           0 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1690             :                           smb2_util_lease_state("RHW"));
    1691           0 :         status = smb2_create(tree2C, mem_ctx, &io3);
    1692           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1693           0 :         h_client2_file3 = io3.out.file.handle;
    1694           0 :         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1695           0 :         CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
    1696           0 :         CHECK_VAL(io3.out.durable_open_v2, false);
    1697           0 :         CHECK_VAL(io3.out.timeout, io2.in.timeout);
    1698           0 :         CHECK_VAL(io3.out.durable_open, false);
    1699           0 :         CHECK_VAL(lease_break_info.count, 0);
    1700             : 
    1701             :         /* Unblock 2A */
    1702           0 :         torture_comment(tctx, "Unblocking 2A\n");
    1703           0 :         unblock_ok = test_unblock_smb2_transport(tctx, transport2A);
    1704           0 :         torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
    1705             : 
    1706             :         /* 1 opens file1 */
    1707           0 :         torture_comment(tctx, "Client opens fname1 with session 1\n");
    1708           0 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
    1709             :                           smb2_util_lease_state("RHW"));
    1710           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    1711           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1712           0 :         h_client1_file1 = io1.out.file.handle;
    1713           0 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1714           0 :         CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
    1715             : 
    1716           0 :         if (lease_break_info.count == 0) {
    1717           0 :                 torture_comment(tctx,
    1718             :                                 "Did not receive expected lease break!!\n");
    1719             :         } else {
    1720           0 :                 torture_comment(tctx,
    1721             :                                 "Received %d lease break(s)!!\n",
    1722             :                                 lease_break_info.count);
    1723             :         }
    1724           0 :         CHECK_VAL(lease_break_info.count, 1);
    1725           0 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
    1726           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1727             : 
    1728             :         /*1 opens file3 */
    1729           0 :         torture_comment(tctx, "client opens fname3 via session 1\n");
    1730             : 
    1731           0 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
    1732             :                           smb2_util_lease_state("RHW"));
    1733           0 :         status = smb2_create(tree1, mem_ctx, &io3);
    1734           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1735           0 :         h_client1_file3 = io3.out.file.handle;
    1736           0 :         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1737           0 :         CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
    1738             : 
    1739           0 :         if (lease_break_info.count == 0) {
    1740           0 :                 torture_comment(tctx,
    1741             :                                 "Did not receive expected lease break!!\n");
    1742             :         } else {
    1743           0 :                 torture_comment(tctx,
    1744             :                                 "Received %d lease break(s)!!\n",
    1745             :                                 lease_break_info.count);
    1746             :         }
    1747           0 :         CHECK_VAL(lease_break_info.count, 1);
    1748           0 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
    1749           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1750             : 
    1751           0 :         smb2_util_close(tree1, h_client1_file1);
    1752           0 :         smb2_util_close(tree1, h_client1_file2);
    1753           0 :         smb2_util_close(tree1, h_client1_file3);
    1754             : 
    1755             :         /*
    1756             :          * Session 2 still has RW lease on file 1. Deletion of this file by 1
    1757             :          *  leads to a lease break call to session 2 file1
    1758             :          */
    1759           0 :         smb2_util_unlink(tree1, fname1);
    1760             :         /*
    1761             :          * Bug - Samba does not revoke Handle lease on unlink
    1762             :          * CHECK_BREAK_INFO("RH", "R", LEASE2F1);
    1763             :          */
    1764           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1765             : 
    1766             :         /*
    1767             :          * Session 2 still has RW lease on file 2. Deletion of this file by 1
    1768             :          *  leads to a lease break call to session 2 file2
    1769             :          */
    1770           0 :         smb2_util_unlink(tree1, fname2);
    1771             :         /*
    1772             :          * Bug - Samba does not revoke Handle lease on unlink
    1773             :          * CHECK_BREAK_INFO("RH", "R", LEASE2F2);
    1774             :          */
    1775           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1776             : 
    1777             :         /*
    1778             :          * Session 2 still has RW lease on file 3. Deletion of this file by 1
    1779             :          *  leads to a lease break call to session 2 file3
    1780             :          */
    1781           0 :         smb2_util_unlink(tree1, fname3);
    1782             :         /*
    1783             :          * Bug - Samba does not revoke Handle lease on unlink
    1784             :          * CHECK_BREAK_INFO("RH", "R", LEASE2F3);
    1785             :          */
    1786           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1787             : 
    1788           0 :         smb2_util_close(tree2C, h_client2_file1);
    1789           0 :         smb2_util_close(tree2C, h_client2_file2);
    1790           0 :         smb2_util_close(tree2C, h_client2_file3);
    1791             : 
    1792           0 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1793           0 :         tree2A = tree2B = tree2C = NULL;
    1794             : 
    1795           0 : done:
    1796           0 :         if (block_ok && !unblock_ok) {
    1797           0 :                 test_unblock_smb2_transport(tctx, transport2A);
    1798             :         }
    1799           0 :         if (block_setup) {
    1800           0 :                 test_cleanup_blocked_transports(tctx);
    1801             :         }
    1802             : 
    1803           0 :         tree1->session = session1;
    1804             : 
    1805           0 :         smb2_util_close(tree1, h_client1_file1);
    1806           0 :         smb2_util_close(tree1, h_client1_file2);
    1807           0 :         smb2_util_close(tree1, h_client1_file3);
    1808           0 :         if (tree2A != NULL) {
    1809           0 :                 smb2_util_close(tree2A, h_client2_file1);
    1810           0 :                 smb2_util_close(tree2A, h_client2_file2);
    1811           0 :                 smb2_util_close(tree2A, h_client2_file3);
    1812             :         }
    1813             : 
    1814           0 :         if (h != NULL) {
    1815           0 :                 smb2_util_close(tree1, *h);
    1816             :         }
    1817             : 
    1818           0 :         smb2_util_unlink(tree1, fname1);
    1819           0 :         smb2_util_unlink(tree1, fname2);
    1820           0 :         smb2_util_unlink(tree1, fname3);
    1821           0 :         smb2_deltree(tree1, BASEDIR);
    1822             : 
    1823           0 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1824           0 :         talloc_free(tree1);
    1825           0 :         talloc_free(mem_ctx);
    1826             : 
    1827           0 :         return ret;
    1828             : }
    1829             : 
    1830             : /*
    1831             :  * Test 3: Check to see how the server behaves if lease break
    1832             :  *      response is sent over a different channel to one over which
    1833             :  *      the break is received.
    1834             :  *      Connect 2A, 2B
    1835             :  *      open file1 in session 2A
    1836             :  *      open file1 in session 1
    1837             :  *           Lease break sent to 2A
    1838             :  *           2B sends back lease break reply.
    1839             :  *      session 1 allowed to open file
    1840             :  */
    1841           0 : static bool test_multichannel_lease_break_test3(struct torture_context *tctx,
    1842             :                                                 struct smb2_tree *tree1)
    1843             : {
    1844           0 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1845           0 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1846           0 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1847             :         NTSTATUS status;
    1848           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1849             :         struct smb2_handle _h;
    1850           0 :         struct smb2_handle *h = NULL;
    1851           0 :         struct smb2_handle h_client1_file1 = {{0}};
    1852           0 :         struct smb2_handle h_client2_file1 = {{0}};
    1853             :         struct smb2_create io1;
    1854           0 :         bool ret = true;
    1855           0 :         const char *fname1 = BASEDIR "\\lease_break_test1.dat";
    1856           0 :         struct smb2_tree *tree2A = NULL;
    1857           0 :         struct smb2_tree *tree2B = NULL;
    1858           0 :         struct smb2_transport *transport1 = tree1->session->transport;
    1859           0 :         struct smb2_transport *transport2A = NULL;
    1860             :         struct smbcli_options transport2_options;
    1861           0 :         uint16_t local_port = 0;
    1862             :         struct smb2_lease ls1;
    1863           0 :         struct tevent_timer *te = NULL;
    1864             :         struct timeval ne;
    1865           0 :         bool timesup = false;
    1866           0 :         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
    1867             : 
    1868           0 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1869           0 :                 return true;
    1870             :         }
    1871             : 
    1872           0 :         torture_comment(tctx, "Lease break retry: Test3\n");
    1873             : 
    1874           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1875             : 
    1876           0 :         transport1->lease.handler = torture_lease_handler;
    1877           0 :         transport1->lease.private_data = tree1;
    1878           0 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1879           0 :         local_port = torture_get_local_port_from_transport(transport1);
    1880           0 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1881             : 
    1882           0 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1883           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1884           0 :         smb2_util_close(tree1, _h);
    1885           0 :         smb2_util_unlink(tree1, fname1);
    1886           0 :         CHECK_VAL(lease_break_info.count, 0);
    1887             : 
    1888           0 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1889             :                           smb2_util_lease_state("RHW"));
    1890           0 :         test_multichannel_init_smb_create(&io1);
    1891             : 
    1892           0 :         transport2_options = transport1->options;
    1893             : 
    1894           0 :         ret = test_multichannel_create_channels(tctx, host, share,
    1895             :                                                 credentials,
    1896             :                                                 &transport2_options,
    1897             :                                                 &tree2A, &tree2B, NULL);
    1898           0 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1899           0 :         transport2A = tree2A->session->transport;
    1900           0 :         transport2A->lease.private_data = tree2B;
    1901             : 
    1902             :         /* 2a opens file1 */
    1903           0 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
    1904           0 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1905             :                           smb2_util_lease_state("RHW"));
    1906           0 :         status = smb2_create(tree2A, mem_ctx, &io1);
    1907           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1908           0 :         h_client2_file1 = io1.out.file.handle;
    1909           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1910           0 :         CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
    1911           0 :         CHECK_VAL(io1.out.durable_open_v2, false); //true);
    1912           0 :         CHECK_VAL(io1.out.timeout, io1.in.timeout);
    1913           0 :         CHECK_VAL(io1.out.durable_open, false);
    1914           0 :         CHECK_VAL(lease_break_info.count, 0);
    1915             : 
    1916             :         /* Set a timeout for 5 seconds for session 1 to open file1 */
    1917           0 :         ne = tevent_timeval_current_ofs(0, 5000000);
    1918           0 :         te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup);
    1919           0 :         if (te == NULL) {
    1920           0 :                 torture_comment(tctx, "Failed to add timer.");
    1921           0 :                 goto done;
    1922             :         }
    1923             : 
    1924             :         /* 1 opens file2 */
    1925           0 :         torture_comment(tctx, "Client opens fname1 with session 1\n");
    1926           0 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
    1927             :                           smb2_util_lease_state("RHW"));
    1928           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    1929           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1930           0 :         h_client1_file1 = io1.out.file.handle;
    1931           0 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1932           0 :         CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
    1933           0 :         CHECK_VAL(io1.out.durable_open_v2, false);
    1934           0 :         CHECK_VAL(io1.out.timeout, 0);
    1935           0 :         CHECK_VAL(io1.out.durable_open, false);
    1936             : 
    1937           0 :         CHECK_VAL(lease_break_info.count, 1);
    1938           0 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
    1939             : 
    1940             :         /*
    1941             :          * Check if timeout handler was fired. This would indicate
    1942             :          * that the server didn't receive a reply for the oplock break
    1943             :          * from the client and the server let session 1 open the file
    1944             :          * only after the oplock break timeout.
    1945             :          */
    1946           0 :         CHECK_VAL(timesup, false);
    1947             : 
    1948           0 : done:
    1949           0 :         smb2_util_close(tree1, h_client1_file1);
    1950           0 :         if (tree2A != NULL) {
    1951           0 :                 smb2_util_close(tree2A, h_client2_file1);
    1952             :         }
    1953             : 
    1954           0 :         if (h != NULL) {
    1955           0 :                 smb2_util_close(tree1, *h);
    1956             :         }
    1957             : 
    1958           0 :         smb2_util_unlink(tree1, fname1);
    1959           0 :         smb2_deltree(tree1, BASEDIR);
    1960             : 
    1961           0 :         test_multichannel_free_channels(tree2A, tree2B, NULL);
    1962           0 :         talloc_free(tree1);
    1963           0 :         talloc_free(mem_ctx);
    1964             : 
    1965           0 :         return ret;
    1966             : }
    1967             : 
    1968             : /*
    1969             :  * Test limits of channels
    1970             :  */
    1971           0 : static bool test_multichannel_num_channels(struct torture_context *tctx,
    1972             :                                            struct smb2_tree *tree1)
    1973             : {
    1974           0 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1975           0 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1976           0 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1977           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1978           0 :         bool ret = true;
    1979           0 :         struct smb2_tree **tree2 = NULL;
    1980           0 :         struct smb2_transport *transport1 = tree1->session->transport;
    1981           0 :         struct smb2_transport **transport2 = NULL;
    1982             :         struct smbcli_options transport2_options;
    1983           0 :         struct smb2_session **session2 = NULL;
    1984             :         uint32_t server_capabilities;
    1985             :         int i;
    1986           0 :         int max_channels = 33; /* 32 is the W2K12R2 and W2K16 limit */
    1987             : 
    1988           0 :         if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
    1989           0 :                 torture_fail(tctx,
    1990             :                              "SMB 3.X Dialect family required for Multichannel"
    1991             :                              " tests\n");
    1992             :         }
    1993             : 
    1994           0 :         server_capabilities = smb2cli_conn_server_capabilities(
    1995           0 :                                         tree1->session->transport->conn);
    1996           0 :         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
    1997           0 :                 torture_fail(tctx,
    1998             :                              "Server does not support multichannel.");
    1999             :         }
    2000             : 
    2001           0 :         torture_comment(tctx, "Testing max. number of channels\n");
    2002             : 
    2003           0 :         transport2_options = transport1->options;
    2004           0 :         transport2_options.client_guid = GUID_random();
    2005             : 
    2006           0 :         tree2           = talloc_zero_array(mem_ctx, struct smb2_tree *,
    2007             :                                             max_channels);
    2008           0 :         transport2      = talloc_zero_array(mem_ctx, struct smb2_transport *,
    2009             :                                             max_channels);
    2010           0 :         session2        = talloc_zero_array(mem_ctx, struct smb2_session *,
    2011             :                                             max_channels);
    2012           0 :         if (tree2 == NULL || transport2 == NULL || session2 == NULL) {
    2013           0 :                 torture_fail(tctx, "out of memory");
    2014             :         }
    2015             : 
    2016           0 :         for (i = 0; i < max_channels; i++) {
    2017             : 
    2018             :                 NTSTATUS expected_status;
    2019             : 
    2020           0 :                 torture_assert_ntstatus_ok_goto(tctx,
    2021             :                         smb2_connect(tctx,
    2022             :                                 host,
    2023             :                                 lpcfg_smb_ports(tctx->lp_ctx),
    2024             :                                 share,
    2025             :                                 lpcfg_resolve_context(tctx->lp_ctx),
    2026             :                                 credentials,
    2027             :                                 &tree2[i],
    2028             :                                 tctx->ev,
    2029             :                                 &transport2_options,
    2030             :                                 lpcfg_socket_options(tctx->lp_ctx),
    2031             :                                 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
    2032             :                                 ),
    2033             :                         ret, done, "smb2_connect failed");
    2034             : 
    2035           0 :                 transport2[i] = tree2[i]->session->transport;
    2036             : 
    2037           0 :                 if (i == 0) {
    2038             :                         /*
    2039             :                          * done for the 1st channel
    2040             :                          *
    2041             :                          * For all remaining channels we do the
    2042             :                          * session setup on our own.
    2043             :                          */
    2044           0 :                         transport2_options.only_negprot = true;
    2045           0 :                         continue;
    2046             :                 }
    2047             : 
    2048             :                 /*
    2049             :                  * Now bind the session2[i] to the transport2
    2050             :                  */
    2051           0 :                 session2[i] = smb2_session_channel(transport2[i],
    2052             :                                                    lpcfg_gensec_settings(tctx,
    2053             :                                                                  tctx->lp_ctx),
    2054             :                                                    tree2[0],
    2055           0 :                                                    tree2[0]->session);
    2056             : 
    2057           0 :                 torture_assert(tctx, session2[i] != NULL,
    2058             :                                "smb2_session_channel failed");
    2059             : 
    2060           0 :                 torture_comment(tctx, "established transport2 [#%d]\n", i);
    2061             : 
    2062           0 :                 if (i >= 32) {
    2063           0 :                         expected_status = NT_STATUS_INSUFFICIENT_RESOURCES;
    2064             :                 } else {
    2065           0 :                         expected_status = NT_STATUS_OK;
    2066             :                 }
    2067             : 
    2068           0 :                 torture_assert_ntstatus_equal_goto(tctx,
    2069             :                         smb2_session_setup_spnego(session2[i],
    2070             :                                 samba_cmdline_get_creds(),
    2071             :                                 0 /* previous_session_id */),
    2072             :                         expected_status,
    2073             :                         ret, done,
    2074             :                         talloc_asprintf(tctx, "failed to establish session "
    2075             :                                               "setup for channel #%d", i));
    2076             : 
    2077           0 :                 torture_comment(tctx, "bound session2 [#%d] to session2 [0]\n",
    2078             :                                 i);
    2079             :         }
    2080             : 
    2081           0 :  done:
    2082           0 :         talloc_free(mem_ctx);
    2083             : 
    2084           0 :         return ret;
    2085             : }
    2086             : 
    2087             : struct test_multichannel_lease_break_state;
    2088             : 
    2089             : struct test_multichannel_lease_break_channel {
    2090             :         struct test_multichannel_lease_break_state *state;
    2091             :         size_t idx;
    2092             :         char name[64];
    2093             :         struct smb2_tree *tree;
    2094             :         bool blocked;
    2095             :         struct timeval break_time;
    2096             :         double full_duration;
    2097             :         double relative_duration;
    2098             :         struct smb2_lease_break lb;
    2099             :         size_t break_num;
    2100             : };
    2101             : 
    2102             : struct test_multichannel_lease_break_state {
    2103             :         struct torture_context *tctx;
    2104             :         struct timeval open_req_time;
    2105             :         struct timeval open_rep_time;
    2106             :         size_t num_breaks;
    2107             :         struct timeval last_break_time;
    2108             :         struct test_multichannel_lease_break_channel channels[32];
    2109             : };
    2110             : 
    2111           0 : static bool test_multichannel_lease_break_handler(struct smb2_transport *transport,
    2112             :                                                   const struct smb2_lease_break *lb,
    2113             :                                                   void *private_data)
    2114             : {
    2115           0 :         struct test_multichannel_lease_break_channel *c =
    2116             :                 (struct test_multichannel_lease_break_channel *)private_data;
    2117           0 :         struct test_multichannel_lease_break_state *state = c->state;
    2118             : 
    2119           0 :         c->break_time = timeval_current();
    2120           0 :         c->full_duration = timeval_elapsed2(&state->open_req_time,
    2121           0 :                                             &c->break_time);
    2122           0 :         c->relative_duration = timeval_elapsed2(&state->last_break_time,
    2123           0 :                                                 &c->break_time);
    2124           0 :         state->last_break_time = c->break_time;
    2125           0 :         c->lb = *lb;
    2126           0 :         c->break_num = ++state->num_breaks;
    2127             : 
    2128           0 :         torture_comment(state->tctx, "Got LEASE break epoch[0x%x] %zu on %s after %f ( %f)\n",
    2129           0 :                         c->lb.new_epoch, c->break_num, c->name,
    2130             :                         c->relative_duration,
    2131             :                         c->full_duration);
    2132             : 
    2133           0 :         return torture_lease_handler(transport, lb, c->tree);
    2134             : }
    2135             : 
    2136           0 : static bool test_multichannel_lease_break_test4(struct torture_context *tctx,
    2137             :                                                 struct smb2_tree *tree1)
    2138             : {
    2139           0 :         const char *host = torture_setting_string(tctx, "host", NULL);
    2140           0 :         const char *share = torture_setting_string(tctx, "share", NULL);
    2141           0 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    2142             :         NTSTATUS status;
    2143           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2144           0 :         struct test_multichannel_lease_break_state state = {
    2145             :                 .tctx = tctx,
    2146             :         };
    2147           0 :         struct test_multichannel_lease_break_channel *open2_channel = NULL;
    2148             :         struct smb2_handle _h;
    2149           0 :         struct smb2_handle *h = NULL;
    2150           0 :         struct smb2_handle h_client1_file1 = {{0}};
    2151           0 :         struct smb2_handle h_client2_file1 = {{0}};
    2152             :         struct smb2_create io1;
    2153             :         struct smb2_create io2;
    2154           0 :         bool ret = true;
    2155           0 :         const char *fname1 = BASEDIR "\\lease_break_test4.dat";
    2156           0 :         struct smb2_tree *trees2[32] = { NULL, };
    2157             :         size_t i;
    2158           0 :         struct smb2_transport *transport1 = tree1->session->transport;
    2159             :         struct smbcli_options transport2_options;
    2160           0 :         struct smb2_session *session1 = tree1->session;
    2161           0 :         uint16_t local_port = 0;
    2162             :         struct smb2_lease ls1;
    2163             :         struct smb2_lease ls2;
    2164           0 :         bool block_setup = false;
    2165           0 :         bool block_ok = false;
    2166             :         double open_duration;
    2167             : 
    2168           0 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    2169           0 :                 return true;
    2170             :         }
    2171             : 
    2172           0 :         torture_comment(tctx, "Lease break retry: Test4\n");
    2173             : 
    2174           0 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    2175           0 :         lease_break_info.lease_skip_ack = true;
    2176             : 
    2177           0 :         transport1->lease.handler = torture_lease_handler;
    2178           0 :         transport1->lease.private_data = tree1;
    2179           0 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    2180           0 :         local_port = torture_get_local_port_from_transport(transport1);
    2181           0 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    2182             : 
    2183           0 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    2184           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2185           0 :         smb2_util_close(tree1, _h);
    2186           0 :         smb2_util_unlink(tree1, fname1);
    2187           0 :         CHECK_VAL(lease_break_info.count, 0);
    2188             : 
    2189           0 :         smb2_lease_v2_create(&io2, &ls2, false, fname1,
    2190             :                              LEASE2F1, NULL,
    2191             :                              smb2_util_lease_state("RHW"),
    2192             :                              0x20);
    2193             : 
    2194           0 :         transport2_options = transport1->options;
    2195             : 
    2196           0 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
    2197             :                                                      &transport2_options,
    2198             :                                                      ARRAY_SIZE(trees2), trees2);
    2199           0 :         torture_assert(tctx, ret, "Could not create channels.\n");
    2200             : 
    2201           0 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    2202           0 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2203           0 :                 struct smb2_transport *t = trees2[i]->session->transport;
    2204             : 
    2205           0 :                 c->state = &state;
    2206           0 :                 c->idx = i+1;
    2207           0 :                 c->tree = trees2[i];
    2208           0 :                 snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
    2209             : 
    2210           0 :                 t->lease.handler = test_multichannel_lease_break_handler;
    2211           0 :                 t->lease.private_data = c;
    2212             :         }
    2213             : 
    2214           0 :         open2_channel = &state.channels[0];
    2215             : 
    2216             :         /* 2a opens file1 */
    2217           0 :         torture_comment(tctx, "client2 opens fname1 via %s\n",
    2218           0 :                         open2_channel->name);
    2219           0 :         status = smb2_create(open2_channel->tree, mem_ctx, &io2);
    2220           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2221           0 :         h_client2_file1 = io2.out.file.handle;
    2222           0 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2223           0 :         CHECK_LEASE_V2(&io2, "RHW", true, LEASE2F1, 0, 0, 0x21);
    2224           0 :         CHECK_VAL(io2.out.durable_open_v2, false);
    2225           0 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
    2226           0 :         CHECK_VAL(io2.out.durable_open, false);
    2227           0 :         CHECK_VAL(lease_break_info.count, 0);
    2228             : 
    2229           0 :         block_setup = test_setup_blocked_transports(tctx);
    2230           0 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
    2231             : 
    2232           0 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    2233           0 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2234           0 :                 struct smb2_transport *t = c->tree->session->transport;
    2235             : 
    2236           0 :                 torture_comment(tctx, "Blocking %s\n", c->name);
    2237           0 :                 block_ok = _test_block_smb2_transport(tctx, t, c->name);
    2238           0 :                 torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
    2239           0 :                 c->blocked = true;
    2240             :         }
    2241             : 
    2242             :         /* 1 opens file2 */
    2243           0 :         torture_comment(tctx,
    2244             :                         "Client opens fname1 with session 1 with all %zu blocked\n",
    2245             :                         ARRAY_SIZE(trees2));
    2246           0 :         smb2_lease_v2_create(&io1, &ls1, false, fname1,
    2247             :                              LEASE1F1, NULL,
    2248             :                              smb2_util_lease_state("RHW"),
    2249             :                              0x10);
    2250           0 :         CHECK_VAL(lease_break_info.count, 0);
    2251           0 :         state.open_req_time = timeval_current();
    2252           0 :         state.last_break_time = state.open_req_time;
    2253           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    2254           0 :         state.open_rep_time = timeval_current();
    2255           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2256           0 :         h_client1_file1 = io1.out.file.handle;
    2257             : 
    2258           0 :         CHECK_VAL_GREATER_THAN(lease_break_info.count, 1);
    2259             : 
    2260           0 :         open_duration = timeval_elapsed2(&state.open_req_time,
    2261             :                                          &state.open_rep_time);
    2262           0 :         torture_comment(tctx, "open_duration: %f\n", open_duration);
    2263           0 :         if (lease_break_info.count < ARRAY_SIZE(state.channels)) {
    2264           0 :                 CHECK_VAL_GREATER_THAN(open_duration, 35);
    2265           0 :                 CHECK_LEASE_V2(&io1, "RH", true, LEASE1F1, 0, 0, 0x11);
    2266             :         } else {
    2267           0 :                 CHECK_LEASE_V2(&io1, "RWH", true, LEASE1F1, 0, 0, 0x11);
    2268             :         }
    2269             : 
    2270           0 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    2271           0 :                 if (lease_break_info.count >= ARRAY_SIZE(state.channels)) {
    2272           0 :                         break;
    2273             :                 }
    2274           0 :                 torture_comment(tctx, "Received %d lease break(s) wait for more!!\n",
    2275             :                                 lease_break_info.count);
    2276           0 :                 torture_wait_for_lease_break(tctx);
    2277             :         }
    2278             : 
    2279           0 :         if (lease_break_info.count == 0) {
    2280           0 :                 torture_comment(tctx,
    2281             :                                 "Did not receive expected lease break!!\n");
    2282             :         } else {
    2283           0 :                 torture_comment(tctx, "Received %d lease break(s)!!\n",
    2284             :                                 lease_break_info.count);
    2285             :         }
    2286             : 
    2287           0 :         if (lease_break_info.count < ARRAY_SIZE(state.channels)) {
    2288           0 :                 CHECK_VAL_GREATER_THAN(lease_break_info.count, 3);
    2289             :         } else {
    2290           0 :                 CHECK_VAL(lease_break_info.count, ARRAY_SIZE(state.channels));
    2291             :         }
    2292             : 
    2293           0 :         for (i = 0; i < lease_break_info.count; i++) {
    2294           0 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2295             : 
    2296           0 :                 torture_comment(tctx, "Verify %s\n", c->name);
    2297           0 :                 torture_assert_int_equal(tctx, c->break_num, c->idx,
    2298             :                                          "Got lease break in wrong order");
    2299           0 :                 CHECK_LEASE_BREAK_V2(c->lb, LEASE2F1, "RWH", "RH",
    2300             :                                      SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED,
    2301             :                                      0x22);
    2302             :         }
    2303             : 
    2304           0 : done:
    2305           0 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    2306           0 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2307           0 :                 struct smb2_transport *t = NULL;
    2308             : 
    2309           0 :                 if (!c->blocked) {
    2310           0 :                         continue;
    2311             :                 }
    2312             : 
    2313           0 :                 t = c->tree->session->transport;
    2314             : 
    2315           0 :                 torture_comment(tctx, "Unblocking %s\n", c->name);
    2316           0 :                 _test_unblock_smb2_transport(tctx, t, c->name);
    2317           0 :                 c->blocked = false;
    2318             :         }
    2319           0 :         if (block_setup) {
    2320           0 :                 test_cleanup_blocked_transports(tctx);
    2321             :         }
    2322             : 
    2323           0 :         tree1->session = session1;
    2324             : 
    2325           0 :         smb2_util_close(tree1, h_client1_file1);
    2326           0 :         if (trees2[0] != NULL) {
    2327           0 :                 smb2_util_close(trees2[0], h_client2_file1);
    2328             :         }
    2329             : 
    2330           0 :         if (h != NULL) {
    2331           0 :                 smb2_util_close(tree1, *h);
    2332             :         }
    2333             : 
    2334           0 :         smb2_util_unlink(tree1, fname1);
    2335           0 :         smb2_deltree(tree1, BASEDIR);
    2336             : 
    2337           0 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    2338           0 :                 if (trees2[i] == NULL) {
    2339           0 :                         continue;
    2340             :                 }
    2341           0 :                 TALLOC_FREE(trees2[i]);
    2342             :         }
    2343           0 :         talloc_free(tree1);
    2344           0 :         talloc_free(mem_ctx);
    2345             : 
    2346           0 :         return ret;
    2347             : }
    2348             : 
    2349             : /*
    2350             :  * Test channel merging race
    2351             :  * This is a regression test for
    2352             :  * https://bugzilla.samba.org/show_bug.cgi?id=15346
    2353             :  */
    2354             : struct test_multichannel_bug_15346_conn;
    2355             : 
    2356             : struct test_multichannel_bug_15346_state {
    2357             :         struct torture_context *tctx;
    2358             :         struct test_multichannel_bug_15346_conn *conns;
    2359             :         size_t num_conns;
    2360             :         size_t num_ready;
    2361             :         bool asserted;
    2362             :         bool looping;
    2363             : };
    2364             : 
    2365             : struct test_multichannel_bug_15346_conn {
    2366             :         struct test_multichannel_bug_15346_state *state;
    2367             :         size_t idx;
    2368             :         struct smbXcli_conn *smbXcli;
    2369             :         struct tevent_req *nreq;
    2370             :         struct tevent_req *ereq;
    2371             : };
    2372             : 
    2373             : static void test_multichannel_bug_15346_ndone(struct tevent_req *subreq);
    2374             : static void test_multichannel_bug_15346_edone(struct tevent_req *subreq);
    2375             : 
    2376           0 : static void test_multichannel_bug_15346_ndone(struct tevent_req *subreq)
    2377             : {
    2378           0 :         struct test_multichannel_bug_15346_conn *conn =
    2379             :                 (struct test_multichannel_bug_15346_conn *)
    2380           0 :                 tevent_req_callback_data_void(subreq);
    2381           0 :         struct test_multichannel_bug_15346_state *state = conn->state;
    2382           0 :         struct torture_context *tctx = state->tctx;
    2383             :         NTSTATUS status;
    2384           0 :         bool ok = false;
    2385             : 
    2386           0 :         SMB_ASSERT(conn->nreq == subreq);
    2387           0 :         conn->nreq = NULL;
    2388             : 
    2389           0 :         status = smbXcli_negprot_recv(subreq, NULL, NULL);
    2390           0 :         TALLOC_FREE(subreq);
    2391           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ok, asserted,
    2392             :                                         "smbXcli_negprot_recv failed");
    2393             : 
    2394           0 :         torture_comment(tctx, "conn[%zu]: negprot done\n", conn->idx);
    2395             : 
    2396           0 :         conn->ereq = smb2cli_echo_send(conn->smbXcli,
    2397             :                                        tctx->ev,
    2398             :                                        conn->smbXcli,
    2399           0 :                                        state->num_conns * 2 * 1000);
    2400           0 :         torture_assert_goto(tctx, conn->ereq != NULL, ok, asserted,
    2401             :                             "smb2cli_echo_send");
    2402           0 :         tevent_req_set_callback(conn->ereq,
    2403             :                                 test_multichannel_bug_15346_edone,
    2404             :                                 conn);
    2405             : 
    2406           0 :         return;
    2407             : 
    2408           0 : asserted:
    2409           0 :         SMB_ASSERT(!ok);
    2410           0 :         state->asserted = true;
    2411           0 :         state->looping = false;
    2412           0 :         return;
    2413             : }
    2414             : 
    2415           0 : static void test_multichannel_bug_15346_edone(struct tevent_req *subreq)
    2416             : {
    2417           0 :         struct test_multichannel_bug_15346_conn *conn =
    2418             :                 (struct test_multichannel_bug_15346_conn *)
    2419           0 :                 tevent_req_callback_data_void(subreq);
    2420           0 :         struct test_multichannel_bug_15346_state *state = conn->state;
    2421           0 :         struct torture_context *tctx = state->tctx;
    2422             :         NTSTATUS status;
    2423           0 :         bool ok = false;
    2424             : 
    2425           0 :         SMB_ASSERT(conn->ereq == subreq);
    2426           0 :         conn->ereq = NULL;
    2427             : 
    2428           0 :         status = smb2cli_echo_recv(subreq);
    2429           0 :         TALLOC_FREE(subreq);
    2430           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ok, asserted,
    2431             :                                         "smb2cli_echo_recv failed");
    2432             : 
    2433           0 :         torture_comment(tctx, "conn[%zu]: echo done\n", conn->idx);
    2434             : 
    2435           0 :         state->num_ready += 1;
    2436           0 :         if (state->num_ready < state->num_conns) {
    2437           0 :                 return;
    2438             :         }
    2439             : 
    2440           0 :         state->looping = false;
    2441           0 :         return;
    2442             : 
    2443           0 : asserted:
    2444           0 :         SMB_ASSERT(!ok);
    2445           0 :         state->asserted = true;
    2446           0 :         state->looping = false;
    2447           0 :         return;
    2448             : }
    2449             : 
    2450           0 : static bool test_multichannel_bug_15346(struct torture_context *tctx,
    2451             :                                         struct smb2_tree *tree1)
    2452             : {
    2453           0 :         const char *host = torture_setting_string(tctx, "host", NULL);
    2454           0 :         const char *share = torture_setting_string(tctx, "share", NULL);
    2455           0 :         struct resolve_context *resolve_ctx = lpcfg_resolve_context(tctx->lp_ctx);
    2456           0 :         const char *socket_options = lpcfg_socket_options(tctx->lp_ctx);
    2457           0 :         struct gensec_settings *gsettings = NULL;
    2458           0 :         bool ret = true;
    2459             :         NTSTATUS status;
    2460           0 :         struct smb2_transport *transport1 = tree1->session->transport;
    2461           0 :         struct test_multichannel_bug_15346_state *state = NULL;
    2462             :         uint32_t server_capabilities;
    2463           0 :         struct smb2_handle root_handle = {{0}};
    2464             :         size_t i;
    2465             : 
    2466           0 :         if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
    2467           0 :                 torture_fail(tctx,
    2468             :                              "SMB 3.X Dialect family required for Multichannel"
    2469             :                              " tests\n");
    2470             :         }
    2471             : 
    2472           0 :         server_capabilities = smb2cli_conn_server_capabilities(
    2473           0 :                                         tree1->session->transport->conn);
    2474           0 :         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
    2475           0 :                 torture_fail(tctx,
    2476             :                              "Server does not support multichannel.");
    2477             :         }
    2478             : 
    2479           0 :         torture_comment(tctx, "Testing for BUG 15346\n");
    2480             : 
    2481           0 :         state = talloc_zero(tctx, struct test_multichannel_bug_15346_state);
    2482           0 :         torture_assert_goto(tctx, state != NULL, ret, done,
    2483             :                             "talloc_zero");
    2484           0 :         state->tctx = tctx;
    2485             : 
    2486           0 :         gsettings = lpcfg_gensec_settings(state, tctx->lp_ctx);
    2487           0 :         torture_assert_goto(tctx, gsettings != NULL, ret, done,
    2488             :                             "lpcfg_gensec_settings");
    2489             : 
    2490             :         /*
    2491             :          * 32 is the W2K12R2 and W2K16 limit
    2492             :          * add 31 additional connections
    2493             :          */
    2494           0 :         state->num_conns = 31;
    2495           0 :         state->conns = talloc_zero_array(state,
    2496             :                                   struct test_multichannel_bug_15346_conn,
    2497             :                                   state->num_conns);
    2498           0 :         torture_assert_goto(tctx, state->conns != NULL, ret, done,
    2499             :                             "talloc_zero_array");
    2500             : 
    2501             :         /*
    2502             :          * First we open additional the tcp connections
    2503             :          */
    2504             : 
    2505           0 :         for (i = 0; i < state->num_conns; i++) {
    2506           0 :                 struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
    2507           0 :                 struct socket_context *sock = NULL;
    2508           0 :                 uint16_t port = 445;
    2509           0 :                 struct smbcli_options options = transport1->options;
    2510             : 
    2511           0 :                 conn->state = state;
    2512           0 :                 conn->idx = i;
    2513             : 
    2514           0 :                 status = socket_connect_multi(state->conns,
    2515             :                                               host,
    2516             :                                               1, &port,
    2517             :                                               resolve_ctx,
    2518             :                                               tctx->ev,
    2519             :                                               &sock,
    2520             :                                               &port);
    2521           0 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2522             :                                                 "socket_connect_multi failed");
    2523             : 
    2524           0 :                 conn->smbXcli = smbXcli_conn_create(state->conns,
    2525           0 :                                         sock->fd,
    2526             :                                         host,
    2527             :                                         SMB_SIGNING_OFF,
    2528             :                                         0,
    2529             :                                         &options.client_guid,
    2530             :                                         options.smb2_capabilities,
    2531             :                                         &options.smb3_capabilities);
    2532           0 :                 torture_assert_goto(tctx, conn->smbXcli != NULL, ret, done,
    2533             :                                     "smbXcli_conn_create failed");
    2534           0 :                 sock->fd = -1;
    2535           0 :                 TALLOC_FREE(sock);
    2536             :         }
    2537             : 
    2538             :         /*
    2539             :          * Now prepare the async SMB2 Negotiate requests
    2540             :          */
    2541           0 :         for (i = 0; i < state->num_conns; i++) {
    2542           0 :                 struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
    2543             : 
    2544           0 :                 conn->nreq = smbXcli_negprot_send(conn->smbXcli,
    2545             :                                                   tctx->ev,
    2546             :                                                   conn->smbXcli,
    2547           0 :                                                   state->num_conns * 2 * 1000,
    2548             :                                                   smbXcli_conn_protocol(transport1->conn),
    2549             :                                                   smbXcli_conn_protocol(transport1->conn),
    2550             :                                                   33, /* max_credits */
    2551             :                                                   NULL);
    2552           0 :                 torture_assert_goto(tctx, conn->nreq != NULL, ret, done, "smbXcli_negprot_send");
    2553           0 :                 tevent_req_set_callback(conn->nreq,
    2554             :                                         test_multichannel_bug_15346_ndone,
    2555             :                                         conn);
    2556             :         }
    2557             : 
    2558             :         /*
    2559             :          * now we loop until all negprot and the first round
    2560             :          * of echos are done.
    2561             :          */
    2562           0 :         state->looping = true;
    2563           0 :         while (state->looping) {
    2564           0 :                 torture_assert_goto(tctx, tevent_loop_once(tctx->ev) == 0,
    2565             :                                     ret, done, "tevent_loop_once");
    2566             :         }
    2567             : 
    2568           0 :         if (state->asserted) {
    2569           0 :                 ret = false;
    2570           0 :                 goto done;
    2571             :         }
    2572             : 
    2573             :         /*
    2574             :          * No we check that the connections are still usable
    2575             :          */
    2576           0 :         for (i = 0; i < state->num_conns; i++) {
    2577           0 :                 struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
    2578             : 
    2579           0 :                 torture_comment(tctx, "conn[%zu]: checking echo again1\n", conn->idx);
    2580             : 
    2581           0 :                 status = smb2cli_echo(conn->smbXcli, 1000);
    2582           0 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2583             :                                                 "smb2cli_echo failed");
    2584             :         }
    2585             : 
    2586           0 :         status = smb2_util_roothandle(tree1, &root_handle);
    2587           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2588             :                                         "smb2_util_roothandle failed");
    2589             : 
    2590             :         /*
    2591             :          * No we check that the connections are still usable
    2592             :          */
    2593           0 :         for (i = 0; i < state->num_conns; i++) {
    2594           0 :                 struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
    2595           0 :                 struct smbcli_options options = transport1->options;
    2596           0 :                 struct smb2_session *session = NULL;
    2597           0 :                 struct smb2_tree *tree = NULL;
    2598             :                 union smb_fileinfo io;
    2599             : 
    2600           0 :                 torture_comment(tctx, "conn[%zu]: checking session bind\n", conn->idx);
    2601             : 
    2602             :                 /*
    2603             :                  * Prepare smb2_{tree,session,transport} structures
    2604             :                  * for the existing connection.
    2605             :                  */
    2606           0 :                 options.only_negprot = true;
    2607           0 :                 status = smb2_connect_ext(state->conns,
    2608             :                                           host,
    2609             :                                           NULL, /* ports */
    2610             :                                           share,
    2611             :                                           resolve_ctx,
    2612             :                                           samba_cmdline_get_creds(),
    2613             :                                           &conn->smbXcli,
    2614             :                                           0, /* previous_session_id */
    2615             :                                           &tree,
    2616             :                                           tctx->ev,
    2617             :                                           &options,
    2618             :                                           socket_options,
    2619             :                                           gsettings);
    2620           0 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2621             :                                                 "smb2_connect_ext failed");
    2622           0 :                 conn->smbXcli = tree->session->transport->conn;
    2623             : 
    2624           0 :                 session = smb2_session_channel(tree->session->transport,
    2625             :                                                lpcfg_gensec_settings(tree, tctx->lp_ctx),
    2626             :                                                tree,
    2627             :                                                tree1->session);
    2628           0 :                 torture_assert_goto(tctx, session != NULL, ret, done,
    2629             :                                     "smb2_session_channel failed");
    2630             : 
    2631           0 :                 status = smb2_session_setup_spnego(session,
    2632             :                                                    samba_cmdline_get_creds(),
    2633             :                                                    0 /* previous_session_id */);
    2634           0 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2635             :                                                 "smb2_session_setup_spnego failed");
    2636             : 
    2637             :                 /*
    2638             :                  * Fix up the bound smb2_tree
    2639             :                  */
    2640           0 :                 tree->session = session;
    2641           0 :                 tree->smbXcli = tree1->smbXcli;
    2642             : 
    2643           0 :                 ZERO_STRUCT(io);
    2644           0 :                 io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    2645           0 :                 io.generic.in.file.handle = root_handle;
    2646             : 
    2647           0 :                 status = smb2_getinfo_file(tree, tree, &io);
    2648           0 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2649             :                                                 "smb2_getinfo_file failed");
    2650             :         }
    2651             : 
    2652           0 :  done:
    2653           0 :         talloc_free(state);
    2654             : 
    2655           0 :         return ret;
    2656             : }
    2657             : 
    2658         964 : struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
    2659             : {
    2660         964 :         struct torture_suite *suite = torture_suite_create(ctx, "multichannel");
    2661         964 :         struct torture_suite *suite_generic = torture_suite_create(ctx,
    2662             :                                                                    "generic");
    2663         964 :         struct torture_suite *suite_oplocks = torture_suite_create(ctx,
    2664             :                                                                    "oplocks");
    2665         964 :         struct torture_suite *suite_leases = torture_suite_create(ctx,
    2666             :                                                                   "leases");
    2667         964 :         struct torture_suite *suite_bugs = torture_suite_create(ctx,
    2668             :                                                                 "bugs");
    2669             : 
    2670         964 :         torture_suite_add_suite(suite, suite_generic);
    2671         964 :         torture_suite_add_suite(suite, suite_oplocks);
    2672         964 :         torture_suite_add_suite(suite, suite_leases);
    2673         964 :         torture_suite_add_suite(suite, suite_bugs);
    2674             : 
    2675         964 :         torture_suite_add_1smb2_test(suite_generic, "interface_info",
    2676             :                                      test_multichannel_interface_info);
    2677         964 :         torture_suite_add_1smb2_test(suite_generic, "num_channels",
    2678             :                                      test_multichannel_num_channels);
    2679         964 :         torture_suite_add_1smb2_test(suite_oplocks, "test1",
    2680             :                                      test_multichannel_oplock_break_test1);
    2681         964 :         torture_suite_add_1smb2_test(suite_oplocks, "test2",
    2682             :                                      test_multichannel_oplock_break_test2);
    2683         964 :         torture_suite_add_1smb2_test(suite_oplocks, "test3_windows",
    2684             :                                      test_multichannel_oplock_break_test3_windows);
    2685         964 :         torture_suite_add_1smb2_test(suite_oplocks, "test3_specification",
    2686             :                                      test_multichannel_oplock_break_test3_specification);
    2687         964 :         torture_suite_add_1smb2_test(suite_leases, "test1",
    2688             :                                      test_multichannel_lease_break_test1);
    2689         964 :         torture_suite_add_1smb2_test(suite_leases, "test2",
    2690             :                                      test_multichannel_lease_break_test2);
    2691         964 :         torture_suite_add_1smb2_test(suite_leases, "test3",
    2692             :                                      test_multichannel_lease_break_test3);
    2693         964 :         torture_suite_add_1smb2_test(suite_leases, "test4",
    2694             :                                      test_multichannel_lease_break_test4);
    2695         964 :         torture_suite_add_1smb2_test(suite_bugs, "bug_15346",
    2696             :                                      test_multichannel_bug_15346);
    2697             : 
    2698         964 :         suite->description = talloc_strdup(suite, "SMB2 Multichannel tests");
    2699             : 
    2700         964 :         return suite;
    2701             : }

Generated by: LCOV version 1.13