s3/docs: Remove reference to nonexistent file.
[Samba/gbeck.git] / source4 / torture / smb2 / oplock.c
blobf686de6a2f761a3f771ce7c5aa82b313fcf12708
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"
30 #include "lib/cmdline/popt_common.h"
31 #include "lib/events/events.h"
33 #include "param/param.h"
34 #include "system/filesys.h"
36 #include "torture/torture.h"
37 #include "torture/smb2/proto.h"
39 #define CHECK_RANGE(v, min, max) do { \
40 if ((v) < (min) || (v) > (max)) { \
41 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
42 "got %d - should be between %d and %d\n", \
43 __location__, #v, (int)v, (int)min, (int)max); \
44 ret = false; \
45 }} while (0)
47 #define CHECK_STRMATCH(v, correct) do { \
48 if (!v || strstr((v),(correct)) == NULL) { \
49 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s "\
50 "got '%s' - should be '%s'\n", \
51 __location__, #v, v?v:"NULL", correct); \
52 ret = false; \
53 }} while (0)
55 #define CHECK_VAL(v, correct) do { \
56 if ((v) != (correct)) { \
57 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
58 "got 0x%x - should be 0x%x\n", \
59 __location__, #v, (int)v, (int)correct); \
60 ret = false; \
61 }} while (0)
63 #define BASEDIR "oplock_test"
65 static struct {
66 struct smb2_handle handle;
67 uint8_t level;
68 struct smb2_break br;
69 int count;
70 int failures;
71 NTSTATUS failure_status;
72 } break_info;
74 static void torture_oplock_break_callback(struct smb2_request *req)
76 NTSTATUS status;
77 struct smb2_break br;
79 ZERO_STRUCT(br);
80 status = smb2_break_recv(req, &break_info.br);
81 if (!NT_STATUS_IS_OK(status)) {
82 break_info.failures++;
83 break_info.failure_status = status;
86 return;
89 /* A general oplock break notification handler. This should be used when a
90 * test expects to break from batch or exclusive to a lower level. */
91 static bool torture_oplock_handler(struct smb2_transport *transport,
92 const struct smb2_handle *handle,
93 uint8_t level,
94 void *private_data)
96 struct smb2_tree *tree = private_data;
97 const char *name;
98 struct smb2_request *req;
99 ZERO_STRUCT(break_info.br);
101 break_info.handle = *handle;
102 break_info.level = level;
103 break_info.count++;
105 switch (level) {
106 case SMB2_OPLOCK_LEVEL_II:
107 name = "level II";
108 break;
109 case SMB2_OPLOCK_LEVEL_NONE:
110 name = "none";
111 break;
112 default:
113 name = "unknown";
114 break_info.failures++;
116 printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
118 break_info.br.in.file.handle = *handle;
119 break_info.br.in.oplock_level = level;
120 break_info.br.in.reserved = 0;
121 break_info.br.in.reserved2 = 0;
123 req = smb2_break_send(tree, &break_info.br);
124 req->async.fn = torture_oplock_break_callback;
125 req->async.private_data = NULL;
126 return true;
130 A handler function for oplock break notifications. Send a break to none
131 request.
133 static bool torture_oplock_handler_ack_to_none(struct smb2_transport *transport,
134 const struct smb2_handle *handle,
135 uint8_t level,
136 void *private_data)
138 struct smb2_tree *tree = private_data;
139 struct smb2_request *req;
141 break_info.handle = *handle;
142 break_info.level = level;
143 break_info.count++;
145 printf("Acking to none in oplock handler\n");
147 ZERO_STRUCT(break_info.br);
148 break_info.br.in.file.handle = *handle;
149 break_info.br.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
150 break_info.br.in.reserved = 0;
151 break_info.br.in.reserved2 = 0;
153 req = smb2_break_send(tree, &break_info.br);
154 req->async.fn = torture_oplock_break_callback;
155 req->async.private_data = NULL;
157 return true;
161 A handler function for oplock break notifications. Break from level II to
162 none. SMB2 requires that the client does not send an oplock break request to
163 the server in this case.
165 static bool torture_oplock_handler_level2_to_none(
166 struct smb2_transport *transport,
167 const struct smb2_handle *handle,
168 uint8_t level,
169 void *private_data)
171 struct smb2_tree *tree = private_data;
173 break_info.handle = *handle;
174 break_info.level = level;
175 break_info.count++;
177 printf("Break from level II to none in oplock handler\n");
179 return true;
182 /* A handler function for oplock break notifications. This should be used when
183 * test expects two break notifications, first to level II, then to none. */
184 static bool torture_oplock_handler_two_notifications(
185 struct smb2_transport *transport,
186 const struct smb2_handle *handle,
187 uint8_t level,
188 void *private_data)
190 struct smb2_tree *tree = private_data;
191 const char *name;
192 struct smb2_request *req;
193 ZERO_STRUCT(break_info.br);
195 break_info.handle = *handle;
196 break_info.level = level;
197 break_info.count++;
199 switch (level) {
200 case SMB2_OPLOCK_LEVEL_II:
201 name = "level II";
202 break;
203 case SMB2_OPLOCK_LEVEL_NONE:
204 name = "none";
205 break;
206 default:
207 name = "unknown";
208 break_info.failures++;
210 printf("Breaking to %s [0x%02X] in oplock handler\n", name, level);
212 if (level == SMB2_OPLOCK_LEVEL_NONE)
213 return true;
215 break_info.br.in.file.handle = *handle;
216 break_info.br.in.oplock_level = level;
217 break_info.br.in.reserved = 0;
218 break_info.br.in.reserved2 = 0;
220 req = smb2_break_send(tree, &break_info.br);
221 req->async.fn = torture_oplock_break_callback;
222 req->async.private_data = NULL;
223 return true;
225 static void torture_oplock_handler_close_recv(struct smb2_request *req)
227 if (!smb2_request_receive(req)) {
228 printf("close failed in oplock_handler_close\n");
229 break_info.failures++;
234 a handler function for oplock break requests - close the file
236 static bool torture_oplock_handler_close(struct smb2_transport *transport,
237 const struct smb2_handle *handle,
238 uint8_t level,
239 void *private_data)
241 struct smb2_close io;
242 struct smb2_tree *tree = private_data;
243 struct smb2_request *req;
245 break_info.handle = *handle;
246 break_info.level = level;
247 break_info.count++;
249 ZERO_STRUCT(io);
250 io.in.file.handle = *handle;
251 io.in.flags = RAW_CLOSE_SMB2;
252 req = smb2_close_send(tree, &io);
253 if (req == NULL) {
254 printf("failed to send close in oplock_handler_close\n");
255 return false;
258 req->async.fn = torture_oplock_handler_close_recv;
259 req->async.private_data = NULL;
261 return true;
265 a handler function for oplock break requests. Let it timeout
267 static bool torture_oplock_handler_timeout(struct smb2_transport *transport,
268 const struct smb2_handle *handle,
269 uint8_t level,
270 void *private_data)
272 break_info.handle = *handle;
273 break_info.level = level;
274 break_info.count++;
276 printf("Let oplock break timeout\n");
277 return true;
280 static bool open_smb2_connection_no_level2_oplocks(struct torture_context *tctx,
281 struct smb2_tree **tree)
283 NTSTATUS status;
284 const char *host = torture_setting_string(tctx, "host", NULL);
285 const char *share = torture_setting_string(tctx, "share", NULL);
286 struct cli_credentials *credentials = cmdline_credentials;
287 struct smbcli_options options;
289 lp_smbcli_options(tctx->lp_ctx, &options);
290 options.use_level2_oplocks = false;
292 status = smb2_connect(tctx, host,
293 lp_smb_ports(tctx->lp_ctx), share,
294 lp_resolve_context(tctx->lp_ctx),
295 credentials, tree, tctx->ev, &options,
296 lp_socket_options(tctx->lp_ctx),
297 lp_gensec_settings(tctx, tctx->lp_ctx));
298 if (!NT_STATUS_IS_OK(status)) {
299 torture_comment(tctx, "Failed to connect to SMB2 share "
300 "\\\\%s\\%s - %s\n", host, share,
301 nt_errstr(status));
302 return false;
304 return true;
308 Timer handler function notifies the registering function that time is up
310 static void timeout_cb(struct tevent_context *ev,
311 struct tevent_timer *te,
312 struct timeval current_time,
313 void *private_data)
315 bool *timesup = (bool *)private_data;
316 *timesup = true;
317 return;
321 Wait a short period of time to receive a single oplock break request
323 static void torture_wait_for_oplock_break(struct torture_context *tctx)
325 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
326 struct tevent_timer *te = NULL;
327 struct timeval ne;
328 bool timesup = false;
329 int old_count = break_info.count;
331 /* Wait .1 seconds for an oplock break */
332 ne = tevent_timeval_current_ofs(0, 100000);
334 if ((te = event_add_timed(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup))
335 == NULL)
337 torture_comment(tctx, "Failed to wait for an oplock break. "
338 "test results may not be accurate.");
339 goto done;
342 while (!timesup && break_info.count < old_count + 1) {
343 if (event_loop_once(tctx->ev) != 0) {
344 torture_comment(tctx, "Failed to wait for an oplock "
345 "break. test results may not be "
346 "accurate.");
347 goto done;
351 done:
352 /* We don't know if the timed event fired and was freed, we received
353 * our oplock break, or some other event triggered the loop. Thus,
354 * we create a tmp_ctx to be able to safely free/remove the timed
355 * event in all 3 cases. */
356 talloc_free(tmp_ctx);
358 return;
361 static bool test_smb2_oplock_exclusive1(struct torture_context *tctx,
362 struct smb2_tree *tree1,
363 struct smb2_tree *tree2)
365 const char *fname = BASEDIR "\\test_exclusive1.dat";
366 NTSTATUS status;
367 bool ret = true;
368 union smb_open io;
369 union smb_unlink unl;
370 struct smb2_handle h1;
371 struct smb2_handle h;
373 status = torture_smb2_testdir(tree1, BASEDIR, &h);
374 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
376 /* cleanup */
377 smb2_util_unlink(tree1, fname);
379 tree1->session->transport->oplock.handler = torture_oplock_handler;
380 tree1->session->transport->oplock.private_data = tree1;
383 base ntcreatex parms
385 ZERO_STRUCT(io.smb2);
386 io.generic.level = RAW_OPEN_SMB2;
387 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
388 io.smb2.in.alloc_size = 0;
389 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
390 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
391 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
392 io.smb2.in.create_options = 0;
393 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
394 io.smb2.in.security_flags = 0;
395 io.smb2.in.fname = fname;
397 torture_comment(tctx, "EXCLUSIVE1: open a file with an exclusive "
398 "oplock (share mode: none)\n");
399 ZERO_STRUCT(break_info);
400 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
402 status = smb2_create(tree1, tctx, &(io.smb2));
403 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
404 h1 = io.smb2.out.file.handle;
405 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
407 torture_comment(tctx, "a 2nd open should not cause a break\n");
408 status = smb2_create(tree2, tctx, &(io.smb2));
409 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
410 "Incorrect status");
411 torture_wait_for_oplock_break(tctx);
412 CHECK_VAL(break_info.count, 0);
413 CHECK_VAL(break_info.failures, 0);
415 torture_comment(tctx, "unlink it - should also be no break\n");
416 unl.unlink.in.pattern = fname;
417 unl.unlink.in.attrib = 0;
418 status = smb2_util_unlink(tree2, fname);
419 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
420 "Incorrect status");
421 torture_wait_for_oplock_break(tctx);
422 CHECK_VAL(break_info.count, 0);
423 CHECK_VAL(break_info.failures, 0);
425 smb2_util_close(tree1, h1);
426 smb2_util_close(tree1, h);
428 smb2_deltree(tree1, BASEDIR);
429 return ret;
432 static bool test_smb2_oplock_exclusive2(struct torture_context *tctx,
433 struct smb2_tree *tree1,
434 struct smb2_tree *tree2)
436 const char *fname = BASEDIR "\\test_exclusive2.dat";
437 NTSTATUS status;
438 bool ret = true;
439 union smb_open io;
440 union smb_unlink unl;
441 struct smb2_handle h, h1, h2;
443 status = torture_smb2_testdir(tree1, BASEDIR, &h);
444 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
446 /* cleanup */
447 smb2_util_unlink(tree1, fname);
449 tree1->session->transport->oplock.handler = torture_oplock_handler;
450 tree1->session->transport->oplock.private_data = tree1;
453 base ntcreatex parms
455 ZERO_STRUCT(io.smb2);
456 io.generic.level = RAW_OPEN_SMB2;
457 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
458 io.smb2.in.alloc_size = 0;
459 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
460 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
461 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
462 io.smb2.in.create_options = 0;
463 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
464 io.smb2.in.security_flags = 0;
465 io.smb2.in.fname = fname;
467 torture_comment(tctx, "EXCLUSIVE2: open a file with an exclusive "
468 "oplock (share mode: all)\n");
469 ZERO_STRUCT(break_info);
470 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
471 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
472 NTCREATEX_SHARE_ACCESS_WRITE|
473 NTCREATEX_SHARE_ACCESS_DELETE;
474 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
476 status = smb2_create(tree1, tctx, &(io.smb2));
477 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
478 h1 = io.smb2.out.file.handle;
479 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
481 torture_comment(tctx, "a 2nd open should cause a break to level 2\n");
482 status = smb2_create(tree2, tctx, &(io.smb2));
483 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
484 h2 = io.smb2.out.file.handle;
485 torture_wait_for_oplock_break(tctx);
486 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
487 CHECK_VAL(break_info.count, 1);
488 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
489 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
490 CHECK_VAL(break_info.failures, 0);
491 ZERO_STRUCT(break_info);
493 /* now we have 2 level II oplocks... */
494 torture_comment(tctx, "try to unlink it - should cause a break\n");
495 unl.unlink.in.pattern = fname;
496 unl.unlink.in.attrib = 0;
497 status = smb2_util_unlink(tree2, fname);
498 torture_assert_ntstatus_ok(tctx, status, "Error unlinking the file");
499 torture_wait_for_oplock_break(tctx);
500 CHECK_VAL(break_info.count, 0);
501 CHECK_VAL(break_info.failures, 0);
503 torture_comment(tctx, "close both handles\n");
504 smb2_util_close(tree1, h1);
505 smb2_util_close(tree1, h2);
506 smb2_util_close(tree1, h);
508 smb2_deltree(tree1, BASEDIR);
509 return ret;
512 static bool test_smb2_oplock_exclusive3(struct torture_context *tctx,
513 struct smb2_tree *tree1,
514 struct smb2_tree *tree2)
516 const char *fname = BASEDIR "\\test_exclusive3.dat";
517 NTSTATUS status;
518 bool ret = true;
519 union smb_open io;
520 union smb_setfileinfo sfi;
521 struct smb2_handle h, h1;
523 status = torture_smb2_testdir(tree1, BASEDIR, &h);
524 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
526 /* cleanup */
527 smb2_util_unlink(tree1, fname);
529 tree1->session->transport->oplock.handler = torture_oplock_handler;
530 tree1->session->transport->oplock.private_data = tree1;
533 base ntcreatex parms
535 ZERO_STRUCT(io.smb2);
536 io.generic.level = RAW_OPEN_SMB2;
537 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
538 io.smb2.in.alloc_size = 0;
539 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
540 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
541 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
542 io.smb2.in.create_options = 0;
543 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
544 io.smb2.in.security_flags = 0;
545 io.smb2.in.fname = fname;
547 torture_comment(tctx, "EXCLUSIVE3: open a file with an exclusive "
548 "oplock (share mode: none)\n");
550 ZERO_STRUCT(break_info);
551 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
552 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
554 status = smb2_create(tree1, tctx, &(io.smb2));
555 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
556 h1 = io.smb2.out.file.handle;
557 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
559 torture_comment(tctx, "setpathinfo EOF should trigger a break to "
560 "none\n");
561 ZERO_STRUCT(sfi);
562 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
563 sfi.generic.in.file.path = fname;
564 sfi.end_of_file_info.in.size = 100;
566 status = smb2_composite_setpathinfo(tree2, &sfi);
568 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
569 "Incorrect status");
570 torture_wait_for_oplock_break(tctx);
571 CHECK_VAL(break_info.count, 0);
572 CHECK_VAL(break_info.failures, 0);
573 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
575 smb2_util_close(tree1, h1);
576 smb2_util_close(tree1, h);
578 smb2_deltree(tree1, BASEDIR);
579 return ret;
582 static bool test_smb2_oplock_exclusive4(struct torture_context *tctx,
583 struct smb2_tree *tree1,
584 struct smb2_tree *tree2)
586 const char *fname = BASEDIR "\\test_exclusive4.dat";
587 NTSTATUS status;
588 bool ret = true;
589 union smb_open io;
590 struct smb2_handle h, h1, h2;
592 status = torture_smb2_testdir(tree1, BASEDIR, &h);
593 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
595 /* cleanup */
596 smb2_util_unlink(tree1, fname);
598 tree1->session->transport->oplock.handler = torture_oplock_handler;
599 tree1->session->transport->oplock.private_data = tree1;
602 base ntcreatex parms
604 ZERO_STRUCT(io.smb2);
605 io.generic.level = RAW_OPEN_SMB2;
606 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
607 io.smb2.in.alloc_size = 0;
608 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
609 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
610 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
611 io.smb2.in.create_options = 0;
612 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
613 io.smb2.in.security_flags = 0;
614 io.smb2.in.fname = fname;
616 torture_comment(tctx, "EXCLUSIVE4: open with exclusive oplock\n");
617 ZERO_STRUCT(break_info);
619 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
620 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
621 status = smb2_create(tree1, tctx, &(io.smb2));
622 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
623 h1 = io.smb2.out.file.handle;
624 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
626 ZERO_STRUCT(break_info);
627 torture_comment(tctx, "second open with attributes only shouldn't "
628 "cause oplock break\n");
630 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
631 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
632 SEC_FILE_WRITE_ATTRIBUTE |
633 SEC_STD_SYNCHRONIZE;
634 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
635 status = smb2_create(tree2, tctx, &(io.smb2));
636 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
637 h2 = io.smb2.out.file.handle;
638 CHECK_VAL(io.smb2.out.oplock_level, NO_OPLOCK_RETURN);
639 torture_wait_for_oplock_break(tctx);
640 CHECK_VAL(break_info.count, 0);
641 CHECK_VAL(break_info.failures, 0);
643 smb2_util_close(tree1, h1);
644 smb2_util_close(tree2, h2);
645 smb2_util_close(tree1, h);
647 smb2_deltree(tree1, BASEDIR);
648 return ret;
651 static bool test_smb2_oplock_exclusive5(struct torture_context *tctx,
652 struct smb2_tree *tree1,
653 struct smb2_tree *tree2)
655 const char *fname = BASEDIR "\\test_exclusive5.dat";
656 NTSTATUS status;
657 bool ret = true;
658 union smb_open io;
659 struct smb2_handle h, h1, h2;
661 status = torture_smb2_testdir(tree1, BASEDIR, &h);
662 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
664 /* cleanup */
665 smb2_util_unlink(tree1, fname);
667 tree1->session->transport->oplock.handler = torture_oplock_handler;
668 tree1->session->transport->oplock.private_data = tree1;
670 tree2->session->transport->oplock.handler = torture_oplock_handler;
671 tree2->session->transport->oplock.private_data = tree2;
674 base ntcreatex parms
676 ZERO_STRUCT(io.smb2);
677 io.generic.level = RAW_OPEN_SMB2;
678 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
679 io.smb2.in.alloc_size = 0;
680 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
681 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
682 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
683 io.smb2.in.create_options = 0;
684 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
685 io.smb2.in.security_flags = 0;
686 io.smb2.in.fname = fname;
688 torture_comment(tctx, "EXCLUSIVE5: open with exclusive oplock\n");
689 ZERO_STRUCT(break_info);
691 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
692 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
693 NTCREATEX_SHARE_ACCESS_WRITE|
694 NTCREATEX_SHARE_ACCESS_DELETE;
695 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
696 status = smb2_create(tree1, tctx, &(io.smb2));
697 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
698 h1 = io.smb2.out.file.handle;
699 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
701 ZERO_STRUCT(break_info);
703 torture_comment(tctx, "second open with attributes only and "
704 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
705 "oplock break\n");
707 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
708 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
709 SEC_FILE_WRITE_ATTRIBUTE |
710 SEC_STD_SYNCHRONIZE;
711 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
712 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
713 status = smb2_create(tree2, tctx, &(io.smb2));
714 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
715 h2 = io.smb2.out.file.handle;
716 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
717 torture_wait_for_oplock_break(tctx);
718 CHECK_VAL(break_info.count, 1);
719 CHECK_VAL(break_info.failures, 0);
721 smb2_util_close(tree1, h1);
722 smb2_util_close(tree2, h2);
723 smb2_util_close(tree1, h);
725 smb2_deltree(tree1, BASEDIR);
726 return ret;
729 static bool test_smb2_oplock_exclusive6(struct torture_context *tctx,
730 struct smb2_tree *tree1,
731 struct smb2_tree *tree2)
733 const char *fname1 = BASEDIR "\\test_exclusive6_1.dat";
734 const char *fname2 = BASEDIR "\\test_exclusive6_2.dat";
735 NTSTATUS status;
736 bool ret = true;
737 union smb_open io;
738 union smb_setfileinfo sinfo;
739 struct smb2_handle h, h1;
741 status = torture_smb2_testdir(tree1, BASEDIR, &h);
742 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
744 /* cleanup */
745 smb2_util_unlink(tree1, fname1);
746 smb2_util_unlink(tree2, fname2);
748 tree1->session->transport->oplock.handler = torture_oplock_handler;
749 tree1->session->transport->oplock.private_data = tree1;
752 base ntcreatex parms
754 ZERO_STRUCT(io.smb2);
755 io.generic.level = RAW_OPEN_SMB2;
756 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
757 io.smb2.in.alloc_size = 0;
758 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
759 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
760 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
761 io.smb2.in.create_options = 0;
762 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
763 io.smb2.in.security_flags = 0;
764 io.smb2.in.fname = fname1;
766 torture_comment(tctx, "EXCLUSIVE6: open a file with an exclusive "
767 "oplock (share mode: none)\n");
768 ZERO_STRUCT(break_info);
769 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
770 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
772 status = smb2_create(tree1, tctx, &(io.smb2));
773 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
774 h1 = io.smb2.out.file.handle;
775 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
777 torture_comment(tctx, "rename should not generate a break but get "
778 "a sharing violation\n");
779 ZERO_STRUCT(sinfo);
780 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
781 sinfo.rename_information.in.file.handle = h1;
782 sinfo.rename_information.in.overwrite = true;
783 sinfo.rename_information.in.new_name = fname2;
784 status = smb2_setinfo_file(tree1, &sinfo);
786 torture_comment(tctx, "trying rename while first file open\n");
787 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
788 "Incorrect status");
789 torture_wait_for_oplock_break(tctx);
790 CHECK_VAL(break_info.count, 0);
791 CHECK_VAL(break_info.failures, 0);
793 smb2_util_close(tree1, h1);
794 smb2_util_close(tree1, h);
796 smb2_deltree(tree1, BASEDIR);
797 return ret;
800 static bool test_smb2_oplock_batch1(struct torture_context *tctx,
801 struct smb2_tree *tree1,
802 struct smb2_tree *tree2)
804 const char *fname = BASEDIR "\\test_batch1.dat";
805 NTSTATUS status;
806 bool ret = true;
807 union smb_open io;
808 struct smb2_handle h, h1;
809 char c = 0;
811 status = torture_smb2_testdir(tree1, BASEDIR, &h);
812 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
814 /* cleanup */
815 smb2_util_unlink(tree1, fname);
817 tree1->session->transport->oplock.handler = torture_oplock_handler;
818 tree1->session->transport->oplock.private_data = tree1;
821 base ntcreatex parms
823 ZERO_STRUCT(io.smb2);
824 io.generic.level = RAW_OPEN_SMB2;
825 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
826 io.smb2.in.alloc_size = 0;
827 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
828 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
829 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
830 io.smb2.in.create_options = 0;
831 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
832 io.smb2.in.security_flags = 0;
833 io.smb2.in.fname = fname;
836 with a batch oplock we get a break
838 torture_comment(tctx, "BATCH1: open with batch oplock\n");
839 ZERO_STRUCT(break_info);
840 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
841 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
842 status = smb2_create(tree1, tctx, &(io.smb2));
843 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
844 h1 = io.smb2.out.file.handle;
845 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
847 torture_comment(tctx, "unlink should generate a break\n");
848 status = smb2_util_unlink(tree2, fname);
849 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
850 "Incorrect status");
852 torture_wait_for_oplock_break(tctx);
853 CHECK_VAL(break_info.count, 1);
854 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
855 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
856 CHECK_VAL(break_info.failures, 0);
858 torture_comment(tctx, "2nd unlink should not generate a break\n");
859 ZERO_STRUCT(break_info);
860 status = smb2_util_unlink(tree2, fname);
861 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
862 "Incorrect status");
864 torture_wait_for_oplock_break(tctx);
865 CHECK_VAL(break_info.count, 0);
867 torture_comment(tctx, "writing should generate a self break to none\n");
868 tree1->session->transport->oplock.handler =
869 torture_oplock_handler_level2_to_none;
870 smb2_util_write(tree1, h1, &c, 0, 1);
872 torture_wait_for_oplock_break(tctx);
874 CHECK_VAL(break_info.count, 1);
875 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
876 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
877 CHECK_VAL(break_info.failures, 0);
879 smb2_util_close(tree1, h1);
880 smb2_util_close(tree1, h);
882 smb2_deltree(tree1, BASEDIR);
883 return ret;
886 static bool test_smb2_oplock_batch2(struct torture_context *tctx,
887 struct smb2_tree *tree1,
888 struct smb2_tree *tree2)
890 const char *fname = BASEDIR "\\test_batch2.dat";
891 NTSTATUS status;
892 bool ret = true;
893 union smb_open io;
894 char c = 0;
895 struct smb2_handle h, h1;
897 status = torture_smb2_testdir(tree1, BASEDIR, &h);
898 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
900 /* cleanup */
901 smb2_util_unlink(tree1, fname);
903 tree1->session->transport->oplock.handler = torture_oplock_handler;
904 tree1->session->transport->oplock.private_data = tree1;
907 base ntcreatex parms
909 ZERO_STRUCT(io.smb2);
910 io.generic.level = RAW_OPEN_SMB2;
911 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
912 io.smb2.in.alloc_size = 0;
913 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
914 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
915 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
916 io.smb2.in.create_options = 0;
917 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
918 io.smb2.in.security_flags = 0;
919 io.smb2.in.fname = fname;
921 torture_comment(tctx, "BATCH2: open with batch oplock\n");
922 ZERO_STRUCT(break_info);
923 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
924 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
925 status = smb2_create(tree1, tctx, &(io.smb2));
926 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
927 h1 = io.smb2.out.file.handle;
928 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
930 torture_comment(tctx, "unlink should generate a break, which we ack "
931 "as break to none\n");
932 tree1->session->transport->oplock.handler =
933 torture_oplock_handler_ack_to_none;
934 tree1->session->transport->oplock.private_data = tree1;
935 status = smb2_util_unlink(tree2, fname);
936 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
937 "Incorrect status");
939 torture_wait_for_oplock_break(tctx);
940 CHECK_VAL(break_info.count, 1);
941 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
942 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
943 CHECK_VAL(break_info.failures, 0);
945 torture_comment(tctx, "2nd unlink should not generate a break\n");
946 ZERO_STRUCT(break_info);
947 status = smb2_util_unlink(tree2, fname);
948 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
949 "Incorrect status");
951 torture_wait_for_oplock_break(tctx);
952 CHECK_VAL(break_info.count, 0);
954 torture_comment(tctx, "writing should not generate a break\n");
955 smb2_util_write(tree1, h1, &c, 0, 1);
957 torture_wait_for_oplock_break(tctx);
958 CHECK_VAL(break_info.count, 0);
960 smb2_util_close(tree1, h1);
961 smb2_util_close(tree1, h);
963 smb2_deltree(tree1, BASEDIR);
964 return ret;
967 static bool test_smb2_oplock_batch3(struct torture_context *tctx,
968 struct smb2_tree *tree1,
969 struct smb2_tree *tree2)
971 const char *fname = BASEDIR "\\test_batch3.dat";
972 NTSTATUS status;
973 bool ret = true;
974 union smb_open io;
975 struct smb2_handle h, h1;
977 status = torture_smb2_testdir(tree1, BASEDIR, &h);
978 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
980 /* cleanup */
981 smb2_util_unlink(tree1, fname);
982 tree1->session->transport->oplock.handler = torture_oplock_handler;
983 tree1->session->transport->oplock.private_data = tree1;
986 base ntcreatex parms
988 ZERO_STRUCT(io.smb2);
989 io.generic.level = RAW_OPEN_SMB2;
990 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
991 io.smb2.in.alloc_size = 0;
992 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
993 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
994 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
995 io.smb2.in.create_options = 0;
996 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
997 io.smb2.in.security_flags = 0;
998 io.smb2.in.fname = fname;
1000 torture_comment(tctx, "BATCH3: if we close on break then the unlink "
1001 "can succeed\n");
1002 ZERO_STRUCT(break_info);
1003 tree1->session->transport->oplock.handler =
1004 torture_oplock_handler_close;
1005 tree1->session->transport->oplock.private_data = tree1;
1007 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1008 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1009 status = smb2_create(tree1, tctx, &(io.smb2));
1010 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1011 h1 = io.smb2.out.file.handle;
1012 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1014 ZERO_STRUCT(break_info);
1015 status = smb2_util_unlink(tree2, fname);
1016 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1018 torture_wait_for_oplock_break(tctx);
1019 CHECK_VAL(break_info.count, 1);
1020 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1021 CHECK_VAL(break_info.level, 1);
1022 CHECK_VAL(break_info.failures, 0);
1024 smb2_util_close(tree1, h1);
1025 smb2_util_close(tree1, h);
1027 smb2_deltree(tree1, BASEDIR);
1028 return ret;
1031 static bool test_smb2_oplock_batch4(struct torture_context *tctx,
1032 struct smb2_tree *tree1,
1033 struct smb2_tree *tree2)
1035 const char *fname = BASEDIR "\\test_batch4.dat";
1036 NTSTATUS status;
1037 bool ret = true;
1038 union smb_open io;
1039 struct smb2_read r;
1040 struct smb2_handle h, h1;
1042 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1043 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1045 /* cleanup */
1046 smb2_util_unlink(tree1, fname);
1048 tree1->session->transport->oplock.handler = torture_oplock_handler;
1049 tree1->session->transport->oplock.private_data = tree1;
1052 base ntcreatex parms
1054 ZERO_STRUCT(io.smb2);
1055 io.generic.level = RAW_OPEN_SMB2;
1056 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1057 io.smb2.in.alloc_size = 0;
1058 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1059 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1060 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1061 io.smb2.in.create_options = 0;
1062 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1063 io.smb2.in.security_flags = 0;
1064 io.smb2.in.fname = fname;
1066 torture_comment(tctx, "BATCH4: a self read should not cause a break\n");
1067 ZERO_STRUCT(break_info);
1069 tree1->session->transport->oplock.handler = torture_oplock_handler;
1070 tree1->session->transport->oplock.private_data = tree1;
1072 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1073 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1074 status = smb2_create(tree1, tctx, &(io.smb2));
1075 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1076 h1 = io.smb2.out.file.handle;
1077 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1079 ZERO_STRUCT(r);
1080 r.in.file.handle = h1;
1081 r.in.offset = 0;
1083 status = smb2_read(tree1, tree1, &r);
1084 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1085 torture_wait_for_oplock_break(tctx);
1086 CHECK_VAL(break_info.count, 0);
1087 CHECK_VAL(break_info.failures, 0);
1089 smb2_util_close(tree1, h1);
1090 smb2_util_close(tree1, h);
1092 smb2_deltree(tree1, BASEDIR);
1093 return ret;
1096 static bool test_smb2_oplock_batch5(struct torture_context *tctx,
1097 struct smb2_tree *tree1,
1098 struct smb2_tree *tree2)
1100 const char *fname = BASEDIR "\\test_batch5.dat";
1101 NTSTATUS status;
1102 bool ret = true;
1103 union smb_open io;
1104 struct smb2_handle h, h1;
1106 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1107 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1109 /* cleanup */
1110 smb2_util_unlink(tree1, fname);
1112 tree1->session->transport->oplock.handler = torture_oplock_handler;
1113 tree1->session->transport->oplock.private_data = tree1;
1116 base ntcreatex parms
1118 ZERO_STRUCT(io.smb2);
1119 io.generic.level = RAW_OPEN_SMB2;
1120 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1121 io.smb2.in.alloc_size = 0;
1122 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1123 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1124 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1125 io.smb2.in.create_options = 0;
1126 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1127 io.smb2.in.security_flags = 0;
1128 io.smb2.in.fname = fname;
1130 torture_comment(tctx, "BATCH5: a 2nd open should give a break\n");
1131 ZERO_STRUCT(break_info);
1133 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1134 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1135 status = smb2_create(tree1, tctx, &(io.smb2));
1136 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1137 h1 = io.smb2.out.file.handle;
1138 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1140 ZERO_STRUCT(break_info);
1142 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1143 status = smb2_create(tree2, tctx, &(io.smb2));
1144 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1145 "Incorrect status");
1147 torture_wait_for_oplock_break(tctx);
1148 CHECK_VAL(break_info.count, 1);
1149 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1150 CHECK_VAL(break_info.level, 1);
1151 CHECK_VAL(break_info.failures, 0);
1153 smb2_util_close(tree1, h1);
1154 smb2_util_close(tree1, h);
1156 smb2_deltree(tree1, BASEDIR);
1157 return ret;
1160 static bool test_smb2_oplock_batch6(struct torture_context *tctx,
1161 struct smb2_tree *tree1,
1162 struct smb2_tree *tree2)
1164 const char *fname = BASEDIR "\\test_batch6.dat";
1165 NTSTATUS status;
1166 bool ret = true;
1167 union smb_open io;
1168 struct smb2_handle h, h1, h2;
1169 char c = 0;
1171 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1172 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1174 /* cleanup */
1175 smb2_util_unlink(tree1, fname);
1177 tree1->session->transport->oplock.handler = torture_oplock_handler;
1178 tree1->session->transport->oplock.private_data = tree1;
1181 base ntcreatex parms
1183 ZERO_STRUCT(io.smb2);
1184 io.generic.level = RAW_OPEN_SMB2;
1185 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1186 io.smb2.in.alloc_size = 0;
1187 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1188 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1189 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1190 io.smb2.in.create_options = 0;
1191 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1192 io.smb2.in.security_flags = 0;
1193 io.smb2.in.fname = fname;
1195 torture_comment(tctx, "BATCH6: a 2nd open should give a break to "
1196 "level II if the first open allowed shared read\n");
1197 ZERO_STRUCT(break_info);
1198 tree2->session->transport->oplock.handler = torture_oplock_handler;
1199 tree2->session->transport->oplock.private_data = tree2;
1201 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
1202 SEC_RIGHTS_FILE_WRITE;
1203 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1204 NTCREATEX_SHARE_ACCESS_WRITE;
1205 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1206 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1207 status = smb2_create(tree1, tctx, &(io.smb2));
1208 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1209 h1 = io.smb2.out.file.handle;
1210 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1212 ZERO_STRUCT(break_info);
1214 status = smb2_create(tree2, tctx, &(io.smb2));
1215 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1216 h2 = io.smb2.out.file.handle;
1217 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1219 torture_wait_for_oplock_break(tctx);
1220 CHECK_VAL(break_info.count, 1);
1221 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1222 CHECK_VAL(break_info.level, 1);
1223 CHECK_VAL(break_info.failures, 0);
1224 ZERO_STRUCT(break_info);
1226 torture_comment(tctx, "write should trigger a break to none on both\n");
1227 tree1->session->transport->oplock.handler =
1228 torture_oplock_handler_level2_to_none;
1229 tree2->session->transport->oplock.handler =
1230 torture_oplock_handler_level2_to_none;
1231 smb2_util_write(tree1, h1, &c, 0, 1);
1233 /* We expect two breaks */
1234 torture_wait_for_oplock_break(tctx);
1235 torture_wait_for_oplock_break(tctx);
1237 CHECK_VAL(break_info.count, 2);
1238 CHECK_VAL(break_info.level, 0);
1239 CHECK_VAL(break_info.failures, 0);
1241 smb2_util_close(tree1, h1);
1242 smb2_util_close(tree2, h2);
1243 smb2_util_close(tree1, h);
1245 smb2_deltree(tree1, BASEDIR);
1246 return ret;
1249 static bool test_smb2_oplock_batch7(struct torture_context *tctx,
1250 struct smb2_tree *tree1,
1251 struct smb2_tree *tree2)
1253 const char *fname = BASEDIR "\\test_batch7.dat";
1254 NTSTATUS status;
1255 bool ret = true;
1256 union smb_open io;
1257 struct smb2_handle h, h1, h2;
1259 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1260 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1262 /* cleanup */
1263 smb2_util_unlink(tree1, fname);
1265 tree1->session->transport->oplock.handler = torture_oplock_handler;
1266 tree1->session->transport->oplock.private_data = tree1;
1269 base ntcreatex parms
1271 ZERO_STRUCT(io.smb2);
1272 io.generic.level = RAW_OPEN_SMB2;
1273 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1274 io.smb2.in.alloc_size = 0;
1275 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1276 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1277 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1278 io.smb2.in.create_options = 0;
1279 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1280 io.smb2.in.security_flags = 0;
1281 io.smb2.in.fname = fname;
1283 torture_comment(tctx, "BATCH7: a 2nd open should get an oplock when "
1284 "we close instead of ack\n");
1285 ZERO_STRUCT(break_info);
1286 tree1->session->transport->oplock.handler =
1287 torture_oplock_handler_close;
1288 tree1->session->transport->oplock.private_data = tree1;
1290 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1291 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1292 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1293 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1294 status = smb2_create(tree1, tctx, &(io.smb2));
1295 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1296 h2 = io.smb2.out.file.handle;
1297 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1299 ZERO_STRUCT(break_info);
1301 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1302 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1303 status = smb2_create(tree2, tctx, &(io.smb2));
1304 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1305 h1 = io.smb2.out.file.handle;
1306 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1308 torture_wait_for_oplock_break(tctx);
1309 CHECK_VAL(break_info.count, 1);
1310 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1311 CHECK_VAL(break_info.level, 1);
1312 CHECK_VAL(break_info.failures, 0);
1314 smb2_util_close(tree2, h1);
1315 smb2_util_close(tree2, h);
1317 smb2_deltree(tree1, BASEDIR);
1318 return ret;
1321 static bool test_smb2_oplock_batch8(struct torture_context *tctx,
1322 struct smb2_tree *tree1,
1323 struct smb2_tree *tree2)
1325 const char *fname = BASEDIR "\\test_batch8.dat";
1326 NTSTATUS status;
1327 bool ret = true;
1328 union smb_open io;
1329 struct smb2_handle h, h1, h2;
1331 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1332 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1334 /* cleanup */
1335 smb2_util_unlink(tree1, fname);
1337 tree1->session->transport->oplock.handler = torture_oplock_handler;
1338 tree1->session->transport->oplock.private_data = tree1;
1341 base ntcreatex parms
1343 ZERO_STRUCT(io.smb2);
1344 io.generic.level = RAW_OPEN_SMB2;
1345 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1346 io.smb2.in.alloc_size = 0;
1347 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1348 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1349 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1350 io.smb2.in.create_options = 0;
1351 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1352 io.smb2.in.security_flags = 0;
1353 io.smb2.in.fname = fname;
1355 torture_comment(tctx, "BATCH8: open with batch oplock\n");
1356 ZERO_STRUCT(break_info);
1358 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1359 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1360 status = smb2_create(tree1, tctx, &(io.smb2));
1361 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1362 h1 = io.smb2.out.file.handle;
1363 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1365 ZERO_STRUCT(break_info);
1366 torture_comment(tctx, "second open with attributes only shouldn't "
1367 "cause oplock break\n");
1369 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1370 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1371 SEC_FILE_WRITE_ATTRIBUTE |
1372 SEC_STD_SYNCHRONIZE;
1373 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1374 status = smb2_create(tree2, tctx, &(io.smb2));
1375 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1376 h2 = io.smb2.out.file.handle;
1377 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1378 torture_wait_for_oplock_break(tctx);
1379 CHECK_VAL(break_info.count, 0);
1380 CHECK_VAL(break_info.failures, 0);
1382 smb2_util_close(tree1, h1);
1383 smb2_util_close(tree2, h2);
1384 smb2_util_close(tree1, h);
1386 smb2_deltree(tree1, BASEDIR);
1387 return ret;
1390 static bool test_smb2_oplock_batch9(struct torture_context *tctx,
1391 struct smb2_tree *tree1,
1392 struct smb2_tree *tree2)
1394 const char *fname = BASEDIR "\\test_batch9.dat";
1395 NTSTATUS status;
1396 bool ret = true;
1397 union smb_open io;
1398 struct smb2_handle h, h1, h2;
1399 char c = 0;
1401 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1402 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1404 /* cleanup */
1405 smb2_util_unlink(tree1, fname);
1407 tree1->session->transport->oplock.handler = torture_oplock_handler;
1408 tree1->session->transport->oplock.private_data = tree1;
1411 base ntcreatex parms
1413 ZERO_STRUCT(io.smb2);
1414 io.generic.level = RAW_OPEN_SMB2;
1415 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1416 io.smb2.in.alloc_size = 0;
1417 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1418 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1419 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1420 io.smb2.in.create_options = 0;
1421 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1422 io.smb2.in.security_flags = 0;
1423 io.smb2.in.fname = fname;
1425 torture_comment(tctx, "BATCH9: open with attributes only can create "
1426 "file\n");
1428 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1429 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1430 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1431 SEC_FILE_WRITE_ATTRIBUTE |
1432 SEC_STD_SYNCHRONIZE;
1433 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1434 status = smb2_create(tree1, tctx, &(io.smb2));
1435 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1436 h1 = io.smb2.out.file.handle;
1437 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1439 torture_comment(tctx, "Subsequent normal open should break oplock on "
1440 "attribute only open to level II\n");
1442 ZERO_STRUCT(break_info);
1444 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1445 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1446 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1447 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1448 status = smb2_create(tree2, tctx, &(io.smb2));
1449 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1450 h2 = io.smb2.out.file.handle;
1451 torture_wait_for_oplock_break(tctx);
1452 CHECK_VAL(break_info.count, 1);
1453 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1454 CHECK_VAL(break_info.failures, 0);
1455 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1456 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1457 smb2_util_close(tree2, h2);
1459 torture_comment(tctx, "third oplocked open should grant level2 without "
1460 "break\n");
1461 ZERO_STRUCT(break_info);
1463 tree2->session->transport->oplock.handler = torture_oplock_handler;
1464 tree2->session->transport->oplock.private_data = tree2;
1466 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1467 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1468 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1469 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1470 status = smb2_create(tree2, tctx, &(io.smb2));
1471 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1472 h2 = io.smb2.out.file.handle;
1473 torture_wait_for_oplock_break(tctx);
1474 CHECK_VAL(break_info.count, 0);
1475 CHECK_VAL(break_info.failures, 0);
1476 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1478 ZERO_STRUCT(break_info);
1480 torture_comment(tctx, "write should trigger a break to none on both\n");
1481 tree1->session->transport->oplock.handler =
1482 torture_oplock_handler_level2_to_none;
1483 tree2->session->transport->oplock.handler =
1484 torture_oplock_handler_level2_to_none;
1485 smb2_util_write(tree2, h2, &c, 0, 1);
1487 /* We expect two breaks */
1488 torture_wait_for_oplock_break(tctx);
1489 torture_wait_for_oplock_break(tctx);
1491 CHECK_VAL(break_info.count, 2);
1492 CHECK_VAL(break_info.level, 0);
1493 CHECK_VAL(break_info.failures, 0);
1495 smb2_util_close(tree1, h1);
1496 smb2_util_close(tree2, h2);
1497 smb2_util_close(tree1, h);
1499 smb2_deltree(tree1, BASEDIR);
1500 return ret;
1503 static bool test_smb2_oplock_batch10(struct torture_context *tctx,
1504 struct smb2_tree *tree1,
1505 struct smb2_tree *tree2)
1507 const char *fname = BASEDIR "\\test_batch10.dat";
1508 NTSTATUS status;
1509 bool ret = true;
1510 union smb_open io;
1511 struct smb2_handle h, h1, h2;
1513 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1514 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1516 /* cleanup */
1517 smb2_util_unlink(tree1, fname);
1519 tree1->session->transport->oplock.handler = torture_oplock_handler;
1520 tree1->session->transport->oplock.private_data = tree1;
1523 base ntcreatex parms
1525 ZERO_STRUCT(io.smb2);
1526 io.generic.level = RAW_OPEN_SMB2;
1527 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1528 io.smb2.in.alloc_size = 0;
1529 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1530 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1531 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1532 io.smb2.in.create_options = 0;
1533 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1534 io.smb2.in.security_flags = 0;
1535 io.smb2.in.fname = fname;
1537 torture_comment(tctx, "BATCH10: Open with oplock after a non-oplock "
1538 "open should grant level2\n");
1539 ZERO_STRUCT(break_info);
1540 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1541 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1542 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1543 NTCREATEX_SHARE_ACCESS_WRITE|
1544 NTCREATEX_SHARE_ACCESS_DELETE;
1545 status = smb2_create(tree1, tctx, &(io.smb2));
1546 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1547 h1 = io.smb2.out.file.handle;
1548 torture_wait_for_oplock_break(tctx);
1549 CHECK_VAL(break_info.count, 0);
1550 CHECK_VAL(break_info.failures, 0);
1551 CHECK_VAL(io.smb2.out.oplock_level, 0);
1553 tree2->session->transport->oplock.handler =
1554 torture_oplock_handler_level2_to_none;
1555 tree2->session->transport->oplock.private_data = tree2;
1557 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1558 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1559 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1560 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1561 NTCREATEX_SHARE_ACCESS_WRITE|
1562 NTCREATEX_SHARE_ACCESS_DELETE;
1563 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1564 status = smb2_create(tree2, tctx, &(io.smb2));
1565 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1566 h2 = io.smb2.out.file.handle;
1567 torture_wait_for_oplock_break(tctx);
1568 CHECK_VAL(break_info.count, 0);
1569 CHECK_VAL(break_info.failures, 0);
1570 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1572 torture_comment(tctx, "write should trigger a break to none\n");
1574 struct smb2_write wr;
1575 DATA_BLOB data;
1576 data = data_blob_talloc(tree1, NULL, UINT16_MAX);
1577 data.data[0] = (const uint8_t)'x';
1578 ZERO_STRUCT(wr);
1579 wr.in.file.handle = h1;
1580 wr.in.offset = 0;
1581 wr.in.data = data;
1582 status = smb2_write(tree1, &wr);
1583 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1586 torture_wait_for_oplock_break(tctx);
1588 CHECK_VAL(break_info.count, 1);
1589 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1590 CHECK_VAL(break_info.level, 0);
1591 CHECK_VAL(break_info.failures, 0);
1593 smb2_util_close(tree1, h1);
1594 smb2_util_close(tree2, h2);
1595 smb2_util_close(tree1, h);
1597 smb2_deltree(tree1, BASEDIR);
1598 return ret;
1601 static bool test_smb2_oplock_batch11(struct torture_context *tctx,
1602 struct smb2_tree *tree1,
1603 struct smb2_tree *tree2)
1605 const char *fname = BASEDIR "\\test_batch11.dat";
1606 NTSTATUS status;
1607 bool ret = true;
1608 union smb_open io;
1609 union smb_setfileinfo sfi;
1610 struct smb2_handle h, h1;
1612 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1613 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1615 /* cleanup */
1616 smb2_util_unlink(tree1, fname);
1618 tree1->session->transport->oplock.handler =
1619 torture_oplock_handler_two_notifications;
1620 tree1->session->transport->oplock.private_data = tree1;
1623 base ntcreatex parms
1625 ZERO_STRUCT(io.smb2);
1626 io.generic.level = RAW_OPEN_SMB2;
1627 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1628 io.smb2.in.alloc_size = 0;
1629 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1630 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1631 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1632 io.smb2.in.create_options = 0;
1633 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1634 io.smb2.in.security_flags = 0;
1635 io.smb2.in.fname = fname;
1637 /* Test if a set-eof on pathname breaks an exclusive oplock. */
1638 torture_comment(tctx, "BATCH11: Test if setpathinfo set EOF breaks "
1639 "oplocks.\n");
1641 ZERO_STRUCT(break_info);
1643 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1644 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1645 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1646 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1647 NTCREATEX_SHARE_ACCESS_WRITE|
1648 NTCREATEX_SHARE_ACCESS_DELETE;
1649 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1650 status = smb2_create(tree1, tctx, &(io.smb2));
1651 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1652 h1 = io.smb2.out.file.handle;
1653 torture_wait_for_oplock_break(tctx);
1654 CHECK_VAL(break_info.count, 0);
1655 CHECK_VAL(break_info.failures, 0);
1656 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1658 ZERO_STRUCT(sfi);
1659 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1660 sfi.generic.in.file.path = fname;
1661 sfi.end_of_file_info.in.size = 100;
1663 status = smb2_composite_setpathinfo(tree2, &sfi);
1664 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1666 /* We expect two breaks */
1667 torture_wait_for_oplock_break(tctx);
1668 torture_wait_for_oplock_break(tctx);
1670 CHECK_VAL(break_info.count, 2);
1671 CHECK_VAL(break_info.failures, 0);
1672 CHECK_VAL(break_info.level, 0);
1674 smb2_util_close(tree1, h1);
1675 smb2_util_close(tree1, h);
1677 smb2_deltree(tree1, BASEDIR);
1678 return ret;
1681 static bool test_smb2_oplock_batch12(struct torture_context *tctx,
1682 struct smb2_tree *tree1,
1683 struct smb2_tree *tree2)
1685 const char *fname = BASEDIR "\\test_batch12.dat";
1686 NTSTATUS status;
1687 bool ret = true;
1688 union smb_open io;
1689 union smb_setfileinfo sfi;
1690 struct smb2_handle h, h1;
1692 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1693 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1695 /* cleanup */
1696 smb2_util_unlink(tree1, fname);
1698 tree1->session->transport->oplock.handler =
1699 torture_oplock_handler_two_notifications;
1700 tree1->session->transport->oplock.private_data = tree1;
1703 base ntcreatex parms
1705 ZERO_STRUCT(io.smb2);
1706 io.generic.level = RAW_OPEN_SMB2;
1707 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1708 io.smb2.in.alloc_size = 0;
1709 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1710 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1711 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1712 io.smb2.in.create_options = 0;
1713 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1714 io.smb2.in.security_flags = 0;
1715 io.smb2.in.fname = fname;
1717 /* Test if a set-allocation size on pathname breaks an exclusive
1718 * oplock. */
1719 torture_comment(tctx, "BATCH12: Test if setpathinfo allocation size "
1720 "breaks oplocks.\n");
1722 ZERO_STRUCT(break_info);
1724 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1725 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1726 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1727 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1728 NTCREATEX_SHARE_ACCESS_WRITE|
1729 NTCREATEX_SHARE_ACCESS_DELETE;
1730 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1731 status = smb2_create(tree1, tctx, &(io.smb2));
1732 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1733 h1 = io.smb2.out.file.handle;
1734 torture_wait_for_oplock_break(tctx);
1735 CHECK_VAL(break_info.count, 0);
1736 CHECK_VAL(break_info.failures, 0);
1737 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1739 ZERO_STRUCT(sfi);
1740 sfi.generic.level = RAW_SFILEINFO_ALLOCATION_INFORMATION;
1741 sfi.generic.in.file.path = fname;
1742 sfi.allocation_info.in.alloc_size = 65536 * 8;
1744 status = smb2_composite_setpathinfo(tree2, &sfi);
1745 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1747 /* We expect two breaks */
1748 torture_wait_for_oplock_break(tctx);
1749 torture_wait_for_oplock_break(tctx);
1751 CHECK_VAL(break_info.count, 2);
1752 CHECK_VAL(break_info.failures, 0);
1753 CHECK_VAL(break_info.level, 0);
1755 smb2_util_close(tree1, h1);
1756 smb2_util_close(tree1, h);
1758 smb2_deltree(tree1, BASEDIR);
1759 return ret;
1762 static bool test_smb2_oplock_batch13(struct torture_context *tctx,
1763 struct smb2_tree *tree1,
1764 struct smb2_tree *tree2)
1766 const char *fname = BASEDIR "\\test_batch13.dat";
1767 NTSTATUS status;
1768 bool ret = true;
1769 union smb_open io;
1770 struct smb2_handle h, h1, h2;
1772 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1773 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1775 /* cleanup */
1776 smb2_util_unlink(tree1, fname);
1778 tree1->session->transport->oplock.handler = torture_oplock_handler;
1779 tree1->session->transport->oplock.private_data = tree1;
1781 tree2->session->transport->oplock.handler = torture_oplock_handler;
1782 tree2->session->transport->oplock.private_data = tree2;
1785 base ntcreatex parms
1787 ZERO_STRUCT(io.smb2);
1788 io.generic.level = RAW_OPEN_SMB2;
1789 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1790 io.smb2.in.alloc_size = 0;
1791 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1792 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1793 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1794 io.smb2.in.create_options = 0;
1795 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1796 io.smb2.in.security_flags = 0;
1797 io.smb2.in.fname = fname;
1799 torture_comment(tctx, "BATCH13: open with batch oplock\n");
1800 ZERO_STRUCT(break_info);
1802 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1803 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1804 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1805 NTCREATEX_SHARE_ACCESS_WRITE|
1806 NTCREATEX_SHARE_ACCESS_DELETE;
1807 status = smb2_create(tree1, tctx, &(io.smb2));
1808 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1809 h1 = io.smb2.out.file.handle;
1810 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1812 ZERO_STRUCT(break_info);
1814 torture_comment(tctx, "second open with attributes only and "
1815 "NTCREATEX_DISP_OVERWRITE dispostion causes "
1816 "oplock break\n");
1818 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1819 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1820 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1821 SEC_FILE_WRITE_ATTRIBUTE |
1822 SEC_STD_SYNCHRONIZE;
1823 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1824 NTCREATEX_SHARE_ACCESS_WRITE|
1825 NTCREATEX_SHARE_ACCESS_DELETE;
1826 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1827 status = smb2_create(tree2, tctx, &(io.smb2));
1828 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1829 h2 = io.smb2.out.file.handle;
1830 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1831 torture_wait_for_oplock_break(tctx);
1832 CHECK_VAL(break_info.count, 1);
1833 CHECK_VAL(break_info.failures, 0);
1835 smb2_util_close(tree1, h1);
1836 smb2_util_close(tree2, h2);
1837 smb2_util_close(tree1, h);
1839 smb2_deltree(tree1, BASEDIR);
1841 return ret;
1844 static bool test_smb2_oplock_batch14(struct torture_context *tctx,
1845 struct smb2_tree *tree1,
1846 struct smb2_tree *tree2)
1848 const char *fname = BASEDIR "\\test_batch14.dat";
1849 NTSTATUS status;
1850 bool ret = true;
1851 union smb_open io;
1852 struct smb2_handle h, h1, h2;
1854 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1855 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1857 /* cleanup */
1858 smb2_util_unlink(tree1, fname);
1860 tree1->session->transport->oplock.handler = torture_oplock_handler;
1861 tree1->session->transport->oplock.private_data = tree1;
1864 base ntcreatex parms
1866 ZERO_STRUCT(io.smb2);
1867 io.generic.level = RAW_OPEN_SMB2;
1868 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1869 io.smb2.in.alloc_size = 0;
1870 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1871 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1872 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1873 io.smb2.in.create_options = 0;
1874 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1875 io.smb2.in.security_flags = 0;
1876 io.smb2.in.fname = fname;
1878 torture_comment(tctx, "BATCH14: open with batch oplock\n");
1879 ZERO_STRUCT(break_info);
1881 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1882 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1883 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1884 NTCREATEX_SHARE_ACCESS_WRITE|
1885 NTCREATEX_SHARE_ACCESS_DELETE;
1886 status = smb2_create(tree1, tctx, &(io.smb2));
1887 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1888 h1 = io.smb2.out.file.handle;
1889 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1891 ZERO_STRUCT(break_info);
1893 torture_comment(tctx, "second open with attributes only and "
1894 "NTCREATEX_DISP_SUPERSEDE dispostion causes "
1895 "oplock break\n");
1897 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1898 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1899 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1900 SEC_FILE_WRITE_ATTRIBUTE |
1901 SEC_STD_SYNCHRONIZE;
1902 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1903 NTCREATEX_SHARE_ACCESS_WRITE|
1904 NTCREATEX_SHARE_ACCESS_DELETE;
1905 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1906 status = smb2_create(tree2, tctx, &(io.smb2));
1907 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1908 h2 = io.smb2.out.file.handle;
1909 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1911 torture_wait_for_oplock_break(tctx);
1912 CHECK_VAL(break_info.count, 1);
1913 CHECK_VAL(break_info.failures, 0);
1915 smb2_util_close(tree1, h1);
1916 smb2_util_close(tree2, h2);
1917 smb2_util_close(tree1, h);
1919 smb2_deltree(tree1, BASEDIR);
1920 return ret;
1923 static bool test_smb2_oplock_batch15(struct torture_context *tctx,
1924 struct smb2_tree *tree1,
1925 struct smb2_tree *tree2)
1927 const char *fname = BASEDIR "\\test_batch15.dat";
1928 NTSTATUS status;
1929 bool ret = true;
1930 union smb_open io;
1931 union smb_fileinfo qfi;
1932 struct smb2_handle h, h1;
1934 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1935 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1937 /* cleanup */
1938 smb2_util_unlink(tree1, fname);
1940 tree1->session->transport->oplock.handler = torture_oplock_handler;
1941 tree1->session->transport->oplock.private_data = tree1;
1944 base ntcreatex parms
1946 ZERO_STRUCT(io.smb2);
1947 io.generic.level = RAW_OPEN_SMB2;
1948 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1949 io.smb2.in.alloc_size = 0;
1950 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1951 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1952 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1953 io.smb2.in.create_options = 0;
1954 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1955 io.smb2.in.security_flags = 0;
1956 io.smb2.in.fname = fname;
1958 /* Test if a qpathinfo all info on pathname breaks a batch oplock. */
1959 torture_comment(tctx, "BATCH15: Test if qpathinfo all info breaks "
1960 "a batch oplock (should not).\n");
1962 ZERO_STRUCT(break_info);
1964 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1965 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1966 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1967 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1968 NTCREATEX_SHARE_ACCESS_WRITE|
1969 NTCREATEX_SHARE_ACCESS_DELETE;
1970 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1971 status = smb2_create(tree1, tctx, &(io.smb2));
1972 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1973 h1 = io.smb2.out.file.handle;
1975 torture_wait_for_oplock_break(tctx);
1976 CHECK_VAL(break_info.count, 0);
1977 CHECK_VAL(break_info.failures, 0);
1978 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1980 ZERO_STRUCT(qfi);
1981 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
1982 qfi.generic.in.file.handle = h1;
1983 status = smb2_getinfo_file(tree2, tctx, &qfi);
1985 torture_wait_for_oplock_break(tctx);
1986 CHECK_VAL(break_info.count, 0);
1988 smb2_util_close(tree1, h1);
1989 smb2_util_close(tree1, h);
1991 smb2_deltree(tree1, BASEDIR);
1992 return ret;
1995 static bool test_smb2_oplock_batch16(struct torture_context *tctx,
1996 struct smb2_tree *tree1,
1997 struct smb2_tree *tree2)
1999 const char *fname = BASEDIR "\\test_batch16.dat";
2000 NTSTATUS status;
2001 bool ret = true;
2002 union smb_open io;
2003 struct smb2_handle h, h1, h2;
2005 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2006 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2008 /* cleanup */
2009 smb2_util_unlink(tree1, fname);
2011 tree1->session->transport->oplock.handler = torture_oplock_handler;
2012 tree1->session->transport->oplock.private_data = tree1;
2014 tree2->session->transport->oplock.handler = torture_oplock_handler;
2015 tree2->session->transport->oplock.private_data = tree2;
2018 base ntcreatex parms
2020 ZERO_STRUCT(io.smb2);
2021 io.generic.level = RAW_OPEN_SMB2;
2022 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2023 io.smb2.in.alloc_size = 0;
2024 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2025 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2026 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2027 io.smb2.in.create_options = 0;
2028 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2029 io.smb2.in.security_flags = 0;
2030 io.smb2.in.fname = fname;
2032 torture_comment(tctx, "BATCH16: open with batch oplock\n");
2033 ZERO_STRUCT(break_info);
2035 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2036 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2037 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2038 NTCREATEX_SHARE_ACCESS_WRITE|
2039 NTCREATEX_SHARE_ACCESS_DELETE;
2040 status = smb2_create(tree1, tctx, &(io.smb2));
2041 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2042 h1 = io.smb2.out.file.handle;
2043 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2045 ZERO_STRUCT(break_info);
2047 torture_comment(tctx, "second open with attributes only and "
2048 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
2049 "oplock break\n");
2051 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2052 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2053 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2054 SEC_FILE_WRITE_ATTRIBUTE |
2055 SEC_STD_SYNCHRONIZE;
2056 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2057 NTCREATEX_SHARE_ACCESS_WRITE|
2058 NTCREATEX_SHARE_ACCESS_DELETE;
2059 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
2060 status = smb2_create(tree2, tctx, &(io.smb2));
2061 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2062 h2 = io.smb2.out.file.handle;
2063 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2065 torture_wait_for_oplock_break(tctx);
2066 CHECK_VAL(break_info.count, 1);
2067 CHECK_VAL(break_info.failures, 0);
2069 smb2_util_close(tree1, h1);
2070 smb2_util_close(tree2, h2);
2071 smb2_util_close(tree1, h);
2073 smb2_deltree(tree1, BASEDIR);
2074 return ret;
2077 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH17 test. Since
2078 * SMB2 doesn't have a RENAME command this test isn't applicable. However,
2079 * it's much less confusing, when comparing test, to keep the SMB1 and SMB2
2080 * test numbers in sync. */
2081 #if 0
2082 static bool test_raw_oplock_batch17(struct torture_context *tctx,
2083 struct smb2_tree *tree1,
2084 struct smb2_tree *tree2)
2086 return true;
2088 #endif
2090 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH18 test. Since
2091 * SMB2 doesn't have an NTRENAME command this test isn't applicable. However,
2092 * it's much less confusing, when comparing tests, to keep the SMB1 and SMB2
2093 * test numbers in sync. */
2094 #if 0
2095 static bool test_raw_oplock_batch18(struct torture_context *tctx,
2096 struct smb2_tree *tree1,
2097 struct smb2_tree *tree2)
2099 return true;
2101 #endif
2103 static bool test_smb2_oplock_batch19(struct torture_context *tctx,
2104 struct smb2_tree *tree1)
2106 const char *fname1 = BASEDIR "\\test_batch19_1.dat";
2107 const char *fname2 = BASEDIR "\\test_batch19_2.dat";
2108 NTSTATUS status;
2109 bool ret = true;
2110 union smb_open io;
2111 union smb_fileinfo qfi;
2112 union smb_setfileinfo sfi;
2113 struct smb2_handle h, h1;
2115 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2116 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2118 /* cleanup */
2119 smb2_util_unlink(tree1, fname1);
2120 smb2_util_unlink(tree1, fname2);
2122 tree1->session->transport->oplock.handler = torture_oplock_handler;
2123 tree1->session->transport->oplock.private_data = tree1;
2126 base ntcreatex parms
2128 ZERO_STRUCT(io.smb2);
2129 io.generic.level = RAW_OPEN_SMB2;
2130 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2131 io.smb2.in.alloc_size = 0;
2132 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2133 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2134 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2135 io.smb2.in.create_options = 0;
2136 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2137 io.smb2.in.security_flags = 0;
2138 io.smb2.in.fname = fname1;
2140 torture_comment(tctx, "BATCH19: open a file with an batch oplock "
2141 "(share mode: none)\n");
2142 ZERO_STRUCT(break_info);
2143 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2144 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2145 status = smb2_create(tree1, tctx, &(io.smb2));
2146 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2147 h1 = io.smb2.out.file.handle;
2148 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2150 torture_comment(tctx, "setfileinfo rename info should not trigger "
2151 "a break but should cause a sharing violation\n");
2152 ZERO_STRUCT(sfi);
2153 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2154 sfi.generic.in.file.path = fname1;
2155 sfi.rename_information.in.file.handle = h1;
2156 sfi.rename_information.in.overwrite = 0;
2157 sfi.rename_information.in.root_fid = 0;
2158 sfi.rename_information.in.new_name = fname2;
2160 status = smb2_setinfo_file(tree1, &sfi);
2162 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2163 "Incorrect status");
2165 torture_wait_for_oplock_break(tctx);
2166 CHECK_VAL(break_info.count, 0);
2168 ZERO_STRUCT(qfi);
2169 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2170 qfi.generic.in.file.handle = h1;
2172 status = smb2_getinfo_file(tree1, tctx, &qfi);
2173 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2174 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2176 smb2_util_close(tree1, h1);
2177 smb2_util_close(tree1, h);
2179 smb2_deltree(tree1, fname1);
2180 smb2_deltree(tree1, fname2);
2181 return ret;
2184 static bool test_smb2_oplock_batch20(struct torture_context *tctx,
2185 struct smb2_tree *tree1,
2186 struct smb2_tree *tree2)
2188 const char *fname1 = BASEDIR "\\test_batch20_1.dat";
2189 const char *fname2 = BASEDIR "\\test_batch20_2.dat";
2190 NTSTATUS status;
2191 bool ret = true;
2192 union smb_open io;
2193 union smb_fileinfo qfi;
2194 union smb_setfileinfo sfi;
2195 struct smb2_handle h, h1, h2;
2197 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2198 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2200 /* cleanup */
2201 smb2_util_unlink(tree1, fname1);
2202 smb2_util_unlink(tree1, fname2);
2204 tree1->session->transport->oplock.handler = torture_oplock_handler;
2205 tree1->session->transport->oplock.private_data = tree1;
2208 base ntcreatex parms
2210 ZERO_STRUCT(io.smb2);
2211 io.generic.level = RAW_OPEN_SMB2;
2212 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2213 io.smb2.in.alloc_size = 0;
2214 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2215 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2216 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2217 io.smb2.in.create_options = 0;
2218 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2219 io.smb2.in.security_flags = 0;
2220 io.smb2.in.fname = fname1;
2222 torture_comment(tctx, "BATCH20: open a file with an batch oplock "
2223 "(share mode: all)\n");
2224 ZERO_STRUCT(break_info);
2225 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2226 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2227 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2228 NTCREATEX_SHARE_ACCESS_WRITE|
2229 NTCREATEX_SHARE_ACCESS_DELETE;
2230 status = smb2_create(tree1, tctx, &(io.smb2));
2231 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2232 h1 = io.smb2.out.file.handle;
2233 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2235 torture_comment(tctx, "setfileinfo rename info should not trigger "
2236 "a break but should cause a sharing violation\n");
2237 ZERO_STRUCT(sfi);
2238 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2239 sfi.rename_information.in.file.handle = h1;
2240 sfi.rename_information.in.overwrite = 0;
2241 sfi.rename_information.in.new_name = fname2;
2243 status = smb2_setinfo_file(tree1, &sfi);
2244 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2245 "Incorrect status");
2247 torture_wait_for_oplock_break(tctx);
2248 CHECK_VAL(break_info.count, 0);
2250 ZERO_STRUCT(qfi);
2251 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2252 qfi.generic.in.file.handle = h1;
2254 status = smb2_getinfo_file(tree1, tctx, &qfi);
2255 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2256 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2258 torture_comment(tctx, "open the file a second time requesting batch "
2259 "(share mode: all)\n");
2260 ZERO_STRUCT(break_info);
2261 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2262 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2263 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2264 NTCREATEX_SHARE_ACCESS_WRITE|
2265 NTCREATEX_SHARE_ACCESS_DELETE;
2266 io.smb2.in.fname = fname1;
2267 status = smb2_create(tree2, tctx, &(io.smb2));
2268 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2269 h2 = io.smb2.out.file.handle;
2270 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2272 torture_wait_for_oplock_break(tctx);
2273 CHECK_VAL(break_info.count, 1);
2274 CHECK_VAL(break_info.failures, 0);
2275 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2277 torture_comment(tctx, "setfileinfo rename info should not trigger "
2278 "a break but should cause a sharing violation\n");
2279 ZERO_STRUCT(break_info);
2280 ZERO_STRUCT(sfi);
2281 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2282 sfi.rename_information.in.file.handle = h2;
2283 sfi.rename_information.in.overwrite = 0;
2284 sfi.rename_information.in.new_name = fname2;
2286 status = smb2_setinfo_file(tree2, &sfi);
2287 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2288 "Incorrect status");
2290 torture_wait_for_oplock_break(tctx);
2291 CHECK_VAL(break_info.count, 0);
2293 ZERO_STRUCT(qfi);
2294 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2295 qfi.generic.in.file.handle = h1;
2297 status = smb2_getinfo_file(tree1, tctx, &qfi);
2298 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2299 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2301 ZERO_STRUCT(qfi);
2302 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2303 qfi.generic.in.file.handle = h2;
2305 status = smb2_getinfo_file(tree2, tctx, &qfi);
2306 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2307 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2309 smb2_util_close(tree1, h1);
2310 smb2_util_close(tree2, h2);
2311 smb2_util_close(tree1, h);
2313 smb2_deltree(tree1, fname1);
2314 return ret;
2317 static bool test_smb2_oplock_batch21(struct torture_context *tctx,
2318 struct smb2_tree *tree1)
2320 const char *fname = BASEDIR "\\test_batch21.dat";
2321 NTSTATUS status;
2322 bool ret = true;
2323 union smb_open io;
2324 struct smb2_handle h, h1;
2325 char c = 0;
2327 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2328 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2330 /* cleanup */
2331 smb2_util_unlink(tree1, fname);
2333 tree1->session->transport->oplock.handler = torture_oplock_handler;
2334 tree1->session->transport->oplock.private_data = tree1;
2337 base ntcreatex parms
2339 ZERO_STRUCT(io.smb2);
2340 io.generic.level = RAW_OPEN_SMB2;
2341 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2342 io.smb2.in.alloc_size = 0;
2343 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2344 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2345 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2346 io.smb2.in.create_options = 0;
2347 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2348 io.smb2.in.security_flags = 0;
2349 io.smb2.in.fname = fname;
2352 with a batch oplock we get a break
2354 torture_comment(tctx, "BATCH21: open with batch oplock\n");
2355 ZERO_STRUCT(break_info);
2356 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2357 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2358 status = smb2_create(tree1, tctx, &(io.smb2));
2359 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2360 h1 = io.smb2.out.file.handle;
2361 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2363 torture_comment(tctx, "writing should not generate a break\n");
2364 status = smb2_util_write(tree1, h1, &c, 0, 1);
2365 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2367 torture_wait_for_oplock_break(tctx);
2368 CHECK_VAL(break_info.count, 0);
2370 smb2_util_close(tree1, h1);
2371 smb2_util_close(tree1, h);
2373 smb2_deltree(tree1, BASEDIR);
2374 return ret;
2377 static bool test_smb2_oplock_batch22(struct torture_context *tctx,
2378 struct smb2_tree *tree1)
2380 const char *fname = BASEDIR "\\test_batch22.dat";
2381 NTSTATUS status;
2382 bool ret = true;
2383 union smb_open io;
2384 struct smb2_handle h, h1, h2;
2385 struct timeval tv;
2386 int timeout = torture_setting_int(tctx, "oplocktimeout", 30);
2387 int te;
2389 if (torture_setting_bool(tctx, "samba3", false)) {
2390 torture_skip(tctx, "BATCH22 disabled against samba3\n");
2393 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2394 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2396 /* cleanup */
2397 smb2_util_unlink(tree1, fname);
2399 tree1->session->transport->oplock.handler = torture_oplock_handler;
2400 tree1->session->transport->oplock.private_data = tree1;
2402 base ntcreatex parms
2404 ZERO_STRUCT(io.smb2);
2405 io.generic.level = RAW_OPEN_SMB2;
2406 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2407 io.smb2.in.alloc_size = 0;
2408 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2409 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2410 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2411 io.smb2.in.create_options = 0;
2412 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2413 io.smb2.in.security_flags = 0;
2414 io.smb2.in.fname = fname;
2417 with a batch oplock we get a break
2419 torture_comment(tctx, "BATCH22: open with batch oplock\n");
2420 ZERO_STRUCT(break_info);
2421 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2422 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2423 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2424 NTCREATEX_SHARE_ACCESS_WRITE|
2425 NTCREATEX_SHARE_ACCESS_DELETE;
2426 status = smb2_create(tree1, tctx, &(io.smb2));
2427 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2428 h1 = io.smb2.out.file.handle;
2429 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2431 torture_comment(tctx, "a 2nd open should succeed after the oplock "
2432 "break timeout\n");
2433 tv = timeval_current();
2434 tree1->session->transport->oplock.handler =
2435 torture_oplock_handler_timeout;
2436 status = smb2_create(tree1, tctx, &(io.smb2));
2437 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2438 h2 = io.smb2.out.file.handle;
2439 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2441 torture_wait_for_oplock_break(tctx);
2442 te = (int)timeval_elapsed(&tv);
2443 CHECK_RANGE(te, timeout - 1, timeout + 15);
2444 torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
2446 CHECK_VAL(break_info.count, 1);
2447 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2448 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2449 CHECK_VAL(break_info.failures, 0);
2451 smb2_util_close(tree1, h1);
2452 smb2_util_close(tree1, h2);
2453 smb2_util_close(tree1, h);
2455 smb2_deltree(tree1, BASEDIR);
2456 return ret;
2459 static bool test_smb2_oplock_batch23(struct torture_context *tctx,
2460 struct smb2_tree *tree1,
2461 struct smb2_tree *tree2)
2463 const char *fname = BASEDIR "\\test_batch23.dat";
2464 NTSTATUS status;
2465 bool ret = true;
2466 union smb_open io;
2467 struct smb2_handle h, h1, h2, h3;
2468 struct smb2_tree *tree3 = NULL;
2470 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2471 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2473 /* cleanup */
2474 smb2_util_unlink(tree1, fname);
2476 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2477 CHECK_VAL(ret, true);
2479 tree1->session->transport->oplock.handler = torture_oplock_handler;
2480 tree1->session->transport->oplock.private_data = tree1;
2482 tree2->session->transport->oplock.handler = torture_oplock_handler;
2483 tree2->session->transport->oplock.private_data = tree2;
2485 tree3->session->transport->oplock.handler = torture_oplock_handler;
2486 tree3->session->transport->oplock.private_data = tree3;
2489 base ntcreatex parms
2491 ZERO_STRUCT(io.smb2);
2492 io.generic.level = RAW_OPEN_SMB2;
2493 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2494 io.smb2.in.alloc_size = 0;
2495 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2496 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2497 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2498 io.smb2.in.create_options = 0;
2499 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2500 io.smb2.in.security_flags = 0;
2501 io.smb2.in.fname = fname;
2503 torture_comment(tctx, "BATCH23: an open and ask for a batch oplock\n");
2504 ZERO_STRUCT(break_info);
2506 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2507 SEC_RIGHTS_FILE_WRITE;
2508 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2509 NTCREATEX_SHARE_ACCESS_WRITE;
2510 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2511 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2512 status = smb2_create(tree1, tctx, &(io.smb2));
2513 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2514 h1 = io.smb2.out.file.handle;
2515 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2517 ZERO_STRUCT(break_info);
2519 torture_comment(tctx, "a 2nd open without level2 oplock support "
2520 "should generate a break to level2\n");
2521 status = smb2_create(tree3, tctx, &(io.smb2));
2522 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2523 h3 = io.smb2.out.file.handle;
2525 torture_wait_for_oplock_break(tctx);
2526 CHECK_VAL(break_info.count, 1);
2527 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2528 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2529 CHECK_VAL(break_info.failures, 0);
2531 ZERO_STRUCT(break_info);
2533 torture_comment(tctx, "a 3rd open with level2 oplock support should "
2534 "not generate a break\n");
2535 status = smb2_create(tree2, tctx, &(io.smb2));
2536 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2537 h2 = io.smb2.out.file.handle;
2538 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2540 torture_wait_for_oplock_break(tctx);
2541 CHECK_VAL(break_info.count, 0);
2543 smb2_util_close(tree1, h1);
2544 smb2_util_close(tree2, h2);
2545 smb2_util_close(tree3, h3);
2546 smb2_util_close(tree1, h);
2548 smb2_deltree(tree1, BASEDIR);
2549 return ret;
2552 static bool test_smb2_oplock_batch24(struct torture_context *tctx,
2553 struct smb2_tree *tree1,
2554 struct smb2_tree *tree2)
2556 const char *fname = BASEDIR "\\test_batch24.dat";
2557 NTSTATUS status;
2558 bool ret = true;
2559 union smb_open io;
2560 struct smb2_handle h, h1, h2;
2561 struct smb2_tree *tree3 = NULL;
2563 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2564 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2566 /* cleanup */
2567 smb2_util_unlink(tree1, fname);
2569 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2570 CHECK_VAL(ret, true);
2572 tree1->session->transport->oplock.handler = torture_oplock_handler;
2573 tree1->session->transport->oplock.private_data = tree1;
2575 tree2->session->transport->oplock.handler = torture_oplock_handler;
2576 tree2->session->transport->oplock.private_data = tree2;
2578 tree3->session->transport->oplock.handler = torture_oplock_handler;
2579 tree3->session->transport->oplock.private_data = tree3;
2582 base ntcreatex parms
2584 ZERO_STRUCT(io.smb2);
2585 io.generic.level = RAW_OPEN_SMB2;
2586 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2587 io.smb2.in.alloc_size = 0;
2588 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2589 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2590 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2591 io.smb2.in.create_options = 0;
2592 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2593 io.smb2.in.security_flags = 0;
2594 io.smb2.in.fname = fname;
2596 torture_comment(tctx, "BATCH24: a open without level support and "
2597 "ask for a batch oplock\n");
2598 ZERO_STRUCT(break_info);
2600 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2601 SEC_RIGHTS_FILE_WRITE;
2602 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2603 NTCREATEX_SHARE_ACCESS_WRITE;
2604 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2605 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2607 status = smb2_create(tree3, tctx, &(io.smb2));
2608 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2609 h2 = io.smb2.out.file.handle;
2610 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2612 ZERO_STRUCT(break_info);
2614 torture_comment(tctx, "a 2nd open with level2 oplock support should "
2615 "generate a break\n");
2616 status = smb2_create(tree2, tctx, &(io.smb2));
2617 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2618 h1 = io.smb2.out.file.handle;
2619 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2621 torture_wait_for_oplock_break(tctx);
2622 CHECK_VAL(break_info.count, 1);
2623 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
2624 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2625 CHECK_VAL(break_info.failures, 0);
2627 smb2_util_close(tree3, h2);
2628 smb2_util_close(tree2, h1);
2629 smb2_util_close(tree1, h);
2631 smb2_deltree(tree1, BASEDIR);
2632 return ret;
2635 static bool test_smb2_oplock_batch25(struct torture_context *tctx,
2636 struct smb2_tree *tree1)
2638 const char *fname = BASEDIR "\\test_batch25.dat";
2639 NTSTATUS status;
2640 bool ret = true;
2641 union smb_open io;
2642 struct smb2_handle h, h1;
2644 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2645 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2647 /* cleanup */
2648 smb2_util_unlink(tree1, fname);
2650 tree1->session->transport->oplock.handler = torture_oplock_handler;
2651 tree1->session->transport->oplock.private_data = tree1;
2654 base ntcreatex parms
2656 ZERO_STRUCT(io.smb2);
2657 io.generic.level = RAW_OPEN_SMB2;
2658 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2659 io.smb2.in.alloc_size = 0;
2660 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2661 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2662 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2663 io.smb2.in.create_options = 0;
2664 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2665 io.smb2.in.security_flags = 0;
2666 io.smb2.in.fname = fname;
2668 torture_comment(tctx, "BATCH25: open a file with an batch oplock "
2669 "(share mode: none)\n");
2671 ZERO_STRUCT(break_info);
2672 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2673 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2675 status = smb2_create(tree1, tctx, &(io.smb2));
2676 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2677 h1 = io.smb2.out.file.handle;
2678 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2680 torture_comment(tctx, "changing the file attribute info should trigger "
2681 "a break and a violation\n");
2683 status = smb2_util_setatr(tree1, fname, FILE_ATTRIBUTE_HIDDEN);
2684 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2685 "Incorrect status");
2687 torture_wait_for_oplock_break(tctx);
2688 CHECK_VAL(break_info.count, 1);
2690 smb2_util_close(tree1, h1);
2691 smb2_util_close(tree1, h);
2693 smb2_deltree(tree1, fname);
2694 return ret;
2697 /* Test how oplocks work on streams. */
2698 static bool test_raw_oplock_stream1(struct torture_context *tctx,
2699 struct smb2_tree *tree1,
2700 struct smb2_tree *tree2)
2702 NTSTATUS status;
2703 union smb_open io;
2704 const char *fname_base = BASEDIR "\\test_stream1.txt";
2705 const char *fname_stream, *fname_default_stream;
2706 const char *default_stream = "::$DATA";
2707 const char *stream = "Stream One:$DATA";
2708 bool ret = true;
2709 struct smb2_handle h, h_base, h_stream;
2710 int i;
2712 #define NSTREAM_OPLOCK_RESULTS 8
2713 struct {
2714 const char **fname;
2715 bool open_base_file;
2716 uint32_t oplock_req;
2717 uint32_t oplock_granted;
2718 } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
2719 /* Request oplock on stream without the base file open. */
2720 {&fname_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2721 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2722 {&fname_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2723 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2725 /* Request oplock on stream with the base file open. */
2726 {&fname_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2727 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_II},
2728 {&fname_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2729 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_II},
2732 /* Only passes against windows at the moment. */
2733 if (torture_setting_bool(tctx, "samba3", false) ||
2734 torture_setting_bool(tctx, "samba4", false)) {
2735 torture_skip(tctx, "STREAM1 disabled against samba3+4\n");
2738 fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
2739 fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
2740 default_stream);
2742 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2743 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2745 /* Initialize handles to "closed". Using -1 in the first 64-bytes
2746 * as the sentry for this */
2747 h_stream.data[0] = -1;
2749 /* cleanup */
2750 smb2_util_unlink(tree1, fname_base);
2752 tree1->session->transport->oplock.handler = torture_oplock_handler;
2753 tree1->session->transport->oplock.private_data = tree1;
2755 tree2->session->transport->oplock.handler = torture_oplock_handler;
2756 tree2->session->transport->oplock.private_data = tree2;
2758 /* Setup generic open parameters. */
2759 ZERO_STRUCT(io.smb2);
2760 io.generic.level = RAW_OPEN_SMB2;
2761 io.smb2.in.desired_access = (SEC_FILE_READ_DATA |
2762 SEC_FILE_WRITE_DATA |
2763 SEC_FILE_APPEND_DATA |
2764 SEC_STD_READ_CONTROL);
2765 io.smb2.in.alloc_size = 0;
2766 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2767 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2768 NTCREATEX_SHARE_ACCESS_WRITE;
2769 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2770 io.smb2.in.create_options = 0;
2771 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2772 io.smb2.in.security_flags = 0;
2774 /* Create the file with a stream */
2775 io.smb2.in.fname = fname_stream;
2776 io.smb2.in.create_flags = 0;
2777 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2778 status = smb2_create(tree1, tctx, &(io.smb2));
2779 torture_assert_ntstatus_ok(tctx, status, "Error creating file");
2780 smb2_util_close(tree1, io.smb2.out.file.handle);
2782 /* Change the disposition to open now that the file has been created. */
2783 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2785 /* Try some permutations of taking oplocks on streams. */
2786 for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
2787 const char *fname = *stream_oplock_results[i].fname;
2788 bool open_base_file = stream_oplock_results[i].open_base_file;
2789 uint32_t oplock_req = stream_oplock_results[i].oplock_req;
2790 uint32_t oplock_granted =
2791 stream_oplock_results[i].oplock_granted;
2793 if (open_base_file) {
2794 torture_comment(tctx, "Opening base file: %s with "
2795 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2796 io.smb2.in.fname = fname_base;
2797 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2798 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2799 status = smb2_create(tree2, tctx, &(io.smb2));
2800 torture_assert_ntstatus_ok(tctx, status,
2801 "Error opening file");
2802 CHECK_VAL(io.smb2.out.oplock_level,
2803 SMB2_OPLOCK_LEVEL_BATCH);
2804 h_base = io.smb2.out.file.handle;
2807 torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
2808 fname, oplock_req);
2809 io.smb2.in.fname = fname;
2810 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2811 io.smb2.in.oplock_level = oplock_req;
2813 /* Do the open with the desired oplock on the stream. */
2814 status = smb2_create(tree1, tctx, &(io.smb2));
2815 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2816 CHECK_VAL(io.smb2.out.oplock_level, oplock_granted);
2817 smb2_util_close(tree1, io.smb2.out.file.handle);
2819 /* Cleanup the base file if it was opened. */
2820 if (open_base_file)
2821 smb2_util_close(tree2, h_base);
2824 /* Open the stream with an exclusive oplock. */
2825 torture_comment(tctx, "Opening stream: %s with %d\n",
2826 fname_stream, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
2827 io.smb2.in.fname = fname_stream;
2828 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2829 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
2830 status = smb2_create(tree1, tctx, &(io.smb2));
2831 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2832 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
2833 h_stream = io.smb2.out.file.handle;
2835 /* Open the base file and see if it contends. */
2836 ZERO_STRUCT(break_info);
2837 torture_comment(tctx, "Opening base file: %s with %d\n",
2838 fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2839 io.smb2.in.fname = fname_base;
2840 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2841 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2842 status = smb2_create(tree2, tctx, &(io.smb2));
2843 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2844 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2845 smb2_util_close(tree2, io.smb2.out.file.handle);
2847 torture_wait_for_oplock_break(tctx);
2848 CHECK_VAL(break_info.count, 0);
2849 CHECK_VAL(break_info.failures, 0);
2851 /* Open the stream again to see if it contends. */
2852 ZERO_STRUCT(break_info);
2853 torture_comment(tctx, "Opening stream again: %s with "
2854 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2855 io.smb2.in.fname = fname_stream;
2856 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2857 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
2858 status = smb2_create(tree2, tctx, &(io.smb2));
2859 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2860 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2861 smb2_util_close(tree2, io.smb2.out.file.handle);
2863 torture_wait_for_oplock_break(tctx);
2864 CHECK_VAL(break_info.count, 1);
2865 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
2866 CHECK_VAL(break_info.failures, 0);
2868 /* Close the stream. */
2869 if (h_stream.data[0] != -1) {
2870 smb2_util_close(tree1, h_stream);
2873 smb2_util_close(tree1, h);
2875 smb2_deltree(tree1, BASEDIR);
2876 return ret;
2879 static bool test_smb2_oplock_doc(struct torture_context *tctx, struct smb2_tree *tree)
2881 const char *fname = BASEDIR "\\test_oplock_doc.dat";
2882 NTSTATUS status;
2883 bool ret = true;
2884 union smb_open io;
2885 struct smb2_handle h, h1;
2887 status = torture_smb2_testdir(tree, BASEDIR, &h);
2888 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2890 /* cleanup */
2891 smb2_util_unlink(tree, fname);
2892 tree->session->transport->oplock.handler = torture_oplock_handler;
2893 tree->session->transport->oplock.private_data = tree;
2896 base ntcreatex parms
2898 ZERO_STRUCT(io.smb2);
2899 io.generic.level = RAW_OPEN_SMB2;
2900 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2901 io.smb2.in.alloc_size = 0;
2902 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2903 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2904 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2905 io.smb2.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
2906 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2907 io.smb2.in.security_flags = 0;
2908 io.smb2.in.fname = fname;
2910 torture_comment(tctx, "open a delete-on-close file with a batch "
2911 "oplock\n");
2912 ZERO_STRUCT(break_info);
2913 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2914 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2916 status = smb2_create(tree, tctx, &(io.smb2));
2917 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2918 h1 = io.smb2.out.file.handle;
2919 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2921 smb2_util_close(tree, h1);
2923 smb2_util_unlink(tree, fname);
2924 smb2_deltree(tree, BASEDIR);
2925 return ret;
2928 /* Open a file with a batch oplock, then open it again from a second client
2929 * requesting no oplock. Having two open file handles should break our own
2930 * oplock during BRL acquisition.
2932 static bool test_smb2_oplock_brl1(struct torture_context *tctx,
2933 struct smb2_tree *tree1,
2934 struct smb2_tree *tree2)
2936 const char *fname = BASEDIR "\\test_batch_brl.dat";
2937 /*int fname, f;*/
2938 bool ret = true;
2939 uint8_t buf[1000];
2940 bool correct = true;
2941 union smb_open io;
2942 NTSTATUS status;
2943 struct smb2_lock lck;
2944 struct smb2_lock_element lock[1];
2945 struct smb2_handle h, h1, h2;
2947 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2948 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2950 /* cleanup */
2951 smb2_util_unlink(tree1, fname);
2953 tree1->session->transport->oplock.handler =
2954 torture_oplock_handler_two_notifications;
2955 tree1->session->transport->oplock.private_data = tree1;
2958 base ntcreatex parms
2960 ZERO_STRUCT(io.smb2);
2961 io.generic.level = RAW_OPEN_SMB2;
2962 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2963 SEC_RIGHTS_FILE_WRITE;
2964 io.smb2.in.alloc_size = 0;
2965 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2966 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2967 NTCREATEX_SHARE_ACCESS_WRITE;
2968 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2969 io.smb2.in.create_options = 0;
2970 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2971 io.smb2.in.security_flags = 0;
2972 io.smb2.in.fname = fname;
2975 with a batch oplock we get a break
2977 torture_comment(tctx, "open with batch oplock\n");
2978 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2979 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2981 status = smb2_create(tree1, tctx, &(io.smb2));
2982 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2983 h1 = io.smb2.out.file.handle;
2984 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2986 /* create a file with bogus data */
2987 memset(buf, 0, sizeof(buf));
2989 status = smb2_util_write(tree1, h1,buf, 0, sizeof(buf));
2990 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
2991 torture_comment(tctx, "Failed to create file\n");
2992 correct = false;
2993 goto done;
2996 torture_comment(tctx, "a 2nd open should give a break\n");
2997 ZERO_STRUCT(break_info);
2999 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3000 io.smb2.in.oplock_level = 0;
3001 status = smb2_create(tree2, tctx, &(io.smb2));
3002 h2 = io.smb2.out.file.handle;
3003 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3005 torture_wait_for_oplock_break(tctx);
3006 CHECK_VAL(break_info.count, 1);
3007 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3008 CHECK_VAL(break_info.failures, 0);
3009 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3011 ZERO_STRUCT(break_info);
3013 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3014 lock[0].offset = 0;
3015 lock[0].length = 4;
3016 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3017 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3019 ZERO_STRUCT(lck);
3020 lck.in.file.handle = h1;
3021 lck.in.locks = &lock[0];
3022 lck.in.lock_count = 1;
3023 status = smb2_lock(tree1, &lck);
3024 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3026 torture_wait_for_oplock_break(tctx);
3027 CHECK_VAL(break_info.count, 1);
3028 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3029 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3030 CHECK_VAL(break_info.failures, 0);
3032 /* expect no oplock break */
3033 ZERO_STRUCT(break_info);
3034 lock[0].offset = 2;
3035 status = smb2_lock(tree1, &lck);
3036 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3037 "Incorrect status");
3039 torture_wait_for_oplock_break(tctx);
3040 CHECK_VAL(break_info.count, 0);
3041 CHECK_VAL(break_info.level, 0);
3042 CHECK_VAL(break_info.failures, 0);
3044 smb2_util_close(tree1, h1);
3045 smb2_util_close(tree2, h2);
3046 smb2_util_close(tree1, h);
3048 done:
3049 smb2_deltree(tree1, BASEDIR);
3050 return ret;
3054 /* Open a file with a batch oplock on one tree and then acquire a brl.
3055 * We should not contend our own oplock.
3057 static bool test_smb2_oplock_brl2(struct torture_context *tctx, struct smb2_tree *tree1)
3059 const char *fname = BASEDIR "\\test_batch_brl.dat";
3060 /*int fname, f;*/
3061 bool ret = true;
3062 uint8_t buf[1000];
3063 bool correct = true;
3064 union smb_open io;
3065 NTSTATUS status;
3066 struct smb2_handle h, h1;
3067 struct smb2_lock lck;
3068 struct smb2_lock_element lock[1];
3070 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3071 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3073 /* cleanup */
3074 smb2_util_unlink(tree1, fname);
3076 tree1->session->transport->oplock.handler = torture_oplock_handler;
3077 tree1->session->transport->oplock.private_data = tree1;
3080 base ntcreatex parms
3082 ZERO_STRUCT(io.smb2);
3083 io.generic.level = RAW_OPEN_SMB2;
3084 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3085 SEC_RIGHTS_FILE_WRITE;
3086 io.smb2.in.alloc_size = 0;
3087 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3088 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3089 NTCREATEX_SHARE_ACCESS_WRITE;
3090 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3091 io.smb2.in.create_options = 0;
3092 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3093 io.smb2.in.security_flags = 0;
3094 io.smb2.in.fname = fname;
3097 with a batch oplock we get a break
3099 torture_comment(tctx, "open with batch oplock\n");
3100 ZERO_STRUCT(break_info);
3101 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3102 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3104 status = smb2_create(tree1, tctx, &(io.smb2));
3105 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3106 h1 = io.smb2.out.file.handle;
3107 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3109 /* create a file with bogus data */
3110 memset(buf, 0, sizeof(buf));
3112 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3113 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3114 torture_comment(tctx, "Failed to create file\n");
3115 correct = false;
3116 goto done;
3119 ZERO_STRUCT(break_info);
3121 torture_comment(tctx, "a self BRL acquisition should not break to "
3122 "none\n");
3124 lock[0].offset = 0;
3125 lock[0].length = 4;
3126 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3127 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3129 ZERO_STRUCT(lck);
3130 lck.in.file.handle = h1;
3131 lck.in.locks = &lock[0];
3132 lck.in.lock_count = 1;
3133 status = smb2_lock(tree1, &lck);
3134 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3136 lock[0].offset = 2;
3137 status = smb2_lock(tree1, &lck);
3138 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3139 "Incorrect status");
3141 /* With one file handle open a BRL should not contend our oplock.
3142 * Thus, no oplock break will be received and the entire break_info
3143 * struct will be 0 */
3144 torture_wait_for_oplock_break(tctx);
3145 CHECK_VAL(break_info.count, 0);
3146 CHECK_VAL(break_info.level, 0);
3147 CHECK_VAL(break_info.failures, 0);
3149 smb2_util_close(tree1, h1);
3150 smb2_util_close(tree1, h);
3152 done:
3153 smb2_deltree(tree1, BASEDIR);
3154 return ret;
3157 /* Open a file with a batch oplock twice from one tree and then acquire a
3158 * brl. BRL acquisition should break our own oplock.
3160 static bool test_smb2_oplock_brl3(struct torture_context *tctx, struct smb2_tree *tree1)
3162 const char *fname = BASEDIR "\\test_batch_brl.dat";
3163 bool ret = true;
3164 uint8_t buf[1000];
3165 bool correct = true;
3166 union smb_open io;
3167 NTSTATUS status;
3168 struct smb2_handle h, h1, h2;
3169 struct smb2_lock lck;
3170 struct smb2_lock_element lock[1];
3172 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3173 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3175 /* cleanup */
3176 smb2_util_unlink(tree1, fname);
3177 tree1->session->transport->oplock.handler =
3178 torture_oplock_handler_two_notifications;
3179 tree1->session->transport->oplock.private_data = tree1;
3182 base ntcreatex parms
3184 ZERO_STRUCT(io.smb2);
3185 io.generic.level = RAW_OPEN_SMB2;
3186 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3187 SEC_RIGHTS_FILE_WRITE;
3188 io.smb2.in.alloc_size = 0;
3189 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3190 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3191 NTCREATEX_SHARE_ACCESS_WRITE;
3192 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3193 io.smb2.in.create_options = 0;
3194 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3195 io.smb2.in.security_flags = 0;
3196 io.smb2.in.fname = fname;
3199 with a batch oplock we get a break
3201 torture_comment(tctx, "open with batch oplock\n");
3202 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3203 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3205 status = smb2_create(tree1, tctx, &(io.smb2));
3206 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3207 h1 = io.smb2.out.file.handle;
3208 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3210 /* create a file with bogus data */
3211 memset(buf, 0, sizeof(buf));
3212 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3214 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3215 torture_comment(tctx, "Failed to create file\n");
3216 correct = false;
3217 goto done;
3220 torture_comment(tctx, "a 2nd open should give a break\n");
3221 ZERO_STRUCT(break_info);
3223 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3224 io.smb2.in.oplock_level = 0;
3225 status = smb2_create(tree1, tctx, &(io.smb2));
3226 h2 = io.smb2.out.file.handle;
3227 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3228 CHECK_VAL(break_info.count, 1);
3229 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3230 CHECK_VAL(break_info.failures, 0);
3231 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3233 ZERO_STRUCT(break_info);
3235 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3237 lock[0].offset = 0;
3238 lock[0].length = 4;
3239 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3240 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3242 ZERO_STRUCT(lck);
3243 lck.in.file.handle = h1;
3244 lck.in.locks = &lock[0];
3245 lck.in.lock_count = 1;
3246 status = smb2_lock(tree1, &lck);
3247 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3249 torture_wait_for_oplock_break(tctx);
3250 CHECK_VAL(break_info.count, 1);
3251 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3252 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3253 CHECK_VAL(break_info.failures, 0);
3255 /* expect no oplock break */
3256 ZERO_STRUCT(break_info);
3257 lock[0].offset = 2;
3258 status = smb2_lock(tree1, &lck);
3259 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3260 "Incorrect status");
3262 torture_wait_for_oplock_break(tctx);
3263 CHECK_VAL(break_info.count, 0);
3264 CHECK_VAL(break_info.level, 0);
3265 CHECK_VAL(break_info.failures, 0);
3267 smb2_util_close(tree1, h1);
3268 smb2_util_close(tree1, h2);
3269 smb2_util_close(tree1, h);
3271 done:
3272 smb2_deltree(tree1, BASEDIR);
3273 return ret;
3277 /* Starting the SMB2 specific oplock tests at 500 so we can keep the SMB1
3278 * tests in sync with an identically numbered SMB2 test */
3280 /* Test whether the server correctly returns an error when we send
3281 * a response to a levelII to none oplock notification. */
3282 static bool test_smb2_oplock_levelII500(struct torture_context *tctx,
3283 struct smb2_tree *tree1)
3285 const char *fname = BASEDIR "\\test_levelII500.dat";
3286 NTSTATUS status;
3287 bool ret = true;
3288 union smb_open io;
3289 struct smb2_handle h, h1;
3290 char c = 0;
3292 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3293 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3295 /* cleanup */
3296 smb2_util_unlink(tree1, fname);
3298 tree1->session->transport->oplock.handler = torture_oplock_handler;
3299 tree1->session->transport->oplock.private_data = tree1;
3302 base ntcreatex parms
3304 ZERO_STRUCT(io.smb2);
3305 io.generic.level = RAW_OPEN_SMB2;
3306 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3307 io.smb2.in.alloc_size = 0;
3308 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3309 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3310 io.smb2.in.create_options = 0;
3311 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3312 io.smb2.in.security_flags = 0;
3313 io.smb2.in.fname = fname;
3315 torture_comment(tctx, "LEVELII500: acknowledging a break from II to "
3316 "none should return an error\n");
3317 ZERO_STRUCT(break_info);
3319 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3320 SEC_RIGHTS_FILE_WRITE;
3321 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3322 NTCREATEX_SHARE_ACCESS_WRITE;
3323 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3324 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
3325 status = smb2_create(tree1, tctx, &(io.smb2));
3326 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3327 h1 = io.smb2.out.file.handle;
3328 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3330 ZERO_STRUCT(break_info);
3332 torture_comment(tctx, "write should trigger a break to none and when "
3333 "we reply, an oplock break failure\n");
3334 smb2_util_write(tree1, h1, &c, 0, 1);
3336 /* Wait several times to receive both the break notification, and the
3337 * NT_STATUS_INVALID_OPLOCK_PROTOCOL error in the break response */
3338 torture_wait_for_oplock_break(tctx);
3339 torture_wait_for_oplock_break(tctx);
3340 torture_wait_for_oplock_break(tctx);
3341 torture_wait_for_oplock_break(tctx);
3343 /* There appears to be a race condition in W2K8 and W2K8R2 where
3344 * sometimes the server will happily reply to our break response with
3345 * NT_STATUS_OK, and sometimes it will return the OPLOCK_PROTOCOL
3346 * error. As the MS-SMB2 doc states that a client should not reply to
3347 * a level2 to none break notification, I'm leaving the protocol error
3348 * as the expected behavior. */
3349 CHECK_VAL(break_info.count, 1);
3350 CHECK_VAL(break_info.level, 0);
3351 CHECK_VAL(break_info.failures, 1);
3352 torture_assert_ntstatus_equal(tctx, break_info.failure_status,
3353 NT_STATUS_INVALID_OPLOCK_PROTOCOL,
3354 "Incorrect status");
3356 smb2_util_close(tree1, h1);
3357 smb2_util_close(tree1, h);
3359 smb2_deltree(tree1, BASEDIR);
3360 return ret;
3363 struct torture_suite *torture_smb2_oplocks_init(void)
3365 struct torture_suite *suite =
3366 torture_suite_create(talloc_autofree_context(), "OPLOCK");
3368 torture_suite_add_2smb2_test(suite, "EXCLUSIVE1", test_smb2_oplock_exclusive1);
3369 torture_suite_add_2smb2_test(suite, "EXCLUSIVE2", test_smb2_oplock_exclusive2);
3370 torture_suite_add_2smb2_test(suite, "EXCLUSIVE3", test_smb2_oplock_exclusive3);
3371 torture_suite_add_2smb2_test(suite, "EXCLUSIVE4", test_smb2_oplock_exclusive4);
3372 torture_suite_add_2smb2_test(suite, "EXCLUSIVE5", test_smb2_oplock_exclusive5);
3373 torture_suite_add_2smb2_test(suite, "EXCLUSIVE6", test_smb2_oplock_exclusive6);
3374 torture_suite_add_2smb2_test(suite, "BATCH1", test_smb2_oplock_batch1);
3375 torture_suite_add_2smb2_test(suite, "BATCH2", test_smb2_oplock_batch2);
3376 torture_suite_add_2smb2_test(suite, "BATCH3", test_smb2_oplock_batch3);
3377 torture_suite_add_2smb2_test(suite, "BATCH4", test_smb2_oplock_batch4);
3378 torture_suite_add_2smb2_test(suite, "BATCH5", test_smb2_oplock_batch5);
3379 torture_suite_add_2smb2_test(suite, "BATCH6", test_smb2_oplock_batch6);
3380 torture_suite_add_2smb2_test(suite, "BATCH7", test_smb2_oplock_batch7);
3381 torture_suite_add_2smb2_test(suite, "BATCH8", test_smb2_oplock_batch8);
3382 torture_suite_add_2smb2_test(suite, "BATCH9", test_smb2_oplock_batch9);
3383 torture_suite_add_2smb2_test(suite, "BATCH10", test_smb2_oplock_batch10);
3384 torture_suite_add_2smb2_test(suite, "BATCH11", test_smb2_oplock_batch11);
3385 torture_suite_add_2smb2_test(suite, "BATCH12", test_smb2_oplock_batch12);
3386 torture_suite_add_2smb2_test(suite, "BATCH13", test_smb2_oplock_batch13);
3387 torture_suite_add_2smb2_test(suite, "BATCH14", test_smb2_oplock_batch14);
3388 torture_suite_add_2smb2_test(suite, "BATCH15", test_smb2_oplock_batch15);
3389 torture_suite_add_2smb2_test(suite, "BATCH16", test_smb2_oplock_batch16);
3390 torture_suite_add_1smb2_test(suite, "BATCH19", test_smb2_oplock_batch19);
3391 torture_suite_add_2smb2_test(suite, "BATCH20", test_smb2_oplock_batch20);
3392 torture_suite_add_1smb2_test(suite, "BATCH21", test_smb2_oplock_batch21);
3393 torture_suite_add_1smb2_test(suite, "BATCH22", test_smb2_oplock_batch22);
3394 torture_suite_add_2smb2_test(suite, "BATCH23", test_smb2_oplock_batch23);
3395 torture_suite_add_2smb2_test(suite, "BATCH24", test_smb2_oplock_batch24);
3396 torture_suite_add_1smb2_test(suite, "BATCH25", test_smb2_oplock_batch25);
3397 torture_suite_add_2smb2_test(suite, "STREAM1", test_raw_oplock_stream1);
3398 torture_suite_add_1smb2_test(suite, "DOC", test_smb2_oplock_doc);
3399 torture_suite_add_2smb2_test(suite, "BRL1", test_smb2_oplock_brl1);
3400 torture_suite_add_1smb2_test(suite, "BRL2", test_smb2_oplock_brl2);
3401 torture_suite_add_1smb2_test(suite, "BRL3", test_smb2_oplock_brl3);
3402 torture_suite_add_1smb2_test(suite, "LEVELII500", test_smb2_oplock_levelII500);
3404 suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
3406 return suite;
3410 stress testing of oplocks
3412 bool test_smb2_bench_oplock(struct torture_context *tctx,
3413 struct smb2_tree *tree)
3415 struct smb2_tree **trees;
3416 bool ret = true;
3417 NTSTATUS status;
3418 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3419 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
3420 int i, count=0;
3421 int timelimit = torture_setting_int(tctx, "timelimit", 10);
3422 union smb_open io;
3423 struct timeval tv;
3424 struct smb2_handle h;
3426 trees = talloc_array(mem_ctx, struct smb2_tree *, torture_nprocs);
3428 torture_comment(tctx, "Opening %d connections\n", torture_nprocs);
3429 for (i=0;i<torture_nprocs;i++) {
3430 if (!torture_smb2_connection(tctx, &trees[i])) {
3431 return false;
3433 talloc_steal(mem_ctx, trees[i]);
3434 trees[i]->session->transport->oplock.handler =
3435 torture_oplock_handler_close;
3436 trees[i]->session->transport->oplock.private_data = trees[i];
3439 status = torture_smb2_testdir(trees[0], BASEDIR, &h);
3440 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3442 ZERO_STRUCT(io.smb2);
3443 io.smb2.level = RAW_OPEN_SMB2;
3444 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3445 io.smb2.in.alloc_size = 0;
3446 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3447 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
3448 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3449 io.smb2.in.create_options = 0;
3450 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3451 io.smb2.in.security_flags = 0;
3452 io.smb2.in.fname = BASEDIR "\\test.dat";
3453 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3454 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3456 tv = timeval_current();
3459 we open the same file with SHARE_ACCESS_NONE from all the
3460 connections in a round robin fashion. Each open causes an
3461 oplock break on the previous connection, which is answered
3462 by the oplock_handler_close() to close the file.
3464 This measures how fast we can pass on oplocks, and stresses
3465 the oplock handling code
3467 torture_comment(tctx, "Running for %d seconds\n", timelimit);
3468 while (timeval_elapsed(&tv) < timelimit) {
3469 for (i=0;i<torture_nprocs;i++) {
3470 NTSTATUS status;
3472 status = smb2_create(trees[i], mem_ctx, &(io.smb2));
3473 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3474 count++;
3477 if (torture_setting_bool(tctx, "progress", true)) {
3478 torture_comment(tctx, "%.2f ops/second\r",
3479 count/timeval_elapsed(&tv));
3483 torture_comment(tctx, "%.2f ops/second\n", count/timeval_elapsed(&tv));
3484 smb2_util_close(trees[0], io.smb2.out.file.handle);
3485 smb2_util_unlink(trees[0], BASEDIR "\\test.dat");
3486 smb2_deltree(trees[0], BASEDIR);
3487 talloc_free(mem_ctx);
3488 return ret;
3491 static struct hold_oplock_info {
3492 const char *fname;
3493 bool close_on_break;
3494 uint32_t share_access;
3495 struct smb2_handle handle;
3496 } hold_info[] = {
3497 { BASEDIR "\\notshared_close", true,
3498 NTCREATEX_SHARE_ACCESS_NONE, },
3499 { BASEDIR "\\notshared_noclose", false,
3500 NTCREATEX_SHARE_ACCESS_NONE, },
3501 { BASEDIR "\\shared_close", true,
3502 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, },
3503 { BASEDIR "\\shared_noclose", false,
3504 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, },
3507 static bool torture_oplock_handler_hold(struct smb2_transport *transport,
3508 const struct smb2_handle *handle,
3509 uint8_t level, void *private_data)
3511 struct hold_oplock_info *info;
3512 int i;
3514 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
3515 if (smb2_util_handle_equal(hold_info[i].handle, *handle))
3516 break;
3519 if (i == ARRAY_SIZE(hold_info)) {
3520 printf("oplock break for unknown handle 0x%llx%llx\n",
3521 handle->data[0], handle->data[1]);
3522 return false;
3525 info = &hold_info[i];
3527 if (info->close_on_break) {
3528 printf("oplock break on %s - closing\n", info->fname);
3529 torture_oplock_handler_close(transport, handle,
3530 level, private_data);
3531 return true;
3534 printf("oplock break on %s - acking break\n", info->fname);
3535 printf("Acking to none in oplock handler\n");
3537 torture_oplock_handler_ack_to_none(transport, handle,
3538 level, private_data);
3539 return true;
3543 used for manual testing of oplocks - especially interaction with
3544 other filesystems (such as NFS and local access)
3546 bool test_smb2_hold_oplock(struct torture_context *tctx,
3547 struct smb2_tree *tree)
3549 struct torture_context *mem_ctx = talloc_new(tctx);
3550 struct tevent_context *ev =
3551 (struct tevent_context *)tree->session->transport->socket->event.ctx;
3552 int i;
3553 struct smb2_handle h;
3554 NTSTATUS status;
3556 torture_comment(tctx, "Setting up open files with oplocks in %s\n",
3557 BASEDIR);
3559 status = torture_smb2_testdir(tree, BASEDIR, &h);
3560 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3562 tree->session->transport->oplock.handler = torture_oplock_handler_hold;
3563 tree->session->transport->oplock.private_data = tree;
3565 /* setup the files */
3566 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
3567 union smb_open io;
3568 NTSTATUS status;
3569 char c = 1;
3571 ZERO_STRUCT(io.smb2);
3572 io.generic.level = RAW_OPEN_SMB2;
3573 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3574 io.smb2.in.alloc_size = 0;
3575 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3576 io.smb2.in.share_access = hold_info[i].share_access;
3577 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3578 io.smb2.in.create_options = 0;
3579 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3580 io.smb2.in.security_flags = 0;
3581 io.smb2.in.fname = hold_info[i].fname;
3582 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3583 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3585 torture_comment(tctx, "opening %s\n", hold_info[i].fname);
3587 status = smb2_create(tree, mem_ctx, &(io.smb2));
3588 if (!NT_STATUS_IS_OK(status)) {
3589 torture_comment(tctx, "Failed to open %s - %s\n",
3590 hold_info[i].fname, nt_errstr(status));
3591 return false;
3594 if (io.smb2.out.oplock_level != SMB2_OPLOCK_LEVEL_BATCH) {
3595 torture_comment(tctx, "Oplock not granted for %s - "
3596 "expected %d but got %d\n",
3597 hold_info[i].fname,
3598 SMB2_OPLOCK_LEVEL_BATCH,
3599 io.smb2.out.oplock_level);
3600 return false;
3602 hold_info[i].handle = io.smb2.out.file.handle;
3604 /* make the file non-zero size */
3605 status = smb2_util_write(tree, hold_info[i].handle, &c, 0, 1);
3606 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3607 torture_comment(tctx, "Failed to write to file\n");
3608 return false;
3612 torture_comment(tctx, "Waiting for oplock events\n");
3613 event_loop_wait(ev);
3614 smb2_deltree(tree, BASEDIR);
3615 talloc_free(mem_ctx);
3616 return true;