torture:smb2: fix crashes in smb2.durable-open.reopen1a test
[bbaumbach/samba-autobuild/.git] / source4 / torture / smb2 / durable_open.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    test suite for SMB2 durable opens
5
6    Copyright (C) Stefan Metzmacher 2008
7    Copyright (C) Michael Adam 2011-2012
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 "../libcli/smb/smbXcli_base.h"
27 #include "torture/torture.h"
28 #include "torture/smb2/proto.h"
29 #include "../libcli/smb/smbXcli_base.h"
30
31 #define CHECK_VAL(v, correct) do { \
32         if ((v) != (correct)) { \
33                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%llx - should be 0x%llx\n", \
34                                 __location__, #v, (unsigned long long)v, (unsigned long long)correct); \
35                 ret = false; \
36         }} while (0)
37
38 #define CHECK_NOT_VAL(v, incorrect) do { \
39         if ((v) == (incorrect)) { \
40                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%llx - should not be 0x%llx\n", \
41                                 __location__, #v, (unsigned long long)v, (unsigned long long)incorrect); \
42                 ret = false; \
43         }} while (0)
44
45 #define CHECK_NOT_NULL(p) do { \
46         if ((p) == NULL) { \
47                 torture_result(tctx, TORTURE_FAIL, "(%s): %s is NULL but it should not be.\n", \
48                                 __location__, #p); \
49                 ret = false; \
50         }} while (0)
51
52 #define CHECK_STATUS(status, correct) do { \
53         if (!NT_STATUS_EQUAL(status, correct)) { \
54                 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
55                        nt_errstr(status), nt_errstr(correct)); \
56                 ret = false; \
57                 goto done; \
58         }} while (0)
59
60 #define CHECK_CREATED(__io, __created, __attribute)                     \
61         do {                                                            \
62                 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
63                 CHECK_VAL((__io)->out.alloc_size, 0);                   \
64                 CHECK_VAL((__io)->out.size, 0);                         \
65                 CHECK_VAL((__io)->out.file_attr, (__attribute));        \
66                 CHECK_VAL((__io)->out.reserved2, 0);                    \
67         } while(0)
68
69 #define CHECK_CREATED_SIZE(__io, __created, __attribute, __alloc_size, __size)  \
70         do {                                                                    \
71                 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
72                 CHECK_VAL((__io)->out.alloc_size, (__alloc_size));              \
73                 CHECK_VAL((__io)->out.size, (__size));                          \
74                 CHECK_VAL((__io)->out.file_attr, (__attribute));                \
75                 CHECK_VAL((__io)->out.reserved2, 0);                            \
76         } while(0)
77
78
79
80 /**
81  * basic durable_open test.
82  * durable state should only be granted when requested
83  * along with a batch oplock or a handle lease.
84  *
85  * This test tests durable open with all possible oplock types.
86  */
87
88 struct durable_open_vs_oplock {
89         const char *level;
90         const char *share_mode;
91         bool expected;
92 };
93
94 #define NUM_OPLOCK_TYPES 4
95 #define NUM_SHARE_MODES 8
96 #define NUM_OPLOCK_OPEN_TESTS ( NUM_OPLOCK_TYPES * NUM_SHARE_MODES )
97 static struct durable_open_vs_oplock durable_open_vs_oplock_table[NUM_OPLOCK_OPEN_TESTS] =
98 {
99         { "", "", false },
100         { "", "R", false },
101         { "", "W", false },
102         { "", "D", false },
103         { "", "RD", false },
104         { "", "RW", false },
105         { "", "WD", false },
106         { "", "RWD", false },
107
108         { "s", "", false },
109         { "s", "R", false },
110         { "s", "W", false },
111         { "s", "D", false },
112         { "s", "RD", false },
113         { "s", "RW", false },
114         { "s", "WD", false },
115         { "s", "RWD", false },
116
117         { "x", "", false },
118         { "x", "R", false },
119         { "x", "W", false },
120         { "x", "D", false },
121         { "x", "RD", false },
122         { "x", "RW", false },
123         { "x", "WD", false },
124         { "x", "RWD", false },
125
126         { "b", "", true },
127         { "b", "R", true },
128         { "b", "W", true },
129         { "b", "D", true },
130         { "b", "RD", true },
131         { "b", "RW", true },
132         { "b", "WD", true },
133         { "b", "RWD", true },
134 };
135
136 static bool test_one_durable_open_open_oplock(struct torture_context *tctx,
137                                               struct smb2_tree *tree,
138                                               const char *fname,
139                                               struct durable_open_vs_oplock test)
140 {
141         NTSTATUS status;
142         TALLOC_CTX *mem_ctx = talloc_new(tctx);
143         struct smb2_handle _h;
144         struct smb2_handle *h = NULL;
145         bool ret = true;
146         struct smb2_create io;
147
148         smb2_util_unlink(tree, fname);
149
150         smb2_oplock_create_share(&io, fname,
151                                  smb2_util_share_access(test.share_mode),
152                                  smb2_util_oplock_level(test.level));
153         io.in.durable_open = true;
154
155         status = smb2_create(tree, mem_ctx, &io);
156         CHECK_STATUS(status, NT_STATUS_OK);
157         _h = io.out.file.handle;
158         h = &_h;
159         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
160         CHECK_VAL(io.out.durable_open, test.expected);
161         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(test.level));
162
163 done:
164         if (h != NULL) {
165                 smb2_util_close(tree, *h);
166         }
167         smb2_util_unlink(tree, fname);
168         talloc_free(mem_ctx);
169
170         return ret;
171 }
172
173 static bool test_durable_open_open_oplock(struct torture_context *tctx,
174                                           struct smb2_tree *tree)
175 {
176         TALLOC_CTX *mem_ctx = talloc_new(tctx);
177         char fname[256];
178         bool ret = true;
179         int i;
180
181         /* Choose a random name in case the state is left a little funky. */
182         snprintf(fname, 256, "durable_open_open_oplock_%s.dat", generate_random_str(tctx, 8));
183
184         smb2_util_unlink(tree, fname);
185
186         /* test various oplock levels with durable open */
187
188         for (i = 0; i < NUM_OPLOCK_OPEN_TESTS; i++) {
189                 ret = test_one_durable_open_open_oplock(tctx,
190                                                         tree,
191                                                         fname,
192                                                         durable_open_vs_oplock_table[i]);
193                 if (ret == false) {
194                         goto done;
195                 }
196         }
197
198 done:
199         smb2_util_unlink(tree, fname);
200         talloc_free(tree);
201         talloc_free(mem_ctx);
202
203         return ret;
204 }
205
206 /**
207  * basic durable_open test.
208  * durable state should only be granted when requested
209  * along with a batch oplock or a handle lease.
210  *
211  * This test tests durable open with all valid lease types.
212  */
213
214 struct durable_open_vs_lease {
215         const char *type;
216         const char *share_mode;
217         bool expected;
218 };
219
220 #define NUM_LEASE_TYPES 5
221 #define NUM_LEASE_OPEN_TESTS ( NUM_LEASE_TYPES * NUM_SHARE_MODES )
222 static struct durable_open_vs_lease durable_open_vs_lease_table[NUM_LEASE_OPEN_TESTS] =
223 {
224         { "", "", false },
225         { "", "R", false },
226         { "", "W", false },
227         { "", "D", false },
228         { "", "RW", false },
229         { "", "RD", false },
230         { "", "WD", false },
231         { "", "RWD", false },
232
233         { "R", "", false },
234         { "R", "R", false },
235         { "R", "W", false },
236         { "R", "D", false },
237         { "R", "RW", false },
238         { "R", "RD", false },
239         { "R", "DW", false },
240         { "R", "RWD", false },
241
242         { "RW", "", false },
243         { "RW", "R", false },
244         { "RW", "W", false },
245         { "RW", "D", false },
246         { "RW", "RW", false },
247         { "RW", "RD", false },
248         { "RW", "WD", false },
249         { "RW", "RWD", false },
250
251         { "RH", "", true },
252         { "RH", "R", true },
253         { "RH", "W", true },
254         { "RH", "D", true },
255         { "RH", "RW", true },
256         { "RH", "RD", true },
257         { "RH", "WD", true },
258         { "RH", "RWD", true },
259
260         { "RHW", "", true },
261         { "RHW", "R", true },
262         { "RHW", "W", true },
263         { "RHW", "D", true },
264         { "RHW", "RW", true },
265         { "RHW", "RD", true },
266         { "RHW", "WD", true },
267         { "RHW", "RWD", true },
268 };
269
270 static bool test_one_durable_open_open_lease(struct torture_context *tctx,
271                                              struct smb2_tree *tree,
272                                              const char *fname,
273                                              struct durable_open_vs_lease test)
274 {
275         NTSTATUS status;
276         TALLOC_CTX *mem_ctx = talloc_new(tctx);
277         struct smb2_handle _h;
278         struct smb2_handle *h = NULL;
279         bool ret = true;
280         struct smb2_create io;
281         struct smb2_lease ls;
282         uint64_t lease;
283         uint32_t caps;
284
285         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
286         if (!(caps & SMB2_CAP_LEASING)) {
287                 torture_skip(tctx, "leases are not supported");
288         }
289
290         smb2_util_unlink(tree, fname);
291
292         lease = random();
293
294         smb2_lease_create_share(&io, &ls, false /* dir */, fname,
295                                 smb2_util_share_access(test.share_mode),
296                                 lease,
297                                 smb2_util_lease_state(test.type));
298         io.in.durable_open = true;
299
300         status = smb2_create(tree, mem_ctx, &io);
301         CHECK_STATUS(status, NT_STATUS_OK);
302         _h = io.out.file.handle;
303         h = &_h;
304         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
305         CHECK_VAL(io.out.durable_open, test.expected);
306         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
307         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
308         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
309         CHECK_VAL(io.out.lease_response.lease_state,
310                   smb2_util_lease_state(test.type));
311 done:
312         if (h != NULL) {
313                 smb2_util_close(tree, *h);
314         }
315         smb2_util_unlink(tree, fname);
316         talloc_free(mem_ctx);
317
318         return ret;
319 }
320
321 static bool test_durable_open_open_lease(struct torture_context *tctx,
322                                          struct smb2_tree *tree)
323 {
324         TALLOC_CTX *mem_ctx = talloc_new(tctx);
325         char fname[256];
326         bool ret = true;
327         int i;
328         uint32_t caps;
329
330         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
331         if (!(caps & SMB2_CAP_LEASING)) {
332                 torture_skip(tctx, "leases are not supported");
333         }
334
335         /* Choose a random name in case the state is left a little funky. */
336         snprintf(fname, 256, "durable_open_open_lease_%s.dat", generate_random_str(tctx, 8));
337
338         smb2_util_unlink(tree, fname);
339
340
341         /* test various oplock levels with durable open */
342
343         for (i = 0; i < NUM_LEASE_OPEN_TESTS; i++) {
344                 ret = test_one_durable_open_open_lease(tctx,
345                                                        tree,
346                                                        fname,
347                                                        durable_open_vs_lease_table[i]);
348                 if (ret == false) {
349                         goto done;
350                 }
351         }
352
353 done:
354         smb2_util_unlink(tree, fname);
355         talloc_free(tree);
356         talloc_free(mem_ctx);
357
358         return ret;
359 }
360
361 /**
362  * basic test for doing a durable open
363  * and do a durable reopen on the same connection
364  * while the first open is still active (fails)
365  */
366 static bool test_durable_open_reopen1(struct torture_context *tctx,
367                                       struct smb2_tree *tree)
368 {
369         NTSTATUS status;
370         TALLOC_CTX *mem_ctx = talloc_new(tctx);
371         char fname[256];
372         struct smb2_handle _h;
373         struct smb2_handle *h = NULL;
374         struct smb2_create io1, io2;
375         bool ret = true;
376
377         /* Choose a random name in case the state is left a little funky. */
378         snprintf(fname, 256, "durable_open_reopen1_%s.dat",
379                  generate_random_str(tctx, 8));
380
381         smb2_util_unlink(tree, fname);
382
383         smb2_oplock_create_share(&io1, fname,
384                                  smb2_util_share_access(""),
385                                  smb2_util_oplock_level("b"));
386         io1.in.durable_open = true;
387
388         status = smb2_create(tree, mem_ctx, &io1);
389         CHECK_STATUS(status, NT_STATUS_OK);
390         _h = io1.out.file.handle;
391         h = &_h;
392         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
393         CHECK_VAL(io1.out.durable_open, true);
394         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
395
396         /* try a durable reconnect while the file is still open */
397         ZERO_STRUCT(io2);
398         io2.in.fname = fname;
399         io2.in.durable_handle = h;
400
401         status = smb2_create(tree, mem_ctx, &io2);
402         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
403
404 done:
405         if (h != NULL) {
406                 smb2_util_close(tree, *h);
407         }
408
409         smb2_util_unlink(tree, fname);
410
411         talloc_free(tree);
412
413         talloc_free(mem_ctx);
414
415         return ret;
416 }
417
418 /**
419  * Basic test for doing a durable open
420  * and do a session reconnect while the first
421  * session is still active and the handle is
422  * still open in the client.
423  * This closes the original session and  a
424  * durable reconnect on the new session succeeds.
425  */
426 static bool test_durable_open_reopen1a(struct torture_context *tctx,
427                                        struct smb2_tree *tree)
428 {
429         NTSTATUS status;
430         TALLOC_CTX *mem_ctx = talloc_new(tctx);
431         char fname[256];
432         struct smb2_handle _h;
433         struct smb2_handle *h = NULL;
434         struct smb2_create io1, io2;
435         bool ret = true;
436         struct smb2_tree *tree2 = NULL;
437         uint64_t previous_session_id;
438         struct smbcli_options options;
439
440         options = tree->session->transport->options;
441
442         /* Choose a random name in case the state is left a little funky. */
443         snprintf(fname, 256, "durable_open_reopen1a_%s.dat",
444                  generate_random_str(tctx, 8));
445
446         smb2_util_unlink(tree, fname);
447
448         smb2_oplock_create_share(&io1, fname,
449                                  smb2_util_share_access(""),
450                                  smb2_util_oplock_level("b"));
451         io1.in.durable_open = true;
452
453         status = smb2_create(tree, mem_ctx, &io1);
454         CHECK_STATUS(status, NT_STATUS_OK);
455         _h = io1.out.file.handle;
456         h = &_h;
457         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
458         CHECK_VAL(io1.out.durable_open, true);
459         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
460
461         /*
462          * a session reconnect on a second tcp connection
463          */
464
465         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
466
467         ret = torture_smb2_connection_ext(tctx, previous_session_id,
468                                           &options, &tree2);
469         torture_assert_goto(tctx, ret, ret, done, "could not reconnect");
470
471         /*
472          * check that this has deleted the old session
473          */
474
475         ZERO_STRUCT(io2);
476         io2.in.fname = fname;
477         io2.in.durable_handle = h;
478
479         status = smb2_create(tree, mem_ctx, &io2);
480         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
481
482         TALLOC_FREE(tree);
483
484         /*
485          * but a durable reconnect on the new session succeeds:
486          */
487
488         ZERO_STRUCT(io2);
489         io2.in.fname = fname;
490         io2.in.durable_handle = h;
491
492         status = smb2_create(tree2, mem_ctx, &io2);
493         CHECK_STATUS(status, NT_STATUS_OK);
494         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
495         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
496         _h = io2.out.file.handle;
497         h = &_h;
498
499 done:
500         if (tree == NULL) {
501                 tree = tree2;
502         }
503
504         if (tree != NULL) {
505                 if (h != NULL) {
506                         smb2_util_close(tree, *h);
507                         h = NULL;
508                 }
509                 smb2_util_unlink(tree, fname);
510
511                 talloc_free(tree);
512         }
513
514         talloc_free(mem_ctx);
515
516         return ret;
517 }
518
519 /**
520  * basic test for doing a durable open
521  * tcp disconnect, reconnect, do a durable reopen (succeeds)
522  */
523 static bool test_durable_open_reopen2(struct torture_context *tctx,
524                                       struct smb2_tree *tree)
525 {
526         NTSTATUS status;
527         TALLOC_CTX *mem_ctx = talloc_new(tctx);
528         char fname[256];
529         struct smb2_handle _h;
530         struct smb2_handle *h = NULL;
531         struct smb2_create io;
532         bool ret = true;
533
534         /* Choose a random name in case the state is left a little funky. */
535         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
536                  generate_random_str(tctx, 8));
537
538         smb2_util_unlink(tree, fname);
539
540         smb2_oplock_create_share(&io, fname,
541                                  smb2_util_share_access(""),
542                                  smb2_util_oplock_level("b"));
543         io.in.durable_open = true;
544
545         status = smb2_create(tree, mem_ctx, &io);
546         CHECK_STATUS(status, NT_STATUS_OK);
547         _h = io.out.file.handle;
548         h = &_h;
549         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
550         CHECK_VAL(io.out.durable_open, true);
551         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
552
553         /* disconnect, leaving the durable in place */
554         TALLOC_FREE(tree);
555
556         if (!torture_smb2_connection(tctx, &tree)) {
557                 torture_warning(tctx, "couldn't reconnect, bailing\n");
558                 ret = false;
559                 goto done;
560         }
561
562         ZERO_STRUCT(io);
563         /* the path name is ignored by the server */
564         io.in.fname = fname;
565         io.in.durable_handle = h; /* durable v1 reconnect request */
566         h = NULL;
567
568         status = smb2_create(tree, mem_ctx, &io);
569         CHECK_STATUS(status, NT_STATUS_OK);
570         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
571         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
572         _h = io.out.file.handle;
573         h = &_h;
574
575         /* disconnect again, leaving the durable in place */
576         TALLOC_FREE(tree);
577
578         if (!torture_smb2_connection(tctx, &tree)) {
579                 torture_warning(tctx, "couldn't reconnect, bailing\n");
580                 ret = false;
581                 goto done;
582         }
583
584         /*
585          * show that the filename and many other fields
586          * are ignored. only the reconnect request blob
587          * is important.
588          */
589         ZERO_STRUCT(io);
590         /* the path name is ignored by the server */
591         io.in.security_flags = 0x78;
592         io.in.oplock_level = 0x78;
593         io.in.impersonation_level = 0x12345678;
594         io.in.create_flags = 0x12345678;
595         io.in.reserved = 0x12345678;
596         io.in.desired_access = 0x12345678;
597         io.in.file_attributes = 0x12345678;
598         io.in.share_access = 0x12345678;
599         io.in.create_disposition = 0x12345678;
600         io.in.create_options = 0x12345678;
601         io.in.fname = "__non_existing_fname__";
602         io.in.durable_handle = h; /* durable v1 reconnect request */
603         h = NULL;
604
605         status = smb2_create(tree, mem_ctx, &io);
606         CHECK_STATUS(status, NT_STATUS_OK);
607         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
608         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
609         _h = io.out.file.handle;
610         h = &_h;
611
612         /* disconnect, leaving the durable in place */
613         TALLOC_FREE(tree);
614
615         if (!torture_smb2_connection(tctx, &tree)) {
616                 torture_warning(tctx, "couldn't reconnect, bailing\n");
617                 ret = false;
618                 goto done;
619         }
620
621         /*
622          * show that an additionally specified durable v1 request
623          * is ignored by the server.
624          * See MS-SMB2, 3.3.5.9.7
625          * Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context
626          */
627         ZERO_STRUCT(io);
628         /* the path name is ignored by the server */
629         io.in.fname = fname;
630         io.in.durable_handle = h;  /* durable v1 reconnect request */
631         io.in.durable_open = true; /* durable v1 handle request */
632         h = NULL;
633
634         status = smb2_create(tree, mem_ctx, &io);
635         CHECK_STATUS(status, NT_STATUS_OK);
636         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
637         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
638         _h = io.out.file.handle;
639         h = &_h;
640
641 done:
642         if (tree != NULL) {
643                 if (h != NULL) {
644                         smb2_util_close(tree, *h);
645                 }
646
647                 smb2_util_unlink(tree, fname);
648
649                 talloc_free(tree);
650         }
651
652         talloc_free(mem_ctx);
653
654         return ret;
655 }
656
657 /**
658  * lease variant of reopen2
659  * basic test for doing a durable open
660  * tcp disconnect, reconnect, do a durable reopen (succeeds)
661  */
662 static bool test_durable_open_reopen2_lease(struct torture_context *tctx,
663                                             struct smb2_tree *tree)
664 {
665         NTSTATUS status;
666         TALLOC_CTX *mem_ctx = talloc_new(tctx);
667         char fname[256];
668         struct smb2_handle _h;
669         struct smb2_handle *h = NULL;
670         struct smb2_create io;
671         struct smb2_lease ls;
672         uint64_t lease_key;
673         bool ret = true;
674         struct smbcli_options options;
675         uint32_t caps;
676
677         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
678         if (!(caps & SMB2_CAP_LEASING)) {
679                 torture_skip(tctx, "leases are not supported");
680         }
681
682         options = tree->session->transport->options;
683
684         /* Choose a random name in case the state is left a little funky. */
685         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
686                  generate_random_str(tctx, 8));
687
688         smb2_util_unlink(tree, fname);
689
690         lease_key = random();
691         smb2_lease_create(&io, &ls, false /* dir */, fname, lease_key,
692                           smb2_util_lease_state("RWH"));
693         io.in.durable_open = true;
694
695         status = smb2_create(tree, mem_ctx, &io);
696         CHECK_STATUS(status, NT_STATUS_OK);
697         _h = io.out.file.handle;
698         h = &_h;
699         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
700
701         CHECK_VAL(io.out.durable_open, true);
702         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
703         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
704         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
705         CHECK_VAL(io.out.lease_response.lease_state,
706                   smb2_util_lease_state("RWH"));
707         CHECK_VAL(io.out.lease_response.lease_flags, 0);
708         CHECK_VAL(io.out.lease_response.lease_duration, 0);
709
710         /* disconnect, reconnect and then do durable reopen */
711         TALLOC_FREE(tree);
712
713         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
714                 torture_warning(tctx, "couldn't reconnect, bailing\n");
715                 ret = false;
716                 goto done;
717         }
718
719
720         /* a few failure tests: */
721
722         /*
723          * several attempts without lease attached:
724          * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
725          * irrespective of file name provided
726          */
727
728         ZERO_STRUCT(io);
729         io.in.fname = "";
730         io.in.durable_handle = h;
731         status = smb2_create(tree, mem_ctx, &io);
732         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
733
734         ZERO_STRUCT(io);
735         io.in.fname = "__non_existing_fname__";
736         io.in.durable_handle = h;
737         status = smb2_create(tree, mem_ctx, &io);
738         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
739
740         ZERO_STRUCT(io);
741         io.in.fname = fname;
742         io.in.durable_handle = h;
743         status = smb2_create(tree, mem_ctx, &io);
744         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
745
746         /*
747          * attempt with lease provided, but
748          * with a changed lease key. => fails
749          */
750         ZERO_STRUCT(io);
751         io.in.fname = fname;
752         io.in.durable_open = false;
753         io.in.durable_handle = h;
754         io.in.lease_request = &ls;
755         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
756         /* a wrong lease key lets the request fail */
757         ls.lease_key.data[0]++;
758
759         status = smb2_create(tree, mem_ctx, &io);
760         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
761
762         /* restore the correct lease key */
763         ls.lease_key.data[0]--;
764
765         /*
766          * this last failing attempt is almost correct:
767          * only problem is: we use the wrong filename...
768          * Note that this gives INVALID_PARAMETER.
769          * This is different from oplocks!
770          */
771         ZERO_STRUCT(io);
772         io.in.fname = "__non_existing_fname__";
773         io.in.durable_open = false;
774         io.in.durable_handle = h;
775         io.in.lease_request = &ls;
776         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
777
778         status = smb2_create(tree, mem_ctx, &io);
779         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
780
781         /*
782          * Now for a succeeding reconnect:
783          */
784
785         ZERO_STRUCT(io);
786         io.in.fname = fname;
787         io.in.durable_open = false;
788         io.in.durable_handle = h;
789         io.in.lease_request = &ls;
790         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
791
792         /* the requested lease state is irrelevant */
793         ls.lease_state = smb2_util_lease_state("");
794
795         h = NULL;
796
797         status = smb2_create(tree, mem_ctx, &io);
798         CHECK_STATUS(status, NT_STATUS_OK);
799
800         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
801         CHECK_VAL(io.out.durable_open, false);
802         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
803         CHECK_VAL(io.out.persistent_open, false);
804         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
805         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
806         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
807         CHECK_VAL(io.out.lease_response.lease_state,
808                   smb2_util_lease_state("RWH"));
809         CHECK_VAL(io.out.lease_response.lease_flags, 0);
810         CHECK_VAL(io.out.lease_response.lease_duration, 0);
811         _h = io.out.file.handle;
812         h = &_h;
813
814         /* disconnect one more time */
815         TALLOC_FREE(tree);
816
817         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
818                 torture_warning(tctx, "couldn't reconnect, bailing\n");
819                 ret = false;
820                 goto done;
821         }
822
823         /*
824          * demonstrate that various parameters are ignored
825          * in the reconnect
826          */
827
828         ZERO_STRUCT(io);
829         /*
830          * These are completely ignored by the server
831          */
832         io.in.security_flags = 0x78;
833         io.in.oplock_level = 0x78;
834         io.in.impersonation_level = 0x12345678;
835         io.in.create_flags = 0x12345678;
836         io.in.reserved = 0x12345678;
837         io.in.desired_access = 0x12345678;
838         io.in.file_attributes = 0x12345678;
839         io.in.share_access = 0x12345678;
840         io.in.create_disposition = 0x12345678;
841         io.in.create_options = 0x12345678;
842
843         /*
844          * only these are checked:
845          * - io.in.fname
846          * - io.in.durable_handle,
847          * - io.in.lease_request->lease_key
848          */
849
850         io.in.fname = fname;
851         io.in.durable_open_v2 = false;
852         io.in.durable_handle_v2 = h;
853         io.in.lease_request = &ls;
854
855         /* the requested lease state is irrelevant */
856         ls.lease_state = smb2_util_lease_state("");
857
858         h = NULL;
859
860         status = smb2_create(tree, mem_ctx, &io);
861         CHECK_STATUS(status, NT_STATUS_OK);
862
863         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
864         CHECK_VAL(io.out.durable_open, false);
865         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
866         CHECK_VAL(io.out.persistent_open, false);
867         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
868         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
869         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
870         CHECK_VAL(io.out.lease_response.lease_state,
871                   smb2_util_lease_state("RWH"));
872         CHECK_VAL(io.out.lease_response.lease_flags, 0);
873         CHECK_VAL(io.out.lease_response.lease_duration, 0);
874
875         _h = io.out.file.handle;
876         h = &_h;
877
878 done:
879         if (tree != NULL) {
880                 if (h != NULL) {
881                         smb2_util_close(tree, *h);
882                 }
883
884                 smb2_util_unlink(tree, fname);
885
886                 talloc_free(tree);
887         }
888
889         talloc_free(mem_ctx);
890
891         return ret;
892 }
893
894 /**
895  * lease v2 variant of reopen2
896  * basic test for doing a durable open
897  * tcp disconnect, reconnect, do a durable reopen (succeeds)
898  */
899 static bool test_durable_open_reopen2_lease_v2(struct torture_context *tctx,
900                                                struct smb2_tree *tree)
901 {
902         NTSTATUS status;
903         TALLOC_CTX *mem_ctx = talloc_new(tctx);
904         char fname[256];
905         struct smb2_handle _h;
906         struct smb2_handle *h = NULL;
907         struct smb2_create io;
908         struct smb2_lease ls;
909         uint64_t lease_key;
910         bool ret = true;
911         struct smbcli_options options;
912         uint32_t caps;
913
914         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
915         if (!(caps & SMB2_CAP_LEASING)) {
916                 torture_skip(tctx, "leases are not supported");
917         }
918
919         options = tree->session->transport->options;
920
921         /* Choose a random name in case the state is left a little funky. */
922         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
923                  generate_random_str(tctx, 8));
924
925         smb2_util_unlink(tree, fname);
926
927         lease_key = random();
928         smb2_lease_v2_create(&io, &ls, false /* dir */, fname,
929                              lease_key, 0, /* parent lease key */
930                              smb2_util_lease_state("RWH"), 0 /* lease epoch */);
931         io.in.durable_open = true;
932
933         status = smb2_create(tree, mem_ctx, &io);
934         CHECK_STATUS(status, NT_STATUS_OK);
935         _h = io.out.file.handle;
936         h = &_h;
937         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
938
939         CHECK_VAL(io.out.durable_open, true);
940         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
941         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
942         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
943         CHECK_VAL(io.out.lease_response_v2.lease_state,
944                   smb2_util_lease_state("RWH"));
945         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
946         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
947
948         /* disconnect, reconnect and then do durable reopen */
949         TALLOC_FREE(tree);
950
951         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
952                 torture_warning(tctx, "couldn't reconnect, bailing\n");
953                 ret = false;
954                 goto done;
955         }
956
957         /* a few failure tests: */
958
959         /*
960          * several attempts without lease attached:
961          * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
962          * irrespective of file name provided
963          */
964
965         ZERO_STRUCT(io);
966         io.in.fname = "";
967         io.in.durable_handle = h;
968         status = smb2_create(tree, mem_ctx, &io);
969         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
970
971         ZERO_STRUCT(io);
972         io.in.fname = "__non_existing_fname__";
973         io.in.durable_handle = h;
974         status = smb2_create(tree, mem_ctx, &io);
975         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
976
977         ZERO_STRUCT(io);
978         io.in.fname = fname;
979         io.in.durable_handle = h;
980         status = smb2_create(tree, mem_ctx, &io);
981         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
982
983         /*
984          * attempt with lease provided, but
985          * with a changed lease key. => fails
986          */
987         ZERO_STRUCT(io);
988         io.in.fname = fname;
989         io.in.durable_open = false;
990         io.in.durable_handle = h;
991         io.in.lease_request_v2 = &ls;
992         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
993         /* a wrong lease key lets the request fail */
994         ls.lease_key.data[0]++;
995
996         status = smb2_create(tree, mem_ctx, &io);
997         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
998
999         /* restore the correct lease key */
1000         ls.lease_key.data[0]--;
1001
1002         /*
1003          * this last failing attempt is almost correct:
1004          * only problem is: we use the wrong filename...
1005          * Note that this gives INVALID_PARAMETER.
1006          * This is different from oplocks!
1007          */
1008         ZERO_STRUCT(io);
1009         io.in.fname = "__non_existing_fname__";
1010         io.in.durable_open = false;
1011         io.in.durable_handle = h;
1012         io.in.lease_request_v2 = &ls;
1013         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
1014
1015         status = smb2_create(tree, mem_ctx, &io);
1016         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1017
1018         /*
1019          * Now for a succeeding reconnect:
1020          */
1021
1022         ZERO_STRUCT(io);
1023         io.in.fname = fname;
1024         io.in.durable_open = false;
1025         io.in.durable_handle = h;
1026         io.in.lease_request_v2 = &ls;
1027         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
1028
1029         /* the requested lease state is irrelevant */
1030         ls.lease_state = smb2_util_lease_state("");
1031
1032         h = NULL;
1033
1034         status = smb2_create(tree, mem_ctx, &io);
1035         CHECK_STATUS(status, NT_STATUS_OK);
1036
1037         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1038         CHECK_VAL(io.out.durable_open, false);
1039         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
1040         CHECK_VAL(io.out.persistent_open, false);
1041         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1042         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
1043         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
1044         CHECK_VAL(io.out.lease_response_v2.lease_state,
1045                   smb2_util_lease_state("RWH"));
1046         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
1047         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
1048         _h = io.out.file.handle;
1049         h = &_h;
1050
1051         /* disconnect one more time */
1052         TALLOC_FREE(tree);
1053
1054         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
1055                 torture_warning(tctx, "couldn't reconnect, bailing\n");
1056                 ret = false;
1057                 goto done;
1058         }
1059
1060         /*
1061          * demonstrate that various parameters are ignored
1062          * in the reconnect
1063          */
1064
1065         ZERO_STRUCT(io);
1066         /*
1067          * These are completely ignored by the server
1068          */
1069         io.in.security_flags = 0x78;
1070         io.in.oplock_level = 0x78;
1071         io.in.impersonation_level = 0x12345678;
1072         io.in.create_flags = 0x12345678;
1073         io.in.reserved = 0x12345678;
1074         io.in.desired_access = 0x12345678;
1075         io.in.file_attributes = 0x12345678;
1076         io.in.share_access = 0x12345678;
1077         io.in.create_disposition = 0x12345678;
1078         io.in.create_options = 0x12345678;
1079
1080         /*
1081          * only these are checked:
1082          * - io.in.fname
1083          * - io.in.durable_handle,
1084          * - io.in.lease_request->lease_key
1085          */
1086
1087         io.in.fname = fname;
1088         io.in.durable_open_v2 = false;
1089         io.in.durable_handle_v2 = h;
1090         io.in.lease_request_v2 = &ls;
1091
1092         /* the requested lease state is irrelevant */
1093         ls.lease_state = smb2_util_lease_state("");
1094
1095         h = NULL;
1096
1097         status = smb2_create(tree, mem_ctx, &io);
1098         CHECK_STATUS(status, NT_STATUS_OK);
1099
1100         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1101         CHECK_VAL(io.out.durable_open, false);
1102         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
1103         CHECK_VAL(io.out.persistent_open, false);
1104         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1105         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
1106         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
1107         CHECK_VAL(io.out.lease_response_v2.lease_state,
1108                   smb2_util_lease_state("RWH"));
1109         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
1110         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
1111
1112         _h = io.out.file.handle;
1113         h = &_h;
1114
1115 done:
1116         if (tree != NULL) {
1117                 if (h != NULL) {
1118                         smb2_util_close(tree, *h);
1119                 }
1120
1121                 smb2_util_unlink(tree, fname);
1122
1123                 talloc_free(tree);
1124         }
1125
1126         talloc_free(mem_ctx);
1127
1128         return ret;
1129 }
1130
1131 /**
1132  * basic test for doing a durable open
1133  * tcp disconnect, reconnect with a session reconnect and
1134  * do a durable reopen (succeeds)
1135  */
1136 static bool test_durable_open_reopen2a(struct torture_context *tctx,
1137                                        struct smb2_tree *tree)
1138 {
1139         NTSTATUS status;
1140         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1141         char fname[256];
1142         struct smb2_handle _h;
1143         struct smb2_handle *h = NULL;
1144         struct smb2_create io1, io2;
1145         uint64_t previous_session_id;
1146         bool ret = true;
1147         struct smbcli_options options;
1148
1149         options = tree->session->transport->options;
1150
1151         /* Choose a random name in case the state is left a little funky. */
1152         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
1153                  generate_random_str(tctx, 8));
1154
1155         smb2_util_unlink(tree, fname);
1156
1157         smb2_oplock_create_share(&io1, fname,
1158                                  smb2_util_share_access(""),
1159                                  smb2_util_oplock_level("b"));
1160         io1.in.durable_open = true;
1161
1162         status = smb2_create(tree, mem_ctx, &io1);
1163         CHECK_STATUS(status, NT_STATUS_OK);
1164         _h = io1.out.file.handle;
1165         h = &_h;
1166         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1167         CHECK_VAL(io1.out.durable_open, true);
1168         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
1169
1170         /* disconnect, reconnect and then do durable reopen */
1171         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
1172         talloc_free(tree);
1173         tree = NULL;
1174
1175         if (!torture_smb2_connection_ext(tctx, previous_session_id,
1176                                          &options, &tree))
1177         {
1178                 torture_warning(tctx, "couldn't reconnect, bailing\n");
1179                 ret = false;
1180                 goto done;
1181         }
1182
1183         ZERO_STRUCT(io2);
1184         io2.in.fname = fname;
1185         io2.in.durable_handle = h;
1186         h = NULL;
1187
1188         status = smb2_create(tree, mem_ctx, &io2);
1189         CHECK_STATUS(status, NT_STATUS_OK);
1190         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1191         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
1192         _h = io2.out.file.handle;
1193         h = &_h;
1194
1195 done:
1196         if (tree != NULL) {
1197                 if (h != NULL) {
1198                         smb2_util_close(tree, *h);
1199                 }
1200
1201                 smb2_util_unlink(tree, fname);
1202
1203                 talloc_free(tree);
1204         }
1205
1206         talloc_free(mem_ctx);
1207
1208         return ret;
1209 }
1210
1211
1212 /**
1213  * basic test for doing a durable open:
1214  * tdis, new tcon, try durable reopen (fails)
1215  */
1216 static bool test_durable_open_reopen3(struct torture_context *tctx,
1217                                       struct smb2_tree *tree)
1218 {
1219         NTSTATUS status;
1220         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1221         char fname[256];
1222         struct smb2_handle _h;
1223         struct smb2_handle *h = NULL;
1224         struct smb2_create io1, io2;
1225         bool ret = true;
1226         struct smb2_tree *tree2;
1227
1228         /* Choose a random name in case the state is left a little funky. */
1229         snprintf(fname, 256, "durable_open_reopen3_%s.dat",
1230                  generate_random_str(tctx, 8));
1231
1232         smb2_util_unlink(tree, fname);
1233
1234         smb2_oplock_create_share(&io1, fname,
1235                                  smb2_util_share_access(""),
1236                                  smb2_util_oplock_level("b"));
1237         io1.in.durable_open = true;
1238
1239         status = smb2_create(tree, mem_ctx, &io1);
1240         CHECK_STATUS(status, NT_STATUS_OK);
1241         _h = io1.out.file.handle;
1242         h = &_h;
1243         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1244         CHECK_VAL(io1.out.durable_open, true);
1245         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
1246
1247         /* disconnect, reconnect and then do durable reopen */
1248         status = smb2_tdis(tree);
1249         CHECK_STATUS(status, NT_STATUS_OK);
1250
1251         if (!torture_smb2_tree_connect(tctx, tree->session, mem_ctx, &tree2)) {
1252                 torture_warning(tctx, "couldn't reconnect to share, bailing\n");
1253                 ret = false;
1254                 goto done;
1255         }
1256
1257
1258         ZERO_STRUCT(io2);
1259         io2.in.fname = fname;
1260         io2.in.durable_handle = h;
1261
1262         status = smb2_create(tree2, mem_ctx, &io2);
1263         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1264
1265 done:
1266         if (tree != NULL) {
1267                 if (h != NULL) {
1268                         smb2_util_close(tree, *h);
1269                 }
1270
1271                 smb2_util_unlink(tree2, fname);
1272
1273                 talloc_free(tree);
1274         }
1275
1276         talloc_free(mem_ctx);
1277
1278         return ret;
1279 }
1280
1281 /**
1282  * basic test for doing a durable open:
1283  * logoff, create a new session, do a durable reopen (succeeds)
1284  */
1285 static bool test_durable_open_reopen4(struct torture_context *tctx,
1286                                       struct smb2_tree *tree)
1287 {
1288         NTSTATUS status;
1289         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1290         char fname[256];
1291         struct smb2_handle _h;
1292         struct smb2_handle *h = NULL;
1293         struct smb2_create io1, io2;
1294         bool ret = true;
1295         struct smb2_transport *transport;
1296         struct smb2_session *session2;
1297         struct smb2_tree *tree2;
1298
1299         /* Choose a random name in case the state is left a little funky. */
1300         snprintf(fname, 256, "durable_open_reopen4_%s.dat",
1301                  generate_random_str(tctx, 8));
1302
1303         smb2_util_unlink(tree, fname);
1304
1305         smb2_oplock_create_share(&io1, fname,
1306                                  smb2_util_share_access(""),
1307                                  smb2_util_oplock_level("b"));
1308         io1.in.durable_open = true;
1309
1310         status = smb2_create(tree, mem_ctx, &io1);
1311         CHECK_STATUS(status, NT_STATUS_OK);
1312         _h = io1.out.file.handle;
1313         h = &_h;
1314         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1315         CHECK_VAL(io1.out.durable_open, true);
1316         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
1317
1318         /*
1319          * do a session logoff, establish a new session and tree
1320          * connect on the same transport, and try a durable reopen
1321          */
1322         transport = tree->session->transport;
1323         status = smb2_logoff(tree->session);
1324         CHECK_STATUS(status, NT_STATUS_OK);
1325
1326         if (!torture_smb2_session_setup(tctx, transport,
1327                                         0, /* previous_session_id */
1328                                         mem_ctx, &session2))
1329         {
1330                 torture_warning(tctx, "session setup failed.\n");
1331                 ret = false;
1332                 goto done;
1333         }
1334
1335         /*
1336          * the session setup has talloc-stolen the transport,
1337          * so we can safely free the old tree+session for clarity
1338          */
1339         TALLOC_FREE(tree);
1340
1341         if (!torture_smb2_tree_connect(tctx, session2, mem_ctx, &tree2)) {
1342                 torture_warning(tctx, "tree connect failed.\n");
1343                 ret = false;
1344                 goto done;
1345         }
1346
1347         ZERO_STRUCT(io2);
1348         io2.in.fname = fname;
1349         io2.in.durable_handle = h;
1350         h = NULL;
1351
1352         status = smb2_create(tree2, mem_ctx, &io2);
1353         CHECK_STATUS(status, NT_STATUS_OK);
1354
1355         _h = io2.out.file.handle;
1356         h = &_h;
1357         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1358         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
1359
1360 done:
1361         if (tree != NULL) {
1362                 if (h != NULL) {
1363                         smb2_util_close(tree2, *h);
1364                 }
1365
1366                 smb2_util_unlink(tree2, fname);
1367
1368                 talloc_free(tree);
1369         }
1370
1371         talloc_free(mem_ctx);
1372
1373         return ret;
1374 }
1375
1376 static bool test_durable_open_delete_on_close1(struct torture_context *tctx,
1377                                                struct smb2_tree *tree)
1378 {
1379         NTSTATUS status;
1380         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1381         char fname[256];
1382         struct smb2_handle _h;
1383         struct smb2_handle *h = NULL;
1384         struct smb2_create io1, io2;
1385         bool ret = true;
1386         uint8_t b = 0;
1387
1388         /* Choose a random name in case the state is left a little funky. */
1389         snprintf(fname, 256, "durable_open_delete_on_close1_%s.dat",
1390                  generate_random_str(tctx, 8));
1391
1392         smb2_util_unlink(tree, fname);
1393
1394         smb2_oplock_create_share(&io1, fname,
1395                                  smb2_util_share_access(""),
1396                                  smb2_util_oplock_level("b"));
1397         io1.in.durable_open = true;
1398         io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1399
1400         status = smb2_create(tree, mem_ctx, &io1);
1401         CHECK_STATUS(status, NT_STATUS_OK);
1402         _h = io1.out.file.handle;
1403         h = &_h;
1404         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1405         CHECK_VAL(io1.out.durable_open, true);
1406         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
1407
1408         status = smb2_util_write(tree, *h, &b, 0, 1);
1409         CHECK_STATUS(status, NT_STATUS_OK);
1410
1411         /* disconnect, leaving the durable handle in place */
1412         TALLOC_FREE(tree);
1413
1414         if (!torture_smb2_connection(tctx, &tree)) {
1415                 torture_warning(tctx, "could not reconnect, bailing\n");
1416                 ret = false;
1417                 goto done;
1418         }
1419
1420         /*
1421          * Open the file on the new connection again
1422          * and check that it has been newly created,
1423          * i.e. delete on close was effective on the disconnected handle.
1424          * Also check that the file is really empty,
1425          * the previously written byte gone.
1426          */
1427         smb2_oplock_create_share(&io2, fname,
1428                                  smb2_util_share_access(""),
1429                                  smb2_util_oplock_level("b"));
1430         io2.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1431
1432         status = smb2_create(tree, mem_ctx, &io2);
1433         CHECK_STATUS(status, NT_STATUS_OK);
1434         _h = io2.out.file.handle;
1435         h = &_h;
1436         CHECK_CREATED_SIZE(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE, 0, 0);
1437         CHECK_VAL(io2.out.durable_open, false);
1438         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
1439
1440 done:
1441         if (tree != NULL) {
1442                 if (h != NULL) {
1443                         smb2_util_close(tree, *h);
1444                 }
1445
1446                 smb2_util_unlink(tree, fname);
1447
1448                 talloc_free(tree);
1449         }
1450
1451         talloc_free(mem_ctx);
1452
1453         return ret;
1454 }
1455
1456
1457 static bool test_durable_open_delete_on_close2(struct torture_context *tctx,
1458                                                struct smb2_tree *tree)
1459 {
1460         NTSTATUS status;
1461         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1462         char fname[256];
1463         struct smb2_handle _h;
1464         struct smb2_handle *h = NULL;
1465         struct smb2_create io;
1466         bool ret = true;
1467         uint8_t b = 0;
1468         uint64_t previous_session_id;
1469         uint64_t alloc_size_step;
1470         struct smbcli_options options;
1471
1472         options = tree->session->transport->options;
1473
1474         /* Choose a random name in case the state is left a little funky. */
1475         snprintf(fname, 256, "durable_open_delete_on_close2_%s.dat",
1476                  generate_random_str(tctx, 8));
1477
1478         smb2_util_unlink(tree, fname);
1479
1480         smb2_oplock_create_share(&io, fname,
1481                                  smb2_util_share_access(""),
1482                                  smb2_util_oplock_level("b"));
1483         io.in.durable_open = true;
1484         io.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1485
1486         status = smb2_create(tree, mem_ctx, &io);
1487         CHECK_STATUS(status, NT_STATUS_OK);
1488         _h = io.out.file.handle;
1489         h = &_h;
1490         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1491         CHECK_VAL(io.out.durable_open, true);
1492         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
1493
1494         status = smb2_util_write(tree, *h, &b, 0, 1);
1495         CHECK_STATUS(status, NT_STATUS_OK);
1496
1497         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
1498
1499         /* disconnect, leaving the durable handle in place */
1500         TALLOC_FREE(tree);
1501
1502         if (!torture_smb2_connection_ext(tctx, previous_session_id,
1503                                          &options, &tree))
1504         {
1505                 torture_warning(tctx, "could not reconnect, bailing\n");
1506                 ret = false;
1507                 goto done;
1508         }
1509
1510         ZERO_STRUCT(io);
1511         io.in.fname = fname;
1512         io.in.durable_handle = h;
1513
1514         status = smb2_create(tree, mem_ctx, &io);
1515         CHECK_STATUS(status, NT_STATUS_OK);
1516         _h = io.out.file.handle;
1517         h = &_h;
1518         alloc_size_step = io.out.alloc_size;
1519         CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE, alloc_size_step, 1);
1520         CHECK_VAL(io.out.durable_open, false);
1521         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
1522
1523         /* close the file, thereby deleting it */
1524         smb2_util_close(tree, *h);
1525         status = smb2_logoff(tree->session);
1526         TALLOC_FREE(tree);
1527
1528         if (!torture_smb2_connection(tctx, &tree)) {
1529                 torture_warning(tctx, "could not reconnect, bailing\n");
1530                 ret = false;
1531                 goto done;
1532         }
1533
1534         /*
1535          * Open the file on the new connection again
1536          * and check that it has been newly created,
1537          * i.e. delete on close was effective on the reconnected handle.
1538          * Also check that the file is really empty,
1539          * the previously written byte gone.
1540          */
1541         smb2_oplock_create_share(&io, fname,
1542                                  smb2_util_share_access(""),
1543                                  smb2_util_oplock_level("b"));
1544         io.in.durable_open = true;
1545         io.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1546
1547         status = smb2_create(tree, mem_ctx, &io);
1548         CHECK_STATUS(status, NT_STATUS_OK);
1549         _h = io.out.file.handle;
1550         h = &_h;
1551         CHECK_CREATED_SIZE(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE, 0, 0);
1552         CHECK_VAL(io.out.durable_open, true);
1553         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
1554
1555 done:
1556         if (tree != NULL) {
1557                 if (h != NULL) {
1558                         smb2_util_close(tree, *h);
1559                 }
1560
1561                 smb2_util_unlink(tree, fname);
1562
1563                 talloc_free(tree);
1564         }
1565
1566         talloc_free(mem_ctx);
1567
1568         return ret;
1569 }
1570
1571 /*
1572    basic testing of SMB2 durable opens
1573    regarding the position information on the handle
1574 */
1575 static bool test_durable_open_file_position(struct torture_context *tctx,
1576                                             struct smb2_tree *tree)
1577 {
1578         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1579         struct smb2_handle h;
1580         struct smb2_create io;
1581         NTSTATUS status;
1582         const char *fname = "durable_open_position.dat";
1583         union smb_fileinfo qfinfo;
1584         union smb_setfileinfo sfinfo;
1585         bool ret = true;
1586         uint64_t pos;
1587         uint64_t previous_session_id;
1588         struct smbcli_options options;
1589
1590         options = tree->session->transport->options;
1591
1592         smb2_util_unlink(tree, fname);
1593
1594         smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_BATCH);
1595         io.in.durable_open = true;
1596
1597         status = smb2_create(tree, mem_ctx, &io);
1598         CHECK_STATUS(status, NT_STATUS_OK);
1599         h = io.out.file.handle;
1600         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1601         CHECK_VAL(io.out.durable_open, true);
1602         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1603
1604         /* TODO: check extra blob content */
1605
1606         ZERO_STRUCT(qfinfo);
1607         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
1608         qfinfo.generic.in.file.handle = h;
1609         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
1610         CHECK_STATUS(status, NT_STATUS_OK);
1611         CHECK_VAL(qfinfo.position_information.out.position, 0);
1612         pos = qfinfo.position_information.out.position;
1613         torture_comment(tctx, "position: %llu\n",
1614                         (unsigned long long)pos);
1615
1616         ZERO_STRUCT(sfinfo);
1617         sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
1618         sfinfo.generic.in.file.handle = h;
1619         sfinfo.position_information.in.position = 0x1000;
1620         status = smb2_setinfo_file(tree, &sfinfo);
1621         CHECK_STATUS(status, NT_STATUS_OK);
1622
1623         ZERO_STRUCT(qfinfo);
1624         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
1625         qfinfo.generic.in.file.handle = h;
1626         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
1627         CHECK_STATUS(status, NT_STATUS_OK);
1628         CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
1629         pos = qfinfo.position_information.out.position;
1630         torture_comment(tctx, "position: %llu\n",
1631                         (unsigned long long)pos);
1632
1633         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
1634
1635         /* tcp disconnect */
1636         talloc_free(tree);
1637         tree = NULL;
1638
1639         /* do a session reconnect */
1640         if (!torture_smb2_connection_ext(tctx, previous_session_id,
1641                                          &options, &tree))
1642         {
1643                 torture_warning(tctx, "couldn't reconnect, bailing\n");
1644                 ret = false;
1645                 goto done;
1646         }
1647
1648         ZERO_STRUCT(qfinfo);
1649         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
1650         qfinfo.generic.in.file.handle = h;
1651         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
1652         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1653
1654         ZERO_STRUCT(io);
1655         io.in.fname = fname;
1656         io.in.durable_handle = &h;
1657
1658         status = smb2_create(tree, mem_ctx, &io);
1659         CHECK_STATUS(status, NT_STATUS_OK);
1660         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1661         CHECK_VAL(io.out.reserved, 0x00);
1662         CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
1663         CHECK_VAL(io.out.alloc_size, 0);
1664         CHECK_VAL(io.out.size, 0);
1665         CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
1666         CHECK_VAL(io.out.reserved2, 0);
1667
1668         h = io.out.file.handle;
1669
1670         ZERO_STRUCT(qfinfo);
1671         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
1672         qfinfo.generic.in.file.handle = h;
1673         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
1674         CHECK_STATUS(status, NT_STATUS_OK);
1675         CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
1676         pos = qfinfo.position_information.out.position;
1677         torture_comment(tctx, "position: %llu\n",
1678                         (unsigned long long)pos);
1679
1680         smb2_util_close(tree, h);
1681
1682         talloc_free(mem_ctx);
1683
1684         smb2_util_unlink(tree, fname);
1685
1686 done:
1687         talloc_free(tree);
1688
1689         return ret;
1690 }
1691
1692 /*
1693   Open, disconnect, oplock break, reconnect.
1694 */
1695 static bool test_durable_open_oplock(struct torture_context *tctx,
1696                                      struct smb2_tree *tree1,
1697                                      struct smb2_tree *tree2)
1698 {
1699         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1700         struct smb2_create io1, io2;
1701         struct smb2_handle h1, h2;
1702         NTSTATUS status;
1703         char fname[256];
1704         bool ret = true;
1705
1706         /* Choose a random name in case the state is left a little funky. */
1707         snprintf(fname, 256, "durable_open_oplock_%s.dat", generate_random_str(tctx, 8));
1708
1709         /* Clean slate */
1710         smb2_util_unlink(tree1, fname);
1711
1712         /* Create with batch oplock */
1713         smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
1714         io1.in.durable_open = true;
1715
1716         io2 = io1;
1717         io2.in.create_disposition = NTCREATEX_DISP_OPEN;
1718
1719         status = smb2_create(tree1, mem_ctx, &io1);
1720         CHECK_STATUS(status, NT_STATUS_OK);
1721         h1 = io1.out.file.handle;
1722         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1723         CHECK_VAL(io1.out.durable_open, true);
1724         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1725
1726         /* Disconnect after getting the batch */
1727         talloc_free(tree1);
1728         tree1 = NULL;
1729
1730         /*
1731          * Windows7 (build 7000) will break a batch oplock immediately if the
1732          * original client is gone. (ZML: This seems like a bug. It should give
1733          * some time for the client to reconnect!)
1734          */
1735         status = smb2_create(tree2, mem_ctx, &io2);
1736         CHECK_STATUS(status, NT_STATUS_OK);
1737         h2 = io2.out.file.handle;
1738         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1739         CHECK_VAL(io2.out.durable_open, true);
1740         CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1741
1742         /* What if tree1 tries to come back and reclaim? */
1743         if (!torture_smb2_connection(tctx, &tree1)) {
1744                 torture_warning(tctx, "couldn't reconnect, bailing\n");
1745                 ret = false;
1746                 goto done;
1747         }
1748
1749         ZERO_STRUCT(io1);
1750         io1.in.fname = fname;
1751         io1.in.durable_handle = &h1;
1752
1753         status = smb2_create(tree1, mem_ctx, &io1);
1754         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1755
1756  done:
1757         smb2_util_close(tree2, h2);
1758         smb2_util_unlink(tree2, fname);
1759
1760         talloc_free(tree1);
1761         talloc_free(tree2);
1762
1763         return ret;
1764 }
1765
1766 /*
1767   Open, disconnect, lease break, reconnect.
1768 */
1769 static bool test_durable_open_lease(struct torture_context *tctx,
1770                                     struct smb2_tree *tree1,
1771                                     struct smb2_tree *tree2)
1772 {
1773         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1774         struct smb2_create io1, io2;
1775         struct smb2_lease ls1, ls2;
1776         struct smb2_handle h1, h2;
1777         NTSTATUS status;
1778         char fname[256];
1779         bool ret = true;
1780         uint64_t lease1, lease2;
1781         uint32_t caps;
1782
1783         caps = smb2cli_conn_server_capabilities(tree1->session->transport->conn);
1784         if (!(caps & SMB2_CAP_LEASING)) {
1785                 torture_skip(tctx, "leases are not supported");
1786         }
1787
1788         /*
1789          * Choose a random name and random lease in case the state is left a
1790          * little funky.
1791          */
1792         lease1 = random();
1793         lease2 = random();
1794         snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
1795
1796         /* Clean slate */
1797         smb2_util_unlink(tree1, fname);
1798
1799         /* Create with lease */
1800         smb2_lease_create(&io1, &ls1, false /* dir */, fname,
1801                           lease1, smb2_util_lease_state("RHW"));
1802         io1.in.durable_open = true;
1803
1804         smb2_lease_create(&io2, &ls2, false /* dir */, fname,
1805                           lease2, smb2_util_lease_state("RHW"));
1806         io2.in.durable_open = true;
1807         io2.in.create_disposition = NTCREATEX_DISP_OPEN;
1808
1809         status = smb2_create(tree1, mem_ctx, &io1);
1810         CHECK_STATUS(status, NT_STATUS_OK);
1811         h1 = io1.out.file.handle;
1812         CHECK_VAL(io1.out.durable_open, true);
1813         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1814
1815         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1816         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease1);
1817         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease1);
1818         CHECK_VAL(io1.out.lease_response.lease_state,
1819             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
1820
1821         /* Disconnect after getting the lease */
1822         talloc_free(tree1);
1823         tree1 = NULL;
1824
1825         /*
1826          * Windows7 (build 7000) will grant an RH lease immediate (not an RHW?)
1827          * even if the original client is gone. (ZML: This seems like a bug. It
1828          * should give some time for the client to reconnect! And why RH?)
1829          * 
1830          * obnox: Current windows 7 and w2k8r2 grant RHW instead of RH.
1831          * Test is adapted accordingly.
1832          */
1833         status = smb2_create(tree2, mem_ctx, &io2);
1834         CHECK_STATUS(status, NT_STATUS_OK);
1835         h2 = io2.out.file.handle;
1836         CHECK_VAL(io2.out.durable_open, true);
1837         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1838
1839         CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1840         CHECK_VAL(io2.out.lease_response.lease_key.data[0], lease2);
1841         CHECK_VAL(io2.out.lease_response.lease_key.data[1], ~lease2);
1842         CHECK_VAL(io2.out.lease_response.lease_state,
1843             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
1844
1845         /* What if tree1 tries to come back and reclaim? */
1846         if (!torture_smb2_connection(tctx, &tree1)) {
1847                 torture_warning(tctx, "couldn't reconnect, bailing\n");
1848                 ret = false;
1849                 goto done;
1850         }
1851
1852         ZERO_STRUCT(io1);
1853         io1.in.fname = fname;
1854         io1.in.durable_handle = &h1;
1855         io1.in.lease_request = &ls1;
1856
1857         status = smb2_create(tree1, mem_ctx, &io1);
1858         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1859
1860  done:
1861         smb2_util_close(tree2, h2);
1862         smb2_util_unlink(tree2, fname);
1863
1864         talloc_free(tree1);
1865         talloc_free(tree2);
1866
1867         return ret;
1868 }
1869
1870 static bool test_durable_open_lock_oplock(struct torture_context *tctx,
1871                                           struct smb2_tree *tree)
1872 {
1873         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1874         struct smb2_create io;
1875         struct smb2_handle h;
1876         struct smb2_lock lck;
1877         struct smb2_lock_element el[2];
1878         NTSTATUS status;
1879         char fname[256];
1880         bool ret = true;
1881
1882         /*
1883          */
1884         snprintf(fname, 256, "durable_open_oplock_lock_%s.dat", generate_random_str(tctx, 8));
1885
1886         /* Clean slate */
1887         smb2_util_unlink(tree, fname);
1888
1889         /* Create with oplock */
1890
1891         smb2_oplock_create_share(&io, fname,
1892                                  smb2_util_share_access(""),
1893                                  smb2_util_oplock_level("b"));
1894         io.in.durable_open = true;
1895
1896         status = smb2_create(tree, mem_ctx, &io);
1897         CHECK_STATUS(status, NT_STATUS_OK);
1898         h = io.out.file.handle;
1899         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1900
1901         CHECK_VAL(io.out.durable_open, true);
1902         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
1903
1904         ZERO_STRUCT(lck);
1905         ZERO_STRUCT(el);
1906         lck.in.locks            = el;
1907         lck.in.lock_count       = 0x0001;
1908         lck.in.lock_sequence    = 0x00000000;
1909         lck.in.file.handle      = h;
1910         el[0].offset            = 0;
1911         el[0].length            = 1;
1912         el[0].reserved          = 0x00000000;
1913         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
1914         status = smb2_lock(tree, &lck);
1915         CHECK_STATUS(status, NT_STATUS_OK);
1916
1917         /* Disconnect/Reconnect. */
1918         talloc_free(tree);
1919         tree = NULL;
1920
1921         if (!torture_smb2_connection(tctx, &tree)) {
1922                 torture_warning(tctx, "couldn't reconnect, bailing\n");
1923                 ret = false;
1924                 goto done;
1925         }
1926
1927         ZERO_STRUCT(io);
1928         io.in.fname = fname;
1929         io.in.durable_handle = &h;
1930
1931         status = smb2_create(tree, mem_ctx, &io);
1932         CHECK_STATUS(status, NT_STATUS_OK);
1933         h = io.out.file.handle;
1934
1935         lck.in.file.handle      = h;
1936         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
1937         status = smb2_lock(tree, &lck);
1938         CHECK_STATUS(status, NT_STATUS_OK);
1939
1940  done:
1941         smb2_util_close(tree, h);
1942         smb2_util_unlink(tree, fname);
1943         talloc_free(tree);
1944
1945         return ret;
1946 }
1947
1948 /*
1949   Open, take BRL, disconnect, reconnect.
1950 */
1951 static bool test_durable_open_lock_lease(struct torture_context *tctx,
1952                                          struct smb2_tree *tree)
1953 {
1954         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1955         struct smb2_create io;
1956         struct smb2_lease ls;
1957         struct smb2_handle h;
1958         struct smb2_lock lck;
1959         struct smb2_lock_element el[2];
1960         NTSTATUS status;
1961         char fname[256];
1962         bool ret = true;
1963         uint64_t lease;
1964         uint32_t caps;
1965         struct smbcli_options options;
1966
1967         options = tree->session->transport->options;
1968
1969         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1970         if (!(caps & SMB2_CAP_LEASING)) {
1971                 torture_skip(tctx, "leases are not supported");
1972         }
1973
1974         /*
1975          * Choose a random name and random lease in case the state is left a
1976          * little funky.
1977          */
1978         lease = random();
1979         snprintf(fname, 256, "durable_open_lease_lock_%s.dat", generate_random_str(tctx, 8));
1980
1981         /* Clean slate */
1982         smb2_util_unlink(tree, fname);
1983
1984         /* Create with lease */
1985
1986         smb2_lease_create(&io, &ls, false /* dir */, fname, lease,
1987                           smb2_util_lease_state("RWH"));
1988         io.in.durable_open              = true;
1989
1990         status = smb2_create(tree, mem_ctx, &io);
1991         CHECK_STATUS(status, NT_STATUS_OK);
1992         h = io.out.file.handle;
1993         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1994
1995         CHECK_VAL(io.out.durable_open, true);
1996         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1997         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
1998         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
1999         CHECK_VAL(io.out.lease_response.lease_state,
2000             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
2001
2002         ZERO_STRUCT(lck);
2003         ZERO_STRUCT(el);
2004         lck.in.locks            = el;
2005         lck.in.lock_count       = 0x0001;
2006         lck.in.lock_sequence    = 0x00000000;
2007         lck.in.file.handle      = h;
2008         el[0].offset            = 0;
2009         el[0].length            = 1;
2010         el[0].reserved          = 0x00000000;
2011         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
2012         status = smb2_lock(tree, &lck);
2013         CHECK_STATUS(status, NT_STATUS_OK);
2014
2015         /* Disconnect/Reconnect. */
2016         talloc_free(tree);
2017         tree = NULL;
2018
2019         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
2020                 torture_warning(tctx, "couldn't reconnect, bailing\n");
2021                 ret = false;
2022                 goto done;
2023         }
2024
2025         ZERO_STRUCT(io);
2026         io.in.fname = fname;
2027         io.in.durable_handle = &h;
2028         io.in.lease_request = &ls;
2029
2030         status = smb2_create(tree, mem_ctx, &io);
2031         CHECK_STATUS(status, NT_STATUS_OK);
2032         h = io.out.file.handle;
2033
2034         lck.in.file.handle      = h;
2035         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
2036         status = smb2_lock(tree, &lck);
2037         CHECK_STATUS(status, NT_STATUS_OK);
2038
2039  done:
2040         smb2_util_close(tree, h);
2041         smb2_util_unlink(tree, fname);
2042         talloc_free(tree);
2043
2044         return ret;
2045 }
2046
2047 /**
2048  * Open with a RH lease, disconnect, open in another tree, reconnect.
2049  *
2050  * This test actually demonstrates a minimum level of respect for the durable
2051  * open in the face of another open. As long as this test shows an inability to
2052  * reconnect after an open, the oplock/lease tests above will certainly
2053  * demonstrate an error on reconnect.
2054  */
2055 static bool test_durable_open_open2_lease(struct torture_context *tctx,
2056                                           struct smb2_tree *tree1,
2057                                           struct smb2_tree *tree2)
2058 {
2059         TALLOC_CTX *mem_ctx = talloc_new(tctx);
2060         struct smb2_create io1, io2;
2061         struct smb2_lease ls;
2062         struct smb2_handle h1, h2;
2063         NTSTATUS status;
2064         char fname[256];
2065         bool ret = true;
2066         uint64_t lease;
2067         uint32_t caps;
2068         struct smbcli_options options;
2069
2070         options = tree1->session->transport->options;
2071
2072         caps = smb2cli_conn_server_capabilities(tree1->session->transport->conn);
2073         if (!(caps & SMB2_CAP_LEASING)) {
2074                 torture_skip(tctx, "leases are not supported");
2075         }
2076
2077         /*
2078          * Choose a random name and random lease in case the state is left a
2079          * little funky.
2080          */
2081         lease = random();
2082         snprintf(fname, 256, "durable_open_open2_lease_%s.dat",
2083                  generate_random_str(tctx, 8));
2084
2085         /* Clean slate */
2086         smb2_util_unlink(tree1, fname);
2087
2088         /* Create with lease */
2089         smb2_lease_create_share(&io1, &ls, false /* dir */, fname,
2090                                 smb2_util_share_access(""),
2091                                 lease,
2092                                 smb2_util_lease_state("RH"));
2093         io1.in.durable_open = true;
2094
2095         status = smb2_create(tree1, mem_ctx, &io1);
2096         CHECK_STATUS(status, NT_STATUS_OK);
2097         h1 = io1.out.file.handle;
2098         CHECK_VAL(io1.out.durable_open, true);
2099         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2100
2101         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
2102         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease);
2103         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease);
2104         CHECK_VAL(io1.out.lease_response.lease_state,
2105                   smb2_util_lease_state("RH"));
2106
2107         /* Disconnect */
2108         talloc_free(tree1);
2109         tree1 = NULL;
2110
2111         /* Open the file in tree2 */
2112         smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2113
2114         status = smb2_create(tree2, mem_ctx, &io2);
2115         CHECK_STATUS(status, NT_STATUS_OK);
2116         h2 = io2.out.file.handle;
2117         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2118
2119         /* Reconnect */
2120         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree1)) {
2121                 torture_warning(tctx, "couldn't reconnect, bailing\n");
2122                 ret = false;
2123                 goto done;
2124         }
2125
2126         ZERO_STRUCT(io1);
2127         io1.in.fname = fname;
2128         io1.in.durable_handle = &h1;
2129         io1.in.lease_request = &ls;
2130
2131         /*
2132          * Windows7 (build 7000) will give away an open immediately if the
2133          * original client is gone. (ZML: This seems like a bug. It should give
2134          * some time for the client to reconnect!)
2135          */
2136         status = smb2_create(tree1, mem_ctx, &io1);
2137         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
2138         h1 = io1.out.file.handle;
2139
2140  done:
2141         if (tree1 != NULL){
2142                 smb2_util_close(tree1, h1);
2143                 smb2_util_unlink(tree1, fname);
2144                 talloc_free(tree1);
2145         }
2146
2147         smb2_util_close(tree2, h2);
2148         smb2_util_unlink(tree2, fname);
2149         talloc_free(tree2);
2150
2151         return ret;
2152 }
2153
2154 /**
2155  * Open with a batch oplock, disconnect, open in another tree, reconnect.
2156  *
2157  * This test actually demonstrates a minimum level of respect for the durable
2158  * open in the face of another open. As long as this test shows an inability to
2159  * reconnect after an open, the oplock/lease tests above will certainly
2160  * demonstrate an error on reconnect.
2161  */
2162 static bool test_durable_open_open2_oplock(struct torture_context *tctx,
2163                                            struct smb2_tree *tree1,
2164                                            struct smb2_tree *tree2)
2165 {
2166         TALLOC_CTX *mem_ctx = talloc_new(tctx);
2167         struct smb2_create io1, io2;
2168         struct smb2_handle h1, h2;
2169         NTSTATUS status;
2170         char fname[256];
2171         bool ret = true;
2172
2173         /*
2174          * Choose a random name and random lease in case the state is left a
2175          * little funky.
2176          */
2177         snprintf(fname, 256, "durable_open_open2_oplock_%s.dat",
2178                  generate_random_str(tctx, 8));
2179
2180         /* Clean slate */
2181         smb2_util_unlink(tree1, fname);
2182
2183         /* Create with batch oplock */
2184         smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
2185         io1.in.durable_open = true;
2186
2187         status = smb2_create(tree1, mem_ctx, &io1);
2188         CHECK_STATUS(status, NT_STATUS_OK);
2189         h1 = io1.out.file.handle;
2190         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2191         CHECK_VAL(io1.out.durable_open, true);
2192         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2193
2194         /* Disconnect */
2195         talloc_free(tree1);
2196         tree1 = NULL;
2197
2198         /* Open the file in tree2 */
2199         smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2200
2201         status = smb2_create(tree2, mem_ctx, &io2);
2202         CHECK_STATUS(status, NT_STATUS_OK);
2203         h2 = io2.out.file.handle;
2204         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2205
2206         /* Reconnect */
2207         if (!torture_smb2_connection(tctx, &tree1)) {
2208                 torture_warning(tctx, "couldn't reconnect, bailing\n");
2209                 ret = false;
2210                 goto done;
2211         }
2212
2213         ZERO_STRUCT(io1);
2214         io1.in.fname = fname;
2215         io1.in.durable_handle = &h1;
2216
2217         status = smb2_create(tree1, mem_ctx, &io1);
2218         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
2219         h1 = io1.out.file.handle;
2220
2221  done:
2222         smb2_util_close(tree2, h2);
2223         smb2_util_unlink(tree2, fname);
2224         if (tree1 != NULL) {
2225                 smb2_util_close(tree1, h1);
2226                 smb2_util_unlink(tree1, fname);
2227         }
2228
2229         talloc_free(tree1);
2230         talloc_free(tree2);
2231
2232         return ret;
2233 }
2234
2235 /**
2236  * test behaviour with initial allocation size
2237  */
2238 static bool test_durable_open_alloc_size(struct torture_context *tctx,
2239                                          struct smb2_tree *tree)
2240 {
2241         NTSTATUS status;
2242         TALLOC_CTX *mem_ctx = talloc_new(tctx);
2243         char fname[256];
2244         struct smb2_handle _h;
2245         struct smb2_handle *h = NULL;
2246         struct smb2_create io;
2247         bool ret = true;
2248         uint64_t previous_session_id;
2249         uint64_t alloc_size_step;
2250         uint64_t initial_alloc_size = 0x100;
2251         const uint8_t *b = NULL;
2252         struct smbcli_options options;
2253
2254         options = tree->session->transport->options;
2255
2256         /* Choose a random name in case the state is left a little funky. */
2257         snprintf(fname, 256, "durable_open_alloc_size_%s.dat",
2258                  generate_random_str(tctx, 8));
2259
2260         smb2_util_unlink(tree, fname);
2261
2262         smb2_oplock_create_share(&io, fname,
2263                                  smb2_util_share_access(""),
2264                                  smb2_util_oplock_level("b"));
2265         io.in.durable_open = true;
2266         io.in.alloc_size = initial_alloc_size;
2267
2268         status = smb2_create(tree, mem_ctx, &io);
2269         CHECK_STATUS(status, NT_STATUS_OK);
2270         _h = io.out.file.handle;
2271         h = &_h;
2272         CHECK_NOT_VAL(io.out.alloc_size, 0);
2273         alloc_size_step = io.out.alloc_size;
2274         CHECK_CREATED_SIZE(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE,
2275                            alloc_size_step, 0);
2276         CHECK_VAL(io.out.durable_open, true);
2277         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2278
2279         /* prepare buffer */
2280         b = talloc_zero_size(mem_ctx, alloc_size_step);
2281         CHECK_NOT_NULL(b);
2282
2283         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
2284
2285         /* disconnect, reconnect and then do durable reopen */
2286         talloc_free(tree);
2287         tree = NULL;
2288
2289         if (!torture_smb2_connection_ext(tctx, previous_session_id,
2290                                          &options, &tree))
2291         {
2292                 torture_warning(tctx, "couldn't reconnect, bailing\n");
2293                 ret = false;
2294                 goto done;
2295         }
2296
2297         ZERO_STRUCT(io);
2298         io.in.fname = fname;
2299         io.in.durable_handle = h;
2300         h = NULL;
2301
2302         status = smb2_create(tree, mem_ctx, &io);
2303         CHECK_STATUS(status, NT_STATUS_OK);
2304         CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
2305                            alloc_size_step, 0);
2306         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2307         _h = io.out.file.handle;
2308         h = &_h;
2309
2310         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
2311
2312         /* write one byte */
2313         status = smb2_util_write(tree, *h, b, 0, 1);
2314         CHECK_STATUS(status, NT_STATUS_OK);
2315
2316         /* disconnect, reconnect and then do durable reopen */
2317         talloc_free(tree);
2318         tree = NULL;
2319
2320         if (!torture_smb2_connection_ext(tctx, previous_session_id,
2321                                          &options, &tree))
2322         {
2323                 torture_warning(tctx, "couldn't reconnect, bailing\n");
2324                 ret = false;
2325                 goto done;
2326         }
2327
2328         ZERO_STRUCT(io);
2329         io.in.fname = fname;
2330         io.in.durable_handle = h;
2331         h = NULL;
2332
2333         status = smb2_create(tree, mem_ctx, &io);
2334         CHECK_STATUS(status, NT_STATUS_OK);
2335         CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
2336                            alloc_size_step, 1);
2337         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2338         _h = io.out.file.handle;
2339         h = &_h;
2340
2341         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
2342
2343         /* write more byte than initial allocation size */
2344         status = smb2_util_write(tree, *h, b, 1, alloc_size_step);
2345
2346         /* disconnect, reconnect and then do durable reopen */
2347         talloc_free(tree);
2348         tree = NULL;
2349
2350         if (!torture_smb2_connection_ext(tctx, previous_session_id,
2351                                          &options, &tree))
2352         {
2353                 torture_warning(tctx, "couldn't reconnect, bailing\n");
2354                 ret = false;
2355                 goto done;
2356         }
2357
2358         ZERO_STRUCT(io);
2359         io.in.fname = fname;
2360         io.in.durable_handle = h;
2361         h = NULL;
2362
2363         status = smb2_create(tree, mem_ctx, &io);
2364         CHECK_STATUS(status, NT_STATUS_OK);
2365         CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
2366                            alloc_size_step * 2, alloc_size_step + 1);
2367         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2368         _h = io.out.file.handle;
2369         h = &_h;
2370
2371 done:
2372         if (h != NULL) {
2373                 smb2_util_close(tree, *h);
2374         }
2375
2376         smb2_util_unlink(tree, fname);
2377
2378         talloc_free(tree);
2379
2380         talloc_free(mem_ctx);
2381
2382         return ret;
2383 }
2384
2385 /**
2386  * test behaviour when a disconnect happens while creating a read-only file
2387  */
2388 static bool test_durable_open_read_only(struct torture_context *tctx,
2389                                         struct smb2_tree *tree)
2390 {
2391         NTSTATUS status;
2392         TALLOC_CTX *mem_ctx = talloc_new(tctx);
2393         char fname[256];
2394         struct smb2_handle _h;
2395         struct smb2_handle *h = NULL;
2396         struct smb2_create io;
2397         bool ret = true;
2398         uint64_t previous_session_id;
2399         const uint8_t b = 0;
2400         uint64_t alloc_size = 0;
2401         struct smbcli_options options;
2402
2403         options = tree->session->transport->options;
2404
2405         /* Choose a random name in case the state is left a little funky. */
2406         snprintf(fname, 256, "durable_open_initial_alloc_%s.dat",
2407                  generate_random_str(tctx, 8));
2408
2409         smb2_util_unlink(tree, fname);
2410
2411         smb2_oplock_create_share(&io, fname,
2412                                  smb2_util_share_access(""),
2413                                  smb2_util_oplock_level("b"));
2414         io.in.durable_open = true;
2415         io.in.file_attributes = FILE_ATTRIBUTE_READONLY;
2416
2417         status = smb2_create(tree, mem_ctx, &io);
2418         CHECK_STATUS(status, NT_STATUS_OK);
2419         _h = io.out.file.handle;
2420         h = &_h;
2421         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE);
2422         CHECK_VAL(io.out.durable_open, true);
2423         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2424
2425         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
2426
2427         /* write one byte */
2428         status = smb2_util_write(tree, *h, &b, 0, 1);
2429         CHECK_STATUS(status, NT_STATUS_OK);
2430
2431         /* disconnect, reconnect and then do durable reopen */
2432         talloc_free(tree);
2433         tree = NULL;
2434
2435         if (!torture_smb2_connection_ext(tctx, previous_session_id,
2436                                          &options, &tree))
2437         {
2438                 torture_warning(tctx, "couldn't reconnect, bailing\n");
2439                 ret = false;
2440                 goto done;
2441         }
2442
2443         ZERO_STRUCT(io);
2444         io.in.fname = fname;
2445         io.in.durable_handle = h;
2446         h = NULL;
2447
2448         status = smb2_create(tree, mem_ctx, &io);
2449         CHECK_STATUS(status, NT_STATUS_OK);
2450         alloc_size = io.out.alloc_size;
2451         CHECK_CREATED_SIZE(&io, EXISTED,
2452                            FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE,
2453                            alloc_size, 1);
2454         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2455         _h = io.out.file.handle;
2456         h = &_h;
2457
2458         /* write one byte */
2459         status = smb2_util_write(tree, *h, &b, 1, 1);
2460         CHECK_STATUS(status, NT_STATUS_OK);
2461
2462 done:
2463         if (h != NULL) {
2464                 union smb_setfileinfo sfinfo;
2465
2466                 ZERO_STRUCT(sfinfo);
2467                 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
2468                 sfinfo.basic_info.in.file.handle = *h;
2469                 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
2470                 smb2_setinfo_file(tree, &sfinfo);
2471
2472                 smb2_util_close(tree, *h);
2473         }
2474
2475         smb2_util_unlink(tree, fname);
2476
2477         talloc_free(tree);
2478
2479         talloc_free(mem_ctx);
2480
2481         return ret;
2482 }
2483
2484 /**
2485  * durable open with oplock, disconnect, exit
2486  */
2487 static bool test_durable_open_oplock_disconnect(struct torture_context *tctx,
2488                                                 struct smb2_tree *tree)
2489 {
2490         TALLOC_CTX *mem_ctx = talloc_new(tctx);
2491         struct smb2_create io;
2492         struct smb2_handle _h;
2493         struct smb2_handle *h = NULL;
2494         NTSTATUS status;
2495         char fname[256];
2496         bool ret = true;
2497
2498         snprintf(fname, 256, "durable_open_oplock_disconnect_%s.dat",
2499                  generate_random_str(mem_ctx, 8));
2500
2501         smb2_util_unlink(tree, fname);
2502
2503         smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_BATCH);
2504         io.in.durable_open = true;
2505
2506         status = smb2_create(tree, mem_ctx, &io);
2507         CHECK_STATUS(status, NT_STATUS_OK);
2508
2509         _h = io.out.file.handle;
2510         h = &_h;
2511
2512         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2513         CHECK_VAL(io.out.durable_open, true);
2514         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2515
2516         /* disconnect */
2517         talloc_free(tree);
2518         tree = NULL;
2519
2520 done:
2521         if (tree != NULL) {
2522                 if (h != NULL) {
2523                         smb2_util_close(tree, *h);
2524                 }
2525                 smb2_util_unlink(tree, fname);
2526         }
2527         talloc_free(mem_ctx);
2528         return ret;
2529 }
2530
2531
2532 struct torture_suite *torture_smb2_durable_open_init(void)
2533 {
2534         struct torture_suite *suite =
2535             torture_suite_create(talloc_autofree_context(), "durable-open");
2536
2537         torture_suite_add_1smb2_test(suite, "open-oplock", test_durable_open_open_oplock);
2538         torture_suite_add_1smb2_test(suite, "open-lease", test_durable_open_open_lease);
2539         torture_suite_add_1smb2_test(suite, "reopen1", test_durable_open_reopen1);
2540         torture_suite_add_1smb2_test(suite, "reopen1a", test_durable_open_reopen1a);
2541         torture_suite_add_1smb2_test(suite, "reopen2", test_durable_open_reopen2);
2542         torture_suite_add_1smb2_test(suite, "reopen2-lease", test_durable_open_reopen2_lease);
2543         torture_suite_add_1smb2_test(suite, "reopen2-lease-v2", test_durable_open_reopen2_lease_v2);
2544         torture_suite_add_1smb2_test(suite, "reopen2a", test_durable_open_reopen2a);
2545         torture_suite_add_1smb2_test(suite, "reopen3", test_durable_open_reopen3);
2546         torture_suite_add_1smb2_test(suite, "reopen4", test_durable_open_reopen4);
2547         torture_suite_add_1smb2_test(suite, "delete_on_close1",
2548                                      test_durable_open_delete_on_close1);
2549         torture_suite_add_1smb2_test(suite, "delete_on_close2",
2550                                      test_durable_open_delete_on_close2);
2551         torture_suite_add_1smb2_test(suite, "file-position",
2552             test_durable_open_file_position);
2553         torture_suite_add_2smb2_test(suite, "oplock", test_durable_open_oplock);
2554         torture_suite_add_2smb2_test(suite, "lease", test_durable_open_lease);
2555         torture_suite_add_1smb2_test(suite, "lock-oplock", test_durable_open_lock_oplock);
2556         torture_suite_add_1smb2_test(suite, "lock-lease", test_durable_open_lock_lease);
2557         torture_suite_add_2smb2_test(suite, "open2-lease",
2558                                      test_durable_open_open2_lease);
2559         torture_suite_add_2smb2_test(suite, "open2-oplock",
2560                                      test_durable_open_open2_oplock);
2561         torture_suite_add_1smb2_test(suite, "alloc-size",
2562                                      test_durable_open_alloc_size);
2563         torture_suite_add_1smb2_test(suite, "read-only",
2564                                      test_durable_open_read_only);
2565
2566         suite->description = talloc_strdup(suite, "SMB2-DURABLE-OPEN tests");
2567
2568         return suite;
2569 }
2570
2571 struct torture_suite *torture_smb2_durable_open_disconnect_init(void)
2572 {
2573         struct torture_suite *suite =
2574             torture_suite_create(talloc_autofree_context(),
2575                                  "durable-open-disconnect");
2576
2577         torture_suite_add_1smb2_test(suite, "open-oplock-disconnect",
2578                                      test_durable_open_oplock_disconnect);
2579
2580         suite->description = talloc_strdup(suite,
2581                                         "SMB2-DURABLE-OPEN-DISCONNECT tests");
2582
2583         return suite;
2584 }