903adc6798f6c7419a4578bb332e6bba5a00c8b2
[metze/samba/wip.git] / source4 / torture / smb2 / replay.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    test suite for SMB2 replay
5
6    Copyright (C) Anubhav Rakshit 2014
7    Copyright (C) Stefan Metzmacher 2014
8
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.
13
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.
18
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/>.
21 */
22
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"
35 #include "oplock_break_handler.h"
36
37 #define CHECK_VAL(v, correct) do { \
38         if ((v) != (correct)) { \
39                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
40                                 __location__, #v, (int)v, (int)correct); \
41                 ret = false; \
42                 goto done; \
43         }} while (0)
44
45 #define CHECK_STATUS(status, correct) do { \
46         if (!NT_STATUS_EQUAL(status, correct)) { \
47                 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
48                        nt_errstr(status), nt_errstr(correct)); \
49                 ret = false; \
50                 goto done; \
51         }} while (0)
52
53 #define CHECK_CREATED(__io, __created, __attribute)                     \
54         do {                                                            \
55                 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
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)
60
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)
66
67 #define __IO_OUT_VAL(__io1, __io2, __m) \
68         CHECK_VAL((__io1)->out.__m, (__io2)->out.__m)
69
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)
94
95 #define BASEDIR "replaytestdir"
96
97 /**
98  * Timer handler function notifies the registering function that time is up
99  */
100 static void timeout_cb(struct tevent_context *ev,
101                        struct tevent_timer *te,
102                        struct timeval current_time,
103                        void *private_data)
104 {
105         bool *timesup = (bool *)private_data;
106         *timesup = true;
107         return;
108 }
109
110 /**
111  *  Wait a short period of time to receive a single oplock break request
112  */
113 static void torture_wait_for_oplock_break(struct torture_context *tctx)
114 {
115         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
116         struct tevent_timer *te = NULL;
117         struct timeval ne;
118         bool timesup = false;
119         int old_count = break_info.count;
120
121         /* Wait .1 seconds for an oplock break */
122         ne = tevent_timeval_current_ofs(0, 100000);
123
124         te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup);
125         if (te == NULL) {
126                 torture_comment(tctx, "Failed to wait for an oplock break. "
127                                       "test results may not be accurate.");
128                 goto done;
129         }
130
131         while (!timesup && break_info.count < old_count + 1) {
132                 if (tevent_loop_once(tctx->ev) != 0) {
133                         torture_comment(tctx, "Failed to wait for an oplock "
134                                               "break. test results may not be "
135                                               "accurate.");
136                         goto done;
137                 }
138         }
139
140 done:
141         /*
142          * We don't know if the timed event fired and was freed, we received
143          * our oplock break, or some other event triggered the loop.  Thus,
144          * we create a tmp_ctx to be able to safely free/remove the timed
145          * event in all 3 cases.
146          */
147         talloc_free(tmp_ctx);
148
149         return;
150 }
151
152 /**
153  * Test what happens when SMB2_FLAGS_REPLAY_OPERATION is enabled for various
154  * commands. We want to verify if the server returns an error code or not.
155  */
156 static bool test_replay_commands(struct torture_context *tctx, struct smb2_tree *tree)
157 {
158         bool ret = true;
159         NTSTATUS status;
160         struct smb2_handle h;
161         uint8_t buf[200];
162         struct smb2_read rd;
163         union smb_setfileinfo sfinfo;
164         union smb_fileinfo qfinfo;
165         union smb_ioctl ioctl;
166         struct smb2_lock lck;
167         struct smb2_lock_element el[2];
168         struct smb2_flush f;
169         TALLOC_CTX *tmp_ctx = talloc_new(tree);
170         const char *fname = BASEDIR "\\replay_commands.dat";
171         struct smb2_transport *transport = tree->session->transport;
172
173         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
174                 torture_skip(tctx, "SMB 3.X Dialect family required for "
175                                    "Replay tests\n");
176         }
177
178         ZERO_STRUCT(break_info);
179         break_info.tctx = tctx;
180         tree->session->transport->oplock.handler = torture_oplock_ack_handler;
181         tree->session->transport->oplock.private_data = tree;
182
183         status = torture_smb2_testdir(tree, BASEDIR, &h);
184         CHECK_STATUS(status, NT_STATUS_OK);
185         smb2_util_close(tree, h);
186
187         smb2cli_session_start_replay(tree->session->smbXcli);
188
189         torture_comment(tctx, "Try Commands with Replay Flags Enabled\n");
190
191         torture_comment(tctx, "Trying create\n");
192         status = torture_smb2_testfile(tree, fname, &h);
193         CHECK_STATUS(status, NT_STATUS_OK);
194         CHECK_VAL(break_info.count, 0);
195         /*
196          * Wireshark shows that the response has SMB2_FLAGS_REPLAY_OPERATION
197          * flags set. The server should ignore this flag.
198          */
199
200         torture_comment(tctx, "Trying write\n");
201         status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
202         CHECK_STATUS(status, NT_STATUS_OK);
203
204         f = (struct smb2_flush) {
205                 .in.file.handle = h
206         };
207         torture_comment(tctx, "Trying flush\n");
208         status = smb2_flush(tree, &f);
209         CHECK_STATUS(status, NT_STATUS_OK);
210
211         rd = (struct smb2_read) {
212                 .in.file.handle = h,
213                 .in.length = 10,
214                 .in.offset = 0,
215                 .in.min_count = 1
216         };
217         torture_comment(tctx, "Trying read\n");
218         status = smb2_read(tree, tmp_ctx, &rd);
219         CHECK_STATUS(status, NT_STATUS_OK);
220         CHECK_VAL(rd.out.data.length, 10);
221
222         sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
223         sfinfo.position_information.in.file.handle = h;
224         sfinfo.position_information.in.position = 0x1000;
225         torture_comment(tctx, "Trying setinfo\n");
226         status = smb2_setinfo_file(tree, &sfinfo);
227         CHECK_STATUS(status, NT_STATUS_OK);
228
229         qfinfo = (union smb_fileinfo) {
230                 .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
231                 .generic.in.file.handle = h
232         };
233         torture_comment(tctx, "Trying getinfo\n");
234         status = smb2_getinfo_file(tree, tmp_ctx, &qfinfo);
235         CHECK_STATUS(status, NT_STATUS_OK);
236         CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
237
238         ioctl = (union smb_ioctl) {
239                 .smb2.level = RAW_IOCTL_SMB2,
240                 .smb2.in.file.handle = h,
241                 .smb2.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID,
242                 .smb2.in.max_output_response = 64,
243                 .smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL
244         };
245         torture_comment(tctx, "Trying ioctl\n");
246         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
247         CHECK_STATUS(status, NT_STATUS_OK);
248
249         lck = (struct smb2_lock) {
250                 .in.locks = el,
251                 .in.lock_count = 0x0001,
252                 .in.lock_sequence = 0x00000000,
253                 .in.file.handle = h
254         };
255         el[0].reserved          = 0x00000000;
256         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE |
257                 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
258
259         torture_comment(tctx, "Trying lock\n");
260         el[0].offset            = 0x0000000000000000;
261         el[0].length            = 0x0000000000000100;
262         status = smb2_lock(tree, &lck);
263         CHECK_STATUS(status, NT_STATUS_OK);
264
265         lck.in.file.handle      = h;
266         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
267         status = smb2_lock(tree, &lck);
268         CHECK_STATUS(status, NT_STATUS_OK);
269
270         CHECK_VAL(break_info.count, 0);
271 done:
272         smb2cli_session_stop_replay(tree->session->smbXcli);
273         smb2_util_close(tree, h);
274         smb2_deltree(tree, BASEDIR);
275
276         talloc_free(tmp_ctx);
277
278         return ret;
279 }
280
281 /**
282  * Test replay detection without create GUID on single channel.
283  * Regular creates can not be replayed.
284  * The return code is unaffected of the REPLAY_OPERATION flag.
285  */
286 static bool test_replay_regular(struct torture_context *tctx,
287                                 struct smb2_tree *tree)
288 {
289         NTSTATUS status;
290         TALLOC_CTX *mem_ctx = talloc_new(tctx);
291         struct smb2_handle _h;
292         struct smb2_handle *h = NULL;
293         struct smb2_create io;
294         uint32_t perms = 0;
295         bool ret = true;
296         const char *fname = BASEDIR "\\replay_regular.dat";
297         struct smb2_transport *transport = tree->session->transport;
298
299         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
300                 torture_skip(tctx, "SMB 3.X Dialect family required for "
301                                    "replay tests\n");
302         }
303
304         ZERO_STRUCT(break_info);
305         break_info.tctx = tctx;
306         tree->session->transport->oplock.handler = torture_oplock_ack_handler;
307         tree->session->transport->oplock.private_data = tree;
308
309         smb2_util_unlink(tree, fname);
310         status = torture_smb2_testdir(tree, BASEDIR, &_h);
311         CHECK_STATUS(status, NT_STATUS_OK);
312         smb2_util_close(tree, _h);
313         CHECK_VAL(break_info.count, 0);
314
315         torture_comment(tctx, "No replay detection for regular create\n");
316
317         perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
318                 SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
319                 SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
320                 SEC_FILE_WRITE_DATA;
321
322         io = (struct smb2_create) {
323                 .in.desired_access  = perms,
324                 .in.file_attributes = 0,
325                 .in.create_disposition = NTCREATEX_DISP_CREATE,
326                 .in.share_access    = NTCREATEX_SHARE_ACCESS_DELETE,
327                 .in.create_options  = 0x0,
328                 .in.fname   = fname
329         };
330
331         status = smb2_create(tree, tctx, &io);
332         CHECK_STATUS(status, NT_STATUS_OK);
333         CHECK_VAL(break_info.count, 0);
334         _h = io.out.file.handle;
335         h = &_h;
336         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
337
338         smb2cli_session_start_replay(tree->session->smbXcli);
339         status = smb2_create(tree, tctx, &io);
340         smb2cli_session_stop_replay(tree->session->smbXcli);
341         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
342         CHECK_VAL(break_info.count, 0);
343
344         smb2_util_close(tree, *h);
345         h = NULL;
346         smb2_util_unlink(tree, fname);
347
348         /*
349          * Same experiment with different create disposition.
350          */
351         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
352         status = smb2_create(tree, tctx, &io);
353         CHECK_STATUS(status, NT_STATUS_OK);
354         CHECK_VAL(break_info.count, 0);
355         _h = io.out.file.handle;
356         h = &_h;
357         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
358
359         smb2cli_session_start_replay(tree->session->smbXcli);
360         status = smb2_create(tree, tctx, &io);
361         smb2cli_session_stop_replay(tree->session->smbXcli);
362         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
363         CHECK_VAL(break_info.count, 0);
364
365         smb2_util_close(tree, *h);
366         h = NULL;
367         smb2_util_unlink(tree, fname);
368
369         /*
370          * Now with more generous share mode.
371          */
372         io.in.share_access = smb2_util_share_access("RWD");
373         status = smb2_create(tree, tctx, &io);
374         CHECK_STATUS(status, NT_STATUS_OK);
375         CHECK_VAL(break_info.count, 0);
376         _h = io.out.file.handle;
377         h = &_h;
378         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
379
380         smb2cli_session_start_replay(tree->session->smbXcli);
381         status = smb2_create(tree, tctx, &io);
382         smb2cli_session_stop_replay(tree->session->smbXcli);
383         CHECK_STATUS(status, NT_STATUS_OK);
384         CHECK_VAL(break_info.count, 0);
385
386 done:
387         if (h != NULL) {
388                 smb2_util_close(tree, *h);
389         }
390         smb2_deltree(tree, BASEDIR);
391
392         talloc_free(tree);
393         talloc_free(mem_ctx);
394
395         return ret;
396 }
397
398 /**
399  * Test Durability V2 Create Replay Detection on Single Channel.
400  */
401 static bool test_replay_dhv2_oplock1(struct torture_context *tctx,
402                                      struct smb2_tree *tree)
403 {
404         NTSTATUS status;
405         TALLOC_CTX *mem_ctx = talloc_new(tctx);
406         struct smb2_handle _h;
407         struct smb2_handle *h = NULL;
408         struct smb2_create io, ref1;
409         struct GUID create_guid = GUID_random();
410         bool ret = true;
411         const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat";
412         struct smb2_transport *transport = tree->session->transport;
413         uint32_t share_capabilities;
414         bool share_is_so;
415
416         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
417                 torture_skip(tctx, "SMB 3.X Dialect family required for "
418                                    "replay tests\n");
419         }
420
421         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
422         share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
423
424         ZERO_STRUCT(break_info);
425         break_info.tctx = tctx;
426         tree->session->transport->oplock.handler = torture_oplock_ack_handler;
427         tree->session->transport->oplock.private_data = tree;
428
429         torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
430                               "Channel\n");
431         smb2_util_unlink(tree, fname);
432         status = torture_smb2_testdir(tree, BASEDIR, &_h);
433         CHECK_STATUS(status, NT_STATUS_OK);
434         smb2_util_close(tree, _h);
435         CHECK_VAL(break_info.count, 0);
436
437         smb2_oplock_create_share(&io, fname,
438                         smb2_util_share_access(""),
439                         smb2_util_oplock_level("b"));
440         io.in.durable_open = false;
441         io.in.durable_open_v2 = true;
442         io.in.persistent_open = false;
443         io.in.create_guid = create_guid;
444         io.in.timeout = UINT32_MAX;
445
446         status = smb2_create(tree, mem_ctx, &io);
447         CHECK_STATUS(status, NT_STATUS_OK);
448         ref1 = io;
449         _h = io.out.file.handle;
450         h = &_h;
451         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
452         CHECK_VAL(io.out.durable_open, false);
453         if (share_is_so) {
454                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
455                 CHECK_VAL(io.out.durable_open_v2, false);
456                 CHECK_VAL(io.out.timeout, 0);
457         } else {
458                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
459                 CHECK_VAL(io.out.durable_open_v2, true);
460                 CHECK_VAL(io.out.timeout, io.in.timeout);
461         }
462
463         /*
464          * Replay Durable V2 Create on single channel
465          */
466         smb2cli_session_start_replay(tree->session->smbXcli);
467         status = smb2_create(tree, mem_ctx, &io);
468         smb2cli_session_stop_replay(tree->session->smbXcli);
469         CHECK_STATUS(status, NT_STATUS_OK);
470         CHECK_CREATE_OUT(&io, &ref1);
471         CHECK_VAL(break_info.count, 0);
472
473 done:
474         if (h != NULL) {
475                 smb2_util_close(tree, *h);
476         }
477         smb2_deltree(tree, BASEDIR);
478
479         talloc_free(tree);
480         talloc_free(mem_ctx);
481
482         return ret;
483 }
484
485 /**
486  * Test Durability V2 Create Replay Detection on Single Channel.
487  * Hand in a different oplock level in the replay.
488  * Server responds with the handed in oplock level and
489  * corresponding durable status, but does not change the
490  * oplock level or durable status of the opened file.
491  */
492 static bool test_replay_dhv2_oplock2(struct torture_context *tctx,
493                                       struct smb2_tree *tree)
494 {
495         NTSTATUS status;
496         TALLOC_CTX *mem_ctx = talloc_new(tctx);
497         struct smb2_handle _h;
498         struct smb2_handle *h = NULL;
499         struct smb2_create io, ref1, ref2;
500         struct GUID create_guid = GUID_random();
501         bool ret = true;
502         const char *fname = BASEDIR "\\replay_dhv2_oplock2.dat";
503         struct smb2_transport *transport = tree->session->transport;
504         uint32_t share_capabilities;
505         bool share_is_so;
506
507         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
508                 torture_skip(tctx, "SMB 3.X Dialect family required for "
509                                    "replay tests\n");
510         }
511
512         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
513         share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
514
515         ZERO_STRUCT(break_info);
516         break_info.tctx = tctx;
517         tree->session->transport->oplock.handler = torture_oplock_ack_handler;
518         tree->session->transport->oplock.private_data = tree;
519
520         torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
521                               "Channel\n");
522         smb2_util_unlink(tree, fname);
523         status = torture_smb2_testdir(tree, BASEDIR, &_h);
524         CHECK_STATUS(status, NT_STATUS_OK);
525         smb2_util_close(tree, _h);
526         CHECK_VAL(break_info.count, 0);
527
528         smb2_oplock_create_share(&io, fname,
529                         smb2_util_share_access(""),
530                         smb2_util_oplock_level("b"));
531         io.in.durable_open = false;
532         io.in.durable_open_v2 = true;
533         io.in.persistent_open = false;
534         io.in.create_guid = create_guid;
535         io.in.timeout = UINT32_MAX;
536
537         status = smb2_create(tree, mem_ctx, &io);
538         CHECK_STATUS(status, NT_STATUS_OK);
539         ref1 = io;
540         _h = io.out.file.handle;
541         h = &_h;
542         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
543         CHECK_VAL(io.out.durable_open, false);
544         if (share_is_so) {
545                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
546                 CHECK_VAL(io.out.durable_open_v2, false);
547                 CHECK_VAL(io.out.timeout, 0);
548         } else {
549                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
550                 CHECK_VAL(io.out.durable_open_v2, true);
551                 CHECK_VAL(io.out.timeout, io.in.timeout);
552         }
553
554         /*
555          * Replay durable v2 create on single channel:
556          *
557          * Replay the create with a different oplock (none).
558          * The server replies with the requested oplock level
559          * and also only replies with durable handle based
560          * on whether it could have been granted based on
561          * the requested oplock type.
562          */
563         smb2_oplock_create_share(&io, fname,
564                         smb2_util_share_access(""),
565                         smb2_util_oplock_level(""));
566         io.in.durable_open = false;
567         io.in.durable_open_v2 = true;
568         io.in.persistent_open = false;
569         io.in.create_guid = create_guid;
570         io.in.timeout = UINT32_MAX;
571
572         /*
573          * Adapt the response to the exepected values
574          */
575         ref2 = ref1;
576         ref2.out.oplock_level = smb2_util_oplock_level("");
577         ref2.out.durable_open_v2 = false;
578         ref2.out.timeout = 0;
579         ref2.out.blobs.num_blobs = 0;
580
581         smb2cli_session_start_replay(tree->session->smbXcli);
582         status = smb2_create(tree, mem_ctx, &io);
583         smb2cli_session_stop_replay(tree->session->smbXcli);
584         CHECK_STATUS(status, NT_STATUS_OK);
585         CHECK_CREATE_OUT(&io, &ref2);
586         CHECK_VAL(break_info.count, 0);
587
588         /*
589          * Prove that the open file still has a batch oplock
590          * by breaking it with another open.
591          */
592         smb2_oplock_create_share(&io, fname,
593                         smb2_util_share_access(""),
594                         smb2_util_oplock_level("b"));
595         io.in.durable_open = false;
596         io.in.durable_open_v2 = true;
597         io.in.persistent_open = false;
598         io.in.create_guid = GUID_random();
599         io.in.timeout = UINT32_MAX;
600         status = smb2_create(tree, mem_ctx, &io);
601         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
602
603         if (!share_is_so) {
604                 CHECK_VAL(break_info.count, 1);
605                 CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle);
606                 CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
607                 ZERO_STRUCT(break_info);
608         }
609
610 done:
611         if (h != NULL) {
612                 smb2_util_close(tree, *h);
613         }
614         smb2_deltree(tree, BASEDIR);
615
616         talloc_free(tree);
617         talloc_free(mem_ctx);
618
619         return ret;
620 }
621
622 /**
623  * Test Durability V2 Create Replay Detection on Single Channel.
624  * Replay with a different share mode. The share mode of
625  * the opened file is not changed by this.
626  */
627 static bool test_replay_dhv2_oplock3(struct torture_context *tctx,
628                                      struct smb2_tree *tree)
629 {
630         NTSTATUS status;
631         TALLOC_CTX *mem_ctx = talloc_new(tctx);
632         struct smb2_handle _h;
633         struct smb2_handle *h = NULL;
634         struct smb2_create io, ref1;
635         struct GUID create_guid = GUID_random();
636         bool ret = true;
637         const char *fname = BASEDIR "\\replay_dhv2_oplock3.dat";
638         struct smb2_transport *transport = tree->session->transport;
639         uint32_t share_capabilities;
640         bool share_is_so;
641
642         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
643                 torture_skip(tctx, "SMB 3.X Dialect family required for "
644                                    "replay tests\n");
645         }
646
647         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
648         share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
649
650         ZERO_STRUCT(break_info);
651         break_info.tctx = tctx;
652         tree->session->transport->oplock.handler = torture_oplock_ack_handler;
653         tree->session->transport->oplock.private_data = tree;
654
655         torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
656                               "Channel\n");
657         smb2_util_unlink(tree, fname);
658         status = torture_smb2_testdir(tree, BASEDIR, &_h);
659         CHECK_STATUS(status, NT_STATUS_OK);
660         smb2_util_close(tree, _h);
661         CHECK_VAL(break_info.count, 0);
662
663         smb2_oplock_create_share(&io, fname,
664                         smb2_util_share_access(""),
665                         smb2_util_oplock_level("b"));
666         io.in.durable_open = false;
667         io.in.durable_open_v2 = true;
668         io.in.persistent_open = false;
669         io.in.create_guid = create_guid;
670         io.in.timeout = UINT32_MAX;
671
672         status = smb2_create(tree, mem_ctx, &io);
673         CHECK_STATUS(status, NT_STATUS_OK);
674         ref1 = io;
675         _h = io.out.file.handle;
676         h = &_h;
677         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
678         CHECK_VAL(io.out.durable_open, false);
679         if (share_is_so) {
680                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
681                 CHECK_VAL(io.out.durable_open_v2, false);
682                 CHECK_VAL(io.out.timeout, 0);
683         } else {
684                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
685                 CHECK_VAL(io.out.durable_open_v2, true);
686                 CHECK_VAL(io.out.timeout, io.in.timeout);
687         }
688
689         /*
690          * Replay durable v2 create on single channel:
691          *
692          * Replay the create with a different share mode.
693          * The server replies with the requested share
694          * mode instead of that which is associated to
695          * the handle.
696          */
697         smb2_oplock_create_share(&io, fname,
698                         smb2_util_share_access("RWD"),
699                         smb2_util_oplock_level("b"));
700         io.in.durable_open = false;
701         io.in.durable_open_v2 = true;
702         io.in.persistent_open = false;
703         io.in.create_guid = create_guid;
704         io.in.timeout = UINT32_MAX;
705
706         smb2cli_session_start_replay(tree->session->smbXcli);
707         status = smb2_create(tree, mem_ctx, &io);
708         smb2cli_session_stop_replay(tree->session->smbXcli);
709         CHECK_STATUS(status, NT_STATUS_OK);
710         CHECK_CREATE_OUT(&io, &ref1);
711         CHECK_VAL(break_info.count, 0);
712
713         /*
714          * In order to prove that the different share mode in the
715          * replayed create had no effect on the open file handle,
716          * show that a new create yields NT_STATUS_SHARING_VIOLATION.
717          */
718         smb2_oplock_create_share(&io, fname,
719                         smb2_util_share_access(""),
720                         smb2_util_oplock_level("b"));
721         io.in.durable_open = false;
722         io.in.durable_open_v2 = true;
723         io.in.persistent_open = false;
724         io.in.create_guid = GUID_random();
725         io.in.timeout = UINT32_MAX;
726         status = smb2_create(tree, mem_ctx, &io);
727         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
728
729         if (!share_is_so) {
730                 CHECK_VAL(break_info.count, 1);
731                 CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle);
732                 CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
733                 ZERO_STRUCT(break_info);
734         }
735
736 done:
737         if (h != NULL) {
738                 smb2_util_close(tree, *h);
739         }
740         smb2_deltree(tree, BASEDIR);
741
742         talloc_free(tree);
743         talloc_free(mem_ctx);
744
745         return ret;
746 }
747
748 /**
749  * Test Durability V2 Create Replay Detection on Single Channel.
750  * Create with an oplock, and replay with a lease.
751  */
752 static bool test_replay_dhv2_oplock_lease(struct torture_context *tctx,
753                                           struct smb2_tree *tree)
754 {
755         NTSTATUS status;
756         TALLOC_CTX *mem_ctx = talloc_new(tctx);
757         struct smb2_handle _h;
758         struct smb2_handle *h = NULL;
759         struct smb2_create io;
760         struct GUID create_guid = GUID_random();
761         bool ret = true;
762         const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat";
763         struct smb2_transport *transport = tree->session->transport;
764         uint32_t share_capabilities;
765         bool share_is_so;
766         uint32_t server_capabilities;
767         struct smb2_lease ls;
768         uint64_t lease_key;
769
770         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
771                 torture_skip(tctx, "SMB 3.X Dialect family required for "
772                                    "replay tests\n");
773         }
774
775         server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
776         if (!(server_capabilities & SMB2_CAP_LEASING)) {
777                 torture_skip(tctx, "leases are not supported");
778         }
779
780         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
781         share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
782
783         ZERO_STRUCT(break_info);
784         break_info.tctx = tctx;
785         tree->session->transport->oplock.handler = torture_oplock_ack_handler;
786         tree->session->transport->oplock.private_data = tree;
787
788         torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
789                               "Channel\n");
790         smb2_util_unlink(tree, fname);
791         status = torture_smb2_testdir(tree, BASEDIR, &_h);
792         CHECK_STATUS(status, NT_STATUS_OK);
793         smb2_util_close(tree, _h);
794         CHECK_VAL(break_info.count, 0);
795
796         smb2_oplock_create_share(&io, fname,
797                         smb2_util_share_access(""),
798                         smb2_util_oplock_level("b"));
799         io.in.durable_open = false;
800         io.in.durable_open_v2 = true;
801         io.in.persistent_open = false;
802         io.in.create_guid = create_guid;
803         io.in.timeout = UINT32_MAX;
804
805         status = smb2_create(tree, mem_ctx, &io);
806         CHECK_STATUS(status, NT_STATUS_OK);
807         _h = io.out.file.handle;
808         h = &_h;
809         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
810         CHECK_VAL(io.out.durable_open, false);
811         if (share_is_so) {
812                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
813                 CHECK_VAL(io.out.durable_open_v2, false);
814                 CHECK_VAL(io.out.timeout, 0);
815         } else {
816                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
817                 CHECK_VAL(io.out.durable_open_v2, true);
818                 CHECK_VAL(io.out.timeout, io.in.timeout);
819         }
820
821         /*
822          * Replay Durable V2 Create on single channel
823          * but replay it with a lease instead of an oplock.
824          */
825         lease_key = random();
826         smb2_lease_create(&io, &ls, false /* dir */, fname,
827                         lease_key, smb2_util_lease_state("RH"));
828         io.in.durable_open = false;
829         io.in.durable_open_v2 = true;
830         io.in.persistent_open = false;
831         io.in.create_guid = create_guid;
832         io.in.timeout = UINT32_MAX;
833
834         smb2cli_session_start_replay(tree->session->smbXcli);
835         status = smb2_create(tree, mem_ctx, &io);
836         smb2cli_session_stop_replay(tree->session->smbXcli);
837         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
838
839 done:
840         if (h != NULL) {
841                 smb2_util_close(tree, *h);
842         }
843         smb2_deltree(tree, BASEDIR);
844
845         talloc_free(tree);
846         talloc_free(mem_ctx);
847
848         return ret;
849 }
850
851
852 /**
853  * Test durability v2 create replay detection on single channel.
854  * Variant with leases instead of oplocks:
855  * - open a file with a rh lease
856  * - upgrade to a rwh lease with a second create
857  * - replay the first create.
858  *   ==> it gets back the upgraded lease level
859  */
860 static bool test_replay_dhv2_lease1(struct torture_context *tctx,
861                                     struct smb2_tree *tree)
862 {
863         NTSTATUS status;
864         TALLOC_CTX *mem_ctx = talloc_new(tctx);
865         struct smb2_handle _h1;
866         struct smb2_handle *h1 = NULL;
867         struct smb2_handle _h2;
868         struct smb2_handle *h2 = NULL;
869         struct smb2_create io1, io2, ref1;
870         struct GUID create_guid = GUID_random();
871         bool ret = true;
872         const char *fname = BASEDIR "\\replay2_lease1.dat";
873         struct smb2_transport *transport = tree->session->transport;
874         uint32_t share_capabilities;
875         bool share_is_so;
876         uint32_t server_capabilities;
877         struct smb2_lease ls1, ls2;
878         uint64_t lease_key;
879
880         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
881                 torture_skip(tctx, "SMB 3.X Dialect family required for "
882                                    "replay tests\n");
883         }
884
885         server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
886         if (!(server_capabilities & SMB2_CAP_LEASING)) {
887                 torture_skip(tctx, "leases are not supported");
888         }
889
890         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
891         share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
892
893         ZERO_STRUCT(break_info);
894         break_info.tctx = tctx;
895         tree->session->transport->oplock.handler = torture_oplock_ack_handler;
896         tree->session->transport->oplock.private_data = tree;
897
898         torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
899                               "on Single Channel\n");
900         smb2_util_unlink(tree, fname);
901         status = torture_smb2_testdir(tree, BASEDIR, &_h1);
902         CHECK_STATUS(status, NT_STATUS_OK);
903         smb2_util_close(tree, _h1);
904         CHECK_VAL(break_info.count, 0);
905
906         lease_key = random();
907
908         smb2_lease_create(&io1, &ls1, false /* dir */, fname,
909                         lease_key, smb2_util_lease_state("RH"));
910         io1.in.durable_open = false;
911         io1.in.durable_open_v2 = true;
912         io1.in.persistent_open = false;
913         io1.in.create_guid = create_guid;
914         io1.in.timeout = UINT32_MAX;
915
916         status = smb2_create(tree, mem_ctx, &io1);
917         CHECK_STATUS(status, NT_STATUS_OK);
918         ref1 = io1;
919         _h1 = io1.out.file.handle;
920         h1 = &_h1;
921         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
922         CHECK_VAL(io1.out.durable_open, false);
923         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
924         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
925         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
926         if (share_is_so) {
927                 CHECK_VAL(io1.out.lease_response.lease_state,
928                           smb2_util_lease_state("R"));
929                 CHECK_VAL(io1.out.durable_open_v2, false);
930                 CHECK_VAL(io1.out.timeout, 0);
931         } else {
932                 CHECK_VAL(io1.out.lease_response.lease_state,
933                           smb2_util_lease_state("RH"));
934                 CHECK_VAL(io1.out.durable_open_v2, true);
935                 CHECK_VAL(io1.out.timeout, io1.in.timeout);
936         }
937
938         /*
939          * Upgrade the lease to RWH
940          */
941         smb2_lease_create(&io2, &ls2, false /* dir */, fname,
942                         lease_key, smb2_util_lease_state("RHW"));
943         io2.in.durable_open = false;
944         io2.in.durable_open_v2 = true;
945         io2.in.persistent_open = false;
946         io2.in.create_guid = GUID_random(); /* new guid... */
947         io2.in.timeout = UINT32_MAX;
948
949         status = smb2_create(tree, mem_ctx, &io2);
950         CHECK_STATUS(status, NT_STATUS_OK);
951         _h2 = io2.out.file.handle;
952         h2 = &_h2;
953
954         /*
955          * Replay Durable V2 Create on single channel.
956          * We get the io from open #1 but with the
957          * upgraded lease.
958          */
959
960         /* adapt expected lease in response */
961         if (!share_is_so) {
962                 ref1.out.lease_response.lease_state =
963                         smb2_util_lease_state("RHW");
964         }
965
966         smb2cli_session_start_replay(tree->session->smbXcli);
967         status = smb2_create(tree, mem_ctx, &io1);
968         smb2cli_session_stop_replay(tree->session->smbXcli);
969         CHECK_STATUS(status, NT_STATUS_OK);
970         CHECK_CREATE_OUT(&io1, &ref1);
971         CHECK_VAL(break_info.count, 0);
972
973 done:
974         smb2cli_session_stop_replay(tree->session->smbXcli);
975
976         if (h1 != NULL) {
977                 smb2_util_close(tree, *h1);
978         }
979         if (h2 != NULL) {
980                 smb2_util_close(tree, *h2);
981         }
982         smb2_deltree(tree, BASEDIR);
983
984         talloc_free(tree);
985         talloc_free(mem_ctx);
986
987         return ret;
988 }
989
990 /**
991  * Test durability v2 create replay detection on single channel.
992  * Variant with leases instead of oplocks, where the
993  * replay does not specify the original lease level but
994  * just a "R" lease. This still gives the upgraded lease
995  * level in the reply.
996  * - open a file with a rh lease
997  * - upgrade to a rwh lease with a second create
998  * - replay the first create.
999  *   ==> it gets back the upgraded lease level
1000  */
1001 static bool test_replay_dhv2_lease2(struct torture_context *tctx,
1002                                     struct smb2_tree *tree)
1003 {
1004         NTSTATUS status;
1005         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1006         struct smb2_handle _h1;
1007         struct smb2_handle *h1 = NULL;
1008         struct smb2_handle _h2;
1009         struct smb2_handle *h2 = NULL;
1010         struct smb2_create io1, io2, ref1;
1011         struct GUID create_guid = GUID_random();
1012         bool ret = true;
1013         const char *fname = BASEDIR "\\replay2_lease2.dat";
1014         struct smb2_transport *transport = tree->session->transport;
1015         uint32_t share_capabilities;
1016         bool share_is_so;
1017         uint32_t server_capabilities;
1018         struct smb2_lease ls1, ls2;
1019         uint64_t lease_key;
1020
1021         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
1022                 torture_skip(tctx, "SMB 3.X Dialect family required for "
1023                                    "replay tests\n");
1024         }
1025
1026         server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
1027         if (!(server_capabilities & SMB2_CAP_LEASING)) {
1028                 torture_skip(tctx, "leases are not supported");
1029         }
1030
1031         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
1032         share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
1033
1034         ZERO_STRUCT(break_info);
1035         break_info.tctx = tctx;
1036         tree->session->transport->oplock.handler = torture_oplock_ack_handler;
1037         tree->session->transport->oplock.private_data = tree;
1038
1039         torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
1040                               "on Single Channel\n");
1041         smb2_util_unlink(tree, fname);
1042         status = torture_smb2_testdir(tree, BASEDIR, &_h1);
1043         CHECK_STATUS(status, NT_STATUS_OK);
1044         smb2_util_close(tree, _h1);
1045         CHECK_VAL(break_info.count, 0);
1046
1047         lease_key = random();
1048
1049         smb2_lease_create(&io1, &ls1, false /* dir */, fname,
1050                         lease_key, smb2_util_lease_state("RH"));
1051         io1.in.durable_open = false;
1052         io1.in.durable_open_v2 = true;
1053         io1.in.persistent_open = false;
1054         io1.in.create_guid = create_guid;
1055         io1.in.timeout = UINT32_MAX;
1056
1057         status = smb2_create(tree, mem_ctx, &io1);
1058         CHECK_STATUS(status, NT_STATUS_OK);
1059         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1060         CHECK_VAL(io1.out.durable_open, false);
1061         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1062         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
1063         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
1064         if (share_is_so) {
1065                 CHECK_VAL(io1.out.lease_response.lease_state,
1066                           smb2_util_lease_state("R"));
1067                 CHECK_VAL(io1.out.durable_open_v2, false);
1068                 CHECK_VAL(io1.out.timeout, 0);
1069         } else {
1070                 CHECK_VAL(io1.out.lease_response.lease_state,
1071                           smb2_util_lease_state("RH"));
1072                 CHECK_VAL(io1.out.durable_open_v2, true);
1073                 CHECK_VAL(io1.out.timeout, io1.in.timeout);
1074         }
1075         ref1 = io1;
1076         _h1 = io1.out.file.handle;
1077         h1 = &_h1;
1078
1079         /*
1080          * Upgrade the lease to RWH
1081          */
1082         smb2_lease_create(&io2, &ls2, false /* dir */, fname,
1083                         lease_key, smb2_util_lease_state("RHW"));
1084         io2.in.durable_open = false;
1085         io2.in.durable_open_v2 = true;
1086         io2.in.persistent_open = false;
1087         io2.in.create_guid = GUID_random(); /* new guid... */
1088         io2.in.timeout = UINT32_MAX;
1089
1090         status = smb2_create(tree, mem_ctx, &io2);
1091         CHECK_STATUS(status, NT_STATUS_OK);
1092         _h2 = io2.out.file.handle;
1093         h2 = &_h2;
1094
1095         /*
1096          * Replay Durable V2 Create on single channel.
1097          * Changing the requested lease level to "R"
1098          * does not change the response:
1099          * We get the reply from open #1 but with the
1100          * upgraded lease.
1101          */
1102
1103         /* adapt the expected response */
1104         if (!share_is_so) {
1105                 ref1.out.lease_response.lease_state =
1106                                         smb2_util_lease_state("RHW");
1107         }
1108
1109         smb2_lease_create(&io1, &ls1, false /* dir */, fname,
1110                         lease_key, smb2_util_lease_state("R"));
1111         io1.in.durable_open = false;
1112         io1.in.durable_open_v2 = true;
1113         io1.in.persistent_open = false;
1114         io1.in.create_guid = create_guid;
1115         io1.in.timeout = UINT32_MAX;
1116
1117         smb2cli_session_start_replay(tree->session->smbXcli);
1118         status = smb2_create(tree, mem_ctx, &io1);
1119         smb2cli_session_stop_replay(tree->session->smbXcli);
1120         CHECK_STATUS(status, NT_STATUS_OK);
1121         CHECK_CREATE_OUT(&io1, &ref1);
1122         CHECK_VAL(break_info.count, 0);
1123
1124 done:
1125         smb2cli_session_stop_replay(tree->session->smbXcli);
1126
1127         if (h1 != NULL) {
1128                 smb2_util_close(tree, *h1);
1129         }
1130         if (h2 != NULL) {
1131                 smb2_util_close(tree, *h2);
1132         }
1133         smb2_deltree(tree, BASEDIR);
1134
1135         talloc_free(tree);
1136         talloc_free(mem_ctx);
1137
1138         return ret;
1139 }
1140
1141 /**
1142  * Test durability v2 create replay detection on single channel.
1143  * create with a lease, and replay with a different lease key
1144  */
1145 static bool test_replay_dhv2_lease3(struct torture_context *tctx,
1146                                     struct smb2_tree *tree)
1147 {
1148         NTSTATUS status;
1149         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1150         struct smb2_handle _h1;
1151         struct smb2_handle *h1 = NULL;
1152         struct smb2_handle _h2;
1153         struct smb2_handle *h2 = NULL;
1154         struct smb2_create io1, io2;
1155         struct GUID create_guid = GUID_random();
1156         bool ret = true;
1157         const char *fname = BASEDIR "\\replay2_lease2.dat";
1158         struct smb2_transport *transport = tree->session->transport;
1159         uint32_t share_capabilities;
1160         bool share_is_so;
1161         uint32_t server_capabilities;
1162         struct smb2_lease ls1, ls2;
1163         uint64_t lease_key;
1164
1165         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
1166                 torture_skip(tctx, "SMB 3.X Dialect family required for "
1167                                    "replay tests\n");
1168         }
1169
1170         server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
1171         if (!(server_capabilities & SMB2_CAP_LEASING)) {
1172                 torture_skip(tctx, "leases are not supported");
1173         }
1174
1175         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
1176         share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
1177
1178         ZERO_STRUCT(break_info);
1179         break_info.tctx = tctx;
1180         tree->session->transport->oplock.handler = torture_oplock_ack_handler;
1181         tree->session->transport->oplock.private_data = tree;
1182
1183         torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
1184                               "on Single Channel\n");
1185         smb2_util_unlink(tree, fname);
1186         status = torture_smb2_testdir(tree, BASEDIR, &_h1);
1187         CHECK_STATUS(status, NT_STATUS_OK);
1188         smb2_util_close(tree, _h1);
1189         CHECK_VAL(break_info.count, 0);
1190
1191         lease_key = random();
1192
1193         smb2_lease_create(&io1, &ls1, false /* dir */, fname,
1194                         lease_key, smb2_util_lease_state("RH"));
1195         io1.in.durable_open = false;
1196         io1.in.durable_open_v2 = true;
1197         io1.in.persistent_open = false;
1198         io1.in.create_guid = create_guid;
1199         io1.in.timeout = UINT32_MAX;
1200
1201         status = smb2_create(tree, mem_ctx, &io1);
1202         CHECK_STATUS(status, NT_STATUS_OK);
1203         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1204         CHECK_VAL(io1.out.durable_open, false);
1205         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1206         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
1207         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
1208         if (share_is_so) {
1209                 CHECK_VAL(io1.out.lease_response.lease_state,
1210                           smb2_util_lease_state("R"));
1211                 CHECK_VAL(io1.out.durable_open_v2, false);
1212                 CHECK_VAL(io1.out.timeout, 0);
1213         } else {
1214                 CHECK_VAL(io1.out.lease_response.lease_state,
1215                           smb2_util_lease_state("RH"));
1216                 CHECK_VAL(io1.out.durable_open_v2, true);
1217                 CHECK_VAL(io1.out.timeout, io1.in.timeout);
1218         }
1219         _h1 = io1.out.file.handle;
1220         h1 = &_h1;
1221
1222         /*
1223          * Upgrade the lease to RWH
1224          */
1225         smb2_lease_create(&io2, &ls2, false /* dir */, fname,
1226                         lease_key, smb2_util_lease_state("RHW"));
1227         io2.in.durable_open = false;
1228         io2.in.durable_open_v2 = true;
1229         io2.in.persistent_open = false;
1230         io2.in.create_guid = GUID_random(); /* new guid... */
1231         io2.in.timeout = UINT32_MAX;
1232
1233         status = smb2_create(tree, mem_ctx, &io2);
1234         CHECK_STATUS(status, NT_STATUS_OK);
1235         _h2 = io2.out.file.handle;
1236         h2 = &_h2;
1237
1238         /*
1239          * Replay Durable V2 Create on single channel.
1240          * use a different lease key.
1241          */
1242
1243         smb2_lease_create(&io1, &ls1, false /* dir */, fname,
1244                         random() /* lease key */,
1245                         smb2_util_lease_state("RH"));
1246         io1.in.durable_open = false;
1247         io1.in.durable_open_v2 = true;
1248         io1.in.persistent_open = false;
1249         io1.in.create_guid = create_guid;
1250         io1.in.timeout = UINT32_MAX;
1251
1252         smb2cli_session_start_replay(tree->session->smbXcli);
1253         status = smb2_create(tree, mem_ctx, &io1);
1254         smb2cli_session_stop_replay(tree->session->smbXcli);
1255         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1256
1257 done:
1258         smb2cli_session_stop_replay(tree->session->smbXcli);
1259
1260         if (h1 != NULL) {
1261                 smb2_util_close(tree, *h1);
1262         }
1263         if (h2 != NULL) {
1264                 smb2_util_close(tree, *h2);
1265         }
1266         smb2_deltree(tree, BASEDIR);
1267
1268         talloc_free(tree);
1269         talloc_free(mem_ctx);
1270
1271         return ret;
1272 }
1273
1274 /**
1275  * Test durability v2 create replay detection on single channel.
1276  * Do the original create with a lease, and do the replay
1277  * with an oplock.
1278  */
1279 static bool test_replay_dhv2_lease_oplock(struct torture_context *tctx,
1280                                           struct smb2_tree *tree)
1281 {
1282         NTSTATUS status;
1283         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1284         struct smb2_handle _h1;
1285         struct smb2_handle *h1 = NULL;
1286         struct smb2_handle _h2;
1287         struct smb2_handle *h2 = NULL;
1288         struct smb2_create io1, io2, ref1;
1289         struct GUID create_guid = GUID_random();
1290         bool ret = true;
1291         const char *fname = BASEDIR "\\replay2_lease1.dat";
1292         struct smb2_transport *transport = tree->session->transport;
1293         uint32_t share_capabilities;
1294         bool share_is_so;
1295         uint32_t server_capabilities;
1296         struct smb2_lease ls1, ls2;
1297         uint64_t lease_key;
1298
1299         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
1300                 torture_skip(tctx, "SMB 3.X Dialect family required for "
1301                                    "replay tests\n");
1302         }
1303
1304         server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
1305         if (!(server_capabilities & SMB2_CAP_LEASING)) {
1306                 torture_skip(tctx, "leases are not supported");
1307         }
1308
1309         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
1310         share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
1311
1312         ZERO_STRUCT(break_info);
1313         break_info.tctx = tctx;
1314         tree->session->transport->oplock.handler = torture_oplock_ack_handler;
1315         tree->session->transport->oplock.private_data = tree;
1316
1317         torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
1318                               "on Single Channel\n");
1319         smb2_util_unlink(tree, fname);
1320         status = torture_smb2_testdir(tree, BASEDIR, &_h1);
1321         CHECK_STATUS(status, NT_STATUS_OK);
1322         smb2_util_close(tree, _h1);
1323         CHECK_VAL(break_info.count, 0);
1324
1325         lease_key = random();
1326
1327         smb2_lease_create(&io1, &ls1, false /* dir */, fname,
1328                         lease_key, smb2_util_lease_state("RH"));
1329         io1.in.durable_open = false;
1330         io1.in.durable_open_v2 = true;
1331         io1.in.persistent_open = false;
1332         io1.in.create_guid = create_guid;
1333         io1.in.timeout = UINT32_MAX;
1334
1335         status = smb2_create(tree, mem_ctx, &io1);
1336         CHECK_STATUS(status, NT_STATUS_OK);
1337         ref1 = io1;
1338         _h1 = io1.out.file.handle;
1339         h1 = &_h1;
1340         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1341         CHECK_VAL(io1.out.durable_open, false);
1342         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1343         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
1344         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
1345         if (share_is_so) {
1346                 CHECK_VAL(io1.out.lease_response.lease_state,
1347                           smb2_util_lease_state("R"));
1348                 CHECK_VAL(io1.out.durable_open_v2, false);
1349                 CHECK_VAL(io1.out.timeout, 0);
1350         } else {
1351                 CHECK_VAL(io1.out.lease_response.lease_state,
1352                           smb2_util_lease_state("RH"));
1353                 CHECK_VAL(io1.out.durable_open_v2, true);
1354                 CHECK_VAL(io1.out.timeout, io1.in.timeout);
1355         }
1356
1357         /*
1358          * Upgrade the lease to RWH
1359          */
1360         smb2_lease_create(&io2, &ls2, false /* dir */, fname,
1361                         lease_key, smb2_util_lease_state("RHW"));
1362         io2.in.durable_open = false;
1363         io2.in.durable_open_v2 = true;
1364         io2.in.persistent_open = false;
1365         io2.in.create_guid = GUID_random(); /* new guid... */
1366         io2.in.timeout = UINT32_MAX;
1367
1368         status = smb2_create(tree, mem_ctx, &io2);
1369         CHECK_STATUS(status, NT_STATUS_OK);
1370         _h2 = io2.out.file.handle;
1371         h2 = &_h2;
1372
1373         /*
1374          * Replay Durable V2 Create on single channel.
1375          * We get the io from open #1 but with the
1376          * upgraded lease.
1377          */
1378
1379         smb2_oplock_create_share(&io2, fname,
1380                         smb2_util_share_access(""),
1381                         smb2_util_oplock_level("b"));
1382         io2.in.durable_open = false;
1383         io2.in.durable_open_v2 = true;
1384         io2.in.persistent_open = false;
1385         io2.in.create_guid = create_guid;
1386         io2.in.timeout = UINT32_MAX;
1387
1388         /* adapt expected lease in response */
1389         if (!share_is_so) {
1390                 ref1.out.lease_response.lease_state =
1391                         smb2_util_lease_state("RHW");
1392         }
1393
1394         smb2cli_session_start_replay(tree->session->smbXcli);
1395         status = smb2_create(tree, mem_ctx, &io1);
1396         smb2cli_session_stop_replay(tree->session->smbXcli);
1397         CHECK_STATUS(status, NT_STATUS_OK);
1398         CHECK_CREATE_OUT(&io1, &ref1);
1399         CHECK_VAL(break_info.count, 0);
1400
1401 done:
1402         smb2cli_session_stop_replay(tree->session->smbXcli);
1403
1404         if (h1 != NULL) {
1405                 smb2_util_close(tree, *h1);
1406         }
1407         if (h2 != NULL) {
1408                 smb2_util_close(tree, *h2);
1409         }
1410         smb2_deltree(tree, BASEDIR);
1411
1412         talloc_free(tree);
1413         talloc_free(mem_ctx);
1414
1415         return ret;
1416 }
1417
1418 static bool test_channel_sequence_table(struct torture_context *tctx,
1419                                         struct smb2_tree *tree,
1420                                         bool do_replay,
1421                                         uint16_t opcode)
1422 {
1423         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1424         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1425         struct smb2_handle handle;
1426         struct smb2_handle *phandle = NULL;
1427         struct smb2_create io;
1428         struct GUID create_guid = GUID_random();
1429         bool ret = true;
1430         const char *fname = BASEDIR "\\channel_sequence.dat";
1431         uint16_t csn = 0;
1432         uint16_t limit = UINT16_MAX - 0x7fff;
1433         int i;
1434         struct {
1435                 uint16_t csn;
1436                 bool csn_rand_low;
1437                 bool csn_rand_high;
1438                 NTSTATUS expected_status;
1439         } tests[] = {
1440                 {
1441                         .csn                    = 0,
1442                         .expected_status        = NT_STATUS_OK,
1443                 },{
1444                         .csn                    = 0x7fff + 1,
1445                         .expected_status        = NT_STATUS_FILE_NOT_AVAILABLE,
1446                 },{
1447                         .csn                    = 0x7fff + 2,
1448                         .expected_status        = NT_STATUS_FILE_NOT_AVAILABLE,
1449                 },{
1450                         .csn                    = -1,
1451                         .csn_rand_high          = true,
1452                         .expected_status        = NT_STATUS_FILE_NOT_AVAILABLE,
1453                 },{
1454                         .csn                    = 0xffff,
1455                         .expected_status        = NT_STATUS_FILE_NOT_AVAILABLE,
1456                 },{
1457                         .csn                    = 0x7fff,
1458                         .expected_status        = NT_STATUS_OK,
1459                 },{
1460                         .csn                    = 0x7ffe,
1461                         .expected_status        = NT_STATUS_FILE_NOT_AVAILABLE,
1462                 },{
1463                         .csn                    = 0,
1464                         .expected_status        = NT_STATUS_FILE_NOT_AVAILABLE,
1465                 },{
1466                         .csn                    = -1,
1467                         .csn_rand_low           = true,
1468                         .expected_status        = NT_STATUS_FILE_NOT_AVAILABLE,
1469                 },{
1470                         .csn                    = 0x7fff + 1,
1471                         .expected_status        = NT_STATUS_OK,
1472                 },{
1473                         .csn                    = 0xffff,
1474                         .expected_status        = NT_STATUS_OK,
1475                 },{
1476                         .csn                    = 0,
1477                         .expected_status        = NT_STATUS_OK,
1478                 },{
1479                         .csn                    = 1,
1480                         .expected_status        = NT_STATUS_OK,
1481                 },{
1482                         .csn                    = 0,
1483                         .expected_status        = NT_STATUS_FILE_NOT_AVAILABLE,
1484                 },{
1485                         .csn                    = 1,
1486                         .expected_status        = NT_STATUS_OK,
1487                 },{
1488                         .csn                    = 0xffff,
1489                         .expected_status        = NT_STATUS_FILE_NOT_AVAILABLE,
1490                 }
1491         };
1492
1493         smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);
1494
1495         csn = smb2cli_session_current_channel_sequence(tree->session->smbXcli);
1496         torture_comment(tctx, "Testing create with channel sequence number: 0x%04x\n", csn);
1497
1498         smb2_oplock_create_share(&io, fname,
1499                         smb2_util_share_access("RWD"),
1500                         smb2_util_oplock_level("b"));
1501         io.in.durable_open = false;
1502         io.in.durable_open_v2 = true;
1503         io.in.create_guid = create_guid;
1504         io.in.timeout = UINT32_MAX;
1505
1506         torture_assert_ntstatus_ok_goto(tctx,
1507                 smb2_create(tree, mem_ctx, &io),
1508                 ret, done, "failed to call smb2_create");
1509
1510         handle = io.out.file.handle;
1511         phandle = &handle;
1512
1513         for (i=0; i <ARRAY_SIZE(tests); i++) {
1514
1515                 const char *opstr = "";
1516                 union smb_fileinfo qfinfo;
1517
1518                 csn = tests[i].csn;
1519
1520                 if (tests[i].csn_rand_low) {
1521                         csn = rand() % limit;
1522                 } else if (tests[i].csn_rand_high) {
1523                         csn = rand() % limit + 0x7fff;
1524                 }
1525
1526                 switch (opcode) {
1527                 case SMB2_OP_WRITE:
1528                         opstr = "write";
1529                         break;
1530                 case SMB2_OP_IOCTL:
1531                         opstr = "ioctl";
1532                         break;
1533                 case SMB2_OP_SETINFO:
1534                         opstr = "setinfo";
1535                         break;
1536                 default:
1537                         break;
1538                 }
1539
1540                 smb2cli_session_reset_channel_sequence(tree->session->smbXcli, csn);
1541                 csn = smb2cli_session_current_channel_sequence(tree->session->smbXcli);
1542
1543                 torture_comment(tctx, "Testing %s (replay: %s) with CSN 0x%04x, expecting: %s\n",
1544                         opstr, do_replay ? "true" : "false", csn,
1545                         nt_errstr(tests[i].expected_status));
1546
1547                 if (do_replay) {
1548                         smb2cli_session_start_replay(tree->session->smbXcli);
1549                 }
1550
1551                 switch (opcode) {
1552                 case SMB2_OP_WRITE: {
1553                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, 255);
1554
1555                         generate_random_buffer(blob.data, blob.length);
1556
1557                         status = smb2_util_write(tree, handle, blob.data, 0, blob.length);
1558                         if (NT_STATUS_IS_OK(status)) {
1559                                 struct smb2_read rd;
1560
1561                                 rd = (struct smb2_read) {
1562                                         .in.file.handle = handle,
1563                                         .in.length = blob.length,
1564                                         .in.offset = 0
1565                                 };
1566
1567                                 torture_assert_ntstatus_ok_goto(tctx,
1568                                         smb2_read(tree, tree, &rd),
1569                                         ret, done, "failed to read after write");
1570
1571                                 torture_assert_data_blob_equal(tctx,
1572                                         rd.out.data, blob,
1573                                         "read/write mismatch");
1574                         }
1575                         break;
1576                 }
1577                 case SMB2_OP_IOCTL: {
1578                         union smb_ioctl ioctl;
1579                         ioctl = (union smb_ioctl) {
1580                                 .smb2.level = RAW_IOCTL_SMB2,
1581                                 .smb2.in.file.handle = handle,
1582                                 .smb2.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID,
1583                                 .smb2.in.max_output_response = 64,
1584                                 .smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL
1585                         };
1586                         status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
1587                         break;
1588                 }
1589                 case SMB2_OP_SETINFO: {
1590                         union smb_setfileinfo sfinfo;
1591                         ZERO_STRUCT(sfinfo);
1592                         sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
1593                         sfinfo.generic.in.file.handle = handle;
1594                         sfinfo.position_information.in.position = 0x1000;
1595                         status = smb2_setinfo_file(tree, &sfinfo);
1596                         break;
1597                 }
1598                 default:
1599                         break;
1600                 }
1601
1602                 qfinfo = (union smb_fileinfo) {
1603                         .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
1604                         .generic.in.file.handle = handle
1605                 };
1606
1607                 torture_assert_ntstatus_ok_goto(tctx,
1608                         smb2_getinfo_file(tree, mem_ctx, &qfinfo),
1609                         ret, done, "failed to read after write");
1610
1611                 if (do_replay) {
1612                         smb2cli_session_stop_replay(tree->session->smbXcli);
1613                 }
1614
1615                 torture_assert_ntstatus_equal_goto(tctx,
1616                         status, tests[i].expected_status,
1617                         ret, done, "got unexpected failure code");
1618
1619         }
1620 done:
1621         if (phandle != NULL) {
1622                 smb2_util_close(tree, *phandle);
1623         }
1624
1625         smb2_util_unlink(tree, fname);
1626
1627         return ret;
1628 }
1629
1630 static bool test_channel_sequence(struct torture_context *tctx,
1631                                   struct smb2_tree *tree)
1632 {
1633         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1634         bool ret = true;
1635         const char *fname = BASEDIR "\\channel_sequence.dat";
1636         struct smb2_transport *transport1 = tree->session->transport;
1637         struct smb2_handle handle;
1638         uint32_t server_capabilities;
1639         uint16_t opcodes[] = { SMB2_OP_WRITE, SMB2_OP_IOCTL, SMB2_OP_SETINFO };
1640         int i;
1641
1642         if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
1643                 torture_skip(tctx, "SMB 3.X Dialect family required for "
1644                                    "Replay tests\n");
1645         }
1646
1647         server_capabilities = smb2cli_conn_server_capabilities(
1648                                         tree->session->transport->conn);
1649         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
1650                 torture_skip(tctx,
1651                              "Server does not support multi-channel.");
1652         }
1653
1654         torture_comment(tctx, "Testing channel sequence numbers\n");
1655
1656         torture_assert_ntstatus_ok_goto(tctx,
1657                 torture_smb2_testdir(tree, BASEDIR, &handle),
1658                 ret, done, "failed to setup test directory");
1659
1660         smb2_util_close(tree, handle);
1661         smb2_util_unlink(tree, fname);
1662
1663         for (i=0; i <ARRAY_SIZE(opcodes); i++) {
1664                 torture_assert(tctx,
1665                         test_channel_sequence_table(tctx, tree, false, opcodes[i]),
1666                         "failed to test CSN without replay flag");
1667                 torture_assert(tctx,
1668                         test_channel_sequence_table(tctx, tree, true, opcodes[i]),
1669                         "failed to test CSN with replay flag");
1670         }
1671
1672 done:
1673
1674         smb2_util_unlink(tree, fname);
1675         smb2_deltree(tree, BASEDIR);
1676
1677         talloc_free(tree);
1678         talloc_free(mem_ctx);
1679
1680         return ret;
1681 }
1682
1683 /**
1684  * Test Durability V2 Create Replay Detection on Multi Channel
1685  */
1686 static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1)
1687 {
1688         const char *host = torture_setting_string(tctx, "host", NULL);
1689         const char *share = torture_setting_string(tctx, "share", NULL);
1690         NTSTATUS status;
1691         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1692         struct smb2_handle _h;
1693         struct smb2_handle *h = NULL;
1694         struct smb2_create io;
1695         struct GUID create_guid = GUID_random();
1696         bool ret = true;
1697         const char *fname = BASEDIR "\\replay3.dat";
1698         struct smb2_tree *tree2 = NULL;
1699         struct smb2_transport *transport1 = tree1->session->transport;
1700         struct smb2_transport *transport2 = NULL;
1701         struct smb2_session *session1_1 = tree1->session;
1702         struct smb2_session *session1_2 = NULL;
1703         uint32_t share_capabilities;
1704         bool share_is_so;
1705         uint32_t server_capabilities;
1706
1707         if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
1708                 torture_skip(tctx, "SMB 3.X Dialect family required for "
1709                                    "Replay tests\n");
1710         }
1711
1712         server_capabilities = smb2cli_conn_server_capabilities(
1713                                         tree1->session->transport->conn);
1714         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
1715                 torture_skip(tctx,
1716                              "Server does not support multi-channel.");
1717         }
1718
1719         share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
1720         share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
1721
1722         ZERO_STRUCT(break_info);
1723         break_info.tctx = tctx;
1724         transport1->oplock.handler = torture_oplock_ack_handler;
1725         transport1->oplock.private_data = tree1;
1726
1727         torture_comment(tctx, "Replay of DurableHandleReqV2 on Multi "
1728                               "Channel\n");
1729         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
1730         CHECK_STATUS(status, NT_STATUS_OK);
1731         smb2_util_close(tree1, _h);
1732         smb2_util_unlink(tree1, fname);
1733         CHECK_VAL(break_info.count, 0);
1734
1735         /*
1736          * use the 1st channel, 1st session
1737          */
1738         smb2_oplock_create_share(&io, fname,
1739                         smb2_util_share_access(""),
1740                         smb2_util_oplock_level("b"));
1741         io.in.durable_open = false;
1742         io.in.durable_open_v2 = true;
1743         io.in.persistent_open = false;
1744         io.in.create_guid = create_guid;
1745         io.in.timeout = UINT32_MAX;
1746
1747         tree1->session = session1_1;
1748         status = smb2_create(tree1, mem_ctx, &io);
1749         CHECK_STATUS(status, NT_STATUS_OK);
1750         _h = io.out.file.handle;
1751         h = &_h;
1752         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1753         if (share_is_so) {
1754                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
1755                 CHECK_VAL(io.out.durable_open_v2, false);
1756                 CHECK_VAL(io.out.timeout, 0);
1757         } else {
1758                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
1759                 CHECK_VAL(io.out.durable_open_v2, true);
1760                 CHECK_VAL(io.out.timeout, io.in.timeout);
1761         }
1762         CHECK_VAL(io.out.durable_open, false);
1763         CHECK_VAL(break_info.count, 0);
1764
1765         status = smb2_connect(tctx,
1766                         host,
1767                         lpcfg_smb_ports(tctx->lp_ctx),
1768                         share,
1769                         lpcfg_resolve_context(tctx->lp_ctx),
1770                         popt_get_cmdline_credentials(),
1771                         &tree2,
1772                         tctx->ev,
1773                         &transport1->options,
1774                         lpcfg_socket_options(tctx->lp_ctx),
1775                         lpcfg_gensec_settings(tctx, tctx->lp_ctx)
1776                         );
1777         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1778                         "smb2_connect failed");
1779         transport2 = tree2->session->transport;
1780
1781         transport2->oplock.handler = torture_oplock_ack_handler;
1782         transport2->oplock.private_data = tree2;
1783
1784         /*
1785          * Now bind the 1st session to 2nd transport channel
1786          */
1787         session1_2 = smb2_session_channel(transport2,
1788                         lpcfg_gensec_settings(tctx, tctx->lp_ctx),
1789                         tree2, session1_1);
1790         torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
1791
1792         status = smb2_session_setup_spnego(session1_2,
1793                         popt_get_cmdline_credentials(),
1794                         0 /* previous_session_id */);
1795         CHECK_STATUS(status, NT_STATUS_OK);
1796
1797         /*
1798          * use the 2nd channel, 1st session
1799          */
1800         tree1->session = session1_2;
1801         smb2cli_session_start_replay(tree1->session->smbXcli);
1802         status = smb2_create(tree1, mem_ctx, &io);
1803         smb2cli_session_stop_replay(tree1->session->smbXcli);
1804         CHECK_STATUS(status, NT_STATUS_OK);
1805         _h = io.out.file.handle;
1806         h = &_h;
1807         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1808         if (share_is_so) {
1809                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
1810                 CHECK_VAL(io.out.durable_open_v2, false);
1811                 CHECK_VAL(io.out.timeout, 0);
1812         } else {
1813                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
1814                 CHECK_VAL(io.out.durable_open_v2, true);
1815                 CHECK_VAL(io.out.timeout, io.in.timeout);
1816         }
1817         CHECK_VAL(io.out.durable_open, false);
1818         CHECK_VAL(break_info.count, 0);
1819
1820         tree1->session = session1_1;
1821         smb2_util_close(tree1, *h);
1822         h = NULL;
1823
1824 done:
1825         talloc_free(tree2);
1826         tree1->session = session1_1;
1827
1828         if (h != NULL) {
1829                 smb2_util_close(tree1, *h);
1830         }
1831
1832         smb2_util_unlink(tree1, fname);
1833         smb2_deltree(tree1, BASEDIR);
1834
1835         talloc_free(tree1);
1836         talloc_free(mem_ctx);
1837
1838         return ret;
1839 }
1840
1841 /**
1842  * Test Multichannel IO Ordering using ChannelSequence/Channel Epoch number
1843  */
1844 static bool test_replay4(struct torture_context *tctx, struct smb2_tree *tree1)
1845 {
1846         const char *host = torture_setting_string(tctx, "host", NULL);
1847         const char *share = torture_setting_string(tctx, "share", NULL);
1848         NTSTATUS status;
1849         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1850         struct smb2_handle _h1;
1851         struct smb2_handle *h1 = NULL;
1852         struct smb2_create io;
1853         struct GUID create_guid = GUID_random();
1854         uint8_t buf[64];
1855         struct smb2_read rd;
1856         union smb_setfileinfo sfinfo;
1857         bool ret = true;
1858         const char *fname = BASEDIR "\\replay4.dat";
1859         struct smb2_tree *tree2 = NULL;
1860         struct smb2_transport *transport1 = tree1->session->transport;
1861         struct smb2_transport *transport2 = NULL;
1862         struct smb2_session *session1_1 = tree1->session;
1863         struct smb2_session *session1_2 = NULL;
1864         uint16_t curr_cs;
1865         uint32_t share_capabilities;
1866         bool share_is_so;
1867         uint32_t server_capabilities;
1868
1869         if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
1870                 torture_skip(tctx, "SMB 3.X Dialect family required for "
1871                                    "Replay tests\n");
1872         }
1873
1874         server_capabilities = smb2cli_conn_server_capabilities(
1875                                         tree1->session->transport->conn);
1876         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
1877                 torture_skip(tctx,
1878                              "Server does not support multi-channel.");
1879         }
1880
1881         share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
1882         share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
1883
1884         ZERO_STRUCT(break_info);
1885         break_info.tctx = tctx;
1886         transport1->oplock.handler = torture_oplock_ack_handler;
1887         transport1->oplock.private_data = tree1;
1888
1889         torture_comment(tctx, "IO Ordering for Multi Channel\n");
1890         status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
1891         CHECK_STATUS(status, NT_STATUS_OK);
1892         smb2_util_close(tree1, _h1);
1893         smb2_util_unlink(tree1, fname);
1894         CHECK_VAL(break_info.count, 0);
1895
1896         /*
1897          * use the 1st channel, 1st session
1898          */
1899
1900         smb2_oplock_create_share(&io, fname,
1901                         smb2_util_share_access(""),
1902                         smb2_util_oplock_level("b"));
1903         io.in.durable_open = false;
1904         io.in.durable_open_v2 = true;
1905         io.in.persistent_open = false;
1906         io.in.create_guid = create_guid;
1907         io.in.timeout = UINT32_MAX;
1908
1909         tree1->session = session1_1;
1910         status = smb2_create(tree1, mem_ctx, &io);
1911         CHECK_STATUS(status, NT_STATUS_OK);
1912         _h1 = io.out.file.handle;
1913         h1 = &_h1;
1914         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1915         if (share_is_so) {
1916                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
1917                 CHECK_VAL(io.out.durable_open_v2, false);
1918                 CHECK_VAL(io.out.timeout, 0);
1919         } else {
1920                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
1921                 CHECK_VAL(io.out.durable_open_v2, true);
1922                 CHECK_VAL(io.out.timeout, io.in.timeout);
1923         }
1924         CHECK_VAL(io.out.durable_open, false);
1925         CHECK_VAL(break_info.count, 0);
1926
1927         status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
1928         CHECK_STATUS(status, NT_STATUS_OK);
1929
1930         /*
1931          * Increment ChannelSequence so that server thinks that there's a
1932          * Channel Failure
1933          */
1934         smb2cli_session_increment_channel_sequence(tree1->session->smbXcli);
1935
1936         /*
1937          * Perform a Read with incremented ChannelSequence
1938          */
1939         rd = (struct smb2_read) {
1940                 .in.file.handle = *h1,
1941                 .in.length = sizeof(buf),
1942                 .in.offset = 0
1943         };
1944         status = smb2_read(tree1, tree1, &rd);
1945         CHECK_STATUS(status, NT_STATUS_OK);
1946
1947         /*
1948          * Performing a Write with Stale ChannelSequence is not allowed by
1949          * server
1950          */
1951         curr_cs = smb2cli_session_reset_channel_sequence(
1952                                                 tree1->session->smbXcli, 0);
1953         status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
1954         CHECK_STATUS(status, NT_STATUS_FILE_NOT_AVAILABLE);
1955
1956         /*
1957          * Performing a Write Replay with Stale ChannelSequence is not allowed
1958          * by server
1959          */
1960         smb2cli_session_start_replay(tree1->session->smbXcli);
1961         smb2cli_session_reset_channel_sequence(tree1->session->smbXcli, 0);
1962         status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
1963         smb2cli_session_stop_replay(tree1->session->smbXcli);
1964         CHECK_STATUS(status, NT_STATUS_FILE_NOT_AVAILABLE);
1965
1966         /*
1967          * Performing a SetInfo with stale ChannelSequence is not allowed by
1968          * server
1969          */
1970         ZERO_STRUCT(sfinfo);
1971         sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
1972         sfinfo.generic.in.file.handle = *h1;
1973         sfinfo.position_information.in.position = 0x1000;
1974         status = smb2_setinfo_file(tree1, &sfinfo);
1975         CHECK_STATUS(status, NT_STATUS_FILE_NOT_AVAILABLE);
1976
1977         /*
1978          * Performing a Read with stale ChannelSequence is allowed
1979          */
1980         rd = (struct smb2_read) {
1981                 .in.file.handle = *h1,
1982                 .in.length = ARRAY_SIZE(buf),
1983                 .in.offset = 0
1984         };
1985         status = smb2_read(tree1, tree1, &rd);
1986         CHECK_STATUS(status, NT_STATUS_OK);
1987
1988         status = smb2_connect(tctx,
1989                         host,
1990                         lpcfg_smb_ports(tctx->lp_ctx),
1991                         share,
1992                         lpcfg_resolve_context(tctx->lp_ctx),
1993                         popt_get_cmdline_credentials(),
1994                         &tree2,
1995                         tctx->ev,
1996                         &transport1->options,
1997                         lpcfg_socket_options(tctx->lp_ctx),
1998                         lpcfg_gensec_settings(tctx, tctx->lp_ctx)
1999                         );
2000         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2001                         "smb2_connect failed");
2002         transport2 = tree2->session->transport;
2003
2004         transport2->oplock.handler = torture_oplock_ack_handler;
2005         transport2->oplock.private_data = tree2;
2006
2007         /*
2008          * Now bind the 1st session to 2nd transport channel
2009          */
2010         session1_2 = smb2_session_channel(transport2,
2011                         lpcfg_gensec_settings(tctx, tctx->lp_ctx),
2012                         tree2, session1_1);
2013         torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
2014
2015         status = smb2_session_setup_spnego(session1_2,
2016                         popt_get_cmdline_credentials(),
2017                         0 /* previous_session_id */);
2018         CHECK_STATUS(status, NT_STATUS_OK);
2019
2020         /*
2021          * use the 2nd channel, 1st session
2022          */
2023         tree1->session = session1_2;
2024
2025         /*
2026          * Write Replay with Correct ChannelSequence is allowed by the server
2027          */
2028         smb2cli_session_start_replay(tree1->session->smbXcli);
2029         smb2cli_session_reset_channel_sequence(tree1->session->smbXcli,
2030                                                curr_cs);
2031         status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
2032         CHECK_STATUS(status, NT_STATUS_OK);
2033         smb2cli_session_stop_replay(tree1->session->smbXcli);
2034
2035         /*
2036          * See what happens if we change the Buffer and perform a Write Replay.
2037          * This is to show that Write Replay does not really care about the data
2038          */
2039         memset(buf, 'r', ARRAY_SIZE(buf));
2040         smb2cli_session_start_replay(tree1->session->smbXcli);
2041         status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
2042         CHECK_STATUS(status, NT_STATUS_OK);
2043         smb2cli_session_stop_replay(tree1->session->smbXcli);
2044
2045         /*
2046          * Read back from File to verify what was written
2047          */
2048         rd = (struct smb2_read) {
2049                 .in.file.handle = *h1,
2050                 .in.length = ARRAY_SIZE(buf),
2051                 .in.offset = 0
2052         };
2053         status = smb2_read(tree1, tree1, &rd);
2054         CHECK_STATUS(status, NT_STATUS_OK);
2055
2056         if ((rd.out.data.length != ARRAY_SIZE(buf)) ||
2057                         memcmp(rd.out.data.data, buf, ARRAY_SIZE(buf))) {
2058                 torture_comment(tctx, "Write Replay Data Mismatch\n");
2059         }
2060
2061         tree1->session = session1_1;
2062         smb2_util_close(tree1, *h1);
2063         h1 = NULL;
2064
2065         if (share_is_so) {
2066                 CHECK_VAL(break_info.count, 1);
2067         } else {
2068                 CHECK_VAL(break_info.count, 0);
2069         }
2070 done:
2071         talloc_free(tree2);
2072         tree1->session = session1_1;
2073
2074         if (h1 != NULL) {
2075                 smb2_util_close(tree1, *h1);
2076         }
2077
2078         smb2_util_unlink(tree1, fname);
2079         smb2_deltree(tree1, BASEDIR);
2080
2081         talloc_free(tree1);
2082         talloc_free(mem_ctx);
2083
2084         return ret;
2085 }
2086
2087 /**
2088  * Test Durability V2 Persistent Create Replay on a Single Channel
2089  */
2090 static bool test_replay5(struct torture_context *tctx, struct smb2_tree *tree)
2091 {
2092         NTSTATUS status;
2093         TALLOC_CTX *mem_ctx = talloc_new(tctx);
2094         struct smb2_handle _h;
2095         struct smb2_handle *h = NULL;
2096         struct smb2_create io;
2097         struct GUID create_guid = GUID_random();
2098         bool ret = true;
2099         uint32_t share_capabilities;
2100         bool share_is_ca;
2101         bool share_is_so;
2102         uint32_t server_capabilities;
2103         const char *fname = BASEDIR "\\replay5.dat";
2104         struct smb2_transport *transport = tree->session->transport;
2105         struct smbcli_options options = tree->session->transport->options;
2106         uint8_t expect_oplock = smb2_util_oplock_level("b");
2107         NTSTATUS expect_status = NT_STATUS_DUPLICATE_OBJECTID;
2108
2109         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
2110                 torture_skip(tctx, "SMB 3.X Dialect family required for "
2111                                 "Replay tests\n");
2112         }
2113
2114         server_capabilities = smb2cli_conn_server_capabilities(
2115                                         tree->session->transport->conn);
2116         if (!(server_capabilities & SMB2_CAP_PERSISTENT_HANDLES)) {
2117                 torture_skip(tctx,
2118                              "Server does not support persistent handles.");
2119         }
2120
2121         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
2122
2123         share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
2124         if (!share_is_ca) {
2125                 torture_skip(tctx, "Share is not continuously available.");
2126         }
2127
2128         share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
2129         if (share_is_so) {
2130                 expect_oplock = smb2_util_oplock_level("s");
2131                 expect_status = NT_STATUS_FILE_NOT_AVAILABLE;
2132         }
2133
2134         ZERO_STRUCT(break_info);
2135         break_info.tctx = tctx;
2136         transport->oplock.handler = torture_oplock_ack_handler;
2137         transport->oplock.private_data = tree;
2138
2139         torture_comment(tctx, "Replay of Persistent DurableHandleReqV2 on Single "
2140                         "Channel\n");
2141         status = torture_smb2_testdir(tree, BASEDIR, &_h);
2142         CHECK_STATUS(status, NT_STATUS_OK);
2143         smb2_util_close(tree, _h);
2144         smb2_util_unlink(tree, fname);
2145         CHECK_VAL(break_info.count, 0);
2146
2147         smb2_oplock_create_share(&io, fname,
2148                         smb2_util_share_access("RWD"),
2149                         smb2_util_oplock_level("b"));
2150         io.in.durable_open = false;
2151         io.in.durable_open_v2 = true;
2152         io.in.persistent_open = true;
2153         io.in.create_guid = create_guid;
2154         io.in.timeout = UINT32_MAX;
2155
2156         status = smb2_create(tree, mem_ctx, &io);
2157         CHECK_STATUS(status, NT_STATUS_OK);
2158         _h = io.out.file.handle;
2159         h = &_h;
2160         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2161         CHECK_VAL(io.out.oplock_level, expect_oplock);
2162         CHECK_VAL(io.out.durable_open, false);
2163         CHECK_VAL(io.out.durable_open_v2, true);
2164         CHECK_VAL(io.out.persistent_open, true);
2165         CHECK_VAL(io.out.timeout, io.in.timeout);
2166         CHECK_VAL(break_info.count, 0);
2167
2168         /* disconnect, leaving the durable open */
2169         TALLOC_FREE(tree);
2170
2171         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
2172                 torture_warning(tctx, "couldn't reconnect, bailing\n");
2173                 ret = false;
2174                 goto done;
2175         }
2176
2177         /* a re-open of a persistent handle causes an error */
2178         status = smb2_create(tree, mem_ctx, &io);
2179         CHECK_STATUS(status, expect_status);
2180
2181         /* SMB2_FLAGS_REPLAY_OPERATION must be set to open the Persistent Handle */
2182         smb2cli_session_start_replay(tree->session->smbXcli);
2183         smb2cli_session_increment_channel_sequence(tree->session->smbXcli);
2184         status = smb2_create(tree, mem_ctx, &io);
2185         CHECK_STATUS(status, NT_STATUS_OK);
2186         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2187         CHECK_VAL(io.out.durable_open, false);
2188         CHECK_VAL(io.out.persistent_open, true);
2189         CHECK_VAL(io.out.oplock_level, expect_oplock);
2190         _h = io.out.file.handle;
2191         h = &_h;
2192
2193         smb2_util_close(tree, *h);
2194         h = NULL;
2195 done:
2196         if (h != NULL) {
2197                 smb2_util_close(tree, *h);
2198         }
2199
2200         smb2_util_unlink(tree, fname);
2201         smb2_deltree(tree, BASEDIR);
2202
2203         talloc_free(tree);
2204         talloc_free(mem_ctx);
2205
2206         return ret;
2207 }
2208
2209
2210 /**
2211  * Test Error Codes when a DurableHandleReqV2 with matching CreateGuid is
2212  * re-sent with or without SMB2_FLAGS_REPLAY_OPERATION
2213  */
2214 static bool test_replay6(struct torture_context *tctx, struct smb2_tree *tree)
2215 {
2216         NTSTATUS status;
2217         TALLOC_CTX *mem_ctx = talloc_new(tctx);
2218         struct smb2_handle _h;
2219         struct smb2_handle *h = NULL;
2220         struct smb2_create io, ref1;
2221         union smb_fileinfo qfinfo;
2222         struct GUID create_guid = GUID_random();
2223         bool ret = true;
2224         const char *fname = BASEDIR "\\replay6.dat";
2225         struct smb2_transport *transport = tree->session->transport;
2226
2227         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
2228                 torture_skip(tctx, "SMB 3.X Dialect family required for "
2229                                    "replay tests\n");
2230         }
2231
2232         torture_reset_break_info(tctx, &break_info);
2233         tree->session->transport->oplock.handler = torture_oplock_ack_handler;
2234         tree->session->transport->oplock.private_data = tree;
2235
2236         torture_comment(tctx, "Error Codes for DurableHandleReqV2 Replay\n");
2237         smb2_util_unlink(tree, fname);
2238         status = torture_smb2_testdir(tree, BASEDIR, &_h);
2239         CHECK_STATUS(status, NT_STATUS_OK);
2240         smb2_util_close(tree, _h);
2241         torture_wait_for_oplock_break(tctx);
2242         CHECK_VAL(break_info.count, 0);
2243         torture_reset_break_info(tctx, &break_info);
2244
2245         smb2_oplock_create_share(&io, fname,
2246                         smb2_util_share_access("RWD"),
2247                         smb2_util_oplock_level("b"));
2248         io.in.durable_open = false;
2249         io.in.durable_open_v2 = true;
2250         io.in.persistent_open = false;
2251         io.in.create_guid = create_guid;
2252         io.in.timeout = UINT32_MAX;
2253
2254         status = smb2_create(tree, mem_ctx, &io);
2255         CHECK_STATUS(status, NT_STATUS_OK);
2256         ref1 = io;
2257         _h = io.out.file.handle;
2258         h = &_h;
2259         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2260         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2261         CHECK_VAL(io.out.durable_open, false);
2262         CHECK_VAL(io.out.durable_open_v2, true);
2263
2264         io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
2265         io.in.create_disposition = NTCREATEX_DISP_OPEN;
2266         smb2cli_session_start_replay(tree->session->smbXcli);
2267         status = smb2_create(tree, mem_ctx, &io);
2268         smb2cli_session_stop_replay(tree->session->smbXcli);
2269         CHECK_STATUS(status, NT_STATUS_OK);
2270         CHECK_CREATE_OUT(&io, &ref1);
2271         torture_wait_for_oplock_break(tctx);
2272         CHECK_VAL(break_info.count, 0);
2273         torture_reset_break_info(tctx, &break_info);
2274
2275         qfinfo = (union smb_fileinfo) {
2276                 .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
2277                 .generic.in.file.handle = *h
2278         };
2279         torture_comment(tctx, "Trying getinfo\n");
2280         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
2281         CHECK_STATUS(status, NT_STATUS_OK);
2282         CHECK_VAL(qfinfo.position_information.out.position, 0);
2283
2284         smb2cli_session_start_replay(tree->session->smbXcli);
2285         status = smb2_create(tree, mem_ctx, &io);
2286         smb2cli_session_stop_replay(tree->session->smbXcli);
2287         CHECK_STATUS(status, NT_STATUS_OK);
2288         torture_assert_u64_not_equal_goto(tctx,
2289                 io.out.file.handle.data[0],
2290                 ref1.out.file.handle.data[0],
2291                 ret, done, "data 0");
2292         torture_assert_u64_not_equal_goto(tctx,
2293                 io.out.file.handle.data[1],
2294                 ref1.out.file.handle.data[1],
2295                 ret, done, "data 1");
2296         torture_wait_for_oplock_break(tctx);
2297         CHECK_VAL(break_info.count, 1);
2298         CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
2299         torture_reset_break_info(tctx, &break_info);
2300
2301         /*
2302          * Resend the matching Durable V2 Create without
2303          * SMB2_FLAGS_REPLAY_OPERATION. This triggers an oplock break and still
2304          * gets NT_STATUS_DUPLICATE_OBJECTID
2305          */
2306         status = smb2_create(tree, mem_ctx, &io);
2307         CHECK_STATUS(status, NT_STATUS_DUPLICATE_OBJECTID);
2308         torture_wait_for_oplock_break(tctx);
2309         CHECK_VAL(break_info.count, 0);
2310         torture_reset_break_info(tctx, &break_info);
2311
2312         /*
2313          * According to MS-SMB2 3.3.5.9.10 if Durable V2 Create is replayed and
2314          * FileAttributes or CreateDisposition do not match the earlier Create
2315          * request the Server fails request with
2316          * NT_STATUS_INVALID_PARAMETER. But through this test we see that server
2317          * does not really care about changed FileAttributes or
2318          * CreateDisposition.
2319          */
2320         io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
2321         io.in.create_disposition = NTCREATEX_DISP_OPEN;
2322         smb2cli_session_start_replay(tree->session->smbXcli);
2323         status = smb2_create(tree, mem_ctx, &io);
2324         smb2cli_session_stop_replay(tree->session->smbXcli);
2325         CHECK_STATUS(status, NT_STATUS_OK);
2326         torture_assert_u64_not_equal_goto(tctx,
2327                 io.out.file.handle.data[0],
2328                 ref1.out.file.handle.data[0],
2329                 ret, done, "data 0");
2330         torture_assert_u64_not_equal_goto(tctx,
2331                 io.out.file.handle.data[1],
2332                 ref1.out.file.handle.data[1],
2333                 ret, done, "data 1");
2334         torture_wait_for_oplock_break(tctx);
2335         CHECK_VAL(break_info.count, 0);
2336
2337 done:
2338         if (h != NULL) {
2339                 smb2_util_close(tree, *h);
2340         }
2341
2342         smb2_util_unlink(tree, fname);
2343         smb2_deltree(tree, BASEDIR);
2344
2345         talloc_free(tree);
2346         talloc_free(mem_ctx);
2347
2348         return ret;
2349 }
2350
2351 static bool test_replay7(struct torture_context *tctx, struct smb2_tree *tree)
2352 {
2353         TALLOC_CTX *mem_ctx = talloc_new(tctx);
2354         struct smb2_transport *transport = tree->session->transport;
2355         NTSTATUS status;
2356         struct smb2_handle _dh;
2357         struct smb2_handle *dh = NULL;
2358         struct smb2_notify notify;
2359         struct smb2_request *req;
2360         union smb_fileinfo qfinfo;
2361         bool ret = false;
2362
2363         if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
2364                 torture_skip(tctx, "SMB 3.X Dialect family required for "
2365                                    "replay tests\n");
2366         }
2367
2368         torture_comment(tctx, "Notify across increment/decrement of csn\n");
2369
2370         smbXcli_conn_set_force_channel_sequence(transport->conn, true);
2371
2372         status = torture_smb2_testdir(tree, BASEDIR, &_dh);
2373         CHECK_STATUS(status, NT_STATUS_OK);
2374         dh = &_dh;
2375
2376         notify.in.recursive             = 0x0000;
2377         notify.in.buffer_size   = 0xffff;
2378         notify.in.file.handle   = _dh;
2379         notify.in.completion_filter     = FILE_NOTIFY_CHANGE_FILE_NAME;
2380         notify.in.unknown               = 0x00000000;
2381
2382         /*
2383          * This posts a long-running request with csn==0 to "dh". Now
2384          * op->request_count==1 in smb2_server.c.
2385          */
2386         smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);
2387         req = smb2_notify_send(tree, &notify);
2388
2389         qfinfo = (union smb_fileinfo) {
2390                 .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
2391                 .generic.in.file.handle = _dh
2392         };
2393
2394         /*
2395          * This sequence of 2 dummy requests moves
2396          * op->request_count==1 to op->pre_request_count. The numbers
2397          * used avoid int16 overflow.
2398          */
2399
2400         smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 30000);
2401         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
2402         CHECK_STATUS(status, NT_STATUS_OK);
2403
2404         smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 60000);
2405         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
2406         CHECK_STATUS(status, NT_STATUS_OK);
2407
2408         /*
2409          * This final request turns the op->global->channel_sequence
2410          * to the same as we had when sending the notify above. The
2411          * notify's request count has in the meantime moved to
2412          * op->pre_request_count.
2413          */
2414
2415         smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);
2416         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
2417         CHECK_STATUS(status, NT_STATUS_OK);
2418
2419         /*
2420          * At this point op->request_count==0.
2421          *
2422          * The next cancel makes us reply to the notify. Because the
2423          * csn we currently use is the same as we used when sending
2424          * the notify, smbd thinks it must decrement op->request_count
2425          * and not op->pre_request_count.
2426          */
2427
2428         status = smb2_cancel(req);
2429         CHECK_STATUS(status, NT_STATUS_OK);
2430
2431         status = smb2_notify_recv(req, mem_ctx, &notify);
2432         CHECK_STATUS(status, NT_STATUS_CANCELLED);
2433
2434         ret = true;
2435
2436 done:
2437         if (dh != NULL) {
2438                 smb2_util_close(tree, _dh);
2439         }
2440         smb2_deltree(tree, BASEDIR);
2441         talloc_free(tree);
2442         talloc_free(mem_ctx);
2443
2444         return ret;
2445 }
2446
2447 struct torture_suite *torture_smb2_replay_init(TALLOC_CTX *ctx)
2448 {
2449         struct torture_suite *suite =
2450                 torture_suite_create(ctx, "replay");
2451
2452         torture_suite_add_1smb2_test(suite, "replay-commands", test_replay_commands);
2453         torture_suite_add_1smb2_test(suite, "replay-regular", test_replay_regular);
2454         torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock1", test_replay_dhv2_oplock1);
2455         torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock2", test_replay_dhv2_oplock2);
2456         torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock3", test_replay_dhv2_oplock3);
2457         torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock-lease", test_replay_dhv2_oplock_lease);
2458         torture_suite_add_1smb2_test(suite, "replay-dhv2-lease1",  test_replay_dhv2_lease1);
2459         torture_suite_add_1smb2_test(suite, "replay-dhv2-lease2",  test_replay_dhv2_lease2);
2460         torture_suite_add_1smb2_test(suite, "replay-dhv2-lease3",  test_replay_dhv2_lease3);
2461         torture_suite_add_1smb2_test(suite, "replay-dhv2-lease-oplock",  test_replay_dhv2_lease_oplock);
2462         torture_suite_add_1smb2_test(suite, "channel-sequence", test_channel_sequence);
2463         torture_suite_add_1smb2_test(suite, "replay3", test_replay3);
2464         torture_suite_add_1smb2_test(suite, "replay4", test_replay4);
2465         torture_suite_add_1smb2_test(suite, "replay5", test_replay5);
2466         torture_suite_add_1smb2_test(suite, "replay6", test_replay6);
2467         torture_suite_add_1smb2_test(suite, "replay7", test_replay7);
2468
2469         suite->description = talloc_strdup(suite, "SMB2 REPLAY tests");
2470
2471         return suite;
2472 }