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/>.
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/popt_common.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"
36 #define CHECK_VAL(v, correct) do { \
37 if ((v) != (correct)) { \
38 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
39 __location__, #v, (int)v, (int)correct); \
44 #define CHECK_STATUS(status, correct) do { \
45 if (!NT_STATUS_EQUAL(status, correct)) { \
46 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
47 nt_errstr(status), nt_errstr(correct)); \
52 #define CHECK_CREATED(__io, __created, __attribute) \
54 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
55 CHECK_VAL((__io)->out.alloc_size, 0); \
56 CHECK_VAL((__io)->out.size, 0); \
57 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
58 CHECK_VAL((__io)->out.reserved2, 0); \
61 #define CHECK_HANDLE(__h1, __h2) \
63 CHECK_VAL((__h1)->data[0], (__h2)->data[0]); \
64 CHECK_VAL((__h1)->data[1], (__h2)->data[1]); \
67 #define __IO_OUT_VAL(__io1, __io2, __m) \
68 CHECK_VAL((__io1)->out.__m, (__io2)->out.__m)
70 #define CHECK_CREATE_OUT(__io1, __io2) \
72 CHECK_HANDLE(&(__io1)->out.file.handle, \
73 &(__io2)->out.file.handle); \
74 __IO_OUT_VAL(__io1, __io2, oplock_level); \
75 __IO_OUT_VAL(__io1, __io2, create_action); \
76 __IO_OUT_VAL(__io1, __io2, create_time); \
77 __IO_OUT_VAL(__io1, __io2, access_time); \
78 __IO_OUT_VAL(__io1, __io2, write_time); \
79 __IO_OUT_VAL(__io1, __io2, change_time); \
80 __IO_OUT_VAL(__io1, __io2, alloc_size); \
81 __IO_OUT_VAL(__io1, __io2, size); \
82 __IO_OUT_VAL(__io1, __io2, file_attr); \
83 __IO_OUT_VAL(__io1, __io2, durable_open); \
84 __IO_OUT_VAL(__io1, __io2, durable_open_v2); \
85 __IO_OUT_VAL(__io1, __io2, persistent_open); \
86 __IO_OUT_VAL(__io1, __io2, timeout); \
87 __IO_OUT_VAL(__io1, __io2, blobs.num_blobs); \
88 if ((__io1)->out.oplock_level == SMB2_OPLOCK_LEVEL_LEASE) { \
89 __IO_OUT_VAL(__io1, __io2, lease_response.lease_state);\
90 __IO_OUT_VAL(__io1, __io2, lease_response.lease_key.data[0]);\
91 __IO_OUT_VAL(__io1, __io2, lease_response.lease_key.data[1]);\
95 #define BASEDIR "replaytestdir"
98 struct torture_context
*tctx
;
99 struct smb2_handle handle
;
101 struct smb2_break br
;
104 NTSTATUS failure_status
;
107 static struct break_info break_info
;
109 static void torture_reset_break_info(struct torture_context
*tctx
,
110 struct break_info
*r
)
116 static void torture_oplock_ack_callback(struct smb2_request
*req
)
120 status
= smb2_break_recv(req
, &break_info
.br
);
121 if (!NT_STATUS_IS_OK(status
)) {
122 break_info
.failures
++;
123 break_info
.failure_status
= status
;
130 * A general oplock break notification handler. This should be used when a
131 * test expects to break from batch or exclusive to a lower level.
133 static bool torture_oplock_ack_handler(struct smb2_transport
*transport
,
134 const struct smb2_handle
*handle
,
138 struct smb2_tree
*tree
= private_data
;
140 struct smb2_request
*req
;
142 ZERO_STRUCT(break_info
.br
);
144 break_info
.handle
= *handle
;
145 break_info
.level
= level
;
149 case SMB2_OPLOCK_LEVEL_II
:
152 case SMB2_OPLOCK_LEVEL_NONE
:
157 break_info
.failures
++;
159 torture_comment(break_info
.tctx
,
160 "Acking to %s [0x%02X] in oplock handler\n",
163 break_info
.br
.in
.file
.handle
= *handle
;
164 break_info
.br
.in
.oplock_level
= level
;
165 break_info
.br
.in
.reserved
= 0;
166 break_info
.br
.in
.reserved2
= 0;
168 req
= smb2_break_send(tree
, &break_info
.br
);
169 req
->async
.fn
= torture_oplock_ack_callback
;
170 req
->async
.private_data
= NULL
;
175 * Timer handler function notifies the registering function that time is up
177 static void timeout_cb(struct tevent_context
*ev
,
178 struct tevent_timer
*te
,
179 struct timeval current_time
,
182 bool *timesup
= (bool *)private_data
;
188 * Wait a short period of time to receive a single oplock break request
190 static void torture_wait_for_oplock_break(struct torture_context
*tctx
)
192 TALLOC_CTX
*tmp_ctx
= talloc_new(NULL
);
193 struct tevent_timer
*te
= NULL
;
195 bool timesup
= false;
196 int old_count
= break_info
.count
;
198 /* Wait .1 seconds for an oplock break */
199 ne
= tevent_timeval_current_ofs(0, 100000);
201 te
= tevent_add_timer(tctx
->ev
, tmp_ctx
, ne
, timeout_cb
, ×up
);
203 torture_comment(tctx
, "Failed to wait for an oplock break. "
204 "test results may not be accurate.");
208 while (!timesup
&& break_info
.count
< old_count
+ 1) {
209 if (tevent_loop_once(tctx
->ev
) != 0) {
210 torture_comment(tctx
, "Failed to wait for an oplock "
211 "break. test results may not be "
219 * We don't know if the timed event fired and was freed, we received
220 * our oplock break, or some other event triggered the loop. Thus,
221 * we create a tmp_ctx to be able to safely free/remove the timed
222 * event in all 3 cases.
224 talloc_free(tmp_ctx
);
230 * Test what happens when SMB2_FLAGS_REPLAY_OPERATION is enabled for various
231 * commands. We want to verify if the server returns an error code or not.
233 static bool test_replay_commands(struct torture_context
*tctx
, struct smb2_tree
*tree
)
237 struct smb2_handle h
;
240 union smb_setfileinfo sfinfo
;
241 union smb_fileinfo qfinfo
;
242 union smb_ioctl ioctl
;
243 struct smb2_lock lck
;
244 struct smb2_lock_element el
[2];
246 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
247 const char *fname
= BASEDIR
"\\replay_commands.dat";
248 struct smb2_transport
*transport
= tree
->session
->transport
;
250 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
251 torture_skip(tctx
, "SMB 3.X Dialect family required for "
255 ZERO_STRUCT(break_info
);
256 break_info
.tctx
= tctx
;
257 tree
->session
->transport
->oplock
.handler
= torture_oplock_ack_handler
;
258 tree
->session
->transport
->oplock
.private_data
= tree
;
260 status
= torture_smb2_testdir(tree
, BASEDIR
, &h
);
261 CHECK_STATUS(status
, NT_STATUS_OK
);
262 smb2_util_close(tree
, h
);
264 smb2cli_session_start_replay(tree
->session
->smbXcli
);
266 torture_comment(tctx
, "Try Commands with Replay Flags Enabled\n");
268 torture_comment(tctx
, "Trying create\n");
269 status
= torture_smb2_testfile(tree
, fname
, &h
);
270 CHECK_STATUS(status
, NT_STATUS_OK
);
271 CHECK_VAL(break_info
.count
, 0);
273 * Wireshark shows that the response has SMB2_FLAGS_REPLAY_OPERATION
274 * flags set. The server should ignore this flag.
277 torture_comment(tctx
, "Trying write\n");
278 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
279 CHECK_STATUS(status
, NT_STATUS_OK
);
281 f
= (struct smb2_flush
) {
284 torture_comment(tctx
, "Trying flush\n");
285 status
= smb2_flush(tree
, &f
);
286 CHECK_STATUS(status
, NT_STATUS_OK
);
288 rd
= (struct smb2_read
) {
294 torture_comment(tctx
, "Trying read\n");
295 status
= smb2_read(tree
, tmp_ctx
, &rd
);
296 CHECK_STATUS(status
, NT_STATUS_OK
);
297 CHECK_VAL(rd
.out
.data
.length
, 10);
299 sfinfo
.generic
.level
= RAW_SFILEINFO_POSITION_INFORMATION
;
300 sfinfo
.position_information
.in
.file
.handle
= h
;
301 sfinfo
.position_information
.in
.position
= 0x1000;
302 torture_comment(tctx
, "Trying setinfo\n");
303 status
= smb2_setinfo_file(tree
, &sfinfo
);
304 CHECK_STATUS(status
, NT_STATUS_OK
);
306 qfinfo
= (union smb_fileinfo
) {
307 .generic
.level
= RAW_SFILEINFO_POSITION_INFORMATION
,
308 .generic
.in
.file
.handle
= h
310 torture_comment(tctx
, "Trying getinfo\n");
311 status
= smb2_getinfo_file(tree
, tmp_ctx
, &qfinfo
);
312 CHECK_STATUS(status
, NT_STATUS_OK
);
313 CHECK_VAL(qfinfo
.position_information
.out
.position
, 0x1000);
315 ioctl
= (union smb_ioctl
) {
316 .smb2
.level
= RAW_IOCTL_SMB2
,
317 .smb2
.in
.file
.handle
= h
,
318 .smb2
.in
.function
= FSCTL_CREATE_OR_GET_OBJECT_ID
,
319 .smb2
.in
.max_response_size
= 64,
320 .smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
322 torture_comment(tctx
, "Trying ioctl\n");
323 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
324 CHECK_STATUS(status
, NT_STATUS_OK
);
326 lck
= (struct smb2_lock
) {
328 .in
.lock_count
= 0x0001,
329 .in
.lock_sequence
= 0x00000000,
332 el
[0].reserved
= 0x00000000;
333 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
|
334 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
336 torture_comment(tctx
, "Trying lock\n");
337 el
[0].offset
= 0x0000000000000000;
338 el
[0].length
= 0x0000000000000100;
339 status
= smb2_lock(tree
, &lck
);
340 CHECK_STATUS(status
, NT_STATUS_OK
);
342 lck
.in
.file
.handle
= h
;
343 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
344 status
= smb2_lock(tree
, &lck
);
345 CHECK_STATUS(status
, NT_STATUS_OK
);
347 CHECK_VAL(break_info
.count
, 0);
349 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
350 smb2_util_close(tree
, h
);
351 smb2_deltree(tree
, BASEDIR
);
353 talloc_free(tmp_ctx
);
359 * Test replay detection without create GUID on single channel.
360 * Regular creates can not be replayed.
361 * The return code is unaffected of the REPLAY_OPERATION flag.
363 static bool test_replay_regular(struct torture_context
*tctx
,
364 struct smb2_tree
*tree
)
367 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
368 struct smb2_handle _h
;
369 struct smb2_handle
*h
= NULL
;
370 struct smb2_create io
;
373 const char *fname
= BASEDIR
"\\replay_regular.dat";
374 struct smb2_transport
*transport
= tree
->session
->transport
;
376 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
377 torture_skip(tctx
, "SMB 3.X Dialect family required for "
381 ZERO_STRUCT(break_info
);
382 break_info
.tctx
= tctx
;
383 tree
->session
->transport
->oplock
.handler
= torture_oplock_ack_handler
;
384 tree
->session
->transport
->oplock
.private_data
= tree
;
386 smb2_util_unlink(tree
, fname
);
387 status
= torture_smb2_testdir(tree
, BASEDIR
, &_h
);
388 CHECK_STATUS(status
, NT_STATUS_OK
);
389 smb2_util_close(tree
, _h
);
390 CHECK_VAL(break_info
.count
, 0);
392 torture_comment(tctx
, "No replay detection for regular create\n");
394 perms
= SEC_STD_SYNCHRONIZE
| SEC_STD_READ_CONTROL
| SEC_STD_DELETE
|
395 SEC_DIR_WRITE_ATTRIBUTE
| SEC_DIR_READ_ATTRIBUTE
|
396 SEC_DIR_WRITE_EA
| SEC_FILE_APPEND_DATA
|
399 io
= (struct smb2_create
) {
400 .in
.desired_access
= perms
,
401 .in
.file_attributes
= 0,
402 .in
.create_disposition
= NTCREATEX_DISP_CREATE
,
403 .in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
,
404 .in
.create_options
= 0x0,
408 status
= smb2_create(tree
, tctx
, &io
);
409 CHECK_STATUS(status
, NT_STATUS_OK
);
410 CHECK_VAL(break_info
.count
, 0);
411 _h
= io
.out
.file
.handle
;
413 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
415 smb2cli_session_start_replay(tree
->session
->smbXcli
);
416 status
= smb2_create(tree
, tctx
, &io
);
417 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
418 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
419 CHECK_VAL(break_info
.count
, 0);
421 smb2_util_close(tree
, *h
);
423 smb2_util_unlink(tree
, fname
);
426 * Same experiment with different create disposition.
428 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
429 status
= smb2_create(tree
, tctx
, &io
);
430 CHECK_STATUS(status
, NT_STATUS_OK
);
431 CHECK_VAL(break_info
.count
, 0);
432 _h
= io
.out
.file
.handle
;
434 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
436 smb2cli_session_start_replay(tree
->session
->smbXcli
);
437 status
= smb2_create(tree
, tctx
, &io
);
438 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
439 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
440 CHECK_VAL(break_info
.count
, 0);
442 smb2_util_close(tree
, *h
);
444 smb2_util_unlink(tree
, fname
);
447 * Now with more generous share mode.
449 io
.in
.share_access
= smb2_util_share_access("RWD");
450 status
= smb2_create(tree
, tctx
, &io
);
451 CHECK_STATUS(status
, NT_STATUS_OK
);
452 CHECK_VAL(break_info
.count
, 0);
453 _h
= io
.out
.file
.handle
;
455 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
457 smb2cli_session_start_replay(tree
->session
->smbXcli
);
458 status
= smb2_create(tree
, tctx
, &io
);
459 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
460 CHECK_STATUS(status
, NT_STATUS_OK
);
461 CHECK_VAL(break_info
.count
, 0);
465 smb2_util_close(tree
, *h
);
467 smb2_deltree(tree
, BASEDIR
);
470 talloc_free(mem_ctx
);
476 * Test Durability V2 Create Replay Detection on Single Channel.
478 static bool test_replay_dhv2_oplock1(struct torture_context
*tctx
,
479 struct smb2_tree
*tree
)
482 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
483 struct smb2_handle _h
;
484 struct smb2_handle
*h
= NULL
;
485 struct smb2_create io
, ref1
;
486 struct GUID create_guid
= GUID_random();
488 const char *fname
= BASEDIR
"\\replay_dhv2_oplock1.dat";
489 struct smb2_transport
*transport
= tree
->session
->transport
;
490 uint32_t share_capabilities
;
493 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
494 torture_skip(tctx
, "SMB 3.X Dialect family required for "
498 share_capabilities
= smb2cli_tcon_capabilities(tree
->smbXcli
);
499 share_is_so
= share_capabilities
& SMB2_SHARE_CAP_SCALEOUT
;
501 ZERO_STRUCT(break_info
);
502 break_info
.tctx
= tctx
;
503 tree
->session
->transport
->oplock
.handler
= torture_oplock_ack_handler
;
504 tree
->session
->transport
->oplock
.private_data
= tree
;
506 torture_comment(tctx
, "Replay of DurableHandleReqV2 on Single "
508 smb2_util_unlink(tree
, fname
);
509 status
= torture_smb2_testdir(tree
, BASEDIR
, &_h
);
510 CHECK_STATUS(status
, NT_STATUS_OK
);
511 smb2_util_close(tree
, _h
);
512 CHECK_VAL(break_info
.count
, 0);
514 smb2_oplock_create_share(&io
, fname
,
515 smb2_util_share_access(""),
516 smb2_util_oplock_level("b"));
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
;
523 status
= smb2_create(tree
, mem_ctx
, &io
);
524 CHECK_STATUS(status
, NT_STATUS_OK
);
526 _h
= io
.out
.file
.handle
;
528 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
529 CHECK_VAL(io
.out
.durable_open
, false);
531 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("s"));
532 CHECK_VAL(io
.out
.durable_open_v2
, false);
533 CHECK_VAL(io
.out
.timeout
, 0);
535 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("b"));
536 CHECK_VAL(io
.out
.durable_open_v2
, true);
537 CHECK_VAL(io
.out
.timeout
, io
.in
.timeout
);
541 * Replay Durable V2 Create on single channel
543 smb2cli_session_start_replay(tree
->session
->smbXcli
);
544 status
= smb2_create(tree
, mem_ctx
, &io
);
545 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
546 CHECK_STATUS(status
, NT_STATUS_OK
);
547 CHECK_CREATE_OUT(&io
, &ref1
);
548 CHECK_VAL(break_info
.count
, 0);
552 smb2_util_close(tree
, *h
);
554 smb2_deltree(tree
, BASEDIR
);
557 talloc_free(mem_ctx
);
563 * Test Durability V2 Create Replay Detection on Single Channel.
564 * Hand in a different oplock level in the replay.
565 * Server responds with the handed in oplock level and
566 * corresponding durable status, but does not change the
567 * oplock level or durable status of the opened file.
569 static bool test_replay_dhv2_oplock2(struct torture_context
*tctx
,
570 struct smb2_tree
*tree
)
573 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
574 struct smb2_handle _h
;
575 struct smb2_handle
*h
= NULL
;
576 struct smb2_create io
, ref1
, ref2
;
577 struct GUID create_guid
= GUID_random();
579 const char *fname
= BASEDIR
"\\replay_dhv2_oplock2.dat";
580 struct smb2_transport
*transport
= tree
->session
->transport
;
581 uint32_t share_capabilities
;
584 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
585 torture_skip(tctx
, "SMB 3.X Dialect family required for "
589 share_capabilities
= smb2cli_tcon_capabilities(tree
->smbXcli
);
590 share_is_so
= share_capabilities
& SMB2_SHARE_CAP_SCALEOUT
;
592 ZERO_STRUCT(break_info
);
593 break_info
.tctx
= tctx
;
594 tree
->session
->transport
->oplock
.handler
= torture_oplock_ack_handler
;
595 tree
->session
->transport
->oplock
.private_data
= tree
;
597 torture_comment(tctx
, "Replay of DurableHandleReqV2 on Single "
599 smb2_util_unlink(tree
, fname
);
600 status
= torture_smb2_testdir(tree
, BASEDIR
, &_h
);
601 CHECK_STATUS(status
, NT_STATUS_OK
);
602 smb2_util_close(tree
, _h
);
603 CHECK_VAL(break_info
.count
, 0);
605 smb2_oplock_create_share(&io
, fname
,
606 smb2_util_share_access(""),
607 smb2_util_oplock_level("b"));
608 io
.in
.durable_open
= false;
609 io
.in
.durable_open_v2
= true;
610 io
.in
.persistent_open
= false;
611 io
.in
.create_guid
= create_guid
;
612 io
.in
.timeout
= UINT32_MAX
;
614 status
= smb2_create(tree
, mem_ctx
, &io
);
615 CHECK_STATUS(status
, NT_STATUS_OK
);
617 _h
= io
.out
.file
.handle
;
619 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
620 CHECK_VAL(io
.out
.durable_open
, false);
622 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("s"));
623 CHECK_VAL(io
.out
.durable_open_v2
, false);
624 CHECK_VAL(io
.out
.timeout
, 0);
626 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("b"));
627 CHECK_VAL(io
.out
.durable_open_v2
, true);
628 CHECK_VAL(io
.out
.timeout
, io
.in
.timeout
);
632 * Replay durable v2 create on single channel:
634 * Replay the create with a different oplock (none).
635 * The server replies with the requested oplock level
636 * and also only replies with durable handle based
637 * on whether it could have been granted based on
638 * the requested oplock type.
640 smb2_oplock_create_share(&io
, fname
,
641 smb2_util_share_access(""),
642 smb2_util_oplock_level(""));
643 io
.in
.durable_open
= false;
644 io
.in
.durable_open_v2
= true;
645 io
.in
.persistent_open
= false;
646 io
.in
.create_guid
= create_guid
;
647 io
.in
.timeout
= UINT32_MAX
;
650 * Adapt the response to the exepected values
653 ref2
.out
.oplock_level
= smb2_util_oplock_level("");
654 ref2
.out
.durable_open_v2
= false;
655 ref2
.out
.timeout
= 0;
656 ref2
.out
.blobs
.num_blobs
= 0;
658 smb2cli_session_start_replay(tree
->session
->smbXcli
);
659 status
= smb2_create(tree
, mem_ctx
, &io
);
660 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
661 CHECK_STATUS(status
, NT_STATUS_OK
);
662 CHECK_CREATE_OUT(&io
, &ref2
);
663 CHECK_VAL(break_info
.count
, 0);
666 * Prove that the open file still has a batch oplock
667 * by breaking it with another open.
669 smb2_oplock_create_share(&io
, fname
,
670 smb2_util_share_access(""),
671 smb2_util_oplock_level("b"));
672 io
.in
.durable_open
= false;
673 io
.in
.durable_open_v2
= true;
674 io
.in
.persistent_open
= false;
675 io
.in
.create_guid
= GUID_random();
676 io
.in
.timeout
= UINT32_MAX
;
677 status
= smb2_create(tree
, mem_ctx
, &io
);
678 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
681 CHECK_VAL(break_info
.count
, 1);
682 CHECK_HANDLE(&break_info
.handle
, &ref1
.out
.file
.handle
);
683 CHECK_VAL(break_info
.level
, smb2_util_oplock_level("s"));
684 ZERO_STRUCT(break_info
);
689 smb2_util_close(tree
, *h
);
691 smb2_deltree(tree
, BASEDIR
);
694 talloc_free(mem_ctx
);
700 * Test Durability V2 Create Replay Detection on Single Channel.
701 * Replay with a different share mode. The share mode of
702 * the opened file is not changed by this.
704 static bool test_replay_dhv2_oplock3(struct torture_context
*tctx
,
705 struct smb2_tree
*tree
)
708 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
709 struct smb2_handle _h
;
710 struct smb2_handle
*h
= NULL
;
711 struct smb2_create io
, ref1
;
712 struct GUID create_guid
= GUID_random();
714 const char *fname
= BASEDIR
"\\replay_dhv2_oplock3.dat";
715 struct smb2_transport
*transport
= tree
->session
->transport
;
716 uint32_t share_capabilities
;
719 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
720 torture_skip(tctx
, "SMB 3.X Dialect family required for "
724 share_capabilities
= smb2cli_tcon_capabilities(tree
->smbXcli
);
725 share_is_so
= share_capabilities
& SMB2_SHARE_CAP_SCALEOUT
;
727 ZERO_STRUCT(break_info
);
728 break_info
.tctx
= tctx
;
729 tree
->session
->transport
->oplock
.handler
= torture_oplock_ack_handler
;
730 tree
->session
->transport
->oplock
.private_data
= tree
;
732 torture_comment(tctx
, "Replay of DurableHandleReqV2 on Single "
734 smb2_util_unlink(tree
, fname
);
735 status
= torture_smb2_testdir(tree
, BASEDIR
, &_h
);
736 CHECK_STATUS(status
, NT_STATUS_OK
);
737 smb2_util_close(tree
, _h
);
738 CHECK_VAL(break_info
.count
, 0);
740 smb2_oplock_create_share(&io
, fname
,
741 smb2_util_share_access(""),
742 smb2_util_oplock_level("b"));
743 io
.in
.durable_open
= false;
744 io
.in
.durable_open_v2
= true;
745 io
.in
.persistent_open
= false;
746 io
.in
.create_guid
= create_guid
;
747 io
.in
.timeout
= UINT32_MAX
;
749 status
= smb2_create(tree
, mem_ctx
, &io
);
750 CHECK_STATUS(status
, NT_STATUS_OK
);
752 _h
= io
.out
.file
.handle
;
754 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
755 CHECK_VAL(io
.out
.durable_open
, false);
757 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("s"));
758 CHECK_VAL(io
.out
.durable_open_v2
, false);
759 CHECK_VAL(io
.out
.timeout
, 0);
761 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("b"));
762 CHECK_VAL(io
.out
.durable_open_v2
, true);
763 CHECK_VAL(io
.out
.timeout
, io
.in
.timeout
);
767 * Replay durable v2 create on single channel:
769 * Replay the create with a different share mode.
770 * The server replies with the requested share
771 * mode instead of that which is associated to
774 smb2_oplock_create_share(&io
, fname
,
775 smb2_util_share_access("RWD"),
776 smb2_util_oplock_level("b"));
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_OK
);
787 CHECK_CREATE_OUT(&io
, &ref1
);
788 CHECK_VAL(break_info
.count
, 0);
791 * In order to prove that the different share mode in the
792 * replayed create had no effect on the open file handle,
793 * show that a new create yields NT_STATUS_SHARING_VIOLATION.
795 smb2_oplock_create_share(&io
, fname
,
796 smb2_util_share_access(""),
797 smb2_util_oplock_level("b"));
798 io
.in
.durable_open
= false;
799 io
.in
.durable_open_v2
= true;
800 io
.in
.persistent_open
= false;
801 io
.in
.create_guid
= GUID_random();
802 io
.in
.timeout
= UINT32_MAX
;
803 status
= smb2_create(tree
, mem_ctx
, &io
);
804 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
807 CHECK_VAL(break_info
.count
, 1);
808 CHECK_HANDLE(&break_info
.handle
, &ref1
.out
.file
.handle
);
809 CHECK_VAL(break_info
.level
, smb2_util_oplock_level("s"));
810 ZERO_STRUCT(break_info
);
815 smb2_util_close(tree
, *h
);
817 smb2_deltree(tree
, BASEDIR
);
820 talloc_free(mem_ctx
);
826 * Test Durability V2 Create Replay Detection on Single Channel.
827 * Create with an oplock, and replay with a lease.
829 static bool test_replay_dhv2_oplock_lease(struct torture_context
*tctx
,
830 struct smb2_tree
*tree
)
833 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
834 struct smb2_handle _h
;
835 struct smb2_handle
*h
= NULL
;
836 struct smb2_create io
;
837 struct GUID create_guid
= GUID_random();
839 const char *fname
= BASEDIR
"\\replay_dhv2_oplock1.dat";
840 struct smb2_transport
*transport
= tree
->session
->transport
;
841 uint32_t share_capabilities
;
843 uint32_t server_capabilities
;
844 struct smb2_lease ls
;
847 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
848 torture_skip(tctx
, "SMB 3.X Dialect family required for "
852 server_capabilities
= smb2cli_conn_server_capabilities(transport
->conn
);
853 if (!(server_capabilities
& SMB2_CAP_LEASING
)) {
854 torture_skip(tctx
, "leases are not supported");
857 share_capabilities
= smb2cli_tcon_capabilities(tree
->smbXcli
);
858 share_is_so
= share_capabilities
& SMB2_SHARE_CAP_SCALEOUT
;
860 ZERO_STRUCT(break_info
);
861 break_info
.tctx
= tctx
;
862 tree
->session
->transport
->oplock
.handler
= torture_oplock_ack_handler
;
863 tree
->session
->transport
->oplock
.private_data
= tree
;
865 torture_comment(tctx
, "Replay of DurableHandleReqV2 on Single "
867 smb2_util_unlink(tree
, fname
);
868 status
= torture_smb2_testdir(tree
, BASEDIR
, &_h
);
869 CHECK_STATUS(status
, NT_STATUS_OK
);
870 smb2_util_close(tree
, _h
);
871 CHECK_VAL(break_info
.count
, 0);
873 smb2_oplock_create_share(&io
, fname
,
874 smb2_util_share_access(""),
875 smb2_util_oplock_level("b"));
876 io
.in
.durable_open
= false;
877 io
.in
.durable_open_v2
= true;
878 io
.in
.persistent_open
= false;
879 io
.in
.create_guid
= create_guid
;
880 io
.in
.timeout
= UINT32_MAX
;
882 status
= smb2_create(tree
, mem_ctx
, &io
);
883 CHECK_STATUS(status
, NT_STATUS_OK
);
884 _h
= io
.out
.file
.handle
;
886 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
887 CHECK_VAL(io
.out
.durable_open
, false);
889 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("s"));
890 CHECK_VAL(io
.out
.durable_open_v2
, false);
891 CHECK_VAL(io
.out
.timeout
, 0);
893 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("b"));
894 CHECK_VAL(io
.out
.durable_open_v2
, true);
895 CHECK_VAL(io
.out
.timeout
, io
.in
.timeout
);
899 * Replay Durable V2 Create on single channel
900 * but replay it with a lease instead of an oplock.
902 lease_key
= random();
903 smb2_lease_create(&io
, &ls
, false /* dir */, fname
,
904 lease_key
, smb2_util_lease_state("RH"));
905 io
.in
.durable_open
= false;
906 io
.in
.durable_open_v2
= true;
907 io
.in
.persistent_open
= false;
908 io
.in
.create_guid
= create_guid
;
909 io
.in
.timeout
= UINT32_MAX
;
911 smb2cli_session_start_replay(tree
->session
->smbXcli
);
912 status
= smb2_create(tree
, mem_ctx
, &io
);
913 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
914 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
918 smb2_util_close(tree
, *h
);
920 smb2_deltree(tree
, BASEDIR
);
923 talloc_free(mem_ctx
);
930 * Test durability v2 create replay detection on single channel.
931 * Variant with leases instead of oplocks:
932 * - open a file with a rh lease
933 * - upgrade to a rwh lease with a second create
934 * - replay the first create.
935 * ==> it gets back the upgraded lease level
937 static bool test_replay_dhv2_lease1(struct torture_context
*tctx
,
938 struct smb2_tree
*tree
)
941 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
942 struct smb2_handle _h1
;
943 struct smb2_handle
*h1
= NULL
;
944 struct smb2_handle _h2
;
945 struct smb2_handle
*h2
= NULL
;
946 struct smb2_create io1
, io2
, ref1
;
947 struct GUID create_guid
= GUID_random();
949 const char *fname
= BASEDIR
"\\replay2_lease1.dat";
950 struct smb2_transport
*transport
= tree
->session
->transport
;
951 uint32_t share_capabilities
;
953 uint32_t server_capabilities
;
954 struct smb2_lease ls1
, ls2
;
957 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
958 torture_skip(tctx
, "SMB 3.X Dialect family required for "
962 server_capabilities
= smb2cli_conn_server_capabilities(transport
->conn
);
963 if (!(server_capabilities
& SMB2_CAP_LEASING
)) {
964 torture_skip(tctx
, "leases are not supported");
967 share_capabilities
= smb2cli_tcon_capabilities(tree
->smbXcli
);
968 share_is_so
= share_capabilities
& SMB2_SHARE_CAP_SCALEOUT
;
970 ZERO_STRUCT(break_info
);
971 break_info
.tctx
= tctx
;
972 tree
->session
->transport
->oplock
.handler
= torture_oplock_ack_handler
;
973 tree
->session
->transport
->oplock
.private_data
= tree
;
975 torture_comment(tctx
, "Replay of DurableHandleReqV2 with Lease "
976 "on Single Channel\n");
977 smb2_util_unlink(tree
, fname
);
978 status
= torture_smb2_testdir(tree
, BASEDIR
, &_h1
);
979 CHECK_STATUS(status
, NT_STATUS_OK
);
980 smb2_util_close(tree
, _h1
);
981 CHECK_VAL(break_info
.count
, 0);
983 lease_key
= random();
985 smb2_lease_create(&io1
, &ls1
, false /* dir */, fname
,
986 lease_key
, smb2_util_lease_state("RH"));
987 io1
.in
.durable_open
= false;
988 io1
.in
.durable_open_v2
= true;
989 io1
.in
.persistent_open
= false;
990 io1
.in
.create_guid
= create_guid
;
991 io1
.in
.timeout
= UINT32_MAX
;
993 status
= smb2_create(tree
, mem_ctx
, &io1
);
994 CHECK_STATUS(status
, NT_STATUS_OK
);
996 _h1
= io1
.out
.file
.handle
;
998 CHECK_CREATED(&io1
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
999 CHECK_VAL(io1
.out
.durable_open
, false);
1000 CHECK_VAL(io1
.out
.oplock_level
, SMB2_OPLOCK_LEVEL_LEASE
);
1001 CHECK_VAL(io1
.out
.lease_response
.lease_key
.data
[0], lease_key
);
1002 CHECK_VAL(io1
.out
.lease_response
.lease_key
.data
[1], ~lease_key
);
1004 CHECK_VAL(io1
.out
.lease_response
.lease_state
,
1005 smb2_util_lease_state("R"));
1006 CHECK_VAL(io1
.out
.durable_open_v2
, false);
1007 CHECK_VAL(io1
.out
.timeout
, 0);
1009 CHECK_VAL(io1
.out
.lease_response
.lease_state
,
1010 smb2_util_lease_state("RH"));
1011 CHECK_VAL(io1
.out
.durable_open_v2
, true);
1012 CHECK_VAL(io1
.out
.timeout
, io1
.in
.timeout
);
1016 * Upgrade the lease to RWH
1018 smb2_lease_create(&io2
, &ls2
, false /* dir */, fname
,
1019 lease_key
, smb2_util_lease_state("RHW"));
1020 io2
.in
.durable_open
= false;
1021 io2
.in
.durable_open_v2
= true;
1022 io2
.in
.persistent_open
= false;
1023 io2
.in
.create_guid
= GUID_random(); /* new guid... */
1024 io2
.in
.timeout
= UINT32_MAX
;
1026 status
= smb2_create(tree
, mem_ctx
, &io2
);
1027 CHECK_STATUS(status
, NT_STATUS_OK
);
1028 _h2
= io2
.out
.file
.handle
;
1032 * Replay Durable V2 Create on single channel.
1033 * We get the io from open #1 but with the
1037 /* adapt expected lease in response */
1039 ref1
.out
.lease_response
.lease_state
=
1040 smb2_util_lease_state("RHW");
1043 smb2cli_session_start_replay(tree
->session
->smbXcli
);
1044 status
= smb2_create(tree
, mem_ctx
, &io1
);
1045 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
1046 CHECK_STATUS(status
, NT_STATUS_OK
);
1047 CHECK_CREATE_OUT(&io1
, &ref1
);
1048 CHECK_VAL(break_info
.count
, 0);
1051 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
1054 smb2_util_close(tree
, *h1
);
1057 smb2_util_close(tree
, *h2
);
1059 smb2_deltree(tree
, BASEDIR
);
1062 talloc_free(mem_ctx
);
1068 * Test durability v2 create replay detection on single channel.
1069 * Variant with leases instead of oplocks, where the
1070 * replay does not specify the original lease level but
1071 * just a "R" lease. This still gives the upgraded lease
1072 * level in the reply.
1073 * - open a file with a rh lease
1074 * - upgrade to a rwh lease with a second create
1075 * - replay the first create.
1076 * ==> it gets back the upgraded lease level
1078 static bool test_replay_dhv2_lease2(struct torture_context
*tctx
,
1079 struct smb2_tree
*tree
)
1082 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1083 struct smb2_handle _h1
;
1084 struct smb2_handle
*h1
= NULL
;
1085 struct smb2_handle _h2
;
1086 struct smb2_handle
*h2
= NULL
;
1087 struct smb2_create io1
, io2
, ref1
;
1088 struct GUID create_guid
= GUID_random();
1090 const char *fname
= BASEDIR
"\\replay2_lease2.dat";
1091 struct smb2_transport
*transport
= tree
->session
->transport
;
1092 uint32_t share_capabilities
;
1094 uint32_t server_capabilities
;
1095 struct smb2_lease ls1
, ls2
;
1098 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
1099 torture_skip(tctx
, "SMB 3.X Dialect family required for "
1103 server_capabilities
= smb2cli_conn_server_capabilities(transport
->conn
);
1104 if (!(server_capabilities
& SMB2_CAP_LEASING
)) {
1105 torture_skip(tctx
, "leases are not supported");
1108 share_capabilities
= smb2cli_tcon_capabilities(tree
->smbXcli
);
1109 share_is_so
= share_capabilities
& SMB2_SHARE_CAP_SCALEOUT
;
1111 ZERO_STRUCT(break_info
);
1112 break_info
.tctx
= tctx
;
1113 tree
->session
->transport
->oplock
.handler
= torture_oplock_ack_handler
;
1114 tree
->session
->transport
->oplock
.private_data
= tree
;
1116 torture_comment(tctx
, "Replay of DurableHandleReqV2 with Lease "
1117 "on Single Channel\n");
1118 smb2_util_unlink(tree
, fname
);
1119 status
= torture_smb2_testdir(tree
, BASEDIR
, &_h1
);
1120 CHECK_STATUS(status
, NT_STATUS_OK
);
1121 smb2_util_close(tree
, _h1
);
1122 CHECK_VAL(break_info
.count
, 0);
1124 lease_key
= random();
1126 smb2_lease_create(&io1
, &ls1
, false /* dir */, fname
,
1127 lease_key
, smb2_util_lease_state("RH"));
1128 io1
.in
.durable_open
= false;
1129 io1
.in
.durable_open_v2
= true;
1130 io1
.in
.persistent_open
= false;
1131 io1
.in
.create_guid
= create_guid
;
1132 io1
.in
.timeout
= UINT32_MAX
;
1134 status
= smb2_create(tree
, mem_ctx
, &io1
);
1135 CHECK_STATUS(status
, NT_STATUS_OK
);
1136 CHECK_CREATED(&io1
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
1137 CHECK_VAL(io1
.out
.durable_open
, false);
1138 CHECK_VAL(io1
.out
.oplock_level
, SMB2_OPLOCK_LEVEL_LEASE
);
1139 CHECK_VAL(io1
.out
.lease_response
.lease_key
.data
[0], lease_key
);
1140 CHECK_VAL(io1
.out
.lease_response
.lease_key
.data
[1], ~lease_key
);
1142 CHECK_VAL(io1
.out
.lease_response
.lease_state
,
1143 smb2_util_lease_state("R"));
1144 CHECK_VAL(io1
.out
.durable_open_v2
, false);
1145 CHECK_VAL(io1
.out
.timeout
, 0);
1147 CHECK_VAL(io1
.out
.lease_response
.lease_state
,
1148 smb2_util_lease_state("RH"));
1149 CHECK_VAL(io1
.out
.durable_open_v2
, true);
1150 CHECK_VAL(io1
.out
.timeout
, io1
.in
.timeout
);
1153 _h1
= io1
.out
.file
.handle
;
1157 * Upgrade the lease to RWH
1159 smb2_lease_create(&io2
, &ls2
, false /* dir */, fname
,
1160 lease_key
, smb2_util_lease_state("RHW"));
1161 io2
.in
.durable_open
= false;
1162 io2
.in
.durable_open_v2
= true;
1163 io2
.in
.persistent_open
= false;
1164 io2
.in
.create_guid
= GUID_random(); /* new guid... */
1165 io2
.in
.timeout
= UINT32_MAX
;
1167 status
= smb2_create(tree
, mem_ctx
, &io2
);
1168 CHECK_STATUS(status
, NT_STATUS_OK
);
1169 _h2
= io2
.out
.file
.handle
;
1173 * Replay Durable V2 Create on single channel.
1174 * Changing the requested lease level to "R"
1175 * does not change the response:
1176 * We get the reply from open #1 but with the
1180 /* adapt the expected response */
1182 ref1
.out
.lease_response
.lease_state
=
1183 smb2_util_lease_state("RHW");
1186 smb2_lease_create(&io1
, &ls1
, false /* dir */, fname
,
1187 lease_key
, smb2_util_lease_state("R"));
1188 io1
.in
.durable_open
= false;
1189 io1
.in
.durable_open_v2
= true;
1190 io1
.in
.persistent_open
= false;
1191 io1
.in
.create_guid
= create_guid
;
1192 io1
.in
.timeout
= UINT32_MAX
;
1194 smb2cli_session_start_replay(tree
->session
->smbXcli
);
1195 status
= smb2_create(tree
, mem_ctx
, &io1
);
1196 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
1197 CHECK_STATUS(status
, NT_STATUS_OK
);
1198 CHECK_CREATE_OUT(&io1
, &ref1
);
1199 CHECK_VAL(break_info
.count
, 0);
1202 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
1205 smb2_util_close(tree
, *h1
);
1208 smb2_util_close(tree
, *h2
);
1210 smb2_deltree(tree
, BASEDIR
);
1213 talloc_free(mem_ctx
);
1219 * Test durability v2 create replay detection on single channel.
1220 * create with a lease, and replay with a different lease key
1222 static bool test_replay_dhv2_lease3(struct torture_context
*tctx
,
1223 struct smb2_tree
*tree
)
1226 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1227 struct smb2_handle _h1
;
1228 struct smb2_handle
*h1
= NULL
;
1229 struct smb2_handle _h2
;
1230 struct smb2_handle
*h2
= NULL
;
1231 struct smb2_create io1
, io2
;
1232 struct GUID create_guid
= GUID_random();
1234 const char *fname
= BASEDIR
"\\replay2_lease2.dat";
1235 struct smb2_transport
*transport
= tree
->session
->transport
;
1236 uint32_t share_capabilities
;
1238 uint32_t server_capabilities
;
1239 struct smb2_lease ls1
, ls2
;
1242 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
1243 torture_skip(tctx
, "SMB 3.X Dialect family required for "
1247 server_capabilities
= smb2cli_conn_server_capabilities(transport
->conn
);
1248 if (!(server_capabilities
& SMB2_CAP_LEASING
)) {
1249 torture_skip(tctx
, "leases are not supported");
1252 share_capabilities
= smb2cli_tcon_capabilities(tree
->smbXcli
);
1253 share_is_so
= share_capabilities
& SMB2_SHARE_CAP_SCALEOUT
;
1255 ZERO_STRUCT(break_info
);
1256 break_info
.tctx
= tctx
;
1257 tree
->session
->transport
->oplock
.handler
= torture_oplock_ack_handler
;
1258 tree
->session
->transport
->oplock
.private_data
= tree
;
1260 torture_comment(tctx
, "Replay of DurableHandleReqV2 with Lease "
1261 "on Single Channel\n");
1262 smb2_util_unlink(tree
, fname
);
1263 status
= torture_smb2_testdir(tree
, BASEDIR
, &_h1
);
1264 CHECK_STATUS(status
, NT_STATUS_OK
);
1265 smb2_util_close(tree
, _h1
);
1266 CHECK_VAL(break_info
.count
, 0);
1268 lease_key
= random();
1270 smb2_lease_create(&io1
, &ls1
, false /* dir */, fname
,
1271 lease_key
, smb2_util_lease_state("RH"));
1272 io1
.in
.durable_open
= false;
1273 io1
.in
.durable_open_v2
= true;
1274 io1
.in
.persistent_open
= false;
1275 io1
.in
.create_guid
= create_guid
;
1276 io1
.in
.timeout
= UINT32_MAX
;
1278 status
= smb2_create(tree
, mem_ctx
, &io1
);
1279 CHECK_STATUS(status
, NT_STATUS_OK
);
1280 CHECK_CREATED(&io1
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
1281 CHECK_VAL(io1
.out
.durable_open
, false);
1282 CHECK_VAL(io1
.out
.oplock_level
, SMB2_OPLOCK_LEVEL_LEASE
);
1283 CHECK_VAL(io1
.out
.lease_response
.lease_key
.data
[0], lease_key
);
1284 CHECK_VAL(io1
.out
.lease_response
.lease_key
.data
[1], ~lease_key
);
1286 CHECK_VAL(io1
.out
.lease_response
.lease_state
,
1287 smb2_util_lease_state("R"));
1288 CHECK_VAL(io1
.out
.durable_open_v2
, false);
1289 CHECK_VAL(io1
.out
.timeout
, 0);
1291 CHECK_VAL(io1
.out
.lease_response
.lease_state
,
1292 smb2_util_lease_state("RH"));
1293 CHECK_VAL(io1
.out
.durable_open_v2
, true);
1294 CHECK_VAL(io1
.out
.timeout
, io1
.in
.timeout
);
1296 _h1
= io1
.out
.file
.handle
;
1300 * Upgrade the lease to RWH
1302 smb2_lease_create(&io2
, &ls2
, false /* dir */, fname
,
1303 lease_key
, smb2_util_lease_state("RHW"));
1304 io2
.in
.durable_open
= false;
1305 io2
.in
.durable_open_v2
= true;
1306 io2
.in
.persistent_open
= false;
1307 io2
.in
.create_guid
= GUID_random(); /* new guid... */
1308 io2
.in
.timeout
= UINT32_MAX
;
1310 status
= smb2_create(tree
, mem_ctx
, &io2
);
1311 CHECK_STATUS(status
, NT_STATUS_OK
);
1312 _h2
= io2
.out
.file
.handle
;
1316 * Replay Durable V2 Create on single channel.
1317 * use a different lease key.
1320 smb2_lease_create(&io1
, &ls1
, false /* dir */, fname
,
1321 random() /* lease key */,
1322 smb2_util_lease_state("RH"));
1323 io1
.in
.durable_open
= false;
1324 io1
.in
.durable_open_v2
= true;
1325 io1
.in
.persistent_open
= false;
1326 io1
.in
.create_guid
= create_guid
;
1327 io1
.in
.timeout
= UINT32_MAX
;
1329 smb2cli_session_start_replay(tree
->session
->smbXcli
);
1330 status
= smb2_create(tree
, mem_ctx
, &io1
);
1331 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
1332 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
1335 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
1338 smb2_util_close(tree
, *h1
);
1341 smb2_util_close(tree
, *h2
);
1343 smb2_deltree(tree
, BASEDIR
);
1346 talloc_free(mem_ctx
);
1352 * Test durability v2 create replay detection on single channel.
1353 * Do the original create with a lease, and do the replay
1356 static bool test_replay_dhv2_lease_oplock(struct torture_context
*tctx
,
1357 struct smb2_tree
*tree
)
1360 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1361 struct smb2_handle _h1
;
1362 struct smb2_handle
*h1
= NULL
;
1363 struct smb2_handle _h2
;
1364 struct smb2_handle
*h2
= NULL
;
1365 struct smb2_create io1
, io2
, ref1
;
1366 struct GUID create_guid
= GUID_random();
1368 const char *fname
= BASEDIR
"\\replay2_lease1.dat";
1369 struct smb2_transport
*transport
= tree
->session
->transport
;
1370 uint32_t share_capabilities
;
1372 uint32_t server_capabilities
;
1373 struct smb2_lease ls1
, ls2
;
1376 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
1377 torture_skip(tctx
, "SMB 3.X Dialect family required for "
1381 server_capabilities
= smb2cli_conn_server_capabilities(transport
->conn
);
1382 if (!(server_capabilities
& SMB2_CAP_LEASING
)) {
1383 torture_skip(tctx
, "leases are not supported");
1386 share_capabilities
= smb2cli_tcon_capabilities(tree
->smbXcli
);
1387 share_is_so
= share_capabilities
& SMB2_SHARE_CAP_SCALEOUT
;
1389 ZERO_STRUCT(break_info
);
1390 break_info
.tctx
= tctx
;
1391 tree
->session
->transport
->oplock
.handler
= torture_oplock_ack_handler
;
1392 tree
->session
->transport
->oplock
.private_data
= tree
;
1394 torture_comment(tctx
, "Replay of DurableHandleReqV2 with Lease "
1395 "on Single Channel\n");
1396 smb2_util_unlink(tree
, fname
);
1397 status
= torture_smb2_testdir(tree
, BASEDIR
, &_h1
);
1398 CHECK_STATUS(status
, NT_STATUS_OK
);
1399 smb2_util_close(tree
, _h1
);
1400 CHECK_VAL(break_info
.count
, 0);
1402 lease_key
= random();
1404 smb2_lease_create(&io1
, &ls1
, false /* dir */, fname
,
1405 lease_key
, smb2_util_lease_state("RH"));
1406 io1
.in
.durable_open
= false;
1407 io1
.in
.durable_open_v2
= true;
1408 io1
.in
.persistent_open
= false;
1409 io1
.in
.create_guid
= create_guid
;
1410 io1
.in
.timeout
= UINT32_MAX
;
1412 status
= smb2_create(tree
, mem_ctx
, &io1
);
1413 CHECK_STATUS(status
, NT_STATUS_OK
);
1415 _h1
= io1
.out
.file
.handle
;
1417 CHECK_CREATED(&io1
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
1418 CHECK_VAL(io1
.out
.durable_open
, false);
1419 CHECK_VAL(io1
.out
.oplock_level
, SMB2_OPLOCK_LEVEL_LEASE
);
1420 CHECK_VAL(io1
.out
.lease_response
.lease_key
.data
[0], lease_key
);
1421 CHECK_VAL(io1
.out
.lease_response
.lease_key
.data
[1], ~lease_key
);
1423 CHECK_VAL(io1
.out
.lease_response
.lease_state
,
1424 smb2_util_lease_state("R"));
1425 CHECK_VAL(io1
.out
.durable_open_v2
, false);
1426 CHECK_VAL(io1
.out
.timeout
, 0);
1428 CHECK_VAL(io1
.out
.lease_response
.lease_state
,
1429 smb2_util_lease_state("RH"));
1430 CHECK_VAL(io1
.out
.durable_open_v2
, true);
1431 CHECK_VAL(io1
.out
.timeout
, io1
.in
.timeout
);
1435 * Upgrade the lease to RWH
1437 smb2_lease_create(&io2
, &ls2
, false /* dir */, fname
,
1438 lease_key
, smb2_util_lease_state("RHW"));
1439 io2
.in
.durable_open
= false;
1440 io2
.in
.durable_open_v2
= true;
1441 io2
.in
.persistent_open
= false;
1442 io2
.in
.create_guid
= GUID_random(); /* new guid... */
1443 io2
.in
.timeout
= UINT32_MAX
;
1445 status
= smb2_create(tree
, mem_ctx
, &io2
);
1446 CHECK_STATUS(status
, NT_STATUS_OK
);
1447 _h2
= io2
.out
.file
.handle
;
1451 * Replay Durable V2 Create on single channel.
1452 * We get the io from open #1 but with the
1456 smb2_oplock_create_share(&io2
, fname
,
1457 smb2_util_share_access(""),
1458 smb2_util_oplock_level("b"));
1459 io2
.in
.durable_open
= false;
1460 io2
.in
.durable_open_v2
= true;
1461 io2
.in
.persistent_open
= false;
1462 io2
.in
.create_guid
= create_guid
;
1463 io2
.in
.timeout
= UINT32_MAX
;
1465 /* adapt expected lease in response */
1467 ref1
.out
.lease_response
.lease_state
=
1468 smb2_util_lease_state("RHW");
1471 smb2cli_session_start_replay(tree
->session
->smbXcli
);
1472 status
= smb2_create(tree
, mem_ctx
, &io1
);
1473 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
1474 CHECK_STATUS(status
, NT_STATUS_OK
);
1475 CHECK_CREATE_OUT(&io1
, &ref1
);
1476 CHECK_VAL(break_info
.count
, 0);
1479 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
1482 smb2_util_close(tree
, *h1
);
1485 smb2_util_close(tree
, *h2
);
1487 smb2_deltree(tree
, BASEDIR
);
1490 talloc_free(mem_ctx
);
1495 static bool test_channel_sequence_table(struct torture_context
*tctx
,
1496 struct smb2_tree
*tree
,
1500 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1501 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1502 struct smb2_handle handle
;
1503 struct smb2_handle
*phandle
= NULL
;
1504 struct smb2_create io
;
1505 struct GUID create_guid
= GUID_random();
1507 const char *fname
= BASEDIR
"\\channel_sequence.dat";
1509 uint16_t limit
= UINT16_MAX
- 0x7fff;
1515 NTSTATUS expected_status
;
1519 .expected_status
= NT_STATUS_OK
,
1522 .expected_status
= NT_STATUS_FILE_NOT_AVAILABLE
,
1525 .expected_status
= NT_STATUS_FILE_NOT_AVAILABLE
,
1528 .csn_rand_high
= true,
1529 .expected_status
= NT_STATUS_FILE_NOT_AVAILABLE
,
1532 .expected_status
= NT_STATUS_FILE_NOT_AVAILABLE
,
1535 .expected_status
= NT_STATUS_OK
,
1538 .expected_status
= NT_STATUS_FILE_NOT_AVAILABLE
,
1541 .expected_status
= NT_STATUS_FILE_NOT_AVAILABLE
,
1544 .csn_rand_low
= true,
1545 .expected_status
= NT_STATUS_FILE_NOT_AVAILABLE
,
1548 .expected_status
= NT_STATUS_OK
,
1551 .expected_status
= NT_STATUS_OK
,
1554 .expected_status
= NT_STATUS_OK
,
1557 .expected_status
= NT_STATUS_OK
,
1560 .expected_status
= NT_STATUS_FILE_NOT_AVAILABLE
,
1563 .expected_status
= NT_STATUS_OK
,
1566 .expected_status
= NT_STATUS_FILE_NOT_AVAILABLE
,
1570 smb2cli_session_reset_channel_sequence(tree
->session
->smbXcli
, 0);
1572 csn
= smb2cli_session_current_channel_sequence(tree
->session
->smbXcli
);
1573 torture_comment(tctx
, "Testing create with channel sequence number: 0x%04x\n", csn
);
1575 smb2_oplock_create_share(&io
, fname
,
1576 smb2_util_share_access("RWD"),
1577 smb2_util_oplock_level("b"));
1578 io
.in
.durable_open
= false;
1579 io
.in
.durable_open_v2
= true;
1580 io
.in
.create_guid
= create_guid
;
1581 io
.in
.timeout
= UINT32_MAX
;
1583 torture_assert_ntstatus_ok_goto(tctx
,
1584 smb2_create(tree
, mem_ctx
, &io
),
1585 ret
, done
, "failed to call smb2_create");
1587 handle
= io
.out
.file
.handle
;
1590 for (i
=0; i
<ARRAY_SIZE(tests
); i
++) {
1592 const char *opstr
= "";
1593 union smb_fileinfo qfinfo
;
1597 if (tests
[i
].csn_rand_low
) {
1598 csn
= rand() % limit
;
1599 } else if (tests
[i
].csn_rand_high
) {
1600 csn
= rand() % limit
+ 0x7fff;
1610 case SMB2_OP_SETINFO
:
1617 smb2cli_session_reset_channel_sequence(tree
->session
->smbXcli
, csn
);
1618 csn
= smb2cli_session_current_channel_sequence(tree
->session
->smbXcli
);
1620 torture_comment(tctx
, "Testing %s (replay: %s) with CSN 0x%04x, expecting: %s\n",
1621 opstr
, do_replay
? "true" : "false", csn
,
1622 nt_errstr(tests
[i
].expected_status
));
1625 smb2cli_session_start_replay(tree
->session
->smbXcli
);
1629 case SMB2_OP_WRITE
: {
1630 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, 255);
1632 generate_random_buffer(blob
.data
, blob
.length
);
1634 status
= smb2_util_write(tree
, handle
, blob
.data
, 0, blob
.length
);
1635 if (NT_STATUS_IS_OK(status
)) {
1636 struct smb2_read rd
;
1638 rd
= (struct smb2_read
) {
1639 .in
.file
.handle
= handle
,
1640 .in
.length
= blob
.length
,
1644 torture_assert_ntstatus_ok_goto(tctx
,
1645 smb2_read(tree
, tree
, &rd
),
1646 ret
, done
, "failed to read after write");
1648 torture_assert_data_blob_equal(tctx
,
1650 "read/write mismatch");
1654 case SMB2_OP_IOCTL
: {
1655 union smb_ioctl ioctl
;
1656 ioctl
= (union smb_ioctl
) {
1657 .smb2
.level
= RAW_IOCTL_SMB2
,
1658 .smb2
.in
.file
.handle
= handle
,
1659 .smb2
.in
.function
= FSCTL_CREATE_OR_GET_OBJECT_ID
,
1660 .smb2
.in
.max_response_size
= 64,
1661 .smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
1663 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
1666 case SMB2_OP_SETINFO
: {
1667 union smb_setfileinfo sfinfo
;
1668 ZERO_STRUCT(sfinfo
);
1669 sfinfo
.generic
.level
= RAW_SFILEINFO_POSITION_INFORMATION
;
1670 sfinfo
.generic
.in
.file
.handle
= handle
;
1671 sfinfo
.position_information
.in
.position
= 0x1000;
1672 status
= smb2_setinfo_file(tree
, &sfinfo
);
1679 qfinfo
= (union smb_fileinfo
) {
1680 .generic
.level
= RAW_SFILEINFO_POSITION_INFORMATION
,
1681 .generic
.in
.file
.handle
= handle
1684 torture_assert_ntstatus_ok_goto(tctx
,
1685 smb2_getinfo_file(tree
, mem_ctx
, &qfinfo
),
1686 ret
, done
, "failed to read after write");
1689 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
1692 torture_assert_ntstatus_equal_goto(tctx
,
1693 status
, tests
[i
].expected_status
,
1694 ret
, done
, "got unexpected failure code");
1698 if (phandle
!= NULL
) {
1699 smb2_util_close(tree
, *phandle
);
1702 smb2_util_unlink(tree
, fname
);
1707 static bool test_channel_sequence(struct torture_context
*tctx
,
1708 struct smb2_tree
*tree
)
1710 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1712 const char *fname
= BASEDIR
"\\channel_sequence.dat";
1713 struct smb2_transport
*transport1
= tree
->session
->transport
;
1714 struct smb2_handle handle
;
1715 uint32_t server_capabilities
;
1716 uint16_t opcodes
[] = { SMB2_OP_WRITE
, SMB2_OP_IOCTL
, SMB2_OP_SETINFO
};
1719 if (smbXcli_conn_protocol(transport1
->conn
) < PROTOCOL_SMB3_00
) {
1720 torture_skip(tctx
, "SMB 3.X Dialect family required for "
1724 server_capabilities
= smb2cli_conn_server_capabilities(
1725 tree
->session
->transport
->conn
);
1726 if (!(server_capabilities
& SMB2_CAP_MULTI_CHANNEL
)) {
1728 "Server does not support multi-channel.");
1731 torture_comment(tctx
, "Testing channel sequence numbers\n");
1733 torture_assert_ntstatus_ok_goto(tctx
,
1734 torture_smb2_testdir(tree
, BASEDIR
, &handle
),
1735 ret
, done
, "failed to setup test directory");
1737 smb2_util_close(tree
, handle
);
1738 smb2_util_unlink(tree
, fname
);
1740 for (i
=0; i
<ARRAY_SIZE(opcodes
); i
++) {
1741 torture_assert(tctx
,
1742 test_channel_sequence_table(tctx
, tree
, false, opcodes
[i
]),
1743 "failed to test CSN without replay flag");
1744 torture_assert(tctx
,
1745 test_channel_sequence_table(tctx
, tree
, true, opcodes
[i
]),
1746 "failed to test CSN with replay flag");
1751 smb2_util_unlink(tree
, fname
);
1752 smb2_deltree(tree
, BASEDIR
);
1755 talloc_free(mem_ctx
);
1761 * Test Durability V2 Create Replay Detection on Multi Channel
1763 static bool test_replay3(struct torture_context
*tctx
, struct smb2_tree
*tree1
)
1765 const char *host
= torture_setting_string(tctx
, "host", NULL
);
1766 const char *share
= torture_setting_string(tctx
, "share", NULL
);
1768 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1769 struct smb2_handle _h
;
1770 struct smb2_handle
*h
= NULL
;
1771 struct smb2_create io
;
1772 struct GUID create_guid
= GUID_random();
1774 const char *fname
= BASEDIR
"\\replay3.dat";
1775 struct smb2_tree
*tree2
= NULL
;
1776 struct smb2_transport
*transport1
= tree1
->session
->transport
;
1777 struct smb2_transport
*transport2
= NULL
;
1778 struct smb2_session
*session1_1
= tree1
->session
;
1779 struct smb2_session
*session1_2
= NULL
;
1780 uint32_t share_capabilities
;
1782 uint32_t server_capabilities
;
1784 if (smbXcli_conn_protocol(transport1
->conn
) < PROTOCOL_SMB3_00
) {
1785 torture_skip(tctx
, "SMB 3.X Dialect family required for "
1789 server_capabilities
= smb2cli_conn_server_capabilities(
1790 tree1
->session
->transport
->conn
);
1791 if (!(server_capabilities
& SMB2_CAP_MULTI_CHANNEL
)) {
1793 "Server does not support multi-channel.");
1796 share_capabilities
= smb2cli_tcon_capabilities(tree1
->smbXcli
);
1797 share_is_so
= share_capabilities
& SMB2_SHARE_CAP_SCALEOUT
;
1799 ZERO_STRUCT(break_info
);
1800 break_info
.tctx
= tctx
;
1801 transport1
->oplock
.handler
= torture_oplock_ack_handler
;
1802 transport1
->oplock
.private_data
= tree1
;
1804 torture_comment(tctx
, "Replay of DurableHandleReqV2 on Multi "
1806 status
= torture_smb2_testdir(tree1
, BASEDIR
, &_h
);
1807 CHECK_STATUS(status
, NT_STATUS_OK
);
1808 smb2_util_close(tree1
, _h
);
1809 smb2_util_unlink(tree1
, fname
);
1810 CHECK_VAL(break_info
.count
, 0);
1813 * use the 1st channel, 1st session
1815 smb2_oplock_create_share(&io
, fname
,
1816 smb2_util_share_access(""),
1817 smb2_util_oplock_level("b"));
1818 io
.in
.durable_open
= false;
1819 io
.in
.durable_open_v2
= true;
1820 io
.in
.persistent_open
= false;
1821 io
.in
.create_guid
= create_guid
;
1822 io
.in
.timeout
= UINT32_MAX
;
1824 tree1
->session
= session1_1
;
1825 status
= smb2_create(tree1
, mem_ctx
, &io
);
1826 CHECK_STATUS(status
, NT_STATUS_OK
);
1827 _h
= io
.out
.file
.handle
;
1829 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
1831 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("s"));
1832 CHECK_VAL(io
.out
.durable_open_v2
, false);
1833 CHECK_VAL(io
.out
.timeout
, 0);
1835 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("b"));
1836 CHECK_VAL(io
.out
.durable_open_v2
, true);
1837 CHECK_VAL(io
.out
.timeout
, io
.in
.timeout
);
1839 CHECK_VAL(io
.out
.durable_open
, false);
1840 CHECK_VAL(break_info
.count
, 0);
1842 status
= smb2_connect(tctx
,
1844 lpcfg_smb_ports(tctx
->lp_ctx
),
1846 lpcfg_resolve_context(tctx
->lp_ctx
),
1847 popt_get_cmdline_credentials(),
1850 &transport1
->options
,
1851 lpcfg_socket_options(tctx
->lp_ctx
),
1852 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
)
1854 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1855 "smb2_connect failed");
1856 transport2
= tree2
->session
->transport
;
1858 transport2
->oplock
.handler
= torture_oplock_ack_handler
;
1859 transport2
->oplock
.private_data
= tree2
;
1862 * Now bind the 1st session to 2nd transport channel
1864 session1_2
= smb2_session_channel(transport2
,
1865 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
),
1867 torture_assert(tctx
, session1_2
!= NULL
, "smb2_session_channel failed");
1869 status
= smb2_session_setup_spnego(session1_2
,
1870 popt_get_cmdline_credentials(),
1871 0 /* previous_session_id */);
1872 CHECK_STATUS(status
, NT_STATUS_OK
);
1875 * use the 2nd channel, 1st session
1877 tree1
->session
= session1_2
;
1878 smb2cli_session_start_replay(tree1
->session
->smbXcli
);
1879 status
= smb2_create(tree1
, mem_ctx
, &io
);
1880 smb2cli_session_stop_replay(tree1
->session
->smbXcli
);
1881 CHECK_STATUS(status
, NT_STATUS_OK
);
1882 _h
= io
.out
.file
.handle
;
1884 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
1886 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("s"));
1887 CHECK_VAL(io
.out
.durable_open_v2
, false);
1888 CHECK_VAL(io
.out
.timeout
, 0);
1890 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("b"));
1891 CHECK_VAL(io
.out
.durable_open_v2
, true);
1892 CHECK_VAL(io
.out
.timeout
, io
.in
.timeout
);
1894 CHECK_VAL(io
.out
.durable_open
, false);
1895 CHECK_VAL(break_info
.count
, 0);
1897 tree1
->session
= session1_1
;
1898 smb2_util_close(tree1
, *h
);
1903 tree1
->session
= session1_1
;
1906 smb2_util_close(tree1
, *h
);
1909 smb2_util_unlink(tree1
, fname
);
1910 smb2_deltree(tree1
, BASEDIR
);
1913 talloc_free(mem_ctx
);
1919 * Test Multichannel IO Ordering using ChannelSequence/Channel Epoch number
1921 static bool test_replay4(struct torture_context
*tctx
, struct smb2_tree
*tree1
)
1923 const char *host
= torture_setting_string(tctx
, "host", NULL
);
1924 const char *share
= torture_setting_string(tctx
, "share", NULL
);
1926 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1927 struct smb2_handle _h1
;
1928 struct smb2_handle
*h1
= NULL
;
1929 struct smb2_create io
;
1930 struct GUID create_guid
= GUID_random();
1932 struct smb2_read rd
;
1933 union smb_setfileinfo sfinfo
;
1935 const char *fname
= BASEDIR
"\\replay4.dat";
1936 struct smb2_tree
*tree2
= NULL
;
1937 struct smb2_transport
*transport1
= tree1
->session
->transport
;
1938 struct smb2_transport
*transport2
= NULL
;
1939 struct smb2_session
*session1_1
= tree1
->session
;
1940 struct smb2_session
*session1_2
= NULL
;
1942 uint32_t share_capabilities
;
1944 uint32_t server_capabilities
;
1946 if (smbXcli_conn_protocol(transport1
->conn
) < PROTOCOL_SMB3_00
) {
1947 torture_skip(tctx
, "SMB 3.X Dialect family required for "
1951 server_capabilities
= smb2cli_conn_server_capabilities(
1952 tree1
->session
->transport
->conn
);
1953 if (!(server_capabilities
& SMB2_CAP_MULTI_CHANNEL
)) {
1955 "Server does not support multi-channel.");
1958 share_capabilities
= smb2cli_tcon_capabilities(tree1
->smbXcli
);
1959 share_is_so
= share_capabilities
& SMB2_SHARE_CAP_SCALEOUT
;
1961 ZERO_STRUCT(break_info
);
1962 break_info
.tctx
= tctx
;
1963 transport1
->oplock
.handler
= torture_oplock_ack_handler
;
1964 transport1
->oplock
.private_data
= tree1
;
1966 torture_comment(tctx
, "IO Ordering for Multi Channel\n");
1967 status
= torture_smb2_testdir(tree1
, BASEDIR
, &_h1
);
1968 CHECK_STATUS(status
, NT_STATUS_OK
);
1969 smb2_util_close(tree1
, _h1
);
1970 smb2_util_unlink(tree1
, fname
);
1971 CHECK_VAL(break_info
.count
, 0);
1974 * use the 1st channel, 1st session
1977 smb2_oplock_create_share(&io
, fname
,
1978 smb2_util_share_access(""),
1979 smb2_util_oplock_level("b"));
1980 io
.in
.durable_open
= false;
1981 io
.in
.durable_open_v2
= true;
1982 io
.in
.persistent_open
= false;
1983 io
.in
.create_guid
= create_guid
;
1984 io
.in
.timeout
= UINT32_MAX
;
1986 tree1
->session
= session1_1
;
1987 status
= smb2_create(tree1
, mem_ctx
, &io
);
1988 CHECK_STATUS(status
, NT_STATUS_OK
);
1989 _h1
= io
.out
.file
.handle
;
1991 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
1993 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("s"));
1994 CHECK_VAL(io
.out
.durable_open_v2
, false);
1995 CHECK_VAL(io
.out
.timeout
, 0);
1997 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("b"));
1998 CHECK_VAL(io
.out
.durable_open_v2
, true);
1999 CHECK_VAL(io
.out
.timeout
, io
.in
.timeout
);
2001 CHECK_VAL(io
.out
.durable_open
, false);
2002 CHECK_VAL(break_info
.count
, 0);
2004 status
= smb2_util_write(tree1
, *h1
, buf
, 0, ARRAY_SIZE(buf
));
2005 CHECK_STATUS(status
, NT_STATUS_OK
);
2008 * Increment ChannelSequence so that server thinks that there's a
2011 smb2cli_session_increment_channel_sequence(tree1
->session
->smbXcli
);
2014 * Perform a Read with incremented ChannelSequence
2016 rd
= (struct smb2_read
) {
2017 .in
.file
.handle
= *h1
,
2018 .in
.length
= sizeof(buf
),
2021 status
= smb2_read(tree1
, tree1
, &rd
);
2022 CHECK_STATUS(status
, NT_STATUS_OK
);
2025 * Performing a Write with Stale ChannelSequence is not allowed by
2028 curr_cs
= smb2cli_session_reset_channel_sequence(
2029 tree1
->session
->smbXcli
, 0);
2030 status
= smb2_util_write(tree1
, *h1
, buf
, 0, ARRAY_SIZE(buf
));
2031 CHECK_STATUS(status
, NT_STATUS_FILE_NOT_AVAILABLE
);
2034 * Performing a Write Replay with Stale ChannelSequence is not allowed
2037 smb2cli_session_start_replay(tree1
->session
->smbXcli
);
2038 smb2cli_session_reset_channel_sequence(tree1
->session
->smbXcli
, 0);
2039 status
= smb2_util_write(tree1
, *h1
, buf
, 0, ARRAY_SIZE(buf
));
2040 smb2cli_session_stop_replay(tree1
->session
->smbXcli
);
2041 CHECK_STATUS(status
, NT_STATUS_FILE_NOT_AVAILABLE
);
2044 * Performing a SetInfo with stale ChannelSequence is not allowed by
2047 ZERO_STRUCT(sfinfo
);
2048 sfinfo
.generic
.level
= RAW_SFILEINFO_POSITION_INFORMATION
;
2049 sfinfo
.generic
.in
.file
.handle
= *h1
;
2050 sfinfo
.position_information
.in
.position
= 0x1000;
2051 status
= smb2_setinfo_file(tree1
, &sfinfo
);
2052 CHECK_STATUS(status
, NT_STATUS_FILE_NOT_AVAILABLE
);
2055 * Performing a Read with stale ChannelSequence is allowed
2057 rd
= (struct smb2_read
) {
2058 .in
.file
.handle
= *h1
,
2059 .in
.length
= ARRAY_SIZE(buf
),
2062 status
= smb2_read(tree1
, tree1
, &rd
);
2063 CHECK_STATUS(status
, NT_STATUS_OK
);
2065 status
= smb2_connect(tctx
,
2067 lpcfg_smb_ports(tctx
->lp_ctx
),
2069 lpcfg_resolve_context(tctx
->lp_ctx
),
2070 popt_get_cmdline_credentials(),
2073 &transport1
->options
,
2074 lpcfg_socket_options(tctx
->lp_ctx
),
2075 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
)
2077 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2078 "smb2_connect failed");
2079 transport2
= tree2
->session
->transport
;
2081 transport2
->oplock
.handler
= torture_oplock_ack_handler
;
2082 transport2
->oplock
.private_data
= tree2
;
2085 * Now bind the 1st session to 2nd transport channel
2087 session1_2
= smb2_session_channel(transport2
,
2088 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
),
2090 torture_assert(tctx
, session1_2
!= NULL
, "smb2_session_channel failed");
2092 status
= smb2_session_setup_spnego(session1_2
,
2093 popt_get_cmdline_credentials(),
2094 0 /* previous_session_id */);
2095 CHECK_STATUS(status
, NT_STATUS_OK
);
2098 * use the 2nd channel, 1st session
2100 tree1
->session
= session1_2
;
2103 * Write Replay with Correct ChannelSequence is allowed by the server
2105 smb2cli_session_start_replay(tree1
->session
->smbXcli
);
2106 smb2cli_session_reset_channel_sequence(tree1
->session
->smbXcli
,
2108 status
= smb2_util_write(tree1
, *h1
, buf
, 0, ARRAY_SIZE(buf
));
2109 CHECK_STATUS(status
, NT_STATUS_OK
);
2110 smb2cli_session_stop_replay(tree1
->session
->smbXcli
);
2113 * See what happens if we change the Buffer and perform a Write Replay.
2114 * This is to show that Write Replay does not really care about the data
2116 memset(buf
, 'r', ARRAY_SIZE(buf
));
2117 smb2cli_session_start_replay(tree1
->session
->smbXcli
);
2118 status
= smb2_util_write(tree1
, *h1
, buf
, 0, ARRAY_SIZE(buf
));
2119 CHECK_STATUS(status
, NT_STATUS_OK
);
2120 smb2cli_session_stop_replay(tree1
->session
->smbXcli
);
2123 * Read back from File to verify what was written
2125 rd
= (struct smb2_read
) {
2126 .in
.file
.handle
= *h1
,
2127 .in
.length
= ARRAY_SIZE(buf
),
2130 status
= smb2_read(tree1
, tree1
, &rd
);
2131 CHECK_STATUS(status
, NT_STATUS_OK
);
2133 if ((rd
.out
.data
.length
!= ARRAY_SIZE(buf
)) ||
2134 memcmp(rd
.out
.data
.data
, buf
, ARRAY_SIZE(buf
))) {
2135 torture_comment(tctx
, "Write Replay Data Mismatch\n");
2138 tree1
->session
= session1_1
;
2139 smb2_util_close(tree1
, *h1
);
2143 CHECK_VAL(break_info
.count
, 1);
2145 CHECK_VAL(break_info
.count
, 0);
2149 tree1
->session
= session1_1
;
2152 smb2_util_close(tree1
, *h1
);
2155 smb2_util_unlink(tree1
, fname
);
2156 smb2_deltree(tree1
, BASEDIR
);
2159 talloc_free(mem_ctx
);
2165 * Test Durability V2 Persistent Create Replay on a Single Channel
2167 static bool test_replay5(struct torture_context
*tctx
, struct smb2_tree
*tree
)
2170 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
2171 struct smb2_handle _h
;
2172 struct smb2_handle
*h
= NULL
;
2173 struct smb2_create io
;
2174 struct GUID create_guid
= GUID_random();
2176 uint32_t share_capabilities
;
2179 uint32_t server_capabilities
;
2180 const char *fname
= BASEDIR
"\\replay5.dat";
2181 struct smb2_transport
*transport
= tree
->session
->transport
;
2182 struct smbcli_options options
= tree
->session
->transport
->options
;
2183 uint8_t expect_oplock
= smb2_util_oplock_level("b");
2184 NTSTATUS expect_status
= NT_STATUS_DUPLICATE_OBJECTID
;
2186 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
2187 torture_skip(tctx
, "SMB 3.X Dialect family required for "
2191 server_capabilities
= smb2cli_conn_server_capabilities(
2192 tree
->session
->transport
->conn
);
2193 if (!(server_capabilities
& SMB2_CAP_PERSISTENT_HANDLES
)) {
2195 "Server does not support persistent handles.");
2198 share_capabilities
= smb2cli_tcon_capabilities(tree
->smbXcli
);
2200 share_is_ca
= share_capabilities
& SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY
;
2202 torture_skip(tctx
, "Share is not continuously available.");
2205 share_is_so
= share_capabilities
& SMB2_SHARE_CAP_SCALEOUT
;
2207 expect_oplock
= smb2_util_oplock_level("s");
2208 expect_status
= NT_STATUS_FILE_NOT_AVAILABLE
;
2211 ZERO_STRUCT(break_info
);
2212 break_info
.tctx
= tctx
;
2213 transport
->oplock
.handler
= torture_oplock_ack_handler
;
2214 transport
->oplock
.private_data
= tree
;
2216 torture_comment(tctx
, "Replay of Persistent DurableHandleReqV2 on Single "
2218 status
= torture_smb2_testdir(tree
, BASEDIR
, &_h
);
2219 CHECK_STATUS(status
, NT_STATUS_OK
);
2220 smb2_util_close(tree
, _h
);
2221 smb2_util_unlink(tree
, fname
);
2222 CHECK_VAL(break_info
.count
, 0);
2224 smb2_oplock_create_share(&io
, fname
,
2225 smb2_util_share_access("RWD"),
2226 smb2_util_oplock_level("b"));
2227 io
.in
.durable_open
= false;
2228 io
.in
.durable_open_v2
= true;
2229 io
.in
.persistent_open
= true;
2230 io
.in
.create_guid
= create_guid
;
2231 io
.in
.timeout
= UINT32_MAX
;
2233 status
= smb2_create(tree
, mem_ctx
, &io
);
2234 CHECK_STATUS(status
, NT_STATUS_OK
);
2235 _h
= io
.out
.file
.handle
;
2237 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
2238 CHECK_VAL(io
.out
.oplock_level
, expect_oplock
);
2239 CHECK_VAL(io
.out
.durable_open
, false);
2240 CHECK_VAL(io
.out
.durable_open_v2
, true);
2241 CHECK_VAL(io
.out
.persistent_open
, true);
2242 CHECK_VAL(io
.out
.timeout
, io
.in
.timeout
);
2243 CHECK_VAL(break_info
.count
, 0);
2245 /* disconnect, leaving the durable open */
2248 if (!torture_smb2_connection_ext(tctx
, 0, &options
, &tree
)) {
2249 torture_warning(tctx
, "couldn't reconnect, bailing\n");
2254 /* a re-open of a persistent handle causes an error */
2255 status
= smb2_create(tree
, mem_ctx
, &io
);
2256 CHECK_STATUS(status
, expect_status
);
2258 /* SMB2_FLAGS_REPLAY_OPERATION must be set to open the Persistent Handle */
2259 smb2cli_session_start_replay(tree
->session
->smbXcli
);
2260 smb2cli_session_increment_channel_sequence(tree
->session
->smbXcli
);
2261 status
= smb2_create(tree
, mem_ctx
, &io
);
2262 CHECK_STATUS(status
, NT_STATUS_OK
);
2263 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
2264 CHECK_VAL(io
.out
.durable_open
, false);
2265 CHECK_VAL(io
.out
.persistent_open
, true);
2266 CHECK_VAL(io
.out
.oplock_level
, expect_oplock
);
2267 _h
= io
.out
.file
.handle
;
2270 smb2_util_close(tree
, *h
);
2274 smb2_util_close(tree
, *h
);
2277 smb2_util_unlink(tree
, fname
);
2278 smb2_deltree(tree
, BASEDIR
);
2281 talloc_free(mem_ctx
);
2288 * Test Error Codes when a DurableHandleReqV2 with matching CreateGuid is
2289 * re-sent with or without SMB2_FLAGS_REPLAY_OPERATION
2291 static bool test_replay6(struct torture_context
*tctx
, struct smb2_tree
*tree
)
2294 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
2295 struct smb2_handle _h
;
2296 struct smb2_handle
*h
= NULL
;
2297 struct smb2_create io
, ref1
;
2298 union smb_fileinfo qfinfo
;
2299 struct GUID create_guid
= GUID_random();
2301 const char *fname
= BASEDIR
"\\replay6.dat";
2302 struct smb2_transport
*transport
= tree
->session
->transport
;
2304 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
2305 torture_skip(tctx
, "SMB 3.X Dialect family required for "
2309 torture_reset_break_info(tctx
, &break_info
);
2310 tree
->session
->transport
->oplock
.handler
= torture_oplock_ack_handler
;
2311 tree
->session
->transport
->oplock
.private_data
= tree
;
2313 torture_comment(tctx
, "Error Codes for DurableHandleReqV2 Replay\n");
2314 smb2_util_unlink(tree
, fname
);
2315 status
= torture_smb2_testdir(tree
, BASEDIR
, &_h
);
2316 CHECK_STATUS(status
, NT_STATUS_OK
);
2317 smb2_util_close(tree
, _h
);
2318 torture_wait_for_oplock_break(tctx
);
2319 CHECK_VAL(break_info
.count
, 0);
2320 torture_reset_break_info(tctx
, &break_info
);
2322 smb2_oplock_create_share(&io
, fname
,
2323 smb2_util_share_access("RWD"),
2324 smb2_util_oplock_level("b"));
2325 io
.in
.durable_open
= false;
2326 io
.in
.durable_open_v2
= true;
2327 io
.in
.persistent_open
= false;
2328 io
.in
.create_guid
= create_guid
;
2329 io
.in
.timeout
= UINT32_MAX
;
2331 status
= smb2_create(tree
, mem_ctx
, &io
);
2332 CHECK_STATUS(status
, NT_STATUS_OK
);
2334 _h
= io
.out
.file
.handle
;
2336 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
2337 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("b"));
2338 CHECK_VAL(io
.out
.durable_open
, false);
2339 CHECK_VAL(io
.out
.durable_open_v2
, true);
2341 io
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2342 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
2343 smb2cli_session_start_replay(tree
->session
->smbXcli
);
2344 status
= smb2_create(tree
, mem_ctx
, &io
);
2345 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
2346 CHECK_STATUS(status
, NT_STATUS_OK
);
2347 CHECK_CREATE_OUT(&io
, &ref1
);
2348 torture_wait_for_oplock_break(tctx
);
2349 CHECK_VAL(break_info
.count
, 0);
2350 torture_reset_break_info(tctx
, &break_info
);
2352 qfinfo
= (union smb_fileinfo
) {
2353 .generic
.level
= RAW_SFILEINFO_POSITION_INFORMATION
,
2354 .generic
.in
.file
.handle
= *h
2356 torture_comment(tctx
, "Trying getinfo\n");
2357 status
= smb2_getinfo_file(tree
, mem_ctx
, &qfinfo
);
2358 CHECK_STATUS(status
, NT_STATUS_OK
);
2359 CHECK_VAL(qfinfo
.position_information
.out
.position
, 0);
2361 smb2cli_session_start_replay(tree
->session
->smbXcli
);
2362 status
= smb2_create(tree
, mem_ctx
, &io
);
2363 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
2364 CHECK_STATUS(status
, NT_STATUS_OK
);
2365 torture_assert_u64_not_equal_goto(tctx
,
2366 io
.out
.file
.handle
.data
[0],
2367 ref1
.out
.file
.handle
.data
[0],
2368 ret
, done
, "data 0");
2369 torture_assert_u64_not_equal_goto(tctx
,
2370 io
.out
.file
.handle
.data
[1],
2371 ref1
.out
.file
.handle
.data
[1],
2372 ret
, done
, "data 1");
2373 torture_wait_for_oplock_break(tctx
);
2374 CHECK_VAL(break_info
.count
, 1);
2375 CHECK_VAL(break_info
.level
, smb2_util_oplock_level("s"));
2376 torture_reset_break_info(tctx
, &break_info
);
2379 * Resend the matching Durable V2 Create without
2380 * SMB2_FLAGS_REPLAY_OPERATION. This triggers an oplock break and still
2381 * gets NT_STATUS_DUPLICATE_OBJECTID
2383 status
= smb2_create(tree
, mem_ctx
, &io
);
2384 CHECK_STATUS(status
, NT_STATUS_DUPLICATE_OBJECTID
);
2385 torture_wait_for_oplock_break(tctx
);
2386 CHECK_VAL(break_info
.count
, 0);
2387 torture_reset_break_info(tctx
, &break_info
);
2390 * According to MS-SMB2 3.3.5.9.10 if Durable V2 Create is replayed and
2391 * FileAttributes or CreateDisposition do not match the earlier Create
2392 * request the Server fails request with
2393 * NT_STATUS_INVALID_PARAMETER. But through this test we see that server
2394 * does not really care about changed FileAttributes or
2395 * CreateDisposition.
2397 io
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2398 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
2399 smb2cli_session_start_replay(tree
->session
->smbXcli
);
2400 status
= smb2_create(tree
, mem_ctx
, &io
);
2401 smb2cli_session_stop_replay(tree
->session
->smbXcli
);
2402 CHECK_STATUS(status
, NT_STATUS_OK
);
2403 torture_assert_u64_not_equal_goto(tctx
,
2404 io
.out
.file
.handle
.data
[0],
2405 ref1
.out
.file
.handle
.data
[0],
2406 ret
, done
, "data 0");
2407 torture_assert_u64_not_equal_goto(tctx
,
2408 io
.out
.file
.handle
.data
[1],
2409 ref1
.out
.file
.handle
.data
[1],
2410 ret
, done
, "data 1");
2411 torture_wait_for_oplock_break(tctx
);
2412 CHECK_VAL(break_info
.count
, 0);
2416 smb2_util_close(tree
, *h
);
2419 smb2_util_unlink(tree
, fname
);
2420 smb2_deltree(tree
, BASEDIR
);
2423 talloc_free(mem_ctx
);
2428 static bool test_replay7(struct torture_context
*tctx
, struct smb2_tree
*tree
)
2430 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
2431 struct smb2_transport
*transport
= tree
->session
->transport
;
2433 struct smb2_handle _dh
;
2434 struct smb2_handle
*dh
= NULL
;
2435 struct smb2_notify notify
;
2436 struct smb2_request
*req
;
2437 union smb_fileinfo qfinfo
;
2440 if (smbXcli_conn_protocol(transport
->conn
) < PROTOCOL_SMB3_00
) {
2441 torture_skip(tctx
, "SMB 3.X Dialect family required for "
2445 torture_comment(tctx
, "Notify across increment/decrement of csn\n");
2447 smbXcli_conn_set_force_channel_sequence(transport
->conn
, true);
2449 status
= torture_smb2_testdir(tree
, BASEDIR
, &_dh
);
2450 CHECK_STATUS(status
, NT_STATUS_OK
);
2453 notify
.in
.recursive
= 0x0000;
2454 notify
.in
.buffer_size
= 0xffff;
2455 notify
.in
.file
.handle
= _dh
;
2456 notify
.in
.completion_filter
= FILE_NOTIFY_CHANGE_FILE_NAME
;
2457 notify
.in
.unknown
= 0x00000000;
2460 * This posts a long-running request with csn==0 to "dh". Now
2461 * op->request_count==1 in smb2_server.c.
2463 smb2cli_session_reset_channel_sequence(tree
->session
->smbXcli
, 0);
2464 req
= smb2_notify_send(tree
, ¬ify
);
2466 qfinfo
= (union smb_fileinfo
) {
2467 .generic
.level
= RAW_FILEINFO_POSITION_INFORMATION
,
2468 .generic
.in
.file
.handle
= _dh
2472 * This sequence of 2 dummy requests moves
2473 * op->request_count==1 to op->pre_request_count. The numbers
2474 * used avoid int16 overflow.
2477 smb2cli_session_reset_channel_sequence(tree
->session
->smbXcli
, 30000);
2478 status
= smb2_getinfo_file(tree
, mem_ctx
, &qfinfo
);
2479 CHECK_STATUS(status
, NT_STATUS_OK
);
2481 smb2cli_session_reset_channel_sequence(tree
->session
->smbXcli
, 60000);
2482 status
= smb2_getinfo_file(tree
, mem_ctx
, &qfinfo
);
2483 CHECK_STATUS(status
, NT_STATUS_OK
);
2486 * This final request turns the op->global->channel_sequence
2487 * to the same as we had when sending the notify above. The
2488 * notify's request count has in the meantime moved to
2489 * op->pre_request_count.
2492 smb2cli_session_reset_channel_sequence(tree
->session
->smbXcli
, 0);
2493 status
= smb2_getinfo_file(tree
, mem_ctx
, &qfinfo
);
2494 CHECK_STATUS(status
, NT_STATUS_OK
);
2497 * At this point op->request_count==0.
2499 * The next cancel makes us reply to the notify. Because the
2500 * csn we currently use is the same as we used when sending
2501 * the notify, smbd thinks it must decrement op->request_count
2502 * and not op->pre_request_count.
2505 status
= smb2_cancel(req
);
2506 CHECK_STATUS(status
, NT_STATUS_OK
);
2508 status
= smb2_notify_recv(req
, mem_ctx
, ¬ify
);
2509 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
2515 smb2_util_close(tree
, _dh
);
2517 smb2_deltree(tree
, BASEDIR
);
2519 talloc_free(mem_ctx
);
2524 struct torture_suite
*torture_smb2_replay_init(TALLOC_CTX
*ctx
)
2526 struct torture_suite
*suite
=
2527 torture_suite_create(ctx
, "replay");
2529 torture_suite_add_1smb2_test(suite
, "replay-commands", test_replay_commands
);
2530 torture_suite_add_1smb2_test(suite
, "replay-regular", test_replay_regular
);
2531 torture_suite_add_1smb2_test(suite
, "replay-dhv2-oplock1", test_replay_dhv2_oplock1
);
2532 torture_suite_add_1smb2_test(suite
, "replay-dhv2-oplock2", test_replay_dhv2_oplock2
);
2533 torture_suite_add_1smb2_test(suite
, "replay-dhv2-oplock3", test_replay_dhv2_oplock3
);
2534 torture_suite_add_1smb2_test(suite
, "replay-dhv2-oplock-lease", test_replay_dhv2_oplock_lease
);
2535 torture_suite_add_1smb2_test(suite
, "replay-dhv2-lease1", test_replay_dhv2_lease1
);
2536 torture_suite_add_1smb2_test(suite
, "replay-dhv2-lease2", test_replay_dhv2_lease2
);
2537 torture_suite_add_1smb2_test(suite
, "replay-dhv2-lease3", test_replay_dhv2_lease3
);
2538 torture_suite_add_1smb2_test(suite
, "replay-dhv2-lease-oplock", test_replay_dhv2_lease_oplock
);
2539 torture_suite_add_1smb2_test(suite
, "channel-sequence", test_channel_sequence
);
2540 torture_suite_add_1smb2_test(suite
, "replay3", test_replay3
);
2541 torture_suite_add_1smb2_test(suite
, "replay4", test_replay4
);
2542 torture_suite_add_1smb2_test(suite
, "replay5", test_replay5
);
2543 torture_suite_add_1smb2_test(suite
, "replay6", test_replay6
);
2544 torture_suite_add_1smb2_test(suite
, "replay7", test_replay7
);
2546 suite
->description
= talloc_strdup(suite
, "SMB2 REPLAY tests");