s4-torture: Add lease break retry tests - test2
[ambi/samba-autobuild/.git] / source4 / torture / smb2 / multichannel.c
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/popt_common.h"
32 #include "libcli/security/security.h"
33 #include "libcli/resolve/resolve.h"
34 #include "lib/param/param.h"
35 #include "lib/events/events.h"
36 #include "oplock_break_handler.h"
37 #include "lease_break_handler.h"
38 #include "torture/smb2/block.h"
39
40 #define BASEDIR "multichanneltestdir"
41
42 #define CHECK_STATUS(status, correct) \
43         torture_assert_ntstatus_equal_goto(tctx, status, correct,\
44                                            ret, done, "")
45
46 #define CHECK_VAL(v, correct) do { \
47         if ((v) != (correct)) { \
48                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s" \
49                                 " got 0x%x - should be 0x%x\n", \
50                                 __location__, #v, (int)v, (int)correct); \
51                 ret = false; \
52                 goto done; \
53         } } while (0)
54
55 #define CHECK_VAL_GREATER_THAN(v, gt_val) do { \
56         if ((v) <= (gt_val)) { \
57                 torture_result(tctx, TORTURE_FAIL, \
58                                 "(%s): wrong value for %s got 0x%x - " \
59                                 "should be greater than 0x%x\n", \
60                                 __location__, #v, (int)v, (int)gt_val); \
61                 ret = false; \
62                 goto done; \
63         } } while (0)
64
65 #define CHECK_CREATED(__io, __created, __attribute)                     \
66         do {                                                            \
67                 CHECK_VAL((__io)->out.create_action,                    \
68                                 NTCREATEX_ACTION_ ## __created);        \
69                 CHECK_VAL((__io)->out.alloc_size, 0);                   \
70                 CHECK_VAL((__io)->out.size, 0);                         \
71                 CHECK_VAL((__io)->out.file_attr, (__attribute));        \
72                 CHECK_VAL((__io)->out.reserved2, 0);                    \
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 static bool test_ioctl_network_interface_info(struct torture_context *tctx,
112                                               struct smb2_tree *tree,
113                                               struct fsctl_net_iface_info *info)
114 {
115         union smb_ioctl ioctl;
116         struct smb2_handle fh;
117         uint32_t caps;
118
119         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
120         if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
121                 torture_skip(tctx,
122                             "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
123         }
124
125         ZERO_STRUCT(ioctl);
126
127         ioctl.smb2.level = RAW_IOCTL_SMB2;
128
129         fh.data[0] = UINT64_MAX;
130         fh.data[1] = UINT64_MAX;
131
132         ioctl.smb2.in.file.handle = fh;
133         ioctl.smb2.in.function = FSCTL_QUERY_NETWORK_INTERFACE_INFO;
134         /* Windows client sets this to 64KiB */
135         ioctl.smb2.in.max_output_response = 0x10000;
136         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
137
138         torture_assert_ntstatus_ok(tctx,
139                 smb2_ioctl(tree, tctx, &ioctl.smb2),
140                 "FSCTL_QUERY_NETWORK_INTERFACE_INFO failed");
141
142         torture_assert(tctx,
143                 (ioctl.smb2.out.out.length != 0),
144                 "no interface info returned???");
145
146         torture_assert_ndr_success(tctx,
147                 ndr_pull_struct_blob(&ioctl.smb2.out.out, tctx, info,
148                         (ndr_pull_flags_fn_t)ndr_pull_fsctl_net_iface_info),
149                 "failed to ndr pull");
150
151         if (DEBUGLVL(1)) {
152                 NDR_PRINT_DEBUG(fsctl_net_iface_info, info);
153         }
154
155         return true;
156 }
157
158 static bool test_multichannel_interface_info(struct torture_context *tctx,
159                                              struct smb2_tree *tree)
160 {
161         struct fsctl_net_iface_info info;
162
163         return test_ioctl_network_interface_info(tctx, tree, &info);
164 }
165
166 static struct smb2_tree *test_multichannel_create_channel(
167                                 struct torture_context *tctx,
168                                 const char *host,
169                                 const char *share,
170                                 struct cli_credentials *credentials,
171                                 struct smbcli_options *transport_options,
172                                 struct smb2_tree *parent_tree
173                                 )
174 {
175         NTSTATUS status;
176         struct smb2_transport *transport;
177         struct smb2_session *session;
178         bool ret = true;
179         struct smb2_tree *tree;
180
181         status = smb2_connect(tctx,
182                         host,
183                         lpcfg_smb_ports(tctx->lp_ctx),
184                         share,
185                         lpcfg_resolve_context(tctx->lp_ctx),
186                         credentials,
187                         &tree,
188                         tctx->ev,
189                         transport_options,
190                         lpcfg_socket_options(tctx->lp_ctx),
191                         lpcfg_gensec_settings(tctx, tctx->lp_ctx)
192                         );
193         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
194                         "smb2_connect failed");
195         transport = tree->session->transport;
196         transport->oplock.handler = torture_oplock_ack_handler;
197         transport->oplock.private_data = tree;
198         transport->lease.handler = torture_lease_handler;
199         transport->lease.private_data = tree;
200         torture_comment(tctx, "established transport [%p]\n", transport);
201
202         /*
203          * If parent tree is set, bind the session to the parent transport
204          */
205         if (parent_tree) {
206                 session = smb2_session_channel(transport,
207                                 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
208                                 parent_tree, parent_tree->session);
209                 torture_assert_goto(tctx, session != NULL, ret, done,
210                                 "smb2_session_channel failed");
211
212                 tree->smbXcli = parent_tree->smbXcli;
213                 tree->session = session;
214                 status = smb2_session_setup_spnego(session,
215                                                 credentials,
216                                                 0 /* previous_session_id */);
217                 CHECK_STATUS(status, NT_STATUS_OK);
218                 torture_comment(tctx, "bound new session to parent\n");
219         }
220         /*
221          * We absolutely need to make sure to send something over this
222          * connection to register the oplock break handler with the smb client
223          * connection. If we do not send something (at least a keepalive), we
224          * will *NEVER* receive anything over this transport.
225          */
226         smb2_keepalive(transport);
227
228 done:
229         if (ret) {
230                 return tree;
231         } else {
232                 return NULL;
233         }
234 }
235
236 bool test_multichannel_create_channels(
237                                 struct torture_context *tctx,
238                                 const char *host,
239                                 const char *share,
240                                 struct cli_credentials *credentials,
241                                 struct smbcli_options *transport_options,
242                                 struct smb2_tree **tree2A,
243                                 struct smb2_tree **tree2B,
244                                 struct smb2_tree **tree2C
245                                 )
246 {
247         struct smb2_tree *tree;
248         struct smb2_transport *transport2A;
249         struct smb2_transport *transport2B;
250         struct smb2_transport *transport2C;
251         uint16_t local_port = 0;
252
253         transport_options->client_guid = GUID_random();
254
255         /* Session 2A */
256         torture_comment(tctx, "Setting up connection 2A\n");
257         tree = test_multichannel_create_channel(tctx, host, share,
258                                 credentials, transport_options, NULL);
259         if (!tree) {
260                 goto done;
261         }
262         *tree2A = tree;
263         transport2A = tree->session->transport;
264         local_port = torture_get_local_port_from_transport(transport2A);
265         torture_comment(tctx, "transport2A uses tcp port: %d\n", local_port);
266
267         /* Session 2B */
268         if (tree2B) {
269                 torture_comment(tctx, "Setting up connection 2B\n");
270                 tree = test_multichannel_create_channel(tctx, host, share,
271                                 credentials, transport_options, *tree2A);
272                 if (!tree) {
273                         goto done;
274                 }
275                 *tree2B = tree;
276                 transport2B = tree->session->transport;
277                 local_port = torture_get_local_port_from_transport(transport2B);
278                 torture_comment(tctx, "transport2B uses tcp port: %d\n",
279                                                                 local_port);
280         }
281
282         /* Session 2C */
283         if (tree2C) {
284                 torture_comment(tctx, "Setting up connection 2C\n");
285                 tree = test_multichannel_create_channel(tctx, host, share,
286                                 credentials, transport_options, *tree2A);
287                 if (!tree) {
288                         goto done;
289                 }
290                 *tree2C = tree;
291                 transport2C = tree->session->transport;
292                 local_port = torture_get_local_port_from_transport(transport2C);
293                 torture_comment(tctx, "transport2C uses tcp port: %d\n",
294                                                                 local_port);
295         }
296
297         return true;
298 done:
299         return false;
300 }
301
302 static void test_multichannel_free_channels(struct smb2_tree *tree2A,
303                                              struct smb2_tree *tree2B,
304                                              struct smb2_tree *tree2C)
305 {
306         TALLOC_FREE(tree2A);
307         TALLOC_FREE(tree2B);
308         TALLOC_FREE(tree2C);
309 }
310
311 static bool test_multichannel_initial_checks(struct torture_context *tctx,
312                                              struct smb2_tree *tree1)
313 {
314         struct smb2_transport *transport1 = tree1->session->transport;
315         uint32_t server_capabilities;
316         struct fsctl_net_iface_info info;
317
318         if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
319                 torture_skip_goto(tctx, fail,
320                                   "SMB 3.X Dialect family required for "
321                                   "Multichannel tests\n");
322         }
323
324         server_capabilities = smb2cli_conn_server_capabilities(
325                                         tree1->session->transport->conn);
326         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
327                 torture_skip_goto(tctx, fail,
328                              "Server does not support multichannel.");
329         }
330
331         torture_assert(tctx,
332                 test_ioctl_network_interface_info(tctx, tree1, &info),
333                 "failed to retrieve network interface info");
334
335         return true;
336 fail:
337         return false;
338 }
339
340 static void test_multichannel_init_smb_create(struct smb2_create *io)
341 {
342         io->in.durable_open = false;
343         io->in.durable_open_v2 = true;
344         io->in.persistent_open = false;
345         io->in.create_guid = GUID_random();
346         io->in.timeout = 0x493E0; /* 300000 */
347         /* windows 2016 returns 300000 0x493E0 */
348 }
349
350 /*
351  * We simulate blocking incoming oplock break requests by simply ignoring
352  * the incoming break requests.
353  */
354 static bool test_set_ignore_break_handler(struct torture_context *tctx,
355                                           struct smb2_transport *transport)
356 {
357         transport->oplock.handler = torture_oplock_ignore_handler;
358         transport->lease.handler = torture_lease_ignore_handler;
359
360         return true;
361 }
362
363 static bool test_reset_break_handler(struct torture_context *tctx,
364                                      struct smb2_transport *transport)
365 {
366         transport->oplock.handler = torture_oplock_ack_handler;
367         transport->lease.handler = torture_lease_handler;
368
369         return true;
370 }
371
372 /*
373  * Use iptables to block channels
374  */
375 static bool test_iptables_block_channel(struct torture_context *tctx,
376                                         struct smb2_transport *transport,
377                                         const char *name)
378 {
379         uint16_t local_port;
380         bool ret;
381
382         local_port = torture_get_local_port_from_transport(transport);
383         torture_comment(tctx, "transport uses tcp port: %d\n", local_port);
384         ret = torture_block_tcp_transport_name(tctx, transport, name);
385         torture_assert(tctx, ret, "we could not block tcp transport");
386
387         return ret;
388 }
389
390 static bool test_iptables_unblock_channel(struct torture_context *tctx,
391                                           struct smb2_transport *transport,
392                                           const char *name)
393 {
394         uint16_t local_port;
395         bool ret;
396
397         local_port = torture_get_local_port_from_transport(transport);
398         torture_comment(tctx, "transport uses tcp port: %d\n", local_port);
399         ret = torture_unblock_tcp_transport_name(tctx, transport, name);
400         torture_assert(tctx, ret, "we could not block tcp transport");
401
402         return ret;
403 }
404
405 #define test_block_channel(_tctx, _t) _test_block_channel(_tctx, _t, #_t)
406 static bool _test_block_channel(struct torture_context *tctx,
407                                           struct smb2_transport *transport,
408                                           const char *name)
409 {
410         bool use_iptables = torture_setting_bool(tctx,
411                                         "use_iptables", false);
412
413         if (use_iptables) {
414                 return test_iptables_block_channel(tctx, transport, name);
415         } else {
416                 return test_set_ignore_break_handler(tctx, transport);
417         }
418 }
419
420 #define test_unblock_channel(_tctx, _t) _test_unblock_channel(_tctx, _t, #_t)
421 static bool _test_unblock_channel(struct torture_context *tctx,
422                                           struct smb2_transport *transport,
423                                           const char *name)
424 {
425         bool use_iptables = torture_setting_bool(tctx,
426                                         "use_iptables", false);
427
428         if (use_iptables) {
429                 return test_iptables_unblock_channel(tctx, transport, name);
430         } else {
431                 return test_reset_break_handler(tctx, transport);
432         }
433 }
434
435 static void test_cleanup_blocked_channels(struct torture_context *tctx)
436 {
437         bool use_iptables = torture_setting_bool(tctx,
438                                         "use_iptables", false);
439
440         if (use_iptables) {
441                 torture_unblock_cleanup(tctx);
442         }
443 }
444
445 /*
446  * Oplock break - Test 1
447  * Test to confirm that server sends oplock breaks as expected.
448  * open file1 in session 2A
449  * open file2 in session 2B
450  * open file1 in session 1
451  *      oplock break received
452  * open file1 in session 1
453  *      oplock break received
454  * Cleanup
455  */
456 static bool test_multichannel_oplock_break_test1(struct torture_context *tctx,
457                                            struct smb2_tree *tree1)
458 {
459         const char *host = torture_setting_string(tctx, "host", NULL);
460         const char *share = torture_setting_string(tctx, "share", NULL);
461         struct cli_credentials *credentials = popt_get_cmdline_credentials();
462         NTSTATUS status;
463         TALLOC_CTX *mem_ctx = talloc_new(tctx);
464         struct smb2_handle _h;
465         struct smb2_handle h_client1_file1 = {{0}};
466         struct smb2_handle h_client1_file2 = {{0}};
467         struct smb2_handle h_client1_file3 = {{0}};
468         struct smb2_handle h_client2_file1 = {{0}};
469         struct smb2_handle h_client2_file2 = {{0}};
470         struct smb2_handle h_client2_file3 = {{0}};
471         struct smb2_create io1, io2, io3;
472         bool ret = true;
473         const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
474         const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
475         const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
476         struct smb2_tree *tree2A = NULL;
477         struct smb2_tree *tree2B = NULL;
478         struct smb2_tree *tree2C = NULL;
479         struct smb2_transport *transport1 = tree1->session->transport;
480         struct smbcli_options transport2_options;
481         struct smb2_session *session1 = tree1->session;
482         uint16_t local_port = 0;
483
484         if (!test_multichannel_initial_checks(tctx, tree1)) {
485                 return true;
486         }
487
488         torture_comment(tctx, "Oplock break retry: Test1\n");
489
490         torture_reset_break_info(tctx, &break_info);
491
492         transport1->oplock.handler = torture_oplock_ack_handler;
493         transport1->oplock.private_data = tree1;
494         torture_comment(tctx, "transport1  [%p]\n", transport1);
495         local_port = torture_get_local_port_from_transport(transport1);
496         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
497
498         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
499         CHECK_STATUS(status, NT_STATUS_OK);
500         smb2_util_close(tree1, _h);
501         smb2_util_unlink(tree1, fname1);
502         smb2_util_unlink(tree1, fname2);
503         smb2_util_unlink(tree1, fname3);
504         CHECK_VAL(break_info.count, 0);
505
506         smb2_oplock_create_share(&io1, fname1,
507                         smb2_util_share_access("RWD"),
508                         smb2_util_oplock_level("b"));
509         test_multichannel_init_smb_create(&io1);
510
511         smb2_oplock_create_share(&io2, fname2,
512                         smb2_util_share_access("RWD"),
513                         smb2_util_oplock_level("b"));
514         test_multichannel_init_smb_create(&io2);
515
516         smb2_oplock_create_share(&io3, fname3,
517                         smb2_util_share_access("RWD"),
518                         smb2_util_oplock_level("b"));
519         test_multichannel_init_smb_create(&io3);
520
521         transport2_options = transport1->options;
522
523         ret = test_multichannel_create_channels(tctx, host, share,
524                                                   credentials,
525                                                   &transport2_options,
526                                                   &tree2A, &tree2B, NULL);
527         torture_assert(tctx, ret, "Could not create channels.\n");
528
529         /* 2a opens file1 */
530         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
531         status = smb2_create(tree2A, mem_ctx, &io1);
532         CHECK_STATUS(status, NT_STATUS_OK);
533         h_client2_file1 = io1.out.file.handle;
534         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
535         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
536         torture_wait_for_oplock_break(tctx);
537         CHECK_VAL(break_info.count, 0);
538
539         /* 2b opens file2 */
540         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
541         status = smb2_create(tree2B, mem_ctx, &io2);
542         CHECK_STATUS(status, NT_STATUS_OK);
543         h_client2_file2 = io2.out.file.handle;
544         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
545         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
546         torture_wait_for_oplock_break(tctx);
547         CHECK_VAL(break_info.count, 0);
548
549
550         /* 1 opens file1 - batchoplock break? */
551         torture_comment(tctx, "client1 opens fname1 via session 1\n");
552         io1.in.oplock_level = smb2_util_oplock_level("b");
553         status = smb2_create(tree1, mem_ctx, &io1);
554         CHECK_STATUS(status, NT_STATUS_OK);
555         h_client1_file1 = io1.out.file.handle;
556         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
557         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
558         torture_wait_for_oplock_break(tctx);
559         CHECK_VAL(break_info.count, 1);
560
561         torture_reset_break_info(tctx, &break_info);
562
563         /* 1 opens file2 - batchoplock break? */
564         torture_comment(tctx, "client1 opens fname2 via session 1\n");
565         io2.in.oplock_level = smb2_util_oplock_level("b");
566         status = smb2_create(tree1, mem_ctx, &io2);
567         CHECK_STATUS(status, NT_STATUS_OK);
568         h_client1_file2 = io2.out.file.handle;
569         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
570         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
571         torture_wait_for_oplock_break(tctx);
572         CHECK_VAL(break_info.count, 1);
573
574         /* cleanup everything */
575         torture_reset_break_info(tctx, &break_info);
576
577         smb2_util_close(tree1, h_client1_file1);
578         smb2_util_close(tree1, h_client1_file2);
579         smb2_util_close(tree1, h_client1_file3);
580         smb2_util_close(tree2A, h_client2_file1);
581         smb2_util_close(tree2A, h_client2_file2);
582         smb2_util_close(tree2A, h_client2_file3);
583
584         smb2_util_unlink(tree1, fname1);
585         smb2_util_unlink(tree1, fname2);
586         smb2_util_unlink(tree1, fname3);
587         CHECK_VAL(break_info.count, 0);
588         test_multichannel_free_channels(tree2A, tree2B, tree2C);
589         tree2A = tree2B = tree2C = NULL;
590 done:
591         tree1->session = session1;
592
593         smb2_util_close(tree1, h_client1_file1);
594         smb2_util_close(tree1, h_client1_file2);
595         smb2_util_close(tree1, h_client1_file3);
596         if (tree2A != NULL) {
597                 smb2_util_close(tree2A, h_client2_file1);
598                 smb2_util_close(tree2A, h_client2_file2);
599                 smb2_util_close(tree2A, h_client2_file3);
600         }
601
602         smb2_util_unlink(tree1, fname1);
603         smb2_util_unlink(tree1, fname2);
604         smb2_util_unlink(tree1, fname3);
605         smb2_deltree(tree1, BASEDIR);
606
607         test_multichannel_free_channels(tree2A, tree2B, tree2C);
608         talloc_free(tree1);
609         talloc_free(mem_ctx);
610
611         return ret;
612 }
613
614 /*
615  * Oplock Break Test 2
616  * Test to see if oplock break retries are sent by the server.
617  * Also checks to see if new channels can be created and used
618  * after an oplock break retry.
619  * open file1 in 2A
620  * open file2 in 2B
621  * open file1 in session 1
622  *      oplock break received
623  * block channel on which oplock break received
624  * open file2 in session 1
625  *      oplock break not received. Retry received.
626  *      file opened
627  * write to file2 on 2B
628  *      Break sent to session 1(which has file2 open)
629  *      Break sent to session 2A(which has read oplock)
630  * close file1 in session 1
631  * open file1 with session 1
632  * unblock blocked channel
633  * disconnect blocked channel
634  * connect channel 2D
635  * open file3 in 2D
636  * open file3 in session 1
637  *      receive break
638  */
639 static bool test_multichannel_oplock_break_test2(struct torture_context *tctx,
640                                            struct smb2_tree *tree1)
641 {
642         const char *host = torture_setting_string(tctx, "host", NULL);
643         const char *share = torture_setting_string(tctx, "share", NULL);
644         struct cli_credentials *credentials = popt_get_cmdline_credentials();
645         NTSTATUS status;
646         TALLOC_CTX *mem_ctx = talloc_new(tctx);
647         struct smb2_handle _h;
648         struct smb2_handle h_client1_file1 = {{0}};
649         struct smb2_handle h_client1_file2 = {{0}};
650         struct smb2_handle h_client1_file3 = {{0}};
651         struct smb2_handle h_client2_file1 = {{0}};
652         struct smb2_handle h_client2_file2 = {{0}};
653         struct smb2_handle h_client2_file3 = {{0}};
654         struct smb2_create io1, io2, io3;
655         bool ret = true;
656         const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
657         const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
658         const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
659         struct smb2_tree *tree2A = NULL;
660         struct smb2_tree *tree2B = NULL;
661         struct smb2_tree *tree2C = NULL;
662         struct smb2_tree *tree2D = NULL;
663         struct smb2_transport *transport1 = tree1->session->transport;
664         struct smb2_transport *transport2 = NULL;
665         struct smbcli_options transport2_options;
666         struct smb2_session *session1 = tree1->session;
667         uint16_t local_port = 0;
668         DATA_BLOB blob;
669         bool block_ok = false;
670         bool unblock_ok = false;
671
672         if (!test_multichannel_initial_checks(tctx, tree1)) {
673                 return true;
674         }
675
676         torture_comment(tctx, "Oplock break retry: Test2\n");
677
678         torture_reset_break_info(tctx, &break_info);
679
680         transport1->oplock.handler = torture_oplock_ack_handler;
681         transport1->oplock.private_data = tree1;
682         torture_comment(tctx, "transport1  [%p]\n", transport1);
683         local_port = torture_get_local_port_from_transport(transport1);
684         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
685
686         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
687         CHECK_STATUS(status, NT_STATUS_OK);
688         smb2_util_close(tree1, _h);
689         smb2_util_unlink(tree1, fname1);
690         smb2_util_unlink(tree1, fname2);
691         smb2_util_unlink(tree1, fname3);
692         CHECK_VAL(break_info.count, 0);
693
694         smb2_oplock_create_share(&io1, fname1,
695                         smb2_util_share_access("RWD"),
696                         smb2_util_oplock_level("b"));
697         test_multichannel_init_smb_create(&io1);
698
699         smb2_oplock_create_share(&io2, fname2,
700                         smb2_util_share_access("RWD"),
701                         smb2_util_oplock_level("b"));
702         test_multichannel_init_smb_create(&io2);
703
704         smb2_oplock_create_share(&io3, fname3,
705                         smb2_util_share_access("RWD"),
706                         smb2_util_oplock_level("b"));
707         test_multichannel_init_smb_create(&io3);
708
709         transport2_options = transport1->options;
710
711         ret = test_multichannel_create_channels(tctx, host, share,
712                                                   credentials,
713                                                   &transport2_options,
714                                                   &tree2A, &tree2B, &tree2C);
715         torture_assert(tctx, ret, "Could not create channels.\n")
716
717         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
718         io1.in.oplock_level = smb2_util_oplock_level("b");
719         status = smb2_create(tree2A, mem_ctx, &io1);
720         CHECK_STATUS(status, NT_STATUS_OK);
721         h_client2_file1 = io1.out.file.handle;
722         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
723         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
724         torture_wait_for_oplock_break(tctx);
725         CHECK_VAL(break_info.count, 0);
726
727
728         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
729         io2.in.oplock_level = smb2_util_oplock_level("b");
730         status = smb2_create(tree2B, mem_ctx, &io2);
731         CHECK_STATUS(status, NT_STATUS_OK);
732         h_client2_file2 = io2.out.file.handle;
733         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
734         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
735         torture_wait_for_oplock_break(tctx);
736         CHECK_VAL(break_info.count, 0);
737
738
739         torture_comment(tctx, "client1 opens fname1 via session 1\n");
740         io1.in.oplock_level = smb2_util_oplock_level("b");
741         status = smb2_create(tree1, mem_ctx, &io1);
742         CHECK_STATUS(status, NT_STATUS_OK);
743         h_client1_file1 = io1.out.file.handle;
744         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
745         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
746         torture_wait_for_oplock_break(tctx);
747         CHECK_VAL(break_info.count, 1);
748
749         /* We use the transport over which this oplock break was received */
750         transport2 = break_info.received_transport;
751         torture_reset_break_info(tctx, &break_info);
752
753         /* block channel */
754         block_ok = test_block_channel(tctx, transport2);
755
756         torture_comment(tctx, "client1 opens fname2 via session 1\n");
757         io2.in.oplock_level = smb2_util_oplock_level("b");
758         status = smb2_create(tree1, mem_ctx, &io2);
759         CHECK_STATUS(status, NT_STATUS_OK);
760         h_client1_file2 = io2.out.file.handle;
761         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
762         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
763
764         /*
765          * Samba downgrades oplock to a level 2 oplock.
766          * Windows 2016 revokes oplock
767          */
768         torture_wait_for_oplock_break(tctx);
769         CHECK_VAL(break_info.count, 1);
770         torture_reset_break_info(tctx, &break_info);
771
772         torture_comment(tctx, "Trying write to file2 on tree2B\n");
773
774         blob = data_blob_string_const("Here I am");
775         status = smb2_util_write(tree2B,
776                                  h_client2_file2,
777                                  blob.data,
778                                  0,
779                                  blob.length);
780         torture_assert_ntstatus_ok(tctx, status,
781                 "failed to write file2 via channel 2B");
782
783         /*
784          * Samba: Write triggers 2 oplock breaks
785          *  for session 1 which has file2 open
786          *  for session 2 which has type 2 oplock
787          * Windows 2016: Only one oplock break for session 1
788          */
789         torture_wait_for_oplock_break(tctx);
790         CHECK_VAL_GREATER_THAN(break_info.count, 0);
791         torture_reset_break_info(tctx, &break_info);
792
793         torture_comment(tctx, "client1 closes fname2 via session 1\n");
794         smb2_util_close(tree1, h_client1_file2);
795
796         torture_comment(tctx, "client1 opens fname2 via session 1 again\n");
797         io2.in.oplock_level = smb2_util_oplock_level("b");
798         status = smb2_create(tree1, mem_ctx, &io2);
799         CHECK_STATUS(status, NT_STATUS_OK);
800         h_client1_file2 = io2.out.file.handle;
801         io2.out.alloc_size = 0;
802         io2.out.size = 0;
803         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
804         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
805
806         /*
807          * now add a fourth channel and repeat the test, we need to reestablish
808          * transport2 because the remote end has invalidated our connection
809          */
810         torture_comment(tctx, "Connecting session 2D\n");
811         tree2D = test_multichannel_create_channel(tctx, host, share,
812                                      credentials, &transport2_options, tree2B);
813         if (!tree2D) {
814                 goto done;
815         }
816
817         torture_reset_break_info(tctx, &break_info);
818         torture_comment(tctx, "client 2 opening fname3 over transport2D\n");
819         status = smb2_create(tree2D, mem_ctx, &io3);
820         CHECK_STATUS(status, NT_STATUS_OK);
821         h_client2_file3 = io3.out.file.handle;
822         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
823         CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("b"));
824         torture_wait_for_oplock_break(tctx);
825         CHECK_VAL(break_info.count, 0);
826
827         torture_comment(tctx, "client1 opens fname3 via session 1\n");
828         status = smb2_create(tree1, mem_ctx, &io3);
829         CHECK_STATUS(status, NT_STATUS_OK);
830         h_client1_file3 = io3.out.file.handle;
831         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
832         CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
833         torture_wait_for_oplock_break(tctx);
834         CHECK_VAL(break_info.count, 1);
835
836 done:
837         if (block_ok && !unblock_ok) {
838                 test_unblock_channel(tctx, transport2);
839         }
840         test_cleanup_blocked_channels(tctx);
841
842         tree1->session = session1;
843
844         smb2_util_close(tree1, h_client1_file1);
845         smb2_util_close(tree1, h_client1_file2);
846         smb2_util_close(tree1, h_client1_file3);
847         if (tree2B != NULL) {
848                 smb2_util_close(tree2B, h_client2_file1);
849                 smb2_util_close(tree2B, h_client2_file2);
850                 smb2_util_close(tree2B, h_client2_file3);
851         }
852
853         smb2_util_unlink(tree1, fname1);
854         smb2_util_unlink(tree1, fname2);
855         smb2_util_unlink(tree1, fname3);
856         smb2_deltree(tree1, BASEDIR);
857
858         test_multichannel_free_channels(tree2A, tree2B, tree2C);
859         if (tree2D != NULL) {
860                 TALLOC_FREE(tree2D);
861         }
862         talloc_free(tree1);
863         talloc_free(mem_ctx);
864
865         return ret;
866 }
867
868 static const uint64_t LEASE1F1 = 0xBADC0FFEE0DDF00Dull;
869 static const uint64_t LEASE1F2 = 0xBADC0FFEE0DDD00Dull;
870 static const uint64_t LEASE1F3 = 0xDADC0FFEE0DDD00Dull;
871 static const uint64_t LEASE2F1 = 0xDEADBEEFFEEDBEADull;
872 static const uint64_t LEASE2F2 = 0xDAD0FFEDD00DF00Dull;
873 static const uint64_t LEASE2F3 = 0xBAD0FFEDD00DF00Dull;
874
875 /*
876  * Lease Break Test 1:
877  * Test to check if lease breaks are sent by the server as expected.
878  *      open file1 in session 2A
879  *      open file2 in session 2B
880  *      open file3 in session 2C
881  *      open file1 in session 1
882  *           lease break sent
883  *      open file2 in session 1
884  *           lease break sent
885  *      open file3 in session 1
886  *           lease break sent
887  */
888 static bool test_multichannel_lease_break_test1(struct torture_context *tctx,
889                                                 struct smb2_tree *tree1)
890 {
891         const char *host = torture_setting_string(tctx, "host", NULL);
892         const char *share = torture_setting_string(tctx, "share", NULL);
893         struct cli_credentials *credentials = popt_get_cmdline_credentials();
894         NTSTATUS status;
895         TALLOC_CTX *mem_ctx = talloc_new(tctx);
896         struct smb2_handle _h;
897         struct smb2_handle *h = NULL;
898         struct smb2_handle h_client1_file1 = {{0}};
899         struct smb2_handle h_client1_file2 = {{0}};
900         struct smb2_handle h_client1_file3 = {{0}};
901         struct smb2_handle h_client2_file1 = {{0}};
902         struct smb2_handle h_client2_file2 = {{0}};
903         struct smb2_handle h_client2_file3 = {{0}};
904         struct smb2_create io1, io2, io3;
905         bool ret = true;
906         const char *fname1 = BASEDIR "\\lease_break_test1.dat";
907         const char *fname2 = BASEDIR "\\lease_break_test2.dat";
908         const char *fname3 = BASEDIR "\\lease_break_test3.dat";
909         struct smb2_tree *tree2A = NULL;
910         struct smb2_tree *tree2B = NULL;
911         struct smb2_tree *tree2C = NULL;
912         struct smb2_transport *transport1 = tree1->session->transport;
913         struct smbcli_options transport2_options;
914         struct smb2_session *session1 = tree1->session;
915         uint16_t local_port = 0;
916         struct smb2_lease ls1;
917         struct smb2_lease ls2;
918         struct smb2_lease ls3;
919
920         if (!test_multichannel_initial_checks(tctx, tree1)) {
921                 return true;
922         }
923
924         torture_comment(tctx, "Lease break retry: Test1\n");
925
926         torture_reset_lease_break_info(tctx, &lease_break_info);
927
928         transport1->lease.handler = torture_lease_handler;
929         transport1->lease.private_data = tree1;
930         torture_comment(tctx, "transport1  [%p]\n", transport1);
931         local_port = torture_get_local_port_from_transport(transport1);
932         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
933
934         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
935         CHECK_STATUS(status, NT_STATUS_OK);
936         smb2_util_close(tree1, _h);
937         smb2_util_unlink(tree1, fname1);
938         smb2_util_unlink(tree1, fname2);
939         smb2_util_unlink(tree1, fname3);
940         CHECK_VAL(lease_break_info.count, 0);
941
942         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
943                           smb2_util_lease_state("RHW"));
944         test_multichannel_init_smb_create(&io1);
945
946         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
947                           smb2_util_lease_state("RHW"));
948         test_multichannel_init_smb_create(&io2);
949
950         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
951                           smb2_util_lease_state("RHW"));
952         test_multichannel_init_smb_create(&io3);
953
954         transport2_options = transport1->options;
955
956         ret = test_multichannel_create_channels(tctx, host, share,
957                                                   credentials,
958                                                   &transport2_options,
959                                                   &tree2A, &tree2B, &tree2C);
960         torture_assert(tctx, ret, "Could not create channels.\n");
961
962         /* 2a opens file1 */
963         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
964         status = smb2_create(tree2A, mem_ctx, &io1);
965         CHECK_STATUS(status, NT_STATUS_OK);
966         h_client2_file1 = io1.out.file.handle;
967         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
968         CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
969         CHECK_VAL(lease_break_info.count, 0);
970
971         /* 2b opens file2 */
972         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
973         status = smb2_create(tree2B, mem_ctx, &io2);
974         CHECK_STATUS(status, NT_STATUS_OK);
975         h_client2_file2 = io2.out.file.handle;
976         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
977         CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
978         CHECK_VAL(lease_break_info.count, 0);
979
980         /* 2c opens file3 */
981         torture_comment(tctx, "client2 opens fname3 via session 2C\n");
982         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
983                           smb2_util_lease_state("RHW"));
984         status = smb2_create(tree2C, mem_ctx, &io3);
985         CHECK_STATUS(status, NT_STATUS_OK);
986         h_client2_file3 = io3.out.file.handle;
987         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
988         CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
989         CHECK_VAL(lease_break_info.count, 0);
990
991         /* 1 opens file1 - lease break? */
992         torture_comment(tctx, "client1 opens fname1 via session 1\n");
993         smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
994                           smb2_util_lease_state("RHW"));
995         status = smb2_create(tree1, mem_ctx, &io1);
996         CHECK_STATUS(status, NT_STATUS_OK);
997         h_client1_file1 = io1.out.file.handle;
998         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
999         CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
1000         CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
1001         CHECK_VAL(lease_break_info.count, 1);
1002
1003         torture_reset_lease_break_info(tctx, &lease_break_info);
1004
1005         /* 1 opens file2 - lease break? */
1006         torture_comment(tctx, "client1 opens fname2 via session 1\n");
1007         smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
1008                           smb2_util_lease_state("RHW"));
1009         status = smb2_create(tree1, mem_ctx, &io2);
1010         CHECK_STATUS(status, NT_STATUS_OK);
1011         h_client1_file2 = io2.out.file.handle;
1012         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1013         CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
1014         CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
1015         CHECK_VAL(lease_break_info.count, 1);
1016
1017         torture_reset_lease_break_info(tctx, &lease_break_info);
1018
1019         /* 1 opens file3 - lease break? */
1020         torture_comment(tctx, "client1 opens fname3 via session 1\n");
1021         smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
1022                           smb2_util_lease_state("RHW"));
1023         status = smb2_create(tree1, mem_ctx, &io3);
1024         CHECK_STATUS(status, NT_STATUS_OK);
1025         h_client1_file3 = io3.out.file.handle;
1026         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1027         CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
1028         CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
1029         CHECK_VAL(lease_break_info.count, 1);
1030
1031         /* cleanup everything */
1032         torture_reset_lease_break_info(tctx, &lease_break_info);
1033
1034         smb2_util_close(tree1, h_client1_file1);
1035         smb2_util_close(tree1, h_client1_file2);
1036         smb2_util_close(tree1, h_client1_file3);
1037         smb2_util_close(tree2A, h_client2_file1);
1038         smb2_util_close(tree2A, h_client2_file2);
1039         smb2_util_close(tree2A, h_client2_file3);
1040
1041         smb2_util_unlink(tree1, fname1);
1042         smb2_util_unlink(tree1, fname2);
1043         smb2_util_unlink(tree1, fname3);
1044         CHECK_VAL(lease_break_info.count, 0);
1045         test_multichannel_free_channels(tree2A, tree2B, tree2C);
1046         tree2A = tree2B = tree2C = NULL;
1047 done:
1048         tree1->session = session1;
1049
1050         smb2_util_close(tree1, h_client1_file1);
1051         smb2_util_close(tree1, h_client1_file2);
1052         smb2_util_close(tree1, h_client1_file3);
1053         if (tree2A != NULL) {
1054                 smb2_util_close(tree2A, h_client2_file1);
1055                 smb2_util_close(tree2A, h_client2_file2);
1056                 smb2_util_close(tree2A, h_client2_file3);
1057         }
1058
1059         if (h != NULL) {
1060                 smb2_util_close(tree1, *h);
1061         }
1062
1063         smb2_util_unlink(tree1, fname1);
1064         smb2_util_unlink(tree1, fname2);
1065         smb2_util_unlink(tree1, fname3);
1066         smb2_deltree(tree1, BASEDIR);
1067
1068         test_multichannel_free_channels(tree2A, tree2B, tree2C);
1069         talloc_free(tree1);
1070         talloc_free(mem_ctx);
1071
1072         return ret;
1073 }
1074
1075 /*
1076  * Lease Break Test 2:
1077  * Test for lease break retries being sent by the server.
1078  *      Connect 2A, 2B
1079  *      open file1 in session 2A
1080  *      open file2 in session 2B
1081  *      block 2A
1082  *      open file2 in session 1
1083  *           lease break retry reaches the client?
1084  *      Connect 2C
1085  *      open file3 in session 2C
1086  *      unblock 2A
1087  *      open file1 in session 1
1088  *           lease break reaches the client?
1089  *      open file3 in session 1
1090  *           lease break reached the client?
1091  *      Cleanup
1092  *           On deletion by 1, lease breaks sent for file1, file2 and file3
1093  *           on 2B
1094  *           This changes RH lease to R for Session 2.
1095  *           (This has been disabled while we add support for sending lease
1096  *            break for handle leases.)
1097  */
1098 static bool test_multichannel_lease_break_test2(struct torture_context *tctx,
1099                                                 struct smb2_tree *tree1)
1100 {
1101         const char *host = torture_setting_string(tctx, "host", NULL);
1102         const char *share = torture_setting_string(tctx, "share", NULL);
1103         struct cli_credentials *credentials = popt_get_cmdline_credentials();
1104         NTSTATUS status;
1105         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1106         struct smb2_handle _h;
1107         struct smb2_handle *h = NULL;
1108         struct smb2_handle h_client1_file1 = {{0}};
1109         struct smb2_handle h_client1_file2 = {{0}};
1110         struct smb2_handle h_client1_file3 = {{0}};
1111         struct smb2_handle h_client2_file1 = {{0}};
1112         struct smb2_handle h_client2_file2 = {{0}};
1113         struct smb2_handle h_client2_file3 = {{0}};
1114         struct smb2_create io1, io2, io3;
1115         bool ret = true;
1116         const char *fname1 = BASEDIR "\\lease_break_test1.dat";
1117         const char *fname2 = BASEDIR "\\lease_break_test2.dat";
1118         const char *fname3 = BASEDIR "\\lease_break_test3.dat";
1119         struct smb2_tree *tree2A = NULL;
1120         struct smb2_tree *tree2B = NULL;
1121         struct smb2_tree *tree2C = NULL;
1122         struct smb2_transport *transport1 = tree1->session->transport;
1123         struct smb2_transport *transport2A = NULL;
1124         struct smbcli_options transport2_options;
1125         struct smb2_session *session1 = tree1->session;
1126         uint16_t local_port = 0;
1127         struct smb2_lease ls1;
1128         struct smb2_lease ls2;
1129         struct smb2_lease ls3;
1130         bool block_ok = false;
1131         bool unblock_ok = false;
1132
1133
1134         if (!test_multichannel_initial_checks(tctx, tree1)) {
1135                 return true;
1136         }
1137
1138         torture_comment(tctx, "Lease break retry: Test2\n");
1139
1140         torture_reset_lease_break_info(tctx, &lease_break_info);
1141
1142         transport1->lease.handler = torture_lease_handler;
1143         transport1->lease.private_data = tree1;
1144         torture_comment(tctx, "transport1  [%p]\n", transport1);
1145         local_port = torture_get_local_port_from_transport(transport1);
1146         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
1147
1148         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
1149         CHECK_STATUS(status, NT_STATUS_OK);
1150         smb2_util_close(tree1, _h);
1151         smb2_util_unlink(tree1, fname1);
1152         smb2_util_unlink(tree1, fname2);
1153         smb2_util_unlink(tree1, fname3);
1154         CHECK_VAL(lease_break_info.count, 0);
1155
1156         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1157                           smb2_util_lease_state("RHW"));
1158         test_multichannel_init_smb_create(&io1);
1159
1160         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
1161                           smb2_util_lease_state("RHW"));
1162         test_multichannel_init_smb_create(&io2);
1163
1164         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
1165                           smb2_util_lease_state("RHW"));
1166         test_multichannel_init_smb_create(&io3);
1167
1168         transport2_options = transport1->options;
1169
1170         ret = test_multichannel_create_channels(tctx, host, share,
1171                                                   credentials,
1172                                                   &transport2_options,
1173                                                   &tree2A, &tree2B, NULL);
1174         torture_assert(tctx, ret, "Could not create channels.\n");
1175         transport2A = tree2A->session->transport;
1176
1177         /* 2a opens file1 */
1178         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
1179         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
1180                           smb2_util_lease_state("RHW"));
1181         status = smb2_create(tree2A, mem_ctx, &io1);
1182         CHECK_STATUS(status, NT_STATUS_OK);
1183         h_client2_file1 = io1.out.file.handle;
1184         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1185         CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
1186         CHECK_VAL(io1.out.durable_open_v2, false); //true);
1187         CHECK_VAL(io1.out.timeout, io1.in.timeout);
1188         CHECK_VAL(io1.out.durable_open, false);
1189         CHECK_VAL(lease_break_info.count, 0);
1190
1191         /* 2b opens file2 */
1192         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
1193         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
1194                           smb2_util_lease_state("RHW"));
1195         status = smb2_create(tree2B, mem_ctx, &io2);
1196         CHECK_STATUS(status, NT_STATUS_OK);
1197         h_client2_file2 = io2.out.file.handle;
1198         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1199         CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
1200         CHECK_VAL(io2.out.durable_open_v2, false); //true);
1201         CHECK_VAL(io2.out.timeout, io2.in.timeout);
1202         CHECK_VAL(io2.out.durable_open, false);
1203         CHECK_VAL(lease_break_info.count, 0);
1204
1205
1206         torture_comment(tctx, "Blocking 2A\n");
1207         /* Block 2A */
1208         block_ok = test_block_channel(tctx, transport2A);
1209         torture_assert(tctx, block_ok, "we could not block tcp transport");
1210
1211         /* 1 opens file2 */
1212         torture_comment(tctx,
1213                         "Client opens fname2 with session1 with 2A blocked\n");
1214         smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
1215                           smb2_util_lease_state("RHW"));
1216         status = smb2_create(tree1, mem_ctx, &io2);
1217         CHECK_STATUS(status, NT_STATUS_OK);
1218         h_client1_file2 = io2.out.file.handle;
1219         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1220         CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
1221         CHECK_VAL(io2.out.durable_open_v2, false);
1222         CHECK_VAL(io2.out.timeout, 0);
1223         CHECK_VAL(io2.out.durable_open, false);
1224
1225         if (lease_break_info.count == 0) {
1226                 torture_comment(tctx,
1227                                 "Did not receive expected lease break!!\n");
1228         } else {
1229                 torture_comment(tctx, "Received %d lease break(s)!!\n",
1230                                 lease_break_info.count);
1231         }
1232
1233         CHECK_VAL(lease_break_info.count, 1);
1234         CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
1235         torture_reset_lease_break_info(tctx, &lease_break_info);
1236
1237         /* Connect 2C */
1238         torture_comment(tctx, "Connecting session 2C\n");
1239         talloc_free(tree2C);
1240         tree2C = test_multichannel_create_channel(tctx, host, share,
1241                                 credentials, &transport2_options, tree2A);
1242         if (!tree2C) {
1243                 goto done;
1244         }
1245
1246         /* 2c opens file3 */
1247         torture_comment(tctx, "client2 opens fname3 via session 2C\n");
1248         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
1249                           smb2_util_lease_state("RHW"));
1250         status = smb2_create(tree2C, mem_ctx, &io3);
1251         CHECK_STATUS(status, NT_STATUS_OK);
1252         h_client2_file3 = io3.out.file.handle;
1253         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1254         CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
1255         CHECK_VAL(io3.out.durable_open_v2, false);
1256         CHECK_VAL(io3.out.timeout, io2.in.timeout);
1257         CHECK_VAL(io3.out.durable_open, false);
1258         CHECK_VAL(lease_break_info.count, 0);
1259
1260         /* Unblock 2A */
1261         torture_comment(tctx, "Unblocking 2A\n");
1262         unblock_ok = test_unblock_channel(tctx, transport2A);
1263         torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
1264
1265         /* 1 opens file1 */
1266         torture_comment(tctx, "Client opens fname1 with session 1\n");
1267         smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
1268                           smb2_util_lease_state("RHW"));
1269         status = smb2_create(tree1, mem_ctx, &io1);
1270         CHECK_STATUS(status, NT_STATUS_OK);
1271         h_client1_file1 = io1.out.file.handle;
1272         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1273         CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
1274
1275         if (lease_break_info.count == 0) {
1276                 torture_comment(tctx,
1277                                 "Did not receive expected lease break!!\n");
1278         } else {
1279                 torture_comment(tctx,
1280                                 "Received %d lease break(s)!!\n",
1281                                 lease_break_info.count);
1282         }
1283         CHECK_VAL(lease_break_info.count, 1);
1284         CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
1285         torture_reset_lease_break_info(tctx, &lease_break_info);
1286
1287         /*1 opens file3 */
1288         torture_comment(tctx, "client opens fname3 via session 1\n");
1289
1290         smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
1291                           smb2_util_lease_state("RHW"));
1292         status = smb2_create(tree1, mem_ctx, &io3);
1293         CHECK_STATUS(status, NT_STATUS_OK);
1294         h_client1_file3 = io3.out.file.handle;
1295         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1296         CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
1297
1298         if (lease_break_info.count == 0) {
1299                 torture_comment(tctx,
1300                                 "Did not receive expected lease break!!\n");
1301         } else {
1302                 torture_comment(tctx,
1303                                 "Received %d lease break(s)!!\n",
1304                                 lease_break_info.count);
1305         }
1306         CHECK_VAL(lease_break_info.count, 1);
1307         CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
1308         torture_reset_lease_break_info(tctx, &lease_break_info);
1309
1310         smb2_util_close(tree1, h_client1_file1);
1311         smb2_util_close(tree1, h_client1_file2);
1312         smb2_util_close(tree1, h_client1_file3);
1313
1314         /*
1315          * Session 2 still has RW lease on file 1. Deletion of this file by 1
1316          *  leads to a lease break call to session 2 file1
1317          */
1318         smb2_util_unlink(tree1, fname1);
1319         /*
1320          * Bug - Samba does not revoke Handle lease on unlink
1321          * CHECK_BREAK_INFO("RH", "R", LEASE2F1);
1322          */
1323         torture_reset_lease_break_info(tctx, &lease_break_info);
1324
1325         /*
1326          * Session 2 still has RW lease on file 2. Deletion of this file by 1
1327          *  leads to a lease break call to session 2 file2
1328          */
1329         smb2_util_unlink(tree1, fname2);
1330         /*
1331          * Bug - Samba does not revoke Handle lease on unlink
1332          * CHECK_BREAK_INFO("RH", "R", LEASE2F2);
1333          */
1334         torture_reset_lease_break_info(tctx, &lease_break_info);
1335
1336         /*
1337          * Session 2 still has RW lease on file 3. Deletion of this file by 1
1338          *  leads to a lease break call to session 2 file3
1339          */
1340         smb2_util_unlink(tree1, fname3);
1341         /*
1342          * Bug - Samba does not revoke Handle lease on unlink
1343          * CHECK_BREAK_INFO("RH", "R", LEASE2F3);
1344          */
1345         torture_reset_lease_break_info(tctx, &lease_break_info);
1346
1347         smb2_util_close(tree2C, h_client2_file1);
1348         smb2_util_close(tree2C, h_client2_file2);
1349         smb2_util_close(tree2C, h_client2_file3);
1350
1351         test_multichannel_free_channels(tree2A, tree2B, tree2C);
1352         tree2A = tree2B = tree2C = NULL;
1353
1354 done:
1355         if (block_ok && !unblock_ok) {
1356                 test_unblock_channel(tctx, transport2A);
1357         }
1358         test_cleanup_blocked_channels(tctx);
1359
1360         tree1->session = session1;
1361
1362         smb2_util_close(tree1, h_client1_file1);
1363         smb2_util_close(tree1, h_client1_file2);
1364         smb2_util_close(tree1, h_client1_file3);
1365         if (tree2A != NULL) {
1366                 smb2_util_close(tree2A, h_client2_file1);
1367                 smb2_util_close(tree2A, h_client2_file2);
1368                 smb2_util_close(tree2A, h_client2_file3);
1369         }
1370
1371         if (h != NULL) {
1372                 smb2_util_close(tree1, *h);
1373         }
1374
1375         smb2_util_unlink(tree1, fname1);
1376         smb2_util_unlink(tree1, fname2);
1377         smb2_util_unlink(tree1, fname3);
1378         smb2_deltree(tree1, BASEDIR);
1379
1380         test_multichannel_free_channels(tree2A, tree2B, tree2C);
1381         talloc_free(tree1);
1382         talloc_free(mem_ctx);
1383
1384         return ret;
1385 }
1386
1387 struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
1388 {
1389         struct torture_suite *suite = torture_suite_create(ctx, "multichannel");
1390         struct torture_suite *suite_generic = torture_suite_create(ctx,
1391                                                                    "generic");
1392         struct torture_suite *suite_oplocks = torture_suite_create(ctx,
1393                                                                    "oplocks");
1394         struct torture_suite *suite_leases = torture_suite_create(ctx,
1395                                                                   "leases");
1396
1397         torture_suite_add_suite(suite, suite_generic);
1398         torture_suite_add_suite(suite, suite_oplocks);
1399         torture_suite_add_suite(suite, suite_leases);
1400
1401         torture_suite_add_1smb2_test(suite, "interface_info",
1402                                      test_multichannel_interface_info);
1403         torture_suite_add_1smb2_test(suite_oplocks, "test1",
1404                                      test_multichannel_oplock_break_test1);
1405         torture_suite_add_1smb2_test(suite_oplocks, "test2",
1406                                      test_multichannel_oplock_break_test2);
1407         torture_suite_add_1smb2_test(suite_leases, "test1",
1408                                      test_multichannel_lease_break_test1);
1409         torture_suite_add_1smb2_test(suite_leases, "test2",
1410                                      test_multichannel_lease_break_test2);
1411
1412         suite->description = talloc_strdup(suite, "SMB2 Multichannel tests");
1413
1414         return suite;
1415 }