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