s4:torture:smb2: fix the durable_open test to succeed against w7 and w2k8r2
[ddiss/samba.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         talloc_free(tree1);
168         talloc_free(tree2);
169
170         return ret;
171 }
172
173 /*
174   Open, disconnect, oplock break, reconnect.
175 */
176 bool test_durable_open_oplock(struct torture_context *tctx,
177                               struct smb2_tree *tree1,
178                               struct smb2_tree *tree2)
179 {
180         TALLOC_CTX *mem_ctx = talloc_new(tctx);
181         struct smb2_create io1, io2;
182         struct smb2_handle h1, h2;
183         NTSTATUS status;
184         char fname[256];
185         bool ret = true;
186
187         /* Choose a random name in case the state is left a little funky. */
188         snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
189
190         /* Clean slate */
191         smb2_util_unlink(tree1, fname);
192
193         /* Create with batch oplock */
194         ZERO_STRUCT(io1);
195         io1.in.security_flags           = 0x00;
196         io1.in.oplock_level             = SMB2_OPLOCK_LEVEL_BATCH;
197         io1.in.impersonation_level      = NTCREATEX_IMPERSONATION_IMPERSONATION;
198         io1.in.create_flags             = 0x00000000;
199         io1.in.reserved                 = 0x00000000;
200         io1.in.desired_access           = SEC_RIGHTS_FILE_ALL;
201         io1.in.file_attributes          = FILE_ATTRIBUTE_NORMAL;
202         io1.in.share_access             = NTCREATEX_SHARE_ACCESS_READ |
203                                           NTCREATEX_SHARE_ACCESS_WRITE |
204                                           NTCREATEX_SHARE_ACCESS_DELETE;
205         io1.in.create_disposition       = NTCREATEX_DISP_OPEN_IF;
206         io1.in.create_options           = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
207                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
208                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
209                                           0x00200000;
210         io1.in.fname                    = fname;
211         io1.in.durable_open             = true;
212
213         io2 = io1;
214         io2.in.create_disposition       = NTCREATEX_DISP_OPEN;
215
216         status = smb2_create(tree1, mem_ctx, &io1);
217         CHECK_STATUS(status, NT_STATUS_OK);
218         h1 = io1.out.file.handle;
219         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
220         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
221
222         /* Disconnect after getting the batch */
223         talloc_free(tree1);
224         tree1 = NULL;
225
226         /*
227          * Windows7 (build 7000) will break a batch oplock immediately if the
228          * original client is gone. (ZML: This seems like a bug. It should give
229          * some time for the client to reconnect!)
230          */
231         status = smb2_create(tree2, mem_ctx, &io2);
232         CHECK_STATUS(status, NT_STATUS_OK);
233         h2 = io2.out.file.handle;
234         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
235         CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
236
237         /* What if tree1 tries to come back and reclaim? */
238         if (!torture_smb2_connection(tctx, &tree1)) {
239                 torture_warning(tctx, "couldn't reconnect, bailing\n");
240                 ret = false;
241                 goto done;
242         }
243
244         ZERO_STRUCT(io1);
245         io1.in.fname = fname;
246         io1.in.durable_handle = &h1;
247
248         status = smb2_create(tree1, mem_ctx, &io1);
249         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
250
251  done:
252         smb2_util_close(tree2, h2);
253         smb2_util_unlink(tree2, fname);
254
255         talloc_free(tree1);
256         talloc_free(tree2);
257
258         return ret;
259 }
260
261 /*
262   Open, disconnect, lease break, reconnect.
263 */
264 bool test_durable_open_lease(struct torture_context *tctx,
265                              struct smb2_tree *tree1,
266                              struct smb2_tree *tree2)
267 {
268         TALLOC_CTX *mem_ctx = talloc_new(tctx);
269         struct smb2_create io1, io2;
270         struct smb2_lease ls1, ls2;
271         struct smb2_handle h1, h2;
272         NTSTATUS status;
273         char fname[256];
274         bool ret = true;
275         uint64_t lease1, lease2;
276
277         /*
278          * Choose a random name and random lease in case the state is left a
279          * little funky.
280          */
281         lease1 = random();
282         lease2 = random();
283         snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
284
285         /* Clean slate */
286         smb2_util_unlink(tree1, fname);
287
288         /* Create with lease */
289         ZERO_STRUCT(io1);
290         io1.in.security_flags           = 0x00;
291         io1.in.oplock_level             = SMB2_OPLOCK_LEVEL_LEASE;
292         io1.in.impersonation_level      = NTCREATEX_IMPERSONATION_IMPERSONATION;
293         io1.in.create_flags             = 0x00000000;
294         io1.in.reserved                 = 0x00000000;
295         io1.in.desired_access           = SEC_RIGHTS_FILE_ALL;
296         io1.in.file_attributes          = FILE_ATTRIBUTE_NORMAL;
297         io1.in.share_access             = NTCREATEX_SHARE_ACCESS_READ |
298                                           NTCREATEX_SHARE_ACCESS_WRITE |
299                                           NTCREATEX_SHARE_ACCESS_DELETE;
300         io1.in.create_disposition       = NTCREATEX_DISP_OPEN_IF;
301         io1.in.create_options           = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
302                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
303                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
304                                           0x00200000;
305         io1.in.fname                    = fname;
306         io1.in.durable_open             = true;
307
308         ZERO_STRUCT(ls1);
309         ls1.lease_key.data[0] = lease1;
310         ls1.lease_key.data[1] = ~lease1;
311         ls1.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE;
312         io1.in.lease_request = &ls1;
313
314         io2 = io1;
315         ls2 = ls1;
316         ls2.lease_key.data[0] = lease2;
317         ls2.lease_key.data[1] = ~lease2;
318         io2.in.lease_request = &ls2;
319         io2.in.create_disposition = NTCREATEX_DISP_OPEN;
320
321         status = smb2_create(tree1, mem_ctx, &io1);
322         CHECK_STATUS(status, NT_STATUS_OK);
323         h1 = io1.out.file.handle;
324         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
325
326         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
327         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease1);
328         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease1);
329         CHECK_VAL(io1.out.lease_response.lease_state,
330             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
331
332         /* Disconnect after getting the lease */
333         talloc_free(tree1);
334         tree1 = NULL;
335
336         /*
337          * Windows7 (build 7000) will grant an RH lease immediate (not an RHW?)
338          * even if the original client is gone. (ZML: This seems like a bug. It
339          * should give some time for the client to reconnect! And why RH?)
340          */
341         status = smb2_create(tree2, mem_ctx, &io2);
342         CHECK_STATUS(status, NT_STATUS_OK);
343         h2 = io2.out.file.handle;
344         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
345
346         CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
347         CHECK_VAL(io2.out.lease_response.lease_key.data[0], lease2);
348         CHECK_VAL(io2.out.lease_response.lease_key.data[1], ~lease2);
349         CHECK_VAL(io2.out.lease_response.lease_state,
350             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
351
352         /* What if tree1 tries to come back and reclaim? */
353         if (!torture_smb2_connection(tctx, &tree1)) {
354                 torture_warning(tctx, "couldn't reconnect, bailing\n");
355                 ret = false;
356                 goto done;
357         }
358
359         ZERO_STRUCT(io1);
360         io1.in.fname = fname;
361         io1.in.durable_handle = &h1;
362         io1.in.lease_request = &ls1;
363
364         status = smb2_create(tree1, mem_ctx, &io1);
365         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
366
367  done:
368         smb2_util_close(tree2, h2);
369         smb2_util_unlink(tree2, fname);
370
371         talloc_free(tree1);
372         talloc_free(tree2);
373
374         return ret;
375 }
376
377 /*
378   Open, take BRL, disconnect, reconnect.
379 */
380 bool test_durable_open_lock(struct torture_context *tctx,
381                             struct smb2_tree *tree)
382 {
383         TALLOC_CTX *mem_ctx = talloc_new(tctx);
384         struct smb2_create io;
385         struct smb2_lease ls;
386         struct smb2_handle h;
387         struct smb2_lock lck;
388         struct smb2_lock_element el[2];
389         NTSTATUS status;
390         char fname[256];
391         bool ret = true;
392         uint64_t lease;
393
394         /*
395          * Choose a random name and random lease in case the state is left a
396          * little funky.
397          */
398         lease = random();
399         snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));
400
401         /* Clean slate */
402         smb2_util_unlink(tree, fname);
403
404         /* Create with lease */
405         ZERO_STRUCT(io);
406         io.in.security_flags            = 0x00;
407         io.in.oplock_level              = SMB2_OPLOCK_LEVEL_LEASE;
408         io.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
409         io.in.create_flags              = 0x00000000;
410         io.in.reserved                  = 0x00000000;
411         io.in.desired_access            = SEC_RIGHTS_FILE_ALL;
412         io.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
413         io.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
414                                           NTCREATEX_SHARE_ACCESS_WRITE |
415                                           NTCREATEX_SHARE_ACCESS_DELETE;
416         io.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
417         io.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
418                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
419                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
420                                           0x00200000;
421         io.in.fname                     = fname;
422         io.in.durable_open              = true;
423
424         ZERO_STRUCT(ls);
425         ls.lease_key.data[0] = lease;
426         ls.lease_key.data[1] = ~lease;
427         ls.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE;
428         io.in.lease_request = &ls;
429
430         status = smb2_create(tree, mem_ctx, &io);
431         CHECK_STATUS(status, NT_STATUS_OK);
432         h = io.out.file.handle;
433         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
434
435         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
436         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
437         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
438         CHECK_VAL(io.out.lease_response.lease_state,
439             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
440
441         ZERO_STRUCT(lck);
442         ZERO_STRUCT(el);
443         lck.in.locks            = el;
444         lck.in.lock_count       = 0x0001;
445         lck.in.lock_sequence    = 0x00000000;
446         lck.in.file.handle      = h;
447         el[0].offset            = 0;
448         el[0].length            = 1;
449         el[0].reserved          = 0x00000000;
450         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
451         status = smb2_lock(tree, &lck);
452         CHECK_STATUS(status, NT_STATUS_OK);
453
454         /* Disconnect/Reconnect. */
455         talloc_free(tree);
456         tree = NULL;
457
458         if (!torture_smb2_connection(tctx, &tree)) {
459                 torture_warning(tctx, "couldn't reconnect, bailing\n");
460                 ret = false;
461                 goto done;
462         }
463
464         ZERO_STRUCT(io);
465         io.in.fname = fname;
466         io.in.durable_handle = &h;
467         io.in.lease_request = &ls;
468
469         status = smb2_create(tree, mem_ctx, &io);
470         CHECK_STATUS(status, NT_STATUS_OK);
471         h = io.out.file.handle;
472
473         lck.in.file.handle      = h;
474         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
475         status = smb2_lock(tree, &lck);
476         CHECK_STATUS(status, NT_STATUS_OK);
477
478  done:
479         smb2_util_close(tree, h);
480         smb2_util_unlink(tree, fname);
481         talloc_free(tree);
482
483         return ret;
484 }
485
486 /*
487   Open, disconnect, open in another tree, reconnect.
488
489   This test actually demonstrates a minimum level of respect for the durable
490   open in the face of another open. As long as this test shows an inability to
491   reconnect after an open, the oplock/lease tests above will certainly
492   demonstrate an error on reconnect.
493 */
494 bool test_durable_open_open(struct torture_context *tctx,
495                             struct smb2_tree *tree1,
496                             struct smb2_tree *tree2)
497 {
498         TALLOC_CTX *mem_ctx = talloc_new(tctx);
499         struct smb2_create io1, io2;
500         struct smb2_lease ls;
501         struct smb2_handle h1, h2;
502         NTSTATUS status;
503         char fname[256];
504         bool ret = true;
505         uint64_t lease;
506
507         /*
508          * Choose a random name and random lease in case the state is left a
509          * little funky.
510          */
511         lease = random();
512         snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));
513
514         /* Clean slate */
515         smb2_util_unlink(tree1, fname);
516
517         /* Create with lease */
518         ZERO_STRUCT(io1);
519         io1.in.security_flags           = 0x00;
520         io1.in.oplock_level             = SMB2_OPLOCK_LEVEL_LEASE;
521         io1.in.impersonation_level      = NTCREATEX_IMPERSONATION_IMPERSONATION;
522         io1.in.create_flags             = 0x00000000;
523         io1.in.reserved                 = 0x00000000;
524         io1.in.desired_access           = SEC_RIGHTS_FILE_ALL;
525         io1.in.file_attributes          = FILE_ATTRIBUTE_NORMAL;
526         io1.in.share_access             = NTCREATEX_SHARE_ACCESS_NONE;
527         io1.in.create_disposition       = NTCREATEX_DISP_OPEN_IF;
528         io1.in.create_options           = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
529                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
530                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
531                                           0x00200000;
532         io1.in.fname                    = fname;
533         io1.in.durable_open             = true;
534
535         io2 = io1;
536         io2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
537         io2.in.durable_open = false;
538
539         ZERO_STRUCT(ls);
540         ls.lease_key.data[0] = lease;
541         ls.lease_key.data[1] = ~lease;
542         ls.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE;
543         io1.in.lease_request = &ls;
544
545         status = smb2_create(tree1, mem_ctx, &io1);
546         CHECK_STATUS(status, NT_STATUS_OK);
547         h1 = io1.out.file.handle;
548         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
549
550         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
551         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease);
552         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease);
553         CHECK_VAL(io1.out.lease_response.lease_state,
554             SMB2_LEASE_READ|SMB2_LEASE_HANDLE);
555
556         /* Disconnect */
557         talloc_free(tree1);
558         tree1 = NULL;
559
560         /* Open the file in tree2 */
561         status = smb2_create(tree2, mem_ctx, &io2);
562         CHECK_STATUS(status, NT_STATUS_OK);
563         h2 = io2.out.file.handle;
564         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
565
566         /* Reconnect */
567         if (!torture_smb2_connection(tctx, &tree1)) {
568                 torture_warning(tctx, "couldn't reconnect, bailing\n");
569                 ret = false;
570                 goto done;
571         }
572
573         ZERO_STRUCT(io1);
574         io1.in.fname = fname;
575         io1.in.durable_handle = &h1;
576         io1.in.lease_request = &ls;
577
578         /*
579          * Windows7 (build 7000) will give away an open immediately if the
580          * original client is gone. (ZML: This seems like a bug. It should give
581          * some time for the client to reconnect!)
582          */
583         status = smb2_create(tree1, mem_ctx, &io1);
584         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
585         h1 = io1.out.file.handle;
586
587  done:
588         smb2_util_close(tree2, h2);
589         smb2_util_unlink(tree2, fname);
590         smb2_util_close(tree1, h1);
591         smb2_util_unlink(tree1, fname);
592
593         talloc_free(tree1);
594         talloc_free(tree2);
595
596         return ret;
597 }
598
599 struct torture_suite *torture_smb2_durable_open_init(void)
600 {
601         struct torture_suite *suite =
602             torture_suite_create(talloc_autofree_context(), "durable-open");
603
604         torture_suite_add_2smb2_test(suite, "file-position",
605             test_durable_open_file_position);
606         torture_suite_add_2smb2_test(suite, "oplock", test_durable_open_oplock);
607         torture_suite_add_2smb2_test(suite, "lease", test_durable_open_lease);
608         torture_suite_add_1smb2_test(suite, "lock", test_durable_open_lock);
609         torture_suite_add_2smb2_test(suite, "open", test_durable_open_open);
610
611         suite->description = talloc_strdup(suite, "SMB2-DURABLE-OPEN tests");
612
613         return suite;
614 }