Line data Source code
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 "torture/util.h"
29 : #include "libcli/smb/smbXcli_base.h"
30 : #include "libcli/security/security.h"
31 : #include "lib/param/param.h"
32 : #include "lease_break_handler.h"
33 :
34 : #define CHECK_VAL(v, correct) do { \
35 : if ((v) != (correct)) { \
36 : torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
37 : __location__, #v, (int)(v), (int)(correct)); \
38 : ret = false; \
39 : }} while (0)
40 :
41 : #define CHECK_STATUS(status, correct) do { \
42 : if (!NT_STATUS_EQUAL(status, correct)) { \
43 : torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
44 : nt_errstr(status), nt_errstr(correct)); \
45 : ret = false; \
46 : goto done; \
47 : }} while (0)
48 :
49 : #define CHECK_CREATED(__io, __created, __attribute) \
50 : do { \
51 : CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
52 : CHECK_VAL((__io)->out.size, 0); \
53 : CHECK_VAL((__io)->out.file_attr, (__attribute)); \
54 : CHECK_VAL((__io)->out.reserved2, 0); \
55 : } while(0)
56 :
57 : #define CHECK_LEASE(__io, __state, __oplevel, __key, __flags) \
58 : do { \
59 : CHECK_VAL((__io)->out.lease_response.lease_version, 1); \
60 : if (__oplevel) { \
61 : CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
62 : CHECK_VAL((__io)->out.lease_response.lease_key.data[0], (__key)); \
63 : CHECK_VAL((__io)->out.lease_response.lease_key.data[1], ~(__key)); \
64 : CHECK_VAL((__io)->out.lease_response.lease_state, smb2_util_lease_state(__state)); \
65 : } else { \
66 : CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
67 : CHECK_VAL((__io)->out.lease_response.lease_key.data[0], 0); \
68 : CHECK_VAL((__io)->out.lease_response.lease_key.data[1], 0); \
69 : CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
70 : } \
71 : \
72 : CHECK_VAL((__io)->out.lease_response.lease_flags, (__flags)); \
73 : CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
74 : CHECK_VAL((__io)->out.lease_response.lease_epoch, 0); \
75 : } while(0)
76 :
77 : #define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent, __epoch) \
78 : do { \
79 : CHECK_VAL((__io)->out.lease_response_v2.lease_version, 2); \
80 : if (__oplevel) { \
81 : CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
82 : CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], (__key)); \
83 : CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], ~(__key)); \
84 : CHECK_VAL((__io)->out.lease_response_v2.lease_state, smb2_util_lease_state(__state)); \
85 : } else { \
86 : CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
87 : CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], 0); \
88 : CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], 0); \
89 : CHECK_VAL((__io)->out.lease_response_v2.lease_state, 0); \
90 : } \
91 : \
92 : CHECK_VAL((__io)->out.lease_response_v2.lease_flags, __flags); \
93 : if (__flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET) { \
94 : CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[0], (__parent)); \
95 : CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[1], ~(__parent)); \
96 : } \
97 : CHECK_VAL((__io)->out.lease_response_v2.lease_duration, 0); \
98 : CHECK_VAL((__io)->out.lease_response_v2.lease_epoch, (__epoch)); \
99 : } while(0)
100 :
101 : static const uint64_t LEASE1 = 0xBADC0FFEE0DDF00Dull;
102 : static const uint64_t LEASE2 = 0xDEADBEEFFEEDBEADull;
103 : static const uint64_t LEASE3 = 0xDAD0FFEDD00DF00Dull;
104 : static const uint64_t LEASE4 = 0xBAD0FFEDD00DF00Dull;
105 :
106 : #define NREQUEST_RESULTS 8
107 : static const char *request_results[NREQUEST_RESULTS][2] = {
108 : { "", "" },
109 : { "R", "R" },
110 : { "H", "" },
111 : { "W", "" },
112 : { "RH", "RH" },
113 : { "RW", "RW" },
114 : { "HW", "" },
115 : { "RHW", "RHW" },
116 : };
117 :
118 0 : static bool test_lease_request(struct torture_context *tctx,
119 : struct smb2_tree *tree)
120 : {
121 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
122 : struct smb2_create io;
123 : struct smb2_lease ls;
124 0 : struct smb2_handle h1 = {{0}};
125 0 : struct smb2_handle h2 = {{0}};
126 : NTSTATUS status;
127 0 : const char *fname = "lease_request.dat";
128 0 : const char *fname2 = "lease_request.2.dat";
129 0 : const char *sname = "lease_request.dat:stream";
130 0 : const char *dname = "lease_request.dir";
131 0 : bool ret = true;
132 : int i;
133 : uint32_t caps;
134 :
135 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
136 0 : if (!(caps & SMB2_CAP_LEASING)) {
137 0 : torture_skip(tctx, "leases are not supported");
138 : }
139 :
140 0 : smb2_util_unlink(tree, fname);
141 0 : smb2_util_unlink(tree, fname2);
142 0 : smb2_util_rmdir(tree, dname);
143 :
144 : /* Win7 is happy to grant RHW leases on files. */
145 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
146 0 : status = smb2_create(tree, mem_ctx, &io);
147 0 : CHECK_STATUS(status, NT_STATUS_OK);
148 0 : h1 = io.out.file.handle;
149 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
150 0 : CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
151 :
152 : /* But will reject leases on directories. */
153 0 : if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
154 0 : smb2_lease_create(&io, &ls, true, dname, LEASE2, smb2_util_lease_state("RHW"));
155 0 : status = smb2_create(tree, mem_ctx, &io);
156 0 : CHECK_STATUS(status, NT_STATUS_OK);
157 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
158 0 : CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
159 0 : smb2_util_close(tree, io.out.file.handle);
160 : }
161 :
162 : /* Also rejects multiple files leased under the same key. */
163 0 : smb2_lease_create(&io, &ls, true, fname2, LEASE1, smb2_util_lease_state("RHW"));
164 0 : status = smb2_create(tree, mem_ctx, &io);
165 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
166 :
167 : /* And grants leases on streams (with separate leasekey). */
168 0 : smb2_lease_create(&io, &ls, false, sname, LEASE2, smb2_util_lease_state("RHW"));
169 0 : status = smb2_create(tree, mem_ctx, &io);
170 0 : h2 = io.out.file.handle;
171 0 : CHECK_STATUS(status, NT_STATUS_OK);
172 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
173 0 : CHECK_LEASE(&io, "RHW", true, LEASE2, 0);
174 0 : smb2_util_close(tree, h2);
175 :
176 0 : smb2_util_close(tree, h1);
177 :
178 : /* Now see what combos are actually granted. */
179 0 : for (i = 0; i < NREQUEST_RESULTS; i++) {
180 0 : torture_comment(tctx, "Requesting lease type %s(%x),"
181 : " expecting %s(%x)\n",
182 : request_results[i][0], smb2_util_lease_state(request_results[i][0]),
183 : request_results[i][1], smb2_util_lease_state(request_results[i][1]));
184 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1,
185 : smb2_util_lease_state(request_results[i][0]));
186 0 : status = smb2_create(tree, mem_ctx, &io);
187 0 : h2 = io.out.file.handle;
188 0 : CHECK_STATUS(status, NT_STATUS_OK);
189 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
190 0 : CHECK_LEASE(&io, request_results[i][1], true, LEASE1, 0);
191 0 : smb2_util_close(tree, io.out.file.handle);
192 : }
193 :
194 0 : done:
195 0 : smb2_util_close(tree, h1);
196 0 : smb2_util_close(tree, h2);
197 :
198 0 : smb2_util_unlink(tree, fname);
199 0 : smb2_util_unlink(tree, fname2);
200 0 : smb2_util_rmdir(tree, dname);
201 :
202 0 : talloc_free(mem_ctx);
203 :
204 0 : return ret;
205 : }
206 :
207 0 : static bool test_lease_upgrade(struct torture_context *tctx,
208 : struct smb2_tree *tree)
209 : {
210 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
211 : struct smb2_create io;
212 : struct smb2_lease ls;
213 0 : struct smb2_handle h = {{0}};
214 0 : struct smb2_handle hnew = {{0}};
215 : NTSTATUS status;
216 0 : const char *fname = "lease_upgrade.dat";
217 0 : bool ret = true;
218 : uint32_t caps;
219 :
220 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
221 0 : if (!(caps & SMB2_CAP_LEASING)) {
222 0 : torture_skip(tctx, "leases are not supported");
223 : }
224 :
225 0 : smb2_util_unlink(tree, fname);
226 :
227 : /* Grab a RH lease. */
228 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
229 0 : status = smb2_create(tree, mem_ctx, &io);
230 0 : CHECK_STATUS(status, NT_STATUS_OK);
231 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
232 0 : CHECK_LEASE(&io, "RH", true, LEASE1, 0);
233 0 : h = io.out.file.handle;
234 :
235 : /* Upgrades (sidegrades?) to RW leave us with an RH. */
236 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RW"));
237 0 : status = smb2_create(tree, mem_ctx, &io);
238 0 : CHECK_STATUS(status, NT_STATUS_OK);
239 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
240 0 : CHECK_LEASE(&io, "RH", true, LEASE1, 0);
241 0 : hnew = io.out.file.handle;
242 :
243 0 : smb2_util_close(tree, hnew);
244 :
245 : /* Upgrade to RHW lease. */
246 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
247 0 : status = smb2_create(tree, mem_ctx, &io);
248 0 : CHECK_STATUS(status, NT_STATUS_OK);
249 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
250 0 : CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
251 0 : hnew = io.out.file.handle;
252 :
253 0 : smb2_util_close(tree, h);
254 0 : h = hnew;
255 :
256 : /* Attempt to downgrade - original lease state is maintained. */
257 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
258 0 : status = smb2_create(tree, mem_ctx, &io);
259 0 : CHECK_STATUS(status, NT_STATUS_OK);
260 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
261 0 : CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
262 0 : hnew = io.out.file.handle;
263 :
264 0 : smb2_util_close(tree, hnew);
265 :
266 0 : done:
267 0 : smb2_util_close(tree, h);
268 0 : smb2_util_close(tree, hnew);
269 :
270 0 : smb2_util_unlink(tree, fname);
271 :
272 0 : talloc_free(mem_ctx);
273 :
274 0 : return ret;
275 : }
276 :
277 : /**
278 : * upgrade2 test.
279 : * full matrix of lease upgrade combinations
280 : * (non-contended case)
281 : *
282 : * The summary of the behaviour is this:
283 : * -------------------------------------
284 : * An uncontended lease upgrade results in a change
285 : * if and only if the requested lease state is
286 : * - valid, and
287 : * - strictly a superset of the lease state already held.
288 : *
289 : * In that case the resulting lease state is the one
290 : * requested in the upgrade.
291 : */
292 : struct lease_upgrade2_test {
293 : const char *initial;
294 : const char *upgrade_to;
295 : const char *expected;
296 : };
297 :
298 : #define NUM_LEASE_TYPES 5
299 : #define NUM_UPGRADE_TESTS ( NUM_LEASE_TYPES * NUM_LEASE_TYPES )
300 : struct lease_upgrade2_test lease_upgrade2_tests[NUM_UPGRADE_TESTS] = {
301 : { "", "", "" },
302 : { "", "R", "R" },
303 : { "", "RH", "RH" },
304 : { "", "RW", "RW" },
305 : { "", "RWH", "RWH" },
306 :
307 : { "R", "", "R" },
308 : { "R", "R", "R" },
309 : { "R", "RH", "RH" },
310 : { "R", "RW", "RW" },
311 : { "R", "RWH", "RWH" },
312 :
313 : { "RH", "", "RH" },
314 : { "RH", "R", "RH" },
315 : { "RH", "RH", "RH" },
316 : { "RH", "RW", "RH" },
317 : { "RH", "RWH", "RWH" },
318 :
319 : { "RW", "", "RW" },
320 : { "RW", "R", "RW" },
321 : { "RW", "RH", "RW" },
322 : { "RW", "RW", "RW" },
323 : { "RW", "RWH", "RWH" },
324 :
325 : { "RWH", "", "RWH" },
326 : { "RWH", "R", "RWH" },
327 : { "RWH", "RH", "RWH" },
328 : { "RWH", "RW", "RWH" },
329 : { "RWH", "RWH", "RWH" },
330 : };
331 :
332 0 : static bool test_lease_upgrade2(struct torture_context *tctx,
333 : struct smb2_tree *tree)
334 : {
335 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
336 : struct smb2_handle h, hnew;
337 : NTSTATUS status;
338 : struct smb2_create io;
339 : struct smb2_lease ls;
340 0 : const char *fname = "lease_upgrade2.dat";
341 0 : bool ret = true;
342 : int i;
343 : uint32_t caps;
344 :
345 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
346 0 : if (!(caps & SMB2_CAP_LEASING)) {
347 0 : torture_skip(tctx, "leases are not supported");
348 : }
349 :
350 0 : for (i = 0; i < NUM_UPGRADE_TESTS; i++) {
351 0 : struct lease_upgrade2_test t = lease_upgrade2_tests[i];
352 :
353 0 : smb2_util_unlink(tree, fname);
354 :
355 : /* Grab a lease. */
356 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.initial));
357 0 : status = smb2_create(tree, mem_ctx, &io);
358 0 : CHECK_STATUS(status, NT_STATUS_OK);
359 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
360 0 : CHECK_LEASE(&io, t.initial, true, LEASE1, 0);
361 0 : h = io.out.file.handle;
362 :
363 : /* Upgrade. */
364 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
365 0 : status = smb2_create(tree, mem_ctx, &io);
366 0 : CHECK_STATUS(status, NT_STATUS_OK);
367 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
368 0 : CHECK_LEASE(&io, t.expected, true, LEASE1, 0);
369 0 : hnew = io.out.file.handle;
370 :
371 0 : smb2_util_close(tree, hnew);
372 0 : smb2_util_close(tree, h);
373 : }
374 :
375 0 : done:
376 0 : smb2_util_close(tree, h);
377 0 : smb2_util_close(tree, hnew);
378 :
379 0 : smb2_util_unlink(tree, fname);
380 :
381 0 : talloc_free(mem_ctx);
382 :
383 0 : return ret;
384 : }
385 :
386 :
387 : /**
388 : * upgrade3:
389 : * full matrix of lease upgrade combinations
390 : * (contended case)
391 : *
392 : * We start with 2 leases, and check how one can
393 : * be upgraded
394 : *
395 : * The summary of the behaviour is this:
396 : * -------------------------------------
397 : *
398 : * If we have two leases (lease1 and lease2) on the same file,
399 : * then attempt to upgrade lease1 results in a change if and only
400 : * if the requested lease state:
401 : * - is valid,
402 : * - is strictly a superset of lease1, and
403 : * - can held together with lease2.
404 : *
405 : * In that case, the resuling lease state of the upgraded lease1
406 : * is the state requested in the upgrade. lease2 is not broken
407 : * and remains unchanged.
408 : *
409 : * Note that this contrasts the case of directly opening with
410 : * an initial requested lease state, in which case you get that
411 : * portion of the requested state that can be shared with the
412 : * already existing leases (or the states that they get broken to).
413 : */
414 : struct lease_upgrade3_test {
415 : const char *held1;
416 : const char *held2;
417 : const char *upgrade_to;
418 : const char *upgraded_to;
419 : };
420 :
421 : #define NUM_UPGRADE3_TESTS ( 20 )
422 : struct lease_upgrade3_test lease_upgrade3_tests[NUM_UPGRADE3_TESTS] = {
423 : {"R", "R", "", "R" },
424 : {"R", "R", "R", "R" },
425 : {"R", "R", "RW", "R" },
426 : {"R", "R", "RH", "RH" },
427 : {"R", "R", "RHW", "R" },
428 :
429 : {"R", "RH", "", "R" },
430 : {"R", "RH", "R", "R" },
431 : {"R", "RH", "RW", "R" },
432 : {"R", "RH", "RH", "RH" },
433 : {"R", "RH", "RHW", "R" },
434 :
435 : {"RH", "R", "", "RH" },
436 : {"RH", "R", "R", "RH" },
437 : {"RH", "R", "RW", "RH" },
438 : {"RH", "R", "RH", "RH" },
439 : {"RH", "R", "RHW", "RH" },
440 :
441 : {"RH", "RH", "", "RH" },
442 : {"RH", "RH", "R", "RH" },
443 : {"RH", "RH", "RW", "RH" },
444 : {"RH", "RH", "RH", "RH" },
445 : {"RH", "RH", "RHW", "RH" },
446 : };
447 :
448 0 : static bool test_lease_upgrade3(struct torture_context *tctx,
449 : struct smb2_tree *tree)
450 : {
451 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
452 : struct smb2_handle h, h2, hnew;
453 : NTSTATUS status;
454 : struct smb2_create io;
455 : struct smb2_lease ls;
456 0 : const char *fname = "lease_upgrade3.dat";
457 0 : bool ret = true;
458 : int i;
459 : uint32_t caps;
460 :
461 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
462 0 : if (!(caps & SMB2_CAP_LEASING)) {
463 0 : torture_skip(tctx, "leases are not supported");
464 : }
465 :
466 0 : tree->session->transport->lease.handler = torture_lease_handler;
467 0 : tree->session->transport->lease.private_data = tree;
468 :
469 0 : smb2_util_unlink(tree, fname);
470 :
471 0 : for (i = 0; i < NUM_UPGRADE3_TESTS; i++) {
472 0 : struct lease_upgrade3_test t = lease_upgrade3_tests[i];
473 :
474 0 : smb2_util_unlink(tree, fname);
475 :
476 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
477 :
478 : /* grab first lease */
479 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.held1));
480 0 : status = smb2_create(tree, mem_ctx, &io);
481 0 : CHECK_STATUS(status, NT_STATUS_OK);
482 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
483 0 : CHECK_LEASE(&io, t.held1, true, LEASE1, 0);
484 0 : h = io.out.file.handle;
485 :
486 : /* grab second lease */
487 0 : smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(t.held2));
488 0 : status = smb2_create(tree, mem_ctx, &io);
489 0 : CHECK_STATUS(status, NT_STATUS_OK);
490 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
491 0 : CHECK_LEASE(&io, t.held2, true, LEASE2, 0);
492 0 : h2 = io.out.file.handle;
493 :
494 : /* no break has happened */
495 0 : CHECK_VAL(lease_break_info.count, 0);
496 0 : CHECK_VAL(lease_break_info.failures, 0);
497 :
498 : /* try to upgrade lease1 */
499 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
500 0 : status = smb2_create(tree, mem_ctx, &io);
501 0 : CHECK_STATUS(status, NT_STATUS_OK);
502 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
503 0 : CHECK_LEASE(&io, t.upgraded_to, true, LEASE1, 0);
504 0 : hnew = io.out.file.handle;
505 :
506 : /* no break has happened */
507 0 : CHECK_VAL(lease_break_info.count, 0);
508 0 : CHECK_VAL(lease_break_info.failures, 0);
509 :
510 0 : smb2_util_close(tree, hnew);
511 0 : smb2_util_close(tree, h);
512 0 : smb2_util_close(tree, h2);
513 : }
514 :
515 0 : done:
516 0 : smb2_util_close(tree, h);
517 0 : smb2_util_close(tree, hnew);
518 0 : smb2_util_close(tree, h2);
519 :
520 0 : smb2_util_unlink(tree, fname);
521 :
522 0 : talloc_free(mem_ctx);
523 :
524 0 : return ret;
525 : }
526 :
527 :
528 :
529 : /*
530 : break_results should be read as "held lease, new lease, hold broken to, new
531 : grant", i.e. { "RH", "RW", "RH", "R" } means that if key1 holds RH and key2
532 : tries for RW, key1 will be broken to RH (in this case, not broken at all)
533 : and key2 will be granted R.
534 :
535 : Note: break_results only includes things that Win7 will actually grant (see
536 : request_results above).
537 : */
538 : #define NBREAK_RESULTS 16
539 : static const char *break_results[NBREAK_RESULTS][4] = {
540 : {"R", "R", "R", "R"},
541 : {"R", "RH", "R", "RH"},
542 : {"R", "RW", "R", "R"},
543 : {"R", "RHW", "R", "RH"},
544 :
545 : {"RH", "R", "RH", "R"},
546 : {"RH", "RH", "RH", "RH"},
547 : {"RH", "RW", "RH", "R"},
548 : {"RH", "RHW", "RH", "RH"},
549 :
550 : {"RW", "R", "R", "R"},
551 : {"RW", "RH", "R", "RH"},
552 : {"RW", "RW", "R", "R"},
553 : {"RW", "RHW", "R", "RH"},
554 :
555 : {"RHW", "R", "RH", "R"},
556 : {"RHW", "RH", "RH", "RH"},
557 : {"RHW", "RW", "RH", "R"},
558 : {"RHW", "RHW", "RH", "RH"},
559 : };
560 :
561 0 : static bool test_lease_break(struct torture_context *tctx,
562 : struct smb2_tree *tree)
563 : {
564 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
565 : struct smb2_create io;
566 : struct smb2_lease ls;
567 : struct smb2_handle h, h2, h3;
568 : NTSTATUS status;
569 0 : const char *fname = "lease_break.dat";
570 0 : bool ret = true;
571 : int i;
572 : uint32_t caps;
573 :
574 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
575 0 : if (!(caps & SMB2_CAP_LEASING)) {
576 0 : torture_skip(tctx, "leases are not supported");
577 : }
578 :
579 0 : tree->session->transport->lease.handler = torture_lease_handler;
580 0 : tree->session->transport->lease.private_data = tree;
581 :
582 0 : smb2_util_unlink(tree, fname);
583 :
584 0 : for (i = 0; i < NBREAK_RESULTS; i++) {
585 0 : const char *held = break_results[i][0];
586 0 : const char *contend = break_results[i][1];
587 0 : const char *brokento = break_results[i][2];
588 0 : const char *granted = break_results[i][3];
589 0 : torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
590 : "expecting break to %s(%x) and grant of %s(%x)\n",
591 : held, smb2_util_lease_state(held), contend, smb2_util_lease_state(contend),
592 : brokento, smb2_util_lease_state(brokento), granted, smb2_util_lease_state(granted));
593 :
594 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
595 :
596 : /* Grab lease. */
597 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
598 0 : status = smb2_create(tree, mem_ctx, &io);
599 0 : CHECK_STATUS(status, NT_STATUS_OK);
600 0 : h = io.out.file.handle;
601 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
602 0 : CHECK_LEASE(&io, held, true, LEASE1, 0);
603 :
604 : /* Possibly contend lease. */
605 0 : smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(contend));
606 0 : status = smb2_create(tree, mem_ctx, &io);
607 0 : CHECK_STATUS(status, NT_STATUS_OK);
608 0 : h2 = io.out.file.handle;
609 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
610 0 : CHECK_LEASE(&io, granted, true, LEASE2, 0);
611 :
612 0 : if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
613 0 : CHECK_BREAK_INFO(held, brokento, LEASE1);
614 : } else {
615 0 : CHECK_NO_BREAK(tctx);
616 : }
617 :
618 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
619 :
620 : /*
621 : Now verify that an attempt to upgrade LEASE1 results in no
622 : break and no change in LEASE1.
623 : */
624 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
625 0 : status = smb2_create(tree, mem_ctx, &io);
626 0 : CHECK_STATUS(status, NT_STATUS_OK);
627 0 : h3 = io.out.file.handle;
628 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
629 0 : CHECK_LEASE(&io, brokento, true, LEASE1, 0);
630 0 : CHECK_VAL(lease_break_info.count, 0);
631 0 : CHECK_VAL(lease_break_info.failures, 0);
632 :
633 0 : smb2_util_close(tree, h);
634 0 : smb2_util_close(tree, h2);
635 0 : smb2_util_close(tree, h3);
636 :
637 0 : status = smb2_util_unlink(tree, fname);
638 0 : CHECK_STATUS(status, NT_STATUS_OK);
639 : }
640 :
641 0 : done:
642 0 : smb2_util_close(tree, h);
643 0 : smb2_util_close(tree, h2);
644 :
645 0 : smb2_util_unlink(tree, fname);
646 :
647 0 : talloc_free(mem_ctx);
648 :
649 0 : return ret;
650 : }
651 :
652 0 : static bool test_lease_nobreakself(struct torture_context *tctx,
653 : struct smb2_tree *tree)
654 : {
655 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
656 : struct smb2_create io;
657 : struct smb2_lease ls;
658 0 : struct smb2_handle h1 = {{0}};
659 0 : struct smb2_handle h2 = {{0}};
660 : NTSTATUS status;
661 0 : const char *fname = "lease_nobreakself.dat";
662 0 : bool ret = true;
663 : uint32_t caps;
664 0 : char c = 0;
665 :
666 0 : caps = smb2cli_conn_server_capabilities(
667 0 : tree->session->transport->conn);
668 0 : if (!(caps & SMB2_CAP_LEASING)) {
669 0 : torture_skip(tctx, "leases are not supported");
670 : }
671 :
672 0 : smb2_util_unlink(tree, fname);
673 :
674 : /* Win7 is happy to grant RHW leases on files. */
675 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1,
676 : smb2_util_lease_state("R"));
677 0 : status = smb2_create(tree, mem_ctx, &io);
678 0 : CHECK_STATUS(status, NT_STATUS_OK);
679 0 : h1 = io.out.file.handle;
680 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
681 0 : CHECK_LEASE(&io, "R", true, LEASE1, 0);
682 :
683 0 : smb2_lease_create(&io, &ls, false, fname, LEASE2,
684 : smb2_util_lease_state("R"));
685 0 : status = smb2_create(tree, mem_ctx, &io);
686 0 : CHECK_STATUS(status, NT_STATUS_OK);
687 0 : h2 = io.out.file.handle;
688 0 : CHECK_LEASE(&io, "R", true, LEASE2, 0);
689 :
690 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
691 :
692 0 : tree->session->transport->lease.handler = torture_lease_handler;
693 0 : tree->session->transport->lease.private_data = tree;
694 :
695 : /* Make sure we don't break ourselves on write */
696 :
697 0 : status = smb2_util_write(tree, h1, &c, 0, 1);
698 0 : CHECK_STATUS(status, NT_STATUS_OK);
699 0 : CHECK_BREAK_INFO("R", "", LEASE2);
700 :
701 : /* Try the other way round. First, upgrade LEASE2 to R again */
702 :
703 0 : smb2_lease_create(&io, &ls, false, fname, LEASE2,
704 : smb2_util_lease_state("R"));
705 0 : status = smb2_create(tree, mem_ctx, &io);
706 0 : CHECK_STATUS(status, NT_STATUS_OK);
707 0 : CHECK_LEASE(&io, "R", true, LEASE2, 0);
708 0 : smb2_util_close(tree, io.out.file.handle);
709 :
710 : /* Now break LEASE1 via h2 */
711 :
712 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
713 0 : status = smb2_util_write(tree, h2, &c, 0, 1);
714 0 : CHECK_STATUS(status, NT_STATUS_OK);
715 0 : CHECK_BREAK_INFO("R", "", LEASE1);
716 :
717 : /* .. and break LEASE2 via h1 */
718 :
719 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
720 0 : status = smb2_util_write(tree, h1, &c, 0, 1);
721 0 : CHECK_STATUS(status, NT_STATUS_OK);
722 0 : CHECK_BREAK_INFO("R", "", LEASE2);
723 :
724 0 : done:
725 0 : smb2_util_close(tree, h2);
726 0 : smb2_util_close(tree, h1);
727 0 : smb2_util_unlink(tree, fname);
728 0 : talloc_free(mem_ctx);
729 0 : return ret;
730 : }
731 :
732 0 : static bool test_lease_statopen(struct torture_context *tctx,
733 : struct smb2_tree *tree)
734 : {
735 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
736 : struct smb2_create io;
737 : struct smb2_lease ls;
738 0 : struct smb2_handle h1 = {{0}};
739 0 : struct smb2_handle h2 = {{0}};
740 : NTSTATUS status;
741 0 : const char *fname = "lease_statopen.dat";
742 0 : bool ret = true;
743 : uint32_t caps;
744 :
745 0 : caps = smb2cli_conn_server_capabilities(
746 0 : tree->session->transport->conn);
747 0 : if (!(caps & SMB2_CAP_LEASING)) {
748 0 : torture_skip(tctx, "leases are not supported");
749 : }
750 :
751 0 : smb2_util_unlink(tree, fname);
752 :
753 : /* Create file. */
754 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1,
755 : smb2_util_lease_state("RWH"));
756 0 : status = smb2_create(tree, mem_ctx, &io);
757 0 : CHECK_STATUS(status, NT_STATUS_OK);
758 0 : h1 = io.out.file.handle;
759 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
760 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
761 0 : smb2_util_close(tree, h1);
762 :
763 : /* Stat open file with RWH lease. */
764 0 : smb2_lease_create_share(&io, &ls, false, fname, 0, LEASE1,
765 : smb2_util_lease_state("RWH"));
766 0 : io.in.desired_access = FILE_READ_ATTRIBUTES;
767 0 : status = smb2_create(tree, mem_ctx, &io);
768 0 : CHECK_STATUS(status, NT_STATUS_OK);
769 0 : h2 = io.out.file.handle;
770 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
771 :
772 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
773 :
774 0 : tree->session->transport->lease.handler = torture_lease_handler;
775 0 : tree->session->transport->lease.private_data = tree;
776 :
777 : /* Ensure non-stat open doesn't break and gets same lease
778 : state as existing stat open. */
779 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1,
780 : smb2_util_lease_state(""));
781 0 : status = smb2_create(tree, mem_ctx, &io);
782 0 : CHECK_STATUS(status, NT_STATUS_OK);
783 0 : h1 = io.out.file.handle;
784 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
785 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
786 :
787 0 : CHECK_NO_BREAK(tctx);
788 0 : smb2_util_close(tree, h1);
789 :
790 : /* Open with conflicting lease. stat open should break down to RH */
791 0 : smb2_lease_create(&io, &ls, false, fname, LEASE2,
792 : smb2_util_lease_state("RWH"));
793 0 : status = smb2_create(tree, mem_ctx, &io);
794 0 : CHECK_STATUS(status, NT_STATUS_OK);
795 0 : h1 = io.out.file.handle;
796 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
797 0 : CHECK_LEASE(&io, "RH", true, LEASE2, 0);
798 :
799 0 : CHECK_BREAK_INFO("RWH", "RH", LEASE1);
800 :
801 0 : done:
802 0 : smb2_util_close(tree, h2);
803 0 : smb2_util_close(tree, h1);
804 0 : smb2_util_unlink(tree, fname);
805 0 : talloc_free(mem_ctx);
806 0 : return ret;
807 : }
808 :
809 0 : static bool test_lease_statopen2(struct torture_context *tctx,
810 : struct smb2_tree *tree)
811 : {
812 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
813 : struct smb2_create io;
814 : struct smb2_lease ls;
815 0 : struct smb2_handle h1 = {{0}};
816 0 : struct smb2_handle h2 = {{0}};
817 0 : struct smb2_handle h3 = {{0}};
818 : NTSTATUS status;
819 0 : const char *fname = "lease_statopen2.dat";
820 0 : bool ret = true;
821 : uint32_t caps;
822 :
823 0 : caps = smb2cli_conn_server_capabilities(
824 0 : tree->session->transport->conn);
825 0 : if (!(caps & SMB2_CAP_LEASING)) {
826 0 : torture_skip(tctx, "leases are not supported");
827 : }
828 :
829 0 : smb2_util_unlink(tree, fname);
830 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
831 0 : tree->session->transport->lease.handler = torture_lease_handler;
832 0 : tree->session->transport->lease.private_data = tree;
833 :
834 0 : status = torture_smb2_testfile(tree, fname, &h1);
835 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
836 : "smb2_create failed\n");
837 0 : smb2_util_close(tree, h1);
838 0 : ZERO_STRUCT(h1);
839 :
840 : /* Open file with RWH lease. */
841 0 : smb2_lease_create_share(&io, &ls, false, fname,
842 : smb2_util_share_access("RWD"),
843 : LEASE1,
844 : smb2_util_lease_state("RWH"));
845 0 : io.in.desired_access = SEC_FILE_WRITE_DATA;
846 0 : status = smb2_create(tree, mem_ctx, &io);
847 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
848 : "smb2_create failed\n");
849 0 : h1 = io.out.file.handle;
850 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
851 :
852 : /* Stat open */
853 0 : ZERO_STRUCT(io);
854 0 : io.in.desired_access = FILE_READ_ATTRIBUTES;
855 0 : io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
856 0 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
857 0 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
858 0 : io.in.fname = fname;
859 0 : status = smb2_create(tree, mem_ctx, &io);
860 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
861 : "smb2_create failed\n");
862 0 : h2 = io.out.file.handle;
863 :
864 : /* Open file with RWH lease. */
865 0 : smb2_lease_create_share(&io, &ls, false, fname,
866 : smb2_util_share_access("RWD"),
867 : LEASE1,
868 : smb2_util_lease_state("RWH"));
869 0 : io.in.desired_access = SEC_FILE_WRITE_DATA;
870 0 : status = smb2_create(tree, mem_ctx, &io);
871 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
872 : "smb2_create failed\n");
873 0 : h3 = io.out.file.handle;
874 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
875 :
876 0 : done:
877 0 : if (!smb2_util_handle_empty(h3)) {
878 0 : smb2_util_close(tree, h3);
879 : }
880 0 : if (!smb2_util_handle_empty(h2)) {
881 0 : smb2_util_close(tree, h2);
882 : }
883 0 : if (!smb2_util_handle_empty(h1)) {
884 0 : smb2_util_close(tree, h1);
885 : }
886 0 : smb2_util_unlink(tree, fname);
887 0 : talloc_free(mem_ctx);
888 0 : return ret;
889 : }
890 :
891 0 : static bool test_lease_statopen3(struct torture_context *tctx,
892 : struct smb2_tree *tree)
893 : {
894 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
895 : struct smb2_create io;
896 : struct smb2_lease ls;
897 0 : struct smb2_handle h1 = {{0}};
898 0 : struct smb2_handle h2 = {{0}};
899 : NTSTATUS status;
900 0 : const char *fname = "lease_statopen3.dat";
901 0 : bool ret = true;
902 : uint32_t caps;
903 :
904 0 : caps = smb2cli_conn_server_capabilities(
905 0 : tree->session->transport->conn);
906 0 : if (!(caps & SMB2_CAP_LEASING)) {
907 0 : torture_skip(tctx, "leases are not supported");
908 : }
909 :
910 0 : smb2_util_unlink(tree, fname);
911 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
912 0 : tree->session->transport->lease.handler = torture_lease_handler;
913 0 : tree->session->transport->lease.private_data = tree;
914 :
915 0 : status = torture_smb2_testfile(tree, fname, &h1);
916 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
917 : "smb2_create failed\n");
918 0 : smb2_util_close(tree, h1);
919 0 : ZERO_STRUCT(h1);
920 :
921 : /* Stat open */
922 0 : ZERO_STRUCT(io);
923 0 : io.in.desired_access = FILE_READ_ATTRIBUTES;
924 0 : io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
925 0 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
926 0 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
927 0 : io.in.fname = fname;
928 0 : status = smb2_create(tree, mem_ctx, &io);
929 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
930 : "smb2_create failed\n");
931 0 : h1 = io.out.file.handle;
932 :
933 : /* Open file with RWH lease. */
934 0 : smb2_lease_create_share(&io, &ls, false, fname,
935 : smb2_util_share_access("RWD"),
936 : LEASE1,
937 : smb2_util_lease_state("RWH"));
938 0 : io.in.desired_access = SEC_FILE_WRITE_DATA;
939 0 : status = smb2_create(tree, mem_ctx, &io);
940 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
941 : "smb2_create failed\n");
942 0 : h2 = io.out.file.handle;
943 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
944 :
945 0 : done:
946 0 : if (!smb2_util_handle_empty(h1)) {
947 0 : smb2_util_close(tree, h1);
948 : }
949 0 : if (!smb2_util_handle_empty(h2)) {
950 0 : smb2_util_close(tree, h2);
951 : }
952 0 : smb2_util_unlink(tree, fname);
953 0 : talloc_free(mem_ctx);
954 0 : return ret;
955 : }
956 :
957 0 : static bool test_lease_statopen4_do(struct torture_context *tctx,
958 : struct smb2_tree *tree,
959 : uint32_t access_mask,
960 : bool expect_stat_open)
961 : {
962 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
963 : struct smb2_create io;
964 : struct smb2_lease ls;
965 0 : struct smb2_handle h1 = {{0}};
966 0 : struct smb2_handle h2 = {{0}};
967 0 : struct smb2_handle h3 = {{0}};
968 : NTSTATUS status;
969 0 : const char *fname = "lease_statopen2.dat";
970 0 : bool ret = true;
971 :
972 : /* Open file with RWH lease. */
973 0 : smb2_lease_create_share(&io, &ls, false, fname,
974 : smb2_util_share_access("RWD"),
975 : LEASE1,
976 : smb2_util_lease_state("RWH"));
977 0 : io.in.desired_access = SEC_FILE_ALL;
978 0 : status = smb2_create(tree, mem_ctx, &io);
979 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
980 : "smb2_create failed\n");
981 0 : h1 = io.out.file.handle;
982 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
983 :
984 : /* Stat open */
985 0 : ZERO_STRUCT(io);
986 0 : io.in.desired_access = access_mask;
987 0 : io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
988 0 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
989 0 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
990 0 : io.in.fname = fname;
991 0 : status = smb2_create(tree, mem_ctx, &io);
992 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
993 : "smb2_create failed\n");
994 0 : h2 = io.out.file.handle;
995 :
996 0 : if (expect_stat_open) {
997 0 : CHECK_NO_BREAK(tctx);
998 0 : if (!ret) {
999 0 : goto done;
1000 : }
1001 : } else {
1002 0 : CHECK_VAL(lease_break_info.count, 1);
1003 0 : if (!ret) {
1004 0 : goto done;
1005 : }
1006 : /*
1007 : * Don't bother checking the lease state of an additional open
1008 : * below...
1009 : */
1010 0 : goto done;
1011 : }
1012 :
1013 : /* Open file with RWH lease. */
1014 0 : smb2_lease_create_share(&io, &ls, false, fname,
1015 : smb2_util_share_access("RWD"),
1016 : LEASE1,
1017 : smb2_util_lease_state("RWH"));
1018 0 : io.in.desired_access = SEC_FILE_WRITE_DATA;
1019 0 : status = smb2_create(tree, mem_ctx, &io);
1020 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1021 : "smb2_create failed\n");
1022 0 : h3 = io.out.file.handle;
1023 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
1024 :
1025 0 : done:
1026 0 : if (!smb2_util_handle_empty(h3)) {
1027 0 : smb2_util_close(tree, h3);
1028 : }
1029 0 : if (!smb2_util_handle_empty(h2)) {
1030 0 : smb2_util_close(tree, h2);
1031 : }
1032 0 : if (!smb2_util_handle_empty(h1)) {
1033 0 : smb2_util_close(tree, h1);
1034 : }
1035 0 : talloc_free(mem_ctx);
1036 0 : return ret;
1037 : }
1038 :
1039 0 : static bool test_lease_statopen4(struct torture_context *tctx,
1040 : struct smb2_tree *tree)
1041 : {
1042 0 : const char *fname = "lease_statopen4.dat";
1043 0 : struct smb2_handle h1 = {{0}};
1044 : uint32_t caps;
1045 : size_t i;
1046 : NTSTATUS status;
1047 0 : bool ret = true;
1048 : struct {
1049 : uint32_t access_mask;
1050 : bool expect_stat_open;
1051 0 : } tests[] = {
1052 : {
1053 : .access_mask = FILE_READ_DATA,
1054 : .expect_stat_open = false,
1055 : },
1056 : {
1057 : .access_mask = FILE_WRITE_DATA,
1058 : .expect_stat_open = false,
1059 : },
1060 : {
1061 : .access_mask = FILE_READ_EA,
1062 : .expect_stat_open = false,
1063 : },
1064 : {
1065 : .access_mask = FILE_WRITE_EA,
1066 : .expect_stat_open = false,
1067 : },
1068 : {
1069 : .access_mask = FILE_EXECUTE,
1070 : .expect_stat_open = false,
1071 : },
1072 : {
1073 : .access_mask = FILE_READ_ATTRIBUTES,
1074 : .expect_stat_open = true,
1075 : },
1076 : {
1077 : .access_mask = FILE_WRITE_ATTRIBUTES,
1078 : .expect_stat_open = true,
1079 : },
1080 : {
1081 : .access_mask = DELETE_ACCESS,
1082 : .expect_stat_open = false,
1083 : },
1084 : {
1085 : .access_mask = READ_CONTROL_ACCESS,
1086 : .expect_stat_open = true,
1087 : },
1088 : {
1089 : .access_mask = WRITE_DAC_ACCESS,
1090 : .expect_stat_open = false,
1091 : },
1092 : {
1093 : .access_mask = WRITE_OWNER_ACCESS,
1094 : .expect_stat_open = false,
1095 : },
1096 : {
1097 : .access_mask = SYNCHRONIZE_ACCESS,
1098 : .expect_stat_open = true,
1099 : },
1100 : };
1101 :
1102 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1103 0 : if (!(caps & SMB2_CAP_LEASING)) {
1104 0 : torture_skip(tctx, "leases are not supported");
1105 : }
1106 :
1107 0 : smb2_util_unlink(tree, fname);
1108 0 : tree->session->transport->lease.handler = torture_lease_handler;
1109 0 : tree->session->transport->lease.private_data = tree;
1110 :
1111 0 : status = torture_smb2_testfile(tree, fname, &h1);
1112 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1113 : "smb2_create failed\n");
1114 0 : smb2_util_close(tree, h1);
1115 0 : ZERO_STRUCT(h1);
1116 :
1117 0 : for (i = 0; i < ARRAY_SIZE(tests); i++) {
1118 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1119 :
1120 0 : ret = test_lease_statopen4_do(tctx,
1121 : tree,
1122 : tests[i].access_mask,
1123 0 : tests[i].expect_stat_open);
1124 0 : if (ret == true) {
1125 0 : continue;
1126 : }
1127 0 : torture_result(tctx, TORTURE_FAIL,
1128 : "test %zu: access_mask: %s, "
1129 : "expect_stat_open: %s\n",
1130 : i,
1131 : get_sec_mask_str(tree, tests[i].access_mask),
1132 0 : tests[i].expect_stat_open ? "yes" : "no");
1133 0 : goto done;
1134 : }
1135 :
1136 0 : done:
1137 0 : smb2_util_unlink(tree, fname);
1138 0 : return ret;
1139 : }
1140 :
1141 0 : static void torture_oplock_break_callback(struct smb2_request *req)
1142 : {
1143 : NTSTATUS status;
1144 : struct smb2_break br;
1145 :
1146 0 : ZERO_STRUCT(br);
1147 0 : status = smb2_break_recv(req, &br);
1148 0 : if (!NT_STATUS_IS_OK(status))
1149 0 : lease_break_info.oplock_failures++;
1150 :
1151 0 : return;
1152 : }
1153 :
1154 : /* a oplock break request handler */
1155 0 : static bool torture_oplock_handler(struct smb2_transport *transport,
1156 : const struct smb2_handle *handle,
1157 : uint8_t level, void *private_data)
1158 : {
1159 0 : struct smb2_tree *tree = private_data;
1160 : struct smb2_request *req;
1161 : struct smb2_break br;
1162 :
1163 0 : lease_break_info.oplock_handle = *handle;
1164 0 : lease_break_info.oplock_level = level;
1165 0 : lease_break_info.oplock_count++;
1166 :
1167 0 : ZERO_STRUCT(br);
1168 0 : br.in.file.handle = *handle;
1169 0 : br.in.oplock_level = level;
1170 :
1171 0 : if (lease_break_info.held_oplock_level > SMB2_OPLOCK_LEVEL_II) {
1172 0 : req = smb2_break_send(tree, &br);
1173 0 : req->async.fn = torture_oplock_break_callback;
1174 0 : req->async.private_data = NULL;
1175 : }
1176 0 : lease_break_info.held_oplock_level = level;
1177 :
1178 0 : return true;
1179 : }
1180 :
1181 : #define NOPLOCK_RESULTS 12
1182 : static const char *oplock_results[NOPLOCK_RESULTS][4] = {
1183 : {"R", "s", "R", "s"},
1184 : {"R", "x", "R", "s"},
1185 : {"R", "b", "R", "s"},
1186 :
1187 : {"RH", "s", "RH", ""},
1188 : {"RH", "x", "RH", ""},
1189 : {"RH", "b", "RH", ""},
1190 :
1191 : {"RW", "s", "R", "s"},
1192 : {"RW", "x", "R", "s"},
1193 : {"RW", "b", "R", "s"},
1194 :
1195 : {"RHW", "s", "RH", ""},
1196 : {"RHW", "x", "RH", ""},
1197 : {"RHW", "b", "RH", ""},
1198 : };
1199 :
1200 : static const char *oplock_results_2[NOPLOCK_RESULTS][4] = {
1201 : {"s", "R", "s", "R"},
1202 : {"s", "RH", "s", "R"},
1203 : {"s", "RW", "s", "R"},
1204 : {"s", "RHW", "s", "R"},
1205 :
1206 : {"x", "R", "s", "R"},
1207 : {"x", "RH", "s", "R"},
1208 : {"x", "RW", "s", "R"},
1209 : {"x", "RHW", "s", "R"},
1210 :
1211 : {"b", "R", "s", "R"},
1212 : {"b", "RH", "s", "R"},
1213 : {"b", "RW", "s", "R"},
1214 : {"b", "RHW", "s", "R"},
1215 : };
1216 :
1217 0 : static bool test_lease_oplock(struct torture_context *tctx,
1218 : struct smb2_tree *tree)
1219 : {
1220 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1221 : struct smb2_create io;
1222 : struct smb2_lease ls;
1223 : struct smb2_handle h, h2;
1224 : NTSTATUS status;
1225 0 : const char *fname = "lease_oplock.dat";
1226 0 : bool ret = true;
1227 : int i;
1228 : uint32_t caps;
1229 :
1230 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1231 0 : if (!(caps & SMB2_CAP_LEASING)) {
1232 0 : torture_skip(tctx, "leases are not supported");
1233 : }
1234 :
1235 0 : tree->session->transport->lease.handler = torture_lease_handler;
1236 0 : tree->session->transport->lease.private_data = tree;
1237 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
1238 0 : tree->session->transport->oplock.private_data = tree;
1239 :
1240 0 : smb2_util_unlink(tree, fname);
1241 :
1242 0 : for (i = 0; i < NOPLOCK_RESULTS; i++) {
1243 0 : const char *held = oplock_results[i][0];
1244 0 : const char *contend = oplock_results[i][1];
1245 0 : const char *brokento = oplock_results[i][2];
1246 0 : const char *granted = oplock_results[i][3];
1247 0 : torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1248 : "expecting break to %s(%x) and grant of %s(%x)\n",
1249 0 : held, smb2_util_lease_state(held), contend, smb2_util_oplock_level(contend),
1250 0 : brokento, smb2_util_lease_state(brokento), granted, smb2_util_oplock_level(granted));
1251 :
1252 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1253 :
1254 : /* Grab lease. */
1255 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
1256 0 : status = smb2_create(tree, mem_ctx, &io);
1257 0 : CHECK_STATUS(status, NT_STATUS_OK);
1258 0 : h = io.out.file.handle;
1259 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1260 0 : CHECK_LEASE(&io, held, true, LEASE1, 0);
1261 :
1262 : /* Does an oplock contend the lease? */
1263 0 : smb2_oplock_create(&io, fname, smb2_util_oplock_level(contend));
1264 0 : status = smb2_create(tree, mem_ctx, &io);
1265 0 : CHECK_STATUS(status, NT_STATUS_OK);
1266 0 : h2 = io.out.file.handle;
1267 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1268 0 : CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(granted));
1269 0 : lease_break_info.held_oplock_level = io.out.oplock_level;
1270 :
1271 0 : if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
1272 0 : CHECK_BREAK_INFO(held, brokento, LEASE1);
1273 : } else {
1274 0 : CHECK_NO_BREAK(tctx);
1275 : }
1276 :
1277 0 : smb2_util_close(tree, h);
1278 0 : smb2_util_close(tree, h2);
1279 :
1280 0 : status = smb2_util_unlink(tree, fname);
1281 0 : CHECK_STATUS(status, NT_STATUS_OK);
1282 : }
1283 :
1284 0 : for (i = 0; i < NOPLOCK_RESULTS; i++) {
1285 0 : const char *held = oplock_results_2[i][0];
1286 0 : const char *contend = oplock_results_2[i][1];
1287 0 : const char *brokento = oplock_results_2[i][2];
1288 0 : const char *granted = oplock_results_2[i][3];
1289 0 : torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1290 : "expecting break to %s(%x) and grant of %s(%x)\n",
1291 0 : held, smb2_util_oplock_level(held), contend, smb2_util_lease_state(contend),
1292 0 : brokento, smb2_util_oplock_level(brokento), granted, smb2_util_lease_state(granted));
1293 :
1294 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1295 :
1296 : /* Grab an oplock. */
1297 0 : smb2_oplock_create(&io, fname, smb2_util_oplock_level(held));
1298 0 : status = smb2_create(tree, mem_ctx, &io);
1299 0 : CHECK_STATUS(status, NT_STATUS_OK);
1300 0 : h = io.out.file.handle;
1301 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1302 0 : CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(held));
1303 0 : lease_break_info.held_oplock_level = io.out.oplock_level;
1304 :
1305 : /* Grab lease. */
1306 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(contend));
1307 0 : status = smb2_create(tree, mem_ctx, &io);
1308 0 : CHECK_STATUS(status, NT_STATUS_OK);
1309 0 : h2 = io.out.file.handle;
1310 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1311 0 : CHECK_LEASE(&io, granted, true, LEASE1, 0);
1312 :
1313 0 : if (smb2_util_oplock_level(held) != smb2_util_oplock_level(brokento)) {
1314 0 : CHECK_OPLOCK_BREAK(brokento);
1315 : } else {
1316 0 : CHECK_NO_BREAK(tctx);
1317 : }
1318 :
1319 0 : smb2_util_close(tree, h);
1320 0 : smb2_util_close(tree, h2);
1321 :
1322 0 : status = smb2_util_unlink(tree, fname);
1323 0 : CHECK_STATUS(status, NT_STATUS_OK);
1324 : }
1325 :
1326 0 : done:
1327 0 : smb2_util_close(tree, h);
1328 0 : smb2_util_close(tree, h2);
1329 :
1330 0 : smb2_util_unlink(tree, fname);
1331 :
1332 0 : talloc_free(mem_ctx);
1333 :
1334 0 : return ret;
1335 : }
1336 :
1337 0 : static bool test_lease_multibreak(struct torture_context *tctx,
1338 : struct smb2_tree *tree)
1339 : {
1340 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1341 : struct smb2_create io;
1342 : struct smb2_lease ls;
1343 0 : struct smb2_handle h = {{0}};
1344 0 : struct smb2_handle h2 = {{0}};
1345 0 : struct smb2_handle h3 = {{0}};
1346 : struct smb2_write w;
1347 : NTSTATUS status;
1348 0 : const char *fname = "lease_multibreak.dat";
1349 0 : bool ret = true;
1350 : uint32_t caps;
1351 :
1352 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1353 0 : if (!(caps & SMB2_CAP_LEASING)) {
1354 0 : torture_skip(tctx, "leases are not supported");
1355 : }
1356 :
1357 0 : tree->session->transport->lease.handler = torture_lease_handler;
1358 0 : tree->session->transport->lease.private_data = tree;
1359 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
1360 0 : tree->session->transport->oplock.private_data = tree;
1361 :
1362 0 : smb2_util_unlink(tree, fname);
1363 :
1364 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1365 :
1366 : /* Grab lease, upgrade to RHW .. */
1367 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
1368 0 : status = smb2_create(tree, mem_ctx, &io);
1369 0 : CHECK_STATUS(status, NT_STATUS_OK);
1370 0 : h = io.out.file.handle;
1371 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1372 0 : CHECK_LEASE(&io, "RH", true, LEASE1, 0);
1373 :
1374 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
1375 0 : status = smb2_create(tree, mem_ctx, &io);
1376 0 : CHECK_STATUS(status, NT_STATUS_OK);
1377 0 : h2 = io.out.file.handle;
1378 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1379 0 : CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1380 :
1381 : /* Contend with LEASE2. */
1382 0 : smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state("RHW"));
1383 0 : status = smb2_create(tree, mem_ctx, &io);
1384 0 : CHECK_STATUS(status, NT_STATUS_OK);
1385 0 : h3 = io.out.file.handle;
1386 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1387 0 : CHECK_LEASE(&io, "RH", true, LEASE2, 0);
1388 :
1389 : /* Verify that we were only sent one break. */
1390 0 : CHECK_BREAK_INFO("RHW", "RH", LEASE1);
1391 :
1392 : /* Drop LEASE1 / LEASE2 */
1393 0 : status = smb2_util_close(tree, h);
1394 0 : CHECK_STATUS(status, NT_STATUS_OK);
1395 0 : status = smb2_util_close(tree, h2);
1396 0 : CHECK_STATUS(status, NT_STATUS_OK);
1397 0 : status = smb2_util_close(tree, h3);
1398 0 : CHECK_STATUS(status, NT_STATUS_OK);
1399 :
1400 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1401 :
1402 : /* Grab an R lease. */
1403 0 : smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("R"));
1404 0 : status = smb2_create(tree, mem_ctx, &io);
1405 0 : CHECK_STATUS(status, NT_STATUS_OK);
1406 0 : h = io.out.file.handle;
1407 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1408 0 : CHECK_LEASE(&io, "R", true, LEASE1, 0);
1409 :
1410 : /* Grab a level-II oplock. */
1411 0 : smb2_oplock_create(&io, fname, smb2_util_oplock_level("s"));
1412 0 : status = smb2_create(tree, mem_ctx, &io);
1413 0 : CHECK_STATUS(status, NT_STATUS_OK);
1414 0 : h2 = io.out.file.handle;
1415 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1416 0 : CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
1417 0 : lease_break_info.held_oplock_level = io.out.oplock_level;
1418 :
1419 : /* Verify no breaks. */
1420 0 : CHECK_NO_BREAK(tctx);
1421 :
1422 : /* Open for truncate, force a break. */
1423 0 : smb2_generic_create(&io, NULL, false, fname,
1424 0 : NTCREATEX_DISP_OVERWRITE_IF, smb2_util_oplock_level(""), 0, 0);
1425 0 : status = smb2_create(tree, mem_ctx, &io);
1426 0 : CHECK_STATUS(status, NT_STATUS_OK);
1427 0 : h3 = io.out.file.handle;
1428 0 : CHECK_CREATED(&io, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
1429 0 : CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(""));
1430 0 : lease_break_info.held_oplock_level = io.out.oplock_level;
1431 :
1432 : /* Sleep, use a write to clear the recv queue. */
1433 0 : smb_msleep(250);
1434 0 : ZERO_STRUCT(w);
1435 0 : w.in.file.handle = h3;
1436 0 : w.in.offset = 0;
1437 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1438 0 : memset(w.in.data.data, 'o', w.in.data.length);
1439 0 : status = smb2_write(tree, &w);
1440 0 : CHECK_STATUS(status, NT_STATUS_OK);
1441 :
1442 : /* Verify one oplock break, one lease break. */
1443 0 : CHECK_OPLOCK_BREAK("");
1444 0 : CHECK_BREAK_INFO("R", "", LEASE1);
1445 :
1446 0 : done:
1447 0 : smb2_util_close(tree, h);
1448 0 : smb2_util_close(tree, h2);
1449 0 : smb2_util_close(tree, h3);
1450 :
1451 0 : smb2_util_unlink(tree, fname);
1452 :
1453 0 : talloc_free(mem_ctx);
1454 :
1455 0 : return ret;
1456 : }
1457 :
1458 0 : static bool test_lease_v2_request_parent(struct torture_context *tctx,
1459 : struct smb2_tree *tree)
1460 : {
1461 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1462 : struct smb2_create io;
1463 : struct smb2_lease ls;
1464 0 : struct smb2_handle h1 = {{0}};
1465 0 : uint64_t parent = LEASE2;
1466 : NTSTATUS status;
1467 0 : const char *fname = "lease_v2_request_parent.dat";
1468 0 : bool ret = true;
1469 : uint32_t caps;
1470 : enum protocol_types protocol;
1471 :
1472 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1473 0 : if (!(caps & SMB2_CAP_LEASING)) {
1474 0 : torture_skip(tctx, "leases are not supported");
1475 : }
1476 0 : if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1477 0 : torture_skip(tctx, "directory leases are not supported");
1478 : }
1479 :
1480 0 : protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1481 0 : if (protocol < PROTOCOL_SMB3_00) {
1482 0 : torture_skip(tctx, "v2 leases are not supported");
1483 : }
1484 :
1485 0 : smb2_util_unlink(tree, fname);
1486 :
1487 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1488 :
1489 0 : ZERO_STRUCT(io);
1490 0 : smb2_lease_v2_create_share(&io, &ls, false, fname,
1491 : smb2_util_share_access("RWD"),
1492 : LEASE1, &parent,
1493 : smb2_util_lease_state("RHW"),
1494 : 0x11);
1495 :
1496 0 : status = smb2_create(tree, mem_ctx, &io);
1497 0 : CHECK_STATUS(status, NT_STATUS_OK);
1498 0 : h1 = io.out.file.handle;
1499 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1500 0 : CHECK_LEASE_V2(&io, "RHW", true, LEASE1,
1501 : SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1502 : ls.lease_epoch + 1);
1503 :
1504 0 : done:
1505 0 : smb2_util_close(tree, h1);
1506 0 : smb2_util_unlink(tree, fname);
1507 :
1508 0 : talloc_free(mem_ctx);
1509 :
1510 0 : return ret;
1511 : }
1512 :
1513 0 : static bool test_lease_break_twice(struct torture_context *tctx,
1514 : struct smb2_tree *tree)
1515 : {
1516 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1517 : struct smb2_create io;
1518 : struct smb2_lease ls1;
1519 : struct smb2_lease ls2;
1520 0 : struct smb2_handle h1 = {{0}};
1521 : NTSTATUS status;
1522 0 : const char *fname = "lease_break_twice.dat";
1523 0 : bool ret = true;
1524 : uint32_t caps;
1525 : enum protocol_types protocol;
1526 :
1527 0 : caps = smb2cli_conn_server_capabilities(
1528 0 : tree->session->transport->conn);
1529 0 : if (!(caps & SMB2_CAP_LEASING)) {
1530 0 : torture_skip(tctx, "leases are not supported");
1531 : }
1532 :
1533 0 : protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1534 0 : if (protocol < PROTOCOL_SMB3_00) {
1535 0 : torture_skip(tctx, "v2 leases are not supported");
1536 : }
1537 :
1538 0 : smb2_util_unlink(tree, fname);
1539 :
1540 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1541 0 : ZERO_STRUCT(io);
1542 :
1543 0 : smb2_lease_v2_create_share(
1544 : &io, &ls1, false, fname, smb2_util_share_access("RWD"),
1545 : LEASE1, NULL, smb2_util_lease_state("RWH"), 0x11);
1546 :
1547 0 : status = smb2_create(tree, mem_ctx, &io);
1548 0 : CHECK_STATUS(status, NT_STATUS_OK);
1549 0 : h1 = io.out.file.handle;
1550 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1551 0 : CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1552 :
1553 0 : tree->session->transport->lease.handler = torture_lease_handler;
1554 0 : tree->session->transport->lease.private_data = tree;
1555 :
1556 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1557 :
1558 0 : smb2_lease_v2_create_share(
1559 : &io, &ls2, false, fname, smb2_util_share_access("R"),
1560 : LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1561 :
1562 0 : status = smb2_create(tree, mem_ctx, &io);
1563 0 : CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1564 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
1565 : "RWH", "RW", LEASE1, ls1.lease_epoch + 2);
1566 :
1567 0 : smb2_lease_v2_create_share(
1568 : &io, &ls2, false, fname, smb2_util_share_access("RWD"),
1569 : LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1570 :
1571 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1572 :
1573 0 : status = smb2_create(tree, mem_ctx, &io);
1574 0 : CHECK_STATUS(status, NT_STATUS_OK);
1575 0 : CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1576 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
1577 : "RW", "R", LEASE1, ls1.lease_epoch + 3);
1578 :
1579 0 : done:
1580 0 : smb2_util_close(tree, h1);
1581 0 : smb2_util_unlink(tree, fname);
1582 0 : talloc_free(mem_ctx);
1583 0 : return ret;
1584 : }
1585 :
1586 0 : static bool test_lease_v2_request(struct torture_context *tctx,
1587 : struct smb2_tree *tree)
1588 : {
1589 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1590 : struct smb2_create io;
1591 : struct smb2_lease ls1, ls2, ls2t, ls3, ls4;
1592 0 : struct smb2_handle h1 = {{0}};
1593 0 : struct smb2_handle h2 = {{0}};
1594 0 : struct smb2_handle h3 = {{0}};
1595 0 : struct smb2_handle h4 = {{0}};
1596 0 : struct smb2_handle h5 = {{0}};
1597 : struct smb2_write w;
1598 : NTSTATUS status;
1599 0 : const char *fname = "lease_v2_request.dat";
1600 0 : const char *dname = "lease_v2_request.dir";
1601 0 : const char *dnamefname = "lease_v2_request.dir\\lease.dat";
1602 0 : const char *dnamefname2 = "lease_v2_request.dir\\lease2.dat";
1603 0 : bool ret = true;
1604 : uint32_t caps;
1605 : enum protocol_types protocol;
1606 :
1607 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1608 0 : if (!(caps & SMB2_CAP_LEASING)) {
1609 0 : torture_skip(tctx, "leases are not supported");
1610 : }
1611 0 : if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1612 0 : torture_skip(tctx, "directory leases are not supported");
1613 : }
1614 :
1615 0 : protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1616 0 : if (protocol < PROTOCOL_SMB3_00) {
1617 0 : torture_skip(tctx, "v2 leases are not supported");
1618 : }
1619 :
1620 0 : smb2_util_unlink(tree, fname);
1621 0 : smb2_deltree(tree, dname);
1622 :
1623 0 : tree->session->transport->lease.handler = torture_lease_handler;
1624 0 : tree->session->transport->lease.private_data = tree;
1625 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
1626 0 : tree->session->transport->oplock.private_data = tree;
1627 :
1628 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1629 :
1630 0 : ZERO_STRUCT(io);
1631 0 : smb2_lease_v2_create_share(&io, &ls1, false, fname,
1632 : smb2_util_share_access("RWD"),
1633 : LEASE1, NULL,
1634 : smb2_util_lease_state("RHW"),
1635 : 0x11);
1636 :
1637 0 : status = smb2_create(tree, mem_ctx, &io);
1638 0 : CHECK_STATUS(status, NT_STATUS_OK);
1639 0 : h1 = io.out.file.handle;
1640 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1641 0 : CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1642 :
1643 0 : ZERO_STRUCT(io);
1644 0 : smb2_lease_v2_create_share(&io, &ls2, true, dname,
1645 : smb2_util_share_access("RWD"),
1646 : LEASE2, NULL,
1647 : smb2_util_lease_state("RHW"),
1648 : 0x22);
1649 0 : status = smb2_create(tree, mem_ctx, &io);
1650 0 : CHECK_STATUS(status, NT_STATUS_OK);
1651 0 : h2 = io.out.file.handle;
1652 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
1653 0 : CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1654 :
1655 0 : ZERO_STRUCT(io);
1656 0 : smb2_lease_v2_create_share(&io, &ls3, false, dnamefname,
1657 : smb2_util_share_access("RWD"),
1658 : LEASE3, &LEASE2,
1659 : smb2_util_lease_state("RHW"),
1660 : 0x33);
1661 0 : status = smb2_create(tree, mem_ctx, &io);
1662 0 : CHECK_STATUS(status, NT_STATUS_OK);
1663 0 : h3 = io.out.file.handle;
1664 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1665 0 : CHECK_LEASE_V2(&io, "RHW", true, LEASE3,
1666 : SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1667 : ls3.lease_epoch + 1);
1668 :
1669 0 : CHECK_NO_BREAK(tctx);
1670 :
1671 0 : ZERO_STRUCT(io);
1672 0 : smb2_lease_v2_create_share(&io, &ls4, false, dnamefname2,
1673 : smb2_util_share_access("RWD"),
1674 : LEASE4, NULL,
1675 : smb2_util_lease_state("RHW"),
1676 : 0x44);
1677 0 : status = smb2_create(tree, mem_ctx, &io);
1678 0 : CHECK_STATUS(status, NT_STATUS_OK);
1679 0 : h4 = io.out.file.handle;
1680 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1681 0 : CHECK_LEASE_V2(&io, "RHW", true, LEASE4, 0, 0, ls4.lease_epoch + 1);
1682 :
1683 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
1684 : "RH", "", LEASE2, ls2.lease_epoch + 2);
1685 :
1686 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1687 :
1688 0 : ZERO_STRUCT(io);
1689 0 : smb2_lease_v2_create_share(&io, &ls2t, true, dname,
1690 : smb2_util_share_access("RWD"),
1691 : LEASE2, NULL,
1692 : smb2_util_lease_state("RHW"),
1693 : 0x222);
1694 0 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
1695 0 : status = smb2_create(tree, mem_ctx, &io);
1696 0 : CHECK_STATUS(status, NT_STATUS_OK);
1697 0 : h5 = io.out.file.handle;
1698 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_DIRECTORY);
1699 0 : CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch+3);
1700 0 : smb2_util_close(tree, h5);
1701 :
1702 0 : ZERO_STRUCT(w);
1703 0 : w.in.file.handle = h4;
1704 0 : w.in.offset = 0;
1705 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1706 0 : memset(w.in.data.data, 'o', w.in.data.length);
1707 0 : status = smb2_write(tree, &w);
1708 0 : CHECK_STATUS(status, NT_STATUS_OK);
1709 :
1710 : /*
1711 : * Wait 4 seconds in order to check if the write time
1712 : * was updated (after 2 seconds).
1713 : */
1714 0 : smb_msleep(4000);
1715 0 : CHECK_NO_BREAK(tctx);
1716 :
1717 : /*
1718 : * only the close on the modified file break the
1719 : * directory lease.
1720 : */
1721 0 : smb2_util_close(tree, h4);
1722 :
1723 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
1724 : "RH", "", LEASE2, ls2.lease_epoch+4);
1725 :
1726 0 : done:
1727 0 : smb2_util_close(tree, h1);
1728 0 : smb2_util_close(tree, h2);
1729 0 : smb2_util_close(tree, h3);
1730 0 : smb2_util_close(tree, h4);
1731 0 : smb2_util_close(tree, h5);
1732 :
1733 0 : smb2_util_unlink(tree, fname);
1734 0 : smb2_deltree(tree, dname);
1735 :
1736 0 : talloc_free(mem_ctx);
1737 :
1738 0 : return ret;
1739 : }
1740 :
1741 0 : static bool test_lease_v2_epoch1(struct torture_context *tctx,
1742 : struct smb2_tree *tree)
1743 : {
1744 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1745 : struct smb2_create io;
1746 : struct smb2_lease ls;
1747 : struct smb2_handle h;
1748 0 : const char *fname = "lease_v2_epoch1.dat";
1749 0 : bool ret = true;
1750 : NTSTATUS status;
1751 : uint32_t caps;
1752 : enum protocol_types protocol;
1753 :
1754 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1755 0 : if (!(caps & SMB2_CAP_LEASING)) {
1756 0 : torture_skip(tctx, "leases are not supported");
1757 : }
1758 :
1759 0 : protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1760 0 : if (protocol < PROTOCOL_SMB3_00) {
1761 0 : torture_skip(tctx, "v2 leases are not supported");
1762 : }
1763 :
1764 0 : smb2_util_unlink(tree, fname);
1765 :
1766 0 : tree->session->transport->lease.handler = torture_lease_handler;
1767 0 : tree->session->transport->lease.private_data = tree;
1768 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
1769 0 : tree->session->transport->oplock.private_data = tree;
1770 :
1771 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1772 :
1773 0 : ZERO_STRUCT(io);
1774 0 : smb2_lease_v2_create_share(&io, &ls, false, fname,
1775 : smb2_util_share_access("RWD"),
1776 : LEASE1, NULL,
1777 : smb2_util_lease_state("RHW"),
1778 : 0x4711);
1779 0 : status = smb2_create(tree, mem_ctx, &io);
1780 0 : CHECK_STATUS(status, NT_STATUS_OK);
1781 0 : h = io.out.file.handle;
1782 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1783 0 : CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1784 0 : smb2_util_close(tree, h);
1785 0 : smb2_util_unlink(tree, fname);
1786 :
1787 0 : smb2_lease_v2_create_share(&io, &ls, false, fname,
1788 : smb2_util_share_access("RWD"),
1789 : LEASE1, NULL,
1790 : smb2_util_lease_state("RHW"),
1791 : 0x11);
1792 :
1793 0 : status = smb2_create(tree, mem_ctx, &io);
1794 0 : CHECK_STATUS(status, NT_STATUS_OK);
1795 0 : h = io.out.file.handle;
1796 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1797 0 : CHECK_LEASE_V2(&io, "RWH", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1798 0 : smb2_util_close(tree, h);
1799 :
1800 0 : done:
1801 0 : smb2_util_unlink(tree, fname);
1802 0 : talloc_free(mem_ctx);
1803 0 : return ret;
1804 : }
1805 :
1806 0 : static bool test_lease_v2_epoch2(struct torture_context *tctx,
1807 : struct smb2_tree *tree)
1808 : {
1809 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1810 : struct smb2_create io;
1811 : struct smb2_lease ls1v2, ls1v2t, ls1v1;
1812 0 : struct smb2_handle hv2 = {}, hv1 = {};
1813 0 : const char *fname = "lease_v2_epoch2.dat";
1814 0 : bool ret = true;
1815 : NTSTATUS status;
1816 : uint32_t caps;
1817 : enum protocol_types protocol;
1818 :
1819 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1820 0 : if (!(caps & SMB2_CAP_LEASING)) {
1821 0 : torture_skip(tctx, "leases are not supported");
1822 : }
1823 :
1824 0 : protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1825 0 : if (protocol < PROTOCOL_SMB3_00) {
1826 0 : torture_skip(tctx, "v2 leases are not supported");
1827 : }
1828 :
1829 0 : smb2_util_unlink(tree, fname);
1830 :
1831 0 : tree->session->transport->lease.handler = torture_lease_handler;
1832 0 : tree->session->transport->lease.private_data = tree;
1833 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
1834 0 : tree->session->transport->oplock.private_data = tree;
1835 :
1836 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1837 :
1838 0 : ZERO_STRUCT(io);
1839 0 : smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1840 : smb2_util_share_access("RWD"),
1841 : LEASE1, NULL,
1842 : smb2_util_lease_state("R"),
1843 : 0x4711);
1844 0 : status = smb2_create(tree, mem_ctx, &io);
1845 0 : CHECK_STATUS(status, NT_STATUS_OK);
1846 0 : hv2 = io.out.file.handle;
1847 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1848 0 : CHECK_LEASE_V2(&io, "R", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
1849 :
1850 0 : ZERO_STRUCT(io);
1851 0 : smb2_lease_create_share(&io, &ls1v1, false, fname,
1852 : smb2_util_share_access("RWD"),
1853 : LEASE1,
1854 : smb2_util_lease_state("RH"));
1855 0 : status = smb2_create(tree, mem_ctx, &io);
1856 0 : CHECK_STATUS(status, NT_STATUS_OK);
1857 0 : hv1 = io.out.file.handle;
1858 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1859 0 : CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1v2.lease_epoch + 2);
1860 :
1861 0 : smb2_util_close(tree, hv2);
1862 :
1863 0 : ZERO_STRUCT(io);
1864 0 : smb2_lease_v2_create_share(&io, &ls1v2t, false, fname,
1865 : smb2_util_share_access("RWD"),
1866 : LEASE1, NULL,
1867 : smb2_util_lease_state("RHW"),
1868 : 0x11);
1869 0 : status = smb2_create(tree, mem_ctx, &io);
1870 0 : CHECK_STATUS(status, NT_STATUS_OK);
1871 0 : hv2 = io.out.file.handle;
1872 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1873 0 : CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 3);
1874 :
1875 0 : smb2_util_close(tree, hv2);
1876 :
1877 0 : smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1878 0 : status = smb2_create(tree, mem_ctx, &io);
1879 0 : CHECK_STATUS(status, NT_STATUS_OK);
1880 0 : hv2 = io.out.file.handle;
1881 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1882 0 : CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1883 :
1884 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
1885 : "RWH", "RH", LEASE1, ls1v2.lease_epoch + 4);
1886 :
1887 0 : smb2_util_close(tree, hv2);
1888 0 : smb2_util_close(tree, hv1);
1889 :
1890 0 : ZERO_STRUCT(io);
1891 0 : smb2_lease_create_share(&io, &ls1v1, false, fname,
1892 : smb2_util_share_access("RWD"),
1893 : LEASE1,
1894 : smb2_util_lease_state("RHW"));
1895 0 : status = smb2_create(tree, mem_ctx, &io);
1896 0 : CHECK_STATUS(status, NT_STATUS_OK);
1897 0 : hv1 = io.out.file.handle;
1898 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1899 0 : CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1900 :
1901 0 : smb2_util_close(tree, hv1);
1902 :
1903 0 : done:
1904 0 : smb2_util_close(tree, hv2);
1905 0 : smb2_util_close(tree, hv1);
1906 0 : smb2_util_unlink(tree, fname);
1907 0 : talloc_free(mem_ctx);
1908 0 : return ret;
1909 : }
1910 :
1911 0 : static bool test_lease_v2_epoch3(struct torture_context *tctx,
1912 : struct smb2_tree *tree)
1913 : {
1914 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1915 : struct smb2_create io;
1916 0 : struct smb2_lease ls1v1 = {}, ls1v1t = {},ls1v2 = {};
1917 0 : struct smb2_handle hv1 = {}, hv2 = {};
1918 0 : const char *fname = "lease_v2_epoch3.dat";
1919 0 : bool ret = true;
1920 : NTSTATUS status;
1921 : uint32_t caps;
1922 : enum protocol_types protocol;
1923 :
1924 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1925 0 : if (!(caps & SMB2_CAP_LEASING)) {
1926 0 : torture_skip(tctx, "leases are not supported");
1927 : }
1928 :
1929 0 : protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1930 0 : if (protocol < PROTOCOL_SMB3_00) {
1931 0 : torture_skip(tctx, "v2 leases are not supported");
1932 : }
1933 :
1934 0 : smb2_util_unlink(tree, fname);
1935 :
1936 0 : tree->session->transport->lease.handler = torture_lease_handler;
1937 0 : tree->session->transport->lease.private_data = tree;
1938 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
1939 0 : tree->session->transport->oplock.private_data = tree;
1940 :
1941 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
1942 :
1943 0 : ZERO_STRUCT(io);
1944 0 : smb2_lease_create_share(&io, &ls1v1, false, fname,
1945 : smb2_util_share_access("RWD"),
1946 : LEASE1,
1947 : smb2_util_lease_state("R"));
1948 0 : status = smb2_create(tree, mem_ctx, &io);
1949 0 : CHECK_STATUS(status, NT_STATUS_OK);
1950 0 : hv1 = io.out.file.handle;
1951 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1952 0 : CHECK_LEASE(&io, "R", true, LEASE1, 0);
1953 :
1954 0 : ZERO_STRUCT(io);
1955 0 : smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1956 : smb2_util_share_access("RWD"),
1957 : LEASE1, NULL,
1958 : smb2_util_lease_state("RW"),
1959 : 0x4711);
1960 0 : status = smb2_create(tree, mem_ctx, &io);
1961 0 : CHECK_STATUS(status, NT_STATUS_OK);
1962 0 : hv2 = io.out.file.handle;
1963 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1964 0 : CHECK_LEASE(&io, "RW", true, LEASE1, 0);
1965 :
1966 0 : smb2_util_close(tree, hv1);
1967 :
1968 0 : ZERO_STRUCT(io);
1969 0 : smb2_lease_create_share(&io, &ls1v1t, false, fname,
1970 : smb2_util_share_access("RWD"),
1971 : LEASE1,
1972 : smb2_util_lease_state("RWH"));
1973 0 : status = smb2_create(tree, mem_ctx, &io);
1974 0 : CHECK_STATUS(status, NT_STATUS_OK);
1975 0 : hv1 = io.out.file.handle;
1976 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1977 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
1978 :
1979 0 : smb2_util_close(tree, hv1);
1980 :
1981 0 : smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1982 0 : status = smb2_create(tree, mem_ctx, &io);
1983 0 : CHECK_STATUS(status, NT_STATUS_OK);
1984 0 : hv1 = io.out.file.handle;
1985 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1986 0 : CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1987 :
1988 0 : CHECK_BREAK_INFO("RWH", "RH", LEASE1);
1989 :
1990 0 : smb2_util_close(tree, hv1);
1991 0 : smb2_util_close(tree, hv2);
1992 :
1993 0 : ZERO_STRUCT(io);
1994 0 : smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1995 : smb2_util_share_access("RWD"),
1996 : LEASE1, NULL,
1997 : smb2_util_lease_state("RWH"),
1998 : 0x4711);
1999 0 : status = smb2_create(tree, mem_ctx, &io);
2000 0 : CHECK_STATUS(status, NT_STATUS_OK);
2001 0 : hv2 = io.out.file.handle;
2002 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2003 0 : CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
2004 0 : smb2_util_close(tree, hv2);
2005 :
2006 0 : done:
2007 0 : smb2_util_close(tree, hv2);
2008 0 : smb2_util_close(tree, hv1);
2009 0 : smb2_util_unlink(tree, fname);
2010 0 : talloc_free(mem_ctx);
2011 0 : return ret;
2012 : }
2013 :
2014 0 : static bool test_lease_breaking1(struct torture_context *tctx,
2015 : struct smb2_tree *tree)
2016 : {
2017 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2018 0 : struct smb2_create io1 = {};
2019 0 : struct smb2_create io2 = {};
2020 0 : struct smb2_lease ls1 = {};
2021 0 : struct smb2_handle h1a = {};
2022 0 : struct smb2_handle h1b = {};
2023 0 : struct smb2_handle h2 = {};
2024 0 : struct smb2_request *req2 = NULL;
2025 0 : struct smb2_lease_break_ack ack = {};
2026 0 : const char *fname = "lease_breaking1.dat";
2027 0 : bool ret = true;
2028 : NTSTATUS status;
2029 : uint32_t caps;
2030 :
2031 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2032 0 : if (!(caps & SMB2_CAP_LEASING)) {
2033 0 : torture_skip(tctx, "leases are not supported");
2034 : }
2035 :
2036 0 : smb2_util_unlink(tree, fname);
2037 :
2038 0 : tree->session->transport->lease.handler = torture_lease_handler;
2039 0 : tree->session->transport->lease.private_data = tree;
2040 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
2041 0 : tree->session->transport->oplock.private_data = tree;
2042 :
2043 : /*
2044 : * we defer acking the lease break.
2045 : */
2046 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2047 0 : lease_break_info.lease_skip_ack = true;
2048 :
2049 0 : smb2_lease_create_share(&io1, &ls1, false, fname,
2050 : smb2_util_share_access("RWD"),
2051 : LEASE1,
2052 : smb2_util_lease_state("RWH"));
2053 0 : status = smb2_create(tree, mem_ctx, &io1);
2054 0 : CHECK_STATUS(status, NT_STATUS_OK);
2055 0 : h1a = io1.out.file.handle;
2056 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2057 0 : CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2058 :
2059 : /*
2060 : * a conflicting open is blocked until we ack the
2061 : * lease break
2062 : */
2063 0 : smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2064 0 : req2 = smb2_create_send(tree, &io2);
2065 0 : torture_assert(tctx, req2 != NULL, "smb2_create_send");
2066 :
2067 : /*
2068 : * we got the lease break, but defer the ack.
2069 : */
2070 0 : CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2071 :
2072 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2073 :
2074 0 : ack.in.lease.lease_key =
2075 : lease_break_info.lease_break.current_lease.lease_key;
2076 0 : ack.in.lease.lease_state =
2077 0 : lease_break_info.lease_break.new_lease_state;
2078 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2079 :
2080 : /*
2081 : * a open using the same lease key is still works,
2082 : * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2083 : */
2084 0 : status = smb2_create(tree, mem_ctx, &io1);
2085 0 : CHECK_STATUS(status, NT_STATUS_OK);
2086 0 : h1b = io1.out.file.handle;
2087 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2088 0 : CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2089 0 : smb2_util_close(tree, h1b);
2090 :
2091 0 : CHECK_NO_BREAK(tctx);
2092 :
2093 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2094 :
2095 : /*
2096 : * We ack the lease break.
2097 : */
2098 0 : status = smb2_lease_break_ack(tree, &ack);
2099 0 : CHECK_STATUS(status, NT_STATUS_OK);
2100 0 : CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2101 :
2102 0 : torture_assert(tctx, req2->cancel.can_cancel,
2103 : "req2 can_cancel");
2104 :
2105 0 : status = smb2_create_recv(req2, tctx, &io2);
2106 0 : CHECK_STATUS(status, NT_STATUS_OK);
2107 0 : h2 = io2.out.file.handle;
2108 0 : CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2109 0 : CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2110 :
2111 0 : CHECK_NO_BREAK(tctx);
2112 0 : done:
2113 0 : smb2_util_close(tree, h1a);
2114 0 : smb2_util_close(tree, h1b);
2115 0 : smb2_util_close(tree, h2);
2116 0 : smb2_util_unlink(tree, fname);
2117 0 : talloc_free(mem_ctx);
2118 0 : return ret;
2119 : }
2120 :
2121 0 : static bool test_lease_breaking2(struct torture_context *tctx,
2122 : struct smb2_tree *tree)
2123 : {
2124 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2125 0 : struct smb2_create io1 = {};
2126 0 : struct smb2_create io2 = {};
2127 0 : struct smb2_lease ls1 = {};
2128 0 : struct smb2_handle h1a = {};
2129 0 : struct smb2_handle h1b = {};
2130 0 : struct smb2_handle h2 = {};
2131 0 : struct smb2_request *req2 = NULL;
2132 0 : struct smb2_lease_break_ack ack = {};
2133 0 : const char *fname = "lease_breaking2.dat";
2134 0 : bool ret = true;
2135 : NTSTATUS status;
2136 : uint32_t caps;
2137 :
2138 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2139 0 : if (!(caps & SMB2_CAP_LEASING)) {
2140 0 : torture_skip(tctx, "leases are not supported");
2141 : }
2142 :
2143 0 : smb2_util_unlink(tree, fname);
2144 :
2145 0 : tree->session->transport->lease.handler = torture_lease_handler;
2146 0 : tree->session->transport->lease.private_data = tree;
2147 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
2148 0 : tree->session->transport->oplock.private_data = tree;
2149 :
2150 : /*
2151 : * we defer acking the lease break.
2152 : */
2153 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2154 0 : lease_break_info.lease_skip_ack = true;
2155 :
2156 0 : smb2_lease_create_share(&io1, &ls1, false, fname,
2157 : smb2_util_share_access("RWD"),
2158 : LEASE1,
2159 : smb2_util_lease_state("RWH"));
2160 0 : status = smb2_create(tree, mem_ctx, &io1);
2161 0 : CHECK_STATUS(status, NT_STATUS_OK);
2162 0 : h1a = io1.out.file.handle;
2163 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2164 0 : CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2165 :
2166 : /*
2167 : * a conflicting open is blocked until we ack the
2168 : * lease break
2169 : */
2170 0 : smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2171 0 : io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2172 0 : req2 = smb2_create_send(tree, &io2);
2173 0 : torture_assert(tctx, req2 != NULL, "smb2_create_send");
2174 :
2175 : /*
2176 : * we got the lease break, but defer the ack.
2177 : */
2178 0 : CHECK_BREAK_INFO("RWH", "", LEASE1);
2179 :
2180 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2181 :
2182 0 : ack.in.lease.lease_key =
2183 : lease_break_info.lease_break.current_lease.lease_key;
2184 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2185 :
2186 : /*
2187 : * a open using the same lease key is still works,
2188 : * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2189 : */
2190 0 : status = smb2_create(tree, mem_ctx, &io1);
2191 0 : CHECK_STATUS(status, NT_STATUS_OK);
2192 0 : h1b = io1.out.file.handle;
2193 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2194 0 : CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2195 0 : smb2_util_close(tree, h1b);
2196 :
2197 0 : CHECK_NO_BREAK(tctx);
2198 :
2199 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2200 :
2201 : /*
2202 : * We ack the lease break.
2203 : */
2204 0 : ack.in.lease.lease_state =
2205 : SMB2_LEASE_READ | SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
2206 0 : status = smb2_lease_break_ack(tree, &ack);
2207 0 : CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2208 :
2209 0 : ack.in.lease.lease_state =
2210 : SMB2_LEASE_READ | SMB2_LEASE_WRITE;
2211 0 : status = smb2_lease_break_ack(tree, &ack);
2212 0 : CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2213 :
2214 0 : ack.in.lease.lease_state =
2215 : SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
2216 0 : status = smb2_lease_break_ack(tree, &ack);
2217 0 : CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2218 :
2219 0 : ack.in.lease.lease_state =
2220 : SMB2_LEASE_READ | SMB2_LEASE_HANDLE;
2221 0 : status = smb2_lease_break_ack(tree, &ack);
2222 0 : CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2223 :
2224 0 : ack.in.lease.lease_state = SMB2_LEASE_WRITE;
2225 0 : status = smb2_lease_break_ack(tree, &ack);
2226 0 : CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2227 :
2228 0 : ack.in.lease.lease_state = SMB2_LEASE_HANDLE;
2229 0 : status = smb2_lease_break_ack(tree, &ack);
2230 0 : CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2231 :
2232 0 : ack.in.lease.lease_state = SMB2_LEASE_READ;
2233 0 : status = smb2_lease_break_ack(tree, &ack);
2234 0 : CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2235 :
2236 : /* Try again with the correct state this time. */
2237 0 : ack.in.lease.lease_state = SMB2_LEASE_NONE;;
2238 0 : status = smb2_lease_break_ack(tree, &ack);
2239 0 : CHECK_STATUS(status, NT_STATUS_OK);
2240 0 : CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2241 :
2242 0 : status = smb2_lease_break_ack(tree, &ack);
2243 0 : CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2244 :
2245 0 : torture_assert(tctx, req2->cancel.can_cancel,
2246 : "req2 can_cancel");
2247 :
2248 0 : status = smb2_create_recv(req2, tctx, &io2);
2249 0 : CHECK_STATUS(status, NT_STATUS_OK);
2250 0 : h2 = io2.out.file.handle;
2251 0 : CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2252 0 : CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2253 :
2254 0 : CHECK_NO_BREAK(tctx);
2255 :
2256 : /* Get state of the original handle. */
2257 0 : smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
2258 0 : status = smb2_create(tree, mem_ctx, &io1);
2259 0 : CHECK_STATUS(status, NT_STATUS_OK);
2260 0 : CHECK_LEASE(&io1, "", true, LEASE1, 0);
2261 0 : smb2_util_close(tree, io1.out.file.handle);
2262 :
2263 0 : done:
2264 0 : smb2_util_close(tree, h1a);
2265 0 : smb2_util_close(tree, h1b);
2266 0 : smb2_util_close(tree, h2);
2267 0 : smb2_util_unlink(tree, fname);
2268 0 : talloc_free(mem_ctx);
2269 0 : return ret;
2270 : }
2271 :
2272 0 : static bool test_lease_breaking3(struct torture_context *tctx,
2273 : struct smb2_tree *tree)
2274 : {
2275 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2276 0 : struct smb2_create io1 = {};
2277 0 : struct smb2_create io2 = {};
2278 0 : struct smb2_create io3 = {};
2279 0 : struct smb2_lease ls1 = {};
2280 0 : struct smb2_handle h1a = {};
2281 0 : struct smb2_handle h1b = {};
2282 0 : struct smb2_handle h2 = {};
2283 0 : struct smb2_handle h3 = {};
2284 0 : struct smb2_request *req2 = NULL;
2285 0 : struct smb2_request *req3 = NULL;
2286 0 : struct lease_break_info lease_break_info_tmp = {};
2287 0 : struct smb2_lease_break_ack ack = {};
2288 0 : const char *fname = "lease_breaking3.dat";
2289 0 : bool ret = true;
2290 : NTSTATUS status;
2291 : uint32_t caps;
2292 :
2293 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2294 0 : if (!(caps & SMB2_CAP_LEASING)) {
2295 0 : torture_skip(tctx, "leases are not supported");
2296 : }
2297 :
2298 0 : smb2_util_unlink(tree, fname);
2299 :
2300 0 : tree->session->transport->lease.handler = torture_lease_handler;
2301 0 : tree->session->transport->lease.private_data = tree;
2302 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
2303 0 : tree->session->transport->oplock.private_data = tree;
2304 :
2305 : /*
2306 : * we defer acking the lease break.
2307 : */
2308 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2309 0 : lease_break_info.lease_skip_ack = true;
2310 :
2311 0 : smb2_lease_create_share(&io1, &ls1, false, fname,
2312 : smb2_util_share_access("RWD"),
2313 : LEASE1,
2314 : smb2_util_lease_state("RWH"));
2315 0 : status = smb2_create(tree, mem_ctx, &io1);
2316 0 : CHECK_STATUS(status, NT_STATUS_OK);
2317 0 : h1a = io1.out.file.handle;
2318 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2319 0 : CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2320 :
2321 : /*
2322 : * a conflicting open is blocked until we ack the
2323 : * lease break
2324 : */
2325 0 : smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2326 0 : req2 = smb2_create_send(tree, &io2);
2327 0 : torture_assert(tctx, req2 != NULL, "smb2_create_send");
2328 :
2329 : /*
2330 : * we got the lease break, but defer the ack.
2331 : */
2332 0 : CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2333 :
2334 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2335 :
2336 : /*
2337 : * a open using the same lease key is still works,
2338 : * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2339 : */
2340 0 : status = smb2_create(tree, mem_ctx, &io1);
2341 0 : CHECK_STATUS(status, NT_STATUS_OK);
2342 0 : h1b = io1.out.file.handle;
2343 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2344 0 : CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2345 0 : smb2_util_close(tree, h1b);
2346 :
2347 : /*
2348 : * a conflicting open with NTCREATEX_DISP_OVERWRITE
2349 : * doesn't trigger an immediate lease break to none.
2350 : */
2351 0 : lease_break_info_tmp = lease_break_info;
2352 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2353 0 : smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
2354 0 : io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2355 0 : req3 = smb2_create_send(tree, &io3);
2356 0 : torture_assert(tctx, req3 != NULL, "smb2_create_send");
2357 0 : CHECK_NO_BREAK(tctx);
2358 0 : lease_break_info = lease_break_info_tmp;
2359 :
2360 0 : torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2361 :
2362 0 : ack.in.lease.lease_key =
2363 : lease_break_info.lease_break.current_lease.lease_key;
2364 0 : ack.in.lease.lease_state =
2365 0 : lease_break_info.lease_break.new_lease_state;
2366 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2367 :
2368 : /*
2369 : * a open using the same lease key is still works,
2370 : * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2371 : */
2372 0 : status = smb2_create(tree, mem_ctx, &io1);
2373 0 : CHECK_STATUS(status, NT_STATUS_OK);
2374 0 : h1b = io1.out.file.handle;
2375 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2376 0 : CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2377 0 : smb2_util_close(tree, h1b);
2378 :
2379 0 : CHECK_NO_BREAK(tctx);
2380 :
2381 : /*
2382 : * We ack the lease break, but defer acking the next break (to "R")
2383 : */
2384 0 : lease_break_info.lease_skip_ack = true;
2385 0 : status = smb2_lease_break_ack(tree, &ack);
2386 0 : CHECK_STATUS(status, NT_STATUS_OK);
2387 0 : CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2388 :
2389 : /*
2390 : * We got an additional break downgrading to just "R"
2391 : * while we defer the ack.
2392 : */
2393 0 : CHECK_BREAK_INFO("RH", "R", LEASE1);
2394 :
2395 0 : ack.in.lease.lease_key =
2396 : lease_break_info.lease_break.current_lease.lease_key;
2397 0 : ack.in.lease.lease_state =
2398 0 : lease_break_info.lease_break.new_lease_state;
2399 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2400 :
2401 : /*
2402 : * a open using the same lease key is still works,
2403 : * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2404 : */
2405 0 : status = smb2_create(tree, mem_ctx, &io1);
2406 0 : CHECK_STATUS(status, NT_STATUS_OK);
2407 0 : h1b = io1.out.file.handle;
2408 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2409 0 : CHECK_LEASE(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2410 0 : smb2_util_close(tree, h1b);
2411 :
2412 0 : CHECK_NO_BREAK(tctx);
2413 :
2414 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2415 0 : torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2416 :
2417 : /*
2418 : * We ack the downgrade to "R" and get an immediate break to none
2419 : */
2420 0 : status = smb2_lease_break_ack(tree, &ack);
2421 0 : CHECK_STATUS(status, NT_STATUS_OK);
2422 0 : CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
2423 :
2424 : /*
2425 : * We get the downgrade to none.
2426 : */
2427 0 : CHECK_BREAK_INFO("R", "", LEASE1);
2428 :
2429 0 : torture_assert(tctx, req2->cancel.can_cancel,
2430 : "req2 can_cancel");
2431 0 : torture_assert(tctx, req3->cancel.can_cancel,
2432 : "req3 can_cancel");
2433 :
2434 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2435 :
2436 0 : status = smb2_create_recv(req2, tctx, &io2);
2437 0 : CHECK_STATUS(status, NT_STATUS_OK);
2438 0 : h2 = io2.out.file.handle;
2439 0 : CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2440 0 : CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2441 :
2442 0 : status = smb2_create_recv(req3, tctx, &io3);
2443 0 : CHECK_STATUS(status, NT_STATUS_OK);
2444 0 : h3 = io3.out.file.handle;
2445 0 : CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2446 0 : CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2447 :
2448 0 : CHECK_NO_BREAK(tctx);
2449 0 : done:
2450 0 : smb2_util_close(tree, h1a);
2451 0 : smb2_util_close(tree, h1b);
2452 0 : smb2_util_close(tree, h2);
2453 0 : smb2_util_close(tree, h3);
2454 :
2455 0 : smb2_util_unlink(tree, fname);
2456 0 : talloc_free(mem_ctx);
2457 0 : return ret;
2458 : }
2459 :
2460 0 : static bool test_lease_v2_breaking3(struct torture_context *tctx,
2461 : struct smb2_tree *tree)
2462 : {
2463 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2464 0 : struct smb2_create io1 = {};
2465 0 : struct smb2_create io2 = {};
2466 0 : struct smb2_create io3 = {};
2467 0 : struct smb2_lease ls1 = {};
2468 0 : struct smb2_handle h1a = {};
2469 0 : struct smb2_handle h1b = {};
2470 0 : struct smb2_handle h2 = {};
2471 0 : struct smb2_handle h3 = {};
2472 0 : struct smb2_request *req2 = NULL;
2473 0 : struct smb2_request *req3 = NULL;
2474 0 : struct lease_break_info lease_break_info_tmp = {};
2475 0 : struct smb2_lease_break_ack ack = {};
2476 0 : const char *fname = "v2_lease_breaking3.dat";
2477 0 : bool ret = true;
2478 : NTSTATUS status;
2479 : uint32_t caps;
2480 : enum protocol_types protocol;
2481 :
2482 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2483 0 : if (!(caps & SMB2_CAP_LEASING)) {
2484 0 : torture_skip(tctx, "leases are not supported");
2485 : }
2486 :
2487 0 : protocol = smbXcli_conn_protocol(tree->session->transport->conn);
2488 0 : if (protocol < PROTOCOL_SMB3_00) {
2489 0 : torture_skip(tctx, "v2 leases are not supported");
2490 : }
2491 :
2492 0 : smb2_util_unlink(tree, fname);
2493 :
2494 0 : tree->session->transport->lease.handler = torture_lease_handler;
2495 0 : tree->session->transport->lease.private_data = tree;
2496 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
2497 0 : tree->session->transport->oplock.private_data = tree;
2498 :
2499 : /*
2500 : * we defer acking the lease break.
2501 : */
2502 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2503 0 : lease_break_info.lease_skip_ack = true;
2504 :
2505 0 : smb2_lease_v2_create_share(&io1, &ls1, false, fname,
2506 : smb2_util_share_access("RWD"),
2507 : LEASE1, NULL,
2508 : smb2_util_lease_state("RHW"),
2509 : 0x11);
2510 0 : status = smb2_create(tree, mem_ctx, &io1);
2511 0 : CHECK_STATUS(status, NT_STATUS_OK);
2512 0 : h1a = io1.out.file.handle;
2513 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2514 : /* Epoch increases on open. */
2515 0 : ls1.lease_epoch += 1;
2516 0 : CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
2517 :
2518 : /*
2519 : * a conflicting open is blocked until we ack the
2520 : * lease break
2521 : */
2522 0 : smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2523 0 : req2 = smb2_create_send(tree, &io2);
2524 0 : torture_assert(tctx, req2 != NULL, "smb2_create_send");
2525 :
2526 : /*
2527 : * we got the lease break, but defer the ack.
2528 : */
2529 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
2530 : "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
2531 :
2532 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2533 :
2534 : /* On receiving a lease break, we must sync the new epoch. */
2535 0 : ls1.lease_epoch = lease_break_info.lease_break.new_epoch;
2536 :
2537 : /*
2538 : * a open using the same lease key is still works,
2539 : * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2540 : */
2541 0 : status = smb2_create(tree, mem_ctx, &io1);
2542 0 : CHECK_STATUS(status, NT_STATUS_OK);
2543 0 : h1b = io1.out.file.handle;
2544 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2545 0 : CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2546 0 : smb2_util_close(tree, h1b);
2547 :
2548 : /*
2549 : * a conflicting open with NTCREATEX_DISP_OVERWRITE
2550 : * doesn't trigger an immediate lease break to none.
2551 : */
2552 0 : lease_break_info_tmp = lease_break_info;
2553 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2554 0 : smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
2555 0 : io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2556 0 : req3 = smb2_create_send(tree, &io3);
2557 0 : torture_assert(tctx, req3 != NULL, "smb2_create_send");
2558 0 : CHECK_NO_BREAK(tctx);
2559 0 : lease_break_info = lease_break_info_tmp;
2560 :
2561 0 : torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2562 :
2563 0 : ack.in.lease.lease_key =
2564 : lease_break_info.lease_break.current_lease.lease_key;
2565 0 : ack.in.lease.lease_state =
2566 0 : lease_break_info.lease_break.new_lease_state;
2567 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2568 :
2569 : /*
2570 : * a open using the same lease key is still works,
2571 : * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2572 : */
2573 0 : status = smb2_create(tree, mem_ctx, &io1);
2574 0 : CHECK_STATUS(status, NT_STATUS_OK);
2575 0 : h1b = io1.out.file.handle;
2576 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2577 0 : CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2578 0 : smb2_util_close(tree, h1b);
2579 :
2580 0 : CHECK_NO_BREAK(tctx);
2581 :
2582 : /*
2583 : * We ack the lease break, but defer acking the next break (to "R")
2584 : */
2585 0 : lease_break_info.lease_skip_ack = true;
2586 0 : status = smb2_lease_break_ack(tree, &ack);
2587 0 : CHECK_STATUS(status, NT_STATUS_OK);
2588 0 : CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2589 :
2590 : /*
2591 : * We got an additional break downgrading to just "R"
2592 : * while we defer the ack.
2593 : */
2594 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
2595 : "RH", "R", LEASE1, ls1.lease_epoch);
2596 : /* On receiving a lease break, we must sync the new epoch. */
2597 0 : ls1.lease_epoch = lease_break_info.lease_break.new_epoch;
2598 :
2599 0 : ack.in.lease.lease_key =
2600 : lease_break_info.lease_break.current_lease.lease_key;
2601 0 : ack.in.lease.lease_state =
2602 0 : lease_break_info.lease_break.new_lease_state;
2603 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2604 :
2605 : /*
2606 : * a open using the same lease key is still works,
2607 : * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2608 : */
2609 0 : status = smb2_create(tree, mem_ctx, &io1);
2610 0 : CHECK_STATUS(status, NT_STATUS_OK);
2611 0 : h1b = io1.out.file.handle;
2612 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2613 0 : CHECK_LEASE_V2(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2614 0 : smb2_util_close(tree, h1b);
2615 :
2616 0 : CHECK_NO_BREAK(tctx);
2617 :
2618 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2619 0 : torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2620 :
2621 : /*
2622 : * We ack the downgrade to "R" and get an immediate break to none
2623 : */
2624 0 : status = smb2_lease_break_ack(tree, &ack);
2625 0 : CHECK_STATUS(status, NT_STATUS_OK);
2626 0 : CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
2627 :
2628 : /*
2629 : * We get the downgrade to none.
2630 : */
2631 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
2632 : "R", "", LEASE1, ls1.lease_epoch);
2633 :
2634 0 : torture_assert(tctx, req2->cancel.can_cancel,
2635 : "req2 can_cancel");
2636 0 : torture_assert(tctx, req3->cancel.can_cancel,
2637 : "req3 can_cancel");
2638 :
2639 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2640 :
2641 0 : status = smb2_create_recv(req2, tctx, &io2);
2642 0 : CHECK_STATUS(status, NT_STATUS_OK);
2643 0 : h2 = io2.out.file.handle;
2644 0 : CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2645 0 : CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2646 :
2647 0 : status = smb2_create_recv(req3, tctx, &io3);
2648 0 : CHECK_STATUS(status, NT_STATUS_OK);
2649 0 : h3 = io3.out.file.handle;
2650 0 : CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2651 0 : CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2652 :
2653 0 : CHECK_NO_BREAK(tctx);
2654 0 : done:
2655 0 : smb2_util_close(tree, h1a);
2656 0 : smb2_util_close(tree, h1b);
2657 0 : smb2_util_close(tree, h2);
2658 0 : smb2_util_close(tree, h3);
2659 :
2660 0 : smb2_util_unlink(tree, fname);
2661 0 : talloc_free(mem_ctx);
2662 0 : return ret;
2663 : }
2664 :
2665 :
2666 0 : static bool test_lease_breaking4(struct torture_context *tctx,
2667 : struct smb2_tree *tree)
2668 : {
2669 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2670 0 : struct smb2_create io1 = {};
2671 0 : struct smb2_create io2 = {};
2672 0 : struct smb2_create io3 = {};
2673 0 : struct smb2_lease ls1 = {};
2674 0 : struct smb2_lease ls1t = {};
2675 0 : struct smb2_handle h1 = {};
2676 0 : struct smb2_handle h2 = {};
2677 0 : struct smb2_handle h3 = {};
2678 0 : struct smb2_request *req2 = NULL;
2679 0 : struct lease_break_info lease_break_info_tmp = {};
2680 0 : struct smb2_lease_break_ack ack = {};
2681 0 : const char *fname = "lease_breaking4.dat";
2682 0 : bool ret = true;
2683 : NTSTATUS status;
2684 : uint32_t caps;
2685 :
2686 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2687 0 : if (!(caps & SMB2_CAP_LEASING)) {
2688 0 : torture_skip(tctx, "leases are not supported");
2689 : }
2690 :
2691 0 : smb2_util_unlink(tree, fname);
2692 :
2693 0 : tree->session->transport->lease.handler = torture_lease_handler;
2694 0 : tree->session->transport->lease.private_data = tree;
2695 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
2696 0 : tree->session->transport->oplock.private_data = tree;
2697 :
2698 : /*
2699 : * we defer acking the lease break.
2700 : */
2701 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2702 0 : lease_break_info.lease_skip_ack = true;
2703 :
2704 0 : smb2_lease_create_share(&io1, &ls1, false, fname,
2705 : smb2_util_share_access("RWD"),
2706 : LEASE1,
2707 : smb2_util_lease_state("RH"));
2708 0 : status = smb2_create(tree, mem_ctx, &io1);
2709 0 : CHECK_STATUS(status, NT_STATUS_OK);
2710 0 : h1 = io1.out.file.handle;
2711 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2712 0 : CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
2713 :
2714 0 : CHECK_NO_BREAK(tctx);
2715 :
2716 : /*
2717 : * a conflicting open is *not* blocked until we ack the
2718 : * lease break
2719 : */
2720 0 : smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2721 0 : io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2722 0 : req2 = smb2_create_send(tree, &io2);
2723 0 : torture_assert(tctx, req2 != NULL, "smb2_create_send");
2724 :
2725 : /*
2726 : * We got a break from RH to NONE, we're supported to ack
2727 : * this downgrade
2728 : */
2729 0 : CHECK_BREAK_INFO("RH", "", LEASE1);
2730 :
2731 0 : lease_break_info_tmp = lease_break_info;
2732 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2733 0 : CHECK_NO_BREAK(tctx);
2734 :
2735 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2736 :
2737 0 : status = smb2_create_recv(req2, tctx, &io2);
2738 0 : CHECK_STATUS(status, NT_STATUS_OK);
2739 0 : h2 = io2.out.file.handle;
2740 0 : CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2741 0 : CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2742 0 : smb2_util_close(tree, h2);
2743 :
2744 0 : CHECK_NO_BREAK(tctx);
2745 :
2746 : /*
2747 : * a conflicting open is *not* blocked until we ack the
2748 : * lease break, even if the lease is in breaking state.
2749 : */
2750 0 : smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2751 0 : io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2752 0 : req2 = smb2_create_send(tree, &io2);
2753 0 : torture_assert(tctx, req2 != NULL, "smb2_create_send");
2754 :
2755 0 : CHECK_NO_BREAK(tctx);
2756 :
2757 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2758 :
2759 0 : status = smb2_create_recv(req2, tctx, &io2);
2760 0 : CHECK_STATUS(status, NT_STATUS_OK);
2761 0 : h2 = io2.out.file.handle;
2762 0 : CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2763 0 : CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2764 0 : smb2_util_close(tree, h2);
2765 :
2766 0 : CHECK_NO_BREAK(tctx);
2767 :
2768 : /*
2769 : * We now ask the server about the current lease state
2770 : * which should still be "RH", but with
2771 : * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2772 : */
2773 0 : smb2_lease_create_share(&io3, &ls1t, false, fname,
2774 : smb2_util_share_access("RWD"),
2775 : LEASE1,
2776 : smb2_util_lease_state(""));
2777 0 : status = smb2_create(tree, mem_ctx, &io3);
2778 0 : CHECK_STATUS(status, NT_STATUS_OK);
2779 0 : h3 = io3.out.file.handle;
2780 0 : CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2781 0 : CHECK_LEASE(&io3, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2782 :
2783 : /*
2784 : * We finally ack the lease break...
2785 : */
2786 0 : CHECK_NO_BREAK(tctx);
2787 0 : lease_break_info = lease_break_info_tmp;
2788 0 : ack.in.lease.lease_key =
2789 : lease_break_info.lease_break.current_lease.lease_key;
2790 0 : ack.in.lease.lease_state =
2791 0 : lease_break_info.lease_break.new_lease_state;
2792 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2793 0 : lease_break_info.lease_skip_ack = true;
2794 :
2795 0 : status = smb2_lease_break_ack(tree, &ack);
2796 0 : CHECK_STATUS(status, NT_STATUS_OK);
2797 0 : CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2798 :
2799 0 : CHECK_NO_BREAK(tctx);
2800 :
2801 0 : done:
2802 0 : smb2_util_close(tree, h1);
2803 0 : smb2_util_close(tree, h2);
2804 0 : smb2_util_close(tree, h3);
2805 :
2806 0 : smb2_util_unlink(tree, fname);
2807 0 : talloc_free(mem_ctx);
2808 0 : return ret;
2809 : }
2810 :
2811 0 : static bool test_lease_breaking5(struct torture_context *tctx,
2812 : struct smb2_tree *tree)
2813 : {
2814 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2815 0 : struct smb2_create io1 = {};
2816 0 : struct smb2_create io2 = {};
2817 0 : struct smb2_create io3 = {};
2818 0 : struct smb2_lease ls1 = {};
2819 0 : struct smb2_lease ls1t = {};
2820 0 : struct smb2_handle h1 = {};
2821 0 : struct smb2_handle h2 = {};
2822 0 : struct smb2_handle h3 = {};
2823 0 : struct smb2_request *req2 = NULL;
2824 0 : struct lease_break_info lease_break_info_tmp = {};
2825 0 : struct smb2_lease_break_ack ack = {};
2826 0 : const char *fname = "lease_breaking5.dat";
2827 0 : bool ret = true;
2828 : NTSTATUS status;
2829 : uint32_t caps;
2830 :
2831 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2832 0 : if (!(caps & SMB2_CAP_LEASING)) {
2833 0 : torture_skip(tctx, "leases are not supported");
2834 : }
2835 :
2836 0 : smb2_util_unlink(tree, fname);
2837 :
2838 0 : tree->session->transport->lease.handler = torture_lease_handler;
2839 0 : tree->session->transport->lease.private_data = tree;
2840 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
2841 0 : tree->session->transport->oplock.private_data = tree;
2842 :
2843 : /*
2844 : * we defer acking the lease break.
2845 : */
2846 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2847 0 : lease_break_info.lease_skip_ack = true;
2848 :
2849 0 : smb2_lease_create_share(&io1, &ls1, false, fname,
2850 : smb2_util_share_access("RWD"),
2851 : LEASE1,
2852 : smb2_util_lease_state("R"));
2853 0 : status = smb2_create(tree, mem_ctx, &io1);
2854 0 : CHECK_STATUS(status, NT_STATUS_OK);
2855 0 : h1 = io1.out.file.handle;
2856 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2857 0 : CHECK_LEASE(&io1, "R", true, LEASE1, 0);
2858 :
2859 0 : CHECK_NO_BREAK(tctx);
2860 :
2861 : /*
2862 : * a conflicting open is *not* blocked until we ack the
2863 : * lease break
2864 : */
2865 0 : smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2866 0 : io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2867 0 : req2 = smb2_create_send(tree, &io2);
2868 0 : torture_assert(tctx, req2 != NULL, "smb2_create_send");
2869 :
2870 : /*
2871 : * We got a break from RH to NONE, we're supported to ack
2872 : * this downgrade
2873 : */
2874 0 : CHECK_BREAK_INFO("R", "", LEASE1);
2875 :
2876 0 : lease_break_info_tmp = lease_break_info;
2877 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2878 0 : CHECK_NO_BREAK(tctx);
2879 :
2880 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2881 :
2882 0 : status = smb2_create_recv(req2, tctx, &io2);
2883 0 : CHECK_STATUS(status, NT_STATUS_OK);
2884 0 : h2 = io2.out.file.handle;
2885 0 : CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2886 0 : CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2887 :
2888 0 : CHECK_NO_BREAK(tctx);
2889 :
2890 : /*
2891 : * We now ask the server about the current lease state
2892 : * which should still be "RH", but with
2893 : * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2894 : */
2895 0 : smb2_lease_create_share(&io3, &ls1t, false, fname,
2896 : smb2_util_share_access("RWD"),
2897 : LEASE1,
2898 : smb2_util_lease_state(""));
2899 0 : status = smb2_create(tree, mem_ctx, &io3);
2900 0 : CHECK_STATUS(status, NT_STATUS_OK);
2901 0 : h3 = io3.out.file.handle;
2902 0 : CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2903 0 : CHECK_LEASE(&io3, "", true, LEASE1, 0);
2904 :
2905 : /*
2906 : * We send an ack without without being asked.
2907 : */
2908 0 : CHECK_NO_BREAK(tctx);
2909 0 : lease_break_info = lease_break_info_tmp;
2910 0 : ack.in.lease.lease_key =
2911 : lease_break_info.lease_break.current_lease.lease_key;
2912 0 : ack.in.lease.lease_state =
2913 0 : lease_break_info.lease_break.new_lease_state;
2914 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2915 0 : status = smb2_lease_break_ack(tree, &ack);
2916 0 : CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2917 :
2918 0 : CHECK_NO_BREAK(tctx);
2919 :
2920 0 : done:
2921 0 : smb2_util_close(tree, h1);
2922 0 : smb2_util_close(tree, h2);
2923 0 : smb2_util_close(tree, h3);
2924 :
2925 0 : smb2_util_unlink(tree, fname);
2926 0 : talloc_free(mem_ctx);
2927 0 : return ret;
2928 : }
2929 :
2930 0 : static bool test_lease_breaking6(struct torture_context *tctx,
2931 : struct smb2_tree *tree)
2932 : {
2933 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2934 0 : struct smb2_create io1 = {};
2935 0 : struct smb2_create io2 = {};
2936 0 : struct smb2_lease ls1 = {};
2937 0 : struct smb2_handle h1a = {};
2938 0 : struct smb2_handle h1b = {};
2939 0 : struct smb2_handle h2 = {};
2940 0 : struct smb2_request *req2 = NULL;
2941 0 : struct smb2_lease_break_ack ack = {};
2942 0 : const char *fname = "lease_breaking6.dat";
2943 0 : bool ret = true;
2944 : NTSTATUS status;
2945 : uint32_t caps;
2946 :
2947 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2948 0 : if (!(caps & SMB2_CAP_LEASING)) {
2949 0 : torture_skip(tctx, "leases are not supported");
2950 : }
2951 :
2952 0 : smb2_util_unlink(tree, fname);
2953 :
2954 0 : tree->session->transport->lease.handler = torture_lease_handler;
2955 0 : tree->session->transport->lease.private_data = tree;
2956 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
2957 0 : tree->session->transport->oplock.private_data = tree;
2958 :
2959 : /*
2960 : * we defer acking the lease break.
2961 : */
2962 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2963 0 : lease_break_info.lease_skip_ack = true;
2964 :
2965 0 : smb2_lease_create_share(&io1, &ls1, false, fname,
2966 : smb2_util_share_access("RWD"),
2967 : LEASE1,
2968 : smb2_util_lease_state("RWH"));
2969 0 : status = smb2_create(tree, mem_ctx, &io1);
2970 0 : CHECK_STATUS(status, NT_STATUS_OK);
2971 0 : h1a = io1.out.file.handle;
2972 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2973 0 : CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2974 :
2975 : /*
2976 : * a conflicting open is blocked until we ack the
2977 : * lease break
2978 : */
2979 0 : smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2980 0 : req2 = smb2_create_send(tree, &io2);
2981 0 : torture_assert(tctx, req2 != NULL, "smb2_create_send");
2982 :
2983 : /*
2984 : * we got the lease break, but defer the ack.
2985 : */
2986 0 : CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2987 :
2988 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2989 :
2990 0 : ack.in.lease.lease_key =
2991 : lease_break_info.lease_break.current_lease.lease_key;
2992 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
2993 :
2994 : /*
2995 : * a open using the same lease key is still works,
2996 : * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2997 : */
2998 0 : status = smb2_create(tree, mem_ctx, &io1);
2999 0 : CHECK_STATUS(status, NT_STATUS_OK);
3000 0 : h1b = io1.out.file.handle;
3001 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3002 0 : CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
3003 0 : smb2_util_close(tree, h1b);
3004 :
3005 0 : CHECK_NO_BREAK(tctx);
3006 :
3007 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
3008 :
3009 : /*
3010 : * We are asked to break to "RH", but we are allowed to
3011 : * break to any of "RH", "R" or NONE.
3012 : */
3013 0 : ack.in.lease.lease_state = SMB2_LEASE_NONE;
3014 0 : status = smb2_lease_break_ack(tree, &ack);
3015 0 : CHECK_STATUS(status, NT_STATUS_OK);
3016 0 : CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
3017 :
3018 0 : torture_assert(tctx, req2->cancel.can_cancel,
3019 : "req2 can_cancel");
3020 :
3021 0 : status = smb2_create_recv(req2, tctx, &io2);
3022 0 : CHECK_STATUS(status, NT_STATUS_OK);
3023 0 : h2 = io2.out.file.handle;
3024 0 : CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3025 0 : CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
3026 :
3027 0 : CHECK_NO_BREAK(tctx);
3028 0 : done:
3029 0 : smb2_util_close(tree, h1a);
3030 0 : smb2_util_close(tree, h1b);
3031 0 : smb2_util_close(tree, h2);
3032 0 : smb2_util_unlink(tree, fname);
3033 0 : talloc_free(mem_ctx);
3034 0 : return ret;
3035 : }
3036 :
3037 0 : static bool test_lease_lock1(struct torture_context *tctx,
3038 : struct smb2_tree *tree1a,
3039 : struct smb2_tree *tree2)
3040 : {
3041 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
3042 0 : struct smb2_create io1 = {};
3043 0 : struct smb2_create io2 = {};
3044 0 : struct smb2_create io3 = {};
3045 0 : struct smb2_lease ls1 = {};
3046 0 : struct smb2_lease ls2 = {};
3047 0 : struct smb2_lease ls3 = {};
3048 0 : struct smb2_handle h1 = {};
3049 0 : struct smb2_handle h2 = {};
3050 0 : struct smb2_handle h3 = {};
3051 : struct smb2_lock lck;
3052 : struct smb2_lock_element el[1];
3053 0 : const char *fname = "locktest.dat";
3054 0 : bool ret = true;
3055 : NTSTATUS status;
3056 : uint32_t caps;
3057 : struct smbcli_options options1;
3058 0 : struct smb2_tree *tree1b = NULL;
3059 :
3060 0 : options1 = tree1a->session->transport->options;
3061 :
3062 0 : caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3063 0 : if (!(caps & SMB2_CAP_LEASING)) {
3064 0 : torture_skip(tctx, "leases are not supported");
3065 : }
3066 :
3067 : /* Set up handlers. */
3068 0 : tree2->session->transport->lease.handler = torture_lease_handler;
3069 0 : tree2->session->transport->lease.private_data = tree2;
3070 0 : tree2->session->transport->oplock.handler = torture_oplock_handler;
3071 0 : tree2->session->transport->oplock.private_data = tree2;
3072 :
3073 0 : tree1a->session->transport->lease.handler = torture_lease_handler;
3074 0 : tree1a->session->transport->lease.private_data = tree1a;
3075 0 : tree1a->session->transport->oplock.handler = torture_oplock_handler;
3076 0 : tree1a->session->transport->oplock.private_data = tree1a;
3077 :
3078 : /* create a new connection (same client_guid) */
3079 0 : if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3080 0 : torture_warning(tctx, "couldn't reconnect, bailing\n");
3081 0 : ret = false;
3082 0 : goto done;
3083 : }
3084 :
3085 0 : tree1b->session->transport->lease.handler = torture_lease_handler;
3086 0 : tree1b->session->transport->lease.private_data = tree1b;
3087 0 : tree1b->session->transport->oplock.handler = torture_oplock_handler;
3088 0 : tree1b->session->transport->oplock.private_data = tree1b;
3089 :
3090 0 : smb2_util_unlink(tree1a, fname);
3091 :
3092 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3093 0 : ZERO_STRUCT(lck);
3094 :
3095 : /* Open a handle on tree1a. */
3096 0 : smb2_lease_create_share(&io1, &ls1, false, fname,
3097 : smb2_util_share_access("RWD"),
3098 : LEASE1,
3099 : smb2_util_lease_state("RWH"));
3100 0 : status = smb2_create(tree1a, mem_ctx, &io1);
3101 0 : CHECK_STATUS(status, NT_STATUS_OK);
3102 0 : h1 = io1.out.file.handle;
3103 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3104 0 : CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
3105 :
3106 : /* Open a second handle on tree1b. */
3107 0 : smb2_lease_create_share(&io2, &ls2, false, fname,
3108 : smb2_util_share_access("RWD"),
3109 : LEASE2,
3110 : smb2_util_lease_state("RWH"));
3111 0 : status = smb2_create(tree1b, mem_ctx, &io2);
3112 0 : CHECK_STATUS(status, NT_STATUS_OK);
3113 0 : h2 = io2.out.file.handle;
3114 0 : CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3115 0 : CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
3116 : /* And LEASE1 got broken to RH. */
3117 0 : CHECK_BREAK_INFO("RWH", "RH", LEASE1);
3118 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3119 :
3120 : /* Now open a lease on a different client guid. */
3121 0 : smb2_lease_create_share(&io3, &ls3, false, fname,
3122 : smb2_util_share_access("RWD"),
3123 : LEASE3,
3124 : smb2_util_lease_state("RWH"));
3125 0 : status = smb2_create(tree2, mem_ctx, &io3);
3126 0 : CHECK_STATUS(status, NT_STATUS_OK);
3127 0 : h3 = io3.out.file.handle;
3128 0 : CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3129 0 : CHECK_LEASE(&io3, "RH", true, LEASE3, 0);
3130 : /* Doesn't break. */
3131 0 : CHECK_NO_BREAK(tctx);
3132 :
3133 0 : lck.in.locks = el;
3134 : /*
3135 : * Try and get get an exclusive byte
3136 : * range lock on H1 (LEASE1).
3137 : */
3138 :
3139 0 : lck.in.lock_count = 1;
3140 0 : lck.in.lock_sequence = 1;
3141 0 : lck.in.file.handle = h1;
3142 0 : el[0].offset = 0;
3143 0 : el[0].length = 1;
3144 0 : el[0].reserved = 0;
3145 0 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
3146 0 : status = smb2_lock(tree1a, &lck);
3147 0 : CHECK_STATUS(status, NT_STATUS_OK);
3148 :
3149 : /* LEASE2 and LEASE3 should get broken to NONE. */
3150 0 : torture_wait_for_lease_break(tctx);
3151 0 : torture_wait_for_lease_break(tctx);
3152 0 : torture_wait_for_lease_break(tctx);
3153 0 : torture_wait_for_lease_break(tctx);
3154 :
3155 0 : CHECK_VAL(lease_break_info.failures, 0); \
3156 0 : CHECK_VAL(lease_break_info.count, 2); \
3157 :
3158 : /* Get state of the H1 (LEASE1) */
3159 0 : smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
3160 0 : status = smb2_create(tree1a, mem_ctx, &io1);
3161 0 : CHECK_STATUS(status, NT_STATUS_OK);
3162 : /* Should still be RH. */
3163 0 : CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
3164 0 : smb2_util_close(tree1a, io1.out.file.handle);
3165 :
3166 : /* Get state of the H2 (LEASE2) */
3167 0 : smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state(""));
3168 0 : status = smb2_create(tree1b, mem_ctx, &io2);
3169 0 : CHECK_STATUS(status, NT_STATUS_OK);
3170 0 : CHECK_LEASE(&io2, "", true, LEASE2, 0);
3171 0 : smb2_util_close(tree1b, io2.out.file.handle);
3172 :
3173 : /* Get state of the H3 (LEASE3) */
3174 0 : smb2_lease_create(&io3, &ls3, false, fname, LEASE3, smb2_util_lease_state(""));
3175 0 : status = smb2_create(tree2, mem_ctx, &io3);
3176 0 : CHECK_STATUS(status, NT_STATUS_OK);
3177 0 : CHECK_LEASE(&io3, "", true, LEASE3, 0);
3178 0 : smb2_util_close(tree2, io3.out.file.handle);
3179 :
3180 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3181 :
3182 : /*
3183 : * Try and get get an exclusive byte
3184 : * range lock on H3 (LEASE3).
3185 : */
3186 0 : lck.in.lock_count = 1;
3187 0 : lck.in.lock_sequence = 2;
3188 0 : lck.in.file.handle = h3;
3189 0 : el[0].offset = 100;
3190 0 : el[0].length = 1;
3191 0 : el[0].reserved = 0;
3192 0 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
3193 0 : status = smb2_lock(tree2, &lck);
3194 0 : CHECK_STATUS(status, NT_STATUS_OK);
3195 : /* LEASE1 got broken to NONE. */
3196 0 : CHECK_BREAK_INFO("RH", "", LEASE1);
3197 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3198 :
3199 0 : done:
3200 0 : smb2_util_close(tree1a, h1);
3201 0 : smb2_util_close(tree1b, h2);
3202 0 : smb2_util_close(tree2, h3);
3203 :
3204 0 : smb2_util_unlink(tree1a, fname);
3205 0 : talloc_free(mem_ctx);
3206 0 : return ret;
3207 : }
3208 :
3209 0 : static bool test_lease_complex1(struct torture_context *tctx,
3210 : struct smb2_tree *tree1a)
3211 : {
3212 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
3213 : struct smb2_create io1;
3214 : struct smb2_create io2;
3215 : struct smb2_lease ls1;
3216 : struct smb2_lease ls2;
3217 0 : struct smb2_handle h = {{0}};
3218 0 : struct smb2_handle h2 = {{0}};
3219 0 : struct smb2_handle h3 = {{0}};
3220 : struct smb2_write w;
3221 : NTSTATUS status;
3222 0 : const char *fname = "lease_complex1.dat";
3223 0 : bool ret = true;
3224 : uint32_t caps;
3225 0 : struct smb2_tree *tree1b = NULL;
3226 : struct smbcli_options options1;
3227 :
3228 0 : options1 = tree1a->session->transport->options;
3229 :
3230 0 : caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3231 0 : if (!(caps & SMB2_CAP_LEASING)) {
3232 0 : torture_skip(tctx, "leases are not supported");
3233 : }
3234 :
3235 0 : tree1a->session->transport->lease.handler = torture_lease_handler;
3236 0 : tree1a->session->transport->lease.private_data = tree1a;
3237 0 : tree1a->session->transport->oplock.handler = torture_oplock_handler;
3238 0 : tree1a->session->transport->oplock.private_data = tree1a;
3239 :
3240 : /* create a new connection (same client_guid) */
3241 0 : if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3242 0 : torture_warning(tctx, "couldn't reconnect, bailing\n");
3243 0 : ret = false;
3244 0 : goto done;
3245 : }
3246 :
3247 0 : tree1b->session->transport->lease.handler = torture_lease_handler;
3248 0 : tree1b->session->transport->lease.private_data = tree1b;
3249 0 : tree1b->session->transport->oplock.handler = torture_oplock_handler;
3250 0 : tree1b->session->transport->oplock.private_data = tree1b;
3251 :
3252 0 : smb2_util_unlink(tree1a, fname);
3253 :
3254 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3255 :
3256 : /* Grab R lease over connection 1a */
3257 0 : smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
3258 0 : status = smb2_create(tree1a, mem_ctx, &io1);
3259 0 : CHECK_STATUS(status, NT_STATUS_OK);
3260 0 : h = io1.out.file.handle;
3261 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3262 0 : CHECK_LEASE(&io1, "R", true, LEASE1, 0);
3263 :
3264 : /* Upgrade to RWH over connection 1b */
3265 0 : ls1.lease_state = smb2_util_lease_state("RWH");
3266 0 : status = smb2_create(tree1b, mem_ctx, &io1);
3267 0 : CHECK_STATUS(status, NT_STATUS_OK);
3268 0 : h2 = io1.out.file.handle;
3269 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3270 0 : CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
3271 :
3272 : /* close over connection 1b */
3273 0 : status = smb2_util_close(tree1b, h2);
3274 0 : CHECK_STATUS(status, NT_STATUS_OK);
3275 :
3276 : /* Contend with LEASE2. */
3277 0 : smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state("R"));
3278 0 : status = smb2_create(tree1b, mem_ctx, &io2);
3279 0 : CHECK_STATUS(status, NT_STATUS_OK);
3280 0 : h3 = io2.out.file.handle;
3281 0 : CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3282 0 : CHECK_LEASE(&io2, "R", true, LEASE2, 0);
3283 :
3284 : /* Verify that we were only sent one break. */
3285 0 : CHECK_BREAK_INFO("RHW", "RH", LEASE1);
3286 :
3287 : /* again RH over connection 1b doesn't change the epoch */
3288 0 : ls1.lease_state = smb2_util_lease_state("RH");
3289 0 : status = smb2_create(tree1b, mem_ctx, &io1);
3290 0 : CHECK_STATUS(status, NT_STATUS_OK);
3291 0 : h2 = io1.out.file.handle;
3292 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3293 0 : CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
3294 :
3295 : /* close over connection 1b */
3296 0 : status = smb2_util_close(tree1b, h2);
3297 0 : CHECK_STATUS(status, NT_STATUS_OK);
3298 :
3299 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3300 :
3301 0 : ZERO_STRUCT(w);
3302 0 : w.in.file.handle = h;
3303 0 : w.in.offset = 0;
3304 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3305 0 : memset(w.in.data.data, 'o', w.in.data.length);
3306 0 : status = smb2_write(tree1a, &w);
3307 0 : CHECK_STATUS(status, NT_STATUS_OK);
3308 :
3309 0 : ls2.lease_epoch += 1;
3310 0 : CHECK_BREAK_INFO("R", "", LEASE2);
3311 :
3312 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3313 :
3314 0 : ZERO_STRUCT(w);
3315 0 : w.in.file.handle = h3;
3316 0 : w.in.offset = 0;
3317 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3318 0 : memset(w.in.data.data, 'o', w.in.data.length);
3319 0 : status = smb2_write(tree1b, &w);
3320 0 : CHECK_STATUS(status, NT_STATUS_OK);
3321 :
3322 0 : ls1.lease_epoch += 1;
3323 0 : CHECK_BREAK_INFO("RH", "", LEASE1);
3324 :
3325 0 : done:
3326 0 : smb2_util_close(tree1a, h);
3327 0 : smb2_util_close(tree1b, h2);
3328 0 : smb2_util_close(tree1b, h3);
3329 :
3330 0 : smb2_util_unlink(tree1a, fname);
3331 :
3332 0 : talloc_free(mem_ctx);
3333 :
3334 0 : return ret;
3335 : }
3336 :
3337 0 : static bool test_lease_v2_complex1(struct torture_context *tctx,
3338 : struct smb2_tree *tree1a)
3339 : {
3340 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
3341 : struct smb2_create io1;
3342 : struct smb2_create io2;
3343 : struct smb2_lease ls1;
3344 : struct smb2_lease ls2;
3345 0 : struct smb2_handle h = {{0}};
3346 0 : struct smb2_handle h2 = {{0}};
3347 0 : struct smb2_handle h3 = {{0}};
3348 : struct smb2_write w;
3349 : NTSTATUS status;
3350 0 : const char *fname = "lease_v2_complex1.dat";
3351 0 : bool ret = true;
3352 : uint32_t caps;
3353 : enum protocol_types protocol;
3354 0 : struct smb2_tree *tree1b = NULL;
3355 : struct smbcli_options options1;
3356 :
3357 0 : options1 = tree1a->session->transport->options;
3358 :
3359 0 : caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3360 0 : if (!(caps & SMB2_CAP_LEASING)) {
3361 0 : torture_skip(tctx, "leases are not supported");
3362 : }
3363 :
3364 0 : protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
3365 0 : if (protocol < PROTOCOL_SMB3_00) {
3366 0 : torture_skip(tctx, "v2 leases are not supported");
3367 : }
3368 :
3369 0 : tree1a->session->transport->lease.handler = torture_lease_handler;
3370 0 : tree1a->session->transport->lease.private_data = tree1a;
3371 0 : tree1a->session->transport->oplock.handler = torture_oplock_handler;
3372 0 : tree1a->session->transport->oplock.private_data = tree1a;
3373 :
3374 : /* create a new connection (same client_guid) */
3375 0 : if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3376 0 : torture_warning(tctx, "couldn't reconnect, bailing\n");
3377 0 : ret = false;
3378 0 : goto done;
3379 : }
3380 :
3381 0 : tree1b->session->transport->lease.handler = torture_lease_handler;
3382 0 : tree1b->session->transport->lease.private_data = tree1b;
3383 0 : tree1b->session->transport->oplock.handler = torture_oplock_handler;
3384 0 : tree1b->session->transport->oplock.private_data = tree1b;
3385 :
3386 0 : smb2_util_unlink(tree1a, fname);
3387 :
3388 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3389 :
3390 : /* Grab R lease over connection 1a */
3391 0 : smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
3392 : smb2_util_lease_state("R"), 0x4711);
3393 0 : status = smb2_create(tree1a, mem_ctx, &io1);
3394 0 : CHECK_STATUS(status, NT_STATUS_OK);
3395 0 : h = io1.out.file.handle;
3396 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3397 0 : ls1.lease_epoch += 1;
3398 0 : CHECK_LEASE_V2(&io1, "R", true, LEASE1,
3399 : 0, 0, ls1.lease_epoch);
3400 :
3401 : /* Upgrade to RWH over connection 1b */
3402 0 : ls1.lease_state = smb2_util_lease_state("RWH");
3403 0 : status = smb2_create(tree1b, mem_ctx, &io1);
3404 0 : CHECK_STATUS(status, NT_STATUS_OK);
3405 0 : h2 = io1.out.file.handle;
3406 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3407 0 : ls1.lease_epoch += 1;
3408 0 : CHECK_LEASE_V2(&io1, "RHW", true, LEASE1,
3409 : 0, 0, ls1.lease_epoch);
3410 :
3411 : /* close over connection 1b */
3412 0 : status = smb2_util_close(tree1b, h2);
3413 0 : CHECK_STATUS(status, NT_STATUS_OK);
3414 :
3415 : /* Contend with LEASE2. */
3416 0 : smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
3417 : smb2_util_lease_state("R"), 0x11);
3418 0 : status = smb2_create(tree1b, mem_ctx, &io2);
3419 0 : CHECK_STATUS(status, NT_STATUS_OK);
3420 0 : h3 = io2.out.file.handle;
3421 0 : CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3422 0 : ls2.lease_epoch += 1;
3423 0 : CHECK_LEASE_V2(&io2, "R", true, LEASE2,
3424 : 0, 0, ls2.lease_epoch);
3425 :
3426 : /* Verify that we were only sent one break. */
3427 0 : ls1.lease_epoch += 1;
3428 0 : CHECK_BREAK_INFO_V2(tree1a->session->transport,
3429 : "RHW", "RH", LEASE1, ls1.lease_epoch);
3430 :
3431 : /* again RH over connection 1b doesn't change the epoch */
3432 0 : ls1.lease_state = smb2_util_lease_state("RH");
3433 0 : status = smb2_create(tree1b, mem_ctx, &io1);
3434 0 : CHECK_STATUS(status, NT_STATUS_OK);
3435 0 : h2 = io1.out.file.handle;
3436 0 : CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3437 0 : CHECK_LEASE_V2(&io1, "RH", true, LEASE1,
3438 : 0, 0, ls1.lease_epoch);
3439 :
3440 : /* close over connection 1b */
3441 0 : status = smb2_util_close(tree1b, h2);
3442 0 : CHECK_STATUS(status, NT_STATUS_OK);
3443 :
3444 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3445 :
3446 0 : ZERO_STRUCT(w);
3447 0 : w.in.file.handle = h;
3448 0 : w.in.offset = 0;
3449 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3450 0 : memset(w.in.data.data, 'o', w.in.data.length);
3451 0 : status = smb2_write(tree1a, &w);
3452 0 : CHECK_STATUS(status, NT_STATUS_OK);
3453 :
3454 0 : ls2.lease_epoch += 1;
3455 0 : CHECK_BREAK_INFO_V2(tree1a->session->transport,
3456 : "R", "", LEASE2, ls2.lease_epoch);
3457 :
3458 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3459 :
3460 0 : ZERO_STRUCT(w);
3461 0 : w.in.file.handle = h3;
3462 0 : w.in.offset = 0;
3463 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3464 0 : memset(w.in.data.data, 'o', w.in.data.length);
3465 0 : status = smb2_write(tree1b, &w);
3466 0 : CHECK_STATUS(status, NT_STATUS_OK);
3467 :
3468 0 : ls1.lease_epoch += 1;
3469 0 : CHECK_BREAK_INFO_V2(tree1a->session->transport,
3470 : "RH", "", LEASE1, ls1.lease_epoch);
3471 :
3472 0 : done:
3473 0 : smb2_util_close(tree1a, h);
3474 0 : smb2_util_close(tree1b, h2);
3475 0 : smb2_util_close(tree1b, h3);
3476 :
3477 0 : smb2_util_unlink(tree1a, fname);
3478 :
3479 0 : talloc_free(mem_ctx);
3480 :
3481 0 : return ret;
3482 : }
3483 :
3484 0 : static bool test_lease_v2_complex2(struct torture_context *tctx,
3485 : struct smb2_tree *tree1a)
3486 : {
3487 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
3488 : struct smb2_create io1;
3489 : struct smb2_create io2;
3490 : struct smb2_lease ls1;
3491 : struct smb2_lease ls2;
3492 0 : struct smb2_handle h = {{0}};
3493 0 : struct smb2_handle h2 = {{0}};
3494 0 : struct smb2_request *req2 = NULL;
3495 0 : struct smb2_lease_break_ack ack = {};
3496 : NTSTATUS status;
3497 0 : const char *fname = "lease_v2_complex2.dat";
3498 0 : bool ret = true;
3499 : uint32_t caps;
3500 : enum protocol_types protocol;
3501 0 : struct smb2_tree *tree1b = NULL;
3502 : struct smbcli_options options1;
3503 :
3504 0 : options1 = tree1a->session->transport->options;
3505 :
3506 0 : caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3507 0 : if (!(caps & SMB2_CAP_LEASING)) {
3508 0 : torture_skip(tctx, "leases are not supported");
3509 : }
3510 :
3511 0 : protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
3512 0 : if (protocol < PROTOCOL_SMB3_00) {
3513 0 : torture_skip(tctx, "v2 leases are not supported");
3514 : }
3515 :
3516 0 : tree1a->session->transport->lease.handler = torture_lease_handler;
3517 0 : tree1a->session->transport->lease.private_data = tree1a;
3518 0 : tree1a->session->transport->oplock.handler = torture_oplock_handler;
3519 0 : tree1a->session->transport->oplock.private_data = tree1a;
3520 :
3521 : /* create a new connection (same client_guid) */
3522 0 : if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3523 0 : torture_warning(tctx, "couldn't reconnect, bailing\n");
3524 0 : ret = false;
3525 0 : goto done;
3526 : }
3527 :
3528 0 : tree1b->session->transport->lease.handler = torture_lease_handler;
3529 0 : tree1b->session->transport->lease.private_data = tree1b;
3530 0 : tree1b->session->transport->oplock.handler = torture_oplock_handler;
3531 0 : tree1b->session->transport->oplock.private_data = tree1b;
3532 :
3533 0 : smb2_util_unlink(tree1a, fname);
3534 :
3535 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3536 :
3537 : /* Grab RWH lease over connection 1a */
3538 0 : smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
3539 : smb2_util_lease_state("RWH"), 0x4711);
3540 0 : status = smb2_create(tree1a, mem_ctx, &io1);
3541 0 : CHECK_STATUS(status, NT_STATUS_OK);
3542 0 : h = io1.out.file.handle;
3543 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3544 0 : ls1.lease_epoch += 1;
3545 0 : CHECK_LEASE_V2(&io1, "RWH", true, LEASE1,
3546 : 0, 0, ls1.lease_epoch);
3547 :
3548 : /*
3549 : * we defer acking the lease break.
3550 : */
3551 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3552 0 : lease_break_info.lease_skip_ack = true;
3553 :
3554 : /* Ask for RWH on connection 1b, different lease. */
3555 0 : smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
3556 : smb2_util_lease_state("RWH"), 0x11);
3557 0 : req2 = smb2_create_send(tree1b, &io2);
3558 0 : torture_assert(tctx, req2 != NULL, "smb2_create_send");
3559 :
3560 0 : ls1.lease_epoch += 1;
3561 :
3562 0 : CHECK_BREAK_INFO_V2(tree1a->session->transport,
3563 : "RWH", "RH", LEASE1, ls1.lease_epoch);
3564 :
3565 : /* Send the break ACK on tree1b. */
3566 0 : ack.in.lease.lease_key =
3567 : lease_break_info.lease_break.current_lease.lease_key;
3568 0 : ack.in.lease.lease_state = SMB2_LEASE_HANDLE|SMB2_LEASE_READ;
3569 :
3570 0 : status = smb2_lease_break_ack(tree1b, &ack);
3571 0 : CHECK_STATUS(status, NT_STATUS_OK);
3572 0 : CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
3573 :
3574 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3575 :
3576 0 : status = smb2_create_recv(req2, tctx, &io2);
3577 0 : CHECK_STATUS(status, NT_STATUS_OK);
3578 0 : CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3579 0 : CHECK_LEASE_V2(&io2, "RH", true, LEASE2,
3580 : 0, 0, ls2.lease_epoch+1);
3581 0 : h2 = io2.out.file.handle;
3582 :
3583 0 : done:
3584 0 : smb2_util_close(tree1a, h);
3585 0 : smb2_util_close(tree1b, h2);
3586 :
3587 0 : smb2_util_unlink(tree1a, fname);
3588 :
3589 0 : talloc_free(mem_ctx);
3590 :
3591 0 : return ret;
3592 : }
3593 :
3594 :
3595 0 : static bool test_lease_timeout(struct torture_context *tctx,
3596 : struct smb2_tree *tree)
3597 : {
3598 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
3599 : struct smb2_create io;
3600 : struct smb2_lease ls1;
3601 : struct smb2_lease ls2;
3602 0 : struct smb2_handle h = {{0}};
3603 0 : struct smb2_handle hnew = {{0}};
3604 0 : struct smb2_handle h1b = {{0}};
3605 : NTSTATUS status;
3606 0 : const char *fname = "lease_timeout.dat";
3607 0 : bool ret = true;
3608 0 : struct smb2_lease_break_ack ack = {};
3609 0 : struct smb2_request *req2 = NULL;
3610 : struct smb2_write w;
3611 : uint32_t caps;
3612 :
3613 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3614 0 : if (!(caps & SMB2_CAP_LEASING)) {
3615 0 : torture_skip(tctx, "leases are not supported");
3616 : }
3617 :
3618 0 : smb2_util_unlink(tree, fname);
3619 :
3620 : /* Grab a RWH lease. */
3621 0 : smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3622 0 : status = smb2_create(tree, mem_ctx, &io);
3623 0 : CHECK_STATUS(status, NT_STATUS_OK);
3624 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3625 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3626 0 : h = io.out.file.handle;
3627 :
3628 0 : tree->session->transport->lease.handler = torture_lease_handler;
3629 0 : tree->session->transport->lease.private_data = tree;
3630 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
3631 0 : tree->session->transport->oplock.private_data = tree;
3632 :
3633 : /*
3634 : * Just don't ack the lease break.
3635 : */
3636 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3637 0 : lease_break_info.lease_skip_ack = true;
3638 :
3639 : /* Break with a RWH request. */
3640 0 : smb2_lease_create(&io, &ls2, false, fname, LEASE2, smb2_util_lease_state("RWH"));
3641 0 : req2 = smb2_create_send(tree, &io);
3642 0 : torture_assert(tctx, req2 != NULL, "smb2_create_send");
3643 0 : torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
3644 :
3645 0 : CHECK_BREAK_INFO("RWH", "RH", LEASE1);
3646 :
3647 : /* Copy the break request. */
3648 0 : ack.in.lease.lease_key =
3649 : lease_break_info.lease_break.current_lease.lease_key;
3650 0 : ack.in.lease.lease_state =
3651 0 : lease_break_info.lease_break.new_lease_state;
3652 :
3653 : /* Now wait for the timeout and get the reply. */
3654 0 : status = smb2_create_recv(req2, tctx, &io);
3655 0 : CHECK_STATUS(status, NT_STATUS_OK);
3656 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3657 0 : CHECK_LEASE(&io, "RH", true, LEASE2, 0);
3658 0 : hnew = io.out.file.handle;
3659 :
3660 : /* Ack the break after the timeout... */
3661 0 : status = smb2_lease_break_ack(tree, &ack);
3662 0 : CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
3663 :
3664 : /* Get state of the original handle. */
3665 0 : smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
3666 0 : status = smb2_create(tree, mem_ctx, &io);
3667 0 : CHECK_STATUS(status, NT_STATUS_OK);
3668 0 : CHECK_LEASE(&io, "", true, LEASE1, 0);
3669 0 : smb2_util_close(tree, io.out.file.handle);
3670 :
3671 : /* Write on the original handle and make sure it's still valid. */
3672 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3673 0 : ZERO_STRUCT(w);
3674 0 : w.in.file.handle = h;
3675 0 : w.in.offset = 0;
3676 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3677 0 : memset(w.in.data.data, '1', w.in.data.length);
3678 0 : status = smb2_write(tree, &w);
3679 0 : CHECK_STATUS(status, NT_STATUS_OK);
3680 :
3681 : /* Causes new handle to break to NONE. */
3682 0 : CHECK_BREAK_INFO("RH", "", LEASE2);
3683 :
3684 : /* Write on the new handle. */
3685 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3686 0 : ZERO_STRUCT(w);
3687 0 : w.in.file.handle = hnew;
3688 0 : w.in.offset = 0;
3689 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
3690 0 : memset(w.in.data.data, '2', w.in.data.length);
3691 0 : status = smb2_write(tree, &w);
3692 0 : CHECK_STATUS(status, NT_STATUS_OK);
3693 : /* No break - original handle was already NONE. */
3694 0 : CHECK_NO_BREAK(tctx);
3695 0 : smb2_util_close(tree, hnew);
3696 :
3697 : /* Upgrade to R on LEASE1. */
3698 0 : smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
3699 0 : status = smb2_create(tree, mem_ctx, &io);
3700 0 : CHECK_STATUS(status, NT_STATUS_OK);
3701 0 : CHECK_LEASE(&io, "R", true, LEASE1, 0);
3702 0 : h1b = io.out.file.handle;
3703 0 : smb2_util_close(tree, h1b);
3704 :
3705 : /* Upgrade to RWH on LEASE1. */
3706 0 : smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3707 0 : status = smb2_create(tree, mem_ctx, &io);
3708 0 : CHECK_STATUS(status, NT_STATUS_OK);
3709 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3710 0 : h1b = io.out.file.handle;
3711 0 : smb2_util_close(tree, h1b);
3712 :
3713 0 : done:
3714 0 : smb2_util_close(tree, h);
3715 0 : smb2_util_close(tree, hnew);
3716 0 : smb2_util_close(tree, h1b);
3717 :
3718 0 : smb2_util_unlink(tree, fname);
3719 :
3720 0 : talloc_free(mem_ctx);
3721 :
3722 0 : return ret;
3723 : }
3724 :
3725 0 : static bool test_lease_rename_wait(struct torture_context *tctx,
3726 : struct smb2_tree *tree)
3727 : {
3728 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
3729 : struct smb2_create io;
3730 : struct smb2_lease ls1;
3731 : struct smb2_lease ls2;
3732 : struct smb2_lease ls3;
3733 0 : struct smb2_handle h1 = {{0}};
3734 0 : struct smb2_handle h2 = {{0}};
3735 0 : struct smb2_handle h3 = {{0}};
3736 : union smb_setfileinfo sinfo;
3737 : NTSTATUS status;
3738 0 : const char *fname_src = "lease_rename_src.dat";
3739 0 : const char *fname_dst = "lease_rename_dst.dat";
3740 0 : bool ret = true;
3741 0 : struct smb2_lease_break_ack ack = {};
3742 0 : struct smb2_request *rename_req = NULL;
3743 : uint32_t caps;
3744 : unsigned int i;
3745 :
3746 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3747 0 : if (!(caps & SMB2_CAP_LEASING)) {
3748 0 : torture_skip(tctx, "leases are not supported");
3749 : }
3750 :
3751 0 : smb2_util_unlink(tree, fname_src);
3752 0 : smb2_util_unlink(tree, fname_dst);
3753 :
3754 : /* Short timeout for fails. */
3755 0 : tree->session->transport->options.request_timeout = 15;
3756 :
3757 : /* Grab a RH lease. */
3758 0 : smb2_lease_create(&io,
3759 : &ls1,
3760 : false,
3761 : fname_src,
3762 : LEASE1,
3763 : smb2_util_lease_state("RH"));
3764 0 : status = smb2_create(tree, mem_ctx, &io);
3765 0 : CHECK_STATUS(status, NT_STATUS_OK);
3766 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3767 0 : CHECK_LEASE(&io, "RH", true, LEASE1, 0);
3768 0 : h1 = io.out.file.handle;
3769 :
3770 : /* Second open with a RH lease. */
3771 0 : smb2_lease_create(&io,
3772 : &ls2,
3773 : false,
3774 : fname_src,
3775 : LEASE2,
3776 : smb2_util_lease_state("RH"));
3777 0 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
3778 0 : io.in.desired_access = GENERIC_READ_ACCESS;
3779 0 : status = smb2_create(tree, mem_ctx, &io);
3780 0 : CHECK_STATUS(status, NT_STATUS_OK);
3781 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3782 0 : CHECK_LEASE(&io, "RH", true, LEASE2, 0);
3783 0 : h2 = io.out.file.handle;
3784 :
3785 : /*
3786 : * Don't ack a lease break.
3787 : */
3788 0 : tree->session->transport->lease.handler = torture_lease_handler;
3789 0 : tree->session->transport->lease.private_data = tree;
3790 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3791 0 : lease_break_info.lease_skip_ack = true;
3792 :
3793 : /* Break with a rename. */
3794 0 : ZERO_STRUCT(sinfo);
3795 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3796 0 : sinfo.rename_information.in.file.handle = h1;
3797 0 : sinfo.rename_information.in.overwrite = true;
3798 0 : sinfo.rename_information.in.new_name = fname_dst;
3799 0 : rename_req = smb2_setinfo_file_send(tree, &sinfo);
3800 :
3801 0 : torture_assert(tctx,
3802 : rename_req != NULL,
3803 : "smb2_setinfo_file_send");
3804 0 : torture_assert(tctx,
3805 : rename_req->state == SMB2_REQUEST_RECV,
3806 : "rename pending");
3807 :
3808 : /* Try and open the destination with a RH lease. */
3809 0 : smb2_lease_create(&io,
3810 : &ls3,
3811 : false,
3812 : fname_dst,
3813 : LEASE3,
3814 : smb2_util_lease_state("RH"));
3815 : /* We want to open, not create. */
3816 0 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
3817 0 : io.in.desired_access = GENERIC_READ_ACCESS;
3818 0 : status = smb2_create(tree, mem_ctx, &io);
3819 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
3820 :
3821 : /*
3822 : * The smb2_create() I/O should have picked up the break request
3823 : * caused by the pending rename.
3824 : */
3825 :
3826 : /* Copy the break request. */
3827 0 : ack.in.lease.lease_key =
3828 : lease_break_info.lease_break.current_lease.lease_key;
3829 0 : ack.in.lease.lease_state =
3830 0 : lease_break_info.lease_break.new_lease_state;
3831 :
3832 : /*
3833 : * Give the server 3 more chances to have renamed
3834 : * the file. Better than doing a sleep.
3835 : */
3836 0 : for (i = 0; i < 3; i++) {
3837 0 : status = smb2_create(tree, mem_ctx, &io);
3838 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
3839 : }
3840 :
3841 : /* Ack the break. The server is now free to rename. */
3842 0 : status = smb2_lease_break_ack(tree, &ack);
3843 0 : CHECK_STATUS(status, NT_STATUS_OK);
3844 :
3845 : /* Get the rename reply. */
3846 0 : status = smb2_setinfo_recv(rename_req);
3847 0 : CHECK_STATUS(status, NT_STATUS_OK);
3848 :
3849 : /* The target should now exist. */
3850 0 : status = smb2_create(tree, mem_ctx, &io);
3851 0 : CHECK_STATUS(status, NT_STATUS_OK);
3852 0 : h3 = io.out.file.handle;
3853 :
3854 0 : done:
3855 0 : smb2_util_close(tree, h1);
3856 0 : smb2_util_close(tree, h2);
3857 0 : smb2_util_close(tree, h3);
3858 :
3859 0 : smb2_util_unlink(tree, fname_src);
3860 0 : smb2_util_unlink(tree, fname_dst);
3861 :
3862 0 : talloc_free(mem_ctx);
3863 :
3864 0 : return ret;
3865 : }
3866 :
3867 0 : static bool test_lease_v2_rename(struct torture_context *tctx,
3868 : struct smb2_tree *tree)
3869 : {
3870 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
3871 : struct smb2_create io;
3872 : struct smb2_lease ls1;
3873 : struct smb2_lease ls2;
3874 0 : struct smb2_handle h = {{0}};
3875 0 : struct smb2_handle h1 = {{0}};
3876 0 : struct smb2_handle h2 = {{0}};
3877 : union smb_setfileinfo sinfo;
3878 0 : const char *fname = "lease_v2_rename_src.dat";
3879 0 : const char *fname_dst = "lease_v2_rename_dst.dat";
3880 0 : bool ret = true;
3881 : NTSTATUS status;
3882 : uint32_t caps;
3883 : enum protocol_types protocol;
3884 :
3885 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3886 0 : if (!(caps & SMB2_CAP_LEASING)) {
3887 0 : torture_skip(tctx, "leases are not supported");
3888 : }
3889 :
3890 0 : protocol = smbXcli_conn_protocol(tree->session->transport->conn);
3891 0 : if (protocol < PROTOCOL_SMB3_00) {
3892 0 : torture_skip(tctx, "v2 leases are not supported");
3893 : }
3894 :
3895 0 : smb2_util_unlink(tree, fname);
3896 0 : smb2_util_unlink(tree, fname_dst);
3897 :
3898 0 : tree->session->transport->lease.handler = torture_lease_handler;
3899 0 : tree->session->transport->lease.private_data = tree;
3900 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
3901 0 : tree->session->transport->oplock.private_data = tree;
3902 :
3903 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3904 :
3905 0 : ZERO_STRUCT(io);
3906 0 : smb2_lease_v2_create_share(&io, &ls1, false, fname,
3907 : smb2_util_share_access("RWD"),
3908 : LEASE1, NULL,
3909 : smb2_util_lease_state("RHW"),
3910 : 0x4711);
3911 0 : status = smb2_create(tree, mem_ctx, &io);
3912 0 : CHECK_STATUS(status, NT_STATUS_OK);
3913 0 : h = io.out.file.handle;
3914 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3915 0 : ls1.lease_epoch += 1;
3916 0 : CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
3917 :
3918 : /* Now rename - what happens ? */
3919 0 : ZERO_STRUCT(sinfo);
3920 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3921 0 : sinfo.rename_information.in.file.handle = h;
3922 0 : sinfo.rename_information.in.overwrite = true;
3923 0 : sinfo.rename_information.in.new_name = fname_dst;
3924 0 : status = smb2_setinfo_file(tree, &sinfo);
3925 0 : CHECK_STATUS(status, NT_STATUS_OK);
3926 :
3927 : /* No lease break. */
3928 0 : CHECK_NO_BREAK(tctx);
3929 :
3930 : /* Check we can open another handle on the new name. */
3931 0 : smb2_lease_v2_create_share(&io, &ls1, false, fname_dst,
3932 : smb2_util_share_access("RWD"),
3933 : LEASE1, NULL,
3934 : smb2_util_lease_state(""),
3935 0 : ls1.lease_epoch);
3936 0 : status = smb2_create(tree, mem_ctx, &io);
3937 0 : CHECK_STATUS(status, NT_STATUS_OK);
3938 0 : h1 = io.out.file.handle;
3939 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3940 0 : CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
3941 0 : smb2_util_close(tree, h1);
3942 :
3943 : /* Try another lease key. */
3944 0 : smb2_lease_v2_create_share(&io, &ls2, false, fname_dst,
3945 : smb2_util_share_access("RWD"),
3946 : LEASE2, NULL,
3947 : smb2_util_lease_state("RWH"),
3948 : 0x44);
3949 0 : status = smb2_create(tree, mem_ctx, &io);
3950 0 : CHECK_STATUS(status, NT_STATUS_OK);
3951 0 : h2 = io.out.file.handle;
3952 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3953 0 : ls2.lease_epoch += 1;
3954 0 : CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch );
3955 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
3956 : "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
3957 0 : ls1.lease_epoch += 1;
3958 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
3959 :
3960 : /* Now rename back. */
3961 0 : ZERO_STRUCT(sinfo);
3962 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3963 0 : sinfo.rename_information.in.file.handle = h;
3964 0 : sinfo.rename_information.in.overwrite = true;
3965 0 : sinfo.rename_information.in.new_name = fname;
3966 0 : status = smb2_setinfo_file(tree, &sinfo);
3967 0 : CHECK_STATUS(status, NT_STATUS_OK);
3968 :
3969 : /* Breaks to R on LEASE2. */
3970 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
3971 : "RH", "R", LEASE2, ls2.lease_epoch + 1);
3972 0 : ls2.lease_epoch += 1;
3973 :
3974 : /* Check we can open another handle on the current name. */
3975 0 : smb2_lease_v2_create_share(&io, &ls1, false, fname,
3976 : smb2_util_share_access("RWD"),
3977 : LEASE1, NULL,
3978 : smb2_util_lease_state(""),
3979 0 : ls1.lease_epoch);
3980 0 : status = smb2_create(tree, mem_ctx, &io);
3981 0 : CHECK_STATUS(status, NT_STATUS_OK);
3982 0 : h1 = io.out.file.handle;
3983 0 : CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3984 0 : CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1.lease_epoch);
3985 0 : smb2_util_close(tree, h1);
3986 :
3987 0 : done:
3988 :
3989 0 : smb2_util_close(tree, h);
3990 0 : smb2_util_close(tree, h1);
3991 0 : smb2_util_close(tree, h2);
3992 :
3993 0 : smb2_util_unlink(tree, fname);
3994 0 : smb2_util_unlink(tree, fname_dst);
3995 :
3996 0 : smb2_util_unlink(tree, fname);
3997 0 : talloc_free(mem_ctx);
3998 0 : return ret;
3999 : }
4000 :
4001 :
4002 0 : static bool test_lease_dynamic_share(struct torture_context *tctx,
4003 : struct smb2_tree *tree1a)
4004 : {
4005 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
4006 : struct smb2_create io;
4007 : struct smb2_lease ls1;
4008 : struct smb2_handle h, h1, h2;
4009 : struct smb2_write w;
4010 : NTSTATUS status;
4011 0 : const char *fname = "dynamic_path.dat";
4012 0 : bool ret = true;
4013 : uint32_t caps;
4014 0 : struct smb2_tree *tree_2 = NULL;
4015 0 : struct smb2_tree *tree_3 = NULL;
4016 : struct smbcli_options options;
4017 0 : const char *orig_share = NULL;
4018 :
4019 0 : if (!TARGET_IS_SAMBA3(tctx)) {
4020 0 : torture_skip(tctx, "dynamic shares are not supported");
4021 : return true;
4022 : }
4023 :
4024 0 : options = tree1a->session->transport->options;
4025 0 : options.client_guid = GUID_random();
4026 :
4027 0 : caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
4028 0 : if (!(caps & SMB2_CAP_LEASING)) {
4029 0 : torture_skip(tctx, "leases are not supported");
4030 : }
4031 :
4032 : /*
4033 : * Save off original share name and change it to dynamic_share.
4034 : * This must have been pre-created with a dynamic path containing
4035 : * %t. It means we'll sleep between the connects in order to
4036 : * get a different timestamp for the share path.
4037 : */
4038 :
4039 0 : orig_share = lpcfg_parm_string(tctx->lp_ctx, NULL, "torture", "share");
4040 0 : orig_share = talloc_strdup(tctx->lp_ctx, orig_share);
4041 0 : if (orig_share == NULL) {
4042 0 : torture_result(tctx, TORTURE_FAIL, __location__ "no memory\n");
4043 0 : ret = false;
4044 0 : goto done;
4045 : }
4046 0 : lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", "dynamic_share");
4047 :
4048 : /* create a new connection (same client_guid) */
4049 0 : sleep(2);
4050 0 : if (!torture_smb2_connection_ext(tctx, 0, &options, &tree_2)) {
4051 0 : torture_result(tctx, TORTURE_FAIL,
4052 : __location__ "couldn't reconnect "
4053 : "max protocol 2.1, bailing\n");
4054 0 : ret = false;
4055 0 : goto done;
4056 : }
4057 :
4058 0 : tree_2->session->transport->lease.handler = torture_lease_handler;
4059 0 : tree_2->session->transport->lease.private_data = tree_2;
4060 0 : tree_2->session->transport->oplock.handler = torture_oplock_handler;
4061 0 : tree_2->session->transport->oplock.private_data = tree_2;
4062 :
4063 0 : smb2_util_unlink(tree_2, fname);
4064 :
4065 : /* create a new connection (same client_guid) */
4066 0 : sleep(2);
4067 0 : if (!torture_smb2_connection_ext(tctx, 0, &options, &tree_3)) {
4068 0 : torture_result(tctx, TORTURE_FAIL,
4069 : __location__ "couldn't reconnect "
4070 : "max protocol 3.0, bailing\n");
4071 0 : ret = false;
4072 0 : goto done;
4073 : }
4074 :
4075 0 : tree_3->session->transport->lease.handler = torture_lease_handler;
4076 0 : tree_3->session->transport->lease.private_data = tree_3;
4077 0 : tree_3->session->transport->oplock.handler = torture_oplock_handler;
4078 0 : tree_3->session->transport->oplock.private_data = tree_3;
4079 :
4080 0 : smb2_util_unlink(tree_3, fname);
4081 :
4082 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
4083 :
4084 : /* Get RWH lease over connection 2 */
4085 0 : smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4086 0 : status = smb2_create(tree_2, mem_ctx, &io);
4087 0 : CHECK_STATUS(status, NT_STATUS_OK);
4088 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4089 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
4090 0 : h = io.out.file.handle;
4091 :
4092 : /* Write some data into it. */
4093 0 : w.in.file.handle = h;
4094 0 : w.in.offset = 0;
4095 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4096 0 : memset(w.in.data.data, '1', w.in.data.length);
4097 0 : status = smb2_write(tree_2, &w);
4098 0 : CHECK_STATUS(status, NT_STATUS_OK);
4099 :
4100 : /* Open the same name over connection 3. */
4101 0 : smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4102 0 : status = smb2_create(tree_3, mem_ctx, &io);
4103 0 : CHECK_STATUS(status, NT_STATUS_OK);
4104 0 : h1 = io.out.file.handle;
4105 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4106 :
4107 : /* h1 should have replied with NONE. */
4108 0 : CHECK_LEASE(&io, "", true, LEASE1, 0);
4109 :
4110 : /* We should have broken h to NONE. */
4111 0 : CHECK_BREAK_INFO("RWH", "", LEASE1);
4112 :
4113 : /* Try to upgrade to RWH over connection 2 */
4114 0 : smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4115 0 : status = smb2_create(tree_2, mem_ctx, &io);
4116 0 : CHECK_STATUS(status, NT_STATUS_OK);
4117 0 : h2 = io.out.file.handle;
4118 0 : CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
4119 0 : CHECK_VAL(io.out.size, 4096);
4120 0 : CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
4121 : /* Should have been denied. */
4122 0 : CHECK_LEASE(&io, "", true, LEASE1, 0);
4123 0 : smb2_util_close(tree_2, h2);
4124 :
4125 : /* Try to upgrade to RWH over connection 3 */
4126 0 : smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4127 0 : status = smb2_create(tree_3, mem_ctx, &io);
4128 0 : CHECK_STATUS(status, NT_STATUS_OK);
4129 0 : h2 = io.out.file.handle;
4130 0 : CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
4131 0 : CHECK_VAL(io.out.size, 0);
4132 0 : CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
4133 : /* Should have been denied. */
4134 0 : CHECK_LEASE(&io, "", true, LEASE1, 0);
4135 0 : smb2_util_close(tree_3, h2);
4136 :
4137 : /* Write some data into it. */
4138 0 : w.in.file.handle = h1;
4139 0 : w.in.offset = 0;
4140 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
4141 0 : memset(w.in.data.data, '2', w.in.data.length);
4142 0 : status = smb2_write(tree_3, &w);
4143 0 : CHECK_STATUS(status, NT_STATUS_OK);
4144 :
4145 : /* Close everything.. */
4146 0 : smb2_util_close(tree_2, h);
4147 0 : smb2_util_close(tree_3, h1);
4148 :
4149 : /* And ensure we can get a lease ! */
4150 0 : smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4151 0 : status = smb2_create(tree_2, mem_ctx, &io);
4152 0 : CHECK_STATUS(status, NT_STATUS_OK);
4153 0 : CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
4154 0 : CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
4155 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
4156 0 : h = io.out.file.handle;
4157 : /* And the file is the right size. */
4158 0 : CHECK_VAL(io.out.size, 4096); \
4159 : /* Close it. */
4160 0 : smb2_util_close(tree_2, h);
4161 :
4162 : /* And ensure we can get a lease ! */
4163 0 : smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4164 0 : status = smb2_create(tree_3, mem_ctx, &io);
4165 0 : CHECK_STATUS(status, NT_STATUS_OK);
4166 0 : CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
4167 0 : CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
4168 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
4169 0 : h = io.out.file.handle;
4170 : /* And the file is the right size. */
4171 0 : CHECK_VAL(io.out.size, 1024); \
4172 : /* Close it. */
4173 0 : smb2_util_close(tree_3, h);
4174 :
4175 0 : done:
4176 :
4177 0 : if (tree_2 != NULL) {
4178 0 : smb2_util_close(tree_2, h);
4179 0 : smb2_util_unlink(tree_2, fname);
4180 : }
4181 0 : if (tree_3 != NULL) {
4182 0 : smb2_util_close(tree_3, h1);
4183 0 : smb2_util_close(tree_3, h2);
4184 :
4185 0 : smb2_util_unlink(tree_3, fname);
4186 : }
4187 :
4188 : /* Set sharename back. */
4189 0 : lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", orig_share);
4190 :
4191 0 : talloc_free(mem_ctx);
4192 :
4193 0 : return ret;
4194 : }
4195 :
4196 : /*
4197 : * Test identifies a bug where the Samba server will not trigger a lease break
4198 : * for a handle caching lease held by a client when the underlying file is
4199 : * deleted.
4200 : * Test:
4201 : * Connect session2.
4202 : * open file in session1
4203 : * session1 should have RWH lease.
4204 : * open file in session2
4205 : * lease break sent to session1 to downgrade lease to RH
4206 : * close file in session 2
4207 : * unlink file in session 2
4208 : * lease break sent to session1 to downgrade lease to R
4209 : * Cleanup
4210 : */
4211 0 : static bool test_lease_unlink(struct torture_context *tctx,
4212 : struct smb2_tree *tree1)
4213 : {
4214 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
4215 : NTSTATUS status;
4216 0 : bool ret = true;
4217 : struct smbcli_options transport2_options;
4218 0 : struct smb2_tree *tree2 = NULL;
4219 0 : struct smb2_transport *transport1 = tree1->session->transport;
4220 : struct smb2_transport *transport2;
4221 0 : struct smb2_handle h1 = {{ 0 }};
4222 0 : struct smb2_handle h2 = {{ 0 }};
4223 0 : const char *fname = "lease_unlink.dat";
4224 : uint32_t caps;
4225 : struct smb2_create io1;
4226 : struct smb2_create io2;
4227 : struct smb2_lease ls1;
4228 : struct smb2_lease ls2;
4229 :
4230 0 : caps = smb2cli_conn_server_capabilities(
4231 0 : tree1->session->transport->conn);
4232 0 : if (!(caps & SMB2_CAP_LEASING)) {
4233 0 : torture_skip(tctx, "leases are not supported");
4234 : }
4235 :
4236 : /* Connect 2nd connection */
4237 0 : transport2_options = transport1->options;
4238 0 : transport2_options.client_guid = GUID_random();
4239 0 : if (!torture_smb2_connection_ext(tctx, 0, &transport2_options, &tree2)) {
4240 0 : torture_warning(tctx, "couldn't reconnect, bailing\n");
4241 0 : return false;
4242 : }
4243 0 : transport2 = tree2->session->transport;
4244 :
4245 : /* Set lease handlers */
4246 0 : transport1->lease.handler = torture_lease_handler;
4247 0 : transport1->lease.private_data = tree1;
4248 0 : transport2->lease.handler = torture_lease_handler;
4249 0 : transport2->lease.private_data = tree2;
4250 :
4251 :
4252 0 : smb2_lease_create(&io1, &ls1, false, fname, LEASE1,
4253 : smb2_util_lease_state("RHW"));
4254 0 : smb2_lease_create(&io2, &ls2, false, fname, LEASE2,
4255 : smb2_util_lease_state("RHW"));
4256 :
4257 0 : smb2_util_unlink(tree1, fname);
4258 :
4259 0 : torture_comment(tctx, "Client opens fname with session 1\n");
4260 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
4261 0 : status = smb2_create(tree1, mem_ctx, &io1);
4262 0 : CHECK_STATUS(status, NT_STATUS_OK);
4263 0 : h1 = io1.out.file.handle;
4264 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4265 0 : CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
4266 0 : CHECK_VAL(lease_break_info.count, 0);
4267 :
4268 0 : torture_comment(tctx, "Client opens fname with session 2\n");
4269 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
4270 0 : status = smb2_create(tree2, mem_ctx, &io2);
4271 0 : CHECK_STATUS(status, NT_STATUS_OK);
4272 0 : h2 = io2.out.file.handle;
4273 0 : CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
4274 0 : CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
4275 0 : CHECK_VAL(lease_break_info.count, 1);
4276 0 : CHECK_BREAK_INFO("RHW", "RH", LEASE1);
4277 :
4278 0 : torture_comment(tctx,
4279 : "Client closes and then unlinks fname with session 2\n");
4280 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
4281 0 : smb2_util_close(tree2, h2);
4282 0 : smb2_util_unlink(tree2, fname);
4283 0 : CHECK_VAL(lease_break_info.count, 1);
4284 0 : CHECK_BREAK_INFO("RH", "R", LEASE1);
4285 :
4286 0 : done:
4287 0 : smb2_util_close(tree1, h1);
4288 0 : smb2_util_close(tree2, h2);
4289 0 : smb2_util_unlink(tree1, fname);
4290 :
4291 0 : return ret;
4292 : }
4293 :
4294 0 : static bool test_lease_timeout_disconnect(struct torture_context *tctx,
4295 : struct smb2_tree *tree1)
4296 : {
4297 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
4298 : NTSTATUS status;
4299 0 : bool ret = true;
4300 : struct smbcli_options transport2_options;
4301 : struct smbcli_options transport3_options;
4302 0 : struct smb2_tree *tree2 = NULL;
4303 0 : struct smb2_tree *tree3 = NULL;
4304 0 : struct smb2_transport *transport1 = tree1->session->transport;
4305 : struct smb2_transport *transport2;
4306 : struct smb2_transport *transport3;
4307 0 : const char *fname = "lease_timeout_logoff.dat" ;
4308 : uint32_t caps;
4309 : struct smb2_create io1;
4310 : struct smb2_create io2;
4311 0 : struct smb2_request *req2 = NULL;
4312 : struct smb2_lease ls1;
4313 :
4314 0 : caps = smb2cli_conn_server_capabilities(
4315 0 : tree1->session->transport->conn);
4316 0 : if (!(caps & SMB2_CAP_LEASING)) {
4317 0 : torture_skip(tctx, "leases are not supported");
4318 : }
4319 :
4320 0 : smb2_util_unlink(tree1, fname);
4321 :
4322 : /* Connect 2nd connection */
4323 0 : torture_comment(tctx, "connect tree2 with the same client_guid\n");
4324 0 : transport2_options = transport1->options;
4325 0 : if (!torture_smb2_connection_ext(tctx, 0, &transport2_options, &tree2)) {
4326 0 : torture_warning(tctx, "couldn't reconnect, bailing\n");
4327 0 : return false;
4328 : }
4329 0 : transport2 = tree2->session->transport;
4330 :
4331 : /* Connect 3rd connection */
4332 0 : torture_comment(tctx, "connect tree3 with the same client_guid\n");
4333 0 : transport3_options = transport1->options;
4334 0 : if (!torture_smb2_connection_ext(tctx, 0, &transport3_options, &tree3)) {
4335 0 : torture_warning(tctx, "couldn't reconnect, bailing\n");
4336 0 : return false;
4337 : }
4338 0 : transport3 = tree3->session->transport;
4339 :
4340 : /* Set lease handlers */
4341 0 : transport1->lease.handler = torture_lease_handler;
4342 0 : transport1->lease.private_data = tree1;
4343 0 : transport2->lease.handler = torture_lease_handler;
4344 0 : transport2->lease.private_data = tree2;
4345 0 : transport3->lease.handler = torture_lease_handler;
4346 0 : transport3->lease.private_data = tree3;
4347 :
4348 0 : smb2_lease_create_share(&io1, &ls1, false, fname,
4349 : smb2_util_share_access(""),
4350 : LEASE1,
4351 : smb2_util_lease_state("RH"));
4352 0 : io1.in.durable_open = true;
4353 0 : smb2_generic_create(&io2, NULL, false, fname,
4354 : NTCREATEX_DISP_OPEN_IF,
4355 : SMB2_OPLOCK_LEVEL_NONE, 0, 0);
4356 :
4357 0 : torture_comment(tctx, "tree1: create file[%s] with durable RH lease (SHARE NONE)\n", fname);
4358 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
4359 0 : lease_break_info.lease_skip_ack = true;
4360 0 : status = smb2_create(tree1, mem_ctx, &io1);
4361 0 : CHECK_STATUS(status, NT_STATUS_OK);
4362 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4363 0 : CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
4364 0 : CHECK_VAL(lease_break_info.count, 0);
4365 :
4366 0 : torture_comment(tctx, "tree1: skip lease acks\n");
4367 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
4368 0 : lease_break_info.lease_skip_ack = true;
4369 0 : torture_comment(tctx, "tree2: open file[%s] without lease (SHARE RWD)\n", fname);
4370 0 : req2 = smb2_create_send(tree2, &io2);
4371 0 : torture_assert(tctx, req2 != NULL, "req2 started");
4372 :
4373 0 : torture_comment(tctx, "tree1: wait for lease break\n");
4374 0 : torture_wait_for_lease_break(tctx);
4375 0 : CHECK_VAL(lease_break_info.count, 1);
4376 0 : CHECK_BREAK_INFO("RH", "R", LEASE1);
4377 :
4378 0 : torture_comment(tctx, "tree1: reset lease handler\n");
4379 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
4380 0 : lease_break_info.lease_skip_ack = true;
4381 0 : CHECK_VAL(lease_break_info.count, 0);
4382 :
4383 0 : torture_comment(tctx, "tree2: check for SMB2_REQUEST_RECV\n");
4384 0 : torture_assert_int_equal(tctx, req2->state,
4385 : SMB2_REQUEST_RECV,
4386 : "SMB2_REQUEST_RECV");
4387 :
4388 0 : torture_comment(tctx, "sleep 1\n");
4389 0 : smb_msleep(1000);
4390 :
4391 0 : torture_comment(tctx, "transport1: keepalive\n");
4392 0 : status = smb2_keepalive(transport1);
4393 0 : CHECK_STATUS(status, NT_STATUS_OK);
4394 :
4395 0 : torture_comment(tctx, "transport2: keepalive\n");
4396 0 : status = smb2_keepalive(transport2);
4397 0 : CHECK_STATUS(status, NT_STATUS_OK);
4398 :
4399 0 : torture_comment(tctx, "transport3: keepalive\n");
4400 0 : status = smb2_keepalive(transport3);
4401 0 : CHECK_STATUS(status, NT_STATUS_OK);
4402 :
4403 0 : torture_comment(tctx, "tree2: check for SMB2_REQUEST_RECV\n");
4404 0 : torture_assert_int_equal(tctx, req2->state,
4405 : SMB2_REQUEST_RECV,
4406 : "SMB2_REQUEST_RECV");
4407 0 : torture_comment(tctx, "tree2: check for STATUS_PENDING\n");
4408 0 : torture_assert(tctx, req2->cancel.can_cancel, "STATUS_PENDING");
4409 :
4410 0 : torture_comment(tctx, "sleep 1\n");
4411 0 : smb_msleep(1000);
4412 0 : torture_comment(tctx, "transport1: keepalive\n");
4413 0 : status = smb2_keepalive(transport1);
4414 0 : CHECK_STATUS(status, NT_STATUS_OK);
4415 0 : torture_comment(tctx, "transport2: disconnect\n");
4416 0 : TALLOC_FREE(tree2);
4417 :
4418 0 : torture_comment(tctx, "sleep 1\n");
4419 0 : smb_msleep(1000);
4420 0 : torture_comment(tctx, "transport1: keepalive\n");
4421 0 : status = smb2_keepalive(transport1);
4422 0 : CHECK_STATUS(status, NT_STATUS_OK);
4423 0 : torture_comment(tctx, "transport1: disconnect\n");
4424 0 : TALLOC_FREE(tree1);
4425 :
4426 0 : torture_comment(tctx, "sleep 1\n");
4427 0 : smb_msleep(1000);
4428 0 : torture_comment(tctx, "transport3: keepalive\n");
4429 0 : status = smb2_keepalive(transport3);
4430 0 : CHECK_STATUS(status, NT_STATUS_OK);
4431 0 : torture_comment(tctx, "transport3: disconnect\n");
4432 0 : TALLOC_FREE(tree3);
4433 :
4434 0 : done:
4435 :
4436 0 : return ret;
4437 : }
4438 :
4439 0 : static bool test_lease_duplicate_create(struct torture_context *tctx,
4440 : struct smb2_tree *tree)
4441 : {
4442 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
4443 : struct smb2_create io;
4444 : struct smb2_lease ls;
4445 0 : struct smb2_handle h1 = {{0}};
4446 0 : struct smb2_handle h2 = {{0}};
4447 : NTSTATUS status;
4448 0 : const char *fname1 = "duplicate_create1.dat";
4449 0 : const char *fname2 = "duplicate_create2.dat";
4450 0 : bool ret = true;
4451 : uint32_t caps;
4452 :
4453 0 : caps = smb2cli_conn_server_capabilities(
4454 0 : tree->session->transport->conn);
4455 0 : if (!(caps & SMB2_CAP_LEASING)) {
4456 0 : torture_skip(tctx, "leases are not supported");
4457 : }
4458 :
4459 : /* Ensure files don't exist. */
4460 0 : smb2_util_unlink(tree, fname1);
4461 0 : smb2_util_unlink(tree, fname2);
4462 :
4463 : /* Create file1 - LEASE1 key. */
4464 0 : smb2_lease_create(&io, &ls, false, fname1, LEASE1,
4465 : smb2_util_lease_state("RWH"));
4466 0 : status = smb2_create(tree, mem_ctx, &io);
4467 0 : CHECK_STATUS(status, NT_STATUS_OK);
4468 0 : h1 = io.out.file.handle;
4469 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4470 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
4471 :
4472 : /*
4473 : * Create file2 with the same LEASE1 key - this should fail with.
4474 : * INVALID_PARAMETER.
4475 : */
4476 0 : smb2_lease_create(&io, &ls, false, fname2, LEASE1,
4477 : smb2_util_lease_state("RWH"));
4478 0 : status = smb2_create(tree, mem_ctx, &io);
4479 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
4480 0 : smb2_util_close(tree, h1);
4481 :
4482 0 : done:
4483 0 : smb2_util_close(tree, h2);
4484 0 : smb2_util_close(tree, h1);
4485 0 : smb2_util_unlink(tree, fname1);
4486 0 : smb2_util_unlink(tree, fname2);
4487 0 : talloc_free(mem_ctx);
4488 0 : return ret;
4489 : }
4490 :
4491 0 : static bool test_lease_duplicate_open(struct torture_context *tctx,
4492 : struct smb2_tree *tree)
4493 : {
4494 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
4495 : struct smb2_create io;
4496 : struct smb2_lease ls;
4497 0 : struct smb2_handle h1 = {{0}};
4498 0 : struct smb2_handle h2 = {{0}};
4499 : NTSTATUS status;
4500 0 : const char *fname1 = "duplicate_open1.dat";
4501 0 : const char *fname2 = "duplicate_open2.dat";
4502 0 : bool ret = true;
4503 : uint32_t caps;
4504 :
4505 0 : caps = smb2cli_conn_server_capabilities(
4506 0 : tree->session->transport->conn);
4507 0 : if (!(caps & SMB2_CAP_LEASING)) {
4508 0 : torture_skip(tctx, "leases are not supported");
4509 : }
4510 :
4511 : /* Ensure files don't exist. */
4512 0 : smb2_util_unlink(tree, fname1);
4513 0 : smb2_util_unlink(tree, fname2);
4514 :
4515 : /* Create file1 - LEASE1 key. */
4516 0 : smb2_lease_create(&io, &ls, false, fname1, LEASE1,
4517 : smb2_util_lease_state("RWH"));
4518 0 : status = smb2_create(tree, mem_ctx, &io);
4519 0 : CHECK_STATUS(status, NT_STATUS_OK);
4520 0 : h1 = io.out.file.handle;
4521 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4522 0 : CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
4523 :
4524 : /* Leave file1 open and leased. */
4525 :
4526 : /* Create file2 - no lease. */
4527 0 : smb2_lease_create(&io, NULL, false, fname2, 0,
4528 : smb2_util_lease_state("RWH"));
4529 0 : status = smb2_create(tree, mem_ctx, &io);
4530 0 : CHECK_STATUS(status, NT_STATUS_OK);
4531 0 : h2 = io.out.file.handle;
4532 0 : CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4533 : /* Close it. */
4534 0 : smb2_util_close(tree, h2);
4535 :
4536 : /*
4537 : * Try and open file2 with the same LEASE1 key - this should fail with.
4538 : * INVALID_PARAMETER.
4539 : */
4540 0 : smb2_lease_create(&io, &ls, false, fname2, LEASE1,
4541 : smb2_util_lease_state("RWH"));
4542 0 : status = smb2_create(tree, mem_ctx, &io);
4543 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
4544 : /*
4545 : * If we did open this is an error, but save off
4546 : * the handle so we close below.
4547 : */
4548 0 : h2 = io.out.file.handle;
4549 :
4550 0 : done:
4551 0 : smb2_util_close(tree, h2);
4552 0 : smb2_util_close(tree, h1);
4553 0 : smb2_util_unlink(tree, fname1);
4554 0 : smb2_util_unlink(tree, fname2);
4555 0 : talloc_free(mem_ctx);
4556 0 : return ret;
4557 : }
4558 :
4559 0 : static bool test_lease_v1_bug_15148(struct torture_context *tctx,
4560 : struct smb2_tree *tree)
4561 : {
4562 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
4563 : struct smb2_create io1;
4564 : struct smb2_create io2;
4565 : struct smb2_lease ls1;
4566 : struct smb2_lease ls2;
4567 0 : struct smb2_handle h1 = {{0}};
4568 0 : struct smb2_handle h2 = {{0}};
4569 : struct smb2_write w;
4570 : NTSTATUS status;
4571 0 : const char *fname = "lease_v1_bug_15148.dat";
4572 0 : bool ret = true;
4573 : uint32_t caps;
4574 :
4575 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
4576 0 : if (!(caps & SMB2_CAP_LEASING)) {
4577 0 : torture_skip(tctx, "leases are not supported");
4578 : }
4579 :
4580 0 : tree->session->transport->lease.handler = torture_lease_handler;
4581 0 : tree->session->transport->lease.private_data = tree;
4582 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
4583 0 : tree->session->transport->oplock.private_data = tree;
4584 :
4585 0 : smb2_util_unlink(tree, fname);
4586 :
4587 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
4588 :
4589 : /* Grab R lease over connection 1a */
4590 0 : smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
4591 0 : status = smb2_create(tree, mem_ctx, &io1);
4592 0 : CHECK_STATUS(status, NT_STATUS_OK);
4593 0 : h1 = io1.out.file.handle;
4594 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4595 0 : CHECK_LEASE(&io1, "R", true, LEASE1, 0);
4596 :
4597 0 : CHECK_NO_BREAK(tctx);
4598 :
4599 : /* Contend with LEASE2. */
4600 0 : smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state("R"));
4601 0 : status = smb2_create(tree, mem_ctx, &io2);
4602 0 : CHECK_STATUS(status, NT_STATUS_OK);
4603 0 : h2 = io2.out.file.handle;
4604 0 : CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
4605 0 : CHECK_LEASE(&io2, "R", true, LEASE2, 0);
4606 :
4607 0 : CHECK_NO_BREAK(tctx);
4608 :
4609 0 : ZERO_STRUCT(w);
4610 0 : w.in.file.handle = h1;
4611 0 : w.in.offset = 0;
4612 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4613 0 : memset(w.in.data.data, 'o', w.in.data.length);
4614 0 : status = smb2_write(tree, &w);
4615 0 : CHECK_STATUS(status, NT_STATUS_OK);
4616 :
4617 0 : ls2.lease_epoch += 1;
4618 0 : CHECK_BREAK_INFO("R", "", LEASE2);
4619 :
4620 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
4621 :
4622 0 : ZERO_STRUCT(w);
4623 0 : w.in.file.handle = h1;
4624 0 : w.in.offset = 0;
4625 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4626 0 : memset(w.in.data.data, 'O', w.in.data.length);
4627 0 : status = smb2_write(tree, &w);
4628 0 : CHECK_STATUS(status, NT_STATUS_OK);
4629 :
4630 0 : CHECK_NO_BREAK(tctx);
4631 :
4632 0 : ZERO_STRUCT(w);
4633 0 : w.in.file.handle = h2;
4634 0 : w.in.offset = 0;
4635 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4636 0 : memset(w.in.data.data, 'o', w.in.data.length);
4637 0 : status = smb2_write(tree, &w);
4638 0 : CHECK_STATUS(status, NT_STATUS_OK);
4639 :
4640 0 : ls1.lease_epoch += 1;
4641 0 : CHECK_BREAK_INFO("R", "", LEASE1);
4642 :
4643 0 : done:
4644 0 : smb2_util_close(tree, h1);
4645 0 : smb2_util_close(tree, h2);
4646 :
4647 0 : smb2_util_unlink(tree, fname);
4648 :
4649 0 : talloc_free(mem_ctx);
4650 :
4651 0 : return ret;
4652 : }
4653 :
4654 0 : static bool test_lease_v2_bug_15148(struct torture_context *tctx,
4655 : struct smb2_tree *tree)
4656 : {
4657 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
4658 : struct smb2_create io1;
4659 : struct smb2_create io2;
4660 : struct smb2_lease ls1;
4661 : struct smb2_lease ls2;
4662 0 : struct smb2_handle h1 = {{0}};
4663 0 : struct smb2_handle h2 = {{0}};
4664 : struct smb2_write w;
4665 : NTSTATUS status;
4666 0 : const char *fname = "lease_v2_bug_15148.dat";
4667 0 : bool ret = true;
4668 : uint32_t caps;
4669 : enum protocol_types protocol;
4670 :
4671 0 : caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
4672 0 : if (!(caps & SMB2_CAP_LEASING)) {
4673 0 : torture_skip(tctx, "leases are not supported");
4674 : }
4675 :
4676 0 : protocol = smbXcli_conn_protocol(tree->session->transport->conn);
4677 0 : if (protocol < PROTOCOL_SMB3_00) {
4678 0 : torture_skip(tctx, "v2 leases are not supported");
4679 : }
4680 :
4681 0 : tree->session->transport->lease.handler = torture_lease_handler;
4682 0 : tree->session->transport->lease.private_data = tree;
4683 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
4684 0 : tree->session->transport->oplock.private_data = tree;
4685 :
4686 0 : smb2_util_unlink(tree, fname);
4687 :
4688 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
4689 :
4690 : /* Grab R lease over connection 1a */
4691 0 : smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
4692 : smb2_util_lease_state("R"), 0x4711);
4693 0 : status = smb2_create(tree, mem_ctx, &io1);
4694 0 : CHECK_STATUS(status, NT_STATUS_OK);
4695 0 : h1 = io1.out.file.handle;
4696 0 : CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4697 0 : ls1.lease_epoch += 1;
4698 0 : CHECK_LEASE_V2(&io1, "R", true, LEASE1,
4699 : 0, 0, ls1.lease_epoch);
4700 :
4701 0 : CHECK_NO_BREAK(tctx);
4702 :
4703 : /* Contend with LEASE2. */
4704 0 : smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
4705 : smb2_util_lease_state("R"), 0x11);
4706 0 : status = smb2_create(tree, mem_ctx, &io2);
4707 0 : CHECK_STATUS(status, NT_STATUS_OK);
4708 0 : h2 = io2.out.file.handle;
4709 0 : CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
4710 0 : ls2.lease_epoch += 1;
4711 0 : CHECK_LEASE_V2(&io2, "R", true, LEASE2,
4712 : 0, 0, ls2.lease_epoch);
4713 :
4714 0 : CHECK_NO_BREAK(tctx);
4715 :
4716 0 : ZERO_STRUCT(w);
4717 0 : w.in.file.handle = h1;
4718 0 : w.in.offset = 0;
4719 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4720 0 : memset(w.in.data.data, 'o', w.in.data.length);
4721 0 : status = smb2_write(tree, &w);
4722 0 : CHECK_STATUS(status, NT_STATUS_OK);
4723 :
4724 0 : ls2.lease_epoch += 1;
4725 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
4726 : "R", "", LEASE2, ls2.lease_epoch);
4727 :
4728 0 : torture_reset_lease_break_info(tctx, &lease_break_info);
4729 :
4730 0 : ZERO_STRUCT(w);
4731 0 : w.in.file.handle = h1;
4732 0 : w.in.offset = 0;
4733 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4734 0 : memset(w.in.data.data, 'O', w.in.data.length);
4735 0 : status = smb2_write(tree, &w);
4736 0 : CHECK_STATUS(status, NT_STATUS_OK);
4737 :
4738 0 : CHECK_NO_BREAK(tctx);
4739 :
4740 0 : ZERO_STRUCT(w);
4741 0 : w.in.file.handle = h2;
4742 0 : w.in.offset = 0;
4743 0 : w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4744 0 : memset(w.in.data.data, 'o', w.in.data.length);
4745 0 : status = smb2_write(tree, &w);
4746 0 : CHECK_STATUS(status, NT_STATUS_OK);
4747 :
4748 0 : ls1.lease_epoch += 1;
4749 0 : CHECK_BREAK_INFO_V2(tree->session->transport,
4750 : "R", "", LEASE1, ls1.lease_epoch);
4751 :
4752 0 : done:
4753 0 : smb2_util_close(tree, h1);
4754 0 : smb2_util_close(tree, h2);
4755 :
4756 0 : smb2_util_unlink(tree, fname);
4757 :
4758 0 : talloc_free(mem_ctx);
4759 :
4760 0 : return ret;
4761 : }
4762 :
4763 964 : struct torture_suite *torture_smb2_lease_init(TALLOC_CTX *ctx)
4764 : {
4765 738 : struct torture_suite *suite =
4766 226 : torture_suite_create(ctx, "lease");
4767 :
4768 964 : torture_suite_add_1smb2_test(suite, "request", test_lease_request);
4769 964 : torture_suite_add_1smb2_test(suite, "break_twice",
4770 : test_lease_break_twice);
4771 964 : torture_suite_add_1smb2_test(suite, "nobreakself",
4772 : test_lease_nobreakself);
4773 964 : torture_suite_add_1smb2_test(suite, "statopen", test_lease_statopen);
4774 964 : torture_suite_add_1smb2_test(suite, "statopen2", test_lease_statopen2);
4775 964 : torture_suite_add_1smb2_test(suite, "statopen3", test_lease_statopen3);
4776 964 : torture_suite_add_1smb2_test(suite, "statopen4", test_lease_statopen4);
4777 964 : torture_suite_add_1smb2_test(suite, "upgrade", test_lease_upgrade);
4778 964 : torture_suite_add_1smb2_test(suite, "upgrade2", test_lease_upgrade2);
4779 964 : torture_suite_add_1smb2_test(suite, "upgrade3", test_lease_upgrade3);
4780 964 : torture_suite_add_1smb2_test(suite, "break", test_lease_break);
4781 964 : torture_suite_add_1smb2_test(suite, "oplock", test_lease_oplock);
4782 964 : torture_suite_add_1smb2_test(suite, "multibreak", test_lease_multibreak);
4783 964 : torture_suite_add_1smb2_test(suite, "breaking1", test_lease_breaking1);
4784 964 : torture_suite_add_1smb2_test(suite, "breaking2", test_lease_breaking2);
4785 964 : torture_suite_add_1smb2_test(suite, "breaking3", test_lease_breaking3);
4786 964 : torture_suite_add_1smb2_test(suite, "v2_breaking3", test_lease_v2_breaking3);
4787 964 : torture_suite_add_1smb2_test(suite, "breaking4", test_lease_breaking4);
4788 964 : torture_suite_add_1smb2_test(suite, "breaking5", test_lease_breaking5);
4789 964 : torture_suite_add_1smb2_test(suite, "breaking6", test_lease_breaking6);
4790 964 : torture_suite_add_2smb2_test(suite, "lock1", test_lease_lock1);
4791 964 : torture_suite_add_1smb2_test(suite, "complex1", test_lease_complex1);
4792 964 : torture_suite_add_1smb2_test(suite, "v2_request_parent",
4793 : test_lease_v2_request_parent);
4794 964 : torture_suite_add_1smb2_test(suite, "v2_request", test_lease_v2_request);
4795 964 : torture_suite_add_1smb2_test(suite, "v2_epoch1", test_lease_v2_epoch1);
4796 964 : torture_suite_add_1smb2_test(suite, "v2_epoch2", test_lease_v2_epoch2);
4797 964 : torture_suite_add_1smb2_test(suite, "v2_epoch3", test_lease_v2_epoch3);
4798 964 : torture_suite_add_1smb2_test(suite, "v2_complex1", test_lease_v2_complex1);
4799 964 : torture_suite_add_1smb2_test(suite, "v2_complex2", test_lease_v2_complex2);
4800 964 : torture_suite_add_1smb2_test(suite, "v2_rename", test_lease_v2_rename);
4801 964 : torture_suite_add_1smb2_test(suite, "dynamic_share", test_lease_dynamic_share);
4802 964 : torture_suite_add_1smb2_test(suite, "timeout", test_lease_timeout);
4803 964 : torture_suite_add_1smb2_test(suite, "unlink", test_lease_unlink);
4804 964 : torture_suite_add_1smb2_test(suite, "timeout-disconnect", test_lease_timeout_disconnect);
4805 964 : torture_suite_add_1smb2_test(suite, "rename_wait",
4806 : test_lease_rename_wait);
4807 964 : torture_suite_add_1smb2_test(suite, "duplicate_create",
4808 : test_lease_duplicate_create);
4809 964 : torture_suite_add_1smb2_test(suite, "duplicate_open",
4810 : test_lease_duplicate_open);
4811 964 : torture_suite_add_1smb2_test(suite, "v1_bug15148",
4812 : test_lease_v1_bug_15148);
4813 964 : torture_suite_add_1smb2_test(suite, "v2_bug15148",
4814 : test_lease_v2_bug_15148);
4815 :
4816 964 : suite->description = talloc_strdup(suite, "SMB2-LEASE tests");
4817 :
4818 964 : return suite;
4819 : }
|