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

Generated by: LCOV version 1.14