VERSION: Disable GIT_SNAPSHOT for the Samba 4.18.0rc1 release.
[Samba.git] / source4 / torture / smb2 / oplock.c
blob8f275bafcdb7c1b2962db8ea15da5bb5b5805cf9
1 /*
2 Unix SMB/CIFS implementation.
4 test suite for SMB2 oplocks
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Stefan Metzmacher 2008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
25 #include "libcli/smb2/smb2.h"
26 #include "libcli/smb2/smb2_calls.h"
27 #include "libcli/smb_composite/smb_composite.h"
28 #include "libcli/resolve/resolve.h"
29 #include "libcli/smb/smbXcli_base.h"
31 #include "lib/cmdline/cmdline.h"
32 #include "lib/events/events.h"
34 #include "param/param.h"
35 #include "system/filesys.h"
37 #include "torture/torture.h"
38 #include "torture/smb2/proto.h"
39 #include "torture/smb2/block.h"
41 #include "lib/util/sys_rw.h"
42 #include "libcli/security/security.h"
44 #define CHECK_RANGE(v, min, max) do { \
45 if ((v) < (min) || (v) > (max)) { \
46 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
47 "got %d - should be between %d and %d\n", \
48 __location__, #v, (int)v, (int)min, (int)max); \
49 ret = false; \
50 }} while (0)
52 #define CHECK_STRMATCH(v, correct) do { \
53 if (!v || strstr((v),(correct)) == NULL) { \
54 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s "\
55 "got '%s' - should be '%s'\n", \
56 __location__, #v, v?v:"NULL", correct); \
57 ret = false; \
58 }} while (0)
60 #define CHECK_VAL(v, correct) do { \
61 if ((v) != (correct)) { \
62 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
63 "got 0x%x - should be 0x%x\n", \
64 __location__, #v, (int)v, (int)correct); \
65 ret = false; \
66 }} while (0)
68 #define BASEDIR "oplock_test"
70 static struct {
71 struct smb2_handle handle;
72 uint8_t level;
73 struct smb2_break br;
74 int count;
75 int failures;
76 NTSTATUS failure_status;
77 } break_info;
79 static void torture_oplock_break_callback(struct smb2_request *req)
81 NTSTATUS status;
82 struct smb2_break br;
84 ZERO_STRUCT(br);
85 status = smb2_break_recv(req, &break_info.br);
86 if (!NT_STATUS_IS_OK(status)) {
87 break_info.failures++;
88 break_info.failure_status = status;
91 return;
94 /* A general oplock break notification handler. This should be used when a
95 * test expects to break from batch or exclusive to a lower level. */
96 static bool torture_oplock_handler(struct smb2_transport *transport,
97 const struct smb2_handle *handle,
98 uint8_t level,
99 void *private_data)
101 struct smb2_tree *tree = private_data;
102 const char *name;
103 struct smb2_request *req;
104 ZERO_STRUCT(break_info.br);
106 break_info.handle = *handle;
107 break_info.level = level;
108 break_info.count++;
110 switch (level) {
111 case SMB2_OPLOCK_LEVEL_II:
112 name = "level II";
113 break;
114 case SMB2_OPLOCK_LEVEL_NONE:
115 name = "none";
116 break;
117 default:
118 name = "unknown";
119 break_info.failures++;
121 printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
123 break_info.br.in.file.handle = *handle;
124 break_info.br.in.oplock_level = level;
125 break_info.br.in.reserved = 0;
126 break_info.br.in.reserved2 = 0;
128 req = smb2_break_send(tree, &break_info.br);
129 req->async.fn = torture_oplock_break_callback;
130 req->async.private_data = NULL;
131 return true;
135 A handler function for oplock break notifications. Send a break to none
136 request.
138 static bool torture_oplock_handler_ack_to_none(struct smb2_transport *transport,
139 const struct smb2_handle *handle,
140 uint8_t level,
141 void *private_data)
143 struct smb2_tree *tree = private_data;
144 struct smb2_request *req;
146 break_info.handle = *handle;
147 break_info.level = level;
148 break_info.count++;
150 printf("Acking to none in oplock handler\n");
152 ZERO_STRUCT(break_info.br);
153 break_info.br.in.file.handle = *handle;
154 break_info.br.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
155 break_info.br.in.reserved = 0;
156 break_info.br.in.reserved2 = 0;
158 req = smb2_break_send(tree, &break_info.br);
159 req->async.fn = torture_oplock_break_callback;
160 req->async.private_data = NULL;
162 return true;
166 A handler function for oplock break notifications. Break from level II to
167 none. SMB2 requires that the client does not send an oplock break request to
168 the server in this case.
170 static bool torture_oplock_handler_level2_to_none(
171 struct smb2_transport *transport,
172 const struct smb2_handle *handle,
173 uint8_t level,
174 void *private_data)
176 break_info.handle = *handle;
177 break_info.level = level;
178 break_info.count++;
180 printf("Break from level II to none in oplock handler\n");
182 return true;
185 /* A handler function for oplock break notifications. This should be used when
186 * test expects two break notifications, first to level II, then to none. */
187 static bool torture_oplock_handler_two_notifications(
188 struct smb2_transport *transport,
189 const struct smb2_handle *handle,
190 uint8_t level,
191 void *private_data)
193 struct smb2_tree *tree = private_data;
194 const char *name;
195 struct smb2_request *req;
196 ZERO_STRUCT(break_info.br);
198 break_info.handle = *handle;
199 break_info.level = level;
200 break_info.count++;
202 switch (level) {
203 case SMB2_OPLOCK_LEVEL_II:
204 name = "level II";
205 break;
206 case SMB2_OPLOCK_LEVEL_NONE:
207 name = "none";
208 break;
209 default:
210 name = "unknown";
211 break_info.failures++;
213 printf("Breaking to %s [0x%02X] in oplock handler\n", name, level);
215 if (level == SMB2_OPLOCK_LEVEL_NONE)
216 return true;
218 break_info.br.in.file.handle = *handle;
219 break_info.br.in.oplock_level = level;
220 break_info.br.in.reserved = 0;
221 break_info.br.in.reserved2 = 0;
223 req = smb2_break_send(tree, &break_info.br);
224 req->async.fn = torture_oplock_break_callback;
225 req->async.private_data = NULL;
226 return true;
228 static void torture_oplock_handler_close_recv(struct smb2_request *req)
230 if (!smb2_request_receive(req)) {
231 printf("close failed in oplock_handler_close\n");
232 break_info.failures++;
237 a handler function for oplock break requests - close the file
239 static bool torture_oplock_handler_close(struct smb2_transport *transport,
240 const struct smb2_handle *handle,
241 uint8_t level,
242 void *private_data)
244 struct smb2_close io;
245 struct smb2_tree *tree = private_data;
246 struct smb2_request *req;
248 break_info.handle = *handle;
249 break_info.level = level;
250 break_info.count++;
252 ZERO_STRUCT(io);
253 io.in.file.handle = *handle;
254 io.in.flags = RAW_CLOSE_SMB2;
255 req = smb2_close_send(tree, &io);
256 if (req == NULL) {
257 printf("failed to send close in oplock_handler_close\n");
258 return false;
261 req->async.fn = torture_oplock_handler_close_recv;
262 req->async.private_data = NULL;
264 return true;
268 a handler function for oplock break requests. Let it timeout
270 static bool torture_oplock_handler_timeout(struct smb2_transport *transport,
271 const struct smb2_handle *handle,
272 uint8_t level,
273 void *private_data)
275 break_info.handle = *handle;
276 break_info.level = level;
277 break_info.count++;
279 printf("Let oplock break timeout\n");
280 return true;
283 static bool open_smb2_connection_no_level2_oplocks(struct torture_context *tctx,
284 struct smb2_tree **tree)
286 NTSTATUS status;
287 const char *host = torture_setting_string(tctx, "host", NULL);
288 const char *share = torture_setting_string(tctx, "share", NULL);
289 struct smbcli_options options;
291 lpcfg_smbcli_options(tctx->lp_ctx, &options);
292 options.use_level2_oplocks = false;
294 status = smb2_connect(tctx, host,
295 lpcfg_smb_ports(tctx->lp_ctx), share,
296 lpcfg_resolve_context(tctx->lp_ctx),
297 samba_cmdline_get_creds(),
298 tree, tctx->ev, &options,
299 lpcfg_socket_options(tctx->lp_ctx),
300 lpcfg_gensec_settings(tctx, tctx->lp_ctx));
301 if (!NT_STATUS_IS_OK(status)) {
302 torture_comment(tctx, "Failed to connect to SMB2 share "
303 "\\\\%s\\%s - %s\n", host, share,
304 nt_errstr(status));
305 return false;
307 return true;
310 static bool test_smb2_oplock_exclusive1(struct torture_context *tctx,
311 struct smb2_tree *tree1,
312 struct smb2_tree *tree2)
314 const char *fname = BASEDIR "\\test_exclusive1.dat";
315 NTSTATUS status;
316 bool ret = true;
317 union smb_open io;
318 struct smb2_handle h1;
319 struct smb2_handle h;
321 status = torture_smb2_testdir(tree1, BASEDIR, &h);
322 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
324 /* cleanup */
325 smb2_util_unlink(tree1, fname);
327 tree1->session->transport->oplock.handler = torture_oplock_handler;
328 tree1->session->transport->oplock.private_data = tree1;
331 base ntcreatex parms
333 ZERO_STRUCT(io.smb2);
334 io.generic.level = RAW_OPEN_SMB2;
335 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
336 io.smb2.in.alloc_size = 0;
337 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
338 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
339 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
340 io.smb2.in.create_options = 0;
341 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
342 io.smb2.in.security_flags = 0;
343 io.smb2.in.fname = fname;
345 torture_comment(tctx, "EXCLUSIVE1: open a file with an exclusive "
346 "oplock (share mode: none)\n");
347 ZERO_STRUCT(break_info);
348 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
350 status = smb2_create(tree1, tctx, &(io.smb2));
351 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
352 h1 = io.smb2.out.file.handle;
353 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
355 torture_comment(tctx, "a 2nd open should not cause a break\n");
356 status = smb2_create(tree2, tctx, &(io.smb2));
357 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
358 "Incorrect status");
359 torture_wait_for_oplock_break(tctx);
360 CHECK_VAL(break_info.count, 0);
361 CHECK_VAL(break_info.failures, 0);
363 torture_comment(tctx, "unlink it - should also be no break\n");
364 status = smb2_util_unlink(tree2, fname);
365 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
366 "Incorrect status");
367 torture_wait_for_oplock_break(tctx);
368 CHECK_VAL(break_info.count, 0);
369 CHECK_VAL(break_info.failures, 0);
371 smb2_util_close(tree1, h1);
372 smb2_util_close(tree1, h);
374 smb2_deltree(tree1, BASEDIR);
375 return ret;
378 static bool test_smb2_oplock_exclusive2(struct torture_context *tctx,
379 struct smb2_tree *tree1,
380 struct smb2_tree *tree2)
382 const char *fname = BASEDIR "\\test_exclusive2.dat";
383 NTSTATUS status;
384 bool ret = true;
385 union smb_open io;
386 struct smb2_handle h, h1, h2;
388 status = torture_smb2_testdir(tree1, BASEDIR, &h);
389 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
391 /* cleanup */
392 smb2_util_unlink(tree1, fname);
394 tree1->session->transport->oplock.handler = torture_oplock_handler;
395 tree1->session->transport->oplock.private_data = tree1;
398 base ntcreatex parms
400 ZERO_STRUCT(io.smb2);
401 io.generic.level = RAW_OPEN_SMB2;
402 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
403 io.smb2.in.alloc_size = 0;
404 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
405 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
406 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
407 io.smb2.in.create_options = 0;
408 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
409 io.smb2.in.security_flags = 0;
410 io.smb2.in.fname = fname;
412 torture_comment(tctx, "EXCLUSIVE2: open a file with an exclusive "
413 "oplock (share mode: all)\n");
414 ZERO_STRUCT(break_info);
415 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
416 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
417 NTCREATEX_SHARE_ACCESS_WRITE|
418 NTCREATEX_SHARE_ACCESS_DELETE;
419 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
421 status = smb2_create(tree1, tctx, &(io.smb2));
422 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
423 h1 = io.smb2.out.file.handle;
424 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
426 torture_comment(tctx, "a 2nd open should cause a break to level 2\n");
427 status = smb2_create(tree2, tctx, &(io.smb2));
428 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
429 h2 = io.smb2.out.file.handle;
430 torture_wait_for_oplock_break(tctx);
431 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
432 CHECK_VAL(break_info.count, 1);
433 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
434 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
435 CHECK_VAL(break_info.failures, 0);
436 ZERO_STRUCT(break_info);
438 /* now we have 2 level II oplocks... */
439 torture_comment(tctx, "try to unlink it - should cause a break\n");
440 status = smb2_util_unlink(tree2, fname);
441 torture_assert_ntstatus_ok(tctx, status, "Error unlinking the file");
442 torture_wait_for_oplock_break(tctx);
443 CHECK_VAL(break_info.count, 0);
444 CHECK_VAL(break_info.failures, 0);
446 torture_comment(tctx, "close both handles\n");
447 smb2_util_close(tree1, h1);
448 smb2_util_close(tree1, h2);
449 smb2_util_close(tree1, h);
451 smb2_deltree(tree1, BASEDIR);
452 return ret;
455 static bool test_smb2_oplock_exclusive3(struct torture_context *tctx,
456 struct smb2_tree *tree1,
457 struct smb2_tree *tree2)
459 const char *fname = BASEDIR "\\test_exclusive3.dat";
460 NTSTATUS status;
461 bool ret = true;
462 union smb_open io;
463 union smb_setfileinfo sfi;
464 struct smb2_handle h, h1;
466 status = torture_smb2_testdir(tree1, BASEDIR, &h);
467 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
469 /* cleanup */
470 smb2_util_unlink(tree1, fname);
472 tree1->session->transport->oplock.handler = torture_oplock_handler;
473 tree1->session->transport->oplock.private_data = tree1;
476 base ntcreatex parms
478 ZERO_STRUCT(io.smb2);
479 io.generic.level = RAW_OPEN_SMB2;
480 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
481 io.smb2.in.alloc_size = 0;
482 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
483 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
484 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
485 io.smb2.in.create_options = 0;
486 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
487 io.smb2.in.security_flags = 0;
488 io.smb2.in.fname = fname;
490 torture_comment(tctx, "EXCLUSIVE3: open a file with an exclusive "
491 "oplock (share mode: none)\n");
493 ZERO_STRUCT(break_info);
494 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
495 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
497 status = smb2_create(tree1, tctx, &(io.smb2));
498 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
499 h1 = io.smb2.out.file.handle;
500 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
502 torture_comment(tctx, "setpathinfo EOF should trigger a break to "
503 "none\n");
504 ZERO_STRUCT(sfi);
505 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
506 sfi.generic.in.file.path = fname;
507 sfi.end_of_file_info.in.size = 100;
509 status = smb2_composite_setpathinfo(tree2, &sfi);
511 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
512 "Incorrect status");
513 torture_wait_for_oplock_break(tctx);
514 CHECK_VAL(break_info.count, 0);
515 CHECK_VAL(break_info.failures, 0);
516 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
518 smb2_util_close(tree1, h1);
519 smb2_util_close(tree1, h);
521 smb2_deltree(tree1, BASEDIR);
522 return ret;
525 static bool test_smb2_oplock_exclusive4(struct torture_context *tctx,
526 struct smb2_tree *tree1,
527 struct smb2_tree *tree2)
529 const char *fname = BASEDIR "\\test_exclusive4.dat";
530 NTSTATUS status;
531 bool ret = true;
532 union smb_open io;
533 struct smb2_handle h, h1, h2;
535 status = torture_smb2_testdir(tree1, BASEDIR, &h);
536 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
538 /* cleanup */
539 smb2_util_unlink(tree1, fname);
541 tree1->session->transport->oplock.handler = torture_oplock_handler;
542 tree1->session->transport->oplock.private_data = tree1;
545 base ntcreatex parms
547 ZERO_STRUCT(io.smb2);
548 io.generic.level = RAW_OPEN_SMB2;
549 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
550 io.smb2.in.alloc_size = 0;
551 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
552 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
553 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
554 io.smb2.in.create_options = 0;
555 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
556 io.smb2.in.security_flags = 0;
557 io.smb2.in.fname = fname;
559 torture_comment(tctx, "EXCLUSIVE4: open with exclusive oplock\n");
560 ZERO_STRUCT(break_info);
562 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
563 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
564 status = smb2_create(tree1, tctx, &(io.smb2));
565 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
566 h1 = io.smb2.out.file.handle;
567 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
569 ZERO_STRUCT(break_info);
570 torture_comment(tctx, "second open with attributes only shouldn't "
571 "cause oplock break\n");
573 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
574 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
575 SEC_FILE_WRITE_ATTRIBUTE |
576 SEC_STD_SYNCHRONIZE;
577 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
578 status = smb2_create(tree2, tctx, &(io.smb2));
579 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
580 h2 = io.smb2.out.file.handle;
581 CHECK_VAL(io.smb2.out.oplock_level, NO_OPLOCK_RETURN);
582 torture_wait_for_oplock_break(tctx);
583 CHECK_VAL(break_info.count, 0);
584 CHECK_VAL(break_info.failures, 0);
586 smb2_util_close(tree1, h1);
587 smb2_util_close(tree2, h2);
588 smb2_util_close(tree1, h);
590 smb2_deltree(tree1, BASEDIR);
591 return ret;
594 static bool test_smb2_oplock_exclusive5(struct torture_context *tctx,
595 struct smb2_tree *tree1,
596 struct smb2_tree *tree2)
598 const char *fname = BASEDIR "\\test_exclusive5.dat";
599 NTSTATUS status;
600 bool ret = true;
601 union smb_open io;
602 struct smb2_handle h, h1, h2;
604 status = torture_smb2_testdir(tree1, BASEDIR, &h);
605 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
607 /* cleanup */
608 smb2_util_unlink(tree1, fname);
610 tree1->session->transport->oplock.handler = torture_oplock_handler;
611 tree1->session->transport->oplock.private_data = tree1;
613 tree2->session->transport->oplock.handler = torture_oplock_handler;
614 tree2->session->transport->oplock.private_data = tree2;
617 base ntcreatex parms
619 ZERO_STRUCT(io.smb2);
620 io.generic.level = RAW_OPEN_SMB2;
621 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
622 io.smb2.in.alloc_size = 0;
623 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
624 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
625 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
626 io.smb2.in.create_options = 0;
627 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
628 io.smb2.in.security_flags = 0;
629 io.smb2.in.fname = fname;
631 torture_comment(tctx, "EXCLUSIVE5: open with exclusive oplock\n");
632 ZERO_STRUCT(break_info);
634 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
635 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
636 NTCREATEX_SHARE_ACCESS_WRITE|
637 NTCREATEX_SHARE_ACCESS_DELETE;
638 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
639 status = smb2_create(tree1, tctx, &(io.smb2));
640 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
641 h1 = io.smb2.out.file.handle;
642 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
644 ZERO_STRUCT(break_info);
646 torture_comment(tctx, "second open with attributes only and "
647 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
648 "oplock break\n");
650 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
651 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
652 SEC_FILE_WRITE_ATTRIBUTE |
653 SEC_STD_SYNCHRONIZE;
654 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
655 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
656 status = smb2_create(tree2, tctx, &(io.smb2));
657 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
658 h2 = io.smb2.out.file.handle;
659 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
660 torture_wait_for_oplock_break(tctx);
661 CHECK_VAL(break_info.count, 1);
662 CHECK_VAL(break_info.failures, 0);
664 smb2_util_close(tree1, h1);
665 smb2_util_close(tree2, h2);
666 smb2_util_close(tree1, h);
668 smb2_deltree(tree1, BASEDIR);
669 return ret;
672 static bool test_smb2_oplock_exclusive6(struct torture_context *tctx,
673 struct smb2_tree *tree1,
674 struct smb2_tree *tree2)
676 const char *fname1 = BASEDIR "\\test_exclusive6_1.dat";
677 const char *fname2 = BASEDIR "\\test_exclusive6_2.dat";
678 NTSTATUS status;
679 bool ret = true;
680 union smb_open io;
681 union smb_setfileinfo sinfo;
682 struct smb2_close closeio;
683 struct smb2_handle h, h1;
685 status = torture_smb2_testdir(tree1, BASEDIR, &h);
686 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
688 /* cleanup */
689 smb2_util_unlink(tree1, fname1);
690 smb2_util_unlink(tree2, fname2);
692 tree1->session->transport->oplock.handler = torture_oplock_handler;
693 tree1->session->transport->oplock.private_data = tree1;
696 base ntcreatex parms
698 ZERO_STRUCT(io.smb2);
699 io.generic.level = RAW_OPEN_SMB2;
700 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
701 io.smb2.in.alloc_size = 0;
702 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
703 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
704 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
705 io.smb2.in.create_options = 0;
706 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
707 io.smb2.in.security_flags = 0;
708 io.smb2.in.fname = fname1;
710 torture_comment(tctx, "EXCLUSIVE6: open a file with an exclusive "
711 "oplock (share mode: none)\n");
712 ZERO_STRUCT(break_info);
713 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
714 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
716 status = smb2_create(tree1, tctx, &(io.smb2));
717 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
718 h1 = io.smb2.out.file.handle;
719 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
721 torture_comment(tctx, "rename with the parent directory handle open "
722 "for DELETE should not generate a break but get "
723 "a sharing violation\n");
724 ZERO_STRUCT(sinfo);
725 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
726 sinfo.rename_information.in.file.handle = h1;
727 sinfo.rename_information.in.overwrite = true;
728 sinfo.rename_information.in.new_name = fname2;
729 status = smb2_setinfo_file(tree1, &sinfo);
731 torture_comment(tctx, "trying rename while parent handle open for delete.\n");
732 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
733 "Incorrect status");
734 torture_wait_for_oplock_break(tctx);
735 CHECK_VAL(break_info.count, 0);
736 CHECK_VAL(break_info.failures, 0);
738 /* Close the parent directory handle. */
739 ZERO_STRUCT(closeio);
740 closeio.in.file.handle = h;
741 status = smb2_close(tree1, &closeio);
742 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
743 "Incorrect status");
745 /* Re-open without DELETE access. */
746 ZERO_STRUCT(io);
747 io.smb2.in.oplock_level = 0;
748 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL & (~SEC_STD_DELETE);
749 io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
750 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
751 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
752 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
753 io.smb2.in.fname = BASEDIR;
755 status = smb2_create(tree1, tctx, &(io.smb2));
756 torture_assert_ntstatus_ok(tctx, status, "Error opening the base directory");
758 torture_comment(tctx, "rename with the parent directory handle open "
759 "without DELETE should succeed without a break\n");
760 ZERO_STRUCT(sinfo);
761 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
762 sinfo.rename_information.in.file.handle = h1;
763 sinfo.rename_information.in.overwrite = true;
764 sinfo.rename_information.in.new_name = fname2;
765 status = smb2_setinfo_file(tree1, &sinfo);
767 torture_comment(tctx, "trying rename while parent handle open without delete\n");
768 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
769 "Incorrect status");
770 torture_wait_for_oplock_break(tctx);
771 CHECK_VAL(break_info.count, 0);
772 CHECK_VAL(break_info.failures, 0);
774 smb2_util_close(tree1, h1);
775 smb2_util_close(tree1, h);
777 smb2_deltree(tree1, BASEDIR);
778 return ret;
781 static bool test_smb2_oplock_exclusive9(struct torture_context *tctx,
782 struct smb2_tree *tree1,
783 struct smb2_tree *tree2)
785 const char *fname = BASEDIR "\\test_exclusive9.dat";
786 NTSTATUS status;
787 bool ret = true;
788 union smb_open io;
789 struct smb2_handle h1, h2;
790 int i;
792 struct {
793 uint32_t create_disposition;
794 uint32_t break_level;
795 } levels[] = {
796 { NTCREATEX_DISP_SUPERSEDE, SMB2_OPLOCK_LEVEL_NONE },
797 { NTCREATEX_DISP_OPEN, SMB2_OPLOCK_LEVEL_II },
798 { NTCREATEX_DISP_OVERWRITE_IF, SMB2_OPLOCK_LEVEL_NONE },
799 { NTCREATEX_DISP_OPEN_IF, SMB2_OPLOCK_LEVEL_II },
803 status = torture_smb2_testdir(tree1, BASEDIR, &h1);
804 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
805 smb2_util_close(tree1, h1);
807 /* cleanup */
808 smb2_util_unlink(tree1, fname);
810 tree1->session->transport->oplock.handler = torture_oplock_handler;
811 tree1->session->transport->oplock.private_data = tree1;
814 base ntcreatex parms
816 ZERO_STRUCT(io.smb2);
817 io.generic.level = RAW_OPEN_SMB2;
818 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
819 io.smb2.in.alloc_size = 0;
820 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
821 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
822 NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
823 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
824 io.smb2.in.create_options = 0;
825 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
826 io.smb2.in.security_flags = 0;
827 io.smb2.in.fname = fname;
829 for (i=0; i<ARRAY_SIZE(levels); i++) {
831 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
832 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
834 status = smb2_create(tree1, tctx, &(io.smb2));
835 torture_assert_ntstatus_ok(tctx, status,
836 "Error opening the file");
837 h1 = io.smb2.out.file.handle;
838 CHECK_VAL(io.smb2.out.oplock_level,
839 SMB2_OPLOCK_LEVEL_EXCLUSIVE);
841 ZERO_STRUCT(break_info);
843 io.smb2.in.create_disposition = levels[i].create_disposition;
844 status = smb2_create(tree2, tctx, &(io.smb2));
845 torture_assert_ntstatus_ok(tctx, status,
846 "Error opening the file");
847 h2 = io.smb2.out.file.handle;
848 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
850 CHECK_VAL(break_info.count, 1);
851 CHECK_VAL(break_info.level, levels[i].break_level);
852 CHECK_VAL(break_info.failures, 0);
854 smb2_util_close(tree2, h2);
855 smb2_util_close(tree1, h1);
858 smb2_deltree(tree1, BASEDIR);
859 return ret;
862 static bool test_smb2_oplock_batch1(struct torture_context *tctx,
863 struct smb2_tree *tree1,
864 struct smb2_tree *tree2)
866 const char *fname = BASEDIR "\\test_batch1.dat";
867 NTSTATUS status;
868 bool ret = true;
869 union smb_open io;
870 struct smb2_handle h, h1;
871 char c = 0;
873 status = torture_smb2_testdir(tree1, BASEDIR, &h);
874 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
876 /* cleanup */
877 smb2_util_unlink(tree1, fname);
879 tree1->session->transport->oplock.handler = torture_oplock_handler;
880 tree1->session->transport->oplock.private_data = tree1;
883 base ntcreatex parms
885 ZERO_STRUCT(io.smb2);
886 io.generic.level = RAW_OPEN_SMB2;
887 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
888 io.smb2.in.alloc_size = 0;
889 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
890 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
891 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
892 io.smb2.in.create_options = 0;
893 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
894 io.smb2.in.security_flags = 0;
895 io.smb2.in.fname = fname;
898 with a batch oplock we get a break
900 torture_comment(tctx, "BATCH1: open with batch oplock\n");
901 ZERO_STRUCT(break_info);
902 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
903 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
904 status = smb2_create(tree1, tctx, &(io.smb2));
905 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
906 h1 = io.smb2.out.file.handle;
907 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
909 torture_comment(tctx, "unlink should generate a break\n");
910 status = smb2_util_unlink(tree2, fname);
911 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
912 "Incorrect status");
914 torture_wait_for_oplock_break(tctx);
915 CHECK_VAL(break_info.count, 1);
916 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
917 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
918 CHECK_VAL(break_info.failures, 0);
920 torture_comment(tctx, "2nd unlink should not generate a break\n");
921 ZERO_STRUCT(break_info);
922 status = smb2_util_unlink(tree2, fname);
923 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
924 "Incorrect status");
926 torture_wait_for_oplock_break(tctx);
927 CHECK_VAL(break_info.count, 0);
929 torture_comment(tctx, "writing should generate a self break to none\n");
930 tree1->session->transport->oplock.handler =
931 torture_oplock_handler_level2_to_none;
932 smb2_util_write(tree1, h1, &c, 0, 1);
934 torture_wait_for_oplock_break(tctx);
936 CHECK_VAL(break_info.count, 1);
937 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
938 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
939 CHECK_VAL(break_info.failures, 0);
941 smb2_util_close(tree1, h1);
942 smb2_util_close(tree1, h);
944 smb2_deltree(tree1, BASEDIR);
945 return ret;
948 static bool test_smb2_oplock_batch2(struct torture_context *tctx,
949 struct smb2_tree *tree1,
950 struct smb2_tree *tree2)
952 const char *fname = BASEDIR "\\test_batch2.dat";
953 NTSTATUS status;
954 bool ret = true;
955 union smb_open io;
956 char c = 0;
957 struct smb2_handle h, h1;
959 status = torture_smb2_testdir(tree1, BASEDIR, &h);
960 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
962 /* cleanup */
963 smb2_util_unlink(tree1, fname);
965 tree1->session->transport->oplock.handler = torture_oplock_handler;
966 tree1->session->transport->oplock.private_data = tree1;
969 base ntcreatex parms
971 ZERO_STRUCT(io.smb2);
972 io.generic.level = RAW_OPEN_SMB2;
973 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
974 io.smb2.in.alloc_size = 0;
975 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
976 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
977 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
978 io.smb2.in.create_options = 0;
979 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
980 io.smb2.in.security_flags = 0;
981 io.smb2.in.fname = fname;
983 torture_comment(tctx, "BATCH2: open with batch oplock\n");
984 ZERO_STRUCT(break_info);
985 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
986 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
987 status = smb2_create(tree1, tctx, &(io.smb2));
988 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
989 h1 = io.smb2.out.file.handle;
990 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
992 torture_comment(tctx, "unlink should generate a break, which we ack "
993 "as break to none\n");
994 tree1->session->transport->oplock.handler =
995 torture_oplock_handler_ack_to_none;
996 tree1->session->transport->oplock.private_data = tree1;
997 status = smb2_util_unlink(tree2, fname);
998 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
999 "Incorrect status");
1001 torture_wait_for_oplock_break(tctx);
1002 CHECK_VAL(break_info.count, 1);
1003 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1004 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1005 CHECK_VAL(break_info.failures, 0);
1007 torture_comment(tctx, "2nd unlink should not generate a break\n");
1008 ZERO_STRUCT(break_info);
1009 status = smb2_util_unlink(tree2, fname);
1010 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1011 "Incorrect status");
1013 torture_wait_for_oplock_break(tctx);
1014 CHECK_VAL(break_info.count, 0);
1016 torture_comment(tctx, "writing should not generate a break\n");
1017 smb2_util_write(tree1, h1, &c, 0, 1);
1019 torture_wait_for_oplock_break(tctx);
1020 CHECK_VAL(break_info.count, 0);
1022 smb2_util_close(tree1, h1);
1023 smb2_util_close(tree1, h);
1025 smb2_deltree(tree1, BASEDIR);
1026 return ret;
1029 static bool test_smb2_oplock_batch3(struct torture_context *tctx,
1030 struct smb2_tree *tree1,
1031 struct smb2_tree *tree2)
1033 const char *fname = BASEDIR "\\test_batch3.dat";
1034 NTSTATUS status;
1035 bool ret = true;
1036 union smb_open io;
1037 struct smb2_handle h, h1;
1039 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1040 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1042 /* cleanup */
1043 smb2_util_unlink(tree1, fname);
1044 tree1->session->transport->oplock.handler = torture_oplock_handler;
1045 tree1->session->transport->oplock.private_data = tree1;
1048 base ntcreatex parms
1050 ZERO_STRUCT(io.smb2);
1051 io.generic.level = RAW_OPEN_SMB2;
1052 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1053 io.smb2.in.alloc_size = 0;
1054 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1055 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1056 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1057 io.smb2.in.create_options = 0;
1058 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1059 io.smb2.in.security_flags = 0;
1060 io.smb2.in.fname = fname;
1062 torture_comment(tctx, "BATCH3: if we close on break then the unlink "
1063 "can succeed\n");
1064 ZERO_STRUCT(break_info);
1065 tree1->session->transport->oplock.handler =
1066 torture_oplock_handler_close;
1067 tree1->session->transport->oplock.private_data = tree1;
1069 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1070 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1071 status = smb2_create(tree1, tctx, &(io.smb2));
1072 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1073 h1 = io.smb2.out.file.handle;
1074 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1076 ZERO_STRUCT(break_info);
1077 status = smb2_util_unlink(tree2, fname);
1078 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1080 torture_wait_for_oplock_break(tctx);
1081 CHECK_VAL(break_info.count, 1);
1082 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1083 CHECK_VAL(break_info.level, 1);
1084 CHECK_VAL(break_info.failures, 0);
1086 smb2_util_close(tree1, h1);
1087 smb2_util_close(tree1, h);
1089 smb2_deltree(tree1, BASEDIR);
1090 return ret;
1093 static bool test_smb2_oplock_batch4(struct torture_context *tctx,
1094 struct smb2_tree *tree1,
1095 struct smb2_tree *tree2)
1097 const char *fname = BASEDIR "\\test_batch4.dat";
1098 NTSTATUS status;
1099 bool ret = true;
1100 union smb_open io;
1101 struct smb2_read r;
1102 struct smb2_handle h, h1;
1104 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1105 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1107 /* cleanup */
1108 smb2_util_unlink(tree1, fname);
1110 tree1->session->transport->oplock.handler = torture_oplock_handler;
1111 tree1->session->transport->oplock.private_data = tree1;
1114 base ntcreatex parms
1116 ZERO_STRUCT(io.smb2);
1117 io.generic.level = RAW_OPEN_SMB2;
1118 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1119 io.smb2.in.alloc_size = 0;
1120 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1121 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1122 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1123 io.smb2.in.create_options = 0;
1124 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1125 io.smb2.in.security_flags = 0;
1126 io.smb2.in.fname = fname;
1128 torture_comment(tctx, "BATCH4: a self read should not cause a break\n");
1129 ZERO_STRUCT(break_info);
1131 tree1->session->transport->oplock.handler = torture_oplock_handler;
1132 tree1->session->transport->oplock.private_data = tree1;
1134 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1135 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1136 status = smb2_create(tree1, tctx, &(io.smb2));
1137 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1138 h1 = io.smb2.out.file.handle;
1139 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1141 ZERO_STRUCT(r);
1142 r.in.file.handle = h1;
1143 r.in.offset = 0;
1145 status = smb2_read(tree1, tree1, &r);
1146 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1147 torture_wait_for_oplock_break(tctx);
1148 CHECK_VAL(break_info.count, 0);
1149 CHECK_VAL(break_info.failures, 0);
1151 smb2_util_close(tree1, h1);
1152 smb2_util_close(tree1, h);
1154 smb2_deltree(tree1, BASEDIR);
1155 return ret;
1158 static bool test_smb2_oplock_batch5(struct torture_context *tctx,
1159 struct smb2_tree *tree1,
1160 struct smb2_tree *tree2)
1162 const char *fname = BASEDIR "\\test_batch5.dat";
1163 NTSTATUS status;
1164 bool ret = true;
1165 union smb_open io;
1166 struct smb2_handle h, h1;
1168 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1169 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1171 /* cleanup */
1172 smb2_util_unlink(tree1, fname);
1174 tree1->session->transport->oplock.handler = torture_oplock_handler;
1175 tree1->session->transport->oplock.private_data = tree1;
1178 base ntcreatex parms
1180 ZERO_STRUCT(io.smb2);
1181 io.generic.level = RAW_OPEN_SMB2;
1182 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1183 io.smb2.in.alloc_size = 0;
1184 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1185 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1186 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1187 io.smb2.in.create_options = 0;
1188 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1189 io.smb2.in.security_flags = 0;
1190 io.smb2.in.fname = fname;
1192 torture_comment(tctx, "BATCH5: a 2nd open should give a break\n");
1193 ZERO_STRUCT(break_info);
1195 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1196 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1197 status = smb2_create(tree1, tctx, &(io.smb2));
1198 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1199 h1 = io.smb2.out.file.handle;
1200 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1202 ZERO_STRUCT(break_info);
1204 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1205 status = smb2_create(tree2, tctx, &(io.smb2));
1206 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1207 "Incorrect status");
1209 torture_wait_for_oplock_break(tctx);
1210 CHECK_VAL(break_info.count, 1);
1211 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1212 CHECK_VAL(break_info.level, 1);
1213 CHECK_VAL(break_info.failures, 0);
1215 smb2_util_close(tree1, h1);
1216 smb2_util_close(tree1, h);
1218 smb2_deltree(tree1, BASEDIR);
1219 return ret;
1222 static bool test_smb2_oplock_batch6(struct torture_context *tctx,
1223 struct smb2_tree *tree1,
1224 struct smb2_tree *tree2)
1226 const char *fname = BASEDIR "\\test_batch6.dat";
1227 NTSTATUS status;
1228 bool ret = true;
1229 union smb_open io;
1230 struct smb2_handle h, h1, h2;
1231 char c = 0;
1233 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1234 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1236 /* cleanup */
1237 smb2_util_unlink(tree1, fname);
1239 tree1->session->transport->oplock.handler = torture_oplock_handler;
1240 tree1->session->transport->oplock.private_data = tree1;
1243 base ntcreatex parms
1245 ZERO_STRUCT(io.smb2);
1246 io.generic.level = RAW_OPEN_SMB2;
1247 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1248 io.smb2.in.alloc_size = 0;
1249 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1250 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1251 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1252 io.smb2.in.create_options = 0;
1253 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1254 io.smb2.in.security_flags = 0;
1255 io.smb2.in.fname = fname;
1257 torture_comment(tctx, "BATCH6: a 2nd open should give a break to "
1258 "level II if the first open allowed shared read\n");
1259 ZERO_STRUCT(break_info);
1260 tree2->session->transport->oplock.handler = torture_oplock_handler;
1261 tree2->session->transport->oplock.private_data = tree2;
1263 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
1264 SEC_RIGHTS_FILE_WRITE;
1265 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1266 NTCREATEX_SHARE_ACCESS_WRITE;
1267 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1268 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1269 status = smb2_create(tree1, tctx, &(io.smb2));
1270 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1271 h1 = io.smb2.out.file.handle;
1272 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1274 ZERO_STRUCT(break_info);
1276 status = smb2_create(tree2, tctx, &(io.smb2));
1277 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1278 h2 = io.smb2.out.file.handle;
1279 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1281 torture_wait_for_oplock_break(tctx);
1282 CHECK_VAL(break_info.count, 1);
1283 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1284 CHECK_VAL(break_info.level, 1);
1285 CHECK_VAL(break_info.failures, 0);
1286 ZERO_STRUCT(break_info);
1288 torture_comment(tctx, "write should trigger a break to none on both\n");
1289 tree1->session->transport->oplock.handler =
1290 torture_oplock_handler_level2_to_none;
1291 tree2->session->transport->oplock.handler =
1292 torture_oplock_handler_level2_to_none;
1293 smb2_util_write(tree1, h1, &c, 0, 1);
1295 /* We expect two breaks */
1296 torture_wait_for_oplock_break(tctx);
1297 torture_wait_for_oplock_break(tctx);
1299 CHECK_VAL(break_info.count, 2);
1300 CHECK_VAL(break_info.level, 0);
1301 CHECK_VAL(break_info.failures, 0);
1303 smb2_util_close(tree1, h1);
1304 smb2_util_close(tree2, h2);
1305 smb2_util_close(tree1, h);
1307 smb2_deltree(tree1, BASEDIR);
1308 return ret;
1311 static bool test_smb2_oplock_batch7(struct torture_context *tctx,
1312 struct smb2_tree *tree1,
1313 struct smb2_tree *tree2)
1315 const char *fname = BASEDIR "\\test_batch7.dat";
1316 NTSTATUS status;
1317 bool ret = true;
1318 union smb_open io;
1319 struct smb2_handle h, h1, h2;
1321 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1322 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1324 /* cleanup */
1325 smb2_util_unlink(tree1, fname);
1327 tree1->session->transport->oplock.handler = torture_oplock_handler;
1328 tree1->session->transport->oplock.private_data = tree1;
1331 base ntcreatex parms
1333 ZERO_STRUCT(io.smb2);
1334 io.generic.level = RAW_OPEN_SMB2;
1335 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1336 io.smb2.in.alloc_size = 0;
1337 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1338 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1339 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1340 io.smb2.in.create_options = 0;
1341 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1342 io.smb2.in.security_flags = 0;
1343 io.smb2.in.fname = fname;
1345 torture_comment(tctx, "BATCH7: a 2nd open should get an oplock when "
1346 "we close instead of ack\n");
1347 ZERO_STRUCT(break_info);
1348 tree1->session->transport->oplock.handler =
1349 torture_oplock_handler_close;
1350 tree1->session->transport->oplock.private_data = tree1;
1352 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1353 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1354 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1355 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1356 status = smb2_create(tree1, tctx, &(io.smb2));
1357 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1358 h2 = io.smb2.out.file.handle;
1359 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1361 ZERO_STRUCT(break_info);
1363 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1364 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1365 status = smb2_create(tree2, tctx, &(io.smb2));
1366 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1367 h1 = io.smb2.out.file.handle;
1368 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1370 torture_wait_for_oplock_break(tctx);
1371 CHECK_VAL(break_info.count, 1);
1372 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1373 CHECK_VAL(break_info.level, 1);
1374 CHECK_VAL(break_info.failures, 0);
1376 smb2_util_close(tree2, h1);
1377 smb2_util_close(tree2, h);
1379 smb2_deltree(tree1, BASEDIR);
1380 return ret;
1383 static bool test_smb2_oplock_batch8(struct torture_context *tctx,
1384 struct smb2_tree *tree1,
1385 struct smb2_tree *tree2)
1387 const char *fname = BASEDIR "\\test_batch8.dat";
1388 NTSTATUS status;
1389 bool ret = true;
1390 union smb_open io;
1391 struct smb2_handle h, h1, h2;
1393 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1394 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1396 /* cleanup */
1397 smb2_util_unlink(tree1, fname);
1399 tree1->session->transport->oplock.handler = torture_oplock_handler;
1400 tree1->session->transport->oplock.private_data = tree1;
1403 base ntcreatex parms
1405 ZERO_STRUCT(io.smb2);
1406 io.generic.level = RAW_OPEN_SMB2;
1407 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1408 io.smb2.in.alloc_size = 0;
1409 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1410 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1411 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1412 io.smb2.in.create_options = 0;
1413 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1414 io.smb2.in.security_flags = 0;
1415 io.smb2.in.fname = fname;
1417 torture_comment(tctx, "BATCH8: open with batch oplock\n");
1418 ZERO_STRUCT(break_info);
1420 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1421 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1422 status = smb2_create(tree1, tctx, &(io.smb2));
1423 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1424 h1 = io.smb2.out.file.handle;
1425 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1427 ZERO_STRUCT(break_info);
1428 torture_comment(tctx, "second open with attributes only shouldn't "
1429 "cause oplock break\n");
1431 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1432 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1433 SEC_FILE_WRITE_ATTRIBUTE |
1434 SEC_STD_SYNCHRONIZE;
1435 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1436 status = smb2_create(tree2, tctx, &(io.smb2));
1437 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1438 h2 = io.smb2.out.file.handle;
1439 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1440 torture_wait_for_oplock_break(tctx);
1441 CHECK_VAL(break_info.count, 0);
1442 CHECK_VAL(break_info.failures, 0);
1444 smb2_util_close(tree1, h1);
1445 smb2_util_close(tree2, h2);
1446 smb2_util_close(tree1, h);
1448 smb2_deltree(tree1, BASEDIR);
1449 return ret;
1452 static bool test_smb2_oplock_batch9(struct torture_context *tctx,
1453 struct smb2_tree *tree1,
1454 struct smb2_tree *tree2)
1456 const char *fname = BASEDIR "\\test_batch9.dat";
1457 NTSTATUS status;
1458 bool ret = true;
1459 union smb_open io;
1460 struct smb2_handle h, h1, h2;
1461 char c = 0;
1463 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1464 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1466 /* cleanup */
1467 smb2_util_unlink(tree1, fname);
1469 tree1->session->transport->oplock.handler = torture_oplock_handler;
1470 tree1->session->transport->oplock.private_data = tree1;
1473 base ntcreatex parms
1475 ZERO_STRUCT(io.smb2);
1476 io.generic.level = RAW_OPEN_SMB2;
1477 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1478 io.smb2.in.alloc_size = 0;
1479 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1480 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1481 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1482 io.smb2.in.create_options = 0;
1483 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1484 io.smb2.in.security_flags = 0;
1485 io.smb2.in.fname = fname;
1487 torture_comment(tctx, "BATCH9: open with attributes only can create "
1488 "file\n");
1490 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1491 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1492 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1493 SEC_FILE_WRITE_ATTRIBUTE |
1494 SEC_STD_SYNCHRONIZE;
1495 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1496 status = smb2_create(tree1, tctx, &(io.smb2));
1497 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1498 h1 = io.smb2.out.file.handle;
1499 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1501 torture_comment(tctx, "Subsequent normal open should break oplock on "
1502 "attribute only open to level II\n");
1504 ZERO_STRUCT(break_info);
1506 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1507 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1508 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1509 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1510 status = smb2_create(tree2, tctx, &(io.smb2));
1511 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1512 h2 = io.smb2.out.file.handle;
1513 torture_wait_for_oplock_break(tctx);
1514 CHECK_VAL(break_info.count, 1);
1515 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1516 CHECK_VAL(break_info.failures, 0);
1517 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1518 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1519 smb2_util_close(tree2, h2);
1521 torture_comment(tctx, "third oplocked open should grant level2 without "
1522 "break\n");
1523 ZERO_STRUCT(break_info);
1525 tree2->session->transport->oplock.handler = torture_oplock_handler;
1526 tree2->session->transport->oplock.private_data = tree2;
1528 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1529 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1530 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1531 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1532 status = smb2_create(tree2, tctx, &(io.smb2));
1533 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1534 h2 = io.smb2.out.file.handle;
1535 torture_wait_for_oplock_break(tctx);
1536 CHECK_VAL(break_info.count, 0);
1537 CHECK_VAL(break_info.failures, 0);
1538 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1540 ZERO_STRUCT(break_info);
1542 torture_comment(tctx, "write should trigger a break to none on both\n");
1543 tree1->session->transport->oplock.handler =
1544 torture_oplock_handler_level2_to_none;
1545 tree2->session->transport->oplock.handler =
1546 torture_oplock_handler_level2_to_none;
1547 smb2_util_write(tree2, h2, &c, 0, 1);
1549 /* We expect two breaks */
1550 torture_wait_for_oplock_break(tctx);
1551 torture_wait_for_oplock_break(tctx);
1553 CHECK_VAL(break_info.count, 2);
1554 CHECK_VAL(break_info.level, 0);
1555 CHECK_VAL(break_info.failures, 0);
1557 smb2_util_close(tree1, h1);
1558 smb2_util_close(tree2, h2);
1559 smb2_util_close(tree1, h);
1561 smb2_deltree(tree1, BASEDIR);
1562 return ret;
1565 static bool test_smb2_oplock_batch9a(struct torture_context *tctx,
1566 struct smb2_tree *tree1,
1567 struct smb2_tree *tree2)
1569 const char *fname = BASEDIR "\\test_batch9a.dat";
1570 NTSTATUS status;
1571 bool ret = true;
1572 union smb_open io;
1573 struct smb2_handle h, h1, h2, h3;
1574 char c = 0;
1576 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1577 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1579 /* cleanup */
1580 smb2_util_unlink(tree1, fname);
1582 tree1->session->transport->oplock.handler = torture_oplock_handler;
1583 tree1->session->transport->oplock.private_data = tree1;
1586 base ntcreatex parms
1588 ZERO_STRUCT(io.smb2);
1589 io.generic.level = RAW_OPEN_SMB2;
1590 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1591 io.smb2.in.alloc_size = 0;
1592 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1593 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1594 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1595 io.smb2.in.create_options = 0;
1596 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1597 io.smb2.in.security_flags = 0;
1598 io.smb2.in.fname = fname;
1600 torture_comment(tctx, "BATCH9: open with attributes only can create "
1601 "file\n");
1603 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1604 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1605 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1606 SEC_FILE_WRITE_ATTRIBUTE |
1607 SEC_STD_SYNCHRONIZE;
1608 status = smb2_create(tree1, tctx, &(io.smb2));
1609 torture_assert_ntstatus_ok(tctx, status, "Error creating the file");
1610 h1 = io.smb2.out.file.handle;
1611 CHECK_VAL(io.smb2.out.create_action, FILE_WAS_CREATED);
1612 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1614 torture_comment(tctx, "Subsequent attributes open should not break\n");
1616 ZERO_STRUCT(break_info);
1618 status = smb2_create(tree2, tctx, &(io.smb2));
1619 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1620 h3 = io.smb2.out.file.handle;
1621 torture_wait_for_oplock_break(tctx);
1622 CHECK_VAL(break_info.count, 0);
1623 CHECK_VAL(io.smb2.out.create_action, FILE_WAS_OPENED);
1624 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1625 smb2_util_close(tree2, h3);
1627 torture_comment(tctx, "Subsequent normal open should break oplock on "
1628 "attribute only open to level II\n");
1630 ZERO_STRUCT(break_info);
1632 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1633 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1634 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1635 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1636 status = smb2_create(tree2, tctx, &(io.smb2));
1637 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1638 h2 = io.smb2.out.file.handle;
1639 torture_wait_for_oplock_break(tctx);
1640 CHECK_VAL(break_info.count, 1);
1641 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1642 CHECK_VAL(break_info.failures, 0);
1643 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1644 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1645 smb2_util_close(tree2, h2);
1647 torture_comment(tctx, "third oplocked open should grant level2 without "
1648 "break\n");
1649 ZERO_STRUCT(break_info);
1651 tree2->session->transport->oplock.handler = torture_oplock_handler;
1652 tree2->session->transport->oplock.private_data = tree2;
1654 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1655 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1656 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1657 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1658 status = smb2_create(tree2, tctx, &(io.smb2));
1659 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1660 h2 = io.smb2.out.file.handle;
1661 torture_wait_for_oplock_break(tctx);
1662 CHECK_VAL(break_info.count, 0);
1663 CHECK_VAL(break_info.failures, 0);
1664 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1666 ZERO_STRUCT(break_info);
1668 torture_comment(tctx, "write should trigger a break to none on both\n");
1669 tree1->session->transport->oplock.handler =
1670 torture_oplock_handler_level2_to_none;
1671 tree2->session->transport->oplock.handler =
1672 torture_oplock_handler_level2_to_none;
1673 smb2_util_write(tree2, h2, &c, 0, 1);
1675 /* We expect two breaks */
1676 torture_wait_for_oplock_break(tctx);
1677 torture_wait_for_oplock_break(tctx);
1679 CHECK_VAL(break_info.count, 2);
1680 CHECK_VAL(break_info.level, 0);
1681 CHECK_VAL(break_info.failures, 0);
1683 smb2_util_close(tree1, h1);
1684 smb2_util_close(tree2, h2);
1685 smb2_util_close(tree1, h);
1687 smb2_deltree(tree1, BASEDIR);
1688 return ret;
1692 static bool test_smb2_oplock_batch10(struct torture_context *tctx,
1693 struct smb2_tree *tree1,
1694 struct smb2_tree *tree2)
1696 const char *fname = BASEDIR "\\test_batch10.dat";
1697 NTSTATUS status;
1698 bool ret = true;
1699 union smb_open io;
1700 struct smb2_handle h, h1, h2;
1702 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1703 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1705 /* cleanup */
1706 smb2_util_unlink(tree1, fname);
1708 tree1->session->transport->oplock.handler = torture_oplock_handler;
1709 tree1->session->transport->oplock.private_data = tree1;
1712 base ntcreatex parms
1714 ZERO_STRUCT(io.smb2);
1715 io.generic.level = RAW_OPEN_SMB2;
1716 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1717 io.smb2.in.alloc_size = 0;
1718 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1719 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1720 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1721 io.smb2.in.create_options = 0;
1722 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1723 io.smb2.in.security_flags = 0;
1724 io.smb2.in.fname = fname;
1726 torture_comment(tctx, "BATCH10: Open with oplock after a non-oplock "
1727 "open should grant level2\n");
1728 ZERO_STRUCT(break_info);
1729 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1730 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1731 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1732 NTCREATEX_SHARE_ACCESS_WRITE|
1733 NTCREATEX_SHARE_ACCESS_DELETE;
1734 status = smb2_create(tree1, tctx, &(io.smb2));
1735 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1736 h1 = io.smb2.out.file.handle;
1737 torture_wait_for_oplock_break(tctx);
1738 CHECK_VAL(break_info.count, 0);
1739 CHECK_VAL(break_info.failures, 0);
1740 CHECK_VAL(io.smb2.out.oplock_level, 0);
1742 tree2->session->transport->oplock.handler =
1743 torture_oplock_handler_level2_to_none;
1744 tree2->session->transport->oplock.private_data = tree2;
1746 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1747 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1748 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1749 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1750 NTCREATEX_SHARE_ACCESS_WRITE|
1751 NTCREATEX_SHARE_ACCESS_DELETE;
1752 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1753 status = smb2_create(tree2, tctx, &(io.smb2));
1754 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1755 h2 = io.smb2.out.file.handle;
1756 torture_wait_for_oplock_break(tctx);
1757 CHECK_VAL(break_info.count, 0);
1758 CHECK_VAL(break_info.failures, 0);
1759 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1761 torture_comment(tctx, "write should trigger a break to none\n");
1763 struct smb2_write wr;
1764 DATA_BLOB data;
1765 data = data_blob_talloc_zero(tree1, UINT16_MAX);
1766 data.data[0] = (const uint8_t)'x';
1767 ZERO_STRUCT(wr);
1768 wr.in.file.handle = h1;
1769 wr.in.offset = 0;
1770 wr.in.data = data;
1771 status = smb2_write(tree1, &wr);
1772 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1775 torture_wait_for_oplock_break(tctx);
1777 CHECK_VAL(break_info.count, 1);
1778 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1779 CHECK_VAL(break_info.level, 0);
1780 CHECK_VAL(break_info.failures, 0);
1782 smb2_util_close(tree1, h1);
1783 smb2_util_close(tree2, h2);
1784 smb2_util_close(tree1, h);
1786 smb2_deltree(tree1, BASEDIR);
1787 return ret;
1790 static bool test_smb2_oplock_batch11(struct torture_context *tctx,
1791 struct smb2_tree *tree1,
1792 struct smb2_tree *tree2)
1794 const char *fname = BASEDIR "\\test_batch11.dat";
1795 NTSTATUS status;
1796 bool ret = true;
1797 union smb_open io;
1798 union smb_setfileinfo sfi;
1799 struct smb2_handle h, h1;
1801 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1802 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1804 /* cleanup */
1805 smb2_util_unlink(tree1, fname);
1807 tree1->session->transport->oplock.handler =
1808 torture_oplock_handler_two_notifications;
1809 tree1->session->transport->oplock.private_data = tree1;
1812 base ntcreatex parms
1814 ZERO_STRUCT(io.smb2);
1815 io.generic.level = RAW_OPEN_SMB2;
1816 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1817 io.smb2.in.alloc_size = 0;
1818 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1819 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1820 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1821 io.smb2.in.create_options = 0;
1822 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1823 io.smb2.in.security_flags = 0;
1824 io.smb2.in.fname = fname;
1826 /* Test if a set-eof on pathname breaks an exclusive oplock. */
1827 torture_comment(tctx, "BATCH11: Test if setpathinfo set EOF breaks "
1828 "oplocks.\n");
1830 ZERO_STRUCT(break_info);
1832 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1833 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1834 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1835 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1836 NTCREATEX_SHARE_ACCESS_WRITE|
1837 NTCREATEX_SHARE_ACCESS_DELETE;
1838 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1839 status = smb2_create(tree1, tctx, &(io.smb2));
1840 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1841 h1 = io.smb2.out.file.handle;
1842 torture_wait_for_oplock_break(tctx);
1843 CHECK_VAL(break_info.count, 0);
1844 CHECK_VAL(break_info.failures, 0);
1845 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1847 ZERO_STRUCT(sfi);
1848 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1849 sfi.generic.in.file.path = fname;
1850 sfi.end_of_file_info.in.size = 100;
1852 status = smb2_composite_setpathinfo(tree2, &sfi);
1853 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1855 /* We expect two breaks */
1856 torture_wait_for_oplock_break(tctx);
1857 torture_wait_for_oplock_break(tctx);
1859 CHECK_VAL(break_info.count, 2);
1860 CHECK_VAL(break_info.failures, 0);
1861 CHECK_VAL(break_info.level, 0);
1863 smb2_util_close(tree1, h1);
1864 smb2_util_close(tree1, h);
1866 smb2_deltree(tree1, BASEDIR);
1867 return ret;
1870 static bool test_smb2_oplock_batch12(struct torture_context *tctx,
1871 struct smb2_tree *tree1,
1872 struct smb2_tree *tree2)
1874 const char *fname = BASEDIR "\\test_batch12.dat";
1875 NTSTATUS status;
1876 bool ret = true;
1877 union smb_open io;
1878 union smb_setfileinfo sfi;
1879 struct smb2_handle h, h1;
1881 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1882 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1884 /* cleanup */
1885 smb2_util_unlink(tree1, fname);
1887 tree1->session->transport->oplock.handler =
1888 torture_oplock_handler_two_notifications;
1889 tree1->session->transport->oplock.private_data = tree1;
1892 base ntcreatex parms
1894 ZERO_STRUCT(io.smb2);
1895 io.generic.level = RAW_OPEN_SMB2;
1896 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1897 io.smb2.in.alloc_size = 0;
1898 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1899 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1900 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1901 io.smb2.in.create_options = 0;
1902 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1903 io.smb2.in.security_flags = 0;
1904 io.smb2.in.fname = fname;
1906 /* Test if a set-allocation size on pathname breaks an exclusive
1907 * oplock. */
1908 torture_comment(tctx, "BATCH12: Test if setpathinfo allocation size "
1909 "breaks oplocks.\n");
1911 ZERO_STRUCT(break_info);
1913 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1914 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1915 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1916 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1917 NTCREATEX_SHARE_ACCESS_WRITE|
1918 NTCREATEX_SHARE_ACCESS_DELETE;
1919 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1920 status = smb2_create(tree1, tctx, &(io.smb2));
1921 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1922 h1 = io.smb2.out.file.handle;
1923 torture_wait_for_oplock_break(tctx);
1924 CHECK_VAL(break_info.count, 0);
1925 CHECK_VAL(break_info.failures, 0);
1926 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1928 ZERO_STRUCT(sfi);
1929 sfi.generic.level = RAW_SFILEINFO_ALLOCATION_INFORMATION;
1930 sfi.generic.in.file.path = fname;
1931 sfi.allocation_info.in.alloc_size = 65536 * 8;
1933 status = smb2_composite_setpathinfo(tree2, &sfi);
1934 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1936 /* We expect two breaks */
1937 torture_wait_for_oplock_break(tctx);
1938 torture_wait_for_oplock_break(tctx);
1940 CHECK_VAL(break_info.count, 2);
1941 CHECK_VAL(break_info.failures, 0);
1942 CHECK_VAL(break_info.level, 0);
1944 smb2_util_close(tree1, h1);
1945 smb2_util_close(tree1, h);
1947 smb2_deltree(tree1, BASEDIR);
1948 return ret;
1951 static bool test_smb2_oplock_batch13(struct torture_context *tctx,
1952 struct smb2_tree *tree1,
1953 struct smb2_tree *tree2)
1955 const char *fname = BASEDIR "\\test_batch13.dat";
1956 NTSTATUS status;
1957 bool ret = true;
1958 union smb_open io;
1959 struct smb2_handle h, h1, h2;
1961 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1962 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1964 /* cleanup */
1965 smb2_util_unlink(tree1, fname);
1967 tree1->session->transport->oplock.handler = torture_oplock_handler;
1968 tree1->session->transport->oplock.private_data = tree1;
1970 tree2->session->transport->oplock.handler = torture_oplock_handler;
1971 tree2->session->transport->oplock.private_data = tree2;
1974 base ntcreatex parms
1976 ZERO_STRUCT(io.smb2);
1977 io.generic.level = RAW_OPEN_SMB2;
1978 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1979 io.smb2.in.alloc_size = 0;
1980 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1981 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1982 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1983 io.smb2.in.create_options = 0;
1984 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1985 io.smb2.in.security_flags = 0;
1986 io.smb2.in.fname = fname;
1988 torture_comment(tctx, "BATCH13: open with batch oplock\n");
1989 ZERO_STRUCT(break_info);
1991 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1992 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1993 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1994 NTCREATEX_SHARE_ACCESS_WRITE|
1995 NTCREATEX_SHARE_ACCESS_DELETE;
1996 status = smb2_create(tree1, tctx, &(io.smb2));
1997 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1998 h1 = io.smb2.out.file.handle;
1999 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2001 ZERO_STRUCT(break_info);
2003 torture_comment(tctx, "second open with attributes only and "
2004 "NTCREATEX_DISP_OVERWRITE dispostion causes "
2005 "oplock break\n");
2007 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2008 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2009 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2010 SEC_FILE_WRITE_ATTRIBUTE |
2011 SEC_STD_SYNCHRONIZE;
2012 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2013 NTCREATEX_SHARE_ACCESS_WRITE|
2014 NTCREATEX_SHARE_ACCESS_DELETE;
2015 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2016 status = smb2_create(tree2, tctx, &(io.smb2));
2017 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2018 h2 = io.smb2.out.file.handle;
2019 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2020 torture_wait_for_oplock_break(tctx);
2021 CHECK_VAL(break_info.count, 1);
2022 CHECK_VAL(break_info.failures, 0);
2024 smb2_util_close(tree1, h1);
2025 smb2_util_close(tree2, h2);
2026 smb2_util_close(tree1, h);
2028 smb2_deltree(tree1, BASEDIR);
2030 return ret;
2033 static bool test_smb2_oplock_batch14(struct torture_context *tctx,
2034 struct smb2_tree *tree1,
2035 struct smb2_tree *tree2)
2037 const char *fname = BASEDIR "\\test_batch14.dat";
2038 NTSTATUS status;
2039 bool ret = true;
2040 union smb_open io;
2041 struct smb2_handle h, h1, h2;
2043 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2044 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2046 /* cleanup */
2047 smb2_util_unlink(tree1, fname);
2049 tree1->session->transport->oplock.handler = torture_oplock_handler;
2050 tree1->session->transport->oplock.private_data = tree1;
2053 base ntcreatex parms
2055 ZERO_STRUCT(io.smb2);
2056 io.generic.level = RAW_OPEN_SMB2;
2057 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2058 io.smb2.in.alloc_size = 0;
2059 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2060 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2061 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2062 io.smb2.in.create_options = 0;
2063 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2064 io.smb2.in.security_flags = 0;
2065 io.smb2.in.fname = fname;
2067 torture_comment(tctx, "BATCH14: open with batch oplock\n");
2068 ZERO_STRUCT(break_info);
2070 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2071 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2072 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2073 NTCREATEX_SHARE_ACCESS_WRITE|
2074 NTCREATEX_SHARE_ACCESS_DELETE;
2075 status = smb2_create(tree1, tctx, &(io.smb2));
2076 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2077 h1 = io.smb2.out.file.handle;
2078 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2080 ZERO_STRUCT(break_info);
2082 torture_comment(tctx, "second open with attributes only and "
2083 "NTCREATEX_DISP_SUPERSEDE dispostion causes "
2084 "oplock break\n");
2086 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2087 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2088 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2089 SEC_FILE_WRITE_ATTRIBUTE |
2090 SEC_STD_SYNCHRONIZE;
2091 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2092 NTCREATEX_SHARE_ACCESS_WRITE|
2093 NTCREATEX_SHARE_ACCESS_DELETE;
2094 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2095 status = smb2_create(tree2, tctx, &(io.smb2));
2096 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2097 h2 = io.smb2.out.file.handle;
2098 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2100 torture_wait_for_oplock_break(tctx);
2101 CHECK_VAL(break_info.count, 1);
2102 CHECK_VAL(break_info.failures, 0);
2104 smb2_util_close(tree1, h1);
2105 smb2_util_close(tree2, h2);
2106 smb2_util_close(tree1, h);
2108 smb2_deltree(tree1, BASEDIR);
2109 return ret;
2112 static bool test_smb2_oplock_batch15(struct torture_context *tctx,
2113 struct smb2_tree *tree1,
2114 struct smb2_tree *tree2)
2116 const char *fname = BASEDIR "\\test_batch15.dat";
2117 NTSTATUS status;
2118 bool ret = true;
2119 union smb_open io;
2120 union smb_fileinfo qfi;
2121 struct smb2_handle h, h1;
2123 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2124 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2126 /* cleanup */
2127 smb2_util_unlink(tree1, fname);
2129 tree1->session->transport->oplock.handler = torture_oplock_handler;
2130 tree1->session->transport->oplock.private_data = tree1;
2133 base ntcreatex parms
2135 ZERO_STRUCT(io.smb2);
2136 io.generic.level = RAW_OPEN_SMB2;
2137 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2138 io.smb2.in.alloc_size = 0;
2139 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2140 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2141 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2142 io.smb2.in.create_options = 0;
2143 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2144 io.smb2.in.security_flags = 0;
2145 io.smb2.in.fname = fname;
2147 /* Test if a qpathinfo all info on pathname breaks a batch oplock. */
2148 torture_comment(tctx, "BATCH15: Test if qpathinfo all info breaks "
2149 "a batch oplock (should not).\n");
2151 ZERO_STRUCT(break_info);
2153 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2154 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2155 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2156 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2157 NTCREATEX_SHARE_ACCESS_WRITE|
2158 NTCREATEX_SHARE_ACCESS_DELETE;
2159 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2160 status = smb2_create(tree1, tctx, &(io.smb2));
2161 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2162 h1 = io.smb2.out.file.handle;
2164 torture_wait_for_oplock_break(tctx);
2165 CHECK_VAL(break_info.count, 0);
2166 CHECK_VAL(break_info.failures, 0);
2167 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2169 ZERO_STRUCT(qfi);
2170 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2171 qfi.generic.in.file.handle = h1;
2172 status = smb2_getinfo_file(tree2, tctx, &qfi);
2174 torture_wait_for_oplock_break(tctx);
2175 CHECK_VAL(break_info.count, 0);
2177 smb2_util_close(tree1, h1);
2178 smb2_util_close(tree1, h);
2180 smb2_deltree(tree1, BASEDIR);
2181 return ret;
2184 static bool test_smb2_oplock_batch16(struct torture_context *tctx,
2185 struct smb2_tree *tree1,
2186 struct smb2_tree *tree2)
2188 const char *fname = BASEDIR "\\test_batch16.dat";
2189 NTSTATUS status;
2190 bool ret = true;
2191 union smb_open io;
2192 struct smb2_handle h, h1, h2;
2194 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2195 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2197 /* cleanup */
2198 smb2_util_unlink(tree1, fname);
2200 tree1->session->transport->oplock.handler = torture_oplock_handler;
2201 tree1->session->transport->oplock.private_data = tree1;
2203 tree2->session->transport->oplock.handler = torture_oplock_handler;
2204 tree2->session->transport->oplock.private_data = tree2;
2207 base ntcreatex parms
2209 ZERO_STRUCT(io.smb2);
2210 io.generic.level = RAW_OPEN_SMB2;
2211 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2212 io.smb2.in.alloc_size = 0;
2213 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2214 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2215 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2216 io.smb2.in.create_options = 0;
2217 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2218 io.smb2.in.security_flags = 0;
2219 io.smb2.in.fname = fname;
2221 torture_comment(tctx, "BATCH16: open with batch oplock\n");
2222 ZERO_STRUCT(break_info);
2224 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2225 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2226 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2227 NTCREATEX_SHARE_ACCESS_WRITE|
2228 NTCREATEX_SHARE_ACCESS_DELETE;
2229 status = smb2_create(tree1, tctx, &(io.smb2));
2230 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2231 h1 = io.smb2.out.file.handle;
2232 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2234 ZERO_STRUCT(break_info);
2236 torture_comment(tctx, "second open with attributes only and "
2237 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
2238 "oplock break\n");
2240 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2241 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2242 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2243 SEC_FILE_WRITE_ATTRIBUTE |
2244 SEC_STD_SYNCHRONIZE;
2245 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2246 NTCREATEX_SHARE_ACCESS_WRITE|
2247 NTCREATEX_SHARE_ACCESS_DELETE;
2248 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
2249 status = smb2_create(tree2, tctx, &(io.smb2));
2250 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2251 h2 = io.smb2.out.file.handle;
2252 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2254 torture_wait_for_oplock_break(tctx);
2255 CHECK_VAL(break_info.count, 1);
2256 CHECK_VAL(break_info.failures, 0);
2258 smb2_util_close(tree1, h1);
2259 smb2_util_close(tree2, h2);
2260 smb2_util_close(tree1, h);
2262 smb2_deltree(tree1, BASEDIR);
2263 return ret;
2266 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH17 test. Since
2267 * SMB2 doesn't have a RENAME command this test isn't applicable. However,
2268 * it's much less confusing, when comparing test, to keep the SMB1 and SMB2
2269 * test numbers in sync. */
2270 #if 0
2271 static bool test_raw_oplock_batch17(struct torture_context *tctx,
2272 struct smb2_tree *tree1,
2273 struct smb2_tree *tree2)
2275 return true;
2277 #endif
2279 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH18 test. Since
2280 * SMB2 doesn't have an NTRENAME command this test isn't applicable. However,
2281 * it's much less confusing, when comparing tests, to keep the SMB1 and SMB2
2282 * test numbers in sync. */
2283 #if 0
2284 static bool test_raw_oplock_batch18(struct torture_context *tctx,
2285 struct smb2_tree *tree1,
2286 struct smb2_tree *tree2)
2288 return true;
2290 #endif
2292 static bool test_smb2_oplock_batch19(struct torture_context *tctx,
2293 struct smb2_tree *tree1)
2295 const char *fname1 = BASEDIR "\\test_batch19_1.dat";
2296 const char *fname2 = BASEDIR "\\test_batch19_2.dat";
2297 NTSTATUS status;
2298 bool ret = true;
2299 union smb_open io;
2300 union smb_fileinfo qfi;
2301 union smb_setfileinfo sfi;
2302 struct smb2_handle h, h1;
2304 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2305 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2307 /* cleanup */
2308 smb2_util_unlink(tree1, fname1);
2309 smb2_util_unlink(tree1, fname2);
2311 tree1->session->transport->oplock.handler = torture_oplock_handler;
2312 tree1->session->transport->oplock.private_data = tree1;
2315 base ntcreatex parms
2317 ZERO_STRUCT(io.smb2);
2318 io.generic.level = RAW_OPEN_SMB2;
2319 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2320 io.smb2.in.alloc_size = 0;
2321 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2322 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2323 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2324 io.smb2.in.create_options = 0;
2325 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2326 io.smb2.in.security_flags = 0;
2327 io.smb2.in.fname = fname1;
2329 torture_comment(tctx, "BATCH19: open a file with an batch oplock "
2330 "(share mode: none)\n");
2331 ZERO_STRUCT(break_info);
2332 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2333 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2334 status = smb2_create(tree1, tctx, &(io.smb2));
2335 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2336 h1 = io.smb2.out.file.handle;
2337 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2339 torture_comment(tctx, "setfileinfo rename info should not trigger "
2340 "a break but should cause a sharing violation\n");
2341 ZERO_STRUCT(sfi);
2342 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2343 sfi.generic.in.file.path = fname1;
2344 sfi.rename_information.in.file.handle = h1;
2345 sfi.rename_information.in.overwrite = 0;
2346 sfi.rename_information.in.root_fid = 0;
2347 sfi.rename_information.in.new_name = fname2;
2349 status = smb2_setinfo_file(tree1, &sfi);
2351 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2352 "Incorrect status");
2354 torture_wait_for_oplock_break(tctx);
2355 CHECK_VAL(break_info.count, 0);
2357 ZERO_STRUCT(qfi);
2358 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2359 qfi.generic.in.file.handle = h1;
2361 status = smb2_getinfo_file(tree1, tctx, &qfi);
2362 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2363 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2365 smb2_util_close(tree1, h1);
2366 smb2_util_close(tree1, h);
2368 smb2_deltree(tree1, fname1);
2369 smb2_deltree(tree1, fname2);
2370 return ret;
2373 static bool test_smb2_oplock_batch20(struct torture_context *tctx,
2374 struct smb2_tree *tree1,
2375 struct smb2_tree *tree2)
2377 const char *fname1 = BASEDIR "\\test_batch20_1.dat";
2378 const char *fname2 = BASEDIR "\\test_batch20_2.dat";
2379 NTSTATUS status;
2380 bool ret = true;
2381 union smb_open io;
2382 union smb_fileinfo qfi;
2383 union smb_setfileinfo sfi;
2384 struct smb2_handle h, h1, h2;
2386 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2387 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2389 /* cleanup */
2390 smb2_util_unlink(tree1, fname1);
2391 smb2_util_unlink(tree1, fname2);
2393 tree1->session->transport->oplock.handler = torture_oplock_handler;
2394 tree1->session->transport->oplock.private_data = tree1;
2397 base ntcreatex parms
2399 ZERO_STRUCT(io.smb2);
2400 io.generic.level = RAW_OPEN_SMB2;
2401 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2402 io.smb2.in.alloc_size = 0;
2403 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2404 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2405 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2406 io.smb2.in.create_options = 0;
2407 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2408 io.smb2.in.security_flags = 0;
2409 io.smb2.in.fname = fname1;
2411 torture_comment(tctx, "BATCH20: open a file with an batch oplock "
2412 "(share mode: all)\n");
2413 ZERO_STRUCT(break_info);
2414 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2415 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2416 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2417 NTCREATEX_SHARE_ACCESS_WRITE|
2418 NTCREATEX_SHARE_ACCESS_DELETE;
2419 status = smb2_create(tree1, tctx, &(io.smb2));
2420 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2421 h1 = io.smb2.out.file.handle;
2422 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2424 torture_comment(tctx, "setfileinfo rename info should not trigger "
2425 "a break but should cause a sharing violation\n");
2426 ZERO_STRUCT(sfi);
2427 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2428 sfi.rename_information.in.file.handle = h1;
2429 sfi.rename_information.in.overwrite = 0;
2430 sfi.rename_information.in.new_name = fname2;
2432 status = smb2_setinfo_file(tree1, &sfi);
2433 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2434 "Incorrect status");
2436 torture_wait_for_oplock_break(tctx);
2437 CHECK_VAL(break_info.count, 0);
2439 ZERO_STRUCT(qfi);
2440 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2441 qfi.generic.in.file.handle = h1;
2443 status = smb2_getinfo_file(tree1, tctx, &qfi);
2444 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2445 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2447 torture_comment(tctx, "open the file a second time requesting batch "
2448 "(share mode: all)\n");
2449 ZERO_STRUCT(break_info);
2450 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2451 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2452 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2453 NTCREATEX_SHARE_ACCESS_WRITE|
2454 NTCREATEX_SHARE_ACCESS_DELETE;
2455 io.smb2.in.fname = fname1;
2456 status = smb2_create(tree2, tctx, &(io.smb2));
2457 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2458 h2 = io.smb2.out.file.handle;
2459 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2461 torture_wait_for_oplock_break(tctx);
2462 CHECK_VAL(break_info.count, 1);
2463 CHECK_VAL(break_info.failures, 0);
2464 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2466 torture_comment(tctx, "setfileinfo rename info should not trigger "
2467 "a break but should cause a sharing violation\n");
2468 ZERO_STRUCT(break_info);
2469 ZERO_STRUCT(sfi);
2470 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2471 sfi.rename_information.in.file.handle = h2;
2472 sfi.rename_information.in.overwrite = 0;
2473 sfi.rename_information.in.new_name = fname2;
2475 status = smb2_setinfo_file(tree2, &sfi);
2476 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2477 "Incorrect status");
2479 torture_wait_for_oplock_break(tctx);
2480 CHECK_VAL(break_info.count, 0);
2482 ZERO_STRUCT(qfi);
2483 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2484 qfi.generic.in.file.handle = h1;
2486 status = smb2_getinfo_file(tree1, tctx, &qfi);
2487 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2488 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2490 ZERO_STRUCT(qfi);
2491 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2492 qfi.generic.in.file.handle = h2;
2494 status = smb2_getinfo_file(tree2, tctx, &qfi);
2495 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2496 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2498 smb2_util_close(tree1, h1);
2499 smb2_util_close(tree2, h2);
2500 smb2_util_close(tree1, h);
2502 smb2_deltree(tree1, fname1);
2503 return ret;
2506 static bool test_smb2_oplock_batch21(struct torture_context *tctx,
2507 struct smb2_tree *tree1)
2509 const char *fname = BASEDIR "\\test_batch21.dat";
2510 NTSTATUS status;
2511 bool ret = true;
2512 union smb_open io;
2513 struct smb2_handle h, h1;
2514 char c = 0;
2516 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2517 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2519 /* cleanup */
2520 smb2_util_unlink(tree1, fname);
2522 tree1->session->transport->oplock.handler = torture_oplock_handler;
2523 tree1->session->transport->oplock.private_data = tree1;
2526 base ntcreatex parms
2528 ZERO_STRUCT(io.smb2);
2529 io.generic.level = RAW_OPEN_SMB2;
2530 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2531 io.smb2.in.alloc_size = 0;
2532 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2533 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2534 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2535 io.smb2.in.create_options = 0;
2536 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2537 io.smb2.in.security_flags = 0;
2538 io.smb2.in.fname = fname;
2541 with a batch oplock we get a break
2543 torture_comment(tctx, "BATCH21: open with batch oplock\n");
2544 ZERO_STRUCT(break_info);
2545 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2546 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2547 status = smb2_create(tree1, tctx, &(io.smb2));
2548 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2549 h1 = io.smb2.out.file.handle;
2550 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2552 torture_comment(tctx, "writing should not generate a break\n");
2553 status = smb2_util_write(tree1, h1, &c, 0, 1);
2554 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2556 torture_wait_for_oplock_break(tctx);
2557 CHECK_VAL(break_info.count, 0);
2559 smb2_util_close(tree1, h1);
2560 smb2_util_close(tree1, h);
2562 smb2_deltree(tree1, BASEDIR);
2563 return ret;
2566 static bool test_smb2_oplock_batch22a(struct torture_context *tctx,
2567 struct smb2_tree *tree1)
2569 const char *fname = BASEDIR "\\test_batch22a.dat";
2570 NTSTATUS status;
2571 bool ret = true;
2572 union smb_open io;
2573 struct smb2_handle h, h1, h2;
2574 struct timeval tv;
2575 int timeout = torture_setting_int(tctx, "oplocktimeout", 35);
2576 int te;
2578 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2579 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2581 /* cleanup */
2582 smb2_util_unlink(tree1, fname);
2584 tree1->session->transport->oplock.handler = torture_oplock_handler;
2585 tree1->session->transport->oplock.private_data = tree1;
2587 base ntcreatex parms
2589 ZERO_STRUCT(io.smb2);
2590 io.generic.level = RAW_OPEN_SMB2;
2591 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2592 io.smb2.in.alloc_size = 0;
2593 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2594 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2595 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2596 io.smb2.in.create_options = 0;
2597 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2598 io.smb2.in.security_flags = 0;
2599 io.smb2.in.fname = fname;
2602 with a batch oplock we get a break
2604 torture_comment(tctx, "BATCH22: open with batch oplock\n");
2605 ZERO_STRUCT(break_info);
2606 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2607 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2608 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2609 NTCREATEX_SHARE_ACCESS_WRITE|
2610 NTCREATEX_SHARE_ACCESS_DELETE;
2611 status = smb2_create(tree1, tctx, &(io.smb2));
2612 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2613 h1 = io.smb2.out.file.handle;
2614 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2616 torture_comment(tctx, "a 2nd open should succeed after the oplock "
2617 "break timeout\n");
2618 tv = timeval_current();
2619 tree1->session->transport->oplock.handler =
2620 torture_oplock_handler_timeout;
2621 status = smb2_create(tree1, tctx, &(io.smb2));
2622 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2623 h2 = io.smb2.out.file.handle;
2624 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2626 torture_wait_for_oplock_break(tctx);
2627 te = (int)timeval_elapsed(&tv);
2628 CHECK_RANGE(te, timeout - 1, timeout + 15);
2629 torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
2631 CHECK_VAL(break_info.count, 1);
2632 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2633 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2634 CHECK_VAL(break_info.failures, 0);
2636 smb2_util_close(tree1, h1);
2637 smb2_util_close(tree1, h2);
2638 smb2_util_close(tree1, h);
2640 smb2_deltree(tree1, BASEDIR);
2641 return ret;
2644 static bool test_smb2_oplock_batch22b(struct torture_context *tctx,
2645 struct smb2_tree *tree1,
2646 struct smb2_tree *tree2)
2648 const char *fname = BASEDIR "\\test_batch22b.dat";
2649 NTSTATUS status;
2650 bool ret = true;
2651 union smb_open io;
2652 struct smb2_handle h, h1, h2 = {{0}};
2653 struct timeval tv;
2654 int timeout = torture_setting_int(tctx, "oplocktimeout", 35);
2655 struct smb2_transport *transport1 = tree1->session->transport;
2656 bool block_setup = false;
2657 bool block_ok = false;
2658 int te;
2660 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2661 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2663 /* cleanup */
2664 smb2_util_unlink(tree1, fname);
2666 tree1->session->transport->oplock.handler = torture_oplock_handler;
2667 tree1->session->transport->oplock.private_data = tree1;
2669 base ntcreatex parms
2671 ZERO_STRUCT(io.smb2);
2672 io.generic.level = RAW_OPEN_SMB2;
2673 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2674 io.smb2.in.alloc_size = 0;
2675 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2676 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2677 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2678 io.smb2.in.create_options = 0;
2679 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2680 io.smb2.in.security_flags = 0;
2681 io.smb2.in.fname = fname;
2684 with a batch oplock we get a break
2686 torture_comment(tctx, "BATCH22: open with batch oplock\n");
2687 ZERO_STRUCT(break_info);
2688 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2689 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2690 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2691 NTCREATEX_SHARE_ACCESS_WRITE|
2692 NTCREATEX_SHARE_ACCESS_DELETE;
2693 status = smb2_create(tree1, tctx, &(io.smb2));
2694 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2695 h1 = io.smb2.out.file.handle;
2696 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2698 torture_comment(tctx, "a 2nd open should succeed after the oplock "
2699 "break timeout\n");
2700 tv = timeval_current();
2701 tree1->session->transport->oplock.handler =
2702 torture_oplock_handler_timeout;
2703 block_setup = test_setup_blocked_transports(tctx);
2704 torture_assert(tctx, block_setup, "test_setup_blocked_transports");
2705 block_ok = test_block_smb2_transport(tctx, transport1);
2706 torture_assert(tctx, block_ok, "test_block_smb2_transport");
2708 status = smb2_create(tree2, tctx, &(io.smb2));
2709 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Incorrect status");
2710 h2 = io.smb2.out.file.handle;
2711 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2713 torture_wait_for_oplock_break(tctx);
2714 te = (int)timeval_elapsed(&tv);
2715 CHECK_RANGE(te, 0, timeout);
2716 torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
2718 CHECK_VAL(break_info.count, 1);
2719 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2720 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2721 CHECK_VAL(break_info.failures, 0);
2723 done:
2724 if (block_ok) {
2725 test_unblock_smb2_transport(tctx, transport1);
2727 test_cleanup_blocked_transports(tctx);
2729 smb2_util_close(tree1, h1);
2730 if (!smb2_util_handle_empty(h2)) {
2731 smb2_util_close(tree1, h2);
2733 smb2_util_close(tree1, h);
2735 smb2_deltree(tree1, BASEDIR);
2736 return ret;
2739 static bool test_smb2_oplock_batch23(struct torture_context *tctx,
2740 struct smb2_tree *tree1,
2741 struct smb2_tree *tree2)
2743 const char *fname = BASEDIR "\\test_batch23.dat";
2744 NTSTATUS status;
2745 bool ret = true;
2746 union smb_open io;
2747 struct smb2_handle h, h1, h2, h3;
2748 struct smb2_tree *tree3 = NULL;
2750 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2751 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2753 /* cleanup */
2754 smb2_util_unlink(tree1, fname);
2756 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2757 CHECK_VAL(ret, true);
2759 tree1->session->transport->oplock.handler = torture_oplock_handler;
2760 tree1->session->transport->oplock.private_data = tree1;
2762 tree2->session->transport->oplock.handler = torture_oplock_handler;
2763 tree2->session->transport->oplock.private_data = tree2;
2765 tree3->session->transport->oplock.handler = torture_oplock_handler;
2766 tree3->session->transport->oplock.private_data = tree3;
2769 base ntcreatex parms
2771 ZERO_STRUCT(io.smb2);
2772 io.generic.level = RAW_OPEN_SMB2;
2773 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2774 io.smb2.in.alloc_size = 0;
2775 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2776 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2777 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2778 io.smb2.in.create_options = 0;
2779 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2780 io.smb2.in.security_flags = 0;
2781 io.smb2.in.fname = fname;
2783 torture_comment(tctx, "BATCH23: an open and ask for a batch oplock\n");
2784 ZERO_STRUCT(break_info);
2786 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2787 SEC_RIGHTS_FILE_WRITE;
2788 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2789 NTCREATEX_SHARE_ACCESS_WRITE;
2790 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2791 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2792 status = smb2_create(tree1, tctx, &(io.smb2));
2793 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2794 h1 = io.smb2.out.file.handle;
2795 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2797 ZERO_STRUCT(break_info);
2799 torture_comment(tctx, "a 2nd open without level2 oplock support "
2800 "should generate a break to level2\n");
2801 status = smb2_create(tree3, tctx, &(io.smb2));
2802 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2803 h3 = io.smb2.out.file.handle;
2805 torture_wait_for_oplock_break(tctx);
2806 CHECK_VAL(break_info.count, 1);
2807 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2808 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2809 CHECK_VAL(break_info.failures, 0);
2811 ZERO_STRUCT(break_info);
2813 torture_comment(tctx, "a 3rd open with level2 oplock support should "
2814 "not generate a break\n");
2815 status = smb2_create(tree2, tctx, &(io.smb2));
2816 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2817 h2 = io.smb2.out.file.handle;
2818 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2820 torture_wait_for_oplock_break(tctx);
2821 CHECK_VAL(break_info.count, 0);
2823 smb2_util_close(tree1, h1);
2824 smb2_util_close(tree2, h2);
2825 smb2_util_close(tree3, h3);
2826 smb2_util_close(tree1, h);
2828 smb2_deltree(tree1, BASEDIR);
2829 return ret;
2832 static bool test_smb2_oplock_batch24(struct torture_context *tctx,
2833 struct smb2_tree *tree1,
2834 struct smb2_tree *tree2)
2836 const char *fname = BASEDIR "\\test_batch24.dat";
2837 NTSTATUS status;
2838 bool ret = true;
2839 union smb_open io;
2840 struct smb2_handle h, h1, h2;
2841 struct smb2_tree *tree3 = NULL;
2843 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2844 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2846 /* cleanup */
2847 smb2_util_unlink(tree1, fname);
2849 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2850 CHECK_VAL(ret, true);
2852 tree1->session->transport->oplock.handler = torture_oplock_handler;
2853 tree1->session->transport->oplock.private_data = tree1;
2855 tree2->session->transport->oplock.handler = torture_oplock_handler;
2856 tree2->session->transport->oplock.private_data = tree2;
2858 tree3->session->transport->oplock.handler = torture_oplock_handler;
2859 tree3->session->transport->oplock.private_data = tree3;
2862 base ntcreatex parms
2864 ZERO_STRUCT(io.smb2);
2865 io.generic.level = RAW_OPEN_SMB2;
2866 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2867 io.smb2.in.alloc_size = 0;
2868 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2869 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2870 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2871 io.smb2.in.create_options = 0;
2872 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2873 io.smb2.in.security_flags = 0;
2874 io.smb2.in.fname = fname;
2876 torture_comment(tctx, "BATCH24: a open without level support and "
2877 "ask for a batch oplock\n");
2878 ZERO_STRUCT(break_info);
2880 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2881 SEC_RIGHTS_FILE_WRITE;
2882 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2883 NTCREATEX_SHARE_ACCESS_WRITE;
2884 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2885 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2887 status = smb2_create(tree3, tctx, &(io.smb2));
2888 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2889 h2 = io.smb2.out.file.handle;
2890 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2892 ZERO_STRUCT(break_info);
2894 torture_comment(tctx, "a 2nd open with level2 oplock support should "
2895 "generate a break\n");
2896 status = smb2_create(tree2, tctx, &(io.smb2));
2897 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2898 h1 = io.smb2.out.file.handle;
2899 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2901 torture_wait_for_oplock_break(tctx);
2902 CHECK_VAL(break_info.count, 1);
2903 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
2904 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2905 CHECK_VAL(break_info.failures, 0);
2907 smb2_util_close(tree3, h2);
2908 smb2_util_close(tree2, h1);
2909 smb2_util_close(tree1, h);
2911 smb2_deltree(tree1, BASEDIR);
2912 return ret;
2915 static bool test_smb2_oplock_batch25(struct torture_context *tctx,
2916 struct smb2_tree *tree1)
2918 const char *fname = BASEDIR "\\test_batch25.dat";
2919 NTSTATUS status;
2920 bool ret = true;
2921 union smb_open io;
2922 struct smb2_handle h, h1;
2924 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2925 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2927 /* cleanup */
2928 smb2_util_unlink(tree1, fname);
2930 tree1->session->transport->oplock.handler = torture_oplock_handler;
2931 tree1->session->transport->oplock.private_data = tree1;
2934 base ntcreatex parms
2936 ZERO_STRUCT(io.smb2);
2937 io.generic.level = RAW_OPEN_SMB2;
2938 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2939 io.smb2.in.alloc_size = 0;
2940 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2941 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2942 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2943 io.smb2.in.create_options = 0;
2944 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2945 io.smb2.in.security_flags = 0;
2946 io.smb2.in.fname = fname;
2948 torture_comment(tctx, "BATCH25: open a file with an batch oplock "
2949 "(share mode: none)\n");
2951 ZERO_STRUCT(break_info);
2952 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2953 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2955 status = smb2_create(tree1, tctx, &(io.smb2));
2956 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2957 h1 = io.smb2.out.file.handle;
2958 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2960 status = smb2_util_setatr(tree1, fname, FILE_ATTRIBUTE_HIDDEN);
2961 torture_assert_ntstatus_ok(tctx, status, "Setting attributes "
2962 "shouldn't trigger an oplock break");
2964 smb2_util_close(tree1, h1);
2965 smb2_util_close(tree1, h);
2967 smb2_deltree(tree1, fname);
2968 return ret;
2971 static bool test_smb2_oplock_batch26(struct torture_context *tctx,
2972 struct smb2_tree *tree1)
2975 NTSTATUS status;
2976 bool ret = true;
2977 union smb_open io;
2978 struct smb2_handle h, h1, h2, h3;
2979 const char *fname_base = BASEDIR "\\test_oplock.txt";
2980 const char *stream = "Stream One:$DATA";
2981 const char *fname_stream;
2983 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2984 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2986 tree1->session->transport->oplock.handler = torture_oplock_handler;
2987 tree1->session->transport->oplock.private_data = tree1;
2989 fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
2992 base ntcreatex parms
2994 ZERO_STRUCT(io.smb2);
2995 io.generic.level = RAW_OPEN_SMB2;
2996 io.smb2.in.desired_access = 0x120089;
2997 io.smb2.in.alloc_size = 0;
2998 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2999 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE |
3000 NTCREATEX_SHARE_ACCESS_WRITE;
3001 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3002 io.smb2.in.create_options = 0;
3003 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3004 io.smb2.in.security_flags = 0;
3005 io.smb2.in.fname = fname_base;
3008 Open base file with a batch oplock.
3010 torture_comment(tctx, "Open the base file with batch oplock\n");
3011 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3012 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3014 status = smb2_create(tree1, tctx, &(io.smb2));
3015 torture_assert_ntstatus_ok(tctx, status, "Error opening base file");
3016 h1 = io.smb2.out.file.handle;
3017 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3019 torture_comment(tctx, "Got batch oplock on base file\n");
3021 torture_comment(tctx, "Opening stream file with batch oplock..\n");
3023 io.smb2.in.fname = fname_stream;
3025 status = smb2_create(tree1, tctx, &(io.smb2));
3026 torture_assert_ntstatus_ok(tctx, status, "Error opening stream file");
3027 h2 = io.smb2.out.file.handle;
3028 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3030 torture_comment(tctx, "Got batch oplock on stream file\n");
3032 torture_comment(tctx, "Open base file again with batch oplock\n");
3034 io.smb2.in.fname = fname_base;
3036 status = smb2_create(tree1, tctx, &(io.smb2));
3037 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3038 h3 = io.smb2.out.file.handle;
3039 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3041 smb2_util_close(tree1, h1);
3042 smb2_util_close(tree1, h2);
3043 smb2_util_close(tree1, h3);
3044 smb2_util_close(tree1, h);
3045 smb2_deltree(tree1, BASEDIR);
3046 return ret;
3050 /* Test how oplocks work on streams. */
3051 static bool test_raw_oplock_stream1(struct torture_context *tctx,
3052 struct smb2_tree *tree1,
3053 struct smb2_tree *tree2)
3055 NTSTATUS status;
3056 union smb_open io;
3057 const char *fname_base = BASEDIR "\\test_stream1.txt";
3058 const char *fname_stream, *fname_default_stream;
3059 const char *default_stream = "::$DATA";
3060 const char *stream = "Stream One:$DATA";
3061 bool ret = true;
3062 struct smb2_handle h, h_base, h_stream;
3063 int i;
3065 #define NSTREAM_OPLOCK_RESULTS 8
3066 struct {
3067 const char **fname;
3068 bool open_base_file;
3069 uint32_t oplock_req;
3070 uint32_t oplock_granted;
3071 } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
3072 /* Request oplock on stream without the base file open. */
3073 {&fname_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3074 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3075 {&fname_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3076 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3078 /* Request oplock on stream with the base file open. */
3079 {&fname_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3080 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_II},
3081 {&fname_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3082 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_II},
3085 fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
3086 fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
3087 default_stream);
3089 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3090 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3092 /* Initialize handles to "closed". Using -1 in the first 64-bytes
3093 * as the sentry for this */
3094 h_stream.data[0] = -1;
3096 /* cleanup */
3097 smb2_util_unlink(tree1, fname_base);
3099 tree1->session->transport->oplock.handler = torture_oplock_handler;
3100 tree1->session->transport->oplock.private_data = tree1;
3102 tree2->session->transport->oplock.handler = torture_oplock_handler;
3103 tree2->session->transport->oplock.private_data = tree2;
3105 /* Setup generic open parameters. */
3106 ZERO_STRUCT(io.smb2);
3107 io.generic.level = RAW_OPEN_SMB2;
3108 io.smb2.in.desired_access = (SEC_FILE_READ_DATA |
3109 SEC_FILE_WRITE_DATA |
3110 SEC_FILE_APPEND_DATA |
3111 SEC_STD_READ_CONTROL);
3112 io.smb2.in.alloc_size = 0;
3113 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3114 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3115 NTCREATEX_SHARE_ACCESS_WRITE;
3116 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3117 io.smb2.in.create_options = 0;
3118 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3119 io.smb2.in.security_flags = 0;
3121 /* Create the file with a stream */
3122 io.smb2.in.fname = fname_stream;
3123 io.smb2.in.create_flags = 0;
3124 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
3125 status = smb2_create(tree1, tctx, &(io.smb2));
3126 torture_assert_ntstatus_ok(tctx, status, "Error creating file");
3127 smb2_util_close(tree1, io.smb2.out.file.handle);
3129 /* Change the disposition to open now that the file has been created. */
3130 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
3132 /* Try some permutations of taking oplocks on streams. */
3133 for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
3134 const char *fname = *stream_oplock_results[i].fname;
3135 bool open_base_file = stream_oplock_results[i].open_base_file;
3136 uint32_t oplock_req = stream_oplock_results[i].oplock_req;
3137 uint32_t oplock_granted =
3138 stream_oplock_results[i].oplock_granted;
3140 if (open_base_file) {
3141 torture_comment(tctx, "Opening base file: %s with "
3142 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3143 io.smb2.in.fname = fname_base;
3144 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3145 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3146 status = smb2_create(tree2, tctx, &(io.smb2));
3147 torture_assert_ntstatus_ok(tctx, status,
3148 "Error opening file");
3149 CHECK_VAL(io.smb2.out.oplock_level,
3150 SMB2_OPLOCK_LEVEL_BATCH);
3151 h_base = io.smb2.out.file.handle;
3154 torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
3155 fname, oplock_req);
3156 io.smb2.in.fname = fname;
3157 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3158 io.smb2.in.oplock_level = oplock_req;
3160 /* Do the open with the desired oplock on the stream. */
3161 status = smb2_create(tree1, tctx, &(io.smb2));
3162 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3163 CHECK_VAL(io.smb2.out.oplock_level, oplock_granted);
3164 smb2_util_close(tree1, io.smb2.out.file.handle);
3166 /* Cleanup the base file if it was opened. */
3167 if (open_base_file)
3168 smb2_util_close(tree2, h_base);
3171 /* Open the stream with an exclusive oplock. */
3172 torture_comment(tctx, "Opening stream: %s with %d\n",
3173 fname_stream, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3174 io.smb2.in.fname = fname_stream;
3175 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3176 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3177 status = smb2_create(tree1, tctx, &(io.smb2));
3178 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3179 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3180 h_stream = io.smb2.out.file.handle;
3182 /* Open the base file and see if it contends. */
3183 ZERO_STRUCT(break_info);
3184 torture_comment(tctx, "Opening base file: %s with %d\n",
3185 fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3186 io.smb2.in.fname = fname_base;
3187 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3188 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3189 status = smb2_create(tree2, tctx, &(io.smb2));
3190 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3191 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3192 smb2_util_close(tree2, io.smb2.out.file.handle);
3194 torture_wait_for_oplock_break(tctx);
3195 CHECK_VAL(break_info.count, 0);
3196 CHECK_VAL(break_info.failures, 0);
3198 /* Open the stream again to see if it contends. */
3199 ZERO_STRUCT(break_info);
3200 torture_comment(tctx, "Opening stream again: %s with "
3201 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3202 io.smb2.in.fname = fname_stream;
3203 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3204 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3205 status = smb2_create(tree2, tctx, &(io.smb2));
3206 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3207 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3208 smb2_util_close(tree2, io.smb2.out.file.handle);
3210 torture_wait_for_oplock_break(tctx);
3211 CHECK_VAL(break_info.count, 1);
3212 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
3213 CHECK_VAL(break_info.failures, 0);
3215 /* Close the stream. */
3216 if (h_stream.data[0] != -1) {
3217 smb2_util_close(tree1, h_stream);
3220 smb2_util_close(tree1, h);
3222 smb2_deltree(tree1, BASEDIR);
3223 return ret;
3226 static bool test_smb2_oplock_doc(struct torture_context *tctx, struct smb2_tree *tree,
3227 struct smb2_tree *tree2)
3229 const char *fname = BASEDIR "\\test_oplock_doc.dat";
3230 NTSTATUS status;
3231 bool ret = true;
3232 union smb_open io;
3233 struct smb2_handle h, h1;
3234 union smb_setfileinfo sfinfo;
3236 status = torture_smb2_testdir(tree, BASEDIR, &h);
3237 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3238 smb2_util_close(tree, h);
3240 /* cleanup */
3241 smb2_util_unlink(tree, fname);
3242 tree->session->transport->oplock.handler = torture_oplock_handler;
3243 tree->session->transport->oplock.private_data = tree;
3246 base ntcreatex parms
3248 ZERO_STRUCT(io.smb2);
3249 io.generic.level = RAW_OPEN_SMB2;
3250 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3251 io.smb2.in.alloc_size = 0;
3252 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3253 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
3254 NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
3255 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3256 io.smb2.in.create_options = 0;
3257 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3258 io.smb2.in.security_flags = 0;
3259 io.smb2.in.fname = fname;
3261 torture_comment(tctx, "open a file with a batch oplock\n");
3262 ZERO_STRUCT(break_info);
3263 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3264 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3266 status = smb2_create(tree, tctx, &(io.smb2));
3267 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3268 h1 = io.smb2.out.file.handle;
3269 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3271 torture_comment(tctx, "Set delete on close\n");
3272 ZERO_STRUCT(sfinfo);
3273 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
3274 sfinfo.generic.in.file.handle = h1;
3275 sfinfo.disposition_info.in.delete_on_close = 1;
3276 status = smb2_setinfo_file(tree, &sfinfo);
3277 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3279 torture_comment(tctx, "2nd open should not break and get "
3280 "DELETE_PENDING\n");
3281 ZERO_STRUCT(break_info);
3282 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
3283 io.smb2.in.create_options = 0;
3284 io.smb2.in.desired_access = SEC_FILE_READ_DATA;
3285 status = smb2_create(tree2, tctx, &io.smb2);
3286 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DELETE_PENDING,
3287 "Incorrect status");
3288 CHECK_VAL(break_info.count, 0);
3290 smb2_util_close(tree, h1);
3292 smb2_util_unlink(tree, fname);
3293 smb2_deltree(tree, BASEDIR);
3294 return ret;
3297 /* Open a file with a batch oplock, then open it again from a second client
3298 * requesting no oplock. Having two open file handles should break our own
3299 * oplock during BRL acquisition.
3301 static bool test_smb2_oplock_brl1(struct torture_context *tctx,
3302 struct smb2_tree *tree1,
3303 struct smb2_tree *tree2)
3305 const char *fname = BASEDIR "\\test_batch_brl.dat";
3306 /*int fname, f;*/
3307 bool ret = true;
3308 uint8_t buf[1000];
3309 union smb_open io;
3310 NTSTATUS status;
3311 struct smb2_lock lck;
3312 struct smb2_lock_element lock[1];
3313 struct smb2_handle h, h1, h2;
3315 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3316 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3318 /* cleanup */
3319 smb2_util_unlink(tree1, fname);
3321 tree1->session->transport->oplock.handler =
3322 torture_oplock_handler_two_notifications;
3323 tree1->session->transport->oplock.private_data = tree1;
3326 base ntcreatex parms
3328 ZERO_STRUCT(io.smb2);
3329 io.generic.level = RAW_OPEN_SMB2;
3330 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3331 SEC_RIGHTS_FILE_WRITE;
3332 io.smb2.in.alloc_size = 0;
3333 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3334 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3335 NTCREATEX_SHARE_ACCESS_WRITE;
3336 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3337 io.smb2.in.create_options = 0;
3338 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3339 io.smb2.in.security_flags = 0;
3340 io.smb2.in.fname = fname;
3343 with a batch oplock we get a break
3345 torture_comment(tctx, "open with batch oplock\n");
3346 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3347 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3349 status = smb2_create(tree1, tctx, &(io.smb2));
3350 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3351 h1 = io.smb2.out.file.handle;
3352 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3354 /* create a file with bogus data */
3355 memset(buf, 0, sizeof(buf));
3357 status = smb2_util_write(tree1, h1,buf, 0, sizeof(buf));
3358 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3359 torture_comment(tctx, "Failed to create file\n");
3360 ret = false;
3361 goto done;
3364 torture_comment(tctx, "a 2nd open should give a break\n");
3365 ZERO_STRUCT(break_info);
3367 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3368 io.smb2.in.oplock_level = 0;
3369 status = smb2_create(tree2, tctx, &(io.smb2));
3370 h2 = io.smb2.out.file.handle;
3371 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3373 torture_wait_for_oplock_break(tctx);
3374 CHECK_VAL(break_info.count, 1);
3375 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3376 CHECK_VAL(break_info.failures, 0);
3377 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3379 ZERO_STRUCT(break_info);
3381 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3383 ZERO_STRUCT(lock);
3385 lock[0].offset = 0;
3386 lock[0].length = 4;
3387 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3388 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3390 ZERO_STRUCT(lck);
3391 lck.in.file.handle = h1;
3392 lck.in.locks = &lock[0];
3393 lck.in.lock_count = 1;
3394 status = smb2_lock(tree1, &lck);
3395 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3397 torture_wait_for_oplock_break(tctx);
3398 CHECK_VAL(break_info.count, 1);
3399 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3400 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3401 CHECK_VAL(break_info.failures, 0);
3403 /* expect no oplock break */
3404 ZERO_STRUCT(break_info);
3405 lock[0].offset = 2;
3406 status = smb2_lock(tree1, &lck);
3407 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3408 "Incorrect status");
3410 torture_wait_for_oplock_break(tctx);
3411 CHECK_VAL(break_info.count, 0);
3412 CHECK_VAL(break_info.level, 0);
3413 CHECK_VAL(break_info.failures, 0);
3415 smb2_util_close(tree1, h1);
3416 smb2_util_close(tree2, h2);
3417 smb2_util_close(tree1, h);
3419 done:
3420 smb2_deltree(tree1, BASEDIR);
3421 return ret;
3425 /* Open a file with a batch oplock on one tree and then acquire a brl.
3426 * We should not contend our own oplock.
3428 static bool test_smb2_oplock_brl2(struct torture_context *tctx, struct smb2_tree *tree1)
3430 const char *fname = BASEDIR "\\test_batch_brl.dat";
3431 /*int fname, f;*/
3432 bool ret = true;
3433 uint8_t buf[1000];
3434 union smb_open io;
3435 NTSTATUS status;
3436 struct smb2_handle h, h1;
3437 struct smb2_lock lck;
3438 struct smb2_lock_element lock[1];
3440 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3441 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3443 /* cleanup */
3444 smb2_util_unlink(tree1, fname);
3446 tree1->session->transport->oplock.handler = torture_oplock_handler;
3447 tree1->session->transport->oplock.private_data = tree1;
3450 base ntcreatex parms
3452 ZERO_STRUCT(io.smb2);
3453 io.generic.level = RAW_OPEN_SMB2;
3454 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3455 SEC_RIGHTS_FILE_WRITE;
3456 io.smb2.in.alloc_size = 0;
3457 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3458 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3459 NTCREATEX_SHARE_ACCESS_WRITE;
3460 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3461 io.smb2.in.create_options = 0;
3462 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3463 io.smb2.in.security_flags = 0;
3464 io.smb2.in.fname = fname;
3467 with a batch oplock we get a break
3469 torture_comment(tctx, "open with batch oplock\n");
3470 ZERO_STRUCT(break_info);
3471 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3472 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3474 status = smb2_create(tree1, tctx, &(io.smb2));
3475 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3476 h1 = io.smb2.out.file.handle;
3477 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3479 /* create a file with bogus data */
3480 memset(buf, 0, sizeof(buf));
3482 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3483 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3484 torture_comment(tctx, "Failed to create file\n");
3485 ret = false;
3486 goto done;
3489 ZERO_STRUCT(break_info);
3491 torture_comment(tctx, "a self BRL acquisition should not break to "
3492 "none\n");
3494 ZERO_STRUCT(lock);
3496 lock[0].offset = 0;
3497 lock[0].length = 4;
3498 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3499 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3501 ZERO_STRUCT(lck);
3502 lck.in.file.handle = h1;
3503 lck.in.locks = &lock[0];
3504 lck.in.lock_count = 1;
3505 status = smb2_lock(tree1, &lck);
3506 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3508 lock[0].offset = 2;
3509 status = smb2_lock(tree1, &lck);
3510 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3511 "Incorrect status");
3513 /* With one file handle open a BRL should not contend our oplock.
3514 * Thus, no oplock break will be received and the entire break_info
3515 * struct will be 0 */
3516 torture_wait_for_oplock_break(tctx);
3517 CHECK_VAL(break_info.count, 0);
3518 CHECK_VAL(break_info.level, 0);
3519 CHECK_VAL(break_info.failures, 0);
3521 smb2_util_close(tree1, h1);
3522 smb2_util_close(tree1, h);
3524 done:
3525 smb2_deltree(tree1, BASEDIR);
3526 return ret;
3529 /* Open a file with a batch oplock twice from one tree and then acquire a
3530 * brl. BRL acquisition should break our own oplock.
3532 static bool test_smb2_oplock_brl3(struct torture_context *tctx, struct smb2_tree *tree1)
3534 const char *fname = BASEDIR "\\test_batch_brl.dat";
3535 bool ret = true;
3536 uint8_t buf[1000];
3537 union smb_open io;
3538 NTSTATUS status;
3539 struct smb2_handle h, h1, h2;
3540 struct smb2_lock lck;
3541 struct smb2_lock_element lock[1];
3543 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3544 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3546 /* cleanup */
3547 smb2_util_unlink(tree1, fname);
3548 tree1->session->transport->oplock.handler =
3549 torture_oplock_handler_two_notifications;
3550 tree1->session->transport->oplock.private_data = tree1;
3553 base ntcreatex parms
3555 ZERO_STRUCT(io.smb2);
3556 io.generic.level = RAW_OPEN_SMB2;
3557 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3558 SEC_RIGHTS_FILE_WRITE;
3559 io.smb2.in.alloc_size = 0;
3560 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3561 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3562 NTCREATEX_SHARE_ACCESS_WRITE;
3563 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3564 io.smb2.in.create_options = 0;
3565 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3566 io.smb2.in.security_flags = 0;
3567 io.smb2.in.fname = fname;
3570 with a batch oplock we get a break
3572 torture_comment(tctx, "open with batch oplock\n");
3573 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3574 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3576 status = smb2_create(tree1, tctx, &(io.smb2));
3577 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3578 h1 = io.smb2.out.file.handle;
3579 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3581 /* create a file with bogus data */
3582 memset(buf, 0, sizeof(buf));
3583 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3585 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3586 torture_comment(tctx, "Failed to create file\n");
3587 ret = false;
3588 goto done;
3591 torture_comment(tctx, "a 2nd open should give a break\n");
3592 ZERO_STRUCT(break_info);
3594 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3595 io.smb2.in.oplock_level = 0;
3596 status = smb2_create(tree1, tctx, &(io.smb2));
3597 h2 = io.smb2.out.file.handle;
3598 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3599 CHECK_VAL(break_info.count, 1);
3600 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3601 CHECK_VAL(break_info.failures, 0);
3602 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3604 ZERO_STRUCT(break_info);
3606 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3608 ZERO_STRUCT(lock);
3610 lock[0].offset = 0;
3611 lock[0].length = 4;
3612 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3613 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3615 ZERO_STRUCT(lck);
3616 lck.in.file.handle = h1;
3617 lck.in.locks = &lock[0];
3618 lck.in.lock_count = 1;
3619 status = smb2_lock(tree1, &lck);
3620 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3622 torture_wait_for_oplock_break(tctx);
3623 CHECK_VAL(break_info.count, 1);
3624 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3625 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3626 CHECK_VAL(break_info.failures, 0);
3628 /* expect no oplock break */
3629 ZERO_STRUCT(break_info);
3630 lock[0].offset = 2;
3631 status = smb2_lock(tree1, &lck);
3632 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3633 "Incorrect status");
3635 torture_wait_for_oplock_break(tctx);
3636 CHECK_VAL(break_info.count, 0);
3637 CHECK_VAL(break_info.level, 0);
3638 CHECK_VAL(break_info.failures, 0);
3640 smb2_util_close(tree1, h1);
3641 smb2_util_close(tree1, h2);
3642 smb2_util_close(tree1, h);
3644 done:
3645 smb2_deltree(tree1, BASEDIR);
3646 return ret;
3650 /* Starting the SMB2 specific oplock tests at 500 so we can keep the SMB1
3651 * tests in sync with an identically numbered SMB2 test */
3653 /* Test whether the server correctly returns an error when we send
3654 * a response to a levelII to none oplock notification. */
3655 static bool test_smb2_oplock_levelII500(struct torture_context *tctx,
3656 struct smb2_tree *tree1)
3658 const char *fname = BASEDIR "\\test_levelII500.dat";
3659 NTSTATUS status;
3660 bool ret = true;
3661 union smb_open io;
3662 struct smb2_handle h, h1;
3663 char c = 0;
3665 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3666 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3668 /* cleanup */
3669 smb2_util_unlink(tree1, fname);
3671 tree1->session->transport->oplock.handler = torture_oplock_handler;
3672 tree1->session->transport->oplock.private_data = tree1;
3675 base ntcreatex parms
3677 ZERO_STRUCT(io.smb2);
3678 io.generic.level = RAW_OPEN_SMB2;
3679 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3680 io.smb2.in.alloc_size = 0;
3681 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3682 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3683 io.smb2.in.create_options = 0;
3684 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3685 io.smb2.in.security_flags = 0;
3686 io.smb2.in.fname = fname;
3688 torture_comment(tctx, "LEVELII500: acknowledging a break from II to "
3689 "none should return an error\n");
3690 ZERO_STRUCT(break_info);
3692 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3693 SEC_RIGHTS_FILE_WRITE;
3694 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3695 NTCREATEX_SHARE_ACCESS_WRITE;
3696 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3697 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
3698 status = smb2_create(tree1, tctx, &(io.smb2));
3699 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3700 h1 = io.smb2.out.file.handle;
3701 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3703 ZERO_STRUCT(break_info);
3705 torture_comment(tctx, "write should trigger a break to none and when "
3706 "we reply, an oplock break failure\n");
3707 smb2_util_write(tree1, h1, &c, 0, 1);
3709 /* Wait several times to receive both the break notification, and the
3710 * NT_STATUS_INVALID_OPLOCK_PROTOCOL error in the break response */
3711 torture_wait_for_oplock_break(tctx);
3712 torture_wait_for_oplock_break(tctx);
3713 torture_wait_for_oplock_break(tctx);
3714 torture_wait_for_oplock_break(tctx);
3716 /* There appears to be a race condition in W2K8 and W2K8R2 where
3717 * sometimes the server will happily reply to our break response with
3718 * NT_STATUS_OK, and sometimes it will return the OPLOCK_PROTOCOL
3719 * error. As the MS-SMB2 doc states that a client should not reply to
3720 * a level2 to none break notification, I'm leaving the protocol error
3721 * as the expected behavior. */
3722 CHECK_VAL(break_info.count, 1);
3723 CHECK_VAL(break_info.level, 0);
3724 CHECK_VAL(break_info.failures, 1);
3725 torture_assert_ntstatus_equal(tctx, break_info.failure_status,
3726 NT_STATUS_INVALID_OPLOCK_PROTOCOL,
3727 "Incorrect status");
3729 smb2_util_close(tree1, h1);
3730 smb2_util_close(tree1, h);
3732 smb2_deltree(tree1, BASEDIR);
3733 return ret;
3737 * Test a double-break. Open a file with exclusive. Send off a second open
3738 * request with OPEN_IF, triggering a break to level2. This should respond
3739 * with level2. Before replying to the break to level2, fire off a third open
3740 * with OVERWRITE_IF. The expected sequence would be that the 3rd opener gets
3741 * a level2 immediately triggered by a break to none, but that seems not the
3742 * case. Still investigating what the right behaviour should be.
3745 struct levelII501_state {
3746 struct torture_context *tctx;
3747 struct smb2_tree *tree1;
3748 struct smb2_tree *tree2;
3749 struct smb2_tree *tree3;
3750 struct smb2_handle h;
3751 struct smb2_handle h1;
3752 union smb_open io;
3754 struct smb2_handle break_handle;
3755 uint8_t break_to;
3756 struct smb2_break br;
3758 bool done;
3761 static bool torture_oplock_break_delay(struct smb2_transport *transport,
3762 const struct smb2_handle *handle,
3763 uint8_t level, void *private_data);
3764 static void levelII501_break_done(struct smb2_request *req);
3765 static void levelII501_open1_done(struct smb2_request *req);
3766 static void levelII501_open2_done(struct smb2_request *req);
3767 static void levelII501_2ndopen_cb(struct tevent_context *ev,
3768 struct tevent_timer *te,
3769 struct timeval current_time,
3770 void *private_data);
3771 static void levelII501_break_timeout_cb(struct tevent_context *ev,
3772 struct tevent_timer *te,
3773 struct timeval current_time,
3774 void *private_data);
3775 static void levelII501_timeout_cb(struct tevent_context *ev,
3776 struct tevent_timer *te,
3777 struct timeval current_time,
3778 void *private_data);
3780 static bool test_smb2_oplock_levelII501(struct torture_context *tctx,
3781 struct smb2_tree *tree1,
3782 struct smb2_tree *tree2)
3784 const char *fname = BASEDIR "\\test_levelII501.dat";
3785 NTSTATUS status;
3786 bool ret = true;
3787 struct levelII501_state *state;
3788 struct smb2_request *req;
3789 struct tevent_timer *te;
3791 state = talloc(tctx, struct levelII501_state);
3792 state->tctx = tctx;
3793 state->done = false;
3794 state->tree1 = tree1;
3795 state->tree2 = tree2;
3797 if (!torture_smb2_connection(tctx, &state->tree3)) {
3798 torture_fail(tctx, "Establishing SMB2 connection failed\n");
3799 return false;
3802 status = torture_smb2_testdir(tree1, BASEDIR, &state->h);
3803 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3805 /* cleanup */
3806 smb2_util_unlink(tree1, fname);
3809 base ntcreatex parms
3811 ZERO_STRUCT(state->io.smb2);
3812 state->io.generic.level = RAW_OPEN_SMB2;
3813 state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3814 state->io.smb2.in.alloc_size = 0;
3815 state->io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3816 state->io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3817 state->io.smb2.in.create_options = 0;
3818 state->io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3819 state->io.smb2.in.security_flags = 0;
3820 state->io.smb2.in.fname = fname;
3822 torture_comment(tctx, "LEVELII501: Test double break sequence\n");
3823 ZERO_STRUCT(break_info);
3825 state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3826 SEC_RIGHTS_FILE_WRITE;
3827 state->io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3828 NTCREATEX_SHARE_ACCESS_WRITE;
3829 state->io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3830 state->io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3832 tree1->session->transport->oplock.handler = torture_oplock_break_delay;
3833 tree1->session->transport->oplock.private_data = state;
3835 status = smb2_create(tree1, tctx, &(state->io.smb2));
3836 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3837 state->h1 = state->io.smb2.out.file.handle;
3838 CHECK_VAL(state->io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3841 * Trigger a break to level2
3844 req = smb2_create_send(tree2, &state->io.smb2);
3845 req->async.fn = levelII501_open1_done;
3846 req->async.private_data = state;
3848 te = tevent_add_timer(
3849 tctx->ev, tctx, tevent_timeval_current_ofs(0, 200000),
3850 levelII501_2ndopen_cb, state);
3851 torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
3853 te = tevent_add_timer(
3854 tctx->ev, tctx, tevent_timeval_current_ofs(2, 0),
3855 levelII501_timeout_cb, state);
3856 torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
3858 while (!state->done) {
3859 if (tevent_loop_once(tctx->ev) != 0) {
3860 torture_comment(tctx, "tevent_loop_once failed\n");
3864 return ret;
3868 * Fire off a second open after a little timeout
3871 static void levelII501_2ndopen_cb(struct tevent_context *ev,
3872 struct tevent_timer *te,
3873 struct timeval current_time,
3874 void *private_data)
3876 struct levelII501_state *state = talloc_get_type_abort(
3877 private_data, struct levelII501_state);
3878 struct smb2_request *req;
3880 state->io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
3881 req = smb2_create_send(state->tree3, &state->io.smb2);
3882 req->async.fn = levelII501_open2_done;
3883 req->async.private_data = state;
3887 * Postpone the break response by 500 msec
3889 static bool torture_oplock_break_delay(struct smb2_transport *transport,
3890 const struct smb2_handle *handle,
3891 uint8_t level, void *private_data)
3893 struct levelII501_state *state = talloc_get_type_abort(
3894 private_data, struct levelII501_state);
3895 const char *name;
3896 struct tevent_timer *te;
3898 break_info.handle = *handle;
3899 break_info.level = level;
3900 break_info.count++;
3902 state->break_handle = *handle;
3903 state->break_to = level;
3905 switch(level) {
3906 case SMB2_OPLOCK_LEVEL_II:
3907 name = "level II";
3908 break;
3909 case SMB2_OPLOCK_LEVEL_NONE:
3910 name = "none";
3911 break;
3912 default:
3913 name = "unknown";
3914 break;
3916 printf("Got break to %s [0x%02X] in oplock handler, postponing "
3917 "break response for 500msec\n", name, level);
3919 te = tevent_add_timer(
3920 state->tctx->ev, state->tctx,
3921 tevent_timeval_current_ofs(0, 500000),
3922 levelII501_break_timeout_cb, state);
3923 torture_assert(state->tctx, te != NULL, "tevent_add_timer failed\n");
3925 return true;
3928 static void levelII501_break_timeout_cb(struct tevent_context *ev,
3929 struct tevent_timer *te,
3930 struct timeval current_time,
3931 void *private_data)
3933 struct levelII501_state *state = talloc_get_type_abort(
3934 private_data, struct levelII501_state);
3935 struct smb2_request *req;
3937 talloc_free(te);
3939 ZERO_STRUCT(state->br);
3940 state->br.in.file.handle = state->break_handle;
3941 state->br.in.oplock_level = state->break_to;
3943 req = smb2_break_send(state->tree1, &state->br);
3944 req->async.fn = levelII501_break_done;
3945 req->async.private_data = state;
3948 static void levelII501_break_done(struct smb2_request *req)
3950 struct smb2_break io;
3951 NTSTATUS status;
3953 status = smb2_break_recv(req, &io);
3954 printf("break done: %s\n", nt_errstr(status));
3957 static void levelII501_open1_done(struct smb2_request *req)
3959 struct levelII501_state *state = talloc_get_type_abort(
3960 req->async.private_data, struct levelII501_state);
3961 struct smb2_create io;
3962 NTSTATUS status;
3964 status = smb2_create_recv(req, state, &io);
3965 printf("open1 done: %s\n", nt_errstr(status));
3968 static void levelII501_open2_done(struct smb2_request *req)
3970 struct levelII501_state *state = talloc_get_type_abort(
3971 req->async.private_data, struct levelII501_state);
3972 struct smb2_create io;
3973 NTSTATUS status;
3975 status = smb2_create_recv(req, state, &io);
3976 printf("open2 done: %s\n", nt_errstr(status));
3979 static void levelII501_timeout_cb(struct tevent_context *ev,
3980 struct tevent_timer *te,
3981 struct timeval current_time,
3982 void *private_data)
3984 struct levelII501_state *state = talloc_get_type_abort(
3985 private_data, struct levelII501_state);
3986 talloc_free(te);
3987 state->done = true;
3990 static bool test_smb2_oplock_levelII502(struct torture_context *tctx,
3991 struct smb2_tree *tree1,
3992 struct smb2_tree *tree2)
3995 const char *fname = BASEDIR "\\test_levelII502.dat";
3996 NTSTATUS status;
3997 union smb_open io;
3998 struct smb2_close closeio;
3999 struct smb2_handle h;
4001 status = torture_smb2_testdir(tree1, BASEDIR, &h);
4002 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4004 /* cleanup */
4005 smb2_util_unlink(tree1, fname);
4008 base ntcreatex parms
4010 ZERO_STRUCT(io.smb2);
4011 io.generic.level = RAW_OPEN_SMB2;
4012 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4013 io.smb2.in.alloc_size = 0;
4014 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4015 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4016 io.smb2.in.create_options = 0;
4017 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4018 io.smb2.in.security_flags = 0;
4019 io.smb2.in.fname = fname;
4021 torture_comment(
4022 tctx,
4023 "LEVELII502: Open a stale LEVEL2 oplock with OVERWRITE");
4025 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
4026 SEC_RIGHTS_FILE_WRITE;
4027 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
4028 NTCREATEX_SHARE_ACCESS_WRITE;
4029 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4030 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
4031 status = smb2_create(tree1, tctx, &(io.smb2));
4032 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
4033 torture_assert(tctx,
4034 io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_II,
4035 "Did not get LEVEL_II oplock\n");
4037 status = smbXcli_conn_samba_suicide(
4038 tree1->session->transport->conn, 93);
4039 torture_assert_ntstatus_ok(tctx, status, "suicide failed");
4041 sleep(1);
4043 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4044 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
4046 status = smb2_create(tree2, tctx, &(io.smb2));
4047 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
4048 torture_assert(tctx,
4049 io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_BATCH,
4050 "Did not get BATCH oplock\n");
4052 closeio = (struct smb2_close) {
4053 .in.file.handle = io.smb2.out.file.handle,
4055 status = smb2_close(tree2, &closeio);
4056 torture_assert_ntstatus_equal(
4057 tctx, status, NT_STATUS_OK, "close failed");
4059 return true;
4062 static bool test_oplock_statopen1_do(struct torture_context *tctx,
4063 struct smb2_tree *tree,
4064 uint32_t access_mask,
4065 bool expect_stat_open)
4067 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4068 struct smb2_create cr;
4069 struct smb2_handle h1 = {{0}};
4070 struct smb2_handle h2 = {{0}};
4071 NTSTATUS status;
4072 const char *fname = "oplock_statopen1.dat";
4073 bool ret = true;
4075 /* Open file with exclusive oplock. */
4076 cr = (struct smb2_create) {
4077 .in.desired_access = SEC_FILE_ALL,
4078 .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
4079 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
4080 .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
4081 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
4082 .in.fname = fname,
4083 .in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH,
4085 status = smb2_create(tree, mem_ctx, &cr);
4086 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4087 "smb2_create failed\n");
4088 h1 = cr.out.file.handle;
4089 CHECK_VAL(cr.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
4091 /* Stat open */
4092 cr = (struct smb2_create) {
4093 .in.desired_access = access_mask,
4094 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
4095 .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
4096 .in.create_disposition = NTCREATEX_DISP_OPEN,
4097 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
4098 .in.fname = fname,
4100 status = smb2_create(tree, mem_ctx, &cr);
4101 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4102 "smb2_create failed\n");
4103 h2 = cr.out.file.handle;
4105 if (expect_stat_open) {
4106 torture_wait_for_oplock_break(tctx);
4107 CHECK_VAL(break_info.count, 0);
4108 CHECK_VAL(break_info.level, 0);
4109 CHECK_VAL(break_info.failures, 0);
4110 if (!ret) {
4111 goto done;
4113 } else {
4114 CHECK_VAL(break_info.count, 1);
4117 done:
4118 if (!smb2_util_handle_empty(h2)) {
4119 smb2_util_close(tree, h2);
4121 if (!smb2_util_handle_empty(h1)) {
4122 smb2_util_close(tree, h1);
4124 talloc_free(mem_ctx);
4125 return ret;
4128 static bool test_smb2_oplock_statopen1(struct torture_context *tctx,
4129 struct smb2_tree *tree)
4131 const char *fname = "oplock_statopen1.dat";
4132 size_t i;
4133 bool ret = true;
4134 struct {
4135 uint32_t access_mask;
4136 bool expect_stat_open;
4137 } tests[] = {
4139 .access_mask = FILE_READ_DATA,
4140 .expect_stat_open = false,
4143 .access_mask = FILE_WRITE_DATA,
4144 .expect_stat_open = false,
4147 .access_mask = FILE_READ_EA,
4148 .expect_stat_open = false,
4151 .access_mask = FILE_WRITE_EA,
4152 .expect_stat_open = false,
4155 .access_mask = FILE_EXECUTE,
4156 .expect_stat_open = false,
4159 .access_mask = FILE_READ_ATTRIBUTES,
4160 .expect_stat_open = true,
4163 .access_mask = FILE_WRITE_ATTRIBUTES,
4164 .expect_stat_open = true,
4167 .access_mask = DELETE_ACCESS,
4168 .expect_stat_open = false,
4171 .access_mask = READ_CONTROL_ACCESS,
4172 .expect_stat_open = false,
4175 .access_mask = WRITE_DAC_ACCESS,
4176 .expect_stat_open = false,
4179 .access_mask = WRITE_OWNER_ACCESS,
4180 .expect_stat_open = false,
4183 .access_mask = SYNCHRONIZE_ACCESS,
4184 .expect_stat_open = true,
4188 tree->session->transport->oplock.handler = torture_oplock_handler;
4189 tree->session->transport->oplock.private_data = tree;
4191 for (i = 0; i < ARRAY_SIZE(tests); i++) {
4192 ZERO_STRUCT(break_info);
4194 ret = test_oplock_statopen1_do(tctx,
4195 tree,
4196 tests[i].access_mask,
4197 tests[i].expect_stat_open);
4198 if (ret == true) {
4199 continue;
4201 torture_result(tctx, TORTURE_FAIL,
4202 "test %zu: access_mask: %s, "
4203 "expect_stat_open: %s\n",
4205 get_sec_mask_str(tree, tests[i].access_mask),
4206 tests[i].expect_stat_open ? "yes" : "no");
4207 goto done;
4210 done:
4211 smb2_util_unlink(tree, fname);
4212 return ret;
4215 struct torture_suite *torture_smb2_oplocks_init(TALLOC_CTX *ctx)
4217 struct torture_suite *suite =
4218 torture_suite_create(ctx, "oplock");
4220 torture_suite_add_2smb2_test(suite, "exclusive1", test_smb2_oplock_exclusive1);
4221 torture_suite_add_2smb2_test(suite, "exclusive2", test_smb2_oplock_exclusive2);
4222 torture_suite_add_2smb2_test(suite, "exclusive3", test_smb2_oplock_exclusive3);
4223 torture_suite_add_2smb2_test(suite, "exclusive4", test_smb2_oplock_exclusive4);
4224 torture_suite_add_2smb2_test(suite, "exclusive5", test_smb2_oplock_exclusive5);
4225 torture_suite_add_2smb2_test(suite, "exclusive6", test_smb2_oplock_exclusive6);
4226 torture_suite_add_2smb2_test(suite, "exclusive9",
4227 test_smb2_oplock_exclusive9);
4228 torture_suite_add_2smb2_test(suite, "batch1", test_smb2_oplock_batch1);
4229 torture_suite_add_2smb2_test(suite, "batch2", test_smb2_oplock_batch2);
4230 torture_suite_add_2smb2_test(suite, "batch3", test_smb2_oplock_batch3);
4231 torture_suite_add_2smb2_test(suite, "batch4", test_smb2_oplock_batch4);
4232 torture_suite_add_2smb2_test(suite, "batch5", test_smb2_oplock_batch5);
4233 torture_suite_add_2smb2_test(suite, "batch6", test_smb2_oplock_batch6);
4234 torture_suite_add_2smb2_test(suite, "batch7", test_smb2_oplock_batch7);
4235 torture_suite_add_2smb2_test(suite, "batch8", test_smb2_oplock_batch8);
4236 torture_suite_add_2smb2_test(suite, "batch9", test_smb2_oplock_batch9);
4237 torture_suite_add_2smb2_test(suite, "batch9a", test_smb2_oplock_batch9a);
4238 torture_suite_add_2smb2_test(suite, "batch10", test_smb2_oplock_batch10);
4239 torture_suite_add_2smb2_test(suite, "batch11", test_smb2_oplock_batch11);
4240 torture_suite_add_2smb2_test(suite, "batch12", test_smb2_oplock_batch12);
4241 torture_suite_add_2smb2_test(suite, "batch13", test_smb2_oplock_batch13);
4242 torture_suite_add_2smb2_test(suite, "batch14", test_smb2_oplock_batch14);
4243 torture_suite_add_2smb2_test(suite, "batch15", test_smb2_oplock_batch15);
4244 torture_suite_add_2smb2_test(suite, "batch16", test_smb2_oplock_batch16);
4245 torture_suite_add_1smb2_test(suite, "batch19", test_smb2_oplock_batch19);
4246 torture_suite_add_2smb2_test(suite, "batch20", test_smb2_oplock_batch20);
4247 torture_suite_add_1smb2_test(suite, "batch21", test_smb2_oplock_batch21);
4248 torture_suite_add_1smb2_test(suite, "batch22a", test_smb2_oplock_batch22a);
4249 torture_suite_add_2smb2_test(suite, "batch22b", test_smb2_oplock_batch22b);
4250 torture_suite_add_2smb2_test(suite, "batch23", test_smb2_oplock_batch23);
4251 torture_suite_add_2smb2_test(suite, "batch24", test_smb2_oplock_batch24);
4252 torture_suite_add_1smb2_test(suite, "batch25", test_smb2_oplock_batch25);
4253 torture_suite_add_1smb2_test(suite, "batch26", test_smb2_oplock_batch26);
4254 torture_suite_add_2smb2_test(suite, "stream1", test_raw_oplock_stream1);
4255 torture_suite_add_2smb2_test(suite, "doc", test_smb2_oplock_doc);
4256 torture_suite_add_2smb2_test(suite, "brl1", test_smb2_oplock_brl1);
4257 torture_suite_add_1smb2_test(suite, "brl2", test_smb2_oplock_brl2);
4258 torture_suite_add_1smb2_test(suite, "brl3", test_smb2_oplock_brl3);
4259 torture_suite_add_1smb2_test(suite, "levelii500", test_smb2_oplock_levelII500);
4260 torture_suite_add_2smb2_test(suite, "levelii501",
4261 test_smb2_oplock_levelII501);
4262 torture_suite_add_2smb2_test(suite, "levelii502",
4263 test_smb2_oplock_levelII502);
4264 torture_suite_add_1smb2_test(suite, "statopen1", test_smb2_oplock_statopen1);
4265 suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
4267 return suite;
4271 stress testing of oplocks
4273 bool test_smb2_bench_oplock(struct torture_context *tctx,
4274 struct smb2_tree *tree)
4276 struct smb2_tree **trees;
4277 bool ret = true;
4278 NTSTATUS status;
4279 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4280 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
4281 int i, count=0;
4282 int timelimit = torture_setting_int(tctx, "timelimit", 10);
4283 union smb_open io;
4284 struct timeval tv;
4285 struct smb2_handle h;
4287 trees = talloc_array(mem_ctx, struct smb2_tree *, torture_nprocs);
4289 torture_comment(tctx, "Opening %d connections\n", torture_nprocs);
4290 for (i=0;i<torture_nprocs;i++) {
4291 if (!torture_smb2_connection(tctx, &trees[i])) {
4292 return false;
4294 talloc_steal(mem_ctx, trees[i]);
4295 trees[i]->session->transport->oplock.handler =
4296 torture_oplock_handler_close;
4297 trees[i]->session->transport->oplock.private_data = trees[i];
4300 status = torture_smb2_testdir(trees[0], BASEDIR, &h);
4301 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4303 ZERO_STRUCT(io.smb2);
4304 io.smb2.level = RAW_OPEN_SMB2;
4305 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4306 io.smb2.in.alloc_size = 0;
4307 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4308 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4309 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4310 io.smb2.in.create_options = 0;
4311 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4312 io.smb2.in.security_flags = 0;
4313 io.smb2.in.fname = BASEDIR "\\test.dat";
4314 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4315 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4317 tv = timeval_current();
4320 we open the same file with SHARE_ACCESS_NONE from all the
4321 connections in a round robin fashion. Each open causes an
4322 oplock break on the previous connection, which is answered
4323 by the oplock_handler_close() to close the file.
4325 This measures how fast we can pass on oplocks, and stresses
4326 the oplock handling code
4328 torture_comment(tctx, "Running for %d seconds\n", timelimit);
4329 while (timeval_elapsed(&tv) < timelimit) {
4330 for (i=0;i<torture_nprocs;i++) {
4331 status = smb2_create(trees[i], mem_ctx, &(io.smb2));
4332 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
4333 count++;
4336 if (torture_setting_bool(tctx, "progress", true)) {
4337 torture_comment(tctx, "%.2f ops/second\r",
4338 count/timeval_elapsed(&tv));
4342 torture_comment(tctx, "%.2f ops/second\n", count/timeval_elapsed(&tv));
4343 smb2_util_close(trees[0], io.smb2.out.file.handle);
4344 smb2_util_unlink(trees[0], BASEDIR "\\test.dat");
4345 smb2_deltree(trees[0], BASEDIR);
4346 talloc_free(mem_ctx);
4347 return ret;
4350 static struct hold_oplock_info {
4351 const char *fname;
4352 bool close_on_break;
4353 uint32_t share_access;
4354 struct smb2_handle handle;
4355 } hold_info[] = {
4357 .fname = BASEDIR "\\notshared_close",
4358 .close_on_break = true,
4359 .share_access = NTCREATEX_SHARE_ACCESS_NONE,
4362 .fname = BASEDIR "\\notshared_noclose",
4363 .close_on_break = false,
4364 .share_access = NTCREATEX_SHARE_ACCESS_NONE,
4367 .fname = BASEDIR "\\shared_close",
4368 .close_on_break = true,
4369 .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
4372 .fname = BASEDIR "\\shared_noclose",
4373 .close_on_break = false,
4374 .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
4378 static bool torture_oplock_handler_hold(struct smb2_transport *transport,
4379 const struct smb2_handle *handle,
4380 uint8_t level, void *private_data)
4382 struct hold_oplock_info *info;
4383 int i;
4385 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
4386 if (smb2_util_handle_equal(hold_info[i].handle, *handle))
4387 break;
4390 if (i == ARRAY_SIZE(hold_info)) {
4391 printf("oplock break for unknown handle 0x%llx%llx\n",
4392 (unsigned long long) handle->data[0],
4393 (unsigned long long) handle->data[1]);
4394 return false;
4397 info = &hold_info[i];
4399 if (info->close_on_break) {
4400 printf("oplock break on %s - closing\n", info->fname);
4401 torture_oplock_handler_close(transport, handle,
4402 level, private_data);
4403 return true;
4406 printf("oplock break on %s - acking break\n", info->fname);
4407 printf("Acking to none in oplock handler\n");
4409 torture_oplock_handler_ack_to_none(transport, handle,
4410 level, private_data);
4411 return true;
4415 used for manual testing of oplocks - especially interaction with
4416 other filesystems (such as NFS and local access)
4418 bool test_smb2_hold_oplock(struct torture_context *tctx,
4419 struct smb2_tree *tree)
4421 struct torture_context *mem_ctx = talloc_new(tctx);
4422 struct tevent_context *ev = tctx->ev;
4423 int i;
4424 struct smb2_handle h;
4425 NTSTATUS status;
4427 torture_comment(tctx, "Setting up open files with oplocks in %s\n",
4428 BASEDIR);
4430 status = torture_smb2_testdir(tree, BASEDIR, &h);
4431 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4433 tree->session->transport->oplock.handler = torture_oplock_handler_hold;
4434 tree->session->transport->oplock.private_data = tree;
4436 /* setup the files */
4437 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
4438 union smb_open io;
4439 char c = 1;
4441 ZERO_STRUCT(io.smb2);
4442 io.generic.level = RAW_OPEN_SMB2;
4443 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4444 io.smb2.in.alloc_size = 0;
4445 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4446 io.smb2.in.share_access = hold_info[i].share_access;
4447 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4448 io.smb2.in.create_options = 0;
4449 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4450 io.smb2.in.security_flags = 0;
4451 io.smb2.in.fname = hold_info[i].fname;
4452 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4453 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4455 torture_comment(tctx, "opening %s\n", hold_info[i].fname);
4457 status = smb2_create(tree, mem_ctx, &(io.smb2));
4458 if (!NT_STATUS_IS_OK(status)) {
4459 torture_comment(tctx, "Failed to open %s - %s\n",
4460 hold_info[i].fname, nt_errstr(status));
4461 return false;
4464 if (io.smb2.out.oplock_level != SMB2_OPLOCK_LEVEL_BATCH) {
4465 torture_comment(tctx, "Oplock not granted for %s - "
4466 "expected %d but got %d\n",
4467 hold_info[i].fname,
4468 SMB2_OPLOCK_LEVEL_BATCH,
4469 io.smb2.out.oplock_level);
4470 return false;
4472 hold_info[i].handle = io.smb2.out.file.handle;
4474 /* make the file non-zero size */
4475 status = smb2_util_write(tree, hold_info[i].handle, &c, 0, 1);
4476 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
4477 torture_comment(tctx, "Failed to write to file\n");
4478 return false;
4482 torture_comment(tctx, "Waiting for oplock events\n");
4483 tevent_loop_wait(ev);
4484 smb2_deltree(tree, BASEDIR);
4485 talloc_free(mem_ctx);
4486 return true;
4490 static bool test_smb2_kernel_oplocks1(struct torture_context *tctx,
4491 struct smb2_tree *tree)
4493 const char *fname = "test_kernel_oplock1.dat";
4494 NTSTATUS status;
4495 bool ret = true;
4496 struct smb2_create create;
4497 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4499 smb2_util_unlink(tree, fname);
4501 tree->session->transport->oplock.handler = torture_oplock_handler;
4502 tree->session->transport->oplock.private_data = tree;
4503 ZERO_STRUCT(break_info);
4505 ZERO_STRUCT(create);
4506 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4507 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4508 create.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4509 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4510 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4511 create.in.fname = fname;
4512 create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4514 status = smb2_create(tree, tctx, &create);
4515 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4516 h1 = create.out.file.handle;
4518 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4519 "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4521 ZERO_STRUCT(create);
4522 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4523 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4524 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4525 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4526 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4527 create.in.fname = fname;
4529 status = smb2_create(tree, tctx, &create);
4530 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done,
4531 "Open didn't return NT_STATUS_SHARING_VIOLATION\n");
4532 h2 = create.out.file.handle;
4534 torture_wait_for_oplock_break(tctx);
4535 if (break_info.count != 0) {
4536 torture_warning(tctx, "Open caused oplock break\n");
4539 smb2_util_close(tree, h1);
4540 smb2_util_close(tree, h2);
4542 done:
4543 if (!smb2_util_handle_empty(h1)) {
4544 smb2_util_close(tree, h1);
4546 if (!smb2_util_handle_empty(h2)) {
4547 smb2_util_close(tree, h2);
4549 smb2_util_unlink(tree, fname);
4550 return ret;
4553 static bool test_smb2_kernel_oplocks2(struct torture_context *tctx,
4554 struct smb2_tree *tree)
4556 const char *fname = "test_kernel_oplock2.dat";
4557 const char *sname = "test_kernel_oplock2.dat:foo";
4558 NTSTATUS status;
4559 bool ret = true;
4560 struct smb2_create create;
4561 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4563 smb2_util_unlink(tree, fname);
4565 tree->session->transport->oplock.handler = torture_oplock_handler;
4566 tree->session->transport->oplock.private_data = tree;
4567 ZERO_STRUCT(break_info);
4569 ZERO_STRUCT(create);
4570 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4571 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4572 create.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4573 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4574 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4575 create.in.fname = fname;
4576 create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4578 status = smb2_create(tree, tctx, &create);
4579 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4580 h1 = create.out.file.handle;
4582 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4583 "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4585 ZERO_STRUCT(create);
4586 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4587 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4588 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4589 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4590 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4591 create.in.fname = sname;
4593 status = smb2_create(tree, tctx, &create);
4594 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4595 h2 = create.out.file.handle;
4597 torture_wait_for_oplock_break(tctx);
4598 if (break_info.count != 0) {
4599 torture_warning(tctx, "Stream open caused oplock break\n");
4602 smb2_util_close(tree, h1);
4603 smb2_util_close(tree, h2);
4605 done:
4606 if (!smb2_util_handle_empty(h1)) {
4607 smb2_util_close(tree, h1);
4609 if (!smb2_util_handle_empty(h2)) {
4610 smb2_util_close(tree, h2);
4612 smb2_util_unlink(tree, fname);
4613 return ret;
4617 * 1. 1st client opens file with oplock
4618 * 2. 2nd client opens file
4620 * Verify 2 triggers an oplock break
4622 static bool test_smb2_kernel_oplocks3(struct torture_context *tctx,
4623 struct smb2_tree *tree,
4624 struct smb2_tree *tree2)
4626 const char *fname = "test_kernel_oplock3.dat";
4627 NTSTATUS status;
4628 bool ret = true;
4629 struct smb2_create create;
4630 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4632 smb2_util_unlink(tree, fname);
4633 status = torture_smb2_testfile(tree, fname, &h1);
4634 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4635 "Error creating testfile\n");
4636 smb2_util_close(tree, h1);
4637 ZERO_STRUCT(h1);
4639 tree->session->transport->oplock.handler = torture_oplock_handler;
4640 tree->session->transport->oplock.private_data = tree;
4641 ZERO_STRUCT(break_info);
4643 /* 1 */
4644 ZERO_STRUCT(create);
4645 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4646 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4647 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4648 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4649 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4650 create.in.fname = fname;
4651 create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4653 status = smb2_create(tree, tctx, &create);
4654 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4655 h1 = create.out.file.handle;
4657 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4658 "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4660 /* 2 */
4661 ZERO_STRUCT(create);
4662 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4663 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4664 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4665 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4666 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4667 create.in.fname = fname;
4669 status = smb2_create(tree2, tctx, &create);
4670 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4671 h2 = create.out.file.handle;
4673 torture_wait_for_oplock_break(tctx);
4674 torture_assert_goto(tctx, break_info.count == 1, ret, done, "Expected 1 oplock break\n");
4676 done:
4677 if (!smb2_util_handle_empty(h1)) {
4678 smb2_util_close(tree, h1);
4680 if (!smb2_util_handle_empty(h2)) {
4681 smb2_util_close(tree, h2);
4683 smb2_util_unlink(tree, fname);
4684 return ret;
4688 * 1) create testfile with stream
4689 * 2) open file r/w with batch oplock, sharing read/delete
4690 * 3) open stream on file for reading
4692 * Verify 3) doesn't trigger an oplock break
4694 static bool test_smb2_kernel_oplocks4(struct torture_context *tctx,
4695 struct smb2_tree *tree)
4697 const char *fname = "test_kernel_oplock4.dat";
4698 const char *sname = "test_kernel_oplock4.dat:foo";
4699 NTSTATUS status;
4700 bool ret = true;
4701 struct smb2_create create;
4702 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4704 tree->session->transport->oplock.handler = torture_oplock_handler;
4705 tree->session->transport->oplock.private_data = tree;
4706 ZERO_STRUCT(break_info);
4707 smb2_util_unlink(tree, fname);
4709 /* 1 */
4710 status = torture_smb2_testfile(tree, fname, &h1);
4711 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4712 "Error creating testfile\n");
4713 smb2_util_close(tree, h1);
4714 ZERO_STRUCT(h1);
4716 ZERO_STRUCT(create);
4717 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4718 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4719 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4720 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4721 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4722 create.in.fname = sname;
4724 status = smb2_create(tree, tctx, &create);
4725 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4726 h1 = create.out.file.handle;
4727 smb2_util_close(tree, h1);
4728 ZERO_STRUCT(h1);
4730 /* 2 */
4731 ZERO_STRUCT(create);
4732 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4733 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4734 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
4735 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4736 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4737 create.in.fname = fname;
4738 create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4740 status = smb2_create(tree, tctx, &create);
4741 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4742 h1 = create.out.file.handle;
4744 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_BATCH, ret, done,
4745 "Oplock level is not SMB2_OPLOCK_LEVEL_BATCH\n");
4747 ZERO_STRUCT(create);
4748 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4749 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4750 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
4751 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4752 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4753 create.in.fname = sname;
4755 status = smb2_create(tree, tctx, &create);
4756 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4757 h2 = create.out.file.handle;
4759 torture_wait_for_oplock_break(tctx);
4760 if (break_info.count != 0) {
4761 torture_warning(tctx, "Stream open caused oplock break\n");
4764 done:
4765 if (!smb2_util_handle_empty(h1)) {
4766 smb2_util_close(tree, h1);
4768 if (!smb2_util_handle_empty(h2)) {
4769 smb2_util_close(tree, h2);
4771 smb2_util_unlink(tree, fname);
4772 return ret;
4776 * 1) create testfile with stream
4777 * 2) open stream r/w with batch oplock -> batch oplock granted
4778 * 3) open stream r/o with batch oplock
4780 * Verify 3) does trigger an oplock break
4782 static bool test_smb2_kernel_oplocks5(struct torture_context *tctx,
4783 struct smb2_tree *tree)
4785 const char *fname = "test_kernel_oplock4.dat";
4786 const char *sname = "test_kernel_oplock4.dat:foo";
4787 NTSTATUS status;
4788 bool ret = true;
4789 struct smb2_create create;
4790 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4792 tree->session->transport->oplock.handler = torture_oplock_handler;
4793 tree->session->transport->oplock.private_data = tree;
4794 ZERO_STRUCT(break_info);
4795 smb2_util_unlink(tree, fname);
4797 /* 1 */
4798 status = torture_smb2_testfile(tree, fname, &h1);
4799 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4800 "Error creating testfile\n");
4801 smb2_util_close(tree, h1);
4802 ZERO_STRUCT(h1);
4804 ZERO_STRUCT(create);
4805 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4806 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4807 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4808 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4809 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4810 create.in.fname = sname;
4812 status = smb2_create(tree, tctx, &create);
4813 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4814 h1 = create.out.file.handle;
4815 smb2_util_close(tree, h1);
4816 ZERO_STRUCT(h1);
4818 /* 2 */
4819 ZERO_STRUCT(create);
4820 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4821 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4822 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4823 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4824 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4825 create.in.fname = sname;
4826 create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4828 status = smb2_create(tree, tctx, &create);
4829 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4830 h1 = create.out.file.handle;
4832 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_BATCH, ret, done,
4833 "Oplock level is not SMB2_OPLOCK_LEVEL_BATCH\n");
4835 ZERO_STRUCT(create);
4836 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4837 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4838 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4839 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4840 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4841 create.in.fname = sname;
4842 create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4844 status = smb2_create(tree, tctx, &create);
4845 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4846 h2 = create.out.file.handle;
4848 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_NONE, ret, done,
4849 "Oplock level is not SMB2_OPLOCK_LEVEL_NONE\n");
4851 torture_wait_for_oplock_break(tctx);
4852 if (break_info.count != 1) {
4853 torture_warning(tctx, "Stream open didn't cause oplock break\n");
4856 done:
4857 if (!smb2_util_handle_empty(h1)) {
4858 smb2_util_close(tree, h1);
4860 if (!smb2_util_handle_empty(h2)) {
4861 smb2_util_close(tree, h2);
4863 smb2_util_unlink(tree, fname);
4864 return ret;
4868 * 1) create testfile with stream
4869 * 2) 1st client opens stream r/w with batch oplock -> batch oplock granted
4870 * 3) 2nd client opens stream r/o with batch oplock
4872 * Verify 3) does trigger an oplock break
4874 static bool test_smb2_kernel_oplocks6(struct torture_context *tctx,
4875 struct smb2_tree *tree,
4876 struct smb2_tree *tree2)
4878 const char *fname = "test_kernel_oplock6.dat";
4879 const char *sname = "test_kernel_oplock6.dat:foo";
4880 NTSTATUS status;
4881 bool ret = true;
4882 struct smb2_create create;
4883 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4885 smb2_util_unlink(tree, fname);
4886 status = torture_smb2_testfile(tree, fname, &h1);
4887 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4888 "Error creating testfile\n");
4889 smb2_util_close(tree, h1);
4890 ZERO_STRUCT(h1);
4892 tree->session->transport->oplock.handler = torture_oplock_handler;
4893 tree->session->transport->oplock.private_data = tree;
4894 ZERO_STRUCT(break_info);
4896 /* 1 */
4897 ZERO_STRUCT(create);
4898 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4899 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4900 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4901 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4902 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4903 create.in.fname = sname;
4905 status = smb2_create(tree, tctx, &create);
4906 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4907 h1 = create.out.file.handle;
4908 smb2_util_close(tree, h1);
4909 ZERO_STRUCT(h1);
4911 /* 2 */
4912 ZERO_STRUCT(create);
4913 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4914 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4915 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4916 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4917 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4918 create.in.fname = fname;
4919 create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4921 status = smb2_create(tree, tctx, &create);
4922 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4923 h1 = create.out.file.handle;
4925 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4926 "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4928 /* 3 */
4929 ZERO_STRUCT(create);
4930 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4931 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4932 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4933 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4934 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4935 create.in.fname = fname;
4937 status = smb2_create(tree2, tctx, &create);
4938 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4939 h2 = create.out.file.handle;
4941 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_NONE, ret, done,
4942 "Oplock level is not SMB2_OPLOCK_LEVEL_NONE\n");
4944 torture_wait_for_oplock_break(tctx);
4945 torture_assert_goto(tctx, break_info.count == 1, ret, done, "Expected 1 oplock break\n");
4947 done:
4948 if (!smb2_util_handle_empty(h1)) {
4949 smb2_util_close(tree, h1);
4951 if (!smb2_util_handle_empty(h2)) {
4952 smb2_util_close(tree, h2);
4954 smb2_util_unlink(tree, fname);
4955 return ret;
4959 * Recreate regression test from bug:
4961 * https://bugzilla.samba.org/show_bug.cgi?id=13058
4963 * 1. smbd-1 opens the file and sets the oplock
4964 * 2. smbd-2 tries to open the file. open() fails(EAGAIN) and open is deferred.
4965 * 3. smbd-1 sends oplock break request to the client.
4966 * 4. smbd-1 closes the file.
4967 * 5. smbd-1 opens the file and sets the oplock.
4968 * 6. smbd-2 calls defer_open_done(), and should re-break the oplock.
4971 static bool test_smb2_kernel_oplocks7(struct torture_context *tctx,
4972 struct smb2_tree *tree,
4973 struct smb2_tree *tree2)
4975 const char *fname = "test_kernel_oplock7.dat";
4976 NTSTATUS status;
4977 bool ret = true;
4978 struct smb2_create create;
4979 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4980 struct smb2_create create_2;
4981 struct smb2_create io;
4982 struct smb2_request *req;
4984 smb2_util_unlink(tree, fname);
4985 status = torture_smb2_testfile(tree, fname, &h1);
4986 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4987 "Error creating testfile\n");
4988 smb2_util_close(tree, h1);
4989 ZERO_STRUCT(h1);
4991 /* Close the open file on break. */
4992 tree->session->transport->oplock.handler = torture_oplock_handler_close;
4993 tree->session->transport->oplock.private_data = tree;
4994 ZERO_STRUCT(break_info);
4996 /* 1 - open file with oplock */
4997 ZERO_STRUCT(create);
4998 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4999 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
5000 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
5001 create.in.create_disposition = NTCREATEX_DISP_OPEN;
5002 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
5003 create.in.fname = fname;
5004 create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
5006 status = smb2_create(tree, tctx, &create);
5007 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5008 "Error opening the file\n");
5009 CHECK_VAL(create.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
5011 /* 2 - open file to break oplock */
5012 ZERO_STRUCT(create_2);
5013 create_2.in.desired_access = SEC_RIGHTS_FILE_ALL;
5014 create_2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
5015 create_2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
5016 create_2.in.create_disposition = NTCREATEX_DISP_OPEN;
5017 create_2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
5018 create_2.in.fname = fname;
5019 create_2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
5021 /* Open on tree2 - should cause a break on tree */
5022 req = smb2_create_send(tree2, &create_2);
5023 torture_assert(tctx, req != NULL, "smb2_create_send");
5025 /* The oplock break handler should close the file. */
5026 /* Steps 3 & 4. */
5027 torture_wait_for_oplock_break(tctx);
5029 tree->session->transport->oplock.handler = torture_oplock_handler;
5032 * 5 - re-open on tree. NB. There is a race here
5033 * depending on which smbd goes first. We either get
5034 * an oplock level of SMB2_OPLOCK_LEVEL_EXCLUSIVE if
5035 * the close and re-open on tree is processed first, or
5036 * SMB2_OPLOCK_LEVEL_NONE if the pending create on
5037 * tree2 is processed first.
5039 status = smb2_create(tree, tctx, &create);
5040 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5041 "Error opening the file\n");
5043 h1 = create.out.file.handle;
5044 if (create.out.oplock_level != SMB2_OPLOCK_LEVEL_EXCLUSIVE &&
5045 create.out.oplock_level != SMB2_OPLOCK_LEVEL_NONE) {
5046 torture_result(tctx,
5047 TORTURE_FAIL,
5048 "(%s): wrong value for oplock got 0x%x\n",
5049 __location__,
5050 (unsigned int)create.out.oplock_level);
5051 ret = false;
5052 goto done;
5056 /* 6 - retrieve the second open. */
5057 status = smb2_create_recv(req, tctx, &io);
5058 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5059 "Error opening the file\n");
5060 h2 = io.out.file.handle;
5061 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
5063 done:
5064 if (!smb2_util_handle_empty(h1)) {
5065 smb2_util_close(tree, h1);
5067 if (!smb2_util_handle_empty(h2)) {
5068 smb2_util_close(tree2, h2);
5070 smb2_util_unlink(tree, fname);
5071 return ret;
5074 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
5076 #ifndef RT_SIGNAL_LEASE
5077 #define RT_SIGNAL_LEASE (SIGRTMIN+1)
5078 #endif
5080 static int got_break;
5083 * Signal handler.
5086 static void got_rt_break(int sig)
5088 got_break = 1;
5091 static int got_alarm;
5094 * Signal handler.
5097 static void got_alarm_fn(int sig)
5099 got_alarm = 1;
5103 * Child process function.
5106 static int do_child_process(int pipefd, const char *name)
5108 int ret = 0;
5109 int fd = -1;
5110 char c = 0;
5111 struct sigaction act;
5112 sigset_t set;
5113 sigset_t empty_set;
5115 /* Block RT_SIGNAL_LEASE and SIGALRM. */
5116 sigemptyset(&set);
5117 sigemptyset(&empty_set);
5118 sigaddset(&set, RT_SIGNAL_LEASE);
5119 sigaddset(&set, SIGALRM);
5120 ret = sigprocmask(SIG_SETMASK, &set, NULL);
5121 if (ret == -1) {
5122 return 11;
5125 /* Set up a signal handler for RT_SIGNAL_LEASE. */
5126 ZERO_STRUCT(act);
5127 act.sa_handler = got_rt_break;
5128 ret = sigaction(RT_SIGNAL_LEASE, &act, NULL);
5129 if (ret == -1) {
5130 return 1;
5132 /* Set up a signal handler for SIGALRM. */
5133 ZERO_STRUCT(act);
5134 act.sa_handler = got_alarm_fn;
5135 ret = sigaction(SIGALRM, &act, NULL);
5136 if (ret == -1) {
5137 return 1;
5139 /* Open the passed in file and get a kernel oplock. */
5140 fd = open(name, O_RDWR, 0666);
5141 if (fd == -1) {
5142 return 2;
5145 ret = fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE);
5146 if (ret == -1) {
5147 close(fd);
5148 return 3;
5151 ret = fcntl(fd, F_SETLEASE, F_WRLCK);
5152 if (ret == -1) {
5153 close(fd);
5154 return 4;
5157 /* Tell the parent we're ready. */
5158 ret = sys_write(pipefd, &c, 1);
5159 if (ret != 1) {
5160 close(fd);
5161 return 5;
5164 /* Ensure the pause doesn't hang forever. */
5165 alarm(5);
5167 /* Wait for RT_SIGNAL_LEASE or SIGALRM. */
5168 ret = sigsuspend(&empty_set);
5169 if (ret != -1 || errno != EINTR) {
5170 close(fd);
5171 return 6;
5174 if (got_alarm == 1) {
5175 close(fd);
5176 return 10;
5179 if (got_break != 1) {
5180 close(fd);
5181 return 7;
5184 /* Cancel any pending alarm. */
5185 alarm(0);
5187 /* Force the server to wait for 3 seconds. */
5188 sleep(3);
5190 /* Remove our lease. */
5191 ret = fcntl(fd, F_SETLEASE, F_UNLCK);
5192 if (ret == -1) {
5193 close(fd);
5194 return 8;
5197 ret = close(fd);
5198 if (ret == -1) {
5199 return 9;
5202 /* All is well. */
5203 return 0;
5206 static bool wait_for_child_oplock(struct torture_context *tctx,
5207 const char *localdir,
5208 const char *fname)
5210 int fds[2];
5211 int ret;
5212 pid_t pid;
5213 char *name = talloc_asprintf(tctx,
5214 "%s/%s",
5215 localdir,
5216 fname);
5218 torture_assert(tctx, name != NULL, "talloc failed");
5220 ret = pipe(fds);
5221 torture_assert(tctx, ret != -1, "pipe failed");
5223 pid = fork();
5224 torture_assert(tctx, pid != (pid_t)-1, "fork failed");
5226 if (pid != (pid_t)0) {
5227 char c;
5228 /* Parent. */
5229 TALLOC_FREE(name);
5230 close(fds[1]);
5231 ret = sys_read(fds[0], &c, 1);
5232 torture_assert(tctx, ret == 1, "read failed");
5233 return true;
5236 /* Child process. */
5237 close(fds[0]);
5238 ret = do_child_process(fds[1], name);
5239 _exit(ret);
5240 /* Notreached. */
5242 #else
5243 static bool wait_for_child_oplock(struct torture_context *tctx,
5244 const char *localdir,
5245 const char *fname)
5247 return false;
5249 #endif
5251 static void child_sig_term_handler(struct tevent_context *ev,
5252 struct tevent_signal *se,
5253 int signum,
5254 int count,
5255 void *siginfo,
5256 void *private_data)
5258 int *pstatus = (int *)private_data;
5259 int status = 0;
5261 wait(&status);
5262 if (WIFEXITED(status)) {
5263 *pstatus = WEXITSTATUS(status);
5264 } else {
5265 *pstatus = status;
5270 * Deal with a non-smbd process holding a kernel oplock.
5273 static bool test_smb2_kernel_oplocks8(struct torture_context *tctx,
5274 struct smb2_tree *tree)
5276 const char *fname = "test_kernel_oplock8.dat";
5277 const char *fname1 = "tmp_test_kernel_oplock8.dat";
5278 NTSTATUS status;
5279 bool ret = true;
5280 struct smb2_create io;
5281 struct smb2_request *req = NULL;
5282 struct smb2_handle h1 = {{0}};
5283 struct smb2_handle h2 = {{0}};
5284 const char *localdir = torture_setting_string(tctx, "localdir", NULL);
5285 struct tevent_signal *se = NULL;
5286 int child_exit_code = -1;
5287 time_t start;
5288 time_t end;
5290 #ifndef HAVE_KERNEL_OPLOCKS_LINUX
5291 torture_skip(tctx, "Need kernel oplocks for test");
5292 #endif
5294 if (localdir == NULL) {
5295 torture_skip(tctx, "Need localdir for test");
5298 smb2_util_unlink(tree, fname);
5299 smb2_util_unlink(tree, fname1);
5300 status = torture_smb2_testfile(tree, fname, &h1);
5301 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5302 "Error creating testfile\n");
5303 smb2_util_close(tree, h1);
5304 ZERO_STRUCT(h1);
5306 se = tevent_add_signal(tctx->ev,
5307 tctx,
5308 SIGCHLD,
5310 child_sig_term_handler,
5311 &child_exit_code);
5312 torture_assert(tctx, se != NULL, "tevent_add_signal failed\n");
5314 /* Take the oplock locally in a sub-process. */
5315 ret = wait_for_child_oplock(tctx, localdir, fname);
5316 torture_assert_goto(tctx, ret, ret, done,
5317 "Wait for child process failed.\n");
5320 * Now try and open. This should block for 3 seconds.
5321 * while the child process is still alive.
5324 ZERO_STRUCT(io);
5325 io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
5326 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
5327 io.in.create_disposition = NTCREATEX_DISP_OPEN;
5328 io.in.share_access =
5329 NTCREATEX_SHARE_ACCESS_DELETE|
5330 NTCREATEX_SHARE_ACCESS_READ|
5331 NTCREATEX_SHARE_ACCESS_WRITE;
5332 io.in.create_options = 0;
5333 io.in.fname = fname;
5335 req = smb2_create_send(tree, &io);
5336 torture_assert_goto(tctx, req != NULL,
5337 ret, done, "smb2_create_send");
5339 /* Ensure while the open is blocked the smbd is
5340 still serving other requests. */
5341 io.in.fname = fname1;
5342 io.in.create_disposition = NTCREATEX_DISP_CREATE;
5344 /* Time the start -> end of the request. */
5345 start = time(NULL);
5346 status = smb2_create(tree, tctx, &io);
5347 end = time(NULL);
5349 /* Should succeed. */
5350 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5351 "Error opening the second file\n");
5352 h1 = io.out.file.handle;
5354 /* in less than 2 seconds. Otherwise the server blocks. */
5355 torture_assert_goto(tctx, end - start < 2,
5356 ret, done, "server was blocked !");
5358 /* Pick up the return for the initial blocking open. */
5359 status = smb2_create_recv(req, tctx, &io);
5361 /* Which should also have succeeded. */
5362 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5363 "Error opening the file\n");
5364 h2 = io.out.file.handle;
5366 /* Wait for the exit code from the child. */
5367 while (child_exit_code == -1) {
5368 int rval = tevent_loop_once(tctx->ev);
5369 torture_assert_goto(tctx, rval == 0, ret,
5370 done, "tevent_loop_once error\n");
5373 torture_assert_int_equal_goto(tctx, child_exit_code, 0,
5374 ret, done, "Bad child exit code");
5376 done:
5377 if (!smb2_util_handle_empty(h1)) {
5378 smb2_util_close(tree, h1);
5380 if (!smb2_util_handle_empty(h2)) {
5381 smb2_util_close(tree, h2);
5383 smb2_util_unlink(tree, fname);
5384 smb2_util_unlink(tree, fname1);
5385 return ret;
5388 struct torture_suite *torture_smb2_kernel_oplocks_init(TALLOC_CTX *ctx)
5390 struct torture_suite *suite =
5391 torture_suite_create(ctx, "kernel-oplocks");
5393 torture_suite_add_1smb2_test(suite, "kernel_oplocks1", test_smb2_kernel_oplocks1);
5394 torture_suite_add_1smb2_test(suite, "kernel_oplocks2", test_smb2_kernel_oplocks2);
5395 torture_suite_add_2smb2_test(suite, "kernel_oplocks3", test_smb2_kernel_oplocks3);
5396 torture_suite_add_1smb2_test(suite, "kernel_oplocks4", test_smb2_kernel_oplocks4);
5397 torture_suite_add_1smb2_test(suite, "kernel_oplocks5", test_smb2_kernel_oplocks5);
5398 torture_suite_add_2smb2_test(suite, "kernel_oplocks6", test_smb2_kernel_oplocks6);
5399 torture_suite_add_2smb2_test(suite, "kernel_oplocks7", test_smb2_kernel_oplocks7);
5400 torture_suite_add_1smb2_test(suite, "kernel_oplocks8", test_smb2_kernel_oplocks8);
5402 suite->description = talloc_strdup(suite, "SMB2-KERNEL-OPLOCK tests");
5404 return suite;