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