s4-smbtorture: Make test names lowercase and dot-separated.
[metze/samba/wip.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
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25 #include "torture/torture.h"
26 #include "torture/smb2/proto.h"
27
28 #define CHECK_VAL(v, correct) do { \
29         if ((v) != (correct)) { \
30                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
31                                 __location__, #v, (int)v, (int)correct); \
32                 ret = false; \
33         }} while (0)
34
35 #define CHECK_STATUS(status, correct) do { \
36         if (!NT_STATUS_EQUAL(status, correct)) { \
37                 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
38                        nt_errstr(status), nt_errstr(correct)); \
39                 ret = false; \
40                 goto done; \
41         }} while (0)
42
43 #define CHECK_CREATED(__io, __created, __attribute)                     \
44         do {                                                            \
45                 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
46                 CHECK_VAL((__io)->out.alloc_size, 0);                   \
47                 CHECK_VAL((__io)->out.size, 0);                         \
48                 CHECK_VAL((__io)->out.file_attr, (__attribute));        \
49                 CHECK_VAL((__io)->out.reserved2, 0);                    \
50         } while(0)
51
52 /*
53    basic testing of SMB2 durable opens
54    regarding the position information on the handle
55 */
56 bool test_durable_open_file_position(struct torture_context *tctx,
57                                      struct smb2_tree *tree1,
58                                      struct smb2_tree *tree2)
59 {
60         TALLOC_CTX *mem_ctx = talloc_new(tctx);
61         struct smb2_handle h1, h2;
62         struct smb2_create io1, io2;
63         NTSTATUS status;
64         const char *fname = "durable_open_position.dat";
65         union smb_fileinfo qfinfo;
66         union smb_setfileinfo sfinfo;
67         bool ret = true;
68         uint64_t pos;
69
70         smb2_util_unlink(tree1, fname);
71
72         ZERO_STRUCT(io1);
73         io1.in.security_flags           = 0x00;
74         io1.in.oplock_level             = SMB2_OPLOCK_LEVEL_BATCH;
75         io1.in.impersonation_level      = NTCREATEX_IMPERSONATION_IMPERSONATION;
76         io1.in.create_flags             = 0x00000000;
77         io1.in.reserved                 = 0x00000000;
78         io1.in.desired_access           = SEC_RIGHTS_FILE_ALL;
79         io1.in.file_attributes          = FILE_ATTRIBUTE_NORMAL;
80         io1.in.share_access             = NTCREATEX_SHARE_ACCESS_READ |
81                                           NTCREATEX_SHARE_ACCESS_WRITE |
82                                           NTCREATEX_SHARE_ACCESS_DELETE;
83         io1.in.create_disposition       = NTCREATEX_DISP_OPEN_IF;
84         io1.in.create_options           = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
85                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
86                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
87                                           0x00200000;
88         io1.in.durable_open             = true;
89         io1.in.fname                    = fname;
90
91         status = smb2_create(tree1, mem_ctx, &io1);
92         CHECK_STATUS(status, NT_STATUS_OK);
93         h1 = io1.out.file.handle;
94         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
95         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
96
97         /* TODO: check extra blob content */
98
99         ZERO_STRUCT(qfinfo);
100         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
101         qfinfo.generic.in.file.handle = h1;
102         status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
103         CHECK_STATUS(status, NT_STATUS_OK);
104         CHECK_VAL(qfinfo.position_information.out.position, 0);
105         pos = qfinfo.position_information.out.position;
106         torture_comment(tctx, "position: %llu\n",
107                         (unsigned long long)pos);
108
109         ZERO_STRUCT(sfinfo);
110         sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
111         sfinfo.generic.in.file.handle = h1;
112         sfinfo.position_information.in.position = 0x1000;
113         status = smb2_setinfo_file(tree1, &sfinfo);
114         CHECK_STATUS(status, NT_STATUS_OK);
115
116         ZERO_STRUCT(qfinfo);
117         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
118         qfinfo.generic.in.file.handle = h1;
119         status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
120         CHECK_STATUS(status, NT_STATUS_OK);
121         CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
122         pos = qfinfo.position_information.out.position;
123         torture_comment(tctx, "position: %llu\n",
124                         (unsigned long long)pos);
125
126         talloc_free(tree1);
127         tree1 = NULL;
128
129         ZERO_STRUCT(qfinfo);
130         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
131         qfinfo.generic.in.file.handle = h1;
132         status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
133         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
134
135         ZERO_STRUCT(io2);
136         io2.in.fname = fname;
137         io2.in.durable_handle = &h1;
138
139         status = smb2_create(tree2, mem_ctx, &io2);
140         CHECK_STATUS(status, NT_STATUS_OK);
141         CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
142         CHECK_VAL(io2.out.reserved, 0x00);
143         CHECK_VAL(io2.out.create_action, NTCREATEX_ACTION_EXISTED);
144         CHECK_VAL(io2.out.alloc_size, 0);
145         CHECK_VAL(io2.out.size, 0);
146         CHECK_VAL(io2.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
147         CHECK_VAL(io2.out.reserved2, 0);
148
149         h2 = io2.out.file.handle;
150
151         ZERO_STRUCT(qfinfo);
152         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
153         qfinfo.generic.in.file.handle = h2;
154         status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
155         CHECK_STATUS(status, NT_STATUS_OK);
156         CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
157         pos = qfinfo.position_information.out.position;
158         torture_comment(tctx, "position: %llu\n",
159                         (unsigned long long)pos);
160
161         smb2_util_close(tree2, h2);
162
163         talloc_free(mem_ctx);
164
165         smb2_util_unlink(tree2, fname);
166 done:
167         return ret;
168 }
169
170 /*
171   Open, disconnect, oplock break, reconnect.
172 */
173 bool test_durable_open_oplock(struct torture_context *tctx,
174                               struct smb2_tree *tree1,
175                               struct smb2_tree *tree2)
176 {
177         TALLOC_CTX *mem_ctx = talloc_new(tctx);
178         struct smb2_create io1, io2;
179         struct smb2_handle h1, h2;
180         NTSTATUS status;
181         char fname[256];
182         bool ret = true;
183
184         /* Choose a random name in case the state is left a little funky. */
185         snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
186
187         /* Clean slate */
188         smb2_util_unlink(tree1, fname);
189
190         /* Create with batch oplock */
191         ZERO_STRUCT(io1);
192         io1.in.security_flags           = 0x00;
193         io1.in.oplock_level             = SMB2_OPLOCK_LEVEL_BATCH;
194         io1.in.impersonation_level      = NTCREATEX_IMPERSONATION_IMPERSONATION;
195         io1.in.create_flags             = 0x00000000;
196         io1.in.reserved                 = 0x00000000;
197         io1.in.desired_access           = SEC_RIGHTS_FILE_ALL;
198         io1.in.file_attributes          = FILE_ATTRIBUTE_NORMAL;
199         io1.in.share_access             = NTCREATEX_SHARE_ACCESS_READ |
200                                           NTCREATEX_SHARE_ACCESS_WRITE |
201                                           NTCREATEX_SHARE_ACCESS_DELETE;
202         io1.in.create_disposition       = NTCREATEX_DISP_OPEN_IF;
203         io1.in.create_options           = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
204                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
205                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
206                                           0x00200000;
207         io1.in.fname                    = fname;
208         io1.in.durable_open             = true;
209
210         io2 = io1;
211         io2.in.create_disposition       = NTCREATEX_DISP_OPEN;
212
213         status = smb2_create(tree1, mem_ctx, &io1);
214         CHECK_STATUS(status, NT_STATUS_OK);
215         h1 = io1.out.file.handle;
216         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
217         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
218
219         /* Disconnect after getting the batch */
220         talloc_free(tree1);
221         tree1 = NULL;
222
223         /*
224          * Windows7 (build 7000) will break a batch oplock immediately if the
225          * original client is gone. (ZML: This seems like a bug. It should give
226          * some time for the client to reconnect!)
227          */
228         status = smb2_create(tree2, mem_ctx, &io2);
229         CHECK_STATUS(status, NT_STATUS_OK);
230         h2 = io2.out.file.handle;
231         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
232         CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
233
234         /* What if tree1 tries to come back and reclaim? */
235         if (!torture_smb2_connection(tctx, &tree1)) {
236                 torture_warning(tctx, "couldn't reconnect, bailing\n");
237                 ret = false;
238                 goto done;
239         }
240
241         ZERO_STRUCT(io1);
242         io1.in.fname = fname;
243         io1.in.durable_handle = &h1;
244
245         status = smb2_create(tree1, mem_ctx, &io1);
246         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
247
248  done:
249         smb2_util_close(tree2, h2);
250         smb2_util_unlink(tree2, fname);
251
252         return ret;
253 }
254
255 /*
256   Open, disconnect, lease break, reconnect.
257 */
258 bool test_durable_open_lease(struct torture_context *tctx,
259                              struct smb2_tree *tree1,
260                              struct smb2_tree *tree2)
261 {
262         TALLOC_CTX *mem_ctx = talloc_new(tctx);
263         struct smb2_create io1, io2;
264         struct smb2_lease ls1, ls2;
265         struct smb2_handle h1, h2;
266         NTSTATUS status;
267         char fname[256];
268         bool ret = true;
269         uint64_t lease1, lease2;
270
271         /*
272          * Choose a random name and random lease in case the state is left a
273          * little funky.
274          */
275         lease1 = random();
276         lease2 = random();
277         snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
278
279         /* Clean slate */
280         smb2_util_unlink(tree1, fname);
281
282         /* Create with lease */
283         ZERO_STRUCT(io1);
284         io1.in.security_flags           = 0x00;
285         io1.in.oplock_level             = SMB2_OPLOCK_LEVEL_LEASE;
286         io1.in.impersonation_level      = NTCREATEX_IMPERSONATION_IMPERSONATION;
287         io1.in.create_flags             = 0x00000000;
288         io1.in.reserved                 = 0x00000000;
289         io1.in.desired_access           = SEC_RIGHTS_FILE_ALL;
290         io1.in.file_attributes          = FILE_ATTRIBUTE_NORMAL;
291         io1.in.share_access             = NTCREATEX_SHARE_ACCESS_READ |
292                                           NTCREATEX_SHARE_ACCESS_WRITE |
293                                           NTCREATEX_SHARE_ACCESS_DELETE;
294         io1.in.create_disposition       = NTCREATEX_DISP_OPEN_IF;
295         io1.in.create_options           = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
296                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
297                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
298                                           0x00200000;
299         io1.in.fname                    = fname;
300         io1.in.durable_open             = true;
301
302         ZERO_STRUCT(ls1);
303         ls1.lease_key.data[0] = lease1;
304         ls1.lease_key.data[1] = ~lease1;
305         ls1.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE;
306         io1.in.lease_request = &ls1;
307
308         io2 = io1;
309         ls2 = ls1;
310         ls2.lease_key.data[0] = lease2;
311         ls2.lease_key.data[1] = ~lease2;
312         io2.in.lease_request = &ls2;
313         io2.in.create_disposition = NTCREATEX_DISP_OPEN;
314
315         status = smb2_create(tree1, mem_ctx, &io1);
316         CHECK_STATUS(status, NT_STATUS_OK);
317         h1 = io1.out.file.handle;
318         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
319
320         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
321         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease1);
322         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease1);
323         CHECK_VAL(io1.out.lease_response.lease_state,
324             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
325
326         /* Disconnect after getting the lease */
327         talloc_free(tree1);
328         tree1 = NULL;
329
330         /*
331          * Windows7 (build 7000) will grant an RH lease immediate (not an RHW?)
332          * even if the original client is gone. (ZML: This seems like a bug. It
333          * should give some time for the client to reconnect! And why RH?)
334          */
335         status = smb2_create(tree2, mem_ctx, &io2);
336         CHECK_STATUS(status, NT_STATUS_OK);
337         h2 = io2.out.file.handle;
338         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
339
340         CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
341         CHECK_VAL(io2.out.lease_response.lease_key.data[0], lease2);
342         CHECK_VAL(io2.out.lease_response.lease_key.data[1], ~lease2);
343         CHECK_VAL(io2.out.lease_response.lease_state,
344             SMB2_LEASE_READ|SMB2_LEASE_HANDLE);
345
346         /* What if tree1 tries to come back and reclaim? */
347         if (!torture_smb2_connection(tctx, &tree1)) {
348                 torture_warning(tctx, "couldn't reconnect, bailing\n");
349                 ret = false;
350                 goto done;
351         }
352
353         ZERO_STRUCT(io1);
354         io1.in.fname = fname;
355         io1.in.durable_handle = &h1;
356         io1.in.lease_request = &ls1;
357
358         status = smb2_create(tree1, mem_ctx, &io1);
359         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
360
361  done:
362         smb2_util_close(tree2, h2);
363         smb2_util_unlink(tree2, fname);
364
365         return ret;
366 }
367
368 /*
369   Open, take BRL, disconnect, reconnect.
370 */
371 bool test_durable_open_lock(struct torture_context *tctx,
372                             struct smb2_tree *tree)
373 {
374         TALLOC_CTX *mem_ctx = talloc_new(tctx);
375         struct smb2_create io;
376         struct smb2_lease ls;
377         struct smb2_handle h;
378         struct smb2_lock lck;
379         struct smb2_lock_element el[2];
380         NTSTATUS status;
381         char fname[256];
382         bool ret = true;
383         uint64_t lease;
384
385         /*
386          * Choose a random name and random lease in case the state is left a
387          * little funky.
388          */
389         lease = random();
390         snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));
391
392         /* Clean slate */
393         smb2_util_unlink(tree, fname);
394
395         /* Create with lease */
396         ZERO_STRUCT(io);
397         io.in.security_flags            = 0x00;
398         io.in.oplock_level              = SMB2_OPLOCK_LEVEL_LEASE;
399         io.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
400         io.in.create_flags              = 0x00000000;
401         io.in.reserved                  = 0x00000000;
402         io.in.desired_access            = SEC_RIGHTS_FILE_ALL;
403         io.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
404         io.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
405                                           NTCREATEX_SHARE_ACCESS_WRITE |
406                                           NTCREATEX_SHARE_ACCESS_DELETE;
407         io.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
408         io.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
409                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
410                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
411                                           0x00200000;
412         io.in.fname                     = fname;
413         io.in.durable_open              = true;
414
415         ZERO_STRUCT(ls);
416         ls.lease_key.data[0] = lease;
417         ls.lease_key.data[1] = ~lease;
418         ls.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE;
419         io.in.lease_request = &ls;
420
421         status = smb2_create(tree, mem_ctx, &io);
422         CHECK_STATUS(status, NT_STATUS_OK);
423         h = io.out.file.handle;
424         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
425
426         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
427         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
428         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
429         CHECK_VAL(io.out.lease_response.lease_state,
430             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
431
432         ZERO_STRUCT(lck);
433         ZERO_STRUCT(el);
434         lck.in.locks            = el;
435         lck.in.lock_count       = 0x0001;
436         lck.in.lock_sequence    = 0x00000000;
437         lck.in.file.handle      = h;
438         el[0].offset            = 0;
439         el[0].length            = 1;
440         el[0].reserved          = 0x00000000;
441         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
442         status = smb2_lock(tree, &lck);
443         CHECK_STATUS(status, NT_STATUS_OK);
444
445         /* Disconnect/Reconnect. */
446         talloc_free(tree);
447         tree = NULL;
448
449         if (!torture_smb2_connection(tctx, &tree)) {
450                 torture_warning(tctx, "couldn't reconnect, bailing\n");
451                 ret = false;
452                 goto done;
453         }
454
455         ZERO_STRUCT(io);
456         io.in.fname = fname;
457         io.in.durable_handle = &h;
458         io.in.lease_request = &ls;
459
460         status = smb2_create(tree, mem_ctx, &io);
461         CHECK_STATUS(status, NT_STATUS_OK);
462         h = io.out.file.handle;
463
464         lck.in.file.handle      = h;
465         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
466         status = smb2_lock(tree, &lck);
467         CHECK_STATUS(status, NT_STATUS_OK);
468
469  done:
470         smb2_util_close(tree, h);
471         smb2_util_unlink(tree, fname);
472
473         return ret;
474 }
475
476 /*
477   Open, disconnect, open in another tree, reconnect.
478
479   This test actually demonstrates a minimum level of respect for the durable
480   open in the face of another open. As long as this test shows an inability to
481   reconnect after an open, the oplock/lease tests above will certainly
482   demonstrate an error on reconnect.
483 */
484 bool test_durable_open_open(struct torture_context *tctx,
485                             struct smb2_tree *tree1,
486                             struct smb2_tree *tree2)
487 {
488         TALLOC_CTX *mem_ctx = talloc_new(tctx);
489         struct smb2_create io1, io2;
490         struct smb2_lease ls;
491         struct smb2_handle h1, h2;
492         NTSTATUS status;
493         char fname[256];
494         bool ret = true;
495         uint64_t lease;
496
497         /*
498          * Choose a random name and random lease in case the state is left a
499          * little funky.
500          */
501         lease = random();
502         snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));
503
504         /* Clean slate */
505         smb2_util_unlink(tree1, fname);
506
507         /* Create with lease */
508         ZERO_STRUCT(io1);
509         io1.in.security_flags           = 0x00;
510         io1.in.oplock_level             = SMB2_OPLOCK_LEVEL_LEASE;
511         io1.in.impersonation_level      = NTCREATEX_IMPERSONATION_IMPERSONATION;
512         io1.in.create_flags             = 0x00000000;
513         io1.in.reserved                 = 0x00000000;
514         io1.in.desired_access           = SEC_RIGHTS_FILE_ALL;
515         io1.in.file_attributes          = FILE_ATTRIBUTE_NORMAL;
516         io1.in.share_access             = NTCREATEX_SHARE_ACCESS_NONE;
517         io1.in.create_disposition       = NTCREATEX_DISP_OPEN_IF;
518         io1.in.create_options           = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
519                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
520                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
521                                           0x00200000;
522         io1.in.fname                    = fname;
523         io1.in.durable_open             = true;
524
525         io2 = io1;
526         io2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
527         io2.in.durable_open = false;
528
529         ZERO_STRUCT(ls);
530         ls.lease_key.data[0] = lease;
531         ls.lease_key.data[1] = ~lease;
532         ls.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE;
533         io1.in.lease_request = &ls;
534
535         status = smb2_create(tree1, mem_ctx, &io1);
536         CHECK_STATUS(status, NT_STATUS_OK);
537         h1 = io1.out.file.handle;
538         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
539
540         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
541         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease);
542         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease);
543         CHECK_VAL(io1.out.lease_response.lease_state,
544             SMB2_LEASE_READ|SMB2_LEASE_HANDLE);
545
546         /* Disconnect */
547         talloc_free(tree1);
548         tree1 = NULL;
549
550         /* Open the file in tree2 */
551         status = smb2_create(tree2, mem_ctx, &io2);
552         CHECK_STATUS(status, NT_STATUS_OK);
553         h2 = io2.out.file.handle;
554         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
555
556         /* Reconnect */
557         if (!torture_smb2_connection(tctx, &tree1)) {
558                 torture_warning(tctx, "couldn't reconnect, bailing\n");
559                 ret = false;
560                 goto done;
561         }
562
563         ZERO_STRUCT(io1);
564         io1.in.fname = fname;
565         io1.in.durable_handle = &h1;
566         io1.in.lease_request = &ls;
567
568         /*
569          * Windows7 (build 7000) will give away an open immediately if the
570          * original client is gone. (ZML: This seems like a bug. It should give
571          * some time for the client to reconnect!)
572          */
573         status = smb2_create(tree1, mem_ctx, &io1);
574         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
575         h1 = io1.out.file.handle;
576
577  done:
578         smb2_util_close(tree2, h2);
579         smb2_util_unlink(tree2, fname);
580         smb2_util_close(tree1, h1);
581         smb2_util_unlink(tree1, fname);
582
583         return ret;
584 }
585
586 struct torture_suite *torture_smb2_durable_open_init(void)
587 {
588         struct torture_suite *suite =
589             torture_suite_create(talloc_autofree_context(), "durable-open");
590
591         torture_suite_add_2smb2_test(suite, "file-position",
592             test_durable_open_file_position);
593         torture_suite_add_2smb2_test(suite, "oplock", test_durable_open_oplock);
594         torture_suite_add_2smb2_test(suite, "lease", test_durable_open_lease);
595         torture_suite_add_1smb2_test(suite, "lock", test_durable_open_lock);
596         torture_suite_add_2smb2_test(suite, "open", test_durable_open_open);
597
598         suite->description = talloc_strdup(suite, "SMB2-DURABLE-OPEN tests");
599
600         return suite;
601 }