torture4: Add a test to break a handle twice
[Samba.git] / source4 / torture / smb2 / lease.c
blob038cc58ad01acdc5cbcef3994f5d137a7cb80b7f
1 /*
2 Unix SMB/CIFS implementation.
4 test suite for SMB2 leases
6 Copyright (C) Zachary Loafman 2009
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.
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.
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/>.
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"
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)
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)
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)
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 } \
68 CHECK_VAL((__io)->out.lease_response.lease_flags, 0); \
69 CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
70 } while(0)
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 } \
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)
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;
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" },
111 static bool test_lease_request(struct torture_context *tctx,
112 struct smb2_tree *tree)
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;
127 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
128 if (!(caps & SMB2_CAP_LEASING)) {
129 torture_skip(tctx, "leases are not supported");
132 smb2_util_unlink(tree, fname);
133 smb2_util_unlink(tree, fname2);
134 smb2_util_rmdir(tree, dname);
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);
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);
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);
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);
166 smb2_util_close(tree, h1);
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);
184 done:
185 smb2_util_close(tree, h1);
186 smb2_util_close(tree, h2);
188 smb2_util_unlink(tree, fname);
189 smb2_util_unlink(tree, fname2);
190 smb2_util_rmdir(tree, dname);
192 talloc_free(mem_ctx);
194 return ret;
197 static bool test_lease_upgrade(struct torture_context *tctx,
198 struct smb2_tree *tree)
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;
209 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
210 if (!(caps & SMB2_CAP_LEASING)) {
211 torture_skip(tctx, "leases are not supported");
214 smb2_util_unlink(tree, fname);
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;
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;
232 smb2_util_close(tree, hnew);
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;
242 smb2_util_close(tree, h);
243 h = hnew;
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;
253 smb2_util_close(tree, hnew);
255 done:
256 smb2_util_close(tree, h);
257 smb2_util_close(tree, hnew);
259 smb2_util_unlink(tree, fname);
261 talloc_free(mem_ctx);
263 return ret;
267 * upgrade2 test.
268 * full matrix of lease upgrade combinations
269 * (non-contended case)
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.
278 * In that case the resulting lease state is the one
279 * requested in the upgrade.
281 struct lease_upgrade2_test {
282 const char *initial;
283 const char *upgrade_to;
284 const char *expected;
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" },
296 { "R", "", "R" },
297 { "R", "R", "R" },
298 { "R", "RH", "RH" },
299 { "R", "RW", "RW" },
300 { "R", "RWH", "RWH" },
302 { "RH", "", "RH" },
303 { "RH", "R", "RH" },
304 { "RH", "RH", "RH" },
305 { "RH", "RW", "RH" },
306 { "RH", "RWH", "RWH" },
308 { "RW", "", "RW" },
309 { "RW", "R", "RW" },
310 { "RW", "RH", "RW" },
311 { "RW", "RW", "RW" },
312 { "RW", "RWH", "RWH" },
314 { "RWH", "", "RWH" },
315 { "RWH", "R", "RWH" },
316 { "RWH", "RH", "RWH" },
317 { "RWH", "RW", "RWH" },
318 { "RWH", "RWH", "RWH" },
321 static bool test_lease_upgrade2(struct torture_context *tctx,
322 struct smb2_tree *tree)
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;
334 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
335 if (!(caps & SMB2_CAP_LEASING)) {
336 torture_skip(tctx, "leases are not supported");
339 for (i = 0; i < NUM_UPGRADE_TESTS; i++) {
340 struct lease_upgrade2_test t = lease_upgrade2_tests[i];
342 smb2_util_unlink(tree, fname);
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;
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;
360 smb2_util_close(tree, hnew);
361 smb2_util_close(tree, h);
364 done:
365 smb2_util_close(tree, h);
366 smb2_util_close(tree, hnew);
368 smb2_util_unlink(tree, fname);
370 talloc_free(mem_ctx);
372 return ret;
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)
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)
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;
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;
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)); \
418 } while(0)
420 static void torture_lease_break_callback(struct smb2_request *req)
422 NTSTATUS status;
424 status = smb2_lease_break_ack_recv(req, &break_info.lease_break_ack);
425 if (!NT_STATUS_IS_OK(status))
426 break_info.failures++;
428 return;
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)
436 struct smb2_tree *tree = private_data;
437 struct smb2_lease_break_ack io;
438 struct smb2_request *req;
440 break_info.lease_break = *lb;
441 break_info.count++;
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;
448 req = smb2_lease_break_ack_send(tree, &io);
449 req->async.fn = torture_lease_break_callback;
450 req->async.private_data = NULL;
453 return true;
457 * upgrade3:
458 * full matrix of lease upgrade combinations
459 * (contended case)
461 * We start with 2 leases, and check how one can
462 * be upgraded
464 * The summary of the behaviour is this:
465 * -------------------------------------
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.
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.
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).
483 struct lease_upgrade3_test {
484 const char *held1;
485 const char *held2;
486 const char *upgrade_to;
487 const char *upgraded_to;
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" },
498 {"R", "RH", "", "R" },
499 {"R", "RH", "R", "R" },
500 {"R", "RH", "RW", "R" },
501 {"R", "RH", "RH", "RH" },
502 {"R", "RH", "RHW", "R" },
504 {"RH", "R", "", "RH" },
505 {"RH", "R", "R", "RH" },
506 {"RH", "R", "RW", "RH" },
507 {"RH", "R", "RH", "RH" },
508 {"RH", "R", "RHW", "RH" },
510 {"RH", "RH", "", "RH" },
511 {"RH", "RH", "R", "RH" },
512 {"RH", "RH", "RW", "RH" },
513 {"RH", "RH", "RH", "RH" },
514 {"RH", "RH", "RHW", "RH" },
517 static bool test_lease_upgrade3(struct torture_context *tctx,
518 struct smb2_tree *tree)
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;
530 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
531 if (!(caps & SMB2_CAP_LEASING)) {
532 torture_skip(tctx, "leases are not supported");
535 tree->session->transport->lease.handler = torture_lease_handler;
536 tree->session->transport->lease.private_data = tree;
538 smb2_util_unlink(tree, fname);
540 for (i = 0; i < NUM_UPGRADE3_TESTS; i++) {
541 struct lease_upgrade3_test t = lease_upgrade3_tests[i];
543 smb2_util_unlink(tree, fname);
545 ZERO_STRUCT(break_info);
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;
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;
563 /* no break has happened */
564 CHECK_VAL(break_info.count, 0);
565 CHECK_VAL(break_info.failures, 0);
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;
575 /* no break has happened */
576 CHECK_VAL(break_info.count, 0);
577 CHECK_VAL(break_info.failures, 0);
579 smb2_util_close(tree, hnew);
580 smb2_util_close(tree, h);
581 smb2_util_close(tree, h2);
584 done:
585 smb2_util_close(tree, h);
586 smb2_util_close(tree, hnew);
587 smb2_util_close(tree, h2);
589 smb2_util_unlink(tree, fname);
591 talloc_free(mem_ctx);
593 return ret;
599 Timer handler function notifies the registering function that time is up
601 static void timeout_cb(struct tevent_context *ev,
602 struct tevent_timer *te,
603 struct timeval current_time,
604 void *private_data)
606 bool *timesup = (bool *)private_data;
607 *timesup = true;
608 return;
612 Wait a short period of time to receive a single oplock break request
614 static void torture_wait_for_lease_break(struct torture_context *tctx)
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;
622 /* Wait .1 seconds for an lease break */
623 ne = tevent_timeval_current_ofs(0, 100000);
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;
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;
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);
648 return;
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.
657 Note: break_results only includes things that Win7 will actually grant (see
658 request_results above).
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"},
667 {"RH", "R", "RH", "R"},
668 {"RH", "RH", "RH", "RH"},
669 {"RH", "RW", "RH", "R"},
670 {"RH", "RHW", "RH", "RH"},
672 {"RW", "R", "R", "R"},
673 {"RW", "RH", "R", "RH"},
674 {"RW", "RW", "R", "R"},
675 {"RW", "RHW", "R", "RH"},
677 {"RHW", "R", "RH", "R"},
678 {"RHW", "RH", "RH", "RH"},
679 {"RHW", "RW", "RH", "R"},
680 {"RHW", "RHW", "RH", "RH"},
683 static bool test_lease_break(struct torture_context *tctx,
684 struct smb2_tree *tree)
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;
696 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
697 if (!(caps & SMB2_CAP_LEASING)) {
698 torture_skip(tctx, "leases are not supported");
701 tree->session->transport->lease.handler = torture_lease_handler;
702 tree->session->transport->lease.private_data = tree;
704 smb2_util_unlink(tree, fname);
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));
716 ZERO_STRUCT(break_info);
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);
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);
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);
741 ZERO_STRUCT(break_info);
744 Now verify that an attempt to upgrade LEASE1 results in no
745 break and no change in LEASE1.
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);
756 smb2_util_close(tree, h);
757 smb2_util_close(tree, h2);
758 smb2_util_close(tree, h3);
760 status = smb2_util_unlink(tree, fname);
761 CHECK_STATUS(status, NT_STATUS_OK);
764 done:
765 smb2_util_close(tree, h);
766 smb2_util_close(tree, h2);
768 smb2_util_unlink(tree, fname);
770 talloc_free(mem_ctx);
772 return ret;
775 static void torture_oplock_break_callback(struct smb2_request *req)
777 NTSTATUS status;
778 struct smb2_break br;
780 ZERO_STRUCT(br);
781 status = smb2_break_recv(req, &br);
782 if (!NT_STATUS_IS_OK(status))
783 break_info.oplock_failures++;
785 return;
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)
793 struct smb2_tree *tree = private_data;
794 struct smb2_request *req;
795 struct smb2_break br;
797 break_info.oplock_handle = *handle;
798 break_info.oplock_level = level;
799 break_info.oplock_count++;
801 ZERO_STRUCT(br);
802 br.in.file.handle = *handle;
803 br.in.oplock_level = level;
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;
810 break_info.held_oplock_level = level;
812 return true;
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"},
821 {"RH", "s", "RH", ""},
822 {"RH", "x", "RH", ""},
823 {"RH", "b", "RH", ""},
825 {"RW", "s", "R", "s"},
826 {"RW", "x", "R", "s"},
827 {"RW", "b", "R", "s"},
829 {"RHW", "s", "RH", ""},
830 {"RHW", "x", "RH", ""},
831 {"RHW", "b", "RH", ""},
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"},
840 {"x", "R", "s", "R"},
841 {"x", "RH", "s", "R"},
842 {"x", "RW", "s", "R"},
843 {"x", "RHW", "s", "R"},
845 {"b", "R", "s", "R"},
846 {"b", "RH", "s", "R"},
847 {"b", "RW", "s", "R"},
848 {"b", "RHW", "s", "R"},
851 static bool test_lease_oplock(struct torture_context *tctx,
852 struct smb2_tree *tree)
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;
864 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
865 if (!(caps & SMB2_CAP_LEASING)) {
866 torture_skip(tctx, "leases are not supported");
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;
874 smb2_util_unlink(tree, fname);
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));
886 ZERO_STRUCT(break_info);
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);
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;
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);
912 smb2_util_close(tree, h);
913 smb2_util_close(tree, h2);
915 status = smb2_util_unlink(tree, fname);
916 CHECK_STATUS(status, NT_STATUS_OK);
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));
929 ZERO_STRUCT(break_info);
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;
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);
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);
958 smb2_util_close(tree, h);
959 smb2_util_close(tree, h2);
961 status = smb2_util_unlink(tree, fname);
962 CHECK_STATUS(status, NT_STATUS_OK);
965 done:
966 smb2_util_close(tree, h);
967 smb2_util_close(tree, h2);
969 smb2_util_unlink(tree, fname);
971 talloc_free(mem_ctx);
973 return ret;
976 static bool test_lease_multibreak(struct torture_context *tctx,
977 struct smb2_tree *tree)
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;
989 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
990 if (!(caps & SMB2_CAP_LEASING)) {
991 torture_skip(tctx, "leases are not supported");
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;
999 smb2_util_unlink(tree, fname);
1001 ZERO_STRUCT(break_info);
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);
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);
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);
1026 /* Verify that we were only sent one break. */
1027 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
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);
1037 ZERO_STRUCT(break_info);
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);
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;
1056 /* Verify no breaks. */
1057 CHECK_VAL(break_info.count, 0);
1058 CHECK_VAL(break_info.failures, 0);
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;
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);
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);
1086 done:
1087 smb2_util_close(tree, h);
1088 smb2_util_close(tree, h2);
1089 smb2_util_close(tree, h3);
1091 smb2_util_unlink(tree, fname);
1093 talloc_free(mem_ctx);
1095 return ret;
1098 static bool test_lease_v2_request_parent(struct torture_context *tctx,
1099 struct smb2_tree *tree)
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;
1110 smb2_util_unlink(tree, fname);
1112 ZERO_STRUCT(break_info);
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"),
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);
1128 done:
1129 smb2_util_close(tree, h1);
1130 smb2_util_unlink(tree, fname);
1132 talloc_free(mem_ctx);
1134 return ret;
1137 static bool test_lease_break_twice(struct torture_context *tctx,
1138 struct smb2_tree *tree)
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;
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");
1155 smb2_util_unlink(tree, fname);
1157 ZERO_STRUCT(break_info);
1158 ZERO_STRUCT(io);
1159 ZERO_STRUCT(ls);
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);
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);
1171 tree->session->transport->lease.handler = torture_lease_handler;
1172 tree->session->transport->lease.private_data = tree;
1174 ZERO_STRUCT(break_info);
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);
1180 status = smb2_create(tree, mem_ctx, &io);
1181 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1182 CHECK_BREAK_INFO("RWH", "RW", LEASE1);
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);
1188 ZERO_STRUCT(break_info);
1190 status = smb2_create(tree, mem_ctx, &io);
1191 CHECK_STATUS(status, NT_STATUS_OK);
1192 CHECK_BREAK_INFO("RW", "R", LEASE1);
1194 done:
1195 smb2_util_close(tree, h1);
1196 smb2_util_unlink(tree, fname);
1197 talloc_free(mem_ctx);
1198 return ret;
1201 static bool test_lease_v2_request(struct torture_context *tctx,
1202 struct smb2_tree *tree)
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;
1216 smb2_util_unlink(tree, fname);
1217 smb2_deltree(tree, dname);
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;
1224 ZERO_STRUCT(break_info);
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"),
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);
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"),
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);
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"),
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);
1264 torture_wait_for_lease_break(tctx);
1265 CHECK_VAL(break_info.count, 0);
1266 CHECK_VAL(break_info.failures, 0);
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"),
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);
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);
1285 ZERO_STRUCT(break_info);
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"),
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);
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);
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);
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);
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);
1327 smb2_util_unlink(tree, fname);
1328 smb2_deltree(tree, dname);
1330 talloc_free(mem_ctx);
1332 return ret;
1335 struct torture_suite *torture_smb2_lease_init(void)
1337 struct torture_suite *suite =
1338 torture_suite_create(talloc_autofree_context(), "lease");
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);
1353 suite->description = talloc_strdup(suite, "SMB2-LEASE tests");
1355 return suite;