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