LCOV - code coverage report
Current view: top level - source4/torture/smb2 - multichannel.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 1320 1471 89.7 %
Date: 2024-04-21 15:09:00 Functions: 23 24 95.8 %

          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          36 : 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           0 :         union smb_ioctl ioctl;
     150           0 :         struct smb2_handle fh;
     151           0 :         uint32_t caps;
     152             : 
     153          36 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
     154          36 :         if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
     155           0 :                 torture_skip(tctx,
     156             :                             "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
     157             :         }
     158             : 
     159          36 :         ZERO_STRUCT(ioctl);
     160             : 
     161          36 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
     162             : 
     163          36 :         fh.data[0] = UINT64_MAX;
     164          36 :         fh.data[1] = UINT64_MAX;
     165             : 
     166          36 :         ioctl.smb2.in.file.handle = fh;
     167          36 :         ioctl.smb2.in.function = FSCTL_QUERY_NETWORK_INTERFACE_INFO;
     168             :         /* Windows client sets this to 64KiB */
     169          36 :         ioctl.smb2.in.max_output_response = 0x10000;
     170          36 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
     171             : 
     172          36 :         torture_assert_ntstatus_ok(tctx,
     173             :                 smb2_ioctl(tree, tctx, &ioctl.smb2),
     174             :                 "FSCTL_QUERY_NETWORK_INTERFACE_INFO failed");
     175             : 
     176          36 :         torture_assert(tctx,
     177             :                 (ioctl.smb2.out.out.length != 0),
     178             :                 "no interface info returned???");
     179             : 
     180          36 :         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          36 :         if (DEBUGLVL(1)) {
     186          36 :                 NDR_PRINT_DEBUG(fsctl_net_iface_info, info);
     187             :         }
     188             : 
     189          36 :         return true;
     190             : }
     191             : 
     192           4 : static bool test_multichannel_interface_info(struct torture_context *tctx,
     193             :                                              struct smb2_tree *tree)
     194             : {
     195           0 :         struct fsctl_net_iface_info info;
     196             : 
     197           4 :         return test_ioctl_network_interface_info(tctx, tree, &info);
     198             : }
     199             : 
     200         436 : 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         436 :         struct smbcli_options transport_options = *_transport_options;
     210           0 :         NTSTATUS status;
     211           0 :         struct smb2_transport *transport;
     212           0 :         struct smb2_session *session;
     213         436 :         bool ret = true;
     214           0 :         struct smb2_tree *tree;
     215             : 
     216         436 :         if (parent_tree) {
     217         404 :                 transport_options.only_negprot = true;
     218             :         }
     219             : 
     220         436 :         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         436 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     233             :                         "smb2_connect failed");
     234         436 :         transport = tree->session->transport;
     235         436 :         transport->oplock.handler = torture_oplock_ack_handler;
     236         436 :         transport->oplock.private_data = tree;
     237         436 :         transport->lease.handler = torture_lease_handler;
     238         436 :         transport->lease.private_data = tree;
     239         436 :         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         436 :         if (parent_tree) {
     245         404 :                 session = smb2_session_channel(transport,
     246             :                                 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
     247             :                                 parent_tree, parent_tree->session);
     248         404 :                 torture_assert_goto(tctx, session != NULL, ret, done,
     249             :                                 "smb2_session_channel failed");
     250             : 
     251         404 :                 tree->smbXcli = parent_tree->smbXcli;
     252         404 :                 tree->session = session;
     253         404 :                 status = smb2_session_setup_spnego(session,
     254             :                                                 credentials,
     255             :                                                 0 /* previous_session_id */);
     256         404 :                 CHECK_STATUS(status, NT_STATUS_OK);
     257         404 :                 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         436 :         smb2_keepalive(transport);
     266             : 
     267         436 : done:
     268         436 :         if (ret) {
     269         436 :                 return tree;
     270             :         } else {
     271           0 :                 return NULL;
     272             :         }
     273             : }
     274             : 
     275          32 : 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           0 :         uint8_t i;
     285             : 
     286          32 :         transport_options->client_guid = GUID_random();
     287             : 
     288         464 :         for (i = 0; i < num_trees; i++) {
     289         432 :                 struct smb2_tree *parent_tree = NULL;
     290         432 :                 struct smb2_tree *tree = NULL;
     291         432 :                 struct smb2_transport *transport = NULL;
     292         432 :                 uint16_t local_port = 0;
     293             : 
     294         432 :                 if (i > 0) {
     295         400 :                         parent_tree = trees[0];
     296             :                 }
     297             : 
     298         432 :                 torture_comment(tctx, "Setting up connection %d\n", i);
     299         432 :                 tree = test_multichannel_create_channel(tctx, host, share,
     300             :                                         credentials, transport_options,
     301             :                                         parent_tree);
     302         432 :                 torture_assert(tctx, tree, "failed to created new channel");
     303             : 
     304         432 :                 trees[i] = tree;
     305         432 :                 transport = tree->session->transport;
     306         432 :                 local_port = torture_get_local_port_from_transport(transport);
     307         432 :                 torture_comment(tctx, "transport[%d] uses tcp port: %d\n",
     308             :                                 i, local_port);
     309             :         }
     310             : 
     311          32 :         return true;
     312             : }
     313             : 
     314          20 : 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          20 :         struct smb2_tree **trees = NULL;
     326          20 :         size_t num_trees = 0;
     327           0 :         bool ret;
     328             : 
     329          20 :         torture_assert(tctx, tree2A, "tree2A required!");
     330          20 :         num_trees += 1;
     331          20 :         torture_assert(tctx, tree2B, "tree2B required!");
     332          20 :         num_trees += 1;
     333          20 :         if (tree2C != NULL) {
     334           8 :                 num_trees += 1;
     335             :         }
     336          20 :         trees = talloc_zero_array(tctx, struct smb2_tree *, num_trees);
     337          20 :         torture_assert(tctx, trees, "out of memory");
     338             : 
     339          20 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
     340             :                                                      transport_options,
     341             :                                                      num_trees, trees);
     342          20 :         if (!ret) {
     343           0 :                 return false;
     344             :         }
     345             : 
     346          20 :         *tree2A = trees[0];
     347          20 :         *tree2B = trees[1];
     348          20 :         if (tree2C != NULL) {
     349           8 :                 *tree2C = trees[2];
     350             :         }
     351             : 
     352          20 :         return true;
     353             : }
     354             : 
     355          28 : static void test_multichannel_free_channels(struct smb2_tree *tree2A,
     356             :                                              struct smb2_tree *tree2B,
     357             :                                              struct smb2_tree *tree2C)
     358             : {
     359          28 :         TALLOC_FREE(tree2A);
     360          28 :         TALLOC_FREE(tree2B);
     361          28 :         TALLOC_FREE(tree2C);
     362          28 : }
     363             : 
     364          32 : static bool test_multichannel_initial_checks(struct torture_context *tctx,
     365             :                                              struct smb2_tree *tree1)
     366             : {
     367          32 :         struct smb2_transport *transport1 = tree1->session->transport;
     368           0 :         uint32_t server_capabilities;
     369           0 :         struct fsctl_net_iface_info info;
     370             : 
     371          32 :         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          32 :         server_capabilities = smb2cli_conn_server_capabilities(
     378          32 :                                         tree1->session->transport->conn);
     379          32 :         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
     380           0 :                 torture_skip_goto(tctx, fail,
     381             :                              "Server does not support multichannel.");
     382             :         }
     383             : 
     384          32 :         torture_assert(tctx,
     385             :                 test_ioctl_network_interface_info(tctx, tree1, &info),
     386             :                 "failed to retrieve network interface info");
     387             : 
     388          32 :         return true;
     389           0 : fail:
     390           0 :         return false;
     391             : }
     392             : 
     393          52 : static void test_multichannel_init_smb_create(struct smb2_create *io)
     394             : {
     395          52 :         io->in.durable_open = false;
     396          52 :         io->in.durable_open_v2 = true;
     397          52 :         io->in.persistent_open = false;
     398          52 :         io->in.create_guid = GUID_random();
     399          52 :         io->in.timeout = 0x493E0; /* 300000 */
     400             :         /* windows 2016 returns 300000 0x493E0 */
     401          52 : }
     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           4 : static bool test_multichannel_oplock_break_test1(struct torture_context *tctx,
     425             :                                            struct smb2_tree *tree1)
     426             : {
     427           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
     428           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
     429           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
     430           0 :         NTSTATUS status;
     431           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     432           0 :         struct smb2_handle _h;
     433           4 :         struct smb2_handle h_client1_file1 = {{0}};
     434           4 :         struct smb2_handle h_client1_file2 = {{0}};
     435           4 :         struct smb2_handle h_client1_file3 = {{0}};
     436           4 :         struct smb2_handle h_client2_file1 = {{0}};
     437           4 :         struct smb2_handle h_client2_file2 = {{0}};
     438           4 :         struct smb2_handle h_client2_file3 = {{0}};
     439           0 :         struct smb2_create io1, io2, io3;
     440           4 :         bool ret = true;
     441           4 :         const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
     442           4 :         const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
     443           4 :         const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
     444           4 :         struct smb2_tree *tree2A = NULL;
     445           4 :         struct smb2_tree *tree2B = NULL;
     446           4 :         struct smb2_tree *tree2C = NULL;
     447           4 :         struct smb2_transport *transport1 = tree1->session->transport;
     448           0 :         struct smbcli_options transport2_options;
     449           4 :         struct smb2_session *session1 = tree1->session;
     450           4 :         uint16_t local_port = 0;
     451             : 
     452           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
     453           0 :                 return true;
     454             :         }
     455             : 
     456           4 :         torture_comment(tctx, "Oplock break retry: Test1\n");
     457             : 
     458           4 :         torture_reset_break_info(tctx, &break_info);
     459             : 
     460           4 :         transport1->oplock.handler = torture_oplock_ack_handler;
     461           4 :         transport1->oplock.private_data = tree1;
     462           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
     463           4 :         local_port = torture_get_local_port_from_transport(transport1);
     464           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
     465             : 
     466           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
     467           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     468           4 :         smb2_util_close(tree1, _h);
     469           4 :         smb2_util_unlink(tree1, fname1);
     470           4 :         smb2_util_unlink(tree1, fname2);
     471           4 :         smb2_util_unlink(tree1, fname3);
     472           4 :         CHECK_VAL(break_info.count, 0);
     473             : 
     474           4 :         smb2_oplock_create_share(&io1, fname1,
     475             :                         smb2_util_share_access("RWD"),
     476           4 :                         smb2_util_oplock_level("b"));
     477           4 :         test_multichannel_init_smb_create(&io1);
     478             : 
     479           4 :         smb2_oplock_create_share(&io2, fname2,
     480             :                         smb2_util_share_access("RWD"),
     481           4 :                         smb2_util_oplock_level("b"));
     482           4 :         test_multichannel_init_smb_create(&io2);
     483             : 
     484           4 :         smb2_oplock_create_share(&io3, fname3,
     485             :                         smb2_util_share_access("RWD"),
     486           4 :                         smb2_util_oplock_level("b"));
     487           4 :         test_multichannel_init_smb_create(&io3);
     488             : 
     489           4 :         transport2_options = transport1->options;
     490             : 
     491           4 :         ret = test_multichannel_create_channels(tctx, host, share,
     492             :                                                   credentials,
     493             :                                                   &transport2_options,
     494             :                                                   &tree2A, &tree2B, NULL);
     495           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
     496             : 
     497             :         /* 2a opens file1 */
     498           4 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
     499           4 :         status = smb2_create(tree2A, mem_ctx, &io1);
     500           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     501           4 :         h_client2_file1 = io1.out.file.handle;
     502           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     503           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
     504           4 :         torture_wait_for_oplock_break(tctx);
     505           4 :         CHECK_VAL(break_info.count, 0);
     506             : 
     507             :         /* 2b opens file2 */
     508           4 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
     509           4 :         status = smb2_create(tree2B, mem_ctx, &io2);
     510           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     511           4 :         h_client2_file2 = io2.out.file.handle;
     512           4 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     513           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
     514           4 :         torture_wait_for_oplock_break(tctx);
     515           4 :         CHECK_VAL(break_info.count, 0);
     516             : 
     517             : 
     518             :         /* 1 opens file1 - batchoplock break? */
     519           4 :         torture_comment(tctx, "client1 opens fname1 via session 1\n");
     520           4 :         io1.in.oplock_level = smb2_util_oplock_level("b");
     521           4 :         status = smb2_create(tree1, mem_ctx, &io1);
     522           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     523           4 :         h_client1_file1 = io1.out.file.handle;
     524           4 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     525           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
     526           4 :         torture_wait_for_oplock_break(tctx);
     527           4 :         CHECK_VAL(break_info.count, 1);
     528             : 
     529           4 :         torture_reset_break_info(tctx, &break_info);
     530             : 
     531             :         /* 1 opens file2 - batchoplock break? */
     532           4 :         torture_comment(tctx, "client1 opens fname2 via session 1\n");
     533           4 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     534           4 :         status = smb2_create(tree1, mem_ctx, &io2);
     535           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     536           4 :         h_client1_file2 = io2.out.file.handle;
     537           4 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     538           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
     539           4 :         torture_wait_for_oplock_break(tctx);
     540           4 :         CHECK_VAL(break_info.count, 1);
     541             : 
     542             :         /* cleanup everything */
     543           4 :         torture_reset_break_info(tctx, &break_info);
     544             : 
     545           4 :         smb2_util_close(tree1, h_client1_file1);
     546           4 :         smb2_util_close(tree1, h_client1_file2);
     547           4 :         smb2_util_close(tree1, h_client1_file3);
     548           4 :         smb2_util_close(tree2A, h_client2_file1);
     549           4 :         smb2_util_close(tree2A, h_client2_file2);
     550           4 :         smb2_util_close(tree2A, h_client2_file3);
     551             : 
     552           4 :         smb2_util_unlink(tree1, fname1);
     553           4 :         smb2_util_unlink(tree1, fname2);
     554           4 :         smb2_util_unlink(tree1, fname3);
     555           4 :         CHECK_VAL(break_info.count, 0);
     556           4 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
     557           4 :         tree2A = tree2B = tree2C = NULL;
     558           4 : done:
     559           4 :         tree1->session = session1;
     560             : 
     561           4 :         smb2_util_close(tree1, h_client1_file1);
     562           4 :         smb2_util_close(tree1, h_client1_file2);
     563           4 :         smb2_util_close(tree1, h_client1_file3);
     564           4 :         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           4 :         smb2_util_unlink(tree1, fname1);
     571           4 :         smb2_util_unlink(tree1, fname2);
     572           4 :         smb2_util_unlink(tree1, fname3);
     573           4 :         smb2_deltree(tree1, BASEDIR);
     574             : 
     575           4 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
     576           4 :         talloc_free(tree1);
     577           4 :         talloc_free(mem_ctx);
     578             : 
     579           4 :         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           4 : static bool test_multichannel_oplock_break_test2(struct torture_context *tctx,
     608             :                                            struct smb2_tree *tree1)
     609             : {
     610           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
     611           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
     612           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
     613           0 :         NTSTATUS status;
     614           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     615           0 :         struct smb2_handle _h;
     616           4 :         struct smb2_handle h_client1_file1 = {{0}};
     617           4 :         struct smb2_handle h_client1_file2 = {{0}};
     618           4 :         struct smb2_handle h_client1_file3 = {{0}};
     619           4 :         struct smb2_handle h_client2_file1 = {{0}};
     620           4 :         struct smb2_handle h_client2_file2 = {{0}};
     621           4 :         struct smb2_handle h_client2_file3 = {{0}};
     622           0 :         struct smb2_create io1, io2, io3;
     623           4 :         bool ret = true;
     624           4 :         const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
     625           4 :         const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
     626           4 :         const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
     627           4 :         struct smb2_tree *tree2A = NULL;
     628           4 :         struct smb2_tree *tree2B = NULL;
     629           4 :         struct smb2_tree *tree2C = NULL;
     630           4 :         struct smb2_tree *tree2D = NULL;
     631           4 :         struct smb2_transport *transport1 = tree1->session->transport;
     632           4 :         struct smb2_transport *transport2 = NULL;
     633           0 :         struct smbcli_options transport2_options;
     634           4 :         struct smb2_session *session1 = tree1->session;
     635           4 :         uint16_t local_port = 0;
     636           0 :         DATA_BLOB blob;
     637           4 :         bool block_setup = false;
     638           4 :         bool block_ok = false;
     639           4 :         bool unblock_ok = false;
     640             : 
     641           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
     642           0 :                 return true;
     643             :         }
     644             : 
     645           4 :         torture_comment(tctx, "Oplock break retry: Test2\n");
     646             : 
     647           4 :         torture_reset_break_info(tctx, &break_info);
     648             : 
     649           4 :         transport1->oplock.handler = torture_oplock_ack_handler;
     650           4 :         transport1->oplock.private_data = tree1;
     651           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
     652           4 :         local_port = torture_get_local_port_from_transport(transport1);
     653           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
     654             : 
     655           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
     656           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     657           4 :         smb2_util_close(tree1, _h);
     658           4 :         smb2_util_unlink(tree1, fname1);
     659           4 :         smb2_util_unlink(tree1, fname2);
     660           4 :         smb2_util_unlink(tree1, fname3);
     661           4 :         CHECK_VAL(break_info.count, 0);
     662             : 
     663           4 :         smb2_oplock_create_share(&io1, fname1,
     664             :                         smb2_util_share_access("RWD"),
     665           4 :                         smb2_util_oplock_level("b"));
     666           4 :         test_multichannel_init_smb_create(&io1);
     667             : 
     668           4 :         smb2_oplock_create_share(&io2, fname2,
     669             :                         smb2_util_share_access("RWD"),
     670           4 :                         smb2_util_oplock_level("b"));
     671           4 :         test_multichannel_init_smb_create(&io2);
     672             : 
     673           4 :         smb2_oplock_create_share(&io3, fname3,
     674             :                         smb2_util_share_access("RWD"),
     675           4 :                         smb2_util_oplock_level("b"));
     676           4 :         test_multichannel_init_smb_create(&io3);
     677             : 
     678           4 :         transport2_options = transport1->options;
     679             : 
     680           4 :         ret = test_multichannel_create_channels(tctx, host, share,
     681             :                                                   credentials,
     682             :                                                   &transport2_options,
     683             :                                                   &tree2A, &tree2B, &tree2C);
     684           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
     685             : 
     686           4 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
     687           4 :         io1.in.oplock_level = smb2_util_oplock_level("b");
     688           4 :         status = smb2_create(tree2A, mem_ctx, &io1);
     689           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     690           4 :         h_client2_file1 = io1.out.file.handle;
     691           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     692           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
     693           4 :         torture_wait_for_oplock_break(tctx);
     694           4 :         CHECK_VAL(break_info.count, 0);
     695             : 
     696             : 
     697           4 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
     698           4 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     699           4 :         status = smb2_create(tree2B, mem_ctx, &io2);
     700           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     701           4 :         h_client2_file2 = io2.out.file.handle;
     702           4 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     703           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
     704           4 :         torture_wait_for_oplock_break(tctx);
     705           4 :         CHECK_VAL(break_info.count, 0);
     706             : 
     707             : 
     708           4 :         torture_comment(tctx, "client1 opens fname1 via session 1\n");
     709           4 :         io1.in.oplock_level = smb2_util_oplock_level("b");
     710           4 :         status = smb2_create(tree1, mem_ctx, &io1);
     711           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     712           4 :         h_client1_file1 = io1.out.file.handle;
     713           4 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     714           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
     715           4 :         torture_wait_for_oplock_break(tctx);
     716           4 :         CHECK_VAL(break_info.count, 1);
     717             : 
     718             :         /* We use the transport over which this oplock break was received */
     719           4 :         transport2 = break_info.received_transport;
     720           4 :         torture_reset_break_info(tctx, &break_info);
     721             : 
     722           4 :         block_setup = test_setup_blocked_transports(tctx);
     723           4 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
     724             : 
     725             :         /* block channel */
     726           4 :         block_ok = test_block_smb2_transport(tctx, transport2);
     727             : 
     728           4 :         torture_comment(tctx, "client1 opens fname2 via session 1\n");
     729           4 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     730           4 :         status = smb2_create(tree1, mem_ctx, &io2);
     731           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     732           4 :         h_client1_file2 = io2.out.file.handle;
     733           4 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     734           4 :         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           4 :         torture_wait_for_oplock_break(tctx);
     741           4 :         CHECK_VAL(break_info.count, 1);
     742           2 :         torture_reset_break_info(tctx, &break_info);
     743             : 
     744           2 :         torture_comment(tctx, "Trying write to file2 on tree2B\n");
     745             : 
     746           2 :         blob = data_blob_string_const("Here I am");
     747           2 :         status = smb2_util_write(tree2B,
     748             :                                  h_client2_file2,
     749           2 :                                  blob.data,
     750             :                                  0,
     751             :                                  blob.length);
     752           2 :         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           2 :         torture_wait_for_oplock_break(tctx);
     762           2 :         CHECK_VAL_GREATER_THAN(break_info.count, 0);
     763           2 :         torture_reset_break_info(tctx, &break_info);
     764             : 
     765           2 :         torture_comment(tctx, "client1 closes fname2 via session 1\n");
     766           2 :         smb2_util_close(tree1, h_client1_file2);
     767             : 
     768           2 :         torture_comment(tctx, "client1 opens fname2 via session 1 again\n");
     769           2 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     770           2 :         status = smb2_create(tree1, mem_ctx, &io2);
     771           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     772           2 :         h_client1_file2 = io2.out.file.handle;
     773           2 :         io2.out.alloc_size = 0;
     774           2 :         io2.out.size = 0;
     775           2 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     776           2 :         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           2 :         torture_comment(tctx, "Connecting session 2D\n");
     783           2 :         tree2D = test_multichannel_create_channel(tctx, host, share,
     784             :                                      credentials, &transport2_options, tree2B);
     785           2 :         if (!tree2D) {
     786           0 :                 goto done;
     787             :         }
     788             : 
     789           2 :         torture_reset_break_info(tctx, &break_info);
     790           2 :         torture_comment(tctx, "client 2 opening fname3 over transport2D\n");
     791           2 :         status = smb2_create(tree2D, mem_ctx, &io3);
     792           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     793           2 :         h_client2_file3 = io3.out.file.handle;
     794           2 :         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     795           2 :         CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("b"));
     796           2 :         torture_wait_for_oplock_break(tctx);
     797           2 :         CHECK_VAL(break_info.count, 0);
     798             : 
     799           2 :         torture_comment(tctx, "client1 opens fname3 via session 1\n");
     800           2 :         status = smb2_create(tree1, mem_ctx, &io3);
     801           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     802           2 :         h_client1_file3 = io3.out.file.handle;
     803           2 :         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     804           2 :         CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
     805           2 :         torture_wait_for_oplock_break(tctx);
     806           2 :         CHECK_VAL(break_info.count, 1);
     807             : 
     808           2 : done:
     809           4 :         if (block_ok && !unblock_ok) {
     810           4 :                 test_unblock_smb2_transport(tctx, transport2);
     811             :         }
     812           4 :         test_cleanup_blocked_transports(tctx);
     813             : 
     814           4 :         tree1->session = session1;
     815             : 
     816           4 :         smb2_util_close(tree1, h_client1_file1);
     817           4 :         smb2_util_close(tree1, h_client1_file2);
     818           4 :         smb2_util_close(tree1, h_client1_file3);
     819           4 :         if (tree2B != NULL) {
     820           4 :                 smb2_util_close(tree2B, h_client2_file1);
     821           4 :                 smb2_util_close(tree2B, h_client2_file2);
     822           4 :                 smb2_util_close(tree2B, h_client2_file3);
     823             :         }
     824             : 
     825           4 :         smb2_util_unlink(tree1, fname1);
     826           4 :         smb2_util_unlink(tree1, fname2);
     827           4 :         smb2_util_unlink(tree1, fname3);
     828           4 :         smb2_deltree(tree1, BASEDIR);
     829             : 
     830           4 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
     831           4 :         if (tree2D != NULL) {
     832           2 :                 TALLOC_FREE(tree2D);
     833             :         }
     834           4 :         talloc_free(tree1);
     835           4 :         talloc_free(mem_ctx);
     836             : 
     837           4 :         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         128 : 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         128 :         struct test_multichannel_oplock_break_channel *c =
     870             :                 (struct test_multichannel_oplock_break_channel *)private_data;
     871         128 :         struct test_multichannel_oplock_break_state *state = c->state;
     872             : 
     873         128 :         c->break_time = timeval_current();
     874         256 :         c->full_duration = timeval_elapsed2(&state->open_req_time,
     875         128 :                                             &c->break_time);
     876         256 :         c->relative_duration = timeval_elapsed2(&state->last_break_time,
     877         128 :                                                 &c->break_time);
     878         128 :         state->last_break_time = c->break_time;
     879         128 :         c->level = level;
     880         128 :         c->break_num = ++state->num_breaks;
     881             : 
     882         128 :         torture_comment(state->tctx, "Got OPLOCK break %zu on %s after %f ( %f)\n",
     883         128 :                         c->break_num, c->name,
     884             :                         c->relative_duration,
     885             :                         c->full_duration);
     886             : 
     887         128 :         return torture_oplock_ack_handler(transport, handle, level, c->tree);
     888             : }
     889             : 
     890           4 : static bool test_multichannel_oplock_break_test3_windows(struct torture_context *tctx,
     891             :                                                          struct smb2_tree *tree1)
     892             : {
     893           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
     894           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
     895           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
     896           0 :         NTSTATUS status;
     897           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     898           4 :         struct test_multichannel_oplock_break_state state = {
     899             :                 .tctx = tctx,
     900             :         };
     901           4 :         struct test_multichannel_oplock_break_channel *open2_channel = NULL;
     902           0 :         struct smb2_handle _h;
     903           4 :         struct smb2_handle *h = NULL;
     904           4 :         struct smb2_handle h_client1_file1 = {{0}};
     905           4 :         struct smb2_handle h_client2_file1 = {{0}};
     906           0 :         struct smb2_create io1;
     907           0 :         struct smb2_create io2;
     908           4 :         bool ret = true;
     909           4 :         const char *fname1 = BASEDIR "\\oplock_break_test3w.dat";
     910           4 :         struct smb2_tree *trees2[32] = { NULL, };
     911           0 :         size_t i;
     912           4 :         struct smb2_transport *transport1 = tree1->session->transport;
     913           0 :         struct smbcli_options transport2_options;
     914           4 :         struct smb2_session *session1 = tree1->session;
     915           4 :         uint16_t local_port = 0;
     916           4 :         bool block_setup = false;
     917           4 :         bool block_ok = false;
     918           0 :         double open_duration;
     919             : 
     920           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
     921           0 :                 return true;
     922             :         }
     923             : 
     924           4 :         torture_comment(tctx, "Oplock break retry: Test3 (Windows behavior)\n");
     925             : 
     926           4 :         torture_reset_break_info(tctx, &break_info);
     927           4 :         break_info.oplock_skip_ack = true;
     928             : 
     929           4 :         transport1->oplock.handler = torture_oplock_ack_handler;
     930           4 :         transport1->oplock.private_data = tree1;
     931           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
     932           4 :         local_port = torture_get_local_port_from_transport(transport1);
     933           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
     934             : 
     935           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
     936           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     937           4 :         smb2_util_close(tree1, _h);
     938           4 :         smb2_util_unlink(tree1, fname1);
     939           4 :         CHECK_VAL(break_info.count, 0);
     940             : 
     941           4 :         smb2_oplock_create_share(&io2, fname1,
     942             :                         smb2_util_share_access("RWD"),
     943           4 :                         smb2_util_oplock_level("b"));
     944             : 
     945           4 :         transport2_options = transport1->options;
     946             : 
     947           4 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
     948             :                                                      &transport2_options,
     949             :                                                      ARRAY_SIZE(trees2), trees2);
     950           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
     951             : 
     952         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
     953         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
     954         128 :                 struct smb2_transport *t = trees2[i]->session->transport;
     955             : 
     956         128 :                 c->state = &state;
     957         128 :                 c->idx = i+1;
     958         128 :                 c->tree = trees2[i];
     959         128 :                 snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
     960             : 
     961         128 :                 t->oplock.handler = test_multichannel_oplock_break_handler;
     962         128 :                 t->oplock.private_data = c;
     963             :         }
     964             : 
     965           4 :         open2_channel = &state.channels[0];
     966             : 
     967             :         /* 2a opens file1 */
     968           4 :         torture_comment(tctx, "client2 opens fname1 via %s\n",
     969           4 :                         open2_channel->name);
     970           4 :         status = smb2_create(open2_channel->tree, mem_ctx, &io2);
     971           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     972           4 :         h_client2_file1 = io2.out.file.handle;
     973           4 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     974           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
     975           4 :         CHECK_VAL(io2.out.durable_open_v2, false);
     976           4 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
     977           4 :         CHECK_VAL(io2.out.durable_open, false);
     978           4 :         CHECK_VAL(break_info.count, 0);
     979             : 
     980           4 :         block_setup = test_setup_blocked_transports(tctx);
     981           4 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
     982             : 
     983         132 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
     984         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
     985         128 :                 struct smb2_transport *t = c->tree->session->transport;
     986             : 
     987         128 :                 torture_comment(tctx, "Blocking %s\n", c->name);
     988         128 :                 block_ok = _test_block_smb2_transport(tctx, t, c->name);
     989         128 :                 torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
     990         128 :                 c->blocked = true;
     991             :         }
     992             : 
     993             :         /* 1 opens file2 */
     994           4 :         torture_comment(tctx,
     995             :                         "Client opens fname1 with session 1 with all %zu blocked\n",
     996             :                         ARRAY_SIZE(trees2));
     997           4 :         smb2_oplock_create_share(&io1, fname1,
     998             :                         smb2_util_share_access("RWD"),
     999           4 :                         smb2_util_oplock_level("b"));
    1000           4 :         CHECK_VAL(lease_break_info.count, 0);
    1001           4 :         state.open_req_time = timeval_current();
    1002           4 :         state.last_break_time = state.open_req_time;
    1003           4 :         status = smb2_create(tree1, mem_ctx, &io1);
    1004           4 :         state.open_rep_time = timeval_current();
    1005           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1006           4 :         h_client1_file1 = io1.out.file.handle;
    1007           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
    1008             : 
    1009           4 :         CHECK_VAL(break_info.count, 1);
    1010             : 
    1011           2 :         open_duration = timeval_elapsed2(&state.open_req_time,
    1012             :                                          &state.open_rep_time);
    1013           2 :         torture_comment(tctx, "open_duration: %f\n", open_duration);
    1014           2 :         CHECK_VAL_GREATER_THAN(open_duration, 35);
    1015             : 
    1016           2 :         if (break_info.count == 0) {
    1017           0 :                 torture_comment(tctx,
    1018             :                                 "Did not receive expected oplock break!!\n");
    1019             :         } else {
    1020           2 :                 torture_comment(tctx, "Received %d oplock break(s)!!\n",
    1021             :                                 break_info.count);
    1022             :         }
    1023             : 
    1024          66 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1025          64 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1026          64 :                 size_t expected_break_num = 0;
    1027             : 
    1028             :                 /*
    1029             :                  * Only the latest channel gets a break notification
    1030             :                  */
    1031          64 :                 if (i == (ARRAY_SIZE(state.channels) - 1)) {
    1032           2 :                         expected_break_num = 1;
    1033             :                 }
    1034             : 
    1035          64 :                 torture_comment(tctx, "Verify %s\n", c->name);
    1036          64 :                 torture_assert_int_equal(tctx, c->break_num, expected_break_num,
    1037             :                                          "Got oplock break on wrong channel");
    1038          64 :                 if (expected_break_num != 0) {
    1039           2 :                         CHECK_VAL(c->level, smb2_util_oplock_level("s"));
    1040             :                 }
    1041             :         }
    1042             : 
    1043           2 : done:
    1044         132 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1045         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1046         128 :                 struct smb2_transport *t = NULL;
    1047             : 
    1048         128 :                 if (!c->blocked) {
    1049           0 :                         continue;
    1050             :                 }
    1051             : 
    1052         128 :                 t = c->tree->session->transport;
    1053             : 
    1054         128 :                 torture_comment(tctx, "Unblocking %s\n", c->name);
    1055         128 :                 _test_unblock_smb2_transport(tctx, t, c->name);
    1056         128 :                 c->blocked = false;
    1057             :         }
    1058           4 :         if (block_setup) {
    1059           4 :                 test_cleanup_blocked_transports(tctx);
    1060             :         }
    1061             : 
    1062           4 :         tree1->session = session1;
    1063             : 
    1064           4 :         smb2_util_close(tree1, h_client1_file1);
    1065           4 :         if (trees2[0] != NULL) {
    1066           4 :                 smb2_util_close(trees2[0], h_client2_file1);
    1067             :         }
    1068             : 
    1069           4 :         if (h != NULL) {
    1070           0 :                 smb2_util_close(tree1, *h);
    1071             :         }
    1072             : 
    1073           4 :         smb2_util_unlink(tree1, fname1);
    1074           4 :         smb2_deltree(tree1, BASEDIR);
    1075             : 
    1076         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    1077         128 :                 if (trees2[i] == NULL) {
    1078           0 :                         continue;
    1079             :                 }
    1080         128 :                 TALLOC_FREE(trees2[i]);
    1081             :         }
    1082           4 :         talloc_free(tree1);
    1083           4 :         talloc_free(mem_ctx);
    1084             : 
    1085           4 :         return ret;
    1086             : }
    1087             : 
    1088           4 : static bool test_multichannel_oplock_break_test3_specification(struct torture_context *tctx,
    1089             :                                                                struct smb2_tree *tree1)
    1090             : {
    1091           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1092           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1093           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1094           0 :         NTSTATUS status;
    1095           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1096           4 :         struct test_multichannel_oplock_break_state state = {
    1097             :                 .tctx = tctx,
    1098             :         };
    1099           4 :         struct test_multichannel_oplock_break_channel *open2_channel = NULL;
    1100           0 :         struct smb2_handle _h;
    1101           4 :         struct smb2_handle *h = NULL;
    1102           4 :         struct smb2_handle h_client1_file1 = {{0}};
    1103           4 :         struct smb2_handle h_client2_file1 = {{0}};
    1104           0 :         struct smb2_create io1;
    1105           0 :         struct smb2_create io2;
    1106           4 :         bool ret = true;
    1107           4 :         const char *fname1 = BASEDIR "\\oplock_break_test3s.dat";
    1108           4 :         struct smb2_tree *trees2[32] = { NULL, };
    1109           0 :         size_t i;
    1110           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    1111           0 :         struct smbcli_options transport2_options;
    1112           4 :         struct smb2_session *session1 = tree1->session;
    1113           4 :         uint16_t local_port = 0;
    1114           4 :         bool block_setup = false;
    1115           4 :         bool block_ok = false;
    1116           0 :         double open_duration;
    1117             : 
    1118           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1119           0 :                 return true;
    1120             :         }
    1121             : 
    1122           4 :         torture_comment(tctx, "Oplock break retry: Test3 (Specification behavior)\n");
    1123             : 
    1124           4 :         torture_reset_break_info(tctx, &break_info);
    1125           4 :         break_info.oplock_skip_ack = true;
    1126             : 
    1127           4 :         transport1->oplock.handler = torture_oplock_ack_handler;
    1128           4 :         transport1->oplock.private_data = tree1;
    1129           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1130           4 :         local_port = torture_get_local_port_from_transport(transport1);
    1131           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1132             : 
    1133           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1134           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1135           4 :         smb2_util_close(tree1, _h);
    1136           4 :         smb2_util_unlink(tree1, fname1);
    1137           4 :         CHECK_VAL(break_info.count, 0);
    1138             : 
    1139           4 :         smb2_oplock_create_share(&io2, fname1,
    1140             :                         smb2_util_share_access("RWD"),
    1141           4 :                         smb2_util_oplock_level("b"));
    1142             : 
    1143           4 :         transport2_options = transport1->options;
    1144             : 
    1145           4 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
    1146             :                                                      &transport2_options,
    1147             :                                                      ARRAY_SIZE(trees2), trees2);
    1148           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1149             : 
    1150         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    1151         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1152         128 :                 struct smb2_transport *t = trees2[i]->session->transport;
    1153             : 
    1154         128 :                 c->state = &state;
    1155         128 :                 c->idx = i+1;
    1156         128 :                 c->tree = trees2[i];
    1157         128 :                 snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
    1158             : 
    1159         128 :                 t->oplock.handler = test_multichannel_oplock_break_handler;
    1160         128 :                 t->oplock.private_data = c;
    1161             :         }
    1162             : 
    1163           4 :         open2_channel = &state.channels[0];
    1164             : 
    1165             :         /* 2a opens file1 */
    1166           4 :         torture_comment(tctx, "client2 opens fname1 via %s\n",
    1167           4 :                         open2_channel->name);
    1168           4 :         status = smb2_create(open2_channel->tree, mem_ctx, &io2);
    1169           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1170           4 :         h_client2_file1 = io2.out.file.handle;
    1171           4 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1172           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
    1173           4 :         CHECK_VAL(io2.out.durable_open_v2, false);
    1174           4 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
    1175           4 :         CHECK_VAL(io2.out.durable_open, false);
    1176           4 :         CHECK_VAL(break_info.count, 0);
    1177             : 
    1178           4 :         block_setup = test_setup_blocked_transports(tctx);
    1179           4 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
    1180             : 
    1181         132 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1182         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1183         128 :                 struct smb2_transport *t = c->tree->session->transport;
    1184             : 
    1185         128 :                 torture_comment(tctx, "Blocking %s\n", c->name);
    1186         128 :                 block_ok = _test_block_smb2_transport(tctx, t, c->name);
    1187         128 :                 torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
    1188         128 :                 c->blocked = true;
    1189             :         }
    1190             : 
    1191             :         /* 1 opens file2 */
    1192           4 :         torture_comment(tctx,
    1193             :                         "Client opens fname1 with session 1 with all %zu blocked\n",
    1194             :                         ARRAY_SIZE(trees2));
    1195           4 :         smb2_oplock_create_share(&io1, fname1,
    1196             :                         smb2_util_share_access("RWD"),
    1197           4 :                         smb2_util_oplock_level("b"));
    1198           4 :         CHECK_VAL(lease_break_info.count, 0);
    1199           4 :         state.open_req_time = timeval_current();
    1200           4 :         state.last_break_time = state.open_req_time;
    1201           4 :         status = smb2_create(tree1, mem_ctx, &io1);
    1202           4 :         state.open_rep_time = timeval_current();
    1203           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1204           4 :         h_client1_file1 = io1.out.file.handle;
    1205             : 
    1206           4 :         CHECK_VAL_GREATER_THAN(break_info.count, 1);
    1207             : 
    1208           2 :         open_duration = timeval_elapsed2(&state.open_req_time,
    1209             :                                          &state.open_rep_time);
    1210           2 :         torture_comment(tctx, "open_duration: %f\n", open_duration);
    1211           2 :         if (break_info.count < ARRAY_SIZE(state.channels)) {
    1212           2 :                 CHECK_VAL_GREATER_THAN(open_duration, 35);
    1213           2 :                 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          10 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1219          10 :                 if (break_info.count >= ARRAY_SIZE(state.channels)) {
    1220           2 :                         break;
    1221             :                 }
    1222           8 :                 torture_comment(tctx, "Received %d oplock break(s) wait for more!!\n",
    1223             :                                 break_info.count);
    1224           8 :                 torture_wait_for_oplock_break(tctx);
    1225             :         }
    1226             : 
    1227           2 :         if (break_info.count == 0) {
    1228           0 :                 torture_comment(tctx,
    1229             :                                 "Did not receive expected oplock break!!\n");
    1230             :         } else {
    1231           2 :                 torture_comment(tctx, "Received %d oplock break(s)!!\n",
    1232             :                                 break_info.count);
    1233             :         }
    1234             : 
    1235           2 :         if (break_info.count < ARRAY_SIZE(state.channels)) {
    1236           0 :                 CHECK_VAL_GREATER_THAN(break_info.count, 3);
    1237             :         } else {
    1238           2 :                 CHECK_VAL(break_info.count, ARRAY_SIZE(state.channels));
    1239             :         }
    1240             : 
    1241          66 :         for (i = 0; i < break_info.count; i++) {
    1242          64 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1243             : 
    1244          64 :                 torture_comment(tctx, "Verify %s\n", c->name);
    1245          64 :                 torture_assert_int_equal(tctx, c->break_num, c->idx,
    1246             :                                          "Got oplock break on wrong channel");
    1247          64 :                 CHECK_VAL(c->level, smb2_util_oplock_level("s"));
    1248             :         }
    1249             : 
    1250           2 : done:
    1251         132 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1252         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1253         128 :                 struct smb2_transport *t = NULL;
    1254             : 
    1255         128 :                 if (!c->blocked) {
    1256           0 :                         continue;
    1257             :                 }
    1258             : 
    1259         128 :                 t = c->tree->session->transport;
    1260             : 
    1261         128 :                 torture_comment(tctx, "Unblocking %s\n", c->name);
    1262         128 :                 _test_unblock_smb2_transport(tctx, t, c->name);
    1263         128 :                 c->blocked = false;
    1264             :         }
    1265           4 :         if (block_setup) {
    1266           4 :                 test_cleanup_blocked_transports(tctx);
    1267             :         }
    1268             : 
    1269           4 :         tree1->session = session1;
    1270             : 
    1271           4 :         smb2_util_close(tree1, h_client1_file1);
    1272           4 :         if (trees2[0] != NULL) {
    1273           4 :                 smb2_util_close(trees2[0], h_client2_file1);
    1274             :         }
    1275             : 
    1276           4 :         if (h != NULL) {
    1277           0 :                 smb2_util_close(tree1, *h);
    1278             :         }
    1279             : 
    1280           4 :         smb2_util_unlink(tree1, fname1);
    1281           4 :         smb2_deltree(tree1, BASEDIR);
    1282             : 
    1283         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    1284         128 :                 if (trees2[i] == NULL) {
    1285           0 :                         continue;
    1286             :                 }
    1287         128 :                 TALLOC_FREE(trees2[i]);
    1288             :         }
    1289           4 :         talloc_free(tree1);
    1290           4 :         talloc_free(mem_ctx);
    1291             : 
    1292           4 :         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           4 : static bool test_multichannel_lease_break_test1(struct torture_context *tctx,
    1316             :                                                 struct smb2_tree *tree1)
    1317             : {
    1318           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1319           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1320           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1321           0 :         NTSTATUS status;
    1322           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1323           0 :         struct smb2_handle _h;
    1324           4 :         struct smb2_handle *h = NULL;
    1325           4 :         struct smb2_handle h_client1_file1 = {{0}};
    1326           4 :         struct smb2_handle h_client1_file2 = {{0}};
    1327           4 :         struct smb2_handle h_client1_file3 = {{0}};
    1328           4 :         struct smb2_handle h_client2_file1 = {{0}};
    1329           4 :         struct smb2_handle h_client2_file2 = {{0}};
    1330           4 :         struct smb2_handle h_client2_file3 = {{0}};
    1331           0 :         struct smb2_create io1, io2, io3;
    1332           4 :         bool ret = true;
    1333           4 :         const char *fname1 = BASEDIR "\\lease_break_test1.dat";
    1334           4 :         const char *fname2 = BASEDIR "\\lease_break_test2.dat";
    1335           4 :         const char *fname3 = BASEDIR "\\lease_break_test3.dat";
    1336           4 :         struct smb2_tree *tree2A = NULL;
    1337           4 :         struct smb2_tree *tree2B = NULL;
    1338           4 :         struct smb2_tree *tree2C = NULL;
    1339           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    1340           0 :         struct smbcli_options transport2_options;
    1341           4 :         struct smb2_session *session1 = tree1->session;
    1342           4 :         uint16_t local_port = 0;
    1343           0 :         struct smb2_lease ls1;
    1344           0 :         struct smb2_lease ls2;
    1345           0 :         struct smb2_lease ls3;
    1346             : 
    1347           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1348           0 :                 return true;
    1349             :         }
    1350             : 
    1351           4 :         torture_comment(tctx, "Lease break retry: Test1\n");
    1352             : 
    1353           4 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1354             : 
    1355           4 :         transport1->lease.handler = torture_lease_handler;
    1356           4 :         transport1->lease.private_data = tree1;
    1357           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1358           4 :         local_port = torture_get_local_port_from_transport(transport1);
    1359           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1360             : 
    1361           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1362           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1363           4 :         smb2_util_close(tree1, _h);
    1364           4 :         smb2_util_unlink(tree1, fname1);
    1365           4 :         smb2_util_unlink(tree1, fname2);
    1366           4 :         smb2_util_unlink(tree1, fname3);
    1367           4 :         CHECK_VAL(lease_break_info.count, 0);
    1368             : 
    1369           4 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1370             :                           smb2_util_lease_state("RHW"));
    1371           4 :         test_multichannel_init_smb_create(&io1);
    1372             : 
    1373           4 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
    1374             :                           smb2_util_lease_state("RHW"));
    1375           4 :         test_multichannel_init_smb_create(&io2);
    1376             : 
    1377           4 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1378             :                           smb2_util_lease_state("RHW"));
    1379           4 :         test_multichannel_init_smb_create(&io3);
    1380             : 
    1381           4 :         transport2_options = transport1->options;
    1382             : 
    1383           4 :         ret = test_multichannel_create_channels(tctx, host, share,
    1384             :                                                   credentials,
    1385             :                                                   &transport2_options,
    1386             :                                                   &tree2A, &tree2B, &tree2C);
    1387           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1388             : 
    1389             :         /* 2a opens file1 */
    1390           4 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
    1391           4 :         status = smb2_create(tree2A, mem_ctx, &io1);
    1392           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1393           4 :         h_client2_file1 = io1.out.file.handle;
    1394           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1395           4 :         CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
    1396           2 :         CHECK_VAL(lease_break_info.count, 0);
    1397             : 
    1398             :         /* 2b opens file2 */
    1399           2 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
    1400           2 :         status = smb2_create(tree2B, mem_ctx, &io2);
    1401           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1402           2 :         h_client2_file2 = io2.out.file.handle;
    1403           2 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1404           2 :         CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
    1405           2 :         CHECK_VAL(lease_break_info.count, 0);
    1406             : 
    1407             :         /* 2c opens file3 */
    1408           2 :         torture_comment(tctx, "client2 opens fname3 via session 2C\n");
    1409           2 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1410             :                           smb2_util_lease_state("RHW"));
    1411           2 :         status = smb2_create(tree2C, mem_ctx, &io3);
    1412           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1413           2 :         h_client2_file3 = io3.out.file.handle;
    1414           2 :         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1415           2 :         CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
    1416           2 :         CHECK_VAL(lease_break_info.count, 0);
    1417             : 
    1418             :         /* 1 opens file1 - lease break? */
    1419           2 :         torture_comment(tctx, "client1 opens fname1 via session 1\n");
    1420           2 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
    1421             :                           smb2_util_lease_state("RHW"));
    1422           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    1423           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1424           2 :         h_client1_file1 = io1.out.file.handle;
    1425           2 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1426           2 :         CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
    1427           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
    1428           2 :         CHECK_VAL(lease_break_info.count, 1);
    1429             : 
    1430           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1431             : 
    1432             :         /* 1 opens file2 - lease break? */
    1433           2 :         torture_comment(tctx, "client1 opens fname2 via session 1\n");
    1434           2 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
    1435             :                           smb2_util_lease_state("RHW"));
    1436           2 :         status = smb2_create(tree1, mem_ctx, &io2);
    1437           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1438           2 :         h_client1_file2 = io2.out.file.handle;
    1439           2 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1440           2 :         CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
    1441           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
    1442           2 :         CHECK_VAL(lease_break_info.count, 1);
    1443             : 
    1444           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1445             : 
    1446             :         /* 1 opens file3 - lease break? */
    1447           2 :         torture_comment(tctx, "client1 opens fname3 via session 1\n");
    1448           2 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
    1449             :                           smb2_util_lease_state("RHW"));
    1450           2 :         status = smb2_create(tree1, mem_ctx, &io3);
    1451           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1452           2 :         h_client1_file3 = io3.out.file.handle;
    1453           2 :         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1454           2 :         CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
    1455           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
    1456           2 :         CHECK_VAL(lease_break_info.count, 1);
    1457             : 
    1458             :         /* cleanup everything */
    1459           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1460             : 
    1461           2 :         smb2_util_close(tree1, h_client1_file1);
    1462           2 :         smb2_util_close(tree1, h_client1_file2);
    1463           2 :         smb2_util_close(tree1, h_client1_file3);
    1464           2 :         smb2_util_close(tree2A, h_client2_file1);
    1465           2 :         smb2_util_close(tree2A, h_client2_file2);
    1466           2 :         smb2_util_close(tree2A, h_client2_file3);
    1467             : 
    1468           2 :         smb2_util_unlink(tree1, fname1);
    1469           2 :         smb2_util_unlink(tree1, fname2);
    1470           2 :         smb2_util_unlink(tree1, fname3);
    1471           2 :         CHECK_VAL(lease_break_info.count, 0);
    1472           2 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1473           2 :         tree2A = tree2B = tree2C = NULL;
    1474           4 : done:
    1475           4 :         tree1->session = session1;
    1476             : 
    1477           4 :         smb2_util_close(tree1, h_client1_file1);
    1478           4 :         smb2_util_close(tree1, h_client1_file2);
    1479           4 :         smb2_util_close(tree1, h_client1_file3);
    1480           4 :         if (tree2A != NULL) {
    1481           2 :                 smb2_util_close(tree2A, h_client2_file1);
    1482           2 :                 smb2_util_close(tree2A, h_client2_file2);
    1483           2 :                 smb2_util_close(tree2A, h_client2_file3);
    1484             :         }
    1485             : 
    1486           4 :         if (h != NULL) {
    1487           0 :                 smb2_util_close(tree1, *h);
    1488             :         }
    1489             : 
    1490           4 :         smb2_util_unlink(tree1, fname1);
    1491           4 :         smb2_util_unlink(tree1, fname2);
    1492           4 :         smb2_util_unlink(tree1, fname3);
    1493           4 :         smb2_deltree(tree1, BASEDIR);
    1494             : 
    1495           4 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1496           4 :         talloc_free(tree1);
    1497           4 :         talloc_free(mem_ctx);
    1498             : 
    1499           4 :         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           4 : static bool test_multichannel_lease_break_test2(struct torture_context *tctx,
    1526             :                                                 struct smb2_tree *tree1)
    1527             : {
    1528           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1529           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1530           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1531           0 :         NTSTATUS status;
    1532           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1533           0 :         struct smb2_handle _h;
    1534           4 :         struct smb2_handle *h = NULL;
    1535           4 :         struct smb2_handle h_client1_file1 = {{0}};
    1536           4 :         struct smb2_handle h_client1_file2 = {{0}};
    1537           4 :         struct smb2_handle h_client1_file3 = {{0}};
    1538           4 :         struct smb2_handle h_client2_file1 = {{0}};
    1539           4 :         struct smb2_handle h_client2_file2 = {{0}};
    1540           4 :         struct smb2_handle h_client2_file3 = {{0}};
    1541           0 :         struct smb2_create io1, io2, io3;
    1542           4 :         bool ret = true;
    1543           4 :         const char *fname1 = BASEDIR "\\lease_break_test1.dat";
    1544           4 :         const char *fname2 = BASEDIR "\\lease_break_test2.dat";
    1545           4 :         const char *fname3 = BASEDIR "\\lease_break_test3.dat";
    1546           4 :         struct smb2_tree *tree2A = NULL;
    1547           4 :         struct smb2_tree *tree2B = NULL;
    1548           4 :         struct smb2_tree *tree2C = NULL;
    1549           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    1550           4 :         struct smb2_transport *transport2A = NULL;
    1551           0 :         struct smbcli_options transport2_options;
    1552           4 :         struct smb2_session *session1 = tree1->session;
    1553           4 :         uint16_t local_port = 0;
    1554           0 :         struct smb2_lease ls1;
    1555           0 :         struct smb2_lease ls2;
    1556           0 :         struct smb2_lease ls3;
    1557           4 :         bool block_setup = false;
    1558           4 :         bool block_ok = false;
    1559           4 :         bool unblock_ok = false;
    1560             : 
    1561             : 
    1562           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1563           0 :                 return true;
    1564             :         }
    1565             : 
    1566           4 :         torture_comment(tctx, "Lease break retry: Test2\n");
    1567             : 
    1568           4 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1569             : 
    1570           4 :         transport1->lease.handler = torture_lease_handler;
    1571           4 :         transport1->lease.private_data = tree1;
    1572           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1573           4 :         local_port = torture_get_local_port_from_transport(transport1);
    1574           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1575             : 
    1576           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1577           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1578           4 :         smb2_util_close(tree1, _h);
    1579           4 :         smb2_util_unlink(tree1, fname1);
    1580           4 :         smb2_util_unlink(tree1, fname2);
    1581           4 :         smb2_util_unlink(tree1, fname3);
    1582           4 :         CHECK_VAL(lease_break_info.count, 0);
    1583             : 
    1584           4 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1585             :                           smb2_util_lease_state("RHW"));
    1586           4 :         test_multichannel_init_smb_create(&io1);
    1587             : 
    1588           4 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
    1589             :                           smb2_util_lease_state("RHW"));
    1590           4 :         test_multichannel_init_smb_create(&io2);
    1591             : 
    1592           4 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1593             :                           smb2_util_lease_state("RHW"));
    1594           4 :         test_multichannel_init_smb_create(&io3);
    1595             : 
    1596           4 :         transport2_options = transport1->options;
    1597             : 
    1598           4 :         ret = test_multichannel_create_channels(tctx, host, share,
    1599             :                                                   credentials,
    1600             :                                                   &transport2_options,
    1601             :                                                   &tree2A, &tree2B, NULL);
    1602           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1603           4 :         transport2A = tree2A->session->transport;
    1604             : 
    1605             :         /* 2a opens file1 */
    1606           4 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
    1607           4 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1608             :                           smb2_util_lease_state("RHW"));
    1609           4 :         status = smb2_create(tree2A, mem_ctx, &io1);
    1610           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1611           4 :         h_client2_file1 = io1.out.file.handle;
    1612           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1613           4 :         CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
    1614           2 :         CHECK_VAL(io1.out.durable_open_v2, false); //true);
    1615           2 :         CHECK_VAL(io1.out.timeout, io1.in.timeout);
    1616           2 :         CHECK_VAL(io1.out.durable_open, false);
    1617           2 :         CHECK_VAL(lease_break_info.count, 0);
    1618             : 
    1619             :         /* 2b opens file2 */
    1620           2 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
    1621           2 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
    1622             :                           smb2_util_lease_state("RHW"));
    1623           2 :         status = smb2_create(tree2B, mem_ctx, &io2);
    1624           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1625           2 :         h_client2_file2 = io2.out.file.handle;
    1626           2 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1627           2 :         CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
    1628           2 :         CHECK_VAL(io2.out.durable_open_v2, false); //true);
    1629           2 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
    1630           2 :         CHECK_VAL(io2.out.durable_open, false);
    1631           2 :         CHECK_VAL(lease_break_info.count, 0);
    1632             : 
    1633           2 :         block_setup = test_setup_blocked_transports(tctx);
    1634           2 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
    1635             : 
    1636           2 :         torture_comment(tctx, "Blocking 2A\n");
    1637             :         /* Block 2A */
    1638           2 :         block_ok = test_block_smb2_transport(tctx, transport2A);
    1639           2 :         torture_assert(tctx, block_ok, "we could not block tcp transport");
    1640             : 
    1641           2 :         torture_wait_for_lease_break(tctx);
    1642           2 :         CHECK_VAL(lease_break_info.count, 0);
    1643             : 
    1644             :         /* 1 opens file2 */
    1645           2 :         torture_comment(tctx,
    1646             :                         "Client opens fname2 with session1 with 2A blocked\n");
    1647           2 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
    1648             :                           smb2_util_lease_state("RHW"));
    1649           2 :         status = smb2_create(tree1, mem_ctx, &io2);
    1650           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1651           2 :         h_client1_file2 = io2.out.file.handle;
    1652           2 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1653           2 :         CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
    1654           2 :         CHECK_VAL(io2.out.durable_open_v2, false);
    1655           2 :         CHECK_VAL(io2.out.timeout, 0);
    1656           2 :         CHECK_VAL(io2.out.durable_open, false);
    1657             : 
    1658           2 :         if (lease_break_info.count == 0) {
    1659           0 :                 torture_comment(tctx,
    1660             :                                 "Did not receive expected lease break!!\n");
    1661             :         } else {
    1662           2 :                 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           2 :         CHECK_VAL(lease_break_info.count, 2);
    1671           2 :         lease_break_info.count -= 1;
    1672           2 :         CHECK_VAL(lease_break_info.failures, 1);
    1673           2 :         lease_break_info.failures -= 1;
    1674           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
    1675           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1676             : 
    1677             :         /* Connect 2C */
    1678           2 :         torture_comment(tctx, "Connecting session 2C\n");
    1679           2 :         talloc_free(tree2C);
    1680           2 :         tree2C = test_multichannel_create_channel(tctx, host, share,
    1681             :                                 credentials, &transport2_options, tree2A);
    1682           2 :         if (!tree2C) {
    1683           0 :                 goto done;
    1684             :         }
    1685             : 
    1686             :         /* 2c opens file3 */
    1687           2 :         torture_comment(tctx, "client2 opens fname3 via session 2C\n");
    1688           2 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1689             :                           smb2_util_lease_state("RHW"));
    1690           2 :         status = smb2_create(tree2C, mem_ctx, &io3);
    1691           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1692           2 :         h_client2_file3 = io3.out.file.handle;
    1693           2 :         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1694           2 :         CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
    1695           2 :         CHECK_VAL(io3.out.durable_open_v2, false);
    1696           2 :         CHECK_VAL(io3.out.timeout, io2.in.timeout);
    1697           2 :         CHECK_VAL(io3.out.durable_open, false);
    1698           2 :         CHECK_VAL(lease_break_info.count, 0);
    1699             : 
    1700             :         /* Unblock 2A */
    1701           2 :         torture_comment(tctx, "Unblocking 2A\n");
    1702           2 :         unblock_ok = test_unblock_smb2_transport(tctx, transport2A);
    1703           2 :         torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
    1704             : 
    1705             :         /* 1 opens file1 */
    1706           2 :         torture_comment(tctx, "Client opens fname1 with session 1\n");
    1707           2 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
    1708             :                           smb2_util_lease_state("RHW"));
    1709           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    1710           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1711           2 :         h_client1_file1 = io1.out.file.handle;
    1712           2 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1713           2 :         CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
    1714             : 
    1715           2 :         if (lease_break_info.count == 0) {
    1716           0 :                 torture_comment(tctx,
    1717             :                                 "Did not receive expected lease break!!\n");
    1718             :         } else {
    1719           2 :                 torture_comment(tctx,
    1720             :                                 "Received %d lease break(s)!!\n",
    1721             :                                 lease_break_info.count);
    1722             :         }
    1723           2 :         CHECK_VAL(lease_break_info.count, 1);
    1724           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
    1725           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1726             : 
    1727             :         /*1 opens file3 */
    1728           2 :         torture_comment(tctx, "client opens fname3 via session 1\n");
    1729             : 
    1730           2 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
    1731             :                           smb2_util_lease_state("RHW"));
    1732           2 :         status = smb2_create(tree1, mem_ctx, &io3);
    1733           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1734           2 :         h_client1_file3 = io3.out.file.handle;
    1735           2 :         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1736           2 :         CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
    1737             : 
    1738           2 :         if (lease_break_info.count == 0) {
    1739           0 :                 torture_comment(tctx,
    1740             :                                 "Did not receive expected lease break!!\n");
    1741             :         } else {
    1742           2 :                 torture_comment(tctx,
    1743             :                                 "Received %d lease break(s)!!\n",
    1744             :                                 lease_break_info.count);
    1745             :         }
    1746           2 :         CHECK_VAL(lease_break_info.count, 1);
    1747           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
    1748           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1749             : 
    1750           2 :         smb2_util_close(tree1, h_client1_file1);
    1751           2 :         smb2_util_close(tree1, h_client1_file2);
    1752           2 :         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           2 :         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           2 :         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           2 :         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           2 :         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           2 :         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           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1786             : 
    1787           2 :         smb2_util_close(tree2C, h_client2_file1);
    1788           2 :         smb2_util_close(tree2C, h_client2_file2);
    1789           2 :         smb2_util_close(tree2C, h_client2_file3);
    1790             : 
    1791           2 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1792           2 :         tree2A = tree2B = tree2C = NULL;
    1793             : 
    1794           4 : done:
    1795           4 :         if (block_ok && !unblock_ok) {
    1796           0 :                 test_unblock_smb2_transport(tctx, transport2A);
    1797             :         }
    1798           4 :         if (block_setup) {
    1799           2 :                 test_cleanup_blocked_transports(tctx);
    1800             :         }
    1801             : 
    1802           4 :         tree1->session = session1;
    1803             : 
    1804           4 :         smb2_util_close(tree1, h_client1_file1);
    1805           4 :         smb2_util_close(tree1, h_client1_file2);
    1806           4 :         smb2_util_close(tree1, h_client1_file3);
    1807           4 :         if (tree2A != NULL) {
    1808           2 :                 smb2_util_close(tree2A, h_client2_file1);
    1809           2 :                 smb2_util_close(tree2A, h_client2_file2);
    1810           2 :                 smb2_util_close(tree2A, h_client2_file3);
    1811             :         }
    1812             : 
    1813           4 :         if (h != NULL) {
    1814           0 :                 smb2_util_close(tree1, *h);
    1815             :         }
    1816             : 
    1817           4 :         smb2_util_unlink(tree1, fname1);
    1818           4 :         smb2_util_unlink(tree1, fname2);
    1819           4 :         smb2_util_unlink(tree1, fname3);
    1820           4 :         smb2_deltree(tree1, BASEDIR);
    1821             : 
    1822           4 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1823           4 :         talloc_free(tree1);
    1824           4 :         talloc_free(mem_ctx);
    1825             : 
    1826           4 :         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           4 : static bool test_multichannel_lease_break_test3(struct torture_context *tctx,
    1841             :                                                 struct smb2_tree *tree1)
    1842             : {
    1843           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1844           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1845           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1846           0 :         NTSTATUS status;
    1847           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1848           0 :         struct smb2_handle _h;
    1849           4 :         struct smb2_handle *h = NULL;
    1850           4 :         struct smb2_handle h_client1_file1 = {{0}};
    1851           4 :         struct smb2_handle h_client2_file1 = {{0}};
    1852           0 :         struct smb2_create io1;
    1853           4 :         bool ret = true;
    1854           4 :         const char *fname1 = BASEDIR "\\lease_break_test1.dat";
    1855           4 :         struct smb2_tree *tree2A = NULL;
    1856           4 :         struct smb2_tree *tree2B = NULL;
    1857           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    1858           4 :         struct smb2_transport *transport2A = NULL;
    1859           0 :         struct smbcli_options transport2_options;
    1860           4 :         uint16_t local_port = 0;
    1861           0 :         struct smb2_lease ls1;
    1862           4 :         struct tevent_timer *te = NULL;
    1863           0 :         struct timeval ne;
    1864           4 :         bool timesup = false;
    1865             : 
    1866           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1867           0 :                 return true;
    1868             :         }
    1869             : 
    1870           4 :         torture_comment(tctx, "Lease break retry: Test3\n");
    1871             : 
    1872           4 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1873             : 
    1874           4 :         transport1->lease.handler = torture_lease_handler;
    1875           4 :         transport1->lease.private_data = tree1;
    1876           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1877           4 :         local_port = torture_get_local_port_from_transport(transport1);
    1878           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1879             : 
    1880           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1881           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1882           4 :         smb2_util_close(tree1, _h);
    1883           4 :         smb2_util_unlink(tree1, fname1);
    1884           4 :         CHECK_VAL(lease_break_info.count, 0);
    1885             : 
    1886           4 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1887             :                           smb2_util_lease_state("RHW"));
    1888           4 :         test_multichannel_init_smb_create(&io1);
    1889             : 
    1890           4 :         transport2_options = transport1->options;
    1891             : 
    1892           4 :         ret = test_multichannel_create_channels(tctx, host, share,
    1893             :                                                 credentials,
    1894             :                                                 &transport2_options,
    1895             :                                                 &tree2A, &tree2B, NULL);
    1896           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1897           4 :         transport2A = tree2A->session->transport;
    1898           4 :         transport2A->lease.private_data = tree2B;
    1899             : 
    1900             :         /* 2a opens file1 */
    1901           4 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
    1902           4 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1903             :                           smb2_util_lease_state("RHW"));
    1904           4 :         status = smb2_create(tree2A, mem_ctx, &io1);
    1905           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1906           4 :         h_client2_file1 = io1.out.file.handle;
    1907           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1908           4 :         CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
    1909           2 :         CHECK_VAL(io1.out.durable_open_v2, false); //true);
    1910           2 :         CHECK_VAL(io1.out.timeout, io1.in.timeout);
    1911           2 :         CHECK_VAL(io1.out.durable_open, false);
    1912           2 :         CHECK_VAL(lease_break_info.count, 0);
    1913             : 
    1914             :         /* Set a timeout for 5 seconds for session 1 to open file1 */
    1915           2 :         ne = tevent_timeval_current_ofs(0, 5000000);
    1916           2 :         te = tevent_add_timer(tctx->ev, mem_ctx, ne, timeout_cb, &timesup);
    1917           2 :         if (te == NULL) {
    1918           0 :                 torture_comment(tctx, "Failed to add timer.");
    1919           0 :                 goto done;
    1920             :         }
    1921             : 
    1922             :         /* 1 opens file2 */
    1923           2 :         torture_comment(tctx, "Client opens fname1 with session 1\n");
    1924           2 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
    1925             :                           smb2_util_lease_state("RHW"));
    1926           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    1927           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1928           2 :         h_client1_file1 = io1.out.file.handle;
    1929           2 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1930           2 :         CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
    1931           2 :         CHECK_VAL(io1.out.durable_open_v2, false);
    1932           2 :         CHECK_VAL(io1.out.timeout, 0);
    1933           2 :         CHECK_VAL(io1.out.durable_open, false);
    1934             : 
    1935           2 :         CHECK_VAL(lease_break_info.count, 1);
    1936           2 :         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           2 :         CHECK_VAL(timesup, false);
    1945             : 
    1946           2 : done:
    1947           4 :         smb2_util_close(tree1, h_client1_file1);
    1948           4 :         if (tree2A != NULL) {
    1949           4 :                 smb2_util_close(tree2A, h_client2_file1);
    1950             :         }
    1951             : 
    1952           4 :         if (h != NULL) {
    1953           0 :                 smb2_util_close(tree1, *h);
    1954             :         }
    1955             : 
    1956           4 :         smb2_util_unlink(tree1, fname1);
    1957           4 :         smb2_deltree(tree1, BASEDIR);
    1958             : 
    1959           4 :         test_multichannel_free_channels(tree2A, tree2B, NULL);
    1960           4 :         talloc_free(tree1);
    1961           4 :         talloc_free(mem_ctx);
    1962             : 
    1963           4 :         return ret;
    1964             : }
    1965             : 
    1966             : /*
    1967             :  * Test limits of channels
    1968             :  */
    1969           4 : static bool test_multichannel_num_channels(struct torture_context *tctx,
    1970             :                                            struct smb2_tree *tree1)
    1971             : {
    1972           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1973           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1974           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1975           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1976           4 :         bool ret = true;
    1977           4 :         struct smb2_tree **tree2 = NULL;
    1978           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    1979           4 :         struct smb2_transport **transport2 = NULL;
    1980           0 :         struct smbcli_options transport2_options;
    1981           4 :         struct smb2_session **session2 = NULL;
    1982           0 :         uint32_t server_capabilities;
    1983           0 :         int i;
    1984           4 :         int max_channels = 33; /* 32 is the W2K12R2 and W2K16 limit */
    1985             : 
    1986           4 :         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           4 :         server_capabilities = smb2cli_conn_server_capabilities(
    1993           4 :                                         tree1->session->transport->conn);
    1994           4 :         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
    1995           0 :                 torture_fail(tctx,
    1996             :                              "Server does not support multichannel.");
    1997             :         }
    1998             : 
    1999           4 :         torture_comment(tctx, "Testing max. number of channels\n");
    2000             : 
    2001           4 :         transport2_options = transport1->options;
    2002           4 :         transport2_options.client_guid = GUID_random();
    2003             : 
    2004           4 :         tree2           = talloc_zero_array(mem_ctx, struct smb2_tree *,
    2005             :                                             max_channels);
    2006           4 :         transport2      = talloc_zero_array(mem_ctx, struct smb2_transport *,
    2007             :                                             max_channels);
    2008           4 :         session2        = talloc_zero_array(mem_ctx, struct smb2_session *,
    2009             :                                             max_channels);
    2010           4 :         if (tree2 == NULL || transport2 == NULL || session2 == NULL) {
    2011           0 :                 torture_fail(tctx, "out of memory");
    2012             :         }
    2013             : 
    2014         136 :         for (i = 0; i < max_channels; i++) {
    2015             : 
    2016           0 :                 NTSTATUS expected_status;
    2017             : 
    2018         132 :                 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         132 :                 transport2[i] = tree2[i]->session->transport;
    2034             : 
    2035         132 :                 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           4 :                         transport2_options.only_negprot = true;
    2043           4 :                         continue;
    2044             :                 }
    2045             : 
    2046             :                 /*
    2047             :                  * Now bind the session2[i] to the transport2
    2048             :                  */
    2049         128 :                 session2[i] = smb2_session_channel(transport2[i],
    2050             :                                                    lpcfg_gensec_settings(tctx,
    2051             :                                                                  tctx->lp_ctx),
    2052             :                                                    tree2[0],
    2053         128 :                                                    tree2[0]->session);
    2054             : 
    2055         128 :                 torture_assert(tctx, session2[i] != NULL,
    2056             :                                "smb2_session_channel failed");
    2057             : 
    2058         128 :                 torture_comment(tctx, "established transport2 [#%d]\n", i);
    2059             : 
    2060         128 :                 if (i >= 32) {
    2061           4 :                         expected_status = NT_STATUS_INSUFFICIENT_RESOURCES;
    2062             :                 } else {
    2063         124 :                         expected_status = NT_STATUS_OK;
    2064             :                 }
    2065             : 
    2066         128 :                 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         128 :                 torture_comment(tctx, "bound session2 [#%d] to session2 [0]\n",
    2076             :                                 i);
    2077             :         }
    2078             : 
    2079           4 :  done:
    2080           4 :         talloc_free(mem_ctx);
    2081             : 
    2082           4 :         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          64 : static bool test_multichannel_lease_break_handler(struct smb2_transport *transport,
    2110             :                                                   const struct smb2_lease_break *lb,
    2111             :                                                   void *private_data)
    2112             : {
    2113          64 :         struct test_multichannel_lease_break_channel *c =
    2114             :                 (struct test_multichannel_lease_break_channel *)private_data;
    2115          64 :         struct test_multichannel_lease_break_state *state = c->state;
    2116             : 
    2117          64 :         c->break_time = timeval_current();
    2118         128 :         c->full_duration = timeval_elapsed2(&state->open_req_time,
    2119          64 :                                             &c->break_time);
    2120         128 :         c->relative_duration = timeval_elapsed2(&state->last_break_time,
    2121          64 :                                                 &c->break_time);
    2122          64 :         state->last_break_time = c->break_time;
    2123          64 :         c->lb = *lb;
    2124          64 :         c->break_num = ++state->num_breaks;
    2125             : 
    2126          64 :         torture_comment(state->tctx, "Got LEASE break epoch[0x%x] %zu on %s after %f ( %f)\n",
    2127          64 :                         c->lb.new_epoch, c->break_num, c->name,
    2128             :                         c->relative_duration,
    2129             :                         c->full_duration);
    2130             : 
    2131          64 :         return torture_lease_handler(transport, lb, c->tree);
    2132             : }
    2133             : 
    2134           4 : static bool test_multichannel_lease_break_test4(struct torture_context *tctx,
    2135             :                                                 struct smb2_tree *tree1)
    2136             : {
    2137           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    2138           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    2139           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    2140           0 :         NTSTATUS status;
    2141           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2142           4 :         struct test_multichannel_lease_break_state state = {
    2143             :                 .tctx = tctx,
    2144             :         };
    2145           4 :         struct test_multichannel_lease_break_channel *open2_channel = NULL;
    2146           0 :         struct smb2_handle _h;
    2147           4 :         struct smb2_handle *h = NULL;
    2148           4 :         struct smb2_handle h_client1_file1 = {{0}};
    2149           4 :         struct smb2_handle h_client2_file1 = {{0}};
    2150           0 :         struct smb2_create io1;
    2151           0 :         struct smb2_create io2;
    2152           4 :         bool ret = true;
    2153           4 :         const char *fname1 = BASEDIR "\\lease_break_test4.dat";
    2154           4 :         struct smb2_tree *trees2[32] = { NULL, };
    2155           0 :         size_t i;
    2156           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    2157           0 :         struct smbcli_options transport2_options;
    2158           4 :         struct smb2_session *session1 = tree1->session;
    2159           4 :         uint16_t local_port = 0;
    2160           0 :         struct smb2_lease ls1;
    2161           0 :         struct smb2_lease ls2;
    2162           4 :         bool block_setup = false;
    2163           4 :         bool block_ok = false;
    2164           0 :         double open_duration;
    2165             : 
    2166           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    2167           0 :                 return true;
    2168             :         }
    2169             : 
    2170           4 :         torture_comment(tctx, "Lease break retry: Test4\n");
    2171             : 
    2172           4 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    2173           4 :         lease_break_info.lease_skip_ack = true;
    2174             : 
    2175           4 :         transport1->lease.handler = torture_lease_handler;
    2176           4 :         transport1->lease.private_data = tree1;
    2177           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    2178           4 :         local_port = torture_get_local_port_from_transport(transport1);
    2179           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    2180             : 
    2181           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    2182           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2183           4 :         smb2_util_close(tree1, _h);
    2184           4 :         smb2_util_unlink(tree1, fname1);
    2185           4 :         CHECK_VAL(lease_break_info.count, 0);
    2186             : 
    2187           4 :         smb2_lease_v2_create(&io2, &ls2, false, fname1,
    2188             :                              LEASE2F1, NULL,
    2189             :                              smb2_util_lease_state("RHW"),
    2190             :                              0x20);
    2191             : 
    2192           4 :         transport2_options = transport1->options;
    2193             : 
    2194           4 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
    2195             :                                                      &transport2_options,
    2196             :                                                      ARRAY_SIZE(trees2), trees2);
    2197           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
    2198             : 
    2199         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    2200         128 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2201         128 :                 struct smb2_transport *t = trees2[i]->session->transport;
    2202             : 
    2203         128 :                 c->state = &state;
    2204         128 :                 c->idx = i+1;
    2205         128 :                 c->tree = trees2[i];
    2206         128 :                 snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
    2207             : 
    2208         128 :                 t->lease.handler = test_multichannel_lease_break_handler;
    2209         128 :                 t->lease.private_data = c;
    2210             :         }
    2211             : 
    2212           4 :         open2_channel = &state.channels[0];
    2213             : 
    2214             :         /* 2a opens file1 */
    2215           4 :         torture_comment(tctx, "client2 opens fname1 via %s\n",
    2216           4 :                         open2_channel->name);
    2217           4 :         status = smb2_create(open2_channel->tree, mem_ctx, &io2);
    2218           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2219           4 :         h_client2_file1 = io2.out.file.handle;
    2220           4 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2221           4 :         CHECK_LEASE_V2(&io2, "RHW", true, LEASE2F1, 0, 0, 0x21);
    2222           2 :         CHECK_VAL(io2.out.durable_open_v2, false);
    2223           2 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
    2224           2 :         CHECK_VAL(io2.out.durable_open, false);
    2225           2 :         CHECK_VAL(lease_break_info.count, 0);
    2226             : 
    2227           2 :         block_setup = test_setup_blocked_transports(tctx);
    2228           2 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
    2229             : 
    2230          66 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    2231          64 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2232          64 :                 struct smb2_transport *t = c->tree->session->transport;
    2233             : 
    2234          64 :                 torture_comment(tctx, "Blocking %s\n", c->name);
    2235          64 :                 block_ok = _test_block_smb2_transport(tctx, t, c->name);
    2236          64 :                 torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
    2237          64 :                 c->blocked = true;
    2238             :         }
    2239             : 
    2240             :         /* 1 opens file2 */
    2241           2 :         torture_comment(tctx,
    2242             :                         "Client opens fname1 with session 1 with all %zu blocked\n",
    2243             :                         ARRAY_SIZE(trees2));
    2244           2 :         smb2_lease_v2_create(&io1, &ls1, false, fname1,
    2245             :                              LEASE1F1, NULL,
    2246             :                              smb2_util_lease_state("RHW"),
    2247             :                              0x10);
    2248           2 :         CHECK_VAL(lease_break_info.count, 0);
    2249           2 :         state.open_req_time = timeval_current();
    2250           2 :         state.last_break_time = state.open_req_time;
    2251           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    2252           2 :         state.open_rep_time = timeval_current();
    2253           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2254           2 :         h_client1_file1 = io1.out.file.handle;
    2255             : 
    2256           2 :         CHECK_VAL_GREATER_THAN(lease_break_info.count, 1);
    2257             : 
    2258           2 :         open_duration = timeval_elapsed2(&state.open_req_time,
    2259             :                                          &state.open_rep_time);
    2260           2 :         torture_comment(tctx, "open_duration: %f\n", open_duration);
    2261           2 :         if (lease_break_info.count < ARRAY_SIZE(state.channels)) {
    2262           2 :                 CHECK_VAL_GREATER_THAN(open_duration, 35);
    2263           2 :                 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          10 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    2269          10 :                 if (lease_break_info.count >= ARRAY_SIZE(state.channels)) {
    2270           2 :                         break;
    2271             :                 }
    2272           8 :                 torture_comment(tctx, "Received %d lease break(s) wait for more!!\n",
    2273             :                                 lease_break_info.count);
    2274           8 :                 torture_wait_for_lease_break(tctx);
    2275             :         }
    2276             : 
    2277           2 :         if (lease_break_info.count == 0) {
    2278           0 :                 torture_comment(tctx,
    2279             :                                 "Did not receive expected lease break!!\n");
    2280             :         } else {
    2281           2 :                 torture_comment(tctx, "Received %d lease break(s)!!\n",
    2282             :                                 lease_break_info.count);
    2283             :         }
    2284             : 
    2285           2 :         if (lease_break_info.count < ARRAY_SIZE(state.channels)) {
    2286           0 :                 CHECK_VAL_GREATER_THAN(lease_break_info.count, 3);
    2287             :         } else {
    2288           2 :                 CHECK_VAL(lease_break_info.count, ARRAY_SIZE(state.channels));
    2289             :         }
    2290             : 
    2291          66 :         for (i = 0; i < lease_break_info.count; i++) {
    2292          64 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2293             : 
    2294          64 :                 torture_comment(tctx, "Verify %s\n", c->name);
    2295          64 :                 torture_assert_int_equal(tctx, c->break_num, c->idx,
    2296             :                                          "Got lease break in wrong order");
    2297          64 :                 CHECK_LEASE_BREAK_V2(c->lb, LEASE2F1, "RWH", "RH",
    2298             :                                      SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED,
    2299             :                                      0x22);
    2300             :         }
    2301             : 
    2302           2 : done:
    2303         132 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    2304         128 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2305         128 :                 struct smb2_transport *t = NULL;
    2306             : 
    2307         128 :                 if (!c->blocked) {
    2308          64 :                         continue;
    2309             :                 }
    2310             : 
    2311          64 :                 t = c->tree->session->transport;
    2312             : 
    2313          64 :                 torture_comment(tctx, "Unblocking %s\n", c->name);
    2314          64 :                 _test_unblock_smb2_transport(tctx, t, c->name);
    2315          64 :                 c->blocked = false;
    2316             :         }
    2317           4 :         if (block_setup) {
    2318           2 :                 test_cleanup_blocked_transports(tctx);
    2319             :         }
    2320             : 
    2321           4 :         tree1->session = session1;
    2322             : 
    2323           4 :         smb2_util_close(tree1, h_client1_file1);
    2324           4 :         if (trees2[0] != NULL) {
    2325           4 :                 smb2_util_close(trees2[0], h_client2_file1);
    2326             :         }
    2327             : 
    2328           4 :         if (h != NULL) {
    2329           0 :                 smb2_util_close(tree1, *h);
    2330             :         }
    2331             : 
    2332           4 :         smb2_util_unlink(tree1, fname1);
    2333           4 :         smb2_deltree(tree1, BASEDIR);
    2334             : 
    2335         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    2336         128 :                 if (trees2[i] == NULL) {
    2337           0 :                         continue;
    2338             :                 }
    2339         128 :                 TALLOC_FREE(trees2[i]);
    2340             :         }
    2341           4 :         talloc_free(tree1);
    2342           4 :         talloc_free(mem_ctx);
    2343             : 
    2344           4 :         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         124 : static void test_multichannel_bug_15346_ndone(struct tevent_req *subreq)
    2375             : {
    2376           0 :         struct test_multichannel_bug_15346_conn *conn =
    2377             :                 (struct test_multichannel_bug_15346_conn *)
    2378         124 :                 tevent_req_callback_data_void(subreq);
    2379         124 :         struct test_multichannel_bug_15346_state *state = conn->state;
    2380         124 :         struct torture_context *tctx = state->tctx;
    2381           0 :         struct timeval current_time;
    2382           0 :         struct tm tm_buf;
    2383         124 :         struct tm *current_tm = NULL;
    2384           0 :         char time_str[sizeof "10000-01-01T00:00:00"];
    2385           0 :         size_t time_str_len;
    2386           0 :         NTSTATUS status;
    2387         124 :         bool ok = false;
    2388             : 
    2389         124 :         SMB_ASSERT(conn->nreq == subreq);
    2390         124 :         conn->nreq = NULL;
    2391             : 
    2392         124 :         status = smbXcli_negprot_recv(subreq, NULL, NULL);
    2393         124 :         TALLOC_FREE(subreq);
    2394         124 :         torture_assert_ntstatus_ok_goto(tctx, status, ok, asserted,
    2395             :                                         "smbXcli_negprot_recv failed");
    2396             : 
    2397         124 :         current_time = tevent_timeval_current();
    2398         124 :         current_tm = gmtime_r(&current_time.tv_sec, &tm_buf);
    2399         124 :         torture_assert_not_null_goto(tctx, current_tm, ok, asserted,
    2400             :                                      "gmtime_r failed");
    2401             : 
    2402         124 :         time_str_len = strftime(time_str, sizeof time_str, "%FT%T", current_tm);
    2403         124 :         torture_assert_size_not_equal_goto(tctx, time_str_len, 0, ok, asserted,
    2404             :                                            "strftime failed");
    2405             : 
    2406         124 :         torture_comment(tctx,
    2407             :                         "%s.%ldZ: conn[%zu]: negprot done\n",
    2408             :                         time_str,
    2409         124 :                         (long)current_time.tv_usec,
    2410             :                         conn->idx);
    2411             : 
    2412         248 :         conn->ereq = smb2cli_echo_send(conn->smbXcli,
    2413             :                                        tctx->ev,
    2414             :                                        conn->smbXcli,
    2415         124 :                                        state->num_conns * 2 * 1000);
    2416         124 :         torture_assert_goto(tctx, conn->ereq != NULL, ok, asserted,
    2417             :                             "smb2cli_echo_send");
    2418         124 :         tevent_req_set_callback(conn->ereq,
    2419             :                                 test_multichannel_bug_15346_edone,
    2420             :                                 conn);
    2421             : 
    2422         124 :         return;
    2423             : 
    2424           0 : asserted:
    2425           0 :         SMB_ASSERT(!ok);
    2426           0 :         state->asserted = true;
    2427           0 :         state->looping = false;
    2428           0 :         return;
    2429             : }
    2430             : 
    2431         124 : static void test_multichannel_bug_15346_edone(struct tevent_req *subreq)
    2432             : {
    2433           0 :         struct test_multichannel_bug_15346_conn *conn =
    2434             :                 (struct test_multichannel_bug_15346_conn *)
    2435         124 :                 tevent_req_callback_data_void(subreq);
    2436         124 :         struct test_multichannel_bug_15346_state *state = conn->state;
    2437         124 :         struct torture_context *tctx = state->tctx;
    2438           0 :         struct timeval current_time;
    2439           0 :         struct tm tm_buf;
    2440         124 :         struct tm *current_tm = NULL;
    2441           0 :         char time_str[sizeof "10000-01-01T00:00:00"];
    2442           0 :         size_t time_str_len;
    2443         124 :         const char *outcome = NULL;
    2444           0 :         NTSTATUS status;
    2445         124 :         bool ok = false;
    2446             : 
    2447         124 :         SMB_ASSERT(conn->ereq == subreq);
    2448         124 :         conn->ereq = NULL;
    2449             : 
    2450         124 :         current_time = tevent_timeval_current();
    2451         124 :         current_tm = gmtime_r(&current_time.tv_sec, &tm_buf);
    2452         124 :         torture_assert_not_null_goto(tctx, current_tm, ok, asserted,
    2453             :                                      "gmtime_r failed");
    2454             : 
    2455         124 :         time_str_len = strftime(time_str, sizeof time_str, "%FT%T", current_tm);
    2456         124 :         torture_assert_size_not_equal_goto(tctx, time_str_len, 0, ok, asserted,
    2457             :                                            "strftime failed");
    2458             : 
    2459         124 :         status = smb2cli_echo_recv(subreq);
    2460         124 :         TALLOC_FREE(subreq);
    2461         124 :         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
    2462           0 :                 outcome = "timed out";
    2463         124 :         } else if (!NT_STATUS_IS_OK(status)) {
    2464           0 :                 outcome = "failed";
    2465             :         } else {
    2466         124 :                 outcome = "done";
    2467             :         }
    2468         124 :         torture_comment(tctx,
    2469             :                         "%s.%ldZ: conn[%zu]: echo %s\n",
    2470             :                         time_str,
    2471         124 :                         (long)current_time.tv_usec,
    2472             :                         conn->idx,
    2473             :                         outcome);
    2474         124 :         torture_assert_ntstatus_ok_goto(tctx, status, ok, asserted,
    2475             :                                         "smb2cli_echo_recv failed");
    2476             : 
    2477         124 :         state->num_ready += 1;
    2478         124 :         if (state->num_ready < state->num_conns) {
    2479         120 :                 return;
    2480             :         }
    2481             : 
    2482           4 :         state->looping = false;
    2483           4 :         return;
    2484             : 
    2485           0 : asserted:
    2486           0 :         SMB_ASSERT(!ok);
    2487           0 :         state->asserted = true;
    2488           0 :         state->looping = false;
    2489           0 :         return;
    2490             : }
    2491             : 
    2492           4 : static bool test_multichannel_bug_15346(struct torture_context *tctx,
    2493             :                                         struct smb2_tree *tree1)
    2494             : {
    2495           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    2496           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    2497           4 :         struct resolve_context *resolve_ctx = lpcfg_resolve_context(tctx->lp_ctx);
    2498           4 :         const char *socket_options = lpcfg_socket_options(tctx->lp_ctx);
    2499           4 :         struct gensec_settings *gsettings = NULL;
    2500           4 :         bool ret = true;
    2501           0 :         NTSTATUS status;
    2502           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    2503           4 :         struct test_multichannel_bug_15346_state *state = NULL;
    2504           0 :         uint32_t server_capabilities;
    2505           4 :         struct smb2_handle root_handle = {{0}};
    2506           0 :         size_t i;
    2507             : 
    2508           4 :         if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
    2509           0 :                 torture_fail(tctx,
    2510             :                              "SMB 3.X Dialect family required for Multichannel"
    2511             :                              " tests\n");
    2512             :         }
    2513             : 
    2514           4 :         server_capabilities = smb2cli_conn_server_capabilities(
    2515           4 :                                         tree1->session->transport->conn);
    2516           4 :         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
    2517           0 :                 torture_fail(tctx,
    2518             :                              "Server does not support multichannel.");
    2519             :         }
    2520             : 
    2521           4 :         torture_comment(tctx, "Testing for BUG 15346\n");
    2522             : 
    2523           4 :         state = talloc_zero(tctx, struct test_multichannel_bug_15346_state);
    2524           4 :         torture_assert_goto(tctx, state != NULL, ret, done,
    2525             :                             "talloc_zero");
    2526           4 :         state->tctx = tctx;
    2527             : 
    2528           4 :         gsettings = lpcfg_gensec_settings(state, tctx->lp_ctx);
    2529           4 :         torture_assert_goto(tctx, gsettings != NULL, ret, done,
    2530             :                             "lpcfg_gensec_settings");
    2531             : 
    2532             :         /*
    2533             :          * 32 is the W2K12R2 and W2K16 limit
    2534             :          * add 31 additional connections
    2535             :          */
    2536           4 :         state->num_conns = 31;
    2537           4 :         state->conns = talloc_zero_array(state,
    2538             :                                   struct test_multichannel_bug_15346_conn,
    2539             :                                   state->num_conns);
    2540           4 :         torture_assert_goto(tctx, state->conns != NULL, ret, done,
    2541             :                             "talloc_zero_array");
    2542             : 
    2543             :         /*
    2544             :          * First we open the additional tcp connections
    2545             :          */
    2546             : 
    2547         128 :         for (i = 0; i < state->num_conns; i++) {
    2548         124 :                 struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
    2549         124 :                 struct socket_context *sock = NULL;
    2550         124 :                 uint16_t port = 445;
    2551         124 :                 struct smbcli_options options = transport1->options;
    2552             : 
    2553         124 :                 conn->state = state;
    2554         124 :                 conn->idx = i;
    2555             : 
    2556         124 :                 status = socket_connect_multi(state->conns,
    2557             :                                               host,
    2558             :                                               1, &port,
    2559             :                                               resolve_ctx,
    2560             :                                               tctx->ev,
    2561             :                                               &sock,
    2562             :                                               &port);
    2563         124 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2564             :                                                 "socket_connect_multi failed");
    2565             : 
    2566         248 :                 conn->smbXcli = smbXcli_conn_create(state->conns,
    2567         124 :                                         sock->fd,
    2568             :                                         host,
    2569             :                                         SMB_SIGNING_OFF,
    2570             :                                         0,
    2571             :                                         &options.client_guid,
    2572             :                                         options.smb2_capabilities,
    2573             :                                         &options.smb3_capabilities);
    2574         124 :                 torture_assert_goto(tctx, conn->smbXcli != NULL, ret, done,
    2575             :                                     "smbXcli_conn_create failed");
    2576         124 :                 sock->fd = -1;
    2577         124 :                 TALLOC_FREE(sock);
    2578             :         }
    2579             : 
    2580             :         /*
    2581             :          * Now prepare the async SMB2 Negotiate requests
    2582             :          */
    2583         128 :         for (i = 0; i < state->num_conns; i++) {
    2584         124 :                 struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
    2585             : 
    2586         124 :                 conn->nreq = smbXcli_negprot_send(conn->smbXcli,
    2587             :                                                   tctx->ev,
    2588             :                                                   conn->smbXcli,
    2589         124 :                                                   state->num_conns * 2 * 1000,
    2590             :                                                   smbXcli_conn_protocol(transport1->conn),
    2591             :                                                   smbXcli_conn_protocol(transport1->conn),
    2592             :                                                   33, /* max_credits */
    2593             :                                                   NULL);
    2594         124 :                 torture_assert_goto(tctx, conn->nreq != NULL, ret, done, "smbXcli_negprot_send");
    2595         124 :                 tevent_req_set_callback(conn->nreq,
    2596             :                                         test_multichannel_bug_15346_ndone,
    2597             :                                         conn);
    2598             :         }
    2599             : 
    2600             :         /*
    2601             :          * now we loop until all negprot and the first round
    2602             :          * of echos are done.
    2603             :          */
    2604           4 :         state->looping = true;
    2605         996 :         while (state->looping) {
    2606         992 :                 torture_assert_goto(tctx, tevent_loop_once(tctx->ev) == 0,
    2607             :                                     ret, done, "tevent_loop_once");
    2608             :         }
    2609             : 
    2610           4 :         if (state->asserted) {
    2611           0 :                 ret = false;
    2612           0 :                 goto done;
    2613             :         }
    2614             : 
    2615             :         /*
    2616             :          * Now we check that the connections are still usable
    2617             :          */
    2618         128 :         for (i = 0; i < state->num_conns; i++) {
    2619         124 :                 struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
    2620             : 
    2621         124 :                 torture_comment(tctx, "conn[%zu]: checking echo again1\n", conn->idx);
    2622             : 
    2623         124 :                 status = smb2cli_echo(conn->smbXcli, 1000);
    2624         124 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2625             :                                                 "smb2cli_echo failed");
    2626             :         }
    2627             : 
    2628           4 :         status = smb2_util_roothandle(tree1, &root_handle);
    2629           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2630             :                                         "smb2_util_roothandle failed");
    2631             : 
    2632             :         /*
    2633             :          * Now we check that the connections are still usable
    2634             :          */
    2635         128 :         for (i = 0; i < state->num_conns; i++) {
    2636         124 :                 struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
    2637         124 :                 struct smbcli_options options = transport1->options;
    2638         124 :                 struct smb2_session *session = NULL;
    2639         124 :                 struct smb2_tree *tree = NULL;
    2640           0 :                 union smb_fileinfo io;
    2641             : 
    2642         124 :                 torture_comment(tctx, "conn[%zu]: checking session bind\n", conn->idx);
    2643             : 
    2644             :                 /*
    2645             :                  * Prepare smb2_{tree,session,transport} structures
    2646             :                  * for the existing connection.
    2647             :                  */
    2648         124 :                 options.only_negprot = true;
    2649         124 :                 status = smb2_connect_ext(state->conns,
    2650             :                                           host,
    2651             :                                           NULL, /* ports */
    2652             :                                           share,
    2653             :                                           resolve_ctx,
    2654             :                                           samba_cmdline_get_creds(),
    2655             :                                           &conn->smbXcli,
    2656             :                                           0, /* previous_session_id */
    2657             :                                           &tree,
    2658             :                                           tctx->ev,
    2659             :                                           &options,
    2660             :                                           socket_options,
    2661             :                                           gsettings);
    2662         124 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2663             :                                                 "smb2_connect_ext failed");
    2664         124 :                 conn->smbXcli = tree->session->transport->conn;
    2665             : 
    2666         124 :                 session = smb2_session_channel(tree->session->transport,
    2667             :                                                lpcfg_gensec_settings(tree, tctx->lp_ctx),
    2668             :                                                tree,
    2669             :                                                tree1->session);
    2670         124 :                 torture_assert_goto(tctx, session != NULL, ret, done,
    2671             :                                     "smb2_session_channel failed");
    2672             : 
    2673         124 :                 status = smb2_session_setup_spnego(session,
    2674             :                                                    samba_cmdline_get_creds(),
    2675             :                                                    0 /* previous_session_id */);
    2676         124 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2677             :                                                 "smb2_session_setup_spnego failed");
    2678             : 
    2679             :                 /*
    2680             :                  * Fix up the bound smb2_tree
    2681             :                  */
    2682         124 :                 tree->session = session;
    2683         124 :                 tree->smbXcli = tree1->smbXcli;
    2684             : 
    2685         124 :                 ZERO_STRUCT(io);
    2686         124 :                 io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    2687         124 :                 io.generic.in.file.handle = root_handle;
    2688             : 
    2689         124 :                 status = smb2_getinfo_file(tree, tree, &io);
    2690         124 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2691             :                                                 "smb2_getinfo_file failed");
    2692             :         }
    2693             : 
    2694           4 :  done:
    2695           4 :         talloc_free(state);
    2696             : 
    2697           4 :         return ret;
    2698             : }
    2699             : 
    2700        2354 : struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
    2701             : {
    2702        2354 :         struct torture_suite *suite = torture_suite_create(ctx, "multichannel");
    2703        2354 :         struct torture_suite *suite_generic = torture_suite_create(ctx,
    2704             :                                                                    "generic");
    2705        2354 :         struct torture_suite *suite_oplocks = torture_suite_create(ctx,
    2706             :                                                                    "oplocks");
    2707        2354 :         struct torture_suite *suite_leases = torture_suite_create(ctx,
    2708             :                                                                   "leases");
    2709        2354 :         struct torture_suite *suite_bugs = torture_suite_create(ctx,
    2710             :                                                                 "bugs");
    2711             : 
    2712        2354 :         torture_suite_add_suite(suite, suite_generic);
    2713        2354 :         torture_suite_add_suite(suite, suite_oplocks);
    2714        2354 :         torture_suite_add_suite(suite, suite_leases);
    2715        2354 :         torture_suite_add_suite(suite, suite_bugs);
    2716             : 
    2717        2354 :         torture_suite_add_1smb2_test(suite_generic, "interface_info",
    2718             :                                      test_multichannel_interface_info);
    2719        2354 :         torture_suite_add_1smb2_test(suite_generic, "num_channels",
    2720             :                                      test_multichannel_num_channels);
    2721        2354 :         torture_suite_add_1smb2_test(suite_oplocks, "test1",
    2722             :                                      test_multichannel_oplock_break_test1);
    2723        2354 :         torture_suite_add_1smb2_test(suite_oplocks, "test2",
    2724             :                                      test_multichannel_oplock_break_test2);
    2725        2354 :         torture_suite_add_1smb2_test(suite_oplocks, "test3_windows",
    2726             :                                      test_multichannel_oplock_break_test3_windows);
    2727        2354 :         torture_suite_add_1smb2_test(suite_oplocks, "test3_specification",
    2728             :                                      test_multichannel_oplock_break_test3_specification);
    2729        2354 :         torture_suite_add_1smb2_test(suite_leases, "test1",
    2730             :                                      test_multichannel_lease_break_test1);
    2731        2354 :         torture_suite_add_1smb2_test(suite_leases, "test2",
    2732             :                                      test_multichannel_lease_break_test2);
    2733        2354 :         torture_suite_add_1smb2_test(suite_leases, "test3",
    2734             :                                      test_multichannel_lease_break_test3);
    2735        2354 :         torture_suite_add_1smb2_test(suite_leases, "test4",
    2736             :                                      test_multichannel_lease_break_test4);
    2737        2354 :         torture_suite_add_1smb2_test(suite_bugs, "bug_15346",
    2738             :                                      test_multichannel_bug_15346);
    2739             : 
    2740        2354 :         suite->description = talloc_strdup(suite, "SMB2 Multichannel tests");
    2741             : 
    2742        2354 :         return suite;
    2743             : }

Generated by: LCOV version 1.14