s3: smbd: Fix schedule_smb2_aio_read() to allow the last read in a compound to go...
[Samba.git] / source4 / torture / smb2 / replay.c
blobb70db372b17d89b16f53d9d2713df41d56f24553
1 /*
2 Unix SMB/CIFS implementation.
4 test suite for SMB2 replay
6 Copyright (C) Anubhav Rakshit 2014
7 Copyright (C) Stefan Metzmacher 2014
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28 #include "../libcli/smb/smbXcli_base.h"
29 #include "lib/cmdline/cmdline.h"
30 #include "auth/credentials/credentials.h"
31 #include "libcli/security/security.h"
32 #include "libcli/resolve/resolve.h"
33 #include "lib/param/param.h"
34 #include "lib/events/events.h"
35 #include "oplock_break_handler.h"
36 #include "lease_break_handler.h"
38 #define CHECK_VAL(v, correct) do { \
39 if ((v) != (correct)) { \
40 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
41 __location__, #v, (int)v, (int)correct); \
42 ret = false; \
43 goto done; \
44 }} while (0)
46 #define CHECK_STATUS(status, correct) do { \
47 if (!NT_STATUS_EQUAL(status, correct)) { \
48 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
49 nt_errstr(status), nt_errstr(correct)); \
50 ret = false; \
51 goto done; \
52 }} while (0)
54 #define CHECK_CREATED(__io, __created, __attribute) \
55 do { \
56 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
57 CHECK_VAL((__io)->out.size, 0); \
58 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
59 CHECK_VAL((__io)->out.reserved2, 0); \
60 } while(0)
62 #define CHECK_HANDLE(__h1, __h2) \
63 do { \
64 CHECK_VAL((__h1)->data[0], (__h2)->data[0]); \
65 CHECK_VAL((__h1)->data[1], (__h2)->data[1]); \
66 } while(0)
68 #define __IO_OUT_VAL(__io1, __io2, __m) \
69 CHECK_VAL((__io1)->out.__m, (__io2)->out.__m)
71 #define CHECK_CREATE_OUT(__io1, __io2) \
72 do { \
73 CHECK_HANDLE(&(__io1)->out.file.handle, \
74 &(__io2)->out.file.handle); \
75 __IO_OUT_VAL(__io1, __io2, oplock_level); \
76 __IO_OUT_VAL(__io1, __io2, create_action); \
77 __IO_OUT_VAL(__io1, __io2, create_time); \
78 __IO_OUT_VAL(__io1, __io2, access_time); \
79 __IO_OUT_VAL(__io1, __io2, write_time); \
80 __IO_OUT_VAL(__io1, __io2, change_time); \
81 __IO_OUT_VAL(__io1, __io2, alloc_size); \
82 __IO_OUT_VAL(__io1, __io2, size); \
83 __IO_OUT_VAL(__io1, __io2, file_attr); \
84 __IO_OUT_VAL(__io1, __io2, durable_open); \
85 __IO_OUT_VAL(__io1, __io2, durable_open_v2); \
86 __IO_OUT_VAL(__io1, __io2, persistent_open); \
87 __IO_OUT_VAL(__io1, __io2, timeout); \
88 __IO_OUT_VAL(__io1, __io2, blobs.num_blobs); \
89 if ((__io1)->out.oplock_level == SMB2_OPLOCK_LEVEL_LEASE) { \
90 __IO_OUT_VAL(__io1, __io2, lease_response.lease_state);\
91 __IO_OUT_VAL(__io1, __io2, lease_response.lease_key.data[0]);\
92 __IO_OUT_VAL(__io1, __io2, lease_response.lease_key.data[1]);\
93 } \
94 } while(0)
96 #define WAIT_FOR_ASYNC_RESPONSE(__tctx, __req) do { \
97 torture_comment((__tctx), "Waiting for async response: %s\n", #__req); \
98 while (!(__req)->cancel.can_cancel && (__req)->state <= SMB2_REQUEST_RECV) { \
99 if (tevent_loop_once((__tctx)->ev) != 0) { \
100 break; \
103 } while(0)
105 #define BASEDIR "replaytestdir"
108 * Test what happens when SMB2_FLAGS_REPLAY_OPERATION is enabled for various
109 * commands. We want to verify if the server returns an error code or not.
111 static bool test_replay_commands(struct torture_context *tctx, struct smb2_tree *tree)
113 bool ret = true;
114 NTSTATUS status;
115 struct smb2_handle h;
116 uint8_t buf[200];
117 struct smb2_read rd;
118 union smb_setfileinfo sfinfo;
119 union smb_fileinfo qfinfo;
120 union smb_ioctl ioctl;
121 struct smb2_lock lck;
122 struct smb2_lock_element el[2];
123 struct smb2_flush f;
124 TALLOC_CTX *tmp_ctx = talloc_new(tree);
125 const char *fname = BASEDIR "\\replay_commands.dat";
126 struct smb2_transport *transport = tree->session->transport;
128 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
129 torture_skip(tctx, "SMB 3.X Dialect family required for "
130 "Replay tests\n");
133 torture_reset_break_info(tctx, &break_info);
134 tree->session->transport->oplock.handler = torture_oplock_ack_handler;
135 tree->session->transport->oplock.private_data = tree;
137 status = torture_smb2_testdir(tree, BASEDIR, &h);
138 CHECK_STATUS(status, NT_STATUS_OK);
139 smb2_util_close(tree, h);
141 smb2cli_session_start_replay(tree->session->smbXcli);
143 torture_comment(tctx, "Try Commands with Replay Flags Enabled\n");
145 torture_comment(tctx, "Trying create\n");
146 status = torture_smb2_testfile(tree, fname, &h);
147 CHECK_STATUS(status, NT_STATUS_OK);
148 CHECK_VAL(break_info.count, 0);
150 * Wireshark shows that the response has SMB2_FLAGS_REPLAY_OPERATION
151 * flags set. The server should ignore this flag.
154 torture_comment(tctx, "Trying write\n");
155 status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
156 CHECK_STATUS(status, NT_STATUS_OK);
158 f = (struct smb2_flush) {
159 .in.file.handle = h
161 torture_comment(tctx, "Trying flush\n");
162 status = smb2_flush(tree, &f);
163 CHECK_STATUS(status, NT_STATUS_OK);
165 rd = (struct smb2_read) {
166 .in.file.handle = h,
167 .in.length = 10,
168 .in.offset = 0,
169 .in.min_count = 1
171 torture_comment(tctx, "Trying read\n");
172 status = smb2_read(tree, tmp_ctx, &rd);
173 CHECK_STATUS(status, NT_STATUS_OK);
174 CHECK_VAL(rd.out.data.length, 10);
176 sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
177 sfinfo.position_information.in.file.handle = h;
178 sfinfo.position_information.in.position = 0x1000;
179 torture_comment(tctx, "Trying setinfo\n");
180 status = smb2_setinfo_file(tree, &sfinfo);
181 CHECK_STATUS(status, NT_STATUS_OK);
183 qfinfo = (union smb_fileinfo) {
184 .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
185 .generic.in.file.handle = h
187 torture_comment(tctx, "Trying getinfo\n");
188 status = smb2_getinfo_file(tree, tmp_ctx, &qfinfo);
189 CHECK_STATUS(status, NT_STATUS_OK);
190 CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
192 ioctl = (union smb_ioctl) {
193 .smb2.level = RAW_IOCTL_SMB2,
194 .smb2.in.file.handle = h,
195 .smb2.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID,
196 .smb2.in.max_output_response = 64,
197 .smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL
199 torture_comment(tctx, "Trying ioctl\n");
200 status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
201 CHECK_STATUS(status, NT_STATUS_OK);
203 lck = (struct smb2_lock) {
204 .in.locks = el,
205 .in.lock_count = 0x0001,
206 .in.lock_sequence = 0x00000000,
207 .in.file.handle = h
209 el[0].reserved = 0x00000000;
210 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
211 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
213 torture_comment(tctx, "Trying lock\n");
214 el[0].offset = 0x0000000000000000;
215 el[0].length = 0x0000000000000100;
216 status = smb2_lock(tree, &lck);
217 CHECK_STATUS(status, NT_STATUS_OK);
219 lck.in.file.handle = h;
220 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
221 status = smb2_lock(tree, &lck);
222 CHECK_STATUS(status, NT_STATUS_OK);
224 CHECK_VAL(break_info.count, 0);
225 done:
226 smb2cli_session_stop_replay(tree->session->smbXcli);
227 smb2_util_close(tree, h);
228 smb2_deltree(tree, BASEDIR);
230 talloc_free(tmp_ctx);
232 return ret;
236 * Test replay detection without create GUID on single channel.
237 * Regular creates can not be replayed.
238 * The return code is unaffected of the REPLAY_OPERATION flag.
240 static bool test_replay_regular(struct torture_context *tctx,
241 struct smb2_tree *tree)
243 NTSTATUS status;
244 TALLOC_CTX *mem_ctx = talloc_new(tctx);
245 struct smb2_handle _h;
246 struct smb2_handle *h = NULL;
247 struct smb2_create io;
248 uint32_t perms = 0;
249 bool ret = true;
250 const char *fname = BASEDIR "\\replay_regular.dat";
251 struct smb2_transport *transport = tree->session->transport;
253 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
254 torture_skip(tctx, "SMB 3.X Dialect family required for "
255 "replay tests\n");
258 torture_reset_break_info(tctx, &break_info);
259 tree->session->transport->oplock.handler = torture_oplock_ack_handler;
260 tree->session->transport->oplock.private_data = tree;
262 smb2_util_unlink(tree, fname);
263 status = torture_smb2_testdir(tree, BASEDIR, &_h);
264 CHECK_STATUS(status, NT_STATUS_OK);
265 smb2_util_close(tree, _h);
266 CHECK_VAL(break_info.count, 0);
268 torture_comment(tctx, "No replay detection for regular create\n");
270 perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
271 SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
272 SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
273 SEC_FILE_WRITE_DATA;
275 io = (struct smb2_create) {
276 .in.desired_access = perms,
277 .in.file_attributes = 0,
278 .in.create_disposition = NTCREATEX_DISP_CREATE,
279 .in.share_access = NTCREATEX_SHARE_ACCESS_DELETE,
280 .in.create_options = 0x0,
281 .in.fname = fname
284 status = smb2_create(tree, tctx, &io);
285 CHECK_STATUS(status, NT_STATUS_OK);
286 CHECK_VAL(break_info.count, 0);
287 _h = io.out.file.handle;
288 h = &_h;
289 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
291 smb2cli_session_start_replay(tree->session->smbXcli);
292 status = smb2_create(tree, tctx, &io);
293 smb2cli_session_stop_replay(tree->session->smbXcli);
294 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
295 CHECK_VAL(break_info.count, 0);
297 smb2_util_close(tree, *h);
298 h = NULL;
299 smb2_util_unlink(tree, fname);
302 * Same experiment with different create disposition.
304 io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
305 status = smb2_create(tree, tctx, &io);
306 CHECK_STATUS(status, NT_STATUS_OK);
307 CHECK_VAL(break_info.count, 0);
308 _h = io.out.file.handle;
309 h = &_h;
310 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
312 smb2cli_session_start_replay(tree->session->smbXcli);
313 status = smb2_create(tree, tctx, &io);
314 smb2cli_session_stop_replay(tree->session->smbXcli);
315 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
316 CHECK_VAL(break_info.count, 0);
318 smb2_util_close(tree, *h);
319 h = NULL;
320 smb2_util_unlink(tree, fname);
323 * Now with more generous share mode.
325 io.in.share_access = smb2_util_share_access("RWD");
326 status = smb2_create(tree, tctx, &io);
327 CHECK_STATUS(status, NT_STATUS_OK);
328 CHECK_VAL(break_info.count, 0);
329 _h = io.out.file.handle;
330 h = &_h;
331 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
333 smb2cli_session_start_replay(tree->session->smbXcli);
334 status = smb2_create(tree, tctx, &io);
335 smb2cli_session_stop_replay(tree->session->smbXcli);
336 CHECK_STATUS(status, NT_STATUS_OK);
337 CHECK_VAL(break_info.count, 0);
339 done:
340 if (h != NULL) {
341 smb2_util_close(tree, *h);
343 smb2_deltree(tree, BASEDIR);
345 talloc_free(tree);
346 talloc_free(mem_ctx);
348 return ret;
352 * Test Durability V2 Create Replay Detection on Single Channel.
354 static bool test_replay_dhv2_oplock1(struct torture_context *tctx,
355 struct smb2_tree *tree)
357 NTSTATUS status;
358 TALLOC_CTX *mem_ctx = talloc_new(tctx);
359 struct smb2_handle _h;
360 struct smb2_handle *h = NULL;
361 struct smb2_create io, ref1;
362 struct GUID create_guid = GUID_random();
363 bool ret = true;
364 const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat";
365 struct smb2_transport *transport = tree->session->transport;
366 uint32_t share_capabilities;
367 bool share_is_so;
369 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
370 torture_skip(tctx, "SMB 3.X Dialect family required for "
371 "replay tests\n");
374 share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
375 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
377 torture_reset_break_info(tctx, &break_info);
378 tree->session->transport->oplock.handler = torture_oplock_ack_handler;
379 tree->session->transport->oplock.private_data = tree;
381 torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
382 "Channel\n");
383 smb2_util_unlink(tree, fname);
384 status = torture_smb2_testdir(tree, BASEDIR, &_h);
385 CHECK_STATUS(status, NT_STATUS_OK);
386 smb2_util_close(tree, _h);
387 CHECK_VAL(break_info.count, 0);
389 smb2_oplock_create_share(&io, fname,
390 smb2_util_share_access(""),
391 smb2_util_oplock_level("b"));
392 io.in.durable_open = false;
393 io.in.durable_open_v2 = true;
394 io.in.persistent_open = false;
395 io.in.create_guid = create_guid;
396 io.in.timeout = UINT32_MAX;
398 status = smb2_create(tree, mem_ctx, &io);
399 CHECK_STATUS(status, NT_STATUS_OK);
400 ref1 = io;
401 _h = io.out.file.handle;
402 h = &_h;
403 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
404 CHECK_VAL(io.out.durable_open, false);
405 if (share_is_so) {
406 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
407 CHECK_VAL(io.out.durable_open_v2, false);
408 CHECK_VAL(io.out.timeout, 0);
409 } else {
410 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
411 CHECK_VAL(io.out.durable_open_v2, true);
412 CHECK_VAL(io.out.timeout, 300*1000);
416 * Replay Durable V2 Create on single channel
418 smb2cli_session_start_replay(tree->session->smbXcli);
419 status = smb2_create(tree, mem_ctx, &io);
420 smb2cli_session_stop_replay(tree->session->smbXcli);
421 CHECK_STATUS(status, NT_STATUS_OK);
422 CHECK_CREATE_OUT(&io, &ref1);
423 CHECK_VAL(break_info.count, 0);
425 done:
426 if (h != NULL) {
427 smb2_util_close(tree, *h);
429 smb2_deltree(tree, BASEDIR);
431 talloc_free(tree);
432 talloc_free(mem_ctx);
434 return ret;
438 * Test Durability V2 Create Replay Detection on Single Channel.
439 * Hand in a different oplock level in the replay.
440 * Server responds with the handed in oplock level and
441 * corresponding durable status, but does not change the
442 * oplock level or durable status of the opened file.
444 static bool test_replay_dhv2_oplock2(struct torture_context *tctx,
445 struct smb2_tree *tree)
447 NTSTATUS status;
448 TALLOC_CTX *mem_ctx = talloc_new(tctx);
449 struct smb2_handle _h;
450 struct smb2_handle *h = NULL;
451 struct smb2_create io, ref1, ref2;
452 struct GUID create_guid = GUID_random();
453 bool ret = true;
454 const char *fname = BASEDIR "\\replay_dhv2_oplock2.dat";
455 struct smb2_transport *transport = tree->session->transport;
456 uint32_t share_capabilities;
457 bool share_is_so;
459 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
460 torture_skip(tctx, "SMB 3.X Dialect family required for "
461 "replay tests\n");
464 share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
465 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
467 torture_reset_break_info(tctx, &break_info);
468 tree->session->transport->oplock.handler = torture_oplock_ack_handler;
469 tree->session->transport->oplock.private_data = tree;
471 torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
472 "Channel\n");
473 smb2_util_unlink(tree, fname);
474 status = torture_smb2_testdir(tree, BASEDIR, &_h);
475 CHECK_STATUS(status, NT_STATUS_OK);
476 smb2_util_close(tree, _h);
477 CHECK_VAL(break_info.count, 0);
479 smb2_oplock_create_share(&io, fname,
480 smb2_util_share_access(""),
481 smb2_util_oplock_level("b"));
482 io.in.durable_open = false;
483 io.in.durable_open_v2 = true;
484 io.in.persistent_open = false;
485 io.in.create_guid = create_guid;
486 io.in.timeout = UINT32_MAX;
488 status = smb2_create(tree, mem_ctx, &io);
489 CHECK_STATUS(status, NT_STATUS_OK);
490 ref1 = io;
491 _h = io.out.file.handle;
492 h = &_h;
493 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
494 CHECK_VAL(io.out.durable_open, false);
495 if (share_is_so) {
496 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
497 CHECK_VAL(io.out.durable_open_v2, false);
498 CHECK_VAL(io.out.timeout, 0);
499 } else {
500 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
501 CHECK_VAL(io.out.durable_open_v2, true);
502 CHECK_VAL(io.out.timeout, 300*1000);
506 * Replay durable v2 create on single channel:
508 * Replay the create with a different oplock (none).
509 * The server replies with the requested oplock level
510 * and also only replies with durable handle based
511 * on whether it could have been granted based on
512 * the requested oplock type.
514 smb2_oplock_create_share(&io, fname,
515 smb2_util_share_access(""),
516 smb2_util_oplock_level(""));
517 io.in.durable_open = false;
518 io.in.durable_open_v2 = true;
519 io.in.persistent_open = false;
520 io.in.create_guid = create_guid;
521 io.in.timeout = UINT32_MAX;
524 * Adapt the response to the exepected values
526 ref2 = ref1;
527 ref2.out.oplock_level = smb2_util_oplock_level("");
528 ref2.out.durable_open_v2 = false;
529 ref2.out.timeout = 0;
530 ref2.out.blobs.num_blobs = 0;
532 smb2cli_session_start_replay(tree->session->smbXcli);
533 status = smb2_create(tree, mem_ctx, &io);
534 smb2cli_session_stop_replay(tree->session->smbXcli);
535 CHECK_STATUS(status, NT_STATUS_OK);
536 CHECK_CREATE_OUT(&io, &ref2);
537 CHECK_VAL(break_info.count, 0);
540 * Prove that the open file still has a batch oplock
541 * by breaking it with another open.
543 smb2_oplock_create_share(&io, fname,
544 smb2_util_share_access(""),
545 smb2_util_oplock_level("b"));
546 io.in.durable_open = false;
547 io.in.durable_open_v2 = true;
548 io.in.persistent_open = false;
549 io.in.create_guid = GUID_random();
550 io.in.timeout = UINT32_MAX;
551 status = smb2_create(tree, mem_ctx, &io);
552 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
554 if (!share_is_so) {
555 CHECK_VAL(break_info.count, 1);
556 CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle);
557 CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
558 torture_reset_break_info(tctx, &break_info);
561 done:
562 if (h != NULL) {
563 smb2_util_close(tree, *h);
565 smb2_deltree(tree, BASEDIR);
567 talloc_free(tree);
568 talloc_free(mem_ctx);
570 return ret;
574 * Test Durability V2 Create Replay Detection on Single Channel.
575 * Replay with a different share mode. The share mode of
576 * the opened file is not changed by this.
578 static bool test_replay_dhv2_oplock3(struct torture_context *tctx,
579 struct smb2_tree *tree)
581 NTSTATUS status;
582 TALLOC_CTX *mem_ctx = talloc_new(tctx);
583 struct smb2_handle _h;
584 struct smb2_handle *h = NULL;
585 struct smb2_create io, ref1;
586 struct GUID create_guid = GUID_random();
587 bool ret = true;
588 const char *fname = BASEDIR "\\replay_dhv2_oplock3.dat";
589 struct smb2_transport *transport = tree->session->transport;
590 uint32_t share_capabilities;
591 bool share_is_so;
593 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
594 torture_skip(tctx, "SMB 3.X Dialect family required for "
595 "replay tests\n");
598 share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
599 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
601 torture_reset_break_info(tctx, &break_info);
602 tree->session->transport->oplock.handler = torture_oplock_ack_handler;
603 tree->session->transport->oplock.private_data = tree;
605 torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
606 "Channel\n");
607 smb2_util_unlink(tree, fname);
608 status = torture_smb2_testdir(tree, BASEDIR, &_h);
609 CHECK_STATUS(status, NT_STATUS_OK);
610 smb2_util_close(tree, _h);
611 CHECK_VAL(break_info.count, 0);
613 smb2_oplock_create_share(&io, fname,
614 smb2_util_share_access(""),
615 smb2_util_oplock_level("b"));
616 io.in.durable_open = false;
617 io.in.durable_open_v2 = true;
618 io.in.persistent_open = false;
619 io.in.create_guid = create_guid;
620 io.in.timeout = UINT32_MAX;
622 status = smb2_create(tree, mem_ctx, &io);
623 CHECK_STATUS(status, NT_STATUS_OK);
624 ref1 = io;
625 _h = io.out.file.handle;
626 h = &_h;
627 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
628 CHECK_VAL(io.out.durable_open, false);
629 if (share_is_so) {
630 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
631 CHECK_VAL(io.out.durable_open_v2, false);
632 CHECK_VAL(io.out.timeout, 0);
633 } else {
634 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
635 CHECK_VAL(io.out.durable_open_v2, true);
636 CHECK_VAL(io.out.timeout, 300*1000);
640 * Replay durable v2 create on single channel:
642 * Replay the create with a different share mode.
643 * The server replies with the requested share
644 * mode instead of that which is associated to
645 * the handle.
647 smb2_oplock_create_share(&io, fname,
648 smb2_util_share_access("RWD"),
649 smb2_util_oplock_level("b"));
650 io.in.durable_open = false;
651 io.in.durable_open_v2 = true;
652 io.in.persistent_open = false;
653 io.in.create_guid = create_guid;
654 io.in.timeout = UINT32_MAX;
656 smb2cli_session_start_replay(tree->session->smbXcli);
657 status = smb2_create(tree, mem_ctx, &io);
658 smb2cli_session_stop_replay(tree->session->smbXcli);
659 CHECK_STATUS(status, NT_STATUS_OK);
660 CHECK_CREATE_OUT(&io, &ref1);
661 CHECK_VAL(break_info.count, 0);
664 * In order to prove that the different share mode in the
665 * replayed create had no effect on the open file handle,
666 * show that a new create yields NT_STATUS_SHARING_VIOLATION.
668 smb2_oplock_create_share(&io, fname,
669 smb2_util_share_access(""),
670 smb2_util_oplock_level("b"));
671 io.in.durable_open = false;
672 io.in.durable_open_v2 = true;
673 io.in.persistent_open = false;
674 io.in.create_guid = GUID_random();
675 io.in.timeout = UINT32_MAX;
676 status = smb2_create(tree, mem_ctx, &io);
677 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
679 if (!share_is_so) {
680 CHECK_VAL(break_info.count, 1);
681 CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle);
682 CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
683 torture_reset_break_info(tctx, &break_info);
686 done:
687 if (h != NULL) {
688 smb2_util_close(tree, *h);
690 smb2_deltree(tree, BASEDIR);
692 talloc_free(tree);
693 talloc_free(mem_ctx);
695 return ret;
699 * Test Durability V2 Create Replay Detection on Single Channel.
700 * Create with an oplock, and replay with a lease.
702 static bool test_replay_dhv2_oplock_lease(struct torture_context *tctx,
703 struct smb2_tree *tree)
705 NTSTATUS status;
706 TALLOC_CTX *mem_ctx = talloc_new(tctx);
707 struct smb2_handle _h;
708 struct smb2_handle *h = NULL;
709 struct smb2_create io;
710 struct GUID create_guid = GUID_random();
711 bool ret = true;
712 const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat";
713 struct smb2_transport *transport = tree->session->transport;
714 uint32_t share_capabilities;
715 bool share_is_so;
716 uint32_t server_capabilities;
717 struct smb2_lease ls;
718 uint64_t lease_key;
720 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
721 torture_skip(tctx, "SMB 3.X Dialect family required for "
722 "replay tests\n");
725 server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
726 if (!(server_capabilities & SMB2_CAP_LEASING)) {
727 torture_skip(tctx, "leases are not supported");
730 share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
731 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
733 torture_reset_break_info(tctx, &break_info);
734 tree->session->transport->oplock.handler = torture_oplock_ack_handler;
735 tree->session->transport->oplock.private_data = tree;
737 torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
738 "Channel\n");
739 smb2_util_unlink(tree, fname);
740 status = torture_smb2_testdir(tree, BASEDIR, &_h);
741 CHECK_STATUS(status, NT_STATUS_OK);
742 smb2_util_close(tree, _h);
743 CHECK_VAL(break_info.count, 0);
745 smb2_oplock_create_share(&io, fname,
746 smb2_util_share_access(""),
747 smb2_util_oplock_level("b"));
748 io.in.durable_open = false;
749 io.in.durable_open_v2 = true;
750 io.in.persistent_open = false;
751 io.in.create_guid = create_guid;
752 io.in.timeout = UINT32_MAX;
754 status = smb2_create(tree, mem_ctx, &io);
755 CHECK_STATUS(status, NT_STATUS_OK);
756 _h = io.out.file.handle;
757 h = &_h;
758 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
759 CHECK_VAL(io.out.durable_open, false);
760 if (share_is_so) {
761 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
762 CHECK_VAL(io.out.durable_open_v2, false);
763 CHECK_VAL(io.out.timeout, 0);
764 } else {
765 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
766 CHECK_VAL(io.out.durable_open_v2, true);
767 CHECK_VAL(io.out.timeout, 300*1000);
771 * Replay Durable V2 Create on single channel
772 * but replay it with a lease instead of an oplock.
774 lease_key = random();
775 smb2_lease_create(&io, &ls, false /* dir */, fname,
776 lease_key, smb2_util_lease_state("RH"));
777 io.in.durable_open = false;
778 io.in.durable_open_v2 = true;
779 io.in.persistent_open = false;
780 io.in.create_guid = create_guid;
781 io.in.timeout = UINT32_MAX;
783 smb2cli_session_start_replay(tree->session->smbXcli);
784 status = smb2_create(tree, mem_ctx, &io);
785 smb2cli_session_stop_replay(tree->session->smbXcli);
786 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
788 done:
789 if (h != NULL) {
790 smb2_util_close(tree, *h);
792 smb2_deltree(tree, BASEDIR);
794 talloc_free(tree);
795 talloc_free(mem_ctx);
797 return ret;
802 * Test durability v2 create replay detection on single channel.
803 * Variant with leases instead of oplocks:
804 * - open a file with a rh lease
805 * - upgrade to a rwh lease with a second create
806 * - replay the first create.
807 * ==> it gets back the upgraded lease level
809 static bool test_replay_dhv2_lease1(struct torture_context *tctx,
810 struct smb2_tree *tree)
812 NTSTATUS status;
813 TALLOC_CTX *mem_ctx = talloc_new(tctx);
814 struct smb2_handle _h1;
815 struct smb2_handle *h1 = NULL;
816 struct smb2_handle _h2;
817 struct smb2_handle *h2 = NULL;
818 struct smb2_create io1, io2, ref1;
819 struct GUID create_guid = GUID_random();
820 bool ret = true;
821 const char *fname = BASEDIR "\\replay2_lease1.dat";
822 struct smb2_transport *transport = tree->session->transport;
823 uint32_t share_capabilities;
824 bool share_is_so;
825 uint32_t server_capabilities;
826 struct smb2_lease ls1, ls2;
827 uint64_t lease_key;
829 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
830 torture_skip(tctx, "SMB 3.X Dialect family required for "
831 "replay tests\n");
834 server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
835 if (!(server_capabilities & SMB2_CAP_LEASING)) {
836 torture_skip(tctx, "leases are not supported");
839 share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
840 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
842 torture_reset_break_info(tctx, &break_info);
843 tree->session->transport->oplock.handler = torture_oplock_ack_handler;
844 tree->session->transport->oplock.private_data = tree;
846 torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
847 "on Single Channel\n");
848 smb2_util_unlink(tree, fname);
849 status = torture_smb2_testdir(tree, BASEDIR, &_h1);
850 CHECK_STATUS(status, NT_STATUS_OK);
851 smb2_util_close(tree, _h1);
852 CHECK_VAL(break_info.count, 0);
854 lease_key = random();
856 smb2_lease_create(&io1, &ls1, false /* dir */, fname,
857 lease_key, smb2_util_lease_state("RH"));
858 io1.in.durable_open = false;
859 io1.in.durable_open_v2 = true;
860 io1.in.persistent_open = false;
861 io1.in.create_guid = create_guid;
862 io1.in.timeout = UINT32_MAX;
864 status = smb2_create(tree, mem_ctx, &io1);
865 CHECK_STATUS(status, NT_STATUS_OK);
866 ref1 = io1;
867 _h1 = io1.out.file.handle;
868 h1 = &_h1;
869 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
870 CHECK_VAL(io1.out.durable_open, false);
871 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
872 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
873 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
874 if (share_is_so) {
875 CHECK_VAL(io1.out.lease_response.lease_state,
876 smb2_util_lease_state("R"));
877 CHECK_VAL(io1.out.durable_open_v2, false);
878 CHECK_VAL(io1.out.timeout, 0);
879 } else {
880 CHECK_VAL(io1.out.lease_response.lease_state,
881 smb2_util_lease_state("RH"));
882 CHECK_VAL(io1.out.durable_open_v2, true);
883 CHECK_VAL(io1.out.timeout, 300*1000);
887 * Upgrade the lease to RWH
889 smb2_lease_create(&io2, &ls2, false /* dir */, fname,
890 lease_key, smb2_util_lease_state("RHW"));
891 io2.in.durable_open = false;
892 io2.in.durable_open_v2 = true;
893 io2.in.persistent_open = false;
894 io2.in.create_guid = GUID_random(); /* new guid... */
895 io2.in.timeout = UINT32_MAX;
897 status = smb2_create(tree, mem_ctx, &io2);
898 CHECK_STATUS(status, NT_STATUS_OK);
899 _h2 = io2.out.file.handle;
900 h2 = &_h2;
903 * Replay Durable V2 Create on single channel.
904 * We get the io from open #1 but with the
905 * upgraded lease.
908 /* adapt expected lease in response */
909 if (!share_is_so) {
910 ref1.out.lease_response.lease_state =
911 smb2_util_lease_state("RHW");
914 smb2cli_session_start_replay(tree->session->smbXcli);
915 status = smb2_create(tree, mem_ctx, &io1);
916 smb2cli_session_stop_replay(tree->session->smbXcli);
917 CHECK_STATUS(status, NT_STATUS_OK);
918 CHECK_CREATE_OUT(&io1, &ref1);
919 CHECK_VAL(break_info.count, 0);
921 done:
922 smb2cli_session_stop_replay(tree->session->smbXcli);
924 if (h1 != NULL) {
925 smb2_util_close(tree, *h1);
927 if (h2 != NULL) {
928 smb2_util_close(tree, *h2);
930 smb2_deltree(tree, BASEDIR);
932 talloc_free(tree);
933 talloc_free(mem_ctx);
935 return ret;
939 * Test durability v2 create replay detection on single channel.
940 * Variant with leases instead of oplocks, where the
941 * replay does not specify the original lease level but
942 * just a "R" lease. This still gives the upgraded lease
943 * level in the reply.
944 * - open a file with a rh lease
945 * - upgrade to a rwh lease with a second create
946 * - replay the first create.
947 * ==> it gets back the upgraded lease level
949 static bool test_replay_dhv2_lease2(struct torture_context *tctx,
950 struct smb2_tree *tree)
952 NTSTATUS status;
953 TALLOC_CTX *mem_ctx = talloc_new(tctx);
954 struct smb2_handle _h1;
955 struct smb2_handle *h1 = NULL;
956 struct smb2_handle _h2;
957 struct smb2_handle *h2 = NULL;
958 struct smb2_create io1, io2, ref1;
959 struct GUID create_guid = GUID_random();
960 bool ret = true;
961 const char *fname = BASEDIR "\\replay2_lease2.dat";
962 struct smb2_transport *transport = tree->session->transport;
963 uint32_t share_capabilities;
964 bool share_is_so;
965 uint32_t server_capabilities;
966 struct smb2_lease ls1, ls2;
967 uint64_t lease_key;
969 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
970 torture_skip(tctx, "SMB 3.X Dialect family required for "
971 "replay tests\n");
974 server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
975 if (!(server_capabilities & SMB2_CAP_LEASING)) {
976 torture_skip(tctx, "leases are not supported");
979 share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
980 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
982 torture_reset_break_info(tctx, &break_info);
983 tree->session->transport->oplock.handler = torture_oplock_ack_handler;
984 tree->session->transport->oplock.private_data = tree;
986 torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
987 "on Single Channel\n");
988 smb2_util_unlink(tree, fname);
989 status = torture_smb2_testdir(tree, BASEDIR, &_h1);
990 CHECK_STATUS(status, NT_STATUS_OK);
991 smb2_util_close(tree, _h1);
992 CHECK_VAL(break_info.count, 0);
994 lease_key = random();
996 smb2_lease_create(&io1, &ls1, false /* dir */, fname,
997 lease_key, smb2_util_lease_state("RH"));
998 io1.in.durable_open = false;
999 io1.in.durable_open_v2 = true;
1000 io1.in.persistent_open = false;
1001 io1.in.create_guid = create_guid;
1002 io1.in.timeout = UINT32_MAX;
1004 status = smb2_create(tree, mem_ctx, &io1);
1005 CHECK_STATUS(status, NT_STATUS_OK);
1006 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1007 CHECK_VAL(io1.out.durable_open, false);
1008 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1009 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
1010 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
1011 if (share_is_so) {
1012 CHECK_VAL(io1.out.lease_response.lease_state,
1013 smb2_util_lease_state("R"));
1014 CHECK_VAL(io1.out.durable_open_v2, false);
1015 CHECK_VAL(io1.out.timeout, 0);
1016 } else {
1017 CHECK_VAL(io1.out.lease_response.lease_state,
1018 smb2_util_lease_state("RH"));
1019 CHECK_VAL(io1.out.durable_open_v2, true);
1020 CHECK_VAL(io1.out.timeout, 300*1000);
1022 ref1 = io1;
1023 _h1 = io1.out.file.handle;
1024 h1 = &_h1;
1027 * Upgrade the lease to RWH
1029 smb2_lease_create(&io2, &ls2, false /* dir */, fname,
1030 lease_key, smb2_util_lease_state("RHW"));
1031 io2.in.durable_open = false;
1032 io2.in.durable_open_v2 = true;
1033 io2.in.persistent_open = false;
1034 io2.in.create_guid = GUID_random(); /* new guid... */
1035 io2.in.timeout = UINT32_MAX;
1037 status = smb2_create(tree, mem_ctx, &io2);
1038 CHECK_STATUS(status, NT_STATUS_OK);
1039 _h2 = io2.out.file.handle;
1040 h2 = &_h2;
1043 * Replay Durable V2 Create on single channel.
1044 * Changing the requested lease level to "R"
1045 * does not change the response:
1046 * We get the reply from open #1 but with the
1047 * upgraded lease.
1050 /* adapt the expected response */
1051 if (!share_is_so) {
1052 ref1.out.lease_response.lease_state =
1053 smb2_util_lease_state("RHW");
1056 smb2_lease_create(&io1, &ls1, false /* dir */, fname,
1057 lease_key, smb2_util_lease_state("R"));
1058 io1.in.durable_open = false;
1059 io1.in.durable_open_v2 = true;
1060 io1.in.persistent_open = false;
1061 io1.in.create_guid = create_guid;
1062 io1.in.timeout = UINT32_MAX;
1064 smb2cli_session_start_replay(tree->session->smbXcli);
1065 status = smb2_create(tree, mem_ctx, &io1);
1066 smb2cli_session_stop_replay(tree->session->smbXcli);
1067 CHECK_STATUS(status, NT_STATUS_OK);
1068 CHECK_CREATE_OUT(&io1, &ref1);
1069 CHECK_VAL(break_info.count, 0);
1071 done:
1072 smb2cli_session_stop_replay(tree->session->smbXcli);
1074 if (h1 != NULL) {
1075 smb2_util_close(tree, *h1);
1077 if (h2 != NULL) {
1078 smb2_util_close(tree, *h2);
1080 smb2_deltree(tree, BASEDIR);
1082 talloc_free(tree);
1083 talloc_free(mem_ctx);
1085 return ret;
1089 * Test durability v2 create replay detection on single channel.
1090 * create with a lease, and replay with a different lease key
1092 static bool test_replay_dhv2_lease3(struct torture_context *tctx,
1093 struct smb2_tree *tree)
1095 NTSTATUS status;
1096 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1097 struct smb2_handle _h1;
1098 struct smb2_handle *h1 = NULL;
1099 struct smb2_handle _h2;
1100 struct smb2_handle *h2 = NULL;
1101 struct smb2_create io1, io2;
1102 struct GUID create_guid = GUID_random();
1103 bool ret = true;
1104 const char *fname = BASEDIR "\\replay2_lease2.dat";
1105 struct smb2_transport *transport = tree->session->transport;
1106 uint32_t share_capabilities;
1107 bool share_is_so;
1108 uint32_t server_capabilities;
1109 struct smb2_lease ls1, ls2;
1110 uint64_t lease_key;
1112 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
1113 torture_skip(tctx, "SMB 3.X Dialect family required for "
1114 "replay tests\n");
1117 server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
1118 if (!(server_capabilities & SMB2_CAP_LEASING)) {
1119 torture_skip(tctx, "leases are not supported");
1122 share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
1123 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
1125 torture_reset_break_info(tctx, &break_info);
1126 tree->session->transport->oplock.handler = torture_oplock_ack_handler;
1127 tree->session->transport->oplock.private_data = tree;
1129 torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
1130 "on Single Channel\n");
1131 smb2_util_unlink(tree, fname);
1132 status = torture_smb2_testdir(tree, BASEDIR, &_h1);
1133 CHECK_STATUS(status, NT_STATUS_OK);
1134 smb2_util_close(tree, _h1);
1135 CHECK_VAL(break_info.count, 0);
1137 lease_key = random();
1139 smb2_lease_create(&io1, &ls1, false /* dir */, fname,
1140 lease_key, smb2_util_lease_state("RH"));
1141 io1.in.durable_open = false;
1142 io1.in.durable_open_v2 = true;
1143 io1.in.persistent_open = false;
1144 io1.in.create_guid = create_guid;
1145 io1.in.timeout = UINT32_MAX;
1147 status = smb2_create(tree, mem_ctx, &io1);
1148 CHECK_STATUS(status, NT_STATUS_OK);
1149 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1150 CHECK_VAL(io1.out.durable_open, false);
1151 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1152 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
1153 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
1154 if (share_is_so) {
1155 CHECK_VAL(io1.out.lease_response.lease_state,
1156 smb2_util_lease_state("R"));
1157 CHECK_VAL(io1.out.durable_open_v2, false);
1158 CHECK_VAL(io1.out.timeout, 0);
1159 } else {
1160 CHECK_VAL(io1.out.lease_response.lease_state,
1161 smb2_util_lease_state("RH"));
1162 CHECK_VAL(io1.out.durable_open_v2, true);
1163 CHECK_VAL(io1.out.timeout, 300*1000);
1165 _h1 = io1.out.file.handle;
1166 h1 = &_h1;
1169 * Upgrade the lease to RWH
1171 smb2_lease_create(&io2, &ls2, false /* dir */, fname,
1172 lease_key, smb2_util_lease_state("RHW"));
1173 io2.in.durable_open = false;
1174 io2.in.durable_open_v2 = true;
1175 io2.in.persistent_open = false;
1176 io2.in.create_guid = GUID_random(); /* new guid... */
1177 io2.in.timeout = UINT32_MAX;
1179 status = smb2_create(tree, mem_ctx, &io2);
1180 CHECK_STATUS(status, NT_STATUS_OK);
1181 _h2 = io2.out.file.handle;
1182 h2 = &_h2;
1185 * Replay Durable V2 Create on single channel.
1186 * use a different lease key.
1189 smb2_lease_create(&io1, &ls1, false /* dir */, fname,
1190 random() /* lease key */,
1191 smb2_util_lease_state("RH"));
1192 io1.in.durable_open = false;
1193 io1.in.durable_open_v2 = true;
1194 io1.in.persistent_open = false;
1195 io1.in.create_guid = create_guid;
1196 io1.in.timeout = UINT32_MAX;
1198 smb2cli_session_start_replay(tree->session->smbXcli);
1199 status = smb2_create(tree, mem_ctx, &io1);
1200 smb2cli_session_stop_replay(tree->session->smbXcli);
1201 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1203 done:
1204 smb2cli_session_stop_replay(tree->session->smbXcli);
1206 if (h1 != NULL) {
1207 smb2_util_close(tree, *h1);
1209 if (h2 != NULL) {
1210 smb2_util_close(tree, *h2);
1212 smb2_deltree(tree, BASEDIR);
1214 talloc_free(tree);
1215 talloc_free(mem_ctx);
1217 return ret;
1221 * Test durability v2 create replay detection on single channel.
1222 * Do the original create with a lease, and do the replay
1223 * with an oplock.
1225 static bool test_replay_dhv2_lease_oplock(struct torture_context *tctx,
1226 struct smb2_tree *tree)
1228 NTSTATUS status;
1229 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1230 struct smb2_handle _h1;
1231 struct smb2_handle *h1 = NULL;
1232 struct smb2_handle _h2;
1233 struct smb2_handle *h2 = NULL;
1234 struct smb2_create io1, io2, ref1;
1235 struct GUID create_guid = GUID_random();
1236 bool ret = true;
1237 const char *fname = BASEDIR "\\replay2_lease1.dat";
1238 struct smb2_transport *transport = tree->session->transport;
1239 uint32_t share_capabilities;
1240 bool share_is_so;
1241 uint32_t server_capabilities;
1242 struct smb2_lease ls1, ls2;
1243 uint64_t lease_key;
1245 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
1246 torture_skip(tctx, "SMB 3.X Dialect family required for "
1247 "replay tests\n");
1250 server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
1251 if (!(server_capabilities & SMB2_CAP_LEASING)) {
1252 torture_skip(tctx, "leases are not supported");
1255 share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
1256 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
1258 torture_reset_break_info(tctx, &break_info);
1259 tree->session->transport->oplock.handler = torture_oplock_ack_handler;
1260 tree->session->transport->oplock.private_data = tree;
1262 torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
1263 "on Single Channel\n");
1264 smb2_util_unlink(tree, fname);
1265 status = torture_smb2_testdir(tree, BASEDIR, &_h1);
1266 CHECK_STATUS(status, NT_STATUS_OK);
1267 smb2_util_close(tree, _h1);
1268 CHECK_VAL(break_info.count, 0);
1270 lease_key = random();
1272 smb2_lease_create(&io1, &ls1, false /* dir */, fname,
1273 lease_key, smb2_util_lease_state("RH"));
1274 io1.in.durable_open = false;
1275 io1.in.durable_open_v2 = true;
1276 io1.in.persistent_open = false;
1277 io1.in.create_guid = create_guid;
1278 io1.in.timeout = UINT32_MAX;
1280 status = smb2_create(tree, mem_ctx, &io1);
1281 CHECK_STATUS(status, NT_STATUS_OK);
1282 ref1 = io1;
1283 _h1 = io1.out.file.handle;
1284 h1 = &_h1;
1285 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1286 CHECK_VAL(io1.out.durable_open, false);
1287 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1288 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
1289 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
1290 if (share_is_so) {
1291 CHECK_VAL(io1.out.lease_response.lease_state,
1292 smb2_util_lease_state("R"));
1293 CHECK_VAL(io1.out.durable_open_v2, false);
1294 CHECK_VAL(io1.out.timeout, 0);
1295 } else {
1296 CHECK_VAL(io1.out.lease_response.lease_state,
1297 smb2_util_lease_state("RH"));
1298 CHECK_VAL(io1.out.durable_open_v2, true);
1299 CHECK_VAL(io1.out.timeout, 300*1000);
1303 * Upgrade the lease to RWH
1305 smb2_lease_create(&io2, &ls2, false /* dir */, fname,
1306 lease_key, smb2_util_lease_state("RHW"));
1307 io2.in.durable_open = false;
1308 io2.in.durable_open_v2 = true;
1309 io2.in.persistent_open = false;
1310 io2.in.create_guid = GUID_random(); /* new guid... */
1311 io2.in.timeout = UINT32_MAX;
1313 status = smb2_create(tree, mem_ctx, &io2);
1314 CHECK_STATUS(status, NT_STATUS_OK);
1315 _h2 = io2.out.file.handle;
1316 h2 = &_h2;
1319 * Replay Durable V2 Create on single channel.
1320 * We get the io from open #1 but with the
1321 * upgraded lease.
1324 smb2_oplock_create_share(&io2, fname,
1325 smb2_util_share_access(""),
1326 smb2_util_oplock_level("b"));
1327 io2.in.durable_open = false;
1328 io2.in.durable_open_v2 = true;
1329 io2.in.persistent_open = false;
1330 io2.in.create_guid = create_guid;
1331 io2.in.timeout = UINT32_MAX;
1333 /* adapt expected lease in response */
1334 if (!share_is_so) {
1335 ref1.out.lease_response.lease_state =
1336 smb2_util_lease_state("RHW");
1339 smb2cli_session_start_replay(tree->session->smbXcli);
1340 status = smb2_create(tree, mem_ctx, &io1);
1341 smb2cli_session_stop_replay(tree->session->smbXcli);
1342 CHECK_STATUS(status, NT_STATUS_OK);
1343 CHECK_CREATE_OUT(&io1, &ref1);
1344 CHECK_VAL(break_info.count, 0);
1346 done:
1347 smb2cli_session_stop_replay(tree->session->smbXcli);
1349 if (h1 != NULL) {
1350 smb2_util_close(tree, *h1);
1352 if (h2 != NULL) {
1353 smb2_util_close(tree, *h2);
1355 smb2_deltree(tree, BASEDIR);
1357 talloc_free(tree);
1358 talloc_free(mem_ctx);
1360 return ret;
1364 * This tests replay with a pending open on a single
1365 * channel. It tests the case where the client2 open
1366 * is deferred because it conflicts with a HANDLE lease,
1367 * which is broken because the operation should otherwise
1368 * return NT_STATUS_SHARING_VIOLATION.
1370 * With a durablev2 request containing a create_guid:
1371 * - client2_level = NONE:
1372 * but without asking for an oplock nor a lease.
1373 * - client2_level = BATCH:
1374 * and asking for a batch oplock.
1375 * - client2_level = LEASE
1376 * and asking for an RWH lease.
1378 * While another client holds a batch oplock or
1379 * RWH lease. (client1_level => LEASE or BATCH).
1381 * There are two modes of this test one, with releaseing
1382 * the oplock/lease of client1 via close or ack.
1383 * (release_op SMB2_OP_CLOSE/SMB2_OP_BREAK).
1385 * Windows doesn't detect replays in this case and
1386 * always result in NT_STATUS_SHARING_VIOLATION.
1388 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
1390 static bool _test_dhv2_pending1_vs_violation(struct torture_context *tctx,
1391 const char *testname,
1392 struct smb2_tree *tree1,
1393 uint8_t client1_level,
1394 uint8_t release_op,
1395 struct smb2_tree *tree2,
1396 uint8_t client2_level,
1397 NTSTATUS orig21_reject_status,
1398 NTSTATUS replay22_reject_status,
1399 NTSTATUS replay23_reject_status)
1401 NTSTATUS status;
1402 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1403 struct smb2_handle _h1;
1404 struct smb2_handle *h1 = NULL;
1405 struct smb2_handle *h2f = NULL;
1406 struct smb2_handle _h21;
1407 struct smb2_handle *h21 = NULL;
1408 struct smb2_handle _h23;
1409 struct smb2_handle *h23 = NULL;
1410 struct smb2_handle _h24;
1411 struct smb2_handle *h24 = NULL;
1412 struct smb2_create io1, io21, io22, io23, io24;
1413 struct GUID create_guid1 = GUID_random();
1414 struct GUID create_guid2 = GUID_random();
1415 struct smb2_request *req21 = NULL;
1416 struct smb2_request *req22 = NULL;
1417 bool ret = true;
1418 char fname[256];
1419 struct smb2_transport *transport1 = tree1->session->transport;
1420 uint32_t server_capabilities;
1421 uint32_t share_capabilities;
1422 struct smb2_lease ls1;
1423 uint64_t lease_key1;
1424 uint16_t lease_epoch1 = 0;
1425 struct smb2_break op_ack1;
1426 struct smb2_lease_break_ack lb_ack1;
1427 struct smb2_lease ls2;
1428 uint64_t lease_key2;
1429 uint16_t lease_epoch2 = 0;
1430 bool share_is_so;
1431 struct smb2_transport *transport2 = tree2->session->transport;
1432 int request_timeout2 = transport2->options.request_timeout;
1433 struct smb2_session *session2 = tree2->session;
1434 const char *hold_name = NULL;
1436 switch (client1_level) {
1437 case SMB2_OPLOCK_LEVEL_LEASE:
1438 hold_name = "RWH Lease";
1439 break;
1440 case SMB2_OPLOCK_LEVEL_BATCH:
1441 hold_name = "BATCH Oplock";
1442 break;
1443 default:
1444 smb_panic(__location__);
1445 break;
1448 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
1449 torture_skip(tctx, "SMB 3.X Dialect family required for "
1450 "replay tests\n");
1453 server_capabilities = smb2cli_conn_server_capabilities(transport1->conn);
1454 if (!(server_capabilities & SMB2_CAP_LEASING)) {
1455 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE ||
1456 client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
1457 torture_skip(tctx, "leases are not supported");
1461 share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
1462 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
1463 if (share_is_so) {
1464 torture_skip(tctx, talloc_asprintf(tctx,
1465 "%s not supported on SCALEOUT share",
1466 hold_name));
1469 /* Add some random component to the file name. */
1470 snprintf(fname, sizeof(fname), "%s\\%s_%s.dat",
1471 BASEDIR, testname, generate_random_str(tctx, 8));
1473 torture_reset_break_info(tctx, &break_info);
1474 break_info.oplock_skip_ack = true;
1475 ZERO_STRUCT(op_ack1);
1476 torture_reset_lease_break_info(tctx, &lease_break_info);
1477 lease_break_info.lease_skip_ack = true;
1478 ZERO_STRUCT(lb_ack1);
1479 transport1->oplock.handler = torture_oplock_ack_handler;
1480 transport1->oplock.private_data = tree1;
1481 transport1->lease.handler = torture_lease_handler;
1482 transport1->lease.private_data = tree1;
1483 smb2_keepalive(transport1);
1484 transport2->oplock.handler = torture_oplock_ack_handler;
1485 transport2->oplock.private_data = tree2;
1486 transport2->lease.handler = torture_lease_handler;
1487 transport2->lease.private_data = tree2;
1488 smb2_keepalive(transport2);
1490 smb2_util_unlink(tree1, fname);
1491 status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
1492 CHECK_STATUS(status, NT_STATUS_OK);
1493 smb2_util_close(tree1, _h1);
1494 CHECK_VAL(break_info.count, 0);
1496 lease_key1 = random();
1497 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
1498 smb2_lease_v2_create(&io1, &ls1, false /* dir */, fname,
1499 lease_key1, NULL, smb2_util_lease_state("RWH"), lease_epoch1++);
1500 } else {
1501 smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
1503 io1.in.share_access = 0;
1504 io1.in.desired_access = SEC_RIGHTS_FILE_ALL;
1505 io1.in.durable_open = false;
1506 io1.in.durable_open_v2 = true;
1507 io1.in.persistent_open = false;
1508 io1.in.create_guid = create_guid1;
1509 io1.in.timeout = UINT32_MAX;
1511 status = smb2_create(tree1, mem_ctx, &io1);
1512 CHECK_STATUS(status, NT_STATUS_OK);
1513 _h1 = io1.out.file.handle;
1514 h1 = &_h1;
1515 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1516 CHECK_VAL(io1.out.durable_open, false);
1517 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
1518 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1519 CHECK_VAL(io1.out.lease_response_v2.lease_key.data[0], lease_key1);
1520 CHECK_VAL(io1.out.lease_response_v2.lease_key.data[1], ~lease_key1);
1521 CHECK_VAL(io1.out.lease_response_v2.lease_epoch, lease_epoch1);
1522 CHECK_VAL(io1.out.lease_response_v2.lease_state,
1523 smb2_util_lease_state("RWH"));
1524 } else {
1525 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1527 CHECK_VAL(io1.out.durable_open_v2, true);
1528 CHECK_VAL(io1.out.timeout, 300*1000);
1530 lease_key2 = random();
1531 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
1532 smb2_lease_v2_create(&io21, &ls2, false /* dir */, fname,
1533 lease_key2, NULL, smb2_util_lease_state("RWH"), lease_epoch2++);
1534 } else {
1535 smb2_oplock_create(&io21, fname, client2_level);
1537 io21.in.share_access = 0;
1538 io21.in.desired_access = SEC_RIGHTS_FILE_ALL;
1539 io21.in.desired_access = SEC_RIGHTS_FILE_READ;
1540 io21.in.durable_open = false;
1541 io21.in.durable_open_v2 = true;
1542 io21.in.persistent_open = false;
1543 io21.in.create_guid = create_guid2;
1544 io21.in.timeout = UINT32_MAX;
1545 io24 = io23 = io22 = io21;
1547 req21 = smb2_create_send(tree2, &io21);
1548 torture_assert(tctx, req21 != NULL, "req21");
1550 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
1551 const struct smb2_lease_break *lb =
1552 &lease_break_info.lease_break;
1553 const struct smb2_lease *l = &lb->current_lease;
1554 const struct smb2_lease_key *k = &l->lease_key;
1556 torture_wait_for_lease_break(tctx);
1557 CHECK_VAL(break_info.count, 0);
1558 CHECK_VAL(lease_break_info.count, 1);
1560 torture_assert(tctx,
1561 lease_break_info.lease_transport == transport1,
1562 "expect lease break on transport1\n");
1563 CHECK_VAL(k->data[0], lease_key1);
1564 CHECK_VAL(k->data[1], ~lease_key1);
1566 * With share none the handle lease
1567 * is broken.
1569 CHECK_VAL(lb->new_lease_state,
1570 smb2_util_lease_state("RW"));
1571 CHECK_VAL(lb->break_flags,
1572 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
1573 CHECK_VAL(lb->new_epoch, lease_epoch1+1);
1574 lease_epoch1 += 1;
1576 lb_ack1.in.lease.lease_key = lb->current_lease.lease_key;
1577 lb_ack1.in.lease.lease_state = lb->new_lease_state;
1578 } else {
1579 torture_wait_for_oplock_break(tctx);
1580 CHECK_VAL(break_info.count, 1);
1581 CHECK_VAL(lease_break_info.count, 0);
1583 torture_assert(tctx,
1584 break_info.received_transport == transport1,
1585 "expect oplock break on transport1\n");
1586 CHECK_VAL(break_info.handle.data[0], _h1.data[0]);
1587 CHECK_VAL(break_info.handle.data[1], _h1.data[1]);
1588 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1590 op_ack1.in = break_info.br.in;
1593 torture_reset_break_info(tctx, &break_info);
1594 break_info.oplock_skip_ack = true;
1595 torture_reset_lease_break_info(tctx, &lease_break_info);
1596 lease_break_info.lease_skip_ack = true;
1598 WAIT_FOR_ASYNC_RESPONSE(tctx, req21);
1600 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
1601 torture_wait_for_lease_break(tctx);
1602 } else {
1603 torture_wait_for_oplock_break(tctx);
1605 CHECK_VAL(break_info.count, 0);
1606 CHECK_VAL(lease_break_info.count, 0);
1608 if (NT_STATUS_EQUAL(replay22_reject_status, NT_STATUS_SHARING_VIOLATION)) {
1610 * The server is broken and doesn't
1611 * detect a replay, so we start an async
1612 * request and send a lease break ack
1613 * after 5 seconds in order to avoid
1614 * the 35 second delay.
1616 torture_comment(tctx, "Starting ASYNC Replay req22 expecting %s\n",
1617 nt_errstr(replay22_reject_status));
1618 smb2cli_session_start_replay(session2->smbXcli);
1619 transport2->options.request_timeout = 15;
1620 req22 = smb2_create_send(tree2, &io22);
1621 torture_assert(tctx, req22 != NULL, "req22");
1622 transport2->options.request_timeout = request_timeout2;
1623 smb2cli_session_stop_replay(session2->smbXcli);
1625 WAIT_FOR_ASYNC_RESPONSE(tctx, req22);
1626 } else {
1627 torture_comment(tctx, "SYNC Replay io22 expecting %s\n",
1628 nt_errstr(replay22_reject_status));
1629 smb2cli_session_start_replay(session2->smbXcli);
1630 transport2->options.request_timeout = 5;
1631 status = smb2_create(tree2, tctx, &io22);
1632 CHECK_STATUS(status, replay22_reject_status);
1633 transport2->options.request_timeout = request_timeout2;
1634 smb2cli_session_stop_replay(session2->smbXcli);
1638 * We don't expect any action for 35 seconds
1640 * But we sleep just 5 seconds before we
1641 * ack the break.
1643 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
1644 torture_wait_for_lease_break(tctx);
1645 torture_wait_for_lease_break(tctx);
1646 torture_wait_for_lease_break(tctx);
1647 torture_wait_for_lease_break(tctx);
1648 torture_wait_for_lease_break(tctx);
1649 CHECK_VAL(break_info.count, 0);
1650 CHECK_VAL(lease_break_info.count, 0);
1652 if (release_op == SMB2_OP_CLOSE) {
1653 torture_comment(tctx, "Closing h1\n");
1654 smb2_util_close(tree1, _h1);
1655 h1 = NULL;
1656 } else {
1657 torture_comment(tctx, "Acking lease_key1\n");
1658 status = smb2_lease_break_ack(tree1, &lb_ack1);
1659 CHECK_STATUS(status, NT_STATUS_OK);
1660 CHECK_VAL(lb_ack1.out.lease.lease_flags, 0);
1661 CHECK_VAL(lb_ack1.out.lease.lease_state, lb_ack1.in.lease.lease_state);
1662 CHECK_VAL(lb_ack1.out.lease.lease_key.data[0], lease_key1);
1663 CHECK_VAL(lb_ack1.out.lease.lease_key.data[1], ~lease_key1);
1664 CHECK_VAL(lb_ack1.out.lease.lease_duration, 0);
1666 } else {
1667 torture_wait_for_oplock_break(tctx);
1668 torture_wait_for_oplock_break(tctx);
1669 torture_wait_for_oplock_break(tctx);
1670 torture_wait_for_oplock_break(tctx);
1671 torture_wait_for_oplock_break(tctx);
1672 CHECK_VAL(break_info.count, 0);
1673 CHECK_VAL(lease_break_info.count, 0);
1675 if (release_op == SMB2_OP_CLOSE) {
1676 torture_comment(tctx, "Closing h1\n");
1677 smb2_util_close(tree1, _h1);
1678 h1 = NULL;
1679 } else {
1680 torture_comment(tctx, "Acking break h1\n");
1681 status = smb2_break(tree1, &op_ack1);
1682 CHECK_STATUS(status, NT_STATUS_OK);
1683 CHECK_VAL(op_ack1.out.oplock_level, op_ack1.in.oplock_level);
1687 torture_comment(tctx, "Checking req21 expecting %s\n",
1688 nt_errstr(orig21_reject_status));
1689 status = smb2_create_recv(req21, tctx, &io21);
1690 CHECK_STATUS(status, orig21_reject_status);
1691 if (NT_STATUS_IS_OK(orig21_reject_status)) {
1692 _h21 = io21.out.file.handle;
1693 h21 = &_h21;
1694 if (h2f == NULL) {
1695 h2f = h21;
1697 CHECK_VAL(h21->data[0], h2f->data[0]);
1698 CHECK_VAL(h21->data[1], h2f->data[1]);
1699 CHECK_CREATED(&io21, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1700 CHECK_VAL(io21.out.oplock_level, client2_level);
1701 CHECK_VAL(io21.out.durable_open, false);
1702 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
1703 CHECK_VAL(io21.out.lease_response_v2.lease_key.data[0], lease_key2);
1704 CHECK_VAL(io21.out.lease_response_v2.lease_key.data[1], ~lease_key2);
1705 CHECK_VAL(io21.out.lease_response_v2.lease_epoch, lease_epoch2);
1706 CHECK_VAL(io21.out.lease_response_v2.lease_state,
1707 smb2_util_lease_state("RHW"));
1708 CHECK_VAL(io21.out.durable_open_v2, true);
1709 CHECK_VAL(io21.out.timeout, 300*1000);
1710 } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
1711 CHECK_VAL(io21.out.durable_open_v2, true);
1712 CHECK_VAL(io21.out.timeout, 300*1000);
1713 } else {
1714 CHECK_VAL(io21.out.durable_open_v2, false);
1718 if (NT_STATUS_EQUAL(replay22_reject_status, NT_STATUS_SHARING_VIOLATION)) {
1719 torture_comment(tctx, "Checking req22 expecting %s\n",
1720 nt_errstr(replay22_reject_status));
1721 status = smb2_create_recv(req22, tctx, &io22);
1722 CHECK_STATUS(status, replay22_reject_status);
1725 torture_comment(tctx, "SYNC Replay io23 expecting %s\n",
1726 nt_errstr(replay23_reject_status));
1727 smb2cli_session_start_replay(session2->smbXcli);
1728 transport2->options.request_timeout = 5;
1729 status = smb2_create(tree2, tctx, &io23);
1730 transport2->options.request_timeout = request_timeout2;
1731 CHECK_STATUS(status, replay23_reject_status);
1732 smb2cli_session_stop_replay(session2->smbXcli);
1733 if (NT_STATUS_IS_OK(replay23_reject_status)) {
1734 _h23 = io23.out.file.handle;
1735 h23 = &_h23;
1736 if (h2f == NULL) {
1737 h2f = h23;
1739 CHECK_VAL(h23->data[0], h2f->data[0]);
1740 CHECK_VAL(h23->data[1], h2f->data[1]);
1741 CHECK_CREATED(&io23, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1742 CHECK_VAL(io23.out.oplock_level, client2_level);
1743 CHECK_VAL(io23.out.durable_open, false);
1744 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
1745 CHECK_VAL(io23.out.lease_response_v2.lease_key.data[0], lease_key2);
1746 CHECK_VAL(io23.out.lease_response_v2.lease_key.data[1], ~lease_key2);
1747 CHECK_VAL(io23.out.lease_response_v2.lease_epoch, lease_epoch2);
1748 CHECK_VAL(io23.out.lease_response_v2.lease_state,
1749 smb2_util_lease_state("RHW"));
1750 CHECK_VAL(io23.out.durable_open_v2, true);
1751 CHECK_VAL(io23.out.timeout, 300*1000);
1752 } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
1753 CHECK_VAL(io23.out.durable_open_v2, true);
1754 CHECK_VAL(io23.out.timeout, 300*1000);
1755 } else {
1756 CHECK_VAL(io23.out.durable_open_v2, false);
1760 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
1761 torture_wait_for_lease_break(tctx);
1762 } else {
1763 torture_wait_for_oplock_break(tctx);
1765 CHECK_VAL(break_info.count, 0);
1766 CHECK_VAL(lease_break_info.count, 0);
1768 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
1769 torture_wait_for_lease_break(tctx);
1770 } else {
1771 torture_wait_for_oplock_break(tctx);
1773 CHECK_VAL(break_info.count, 0);
1774 CHECK_VAL(lease_break_info.count, 0);
1776 if (h1 != NULL) {
1777 torture_comment(tctx, "Closing h1\n");
1778 smb2_util_close(tree1, _h1);
1779 h1 = NULL;
1782 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
1783 torture_wait_for_lease_break(tctx);
1784 } else {
1785 torture_wait_for_oplock_break(tctx);
1787 CHECK_VAL(break_info.count, 0);
1788 CHECK_VAL(lease_break_info.count, 0);
1790 torture_comment(tctx, "SYNC Replay io24 expecting %s\n",
1791 nt_errstr(NT_STATUS_OK));
1792 smb2cli_session_start_replay(session2->smbXcli);
1793 transport2->options.request_timeout = 5;
1794 status = smb2_create(tree2, tctx, &io24);
1795 transport2->options.request_timeout = request_timeout2;
1796 smb2cli_session_stop_replay(session2->smbXcli);
1797 CHECK_STATUS(status, NT_STATUS_OK);
1798 _h24 = io24.out.file.handle;
1799 h24 = &_h24;
1800 if (h2f == NULL) {
1801 h2f = h24;
1803 CHECK_VAL(h24->data[0], h2f->data[0]);
1804 CHECK_VAL(h24->data[1], h2f->data[1]);
1805 CHECK_CREATED(&io24, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1806 CHECK_VAL(io24.out.oplock_level, client2_level);
1807 CHECK_VAL(io24.out.durable_open, false);
1808 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
1809 CHECK_VAL(io24.out.lease_response_v2.lease_key.data[0], lease_key2);
1810 CHECK_VAL(io24.out.lease_response_v2.lease_key.data[1], ~lease_key2);
1811 CHECK_VAL(io24.out.lease_response_v2.lease_epoch, lease_epoch2);
1812 CHECK_VAL(io24.out.lease_response_v2.lease_state,
1813 smb2_util_lease_state("RHW"));
1814 CHECK_VAL(io24.out.durable_open_v2, true);
1815 CHECK_VAL(io24.out.timeout, 300*1000);
1816 } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
1817 CHECK_VAL(io24.out.durable_open_v2, true);
1818 CHECK_VAL(io24.out.timeout, 300*1000);
1819 } else {
1820 CHECK_VAL(io24.out.durable_open_v2, false);
1823 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
1824 torture_wait_for_lease_break(tctx);
1825 } else {
1826 torture_wait_for_oplock_break(tctx);
1828 CHECK_VAL(break_info.count, 0);
1829 CHECK_VAL(lease_break_info.count, 0);
1830 status = smb2_util_close(tree2, *h24);
1831 CHECK_STATUS(status, NT_STATUS_OK);
1832 h24 = NULL;
1834 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
1835 torture_wait_for_lease_break(tctx);
1836 } else {
1837 torture_wait_for_oplock_break(tctx);
1839 CHECK_VAL(break_info.count, 0);
1840 CHECK_VAL(lease_break_info.count, 0);
1842 done:
1844 smbXcli_conn_disconnect(transport2->conn, NT_STATUS_LOCAL_DISCONNECT);
1846 if (h1 != NULL) {
1847 smb2_util_close(tree1, *h1);
1850 smb2_deltree(tree1, BASEDIR);
1852 TALLOC_FREE(tree1);
1853 talloc_free(mem_ctx);
1855 return ret;
1859 * This tests replay with a pending open on a single
1860 * channel. It tests the case where the client2 open
1861 * is deferred because it conflicts with a HANDLE lease,
1862 * which is broken because the operation should otherwise
1863 * return NT_STATUS_SHARING_VIOLATION.
1865 * With a durablev2 request containing a create_guid,
1866 * but without asking for an oplock nor a lease.
1868 * While another client holds an RWH lease,
1869 * which is released by a close.
1871 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
1873 * This expects the sane reject status of
1874 * NT_STATUS_FILE_NOT_AVAILABLE.
1876 * It won't pass against Windows as it returns
1877 * NT_STATUS_SHARING_VIOLATION to the replay (after
1878 * 35 seconds), and this tests reports NT_STATUS_IO_TIMEOUT,
1879 * as it expectes a NT_STATUS_FILE_NOT_AVAILABLE within 5 seconds.
1880 * see test_dhv2_pending1n_vs_violation_lease_close_windows().
1882 static bool test_dhv2_pending1n_vs_violation_lease_close_sane(struct torture_context *tctx,
1883 struct smb2_tree *tree1,
1884 struct smb2_tree *tree2)
1886 return _test_dhv2_pending1_vs_violation(tctx, __func__,
1887 tree1,
1888 SMB2_OPLOCK_LEVEL_LEASE,
1889 SMB2_OP_CLOSE,
1890 tree2,
1891 SMB2_OPLOCK_LEVEL_NONE,
1892 NT_STATUS_OK,
1893 NT_STATUS_FILE_NOT_AVAILABLE,
1894 NT_STATUS_OK);
1898 * This tests replay with a pending open on a single
1899 * channel. It tests the case where the client2 open
1900 * is deferred because it conflicts with a HANDLE lease,
1901 * which is broken because the operation should otherwise
1902 * return NT_STATUS_SHARING_VIOLATION.
1904 * With a durablev2 request containing a create_guid,
1905 * but without asking for an oplock nor a lease.
1907 * While another client holds an RWH lease,
1908 * which is released by a close.
1910 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
1912 * This expects the strange behavior of ignoring the
1913 * replay, which is returned done by Windows Servers.
1915 * It won't pass against Samba as it returns
1916 * NT_STATUS_FILE_NOT_AVAILABLE
1917 * see test_dhv2_pending1n_vs_violation_lease_close_sane().
1919 static bool test_dhv2_pending1n_vs_violation_lease_close_windows(struct torture_context *tctx,
1920 struct smb2_tree *tree1,
1921 struct smb2_tree *tree2)
1923 return _test_dhv2_pending1_vs_violation(tctx, __func__,
1924 tree1,
1925 SMB2_OPLOCK_LEVEL_LEASE,
1926 SMB2_OP_CLOSE,
1927 tree2,
1928 SMB2_OPLOCK_LEVEL_NONE,
1929 NT_STATUS_OK,
1930 NT_STATUS_SHARING_VIOLATION,
1931 NT_STATUS_OK);
1935 * This tests replay with a pending open on a single
1936 * channel. It tests the case where the client2 open
1937 * is deferred because it conflicts with a HANDLE lease,
1938 * which is broken because the operation should otherwise
1939 * return NT_STATUS_SHARING_VIOLATION.
1941 * With a durablev2 request containing a create_guid,
1942 * but without asking for an oplock nor a lease.
1944 * While another client holds an RWH lease,
1945 * which is released by a lease break ack.
1947 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
1949 * This expects the sane reject status of
1950 * NT_STATUS_FILE_NOT_AVAILABLE.
1952 * It won't pass against Windows as it returns
1953 * NT_STATUS_SHARING_VIOLATION to the replay (after
1954 * 35 seconds), and this tests reports NT_STATUS_IO_TIMEOUT,
1955 * as it expectes a NT_STATUS_FILE_NOT_AVAILABLE within 5 seconds.
1956 * see test_dhv2_pending1n_vs_violation_lease_ack_windows().
1958 static bool test_dhv2_pending1n_vs_violation_lease_ack_sane(struct torture_context *tctx,
1959 struct smb2_tree *tree1,
1960 struct smb2_tree *tree2)
1962 return _test_dhv2_pending1_vs_violation(tctx, __func__,
1963 tree1,
1964 SMB2_OPLOCK_LEVEL_LEASE,
1965 SMB2_OP_BREAK,
1966 tree2,
1967 SMB2_OPLOCK_LEVEL_NONE,
1968 NT_STATUS_SHARING_VIOLATION,
1969 NT_STATUS_FILE_NOT_AVAILABLE,
1970 NT_STATUS_SHARING_VIOLATION);
1974 * This tests replay with a pending open on a single
1975 * channel. It tests the case where the client2 open
1976 * is deferred because it conflicts with a HANDLE lease,
1977 * which is broken because the operation should otherwise
1978 * return NT_STATUS_SHARING_VIOLATION.
1980 * With a durablev2 request containing a create_guid,
1981 * but without asking for an oplock nor a lease.
1983 * While another client holds an RWH lease,
1984 * which is released by a close.
1986 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
1988 * This expects the strange behavior of ignoring the
1989 * replay, which is returned done by Windows Servers.
1991 * It won't pass against Samba as it returns
1992 * NT_STATUS_FILE_NOT_AVAILABLE
1993 * see test_dhv2_pending1n_vs_violation_lease_ack_sane().
1995 static bool test_dhv2_pending1n_vs_violation_lease_ack_windows(struct torture_context *tctx,
1996 struct smb2_tree *tree1,
1997 struct smb2_tree *tree2)
1999 return _test_dhv2_pending1_vs_violation(tctx, __func__,
2000 tree1,
2001 SMB2_OPLOCK_LEVEL_LEASE,
2002 SMB2_OP_BREAK,
2003 tree2,
2004 SMB2_OPLOCK_LEVEL_NONE,
2005 NT_STATUS_SHARING_VIOLATION,
2006 NT_STATUS_SHARING_VIOLATION,
2007 NT_STATUS_SHARING_VIOLATION);
2011 * This tests replay with a pending open on a single
2012 * channel.
2014 * With a durablev2 request containing a create_guid and
2015 * a share_access of READ/WRITE/DELETE:
2016 * - client2_level = NONE:
2017 * but without asking for an oplock nor a lease.
2018 * - client2_level = BATCH:
2019 * and asking for a batch oplock.
2020 * - client2_level = LEASE
2021 * and asking for an RWH lease.
2023 * While another client holds a batch oplock or
2024 * RWH lease. (client1_level => LEASE or BATCH).
2025 * And allows share_access of READ/WRITE/DELETE.
2027 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2029 static bool _test_dhv2_pending1_vs_hold(struct torture_context *tctx,
2030 const char *testname,
2031 uint8_t client1_level,
2032 uint8_t client2_level,
2033 NTSTATUS reject_status,
2034 struct smb2_tree *tree1,
2035 struct smb2_tree *tree2)
2037 NTSTATUS status;
2038 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2039 struct smb2_handle _h1;
2040 struct smb2_handle *h1 = NULL;
2041 struct smb2_handle _h21;
2042 struct smb2_handle *h21 = NULL;
2043 struct smb2_handle _h24;
2044 struct smb2_handle *h24 = NULL;
2045 struct smb2_create io1, io21, io22, io23, io24;
2046 struct GUID create_guid1 = GUID_random();
2047 struct GUID create_guid2 = GUID_random();
2048 struct smb2_request *req21 = NULL;
2049 bool ret = true;
2050 char fname[256];
2051 struct smb2_transport *transport1 = tree1->session->transport;
2052 uint32_t server_capabilities;
2053 uint32_t share_capabilities;
2054 struct smb2_lease ls1;
2055 uint64_t lease_key1;
2056 uint16_t lease_epoch1 = 0;
2057 struct smb2_lease ls2;
2058 uint64_t lease_key2;
2059 uint16_t lease_epoch2 = 0;
2060 bool share_is_so;
2061 struct smb2_transport *transport2 = tree2->session->transport;
2062 int request_timeout2 = transport2->options.request_timeout;
2063 struct smb2_session *session2 = tree2->session;
2064 const char *hold_name = NULL;
2066 switch (client1_level) {
2067 case SMB2_OPLOCK_LEVEL_LEASE:
2068 hold_name = "RWH Lease";
2069 break;
2070 case SMB2_OPLOCK_LEVEL_BATCH:
2071 hold_name = "BATCH Oplock";
2072 break;
2073 default:
2074 smb_panic(__location__);
2075 break;
2078 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
2079 torture_skip(tctx, "SMB 3.X Dialect family required for "
2080 "replay tests\n");
2083 server_capabilities = smb2cli_conn_server_capabilities(transport1->conn);
2084 if (!(server_capabilities & SMB2_CAP_LEASING)) {
2085 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE ||
2086 client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
2087 torture_skip(tctx, "leases are not supported");
2091 share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
2092 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
2093 if (share_is_so) {
2094 torture_skip(tctx, talloc_asprintf(tctx,
2095 "%s not supported on SCALEOUT share",
2096 hold_name));
2099 /* Add some random component to the file name. */
2100 snprintf(fname, sizeof(fname), "%s\\%s_%s.dat",
2101 BASEDIR, testname, generate_random_str(tctx, 8));
2103 torture_reset_break_info(tctx, &break_info);
2104 break_info.oplock_skip_ack = true;
2105 torture_reset_lease_break_info(tctx, &lease_break_info);
2106 lease_break_info.lease_skip_ack = true;
2107 transport1->oplock.handler = torture_oplock_ack_handler;
2108 transport1->oplock.private_data = tree1;
2109 transport1->lease.handler = torture_lease_handler;
2110 transport1->lease.private_data = tree1;
2111 smb2_keepalive(transport1);
2112 transport2->oplock.handler = torture_oplock_ack_handler;
2113 transport2->oplock.private_data = tree2;
2114 transport2->lease.handler = torture_lease_handler;
2115 transport2->lease.private_data = tree2;
2116 smb2_keepalive(transport2);
2118 smb2_util_unlink(tree1, fname);
2119 status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
2120 CHECK_STATUS(status, NT_STATUS_OK);
2121 smb2_util_close(tree1, _h1);
2122 CHECK_VAL(break_info.count, 0);
2124 lease_key1 = random();
2125 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
2126 smb2_lease_v2_create(&io1, &ls1, false /* dir */, fname,
2127 lease_key1, NULL, smb2_util_lease_state("RWH"), lease_epoch1++);
2128 } else {
2129 smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
2131 io1.in.share_access = smb2_util_share_access("RWD");
2132 io1.in.durable_open = false;
2133 io1.in.durable_open_v2 = true;
2134 io1.in.persistent_open = false;
2135 io1.in.create_guid = create_guid1;
2136 io1.in.timeout = UINT32_MAX;
2138 status = smb2_create(tree1, mem_ctx, &io1);
2139 CHECK_STATUS(status, NT_STATUS_OK);
2140 _h1 = io1.out.file.handle;
2141 h1 = &_h1;
2142 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2143 CHECK_VAL(io1.out.durable_open, false);
2144 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
2145 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
2146 CHECK_VAL(io1.out.lease_response_v2.lease_key.data[0], lease_key1);
2147 CHECK_VAL(io1.out.lease_response_v2.lease_key.data[1], ~lease_key1);
2148 CHECK_VAL(io1.out.lease_response_v2.lease_epoch, lease_epoch1);
2149 CHECK_VAL(io1.out.lease_response_v2.lease_state,
2150 smb2_util_lease_state("RHW"));
2151 } else {
2152 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2154 CHECK_VAL(io1.out.durable_open_v2, true);
2155 CHECK_VAL(io1.out.timeout, 300*1000);
2157 lease_key2 = random();
2158 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
2159 smb2_lease_v2_create(&io21, &ls2, false /* dir */, fname,
2160 lease_key2, NULL, smb2_util_lease_state("RWH"), lease_epoch2++);
2161 } else {
2162 smb2_oplock_create(&io21, fname, client2_level);
2164 io21.in.share_access = smb2_util_share_access("RWD");
2165 io21.in.durable_open = false;
2166 io21.in.durable_open_v2 = true;
2167 io21.in.persistent_open = false;
2168 io21.in.create_guid = create_guid2;
2169 io21.in.timeout = UINT32_MAX;
2170 io24 = io23 = io22 = io21;
2172 req21 = smb2_create_send(tree2, &io21);
2173 torture_assert(tctx, req21 != NULL, "req21");
2175 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
2176 const struct smb2_lease_break *lb =
2177 &lease_break_info.lease_break;
2178 const struct smb2_lease *l = &lb->current_lease;
2179 const struct smb2_lease_key *k = &l->lease_key;
2181 torture_wait_for_lease_break(tctx);
2182 CHECK_VAL(break_info.count, 0);
2183 CHECK_VAL(lease_break_info.count, 1);
2185 torture_assert(tctx,
2186 lease_break_info.lease_transport == transport1,
2187 "expect lease break on transport1\n");
2188 CHECK_VAL(k->data[0], lease_key1);
2189 CHECK_VAL(k->data[1], ~lease_key1);
2190 CHECK_VAL(lb->new_lease_state,
2191 smb2_util_lease_state("RH"));
2192 CHECK_VAL(lb->break_flags,
2193 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
2194 CHECK_VAL(lb->new_epoch, lease_epoch1+1);
2195 lease_epoch1 += 1;
2196 } else {
2197 torture_wait_for_oplock_break(tctx);
2198 CHECK_VAL(break_info.count, 1);
2199 CHECK_VAL(lease_break_info.count, 0);
2201 torture_assert(tctx,
2202 break_info.received_transport == transport1,
2203 "expect oplock break on transport1\n");
2204 CHECK_VAL(break_info.handle.data[0], _h1.data[0]);
2205 CHECK_VAL(break_info.handle.data[1], _h1.data[1]);
2206 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2209 torture_reset_break_info(tctx, &break_info);
2210 break_info.oplock_skip_ack = true;
2211 torture_reset_lease_break_info(tctx, &lease_break_info);
2212 lease_break_info.lease_skip_ack = true;
2214 WAIT_FOR_ASYNC_RESPONSE(tctx, req21);
2216 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
2217 torture_wait_for_lease_break(tctx);
2218 } else {
2219 torture_wait_for_oplock_break(tctx);
2221 CHECK_VAL(break_info.count, 0);
2222 CHECK_VAL(lease_break_info.count, 0);
2224 smb2cli_session_start_replay(session2->smbXcli);
2225 transport2->options.request_timeout = 5;
2226 status = smb2_create(tree2, tctx, &io22);
2227 transport2->options.request_timeout = request_timeout2;
2228 CHECK_STATUS(status, reject_status);
2229 smb2cli_session_stop_replay(session2->smbXcli);
2231 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
2232 torture_wait_for_lease_break(tctx);
2233 } else {
2234 torture_wait_for_oplock_break(tctx);
2236 CHECK_VAL(break_info.count, 0);
2237 CHECK_VAL(lease_break_info.count, 0);
2239 smb2cli_session_start_replay(session2->smbXcli);
2240 transport2->options.request_timeout = 5;
2241 status = smb2_create(tree2, tctx, &io23);
2242 transport2->options.request_timeout = request_timeout2;
2243 CHECK_STATUS(status, reject_status);
2244 smb2cli_session_stop_replay(session2->smbXcli);
2246 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
2247 torture_wait_for_lease_break(tctx);
2248 } else {
2249 torture_wait_for_oplock_break(tctx);
2251 CHECK_VAL(break_info.count, 0);
2252 CHECK_VAL(lease_break_info.count, 0);
2254 smb2_util_close(tree1, _h1);
2255 h1 = NULL;
2257 status = smb2_create_recv(req21, tctx, &io21);
2258 CHECK_STATUS(status, NT_STATUS_OK);
2259 _h21 = io21.out.file.handle;
2260 h21 = &_h21;
2261 CHECK_CREATED(&io21, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2262 CHECK_VAL(io21.out.oplock_level, client2_level);
2263 CHECK_VAL(io21.out.durable_open, false);
2264 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
2265 CHECK_VAL(io21.out.lease_response_v2.lease_key.data[0], lease_key2);
2266 CHECK_VAL(io21.out.lease_response_v2.lease_key.data[1], ~lease_key2);
2267 CHECK_VAL(io21.out.lease_response_v2.lease_epoch, lease_epoch2);
2268 CHECK_VAL(io21.out.lease_response_v2.lease_state,
2269 smb2_util_lease_state("RHW"));
2270 CHECK_VAL(io21.out.durable_open_v2, true);
2271 CHECK_VAL(io21.out.timeout, 300*1000);
2272 } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
2273 CHECK_VAL(io21.out.durable_open_v2, true);
2274 CHECK_VAL(io21.out.timeout, 300*1000);
2275 } else {
2276 CHECK_VAL(io21.out.durable_open_v2, false);
2279 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
2280 torture_wait_for_lease_break(tctx);
2281 } else {
2282 torture_wait_for_oplock_break(tctx);
2284 CHECK_VAL(break_info.count, 0);
2285 CHECK_VAL(lease_break_info.count, 0);
2287 smb2cli_session_start_replay(session2->smbXcli);
2288 status = smb2_create(tree2, tctx, &io24);
2289 smb2cli_session_stop_replay(session2->smbXcli);
2290 CHECK_STATUS(status, NT_STATUS_OK);
2291 _h24 = io24.out.file.handle;
2292 h24 = &_h24;
2293 CHECK_CREATED(&io24, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2294 CHECK_VAL(h24->data[0], h21->data[0]);
2295 CHECK_VAL(h24->data[1], h21->data[1]);
2296 CHECK_VAL(io24.out.oplock_level, client2_level);
2297 CHECK_VAL(io24.out.durable_open, false);
2298 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
2299 CHECK_VAL(io24.out.lease_response_v2.lease_key.data[0], lease_key2);
2300 CHECK_VAL(io24.out.lease_response_v2.lease_key.data[1], ~lease_key2);
2301 CHECK_VAL(io24.out.lease_response_v2.lease_epoch, lease_epoch2);
2302 CHECK_VAL(io24.out.lease_response_v2.lease_state,
2303 smb2_util_lease_state("RHW"));
2304 CHECK_VAL(io24.out.durable_open_v2, true);
2305 CHECK_VAL(io24.out.timeout, 300*1000);
2306 } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
2307 CHECK_VAL(io24.out.durable_open_v2, true);
2308 CHECK_VAL(io24.out.timeout, 300*1000);
2309 } else {
2310 CHECK_VAL(io24.out.durable_open_v2, false);
2313 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
2314 torture_wait_for_lease_break(tctx);
2315 } else {
2316 torture_wait_for_oplock_break(tctx);
2318 CHECK_VAL(break_info.count, 0);
2319 CHECK_VAL(lease_break_info.count, 0);
2320 status = smb2_util_close(tree2, *h24);
2321 CHECK_STATUS(status, NT_STATUS_OK);
2322 h24 = NULL;
2324 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
2325 torture_wait_for_lease_break(tctx);
2326 } else {
2327 torture_wait_for_oplock_break(tctx);
2329 CHECK_VAL(break_info.count, 0);
2330 CHECK_VAL(lease_break_info.count, 0);
2332 done:
2334 smbXcli_conn_disconnect(transport2->conn, NT_STATUS_LOCAL_DISCONNECT);
2336 if (h1 != NULL) {
2337 smb2_util_close(tree1, *h1);
2340 smb2_deltree(tree1, BASEDIR);
2342 TALLOC_FREE(tree1);
2343 talloc_free(mem_ctx);
2345 return ret;
2349 * This tests replay with a pending open on a single
2350 * channel.
2352 * With a durablev2 request containing a create_guid,
2353 * a share_access of READ/WRITE/DELETE,
2354 * but without asking for an oplock nor a lease.
2356 * While another client holds a batch oplock.
2357 * And allows share_access of READ/WRITE/DELETE.
2359 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2361 * This expects the sane reject status of
2362 * NT_STATUS_FILE_NOT_AVAILABLE.
2364 * It won't pass against Windows as it returns
2365 * NT_STATUS_ACCESS_DENIED see
2366 * test_dhv2_pending1n_vs_oplock_windows().
2368 static bool test_dhv2_pending1n_vs_oplock_sane(struct torture_context *tctx,
2369 struct smb2_tree *tree1,
2370 struct smb2_tree *tree2)
2372 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2373 SMB2_OPLOCK_LEVEL_BATCH,
2374 SMB2_OPLOCK_LEVEL_NONE,
2375 NT_STATUS_FILE_NOT_AVAILABLE,
2376 tree1, tree2);
2380 * This tests replay with a pending open on a single
2381 * channel.
2383 * With a durablev2 request containing a create_guid,
2384 * a share_access of READ/WRITE/DELETE,
2385 * but without asking for an oplock nor a lease.
2387 * While another client holds a batch oplock.
2388 * And allows share_access of READ/WRITE/DELETE.
2390 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2392 * This expects the strange reject status of
2393 * NT_STATUS_ACCESS_DENIED, which is returned
2394 * by Windows Servers.
2396 * It won't pass against Samba as it returns
2397 * NT_STATUS_FILE_NOT_AVAILABLE. see
2398 * test_dhv2_pending1n_vs_oplock_sane.
2400 static bool test_dhv2_pending1n_vs_oplock_windows(struct torture_context *tctx,
2401 struct smb2_tree *tree1,
2402 struct smb2_tree *tree2)
2404 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2405 SMB2_OPLOCK_LEVEL_BATCH,
2406 SMB2_OPLOCK_LEVEL_NONE,
2407 NT_STATUS_ACCESS_DENIED,
2408 tree1, tree2);
2412 * This tests replay with a pending open on a single
2413 * channel.
2415 * With a durablev2 request containing a create_guid,
2416 * a share_access of READ/WRITE/DELETE,
2417 * but without asking for an oplock nor a lease.
2419 * While another client holds an RWH lease.
2420 * And allows share_access of READ/WRITE/DELETE.
2422 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2424 * This expects the sane reject status of
2425 * NT_STATUS_FILE_NOT_AVAILABLE.
2427 * It won't pass against Windows as it returns
2428 * NT_STATUS_ACCESS_DENIED see
2429 * test_dhv2_pending1n_vs_lease_windows().
2431 static bool test_dhv2_pending1n_vs_lease_sane(struct torture_context *tctx,
2432 struct smb2_tree *tree1,
2433 struct smb2_tree *tree2)
2435 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2436 SMB2_OPLOCK_LEVEL_LEASE,
2437 SMB2_OPLOCK_LEVEL_NONE,
2438 NT_STATUS_FILE_NOT_AVAILABLE,
2439 tree1, tree2);
2443 * This tests replay with a pending open on a single
2444 * channel.
2446 * With a durablev2 request containing a create_guid,
2447 * a share_access of READ/WRITE/DELETE,
2448 * but without asking for an oplock nor a lease.
2450 * While another client holds an RWH lease.
2451 * And allows share_access of READ/WRITE/DELETE.
2453 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2455 * This expects the strange reject status of
2456 * NT_STATUS_ACCESS_DENIED, which is returned
2457 * by Windows Servers.
2459 * It won't pass against Samba as it returns
2460 * NT_STATUS_FILE_NOT_AVAILABLE. see
2461 * test_dhv2_pending1n_vs_lease_sane.
2463 static bool test_dhv2_pending1n_vs_lease_windows(struct torture_context *tctx,
2464 struct smb2_tree *tree1,
2465 struct smb2_tree *tree2)
2467 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2468 SMB2_OPLOCK_LEVEL_LEASE,
2469 SMB2_OPLOCK_LEVEL_NONE,
2470 NT_STATUS_ACCESS_DENIED,
2471 tree1, tree2);
2475 * This tests replay with a pending open on a single
2476 * channel.
2478 * With a durablev2 request containing a create_guid,
2479 * a share_access of READ/WRITE/DELETE,
2480 * and asking for a v2 lease.
2482 * While another client holds a batch oplock.
2483 * And allows share_access of READ/WRITE/DELETE.
2485 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2487 * This expects the sane reject status of
2488 * NT_STATUS_FILE_NOT_AVAILABLE.
2490 * It won't pass against Windows as it returns
2491 * NT_STATUS_ACCESS_DENIED see
2492 * test_dhv2_pending1l_vs_oplock_windows().
2494 static bool test_dhv2_pending1l_vs_oplock_sane(struct torture_context *tctx,
2495 struct smb2_tree *tree1,
2496 struct smb2_tree *tree2)
2498 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2499 SMB2_OPLOCK_LEVEL_BATCH,
2500 SMB2_OPLOCK_LEVEL_LEASE,
2501 NT_STATUS_FILE_NOT_AVAILABLE,
2502 tree1, tree2);
2506 * This tests replay with a pending open on a single
2507 * channel.
2509 * With a durablev2 request containing a create_guid,
2510 * a share_access of READ/WRITE/DELETE,
2511 * and asking for a v2 lease.
2513 * While another client holds a batch oplock.
2514 * And allows share_access of READ/WRITE/DELETE.
2516 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2518 * This expects the strange reject status of
2519 * NT_STATUS_ACCESS_DENIED, which is returned
2520 * by Windows Servers.
2522 * It won't pass against Samba as it returns
2523 * NT_STATUS_FILE_NOT_AVAILABLE. see
2524 * test_dhv2_pending1l_vs_oplock_sane.
2526 static bool test_dhv2_pending1l_vs_oplock_windows(struct torture_context *tctx,
2527 struct smb2_tree *tree1,
2528 struct smb2_tree *tree2)
2530 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2531 SMB2_OPLOCK_LEVEL_BATCH,
2532 SMB2_OPLOCK_LEVEL_LEASE,
2533 NT_STATUS_ACCESS_DENIED,
2534 tree1, tree2);
2538 * This tests replay with a pending open on a single
2539 * channel.
2541 * With a durablev2 request containing a create_guid,
2542 * a share_access of READ/WRITE/DELETE,
2543 * and asking for a v2 lease.
2545 * While another client holds an RWH lease.
2546 * And allows share_access of READ/WRITE/DELETE.
2548 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2550 * This expects the sane reject status of
2551 * NT_STATUS_FILE_NOT_AVAILABLE.
2553 * It won't pass against Windows as it returns
2554 * NT_STATUS_ACCESS_DENIED see
2555 * test_dhv2_pending1l_vs_lease_windows().
2557 static bool test_dhv2_pending1l_vs_lease_sane(struct torture_context *tctx,
2558 struct smb2_tree *tree1,
2559 struct smb2_tree *tree2)
2561 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2562 SMB2_OPLOCK_LEVEL_LEASE,
2563 SMB2_OPLOCK_LEVEL_LEASE,
2564 NT_STATUS_FILE_NOT_AVAILABLE,
2565 tree1, tree2);
2569 * This tests replay with a pending open on a single
2570 * channel.
2572 * With a durablev2 request containing a create_guid,
2573 * a share_access of READ/WRITE/DELETE,
2574 * and asking for a v2 lease.
2576 * While another client holds an RWH lease.
2577 * And allows share_access of READ/WRITE/DELETE.
2579 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2581 * This expects the strange reject status of
2582 * NT_STATUS_ACCESS_DENIED, which is returned
2583 * by Windows Servers.
2585 * It won't pass against Samba as it returns
2586 * NT_STATUS_FILE_NOT_AVAILABLE. see
2587 * test_dhv2_pending1l_vs_lease_sane.
2589 static bool test_dhv2_pending1l_vs_lease_windows(struct torture_context *tctx,
2590 struct smb2_tree *tree1,
2591 struct smb2_tree *tree2)
2593 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2594 SMB2_OPLOCK_LEVEL_LEASE,
2595 SMB2_OPLOCK_LEVEL_LEASE,
2596 NT_STATUS_ACCESS_DENIED,
2597 tree1, tree2);
2601 * This tests replay with a pending open on a single
2602 * channel.
2604 * With a durablev2 request containing a create_guid,
2605 * a share_access of READ/WRITE/DELETE,
2606 * and asking for a batch oplock.
2608 * While another client holds a batch oplock.
2609 * And allows share_access of READ/WRITE/DELETE.
2611 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2613 * This expects the sane reject status of
2614 * NT_STATUS_FILE_NOT_AVAILABLE.
2616 * It won't pass against Windows as it returns
2617 * NT_STATUS_ACCESS_DENIED see
2618 * test_dhv2_pending1o_vs_oplock_windows().
2620 static bool test_dhv2_pending1o_vs_oplock_sane(struct torture_context *tctx,
2621 struct smb2_tree *tree1,
2622 struct smb2_tree *tree2)
2624 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2625 SMB2_OPLOCK_LEVEL_BATCH,
2626 SMB2_OPLOCK_LEVEL_BATCH,
2627 NT_STATUS_FILE_NOT_AVAILABLE,
2628 tree1, tree2);
2632 * This tests replay with a pending open on a single
2633 * channel.
2635 * With a durablev2 request containing a create_guid,
2636 * a share_access of READ/WRITE/DELETE,
2637 * and asking for a batch oplock.
2639 * While another client holds a batch oplock.
2640 * And allows share_access of READ/WRITE/DELETE.
2642 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2644 * This expects the strange reject status of
2645 * NT_STATUS_ACCESS_DENIED, which is returned
2646 * by Windows Servers.
2648 * It won't pass against Samba as it returns
2649 * NT_STATUS_FILE_NOT_AVAILABLE. see
2650 * test_dhv2_pending1o_vs_oplock_sane.
2652 static bool test_dhv2_pending1o_vs_oplock_windows(struct torture_context *tctx,
2653 struct smb2_tree *tree1,
2654 struct smb2_tree *tree2)
2656 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2657 SMB2_OPLOCK_LEVEL_BATCH,
2658 SMB2_OPLOCK_LEVEL_BATCH,
2659 NT_STATUS_ACCESS_DENIED,
2660 tree1, tree2);
2664 * This tests replay with a pending open on a single
2665 * channel.
2667 * With a durablev2 request containing a create_guid,
2668 * a share_access of READ/WRITE/DELETE,
2669 * and asking for a batch oplock.
2671 * While another client holds an RWH lease.
2672 * And allows share_access of READ/WRITE/DELETE.
2674 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2676 * This expects the sane reject status of
2677 * NT_STATUS_FILE_NOT_AVAILABLE.
2679 * It won't pass against Windows as it returns
2680 * NT_STATUS_ACCESS_DENIED see
2681 * test_dhv2_pending1o_vs_lease_windows().
2683 static bool test_dhv2_pending1o_vs_lease_sane(struct torture_context *tctx,
2684 struct smb2_tree *tree1,
2685 struct smb2_tree *tree2_1)
2687 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2688 SMB2_OPLOCK_LEVEL_LEASE,
2689 SMB2_OPLOCK_LEVEL_BATCH,
2690 NT_STATUS_FILE_NOT_AVAILABLE,
2691 tree1, tree2_1);
2695 * This tests replay with a pending open on a single
2696 * channel.
2698 * With a durablev2 request containing a create_guid,
2699 * a share_access of READ/WRITE/DELETE,
2700 * and asking for a batch oplock.
2702 * While another client holds an RWH lease.
2703 * And allows share_access of READ/WRITE/DELETE.
2705 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2707 * This expects the strange reject status of
2708 * NT_STATUS_ACCESS_DENIED, which is returned
2709 * by Windows Servers.
2711 * It won't pass against Samba as it returns
2712 * NT_STATUS_FILE_NOT_AVAILABLE. see
2713 * test_dhv2_pending1o_vs_lease_sane.
2715 static bool test_dhv2_pending1o_vs_lease_windows(struct torture_context *tctx,
2716 struct smb2_tree *tree1,
2717 struct smb2_tree *tree2)
2719 return _test_dhv2_pending1_vs_hold(tctx, __func__,
2720 SMB2_OPLOCK_LEVEL_LEASE,
2721 SMB2_OPLOCK_LEVEL_BATCH,
2722 NT_STATUS_ACCESS_DENIED,
2723 tree1, tree2);
2727 * This tests replay with a pending open with 4 channels
2728 * and closed transports on the client and server side.
2730 * With a durablev2 request containing a create_guid and
2731 * a share_access of READ/WRITE/DELETE:
2732 * - client2_level = NONE:
2733 * but without asking for an oplock nor a lease.
2734 * - client2_level = BATCH:
2735 * and asking for a batch oplock.
2736 * - client2_level = LEASE
2737 * and asking for an RWH lease.
2739 * While another client holds a batch oplock or
2740 * RWH lease. (client1_level => LEASE or BATCH).
2741 * And allows share_access of READ/WRITE/DELETE.
2743 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
2745 static bool _test_dhv2_pending2_vs_hold(struct torture_context *tctx,
2746 const char *testname,
2747 uint8_t client1_level,
2748 uint8_t client2_level,
2749 NTSTATUS reject_status,
2750 struct smb2_tree *tree1,
2751 struct smb2_tree *tree2_1)
2753 const char *host = torture_setting_string(tctx, "host", NULL);
2754 const char *share = torture_setting_string(tctx, "share", NULL);
2755 struct cli_credentials *credentials = samba_cmdline_get_creds();
2756 NTSTATUS status;
2757 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2758 struct smb2_handle _h1;
2759 struct smb2_handle *h1 = NULL;
2760 struct smb2_handle _h24;
2761 struct smb2_handle *h24 = NULL;
2762 struct smb2_create io1, io21, io22, io23, io24;
2763 struct GUID create_guid1 = GUID_random();
2764 struct GUID create_guid2 = GUID_random();
2765 struct smb2_request *req21 = NULL;
2766 bool ret = true;
2767 char fname[256];
2768 struct smb2_transport *transport1 = tree1->session->transport;
2769 uint32_t server_capabilities;
2770 uint32_t share_capabilities;
2771 struct smb2_lease ls1;
2772 uint64_t lease_key1;
2773 uint16_t lease_epoch1 = 0;
2774 struct smb2_lease ls2;
2775 uint64_t lease_key2;
2776 uint16_t lease_epoch2 = 0;
2777 bool share_is_so;
2778 struct smb2_transport *transport2_1 = tree2_1->session->transport;
2779 int request_timeout2 = transport2_1->options.request_timeout;
2780 struct smbcli_options options2x;
2781 struct smb2_tree *tree2_2 = NULL;
2782 struct smb2_tree *tree2_3 = NULL;
2783 struct smb2_tree *tree2_4 = NULL;
2784 struct smb2_transport *transport2_2 = NULL;
2785 struct smb2_transport *transport2_3 = NULL;
2786 struct smb2_transport *transport2_4 = NULL;
2787 struct smb2_session *session2_1 = tree2_1->session;
2788 struct smb2_session *session2_2 = NULL;
2789 struct smb2_session *session2_3 = NULL;
2790 struct smb2_session *session2_4 = NULL;
2791 uint16_t csn2 = 1;
2792 const char *hold_name = NULL;
2794 switch (client1_level) {
2795 case SMB2_OPLOCK_LEVEL_LEASE:
2796 hold_name = "RWH Lease";
2797 break;
2798 case SMB2_OPLOCK_LEVEL_BATCH:
2799 hold_name = "BATCH Oplock";
2800 break;
2801 default:
2802 smb_panic(__location__);
2803 break;
2806 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
2807 torture_skip(tctx, "SMB 3.X Dialect family required for "
2808 "replay tests\n");
2811 server_capabilities = smb2cli_conn_server_capabilities(transport1->conn);
2812 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
2813 torture_skip(tctx, "MULTI_CHANNEL are not supported");
2815 if (!(server_capabilities & SMB2_CAP_LEASING)) {
2816 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE ||
2817 client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
2818 torture_skip(tctx, "leases are not supported");
2822 share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
2823 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
2824 if (share_is_so) {
2825 torture_skip(tctx, talloc_asprintf(tctx,
2826 "%s not supported on SCALEOUT share",
2827 hold_name));
2830 /* Add some random component to the file name. */
2831 snprintf(fname, sizeof(fname), "%s\\%s_%s.dat",
2832 BASEDIR, testname, generate_random_str(tctx, 8));
2834 options2x = transport2_1->options;
2835 options2x.only_negprot = true;
2837 status = smb2_connect(tctx,
2838 host,
2839 lpcfg_smb_ports(tctx->lp_ctx),
2840 share,
2841 lpcfg_resolve_context(tctx->lp_ctx),
2842 credentials,
2843 &tree2_2,
2844 tctx->ev,
2845 &options2x,
2846 lpcfg_socket_options(tctx->lp_ctx),
2847 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
2849 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2850 "smb2_connect failed");
2851 transport2_2 = tree2_2->session->transport;
2853 session2_2 = smb2_session_channel(transport2_2,
2854 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
2855 tctx,
2856 session2_1);
2857 torture_assert(tctx, session2_2 != NULL, "smb2_session_channel failed");
2859 status = smb2_session_setup_spnego(session2_2,
2860 credentials,
2861 0 /* previous_session_id */);
2862 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2863 "smb2_session_setup_spnego failed");
2864 tree2_2->smbXcli = tree2_1->smbXcli;
2865 tree2_2->session = session2_2;
2867 status = smb2_connect(tctx,
2868 host,
2869 lpcfg_smb_ports(tctx->lp_ctx),
2870 share,
2871 lpcfg_resolve_context(tctx->lp_ctx),
2872 credentials,
2873 &tree2_3,
2874 tctx->ev,
2875 &options2x,
2876 lpcfg_socket_options(tctx->lp_ctx),
2877 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
2879 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2880 "smb2_connect failed");
2881 transport2_3 = tree2_3->session->transport;
2883 session2_3 = smb2_session_channel(transport2_3,
2884 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
2885 tctx,
2886 session2_1);
2887 torture_assert(tctx, session2_3 != NULL, "smb2_session_channel failed");
2889 status = smb2_session_setup_spnego(session2_3,
2890 credentials,
2891 0 /* previous_session_id */);
2892 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2893 "smb2_session_setup_spnego failed");
2894 tree2_3->smbXcli = tree2_1->smbXcli;
2895 tree2_3->session = session2_3;
2897 status = smb2_connect(tctx,
2898 host,
2899 lpcfg_smb_ports(tctx->lp_ctx),
2900 share,
2901 lpcfg_resolve_context(tctx->lp_ctx),
2902 credentials,
2903 &tree2_4,
2904 tctx->ev,
2905 &options2x,
2906 lpcfg_socket_options(tctx->lp_ctx),
2907 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
2909 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2910 "smb2_connect failed");
2911 transport2_4 = tree2_4->session->transport;
2913 session2_4 = smb2_session_channel(transport2_4,
2914 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
2915 tctx,
2916 session2_1);
2917 torture_assert(tctx, session2_4 != NULL, "smb2_session_channel failed");
2919 status = smb2_session_setup_spnego(session2_4,
2920 credentials,
2921 0 /* previous_session_id */);
2922 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2923 "smb2_session_setup_spnego failed");
2924 tree2_4->smbXcli = tree2_1->smbXcli;
2925 tree2_4->session = session2_4;
2927 smb2cli_session_reset_channel_sequence(session2_2->smbXcli, csn2++);
2929 torture_reset_break_info(tctx, &break_info);
2930 break_info.oplock_skip_ack = true;
2931 torture_reset_lease_break_info(tctx, &lease_break_info);
2932 lease_break_info.lease_skip_ack = true;
2933 transport1->oplock.handler = torture_oplock_ack_handler;
2934 transport1->oplock.private_data = tree1;
2935 transport1->lease.handler = torture_lease_handler;
2936 transport1->lease.private_data = tree1;
2937 smb2_keepalive(transport1);
2938 transport2_1->oplock.handler = torture_oplock_ack_handler;
2939 transport2_1->oplock.private_data = tree2_1;
2940 transport2_1->lease.handler = torture_lease_handler;
2941 transport2_1->lease.private_data = tree2_1;
2942 smb2_keepalive(transport2_1);
2943 transport2_2->oplock.handler = torture_oplock_ack_handler;
2944 transport2_2->oplock.private_data = tree2_2;
2945 transport2_2->lease.handler = torture_lease_handler;
2946 transport2_2->lease.private_data = tree2_2;
2947 smb2_keepalive(transport2_2);
2948 transport2_3->oplock.handler = torture_oplock_ack_handler;
2949 transport2_3->oplock.private_data = tree2_3;
2950 transport2_3->lease.handler = torture_lease_handler;
2951 transport2_3->lease.private_data = tree2_3;
2952 smb2_keepalive(transport2_3);
2953 transport2_4->oplock.handler = torture_oplock_ack_handler;
2954 transport2_4->oplock.private_data = tree2_4;
2955 transport2_4->lease.handler = torture_lease_handler;
2956 transport2_4->lease.private_data = tree2_4;
2957 smb2_keepalive(transport2_4);
2959 smb2_util_unlink(tree1, fname);
2960 status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
2961 CHECK_STATUS(status, NT_STATUS_OK);
2962 smb2_util_close(tree1, _h1);
2963 CHECK_VAL(break_info.count, 0);
2965 lease_key1 = random();
2966 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
2967 smb2_lease_v2_create(&io1, &ls1, false /* dir */, fname,
2968 lease_key1, NULL, smb2_util_lease_state("RWH"), lease_epoch1++);
2969 } else {
2970 smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
2972 io1.in.durable_open = false;
2973 io1.in.durable_open_v2 = true;
2974 io1.in.persistent_open = false;
2975 io1.in.create_guid = create_guid1;
2976 io1.in.timeout = UINT32_MAX;
2978 status = smb2_create(tree1, mem_ctx, &io1);
2979 CHECK_STATUS(status, NT_STATUS_OK);
2980 _h1 = io1.out.file.handle;
2981 h1 = &_h1;
2982 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2983 CHECK_VAL(io1.out.durable_open, false);
2984 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
2985 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
2986 CHECK_VAL(io1.out.lease_response_v2.lease_key.data[0], lease_key1);
2987 CHECK_VAL(io1.out.lease_response_v2.lease_key.data[1], ~lease_key1);
2988 CHECK_VAL(io1.out.lease_response_v2.lease_epoch, lease_epoch1);
2989 CHECK_VAL(io1.out.lease_response_v2.lease_state,
2990 smb2_util_lease_state("RHW"));
2991 } else {
2992 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2994 CHECK_VAL(io1.out.durable_open_v2, true);
2995 CHECK_VAL(io1.out.timeout, 300*1000);
2997 lease_key2 = random();
2998 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
2999 smb2_lease_v2_create(&io21, &ls2, false /* dir */, fname,
3000 lease_key2, NULL, smb2_util_lease_state("RWH"), lease_epoch2++);
3001 } else {
3002 smb2_oplock_create(&io21, fname, client2_level);
3004 io21.in.durable_open = false;
3005 io21.in.durable_open_v2 = true;
3006 io21.in.persistent_open = false;
3007 io21.in.create_guid = create_guid2;
3008 io21.in.timeout = UINT32_MAX;
3009 io24 = io23 = io22 = io21;
3011 req21 = smb2_create_send(tree2_1, &io21);
3012 torture_assert(tctx, req21 != NULL, "req21");
3014 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3015 const struct smb2_lease_break *lb =
3016 &lease_break_info.lease_break;
3017 const struct smb2_lease *l = &lb->current_lease;
3018 const struct smb2_lease_key *k = &l->lease_key;
3020 torture_wait_for_lease_break(tctx);
3021 CHECK_VAL(break_info.count, 0);
3022 CHECK_VAL(lease_break_info.count, 1);
3024 torture_assert(tctx,
3025 lease_break_info.lease_transport == transport1,
3026 "expect lease break on transport1\n");
3027 CHECK_VAL(k->data[0], lease_key1);
3028 CHECK_VAL(k->data[1], ~lease_key1);
3029 CHECK_VAL(lb->new_lease_state,
3030 smb2_util_lease_state("RH"));
3031 CHECK_VAL(lb->break_flags,
3032 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
3033 CHECK_VAL(lb->new_epoch, lease_epoch1+1);
3034 lease_epoch1 += 1;
3035 } else {
3036 torture_wait_for_oplock_break(tctx);
3037 CHECK_VAL(break_info.count, 1);
3038 CHECK_VAL(lease_break_info.count, 0);
3040 torture_assert(tctx,
3041 break_info.received_transport == transport1,
3042 "expect oplock break on transport1\n");
3043 CHECK_VAL(break_info.handle.data[0], _h1.data[0]);
3044 CHECK_VAL(break_info.handle.data[1], _h1.data[1]);
3045 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3048 torture_reset_break_info(tctx, &break_info);
3049 break_info.oplock_skip_ack = true;
3050 torture_reset_lease_break_info(tctx, &lease_break_info);
3051 lease_break_info.lease_skip_ack = true;
3053 WAIT_FOR_ASYNC_RESPONSE(tctx, req21);
3055 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3056 torture_wait_for_lease_break(tctx);
3057 } else {
3058 torture_wait_for_oplock_break(tctx);
3060 CHECK_VAL(break_info.count, 0);
3061 CHECK_VAL(lease_break_info.count, 0);
3063 smbXcli_conn_disconnect(transport2_1->conn, NT_STATUS_LOCAL_DISCONNECT);
3064 smb2cli_session_reset_channel_sequence(session2_1->smbXcli, csn2++);
3066 smb2cli_session_start_replay(session2_2->smbXcli);
3067 transport2_2->options.request_timeout = 5;
3068 status = smb2_create(tree2_2, tctx, &io22);
3069 transport2_2->options.request_timeout = request_timeout2;
3070 CHECK_STATUS(status, reject_status);
3071 smb2cli_session_stop_replay(session2_2->smbXcli);
3073 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3074 torture_wait_for_lease_break(tctx);
3075 } else {
3076 torture_wait_for_oplock_break(tctx);
3078 CHECK_VAL(break_info.count, 0);
3079 CHECK_VAL(lease_break_info.count, 0);
3081 smbXcli_conn_disconnect(transport2_2->conn, NT_STATUS_LOCAL_DISCONNECT);
3082 smb2cli_session_reset_channel_sequence(session2_2->smbXcli, csn2++);
3084 smb2cli_session_start_replay(session2_3->smbXcli);
3085 transport2_3->options.request_timeout = 5;
3086 status = smb2_create(tree2_3, tctx, &io23);
3087 transport2_3->options.request_timeout = request_timeout2;
3088 CHECK_STATUS(status, reject_status);
3089 smb2cli_session_stop_replay(session2_3->smbXcli);
3091 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3092 torture_wait_for_lease_break(tctx);
3093 } else {
3094 torture_wait_for_oplock_break(tctx);
3096 CHECK_VAL(break_info.count, 0);
3097 CHECK_VAL(lease_break_info.count, 0);
3099 smb2_util_close(tree1, _h1);
3100 h1 = NULL;
3102 status = smb2_create_recv(req21, tctx, &io21);
3103 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
3105 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3106 torture_wait_for_lease_break(tctx);
3107 } else {
3108 torture_wait_for_oplock_break(tctx);
3110 CHECK_VAL(break_info.count, 0);
3111 CHECK_VAL(lease_break_info.count, 0);
3113 smbXcli_conn_disconnect(transport2_3->conn, NT_STATUS_LOCAL_DISCONNECT);
3114 smb2cli_session_reset_channel_sequence(session2_3->smbXcli, csn2++);
3116 smb2cli_session_start_replay(session2_4->smbXcli);
3117 status = smb2_create(tree2_4, tctx, &io24);
3118 smb2cli_session_stop_replay(session2_4->smbXcli);
3119 CHECK_STATUS(status, NT_STATUS_OK);
3120 _h24 = io24.out.file.handle;
3121 h24 = &_h24;
3122 CHECK_CREATED(&io24, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3123 CHECK_VAL(io24.out.oplock_level, client2_level);
3124 CHECK_VAL(io24.out.durable_open, false);
3125 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
3126 CHECK_VAL(io24.out.lease_response_v2.lease_key.data[0], lease_key2);
3127 CHECK_VAL(io24.out.lease_response_v2.lease_key.data[1], ~lease_key2);
3128 CHECK_VAL(io24.out.lease_response_v2.lease_epoch, lease_epoch2);
3129 CHECK_VAL(io24.out.lease_response_v2.lease_state,
3130 smb2_util_lease_state("RHW"));
3131 CHECK_VAL(io24.out.durable_open_v2, true);
3132 CHECK_VAL(io24.out.timeout, 300*1000);
3133 } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
3134 CHECK_VAL(io24.out.durable_open_v2, true);
3135 CHECK_VAL(io24.out.timeout, 300*1000);
3136 } else {
3137 CHECK_VAL(io24.out.durable_open_v2, false);
3140 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3141 torture_wait_for_lease_break(tctx);
3142 } else {
3143 torture_wait_for_oplock_break(tctx);
3145 CHECK_VAL(break_info.count, 0);
3146 CHECK_VAL(lease_break_info.count, 0);
3147 status = smb2_util_close(tree2_4, *h24);
3148 CHECK_STATUS(status, NT_STATUS_OK);
3149 h24 = NULL;
3151 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3152 torture_wait_for_lease_break(tctx);
3153 } else {
3154 torture_wait_for_oplock_break(tctx);
3156 CHECK_VAL(break_info.count, 0);
3157 CHECK_VAL(lease_break_info.count, 0);
3159 done:
3161 smbXcli_conn_disconnect(transport2_1->conn, NT_STATUS_LOCAL_DISCONNECT);
3162 smbXcli_conn_disconnect(transport2_2->conn, NT_STATUS_LOCAL_DISCONNECT);
3163 smbXcli_conn_disconnect(transport2_3->conn, NT_STATUS_LOCAL_DISCONNECT);
3164 smbXcli_conn_disconnect(transport2_4->conn, NT_STATUS_LOCAL_DISCONNECT);
3166 if (h1 != NULL) {
3167 smb2_util_close(tree1, *h1);
3170 smb2_deltree(tree1, BASEDIR);
3172 TALLOC_FREE(tree1);
3173 talloc_free(mem_ctx);
3175 return ret;
3179 * This tests replay with a pending open with 4 channels
3180 * and closed transports on the client and server side.
3182 * With a durablev2 request containing a create_guid,
3183 * a share_access of READ/WRITE/DELETE,
3184 * but without asking for an oplock nor a lease.
3186 * While another client holds an RWH lease.
3187 * And allows share_access of READ/WRITE/DELETE.
3189 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3191 * This expects the sane reject status of
3192 * NT_STATUS_FILE_NOT_AVAILABLE.
3194 * It won't pass against Windows as it returns
3195 * NT_STATUS_ACCESS_DENIED see
3196 * test_dhv2_pending2n_vs_lease_windows().
3198 static bool test_dhv2_pending2n_vs_lease_sane(struct torture_context *tctx,
3199 struct smb2_tree *tree1,
3200 struct smb2_tree *tree2_1)
3202 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3203 SMB2_OPLOCK_LEVEL_LEASE,
3204 SMB2_OPLOCK_LEVEL_NONE,
3205 NT_STATUS_FILE_NOT_AVAILABLE,
3206 tree1, tree2_1);
3210 * This tests replay with a pending open with 4 channels
3211 * and closed transports on the client and server side.
3213 * With a durablev2 request containing a create_guid,
3214 * a share_access of READ/WRITE/DELETE,
3215 * but without asking for an oplock nor a lease.
3217 * While another client holds an RWH lease.
3218 * And allows share_access of READ/WRITE/DELETE.
3220 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3222 * This expects the strange reject status of
3223 * NT_STATUS_ACCESS_DENIED, which is returned
3224 * by Windows Servers.
3226 * It won't pass against Samba as it returns
3227 * NT_STATUS_FILE_NOT_AVAILABLE. see
3228 * test_dhv2_pending2n_vs_lease_sane().
3230 static bool test_dhv2_pending2n_vs_lease_windows(struct torture_context *tctx,
3231 struct smb2_tree *tree1,
3232 struct smb2_tree *tree2_1)
3234 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3235 SMB2_OPLOCK_LEVEL_LEASE,
3236 SMB2_OPLOCK_LEVEL_NONE,
3237 NT_STATUS_ACCESS_DENIED,
3238 tree1, tree2_1);
3242 * This tests replay with a pending open with 4 channels
3243 * and closed transports on the client and server side.
3245 * With a durablev2 request containing a create_guid,
3246 * a share_access of READ/WRITE/DELETE,
3247 * but without asking for an oplock nor a lease.
3249 * While another client holds a batch oplock.
3250 * And allows share_access of READ/WRITE/DELETE.
3252 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3254 * This expects the sane reject status of
3255 * NT_STATUS_FILE_NOT_AVAILABLE.
3257 * It won't pass against Windows as it returns
3258 * NT_STATUS_ACCESS_DENIED see
3259 * test_dhv2_pending2n_vs_oplock_windows().
3261 static bool test_dhv2_pending2n_vs_oplock_sane(struct torture_context *tctx,
3262 struct smb2_tree *tree1,
3263 struct smb2_tree *tree2_1)
3265 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3266 SMB2_OPLOCK_LEVEL_BATCH,
3267 SMB2_OPLOCK_LEVEL_NONE,
3268 NT_STATUS_FILE_NOT_AVAILABLE,
3269 tree1, tree2_1);
3273 * This tests replay with a pending open with 4 channels
3274 * and closed transports on the client and server side.
3276 * With a durablev2 request containing a create_guid,
3277 * a share_access of READ/WRITE/DELETE,
3278 * but without asking for an oplock nor a lease.
3280 * While another client holds a batch oplock.
3281 * And allows share_access of READ/WRITE/DELETE.
3283 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3285 * This expects the strange reject status of
3286 * NT_STATUS_ACCESS_DENIED, which is returned
3287 * by Windows Servers.
3289 * It won't pass against Samba as it returns
3290 * NT_STATUS_FILE_NOT_AVAILABLE. see
3291 * test_dhv2_pending2n_vs_oplock_sane().
3293 static bool test_dhv2_pending2n_vs_oplock_windows(struct torture_context *tctx,
3294 struct smb2_tree *tree1,
3295 struct smb2_tree *tree2_1)
3297 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3298 SMB2_OPLOCK_LEVEL_BATCH,
3299 SMB2_OPLOCK_LEVEL_NONE,
3300 NT_STATUS_ACCESS_DENIED,
3301 tree1, tree2_1);
3305 * This tests replay with a pending open with 4 channels
3306 * and closed transports on the client and server side.
3308 * With a durablev2 request containing a create_guid,
3309 * a share_access of READ/WRITE/DELETE,
3310 * and asking for a v2 lease.
3312 * While another client holds a batch oplock.
3313 * And allows share_access of READ/WRITE/DELETE.
3315 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3317 * This expects the sane reject status of
3318 * NT_STATUS_FILE_NOT_AVAILABLE.
3320 * It won't pass against Windows as it returns
3321 * NT_STATUS_ACCESS_DENIED see
3322 * test_dhv2_pending2l_vs_oplock_windows().
3324 static bool test_dhv2_pending2l_vs_oplock_sane(struct torture_context *tctx,
3325 struct smb2_tree *tree1,
3326 struct smb2_tree *tree2_1)
3328 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3329 SMB2_OPLOCK_LEVEL_BATCH,
3330 SMB2_OPLOCK_LEVEL_LEASE,
3331 NT_STATUS_FILE_NOT_AVAILABLE,
3332 tree1, tree2_1);
3336 * This tests replay with a pending open with 4 channels
3337 * and closed transports on the client and server side.
3339 * With a durablev2 request containing a create_guid,
3340 * a share_access of READ/WRITE/DELETE,
3341 * and asking for a v2 lease.
3343 * While another client holds a batch oplock.
3344 * And allows share_access of READ/WRITE/DELETE.
3346 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3348 * This expects the strange reject status of
3349 * NT_STATUS_ACCESS_DENIED, which is returned
3350 * by Windows Servers.
3352 * It won't pass against Samba as it returns
3353 * NT_STATUS_FILE_NOT_AVAILABLE. see
3354 * test_dhv2_pending2l_vs_oplock_sane().
3356 static bool test_dhv2_pending2l_vs_oplock_windows(struct torture_context *tctx,
3357 struct smb2_tree *tree1,
3358 struct smb2_tree *tree2_1)
3360 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3361 SMB2_OPLOCK_LEVEL_BATCH,
3362 SMB2_OPLOCK_LEVEL_LEASE,
3363 NT_STATUS_ACCESS_DENIED,
3364 tree1, tree2_1);
3368 * This tests replay with a pending open with 4 channels
3369 * and closed transports on the client and server side.
3371 * With a durablev2 request containing a create_guid,
3372 * a share_access of READ/WRITE/DELETE,
3373 * and asking for a v2 lease.
3375 * While another client holds an RWH lease.
3376 * And allows share_access of READ/WRITE/DELETE.
3378 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3380 * This expects the sane reject status of
3381 * NT_STATUS_FILE_NOT_AVAILABLE.
3383 * It won't pass against Windows as it returns
3384 * NT_STATUS_ACCESS_DENIED see
3385 * test_dhv2_pending2l_vs_oplock_windows().
3387 static bool test_dhv2_pending2l_vs_lease_sane(struct torture_context *tctx,
3388 struct smb2_tree *tree1,
3389 struct smb2_tree *tree2_1)
3391 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3392 SMB2_OPLOCK_LEVEL_LEASE,
3393 SMB2_OPLOCK_LEVEL_LEASE,
3394 NT_STATUS_FILE_NOT_AVAILABLE,
3395 tree1, tree2_1);
3399 * This tests replay with a pending open with 4 channels
3400 * and closed transports on the client and server side.
3402 * With a durablev2 request containing a create_guid,
3403 * a share_access of READ/WRITE/DELETE,
3404 * and asking for a v2 lease.
3406 * While another client holds an RWH lease.
3407 * And allows share_access of READ/WRITE/DELETE.
3409 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3411 * This expects the strange reject status of
3412 * NT_STATUS_ACCESS_DENIED, which is returned
3413 * by Windows Servers.
3415 * It won't pass against Samba as it returns
3416 * NT_STATUS_FILE_NOT_AVAILABLE. see
3417 * test_dhv2_pending2l_vs_oplock_sane().
3419 static bool test_dhv2_pending2l_vs_lease_windows(struct torture_context *tctx,
3420 struct smb2_tree *tree1,
3421 struct smb2_tree *tree2_1)
3423 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3424 SMB2_OPLOCK_LEVEL_LEASE,
3425 SMB2_OPLOCK_LEVEL_LEASE,
3426 NT_STATUS_ACCESS_DENIED,
3427 tree1, tree2_1);
3431 * This tests replay with a pending open with 4 channels
3432 * and closed transports on the client and server side.
3434 * With a durablev2 request containing a create_guid,
3435 * a share_access of READ/WRITE/DELETE,
3436 * and asking for a batch oplock
3438 * While another client holds a batch oplock.
3439 * And allows share_access of READ/WRITE/DELETE.
3441 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3443 * This expects the sane reject status of
3444 * NT_STATUS_FILE_NOT_AVAILABLE.
3446 * It won't pass against Windows as it returns
3447 * NT_STATUS_ACCESS_DENIED see
3448 * test_dhv2_pending2o_vs_oplock_windows().
3450 static bool test_dhv2_pending2o_vs_oplock_sane(struct torture_context *tctx,
3451 struct smb2_tree *tree1,
3452 struct smb2_tree *tree2_1)
3454 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3455 SMB2_OPLOCK_LEVEL_BATCH,
3456 SMB2_OPLOCK_LEVEL_BATCH,
3457 NT_STATUS_FILE_NOT_AVAILABLE,
3458 tree1, tree2_1);
3462 * This tests replay with a pending open with 4 channels
3463 * and closed transports on the client and server side.
3465 * With a durablev2 request containing a create_guid,
3466 * a share_access of READ/WRITE/DELETE,
3467 * and asking for a batch oplock.
3469 * While another client holds a batch oplock.
3470 * And allows share_access of READ/WRITE/DELETE.
3472 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3474 * This expects the strange reject status of
3475 * NT_STATUS_ACCESS_DENIED, which is returned
3476 * by Windows Servers.
3478 * It won't pass against Samba as it returns
3479 * NT_STATUS_FILE_NOT_AVAILABLE. see
3480 * test_dhv2_pending2o_vs_oplock_sane().
3482 static bool test_dhv2_pending2o_vs_oplock_windows(struct torture_context *tctx,
3483 struct smb2_tree *tree1,
3484 struct smb2_tree *tree2_1)
3486 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3487 SMB2_OPLOCK_LEVEL_BATCH,
3488 SMB2_OPLOCK_LEVEL_BATCH,
3489 NT_STATUS_ACCESS_DENIED,
3490 tree1, tree2_1);
3494 * This tests replay with a pending open with 4 channels
3495 * and closed transports on the client and server side.
3497 * With a durablev2 request containing a create_guid,
3498 * a share_access of READ/WRITE/DELETE,
3499 * and asking for a batch oplock
3501 * While another client holds an RWH lease.
3502 * And allows share_access of READ/WRITE/DELETE.
3504 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3506 * This expects the sane reject status of
3507 * NT_STATUS_FILE_NOT_AVAILABLE.
3509 * It won't pass against Windows as it returns
3510 * NT_STATUS_ACCESS_DENIED see
3511 * test_dhv2_pending2o_vs_lease_windows().
3513 static bool test_dhv2_pending2o_vs_lease_sane(struct torture_context *tctx,
3514 struct smb2_tree *tree1,
3515 struct smb2_tree *tree2_1)
3517 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3518 SMB2_OPLOCK_LEVEL_LEASE,
3519 SMB2_OPLOCK_LEVEL_BATCH,
3520 NT_STATUS_FILE_NOT_AVAILABLE,
3521 tree1, tree2_1);
3525 * This tests replay with a pending open with 4 channels
3526 * and closed transports on the client and server side.
3528 * With a durablev2 request containing a create_guid,
3529 * a share_access of READ/WRITE/DELETE,
3530 * and asking for a batch oplock.
3532 * While another client holds an RWH lease.
3533 * And allows share_access of READ/WRITE/DELETE.
3535 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3537 * This expects the strange reject status of
3538 * NT_STATUS_ACCESS_DENIED, which is returned
3539 * by Windows Servers.
3541 * It won't pass against Samba as it returns
3542 * NT_STATUS_FILE_NOT_AVAILABLE. see
3543 * test_dhv2_pending2o_vs_lease_sane().
3545 static bool test_dhv2_pending2o_vs_lease_windows(struct torture_context *tctx,
3546 struct smb2_tree *tree1,
3547 struct smb2_tree *tree2_1)
3549 return _test_dhv2_pending2_vs_hold(tctx, __func__,
3550 SMB2_OPLOCK_LEVEL_LEASE,
3551 SMB2_OPLOCK_LEVEL_BATCH,
3552 NT_STATUS_ACCESS_DENIED,
3553 tree1, tree2_1);
3557 * This tests replay with a pending open with 4 channels
3558 * and blocked transports on the client side.
3560 * With a durablev2 request containing a create_guid and
3561 * a share_access of READ/WRITE/DELETE:
3562 * - client2_level = NONE:
3563 * but without asking for an oplock nor a lease.
3564 * - client2_level = BATCH:
3565 * and asking for a batch oplock.
3566 * - client2_level = LEASE
3567 * and asking for an RWH lease.
3569 * While another client holds a batch oplock or
3570 * RWH lease. (client1_level => LEASE or BATCH).
3571 * And allows share_access of READ/WRITE/DELETE.
3573 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
3575 static bool _test_dhv2_pending3_vs_hold(struct torture_context *tctx,
3576 const char *testname,
3577 uint8_t client1_level,
3578 uint8_t client2_level,
3579 NTSTATUS reject_status,
3580 struct smb2_tree *tree1,
3581 struct smb2_tree *tree2_1)
3583 const char *host = torture_setting_string(tctx, "host", NULL);
3584 const char *share = torture_setting_string(tctx, "share", NULL);
3585 struct cli_credentials *credentials = samba_cmdline_get_creds();
3586 NTSTATUS status;
3587 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3588 struct smb2_handle _h1;
3589 struct smb2_handle *h1 = NULL;
3590 struct smb2_handle _h21;
3591 struct smb2_handle *h21 = NULL;
3592 struct smb2_handle _h24;
3593 struct smb2_handle *h24 = NULL;
3594 struct smb2_create io1, io21, io22, io23, io24;
3595 struct GUID create_guid1 = GUID_random();
3596 struct GUID create_guid2 = GUID_random();
3597 struct smb2_request *req21 = NULL;
3598 bool ret = true;
3599 char fname[256];
3600 struct smb2_transport *transport1 = tree1->session->transport;
3601 uint32_t server_capabilities;
3602 uint32_t share_capabilities;
3603 struct smb2_lease ls1;
3604 uint64_t lease_key1;
3605 uint16_t lease_epoch1 = 0;
3606 struct smb2_lease ls2;
3607 uint64_t lease_key2;
3608 uint16_t lease_epoch2 = 0;
3609 bool share_is_so;
3610 struct smb2_transport *transport2_1 = tree2_1->session->transport;
3611 int request_timeout2 = transport2_1->options.request_timeout;
3612 struct smbcli_options options2x;
3613 struct smb2_tree *tree2_2 = NULL;
3614 struct smb2_tree *tree2_3 = NULL;
3615 struct smb2_tree *tree2_4 = NULL;
3616 struct smb2_transport *transport2_2 = NULL;
3617 struct smb2_transport *transport2_3 = NULL;
3618 struct smb2_transport *transport2_4 = NULL;
3619 struct smb2_session *session2_1 = tree2_1->session;
3620 struct smb2_session *session2_2 = NULL;
3621 struct smb2_session *session2_3 = NULL;
3622 struct smb2_session *session2_4 = NULL;
3623 bool block_setup = false;
3624 bool blocked2_1 = false;
3625 bool blocked2_2 = false;
3626 bool blocked2_3 = false;
3627 uint16_t csn2 = 1;
3628 const char *hold_name = NULL;
3630 switch (client1_level) {
3631 case SMB2_OPLOCK_LEVEL_LEASE:
3632 hold_name = "RWH Lease";
3633 break;
3634 case SMB2_OPLOCK_LEVEL_BATCH:
3635 hold_name = "BATCH Oplock";
3636 break;
3637 default:
3638 smb_panic(__location__);
3639 break;
3642 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
3643 torture_skip(tctx, "SMB 3.X Dialect family required for "
3644 "replay tests\n");
3647 server_capabilities = smb2cli_conn_server_capabilities(transport1->conn);
3648 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
3649 torture_skip(tctx, "MULTI_CHANNEL are not supported");
3651 if (!(server_capabilities & SMB2_CAP_LEASING)) {
3652 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE ||
3653 client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
3654 torture_skip(tctx, "leases are not supported");
3658 share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
3659 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
3660 if (share_is_so) {
3661 torture_skip(tctx, talloc_asprintf(tctx,
3662 "%s not supported on SCALEOUT share",
3663 hold_name));
3666 /* Add some random component to the file name. */
3667 snprintf(fname, sizeof(fname), "%s\\%s_%s.dat",
3668 BASEDIR, testname, generate_random_str(tctx, 8));
3670 options2x = transport2_1->options;
3671 options2x.only_negprot = true;
3673 status = smb2_connect(tctx,
3674 host,
3675 lpcfg_smb_ports(tctx->lp_ctx),
3676 share,
3677 lpcfg_resolve_context(tctx->lp_ctx),
3678 credentials,
3679 &tree2_2,
3680 tctx->ev,
3681 &options2x,
3682 lpcfg_socket_options(tctx->lp_ctx),
3683 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
3685 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3686 "smb2_connect failed");
3687 transport2_2 = tree2_2->session->transport;
3689 session2_2 = smb2_session_channel(transport2_2,
3690 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
3691 tctx,
3692 session2_1);
3693 torture_assert(tctx, session2_2 != NULL, "smb2_session_channel failed");
3695 status = smb2_session_setup_spnego(session2_2,
3696 credentials,
3697 0 /* previous_session_id */);
3698 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3699 "smb2_session_setup_spnego failed");
3700 tree2_2->smbXcli = tree2_1->smbXcli;
3701 tree2_2->session = session2_2;
3703 status = smb2_connect(tctx,
3704 host,
3705 lpcfg_smb_ports(tctx->lp_ctx),
3706 share,
3707 lpcfg_resolve_context(tctx->lp_ctx),
3708 credentials,
3709 &tree2_3,
3710 tctx->ev,
3711 &options2x,
3712 lpcfg_socket_options(tctx->lp_ctx),
3713 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
3715 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3716 "smb2_connect failed");
3717 transport2_3 = tree2_3->session->transport;
3719 session2_3 = smb2_session_channel(transport2_3,
3720 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
3721 tctx,
3722 session2_1);
3723 torture_assert(tctx, session2_3 != NULL, "smb2_session_channel failed");
3725 status = smb2_session_setup_spnego(session2_3,
3726 credentials,
3727 0 /* previous_session_id */);
3728 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3729 "smb2_session_setup_spnego failed");
3730 tree2_3->smbXcli = tree2_1->smbXcli;
3731 tree2_3->session = session2_3;
3733 status = smb2_connect(tctx,
3734 host,
3735 lpcfg_smb_ports(tctx->lp_ctx),
3736 share,
3737 lpcfg_resolve_context(tctx->lp_ctx),
3738 credentials,
3739 &tree2_4,
3740 tctx->ev,
3741 &options2x,
3742 lpcfg_socket_options(tctx->lp_ctx),
3743 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
3745 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3746 "smb2_connect failed");
3747 transport2_4 = tree2_4->session->transport;
3749 session2_4 = smb2_session_channel(transport2_4,
3750 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
3751 tctx,
3752 session2_1);
3753 torture_assert(tctx, session2_4 != NULL, "smb2_session_channel failed");
3755 status = smb2_session_setup_spnego(session2_4,
3756 credentials,
3757 0 /* previous_session_id */);
3758 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3759 "smb2_session_setup_spnego failed");
3760 tree2_4->smbXcli = tree2_1->smbXcli;
3761 tree2_4->session = session2_4;
3763 smb2cli_session_reset_channel_sequence(session2_2->smbXcli, csn2++);
3765 torture_reset_break_info(tctx, &break_info);
3766 break_info.oplock_skip_ack = true;
3767 torture_reset_lease_break_info(tctx, &lease_break_info);
3768 lease_break_info.lease_skip_ack = true;
3769 transport1->oplock.handler = torture_oplock_ack_handler;
3770 transport1->oplock.private_data = tree1;
3771 transport1->lease.handler = torture_lease_handler;
3772 transport1->lease.private_data = tree1;
3773 smb2_keepalive(transport1);
3774 transport2_1->oplock.handler = torture_oplock_ack_handler;
3775 transport2_1->oplock.private_data = tree2_1;
3776 transport2_1->lease.handler = torture_lease_handler;
3777 transport2_1->lease.private_data = tree2_1;
3778 smb2_keepalive(transport2_1);
3779 transport2_2->oplock.handler = torture_oplock_ack_handler;
3780 transport2_2->oplock.private_data = tree2_2;
3781 transport2_2->lease.handler = torture_lease_handler;
3782 transport2_2->lease.private_data = tree2_2;
3783 smb2_keepalive(transport2_2);
3784 transport2_3->oplock.handler = torture_oplock_ack_handler;
3785 transport2_3->oplock.private_data = tree2_3;
3786 transport2_3->lease.handler = torture_lease_handler;
3787 transport2_3->lease.private_data = tree2_3;
3788 smb2_keepalive(transport2_3);
3789 transport2_4->oplock.handler = torture_oplock_ack_handler;
3790 transport2_4->oplock.private_data = tree2_4;
3791 transport2_4->lease.handler = torture_lease_handler;
3792 transport2_4->lease.private_data = tree2_4;
3793 smb2_keepalive(transport2_4);
3795 smb2_util_unlink(tree1, fname);
3796 status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
3797 CHECK_STATUS(status, NT_STATUS_OK);
3798 smb2_util_close(tree1, _h1);
3799 CHECK_VAL(break_info.count, 0);
3801 lease_key1 = random();
3802 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3803 smb2_lease_v2_create(&io1, &ls1, false /* dir */, fname,
3804 lease_key1, NULL, smb2_util_lease_state("RWH"), lease_epoch1++);
3805 } else {
3806 smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
3808 io1.in.durable_open = false;
3809 io1.in.durable_open_v2 = true;
3810 io1.in.persistent_open = false;
3811 io1.in.create_guid = create_guid1;
3812 io1.in.timeout = UINT32_MAX;
3814 status = smb2_create(tree1, mem_ctx, &io1);
3815 CHECK_STATUS(status, NT_STATUS_OK);
3816 _h1 = io1.out.file.handle;
3817 h1 = &_h1;
3818 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3819 CHECK_VAL(io1.out.durable_open, false);
3820 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3821 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
3822 CHECK_VAL(io1.out.lease_response_v2.lease_key.data[0], lease_key1);
3823 CHECK_VAL(io1.out.lease_response_v2.lease_key.data[1], ~lease_key1);
3824 CHECK_VAL(io1.out.lease_response_v2.lease_epoch, lease_epoch1);
3825 CHECK_VAL(io1.out.lease_response_v2.lease_state,
3826 smb2_util_lease_state("RHW"));
3827 } else {
3828 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3830 CHECK_VAL(io1.out.durable_open_v2, true);
3831 CHECK_VAL(io1.out.timeout, 300*1000);
3833 lease_key2 = random();
3834 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
3835 smb2_lease_v2_create(&io21, &ls2, false /* dir */, fname,
3836 lease_key2, NULL, smb2_util_lease_state("RWH"), lease_epoch2++);
3837 } else {
3838 smb2_oplock_create(&io21, fname, client2_level);
3840 io21.in.durable_open = false;
3841 io21.in.durable_open_v2 = true;
3842 io21.in.persistent_open = false;
3843 io21.in.create_guid = create_guid2;
3844 io21.in.timeout = UINT32_MAX;
3845 io24 = io23 = io22 = io21;
3847 req21 = smb2_create_send(tree2_1, &io21);
3848 torture_assert(tctx, req21 != NULL, "req21");
3850 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3851 const struct smb2_lease_break *lb =
3852 &lease_break_info.lease_break;
3853 const struct smb2_lease *l = &lb->current_lease;
3854 const struct smb2_lease_key *k = &l->lease_key;
3856 torture_wait_for_lease_break(tctx);
3857 CHECK_VAL(break_info.count, 0);
3858 CHECK_VAL(lease_break_info.count, 1);
3860 torture_assert(tctx,
3861 lease_break_info.lease_transport == transport1,
3862 "expect lease break on transport1\n");
3863 CHECK_VAL(k->data[0], lease_key1);
3864 CHECK_VAL(k->data[1], ~lease_key1);
3865 CHECK_VAL(lb->new_lease_state,
3866 smb2_util_lease_state("RH"));
3867 CHECK_VAL(lb->break_flags,
3868 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
3869 CHECK_VAL(lb->new_epoch, lease_epoch1+1);
3870 lease_epoch1 += 1;
3871 } else {
3872 torture_wait_for_oplock_break(tctx);
3873 CHECK_VAL(break_info.count, 1);
3874 CHECK_VAL(lease_break_info.count, 0);
3876 torture_assert(tctx,
3877 break_info.received_transport == transport1,
3878 "expect oplock break on transport1\n");
3879 CHECK_VAL(break_info.handle.data[0], _h1.data[0]);
3880 CHECK_VAL(break_info.handle.data[1], _h1.data[1]);
3881 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3884 torture_reset_break_info(tctx, &break_info);
3885 break_info.oplock_skip_ack = true;
3886 torture_reset_lease_break_info(tctx, &lease_break_info);
3887 lease_break_info.lease_skip_ack = true;
3889 WAIT_FOR_ASYNC_RESPONSE(tctx, req21);
3891 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3892 torture_wait_for_lease_break(tctx);
3893 } else {
3894 torture_wait_for_oplock_break(tctx);
3896 CHECK_VAL(break_info.count, 0);
3897 CHECK_VAL(lease_break_info.count, 0);
3899 block_setup = test_setup_blocked_transports(tctx);
3900 torture_assert(tctx, block_setup, "test_setup_blocked_transports");
3902 blocked2_1 = _test_block_smb2_transport(tctx, transport2_1, "transport2_1");
3903 torture_assert_goto(tctx, blocked2_1, ret, done, "we could not block tcp transport");
3904 smb2cli_session_reset_channel_sequence(session2_1->smbXcli, csn2++);
3906 smb2cli_session_start_replay(session2_2->smbXcli);
3907 transport2_2->options.request_timeout = 5;
3908 status = smb2_create(tree2_2, tctx, &io22);
3909 transport2_2->options.request_timeout = request_timeout2;
3910 CHECK_STATUS(status, reject_status);
3911 smb2cli_session_stop_replay(session2_2->smbXcli);
3913 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3914 torture_wait_for_lease_break(tctx);
3915 } else {
3916 torture_wait_for_oplock_break(tctx);
3918 CHECK_VAL(break_info.count, 0);
3919 CHECK_VAL(lease_break_info.count, 0);
3921 blocked2_2 = _test_block_smb2_transport(tctx, transport2_2, "transport2_2");
3922 torture_assert_goto(tctx, blocked2_2, ret, done, "we could not block tcp transport");
3923 smb2cli_session_reset_channel_sequence(session2_2->smbXcli, csn2++);
3925 smb2cli_session_start_replay(session2_3->smbXcli);
3926 transport2_3->options.request_timeout = 5;
3927 status = smb2_create(tree2_3, tctx, &io23);
3928 transport2_3->options.request_timeout = request_timeout2;
3929 CHECK_STATUS(status, reject_status);
3930 smb2cli_session_stop_replay(session2_3->smbXcli);
3932 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3933 torture_wait_for_lease_break(tctx);
3934 } else {
3935 torture_wait_for_oplock_break(tctx);
3937 CHECK_VAL(break_info.count, 0);
3938 CHECK_VAL(lease_break_info.count, 0);
3940 smb2_util_close(tree1, _h1);
3941 h1 = NULL;
3943 status = smb2_create_recv(req21, tctx, &io21);
3944 CHECK_STATUS(status, NT_STATUS_OK);
3945 _h21 = io21.out.file.handle;
3946 h21 = &_h21;
3947 CHECK_CREATED(&io21, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3948 CHECK_VAL(io21.out.oplock_level, client2_level);
3949 CHECK_VAL(io21.out.durable_open, false);
3950 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
3951 CHECK_VAL(io21.out.lease_response_v2.lease_key.data[0], lease_key2);
3952 CHECK_VAL(io21.out.lease_response_v2.lease_key.data[1], ~lease_key2);
3953 CHECK_VAL(io21.out.lease_response_v2.lease_epoch, lease_epoch2);
3954 CHECK_VAL(io21.out.lease_response_v2.lease_state,
3955 smb2_util_lease_state("RHW"));
3956 CHECK_VAL(io21.out.durable_open_v2, true);
3957 CHECK_VAL(io21.out.timeout, 300*1000);
3958 } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
3959 CHECK_VAL(io21.out.durable_open_v2, true);
3960 CHECK_VAL(io21.out.timeout, 300*1000);
3961 } else {
3962 CHECK_VAL(io21.out.durable_open_v2, false);
3965 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
3966 torture_wait_for_lease_break(tctx);
3967 } else {
3968 torture_wait_for_oplock_break(tctx);
3970 CHECK_VAL(break_info.count, 0);
3971 CHECK_VAL(lease_break_info.count, 0);
3973 blocked2_3 = _test_block_smb2_transport(tctx, transport2_3, "transport2_3");
3974 torture_assert_goto(tctx, blocked2_3, ret, done, "we could not block tcp transport");
3975 smb2cli_session_reset_channel_sequence(session2_3->smbXcli, csn2++);
3977 smb2cli_session_start_replay(session2_4->smbXcli);
3978 status = smb2_create(tree2_4, tctx, &io24);
3979 smb2cli_session_stop_replay(session2_4->smbXcli);
3980 CHECK_STATUS(status, NT_STATUS_OK);
3981 _h24 = io24.out.file.handle;
3982 h24 = &_h24;
3983 CHECK_CREATED(&io24, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3984 CHECK_VAL(h24->data[0], h21->data[0]);
3985 CHECK_VAL(h24->data[1], h21->data[1]);
3986 if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
3987 CHECK_VAL(io24.out.lease_response_v2.lease_key.data[0], lease_key2);
3988 CHECK_VAL(io24.out.lease_response_v2.lease_key.data[1], ~lease_key2);
3989 CHECK_VAL(io24.out.lease_response_v2.lease_epoch, lease_epoch2);
3990 CHECK_VAL(io24.out.lease_response_v2.lease_state,
3991 smb2_util_lease_state("RHW"));
3992 CHECK_VAL(io24.out.durable_open_v2, true);
3993 CHECK_VAL(io24.out.timeout, 300*1000);
3994 } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
3995 CHECK_VAL(io24.out.durable_open_v2, true);
3996 CHECK_VAL(io24.out.timeout, 300*1000);
3997 } else {
3998 CHECK_VAL(io24.out.durable_open_v2, false);
4001 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
4002 torture_wait_for_lease_break(tctx);
4003 } else {
4004 torture_wait_for_oplock_break(tctx);
4006 CHECK_VAL(break_info.count, 0);
4007 CHECK_VAL(lease_break_info.count, 0);
4008 status = smb2_util_close(tree2_4, *h24);
4009 CHECK_STATUS(status, NT_STATUS_OK);
4010 h24 = NULL;
4012 if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
4013 torture_wait_for_lease_break(tctx);
4014 } else {
4015 torture_wait_for_oplock_break(tctx);
4017 CHECK_VAL(break_info.count, 0);
4018 CHECK_VAL(lease_break_info.count, 0);
4020 done:
4022 if (blocked2_3) {
4023 _test_unblock_smb2_transport(tctx, transport2_3, "transport2_3");
4025 if (blocked2_2) {
4026 _test_unblock_smb2_transport(tctx, transport2_2, "transport2_2");
4028 if (blocked2_1) {
4029 _test_unblock_smb2_transport(tctx, transport2_1, "transport2_1");
4031 if (block_setup) {
4032 test_cleanup_blocked_transports(tctx);
4035 smbXcli_conn_disconnect(transport2_1->conn, NT_STATUS_LOCAL_DISCONNECT);
4036 smbXcli_conn_disconnect(transport2_2->conn, NT_STATUS_LOCAL_DISCONNECT);
4037 smbXcli_conn_disconnect(transport2_3->conn, NT_STATUS_LOCAL_DISCONNECT);
4038 smbXcli_conn_disconnect(transport2_4->conn, NT_STATUS_LOCAL_DISCONNECT);
4040 if (h1 != NULL) {
4041 smb2_util_close(tree1, *h1);
4044 smb2_deltree(tree1, BASEDIR);
4046 TALLOC_FREE(tree1);
4047 talloc_free(mem_ctx);
4049 return ret;
4053 * This tests replay with a pending open with 4 channels
4054 * and blocked transports on the client side.
4056 * With a durablev2 request containing a create_guid,
4057 * a share_access of READ/WRITE/DELETE,
4058 * but without asking for an oplock nor a lease.
4060 * While another client holds an RWH lease.
4061 * And allows share_access of READ/WRITE/DELETE.
4063 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4065 * This expects the sane reject status of
4066 * NT_STATUS_FILE_NOT_AVAILABLE.
4068 * It won't pass against Windows as it returns
4069 * NT_STATUS_ACCESS_DENIED see
4070 * test_dhv2_pending3n_vs_lease_windows().
4072 static bool test_dhv2_pending3n_vs_lease_sane(struct torture_context *tctx,
4073 struct smb2_tree *tree1,
4074 struct smb2_tree *tree2_1)
4076 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4077 SMB2_OPLOCK_LEVEL_LEASE,
4078 SMB2_OPLOCK_LEVEL_NONE,
4079 NT_STATUS_FILE_NOT_AVAILABLE,
4080 tree1, tree2_1);
4084 * This tests replay with a pending open with 4 channels
4085 * and blocked transports on the client side.
4087 * With a durablev2 request containing a create_guid,
4088 * a share_access of READ/WRITE/DELETE,
4089 * but without asking for an oplock nor a lease.
4091 * While another client holds an RWH lease.
4092 * And allows share_access of READ/WRITE/DELETE.
4094 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4096 * This expects the strange reject status of
4097 * NT_STATUS_ACCESS_DENIED, which is returned
4098 * by Windows Servers.
4100 * It won't pass against Samba as it returns
4101 * NT_STATUS_FILE_NOT_AVAILABLE. see
4102 * test_dhv2_pending3n_vs_lease_sane.
4104 static bool test_dhv2_pending3n_vs_lease_windows(struct torture_context *tctx,
4105 struct smb2_tree *tree1,
4106 struct smb2_tree *tree2_1)
4108 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4109 SMB2_OPLOCK_LEVEL_LEASE,
4110 SMB2_OPLOCK_LEVEL_NONE,
4111 NT_STATUS_ACCESS_DENIED,
4112 tree1, tree2_1);
4116 * This tests replay with a pending open with 4 channels
4117 * and blocked transports on the client side.
4119 * With a durablev2 request containing a create_guid,
4120 * a share_access of READ/WRITE/DELETE,
4121 * but without asking for an oplock nor a lease.
4123 * While another client holds a batch oplock.
4124 * And allows share_access of READ/WRITE/DELETE.
4126 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4128 * This expects the sane reject status of
4129 * NT_STATUS_FILE_NOT_AVAILABLE.
4131 * It won't pass against Windows as it returns
4132 * NT_STATUS_ACCESS_DENIED see
4133 * test_dhv2_pending3n_vs_oplock_windows().
4135 static bool test_dhv2_pending3n_vs_oplock_sane(struct torture_context *tctx,
4136 struct smb2_tree *tree1,
4137 struct smb2_tree *tree2_1)
4139 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4140 SMB2_OPLOCK_LEVEL_BATCH,
4141 SMB2_OPLOCK_LEVEL_NONE,
4142 NT_STATUS_FILE_NOT_AVAILABLE,
4143 tree1, tree2_1);
4147 * This tests replay with a pending open with 4 channels
4148 * and blocked transports on the client side.
4150 * With a durablev2 request containing a create_guid,
4151 * a share_access of READ/WRITE/DELETE,
4152 * but without asking for an oplock nor a lease.
4154 * While another client holds a batch oplock.
4155 * And allows share_access of READ/WRITE/DELETE.
4157 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4159 * This expects the strange reject status of
4160 * NT_STATUS_ACCESS_DENIED, which is returned
4161 * by Windows Servers.
4163 * It won't pass against Samba as it returns
4164 * NT_STATUS_FILE_NOT_AVAILABLE. see
4165 * test_dhv2_pending3n_vs_oplock_sane.
4167 static bool test_dhv2_pending3n_vs_oplock_windows(struct torture_context *tctx,
4168 struct smb2_tree *tree1,
4169 struct smb2_tree *tree2_1)
4171 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4172 SMB2_OPLOCK_LEVEL_BATCH,
4173 SMB2_OPLOCK_LEVEL_NONE,
4174 NT_STATUS_ACCESS_DENIED,
4175 tree1, tree2_1);
4179 * This tests replay with a pending open with 4 channels
4180 * and blocked transports on the client side.
4182 * With a durablev2 request containing a create_guid,
4183 * a share_access of READ/WRITE/DELETE,
4184 * and asking for a v2 lease.
4186 * While another client holds a batch oplock.
4187 * And allows share_access of READ/WRITE/DELETE.
4189 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4191 * This expects the sane reject status of
4192 * NT_STATUS_FILE_NOT_AVAILABLE.
4194 * It won't pass against Windows as it returns
4195 * NT_STATUS_ACCESS_DENIED see
4196 * test_dhv2_pending3l_vs_oplock_windows().
4198 static bool test_dhv2_pending3l_vs_oplock_sane(struct torture_context *tctx,
4199 struct smb2_tree *tree1,
4200 struct smb2_tree *tree2_1)
4202 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4203 SMB2_OPLOCK_LEVEL_BATCH,
4204 SMB2_OPLOCK_LEVEL_LEASE,
4205 NT_STATUS_FILE_NOT_AVAILABLE,
4206 tree1, tree2_1);
4210 * This tests replay with a pending open with 4 channels
4211 * and blocked transports on the client side.
4213 * With a durablev2 request containing a create_guid,
4214 * a share_access of READ/WRITE/DELETE,
4215 * and asking for a v2 lease.
4217 * While another client holds a batch oplock.
4218 * And allows share_access of READ/WRITE/DELETE.
4220 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4222 * This expects the strange reject status of
4223 * NT_STATUS_ACCESS_DENIED, which is returned
4224 * by Windows Servers.
4226 * It won't pass against Samba as it returns
4227 * NT_STATUS_FILE_NOT_AVAILABLE. see
4228 * test_dhv2_pending3l_vs_oplock_sane.
4230 static bool test_dhv2_pending3l_vs_oplock_windows(struct torture_context *tctx,
4231 struct smb2_tree *tree1,
4232 struct smb2_tree *tree2_1)
4234 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4235 SMB2_OPLOCK_LEVEL_BATCH,
4236 SMB2_OPLOCK_LEVEL_LEASE,
4237 NT_STATUS_ACCESS_DENIED,
4238 tree1, tree2_1);
4242 * This tests replay with a pending open with 4 channels
4243 * and blocked transports on the client side.
4245 * With a durablev2 request containing a create_guid,
4246 * a share_access of READ/WRITE/DELETE,
4247 * and asking for a v2 lease.
4249 * While another client holds an RWH lease.
4250 * And allows share_access of READ/WRITE/DELETE.
4252 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4254 * This expects the sane reject status of
4255 * NT_STATUS_FILE_NOT_AVAILABLE.
4257 * It won't pass against Windows as it returns
4258 * NT_STATUS_ACCESS_DENIED see
4259 * test_dhv2_pending3l_vs_lease_windows().
4261 static bool test_dhv2_pending3l_vs_lease_sane(struct torture_context *tctx,
4262 struct smb2_tree *tree1,
4263 struct smb2_tree *tree2_1)
4265 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4266 SMB2_OPLOCK_LEVEL_LEASE,
4267 SMB2_OPLOCK_LEVEL_LEASE,
4268 NT_STATUS_FILE_NOT_AVAILABLE,
4269 tree1, tree2_1);
4273 * This tests replay with a pending open with 4 channels
4274 * and blocked transports on the client side.
4276 * With a durablev2 request containing a create_guid,
4277 * a share_access of READ/WRITE/DELETE,
4278 * and asking for a v2 lease.
4280 * While another client holds an RWH lease.
4281 * And allows share_access of READ/WRITE/DELETE.
4283 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4285 * This expects the strange reject status of
4286 * NT_STATUS_ACCESS_DENIED, which is returned
4287 * by Windows Servers.
4289 * It won't pass against Samba as it returns
4290 * NT_STATUS_FILE_NOT_AVAILABLE. see
4291 * test_dhv2_pending3l_vs_lease_sane().
4293 static bool test_dhv2_pending3l_vs_lease_windows(struct torture_context *tctx,
4294 struct smb2_tree *tree1,
4295 struct smb2_tree *tree2_1)
4297 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4298 SMB2_OPLOCK_LEVEL_LEASE,
4299 SMB2_OPLOCK_LEVEL_LEASE,
4300 NT_STATUS_ACCESS_DENIED,
4301 tree1, tree2_1);
4305 * This tests replay with a pending open with 4 channels
4306 * and blocked transports on the client side.
4308 * With a durablev2 request containing a create_guid,
4309 * a share_access of READ/WRITE/DELETE,
4310 * and asking for a batch oplock.
4312 * While another client holds a batch oplock.
4313 * And allows share_access of READ/WRITE/DELETE.
4315 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4317 * This expects the sane reject status of
4318 * NT_STATUS_FILE_NOT_AVAILABLE.
4320 * It won't pass against Windows as it returns
4321 * NT_STATUS_ACCESS_DENIED see
4322 * test_dhv2_pending3o_vs_oplock_windows().
4324 static bool test_dhv2_pending3o_vs_oplock_sane(struct torture_context *tctx,
4325 struct smb2_tree *tree1,
4326 struct smb2_tree *tree2_1)
4328 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4329 SMB2_OPLOCK_LEVEL_BATCH,
4330 SMB2_OPLOCK_LEVEL_BATCH,
4331 NT_STATUS_FILE_NOT_AVAILABLE,
4332 tree1, tree2_1);
4336 * This tests replay with a pending open with 4 channels
4337 * and blocked transports on the client side.
4339 * With a durablev2 request containing a create_guid,
4340 * a share_access of READ/WRITE/DELETE,
4341 * and asking for a batch oplock.
4343 * While another client holds a batch oplock.
4344 * And allows share_access of READ/WRITE/DELETE.
4346 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4348 * This expects the strange reject status of
4349 * NT_STATUS_ACCESS_DENIED, which is returned
4350 * by Windows Servers.
4352 * It won't pass against Samba as it returns
4353 * NT_STATUS_FILE_NOT_AVAILABLE. see
4354 * test_dhv2_pending3o_vs_oplock_sane().
4356 static bool test_dhv2_pending3o_vs_oplock_windows(struct torture_context *tctx,
4357 struct smb2_tree *tree1,
4358 struct smb2_tree *tree2_1)
4360 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4361 SMB2_OPLOCK_LEVEL_BATCH,
4362 SMB2_OPLOCK_LEVEL_BATCH,
4363 NT_STATUS_ACCESS_DENIED,
4364 tree1, tree2_1);
4368 * This tests replay with a pending open with 4 channels
4369 * and blocked transports on the client side.
4371 * With a durablev2 request containing a create_guid,
4372 * a share_access of READ/WRITE/DELETE,
4373 * and asking for a batch oplock.
4375 * While another client holds an RWH lease.
4376 * And allows share_access of READ/WRITE/DELETE.
4378 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4380 * This expects the sane reject status of
4381 * NT_STATUS_FILE_NOT_AVAILABLE.
4383 * It won't pass against Windows as it returns
4384 * NT_STATUS_ACCESS_DENIED see
4385 * test_dhv2_pending3o_vs_lease_windows().
4387 static bool test_dhv2_pending3o_vs_lease_sane(struct torture_context *tctx,
4388 struct smb2_tree *tree1,
4389 struct smb2_tree *tree2_1)
4391 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4392 SMB2_OPLOCK_LEVEL_LEASE,
4393 SMB2_OPLOCK_LEVEL_BATCH,
4394 NT_STATUS_FILE_NOT_AVAILABLE,
4395 tree1, tree2_1);
4399 * This tests replay with a pending open with 4 channels
4400 * and blocked transports on the client side.
4402 * With a durablev2 request containing a create_guid,
4403 * a share_access of READ/WRITE/DELETE,
4404 * and asking for a batch oplock.
4406 * While another client holds an RWH lease.
4407 * And allows share_access of READ/WRITE/DELETE.
4409 * See https://bugzilla.samba.org/show_bug.cgi?id=14449
4411 * This expects the strange reject status of
4412 * NT_STATUS_ACCESS_DENIED, which is returned
4413 * by Windows Servers.
4415 * It won't pass against Samba as it returns
4416 * NT_STATUS_FILE_NOT_AVAILABLE. see
4417 * test_dhv2_pending3o_vs_lease_sane().
4419 static bool test_dhv2_pending3o_vs_lease_windows(struct torture_context *tctx,
4420 struct smb2_tree *tree1,
4421 struct smb2_tree *tree2_1)
4423 return _test_dhv2_pending3_vs_hold(tctx, __func__,
4424 SMB2_OPLOCK_LEVEL_LEASE,
4425 SMB2_OPLOCK_LEVEL_BATCH,
4426 NT_STATUS_ACCESS_DENIED,
4427 tree1, tree2_1);
4430 static bool test_channel_sequence_table(struct torture_context *tctx,
4431 struct smb2_tree *tree,
4432 bool do_replay,
4433 uint16_t opcode)
4435 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
4436 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4437 struct smb2_handle handle;
4438 struct smb2_handle *phandle = NULL;
4439 struct smb2_create io;
4440 struct GUID create_guid = GUID_random();
4441 bool ret = true;
4442 const char *fname = BASEDIR "\\channel_sequence.dat";
4443 uint16_t csn = 0;
4444 uint16_t limit = UINT16_MAX - 0x7fff;
4445 int i;
4446 struct {
4447 uint16_t csn;
4448 bool csn_rand_low;
4449 bool csn_rand_high;
4450 NTSTATUS expected_status;
4451 } tests[] = {
4453 .csn = 0,
4454 .expected_status = NT_STATUS_OK,
4456 .csn = 0x7fff + 1,
4457 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
4459 .csn = 0x7fff + 2,
4460 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
4462 .csn = -1,
4463 .csn_rand_high = true,
4464 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
4466 .csn = 0xffff,
4467 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
4469 .csn = 0x7fff,
4470 .expected_status = NT_STATUS_OK,
4472 .csn = 0x7ffe,
4473 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
4475 .csn = 0,
4476 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
4478 .csn = -1,
4479 .csn_rand_low = true,
4480 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
4482 .csn = 0x7fff + 1,
4483 .expected_status = NT_STATUS_OK,
4485 .csn = 0xffff,
4486 .expected_status = NT_STATUS_OK,
4488 .csn = 0,
4489 .expected_status = NT_STATUS_OK,
4491 .csn = 1,
4492 .expected_status = NT_STATUS_OK,
4494 .csn = 0,
4495 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
4497 .csn = 1,
4498 .expected_status = NT_STATUS_OK,
4500 .csn = 0xffff,
4501 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
4505 smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);
4507 csn = smb2cli_session_current_channel_sequence(tree->session->smbXcli);
4508 torture_comment(tctx, "Testing create with channel sequence number: 0x%04x\n", csn);
4510 smb2_oplock_create_share(&io, fname,
4511 smb2_util_share_access("RWD"),
4512 smb2_util_oplock_level("b"));
4513 io.in.durable_open = false;
4514 io.in.durable_open_v2 = true;
4515 io.in.create_guid = create_guid;
4516 io.in.timeout = UINT32_MAX;
4518 torture_assert_ntstatus_ok_goto(tctx,
4519 smb2_create(tree, mem_ctx, &io),
4520 ret, done, "failed to call smb2_create");
4522 handle = io.out.file.handle;
4523 phandle = &handle;
4525 for (i=0; i <ARRAY_SIZE(tests); i++) {
4527 const char *opstr = "";
4528 union smb_fileinfo qfinfo;
4530 csn = tests[i].csn;
4532 if (tests[i].csn_rand_low) {
4533 csn = rand() % limit;
4534 } else if (tests[i].csn_rand_high) {
4535 csn = rand() % limit + 0x7fff;
4538 switch (opcode) {
4539 case SMB2_OP_WRITE:
4540 opstr = "write";
4541 break;
4542 case SMB2_OP_IOCTL:
4543 opstr = "ioctl";
4544 break;
4545 case SMB2_OP_SETINFO:
4546 opstr = "setinfo";
4547 break;
4548 default:
4549 break;
4552 smb2cli_session_reset_channel_sequence(tree->session->smbXcli, csn);
4553 csn = smb2cli_session_current_channel_sequence(tree->session->smbXcli);
4555 torture_comment(tctx, "Testing %s (replay: %s) with CSN 0x%04x, expecting: %s\n",
4556 opstr, do_replay ? "true" : "false", csn,
4557 nt_errstr(tests[i].expected_status));
4559 if (do_replay) {
4560 smb2cli_session_start_replay(tree->session->smbXcli);
4563 switch (opcode) {
4564 case SMB2_OP_WRITE: {
4565 DATA_BLOB blob = data_blob_talloc(tctx, NULL, 255);
4567 generate_random_buffer(blob.data, blob.length);
4569 status = smb2_util_write(tree, handle, blob.data, 0, blob.length);
4570 if (NT_STATUS_IS_OK(status)) {
4571 struct smb2_read rd;
4573 rd = (struct smb2_read) {
4574 .in.file.handle = handle,
4575 .in.length = blob.length,
4576 .in.offset = 0
4579 torture_assert_ntstatus_ok_goto(tctx,
4580 smb2_read(tree, tree, &rd),
4581 ret, done, "failed to read after write");
4583 torture_assert_data_blob_equal(tctx,
4584 rd.out.data, blob,
4585 "read/write mismatch");
4587 break;
4589 case SMB2_OP_IOCTL: {
4590 union smb_ioctl ioctl;
4591 ioctl = (union smb_ioctl) {
4592 .smb2.level = RAW_IOCTL_SMB2,
4593 .smb2.in.file.handle = handle,
4594 .smb2.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID,
4595 .smb2.in.max_output_response = 64,
4596 .smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL
4598 status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
4599 break;
4601 case SMB2_OP_SETINFO: {
4602 union smb_setfileinfo sfinfo;
4603 ZERO_STRUCT(sfinfo);
4604 sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
4605 sfinfo.generic.in.file.handle = handle;
4606 sfinfo.position_information.in.position = 0x1000;
4607 status = smb2_setinfo_file(tree, &sfinfo);
4608 break;
4610 default:
4611 break;
4614 qfinfo = (union smb_fileinfo) {
4615 .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
4616 .generic.in.file.handle = handle
4619 torture_assert_ntstatus_ok_goto(tctx,
4620 smb2_getinfo_file(tree, mem_ctx, &qfinfo),
4621 ret, done, "failed to read after write");
4623 if (do_replay) {
4624 smb2cli_session_stop_replay(tree->session->smbXcli);
4627 torture_assert_ntstatus_equal_goto(tctx,
4628 status, tests[i].expected_status,
4629 ret, done, "got unexpected failure code");
4632 done:
4633 if (phandle != NULL) {
4634 smb2_util_close(tree, *phandle);
4637 smb2_util_unlink(tree, fname);
4639 return ret;
4642 static bool test_channel_sequence(struct torture_context *tctx,
4643 struct smb2_tree *tree)
4645 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4646 bool ret = true;
4647 const char *fname = BASEDIR "\\channel_sequence.dat";
4648 struct smb2_transport *transport1 = tree->session->transport;
4649 struct smb2_handle handle;
4650 uint16_t opcodes[] = { SMB2_OP_WRITE, SMB2_OP_IOCTL, SMB2_OP_SETINFO };
4651 int i;
4653 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
4654 torture_skip(tctx, "SMB 3.X Dialect family required for "
4655 "Replay tests\n");
4658 torture_comment(tctx, "Testing channel sequence numbers\n");
4660 smbXcli_conn_set_force_channel_sequence(transport1->conn, true);
4662 torture_assert_ntstatus_ok_goto(tctx,
4663 torture_smb2_testdir(tree, BASEDIR, &handle),
4664 ret, done, "failed to setup test directory");
4666 smb2_util_close(tree, handle);
4667 smb2_util_unlink(tree, fname);
4669 for (i=0; i <ARRAY_SIZE(opcodes); i++) {
4670 torture_assert(tctx,
4671 test_channel_sequence_table(tctx, tree, false, opcodes[i]),
4672 "failed to test CSN without replay flag");
4673 torture_assert(tctx,
4674 test_channel_sequence_table(tctx, tree, true, opcodes[i]),
4675 "failed to test CSN with replay flag");
4678 done:
4680 smb2_util_unlink(tree, fname);
4681 smb2_deltree(tree, BASEDIR);
4683 talloc_free(tree);
4684 talloc_free(mem_ctx);
4686 return ret;
4690 * Test Durability V2 Create Replay Detection on Multi Channel
4692 static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1)
4694 const char *host = torture_setting_string(tctx, "host", NULL);
4695 const char *share = torture_setting_string(tctx, "share", NULL);
4696 NTSTATUS status;
4697 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4698 struct smb2_handle _h;
4699 struct smb2_handle *h = NULL;
4700 struct smb2_create io;
4701 struct GUID create_guid = GUID_random();
4702 bool ret = true;
4703 const char *fname = BASEDIR "\\replay3.dat";
4704 struct smb2_tree *tree2 = NULL;
4705 struct smb2_transport *transport1 = tree1->session->transport;
4706 struct smb2_transport *transport2 = NULL;
4707 struct smb2_session *session1_1 = tree1->session;
4708 struct smb2_session *session1_2 = NULL;
4709 uint32_t share_capabilities;
4710 bool share_is_so;
4711 uint32_t server_capabilities;
4713 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
4714 torture_skip(tctx, "SMB 3.X Dialect family required for "
4715 "Replay tests\n");
4718 server_capabilities = smb2cli_conn_server_capabilities(
4719 tree1->session->transport->conn);
4720 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
4721 torture_skip(tctx,
4722 "Server does not support multi-channel.");
4725 share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
4726 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
4728 torture_reset_break_info(tctx, &break_info);
4729 transport1->oplock.handler = torture_oplock_ack_handler;
4730 transport1->oplock.private_data = tree1;
4732 torture_comment(tctx, "Replay of DurableHandleReqV2 on Multi "
4733 "Channel\n");
4734 status = torture_smb2_testdir(tree1, BASEDIR, &_h);
4735 CHECK_STATUS(status, NT_STATUS_OK);
4736 smb2_util_close(tree1, _h);
4737 smb2_util_unlink(tree1, fname);
4738 CHECK_VAL(break_info.count, 0);
4741 * use the 1st channel, 1st session
4743 smb2_oplock_create_share(&io, fname,
4744 smb2_util_share_access(""),
4745 smb2_util_oplock_level("b"));
4746 io.in.durable_open = false;
4747 io.in.durable_open_v2 = true;
4748 io.in.persistent_open = false;
4749 io.in.create_guid = create_guid;
4750 io.in.timeout = UINT32_MAX;
4752 tree1->session = session1_1;
4753 status = smb2_create(tree1, mem_ctx, &io);
4754 CHECK_STATUS(status, NT_STATUS_OK);
4755 _h = io.out.file.handle;
4756 h = &_h;
4757 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4758 if (share_is_so) {
4759 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
4760 CHECK_VAL(io.out.durable_open_v2, false);
4761 CHECK_VAL(io.out.timeout, 0);
4762 } else {
4763 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
4764 CHECK_VAL(io.out.durable_open_v2, true);
4765 CHECK_VAL(io.out.timeout, 300*1000);
4767 CHECK_VAL(io.out.durable_open, false);
4768 CHECK_VAL(break_info.count, 0);
4770 status = smb2_connect(tctx,
4771 host,
4772 lpcfg_smb_ports(tctx->lp_ctx),
4773 share,
4774 lpcfg_resolve_context(tctx->lp_ctx),
4775 samba_cmdline_get_creds(),
4776 &tree2,
4777 tctx->ev,
4778 &transport1->options,
4779 lpcfg_socket_options(tctx->lp_ctx),
4780 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
4782 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4783 "smb2_connect failed");
4784 transport2 = tree2->session->transport;
4786 transport2->oplock.handler = torture_oplock_ack_handler;
4787 transport2->oplock.private_data = tree2;
4790 * Now bind the 1st session to 2nd transport channel
4792 session1_2 = smb2_session_channel(transport2,
4793 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
4794 tree2, session1_1);
4795 torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
4797 status = smb2_session_setup_spnego(session1_2,
4798 samba_cmdline_get_creds(),
4799 0 /* previous_session_id */);
4800 CHECK_STATUS(status, NT_STATUS_OK);
4803 * use the 2nd channel, 1st session
4805 tree1->session = session1_2;
4806 smb2cli_session_start_replay(tree1->session->smbXcli);
4807 status = smb2_create(tree1, mem_ctx, &io);
4808 smb2cli_session_stop_replay(tree1->session->smbXcli);
4809 CHECK_STATUS(status, NT_STATUS_OK);
4810 _h = io.out.file.handle;
4811 h = &_h;
4812 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4813 if (share_is_so) {
4814 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
4815 CHECK_VAL(io.out.durable_open_v2, false);
4816 CHECK_VAL(io.out.timeout, 0);
4817 } else {
4818 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
4819 CHECK_VAL(io.out.durable_open_v2, true);
4820 CHECK_VAL(io.out.timeout, 300*1000);
4822 CHECK_VAL(io.out.durable_open, false);
4823 CHECK_VAL(break_info.count, 0);
4825 tree1->session = session1_1;
4826 smb2_util_close(tree1, *h);
4827 h = NULL;
4829 done:
4830 talloc_free(tree2);
4831 tree1->session = session1_1;
4833 if (h != NULL) {
4834 smb2_util_close(tree1, *h);
4837 smb2_util_unlink(tree1, fname);
4838 smb2_deltree(tree1, BASEDIR);
4840 talloc_free(tree1);
4841 talloc_free(mem_ctx);
4843 return ret;
4847 * Test Multichannel IO Ordering using ChannelSequence/Channel Epoch number
4849 static bool test_replay4(struct torture_context *tctx, struct smb2_tree *tree1)
4851 const char *host = torture_setting_string(tctx, "host", NULL);
4852 const char *share = torture_setting_string(tctx, "share", NULL);
4853 NTSTATUS status;
4854 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4855 struct smb2_handle _h1;
4856 struct smb2_handle *h1 = NULL;
4857 struct smb2_create io;
4858 struct GUID create_guid = GUID_random();
4859 uint8_t buf[64];
4860 struct smb2_read rd;
4861 union smb_setfileinfo sfinfo;
4862 bool ret = true;
4863 const char *fname = BASEDIR "\\replay4.dat";
4864 struct smb2_tree *tree2 = NULL;
4865 struct smb2_transport *transport1 = tree1->session->transport;
4866 struct smb2_transport *transport2 = NULL;
4867 struct smb2_session *session1_1 = tree1->session;
4868 struct smb2_session *session1_2 = NULL;
4869 uint16_t curr_cs;
4870 uint32_t share_capabilities;
4871 bool share_is_so;
4872 uint32_t server_capabilities;
4874 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
4875 torture_skip(tctx, "SMB 3.X Dialect family required for "
4876 "Replay tests\n");
4879 server_capabilities = smb2cli_conn_server_capabilities(
4880 tree1->session->transport->conn);
4881 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
4882 torture_skip(tctx,
4883 "Server does not support multi-channel.");
4886 share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
4887 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
4889 torture_reset_break_info(tctx, &break_info);
4890 transport1->oplock.handler = torture_oplock_ack_handler;
4891 transport1->oplock.private_data = tree1;
4893 torture_comment(tctx, "IO Ordering for Multi Channel\n");
4894 status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
4895 CHECK_STATUS(status, NT_STATUS_OK);
4896 smb2_util_close(tree1, _h1);
4897 smb2_util_unlink(tree1, fname);
4898 CHECK_VAL(break_info.count, 0);
4901 * use the 1st channel, 1st session
4904 smb2_oplock_create_share(&io, fname,
4905 smb2_util_share_access(""),
4906 smb2_util_oplock_level("b"));
4907 io.in.durable_open = false;
4908 io.in.durable_open_v2 = true;
4909 io.in.persistent_open = false;
4910 io.in.create_guid = create_guid;
4911 io.in.timeout = UINT32_MAX;
4913 tree1->session = session1_1;
4914 status = smb2_create(tree1, mem_ctx, &io);
4915 CHECK_STATUS(status, NT_STATUS_OK);
4916 _h1 = io.out.file.handle;
4917 h1 = &_h1;
4918 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4919 if (share_is_so) {
4920 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
4921 CHECK_VAL(io.out.durable_open_v2, false);
4922 CHECK_VAL(io.out.timeout, 0);
4923 } else {
4924 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
4925 CHECK_VAL(io.out.durable_open_v2, true);
4926 CHECK_VAL(io.out.timeout, 300*1000);
4928 CHECK_VAL(io.out.durable_open, false);
4929 CHECK_VAL(break_info.count, 0);
4931 status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
4932 CHECK_STATUS(status, NT_STATUS_OK);
4935 * Increment ChannelSequence so that server thinks that there's a
4936 * Channel Failure
4938 smb2cli_session_increment_channel_sequence(tree1->session->smbXcli);
4941 * Perform a Read with incremented ChannelSequence
4943 rd = (struct smb2_read) {
4944 .in.file.handle = *h1,
4945 .in.length = sizeof(buf),
4946 .in.offset = 0
4948 status = smb2_read(tree1, tree1, &rd);
4949 CHECK_STATUS(status, NT_STATUS_OK);
4952 * Performing a Write with Stale ChannelSequence is not allowed by
4953 * server
4955 curr_cs = smb2cli_session_reset_channel_sequence(
4956 tree1->session->smbXcli, 0);
4957 status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
4958 CHECK_STATUS(status, NT_STATUS_FILE_NOT_AVAILABLE);
4961 * Performing a Write Replay with Stale ChannelSequence is not allowed
4962 * by server
4964 smb2cli_session_start_replay(tree1->session->smbXcli);
4965 smb2cli_session_reset_channel_sequence(tree1->session->smbXcli, 0);
4966 status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
4967 smb2cli_session_stop_replay(tree1->session->smbXcli);
4968 CHECK_STATUS(status, NT_STATUS_FILE_NOT_AVAILABLE);
4971 * Performing a SetInfo with stale ChannelSequence is not allowed by
4972 * server
4974 ZERO_STRUCT(sfinfo);
4975 sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
4976 sfinfo.generic.in.file.handle = *h1;
4977 sfinfo.position_information.in.position = 0x1000;
4978 status = smb2_setinfo_file(tree1, &sfinfo);
4979 CHECK_STATUS(status, NT_STATUS_FILE_NOT_AVAILABLE);
4982 * Performing a Read with stale ChannelSequence is allowed
4984 rd = (struct smb2_read) {
4985 .in.file.handle = *h1,
4986 .in.length = ARRAY_SIZE(buf),
4987 .in.offset = 0
4989 status = smb2_read(tree1, tree1, &rd);
4990 CHECK_STATUS(status, NT_STATUS_OK);
4992 status = smb2_connect(tctx,
4993 host,
4994 lpcfg_smb_ports(tctx->lp_ctx),
4995 share,
4996 lpcfg_resolve_context(tctx->lp_ctx),
4997 samba_cmdline_get_creds(),
4998 &tree2,
4999 tctx->ev,
5000 &transport1->options,
5001 lpcfg_socket_options(tctx->lp_ctx),
5002 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
5004 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5005 "smb2_connect failed");
5006 transport2 = tree2->session->transport;
5008 transport2->oplock.handler = torture_oplock_ack_handler;
5009 transport2->oplock.private_data = tree2;
5012 * Now bind the 1st session to 2nd transport channel
5014 session1_2 = smb2_session_channel(transport2,
5015 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
5016 tree2, session1_1);
5017 torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
5019 status = smb2_session_setup_spnego(session1_2,
5020 samba_cmdline_get_creds(),
5021 0 /* previous_session_id */);
5022 CHECK_STATUS(status, NT_STATUS_OK);
5025 * use the 2nd channel, 1st session
5027 tree1->session = session1_2;
5030 * Write Replay with Correct ChannelSequence is allowed by the server
5032 smb2cli_session_start_replay(tree1->session->smbXcli);
5033 smb2cli_session_reset_channel_sequence(tree1->session->smbXcli,
5034 curr_cs);
5035 status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
5036 CHECK_STATUS(status, NT_STATUS_OK);
5037 smb2cli_session_stop_replay(tree1->session->smbXcli);
5040 * See what happens if we change the Buffer and perform a Write Replay.
5041 * This is to show that Write Replay does not really care about the data
5043 memset(buf, 'r', ARRAY_SIZE(buf));
5044 smb2cli_session_start_replay(tree1->session->smbXcli);
5045 status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
5046 CHECK_STATUS(status, NT_STATUS_OK);
5047 smb2cli_session_stop_replay(tree1->session->smbXcli);
5050 * Read back from File to verify what was written
5052 rd = (struct smb2_read) {
5053 .in.file.handle = *h1,
5054 .in.length = ARRAY_SIZE(buf),
5055 .in.offset = 0
5057 status = smb2_read(tree1, tree1, &rd);
5058 CHECK_STATUS(status, NT_STATUS_OK);
5060 if ((rd.out.data.length != ARRAY_SIZE(buf)) ||
5061 memcmp(rd.out.data.data, buf, ARRAY_SIZE(buf))) {
5062 torture_comment(tctx, "Write Replay Data Mismatch\n");
5065 tree1->session = session1_1;
5066 smb2_util_close(tree1, *h1);
5067 h1 = NULL;
5069 if (share_is_so) {
5070 CHECK_VAL(break_info.count, 1);
5071 } else {
5072 CHECK_VAL(break_info.count, 0);
5074 done:
5075 talloc_free(tree2);
5076 tree1->session = session1_1;
5078 if (h1 != NULL) {
5079 smb2_util_close(tree1, *h1);
5082 smb2_util_unlink(tree1, fname);
5083 smb2_deltree(tree1, BASEDIR);
5085 talloc_free(tree1);
5086 talloc_free(mem_ctx);
5088 return ret;
5092 * Test Durability V2 Persistent Create Replay on a Single Channel
5094 static bool test_replay5(struct torture_context *tctx, struct smb2_tree *tree)
5096 NTSTATUS status;
5097 TALLOC_CTX *mem_ctx = talloc_new(tctx);
5098 struct smb2_handle _h;
5099 struct smb2_handle *h = NULL;
5100 struct smb2_create io;
5101 struct GUID create_guid = GUID_random();
5102 bool ret = true;
5103 uint32_t share_capabilities;
5104 bool share_is_ca;
5105 bool share_is_so;
5106 uint32_t server_capabilities;
5107 const char *fname = BASEDIR "\\replay5.dat";
5108 struct smb2_transport *transport = tree->session->transport;
5109 struct smbcli_options options = tree->session->transport->options;
5110 uint8_t expect_oplock = smb2_util_oplock_level("b");
5111 NTSTATUS expect_status = NT_STATUS_DUPLICATE_OBJECTID;
5113 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
5114 torture_skip(tctx, "SMB 3.X Dialect family required for "
5115 "Replay tests\n");
5118 server_capabilities = smb2cli_conn_server_capabilities(
5119 tree->session->transport->conn);
5120 if (!(server_capabilities & SMB2_CAP_PERSISTENT_HANDLES)) {
5121 torture_skip(tctx,
5122 "Server does not support persistent handles.");
5125 share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
5127 share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
5128 if (!share_is_ca) {
5129 torture_skip(tctx, "Share is not continuously available.");
5132 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
5133 if (share_is_so) {
5134 expect_oplock = smb2_util_oplock_level("s");
5135 expect_status = NT_STATUS_FILE_NOT_AVAILABLE;
5138 torture_reset_break_info(tctx, &break_info);
5139 transport->oplock.handler = torture_oplock_ack_handler;
5140 transport->oplock.private_data = tree;
5142 torture_comment(tctx, "Replay of Persistent DurableHandleReqV2 on Single "
5143 "Channel\n");
5144 status = torture_smb2_testdir(tree, BASEDIR, &_h);
5145 CHECK_STATUS(status, NT_STATUS_OK);
5146 smb2_util_close(tree, _h);
5147 smb2_util_unlink(tree, fname);
5148 CHECK_VAL(break_info.count, 0);
5150 smb2_oplock_create_share(&io, fname,
5151 smb2_util_share_access("RWD"),
5152 smb2_util_oplock_level("b"));
5153 io.in.durable_open = false;
5154 io.in.durable_open_v2 = true;
5155 io.in.persistent_open = true;
5156 io.in.create_guid = create_guid;
5157 io.in.timeout = UINT32_MAX;
5159 status = smb2_create(tree, mem_ctx, &io);
5160 CHECK_STATUS(status, NT_STATUS_OK);
5161 _h = io.out.file.handle;
5162 h = &_h;
5163 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
5164 CHECK_VAL(io.out.oplock_level, expect_oplock);
5165 CHECK_VAL(io.out.durable_open, false);
5166 CHECK_VAL(io.out.durable_open_v2, true);
5167 CHECK_VAL(io.out.persistent_open, true);
5168 CHECK_VAL(io.out.timeout, 300*1000);
5169 CHECK_VAL(break_info.count, 0);
5171 /* disconnect, leaving the durable open */
5172 TALLOC_FREE(tree);
5174 if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
5175 torture_warning(tctx, "couldn't reconnect, bailing\n");
5176 ret = false;
5177 goto done;
5180 /* a re-open of a persistent handle causes an error */
5181 status = smb2_create(tree, mem_ctx, &io);
5182 CHECK_STATUS(status, expect_status);
5184 /* SMB2_FLAGS_REPLAY_OPERATION must be set to open the Persistent Handle */
5185 smb2cli_session_start_replay(tree->session->smbXcli);
5186 smb2cli_session_increment_channel_sequence(tree->session->smbXcli);
5187 status = smb2_create(tree, mem_ctx, &io);
5188 CHECK_STATUS(status, NT_STATUS_OK);
5189 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
5190 CHECK_VAL(io.out.durable_open, false);
5191 CHECK_VAL(io.out.persistent_open, true);
5192 CHECK_VAL(io.out.oplock_level, expect_oplock);
5193 _h = io.out.file.handle;
5194 h = &_h;
5196 smb2_util_close(tree, *h);
5197 h = NULL;
5198 done:
5199 if (h != NULL) {
5200 smb2_util_close(tree, *h);
5203 smb2_util_unlink(tree, fname);
5204 smb2_deltree(tree, BASEDIR);
5206 talloc_free(tree);
5207 talloc_free(mem_ctx);
5209 return ret;
5214 * Test Error Codes when a DurableHandleReqV2 with matching CreateGuid is
5215 * re-sent with or without SMB2_FLAGS_REPLAY_OPERATION
5217 static bool test_replay6(struct torture_context *tctx, struct smb2_tree *tree)
5219 NTSTATUS status;
5220 TALLOC_CTX *mem_ctx = talloc_new(tctx);
5221 struct smb2_handle _h;
5222 struct smb2_handle *h = NULL;
5223 struct smb2_create io, ref1;
5224 union smb_fileinfo qfinfo;
5225 struct GUID create_guid = GUID_random();
5226 bool ret = true;
5227 const char *fname = BASEDIR "\\replay6.dat";
5228 struct smb2_transport *transport = tree->session->transport;
5230 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
5231 torture_skip(tctx, "SMB 3.X Dialect family required for "
5232 "replay tests\n");
5235 torture_reset_break_info(tctx, &break_info);
5236 tree->session->transport->oplock.handler = torture_oplock_ack_handler;
5237 tree->session->transport->oplock.private_data = tree;
5239 torture_comment(tctx, "Error Codes for DurableHandleReqV2 Replay\n");
5240 smb2_util_unlink(tree, fname);
5241 status = torture_smb2_testdir(tree, BASEDIR, &_h);
5242 CHECK_STATUS(status, NT_STATUS_OK);
5243 smb2_util_close(tree, _h);
5244 torture_wait_for_oplock_break(tctx);
5245 CHECK_VAL(break_info.count, 0);
5246 torture_reset_break_info(tctx, &break_info);
5248 smb2_oplock_create_share(&io, fname,
5249 smb2_util_share_access("RWD"),
5250 smb2_util_oplock_level("b"));
5251 io.in.durable_open = false;
5252 io.in.durable_open_v2 = true;
5253 io.in.persistent_open = false;
5254 io.in.create_guid = create_guid;
5255 io.in.timeout = UINT32_MAX;
5257 status = smb2_create(tree, mem_ctx, &io);
5258 CHECK_STATUS(status, NT_STATUS_OK);
5259 ref1 = io;
5260 _h = io.out.file.handle;
5261 h = &_h;
5262 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
5263 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
5264 CHECK_VAL(io.out.durable_open, false);
5265 CHECK_VAL(io.out.durable_open_v2, true);
5267 io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
5268 io.in.create_disposition = NTCREATEX_DISP_OPEN;
5269 smb2cli_session_start_replay(tree->session->smbXcli);
5270 status = smb2_create(tree, mem_ctx, &io);
5271 smb2cli_session_stop_replay(tree->session->smbXcli);
5272 CHECK_STATUS(status, NT_STATUS_OK);
5273 CHECK_CREATE_OUT(&io, &ref1);
5274 torture_wait_for_oplock_break(tctx);
5275 CHECK_VAL(break_info.count, 0);
5276 torture_reset_break_info(tctx, &break_info);
5278 qfinfo = (union smb_fileinfo) {
5279 .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
5280 .generic.in.file.handle = *h
5282 torture_comment(tctx, "Trying getinfo\n");
5283 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
5284 CHECK_STATUS(status, NT_STATUS_OK);
5285 CHECK_VAL(qfinfo.position_information.out.position, 0);
5287 smb2cli_session_start_replay(tree->session->smbXcli);
5288 status = smb2_create(tree, mem_ctx, &io);
5289 smb2cli_session_stop_replay(tree->session->smbXcli);
5290 CHECK_STATUS(status, NT_STATUS_OK);
5291 torture_assert_u64_not_equal_goto(tctx,
5292 io.out.file.handle.data[0],
5293 ref1.out.file.handle.data[0],
5294 ret, done, "data 0");
5295 torture_assert_u64_not_equal_goto(tctx,
5296 io.out.file.handle.data[1],
5297 ref1.out.file.handle.data[1],
5298 ret, done, "data 1");
5299 torture_wait_for_oplock_break(tctx);
5300 CHECK_VAL(break_info.count, 1);
5301 CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
5302 torture_reset_break_info(tctx, &break_info);
5305 * Resend the matching Durable V2 Create without
5306 * SMB2_FLAGS_REPLAY_OPERATION. This triggers an oplock break and still
5307 * gets NT_STATUS_DUPLICATE_OBJECTID
5309 status = smb2_create(tree, mem_ctx, &io);
5310 CHECK_STATUS(status, NT_STATUS_DUPLICATE_OBJECTID);
5311 torture_wait_for_oplock_break(tctx);
5312 CHECK_VAL(break_info.count, 0);
5313 torture_reset_break_info(tctx, &break_info);
5316 * According to MS-SMB2 3.3.5.9.10 if Durable V2 Create is replayed and
5317 * FileAttributes or CreateDisposition do not match the earlier Create
5318 * request the Server fails request with
5319 * NT_STATUS_INVALID_PARAMETER. But through this test we see that server
5320 * does not really care about changed FileAttributes or
5321 * CreateDisposition.
5323 io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
5324 io.in.create_disposition = NTCREATEX_DISP_OPEN;
5325 smb2cli_session_start_replay(tree->session->smbXcli);
5326 status = smb2_create(tree, mem_ctx, &io);
5327 smb2cli_session_stop_replay(tree->session->smbXcli);
5328 CHECK_STATUS(status, NT_STATUS_OK);
5329 torture_assert_u64_not_equal_goto(tctx,
5330 io.out.file.handle.data[0],
5331 ref1.out.file.handle.data[0],
5332 ret, done, "data 0");
5333 torture_assert_u64_not_equal_goto(tctx,
5334 io.out.file.handle.data[1],
5335 ref1.out.file.handle.data[1],
5336 ret, done, "data 1");
5337 torture_wait_for_oplock_break(tctx);
5338 CHECK_VAL(break_info.count, 0);
5340 done:
5341 if (h != NULL) {
5342 smb2_util_close(tree, *h);
5345 smb2_util_unlink(tree, fname);
5346 smb2_deltree(tree, BASEDIR);
5348 talloc_free(tree);
5349 talloc_free(mem_ctx);
5351 return ret;
5354 static bool test_replay7(struct torture_context *tctx, struct smb2_tree *tree)
5356 TALLOC_CTX *mem_ctx = talloc_new(tctx);
5357 struct smb2_transport *transport = tree->session->transport;
5358 NTSTATUS status;
5359 struct smb2_handle _dh;
5360 struct smb2_handle *dh = NULL;
5361 struct smb2_notify notify;
5362 struct smb2_request *req;
5363 union smb_fileinfo qfinfo;
5364 bool ret = false;
5366 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
5367 torture_skip(tctx, "SMB 3.X Dialect family required for "
5368 "replay tests\n");
5371 torture_comment(tctx, "Notify across increment/decrement of csn\n");
5373 smbXcli_conn_set_force_channel_sequence(transport->conn, true);
5375 status = torture_smb2_testdir(tree, BASEDIR, &_dh);
5376 CHECK_STATUS(status, NT_STATUS_OK);
5377 dh = &_dh;
5379 notify.in.recursive = 0x0000;
5380 notify.in.buffer_size = 0xffff;
5381 notify.in.file.handle = _dh;
5382 notify.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
5383 notify.in.unknown = 0x00000000;
5386 * This posts a long-running request with csn==0 to "dh". Now
5387 * op->request_count==1 in smb2_server.c.
5389 smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);
5390 req = smb2_notify_send(tree, &notify);
5392 qfinfo = (union smb_fileinfo) {
5393 .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
5394 .generic.in.file.handle = _dh
5398 * This sequence of 2 dummy requests moves
5399 * op->request_count==1 to op->pre_request_count. The numbers
5400 * used avoid int16 overflow.
5403 smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 30000);
5404 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
5405 CHECK_STATUS(status, NT_STATUS_OK);
5407 smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 60000);
5408 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
5409 CHECK_STATUS(status, NT_STATUS_OK);
5412 * This final request turns the op->global->channel_sequence
5413 * to the same as we had when sending the notify above. The
5414 * notify's request count has in the meantime moved to
5415 * op->pre_request_count.
5418 smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);
5419 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
5420 CHECK_STATUS(status, NT_STATUS_OK);
5423 * At this point op->request_count==0.
5425 * The next cancel makes us reply to the notify. Because the
5426 * csn we currently use is the same as we used when sending
5427 * the notify, smbd thinks it must decrement op->request_count
5428 * and not op->pre_request_count.
5431 status = smb2_cancel(req);
5432 CHECK_STATUS(status, NT_STATUS_OK);
5434 status = smb2_notify_recv(req, mem_ctx, &notify);
5435 CHECK_STATUS(status, NT_STATUS_CANCELLED);
5437 ret = true;
5439 done:
5440 if (dh != NULL) {
5441 smb2_util_close(tree, _dh);
5443 smb2_deltree(tree, BASEDIR);
5444 talloc_free(tree);
5445 talloc_free(mem_ctx);
5447 return ret;
5450 struct torture_suite *torture_smb2_replay_init(TALLOC_CTX *ctx)
5452 struct torture_suite *suite =
5453 torture_suite_create(ctx, "replay");
5455 torture_suite_add_1smb2_test(suite, "replay-commands", test_replay_commands);
5456 torture_suite_add_1smb2_test(suite, "replay-regular", test_replay_regular);
5457 torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock1", test_replay_dhv2_oplock1);
5458 torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock2", test_replay_dhv2_oplock2);
5459 torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock3", test_replay_dhv2_oplock3);
5460 torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock-lease", test_replay_dhv2_oplock_lease);
5461 torture_suite_add_1smb2_test(suite, "replay-dhv2-lease1", test_replay_dhv2_lease1);
5462 torture_suite_add_1smb2_test(suite, "replay-dhv2-lease2", test_replay_dhv2_lease2);
5463 torture_suite_add_1smb2_test(suite, "replay-dhv2-lease3", test_replay_dhv2_lease3);
5464 torture_suite_add_1smb2_test(suite, "replay-dhv2-lease-oplock", test_replay_dhv2_lease_oplock);
5465 torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-violation-lease-close-sane", test_dhv2_pending1n_vs_violation_lease_close_sane);
5466 torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-violation-lease-ack-sane", test_dhv2_pending1n_vs_violation_lease_ack_sane);
5467 torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-violation-lease-close-windows", test_dhv2_pending1n_vs_violation_lease_close_windows);
5468 torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-violation-lease-ack-windows", test_dhv2_pending1n_vs_violation_lease_ack_windows);
5469 torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-oplock-sane", test_dhv2_pending1n_vs_oplock_sane);
5470 torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-oplock-windows", test_dhv2_pending1n_vs_oplock_windows);
5471 torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-lease-sane", test_dhv2_pending1n_vs_lease_sane);
5472 torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-lease-windows", test_dhv2_pending1n_vs_lease_windows);
5473 torture_suite_add_2smb2_test(suite, "dhv2-pending1l-vs-oplock-sane", test_dhv2_pending1l_vs_oplock_sane);
5474 torture_suite_add_2smb2_test(suite, "dhv2-pending1l-vs-oplock-windows", test_dhv2_pending1l_vs_oplock_windows);
5475 torture_suite_add_2smb2_test(suite, "dhv2-pending1l-vs-lease-sane", test_dhv2_pending1l_vs_lease_sane);
5476 torture_suite_add_2smb2_test(suite, "dhv2-pending1l-vs-lease-windows", test_dhv2_pending1l_vs_lease_windows);
5477 torture_suite_add_2smb2_test(suite, "dhv2-pending1o-vs-oplock-sane", test_dhv2_pending1o_vs_oplock_sane);
5478 torture_suite_add_2smb2_test(suite, "dhv2-pending1o-vs-oplock-windows", test_dhv2_pending1o_vs_oplock_windows);
5479 torture_suite_add_2smb2_test(suite, "dhv2-pending1o-vs-lease-sane", test_dhv2_pending1o_vs_lease_sane);
5480 torture_suite_add_2smb2_test(suite, "dhv2-pending1o-vs-lease-windows", test_dhv2_pending1o_vs_lease_windows);
5481 torture_suite_add_2smb2_test(suite, "dhv2-pending2n-vs-oplock-sane", test_dhv2_pending2n_vs_oplock_sane);
5482 torture_suite_add_2smb2_test(suite, "dhv2-pending2n-vs-oplock-windows", test_dhv2_pending2n_vs_oplock_windows);
5483 torture_suite_add_2smb2_test(suite, "dhv2-pending2n-vs-lease-sane", test_dhv2_pending2n_vs_lease_sane);
5484 torture_suite_add_2smb2_test(suite, "dhv2-pending2n-vs-lease-windows", test_dhv2_pending2n_vs_lease_windows);
5485 torture_suite_add_2smb2_test(suite, "dhv2-pending2l-vs-oplock-sane", test_dhv2_pending2l_vs_oplock_sane);
5486 torture_suite_add_2smb2_test(suite, "dhv2-pending2l-vs-oplock-windows", test_dhv2_pending2l_vs_oplock_windows);
5487 torture_suite_add_2smb2_test(suite, "dhv2-pending2l-vs-lease-sane", test_dhv2_pending2l_vs_lease_sane);
5488 torture_suite_add_2smb2_test(suite, "dhv2-pending2l-vs-lease-windows", test_dhv2_pending2l_vs_lease_windows);
5489 torture_suite_add_2smb2_test(suite, "dhv2-pending2o-vs-oplock-sane", test_dhv2_pending2o_vs_oplock_sane);
5490 torture_suite_add_2smb2_test(suite, "dhv2-pending2o-vs-oplock-windows", test_dhv2_pending2o_vs_oplock_windows);
5491 torture_suite_add_2smb2_test(suite, "dhv2-pending2o-vs-lease-sane", test_dhv2_pending2o_vs_lease_sane);
5492 torture_suite_add_2smb2_test(suite, "dhv2-pending2o-vs-lease-windows", test_dhv2_pending2o_vs_lease_windows);
5493 torture_suite_add_2smb2_test(suite, "dhv2-pending3n-vs-oplock-sane", test_dhv2_pending3n_vs_oplock_sane);
5494 torture_suite_add_2smb2_test(suite, "dhv2-pending3n-vs-oplock-windows", test_dhv2_pending3n_vs_oplock_windows);
5495 torture_suite_add_2smb2_test(suite, "dhv2-pending3n-vs-lease-sane", test_dhv2_pending3n_vs_lease_sane);
5496 torture_suite_add_2smb2_test(suite, "dhv2-pending3n-vs-lease-windows", test_dhv2_pending3n_vs_lease_windows);
5497 torture_suite_add_2smb2_test(suite, "dhv2-pending3l-vs-oplock-sane", test_dhv2_pending3l_vs_oplock_sane);
5498 torture_suite_add_2smb2_test(suite, "dhv2-pending3l-vs-oplock-windows", test_dhv2_pending3l_vs_oplock_windows);
5499 torture_suite_add_2smb2_test(suite, "dhv2-pending3l-vs-lease-sane", test_dhv2_pending3l_vs_lease_sane);
5500 torture_suite_add_2smb2_test(suite, "dhv2-pending3l-vs-lease-windows", test_dhv2_pending3l_vs_lease_windows);
5501 torture_suite_add_2smb2_test(suite, "dhv2-pending3o-vs-oplock-sane", test_dhv2_pending3o_vs_oplock_sane);
5502 torture_suite_add_2smb2_test(suite, "dhv2-pending3o-vs-oplock-windows", test_dhv2_pending3o_vs_oplock_windows);
5503 torture_suite_add_2smb2_test(suite, "dhv2-pending3o-vs-lease-sane", test_dhv2_pending3o_vs_lease_sane);
5504 torture_suite_add_2smb2_test(suite, "dhv2-pending3o-vs-lease-windows", test_dhv2_pending3o_vs_lease_windows);
5505 torture_suite_add_1smb2_test(suite, "channel-sequence", test_channel_sequence);
5506 torture_suite_add_1smb2_test(suite, "replay3", test_replay3);
5507 torture_suite_add_1smb2_test(suite, "replay4", test_replay4);
5508 torture_suite_add_1smb2_test(suite, "replay5", test_replay5);
5509 torture_suite_add_1smb2_test(suite, "replay6", test_replay6);
5510 torture_suite_add_1smb2_test(suite, "replay7", test_replay7);
5512 suite->description = talloc_strdup(suite, "SMB2 REPLAY tests");
5514 return suite;