torture: Add test for channel sequence number handling
[Samba.git] / source4 / torture / smb2 / replay.c
blob021346a60c0dacdab7bc0c869a9f38a7334c2497
1 /*
2 Unix SMB/CIFS implementation.
4 test suite for SMB2 replay
6 Copyright (C) Anubhav Rakshit 2014
7 Copyright (C) Stefan Metzmacher 2014
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28 #include "../libcli/smb/smbXcli_base.h"
29 #include "lib/cmdline/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); \
40 ret = false; \
41 goto done; \
42 }} while (0)
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)); \
48 ret = false; \
49 goto done; \
50 }} while (0)
52 #define CHECK_CREATED(__io, __created, __attribute) \
53 do { \
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); \
59 } while(0)
61 #define CHECK_HANDLE(__h1, __h2) \
62 do { \
63 CHECK_VAL((__h1)->data[0], (__h2)->data[0]); \
64 CHECK_VAL((__h1)->data[1], (__h2)->data[1]); \
65 } while(0)
67 #define __IO_OUT_VAL(__io1, __io2, __m) \
68 CHECK_VAL((__io1)->out.__m, (__io2)->out.__m)
70 #define CHECK_CREATE_OUT(__io1, __io2) \
71 do { \
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]);\
92 } \
93 } while(0)
95 #define BASEDIR "replaytestdir"
97 struct break_info {
98 struct torture_context *tctx;
99 struct smb2_handle handle;
100 uint8_t level;
101 struct smb2_break br;
102 int count;
103 int failures;
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)
112 ZERO_STRUCTP(r);
113 r->tctx = tctx;
116 static void torture_oplock_ack_callback(struct smb2_request *req)
118 NTSTATUS status;
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;
126 return;
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,
135 uint8_t level,
136 void *private_data)
138 struct smb2_tree *tree = private_data;
139 const char *name;
140 struct smb2_request *req;
142 ZERO_STRUCT(break_info.br);
144 break_info.handle = *handle;
145 break_info.level = level;
146 break_info.count++;
148 switch (level) {
149 case SMB2_OPLOCK_LEVEL_II:
150 name = "level II";
151 break;
152 case SMB2_OPLOCK_LEVEL_NONE:
153 name = "none";
154 break;
155 default:
156 name = "unknown";
157 break_info.failures++;
159 torture_comment(break_info.tctx,
160 "Acking to %s [0x%02X] in oplock handler\n",
161 name, level);
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;
171 return true;
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,
180 void *private_data)
182 bool *timesup = (bool *)private_data;
183 *timesup = true;
184 return;
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;
194 struct timeval ne;
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, &timesup);
202 if (te == NULL) {
203 torture_comment(tctx, "Failed to wait for an oplock break. "
204 "test results may not be accurate.");
205 goto done;
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 "
212 "accurate.");
213 goto done;
217 done:
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);
226 return;
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)
235 bool ret = true;
236 NTSTATUS status;
237 struct smb2_handle h;
238 uint8_t buf[200];
239 struct smb2_read rd;
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];
245 struct smb2_flush f;
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 "
252 "Replay tests\n");
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) {
282 .in.file.handle = h
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) {
289 .in.file.handle = h,
290 .in.length = 10,
291 .in.offset = 0,
292 .in.min_count = 1
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) {
327 .in.locks = el,
328 .in.lock_count = 0x0001,
329 .in.lock_sequence = 0x00000000,
330 .in.file.handle = h
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);
348 done:
349 smb2cli_session_stop_replay(tree->session->smbXcli);
350 smb2_util_close(tree, h);
351 smb2_deltree(tree, BASEDIR);
353 talloc_free(tmp_ctx);
355 return ret;
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)
366 NTSTATUS status;
367 TALLOC_CTX *mem_ctx = talloc_new(tctx);
368 struct smb2_handle _h;
369 struct smb2_handle *h = NULL;
370 struct smb2_create io;
371 uint32_t perms = 0;
372 bool ret = true;
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 "
378 "replay tests\n");
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 |
397 SEC_FILE_WRITE_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,
405 .in.fname = fname
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;
412 h = &_h;
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);
422 h = NULL;
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;
433 h = &_h;
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);
443 h = NULL;
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;
454 h = &_h;
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);
463 done:
464 if (h != NULL) {
465 smb2_util_close(tree, *h);
467 smb2_deltree(tree, BASEDIR);
469 talloc_free(tree);
470 talloc_free(mem_ctx);
472 return ret;
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)
481 NTSTATUS status;
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();
487 bool ret = true;
488 const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat";
489 struct smb2_transport *transport = tree->session->transport;
490 uint32_t share_capabilities;
491 bool share_is_so;
493 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
494 torture_skip(tctx, "SMB 3.X Dialect family required for "
495 "replay tests\n");
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 "
507 "Channel\n");
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);
525 ref1 = io;
526 _h = io.out.file.handle;
527 h = &_h;
528 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
529 CHECK_VAL(io.out.durable_open, false);
530 if (share_is_so) {
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);
534 } else {
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);
550 done:
551 if (h != NULL) {
552 smb2_util_close(tree, *h);
554 smb2_deltree(tree, BASEDIR);
556 talloc_free(tree);
557 talloc_free(mem_ctx);
559 return ret;
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)
572 NTSTATUS status;
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();
578 bool ret = true;
579 const char *fname = BASEDIR "\\replay_dhv2_oplock2.dat";
580 struct smb2_transport *transport = tree->session->transport;
581 uint32_t share_capabilities;
582 bool share_is_so;
584 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
585 torture_skip(tctx, "SMB 3.X Dialect family required for "
586 "replay tests\n");
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 "
598 "Channel\n");
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);
616 ref1 = io;
617 _h = io.out.file.handle;
618 h = &_h;
619 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
620 CHECK_VAL(io.out.durable_open, false);
621 if (share_is_so) {
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);
625 } else {
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
652 ref2 = ref1;
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);
680 if (!share_is_so) {
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);
687 done:
688 if (h != NULL) {
689 smb2_util_close(tree, *h);
691 smb2_deltree(tree, BASEDIR);
693 talloc_free(tree);
694 talloc_free(mem_ctx);
696 return ret;
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)
707 NTSTATUS status;
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();
713 bool ret = true;
714 const char *fname = BASEDIR "\\replay_dhv2_oplock3.dat";
715 struct smb2_transport *transport = tree->session->transport;
716 uint32_t share_capabilities;
717 bool share_is_so;
719 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
720 torture_skip(tctx, "SMB 3.X Dialect family required for "
721 "replay tests\n");
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 "
733 "Channel\n");
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);
751 ref1 = io;
752 _h = io.out.file.handle;
753 h = &_h;
754 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
755 CHECK_VAL(io.out.durable_open, false);
756 if (share_is_so) {
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);
760 } else {
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
772 * the handle.
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);
806 if (!share_is_so) {
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);
813 done:
814 if (h != NULL) {
815 smb2_util_close(tree, *h);
817 smb2_deltree(tree, BASEDIR);
819 talloc_free(tree);
820 talloc_free(mem_ctx);
822 return ret;
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)
832 NTSTATUS status;
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();
838 bool ret = true;
839 const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat";
840 struct smb2_transport *transport = tree->session->transport;
841 uint32_t share_capabilities;
842 bool share_is_so;
843 uint32_t server_capabilities;
844 struct smb2_lease ls;
845 uint64_t lease_key;
847 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
848 torture_skip(tctx, "SMB 3.X Dialect family required for "
849 "replay tests\n");
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 "
866 "Channel\n");
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;
885 h = &_h;
886 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
887 CHECK_VAL(io.out.durable_open, false);
888 if (share_is_so) {
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);
892 } else {
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);
916 done:
917 if (h != NULL) {
918 smb2_util_close(tree, *h);
920 smb2_deltree(tree, BASEDIR);
922 talloc_free(tree);
923 talloc_free(mem_ctx);
925 return ret;
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)
940 NTSTATUS status;
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();
948 bool ret = true;
949 const char *fname = BASEDIR "\\replay2_lease1.dat";
950 struct smb2_transport *transport = tree->session->transport;
951 uint32_t share_capabilities;
952 bool share_is_so;
953 uint32_t server_capabilities;
954 struct smb2_lease ls1, ls2;
955 uint64_t lease_key;
957 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
958 torture_skip(tctx, "SMB 3.X Dialect family required for "
959 "replay tests\n");
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);
995 ref1 = io1;
996 _h1 = io1.out.file.handle;
997 h1 = &_h1;
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);
1003 if (share_is_so) {
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);
1008 } else {
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;
1029 h2 = &_h2;
1032 * Replay Durable V2 Create on single channel.
1033 * We get the io from open #1 but with the
1034 * upgraded lease.
1037 /* adapt expected lease in response */
1038 if (!share_is_so) {
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);
1050 done:
1051 smb2cli_session_stop_replay(tree->session->smbXcli);
1053 if (h1 != NULL) {
1054 smb2_util_close(tree, *h1);
1056 if (h2 != NULL) {
1057 smb2_util_close(tree, *h2);
1059 smb2_deltree(tree, BASEDIR);
1061 talloc_free(tree);
1062 talloc_free(mem_ctx);
1064 return ret;
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)
1081 NTSTATUS status;
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();
1089 bool ret = true;
1090 const char *fname = BASEDIR "\\replay2_lease2.dat";
1091 struct smb2_transport *transport = tree->session->transport;
1092 uint32_t share_capabilities;
1093 bool share_is_so;
1094 uint32_t server_capabilities;
1095 struct smb2_lease ls1, ls2;
1096 uint64_t lease_key;
1098 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
1099 torture_skip(tctx, "SMB 3.X Dialect family required for "
1100 "replay tests\n");
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);
1141 if (share_is_so) {
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);
1146 } else {
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);
1152 ref1 = io1;
1153 _h1 = io1.out.file.handle;
1154 h1 = &_h1;
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;
1170 h2 = &_h2;
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
1177 * upgraded lease.
1180 /* adapt the expected response */
1181 if (!share_is_so) {
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);
1201 done:
1202 smb2cli_session_stop_replay(tree->session->smbXcli);
1204 if (h1 != NULL) {
1205 smb2_util_close(tree, *h1);
1207 if (h2 != NULL) {
1208 smb2_util_close(tree, *h2);
1210 smb2_deltree(tree, BASEDIR);
1212 talloc_free(tree);
1213 talloc_free(mem_ctx);
1215 return ret;
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)
1225 NTSTATUS status;
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();
1233 bool ret = true;
1234 const char *fname = BASEDIR "\\replay2_lease2.dat";
1235 struct smb2_transport *transport = tree->session->transport;
1236 uint32_t share_capabilities;
1237 bool share_is_so;
1238 uint32_t server_capabilities;
1239 struct smb2_lease ls1, ls2;
1240 uint64_t lease_key;
1242 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
1243 torture_skip(tctx, "SMB 3.X Dialect family required for "
1244 "replay tests\n");
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);
1285 if (share_is_so) {
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);
1290 } else {
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;
1297 h1 = &_h1;
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;
1313 h2 = &_h2;
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);
1334 done:
1335 smb2cli_session_stop_replay(tree->session->smbXcli);
1337 if (h1 != NULL) {
1338 smb2_util_close(tree, *h1);
1340 if (h2 != NULL) {
1341 smb2_util_close(tree, *h2);
1343 smb2_deltree(tree, BASEDIR);
1345 talloc_free(tree);
1346 talloc_free(mem_ctx);
1348 return ret;
1352 * Test durability v2 create replay detection on single channel.
1353 * Do the original create with a lease, and do the replay
1354 * with an oplock.
1356 static bool test_replay_dhv2_lease_oplock(struct torture_context *tctx,
1357 struct smb2_tree *tree)
1359 NTSTATUS status;
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();
1367 bool ret = true;
1368 const char *fname = BASEDIR "\\replay2_lease1.dat";
1369 struct smb2_transport *transport = tree->session->transport;
1370 uint32_t share_capabilities;
1371 bool share_is_so;
1372 uint32_t server_capabilities;
1373 struct smb2_lease ls1, ls2;
1374 uint64_t lease_key;
1376 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
1377 torture_skip(tctx, "SMB 3.X Dialect family required for "
1378 "replay tests\n");
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);
1414 ref1 = io1;
1415 _h1 = io1.out.file.handle;
1416 h1 = &_h1;
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);
1422 if (share_is_so) {
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);
1427 } else {
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;
1448 h2 = &_h2;
1451 * Replay Durable V2 Create on single channel.
1452 * We get the io from open #1 but with the
1453 * upgraded lease.
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 */
1466 if (!share_is_so) {
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);
1478 done:
1479 smb2cli_session_stop_replay(tree->session->smbXcli);
1481 if (h1 != NULL) {
1482 smb2_util_close(tree, *h1);
1484 if (h2 != NULL) {
1485 smb2_util_close(tree, *h2);
1487 smb2_deltree(tree, BASEDIR);
1489 talloc_free(tree);
1490 talloc_free(mem_ctx);
1492 return ret;
1495 static bool test_channel_sequence_table(struct torture_context *tctx,
1496 struct smb2_tree *tree,
1497 bool do_replay,
1498 uint16_t opcode)
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();
1506 bool ret = true;
1507 const char *fname = BASEDIR "\\channel_sequence.dat";
1508 uint16_t csn = 0;
1509 uint16_t limit = UINT16_MAX - 0x7fff;
1510 int i;
1511 struct {
1512 uint16_t csn;
1513 bool csn_rand_low;
1514 bool csn_rand_high;
1515 NTSTATUS expected_status;
1516 } tests[] = {
1518 .csn = 0,
1519 .expected_status = NT_STATUS_OK,
1521 .csn = 0x7fff + 1,
1522 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
1524 .csn = 0x7fff + 2,
1525 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
1527 .csn = -1,
1528 .csn_rand_high = true,
1529 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
1531 .csn = 0xffff,
1532 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
1534 .csn = 0x7fff,
1535 .expected_status = NT_STATUS_OK,
1537 .csn = 0x7ffe,
1538 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
1540 .csn = 0,
1541 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
1543 .csn = -1,
1544 .csn_rand_low = true,
1545 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
1547 .csn = 0x7fff + 1,
1548 .expected_status = NT_STATUS_OK,
1550 .csn = 0xffff,
1551 .expected_status = NT_STATUS_OK,
1553 .csn = 0,
1554 .expected_status = NT_STATUS_OK,
1556 .csn = 1,
1557 .expected_status = NT_STATUS_OK,
1559 .csn = 0,
1560 .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
1562 .csn = 1,
1563 .expected_status = NT_STATUS_OK,
1565 .csn = 0xffff,
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;
1588 phandle = &handle;
1590 for (i=0; i <ARRAY_SIZE(tests); i++) {
1592 const char *opstr = "";
1593 union smb_fileinfo qfinfo;
1595 csn = tests[i].csn;
1597 if (tests[i].csn_rand_low) {
1598 csn = rand() % limit;
1599 } else if (tests[i].csn_rand_high) {
1600 csn = rand() % limit + 0x7fff;
1603 switch (opcode) {
1604 case SMB2_OP_WRITE:
1605 opstr = "write";
1606 break;
1607 case SMB2_OP_IOCTL:
1608 opstr = "ioctl";
1609 break;
1610 case SMB2_OP_SETINFO:
1611 opstr = "setinfo";
1612 break;
1613 default:
1614 break;
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));
1624 if (do_replay) {
1625 smb2cli_session_start_replay(tree->session->smbXcli);
1628 switch (opcode) {
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,
1641 .in.offset = 0
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,
1649 rd.out.data, blob,
1650 "read/write mismatch");
1652 break;
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);
1664 break;
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);
1673 break;
1675 default:
1676 break;
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");
1688 if (do_replay) {
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");
1697 done:
1698 if (phandle != NULL) {
1699 smb2_util_close(tree, *phandle);
1702 smb2_util_unlink(tree, fname);
1704 return ret;
1707 static bool test_channel_sequence(struct torture_context *tctx,
1708 struct smb2_tree *tree)
1710 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1711 bool ret = true;
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 };
1717 int i;
1719 if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
1720 torture_skip(tctx, "SMB 3.X Dialect family required for "
1721 "Replay tests\n");
1724 server_capabilities = smb2cli_conn_server_capabilities(
1725 tree->session->transport->conn);
1726 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
1727 torture_skip(tctx,
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");
1749 done:
1751 smb2_util_unlink(tree, fname);
1752 smb2_deltree(tree, BASEDIR);
1754 talloc_free(tree);
1755 talloc_free(mem_ctx);
1757 return ret;
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);
1767 NTSTATUS status;
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();
1773 bool ret = true;
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;
1781 bool share_is_so;
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 "
1786 "Replay tests\n");
1789 server_capabilities = smb2cli_conn_server_capabilities(
1790 tree1->session->transport->conn);
1791 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
1792 torture_skip(tctx,
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 "
1805 "Channel\n");
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;
1828 h = &_h;
1829 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1830 if (share_is_so) {
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);
1834 } else {
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,
1843 host,
1844 lpcfg_smb_ports(tctx->lp_ctx),
1845 share,
1846 lpcfg_resolve_context(tctx->lp_ctx),
1847 popt_get_cmdline_credentials(),
1848 &tree2,
1849 tctx->ev,
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),
1866 tree2, session1_1);
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;
1883 h = &_h;
1884 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1885 if (share_is_so) {
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);
1889 } else {
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);
1899 h = NULL;
1901 done:
1902 talloc_free(tree2);
1903 tree1->session = session1_1;
1905 if (h != NULL) {
1906 smb2_util_close(tree1, *h);
1909 smb2_util_unlink(tree1, fname);
1910 smb2_deltree(tree1, BASEDIR);
1912 talloc_free(tree1);
1913 talloc_free(mem_ctx);
1915 return ret;
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);
1925 NTSTATUS status;
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();
1931 uint8_t buf[64];
1932 struct smb2_read rd;
1933 union smb_setfileinfo sfinfo;
1934 bool ret = true;
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;
1941 uint16_t curr_cs;
1942 uint32_t share_capabilities;
1943 bool share_is_so;
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 "
1948 "Replay tests\n");
1951 server_capabilities = smb2cli_conn_server_capabilities(
1952 tree1->session->transport->conn);
1953 if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
1954 torture_skip(tctx,
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;
1990 h1 = &_h1;
1991 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1992 if (share_is_so) {
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);
1996 } else {
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
2009 * Channel Failure
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),
2019 .in.offset = 0
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
2026 * server
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
2035 * by server
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
2045 * server
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),
2060 .in.offset = 0
2062 status = smb2_read(tree1, tree1, &rd);
2063 CHECK_STATUS(status, NT_STATUS_OK);
2065 status = smb2_connect(tctx,
2066 host,
2067 lpcfg_smb_ports(tctx->lp_ctx),
2068 share,
2069 lpcfg_resolve_context(tctx->lp_ctx),
2070 popt_get_cmdline_credentials(),
2071 &tree2,
2072 tctx->ev,
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),
2089 tree2, session1_1);
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,
2107 curr_cs);
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),
2128 .in.offset = 0
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);
2140 h1 = NULL;
2142 if (share_is_so) {
2143 CHECK_VAL(break_info.count, 1);
2144 } else {
2145 CHECK_VAL(break_info.count, 0);
2147 done:
2148 talloc_free(tree2);
2149 tree1->session = session1_1;
2151 if (h1 != NULL) {
2152 smb2_util_close(tree1, *h1);
2155 smb2_util_unlink(tree1, fname);
2156 smb2_deltree(tree1, BASEDIR);
2158 talloc_free(tree1);
2159 talloc_free(mem_ctx);
2161 return ret;
2165 * Test Durability V2 Persistent Create Replay on a Single Channel
2167 static bool test_replay5(struct torture_context *tctx, struct smb2_tree *tree)
2169 NTSTATUS status;
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();
2175 bool ret = true;
2176 uint32_t share_capabilities;
2177 bool share_is_ca;
2178 bool share_is_so;
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 "
2188 "Replay tests\n");
2191 server_capabilities = smb2cli_conn_server_capabilities(
2192 tree->session->transport->conn);
2193 if (!(server_capabilities & SMB2_CAP_PERSISTENT_HANDLES)) {
2194 torture_skip(tctx,
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;
2201 if (!share_is_ca) {
2202 torture_skip(tctx, "Share is not continuously available.");
2205 share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
2206 if (share_is_so) {
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 "
2217 "Channel\n");
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;
2236 h = &_h;
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 */
2246 TALLOC_FREE(tree);
2248 if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
2249 torture_warning(tctx, "couldn't reconnect, bailing\n");
2250 ret = false;
2251 goto done;
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;
2268 h = &_h;
2270 smb2_util_close(tree, *h);
2271 h = NULL;
2272 done:
2273 if (h != NULL) {
2274 smb2_util_close(tree, *h);
2277 smb2_util_unlink(tree, fname);
2278 smb2_deltree(tree, BASEDIR);
2280 talloc_free(tree);
2281 talloc_free(mem_ctx);
2283 return ret;
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)
2293 NTSTATUS status;
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();
2300 bool ret = true;
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 "
2306 "replay tests\n");
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);
2333 ref1 = io;
2334 _h = io.out.file.handle;
2335 h = &_h;
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);
2414 done:
2415 if (h != NULL) {
2416 smb2_util_close(tree, *h);
2419 smb2_util_unlink(tree, fname);
2420 smb2_deltree(tree, BASEDIR);
2422 talloc_free(tree);
2423 talloc_free(mem_ctx);
2425 return ret;
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;
2432 NTSTATUS status;
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;
2438 bool ret = false;
2440 if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
2441 torture_skip(tctx, "SMB 3.X Dialect family required for "
2442 "replay tests\n");
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);
2451 dh = &_dh;
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, &notify);
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, &notify);
2509 CHECK_STATUS(status, NT_STATUS_CANCELLED);
2511 ret = true;
2513 done:
2514 if (dh != NULL) {
2515 smb2_util_close(tree, _dh);
2517 smb2_deltree(tree, BASEDIR);
2518 talloc_free(tree);
2519 talloc_free(mem_ctx);
2521 return ret;
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");
2548 return suite;