source: branches/samba-3.5.x/source4/torture/smb2/lease.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 16 years ago

Samba 3.5.0: Initial import

File size: 24.9 KB
Line 
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 "lib/events/events.h"
24#include "librpc/gen_ndr/security.h"
25#include "libcli/smb2/smb2.h"
26#include "libcli/smb2/smb2_calls.h"
27#include "torture/torture.h"
28#include "torture/smb2/proto.h"
29
30static inline uint32_t lease(const char *ls) {
31 uint32_t val = 0;
32 int i;
33
34 for (i = 0; i < strlen(ls); i++) {
35 switch (ls[i]) {
36 case 'R':
37 val |= SMB2_LEASE_READ;
38 break;
39 case 'H':
40 val |= SMB2_LEASE_HANDLE;
41 break;
42 case 'W':
43 val |= SMB2_LEASE_WRITE;
44 break;
45 }
46 }
47
48 return val;
49}
50
51#define CHECK_VAL(v, correct) do { \
52 if ((v) != (correct)) { \
53 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
54 __location__, #v, (int)(v), (int)(correct)); \
55 ret = false; \
56 }} while (0)
57
58#define CHECK_STATUS(status, correct) do { \
59 if (!NT_STATUS_EQUAL(status, correct)) { \
60 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
61 nt_errstr(status), nt_errstr(correct)); \
62 ret = false; \
63 goto done; \
64 }} while (0)
65
66static void smb2_generic_create(struct smb2_create *io, struct smb2_lease *ls,
67 bool dir, const char *name, uint32_t disposition,
68 uint32_t oplock, uint64_t leasekey,
69 uint32_t leasestate)
70{
71 ZERO_STRUCT(*io);
72 io->in.security_flags = 0x00;
73 io->in.oplock_level = oplock;
74 io->in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
75 io->in.create_flags = 0x00000000;
76 io->in.reserved = 0x00000000;
77 io->in.desired_access = SEC_RIGHTS_FILE_ALL;
78 io->in.file_attributes = FILE_ATTRIBUTE_NORMAL;
79 io->in.share_access = NTCREATEX_SHARE_ACCESS_READ |
80 NTCREATEX_SHARE_ACCESS_WRITE |
81 NTCREATEX_SHARE_ACCESS_DELETE;
82 io->in.create_disposition = disposition;
83 io->in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
84 NTCREATEX_OPTIONS_ASYNC_ALERT |
85 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
86 0x00200000;
87 io->in.fname = name;
88
89 if (dir) {
90 io->in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
91 io->in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE;
92 io->in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
93 io->in.create_disposition = NTCREATEX_DISP_CREATE;
94 }
95
96 if (ls) {
97 ZERO_STRUCT(*ls);
98 ls->lease_key.data[0] = leasekey;
99 ls->lease_key.data[1] = ~leasekey;
100 ls->lease_state = leasestate;
101 io->in.lease_request = ls;
102 }
103}
104
105static void smb2_lease_create(struct smb2_create *io, struct smb2_lease *ls,
106 bool dir, const char *name, uint64_t leasekey,
107 uint32_t leasestate)
108{
109 smb2_generic_create(io, ls, dir, name, NTCREATEX_DISP_OPEN_IF,
110 SMB2_OPLOCK_LEVEL_LEASE, leasekey, leasestate);
111}
112
113static void smb2_oplock_create(struct smb2_create *io, const char *name,
114 uint32_t oplock)
115{
116 smb2_generic_create(io, NULL, false, name, NTCREATEX_DISP_OPEN_IF,
117 oplock, 0, 0);
118}
119
120#define CHECK_CREATED(__io, __created, __attribute) \
121 do { \
122 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
123 CHECK_VAL((__io)->out.alloc_size, 0); \
124 CHECK_VAL((__io)->out.size, 0); \
125 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
126 CHECK_VAL((__io)->out.reserved2, 0); \
127 } while(0)
128
129#define CHECK_LEASE(__io, __state, __oplevel, __key) \
130 do { \
131 if (__oplevel) { \
132 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
133 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], (__key)); \
134 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], ~(__key)); \
135 CHECK_VAL((__io)->out.lease_response.lease_state, lease(__state)); \
136 } else { \
137 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
138 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], 0); \
139 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], 0); \
140 CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
141 } \
142 \
143 CHECK_VAL((__io)->out.lease_response.lease_flags, 0); \
144 CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
145 } while(0) \
146
147static const uint64_t LEASE1 = 0xBADC0FFEE0DDF00Dull;
148static const uint64_t LEASE2 = 0xDEADBEEFFEEDBEADull;
149static const uint64_t LEASE3 = 0xDAD0FFEDD00DF00Dull;
150
151#define NREQUEST_RESULTS 8
152static const char *request_results[NREQUEST_RESULTS][2] = {
153 { "", "" },
154 { "R", "R" },
155 { "H", "" },
156 { "W", "" },
157 { "RH", "RH" },
158 { "RW", "RW" },
159 { "HW", "" },
160 { "RHW", "RHW" },
161};
162
163static bool test_lease_request(struct torture_context *tctx,
164 struct smb2_tree *tree)
165{
166 TALLOC_CTX *mem_ctx = talloc_new(tctx);
167 struct smb2_create io;
168 struct smb2_lease ls;
169 struct smb2_handle h1, h2;
170 NTSTATUS status;
171 const char *fname = "lease.dat";
172 const char *fname2 = "lease2.dat";
173 const char *sname = "lease.dat:stream";
174 const char *dname = "lease.dir";
175 bool ret = true;
176 int i;
177
178 smb2_util_unlink(tree, fname);
179 smb2_util_unlink(tree, fname2);
180 smb2_util_rmdir(tree, dname);
181
182 /* Win7 is happy to grant RHW leases on files. */
183 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease("RHW"));
184 status = smb2_create(tree, mem_ctx, &io);
185 CHECK_STATUS(status, NT_STATUS_OK);
186 h1 = io.out.file.handle;
187 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
188 CHECK_LEASE(&io, "RHW", true, LEASE1);
189
190 /* But will reject leases on directories. */
191 smb2_lease_create(&io, &ls, true, dname, LEASE2, lease("RHW"));
192 status = smb2_create(tree, mem_ctx, &io);
193 CHECK_STATUS(status, NT_STATUS_OK);
194 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
195 CHECK_LEASE(&io, "", false, 0);
196 smb2_util_close(tree, io.out.file.handle);
197
198 /* Also rejects multiple files leased under the same key. */
199 smb2_lease_create(&io, &ls, true, fname2, LEASE1, lease("RHW"));
200 status = smb2_create(tree, mem_ctx, &io);
201 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
202
203 /* And grants leases on streams (with separate leasekey). */
204 smb2_lease_create(&io, &ls, false, sname, LEASE2, lease("RHW"));
205 status = smb2_create(tree, mem_ctx, &io);
206 h2 = io.out.file.handle;
207 CHECK_STATUS(status, NT_STATUS_OK);
208 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
209 CHECK_LEASE(&io, "RHW", true, LEASE2);
210 smb2_util_close(tree, h2);
211
212 smb2_util_close(tree, h1);
213
214 /* Now see what combos are actually granted. */
215 for (i = 0; i < NREQUEST_RESULTS; i++) {
216 torture_comment(tctx, "Requesting lease type %s(%x),"
217 " expecting %s(%x)\n",
218 request_results[i][0], lease(request_results[i][0]),
219 request_results[i][1], lease(request_results[i][1]));
220 smb2_lease_create(&io, &ls, false, fname, LEASE1,
221 lease(request_results[i][0]));
222 status = smb2_create(tree, mem_ctx, &io);
223 h2 = io.out.file.handle;
224 CHECK_STATUS(status, NT_STATUS_OK);
225 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
226 CHECK_LEASE(&io, request_results[i][1], true, LEASE1);
227 smb2_util_close(tree, io.out.file.handle);
228 }
229
230 done:
231 smb2_util_close(tree, h1);
232 smb2_util_close(tree, h2);
233
234 smb2_util_unlink(tree, fname);
235 smb2_util_unlink(tree, fname2);
236 smb2_util_rmdir(tree, dname);
237
238 talloc_free(mem_ctx);
239
240 return ret;
241}
242
243static bool test_lease_upgrade(struct torture_context *tctx,
244 struct smb2_tree *tree)
245{
246 TALLOC_CTX *mem_ctx = talloc_new(tctx);
247 struct smb2_create io;
248 struct smb2_lease ls;
249 struct smb2_handle h, hnew;
250 NTSTATUS status;
251 const char *fname = "lease.dat";
252 bool ret = true;
253
254 smb2_util_unlink(tree, fname);
255
256 /* Grab a RH lease. */
257 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease("RH"));
258 status = smb2_create(tree, mem_ctx, &io);
259 CHECK_STATUS(status, NT_STATUS_OK);
260 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
261 CHECK_LEASE(&io, "RH", true, LEASE1);
262 h = io.out.file.handle;
263
264 /* Upgrades (sidegrades?) to RW leave us with an RH. */
265 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease("RW"));
266 status = smb2_create(tree, mem_ctx, &io);
267 CHECK_STATUS(status, NT_STATUS_OK);
268 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
269 CHECK_LEASE(&io, "RH", true, LEASE1);
270 hnew = io.out.file.handle;
271
272 smb2_util_close(tree, hnew);
273
274 /* Upgrade to RHW lease. */
275 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease("RHW"));
276 status = smb2_create(tree, mem_ctx, &io);
277 CHECK_STATUS(status, NT_STATUS_OK);
278 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
279 CHECK_LEASE(&io, "RHW", true, LEASE1);
280 hnew = io.out.file.handle;
281
282 smb2_util_close(tree, h);
283 h = hnew;
284
285 /* Attempt to downgrade - original lease state is maintained. */
286 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease("RH"));
287 status = smb2_create(tree, mem_ctx, &io);
288 CHECK_STATUS(status, NT_STATUS_OK);
289 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
290 CHECK_LEASE(&io, "RHW", true, LEASE1);
291 hnew = io.out.file.handle;
292
293 smb2_util_close(tree, hnew);
294
295 done:
296 smb2_util_close(tree, h);
297 smb2_util_close(tree, hnew);
298
299 smb2_util_unlink(tree, fname);
300
301 talloc_free(mem_ctx);
302
303 return ret;
304}
305
306#define CHECK_LEASE_BREAK(__lb, __oldstate, __state, __key) \
307 do { \
308 CHECK_VAL((__lb)->new_lease_state, lease(__state)); \
309 CHECK_VAL((__lb)->current_lease.lease_state, lease(__oldstate)); \
310 CHECK_VAL((__lb)->current_lease.lease_key.data[0], (__key)); \
311 CHECK_VAL((__lb)->current_lease.lease_key.data[1], ~(__key)); \
312 } while(0)
313
314#define CHECK_LEASE_BREAK_ACK(__lba, __state, __key) \
315 do { \
316 CHECK_VAL((__lba)->out.reserved, 0); \
317 CHECK_VAL((__lba)->out.lease.lease_key.data[0], (__key)); \
318 CHECK_VAL((__lba)->out.lease.lease_key.data[1], ~(__key)); \
319 CHECK_VAL((__lba)->out.lease.lease_state, lease(__state)); \
320 CHECK_VAL((__lba)->out.lease.lease_flags, 0); \
321 CHECK_VAL((__lba)->out.lease.lease_duration, 0); \
322 } while(0)
323
324static struct {
325 struct smb2_lease_break lease_break;
326 struct smb2_lease_break_ack lease_break_ack;
327 int count;
328 int failures;
329
330 struct smb2_handle oplock_handle;
331 int held_oplock_level;
332 int oplock_level;
333 int oplock_count;
334 int oplock_failures;
335} break_info;
336
337#define CHECK_BREAK_INFO(__oldstate, __state, __key) \
338 do { \
339 CHECK_VAL(break_info.failures, 0); \
340 CHECK_VAL(break_info.count, 1); \
341 CHECK_LEASE_BREAK(&break_info.lease_break, (__oldstate), \
342 (__state), (__key)); \
343 if (break_info.lease_break.break_flags & \
344 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) { \
345 CHECK_LEASE_BREAK_ACK(&break_info.lease_break_ack, \
346 (__state), (__key)); \
347 } \
348 } while(0)
349
350static void torture_lease_break_callback(struct smb2_request *req)
351{
352 NTSTATUS status;
353
354 status = smb2_lease_break_ack_recv(req, &break_info.lease_break_ack);
355 if (!NT_STATUS_IS_OK(status))
356 break_info.failures++;
357
358 return;
359}
360
361/* a lease break request handler */
362static bool torture_lease_handler(struct smb2_transport *transport,
363 const struct smb2_lease_break *lb,
364 void *private_data)
365{
366 struct smb2_tree *tree = private_data;
367 struct smb2_lease_break_ack io;
368 struct smb2_request *req;
369
370 break_info.lease_break = *lb;
371 break_info.count++;
372
373 if (lb->break_flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) {
374 ZERO_STRUCT(io);
375 io.in.lease.lease_key = lb->current_lease.lease_key;
376 io.in.lease.lease_state = lb->new_lease_state;
377
378 req = smb2_lease_break_ack_send(tree, &io);
379 req->async.fn = torture_lease_break_callback;
380 req->async.private_data = NULL;
381 }
382
383 return true;
384}
385
386/*
387 break_results should be read as "held lease, new lease, hold broken to, new
388 grant", i.e. { "RH", "RW", "RH", "R" } means that if key1 holds RH and key2
389 tries for RW, key1 will be broken to RH (in this case, not broken at all)
390 and key2 will be granted R.
391
392 Note: break_results only includes things that Win7 will actually grant (see
393 request_results above).
394 */
395#define NBREAK_RESULTS 16
396static const char *break_results[NBREAK_RESULTS][4] = {
397 {"R", "R", "R", "R"},
398 {"R", "RH", "R", "RH"},
399 {"R", "RW", "R", "R"},
400 {"R", "RHW", "R", "RH"},
401
402 {"RH", "R", "RH", "R"},
403 {"RH", "RH", "RH", "RH"},
404 {"RH", "RW", "RH", "R"},
405 {"RH", "RHW", "RH", "RH"},
406
407 {"RW", "R", "R", "R"},
408 {"RW", "RH", "R", "RH"},
409 {"RW", "RW", "R", "R"},
410 {"RW", "RHW", "R", "RH"},
411
412 {"RHW", "R", "RH", "R"},
413 {"RHW", "RH", "RH", "RH"},
414 {"RHW", "RW", "RH", "R"},
415 {"RHW", "RHW", "RH", "RH"},
416};
417
418static bool test_lease_break(struct torture_context *tctx,
419 struct smb2_tree *tree)
420{
421 TALLOC_CTX *mem_ctx = talloc_new(tctx);
422 struct smb2_create io;
423 struct smb2_lease ls;
424 struct smb2_handle h, h2, h3;
425 NTSTATUS status;
426 const char *fname = "lease.dat";
427 bool ret = true;
428 int i;
429
430 tree->session->transport->lease.handler = torture_lease_handler;
431 tree->session->transport->lease.private_data = tree;
432
433 smb2_util_unlink(tree, fname);
434
435 for (i = 0; i < NBREAK_RESULTS; i++) {
436 const char *held = break_results[i][0];
437 const char *contend = break_results[i][1];
438 const char *brokento = break_results[i][2];
439 const char *granted = break_results[i][3];
440 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
441 "expecting break to %s(%x) and grant of %s(%x)\n",
442 held, lease(held), contend, lease(contend),
443 brokento, lease(brokento), granted, lease(granted));
444
445 ZERO_STRUCT(break_info);
446
447 /* Grab lease. */
448 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease(held));
449 status = smb2_create(tree, mem_ctx, &io);
450 CHECK_STATUS(status, NT_STATUS_OK);
451 h = io.out.file.handle;
452 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
453 CHECK_LEASE(&io, held, true, LEASE1);
454
455 /* Possibly contend lease. */
456 smb2_lease_create(&io, &ls, false, fname, LEASE2, lease(contend));
457 status = smb2_create(tree, mem_ctx, &io);
458 CHECK_STATUS(status, NT_STATUS_OK);
459 h2 = io.out.file.handle;
460 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
461 CHECK_LEASE(&io, granted, true, LEASE2);
462
463 if (lease(held) != lease(brokento)) {
464 CHECK_BREAK_INFO(held, brokento, LEASE1);
465 } else {
466 CHECK_VAL(break_info.count, 0);
467 CHECK_VAL(break_info.failures, 0);
468 }
469
470 ZERO_STRUCT(break_info);
471
472 /*
473 Now verify that an attempt to upgrade LEASE1 results in no
474 break and no change in LEASE1.
475 */
476 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease("RHW"));
477 status = smb2_create(tree, mem_ctx, &io);
478 CHECK_STATUS(status, NT_STATUS_OK);
479 h3 = io.out.file.handle;
480 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
481 CHECK_LEASE(&io, brokento, true, LEASE1);
482 CHECK_VAL(break_info.count, 0);
483 CHECK_VAL(break_info.failures, 0);
484
485 smb2_util_close(tree, h);
486 smb2_util_close(tree, h2);
487 smb2_util_close(tree, h3);
488
489 status = smb2_util_unlink(tree, fname);
490 CHECK_STATUS(status, NT_STATUS_OK);
491 }
492
493 done:
494 smb2_util_close(tree, h);
495 smb2_util_close(tree, h2);
496
497 smb2_util_unlink(tree, fname);
498
499 talloc_free(mem_ctx);
500
501 return ret;
502}
503
504static void torture_oplock_break_callback(struct smb2_request *req)
505{
506 NTSTATUS status;
507 struct smb2_break br;
508
509 ZERO_STRUCT(br);
510 status = smb2_break_recv(req, &br);
511 if (!NT_STATUS_IS_OK(status))
512 break_info.oplock_failures++;
513
514 return;
515}
516
517/* a oplock break request handler */
518static bool torture_oplock_handler(struct smb2_transport *transport,
519 const struct smb2_handle *handle,
520 uint8_t level, void *private_data)
521{
522 struct smb2_tree *tree = private_data;
523 struct smb2_request *req;
524 struct smb2_break br;
525
526 break_info.oplock_handle = *handle;
527 break_info.oplock_level = level;
528 break_info.oplock_count++;
529
530 ZERO_STRUCT(br);
531 br.in.file.handle = *handle;
532 br.in.oplock_level = level;
533
534 if (break_info.held_oplock_level > SMB2_OPLOCK_LEVEL_II) {
535 req = smb2_break_send(tree, &br);
536 req->async.fn = torture_oplock_break_callback;
537 req->async.private_data = NULL;
538 }
539 break_info.held_oplock_level = level;
540
541 return true;
542}
543
544static inline uint32_t oplock(const char *op) {
545 uint32_t val = SMB2_OPLOCK_LEVEL_NONE;
546 int i;
547
548 for (i = 0; i < strlen(op); i++) {
549 switch (op[i]) {
550 case 's':
551 return SMB2_OPLOCK_LEVEL_II;
552 case 'x':
553 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
554 case 'b':
555 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
556 default:
557 continue;
558 }
559 }
560
561 return val;
562}
563
564#define NOPLOCK_RESULTS 12
565static const char *oplock_results[NOPLOCK_RESULTS][4] = {
566 {"R", "s", "R", "s"},
567 {"R", "x", "R", "s"},
568 {"R", "b", "R", "s"},
569
570 {"RH", "s", "RH", ""},
571 {"RH", "x", "RH", ""},
572 {"RH", "b", "RH", ""},
573
574 {"RW", "s", "R", "s"},
575 {"RW", "x", "R", "s"},
576 {"RW", "b", "R", "s"},
577
578 {"RHW", "s", "RH", ""},
579 {"RHW", "x", "RH", ""},
580 {"RHW", "b", "RH", ""},
581};
582
583static const char *oplock_results_2[NOPLOCK_RESULTS][4] = {
584 {"s", "R", "s", "R"},
585 {"s", "RH", "s", "R"},
586 {"s", "RW", "s", "R"},
587 {"s", "RHW", "s", "R"},
588
589 {"x", "R", "s", "R"},
590 {"x", "RH", "s", "R"},
591 {"x", "RW", "s", "R"},
592 {"x", "RHW", "s", "R"},
593
594 {"b", "R", "s", "R"},
595 {"b", "RH", "s", "R"},
596 {"b", "RW", "s", "R"},
597 {"b", "RHW", "s", "R"},
598};
599
600static bool test_lease_oplock(struct torture_context *tctx,
601 struct smb2_tree *tree)
602{
603 TALLOC_CTX *mem_ctx = talloc_new(tctx);
604 struct smb2_create io;
605 struct smb2_lease ls;
606 struct smb2_handle h, h2;
607 NTSTATUS status;
608 const char *fname = "lease.dat";
609 bool ret = true;
610 int i;
611
612 tree->session->transport->lease.handler = torture_lease_handler;
613 tree->session->transport->lease.private_data = tree;
614 tree->session->transport->oplock.handler = torture_oplock_handler;
615 tree->session->transport->oplock.private_data = tree;
616
617 smb2_util_unlink(tree, fname);
618
619 for (i = 0; i < NOPLOCK_RESULTS; i++) {
620 const char *held = oplock_results[i][0];
621 const char *contend = oplock_results[i][1];
622 const char *brokento = oplock_results[i][2];
623 const char *granted = oplock_results[i][3];
624 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
625 "expecting break to %s(%x) and grant of %s(%x)\n",
626 held, lease(held), contend, oplock(contend),
627 brokento, lease(brokento), granted, oplock(granted));
628
629 ZERO_STRUCT(break_info);
630
631 /* Grab lease. */
632 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease(held));
633 status = smb2_create(tree, mem_ctx, &io);
634 CHECK_STATUS(status, NT_STATUS_OK);
635 h = io.out.file.handle;
636 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
637 CHECK_LEASE(&io, held, true, LEASE1);
638
639 /* Does an oplock contend the lease? */
640 smb2_oplock_create(&io, fname, oplock(contend));
641 status = smb2_create(tree, mem_ctx, &io);
642 CHECK_STATUS(status, NT_STATUS_OK);
643 h2 = io.out.file.handle;
644 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
645 CHECK_VAL(io.out.oplock_level, oplock(granted));
646 break_info.held_oplock_level = io.out.oplock_level;
647
648 if (lease(held) != lease(brokento)) {
649 CHECK_BREAK_INFO(held, brokento, LEASE1);
650 } else {
651 CHECK_VAL(break_info.count, 0);
652 CHECK_VAL(break_info.failures, 0);
653 }
654
655 smb2_util_close(tree, h);
656 smb2_util_close(tree, h2);
657
658 status = smb2_util_unlink(tree, fname);
659 CHECK_STATUS(status, NT_STATUS_OK);
660 }
661
662 for (i = 0; i < NOPLOCK_RESULTS; i++) {
663 const char *held = oplock_results_2[i][0];
664 const char *contend = oplock_results_2[i][1];
665 const char *brokento = oplock_results_2[i][2];
666 const char *granted = oplock_results_2[i][3];
667 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
668 "expecting break to %s(%x) and grant of %s(%x)\n",
669 held, oplock(held), contend, lease(contend),
670 brokento, oplock(brokento), granted, lease(granted));
671
672 ZERO_STRUCT(break_info);
673
674 /* Grab an oplock. */
675 smb2_oplock_create(&io, fname, oplock(held));
676 status = smb2_create(tree, mem_ctx, &io);
677 CHECK_STATUS(status, NT_STATUS_OK);
678 h = io.out.file.handle;
679 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
680 CHECK_VAL(io.out.oplock_level, oplock(held));
681 break_info.held_oplock_level = io.out.oplock_level;
682
683 /* Grab lease. */
684 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease(contend));
685 status = smb2_create(tree, mem_ctx, &io);
686 CHECK_STATUS(status, NT_STATUS_OK);
687 h2 = io.out.file.handle;
688 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
689 CHECK_LEASE(&io, granted, true, LEASE1);
690
691 if (oplock(held) != oplock(brokento)) {
692 CHECK_VAL(break_info.oplock_count, 1);
693 CHECK_VAL(break_info.oplock_failures, 0);
694 CHECK_VAL(break_info.oplock_level, oplock(brokento));
695 break_info.held_oplock_level = break_info.oplock_level;
696 } else {
697 CHECK_VAL(break_info.oplock_count, 0);
698 CHECK_VAL(break_info.oplock_failures, 0);
699 }
700
701 smb2_util_close(tree, h);
702 smb2_util_close(tree, h2);
703
704 status = smb2_util_unlink(tree, fname);
705 CHECK_STATUS(status, NT_STATUS_OK);
706 }
707
708 done:
709 smb2_util_close(tree, h);
710 smb2_util_close(tree, h2);
711
712 smb2_util_unlink(tree, fname);
713
714 talloc_free(mem_ctx);
715
716 return ret;
717}
718
719static bool test_lease_multibreak(struct torture_context *tctx,
720 struct smb2_tree *tree)
721{
722 TALLOC_CTX *mem_ctx = talloc_new(tctx);
723 struct smb2_create io;
724 struct smb2_lease ls;
725 struct smb2_handle h, h2, h3;
726 struct smb2_write w;
727 NTSTATUS status;
728 const char *fname = "lease.dat";
729 bool ret = true;
730
731 tree->session->transport->lease.handler = torture_lease_handler;
732 tree->session->transport->lease.private_data = tree;
733 tree->session->transport->oplock.handler = torture_oplock_handler;
734 tree->session->transport->oplock.private_data = tree;
735
736 smb2_util_unlink(tree, fname);
737
738 ZERO_STRUCT(break_info);
739
740 /* Grab lease, upgrade to RHW .. */
741 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease("RH"));
742 status = smb2_create(tree, mem_ctx, &io);
743 CHECK_STATUS(status, NT_STATUS_OK);
744 h = io.out.file.handle;
745 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
746 CHECK_LEASE(&io, "RH", true, LEASE1);
747
748 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease("RHW"));
749 status = smb2_create(tree, mem_ctx, &io);
750 CHECK_STATUS(status, NT_STATUS_OK);
751 h2 = io.out.file.handle;
752 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
753 CHECK_LEASE(&io, "RHW", true, LEASE1);
754
755 /* Contend with LEASE2. */
756 smb2_lease_create(&io, &ls, false, fname, LEASE2, lease("RHW"));
757 status = smb2_create(tree, mem_ctx, &io);
758 CHECK_STATUS(status, NT_STATUS_OK);
759 h3 = io.out.file.handle;
760 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
761 CHECK_LEASE(&io, "RH", true, LEASE2);
762
763 /* Verify that we were only sent one break. */
764 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
765
766 /* Drop LEASE1 / LEASE2 */
767 status = smb2_util_close(tree, h);
768 CHECK_STATUS(status, NT_STATUS_OK);
769 status = smb2_util_close(tree, h2);
770 CHECK_STATUS(status, NT_STATUS_OK);
771 status = smb2_util_close(tree, h3);
772 CHECK_STATUS(status, NT_STATUS_OK);
773
774 ZERO_STRUCT(break_info);
775
776 /* Grab an R lease. */
777 smb2_lease_create(&io, &ls, false, fname, LEASE1, lease("R"));
778 status = smb2_create(tree, mem_ctx, &io);
779 CHECK_STATUS(status, NT_STATUS_OK);
780 h = io.out.file.handle;
781 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
782 CHECK_LEASE(&io, "R", true, LEASE1);
783
784 /* Grab a level-II oplock. */
785 smb2_oplock_create(&io, fname, oplock("s"));
786 status = smb2_create(tree, mem_ctx, &io);
787 CHECK_STATUS(status, NT_STATUS_OK);
788 h2 = io.out.file.handle;
789 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
790 CHECK_VAL(io.out.oplock_level, oplock("s"));
791 break_info.held_oplock_level = io.out.oplock_level;
792
793 /* Verify no breaks. */
794 CHECK_VAL(break_info.count, 0);
795 CHECK_VAL(break_info.failures, 0);
796
797 /* Open for truncate, force a break. */
798 smb2_generic_create(&io, NULL, false, fname,
799 NTCREATEX_DISP_OVERWRITE_IF, oplock(""), 0, 0);
800 status = smb2_create(tree, mem_ctx, &io);
801 CHECK_STATUS(status, NT_STATUS_OK);
802 h3 = io.out.file.handle;
803 CHECK_CREATED(&io, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
804 CHECK_VAL(io.out.oplock_level, oplock(""));
805 break_info.held_oplock_level = io.out.oplock_level;
806
807 /* Sleep, use a write to clear the recv queue. */
808 msleep(250);
809 ZERO_STRUCT(w);
810 w.in.file.handle = h3;
811 w.in.offset = 0;
812 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
813 status = smb2_write(tree, &w);
814 CHECK_STATUS(status, NT_STATUS_OK);
815
816 /* Verify one oplock break, one lease break. */
817 CHECK_VAL(break_info.oplock_count, 1);
818 CHECK_VAL(break_info.oplock_failures, 0);
819 CHECK_VAL(break_info.oplock_level, oplock(""));
820 CHECK_BREAK_INFO("R", "", LEASE1);
821
822 done:
823 smb2_util_close(tree, h);
824 smb2_util_close(tree, h2);
825 smb2_util_close(tree, h3);
826
827 smb2_util_unlink(tree, fname);
828
829 talloc_free(mem_ctx);
830
831 return ret;
832}
833
834struct torture_suite *torture_smb2_lease_init(void)
835{
836 struct torture_suite *suite =
837 torture_suite_create(talloc_autofree_context(), "LEASE");
838
839 torture_suite_add_1smb2_test(suite, "REQUEST", test_lease_request);
840 torture_suite_add_1smb2_test(suite, "UPGRADE", test_lease_upgrade);
841 torture_suite_add_1smb2_test(suite, "BREAK", test_lease_break);
842 torture_suite_add_1smb2_test(suite, "OPLOCK", test_lease_oplock);
843 torture_suite_add_1smb2_test(suite, "MULTIBREAK", test_lease_multibreak);
844
845 suite->description = talloc_strdup(suite, "SMB2-LEASE tests");
846
847 return suite;
848}
Note: See TracBrowser for help on using the repository browser.