s3: smbd: dfs: Move lp_msdfs_shuffle_referrals() call out of parse_msdfs_symlink().
[Samba.git] / source4 / torture / smb2 / oplock.c
blob30bbd92e7ec3f3ac215a7d84e65321dd5774f285
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/popt_common.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"
40 #include "lib/util/sys_rw.h"
42 #define CHECK_RANGE(v, min, max) do { \
43 if ((v) < (min) || (v) > (max)) { \
44 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
45 "got %d - should be between %d and %d\n", \
46 __location__, #v, (int)v, (int)min, (int)max); \
47 ret = false; \
48 }} while (0)
50 #define CHECK_STRMATCH(v, correct) do { \
51 if (!v || strstr((v),(correct)) == NULL) { \
52 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s "\
53 "got '%s' - should be '%s'\n", \
54 __location__, #v, v?v:"NULL", correct); \
55 ret = false; \
56 }} while (0)
58 #define CHECK_VAL(v, correct) do { \
59 if ((v) != (correct)) { \
60 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
61 "got 0x%x - should be 0x%x\n", \
62 __location__, #v, (int)v, (int)correct); \
63 ret = false; \
64 }} while (0)
66 #define BASEDIR "oplock_test"
68 static struct {
69 struct smb2_handle handle;
70 uint8_t level;
71 struct smb2_break br;
72 int count;
73 int failures;
74 NTSTATUS failure_status;
75 } break_info;
77 static void torture_oplock_break_callback(struct smb2_request *req)
79 NTSTATUS status;
80 struct smb2_break br;
82 ZERO_STRUCT(br);
83 status = smb2_break_recv(req, &break_info.br);
84 if (!NT_STATUS_IS_OK(status)) {
85 break_info.failures++;
86 break_info.failure_status = status;
89 return;
92 /* A general oplock break notification handler. This should be used when a
93 * test expects to break from batch or exclusive to a lower level. */
94 static bool torture_oplock_handler(struct smb2_transport *transport,
95 const struct smb2_handle *handle,
96 uint8_t level,
97 void *private_data)
99 struct smb2_tree *tree = private_data;
100 const char *name;
101 struct smb2_request *req;
102 ZERO_STRUCT(break_info.br);
104 break_info.handle = *handle;
105 break_info.level = level;
106 break_info.count++;
108 switch (level) {
109 case SMB2_OPLOCK_LEVEL_II:
110 name = "level II";
111 break;
112 case SMB2_OPLOCK_LEVEL_NONE:
113 name = "none";
114 break;
115 default:
116 name = "unknown";
117 break_info.failures++;
119 printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
121 break_info.br.in.file.handle = *handle;
122 break_info.br.in.oplock_level = level;
123 break_info.br.in.reserved = 0;
124 break_info.br.in.reserved2 = 0;
126 req = smb2_break_send(tree, &break_info.br);
127 req->async.fn = torture_oplock_break_callback;
128 req->async.private_data = NULL;
129 return true;
133 A handler function for oplock break notifications. Send a break to none
134 request.
136 static bool torture_oplock_handler_ack_to_none(struct smb2_transport *transport,
137 const struct smb2_handle *handle,
138 uint8_t level,
139 void *private_data)
141 struct smb2_tree *tree = private_data;
142 struct smb2_request *req;
144 break_info.handle = *handle;
145 break_info.level = level;
146 break_info.count++;
148 printf("Acking to none in oplock handler\n");
150 ZERO_STRUCT(break_info.br);
151 break_info.br.in.file.handle = *handle;
152 break_info.br.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
153 break_info.br.in.reserved = 0;
154 break_info.br.in.reserved2 = 0;
156 req = smb2_break_send(tree, &break_info.br);
157 req->async.fn = torture_oplock_break_callback;
158 req->async.private_data = NULL;
160 return true;
164 A handler function for oplock break notifications. Break from level II to
165 none. SMB2 requires that the client does not send an oplock break request to
166 the server in this case.
168 static bool torture_oplock_handler_level2_to_none(
169 struct smb2_transport *transport,
170 const struct smb2_handle *handle,
171 uint8_t level,
172 void *private_data)
174 break_info.handle = *handle;
175 break_info.level = level;
176 break_info.count++;
178 printf("Break from level II to none in oplock handler\n");
180 return true;
183 /* A handler function for oplock break notifications. This should be used when
184 * test expects two break notifications, first to level II, then to none. */
185 static bool torture_oplock_handler_two_notifications(
186 struct smb2_transport *transport,
187 const struct smb2_handle *handle,
188 uint8_t level,
189 void *private_data)
191 struct smb2_tree *tree = private_data;
192 const char *name;
193 struct smb2_request *req;
194 ZERO_STRUCT(break_info.br);
196 break_info.handle = *handle;
197 break_info.level = level;
198 break_info.count++;
200 switch (level) {
201 case SMB2_OPLOCK_LEVEL_II:
202 name = "level II";
203 break;
204 case SMB2_OPLOCK_LEVEL_NONE:
205 name = "none";
206 break;
207 default:
208 name = "unknown";
209 break_info.failures++;
211 printf("Breaking to %s [0x%02X] in oplock handler\n", name, level);
213 if (level == SMB2_OPLOCK_LEVEL_NONE)
214 return true;
216 break_info.br.in.file.handle = *handle;
217 break_info.br.in.oplock_level = level;
218 break_info.br.in.reserved = 0;
219 break_info.br.in.reserved2 = 0;
221 req = smb2_break_send(tree, &break_info.br);
222 req->async.fn = torture_oplock_break_callback;
223 req->async.private_data = NULL;
224 return true;
226 static void torture_oplock_handler_close_recv(struct smb2_request *req)
228 if (!smb2_request_receive(req)) {
229 printf("close failed in oplock_handler_close\n");
230 break_info.failures++;
235 a handler function for oplock break requests - close the file
237 static bool torture_oplock_handler_close(struct smb2_transport *transport,
238 const struct smb2_handle *handle,
239 uint8_t level,
240 void *private_data)
242 struct smb2_close io;
243 struct smb2_tree *tree = private_data;
244 struct smb2_request *req;
246 break_info.handle = *handle;
247 break_info.level = level;
248 break_info.count++;
250 ZERO_STRUCT(io);
251 io.in.file.handle = *handle;
252 io.in.flags = RAW_CLOSE_SMB2;
253 req = smb2_close_send(tree, &io);
254 if (req == NULL) {
255 printf("failed to send close in oplock_handler_close\n");
256 return false;
259 req->async.fn = torture_oplock_handler_close_recv;
260 req->async.private_data = NULL;
262 return true;
266 a handler function for oplock break requests. Let it timeout
268 static bool torture_oplock_handler_timeout(struct smb2_transport *transport,
269 const struct smb2_handle *handle,
270 uint8_t level,
271 void *private_data)
273 break_info.handle = *handle;
274 break_info.level = level;
275 break_info.count++;
277 printf("Let oplock break timeout\n");
278 return true;
281 static bool open_smb2_connection_no_level2_oplocks(struct torture_context *tctx,
282 struct smb2_tree **tree)
284 NTSTATUS status;
285 const char *host = torture_setting_string(tctx, "host", NULL);
286 const char *share = torture_setting_string(tctx, "share", NULL);
287 struct smbcli_options options;
289 lpcfg_smbcli_options(tctx->lp_ctx, &options);
290 options.use_level2_oplocks = false;
292 status = smb2_connect(tctx, host,
293 lpcfg_smb_ports(tctx->lp_ctx), share,
294 lpcfg_resolve_context(tctx->lp_ctx),
295 popt_get_cmdline_credentials(),
296 tree, tctx->ev, &options,
297 lpcfg_socket_options(tctx->lp_ctx),
298 lpcfg_gensec_settings(tctx, tctx->lp_ctx));
299 if (!NT_STATUS_IS_OK(status)) {
300 torture_comment(tctx, "Failed to connect to SMB2 share "
301 "\\\\%s\\%s - %s\n", host, share,
302 nt_errstr(status));
303 return false;
305 return true;
308 static bool test_smb2_oplock_exclusive1(struct torture_context *tctx,
309 struct smb2_tree *tree1,
310 struct smb2_tree *tree2)
312 const char *fname = BASEDIR "\\test_exclusive1.dat";
313 NTSTATUS status;
314 bool ret = true;
315 union smb_open io;
316 struct smb2_handle h1;
317 struct smb2_handle h;
319 status = torture_smb2_testdir(tree1, BASEDIR, &h);
320 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
322 /* cleanup */
323 smb2_util_unlink(tree1, fname);
325 tree1->session->transport->oplock.handler = torture_oplock_handler;
326 tree1->session->transport->oplock.private_data = tree1;
329 base ntcreatex parms
331 ZERO_STRUCT(io.smb2);
332 io.generic.level = RAW_OPEN_SMB2;
333 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
334 io.smb2.in.alloc_size = 0;
335 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
336 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
337 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
338 io.smb2.in.create_options = 0;
339 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
340 io.smb2.in.security_flags = 0;
341 io.smb2.in.fname = fname;
343 torture_comment(tctx, "EXCLUSIVE1: open a file with an exclusive "
344 "oplock (share mode: none)\n");
345 ZERO_STRUCT(break_info);
346 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
348 status = smb2_create(tree1, tctx, &(io.smb2));
349 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
350 h1 = io.smb2.out.file.handle;
351 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
353 torture_comment(tctx, "a 2nd open should not cause a break\n");
354 status = smb2_create(tree2, tctx, &(io.smb2));
355 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
356 "Incorrect status");
357 torture_wait_for_oplock_break(tctx);
358 CHECK_VAL(break_info.count, 0);
359 CHECK_VAL(break_info.failures, 0);
361 torture_comment(tctx, "unlink it - should also be no break\n");
362 status = smb2_util_unlink(tree2, fname);
363 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
364 "Incorrect status");
365 torture_wait_for_oplock_break(tctx);
366 CHECK_VAL(break_info.count, 0);
367 CHECK_VAL(break_info.failures, 0);
369 smb2_util_close(tree1, h1);
370 smb2_util_close(tree1, h);
372 smb2_deltree(tree1, BASEDIR);
373 return ret;
376 static bool test_smb2_oplock_exclusive2(struct torture_context *tctx,
377 struct smb2_tree *tree1,
378 struct smb2_tree *tree2)
380 const char *fname = BASEDIR "\\test_exclusive2.dat";
381 NTSTATUS status;
382 bool ret = true;
383 union smb_open io;
384 struct smb2_handle h, h1, h2;
386 status = torture_smb2_testdir(tree1, BASEDIR, &h);
387 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
389 /* cleanup */
390 smb2_util_unlink(tree1, fname);
392 tree1->session->transport->oplock.handler = torture_oplock_handler;
393 tree1->session->transport->oplock.private_data = tree1;
396 base ntcreatex parms
398 ZERO_STRUCT(io.smb2);
399 io.generic.level = RAW_OPEN_SMB2;
400 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
401 io.smb2.in.alloc_size = 0;
402 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
403 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
404 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
405 io.smb2.in.create_options = 0;
406 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
407 io.smb2.in.security_flags = 0;
408 io.smb2.in.fname = fname;
410 torture_comment(tctx, "EXCLUSIVE2: open a file with an exclusive "
411 "oplock (share mode: all)\n");
412 ZERO_STRUCT(break_info);
413 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
414 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
415 NTCREATEX_SHARE_ACCESS_WRITE|
416 NTCREATEX_SHARE_ACCESS_DELETE;
417 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
419 status = smb2_create(tree1, tctx, &(io.smb2));
420 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
421 h1 = io.smb2.out.file.handle;
422 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
424 torture_comment(tctx, "a 2nd open should cause a break to level 2\n");
425 status = smb2_create(tree2, tctx, &(io.smb2));
426 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
427 h2 = io.smb2.out.file.handle;
428 torture_wait_for_oplock_break(tctx);
429 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
430 CHECK_VAL(break_info.count, 1);
431 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
432 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
433 CHECK_VAL(break_info.failures, 0);
434 ZERO_STRUCT(break_info);
436 /* now we have 2 level II oplocks... */
437 torture_comment(tctx, "try to unlink it - should cause a break\n");
438 status = smb2_util_unlink(tree2, fname);
439 torture_assert_ntstatus_ok(tctx, status, "Error unlinking the file");
440 torture_wait_for_oplock_break(tctx);
441 CHECK_VAL(break_info.count, 0);
442 CHECK_VAL(break_info.failures, 0);
444 torture_comment(tctx, "close both handles\n");
445 smb2_util_close(tree1, h1);
446 smb2_util_close(tree1, h2);
447 smb2_util_close(tree1, h);
449 smb2_deltree(tree1, BASEDIR);
450 return ret;
453 static bool test_smb2_oplock_exclusive3(struct torture_context *tctx,
454 struct smb2_tree *tree1,
455 struct smb2_tree *tree2)
457 const char *fname = BASEDIR "\\test_exclusive3.dat";
458 NTSTATUS status;
459 bool ret = true;
460 union smb_open io;
461 union smb_setfileinfo sfi;
462 struct smb2_handle h, h1;
464 status = torture_smb2_testdir(tree1, BASEDIR, &h);
465 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
467 /* cleanup */
468 smb2_util_unlink(tree1, fname);
470 tree1->session->transport->oplock.handler = torture_oplock_handler;
471 tree1->session->transport->oplock.private_data = tree1;
474 base ntcreatex parms
476 ZERO_STRUCT(io.smb2);
477 io.generic.level = RAW_OPEN_SMB2;
478 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
479 io.smb2.in.alloc_size = 0;
480 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
481 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
482 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
483 io.smb2.in.create_options = 0;
484 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
485 io.smb2.in.security_flags = 0;
486 io.smb2.in.fname = fname;
488 torture_comment(tctx, "EXCLUSIVE3: open a file with an exclusive "
489 "oplock (share mode: none)\n");
491 ZERO_STRUCT(break_info);
492 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
493 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
495 status = smb2_create(tree1, tctx, &(io.smb2));
496 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
497 h1 = io.smb2.out.file.handle;
498 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
500 torture_comment(tctx, "setpathinfo EOF should trigger a break to "
501 "none\n");
502 ZERO_STRUCT(sfi);
503 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
504 sfi.generic.in.file.path = fname;
505 sfi.end_of_file_info.in.size = 100;
507 status = smb2_composite_setpathinfo(tree2, &sfi);
509 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
510 "Incorrect status");
511 torture_wait_for_oplock_break(tctx);
512 CHECK_VAL(break_info.count, 0);
513 CHECK_VAL(break_info.failures, 0);
514 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
516 smb2_util_close(tree1, h1);
517 smb2_util_close(tree1, h);
519 smb2_deltree(tree1, BASEDIR);
520 return ret;
523 static bool test_smb2_oplock_exclusive4(struct torture_context *tctx,
524 struct smb2_tree *tree1,
525 struct smb2_tree *tree2)
527 const char *fname = BASEDIR "\\test_exclusive4.dat";
528 NTSTATUS status;
529 bool ret = true;
530 union smb_open io;
531 struct smb2_handle h, h1, h2;
533 status = torture_smb2_testdir(tree1, BASEDIR, &h);
534 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
536 /* cleanup */
537 smb2_util_unlink(tree1, fname);
539 tree1->session->transport->oplock.handler = torture_oplock_handler;
540 tree1->session->transport->oplock.private_data = tree1;
543 base ntcreatex parms
545 ZERO_STRUCT(io.smb2);
546 io.generic.level = RAW_OPEN_SMB2;
547 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
548 io.smb2.in.alloc_size = 0;
549 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
550 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
551 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
552 io.smb2.in.create_options = 0;
553 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
554 io.smb2.in.security_flags = 0;
555 io.smb2.in.fname = fname;
557 torture_comment(tctx, "EXCLUSIVE4: open with exclusive oplock\n");
558 ZERO_STRUCT(break_info);
560 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
561 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
562 status = smb2_create(tree1, tctx, &(io.smb2));
563 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
564 h1 = io.smb2.out.file.handle;
565 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
567 ZERO_STRUCT(break_info);
568 torture_comment(tctx, "second open with attributes only shouldn't "
569 "cause oplock break\n");
571 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
572 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
573 SEC_FILE_WRITE_ATTRIBUTE |
574 SEC_STD_SYNCHRONIZE;
575 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
576 status = smb2_create(tree2, tctx, &(io.smb2));
577 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
578 h2 = io.smb2.out.file.handle;
579 CHECK_VAL(io.smb2.out.oplock_level, NO_OPLOCK_RETURN);
580 torture_wait_for_oplock_break(tctx);
581 CHECK_VAL(break_info.count, 0);
582 CHECK_VAL(break_info.failures, 0);
584 smb2_util_close(tree1, h1);
585 smb2_util_close(tree2, h2);
586 smb2_util_close(tree1, h);
588 smb2_deltree(tree1, BASEDIR);
589 return ret;
592 static bool test_smb2_oplock_exclusive5(struct torture_context *tctx,
593 struct smb2_tree *tree1,
594 struct smb2_tree *tree2)
596 const char *fname = BASEDIR "\\test_exclusive5.dat";
597 NTSTATUS status;
598 bool ret = true;
599 union smb_open io;
600 struct smb2_handle h, h1, h2;
602 status = torture_smb2_testdir(tree1, BASEDIR, &h);
603 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
605 /* cleanup */
606 smb2_util_unlink(tree1, fname);
608 tree1->session->transport->oplock.handler = torture_oplock_handler;
609 tree1->session->transport->oplock.private_data = tree1;
611 tree2->session->transport->oplock.handler = torture_oplock_handler;
612 tree2->session->transport->oplock.private_data = tree2;
615 base ntcreatex parms
617 ZERO_STRUCT(io.smb2);
618 io.generic.level = RAW_OPEN_SMB2;
619 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
620 io.smb2.in.alloc_size = 0;
621 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
622 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
623 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
624 io.smb2.in.create_options = 0;
625 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
626 io.smb2.in.security_flags = 0;
627 io.smb2.in.fname = fname;
629 torture_comment(tctx, "EXCLUSIVE5: open with exclusive oplock\n");
630 ZERO_STRUCT(break_info);
632 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
633 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
634 NTCREATEX_SHARE_ACCESS_WRITE|
635 NTCREATEX_SHARE_ACCESS_DELETE;
636 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
637 status = smb2_create(tree1, tctx, &(io.smb2));
638 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
639 h1 = io.smb2.out.file.handle;
640 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
642 ZERO_STRUCT(break_info);
644 torture_comment(tctx, "second open with attributes only and "
645 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
646 "oplock break\n");
648 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
649 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
650 SEC_FILE_WRITE_ATTRIBUTE |
651 SEC_STD_SYNCHRONIZE;
652 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
653 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
654 status = smb2_create(tree2, tctx, &(io.smb2));
655 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
656 h2 = io.smb2.out.file.handle;
657 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
658 torture_wait_for_oplock_break(tctx);
659 CHECK_VAL(break_info.count, 1);
660 CHECK_VAL(break_info.failures, 0);
662 smb2_util_close(tree1, h1);
663 smb2_util_close(tree2, h2);
664 smb2_util_close(tree1, h);
666 smb2_deltree(tree1, BASEDIR);
667 return ret;
670 static bool test_smb2_oplock_exclusive6(struct torture_context *tctx,
671 struct smb2_tree *tree1,
672 struct smb2_tree *tree2)
674 const char *fname1 = BASEDIR "\\test_exclusive6_1.dat";
675 const char *fname2 = BASEDIR "\\test_exclusive6_2.dat";
676 NTSTATUS status;
677 bool ret = true;
678 union smb_open io;
679 union smb_setfileinfo sinfo;
680 struct smb2_close closeio;
681 struct smb2_handle h, h1;
683 status = torture_smb2_testdir(tree1, BASEDIR, &h);
684 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
686 /* cleanup */
687 smb2_util_unlink(tree1, fname1);
688 smb2_util_unlink(tree2, fname2);
690 tree1->session->transport->oplock.handler = torture_oplock_handler;
691 tree1->session->transport->oplock.private_data = tree1;
694 base ntcreatex parms
696 ZERO_STRUCT(io.smb2);
697 io.generic.level = RAW_OPEN_SMB2;
698 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
699 io.smb2.in.alloc_size = 0;
700 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
701 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
702 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
703 io.smb2.in.create_options = 0;
704 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
705 io.smb2.in.security_flags = 0;
706 io.smb2.in.fname = fname1;
708 torture_comment(tctx, "EXCLUSIVE6: open a file with an exclusive "
709 "oplock (share mode: none)\n");
710 ZERO_STRUCT(break_info);
711 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
712 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
714 status = smb2_create(tree1, tctx, &(io.smb2));
715 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
716 h1 = io.smb2.out.file.handle;
717 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
719 torture_comment(tctx, "rename with the parent directory handle open "
720 "for DELETE should not generate a break but get "
721 "a sharing violation\n");
722 ZERO_STRUCT(sinfo);
723 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
724 sinfo.rename_information.in.file.handle = h1;
725 sinfo.rename_information.in.overwrite = true;
726 sinfo.rename_information.in.new_name = fname2;
727 status = smb2_setinfo_file(tree1, &sinfo);
729 torture_comment(tctx, "trying rename while parent handle open for delete.\n");
730 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
731 "Incorrect status");
732 torture_wait_for_oplock_break(tctx);
733 CHECK_VAL(break_info.count, 0);
734 CHECK_VAL(break_info.failures, 0);
736 /* Close the parent directory handle. */
737 ZERO_STRUCT(closeio);
738 closeio.in.file.handle = h;
739 status = smb2_close(tree1, &closeio);
740 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
741 "Incorrect status");
743 /* Re-open without DELETE access. */
744 ZERO_STRUCT(io);
745 io.smb2.in.oplock_level = 0;
746 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL & (~SEC_STD_DELETE);
747 io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
748 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
749 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
750 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
751 io.smb2.in.fname = BASEDIR;
753 status = smb2_create(tree1, tctx, &(io.smb2));
754 torture_assert_ntstatus_ok(tctx, status, "Error opening the base directory");
756 torture_comment(tctx, "rename with the parent directory handle open "
757 "without DELETE should succeed without a break\n");
758 ZERO_STRUCT(sinfo);
759 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
760 sinfo.rename_information.in.file.handle = h1;
761 sinfo.rename_information.in.overwrite = true;
762 sinfo.rename_information.in.new_name = fname2;
763 status = smb2_setinfo_file(tree1, &sinfo);
765 torture_comment(tctx, "trying rename while parent handle open without delete\n");
766 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
767 "Incorrect status");
768 torture_wait_for_oplock_break(tctx);
769 CHECK_VAL(break_info.count, 0);
770 CHECK_VAL(break_info.failures, 0);
772 smb2_util_close(tree1, h1);
773 smb2_util_close(tree1, h);
775 smb2_deltree(tree1, BASEDIR);
776 return ret;
779 static bool test_smb2_oplock_exclusive9(struct torture_context *tctx,
780 struct smb2_tree *tree1,
781 struct smb2_tree *tree2)
783 const char *fname = BASEDIR "\\test_exclusive9.dat";
784 NTSTATUS status;
785 bool ret = true;
786 union smb_open io;
787 struct smb2_handle h1, h2;
788 int i;
790 struct {
791 uint32_t create_disposition;
792 uint32_t break_level;
793 } levels[] = {
794 { NTCREATEX_DISP_SUPERSEDE, SMB2_OPLOCK_LEVEL_NONE },
795 { NTCREATEX_DISP_OPEN, SMB2_OPLOCK_LEVEL_II },
796 { NTCREATEX_DISP_OVERWRITE_IF, SMB2_OPLOCK_LEVEL_NONE },
797 { NTCREATEX_DISP_OPEN_IF, SMB2_OPLOCK_LEVEL_II },
801 status = torture_smb2_testdir(tree1, BASEDIR, &h1);
802 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
803 smb2_util_close(tree1, h1);
805 /* cleanup */
806 smb2_util_unlink(tree1, fname);
808 tree1->session->transport->oplock.handler = torture_oplock_handler;
809 tree1->session->transport->oplock.private_data = tree1;
812 base ntcreatex parms
814 ZERO_STRUCT(io.smb2);
815 io.generic.level = RAW_OPEN_SMB2;
816 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
817 io.smb2.in.alloc_size = 0;
818 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
819 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
820 NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
821 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
822 io.smb2.in.create_options = 0;
823 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
824 io.smb2.in.security_flags = 0;
825 io.smb2.in.fname = fname;
827 for (i=0; i<ARRAY_SIZE(levels); i++) {
829 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
830 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
832 status = smb2_create(tree1, tctx, &(io.smb2));
833 torture_assert_ntstatus_ok(tctx, status,
834 "Error opening the file");
835 h1 = io.smb2.out.file.handle;
836 CHECK_VAL(io.smb2.out.oplock_level,
837 SMB2_OPLOCK_LEVEL_EXCLUSIVE);
839 ZERO_STRUCT(break_info);
841 io.smb2.in.create_disposition = levels[i].create_disposition;
842 status = smb2_create(tree2, tctx, &(io.smb2));
843 torture_assert_ntstatus_ok(tctx, status,
844 "Error opening the file");
845 h2 = io.smb2.out.file.handle;
846 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
848 CHECK_VAL(break_info.count, 1);
849 CHECK_VAL(break_info.level, levels[i].break_level);
850 CHECK_VAL(break_info.failures, 0);
852 smb2_util_close(tree2, h2);
853 smb2_util_close(tree1, h1);
856 smb2_deltree(tree1, BASEDIR);
857 return ret;
860 static bool test_smb2_oplock_batch1(struct torture_context *tctx,
861 struct smb2_tree *tree1,
862 struct smb2_tree *tree2)
864 const char *fname = BASEDIR "\\test_batch1.dat";
865 NTSTATUS status;
866 bool ret = true;
867 union smb_open io;
868 struct smb2_handle h, h1;
869 char c = 0;
871 status = torture_smb2_testdir(tree1, BASEDIR, &h);
872 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
874 /* cleanup */
875 smb2_util_unlink(tree1, fname);
877 tree1->session->transport->oplock.handler = torture_oplock_handler;
878 tree1->session->transport->oplock.private_data = tree1;
881 base ntcreatex parms
883 ZERO_STRUCT(io.smb2);
884 io.generic.level = RAW_OPEN_SMB2;
885 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
886 io.smb2.in.alloc_size = 0;
887 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
888 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
889 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
890 io.smb2.in.create_options = 0;
891 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
892 io.smb2.in.security_flags = 0;
893 io.smb2.in.fname = fname;
896 with a batch oplock we get a break
898 torture_comment(tctx, "BATCH1: open with batch oplock\n");
899 ZERO_STRUCT(break_info);
900 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
901 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
902 status = smb2_create(tree1, tctx, &(io.smb2));
903 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
904 h1 = io.smb2.out.file.handle;
905 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
907 torture_comment(tctx, "unlink should generate a break\n");
908 status = smb2_util_unlink(tree2, fname);
909 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
910 "Incorrect status");
912 torture_wait_for_oplock_break(tctx);
913 CHECK_VAL(break_info.count, 1);
914 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
915 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
916 CHECK_VAL(break_info.failures, 0);
918 torture_comment(tctx, "2nd unlink should not generate a break\n");
919 ZERO_STRUCT(break_info);
920 status = smb2_util_unlink(tree2, fname);
921 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
922 "Incorrect status");
924 torture_wait_for_oplock_break(tctx);
925 CHECK_VAL(break_info.count, 0);
927 torture_comment(tctx, "writing should generate a self break to none\n");
928 tree1->session->transport->oplock.handler =
929 torture_oplock_handler_level2_to_none;
930 smb2_util_write(tree1, h1, &c, 0, 1);
932 torture_wait_for_oplock_break(tctx);
934 CHECK_VAL(break_info.count, 1);
935 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
936 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
937 CHECK_VAL(break_info.failures, 0);
939 smb2_util_close(tree1, h1);
940 smb2_util_close(tree1, h);
942 smb2_deltree(tree1, BASEDIR);
943 return ret;
946 static bool test_smb2_oplock_batch2(struct torture_context *tctx,
947 struct smb2_tree *tree1,
948 struct smb2_tree *tree2)
950 const char *fname = BASEDIR "\\test_batch2.dat";
951 NTSTATUS status;
952 bool ret = true;
953 union smb_open io;
954 char c = 0;
955 struct smb2_handle h, h1;
957 status = torture_smb2_testdir(tree1, BASEDIR, &h);
958 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
960 /* cleanup */
961 smb2_util_unlink(tree1, fname);
963 tree1->session->transport->oplock.handler = torture_oplock_handler;
964 tree1->session->transport->oplock.private_data = tree1;
967 base ntcreatex parms
969 ZERO_STRUCT(io.smb2);
970 io.generic.level = RAW_OPEN_SMB2;
971 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
972 io.smb2.in.alloc_size = 0;
973 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
974 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
975 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
976 io.smb2.in.create_options = 0;
977 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
978 io.smb2.in.security_flags = 0;
979 io.smb2.in.fname = fname;
981 torture_comment(tctx, "BATCH2: open with batch oplock\n");
982 ZERO_STRUCT(break_info);
983 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
984 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
985 status = smb2_create(tree1, tctx, &(io.smb2));
986 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
987 h1 = io.smb2.out.file.handle;
988 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
990 torture_comment(tctx, "unlink should generate a break, which we ack "
991 "as break to none\n");
992 tree1->session->transport->oplock.handler =
993 torture_oplock_handler_ack_to_none;
994 tree1->session->transport->oplock.private_data = tree1;
995 status = smb2_util_unlink(tree2, fname);
996 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
997 "Incorrect status");
999 torture_wait_for_oplock_break(tctx);
1000 CHECK_VAL(break_info.count, 1);
1001 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1002 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1003 CHECK_VAL(break_info.failures, 0);
1005 torture_comment(tctx, "2nd unlink should not generate a break\n");
1006 ZERO_STRUCT(break_info);
1007 status = smb2_util_unlink(tree2, fname);
1008 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1009 "Incorrect status");
1011 torture_wait_for_oplock_break(tctx);
1012 CHECK_VAL(break_info.count, 0);
1014 torture_comment(tctx, "writing should not generate a break\n");
1015 smb2_util_write(tree1, h1, &c, 0, 1);
1017 torture_wait_for_oplock_break(tctx);
1018 CHECK_VAL(break_info.count, 0);
1020 smb2_util_close(tree1, h1);
1021 smb2_util_close(tree1, h);
1023 smb2_deltree(tree1, BASEDIR);
1024 return ret;
1027 static bool test_smb2_oplock_batch3(struct torture_context *tctx,
1028 struct smb2_tree *tree1,
1029 struct smb2_tree *tree2)
1031 const char *fname = BASEDIR "\\test_batch3.dat";
1032 NTSTATUS status;
1033 bool ret = true;
1034 union smb_open io;
1035 struct smb2_handle h, h1;
1037 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1038 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1040 /* cleanup */
1041 smb2_util_unlink(tree1, fname);
1042 tree1->session->transport->oplock.handler = torture_oplock_handler;
1043 tree1->session->transport->oplock.private_data = tree1;
1046 base ntcreatex parms
1048 ZERO_STRUCT(io.smb2);
1049 io.generic.level = RAW_OPEN_SMB2;
1050 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1051 io.smb2.in.alloc_size = 0;
1052 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1053 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1054 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1055 io.smb2.in.create_options = 0;
1056 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1057 io.smb2.in.security_flags = 0;
1058 io.smb2.in.fname = fname;
1060 torture_comment(tctx, "BATCH3: if we close on break then the unlink "
1061 "can succeed\n");
1062 ZERO_STRUCT(break_info);
1063 tree1->session->transport->oplock.handler =
1064 torture_oplock_handler_close;
1065 tree1->session->transport->oplock.private_data = tree1;
1067 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1068 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1069 status = smb2_create(tree1, tctx, &(io.smb2));
1070 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1071 h1 = io.smb2.out.file.handle;
1072 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1074 ZERO_STRUCT(break_info);
1075 status = smb2_util_unlink(tree2, fname);
1076 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1078 torture_wait_for_oplock_break(tctx);
1079 CHECK_VAL(break_info.count, 1);
1080 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1081 CHECK_VAL(break_info.level, 1);
1082 CHECK_VAL(break_info.failures, 0);
1084 smb2_util_close(tree1, h1);
1085 smb2_util_close(tree1, h);
1087 smb2_deltree(tree1, BASEDIR);
1088 return ret;
1091 static bool test_smb2_oplock_batch4(struct torture_context *tctx,
1092 struct smb2_tree *tree1,
1093 struct smb2_tree *tree2)
1095 const char *fname = BASEDIR "\\test_batch4.dat";
1096 NTSTATUS status;
1097 bool ret = true;
1098 union smb_open io;
1099 struct smb2_read r;
1100 struct smb2_handle h, h1;
1102 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1103 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1105 /* cleanup */
1106 smb2_util_unlink(tree1, fname);
1108 tree1->session->transport->oplock.handler = torture_oplock_handler;
1109 tree1->session->transport->oplock.private_data = tree1;
1112 base ntcreatex parms
1114 ZERO_STRUCT(io.smb2);
1115 io.generic.level = RAW_OPEN_SMB2;
1116 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1117 io.smb2.in.alloc_size = 0;
1118 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1119 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1120 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1121 io.smb2.in.create_options = 0;
1122 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1123 io.smb2.in.security_flags = 0;
1124 io.smb2.in.fname = fname;
1126 torture_comment(tctx, "BATCH4: a self read should not cause a break\n");
1127 ZERO_STRUCT(break_info);
1129 tree1->session->transport->oplock.handler = torture_oplock_handler;
1130 tree1->session->transport->oplock.private_data = tree1;
1132 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1133 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1134 status = smb2_create(tree1, tctx, &(io.smb2));
1135 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1136 h1 = io.smb2.out.file.handle;
1137 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1139 ZERO_STRUCT(r);
1140 r.in.file.handle = h1;
1141 r.in.offset = 0;
1143 status = smb2_read(tree1, tree1, &r);
1144 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1145 torture_wait_for_oplock_break(tctx);
1146 CHECK_VAL(break_info.count, 0);
1147 CHECK_VAL(break_info.failures, 0);
1149 smb2_util_close(tree1, h1);
1150 smb2_util_close(tree1, h);
1152 smb2_deltree(tree1, BASEDIR);
1153 return ret;
1156 static bool test_smb2_oplock_batch5(struct torture_context *tctx,
1157 struct smb2_tree *tree1,
1158 struct smb2_tree *tree2)
1160 const char *fname = BASEDIR "\\test_batch5.dat";
1161 NTSTATUS status;
1162 bool ret = true;
1163 union smb_open io;
1164 struct smb2_handle h, h1;
1166 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1167 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1169 /* cleanup */
1170 smb2_util_unlink(tree1, fname);
1172 tree1->session->transport->oplock.handler = torture_oplock_handler;
1173 tree1->session->transport->oplock.private_data = tree1;
1176 base ntcreatex parms
1178 ZERO_STRUCT(io.smb2);
1179 io.generic.level = RAW_OPEN_SMB2;
1180 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1181 io.smb2.in.alloc_size = 0;
1182 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1183 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1184 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1185 io.smb2.in.create_options = 0;
1186 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1187 io.smb2.in.security_flags = 0;
1188 io.smb2.in.fname = fname;
1190 torture_comment(tctx, "BATCH5: a 2nd open should give a break\n");
1191 ZERO_STRUCT(break_info);
1193 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1194 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1195 status = smb2_create(tree1, tctx, &(io.smb2));
1196 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1197 h1 = io.smb2.out.file.handle;
1198 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1200 ZERO_STRUCT(break_info);
1202 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1203 status = smb2_create(tree2, tctx, &(io.smb2));
1204 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1205 "Incorrect status");
1207 torture_wait_for_oplock_break(tctx);
1208 CHECK_VAL(break_info.count, 1);
1209 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1210 CHECK_VAL(break_info.level, 1);
1211 CHECK_VAL(break_info.failures, 0);
1213 smb2_util_close(tree1, h1);
1214 smb2_util_close(tree1, h);
1216 smb2_deltree(tree1, BASEDIR);
1217 return ret;
1220 static bool test_smb2_oplock_batch6(struct torture_context *tctx,
1221 struct smb2_tree *tree1,
1222 struct smb2_tree *tree2)
1224 const char *fname = BASEDIR "\\test_batch6.dat";
1225 NTSTATUS status;
1226 bool ret = true;
1227 union smb_open io;
1228 struct smb2_handle h, h1, h2;
1229 char c = 0;
1231 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1232 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1234 /* cleanup */
1235 smb2_util_unlink(tree1, fname);
1237 tree1->session->transport->oplock.handler = torture_oplock_handler;
1238 tree1->session->transport->oplock.private_data = tree1;
1241 base ntcreatex parms
1243 ZERO_STRUCT(io.smb2);
1244 io.generic.level = RAW_OPEN_SMB2;
1245 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1246 io.smb2.in.alloc_size = 0;
1247 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1248 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1249 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1250 io.smb2.in.create_options = 0;
1251 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1252 io.smb2.in.security_flags = 0;
1253 io.smb2.in.fname = fname;
1255 torture_comment(tctx, "BATCH6: a 2nd open should give a break to "
1256 "level II if the first open allowed shared read\n");
1257 ZERO_STRUCT(break_info);
1258 tree2->session->transport->oplock.handler = torture_oplock_handler;
1259 tree2->session->transport->oplock.private_data = tree2;
1261 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
1262 SEC_RIGHTS_FILE_WRITE;
1263 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1264 NTCREATEX_SHARE_ACCESS_WRITE;
1265 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1266 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1267 status = smb2_create(tree1, tctx, &(io.smb2));
1268 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1269 h1 = io.smb2.out.file.handle;
1270 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1272 ZERO_STRUCT(break_info);
1274 status = smb2_create(tree2, tctx, &(io.smb2));
1275 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1276 h2 = io.smb2.out.file.handle;
1277 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1279 torture_wait_for_oplock_break(tctx);
1280 CHECK_VAL(break_info.count, 1);
1281 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1282 CHECK_VAL(break_info.level, 1);
1283 CHECK_VAL(break_info.failures, 0);
1284 ZERO_STRUCT(break_info);
1286 torture_comment(tctx, "write should trigger a break to none on both\n");
1287 tree1->session->transport->oplock.handler =
1288 torture_oplock_handler_level2_to_none;
1289 tree2->session->transport->oplock.handler =
1290 torture_oplock_handler_level2_to_none;
1291 smb2_util_write(tree1, h1, &c, 0, 1);
1293 /* We expect two breaks */
1294 torture_wait_for_oplock_break(tctx);
1295 torture_wait_for_oplock_break(tctx);
1297 CHECK_VAL(break_info.count, 2);
1298 CHECK_VAL(break_info.level, 0);
1299 CHECK_VAL(break_info.failures, 0);
1301 smb2_util_close(tree1, h1);
1302 smb2_util_close(tree2, h2);
1303 smb2_util_close(tree1, h);
1305 smb2_deltree(tree1, BASEDIR);
1306 return ret;
1309 static bool test_smb2_oplock_batch7(struct torture_context *tctx,
1310 struct smb2_tree *tree1,
1311 struct smb2_tree *tree2)
1313 const char *fname = BASEDIR "\\test_batch7.dat";
1314 NTSTATUS status;
1315 bool ret = true;
1316 union smb_open io;
1317 struct smb2_handle h, h1, h2;
1319 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1320 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1322 /* cleanup */
1323 smb2_util_unlink(tree1, fname);
1325 tree1->session->transport->oplock.handler = torture_oplock_handler;
1326 tree1->session->transport->oplock.private_data = tree1;
1329 base ntcreatex parms
1331 ZERO_STRUCT(io.smb2);
1332 io.generic.level = RAW_OPEN_SMB2;
1333 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1334 io.smb2.in.alloc_size = 0;
1335 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1336 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1337 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1338 io.smb2.in.create_options = 0;
1339 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1340 io.smb2.in.security_flags = 0;
1341 io.smb2.in.fname = fname;
1343 torture_comment(tctx, "BATCH7: a 2nd open should get an oplock when "
1344 "we close instead of ack\n");
1345 ZERO_STRUCT(break_info);
1346 tree1->session->transport->oplock.handler =
1347 torture_oplock_handler_close;
1348 tree1->session->transport->oplock.private_data = tree1;
1350 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1351 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1352 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1353 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1354 status = smb2_create(tree1, tctx, &(io.smb2));
1355 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1356 h2 = io.smb2.out.file.handle;
1357 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1359 ZERO_STRUCT(break_info);
1361 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1362 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1363 status = smb2_create(tree2, tctx, &(io.smb2));
1364 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1365 h1 = io.smb2.out.file.handle;
1366 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1368 torture_wait_for_oplock_break(tctx);
1369 CHECK_VAL(break_info.count, 1);
1370 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1371 CHECK_VAL(break_info.level, 1);
1372 CHECK_VAL(break_info.failures, 0);
1374 smb2_util_close(tree2, h1);
1375 smb2_util_close(tree2, h);
1377 smb2_deltree(tree1, BASEDIR);
1378 return ret;
1381 static bool test_smb2_oplock_batch8(struct torture_context *tctx,
1382 struct smb2_tree *tree1,
1383 struct smb2_tree *tree2)
1385 const char *fname = BASEDIR "\\test_batch8.dat";
1386 NTSTATUS status;
1387 bool ret = true;
1388 union smb_open io;
1389 struct smb2_handle h, h1, h2;
1391 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1392 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1394 /* cleanup */
1395 smb2_util_unlink(tree1, fname);
1397 tree1->session->transport->oplock.handler = torture_oplock_handler;
1398 tree1->session->transport->oplock.private_data = tree1;
1401 base ntcreatex parms
1403 ZERO_STRUCT(io.smb2);
1404 io.generic.level = RAW_OPEN_SMB2;
1405 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1406 io.smb2.in.alloc_size = 0;
1407 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1408 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1409 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1410 io.smb2.in.create_options = 0;
1411 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1412 io.smb2.in.security_flags = 0;
1413 io.smb2.in.fname = fname;
1415 torture_comment(tctx, "BATCH8: open with batch oplock\n");
1416 ZERO_STRUCT(break_info);
1418 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1419 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1420 status = smb2_create(tree1, tctx, &(io.smb2));
1421 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1422 h1 = io.smb2.out.file.handle;
1423 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1425 ZERO_STRUCT(break_info);
1426 torture_comment(tctx, "second open with attributes only shouldn't "
1427 "cause oplock break\n");
1429 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1430 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1431 SEC_FILE_WRITE_ATTRIBUTE |
1432 SEC_STD_SYNCHRONIZE;
1433 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1434 status = smb2_create(tree2, tctx, &(io.smb2));
1435 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1436 h2 = io.smb2.out.file.handle;
1437 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1438 torture_wait_for_oplock_break(tctx);
1439 CHECK_VAL(break_info.count, 0);
1440 CHECK_VAL(break_info.failures, 0);
1442 smb2_util_close(tree1, h1);
1443 smb2_util_close(tree2, h2);
1444 smb2_util_close(tree1, h);
1446 smb2_deltree(tree1, BASEDIR);
1447 return ret;
1450 static bool test_smb2_oplock_batch9(struct torture_context *tctx,
1451 struct smb2_tree *tree1,
1452 struct smb2_tree *tree2)
1454 const char *fname = BASEDIR "\\test_batch9.dat";
1455 NTSTATUS status;
1456 bool ret = true;
1457 union smb_open io;
1458 struct smb2_handle h, h1, h2;
1459 char c = 0;
1461 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1462 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1464 /* cleanup */
1465 smb2_util_unlink(tree1, fname);
1467 tree1->session->transport->oplock.handler = torture_oplock_handler;
1468 tree1->session->transport->oplock.private_data = tree1;
1471 base ntcreatex parms
1473 ZERO_STRUCT(io.smb2);
1474 io.generic.level = RAW_OPEN_SMB2;
1475 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1476 io.smb2.in.alloc_size = 0;
1477 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1478 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1479 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1480 io.smb2.in.create_options = 0;
1481 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1482 io.smb2.in.security_flags = 0;
1483 io.smb2.in.fname = fname;
1485 torture_comment(tctx, "BATCH9: open with attributes only can create "
1486 "file\n");
1488 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1489 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1490 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1491 SEC_FILE_WRITE_ATTRIBUTE |
1492 SEC_STD_SYNCHRONIZE;
1493 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1494 status = smb2_create(tree1, tctx, &(io.smb2));
1495 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1496 h1 = io.smb2.out.file.handle;
1497 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1499 torture_comment(tctx, "Subsequent normal open should break oplock on "
1500 "attribute only open to level II\n");
1502 ZERO_STRUCT(break_info);
1504 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1505 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1506 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1507 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1508 status = smb2_create(tree2, tctx, &(io.smb2));
1509 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1510 h2 = io.smb2.out.file.handle;
1511 torture_wait_for_oplock_break(tctx);
1512 CHECK_VAL(break_info.count, 1);
1513 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1514 CHECK_VAL(break_info.failures, 0);
1515 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1516 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1517 smb2_util_close(tree2, h2);
1519 torture_comment(tctx, "third oplocked open should grant level2 without "
1520 "break\n");
1521 ZERO_STRUCT(break_info);
1523 tree2->session->transport->oplock.handler = torture_oplock_handler;
1524 tree2->session->transport->oplock.private_data = tree2;
1526 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1527 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1528 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1529 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1530 status = smb2_create(tree2, tctx, &(io.smb2));
1531 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1532 h2 = io.smb2.out.file.handle;
1533 torture_wait_for_oplock_break(tctx);
1534 CHECK_VAL(break_info.count, 0);
1535 CHECK_VAL(break_info.failures, 0);
1536 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1538 ZERO_STRUCT(break_info);
1540 torture_comment(tctx, "write should trigger a break to none on both\n");
1541 tree1->session->transport->oplock.handler =
1542 torture_oplock_handler_level2_to_none;
1543 tree2->session->transport->oplock.handler =
1544 torture_oplock_handler_level2_to_none;
1545 smb2_util_write(tree2, h2, &c, 0, 1);
1547 /* We expect two breaks */
1548 torture_wait_for_oplock_break(tctx);
1549 torture_wait_for_oplock_break(tctx);
1551 CHECK_VAL(break_info.count, 2);
1552 CHECK_VAL(break_info.level, 0);
1553 CHECK_VAL(break_info.failures, 0);
1555 smb2_util_close(tree1, h1);
1556 smb2_util_close(tree2, h2);
1557 smb2_util_close(tree1, h);
1559 smb2_deltree(tree1, BASEDIR);
1560 return ret;
1563 static bool test_smb2_oplock_batch9a(struct torture_context *tctx,
1564 struct smb2_tree *tree1,
1565 struct smb2_tree *tree2)
1567 const char *fname = BASEDIR "\\test_batch9a.dat";
1568 NTSTATUS status;
1569 bool ret = true;
1570 union smb_open io;
1571 struct smb2_handle h, h1, h2, h3;
1572 char c = 0;
1574 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1575 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1577 /* cleanup */
1578 smb2_util_unlink(tree1, fname);
1580 tree1->session->transport->oplock.handler = torture_oplock_handler;
1581 tree1->session->transport->oplock.private_data = tree1;
1584 base ntcreatex parms
1586 ZERO_STRUCT(io.smb2);
1587 io.generic.level = RAW_OPEN_SMB2;
1588 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1589 io.smb2.in.alloc_size = 0;
1590 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1591 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1592 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1593 io.smb2.in.create_options = 0;
1594 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1595 io.smb2.in.security_flags = 0;
1596 io.smb2.in.fname = fname;
1598 torture_comment(tctx, "BATCH9: open with attributes only can create "
1599 "file\n");
1601 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1602 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1603 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1604 SEC_FILE_WRITE_ATTRIBUTE |
1605 SEC_STD_SYNCHRONIZE;
1606 status = smb2_create(tree1, tctx, &(io.smb2));
1607 torture_assert_ntstatus_ok(tctx, status, "Error creating the file");
1608 h1 = io.smb2.out.file.handle;
1609 CHECK_VAL(io.smb2.out.create_action, FILE_WAS_CREATED);
1610 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1612 torture_comment(tctx, "Subsequent attributes open should not break\n");
1614 ZERO_STRUCT(break_info);
1616 status = smb2_create(tree2, tctx, &(io.smb2));
1617 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1618 h3 = io.smb2.out.file.handle;
1619 torture_wait_for_oplock_break(tctx);
1620 CHECK_VAL(break_info.count, 0);
1621 CHECK_VAL(io.smb2.out.create_action, FILE_WAS_OPENED);
1622 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1623 smb2_util_close(tree2, h3);
1625 torture_comment(tctx, "Subsequent normal open should break oplock on "
1626 "attribute only open to level II\n");
1628 ZERO_STRUCT(break_info);
1630 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1631 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1632 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1633 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1634 status = smb2_create(tree2, tctx, &(io.smb2));
1635 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1636 h2 = io.smb2.out.file.handle;
1637 torture_wait_for_oplock_break(tctx);
1638 CHECK_VAL(break_info.count, 1);
1639 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1640 CHECK_VAL(break_info.failures, 0);
1641 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1642 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1643 smb2_util_close(tree2, h2);
1645 torture_comment(tctx, "third oplocked open should grant level2 without "
1646 "break\n");
1647 ZERO_STRUCT(break_info);
1649 tree2->session->transport->oplock.handler = torture_oplock_handler;
1650 tree2->session->transport->oplock.private_data = tree2;
1652 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1653 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1654 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1655 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1656 status = smb2_create(tree2, tctx, &(io.smb2));
1657 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1658 h2 = io.smb2.out.file.handle;
1659 torture_wait_for_oplock_break(tctx);
1660 CHECK_VAL(break_info.count, 0);
1661 CHECK_VAL(break_info.failures, 0);
1662 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1664 ZERO_STRUCT(break_info);
1666 torture_comment(tctx, "write should trigger a break to none on both\n");
1667 tree1->session->transport->oplock.handler =
1668 torture_oplock_handler_level2_to_none;
1669 tree2->session->transport->oplock.handler =
1670 torture_oplock_handler_level2_to_none;
1671 smb2_util_write(tree2, h2, &c, 0, 1);
1673 /* We expect two breaks */
1674 torture_wait_for_oplock_break(tctx);
1675 torture_wait_for_oplock_break(tctx);
1677 CHECK_VAL(break_info.count, 2);
1678 CHECK_VAL(break_info.level, 0);
1679 CHECK_VAL(break_info.failures, 0);
1681 smb2_util_close(tree1, h1);
1682 smb2_util_close(tree2, h2);
1683 smb2_util_close(tree1, h);
1685 smb2_deltree(tree1, BASEDIR);
1686 return ret;
1690 static bool test_smb2_oplock_batch10(struct torture_context *tctx,
1691 struct smb2_tree *tree1,
1692 struct smb2_tree *tree2)
1694 const char *fname = BASEDIR "\\test_batch10.dat";
1695 NTSTATUS status;
1696 bool ret = true;
1697 union smb_open io;
1698 struct smb2_handle h, h1, h2;
1700 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1701 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1703 /* cleanup */
1704 smb2_util_unlink(tree1, fname);
1706 tree1->session->transport->oplock.handler = torture_oplock_handler;
1707 tree1->session->transport->oplock.private_data = tree1;
1710 base ntcreatex parms
1712 ZERO_STRUCT(io.smb2);
1713 io.generic.level = RAW_OPEN_SMB2;
1714 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1715 io.smb2.in.alloc_size = 0;
1716 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1717 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1718 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1719 io.smb2.in.create_options = 0;
1720 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1721 io.smb2.in.security_flags = 0;
1722 io.smb2.in.fname = fname;
1724 torture_comment(tctx, "BATCH10: Open with oplock after a non-oplock "
1725 "open should grant level2\n");
1726 ZERO_STRUCT(break_info);
1727 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1728 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1729 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1730 NTCREATEX_SHARE_ACCESS_WRITE|
1731 NTCREATEX_SHARE_ACCESS_DELETE;
1732 status = smb2_create(tree1, tctx, &(io.smb2));
1733 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1734 h1 = io.smb2.out.file.handle;
1735 torture_wait_for_oplock_break(tctx);
1736 CHECK_VAL(break_info.count, 0);
1737 CHECK_VAL(break_info.failures, 0);
1738 CHECK_VAL(io.smb2.out.oplock_level, 0);
1740 tree2->session->transport->oplock.handler =
1741 torture_oplock_handler_level2_to_none;
1742 tree2->session->transport->oplock.private_data = tree2;
1744 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1745 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1746 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1747 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1748 NTCREATEX_SHARE_ACCESS_WRITE|
1749 NTCREATEX_SHARE_ACCESS_DELETE;
1750 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1751 status = smb2_create(tree2, tctx, &(io.smb2));
1752 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1753 h2 = io.smb2.out.file.handle;
1754 torture_wait_for_oplock_break(tctx);
1755 CHECK_VAL(break_info.count, 0);
1756 CHECK_VAL(break_info.failures, 0);
1757 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1759 torture_comment(tctx, "write should trigger a break to none\n");
1761 struct smb2_write wr;
1762 DATA_BLOB data;
1763 data = data_blob_talloc_zero(tree1, UINT16_MAX);
1764 data.data[0] = (const uint8_t)'x';
1765 ZERO_STRUCT(wr);
1766 wr.in.file.handle = h1;
1767 wr.in.offset = 0;
1768 wr.in.data = data;
1769 status = smb2_write(tree1, &wr);
1770 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1773 torture_wait_for_oplock_break(tctx);
1775 CHECK_VAL(break_info.count, 1);
1776 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1777 CHECK_VAL(break_info.level, 0);
1778 CHECK_VAL(break_info.failures, 0);
1780 smb2_util_close(tree1, h1);
1781 smb2_util_close(tree2, h2);
1782 smb2_util_close(tree1, h);
1784 smb2_deltree(tree1, BASEDIR);
1785 return ret;
1788 static bool test_smb2_oplock_batch11(struct torture_context *tctx,
1789 struct smb2_tree *tree1,
1790 struct smb2_tree *tree2)
1792 const char *fname = BASEDIR "\\test_batch11.dat";
1793 NTSTATUS status;
1794 bool ret = true;
1795 union smb_open io;
1796 union smb_setfileinfo sfi;
1797 struct smb2_handle h, h1;
1799 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1800 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1802 /* cleanup */
1803 smb2_util_unlink(tree1, fname);
1805 tree1->session->transport->oplock.handler =
1806 torture_oplock_handler_two_notifications;
1807 tree1->session->transport->oplock.private_data = tree1;
1810 base ntcreatex parms
1812 ZERO_STRUCT(io.smb2);
1813 io.generic.level = RAW_OPEN_SMB2;
1814 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1815 io.smb2.in.alloc_size = 0;
1816 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1817 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1818 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1819 io.smb2.in.create_options = 0;
1820 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1821 io.smb2.in.security_flags = 0;
1822 io.smb2.in.fname = fname;
1824 /* Test if a set-eof on pathname breaks an exclusive oplock. */
1825 torture_comment(tctx, "BATCH11: Test if setpathinfo set EOF breaks "
1826 "oplocks.\n");
1828 ZERO_STRUCT(break_info);
1830 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1831 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1832 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1833 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1834 NTCREATEX_SHARE_ACCESS_WRITE|
1835 NTCREATEX_SHARE_ACCESS_DELETE;
1836 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1837 status = smb2_create(tree1, tctx, &(io.smb2));
1838 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1839 h1 = io.smb2.out.file.handle;
1840 torture_wait_for_oplock_break(tctx);
1841 CHECK_VAL(break_info.count, 0);
1842 CHECK_VAL(break_info.failures, 0);
1843 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1845 ZERO_STRUCT(sfi);
1846 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1847 sfi.generic.in.file.path = fname;
1848 sfi.end_of_file_info.in.size = 100;
1850 status = smb2_composite_setpathinfo(tree2, &sfi);
1851 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1853 /* We expect two breaks */
1854 torture_wait_for_oplock_break(tctx);
1855 torture_wait_for_oplock_break(tctx);
1857 CHECK_VAL(break_info.count, 2);
1858 CHECK_VAL(break_info.failures, 0);
1859 CHECK_VAL(break_info.level, 0);
1861 smb2_util_close(tree1, h1);
1862 smb2_util_close(tree1, h);
1864 smb2_deltree(tree1, BASEDIR);
1865 return ret;
1868 static bool test_smb2_oplock_batch12(struct torture_context *tctx,
1869 struct smb2_tree *tree1,
1870 struct smb2_tree *tree2)
1872 const char *fname = BASEDIR "\\test_batch12.dat";
1873 NTSTATUS status;
1874 bool ret = true;
1875 union smb_open io;
1876 union smb_setfileinfo sfi;
1877 struct smb2_handle h, h1;
1879 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1880 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1882 /* cleanup */
1883 smb2_util_unlink(tree1, fname);
1885 tree1->session->transport->oplock.handler =
1886 torture_oplock_handler_two_notifications;
1887 tree1->session->transport->oplock.private_data = tree1;
1890 base ntcreatex parms
1892 ZERO_STRUCT(io.smb2);
1893 io.generic.level = RAW_OPEN_SMB2;
1894 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1895 io.smb2.in.alloc_size = 0;
1896 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1897 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1898 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1899 io.smb2.in.create_options = 0;
1900 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1901 io.smb2.in.security_flags = 0;
1902 io.smb2.in.fname = fname;
1904 /* Test if a set-allocation size on pathname breaks an exclusive
1905 * oplock. */
1906 torture_comment(tctx, "BATCH12: Test if setpathinfo allocation size "
1907 "breaks oplocks.\n");
1909 ZERO_STRUCT(break_info);
1911 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1912 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1913 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1914 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1915 NTCREATEX_SHARE_ACCESS_WRITE|
1916 NTCREATEX_SHARE_ACCESS_DELETE;
1917 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1918 status = smb2_create(tree1, tctx, &(io.smb2));
1919 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1920 h1 = io.smb2.out.file.handle;
1921 torture_wait_for_oplock_break(tctx);
1922 CHECK_VAL(break_info.count, 0);
1923 CHECK_VAL(break_info.failures, 0);
1924 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1926 ZERO_STRUCT(sfi);
1927 sfi.generic.level = RAW_SFILEINFO_ALLOCATION_INFORMATION;
1928 sfi.generic.in.file.path = fname;
1929 sfi.allocation_info.in.alloc_size = 65536 * 8;
1931 status = smb2_composite_setpathinfo(tree2, &sfi);
1932 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1934 /* We expect two breaks */
1935 torture_wait_for_oplock_break(tctx);
1936 torture_wait_for_oplock_break(tctx);
1938 CHECK_VAL(break_info.count, 2);
1939 CHECK_VAL(break_info.failures, 0);
1940 CHECK_VAL(break_info.level, 0);
1942 smb2_util_close(tree1, h1);
1943 smb2_util_close(tree1, h);
1945 smb2_deltree(tree1, BASEDIR);
1946 return ret;
1949 static bool test_smb2_oplock_batch13(struct torture_context *tctx,
1950 struct smb2_tree *tree1,
1951 struct smb2_tree *tree2)
1953 const char *fname = BASEDIR "\\test_batch13.dat";
1954 NTSTATUS status;
1955 bool ret = true;
1956 union smb_open io;
1957 struct smb2_handle h, h1, h2;
1959 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1960 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1962 /* cleanup */
1963 smb2_util_unlink(tree1, fname);
1965 tree1->session->transport->oplock.handler = torture_oplock_handler;
1966 tree1->session->transport->oplock.private_data = tree1;
1968 tree2->session->transport->oplock.handler = torture_oplock_handler;
1969 tree2->session->transport->oplock.private_data = tree2;
1972 base ntcreatex parms
1974 ZERO_STRUCT(io.smb2);
1975 io.generic.level = RAW_OPEN_SMB2;
1976 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1977 io.smb2.in.alloc_size = 0;
1978 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1979 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1980 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1981 io.smb2.in.create_options = 0;
1982 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1983 io.smb2.in.security_flags = 0;
1984 io.smb2.in.fname = fname;
1986 torture_comment(tctx, "BATCH13: open with batch oplock\n");
1987 ZERO_STRUCT(break_info);
1989 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1990 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1991 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1992 NTCREATEX_SHARE_ACCESS_WRITE|
1993 NTCREATEX_SHARE_ACCESS_DELETE;
1994 status = smb2_create(tree1, tctx, &(io.smb2));
1995 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1996 h1 = io.smb2.out.file.handle;
1997 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1999 ZERO_STRUCT(break_info);
2001 torture_comment(tctx, "second open with attributes only and "
2002 "NTCREATEX_DISP_OVERWRITE dispostion causes "
2003 "oplock break\n");
2005 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2006 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2007 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2008 SEC_FILE_WRITE_ATTRIBUTE |
2009 SEC_STD_SYNCHRONIZE;
2010 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2011 NTCREATEX_SHARE_ACCESS_WRITE|
2012 NTCREATEX_SHARE_ACCESS_DELETE;
2013 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2014 status = smb2_create(tree2, tctx, &(io.smb2));
2015 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2016 h2 = io.smb2.out.file.handle;
2017 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2018 torture_wait_for_oplock_break(tctx);
2019 CHECK_VAL(break_info.count, 1);
2020 CHECK_VAL(break_info.failures, 0);
2022 smb2_util_close(tree1, h1);
2023 smb2_util_close(tree2, h2);
2024 smb2_util_close(tree1, h);
2026 smb2_deltree(tree1, BASEDIR);
2028 return ret;
2031 static bool test_smb2_oplock_batch14(struct torture_context *tctx,
2032 struct smb2_tree *tree1,
2033 struct smb2_tree *tree2)
2035 const char *fname = BASEDIR "\\test_batch14.dat";
2036 NTSTATUS status;
2037 bool ret = true;
2038 union smb_open io;
2039 struct smb2_handle h, h1, h2;
2041 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2042 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2044 /* cleanup */
2045 smb2_util_unlink(tree1, fname);
2047 tree1->session->transport->oplock.handler = torture_oplock_handler;
2048 tree1->session->transport->oplock.private_data = tree1;
2051 base ntcreatex parms
2053 ZERO_STRUCT(io.smb2);
2054 io.generic.level = RAW_OPEN_SMB2;
2055 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2056 io.smb2.in.alloc_size = 0;
2057 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2058 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2059 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2060 io.smb2.in.create_options = 0;
2061 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2062 io.smb2.in.security_flags = 0;
2063 io.smb2.in.fname = fname;
2065 torture_comment(tctx, "BATCH14: open with batch oplock\n");
2066 ZERO_STRUCT(break_info);
2068 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2069 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2070 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2071 NTCREATEX_SHARE_ACCESS_WRITE|
2072 NTCREATEX_SHARE_ACCESS_DELETE;
2073 status = smb2_create(tree1, tctx, &(io.smb2));
2074 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2075 h1 = io.smb2.out.file.handle;
2076 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2078 ZERO_STRUCT(break_info);
2080 torture_comment(tctx, "second open with attributes only and "
2081 "NTCREATEX_DISP_SUPERSEDE dispostion causes "
2082 "oplock break\n");
2084 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2085 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2086 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2087 SEC_FILE_WRITE_ATTRIBUTE |
2088 SEC_STD_SYNCHRONIZE;
2089 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2090 NTCREATEX_SHARE_ACCESS_WRITE|
2091 NTCREATEX_SHARE_ACCESS_DELETE;
2092 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2093 status = smb2_create(tree2, tctx, &(io.smb2));
2094 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2095 h2 = io.smb2.out.file.handle;
2096 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2098 torture_wait_for_oplock_break(tctx);
2099 CHECK_VAL(break_info.count, 1);
2100 CHECK_VAL(break_info.failures, 0);
2102 smb2_util_close(tree1, h1);
2103 smb2_util_close(tree2, h2);
2104 smb2_util_close(tree1, h);
2106 smb2_deltree(tree1, BASEDIR);
2107 return ret;
2110 static bool test_smb2_oplock_batch15(struct torture_context *tctx,
2111 struct smb2_tree *tree1,
2112 struct smb2_tree *tree2)
2114 const char *fname = BASEDIR "\\test_batch15.dat";
2115 NTSTATUS status;
2116 bool ret = true;
2117 union smb_open io;
2118 union smb_fileinfo qfi;
2119 struct smb2_handle h, h1;
2121 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2122 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2124 /* cleanup */
2125 smb2_util_unlink(tree1, fname);
2127 tree1->session->transport->oplock.handler = torture_oplock_handler;
2128 tree1->session->transport->oplock.private_data = tree1;
2131 base ntcreatex parms
2133 ZERO_STRUCT(io.smb2);
2134 io.generic.level = RAW_OPEN_SMB2;
2135 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2136 io.smb2.in.alloc_size = 0;
2137 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2138 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2139 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2140 io.smb2.in.create_options = 0;
2141 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2142 io.smb2.in.security_flags = 0;
2143 io.smb2.in.fname = fname;
2145 /* Test if a qpathinfo all info on pathname breaks a batch oplock. */
2146 torture_comment(tctx, "BATCH15: Test if qpathinfo all info breaks "
2147 "a batch oplock (should not).\n");
2149 ZERO_STRUCT(break_info);
2151 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2152 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2153 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2154 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2155 NTCREATEX_SHARE_ACCESS_WRITE|
2156 NTCREATEX_SHARE_ACCESS_DELETE;
2157 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2158 status = smb2_create(tree1, tctx, &(io.smb2));
2159 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2160 h1 = io.smb2.out.file.handle;
2162 torture_wait_for_oplock_break(tctx);
2163 CHECK_VAL(break_info.count, 0);
2164 CHECK_VAL(break_info.failures, 0);
2165 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2167 ZERO_STRUCT(qfi);
2168 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2169 qfi.generic.in.file.handle = h1;
2170 status = smb2_getinfo_file(tree2, tctx, &qfi);
2172 torture_wait_for_oplock_break(tctx);
2173 CHECK_VAL(break_info.count, 0);
2175 smb2_util_close(tree1, h1);
2176 smb2_util_close(tree1, h);
2178 smb2_deltree(tree1, BASEDIR);
2179 return ret;
2182 static bool test_smb2_oplock_batch16(struct torture_context *tctx,
2183 struct smb2_tree *tree1,
2184 struct smb2_tree *tree2)
2186 const char *fname = BASEDIR "\\test_batch16.dat";
2187 NTSTATUS status;
2188 bool ret = true;
2189 union smb_open io;
2190 struct smb2_handle h, h1, h2;
2192 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2193 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2195 /* cleanup */
2196 smb2_util_unlink(tree1, fname);
2198 tree1->session->transport->oplock.handler = torture_oplock_handler;
2199 tree1->session->transport->oplock.private_data = tree1;
2201 tree2->session->transport->oplock.handler = torture_oplock_handler;
2202 tree2->session->transport->oplock.private_data = tree2;
2205 base ntcreatex parms
2207 ZERO_STRUCT(io.smb2);
2208 io.generic.level = RAW_OPEN_SMB2;
2209 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2210 io.smb2.in.alloc_size = 0;
2211 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2212 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2213 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2214 io.smb2.in.create_options = 0;
2215 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2216 io.smb2.in.security_flags = 0;
2217 io.smb2.in.fname = fname;
2219 torture_comment(tctx, "BATCH16: open with batch oplock\n");
2220 ZERO_STRUCT(break_info);
2222 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2223 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2224 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2225 NTCREATEX_SHARE_ACCESS_WRITE|
2226 NTCREATEX_SHARE_ACCESS_DELETE;
2227 status = smb2_create(tree1, tctx, &(io.smb2));
2228 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2229 h1 = io.smb2.out.file.handle;
2230 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2232 ZERO_STRUCT(break_info);
2234 torture_comment(tctx, "second open with attributes only and "
2235 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
2236 "oplock break\n");
2238 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2239 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2240 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2241 SEC_FILE_WRITE_ATTRIBUTE |
2242 SEC_STD_SYNCHRONIZE;
2243 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2244 NTCREATEX_SHARE_ACCESS_WRITE|
2245 NTCREATEX_SHARE_ACCESS_DELETE;
2246 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
2247 status = smb2_create(tree2, tctx, &(io.smb2));
2248 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2249 h2 = io.smb2.out.file.handle;
2250 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2252 torture_wait_for_oplock_break(tctx);
2253 CHECK_VAL(break_info.count, 1);
2254 CHECK_VAL(break_info.failures, 0);
2256 smb2_util_close(tree1, h1);
2257 smb2_util_close(tree2, h2);
2258 smb2_util_close(tree1, h);
2260 smb2_deltree(tree1, BASEDIR);
2261 return ret;
2264 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH17 test. Since
2265 * SMB2 doesn't have a RENAME command this test isn't applicable. However,
2266 * it's much less confusing, when comparing test, to keep the SMB1 and SMB2
2267 * test numbers in sync. */
2268 #if 0
2269 static bool test_raw_oplock_batch17(struct torture_context *tctx,
2270 struct smb2_tree *tree1,
2271 struct smb2_tree *tree2)
2273 return true;
2275 #endif
2277 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH18 test. Since
2278 * SMB2 doesn't have an NTRENAME command this test isn't applicable. However,
2279 * it's much less confusing, when comparing tests, to keep the SMB1 and SMB2
2280 * test numbers in sync. */
2281 #if 0
2282 static bool test_raw_oplock_batch18(struct torture_context *tctx,
2283 struct smb2_tree *tree1,
2284 struct smb2_tree *tree2)
2286 return true;
2288 #endif
2290 static bool test_smb2_oplock_batch19(struct torture_context *tctx,
2291 struct smb2_tree *tree1)
2293 const char *fname1 = BASEDIR "\\test_batch19_1.dat";
2294 const char *fname2 = BASEDIR "\\test_batch19_2.dat";
2295 NTSTATUS status;
2296 bool ret = true;
2297 union smb_open io;
2298 union smb_fileinfo qfi;
2299 union smb_setfileinfo sfi;
2300 struct smb2_handle h, h1;
2302 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2303 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2305 /* cleanup */
2306 smb2_util_unlink(tree1, fname1);
2307 smb2_util_unlink(tree1, fname2);
2309 tree1->session->transport->oplock.handler = torture_oplock_handler;
2310 tree1->session->transport->oplock.private_data = tree1;
2313 base ntcreatex parms
2315 ZERO_STRUCT(io.smb2);
2316 io.generic.level = RAW_OPEN_SMB2;
2317 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2318 io.smb2.in.alloc_size = 0;
2319 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2320 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2321 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2322 io.smb2.in.create_options = 0;
2323 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2324 io.smb2.in.security_flags = 0;
2325 io.smb2.in.fname = fname1;
2327 torture_comment(tctx, "BATCH19: open a file with an batch oplock "
2328 "(share mode: none)\n");
2329 ZERO_STRUCT(break_info);
2330 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2331 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2332 status = smb2_create(tree1, tctx, &(io.smb2));
2333 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2334 h1 = io.smb2.out.file.handle;
2335 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2337 torture_comment(tctx, "setfileinfo rename info should not trigger "
2338 "a break but should cause a sharing violation\n");
2339 ZERO_STRUCT(sfi);
2340 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2341 sfi.generic.in.file.path = fname1;
2342 sfi.rename_information.in.file.handle = h1;
2343 sfi.rename_information.in.overwrite = 0;
2344 sfi.rename_information.in.root_fid = 0;
2345 sfi.rename_information.in.new_name = fname2;
2347 status = smb2_setinfo_file(tree1, &sfi);
2349 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2350 "Incorrect status");
2352 torture_wait_for_oplock_break(tctx);
2353 CHECK_VAL(break_info.count, 0);
2355 ZERO_STRUCT(qfi);
2356 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2357 qfi.generic.in.file.handle = h1;
2359 status = smb2_getinfo_file(tree1, tctx, &qfi);
2360 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2361 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2363 smb2_util_close(tree1, h1);
2364 smb2_util_close(tree1, h);
2366 smb2_deltree(tree1, fname1);
2367 smb2_deltree(tree1, fname2);
2368 return ret;
2371 static bool test_smb2_oplock_batch20(struct torture_context *tctx,
2372 struct smb2_tree *tree1,
2373 struct smb2_tree *tree2)
2375 const char *fname1 = BASEDIR "\\test_batch20_1.dat";
2376 const char *fname2 = BASEDIR "\\test_batch20_2.dat";
2377 NTSTATUS status;
2378 bool ret = true;
2379 union smb_open io;
2380 union smb_fileinfo qfi;
2381 union smb_setfileinfo sfi;
2382 struct smb2_handle h, h1, h2;
2384 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2385 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2387 /* cleanup */
2388 smb2_util_unlink(tree1, fname1);
2389 smb2_util_unlink(tree1, fname2);
2391 tree1->session->transport->oplock.handler = torture_oplock_handler;
2392 tree1->session->transport->oplock.private_data = tree1;
2395 base ntcreatex parms
2397 ZERO_STRUCT(io.smb2);
2398 io.generic.level = RAW_OPEN_SMB2;
2399 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2400 io.smb2.in.alloc_size = 0;
2401 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2402 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2403 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2404 io.smb2.in.create_options = 0;
2405 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2406 io.smb2.in.security_flags = 0;
2407 io.smb2.in.fname = fname1;
2409 torture_comment(tctx, "BATCH20: open a file with an batch oplock "
2410 "(share mode: all)\n");
2411 ZERO_STRUCT(break_info);
2412 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2413 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2414 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2415 NTCREATEX_SHARE_ACCESS_WRITE|
2416 NTCREATEX_SHARE_ACCESS_DELETE;
2417 status = smb2_create(tree1, tctx, &(io.smb2));
2418 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2419 h1 = io.smb2.out.file.handle;
2420 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2422 torture_comment(tctx, "setfileinfo rename info should not trigger "
2423 "a break but should cause a sharing violation\n");
2424 ZERO_STRUCT(sfi);
2425 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2426 sfi.rename_information.in.file.handle = h1;
2427 sfi.rename_information.in.overwrite = 0;
2428 sfi.rename_information.in.new_name = fname2;
2430 status = smb2_setinfo_file(tree1, &sfi);
2431 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2432 "Incorrect status");
2434 torture_wait_for_oplock_break(tctx);
2435 CHECK_VAL(break_info.count, 0);
2437 ZERO_STRUCT(qfi);
2438 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2439 qfi.generic.in.file.handle = h1;
2441 status = smb2_getinfo_file(tree1, tctx, &qfi);
2442 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2443 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2445 torture_comment(tctx, "open the file a second time requesting batch "
2446 "(share mode: all)\n");
2447 ZERO_STRUCT(break_info);
2448 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2449 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2450 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2451 NTCREATEX_SHARE_ACCESS_WRITE|
2452 NTCREATEX_SHARE_ACCESS_DELETE;
2453 io.smb2.in.fname = fname1;
2454 status = smb2_create(tree2, tctx, &(io.smb2));
2455 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2456 h2 = io.smb2.out.file.handle;
2457 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2459 torture_wait_for_oplock_break(tctx);
2460 CHECK_VAL(break_info.count, 1);
2461 CHECK_VAL(break_info.failures, 0);
2462 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2464 torture_comment(tctx, "setfileinfo rename info should not trigger "
2465 "a break but should cause a sharing violation\n");
2466 ZERO_STRUCT(break_info);
2467 ZERO_STRUCT(sfi);
2468 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2469 sfi.rename_information.in.file.handle = h2;
2470 sfi.rename_information.in.overwrite = 0;
2471 sfi.rename_information.in.new_name = fname2;
2473 status = smb2_setinfo_file(tree2, &sfi);
2474 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2475 "Incorrect status");
2477 torture_wait_for_oplock_break(tctx);
2478 CHECK_VAL(break_info.count, 0);
2480 ZERO_STRUCT(qfi);
2481 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2482 qfi.generic.in.file.handle = h1;
2484 status = smb2_getinfo_file(tree1, tctx, &qfi);
2485 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2486 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2488 ZERO_STRUCT(qfi);
2489 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2490 qfi.generic.in.file.handle = h2;
2492 status = smb2_getinfo_file(tree2, tctx, &qfi);
2493 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2494 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2496 smb2_util_close(tree1, h1);
2497 smb2_util_close(tree2, h2);
2498 smb2_util_close(tree1, h);
2500 smb2_deltree(tree1, fname1);
2501 return ret;
2504 static bool test_smb2_oplock_batch21(struct torture_context *tctx,
2505 struct smb2_tree *tree1)
2507 const char *fname = BASEDIR "\\test_batch21.dat";
2508 NTSTATUS status;
2509 bool ret = true;
2510 union smb_open io;
2511 struct smb2_handle h, h1;
2512 char c = 0;
2514 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2515 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2517 /* cleanup */
2518 smb2_util_unlink(tree1, fname);
2520 tree1->session->transport->oplock.handler = torture_oplock_handler;
2521 tree1->session->transport->oplock.private_data = tree1;
2524 base ntcreatex parms
2526 ZERO_STRUCT(io.smb2);
2527 io.generic.level = RAW_OPEN_SMB2;
2528 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2529 io.smb2.in.alloc_size = 0;
2530 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2531 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2532 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2533 io.smb2.in.create_options = 0;
2534 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2535 io.smb2.in.security_flags = 0;
2536 io.smb2.in.fname = fname;
2539 with a batch oplock we get a break
2541 torture_comment(tctx, "BATCH21: open with batch oplock\n");
2542 ZERO_STRUCT(break_info);
2543 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2544 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2545 status = smb2_create(tree1, tctx, &(io.smb2));
2546 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2547 h1 = io.smb2.out.file.handle;
2548 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2550 torture_comment(tctx, "writing should not generate a break\n");
2551 status = smb2_util_write(tree1, h1, &c, 0, 1);
2552 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2554 torture_wait_for_oplock_break(tctx);
2555 CHECK_VAL(break_info.count, 0);
2557 smb2_util_close(tree1, h1);
2558 smb2_util_close(tree1, h);
2560 smb2_deltree(tree1, BASEDIR);
2561 return ret;
2564 static bool test_smb2_oplock_batch22(struct torture_context *tctx,
2565 struct smb2_tree *tree1)
2567 const char *fname = BASEDIR "\\test_batch22.dat";
2568 NTSTATUS status;
2569 bool ret = true;
2570 union smb_open io;
2571 struct smb2_handle h, h1, h2;
2572 struct timeval tv;
2573 int timeout = torture_setting_int(tctx, "oplocktimeout", 30);
2574 int te;
2576 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2577 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2579 /* cleanup */
2580 smb2_util_unlink(tree1, fname);
2582 tree1->session->transport->oplock.handler = torture_oplock_handler;
2583 tree1->session->transport->oplock.private_data = tree1;
2585 base ntcreatex parms
2587 ZERO_STRUCT(io.smb2);
2588 io.generic.level = RAW_OPEN_SMB2;
2589 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2590 io.smb2.in.alloc_size = 0;
2591 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2592 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2593 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2594 io.smb2.in.create_options = 0;
2595 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2596 io.smb2.in.security_flags = 0;
2597 io.smb2.in.fname = fname;
2600 with a batch oplock we get a break
2602 torture_comment(tctx, "BATCH22: open with batch oplock\n");
2603 ZERO_STRUCT(break_info);
2604 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2605 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2606 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2607 NTCREATEX_SHARE_ACCESS_WRITE|
2608 NTCREATEX_SHARE_ACCESS_DELETE;
2609 status = smb2_create(tree1, tctx, &(io.smb2));
2610 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2611 h1 = io.smb2.out.file.handle;
2612 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2614 torture_comment(tctx, "a 2nd open should succeed after the oplock "
2615 "break timeout\n");
2616 tv = timeval_current();
2617 tree1->session->transport->oplock.handler =
2618 torture_oplock_handler_timeout;
2619 status = smb2_create(tree1, tctx, &(io.smb2));
2620 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2621 h2 = io.smb2.out.file.handle;
2622 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2624 torture_wait_for_oplock_break(tctx);
2625 te = (int)timeval_elapsed(&tv);
2626 CHECK_RANGE(te, timeout - 1, timeout + 15);
2627 torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
2629 CHECK_VAL(break_info.count, 1);
2630 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2631 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2632 CHECK_VAL(break_info.failures, 0);
2634 smb2_util_close(tree1, h1);
2635 smb2_util_close(tree1, h2);
2636 smb2_util_close(tree1, h);
2638 smb2_deltree(tree1, BASEDIR);
2639 return ret;
2642 static bool test_smb2_oplock_batch23(struct torture_context *tctx,
2643 struct smb2_tree *tree1,
2644 struct smb2_tree *tree2)
2646 const char *fname = BASEDIR "\\test_batch23.dat";
2647 NTSTATUS status;
2648 bool ret = true;
2649 union smb_open io;
2650 struct smb2_handle h, h1, h2, h3;
2651 struct smb2_tree *tree3 = NULL;
2653 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2654 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2656 /* cleanup */
2657 smb2_util_unlink(tree1, fname);
2659 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2660 CHECK_VAL(ret, true);
2662 tree1->session->transport->oplock.handler = torture_oplock_handler;
2663 tree1->session->transport->oplock.private_data = tree1;
2665 tree2->session->transport->oplock.handler = torture_oplock_handler;
2666 tree2->session->transport->oplock.private_data = tree2;
2668 tree3->session->transport->oplock.handler = torture_oplock_handler;
2669 tree3->session->transport->oplock.private_data = tree3;
2672 base ntcreatex parms
2674 ZERO_STRUCT(io.smb2);
2675 io.generic.level = RAW_OPEN_SMB2;
2676 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2677 io.smb2.in.alloc_size = 0;
2678 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2679 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2680 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2681 io.smb2.in.create_options = 0;
2682 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2683 io.smb2.in.security_flags = 0;
2684 io.smb2.in.fname = fname;
2686 torture_comment(tctx, "BATCH23: an open and ask for a batch oplock\n");
2687 ZERO_STRUCT(break_info);
2689 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2690 SEC_RIGHTS_FILE_WRITE;
2691 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2692 NTCREATEX_SHARE_ACCESS_WRITE;
2693 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2694 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2695 status = smb2_create(tree1, tctx, &(io.smb2));
2696 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2697 h1 = io.smb2.out.file.handle;
2698 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2700 ZERO_STRUCT(break_info);
2702 torture_comment(tctx, "a 2nd open without level2 oplock support "
2703 "should generate a break to level2\n");
2704 status = smb2_create(tree3, tctx, &(io.smb2));
2705 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2706 h3 = io.smb2.out.file.handle;
2708 torture_wait_for_oplock_break(tctx);
2709 CHECK_VAL(break_info.count, 1);
2710 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2711 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2712 CHECK_VAL(break_info.failures, 0);
2714 ZERO_STRUCT(break_info);
2716 torture_comment(tctx, "a 3rd open with level2 oplock support should "
2717 "not generate a break\n");
2718 status = smb2_create(tree2, tctx, &(io.smb2));
2719 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2720 h2 = io.smb2.out.file.handle;
2721 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2723 torture_wait_for_oplock_break(tctx);
2724 CHECK_VAL(break_info.count, 0);
2726 smb2_util_close(tree1, h1);
2727 smb2_util_close(tree2, h2);
2728 smb2_util_close(tree3, h3);
2729 smb2_util_close(tree1, h);
2731 smb2_deltree(tree1, BASEDIR);
2732 return ret;
2735 static bool test_smb2_oplock_batch24(struct torture_context *tctx,
2736 struct smb2_tree *tree1,
2737 struct smb2_tree *tree2)
2739 const char *fname = BASEDIR "\\test_batch24.dat";
2740 NTSTATUS status;
2741 bool ret = true;
2742 union smb_open io;
2743 struct smb2_handle h, h1, h2;
2744 struct smb2_tree *tree3 = NULL;
2746 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2747 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2749 /* cleanup */
2750 smb2_util_unlink(tree1, fname);
2752 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2753 CHECK_VAL(ret, true);
2755 tree1->session->transport->oplock.handler = torture_oplock_handler;
2756 tree1->session->transport->oplock.private_data = tree1;
2758 tree2->session->transport->oplock.handler = torture_oplock_handler;
2759 tree2->session->transport->oplock.private_data = tree2;
2761 tree3->session->transport->oplock.handler = torture_oplock_handler;
2762 tree3->session->transport->oplock.private_data = tree3;
2765 base ntcreatex parms
2767 ZERO_STRUCT(io.smb2);
2768 io.generic.level = RAW_OPEN_SMB2;
2769 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2770 io.smb2.in.alloc_size = 0;
2771 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2772 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2773 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2774 io.smb2.in.create_options = 0;
2775 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2776 io.smb2.in.security_flags = 0;
2777 io.smb2.in.fname = fname;
2779 torture_comment(tctx, "BATCH24: a open without level support and "
2780 "ask for a batch oplock\n");
2781 ZERO_STRUCT(break_info);
2783 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2784 SEC_RIGHTS_FILE_WRITE;
2785 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2786 NTCREATEX_SHARE_ACCESS_WRITE;
2787 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2788 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2790 status = smb2_create(tree3, tctx, &(io.smb2));
2791 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2792 h2 = io.smb2.out.file.handle;
2793 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2795 ZERO_STRUCT(break_info);
2797 torture_comment(tctx, "a 2nd open with level2 oplock support should "
2798 "generate a break\n");
2799 status = smb2_create(tree2, tctx, &(io.smb2));
2800 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2801 h1 = io.smb2.out.file.handle;
2802 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2804 torture_wait_for_oplock_break(tctx);
2805 CHECK_VAL(break_info.count, 1);
2806 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
2807 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2808 CHECK_VAL(break_info.failures, 0);
2810 smb2_util_close(tree3, h2);
2811 smb2_util_close(tree2, h1);
2812 smb2_util_close(tree1, h);
2814 smb2_deltree(tree1, BASEDIR);
2815 return ret;
2818 static bool test_smb2_oplock_batch25(struct torture_context *tctx,
2819 struct smb2_tree *tree1)
2821 const char *fname = BASEDIR "\\test_batch25.dat";
2822 NTSTATUS status;
2823 bool ret = true;
2824 union smb_open io;
2825 struct smb2_handle h, h1;
2827 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2828 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2830 /* cleanup */
2831 smb2_util_unlink(tree1, fname);
2833 tree1->session->transport->oplock.handler = torture_oplock_handler;
2834 tree1->session->transport->oplock.private_data = tree1;
2837 base ntcreatex parms
2839 ZERO_STRUCT(io.smb2);
2840 io.generic.level = RAW_OPEN_SMB2;
2841 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2842 io.smb2.in.alloc_size = 0;
2843 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2844 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2845 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2846 io.smb2.in.create_options = 0;
2847 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2848 io.smb2.in.security_flags = 0;
2849 io.smb2.in.fname = fname;
2851 torture_comment(tctx, "BATCH25: open a file with an batch oplock "
2852 "(share mode: none)\n");
2854 ZERO_STRUCT(break_info);
2855 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2856 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2858 status = smb2_create(tree1, tctx, &(io.smb2));
2859 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2860 h1 = io.smb2.out.file.handle;
2861 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2863 torture_comment(tctx, "changing the file attribute info should trigger "
2864 "a break and a violation\n");
2866 status = smb2_util_setatr(tree1, fname, FILE_ATTRIBUTE_HIDDEN);
2867 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2868 "Incorrect status");
2870 torture_wait_for_oplock_break(tctx);
2871 CHECK_VAL(break_info.count, 1);
2873 smb2_util_close(tree1, h1);
2874 smb2_util_close(tree1, h);
2876 smb2_deltree(tree1, fname);
2877 return ret;
2880 static bool test_smb2_oplock_batch26(struct torture_context *tctx,
2881 struct smb2_tree *tree1)
2884 NTSTATUS status;
2885 bool ret = true;
2886 union smb_open io;
2887 struct smb2_handle h, h1, h2, h3;
2888 const char *fname_base = BASEDIR "\\test_oplock.txt";
2889 const char *stream = "Stream One:$DATA";
2890 const char *fname_stream;
2892 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2893 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2895 tree1->session->transport->oplock.handler = torture_oplock_handler;
2896 tree1->session->transport->oplock.private_data = tree1;
2898 fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
2901 base ntcreatex parms
2903 ZERO_STRUCT(io.smb2);
2904 io.generic.level = RAW_OPEN_SMB2;
2905 io.smb2.in.desired_access = 0x120089;
2906 io.smb2.in.alloc_size = 0;
2907 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2908 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE |
2909 NTCREATEX_SHARE_ACCESS_WRITE;
2910 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2911 io.smb2.in.create_options = 0;
2912 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2913 io.smb2.in.security_flags = 0;
2914 io.smb2.in.fname = fname_base;
2917 Open base file with a batch oplock.
2919 torture_comment(tctx, "Open the base file with batch oplock\n");
2920 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2921 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2923 status = smb2_create(tree1, tctx, &(io.smb2));
2924 torture_assert_ntstatus_ok(tctx, status, "Error opening base file");
2925 h1 = io.smb2.out.file.handle;
2926 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2928 torture_comment(tctx, "Got batch oplock on base file\n");
2930 torture_comment(tctx, "Opening stream file with batch oplock..\n");
2932 io.smb2.in.fname = fname_stream;
2934 status = smb2_create(tree1, tctx, &(io.smb2));
2935 torture_assert_ntstatus_ok(tctx, status, "Error opening stream file");
2936 h2 = io.smb2.out.file.handle;
2937 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2939 torture_comment(tctx, "Got batch oplock on stream file\n");
2941 torture_comment(tctx, "Open base file again with batch oplock\n");
2943 io.smb2.in.fname = fname_base;
2945 status = smb2_create(tree1, tctx, &(io.smb2));
2946 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2947 h3 = io.smb2.out.file.handle;
2948 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2950 smb2_util_close(tree1, h1);
2951 smb2_util_close(tree1, h2);
2952 smb2_util_close(tree1, h3);
2953 smb2_util_close(tree1, h);
2954 smb2_deltree(tree1, BASEDIR);
2955 return ret;
2959 /* Test how oplocks work on streams. */
2960 static bool test_raw_oplock_stream1(struct torture_context *tctx,
2961 struct smb2_tree *tree1,
2962 struct smb2_tree *tree2)
2964 NTSTATUS status;
2965 union smb_open io;
2966 const char *fname_base = BASEDIR "\\test_stream1.txt";
2967 const char *fname_stream, *fname_default_stream;
2968 const char *default_stream = "::$DATA";
2969 const char *stream = "Stream One:$DATA";
2970 bool ret = true;
2971 struct smb2_handle h, h_base, h_stream;
2972 int i;
2974 #define NSTREAM_OPLOCK_RESULTS 8
2975 struct {
2976 const char **fname;
2977 bool open_base_file;
2978 uint32_t oplock_req;
2979 uint32_t oplock_granted;
2980 } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
2981 /* Request oplock on stream without the base file open. */
2982 {&fname_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2983 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2984 {&fname_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2985 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2987 /* Request oplock on stream with the base file open. */
2988 {&fname_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2989 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_II},
2990 {&fname_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2991 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_II},
2994 fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
2995 fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
2996 default_stream);
2998 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2999 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3001 /* Initialize handles to "closed". Using -1 in the first 64-bytes
3002 * as the sentry for this */
3003 h_stream.data[0] = -1;
3005 /* cleanup */
3006 smb2_util_unlink(tree1, fname_base);
3008 tree1->session->transport->oplock.handler = torture_oplock_handler;
3009 tree1->session->transport->oplock.private_data = tree1;
3011 tree2->session->transport->oplock.handler = torture_oplock_handler;
3012 tree2->session->transport->oplock.private_data = tree2;
3014 /* Setup generic open parameters. */
3015 ZERO_STRUCT(io.smb2);
3016 io.generic.level = RAW_OPEN_SMB2;
3017 io.smb2.in.desired_access = (SEC_FILE_READ_DATA |
3018 SEC_FILE_WRITE_DATA |
3019 SEC_FILE_APPEND_DATA |
3020 SEC_STD_READ_CONTROL);
3021 io.smb2.in.alloc_size = 0;
3022 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3023 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3024 NTCREATEX_SHARE_ACCESS_WRITE;
3025 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3026 io.smb2.in.create_options = 0;
3027 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3028 io.smb2.in.security_flags = 0;
3030 /* Create the file with a stream */
3031 io.smb2.in.fname = fname_stream;
3032 io.smb2.in.create_flags = 0;
3033 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
3034 status = smb2_create(tree1, tctx, &(io.smb2));
3035 torture_assert_ntstatus_ok(tctx, status, "Error creating file");
3036 smb2_util_close(tree1, io.smb2.out.file.handle);
3038 /* Change the disposition to open now that the file has been created. */
3039 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
3041 /* Try some permutations of taking oplocks on streams. */
3042 for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
3043 const char *fname = *stream_oplock_results[i].fname;
3044 bool open_base_file = stream_oplock_results[i].open_base_file;
3045 uint32_t oplock_req = stream_oplock_results[i].oplock_req;
3046 uint32_t oplock_granted =
3047 stream_oplock_results[i].oplock_granted;
3049 if (open_base_file) {
3050 torture_comment(tctx, "Opening base file: %s with "
3051 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3052 io.smb2.in.fname = fname_base;
3053 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3054 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3055 status = smb2_create(tree2, tctx, &(io.smb2));
3056 torture_assert_ntstatus_ok(tctx, status,
3057 "Error opening file");
3058 CHECK_VAL(io.smb2.out.oplock_level,
3059 SMB2_OPLOCK_LEVEL_BATCH);
3060 h_base = io.smb2.out.file.handle;
3063 torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
3064 fname, oplock_req);
3065 io.smb2.in.fname = fname;
3066 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3067 io.smb2.in.oplock_level = oplock_req;
3069 /* Do the open with the desired oplock on the stream. */
3070 status = smb2_create(tree1, tctx, &(io.smb2));
3071 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3072 CHECK_VAL(io.smb2.out.oplock_level, oplock_granted);
3073 smb2_util_close(tree1, io.smb2.out.file.handle);
3075 /* Cleanup the base file if it was opened. */
3076 if (open_base_file)
3077 smb2_util_close(tree2, h_base);
3080 /* Open the stream with an exclusive oplock. */
3081 torture_comment(tctx, "Opening stream: %s with %d\n",
3082 fname_stream, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3083 io.smb2.in.fname = fname_stream;
3084 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3085 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3086 status = smb2_create(tree1, tctx, &(io.smb2));
3087 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3088 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3089 h_stream = io.smb2.out.file.handle;
3091 /* Open the base file and see if it contends. */
3092 ZERO_STRUCT(break_info);
3093 torture_comment(tctx, "Opening base file: %s with %d\n",
3094 fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3095 io.smb2.in.fname = fname_base;
3096 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3097 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3098 status = smb2_create(tree2, tctx, &(io.smb2));
3099 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3100 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3101 smb2_util_close(tree2, io.smb2.out.file.handle);
3103 torture_wait_for_oplock_break(tctx);
3104 CHECK_VAL(break_info.count, 0);
3105 CHECK_VAL(break_info.failures, 0);
3107 /* Open the stream again to see if it contends. */
3108 ZERO_STRUCT(break_info);
3109 torture_comment(tctx, "Opening stream again: %s with "
3110 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3111 io.smb2.in.fname = fname_stream;
3112 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3113 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3114 status = smb2_create(tree2, tctx, &(io.smb2));
3115 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3116 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3117 smb2_util_close(tree2, io.smb2.out.file.handle);
3119 torture_wait_for_oplock_break(tctx);
3120 CHECK_VAL(break_info.count, 1);
3121 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
3122 CHECK_VAL(break_info.failures, 0);
3124 /* Close the stream. */
3125 if (h_stream.data[0] != -1) {
3126 smb2_util_close(tree1, h_stream);
3129 smb2_util_close(tree1, h);
3131 smb2_deltree(tree1, BASEDIR);
3132 return ret;
3135 static bool test_smb2_oplock_doc(struct torture_context *tctx, struct smb2_tree *tree,
3136 struct smb2_tree *tree2)
3138 const char *fname = BASEDIR "\\test_oplock_doc.dat";
3139 NTSTATUS status;
3140 bool ret = true;
3141 union smb_open io;
3142 struct smb2_handle h, h1;
3143 union smb_setfileinfo sfinfo;
3145 status = torture_smb2_testdir(tree, BASEDIR, &h);
3146 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3147 smb2_util_close(tree, h);
3149 /* cleanup */
3150 smb2_util_unlink(tree, fname);
3151 tree->session->transport->oplock.handler = torture_oplock_handler;
3152 tree->session->transport->oplock.private_data = tree;
3155 base ntcreatex parms
3157 ZERO_STRUCT(io.smb2);
3158 io.generic.level = RAW_OPEN_SMB2;
3159 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3160 io.smb2.in.alloc_size = 0;
3161 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3162 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
3163 NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
3164 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3165 io.smb2.in.create_options = 0;
3166 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3167 io.smb2.in.security_flags = 0;
3168 io.smb2.in.fname = fname;
3170 torture_comment(tctx, "open a file with a batch oplock\n");
3171 ZERO_STRUCT(break_info);
3172 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3173 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3175 status = smb2_create(tree, tctx, &(io.smb2));
3176 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3177 h1 = io.smb2.out.file.handle;
3178 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3180 torture_comment(tctx, "Set delete on close\n");
3181 ZERO_STRUCT(sfinfo);
3182 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
3183 sfinfo.generic.in.file.handle = h1;
3184 sfinfo.disposition_info.in.delete_on_close = 1;
3185 status = smb2_setinfo_file(tree, &sfinfo);
3186 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3188 torture_comment(tctx, "2nd open should not break and get "
3189 "DELETE_PENDING\n");
3190 ZERO_STRUCT(break_info);
3191 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
3192 io.smb2.in.create_options = 0;
3193 io.smb2.in.desired_access = SEC_FILE_READ_DATA;
3194 status = smb2_create(tree2, tctx, &io.smb2);
3195 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DELETE_PENDING,
3196 "Incorrect status");
3197 CHECK_VAL(break_info.count, 0);
3199 smb2_util_close(tree, h1);
3201 smb2_util_unlink(tree, fname);
3202 smb2_deltree(tree, BASEDIR);
3203 return ret;
3206 /* Open a file with a batch oplock, then open it again from a second client
3207 * requesting no oplock. Having two open file handles should break our own
3208 * oplock during BRL acquisition.
3210 static bool test_smb2_oplock_brl1(struct torture_context *tctx,
3211 struct smb2_tree *tree1,
3212 struct smb2_tree *tree2)
3214 const char *fname = BASEDIR "\\test_batch_brl.dat";
3215 /*int fname, f;*/
3216 bool ret = true;
3217 uint8_t buf[1000];
3218 union smb_open io;
3219 NTSTATUS status;
3220 struct smb2_lock lck;
3221 struct smb2_lock_element lock[1];
3222 struct smb2_handle h, h1, h2;
3224 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3225 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3227 /* cleanup */
3228 smb2_util_unlink(tree1, fname);
3230 tree1->session->transport->oplock.handler =
3231 torture_oplock_handler_two_notifications;
3232 tree1->session->transport->oplock.private_data = tree1;
3235 base ntcreatex parms
3237 ZERO_STRUCT(io.smb2);
3238 io.generic.level = RAW_OPEN_SMB2;
3239 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3240 SEC_RIGHTS_FILE_WRITE;
3241 io.smb2.in.alloc_size = 0;
3242 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3243 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3244 NTCREATEX_SHARE_ACCESS_WRITE;
3245 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3246 io.smb2.in.create_options = 0;
3247 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3248 io.smb2.in.security_flags = 0;
3249 io.smb2.in.fname = fname;
3252 with a batch oplock we get a break
3254 torture_comment(tctx, "open with batch oplock\n");
3255 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3256 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3258 status = smb2_create(tree1, tctx, &(io.smb2));
3259 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3260 h1 = io.smb2.out.file.handle;
3261 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3263 /* create a file with bogus data */
3264 memset(buf, 0, sizeof(buf));
3266 status = smb2_util_write(tree1, h1,buf, 0, sizeof(buf));
3267 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3268 torture_comment(tctx, "Failed to create file\n");
3269 ret = false;
3270 goto done;
3273 torture_comment(tctx, "a 2nd open should give a break\n");
3274 ZERO_STRUCT(break_info);
3276 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3277 io.smb2.in.oplock_level = 0;
3278 status = smb2_create(tree2, tctx, &(io.smb2));
3279 h2 = io.smb2.out.file.handle;
3280 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3282 torture_wait_for_oplock_break(tctx);
3283 CHECK_VAL(break_info.count, 1);
3284 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3285 CHECK_VAL(break_info.failures, 0);
3286 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3288 ZERO_STRUCT(break_info);
3290 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3292 ZERO_STRUCT(lock);
3294 lock[0].offset = 0;
3295 lock[0].length = 4;
3296 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3297 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3299 ZERO_STRUCT(lck);
3300 lck.in.file.handle = h1;
3301 lck.in.locks = &lock[0];
3302 lck.in.lock_count = 1;
3303 status = smb2_lock(tree1, &lck);
3304 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3306 torture_wait_for_oplock_break(tctx);
3307 CHECK_VAL(break_info.count, 1);
3308 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3309 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3310 CHECK_VAL(break_info.failures, 0);
3312 /* expect no oplock break */
3313 ZERO_STRUCT(break_info);
3314 lock[0].offset = 2;
3315 status = smb2_lock(tree1, &lck);
3316 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3317 "Incorrect status");
3319 torture_wait_for_oplock_break(tctx);
3320 CHECK_VAL(break_info.count, 0);
3321 CHECK_VAL(break_info.level, 0);
3322 CHECK_VAL(break_info.failures, 0);
3324 smb2_util_close(tree1, h1);
3325 smb2_util_close(tree2, h2);
3326 smb2_util_close(tree1, h);
3328 done:
3329 smb2_deltree(tree1, BASEDIR);
3330 return ret;
3334 /* Open a file with a batch oplock on one tree and then acquire a brl.
3335 * We should not contend our own oplock.
3337 static bool test_smb2_oplock_brl2(struct torture_context *tctx, struct smb2_tree *tree1)
3339 const char *fname = BASEDIR "\\test_batch_brl.dat";
3340 /*int fname, f;*/
3341 bool ret = true;
3342 uint8_t buf[1000];
3343 union smb_open io;
3344 NTSTATUS status;
3345 struct smb2_handle h, h1;
3346 struct smb2_lock lck;
3347 struct smb2_lock_element lock[1];
3349 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3350 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3352 /* cleanup */
3353 smb2_util_unlink(tree1, fname);
3355 tree1->session->transport->oplock.handler = torture_oplock_handler;
3356 tree1->session->transport->oplock.private_data = tree1;
3359 base ntcreatex parms
3361 ZERO_STRUCT(io.smb2);
3362 io.generic.level = RAW_OPEN_SMB2;
3363 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3364 SEC_RIGHTS_FILE_WRITE;
3365 io.smb2.in.alloc_size = 0;
3366 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3367 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3368 NTCREATEX_SHARE_ACCESS_WRITE;
3369 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3370 io.smb2.in.create_options = 0;
3371 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3372 io.smb2.in.security_flags = 0;
3373 io.smb2.in.fname = fname;
3376 with a batch oplock we get a break
3378 torture_comment(tctx, "open with batch oplock\n");
3379 ZERO_STRUCT(break_info);
3380 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3381 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3383 status = smb2_create(tree1, tctx, &(io.smb2));
3384 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3385 h1 = io.smb2.out.file.handle;
3386 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3388 /* create a file with bogus data */
3389 memset(buf, 0, sizeof(buf));
3391 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3392 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3393 torture_comment(tctx, "Failed to create file\n");
3394 ret = false;
3395 goto done;
3398 ZERO_STRUCT(break_info);
3400 torture_comment(tctx, "a self BRL acquisition should not break to "
3401 "none\n");
3403 ZERO_STRUCT(lock);
3405 lock[0].offset = 0;
3406 lock[0].length = 4;
3407 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3408 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3410 ZERO_STRUCT(lck);
3411 lck.in.file.handle = h1;
3412 lck.in.locks = &lock[0];
3413 lck.in.lock_count = 1;
3414 status = smb2_lock(tree1, &lck);
3415 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3417 lock[0].offset = 2;
3418 status = smb2_lock(tree1, &lck);
3419 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3420 "Incorrect status");
3422 /* With one file handle open a BRL should not contend our oplock.
3423 * Thus, no oplock break will be received and the entire break_info
3424 * struct will be 0 */
3425 torture_wait_for_oplock_break(tctx);
3426 CHECK_VAL(break_info.count, 0);
3427 CHECK_VAL(break_info.level, 0);
3428 CHECK_VAL(break_info.failures, 0);
3430 smb2_util_close(tree1, h1);
3431 smb2_util_close(tree1, h);
3433 done:
3434 smb2_deltree(tree1, BASEDIR);
3435 return ret;
3438 /* Open a file with a batch oplock twice from one tree and then acquire a
3439 * brl. BRL acquisition should break our own oplock.
3441 static bool test_smb2_oplock_brl3(struct torture_context *tctx, struct smb2_tree *tree1)
3443 const char *fname = BASEDIR "\\test_batch_brl.dat";
3444 bool ret = true;
3445 uint8_t buf[1000];
3446 union smb_open io;
3447 NTSTATUS status;
3448 struct smb2_handle h, h1, h2;
3449 struct smb2_lock lck;
3450 struct smb2_lock_element lock[1];
3452 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3453 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3455 /* cleanup */
3456 smb2_util_unlink(tree1, fname);
3457 tree1->session->transport->oplock.handler =
3458 torture_oplock_handler_two_notifications;
3459 tree1->session->transport->oplock.private_data = tree1;
3462 base ntcreatex parms
3464 ZERO_STRUCT(io.smb2);
3465 io.generic.level = RAW_OPEN_SMB2;
3466 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3467 SEC_RIGHTS_FILE_WRITE;
3468 io.smb2.in.alloc_size = 0;
3469 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3470 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3471 NTCREATEX_SHARE_ACCESS_WRITE;
3472 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3473 io.smb2.in.create_options = 0;
3474 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3475 io.smb2.in.security_flags = 0;
3476 io.smb2.in.fname = fname;
3479 with a batch oplock we get a break
3481 torture_comment(tctx, "open with batch oplock\n");
3482 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3483 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3485 status = smb2_create(tree1, tctx, &(io.smb2));
3486 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3487 h1 = io.smb2.out.file.handle;
3488 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3490 /* create a file with bogus data */
3491 memset(buf, 0, sizeof(buf));
3492 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3494 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3495 torture_comment(tctx, "Failed to create file\n");
3496 ret = false;
3497 goto done;
3500 torture_comment(tctx, "a 2nd open should give a break\n");
3501 ZERO_STRUCT(break_info);
3503 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3504 io.smb2.in.oplock_level = 0;
3505 status = smb2_create(tree1, tctx, &(io.smb2));
3506 h2 = io.smb2.out.file.handle;
3507 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3508 CHECK_VAL(break_info.count, 1);
3509 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3510 CHECK_VAL(break_info.failures, 0);
3511 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3513 ZERO_STRUCT(break_info);
3515 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3517 ZERO_STRUCT(lock);
3519 lock[0].offset = 0;
3520 lock[0].length = 4;
3521 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3522 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3524 ZERO_STRUCT(lck);
3525 lck.in.file.handle = h1;
3526 lck.in.locks = &lock[0];
3527 lck.in.lock_count = 1;
3528 status = smb2_lock(tree1, &lck);
3529 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3531 torture_wait_for_oplock_break(tctx);
3532 CHECK_VAL(break_info.count, 1);
3533 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3534 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3535 CHECK_VAL(break_info.failures, 0);
3537 /* expect no oplock break */
3538 ZERO_STRUCT(break_info);
3539 lock[0].offset = 2;
3540 status = smb2_lock(tree1, &lck);
3541 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3542 "Incorrect status");
3544 torture_wait_for_oplock_break(tctx);
3545 CHECK_VAL(break_info.count, 0);
3546 CHECK_VAL(break_info.level, 0);
3547 CHECK_VAL(break_info.failures, 0);
3549 smb2_util_close(tree1, h1);
3550 smb2_util_close(tree1, h2);
3551 smb2_util_close(tree1, h);
3553 done:
3554 smb2_deltree(tree1, BASEDIR);
3555 return ret;
3559 /* Starting the SMB2 specific oplock tests at 500 so we can keep the SMB1
3560 * tests in sync with an identically numbered SMB2 test */
3562 /* Test whether the server correctly returns an error when we send
3563 * a response to a levelII to none oplock notification. */
3564 static bool test_smb2_oplock_levelII500(struct torture_context *tctx,
3565 struct smb2_tree *tree1)
3567 const char *fname = BASEDIR "\\test_levelII500.dat";
3568 NTSTATUS status;
3569 bool ret = true;
3570 union smb_open io;
3571 struct smb2_handle h, h1;
3572 char c = 0;
3574 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3575 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3577 /* cleanup */
3578 smb2_util_unlink(tree1, fname);
3580 tree1->session->transport->oplock.handler = torture_oplock_handler;
3581 tree1->session->transport->oplock.private_data = tree1;
3584 base ntcreatex parms
3586 ZERO_STRUCT(io.smb2);
3587 io.generic.level = RAW_OPEN_SMB2;
3588 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3589 io.smb2.in.alloc_size = 0;
3590 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3591 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3592 io.smb2.in.create_options = 0;
3593 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3594 io.smb2.in.security_flags = 0;
3595 io.smb2.in.fname = fname;
3597 torture_comment(tctx, "LEVELII500: acknowledging a break from II to "
3598 "none should return an error\n");
3599 ZERO_STRUCT(break_info);
3601 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3602 SEC_RIGHTS_FILE_WRITE;
3603 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3604 NTCREATEX_SHARE_ACCESS_WRITE;
3605 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3606 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
3607 status = smb2_create(tree1, tctx, &(io.smb2));
3608 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3609 h1 = io.smb2.out.file.handle;
3610 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3612 ZERO_STRUCT(break_info);
3614 torture_comment(tctx, "write should trigger a break to none and when "
3615 "we reply, an oplock break failure\n");
3616 smb2_util_write(tree1, h1, &c, 0, 1);
3618 /* Wait several times to receive both the break notification, and the
3619 * NT_STATUS_INVALID_OPLOCK_PROTOCOL error in the break response */
3620 torture_wait_for_oplock_break(tctx);
3621 torture_wait_for_oplock_break(tctx);
3622 torture_wait_for_oplock_break(tctx);
3623 torture_wait_for_oplock_break(tctx);
3625 /* There appears to be a race condition in W2K8 and W2K8R2 where
3626 * sometimes the server will happily reply to our break response with
3627 * NT_STATUS_OK, and sometimes it will return the OPLOCK_PROTOCOL
3628 * error. As the MS-SMB2 doc states that a client should not reply to
3629 * a level2 to none break notification, I'm leaving the protocol error
3630 * as the expected behavior. */
3631 CHECK_VAL(break_info.count, 1);
3632 CHECK_VAL(break_info.level, 0);
3633 CHECK_VAL(break_info.failures, 1);
3634 torture_assert_ntstatus_equal(tctx, break_info.failure_status,
3635 NT_STATUS_INVALID_OPLOCK_PROTOCOL,
3636 "Incorrect status");
3638 smb2_util_close(tree1, h1);
3639 smb2_util_close(tree1, h);
3641 smb2_deltree(tree1, BASEDIR);
3642 return ret;
3646 * Test a double-break. Open a file with exclusive. Send off a second open
3647 * request with OPEN_IF, triggering a break to level2. This should respond
3648 * with level2. Before replying to the break to level2, fire off a third open
3649 * with OVERWRITE_IF. The expected sequence would be that the 3rd opener gets
3650 * a level2 immediately triggered by a break to none, but that seems not the
3651 * case. Still investigating what the right behaviour should be.
3654 struct levelII501_state {
3655 struct torture_context *tctx;
3656 struct smb2_tree *tree1;
3657 struct smb2_tree *tree2;
3658 struct smb2_tree *tree3;
3659 struct smb2_handle h;
3660 struct smb2_handle h1;
3661 union smb_open io;
3663 struct smb2_handle break_handle;
3664 uint8_t break_to;
3665 struct smb2_break br;
3667 bool done;
3670 static bool torture_oplock_break_delay(struct smb2_transport *transport,
3671 const struct smb2_handle *handle,
3672 uint8_t level, void *private_data);
3673 static void levelII501_break_done(struct smb2_request *req);
3674 static void levelII501_open1_done(struct smb2_request *req);
3675 static void levelII501_open2_done(struct smb2_request *req);
3676 static void levelII501_2ndopen_cb(struct tevent_context *ev,
3677 struct tevent_timer *te,
3678 struct timeval current_time,
3679 void *private_data);
3680 static void levelII501_break_timeout_cb(struct tevent_context *ev,
3681 struct tevent_timer *te,
3682 struct timeval current_time,
3683 void *private_data);
3684 static void levelII501_timeout_cb(struct tevent_context *ev,
3685 struct tevent_timer *te,
3686 struct timeval current_time,
3687 void *private_data);
3689 static bool test_smb2_oplock_levelII501(struct torture_context *tctx,
3690 struct smb2_tree *tree1,
3691 struct smb2_tree *tree2)
3693 const char *fname = BASEDIR "\\test_levelII501.dat";
3694 NTSTATUS status;
3695 bool ret = true;
3696 struct levelII501_state *state;
3697 struct smb2_request *req;
3698 struct tevent_timer *te;
3700 state = talloc(tctx, struct levelII501_state);
3701 state->tctx = tctx;
3702 state->done = false;
3703 state->tree1 = tree1;
3704 state->tree2 = tree2;
3706 if (!torture_smb2_connection(tctx, &state->tree3)) {
3707 torture_fail(tctx, "Establishing SMB2 connection failed\n");
3708 return false;
3711 status = torture_smb2_testdir(tree1, BASEDIR, &state->h);
3712 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3714 /* cleanup */
3715 smb2_util_unlink(tree1, fname);
3718 base ntcreatex parms
3720 ZERO_STRUCT(state->io.smb2);
3721 state->io.generic.level = RAW_OPEN_SMB2;
3722 state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3723 state->io.smb2.in.alloc_size = 0;
3724 state->io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3725 state->io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3726 state->io.smb2.in.create_options = 0;
3727 state->io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3728 state->io.smb2.in.security_flags = 0;
3729 state->io.smb2.in.fname = fname;
3731 torture_comment(tctx, "LEVELII501: Test double break sequence\n");
3732 ZERO_STRUCT(break_info);
3734 state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3735 SEC_RIGHTS_FILE_WRITE;
3736 state->io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3737 NTCREATEX_SHARE_ACCESS_WRITE;
3738 state->io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3739 state->io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3741 tree1->session->transport->oplock.handler = torture_oplock_break_delay;
3742 tree1->session->transport->oplock.private_data = state;
3744 status = smb2_create(tree1, tctx, &(state->io.smb2));
3745 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3746 state->h1 = state->io.smb2.out.file.handle;
3747 CHECK_VAL(state->io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3750 * Trigger a break to level2
3753 req = smb2_create_send(tree2, &state->io.smb2);
3754 req->async.fn = levelII501_open1_done;
3755 req->async.private_data = state;
3757 te = tevent_add_timer(
3758 tctx->ev, tctx, tevent_timeval_current_ofs(0, 200000),
3759 levelII501_2ndopen_cb, state);
3760 torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
3762 te = tevent_add_timer(
3763 tctx->ev, tctx, tevent_timeval_current_ofs(2, 0),
3764 levelII501_timeout_cb, state);
3765 torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
3767 while (!state->done) {
3768 if (tevent_loop_once(tctx->ev) != 0) {
3769 torture_comment(tctx, "tevent_loop_once failed\n");
3773 return ret;
3777 * Fire off a second open after a little timeout
3780 static void levelII501_2ndopen_cb(struct tevent_context *ev,
3781 struct tevent_timer *te,
3782 struct timeval current_time,
3783 void *private_data)
3785 struct levelII501_state *state = talloc_get_type_abort(
3786 private_data, struct levelII501_state);
3787 struct smb2_request *req;
3789 state->io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
3790 req = smb2_create_send(state->tree3, &state->io.smb2);
3791 req->async.fn = levelII501_open2_done;
3792 req->async.private_data = state;
3796 * Postpone the break response by 500 msec
3798 static bool torture_oplock_break_delay(struct smb2_transport *transport,
3799 const struct smb2_handle *handle,
3800 uint8_t level, void *private_data)
3802 struct levelII501_state *state = talloc_get_type_abort(
3803 private_data, struct levelII501_state);
3804 const char *name;
3805 struct tevent_timer *te;
3807 break_info.handle = *handle;
3808 break_info.level = level;
3809 break_info.count++;
3811 state->break_handle = *handle;
3812 state->break_to = level;
3814 switch(level) {
3815 case SMB2_OPLOCK_LEVEL_II:
3816 name = "level II";
3817 break;
3818 case SMB2_OPLOCK_LEVEL_NONE:
3819 name = "none";
3820 break;
3821 default:
3822 name = "unknown";
3823 break;
3825 printf("Got break to %s [0x%02X] in oplock handler, postponing "
3826 "break response for 500msec\n", name, level);
3828 te = tevent_add_timer(
3829 state->tctx->ev, state->tctx,
3830 tevent_timeval_current_ofs(0, 500000),
3831 levelII501_break_timeout_cb, state);
3832 torture_assert(state->tctx, te != NULL, "tevent_add_timer failed\n");
3834 return true;
3837 static void levelII501_break_timeout_cb(struct tevent_context *ev,
3838 struct tevent_timer *te,
3839 struct timeval current_time,
3840 void *private_data)
3842 struct levelII501_state *state = talloc_get_type_abort(
3843 private_data, struct levelII501_state);
3844 struct smb2_request *req;
3846 talloc_free(te);
3848 ZERO_STRUCT(state->br);
3849 state->br.in.file.handle = state->break_handle;
3850 state->br.in.oplock_level = state->break_to;
3852 req = smb2_break_send(state->tree1, &state->br);
3853 req->async.fn = levelII501_break_done;
3854 req->async.private_data = state;
3857 static void levelII501_break_done(struct smb2_request *req)
3859 struct smb2_break io;
3860 NTSTATUS status;
3862 status = smb2_break_recv(req, &io);
3863 printf("break done: %s\n", nt_errstr(status));
3866 static void levelII501_open1_done(struct smb2_request *req)
3868 struct levelII501_state *state = talloc_get_type_abort(
3869 req->async.private_data, struct levelII501_state);
3870 struct smb2_create io;
3871 NTSTATUS status;
3873 status = smb2_create_recv(req, state, &io);
3874 printf("open1 done: %s\n", nt_errstr(status));
3877 static void levelII501_open2_done(struct smb2_request *req)
3879 struct levelII501_state *state = talloc_get_type_abort(
3880 req->async.private_data, struct levelII501_state);
3881 struct smb2_create io;
3882 NTSTATUS status;
3884 status = smb2_create_recv(req, state, &io);
3885 printf("open2 done: %s\n", nt_errstr(status));
3888 static void levelII501_timeout_cb(struct tevent_context *ev,
3889 struct tevent_timer *te,
3890 struct timeval current_time,
3891 void *private_data)
3893 struct levelII501_state *state = talloc_get_type_abort(
3894 private_data, struct levelII501_state);
3895 talloc_free(te);
3896 state->done = true;
3899 static bool test_smb2_oplock_levelII502(struct torture_context *tctx,
3900 struct smb2_tree *tree1,
3901 struct smb2_tree *tree2)
3904 const char *fname = BASEDIR "\\test_levelII502.dat";
3905 NTSTATUS status;
3906 union smb_open io;
3907 struct smb2_close closeio;
3908 struct smb2_handle h;
3910 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3911 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3913 /* cleanup */
3914 smb2_util_unlink(tree1, fname);
3917 base ntcreatex parms
3919 ZERO_STRUCT(io.smb2);
3920 io.generic.level = RAW_OPEN_SMB2;
3921 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3922 io.smb2.in.alloc_size = 0;
3923 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3924 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3925 io.smb2.in.create_options = 0;
3926 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3927 io.smb2.in.security_flags = 0;
3928 io.smb2.in.fname = fname;
3930 torture_comment(
3931 tctx,
3932 "LEVELII502: Open a stale LEVEL2 oplock with OVERWRITE");
3934 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3935 SEC_RIGHTS_FILE_WRITE;
3936 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3937 NTCREATEX_SHARE_ACCESS_WRITE;
3938 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3939 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
3940 status = smb2_create(tree1, tctx, &(io.smb2));
3941 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3942 torture_assert(tctx,
3943 io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_II,
3944 "Did not get LEVEL_II oplock\n");
3946 status = smbXcli_conn_samba_suicide(
3947 tree1->session->transport->conn, 93);
3948 torture_assert_ntstatus_ok(tctx, status, "suicide failed");
3950 sleep(1);
3952 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3953 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
3955 status = smb2_create(tree2, tctx, &(io.smb2));
3956 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3957 torture_assert(tctx,
3958 io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_BATCH,
3959 "Did not get BATCH oplock\n");
3961 closeio = (struct smb2_close) {
3962 .in.file.handle = io.smb2.out.file.handle,
3964 status = smb2_close(tree2, &closeio);
3965 torture_assert_ntstatus_equal(
3966 tctx, status, NT_STATUS_OK, "close failed");
3968 return true;
3971 struct torture_suite *torture_smb2_oplocks_init(TALLOC_CTX *ctx)
3973 struct torture_suite *suite =
3974 torture_suite_create(ctx, "oplock");
3976 torture_suite_add_2smb2_test(suite, "exclusive1", test_smb2_oplock_exclusive1);
3977 torture_suite_add_2smb2_test(suite, "exclusive2", test_smb2_oplock_exclusive2);
3978 torture_suite_add_2smb2_test(suite, "exclusive3", test_smb2_oplock_exclusive3);
3979 torture_suite_add_2smb2_test(suite, "exclusive4", test_smb2_oplock_exclusive4);
3980 torture_suite_add_2smb2_test(suite, "exclusive5", test_smb2_oplock_exclusive5);
3981 torture_suite_add_2smb2_test(suite, "exclusive6", test_smb2_oplock_exclusive6);
3982 torture_suite_add_2smb2_test(suite, "exclusive9",
3983 test_smb2_oplock_exclusive9);
3984 torture_suite_add_2smb2_test(suite, "batch1", test_smb2_oplock_batch1);
3985 torture_suite_add_2smb2_test(suite, "batch2", test_smb2_oplock_batch2);
3986 torture_suite_add_2smb2_test(suite, "batch3", test_smb2_oplock_batch3);
3987 torture_suite_add_2smb2_test(suite, "batch4", test_smb2_oplock_batch4);
3988 torture_suite_add_2smb2_test(suite, "batch5", test_smb2_oplock_batch5);
3989 torture_suite_add_2smb2_test(suite, "batch6", test_smb2_oplock_batch6);
3990 torture_suite_add_2smb2_test(suite, "batch7", test_smb2_oplock_batch7);
3991 torture_suite_add_2smb2_test(suite, "batch8", test_smb2_oplock_batch8);
3992 torture_suite_add_2smb2_test(suite, "batch9", test_smb2_oplock_batch9);
3993 torture_suite_add_2smb2_test(suite, "batch9a", test_smb2_oplock_batch9a);
3994 torture_suite_add_2smb2_test(suite, "batch10", test_smb2_oplock_batch10);
3995 torture_suite_add_2smb2_test(suite, "batch11", test_smb2_oplock_batch11);
3996 torture_suite_add_2smb2_test(suite, "batch12", test_smb2_oplock_batch12);
3997 torture_suite_add_2smb2_test(suite, "batch13", test_smb2_oplock_batch13);
3998 torture_suite_add_2smb2_test(suite, "batch14", test_smb2_oplock_batch14);
3999 torture_suite_add_2smb2_test(suite, "batch15", test_smb2_oplock_batch15);
4000 torture_suite_add_2smb2_test(suite, "batch16", test_smb2_oplock_batch16);
4001 torture_suite_add_1smb2_test(suite, "batch19", test_smb2_oplock_batch19);
4002 torture_suite_add_2smb2_test(suite, "batch20", test_smb2_oplock_batch20);
4003 torture_suite_add_1smb2_test(suite, "batch21", test_smb2_oplock_batch21);
4004 torture_suite_add_1smb2_test(suite, "batch22", test_smb2_oplock_batch22);
4005 torture_suite_add_2smb2_test(suite, "batch23", test_smb2_oplock_batch23);
4006 torture_suite_add_2smb2_test(suite, "batch24", test_smb2_oplock_batch24);
4007 torture_suite_add_1smb2_test(suite, "batch25", test_smb2_oplock_batch25);
4008 torture_suite_add_1smb2_test(suite, "batch26", test_smb2_oplock_batch26);
4009 torture_suite_add_2smb2_test(suite, "stream1", test_raw_oplock_stream1);
4010 torture_suite_add_2smb2_test(suite, "doc", test_smb2_oplock_doc);
4011 torture_suite_add_2smb2_test(suite, "brl1", test_smb2_oplock_brl1);
4012 torture_suite_add_1smb2_test(suite, "brl2", test_smb2_oplock_brl2);
4013 torture_suite_add_1smb2_test(suite, "brl3", test_smb2_oplock_brl3);
4014 torture_suite_add_1smb2_test(suite, "levelii500", test_smb2_oplock_levelII500);
4015 torture_suite_add_2smb2_test(suite, "levelii501",
4016 test_smb2_oplock_levelII501);
4017 torture_suite_add_2smb2_test(suite, "levelii502",
4018 test_smb2_oplock_levelII502);
4019 suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
4021 return suite;
4025 stress testing of oplocks
4027 bool test_smb2_bench_oplock(struct torture_context *tctx,
4028 struct smb2_tree *tree)
4030 struct smb2_tree **trees;
4031 bool ret = true;
4032 NTSTATUS status;
4033 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4034 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
4035 int i, count=0;
4036 int timelimit = torture_setting_int(tctx, "timelimit", 10);
4037 union smb_open io;
4038 struct timeval tv;
4039 struct smb2_handle h;
4041 trees = talloc_array(mem_ctx, struct smb2_tree *, torture_nprocs);
4043 torture_comment(tctx, "Opening %d connections\n", torture_nprocs);
4044 for (i=0;i<torture_nprocs;i++) {
4045 if (!torture_smb2_connection(tctx, &trees[i])) {
4046 return false;
4048 talloc_steal(mem_ctx, trees[i]);
4049 trees[i]->session->transport->oplock.handler =
4050 torture_oplock_handler_close;
4051 trees[i]->session->transport->oplock.private_data = trees[i];
4054 status = torture_smb2_testdir(trees[0], BASEDIR, &h);
4055 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4057 ZERO_STRUCT(io.smb2);
4058 io.smb2.level = RAW_OPEN_SMB2;
4059 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4060 io.smb2.in.alloc_size = 0;
4061 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4062 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4063 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4064 io.smb2.in.create_options = 0;
4065 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4066 io.smb2.in.security_flags = 0;
4067 io.smb2.in.fname = BASEDIR "\\test.dat";
4068 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4069 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4071 tv = timeval_current();
4074 we open the same file with SHARE_ACCESS_NONE from all the
4075 connections in a round robin fashion. Each open causes an
4076 oplock break on the previous connection, which is answered
4077 by the oplock_handler_close() to close the file.
4079 This measures how fast we can pass on oplocks, and stresses
4080 the oplock handling code
4082 torture_comment(tctx, "Running for %d seconds\n", timelimit);
4083 while (timeval_elapsed(&tv) < timelimit) {
4084 for (i=0;i<torture_nprocs;i++) {
4085 status = smb2_create(trees[i], mem_ctx, &(io.smb2));
4086 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
4087 count++;
4090 if (torture_setting_bool(tctx, "progress", true)) {
4091 torture_comment(tctx, "%.2f ops/second\r",
4092 count/timeval_elapsed(&tv));
4096 torture_comment(tctx, "%.2f ops/second\n", count/timeval_elapsed(&tv));
4097 smb2_util_close(trees[0], io.smb2.out.file.handle);
4098 smb2_util_unlink(trees[0], BASEDIR "\\test.dat");
4099 smb2_deltree(trees[0], BASEDIR);
4100 talloc_free(mem_ctx);
4101 return ret;
4104 static struct hold_oplock_info {
4105 const char *fname;
4106 bool close_on_break;
4107 uint32_t share_access;
4108 struct smb2_handle handle;
4109 } hold_info[] = {
4111 .fname = BASEDIR "\\notshared_close",
4112 .close_on_break = true,
4113 .share_access = NTCREATEX_SHARE_ACCESS_NONE,
4116 .fname = BASEDIR "\\notshared_noclose",
4117 .close_on_break = false,
4118 .share_access = NTCREATEX_SHARE_ACCESS_NONE,
4121 .fname = BASEDIR "\\shared_close",
4122 .close_on_break = true,
4123 .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
4126 .fname = BASEDIR "\\shared_noclose",
4127 .close_on_break = false,
4128 .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
4132 static bool torture_oplock_handler_hold(struct smb2_transport *transport,
4133 const struct smb2_handle *handle,
4134 uint8_t level, void *private_data)
4136 struct hold_oplock_info *info;
4137 int i;
4139 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
4140 if (smb2_util_handle_equal(hold_info[i].handle, *handle))
4141 break;
4144 if (i == ARRAY_SIZE(hold_info)) {
4145 printf("oplock break for unknown handle 0x%llx%llx\n",
4146 (unsigned long long) handle->data[0],
4147 (unsigned long long) handle->data[1]);
4148 return false;
4151 info = &hold_info[i];
4153 if (info->close_on_break) {
4154 printf("oplock break on %s - closing\n", info->fname);
4155 torture_oplock_handler_close(transport, handle,
4156 level, private_data);
4157 return true;
4160 printf("oplock break on %s - acking break\n", info->fname);
4161 printf("Acking to none in oplock handler\n");
4163 torture_oplock_handler_ack_to_none(transport, handle,
4164 level, private_data);
4165 return true;
4169 used for manual testing of oplocks - especially interaction with
4170 other filesystems (such as NFS and local access)
4172 bool test_smb2_hold_oplock(struct torture_context *tctx,
4173 struct smb2_tree *tree)
4175 struct torture_context *mem_ctx = talloc_new(tctx);
4176 struct tevent_context *ev = tctx->ev;
4177 int i;
4178 struct smb2_handle h;
4179 NTSTATUS status;
4181 torture_comment(tctx, "Setting up open files with oplocks in %s\n",
4182 BASEDIR);
4184 status = torture_smb2_testdir(tree, BASEDIR, &h);
4185 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4187 tree->session->transport->oplock.handler = torture_oplock_handler_hold;
4188 tree->session->transport->oplock.private_data = tree;
4190 /* setup the files */
4191 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
4192 union smb_open io;
4193 char c = 1;
4195 ZERO_STRUCT(io.smb2);
4196 io.generic.level = RAW_OPEN_SMB2;
4197 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4198 io.smb2.in.alloc_size = 0;
4199 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4200 io.smb2.in.share_access = hold_info[i].share_access;
4201 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4202 io.smb2.in.create_options = 0;
4203 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4204 io.smb2.in.security_flags = 0;
4205 io.smb2.in.fname = hold_info[i].fname;
4206 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4207 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4209 torture_comment(tctx, "opening %s\n", hold_info[i].fname);
4211 status = smb2_create(tree, mem_ctx, &(io.smb2));
4212 if (!NT_STATUS_IS_OK(status)) {
4213 torture_comment(tctx, "Failed to open %s - %s\n",
4214 hold_info[i].fname, nt_errstr(status));
4215 return false;
4218 if (io.smb2.out.oplock_level != SMB2_OPLOCK_LEVEL_BATCH) {
4219 torture_comment(tctx, "Oplock not granted for %s - "
4220 "expected %d but got %d\n",
4221 hold_info[i].fname,
4222 SMB2_OPLOCK_LEVEL_BATCH,
4223 io.smb2.out.oplock_level);
4224 return false;
4226 hold_info[i].handle = io.smb2.out.file.handle;
4228 /* make the file non-zero size */
4229 status = smb2_util_write(tree, hold_info[i].handle, &c, 0, 1);
4230 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
4231 torture_comment(tctx, "Failed to write to file\n");
4232 return false;
4236 torture_comment(tctx, "Waiting for oplock events\n");
4237 tevent_loop_wait(ev);
4238 smb2_deltree(tree, BASEDIR);
4239 talloc_free(mem_ctx);
4240 return true;
4244 static bool test_smb2_kernel_oplocks1(struct torture_context *tctx,
4245 struct smb2_tree *tree)
4247 const char *fname = "test_kernel_oplock1.dat";
4248 NTSTATUS status;
4249 bool ret = true;
4250 struct smb2_create create;
4251 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4253 smb2_util_unlink(tree, fname);
4255 tree->session->transport->oplock.handler = torture_oplock_handler;
4256 tree->session->transport->oplock.private_data = tree;
4257 ZERO_STRUCT(break_info);
4259 ZERO_STRUCT(create);
4260 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4261 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4262 create.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4263 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4264 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4265 create.in.fname = fname;
4266 create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4268 status = smb2_create(tree, tctx, &create);
4269 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4270 h1 = create.out.file.handle;
4272 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4273 "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4275 ZERO_STRUCT(create);
4276 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4277 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4278 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4279 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4280 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4281 create.in.fname = fname;
4283 status = smb2_create(tree, tctx, &create);
4284 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done,
4285 "Open didn't return NT_STATUS_SHARING_VIOLATION\n");
4286 h2 = create.out.file.handle;
4288 torture_wait_for_oplock_break(tctx);
4289 if (break_info.count != 0) {
4290 torture_warning(tctx, "Open caused oplock break\n");
4293 smb2_util_close(tree, h1);
4294 smb2_util_close(tree, h2);
4296 done:
4297 if (!smb2_util_handle_empty(h1)) {
4298 smb2_util_close(tree, h1);
4300 if (!smb2_util_handle_empty(h2)) {
4301 smb2_util_close(tree, h2);
4303 smb2_util_unlink(tree, fname);
4304 return ret;
4307 static bool test_smb2_kernel_oplocks2(struct torture_context *tctx,
4308 struct smb2_tree *tree)
4310 const char *fname = "test_kernel_oplock2.dat";
4311 const char *sname = "test_kernel_oplock2.dat:foo";
4312 NTSTATUS status;
4313 bool ret = true;
4314 struct smb2_create create;
4315 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4317 smb2_util_unlink(tree, fname);
4319 tree->session->transport->oplock.handler = torture_oplock_handler;
4320 tree->session->transport->oplock.private_data = tree;
4321 ZERO_STRUCT(break_info);
4323 ZERO_STRUCT(create);
4324 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4325 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4326 create.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4327 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4328 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4329 create.in.fname = fname;
4330 create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4332 status = smb2_create(tree, tctx, &create);
4333 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4334 h1 = create.out.file.handle;
4336 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4337 "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4339 ZERO_STRUCT(create);
4340 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4341 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4342 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4343 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4344 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4345 create.in.fname = sname;
4347 status = smb2_create(tree, tctx, &create);
4348 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4349 h2 = create.out.file.handle;
4351 torture_wait_for_oplock_break(tctx);
4352 if (break_info.count != 0) {
4353 torture_warning(tctx, "Stream open caused oplock break\n");
4356 smb2_util_close(tree, h1);
4357 smb2_util_close(tree, h2);
4359 done:
4360 if (!smb2_util_handle_empty(h1)) {
4361 smb2_util_close(tree, h1);
4363 if (!smb2_util_handle_empty(h2)) {
4364 smb2_util_close(tree, h2);
4366 smb2_util_unlink(tree, fname);
4367 return ret;
4371 * 1. 1st client opens file with oplock
4372 * 2. 2nd client opens file
4374 * Verify 2 triggers an oplock break
4376 static bool test_smb2_kernel_oplocks3(struct torture_context *tctx,
4377 struct smb2_tree *tree,
4378 struct smb2_tree *tree2)
4380 const char *fname = "test_kernel_oplock3.dat";
4381 NTSTATUS status;
4382 bool ret = true;
4383 struct smb2_create create;
4384 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4386 smb2_util_unlink(tree, fname);
4387 status = torture_smb2_testfile(tree, fname, &h1);
4388 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4389 "Error creating testfile\n");
4390 smb2_util_close(tree, h1);
4391 ZERO_STRUCT(h1);
4393 tree->session->transport->oplock.handler = torture_oplock_handler;
4394 tree->session->transport->oplock.private_data = tree;
4395 ZERO_STRUCT(break_info);
4397 /* 1 */
4398 ZERO_STRUCT(create);
4399 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4400 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4401 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4402 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4403 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4404 create.in.fname = fname;
4405 create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4407 status = smb2_create(tree, tctx, &create);
4408 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4409 h1 = create.out.file.handle;
4411 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4412 "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4414 /* 2 */
4415 ZERO_STRUCT(create);
4416 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4417 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4418 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4419 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4420 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4421 create.in.fname = fname;
4423 status = smb2_create(tree2, tctx, &create);
4424 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4425 h2 = create.out.file.handle;
4427 torture_wait_for_oplock_break(tctx);
4428 torture_assert_goto(tctx, break_info.count == 1, ret, done, "Expected 1 oplock break\n");
4430 done:
4431 if (!smb2_util_handle_empty(h1)) {
4432 smb2_util_close(tree, h1);
4434 if (!smb2_util_handle_empty(h2)) {
4435 smb2_util_close(tree, h2);
4437 smb2_util_unlink(tree, fname);
4438 return ret;
4442 * 1) create testfile with stream
4443 * 2) open file r/w with batch oplock, sharing read/delete
4444 * 3) open stream on file for reading
4446 * Verify 3) doesn't trigger an oplock break
4448 static bool test_smb2_kernel_oplocks4(struct torture_context *tctx,
4449 struct smb2_tree *tree)
4451 const char *fname = "test_kernel_oplock4.dat";
4452 const char *sname = "test_kernel_oplock4.dat:foo";
4453 NTSTATUS status;
4454 bool ret = true;
4455 struct smb2_create create;
4456 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4458 tree->session->transport->oplock.handler = torture_oplock_handler;
4459 tree->session->transport->oplock.private_data = tree;
4460 ZERO_STRUCT(break_info);
4461 smb2_util_unlink(tree, fname);
4463 /* 1 */
4464 status = torture_smb2_testfile(tree, fname, &h1);
4465 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4466 "Error creating testfile\n");
4467 smb2_util_close(tree, h1);
4468 ZERO_STRUCT(h1);
4470 ZERO_STRUCT(create);
4471 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4472 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4473 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4474 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4475 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4476 create.in.fname = sname;
4478 status = smb2_create(tree, tctx, &create);
4479 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4480 h1 = create.out.file.handle;
4481 smb2_util_close(tree, h1);
4482 ZERO_STRUCT(h1);
4484 /* 2 */
4485 ZERO_STRUCT(create);
4486 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4487 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4488 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
4489 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4490 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4491 create.in.fname = fname;
4492 create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4494 status = smb2_create(tree, tctx, &create);
4495 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4496 h1 = create.out.file.handle;
4498 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_BATCH, ret, done,
4499 "Oplock level is not SMB2_OPLOCK_LEVEL_BATCH\n");
4501 ZERO_STRUCT(create);
4502 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4503 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4504 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
4505 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4506 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4507 create.in.fname = sname;
4509 status = smb2_create(tree, tctx, &create);
4510 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4511 h2 = create.out.file.handle;
4513 torture_wait_for_oplock_break(tctx);
4514 if (break_info.count != 0) {
4515 torture_warning(tctx, "Stream open caused oplock break\n");
4518 done:
4519 if (!smb2_util_handle_empty(h1)) {
4520 smb2_util_close(tree, h1);
4522 if (!smb2_util_handle_empty(h2)) {
4523 smb2_util_close(tree, h2);
4525 smb2_util_unlink(tree, fname);
4526 return ret;
4530 * 1) create testfile with stream
4531 * 2) open stream r/w with batch oplock -> batch oplock granted
4532 * 3) open stream r/o with batch oplock
4534 * Verify 3) does trigger an oplock break
4536 static bool test_smb2_kernel_oplocks5(struct torture_context *tctx,
4537 struct smb2_tree *tree)
4539 const char *fname = "test_kernel_oplock4.dat";
4540 const char *sname = "test_kernel_oplock4.dat:foo";
4541 NTSTATUS status;
4542 bool ret = true;
4543 struct smb2_create create;
4544 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4546 tree->session->transport->oplock.handler = torture_oplock_handler;
4547 tree->session->transport->oplock.private_data = tree;
4548 ZERO_STRUCT(break_info);
4549 smb2_util_unlink(tree, fname);
4551 /* 1 */
4552 status = torture_smb2_testfile(tree, fname, &h1);
4553 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4554 "Error creating testfile\n");
4555 smb2_util_close(tree, h1);
4556 ZERO_STRUCT(h1);
4558 ZERO_STRUCT(create);
4559 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4560 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4561 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4562 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4563 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4564 create.in.fname = sname;
4566 status = smb2_create(tree, tctx, &create);
4567 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4568 h1 = create.out.file.handle;
4569 smb2_util_close(tree, h1);
4570 ZERO_STRUCT(h1);
4572 /* 2 */
4573 ZERO_STRUCT(create);
4574 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4575 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4576 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4577 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4578 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4579 create.in.fname = sname;
4580 create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4582 status = smb2_create(tree, tctx, &create);
4583 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4584 h1 = create.out.file.handle;
4586 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_BATCH, ret, done,
4587 "Oplock level is not SMB2_OPLOCK_LEVEL_BATCH\n");
4589 ZERO_STRUCT(create);
4590 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4591 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4592 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4593 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4594 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4595 create.in.fname = sname;
4596 create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4598 status = smb2_create(tree, tctx, &create);
4599 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4600 h2 = create.out.file.handle;
4602 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_NONE, ret, done,
4603 "Oplock level is not SMB2_OPLOCK_LEVEL_NONE\n");
4605 torture_wait_for_oplock_break(tctx);
4606 if (break_info.count != 1) {
4607 torture_warning(tctx, "Stream open didn't cause oplock break\n");
4610 done:
4611 if (!smb2_util_handle_empty(h1)) {
4612 smb2_util_close(tree, h1);
4614 if (!smb2_util_handle_empty(h2)) {
4615 smb2_util_close(tree, h2);
4617 smb2_util_unlink(tree, fname);
4618 return ret;
4622 * 1) create testfile with stream
4623 * 2) 1st client opens stream r/w with batch oplock -> batch oplock granted
4624 * 3) 2nd client opens stream r/o with batch oplock
4626 * Verify 3) does trigger an oplock break
4628 static bool test_smb2_kernel_oplocks6(struct torture_context *tctx,
4629 struct smb2_tree *tree,
4630 struct smb2_tree *tree2)
4632 const char *fname = "test_kernel_oplock6.dat";
4633 const char *sname = "test_kernel_oplock6.dat:foo";
4634 NTSTATUS status;
4635 bool ret = true;
4636 struct smb2_create create;
4637 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4639 smb2_util_unlink(tree, fname);
4640 status = torture_smb2_testfile(tree, fname, &h1);
4641 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4642 "Error creating testfile\n");
4643 smb2_util_close(tree, h1);
4644 ZERO_STRUCT(h1);
4646 tree->session->transport->oplock.handler = torture_oplock_handler;
4647 tree->session->transport->oplock.private_data = tree;
4648 ZERO_STRUCT(break_info);
4650 /* 1 */
4651 ZERO_STRUCT(create);
4652 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4653 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4654 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4655 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4656 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4657 create.in.fname = sname;
4659 status = smb2_create(tree, tctx, &create);
4660 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4661 h1 = create.out.file.handle;
4662 smb2_util_close(tree, h1);
4663 ZERO_STRUCT(h1);
4665 /* 2 */
4666 ZERO_STRUCT(create);
4667 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4668 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4669 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4670 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4671 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4672 create.in.fname = fname;
4673 create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4675 status = smb2_create(tree, tctx, &create);
4676 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4677 h1 = create.out.file.handle;
4679 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4680 "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4682 /* 3 */
4683 ZERO_STRUCT(create);
4684 create.in.desired_access = SEC_RIGHTS_FILE_READ;
4685 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4686 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4687 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4688 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4689 create.in.fname = fname;
4691 status = smb2_create(tree2, tctx, &create);
4692 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4693 h2 = create.out.file.handle;
4695 torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_NONE, ret, done,
4696 "Oplock level is not SMB2_OPLOCK_LEVEL_NONE\n");
4698 torture_wait_for_oplock_break(tctx);
4699 torture_assert_goto(tctx, break_info.count == 1, ret, done, "Expected 1 oplock break\n");
4701 done:
4702 if (!smb2_util_handle_empty(h1)) {
4703 smb2_util_close(tree, h1);
4705 if (!smb2_util_handle_empty(h2)) {
4706 smb2_util_close(tree, h2);
4708 smb2_util_unlink(tree, fname);
4709 return ret;
4713 * Recreate regression test from bug:
4715 * https://bugzilla.samba.org/show_bug.cgi?id=13058
4717 * 1. smbd-1 opens the file and sets the oplock
4718 * 2. smbd-2 tries to open the file. open() fails(EAGAIN) and open is deferred.
4719 * 3. smbd-1 sends oplock break request to the client.
4720 * 4. smbd-1 closes the file.
4721 * 5. smbd-1 opens the file and sets the oplock.
4722 * 6. smbd-2 calls defer_open_done(), and should re-break the oplock.
4725 static bool test_smb2_kernel_oplocks7(struct torture_context *tctx,
4726 struct smb2_tree *tree,
4727 struct smb2_tree *tree2)
4729 const char *fname = "test_kernel_oplock7.dat";
4730 NTSTATUS status;
4731 bool ret = true;
4732 struct smb2_create create;
4733 struct smb2_handle h1 = {{0}}, h2 = {{0}};
4734 struct smb2_create create_2;
4735 struct smb2_create io;
4736 struct smb2_request *req;
4738 smb2_util_unlink(tree, fname);
4739 status = torture_smb2_testfile(tree, fname, &h1);
4740 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4741 "Error creating testfile\n");
4742 smb2_util_close(tree, h1);
4743 ZERO_STRUCT(h1);
4745 /* Close the open file on break. */
4746 tree->session->transport->oplock.handler = torture_oplock_handler_close;
4747 tree->session->transport->oplock.private_data = tree;
4748 ZERO_STRUCT(break_info);
4750 /* 1 - open file with oplock */
4751 ZERO_STRUCT(create);
4752 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4753 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4754 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4755 create.in.create_disposition = NTCREATEX_DISP_OPEN;
4756 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4757 create.in.fname = fname;
4758 create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4760 status = smb2_create(tree, tctx, &create);
4761 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4762 "Error opening the file\n");
4763 CHECK_VAL(create.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
4765 /* 2 - open file to break oplock */
4766 ZERO_STRUCT(create_2);
4767 create_2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4768 create_2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4769 create_2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4770 create_2.in.create_disposition = NTCREATEX_DISP_OPEN;
4771 create_2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4772 create_2.in.fname = fname;
4773 create_2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
4775 /* Open on tree2 - should cause a break on tree */
4776 req = smb2_create_send(tree2, &create_2);
4777 torture_assert(tctx, req != NULL, "smb2_create_send");
4779 /* The oplock break handler should close the file. */
4780 /* Steps 3 & 4. */
4781 torture_wait_for_oplock_break(tctx);
4783 tree->session->transport->oplock.handler = torture_oplock_handler;
4786 * 5 - re-open on tree. NB. There is a race here
4787 * depending on which smbd goes first. We either get
4788 * an oplock level of SMB2_OPLOCK_LEVEL_EXCLUSIVE if
4789 * the close and re-open on tree is processed first, or
4790 * SMB2_OPLOCK_LEVEL_NONE if the pending create on
4791 * tree2 is processed first.
4793 status = smb2_create(tree, tctx, &create);
4794 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4795 "Error opening the file\n");
4797 h1 = create.out.file.handle;
4798 if (create.out.oplock_level != SMB2_OPLOCK_LEVEL_EXCLUSIVE &&
4799 create.out.oplock_level != SMB2_OPLOCK_LEVEL_NONE) {
4800 torture_result(tctx,
4801 TORTURE_FAIL,
4802 "(%s): wrong value for oplock got 0x%x\n",
4803 __location__,
4804 (unsigned int)create.out.oplock_level);
4805 ret = false;
4806 goto done;
4810 /* 6 - retrieve the second open. */
4811 status = smb2_create_recv(req, tctx, &io);
4812 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4813 "Error opening the file\n");
4814 h2 = io.out.file.handle;
4815 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
4817 done:
4818 if (!smb2_util_handle_empty(h1)) {
4819 smb2_util_close(tree, h1);
4821 if (!smb2_util_handle_empty(h2)) {
4822 smb2_util_close(tree2, h2);
4824 smb2_util_unlink(tree, fname);
4825 return ret;
4828 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
4830 #ifndef F_SETLEASE
4831 #define F_SETLEASE 1024
4832 #endif
4834 #ifndef RT_SIGNAL_LEASE
4835 #define RT_SIGNAL_LEASE (SIGRTMIN+1)
4836 #endif
4838 #ifndef F_SETSIG
4839 #define F_SETSIG 10
4840 #endif
4842 static int got_break;
4845 * Signal handler.
4848 static void got_rt_break(int sig)
4850 got_break = 1;
4853 static int got_alarm;
4856 * Signal handler.
4859 static void got_alarm_fn(int sig)
4861 got_alarm = 1;
4865 * Child process function.
4868 static int do_child_process(int pipefd, const char *name)
4870 int ret = 0;
4871 int fd = -1;
4872 char c = 0;
4873 struct sigaction act;
4874 sigset_t set;
4875 sigset_t empty_set;
4877 /* Block RT_SIGNAL_LEASE and SIGALRM. */
4878 sigemptyset(&set);
4879 sigemptyset(&empty_set);
4880 sigaddset(&set, RT_SIGNAL_LEASE);
4881 sigaddset(&set, SIGALRM);
4882 ret = sigprocmask(SIG_SETMASK, &set, NULL);
4883 if (ret == -1) {
4884 return 11;
4887 /* Set up a signal handler for RT_SIGNAL_LEASE. */
4888 ZERO_STRUCT(act);
4889 act.sa_handler = got_rt_break;
4890 ret = sigaction(RT_SIGNAL_LEASE, &act, NULL);
4891 if (ret == -1) {
4892 return 1;
4894 /* Set up a signal handler for SIGALRM. */
4895 ZERO_STRUCT(act);
4896 act.sa_handler = got_alarm_fn;
4897 ret = sigaction(SIGALRM, &act, NULL);
4898 if (ret == -1) {
4899 return 1;
4901 /* Open the passed in file and get a kernel oplock. */
4902 fd = open(name, O_RDWR, 0666);
4903 if (fd == -1) {
4904 return 2;
4907 ret = fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE);
4908 if (ret == -1) {
4909 close(fd);
4910 return 3;
4913 ret = fcntl(fd, F_SETLEASE, F_WRLCK);
4914 if (ret == -1) {
4915 close(fd);
4916 return 4;
4919 /* Tell the parent we're ready. */
4920 ret = sys_write(pipefd, &c, 1);
4921 if (ret != 1) {
4922 close(fd);
4923 return 5;
4926 /* Ensure the pause doesn't hang forever. */
4927 alarm(5);
4929 /* Wait for RT_SIGNAL_LEASE or SIGALRM. */
4930 ret = sigsuspend(&empty_set);
4931 if (ret != -1 || errno != EINTR) {
4932 close(fd);
4933 return 6;
4936 if (got_alarm == 1) {
4937 close(fd);
4938 return 10;
4941 if (got_break != 1) {
4942 close(fd);
4943 return 7;
4946 /* Cancel any pending alarm. */
4947 alarm(0);
4949 /* Force the server to wait for 3 seconds. */
4950 sleep(3);
4952 /* Remove our lease. */
4953 ret = fcntl(fd, F_SETLEASE, F_UNLCK);
4954 if (ret == -1) {
4955 close(fd);
4956 return 8;
4959 ret = close(fd);
4960 if (ret == -1) {
4961 return 9;
4964 /* All is well. */
4965 return 0;
4968 static bool wait_for_child_oplock(struct torture_context *tctx,
4969 const char *localdir,
4970 const char *fname)
4972 int fds[2];
4973 int ret;
4974 pid_t pid;
4975 char *name = talloc_asprintf(tctx,
4976 "%s/%s",
4977 localdir,
4978 fname);
4980 torture_assert(tctx, name != NULL, "talloc failed");
4982 ret = pipe(fds);
4983 torture_assert(tctx, ret != -1, "pipe failed");
4985 pid = fork();
4986 torture_assert(tctx, pid != (pid_t)-1, "fork failed");
4988 if (pid != (pid_t)0) {
4989 char c;
4990 /* Parent. */
4991 TALLOC_FREE(name);
4992 close(fds[1]);
4993 ret = sys_read(fds[0], &c, 1);
4994 torture_assert(tctx, ret == 1, "read failed");
4995 return true;
4998 /* Child process. */
4999 close(fds[0]);
5000 ret = do_child_process(fds[1], name);
5001 _exit(ret);
5002 /* Notreached. */
5004 #else
5005 static bool wait_for_child_oplock(struct torture_context *tctx,
5006 const char *localdir,
5007 const char *fname)
5009 return false;
5011 #endif
5013 static void child_sig_term_handler(struct tevent_context *ev,
5014 struct tevent_signal *se,
5015 int signum,
5016 int count,
5017 void *siginfo,
5018 void *private_data)
5020 int *pstatus = (int *)private_data;
5021 int status = 0;
5023 wait(&status);
5024 if (WIFEXITED(status)) {
5025 *pstatus = WEXITSTATUS(status);
5026 } else {
5027 *pstatus = status;
5032 * Deal with a non-smbd process holding a kernel oplock.
5035 static bool test_smb2_kernel_oplocks8(struct torture_context *tctx,
5036 struct smb2_tree *tree)
5038 const char *fname = "test_kernel_oplock8.dat";
5039 const char *fname1 = "tmp_test_kernel_oplock8.dat";
5040 NTSTATUS status;
5041 bool ret = true;
5042 struct smb2_create io;
5043 struct smb2_request *req = NULL;
5044 struct smb2_handle h1 = {{0}};
5045 struct smb2_handle h2 = {{0}};
5046 const char *localdir = torture_setting_string(tctx, "localdir", NULL);
5047 struct tevent_signal *se = NULL;
5048 int child_exit_code = -1;
5049 time_t start;
5050 time_t end;
5052 #ifndef HAVE_KERNEL_OPLOCKS_LINUX
5053 torture_skip(tctx, "Need kernel oplocks for test");
5054 #endif
5056 if (localdir == NULL) {
5057 torture_skip(tctx, "Need localdir for test");
5060 smb2_util_unlink(tree, fname);
5061 smb2_util_unlink(tree, fname1);
5062 status = torture_smb2_testfile(tree, fname, &h1);
5063 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5064 "Error creating testfile\n");
5065 smb2_util_close(tree, h1);
5066 ZERO_STRUCT(h1);
5068 se = tevent_add_signal(tctx->ev,
5069 tctx,
5070 SIGCHLD,
5072 child_sig_term_handler,
5073 &child_exit_code);
5074 torture_assert(tctx, se != NULL, "tevent_add_signal failed\n");
5076 /* Take the oplock locally in a sub-process. */
5077 ret = wait_for_child_oplock(tctx, localdir, fname);
5078 torture_assert_goto(tctx, ret, ret, done,
5079 "Wait for child process failed.\n");
5082 * Now try and open. This should block for 3 seconds.
5083 * while the child process is still alive.
5086 ZERO_STRUCT(io);
5087 io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
5088 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
5089 io.in.create_disposition = NTCREATEX_DISP_OPEN;
5090 io.in.share_access =
5091 NTCREATEX_SHARE_ACCESS_DELETE|
5092 NTCREATEX_SHARE_ACCESS_READ|
5093 NTCREATEX_SHARE_ACCESS_WRITE;
5094 io.in.create_options = 0;
5095 io.in.fname = fname;
5097 req = smb2_create_send(tree, &io);
5098 torture_assert_goto(tctx, req != NULL,
5099 ret, done, "smb2_create_send");
5101 /* Ensure while the open is blocked the smbd is
5102 still serving other requests. */
5103 io.in.fname = fname1;
5104 io.in.create_disposition = NTCREATEX_DISP_CREATE;
5106 /* Time the start -> end of the request. */
5107 start = time(NULL);
5108 status = smb2_create(tree, tctx, &io);
5109 end = time(NULL);
5111 /* Should succeed. */
5112 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5113 "Error opening the second file\n");
5114 h1 = io.out.file.handle;
5116 /* in less than 2 seconds. Otherwise the server blocks. */
5117 torture_assert_goto(tctx, end - start < 2,
5118 ret, done, "server was blocked !");
5120 /* Pick up the return for the initial blocking open. */
5121 status = smb2_create_recv(req, tctx, &io);
5123 /* Which should also have succeeded. */
5124 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5125 "Error opening the file\n");
5126 h2 = io.out.file.handle;
5128 /* Wait for the exit code from the child. */
5129 while (child_exit_code == -1) {
5130 int rval = tevent_loop_once(tctx->ev);
5131 torture_assert_goto(tctx, rval == 0, ret,
5132 done, "tevent_loop_once error\n");
5135 torture_assert_int_equal_goto(tctx, child_exit_code, 0,
5136 ret, done, "Bad child exit code");
5138 done:
5139 if (!smb2_util_handle_empty(h1)) {
5140 smb2_util_close(tree, h1);
5142 if (!smb2_util_handle_empty(h2)) {
5143 smb2_util_close(tree, h2);
5145 smb2_util_unlink(tree, fname);
5146 smb2_util_unlink(tree, fname1);
5147 return ret;
5150 struct torture_suite *torture_smb2_kernel_oplocks_init(TALLOC_CTX *ctx)
5152 struct torture_suite *suite =
5153 torture_suite_create(ctx, "kernel-oplocks");
5155 torture_suite_add_1smb2_test(suite, "kernel_oplocks1", test_smb2_kernel_oplocks1);
5156 torture_suite_add_1smb2_test(suite, "kernel_oplocks2", test_smb2_kernel_oplocks2);
5157 torture_suite_add_2smb2_test(suite, "kernel_oplocks3", test_smb2_kernel_oplocks3);
5158 torture_suite_add_1smb2_test(suite, "kernel_oplocks4", test_smb2_kernel_oplocks4);
5159 torture_suite_add_1smb2_test(suite, "kernel_oplocks5", test_smb2_kernel_oplocks5);
5160 torture_suite_add_2smb2_test(suite, "kernel_oplocks6", test_smb2_kernel_oplocks6);
5161 torture_suite_add_2smb2_test(suite, "kernel_oplocks7", test_smb2_kernel_oplocks7);
5162 torture_suite_add_1smb2_test(suite, "kernel_oplocks8", test_smb2_kernel_oplocks8);
5164 suite->description = talloc_strdup(suite, "SMB2-KERNEL-OPLOCK tests");
5166 return suite;