torture4: Add a test to break a handle twice
[nivanova/samba-autobuild/.git] / source4 / torture / smb2 / lease.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    test suite for SMB2 leases
5
6    Copyright (C) Zachary Loafman 2009
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 <tevent.h>
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28 #include "libcli/smb/smbXcli_base.h"
29
30 #define CHECK_VAL(v, correct) do { \
31         if ((v) != (correct)) { \
32                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
33                                 __location__, #v, (int)(v), (int)(correct)); \
34                 ret = false; \
35         }} while (0)
36
37 #define CHECK_STATUS(status, correct) do { \
38         if (!NT_STATUS_EQUAL(status, correct)) { \
39                 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
40                        nt_errstr(status), nt_errstr(correct)); \
41                 ret = false; \
42                 goto done; \
43         }} while (0)
44
45 #define CHECK_CREATED(__io, __created, __attribute)                     \
46         do {                                                            \
47                 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
48                 CHECK_VAL((__io)->out.alloc_size, 0);                   \
49                 CHECK_VAL((__io)->out.size, 0);                         \
50                 CHECK_VAL((__io)->out.file_attr, (__attribute));        \
51                 CHECK_VAL((__io)->out.reserved2, 0);                    \
52         } while(0)
53
54 #define CHECK_LEASE(__io, __state, __oplevel, __key)                    \
55         do {                                                            \
56                 if (__oplevel) {                                        \
57                         CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
58                         CHECK_VAL((__io)->out.lease_response.lease_key.data[0], (__key)); \
59                         CHECK_VAL((__io)->out.lease_response.lease_key.data[1], ~(__key)); \
60                         CHECK_VAL((__io)->out.lease_response.lease_state, smb2_util_lease_state(__state)); \
61                 } else {                                                \
62                         CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
63                         CHECK_VAL((__io)->out.lease_response.lease_key.data[0], 0); \
64                         CHECK_VAL((__io)->out.lease_response.lease_key.data[1], 0); \
65                         CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
66                 }                                                       \
67                                                                         \
68                 CHECK_VAL((__io)->out.lease_response.lease_flags, 0);   \
69                 CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
70         } while(0)
71
72 #define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent) \
73         do {                                                            \
74                 if (__oplevel) {                                        \
75                         CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
76                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], (__key)); \
77                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], ~(__key)); \
78                         CHECK_VAL((__io)->out.lease_response_v2.lease_state, smb2_util_lease_state(__state)); \
79                 } else {                                                \
80                         CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
81                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], 0); \
82                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], 0); \
83                         CHECK_VAL((__io)->out.lease_response_v2.lease_state, 0); \
84                 }                                                       \
85                                                                         \
86                 CHECK_VAL((__io)->out.lease_response_v2.lease_flags, __flags); \
87                 if (__flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET) { \
88                         CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[0], (__parent)); \
89                         CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[1], ~(__parent)); \
90                 } \
91                 CHECK_VAL((__io)->out.lease_response_v2.lease_duration, 0); \
92         } while(0)
93
94 static const uint64_t LEASE1 = 0xBADC0FFEE0DDF00Dull;
95 static const uint64_t LEASE2 = 0xDEADBEEFFEEDBEADull;
96 static const uint64_t LEASE3 = 0xDAD0FFEDD00DF00Dull;
97 static const uint64_t LEASE4 = 0xBAD0FFEDD00DF00Dull;
98
99 #define NREQUEST_RESULTS 8
100 static const char *request_results[NREQUEST_RESULTS][2] = {
101         { "", "" },
102         { "R", "R" },
103         { "H", "" },
104         { "W", "" },
105         { "RH", "RH" },
106         { "RW", "RW" },
107         { "HW", "" },
108         { "RHW", "RHW" },
109 };
110
111 static bool test_lease_request(struct torture_context *tctx,
112                                struct smb2_tree *tree)
113 {
114         TALLOC_CTX *mem_ctx = talloc_new(tctx);
115         struct smb2_create io;
116         struct smb2_lease ls;
117         struct smb2_handle h1, h2;
118         NTSTATUS status;
119         const char *fname = "lease.dat";
120         const char *fname2 = "lease2.dat";
121         const char *sname = "lease.dat:stream";
122         const char *dname = "lease.dir";
123         bool ret = true;
124         int i;
125         uint32_t caps;
126
127         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
128         if (!(caps & SMB2_CAP_LEASING)) {
129                 torture_skip(tctx, "leases are not supported");
130         }
131
132         smb2_util_unlink(tree, fname);
133         smb2_util_unlink(tree, fname2);
134         smb2_util_rmdir(tree, dname);
135
136         /* Win7 is happy to grant RHW leases on files. */
137         smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
138         status = smb2_create(tree, mem_ctx, &io);
139         CHECK_STATUS(status, NT_STATUS_OK);
140         h1 = io.out.file.handle;
141         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
142         CHECK_LEASE(&io, "RHW", true, LEASE1);
143
144         /* But will reject leases on directories. */
145         smb2_lease_create(&io, &ls, true, dname, LEASE2, smb2_util_lease_state("RHW"));
146         status = smb2_create(tree, mem_ctx, &io);
147         CHECK_STATUS(status, NT_STATUS_OK);
148         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
149         CHECK_LEASE(&io, "", false, 0);
150         smb2_util_close(tree, io.out.file.handle);
151
152         /* Also rejects multiple files leased under the same key. */
153         smb2_lease_create(&io, &ls, true, fname2, LEASE1, smb2_util_lease_state("RHW"));
154         status = smb2_create(tree, mem_ctx, &io);
155         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
156
157         /* And grants leases on streams (with separate leasekey). */
158         smb2_lease_create(&io, &ls, false, sname, LEASE2, smb2_util_lease_state("RHW"));
159         status = smb2_create(tree, mem_ctx, &io);
160         h2 = io.out.file.handle;
161         CHECK_STATUS(status, NT_STATUS_OK);
162         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
163         CHECK_LEASE(&io, "RHW", true, LEASE2);
164         smb2_util_close(tree, h2);
165
166         smb2_util_close(tree, h1);
167
168         /* Now see what combos are actually granted. */
169         for (i = 0; i < NREQUEST_RESULTS; i++) {
170                 torture_comment(tctx, "Requesting lease type %s(%x),"
171                     " expecting %s(%x)\n",
172                     request_results[i][0], smb2_util_lease_state(request_results[i][0]),
173                     request_results[i][1], smb2_util_lease_state(request_results[i][1]));
174                 smb2_lease_create(&io, &ls, false, fname, LEASE1,
175                     smb2_util_lease_state(request_results[i][0]));
176                 status = smb2_create(tree, mem_ctx, &io);
177                 h2 = io.out.file.handle;
178                 CHECK_STATUS(status, NT_STATUS_OK);
179                 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
180                 CHECK_LEASE(&io, request_results[i][1], true, LEASE1);
181                 smb2_util_close(tree, io.out.file.handle);
182         }
183
184  done:
185         smb2_util_close(tree, h1);
186         smb2_util_close(tree, h2);
187
188         smb2_util_unlink(tree, fname);
189         smb2_util_unlink(tree, fname2);
190         smb2_util_rmdir(tree, dname);
191
192         talloc_free(mem_ctx);
193
194         return ret;
195 }
196
197 static bool test_lease_upgrade(struct torture_context *tctx,
198                                struct smb2_tree *tree)
199 {
200         TALLOC_CTX *mem_ctx = talloc_new(tctx);
201         struct smb2_create io;
202         struct smb2_lease ls;
203         struct smb2_handle h, hnew;
204         NTSTATUS status;
205         const char *fname = "lease.dat";
206         bool ret = true;
207         uint32_t caps;
208
209         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
210         if (!(caps & SMB2_CAP_LEASING)) {
211                 torture_skip(tctx, "leases are not supported");
212         }
213
214         smb2_util_unlink(tree, fname);
215
216         /* Grab a RH lease. */
217         smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
218         status = smb2_create(tree, mem_ctx, &io);
219         CHECK_STATUS(status, NT_STATUS_OK);
220         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
221         CHECK_LEASE(&io, "RH", true, LEASE1);
222         h = io.out.file.handle;
223
224         /* Upgrades (sidegrades?) to RW leave us with an RH. */
225         smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RW"));
226         status = smb2_create(tree, mem_ctx, &io);
227         CHECK_STATUS(status, NT_STATUS_OK);
228         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
229         CHECK_LEASE(&io, "RH", true, LEASE1);
230         hnew = io.out.file.handle;
231
232         smb2_util_close(tree, hnew);
233
234         /* Upgrade to RHW lease. */
235         smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
236         status = smb2_create(tree, mem_ctx, &io);
237         CHECK_STATUS(status, NT_STATUS_OK);
238         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
239         CHECK_LEASE(&io, "RHW", true, LEASE1);
240         hnew = io.out.file.handle;
241
242         smb2_util_close(tree, h);
243         h = hnew;
244
245         /* Attempt to downgrade - original lease state is maintained. */
246         smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
247         status = smb2_create(tree, mem_ctx, &io);
248         CHECK_STATUS(status, NT_STATUS_OK);
249         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
250         CHECK_LEASE(&io, "RHW", true, LEASE1);
251         hnew = io.out.file.handle;
252
253         smb2_util_close(tree, hnew);
254
255  done:
256         smb2_util_close(tree, h);
257         smb2_util_close(tree, hnew);
258
259         smb2_util_unlink(tree, fname);
260
261         talloc_free(mem_ctx);
262
263         return ret;
264 }
265
266 /**
267  * upgrade2 test.
268  * full matrix of lease upgrade combinations
269  * (non-contended case)
270  *
271  * The summary of the behaviour is this:
272  * -------------------------------------
273  * An uncontended lease upgrade results in a change
274  * if and only if the requested lease state is
275  * - valid, and
276  * - strictly a superset of the lease state already held.
277  *
278  * In that case the resulting lease state is the one
279  * requested in the upgrade.
280  */
281 struct lease_upgrade2_test {
282         const char *initial;
283         const char *upgrade_to;
284         const char *expected;
285 };
286
287 #define NUM_LEASE_TYPES 5
288 #define NUM_UPGRADE_TESTS ( NUM_LEASE_TYPES * NUM_LEASE_TYPES )
289 struct lease_upgrade2_test lease_upgrade2_tests[NUM_UPGRADE_TESTS] = {
290         { "", "", "" },
291         { "", "R", "R" },
292         { "", "RH", "RH" },
293         { "", "RW", "RW" },
294         { "", "RWH", "RWH" },
295
296         { "R", "", "R" },
297         { "R", "R", "R" },
298         { "R", "RH", "RH" },
299         { "R", "RW", "RW" },
300         { "R", "RWH", "RWH" },
301
302         { "RH", "", "RH" },
303         { "RH", "R", "RH" },
304         { "RH", "RH", "RH" },
305         { "RH", "RW", "RH" },
306         { "RH", "RWH", "RWH" },
307
308         { "RW", "", "RW" },
309         { "RW", "R", "RW" },
310         { "RW", "RH", "RW" },
311         { "RW", "RW", "RW" },
312         { "RW", "RWH", "RWH" },
313
314         { "RWH", "", "RWH" },
315         { "RWH", "R", "RWH" },
316         { "RWH", "RH", "RWH" },
317         { "RWH", "RW", "RWH" },
318         { "RWH", "RWH", "RWH" },
319 };
320
321 static bool test_lease_upgrade2(struct torture_context *tctx,
322                                 struct smb2_tree *tree)
323 {
324         TALLOC_CTX *mem_ctx = talloc_new(tctx);
325         struct smb2_handle h, hnew;
326         NTSTATUS status;
327         struct smb2_create io;
328         struct smb2_lease ls;
329         const char *fname = "lease.dat";
330         bool ret = true;
331         int i;
332         uint32_t caps;
333
334         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
335         if (!(caps & SMB2_CAP_LEASING)) {
336                 torture_skip(tctx, "leases are not supported");
337         }
338
339         for (i = 0; i < NUM_UPGRADE_TESTS; i++) {
340                 struct lease_upgrade2_test t = lease_upgrade2_tests[i];
341
342                 smb2_util_unlink(tree, fname);
343
344                 /* Grab a lease. */
345                 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.initial));
346                 status = smb2_create(tree, mem_ctx, &io);
347                 CHECK_STATUS(status, NT_STATUS_OK);
348                 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
349                 CHECK_LEASE(&io, t.initial, true, LEASE1);
350                 h = io.out.file.handle;
351
352                 /* Upgrade. */
353                 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
354                 status = smb2_create(tree, mem_ctx, &io);
355                 CHECK_STATUS(status, NT_STATUS_OK);
356                 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
357                 CHECK_LEASE(&io, t.expected, true, LEASE1);
358                 hnew = io.out.file.handle;
359
360                 smb2_util_close(tree, hnew);
361                 smb2_util_close(tree, h);
362         }
363
364  done:
365         smb2_util_close(tree, h);
366         smb2_util_close(tree, hnew);
367
368         smb2_util_unlink(tree, fname);
369
370         talloc_free(mem_ctx);
371
372         return ret;
373 }
374
375
376 #define CHECK_LEASE_BREAK(__lb, __oldstate, __state, __key)             \
377         do {                                                            \
378                 CHECK_VAL((__lb)->new_lease_state, smb2_util_lease_state(__state));     \
379                 CHECK_VAL((__lb)->current_lease.lease_state, smb2_util_lease_state(__oldstate)); \
380                 CHECK_VAL((__lb)->current_lease.lease_key.data[0], (__key)); \
381                 CHECK_VAL((__lb)->current_lease.lease_key.data[1], ~(__key)); \
382         } while(0)
383
384 #define CHECK_LEASE_BREAK_ACK(__lba, __state, __key)                    \
385         do {                                                            \
386                 CHECK_VAL((__lba)->out.reserved, 0);                    \
387                 CHECK_VAL((__lba)->out.lease.lease_key.data[0], (__key)); \
388                 CHECK_VAL((__lba)->out.lease.lease_key.data[1], ~(__key)); \
389                 CHECK_VAL((__lba)->out.lease.lease_state, smb2_util_lease_state(__state)); \
390                 CHECK_VAL((__lba)->out.lease.lease_flags, 0);           \
391                 CHECK_VAL((__lba)->out.lease.lease_duration, 0);        \
392         } while(0)
393
394 static struct {
395         struct smb2_lease_break lease_break;
396         struct smb2_lease_break_ack lease_break_ack;
397         int count;
398         int failures;
399
400         struct smb2_handle oplock_handle;
401         uint8_t held_oplock_level;
402         uint8_t oplock_level;
403         int oplock_count;
404         int oplock_failures;
405 } break_info;
406
407 #define CHECK_BREAK_INFO(__oldstate, __state, __key)                    \
408         do {                                                            \
409                 CHECK_VAL(break_info.failures, 0);                      \
410                 CHECK_VAL(break_info.count, 1);                         \
411                 CHECK_LEASE_BREAK(&break_info.lease_break, (__oldstate), \
412                     (__state), (__key));                                \
413                 if (break_info.lease_break.break_flags &                \
414                     SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) {        \
415                         CHECK_LEASE_BREAK_ACK(&break_info.lease_break_ack, \
416                                               (__state), (__key));      \
417                 }                                                       \
418         } while(0)
419
420 static void torture_lease_break_callback(struct smb2_request *req)
421 {
422         NTSTATUS status;
423
424         status = smb2_lease_break_ack_recv(req, &break_info.lease_break_ack);
425         if (!NT_STATUS_IS_OK(status))
426                 break_info.failures++;
427
428         return;
429 }
430
431 /* a lease break request handler */
432 static bool torture_lease_handler(struct smb2_transport *transport,
433                                   const struct smb2_lease_break *lb,
434                                   void *private_data)
435 {
436         struct smb2_tree *tree = private_data;
437         struct smb2_lease_break_ack io;
438         struct smb2_request *req;
439
440         break_info.lease_break = *lb;
441         break_info.count++;
442
443         if (lb->break_flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) {
444                 ZERO_STRUCT(io);
445                 io.in.lease.lease_key = lb->current_lease.lease_key;
446                 io.in.lease.lease_state = lb->new_lease_state;
447
448                 req = smb2_lease_break_ack_send(tree, &io);
449                 req->async.fn = torture_lease_break_callback;
450                 req->async.private_data = NULL;
451         }
452
453         return true;
454 }
455
456 /**
457  * upgrade3:
458  * full matrix of lease upgrade combinations
459  * (contended case)
460  *
461  * We start with 2 leases, and check how one can
462  * be upgraded
463  *
464  * The summary of the behaviour is this:
465  * -------------------------------------
466  *
467  * If we have two leases (lease1 and lease2) on the same file,
468  * then attempt to upgrade lease1 results in a change if and only
469  * if the requested lease state:
470  * - is valid,
471  * - is strictly a superset of lease1, and
472  * - can held together with lease2.
473  *
474  * In that case, the resuling lease state of the upgraded lease1
475  * is the state requested in the upgrade. lease2 is not broken
476  * and remains unchanged.
477  *
478  * Note that this contrasts the case of directly opening with
479  * an initial requested lease state, in which case you get that
480  * portion of the requested state that can be shared with the
481  * already existing leases (or the states that they get broken to).
482  */
483 struct lease_upgrade3_test {
484         const char *held1;
485         const char *held2;
486         const char *upgrade_to;
487         const char *upgraded_to;
488 };
489
490 #define NUM_UPGRADE3_TESTS ( 20 )
491 struct lease_upgrade3_test lease_upgrade3_tests[NUM_UPGRADE3_TESTS] = {
492         {"R", "R", "", "R" },
493         {"R", "R", "R", "R" },
494         {"R", "R", "RW", "R" },
495         {"R", "R", "RH", "RH" },
496         {"R", "R", "RHW", "R" },
497
498         {"R", "RH", "", "R" },
499         {"R", "RH", "R", "R" },
500         {"R", "RH", "RW", "R" },
501         {"R", "RH", "RH", "RH" },
502         {"R", "RH", "RHW", "R" },
503
504         {"RH", "R", "", "RH" },
505         {"RH", "R", "R", "RH" },
506         {"RH", "R", "RW", "RH" },
507         {"RH", "R", "RH", "RH" },
508         {"RH", "R", "RHW", "RH" },
509
510         {"RH", "RH", "", "RH" },
511         {"RH", "RH", "R", "RH" },
512         {"RH", "RH", "RW", "RH" },
513         {"RH", "RH", "RH", "RH" },
514         {"RH", "RH", "RHW", "RH" },
515 };
516
517 static bool test_lease_upgrade3(struct torture_context *tctx,
518                                 struct smb2_tree *tree)
519 {
520         TALLOC_CTX *mem_ctx = talloc_new(tctx);
521         struct smb2_handle h, h2, hnew;
522         NTSTATUS status;
523         struct smb2_create io;
524         struct smb2_lease ls;
525         const char *fname = "upgrade3.dat";
526         bool ret = true;
527         int i;
528         uint32_t caps;
529
530         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
531         if (!(caps & SMB2_CAP_LEASING)) {
532                 torture_skip(tctx, "leases are not supported");
533         }
534
535         tree->session->transport->lease.handler = torture_lease_handler;
536         tree->session->transport->lease.private_data = tree;
537
538         smb2_util_unlink(tree, fname);
539
540         for (i = 0; i < NUM_UPGRADE3_TESTS; i++) {
541                 struct lease_upgrade3_test t = lease_upgrade3_tests[i];
542
543                 smb2_util_unlink(tree, fname);
544
545                 ZERO_STRUCT(break_info);
546
547                 /* grab first lease */
548                 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.held1));
549                 status = smb2_create(tree, mem_ctx, &io);
550                 CHECK_STATUS(status, NT_STATUS_OK);
551                 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
552                 CHECK_LEASE(&io, t.held1, true, LEASE1);
553                 h = io.out.file.handle;
554
555                 /* grab second lease */
556                 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(t.held2));
557                 status = smb2_create(tree, mem_ctx, &io);
558                 CHECK_STATUS(status, NT_STATUS_OK);
559                 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
560                 CHECK_LEASE(&io, t.held2, true, LEASE2);
561                 h2 = io.out.file.handle;
562
563                 /* no break has happened */
564                 CHECK_VAL(break_info.count, 0);
565                 CHECK_VAL(break_info.failures, 0);
566
567                 /* try to upgrade lease1 */
568                 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
569                 status = smb2_create(tree, mem_ctx, &io);
570                 CHECK_STATUS(status, NT_STATUS_OK);
571                 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
572                 CHECK_LEASE(&io, t.upgraded_to, true, LEASE1);
573                 hnew = io.out.file.handle;
574
575                 /* no break has happened */
576                 CHECK_VAL(break_info.count, 0);
577                 CHECK_VAL(break_info.failures, 0);
578
579                 smb2_util_close(tree, hnew);
580                 smb2_util_close(tree, h);
581                 smb2_util_close(tree, h2);
582         }
583
584  done:
585         smb2_util_close(tree, h);
586         smb2_util_close(tree, hnew);
587         smb2_util_close(tree, h2);
588
589         smb2_util_unlink(tree, fname);
590
591         talloc_free(mem_ctx);
592
593         return ret;
594 }
595
596
597
598 /*
599    Timer handler function notifies the registering function that time is up
600 */
601 static void timeout_cb(struct tevent_context *ev,
602                        struct tevent_timer *te,
603                        struct timeval current_time,
604                        void *private_data)
605 {
606         bool *timesup = (bool *)private_data;
607         *timesup = true;
608         return;
609 }
610
611 /*
612    Wait a short period of time to receive a single oplock break request
613 */
614 static void torture_wait_for_lease_break(struct torture_context *tctx)
615 {
616         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
617         struct tevent_timer *te = NULL;
618         struct timeval ne;
619         bool timesup = false;
620         int old_count = break_info.count;
621
622         /* Wait .1 seconds for an lease break */
623         ne = tevent_timeval_current_ofs(0, 100000);
624
625         te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup);
626         if (te == NULL) {
627                 torture_comment(tctx, "Failed to wait for an oplock break. "
628                                       "test results may not be accurate.");
629                 goto done;
630         }
631
632         while (!timesup && break_info.count < old_count + 1) {
633                 if (tevent_loop_once(tctx->ev) != 0) {
634                         torture_comment(tctx, "Failed to wait for an oplock "
635                                               "break. test results may not be "
636                                               "accurate.");
637                         goto done;
638                 }
639         }
640
641 done:
642         /* We don't know if the timed event fired and was freed, we received
643          * our oplock break, or some other event triggered the loop.  Thus,
644          * we create a tmp_ctx to be able to safely free/remove the timed
645          * event in all 3 cases. */
646         talloc_free(tmp_ctx);
647
648         return;
649 }
650
651 /*
652   break_results should be read as "held lease, new lease, hold broken to, new
653   grant", i.e. { "RH", "RW", "RH", "R" } means that if key1 holds RH and key2
654   tries for RW, key1 will be broken to RH (in this case, not broken at all)
655   and key2 will be granted R.
656
657   Note: break_results only includes things that Win7 will actually grant (see
658   request_results above).
659  */
660 #define NBREAK_RESULTS 16
661 static const char *break_results[NBREAK_RESULTS][4] = {
662         {"R",   "R",    "R",    "R"},
663         {"R",   "RH",   "R",    "RH"},
664         {"R",   "RW",   "R",    "R"},
665         {"R",   "RHW",  "R",    "RH"},
666
667         {"RH",  "R",    "RH",   "R"},
668         {"RH",  "RH",   "RH",   "RH"},
669         {"RH",  "RW",   "RH",   "R"},
670         {"RH",  "RHW",  "RH",   "RH"},
671
672         {"RW",  "R",    "R",    "R"},
673         {"RW",  "RH",   "R",    "RH"},
674         {"RW",  "RW",   "R",    "R"},
675         {"RW",  "RHW",  "R",    "RH"},
676
677         {"RHW", "R",    "RH",   "R"},
678         {"RHW", "RH",   "RH",   "RH"},
679         {"RHW", "RW",   "RH",   "R"},
680         {"RHW", "RHW",  "RH",   "RH"},
681 };
682
683 static bool test_lease_break(struct torture_context *tctx,
684                                struct smb2_tree *tree)
685 {
686         TALLOC_CTX *mem_ctx = talloc_new(tctx);
687         struct smb2_create io;
688         struct smb2_lease ls;
689         struct smb2_handle h, h2, h3;
690         NTSTATUS status;
691         const char *fname = "lease.dat";
692         bool ret = true;
693         int i;
694         uint32_t caps;
695
696         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
697         if (!(caps & SMB2_CAP_LEASING)) {
698                 torture_skip(tctx, "leases are not supported");
699         }
700
701         tree->session->transport->lease.handler = torture_lease_handler;
702         tree->session->transport->lease.private_data = tree;
703
704         smb2_util_unlink(tree, fname);
705
706         for (i = 0; i < NBREAK_RESULTS; i++) {
707                 const char *held = break_results[i][0];
708                 const char *contend = break_results[i][1];
709                 const char *brokento = break_results[i][2];
710                 const char *granted = break_results[i][3];
711                 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
712                     "expecting break to %s(%x) and grant of %s(%x)\n",
713                     held, smb2_util_lease_state(held), contend, smb2_util_lease_state(contend),
714                     brokento, smb2_util_lease_state(brokento), granted, smb2_util_lease_state(granted));
715
716                 ZERO_STRUCT(break_info);
717
718                 /* Grab lease. */
719                 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
720                 status = smb2_create(tree, mem_ctx, &io);
721                 CHECK_STATUS(status, NT_STATUS_OK);
722                 h = io.out.file.handle;
723                 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
724                 CHECK_LEASE(&io, held, true, LEASE1);
725
726                 /* Possibly contend lease. */
727                 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(contend));
728                 status = smb2_create(tree, mem_ctx, &io);
729                 CHECK_STATUS(status, NT_STATUS_OK);
730                 h2 = io.out.file.handle;
731                 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
732                 CHECK_LEASE(&io, granted, true, LEASE2);
733
734                 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
735                         CHECK_BREAK_INFO(held, brokento, LEASE1);
736                 } else {
737                         CHECK_VAL(break_info.count, 0);
738                         CHECK_VAL(break_info.failures, 0);
739                 }
740
741                 ZERO_STRUCT(break_info);
742
743                 /*
744                   Now verify that an attempt to upgrade LEASE1 results in no
745                   break and no change in LEASE1.
746                  */
747                 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
748                 status = smb2_create(tree, mem_ctx, &io);
749                 CHECK_STATUS(status, NT_STATUS_OK);
750                 h3 = io.out.file.handle;
751                 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
752                 CHECK_LEASE(&io, brokento, true, LEASE1);
753                 CHECK_VAL(break_info.count, 0);
754                 CHECK_VAL(break_info.failures, 0);
755
756                 smb2_util_close(tree, h);
757                 smb2_util_close(tree, h2);
758                 smb2_util_close(tree, h3);
759
760                 status = smb2_util_unlink(tree, fname);
761                 CHECK_STATUS(status, NT_STATUS_OK);
762         }
763
764  done:
765         smb2_util_close(tree, h);
766         smb2_util_close(tree, h2);
767
768         smb2_util_unlink(tree, fname);
769
770         talloc_free(mem_ctx);
771
772         return ret;
773 }
774
775 static void torture_oplock_break_callback(struct smb2_request *req)
776 {
777         NTSTATUS status;
778         struct smb2_break br;
779
780         ZERO_STRUCT(br);
781         status = smb2_break_recv(req, &br);
782         if (!NT_STATUS_IS_OK(status))
783                 break_info.oplock_failures++;
784
785         return;
786 }
787
788 /* a oplock break request handler */
789 static bool torture_oplock_handler(struct smb2_transport *transport,
790                                    const struct smb2_handle *handle,
791                                    uint8_t level, void *private_data)
792 {
793         struct smb2_tree *tree = private_data;
794         struct smb2_request *req;
795         struct smb2_break br;
796
797         break_info.oplock_handle = *handle;
798         break_info.oplock_level = level;
799         break_info.oplock_count++;
800
801         ZERO_STRUCT(br);
802         br.in.file.handle = *handle;
803         br.in.oplock_level = level;
804
805         if (break_info.held_oplock_level > SMB2_OPLOCK_LEVEL_II) {
806                 req = smb2_break_send(tree, &br);
807                 req->async.fn = torture_oplock_break_callback;
808                 req->async.private_data = NULL;
809         }
810         break_info.held_oplock_level = level;
811
812         return true;
813 }
814
815 #define NOPLOCK_RESULTS 12
816 static const char *oplock_results[NOPLOCK_RESULTS][4] = {
817         {"R",   "s",    "R",    "s"},
818         {"R",   "x",    "R",    "s"},
819         {"R",   "b",    "R",    "s"},
820
821         {"RH",  "s",    "RH",   ""},
822         {"RH",  "x",    "RH",   ""},
823         {"RH",  "b",    "RH",   ""},
824
825         {"RW",  "s",    "R",    "s"},
826         {"RW",  "x",    "R",    "s"},
827         {"RW",  "b",    "R",    "s"},
828
829         {"RHW", "s",    "RH",   ""},
830         {"RHW", "x",    "RH",   ""},
831         {"RHW", "b",    "RH",   ""},
832 };
833
834 static const char *oplock_results_2[NOPLOCK_RESULTS][4] = {
835         {"s",   "R",    "s",    "R"},
836         {"s",   "RH",   "s",    "R"},
837         {"s",   "RW",   "s",    "R"},
838         {"s",   "RHW",  "s",    "R"},
839
840         {"x",   "R",    "s",    "R"},
841         {"x",   "RH",   "s",    "R"},
842         {"x",   "RW",   "s",    "R"},
843         {"x",   "RHW",  "s",    "R"},
844
845         {"b",   "R",    "s",    "R"},
846         {"b",   "RH",   "s",    "R"},
847         {"b",   "RW",   "s",    "R"},
848         {"b",   "RHW",  "s",    "R"},
849 };
850
851 static bool test_lease_oplock(struct torture_context *tctx,
852                               struct smb2_tree *tree)
853 {
854         TALLOC_CTX *mem_ctx = talloc_new(tctx);
855         struct smb2_create io;
856         struct smb2_lease ls;
857         struct smb2_handle h, h2;
858         NTSTATUS status;
859         const char *fname = "lease.dat";
860         bool ret = true;
861         int i;
862         uint32_t caps;
863
864         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
865         if (!(caps & SMB2_CAP_LEASING)) {
866                 torture_skip(tctx, "leases are not supported");
867         }
868
869         tree->session->transport->lease.handler = torture_lease_handler;
870         tree->session->transport->lease.private_data = tree;
871         tree->session->transport->oplock.handler = torture_oplock_handler;
872         tree->session->transport->oplock.private_data = tree;
873
874         smb2_util_unlink(tree, fname);
875
876         for (i = 0; i < NOPLOCK_RESULTS; i++) {
877                 const char *held = oplock_results[i][0];
878                 const char *contend = oplock_results[i][1];
879                 const char *brokento = oplock_results[i][2];
880                 const char *granted = oplock_results[i][3];
881                 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
882                     "expecting break to %s(%x) and grant of %s(%x)\n",
883                     held, smb2_util_lease_state(held), contend, smb2_util_oplock_level(contend),
884                     brokento, smb2_util_lease_state(brokento), granted, smb2_util_oplock_level(granted));
885
886                 ZERO_STRUCT(break_info);
887
888                 /* Grab lease. */
889                 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
890                 status = smb2_create(tree, mem_ctx, &io);
891                 CHECK_STATUS(status, NT_STATUS_OK);
892                 h = io.out.file.handle;
893                 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
894                 CHECK_LEASE(&io, held, true, LEASE1);
895
896                 /* Does an oplock contend the lease? */
897                 smb2_oplock_create(&io, fname, smb2_util_oplock_level(contend));
898                 status = smb2_create(tree, mem_ctx, &io);
899                 CHECK_STATUS(status, NT_STATUS_OK);
900                 h2 = io.out.file.handle;
901                 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
902                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(granted));
903                 break_info.held_oplock_level = io.out.oplock_level;
904
905                 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
906                         CHECK_BREAK_INFO(held, brokento, LEASE1);
907                 } else {
908                         CHECK_VAL(break_info.count, 0);
909                         CHECK_VAL(break_info.failures, 0);
910                 }
911
912                 smb2_util_close(tree, h);
913                 smb2_util_close(tree, h2);
914
915                 status = smb2_util_unlink(tree, fname);
916                 CHECK_STATUS(status, NT_STATUS_OK);
917         }
918
919         for (i = 0; i < NOPLOCK_RESULTS; i++) {
920                 const char *held = oplock_results_2[i][0];
921                 const char *contend = oplock_results_2[i][1];
922                 const char *brokento = oplock_results_2[i][2];
923                 const char *granted = oplock_results_2[i][3];
924                 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
925                     "expecting break to %s(%x) and grant of %s(%x)\n",
926                     held, smb2_util_oplock_level(held), contend, smb2_util_lease_state(contend),
927                     brokento, smb2_util_oplock_level(brokento), granted, smb2_util_lease_state(granted));
928
929                 ZERO_STRUCT(break_info);
930
931                 /* Grab an oplock. */
932                 smb2_oplock_create(&io, fname, smb2_util_oplock_level(held));
933                 status = smb2_create(tree, mem_ctx, &io);
934                 CHECK_STATUS(status, NT_STATUS_OK);
935                 h = io.out.file.handle;
936                 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
937                 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(held));
938                 break_info.held_oplock_level = io.out.oplock_level;
939
940                 /* Grab lease. */
941                 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(contend));
942                 status = smb2_create(tree, mem_ctx, &io);
943                 CHECK_STATUS(status, NT_STATUS_OK);
944                 h2 = io.out.file.handle;
945                 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
946                 CHECK_LEASE(&io, granted, true, LEASE1);
947
948                 if (smb2_util_oplock_level(held) != smb2_util_oplock_level(brokento)) {
949                         CHECK_VAL(break_info.oplock_count, 1);
950                         CHECK_VAL(break_info.oplock_failures, 0);
951                         CHECK_VAL(break_info.oplock_level, smb2_util_oplock_level(brokento));
952                         break_info.held_oplock_level = break_info.oplock_level;
953                 } else {
954                         CHECK_VAL(break_info.oplock_count, 0);
955                         CHECK_VAL(break_info.oplock_failures, 0);
956                 }
957
958                 smb2_util_close(tree, h);
959                 smb2_util_close(tree, h2);
960
961                 status = smb2_util_unlink(tree, fname);
962                 CHECK_STATUS(status, NT_STATUS_OK);
963         }
964
965  done:
966         smb2_util_close(tree, h);
967         smb2_util_close(tree, h2);
968
969         smb2_util_unlink(tree, fname);
970
971         talloc_free(mem_ctx);
972
973         return ret;
974 }
975
976 static bool test_lease_multibreak(struct torture_context *tctx,
977                                   struct smb2_tree *tree)
978 {
979         TALLOC_CTX *mem_ctx = talloc_new(tctx);
980         struct smb2_create io;
981         struct smb2_lease ls;
982         struct smb2_handle h, h2, h3;
983         struct smb2_write w;
984         NTSTATUS status;
985         const char *fname = "lease.dat";
986         bool ret = true;
987         uint32_t caps;
988
989         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
990         if (!(caps & SMB2_CAP_LEASING)) {
991                 torture_skip(tctx, "leases are not supported");
992         }
993
994         tree->session->transport->lease.handler = torture_lease_handler;
995         tree->session->transport->lease.private_data = tree;
996         tree->session->transport->oplock.handler = torture_oplock_handler;
997         tree->session->transport->oplock.private_data = tree;
998
999         smb2_util_unlink(tree, fname);
1000
1001         ZERO_STRUCT(break_info);
1002
1003         /* Grab lease, upgrade to RHW .. */
1004         smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
1005         status = smb2_create(tree, mem_ctx, &io);
1006         CHECK_STATUS(status, NT_STATUS_OK);
1007         h = io.out.file.handle;
1008         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1009         CHECK_LEASE(&io, "RH", true, LEASE1);
1010
1011         smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
1012         status = smb2_create(tree, mem_ctx, &io);
1013         CHECK_STATUS(status, NT_STATUS_OK);
1014         h2 = io.out.file.handle;
1015         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1016         CHECK_LEASE(&io, "RHW", true, LEASE1);
1017
1018         /* Contend with LEASE2. */
1019         smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state("RHW"));
1020         status = smb2_create(tree, mem_ctx, &io);
1021         CHECK_STATUS(status, NT_STATUS_OK);
1022         h3 = io.out.file.handle;
1023         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1024         CHECK_LEASE(&io, "RH", true, LEASE2);
1025
1026         /* Verify that we were only sent one break. */
1027         CHECK_BREAK_INFO("RHW", "RH", LEASE1);
1028
1029         /* Drop LEASE1 / LEASE2 */
1030         status = smb2_util_close(tree, h);
1031         CHECK_STATUS(status, NT_STATUS_OK);
1032         status = smb2_util_close(tree, h2);
1033         CHECK_STATUS(status, NT_STATUS_OK);
1034         status = smb2_util_close(tree, h3);
1035         CHECK_STATUS(status, NT_STATUS_OK);
1036
1037         ZERO_STRUCT(break_info);
1038
1039         /* Grab an R lease. */
1040         smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("R"));
1041         status = smb2_create(tree, mem_ctx, &io);
1042         CHECK_STATUS(status, NT_STATUS_OK);
1043         h = io.out.file.handle;
1044         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1045         CHECK_LEASE(&io, "R", true, LEASE1);
1046
1047         /* Grab a level-II oplock. */
1048         smb2_oplock_create(&io, fname, smb2_util_oplock_level("s"));
1049         status = smb2_create(tree, mem_ctx, &io);
1050         CHECK_STATUS(status, NT_STATUS_OK);
1051         h2 = io.out.file.handle;
1052         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1053         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
1054         break_info.held_oplock_level = io.out.oplock_level;
1055
1056         /* Verify no breaks. */
1057         CHECK_VAL(break_info.count, 0);
1058         CHECK_VAL(break_info.failures, 0);
1059
1060         /* Open for truncate, force a break. */
1061         smb2_generic_create(&io, NULL, false, fname,
1062             NTCREATEX_DISP_OVERWRITE_IF, smb2_util_oplock_level(""), 0, 0);
1063         status = smb2_create(tree, mem_ctx, &io);
1064         CHECK_STATUS(status, NT_STATUS_OK);
1065         h3 = io.out.file.handle;
1066         CHECK_CREATED(&io, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
1067         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(""));
1068         break_info.held_oplock_level = io.out.oplock_level;
1069
1070         /* Sleep, use a write to clear the recv queue. */
1071         smb_msleep(250);
1072         ZERO_STRUCT(w);
1073         w.in.file.handle = h3;
1074         w.in.offset      = 0;
1075         w.in.data        = data_blob_talloc(mem_ctx, NULL, 4096);
1076         memset(w.in.data.data, 'o', w.in.data.length);
1077         status = smb2_write(tree, &w);
1078         CHECK_STATUS(status, NT_STATUS_OK);
1079
1080         /* Verify one oplock break, one lease break. */
1081         CHECK_VAL(break_info.oplock_count, 1);
1082         CHECK_VAL(break_info.oplock_failures, 0);
1083         CHECK_VAL(break_info.oplock_level, smb2_util_oplock_level(""));
1084         CHECK_BREAK_INFO("R", "", LEASE1);
1085
1086  done:
1087         smb2_util_close(tree, h);
1088         smb2_util_close(tree, h2);
1089         smb2_util_close(tree, h3);
1090
1091         smb2_util_unlink(tree, fname);
1092
1093         talloc_free(mem_ctx);
1094
1095         return ret;
1096 }
1097
1098 static bool test_lease_v2_request_parent(struct torture_context *tctx,
1099                                          struct smb2_tree *tree)
1100 {
1101         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1102         struct smb2_create io;
1103         struct smb2_lease ls;
1104         struct smb2_handle h1;
1105         uint64_t parent = LEASE2;
1106         NTSTATUS status;
1107         const char *fname = "lease.dat";
1108         bool ret = true;
1109
1110         smb2_util_unlink(tree, fname);
1111
1112         ZERO_STRUCT(break_info);
1113
1114         ZERO_STRUCT(io);
1115         smb2_lease_v2_create_share(&io, &ls, false, fname,
1116                                    smb2_util_share_access("RWD"),
1117                                    LEASE1, &parent,
1118                                    smb2_util_lease_state("RHW"),
1119                                    0);
1120
1121         status = smb2_create(tree, mem_ctx, &io);
1122         CHECK_STATUS(status, NT_STATUS_OK);
1123         h1 = io.out.file.handle;
1124         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1125         CHECK_LEASE_V2(&io, "RHW", true, LEASE1,
1126                        SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2);
1127
1128  done:
1129         smb2_util_close(tree, h1);
1130         smb2_util_unlink(tree, fname);
1131
1132         talloc_free(mem_ctx);
1133
1134         return ret;
1135 }
1136
1137 static bool test_lease_break_twice(struct torture_context *tctx,
1138                                    struct smb2_tree *tree)
1139 {
1140         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1141         struct smb2_create io;
1142         struct smb2_lease ls;
1143         struct smb2_handle h1;
1144         NTSTATUS status;
1145         const char *fname = "lease.dat";
1146         bool ret = true;
1147         uint32_t caps;
1148
1149         caps = smb2cli_conn_server_capabilities(
1150                 tree->session->transport->conn);
1151         if (!(caps & SMB2_CAP_LEASING)) {
1152                 torture_skip(tctx, "leases are not supported");
1153         }
1154
1155         smb2_util_unlink(tree, fname);
1156
1157         ZERO_STRUCT(break_info);
1158         ZERO_STRUCT(io);
1159         ZERO_STRUCT(ls);
1160
1161         smb2_lease_v2_create_share(
1162                 &io, &ls, false, fname, smb2_util_share_access("RWD"),
1163                 LEASE1, NULL, smb2_util_lease_state("RWH"), 0);
1164
1165         status = smb2_create(tree, mem_ctx, &io);
1166         CHECK_STATUS(status, NT_STATUS_OK);
1167         h1 = io.out.file.handle;
1168         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1169         CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0);
1170
1171         tree->session->transport->lease.handler = torture_lease_handler;
1172         tree->session->transport->lease.private_data = tree;
1173
1174         ZERO_STRUCT(break_info);
1175
1176         smb2_lease_v2_create_share(
1177                 &io, &ls, false, fname, smb2_util_share_access("R"),
1178                 LEASE2, NULL, smb2_util_lease_state("RWH"), 0);
1179
1180         status = smb2_create(tree, mem_ctx, &io);
1181         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1182         CHECK_BREAK_INFO("RWH", "RW", LEASE1);
1183
1184         smb2_lease_v2_create_share(
1185                 &io, &ls, false, fname, smb2_util_share_access("RWD"),
1186                 LEASE2, NULL, smb2_util_lease_state("RWH"), 0);
1187
1188         ZERO_STRUCT(break_info);
1189
1190         status = smb2_create(tree, mem_ctx, &io);
1191         CHECK_STATUS(status, NT_STATUS_OK);
1192         CHECK_BREAK_INFO("RW", "R", LEASE1);
1193
1194 done:
1195         smb2_util_close(tree, h1);
1196         smb2_util_unlink(tree, fname);
1197         talloc_free(mem_ctx);
1198         return ret;
1199 }
1200
1201 static bool test_lease_v2_request(struct torture_context *tctx,
1202                                   struct smb2_tree *tree)
1203 {
1204         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1205         struct smb2_create io;
1206         struct smb2_lease ls;
1207         struct smb2_handle h1, h2, h3, h4, h5;
1208         struct smb2_write w;
1209         NTSTATUS status;
1210         const char *fname = "lease.dat";
1211         const char *dname = "lease.dir";
1212         const char *dnamefname = "lease.dir\\lease.dat";
1213         const char *dnamefname2 = "lease.dir\\lease2.dat";
1214         bool ret = true;
1215
1216         smb2_util_unlink(tree, fname);
1217         smb2_deltree(tree, dname);
1218
1219         tree->session->transport->lease.handler = torture_lease_handler;
1220         tree->session->transport->lease.private_data = tree;
1221         tree->session->transport->oplock.handler = torture_oplock_handler;
1222         tree->session->transport->oplock.private_data = tree;
1223
1224         ZERO_STRUCT(break_info);
1225
1226         ZERO_STRUCT(io);
1227         smb2_lease_v2_create_share(&io, &ls, false, fname,
1228                                    smb2_util_share_access("RWD"),
1229                                    LEASE1, NULL,
1230                                    smb2_util_lease_state("RHW"),
1231                                    0);
1232
1233         status = smb2_create(tree, mem_ctx, &io);
1234         CHECK_STATUS(status, NT_STATUS_OK);
1235         h1 = io.out.file.handle;
1236         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1237         CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0);
1238
1239         ZERO_STRUCT(io);
1240         smb2_lease_v2_create_share(&io, &ls, true, dname,
1241                                    smb2_util_share_access("RWD"),
1242                                    LEASE2, NULL,
1243                                    smb2_util_lease_state("RHW"),
1244                                    0);
1245         status = smb2_create(tree, mem_ctx, &io);
1246         CHECK_STATUS(status, NT_STATUS_OK);
1247         h2 = io.out.file.handle;
1248         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
1249         CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0);
1250
1251         ZERO_STRUCT(io);
1252         smb2_lease_v2_create_share(&io, &ls, false, dnamefname,
1253                                    smb2_util_share_access("RWD"),
1254                                    LEASE3, &LEASE2,
1255                                    smb2_util_lease_state("RHW"),
1256                                    0);
1257         status = smb2_create(tree, mem_ctx, &io);
1258         CHECK_STATUS(status, NT_STATUS_OK);
1259         h3 = io.out.file.handle;
1260         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1261         CHECK_LEASE_V2(&io, "RHW", true, LEASE3,
1262                        SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2);
1263
1264         torture_wait_for_lease_break(tctx);
1265         CHECK_VAL(break_info.count, 0);
1266         CHECK_VAL(break_info.failures, 0);
1267
1268         ZERO_STRUCT(io);
1269         smb2_lease_v2_create_share(&io, &ls, false, dnamefname2,
1270                                    smb2_util_share_access("RWD"),
1271                                    LEASE4, NULL,
1272                                    smb2_util_lease_state("RHW"),
1273                                    0);
1274         status = smb2_create(tree, mem_ctx, &io);
1275         CHECK_STATUS(status, NT_STATUS_OK);
1276         h4 = io.out.file.handle;
1277         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1278         CHECK_LEASE_V2(&io, "RHW", true, LEASE4, 0, 0);
1279
1280         torture_wait_for_lease_break(tctx);
1281         torture_wait_for_lease_break(tctx);
1282         CHECK_BREAK_INFO("RH", "", LEASE2);
1283         torture_wait_for_lease_break(tctx);
1284
1285         ZERO_STRUCT(break_info);
1286
1287         ZERO_STRUCT(io);
1288         smb2_lease_v2_create_share(&io, &ls, true, dname,
1289                                    smb2_util_share_access("RWD"),
1290                                    LEASE2, NULL,
1291                                    smb2_util_lease_state("RHW"),
1292                                    0);
1293         io.in.create_disposition = NTCREATEX_DISP_OPEN;
1294         status = smb2_create(tree, mem_ctx, &io);
1295         CHECK_STATUS(status, NT_STATUS_OK);
1296         h5 = io.out.file.handle;
1297         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_DIRECTORY);
1298         CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0);
1299         smb2_util_close(tree, h5);
1300
1301         ZERO_STRUCT(w);
1302         w.in.file.handle = h4;
1303         w.in.offset      = 0;
1304         w.in.data        = data_blob_talloc(mem_ctx, NULL, 4096);
1305         memset(w.in.data.data, 'o', w.in.data.length);
1306         status = smb2_write(tree, &w);
1307         CHECK_STATUS(status, NT_STATUS_OK);
1308
1309         smb_msleep(2000);
1310         torture_wait_for_lease_break(tctx);
1311         CHECK_VAL(break_info.count, 0);
1312         CHECK_VAL(break_info.failures, 0);
1313
1314         smb2_util_close(tree, h4);
1315         torture_wait_for_lease_break(tctx);
1316         torture_wait_for_lease_break(tctx);
1317         CHECK_BREAK_INFO("RH", "", LEASE2);
1318         torture_wait_for_lease_break(tctx);
1319
1320  done:
1321         smb2_util_close(tree, h1);
1322         smb2_util_close(tree, h2);
1323         smb2_util_close(tree, h3);
1324         smb2_util_close(tree, h4);
1325         smb2_util_close(tree, h5);
1326
1327         smb2_util_unlink(tree, fname);
1328         smb2_deltree(tree, dname);
1329
1330         talloc_free(mem_ctx);
1331
1332         return ret;
1333 }
1334
1335 struct torture_suite *torture_smb2_lease_init(void)
1336 {
1337         struct torture_suite *suite =
1338             torture_suite_create(talloc_autofree_context(), "lease");
1339
1340         torture_suite_add_1smb2_test(suite, "request", test_lease_request);
1341         torture_suite_add_1smb2_test(suite, "break_twice",
1342                                      test_lease_break_twice);
1343         torture_suite_add_1smb2_test(suite, "upgrade", test_lease_upgrade);
1344         torture_suite_add_1smb2_test(suite, "upgrade2", test_lease_upgrade2);
1345         torture_suite_add_1smb2_test(suite, "upgrade3", test_lease_upgrade3);
1346         torture_suite_add_1smb2_test(suite, "break", test_lease_break);
1347         torture_suite_add_1smb2_test(suite, "oplock", test_lease_oplock);
1348         torture_suite_add_1smb2_test(suite, "multibreak", test_lease_multibreak);
1349         torture_suite_add_1smb2_test(suite, "v2_request_parent",
1350                                      test_lease_v2_request_parent);
1351         torture_suite_add_1smb2_test(suite, "v2_request", test_lease_v2_request);
1352
1353         suite->description = talloc_strdup(suite, "SMB2-LEASE tests");
1354
1355         return suite;
1356 }