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_FILEINFO_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_FILEINFO_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_FILEINFO_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 struct torture_suite *torture_smb2_replay_init(TALLOC_CTX *ctx)
2430 struct torture_suite *suite =
2431 torture_suite_create(ctx, "replay");
2433 torture_suite_add_1smb2_test(suite, "replay-commands", test_replay_commands);
2434 torture_suite_add_1smb2_test(suite, "replay-regular", test_replay_regular);
2435 torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock1", test_replay_dhv2_oplock1);
2436 torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock2", test_replay_dhv2_oplock2);
2437 torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock3", test_replay_dhv2_oplock3);
2438 torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock-lease", test_replay_dhv2_oplock_lease);
2439 torture_suite_add_1smb2_test(suite, "replay-dhv2-lease1", test_replay_dhv2_lease1);
2440 torture_suite_add_1smb2_test(suite, "replay-dhv2-lease2", test_replay_dhv2_lease2);
2441 torture_suite_add_1smb2_test(suite, "replay-dhv2-lease3", test_replay_dhv2_lease3);
2442 torture_suite_add_1smb2_test(suite, "replay-dhv2-lease-oplock", test_replay_dhv2_lease_oplock);
2443 torture_suite_add_1smb2_test(suite, "channel-sequence", test_channel_sequence);
2444 torture_suite_add_1smb2_test(suite, "replay3", test_replay3);
2445 torture_suite_add_1smb2_test(suite, "replay4", test_replay4);
2446 torture_suite_add_1smb2_test(suite, "replay5", test_replay5);
2447 torture_suite_add_1smb2_test(suite, "replay6", test_replay6);
2449 suite->description = talloc_strdup(suite, "SMB2 REPLAY tests");