s4:torture/smb2: remove samba specific stuff from smb2.oplock
[Samba/gebeck_regimport.git] / source4 / torture / smb2 / oplock.c
blob4cf7c7d72ffe32b3738840a59650ac10b409659c
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 break_info.handle = *handle;
172 break_info.level = level;
173 break_info.count++;
175 printf("Break from level II to none in oplock handler\n");
177 return true;
180 /* A handler function for oplock break notifications. This should be used when
181 * test expects two break notifications, first to level II, then to none. */
182 static bool torture_oplock_handler_two_notifications(
183 struct smb2_transport *transport,
184 const struct smb2_handle *handle,
185 uint8_t level,
186 void *private_data)
188 struct smb2_tree *tree = private_data;
189 const char *name;
190 struct smb2_request *req;
191 ZERO_STRUCT(break_info.br);
193 break_info.handle = *handle;
194 break_info.level = level;
195 break_info.count++;
197 switch (level) {
198 case SMB2_OPLOCK_LEVEL_II:
199 name = "level II";
200 break;
201 case SMB2_OPLOCK_LEVEL_NONE:
202 name = "none";
203 break;
204 default:
205 name = "unknown";
206 break_info.failures++;
208 printf("Breaking to %s [0x%02X] in oplock handler\n", name, level);
210 if (level == SMB2_OPLOCK_LEVEL_NONE)
211 return true;
213 break_info.br.in.file.handle = *handle;
214 break_info.br.in.oplock_level = level;
215 break_info.br.in.reserved = 0;
216 break_info.br.in.reserved2 = 0;
218 req = smb2_break_send(tree, &break_info.br);
219 req->async.fn = torture_oplock_break_callback;
220 req->async.private_data = NULL;
221 return true;
223 static void torture_oplock_handler_close_recv(struct smb2_request *req)
225 if (!smb2_request_receive(req)) {
226 printf("close failed in oplock_handler_close\n");
227 break_info.failures++;
232 a handler function for oplock break requests - close the file
234 static bool torture_oplock_handler_close(struct smb2_transport *transport,
235 const struct smb2_handle *handle,
236 uint8_t level,
237 void *private_data)
239 struct smb2_close io;
240 struct smb2_tree *tree = private_data;
241 struct smb2_request *req;
243 break_info.handle = *handle;
244 break_info.level = level;
245 break_info.count++;
247 ZERO_STRUCT(io);
248 io.in.file.handle = *handle;
249 io.in.flags = RAW_CLOSE_SMB2;
250 req = smb2_close_send(tree, &io);
251 if (req == NULL) {
252 printf("failed to send close in oplock_handler_close\n");
253 return false;
256 req->async.fn = torture_oplock_handler_close_recv;
257 req->async.private_data = NULL;
259 return true;
263 a handler function for oplock break requests. Let it timeout
265 static bool torture_oplock_handler_timeout(struct smb2_transport *transport,
266 const struct smb2_handle *handle,
267 uint8_t level,
268 void *private_data)
270 break_info.handle = *handle;
271 break_info.level = level;
272 break_info.count++;
274 printf("Let oplock break timeout\n");
275 return true;
278 static bool open_smb2_connection_no_level2_oplocks(struct torture_context *tctx,
279 struct smb2_tree **tree)
281 NTSTATUS status;
282 const char *host = torture_setting_string(tctx, "host", NULL);
283 const char *share = torture_setting_string(tctx, "share", NULL);
284 struct cli_credentials *credentials = cmdline_credentials;
285 struct smbcli_options options;
287 lpcfg_smbcli_options(tctx->lp_ctx, &options);
288 options.use_level2_oplocks = false;
290 status = smb2_connect(tctx, host,
291 lpcfg_smb_ports(tctx->lp_ctx), share,
292 lpcfg_resolve_context(tctx->lp_ctx),
293 credentials, tree, tctx->ev, &options,
294 lpcfg_socket_options(tctx->lp_ctx),
295 lpcfg_gensec_settings(tctx, tctx->lp_ctx));
296 if (!NT_STATUS_IS_OK(status)) {
297 torture_comment(tctx, "Failed to connect to SMB2 share "
298 "\\\\%s\\%s - %s\n", host, share,
299 nt_errstr(status));
300 return false;
302 return true;
306 Timer handler function notifies the registering function that time is up
308 static void timeout_cb(struct tevent_context *ev,
309 struct tevent_timer *te,
310 struct timeval current_time,
311 void *private_data)
313 bool *timesup = (bool *)private_data;
314 *timesup = true;
315 return;
319 Wait a short period of time to receive a single oplock break request
321 static void torture_wait_for_oplock_break(struct torture_context *tctx)
323 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
324 struct tevent_timer *te = NULL;
325 struct timeval ne;
326 bool timesup = false;
327 int old_count = break_info.count;
329 /* Wait .1 seconds for an oplock break */
330 ne = tevent_timeval_current_ofs(0, 100000);
332 if ((te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup))
333 == NULL)
335 torture_comment(tctx, "Failed to wait for an oplock break. "
336 "test results may not be accurate.");
337 goto done;
340 while (!timesup && break_info.count < old_count + 1) {
341 if (tevent_loop_once(tctx->ev) != 0) {
342 torture_comment(tctx, "Failed to wait for an oplock "
343 "break. test results may not be "
344 "accurate.");
345 goto done;
349 done:
350 /* We don't know if the timed event fired and was freed, we received
351 * our oplock break, or some other event triggered the loop. Thus,
352 * we create a tmp_ctx to be able to safely free/remove the timed
353 * event in all 3 cases. */
354 talloc_free(tmp_ctx);
356 return;
359 static bool test_smb2_oplock_exclusive1(struct torture_context *tctx,
360 struct smb2_tree *tree1,
361 struct smb2_tree *tree2)
363 const char *fname = BASEDIR "\\test_exclusive1.dat";
364 NTSTATUS status;
365 bool ret = true;
366 union smb_open io;
367 struct smb2_handle h1;
368 struct smb2_handle h;
370 status = torture_smb2_testdir(tree1, BASEDIR, &h);
371 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
373 /* cleanup */
374 smb2_util_unlink(tree1, fname);
376 tree1->session->transport->oplock.handler = torture_oplock_handler;
377 tree1->session->transport->oplock.private_data = tree1;
380 base ntcreatex parms
382 ZERO_STRUCT(io.smb2);
383 io.generic.level = RAW_OPEN_SMB2;
384 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
385 io.smb2.in.alloc_size = 0;
386 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
387 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
388 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
389 io.smb2.in.create_options = 0;
390 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
391 io.smb2.in.security_flags = 0;
392 io.smb2.in.fname = fname;
394 torture_comment(tctx, "EXCLUSIVE1: open a file with an exclusive "
395 "oplock (share mode: none)\n");
396 ZERO_STRUCT(break_info);
397 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
399 status = smb2_create(tree1, tctx, &(io.smb2));
400 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
401 h1 = io.smb2.out.file.handle;
402 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
404 torture_comment(tctx, "a 2nd open should not cause a break\n");
405 status = smb2_create(tree2, tctx, &(io.smb2));
406 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
407 "Incorrect status");
408 torture_wait_for_oplock_break(tctx);
409 CHECK_VAL(break_info.count, 0);
410 CHECK_VAL(break_info.failures, 0);
412 torture_comment(tctx, "unlink it - should also be no break\n");
413 status = smb2_util_unlink(tree2, fname);
414 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
415 "Incorrect status");
416 torture_wait_for_oplock_break(tctx);
417 CHECK_VAL(break_info.count, 0);
418 CHECK_VAL(break_info.failures, 0);
420 smb2_util_close(tree1, h1);
421 smb2_util_close(tree1, h);
423 smb2_deltree(tree1, BASEDIR);
424 return ret;
427 static bool test_smb2_oplock_exclusive2(struct torture_context *tctx,
428 struct smb2_tree *tree1,
429 struct smb2_tree *tree2)
431 const char *fname = BASEDIR "\\test_exclusive2.dat";
432 NTSTATUS status;
433 bool ret = true;
434 union smb_open io;
435 struct smb2_handle h, h1, h2;
437 status = torture_smb2_testdir(tree1, BASEDIR, &h);
438 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
440 /* cleanup */
441 smb2_util_unlink(tree1, fname);
443 tree1->session->transport->oplock.handler = torture_oplock_handler;
444 tree1->session->transport->oplock.private_data = tree1;
447 base ntcreatex parms
449 ZERO_STRUCT(io.smb2);
450 io.generic.level = RAW_OPEN_SMB2;
451 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
452 io.smb2.in.alloc_size = 0;
453 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
454 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
455 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
456 io.smb2.in.create_options = 0;
457 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
458 io.smb2.in.security_flags = 0;
459 io.smb2.in.fname = fname;
461 torture_comment(tctx, "EXCLUSIVE2: open a file with an exclusive "
462 "oplock (share mode: all)\n");
463 ZERO_STRUCT(break_info);
464 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
465 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
466 NTCREATEX_SHARE_ACCESS_WRITE|
467 NTCREATEX_SHARE_ACCESS_DELETE;
468 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
470 status = smb2_create(tree1, tctx, &(io.smb2));
471 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
472 h1 = io.smb2.out.file.handle;
473 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
475 torture_comment(tctx, "a 2nd open should cause a break to level 2\n");
476 status = smb2_create(tree2, tctx, &(io.smb2));
477 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
478 h2 = io.smb2.out.file.handle;
479 torture_wait_for_oplock_break(tctx);
480 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
481 CHECK_VAL(break_info.count, 1);
482 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
483 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
484 CHECK_VAL(break_info.failures, 0);
485 ZERO_STRUCT(break_info);
487 /* now we have 2 level II oplocks... */
488 torture_comment(tctx, "try to unlink it - should cause a break\n");
489 status = smb2_util_unlink(tree2, fname);
490 torture_assert_ntstatus_ok(tctx, status, "Error unlinking the file");
491 torture_wait_for_oplock_break(tctx);
492 CHECK_VAL(break_info.count, 0);
493 CHECK_VAL(break_info.failures, 0);
495 torture_comment(tctx, "close both handles\n");
496 smb2_util_close(tree1, h1);
497 smb2_util_close(tree1, h2);
498 smb2_util_close(tree1, h);
500 smb2_deltree(tree1, BASEDIR);
501 return ret;
504 static bool test_smb2_oplock_exclusive3(struct torture_context *tctx,
505 struct smb2_tree *tree1,
506 struct smb2_tree *tree2)
508 const char *fname = BASEDIR "\\test_exclusive3.dat";
509 NTSTATUS status;
510 bool ret = true;
511 union smb_open io;
512 union smb_setfileinfo sfi;
513 struct smb2_handle h, h1;
515 status = torture_smb2_testdir(tree1, BASEDIR, &h);
516 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
518 /* cleanup */
519 smb2_util_unlink(tree1, fname);
521 tree1->session->transport->oplock.handler = torture_oplock_handler;
522 tree1->session->transport->oplock.private_data = tree1;
525 base ntcreatex parms
527 ZERO_STRUCT(io.smb2);
528 io.generic.level = RAW_OPEN_SMB2;
529 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
530 io.smb2.in.alloc_size = 0;
531 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
532 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
533 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
534 io.smb2.in.create_options = 0;
535 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
536 io.smb2.in.security_flags = 0;
537 io.smb2.in.fname = fname;
539 torture_comment(tctx, "EXCLUSIVE3: open a file with an exclusive "
540 "oplock (share mode: none)\n");
542 ZERO_STRUCT(break_info);
543 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
544 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
546 status = smb2_create(tree1, tctx, &(io.smb2));
547 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
548 h1 = io.smb2.out.file.handle;
549 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
551 torture_comment(tctx, "setpathinfo EOF should trigger a break to "
552 "none\n");
553 ZERO_STRUCT(sfi);
554 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
555 sfi.generic.in.file.path = fname;
556 sfi.end_of_file_info.in.size = 100;
558 status = smb2_composite_setpathinfo(tree2, &sfi);
560 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
561 "Incorrect status");
562 torture_wait_for_oplock_break(tctx);
563 CHECK_VAL(break_info.count, 0);
564 CHECK_VAL(break_info.failures, 0);
565 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
567 smb2_util_close(tree1, h1);
568 smb2_util_close(tree1, h);
570 smb2_deltree(tree1, BASEDIR);
571 return ret;
574 static bool test_smb2_oplock_exclusive4(struct torture_context *tctx,
575 struct smb2_tree *tree1,
576 struct smb2_tree *tree2)
578 const char *fname = BASEDIR "\\test_exclusive4.dat";
579 NTSTATUS status;
580 bool ret = true;
581 union smb_open io;
582 struct smb2_handle h, h1, h2;
584 status = torture_smb2_testdir(tree1, BASEDIR, &h);
585 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
587 /* cleanup */
588 smb2_util_unlink(tree1, fname);
590 tree1->session->transport->oplock.handler = torture_oplock_handler;
591 tree1->session->transport->oplock.private_data = tree1;
594 base ntcreatex parms
596 ZERO_STRUCT(io.smb2);
597 io.generic.level = RAW_OPEN_SMB2;
598 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
599 io.smb2.in.alloc_size = 0;
600 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
601 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
602 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
603 io.smb2.in.create_options = 0;
604 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
605 io.smb2.in.security_flags = 0;
606 io.smb2.in.fname = fname;
608 torture_comment(tctx, "EXCLUSIVE4: open with exclusive oplock\n");
609 ZERO_STRUCT(break_info);
611 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
612 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
613 status = smb2_create(tree1, tctx, &(io.smb2));
614 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
615 h1 = io.smb2.out.file.handle;
616 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
618 ZERO_STRUCT(break_info);
619 torture_comment(tctx, "second open with attributes only shouldn't "
620 "cause oplock break\n");
622 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
623 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
624 SEC_FILE_WRITE_ATTRIBUTE |
625 SEC_STD_SYNCHRONIZE;
626 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
627 status = smb2_create(tree2, tctx, &(io.smb2));
628 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
629 h2 = io.smb2.out.file.handle;
630 CHECK_VAL(io.smb2.out.oplock_level, NO_OPLOCK_RETURN);
631 torture_wait_for_oplock_break(tctx);
632 CHECK_VAL(break_info.count, 0);
633 CHECK_VAL(break_info.failures, 0);
635 smb2_util_close(tree1, h1);
636 smb2_util_close(tree2, h2);
637 smb2_util_close(tree1, h);
639 smb2_deltree(tree1, BASEDIR);
640 return ret;
643 static bool test_smb2_oplock_exclusive5(struct torture_context *tctx,
644 struct smb2_tree *tree1,
645 struct smb2_tree *tree2)
647 const char *fname = BASEDIR "\\test_exclusive5.dat";
648 NTSTATUS status;
649 bool ret = true;
650 union smb_open io;
651 struct smb2_handle h, h1, h2;
653 status = torture_smb2_testdir(tree1, BASEDIR, &h);
654 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
656 /* cleanup */
657 smb2_util_unlink(tree1, fname);
659 tree1->session->transport->oplock.handler = torture_oplock_handler;
660 tree1->session->transport->oplock.private_data = tree1;
662 tree2->session->transport->oplock.handler = torture_oplock_handler;
663 tree2->session->transport->oplock.private_data = tree2;
666 base ntcreatex parms
668 ZERO_STRUCT(io.smb2);
669 io.generic.level = RAW_OPEN_SMB2;
670 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
671 io.smb2.in.alloc_size = 0;
672 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
673 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
674 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
675 io.smb2.in.create_options = 0;
676 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
677 io.smb2.in.security_flags = 0;
678 io.smb2.in.fname = fname;
680 torture_comment(tctx, "EXCLUSIVE5: open with exclusive oplock\n");
681 ZERO_STRUCT(break_info);
683 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
684 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
685 NTCREATEX_SHARE_ACCESS_WRITE|
686 NTCREATEX_SHARE_ACCESS_DELETE;
687 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
688 status = smb2_create(tree1, tctx, &(io.smb2));
689 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
690 h1 = io.smb2.out.file.handle;
691 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
693 ZERO_STRUCT(break_info);
695 torture_comment(tctx, "second open with attributes only and "
696 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
697 "oplock break\n");
699 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
700 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
701 SEC_FILE_WRITE_ATTRIBUTE |
702 SEC_STD_SYNCHRONIZE;
703 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
704 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
705 status = smb2_create(tree2, tctx, &(io.smb2));
706 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
707 h2 = io.smb2.out.file.handle;
708 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
709 torture_wait_for_oplock_break(tctx);
710 CHECK_VAL(break_info.count, 1);
711 CHECK_VAL(break_info.failures, 0);
713 smb2_util_close(tree1, h1);
714 smb2_util_close(tree2, h2);
715 smb2_util_close(tree1, h);
717 smb2_deltree(tree1, BASEDIR);
718 return ret;
721 static bool test_smb2_oplock_exclusive6(struct torture_context *tctx,
722 struct smb2_tree *tree1,
723 struct smb2_tree *tree2)
725 const char *fname1 = BASEDIR "\\test_exclusive6_1.dat";
726 const char *fname2 = BASEDIR "\\test_exclusive6_2.dat";
727 NTSTATUS status;
728 bool ret = true;
729 union smb_open io;
730 union smb_setfileinfo sinfo;
731 struct smb2_close closeio;
732 struct smb2_handle h, h1;
734 status = torture_smb2_testdir(tree1, BASEDIR, &h);
735 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
737 /* cleanup */
738 smb2_util_unlink(tree1, fname1);
739 smb2_util_unlink(tree2, fname2);
741 tree1->session->transport->oplock.handler = torture_oplock_handler;
742 tree1->session->transport->oplock.private_data = tree1;
745 base ntcreatex parms
747 ZERO_STRUCT(io.smb2);
748 io.generic.level = RAW_OPEN_SMB2;
749 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
750 io.smb2.in.alloc_size = 0;
751 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
752 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
753 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
754 io.smb2.in.create_options = 0;
755 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
756 io.smb2.in.security_flags = 0;
757 io.smb2.in.fname = fname1;
759 torture_comment(tctx, "EXCLUSIVE6: open a file with an exclusive "
760 "oplock (share mode: none)\n");
761 ZERO_STRUCT(break_info);
762 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
763 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
765 status = smb2_create(tree1, tctx, &(io.smb2));
766 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
767 h1 = io.smb2.out.file.handle;
768 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
770 torture_comment(tctx, "rename with the parent directory handle open "
771 "for DELETE should not generate a break but get "
772 "a sharing violation\n");
773 ZERO_STRUCT(sinfo);
774 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
775 sinfo.rename_information.in.file.handle = h1;
776 sinfo.rename_information.in.overwrite = true;
777 sinfo.rename_information.in.new_name = fname2;
778 status = smb2_setinfo_file(tree1, &sinfo);
780 torture_comment(tctx, "trying rename while parent handle open for delete.\n");
781 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
782 "Incorrect status");
783 torture_wait_for_oplock_break(tctx);
784 CHECK_VAL(break_info.count, 0);
785 CHECK_VAL(break_info.failures, 0);
787 /* Close the parent directory handle. */
788 ZERO_STRUCT(closeio);
789 closeio.in.file.handle = h;
790 status = smb2_close(tree1, &closeio);
791 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
792 "Incorrect status");
794 /* Re-open without DELETE access. */
795 ZERO_STRUCT(io);
796 io.smb2.in.oplock_level = 0;
797 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL & (~SEC_STD_DELETE);
798 io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
799 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
800 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
801 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
802 io.smb2.in.fname = BASEDIR;
804 status = smb2_create(tree1, tctx, &(io.smb2));
805 torture_assert_ntstatus_ok(tctx, status, "Error opening the base directory");
807 torture_comment(tctx, "rename with the parent directory handle open "
808 "without DELETE should succeed without a break\n");
809 ZERO_STRUCT(sinfo);
810 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
811 sinfo.rename_information.in.file.handle = h1;
812 sinfo.rename_information.in.overwrite = true;
813 sinfo.rename_information.in.new_name = fname2;
814 status = smb2_setinfo_file(tree1, &sinfo);
816 torture_comment(tctx, "trying rename while parent handle open without delete\n");
817 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
818 "Incorrect status");
819 torture_wait_for_oplock_break(tctx);
820 CHECK_VAL(break_info.count, 0);
821 CHECK_VAL(break_info.failures, 0);
823 smb2_util_close(tree1, h1);
824 smb2_util_close(tree1, h);
826 smb2_deltree(tree1, BASEDIR);
827 return ret;
830 static bool test_smb2_oplock_batch1(struct torture_context *tctx,
831 struct smb2_tree *tree1,
832 struct smb2_tree *tree2)
834 const char *fname = BASEDIR "\\test_batch1.dat";
835 NTSTATUS status;
836 bool ret = true;
837 union smb_open io;
838 struct smb2_handle h, h1;
839 char c = 0;
841 status = torture_smb2_testdir(tree1, BASEDIR, &h);
842 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
844 /* cleanup */
845 smb2_util_unlink(tree1, fname);
847 tree1->session->transport->oplock.handler = torture_oplock_handler;
848 tree1->session->transport->oplock.private_data = tree1;
851 base ntcreatex parms
853 ZERO_STRUCT(io.smb2);
854 io.generic.level = RAW_OPEN_SMB2;
855 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
856 io.smb2.in.alloc_size = 0;
857 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
858 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
859 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
860 io.smb2.in.create_options = 0;
861 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
862 io.smb2.in.security_flags = 0;
863 io.smb2.in.fname = fname;
866 with a batch oplock we get a break
868 torture_comment(tctx, "BATCH1: open with batch oplock\n");
869 ZERO_STRUCT(break_info);
870 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
871 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
872 status = smb2_create(tree1, tctx, &(io.smb2));
873 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
874 h1 = io.smb2.out.file.handle;
875 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
877 torture_comment(tctx, "unlink should generate a break\n");
878 status = smb2_util_unlink(tree2, fname);
879 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
880 "Incorrect status");
882 torture_wait_for_oplock_break(tctx);
883 CHECK_VAL(break_info.count, 1);
884 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
885 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
886 CHECK_VAL(break_info.failures, 0);
888 torture_comment(tctx, "2nd unlink should not generate a break\n");
889 ZERO_STRUCT(break_info);
890 status = smb2_util_unlink(tree2, fname);
891 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
892 "Incorrect status");
894 torture_wait_for_oplock_break(tctx);
895 CHECK_VAL(break_info.count, 0);
897 torture_comment(tctx, "writing should generate a self break to none\n");
898 tree1->session->transport->oplock.handler =
899 torture_oplock_handler_level2_to_none;
900 smb2_util_write(tree1, h1, &c, 0, 1);
902 torture_wait_for_oplock_break(tctx);
904 CHECK_VAL(break_info.count, 1);
905 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
906 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
907 CHECK_VAL(break_info.failures, 0);
909 smb2_util_close(tree1, h1);
910 smb2_util_close(tree1, h);
912 smb2_deltree(tree1, BASEDIR);
913 return ret;
916 static bool test_smb2_oplock_batch2(struct torture_context *tctx,
917 struct smb2_tree *tree1,
918 struct smb2_tree *tree2)
920 const char *fname = BASEDIR "\\test_batch2.dat";
921 NTSTATUS status;
922 bool ret = true;
923 union smb_open io;
924 char c = 0;
925 struct smb2_handle h, h1;
927 status = torture_smb2_testdir(tree1, BASEDIR, &h);
928 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
930 /* cleanup */
931 smb2_util_unlink(tree1, fname);
933 tree1->session->transport->oplock.handler = torture_oplock_handler;
934 tree1->session->transport->oplock.private_data = tree1;
937 base ntcreatex parms
939 ZERO_STRUCT(io.smb2);
940 io.generic.level = RAW_OPEN_SMB2;
941 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
942 io.smb2.in.alloc_size = 0;
943 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
944 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
945 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
946 io.smb2.in.create_options = 0;
947 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
948 io.smb2.in.security_flags = 0;
949 io.smb2.in.fname = fname;
951 torture_comment(tctx, "BATCH2: open with batch oplock\n");
952 ZERO_STRUCT(break_info);
953 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
954 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
955 status = smb2_create(tree1, tctx, &(io.smb2));
956 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
957 h1 = io.smb2.out.file.handle;
958 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
960 torture_comment(tctx, "unlink should generate a break, which we ack "
961 "as break to none\n");
962 tree1->session->transport->oplock.handler =
963 torture_oplock_handler_ack_to_none;
964 tree1->session->transport->oplock.private_data = tree1;
965 status = smb2_util_unlink(tree2, fname);
966 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
967 "Incorrect status");
969 torture_wait_for_oplock_break(tctx);
970 CHECK_VAL(break_info.count, 1);
971 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
972 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
973 CHECK_VAL(break_info.failures, 0);
975 torture_comment(tctx, "2nd unlink should not generate a break\n");
976 ZERO_STRUCT(break_info);
977 status = smb2_util_unlink(tree2, fname);
978 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
979 "Incorrect status");
981 torture_wait_for_oplock_break(tctx);
982 CHECK_VAL(break_info.count, 0);
984 torture_comment(tctx, "writing should not generate a break\n");
985 smb2_util_write(tree1, h1, &c, 0, 1);
987 torture_wait_for_oplock_break(tctx);
988 CHECK_VAL(break_info.count, 0);
990 smb2_util_close(tree1, h1);
991 smb2_util_close(tree1, h);
993 smb2_deltree(tree1, BASEDIR);
994 return ret;
997 static bool test_smb2_oplock_batch3(struct torture_context *tctx,
998 struct smb2_tree *tree1,
999 struct smb2_tree *tree2)
1001 const char *fname = BASEDIR "\\test_batch3.dat";
1002 NTSTATUS status;
1003 bool ret = true;
1004 union smb_open io;
1005 struct smb2_handle h, h1;
1007 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1008 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1010 /* cleanup */
1011 smb2_util_unlink(tree1, fname);
1012 tree1->session->transport->oplock.handler = torture_oplock_handler;
1013 tree1->session->transport->oplock.private_data = tree1;
1016 base ntcreatex parms
1018 ZERO_STRUCT(io.smb2);
1019 io.generic.level = RAW_OPEN_SMB2;
1020 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1021 io.smb2.in.alloc_size = 0;
1022 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1023 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1024 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1025 io.smb2.in.create_options = 0;
1026 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1027 io.smb2.in.security_flags = 0;
1028 io.smb2.in.fname = fname;
1030 torture_comment(tctx, "BATCH3: if we close on break then the unlink "
1031 "can succeed\n");
1032 ZERO_STRUCT(break_info);
1033 tree1->session->transport->oplock.handler =
1034 torture_oplock_handler_close;
1035 tree1->session->transport->oplock.private_data = tree1;
1037 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1038 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1039 status = smb2_create(tree1, tctx, &(io.smb2));
1040 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1041 h1 = io.smb2.out.file.handle;
1042 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1044 ZERO_STRUCT(break_info);
1045 status = smb2_util_unlink(tree2, fname);
1046 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1048 torture_wait_for_oplock_break(tctx);
1049 CHECK_VAL(break_info.count, 1);
1050 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1051 CHECK_VAL(break_info.level, 1);
1052 CHECK_VAL(break_info.failures, 0);
1054 smb2_util_close(tree1, h1);
1055 smb2_util_close(tree1, h);
1057 smb2_deltree(tree1, BASEDIR);
1058 return ret;
1061 static bool test_smb2_oplock_batch4(struct torture_context *tctx,
1062 struct smb2_tree *tree1,
1063 struct smb2_tree *tree2)
1065 const char *fname = BASEDIR "\\test_batch4.dat";
1066 NTSTATUS status;
1067 bool ret = true;
1068 union smb_open io;
1069 struct smb2_read r;
1070 struct smb2_handle h, h1;
1072 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1073 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1075 /* cleanup */
1076 smb2_util_unlink(tree1, fname);
1078 tree1->session->transport->oplock.handler = torture_oplock_handler;
1079 tree1->session->transport->oplock.private_data = tree1;
1082 base ntcreatex parms
1084 ZERO_STRUCT(io.smb2);
1085 io.generic.level = RAW_OPEN_SMB2;
1086 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1087 io.smb2.in.alloc_size = 0;
1088 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1089 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1090 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1091 io.smb2.in.create_options = 0;
1092 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1093 io.smb2.in.security_flags = 0;
1094 io.smb2.in.fname = fname;
1096 torture_comment(tctx, "BATCH4: a self read should not cause a break\n");
1097 ZERO_STRUCT(break_info);
1099 tree1->session->transport->oplock.handler = torture_oplock_handler;
1100 tree1->session->transport->oplock.private_data = tree1;
1102 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1103 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1104 status = smb2_create(tree1, tctx, &(io.smb2));
1105 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1106 h1 = io.smb2.out.file.handle;
1107 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1109 ZERO_STRUCT(r);
1110 r.in.file.handle = h1;
1111 r.in.offset = 0;
1113 status = smb2_read(tree1, tree1, &r);
1114 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1115 torture_wait_for_oplock_break(tctx);
1116 CHECK_VAL(break_info.count, 0);
1117 CHECK_VAL(break_info.failures, 0);
1119 smb2_util_close(tree1, h1);
1120 smb2_util_close(tree1, h);
1122 smb2_deltree(tree1, BASEDIR);
1123 return ret;
1126 static bool test_smb2_oplock_batch5(struct torture_context *tctx,
1127 struct smb2_tree *tree1,
1128 struct smb2_tree *tree2)
1130 const char *fname = BASEDIR "\\test_batch5.dat";
1131 NTSTATUS status;
1132 bool ret = true;
1133 union smb_open io;
1134 struct smb2_handle h, h1;
1136 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1137 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1139 /* cleanup */
1140 smb2_util_unlink(tree1, fname);
1142 tree1->session->transport->oplock.handler = torture_oplock_handler;
1143 tree1->session->transport->oplock.private_data = tree1;
1146 base ntcreatex parms
1148 ZERO_STRUCT(io.smb2);
1149 io.generic.level = RAW_OPEN_SMB2;
1150 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1151 io.smb2.in.alloc_size = 0;
1152 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1153 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1154 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1155 io.smb2.in.create_options = 0;
1156 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1157 io.smb2.in.security_flags = 0;
1158 io.smb2.in.fname = fname;
1160 torture_comment(tctx, "BATCH5: a 2nd open should give a break\n");
1161 ZERO_STRUCT(break_info);
1163 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1164 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1165 status = smb2_create(tree1, tctx, &(io.smb2));
1166 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1167 h1 = io.smb2.out.file.handle;
1168 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1170 ZERO_STRUCT(break_info);
1172 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1173 status = smb2_create(tree2, tctx, &(io.smb2));
1174 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1175 "Incorrect status");
1177 torture_wait_for_oplock_break(tctx);
1178 CHECK_VAL(break_info.count, 1);
1179 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1180 CHECK_VAL(break_info.level, 1);
1181 CHECK_VAL(break_info.failures, 0);
1183 smb2_util_close(tree1, h1);
1184 smb2_util_close(tree1, h);
1186 smb2_deltree(tree1, BASEDIR);
1187 return ret;
1190 static bool test_smb2_oplock_batch6(struct torture_context *tctx,
1191 struct smb2_tree *tree1,
1192 struct smb2_tree *tree2)
1194 const char *fname = BASEDIR "\\test_batch6.dat";
1195 NTSTATUS status;
1196 bool ret = true;
1197 union smb_open io;
1198 struct smb2_handle h, h1, h2;
1199 char c = 0;
1201 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1202 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1204 /* cleanup */
1205 smb2_util_unlink(tree1, fname);
1207 tree1->session->transport->oplock.handler = torture_oplock_handler;
1208 tree1->session->transport->oplock.private_data = tree1;
1211 base ntcreatex parms
1213 ZERO_STRUCT(io.smb2);
1214 io.generic.level = RAW_OPEN_SMB2;
1215 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1216 io.smb2.in.alloc_size = 0;
1217 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1218 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1219 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1220 io.smb2.in.create_options = 0;
1221 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1222 io.smb2.in.security_flags = 0;
1223 io.smb2.in.fname = fname;
1225 torture_comment(tctx, "BATCH6: a 2nd open should give a break to "
1226 "level II if the first open allowed shared read\n");
1227 ZERO_STRUCT(break_info);
1228 tree2->session->transport->oplock.handler = torture_oplock_handler;
1229 tree2->session->transport->oplock.private_data = tree2;
1231 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
1232 SEC_RIGHTS_FILE_WRITE;
1233 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1234 NTCREATEX_SHARE_ACCESS_WRITE;
1235 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1236 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1237 status = smb2_create(tree1, tctx, &(io.smb2));
1238 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1239 h1 = io.smb2.out.file.handle;
1240 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1242 ZERO_STRUCT(break_info);
1244 status = smb2_create(tree2, tctx, &(io.smb2));
1245 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1246 h2 = io.smb2.out.file.handle;
1247 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1249 torture_wait_for_oplock_break(tctx);
1250 CHECK_VAL(break_info.count, 1);
1251 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1252 CHECK_VAL(break_info.level, 1);
1253 CHECK_VAL(break_info.failures, 0);
1254 ZERO_STRUCT(break_info);
1256 torture_comment(tctx, "write should trigger a break to none on both\n");
1257 tree1->session->transport->oplock.handler =
1258 torture_oplock_handler_level2_to_none;
1259 tree2->session->transport->oplock.handler =
1260 torture_oplock_handler_level2_to_none;
1261 smb2_util_write(tree1, h1, &c, 0, 1);
1263 /* We expect two breaks */
1264 torture_wait_for_oplock_break(tctx);
1265 torture_wait_for_oplock_break(tctx);
1267 CHECK_VAL(break_info.count, 2);
1268 CHECK_VAL(break_info.level, 0);
1269 CHECK_VAL(break_info.failures, 0);
1271 smb2_util_close(tree1, h1);
1272 smb2_util_close(tree2, h2);
1273 smb2_util_close(tree1, h);
1275 smb2_deltree(tree1, BASEDIR);
1276 return ret;
1279 static bool test_smb2_oplock_batch7(struct torture_context *tctx,
1280 struct smb2_tree *tree1,
1281 struct smb2_tree *tree2)
1283 const char *fname = BASEDIR "\\test_batch7.dat";
1284 NTSTATUS status;
1285 bool ret = true;
1286 union smb_open io;
1287 struct smb2_handle h, h1, h2;
1289 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1290 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1292 /* cleanup */
1293 smb2_util_unlink(tree1, fname);
1295 tree1->session->transport->oplock.handler = torture_oplock_handler;
1296 tree1->session->transport->oplock.private_data = tree1;
1299 base ntcreatex parms
1301 ZERO_STRUCT(io.smb2);
1302 io.generic.level = RAW_OPEN_SMB2;
1303 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1304 io.smb2.in.alloc_size = 0;
1305 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1306 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1307 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1308 io.smb2.in.create_options = 0;
1309 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1310 io.smb2.in.security_flags = 0;
1311 io.smb2.in.fname = fname;
1313 torture_comment(tctx, "BATCH7: a 2nd open should get an oplock when "
1314 "we close instead of ack\n");
1315 ZERO_STRUCT(break_info);
1316 tree1->session->transport->oplock.handler =
1317 torture_oplock_handler_close;
1318 tree1->session->transport->oplock.private_data = tree1;
1320 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1321 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1322 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1323 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1324 status = smb2_create(tree1, tctx, &(io.smb2));
1325 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1326 h2 = io.smb2.out.file.handle;
1327 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1329 ZERO_STRUCT(break_info);
1331 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1332 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1333 status = smb2_create(tree2, tctx, &(io.smb2));
1334 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1335 h1 = io.smb2.out.file.handle;
1336 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1338 torture_wait_for_oplock_break(tctx);
1339 CHECK_VAL(break_info.count, 1);
1340 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1341 CHECK_VAL(break_info.level, 1);
1342 CHECK_VAL(break_info.failures, 0);
1344 smb2_util_close(tree2, h1);
1345 smb2_util_close(tree2, h);
1347 smb2_deltree(tree1, BASEDIR);
1348 return ret;
1351 static bool test_smb2_oplock_batch8(struct torture_context *tctx,
1352 struct smb2_tree *tree1,
1353 struct smb2_tree *tree2)
1355 const char *fname = BASEDIR "\\test_batch8.dat";
1356 NTSTATUS status;
1357 bool ret = true;
1358 union smb_open io;
1359 struct smb2_handle h, h1, h2;
1361 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1362 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1364 /* cleanup */
1365 smb2_util_unlink(tree1, fname);
1367 tree1->session->transport->oplock.handler = torture_oplock_handler;
1368 tree1->session->transport->oplock.private_data = tree1;
1371 base ntcreatex parms
1373 ZERO_STRUCT(io.smb2);
1374 io.generic.level = RAW_OPEN_SMB2;
1375 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1376 io.smb2.in.alloc_size = 0;
1377 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1378 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1379 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1380 io.smb2.in.create_options = 0;
1381 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1382 io.smb2.in.security_flags = 0;
1383 io.smb2.in.fname = fname;
1385 torture_comment(tctx, "BATCH8: open with batch oplock\n");
1386 ZERO_STRUCT(break_info);
1388 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1389 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1390 status = smb2_create(tree1, tctx, &(io.smb2));
1391 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1392 h1 = io.smb2.out.file.handle;
1393 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1395 ZERO_STRUCT(break_info);
1396 torture_comment(tctx, "second open with attributes only shouldn't "
1397 "cause oplock break\n");
1399 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1400 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1401 SEC_FILE_WRITE_ATTRIBUTE |
1402 SEC_STD_SYNCHRONIZE;
1403 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1404 status = smb2_create(tree2, tctx, &(io.smb2));
1405 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1406 h2 = io.smb2.out.file.handle;
1407 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1408 torture_wait_for_oplock_break(tctx);
1409 CHECK_VAL(break_info.count, 0);
1410 CHECK_VAL(break_info.failures, 0);
1412 smb2_util_close(tree1, h1);
1413 smb2_util_close(tree2, h2);
1414 smb2_util_close(tree1, h);
1416 smb2_deltree(tree1, BASEDIR);
1417 return ret;
1420 static bool test_smb2_oplock_batch9(struct torture_context *tctx,
1421 struct smb2_tree *tree1,
1422 struct smb2_tree *tree2)
1424 const char *fname = BASEDIR "\\test_batch9.dat";
1425 NTSTATUS status;
1426 bool ret = true;
1427 union smb_open io;
1428 struct smb2_handle h, h1, h2;
1429 char c = 0;
1431 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1432 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1434 /* cleanup */
1435 smb2_util_unlink(tree1, fname);
1437 tree1->session->transport->oplock.handler = torture_oplock_handler;
1438 tree1->session->transport->oplock.private_data = tree1;
1441 base ntcreatex parms
1443 ZERO_STRUCT(io.smb2);
1444 io.generic.level = RAW_OPEN_SMB2;
1445 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1446 io.smb2.in.alloc_size = 0;
1447 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1448 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1449 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1450 io.smb2.in.create_options = 0;
1451 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1452 io.smb2.in.security_flags = 0;
1453 io.smb2.in.fname = fname;
1455 torture_comment(tctx, "BATCH9: open with attributes only can create "
1456 "file\n");
1458 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1459 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1460 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1461 SEC_FILE_WRITE_ATTRIBUTE |
1462 SEC_STD_SYNCHRONIZE;
1463 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1464 status = smb2_create(tree1, tctx, &(io.smb2));
1465 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1466 h1 = io.smb2.out.file.handle;
1467 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1469 torture_comment(tctx, "Subsequent normal open should break oplock on "
1470 "attribute only open to level II\n");
1472 ZERO_STRUCT(break_info);
1474 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1475 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1476 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1477 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1478 status = smb2_create(tree2, tctx, &(io.smb2));
1479 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1480 h2 = io.smb2.out.file.handle;
1481 torture_wait_for_oplock_break(tctx);
1482 CHECK_VAL(break_info.count, 1);
1483 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1484 CHECK_VAL(break_info.failures, 0);
1485 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1486 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1487 smb2_util_close(tree2, h2);
1489 torture_comment(tctx, "third oplocked open should grant level2 without "
1490 "break\n");
1491 ZERO_STRUCT(break_info);
1493 tree2->session->transport->oplock.handler = torture_oplock_handler;
1494 tree2->session->transport->oplock.private_data = tree2;
1496 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1497 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1498 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1499 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1500 status = smb2_create(tree2, tctx, &(io.smb2));
1501 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1502 h2 = io.smb2.out.file.handle;
1503 torture_wait_for_oplock_break(tctx);
1504 CHECK_VAL(break_info.count, 0);
1505 CHECK_VAL(break_info.failures, 0);
1506 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1508 ZERO_STRUCT(break_info);
1510 torture_comment(tctx, "write should trigger a break to none on both\n");
1511 tree1->session->transport->oplock.handler =
1512 torture_oplock_handler_level2_to_none;
1513 tree2->session->transport->oplock.handler =
1514 torture_oplock_handler_level2_to_none;
1515 smb2_util_write(tree2, h2, &c, 0, 1);
1517 /* We expect two breaks */
1518 torture_wait_for_oplock_break(tctx);
1519 torture_wait_for_oplock_break(tctx);
1521 CHECK_VAL(break_info.count, 2);
1522 CHECK_VAL(break_info.level, 0);
1523 CHECK_VAL(break_info.failures, 0);
1525 smb2_util_close(tree1, h1);
1526 smb2_util_close(tree2, h2);
1527 smb2_util_close(tree1, h);
1529 smb2_deltree(tree1, BASEDIR);
1530 return ret;
1533 static bool test_smb2_oplock_batch10(struct torture_context *tctx,
1534 struct smb2_tree *tree1,
1535 struct smb2_tree *tree2)
1537 const char *fname = BASEDIR "\\test_batch10.dat";
1538 NTSTATUS status;
1539 bool ret = true;
1540 union smb_open io;
1541 struct smb2_handle h, h1, h2;
1543 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1544 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1546 /* cleanup */
1547 smb2_util_unlink(tree1, fname);
1549 tree1->session->transport->oplock.handler = torture_oplock_handler;
1550 tree1->session->transport->oplock.private_data = tree1;
1553 base ntcreatex parms
1555 ZERO_STRUCT(io.smb2);
1556 io.generic.level = RAW_OPEN_SMB2;
1557 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1558 io.smb2.in.alloc_size = 0;
1559 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1560 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1561 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1562 io.smb2.in.create_options = 0;
1563 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1564 io.smb2.in.security_flags = 0;
1565 io.smb2.in.fname = fname;
1567 torture_comment(tctx, "BATCH10: Open with oplock after a non-oplock "
1568 "open should grant level2\n");
1569 ZERO_STRUCT(break_info);
1570 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1571 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1572 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1573 NTCREATEX_SHARE_ACCESS_WRITE|
1574 NTCREATEX_SHARE_ACCESS_DELETE;
1575 status = smb2_create(tree1, tctx, &(io.smb2));
1576 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1577 h1 = io.smb2.out.file.handle;
1578 torture_wait_for_oplock_break(tctx);
1579 CHECK_VAL(break_info.count, 0);
1580 CHECK_VAL(break_info.failures, 0);
1581 CHECK_VAL(io.smb2.out.oplock_level, 0);
1583 tree2->session->transport->oplock.handler =
1584 torture_oplock_handler_level2_to_none;
1585 tree2->session->transport->oplock.private_data = tree2;
1587 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1588 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1589 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1590 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1591 NTCREATEX_SHARE_ACCESS_WRITE|
1592 NTCREATEX_SHARE_ACCESS_DELETE;
1593 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1594 status = smb2_create(tree2, tctx, &(io.smb2));
1595 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1596 h2 = io.smb2.out.file.handle;
1597 torture_wait_for_oplock_break(tctx);
1598 CHECK_VAL(break_info.count, 0);
1599 CHECK_VAL(break_info.failures, 0);
1600 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1602 torture_comment(tctx, "write should trigger a break to none\n");
1604 struct smb2_write wr;
1605 DATA_BLOB data;
1606 data = data_blob_talloc(tree1, NULL, UINT16_MAX);
1607 data.data[0] = (const uint8_t)'x';
1608 ZERO_STRUCT(wr);
1609 wr.in.file.handle = h1;
1610 wr.in.offset = 0;
1611 wr.in.data = data;
1612 status = smb2_write(tree1, &wr);
1613 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1616 torture_wait_for_oplock_break(tctx);
1618 CHECK_VAL(break_info.count, 1);
1619 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1620 CHECK_VAL(break_info.level, 0);
1621 CHECK_VAL(break_info.failures, 0);
1623 smb2_util_close(tree1, h1);
1624 smb2_util_close(tree2, h2);
1625 smb2_util_close(tree1, h);
1627 smb2_deltree(tree1, BASEDIR);
1628 return ret;
1631 static bool test_smb2_oplock_batch11(struct torture_context *tctx,
1632 struct smb2_tree *tree1,
1633 struct smb2_tree *tree2)
1635 const char *fname = BASEDIR "\\test_batch11.dat";
1636 NTSTATUS status;
1637 bool ret = true;
1638 union smb_open io;
1639 union smb_setfileinfo sfi;
1640 struct smb2_handle h, h1;
1642 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1643 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1645 /* cleanup */
1646 smb2_util_unlink(tree1, fname);
1648 tree1->session->transport->oplock.handler =
1649 torture_oplock_handler_two_notifications;
1650 tree1->session->transport->oplock.private_data = tree1;
1653 base ntcreatex parms
1655 ZERO_STRUCT(io.smb2);
1656 io.generic.level = RAW_OPEN_SMB2;
1657 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1658 io.smb2.in.alloc_size = 0;
1659 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1660 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1661 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1662 io.smb2.in.create_options = 0;
1663 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1664 io.smb2.in.security_flags = 0;
1665 io.smb2.in.fname = fname;
1667 /* Test if a set-eof on pathname breaks an exclusive oplock. */
1668 torture_comment(tctx, "BATCH11: Test if setpathinfo set EOF breaks "
1669 "oplocks.\n");
1671 ZERO_STRUCT(break_info);
1673 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1674 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1675 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1676 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1677 NTCREATEX_SHARE_ACCESS_WRITE|
1678 NTCREATEX_SHARE_ACCESS_DELETE;
1679 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1680 status = smb2_create(tree1, tctx, &(io.smb2));
1681 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1682 h1 = io.smb2.out.file.handle;
1683 torture_wait_for_oplock_break(tctx);
1684 CHECK_VAL(break_info.count, 0);
1685 CHECK_VAL(break_info.failures, 0);
1686 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1688 ZERO_STRUCT(sfi);
1689 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1690 sfi.generic.in.file.path = fname;
1691 sfi.end_of_file_info.in.size = 100;
1693 status = smb2_composite_setpathinfo(tree2, &sfi);
1694 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1696 /* We expect two breaks */
1697 torture_wait_for_oplock_break(tctx);
1698 torture_wait_for_oplock_break(tctx);
1700 CHECK_VAL(break_info.count, 2);
1701 CHECK_VAL(break_info.failures, 0);
1702 CHECK_VAL(break_info.level, 0);
1704 smb2_util_close(tree1, h1);
1705 smb2_util_close(tree1, h);
1707 smb2_deltree(tree1, BASEDIR);
1708 return ret;
1711 static bool test_smb2_oplock_batch12(struct torture_context *tctx,
1712 struct smb2_tree *tree1,
1713 struct smb2_tree *tree2)
1715 const char *fname = BASEDIR "\\test_batch12.dat";
1716 NTSTATUS status;
1717 bool ret = true;
1718 union smb_open io;
1719 union smb_setfileinfo sfi;
1720 struct smb2_handle h, h1;
1722 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1723 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1725 /* cleanup */
1726 smb2_util_unlink(tree1, fname);
1728 tree1->session->transport->oplock.handler =
1729 torture_oplock_handler_two_notifications;
1730 tree1->session->transport->oplock.private_data = tree1;
1733 base ntcreatex parms
1735 ZERO_STRUCT(io.smb2);
1736 io.generic.level = RAW_OPEN_SMB2;
1737 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1738 io.smb2.in.alloc_size = 0;
1739 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1740 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1741 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1742 io.smb2.in.create_options = 0;
1743 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1744 io.smb2.in.security_flags = 0;
1745 io.smb2.in.fname = fname;
1747 /* Test if a set-allocation size on pathname breaks an exclusive
1748 * oplock. */
1749 torture_comment(tctx, "BATCH12: Test if setpathinfo allocation size "
1750 "breaks oplocks.\n");
1752 ZERO_STRUCT(break_info);
1754 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1755 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1756 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1757 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1758 NTCREATEX_SHARE_ACCESS_WRITE|
1759 NTCREATEX_SHARE_ACCESS_DELETE;
1760 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1761 status = smb2_create(tree1, tctx, &(io.smb2));
1762 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1763 h1 = io.smb2.out.file.handle;
1764 torture_wait_for_oplock_break(tctx);
1765 CHECK_VAL(break_info.count, 0);
1766 CHECK_VAL(break_info.failures, 0);
1767 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1769 ZERO_STRUCT(sfi);
1770 sfi.generic.level = RAW_SFILEINFO_ALLOCATION_INFORMATION;
1771 sfi.generic.in.file.path = fname;
1772 sfi.allocation_info.in.alloc_size = 65536 * 8;
1774 status = smb2_composite_setpathinfo(tree2, &sfi);
1775 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1777 /* We expect two breaks */
1778 torture_wait_for_oplock_break(tctx);
1779 torture_wait_for_oplock_break(tctx);
1781 CHECK_VAL(break_info.count, 2);
1782 CHECK_VAL(break_info.failures, 0);
1783 CHECK_VAL(break_info.level, 0);
1785 smb2_util_close(tree1, h1);
1786 smb2_util_close(tree1, h);
1788 smb2_deltree(tree1, BASEDIR);
1789 return ret;
1792 static bool test_smb2_oplock_batch13(struct torture_context *tctx,
1793 struct smb2_tree *tree1,
1794 struct smb2_tree *tree2)
1796 const char *fname = BASEDIR "\\test_batch13.dat";
1797 NTSTATUS status;
1798 bool ret = true;
1799 union smb_open io;
1800 struct smb2_handle h, h1, h2;
1802 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1803 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1805 /* cleanup */
1806 smb2_util_unlink(tree1, fname);
1808 tree1->session->transport->oplock.handler = torture_oplock_handler;
1809 tree1->session->transport->oplock.private_data = tree1;
1811 tree2->session->transport->oplock.handler = torture_oplock_handler;
1812 tree2->session->transport->oplock.private_data = tree2;
1815 base ntcreatex parms
1817 ZERO_STRUCT(io.smb2);
1818 io.generic.level = RAW_OPEN_SMB2;
1819 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1820 io.smb2.in.alloc_size = 0;
1821 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1822 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1823 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1824 io.smb2.in.create_options = 0;
1825 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1826 io.smb2.in.security_flags = 0;
1827 io.smb2.in.fname = fname;
1829 torture_comment(tctx, "BATCH13: open with batch oplock\n");
1830 ZERO_STRUCT(break_info);
1832 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1833 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1834 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1835 NTCREATEX_SHARE_ACCESS_WRITE|
1836 NTCREATEX_SHARE_ACCESS_DELETE;
1837 status = smb2_create(tree1, tctx, &(io.smb2));
1838 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1839 h1 = io.smb2.out.file.handle;
1840 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1842 ZERO_STRUCT(break_info);
1844 torture_comment(tctx, "second open with attributes only and "
1845 "NTCREATEX_DISP_OVERWRITE dispostion causes "
1846 "oplock break\n");
1848 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1849 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1850 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1851 SEC_FILE_WRITE_ATTRIBUTE |
1852 SEC_STD_SYNCHRONIZE;
1853 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1854 NTCREATEX_SHARE_ACCESS_WRITE|
1855 NTCREATEX_SHARE_ACCESS_DELETE;
1856 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1857 status = smb2_create(tree2, tctx, &(io.smb2));
1858 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1859 h2 = io.smb2.out.file.handle;
1860 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1861 torture_wait_for_oplock_break(tctx);
1862 CHECK_VAL(break_info.count, 1);
1863 CHECK_VAL(break_info.failures, 0);
1865 smb2_util_close(tree1, h1);
1866 smb2_util_close(tree2, h2);
1867 smb2_util_close(tree1, h);
1869 smb2_deltree(tree1, BASEDIR);
1871 return ret;
1874 static bool test_smb2_oplock_batch14(struct torture_context *tctx,
1875 struct smb2_tree *tree1,
1876 struct smb2_tree *tree2)
1878 const char *fname = BASEDIR "\\test_batch14.dat";
1879 NTSTATUS status;
1880 bool ret = true;
1881 union smb_open io;
1882 struct smb2_handle h, h1, h2;
1884 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1885 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1887 /* cleanup */
1888 smb2_util_unlink(tree1, fname);
1890 tree1->session->transport->oplock.handler = torture_oplock_handler;
1891 tree1->session->transport->oplock.private_data = tree1;
1894 base ntcreatex parms
1896 ZERO_STRUCT(io.smb2);
1897 io.generic.level = RAW_OPEN_SMB2;
1898 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1899 io.smb2.in.alloc_size = 0;
1900 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1901 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1902 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1903 io.smb2.in.create_options = 0;
1904 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1905 io.smb2.in.security_flags = 0;
1906 io.smb2.in.fname = fname;
1908 torture_comment(tctx, "BATCH14: open with batch oplock\n");
1909 ZERO_STRUCT(break_info);
1911 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1912 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1913 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1914 NTCREATEX_SHARE_ACCESS_WRITE|
1915 NTCREATEX_SHARE_ACCESS_DELETE;
1916 status = smb2_create(tree1, tctx, &(io.smb2));
1917 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1918 h1 = io.smb2.out.file.handle;
1919 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1921 ZERO_STRUCT(break_info);
1923 torture_comment(tctx, "second open with attributes only and "
1924 "NTCREATEX_DISP_SUPERSEDE dispostion causes "
1925 "oplock break\n");
1927 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1928 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1929 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1930 SEC_FILE_WRITE_ATTRIBUTE |
1931 SEC_STD_SYNCHRONIZE;
1932 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1933 NTCREATEX_SHARE_ACCESS_WRITE|
1934 NTCREATEX_SHARE_ACCESS_DELETE;
1935 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1936 status = smb2_create(tree2, tctx, &(io.smb2));
1937 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1938 h2 = io.smb2.out.file.handle;
1939 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1941 torture_wait_for_oplock_break(tctx);
1942 CHECK_VAL(break_info.count, 1);
1943 CHECK_VAL(break_info.failures, 0);
1945 smb2_util_close(tree1, h1);
1946 smb2_util_close(tree2, h2);
1947 smb2_util_close(tree1, h);
1949 smb2_deltree(tree1, BASEDIR);
1950 return ret;
1953 static bool test_smb2_oplock_batch15(struct torture_context *tctx,
1954 struct smb2_tree *tree1,
1955 struct smb2_tree *tree2)
1957 const char *fname = BASEDIR "\\test_batch15.dat";
1958 NTSTATUS status;
1959 bool ret = true;
1960 union smb_open io;
1961 union smb_fileinfo qfi;
1962 struct smb2_handle h, h1;
1964 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1965 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1967 /* cleanup */
1968 smb2_util_unlink(tree1, fname);
1970 tree1->session->transport->oplock.handler = torture_oplock_handler;
1971 tree1->session->transport->oplock.private_data = tree1;
1974 base ntcreatex parms
1976 ZERO_STRUCT(io.smb2);
1977 io.generic.level = RAW_OPEN_SMB2;
1978 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1979 io.smb2.in.alloc_size = 0;
1980 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1981 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1982 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1983 io.smb2.in.create_options = 0;
1984 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1985 io.smb2.in.security_flags = 0;
1986 io.smb2.in.fname = fname;
1988 /* Test if a qpathinfo all info on pathname breaks a batch oplock. */
1989 torture_comment(tctx, "BATCH15: Test if qpathinfo all info breaks "
1990 "a batch oplock (should not).\n");
1992 ZERO_STRUCT(break_info);
1994 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1995 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1996 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1997 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1998 NTCREATEX_SHARE_ACCESS_WRITE|
1999 NTCREATEX_SHARE_ACCESS_DELETE;
2000 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2001 status = smb2_create(tree1, tctx, &(io.smb2));
2002 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2003 h1 = io.smb2.out.file.handle;
2005 torture_wait_for_oplock_break(tctx);
2006 CHECK_VAL(break_info.count, 0);
2007 CHECK_VAL(break_info.failures, 0);
2008 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2010 ZERO_STRUCT(qfi);
2011 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2012 qfi.generic.in.file.handle = h1;
2013 status = smb2_getinfo_file(tree2, tctx, &qfi);
2015 torture_wait_for_oplock_break(tctx);
2016 CHECK_VAL(break_info.count, 0);
2018 smb2_util_close(tree1, h1);
2019 smb2_util_close(tree1, h);
2021 smb2_deltree(tree1, BASEDIR);
2022 return ret;
2025 static bool test_smb2_oplock_batch16(struct torture_context *tctx,
2026 struct smb2_tree *tree1,
2027 struct smb2_tree *tree2)
2029 const char *fname = BASEDIR "\\test_batch16.dat";
2030 NTSTATUS status;
2031 bool ret = true;
2032 union smb_open io;
2033 struct smb2_handle h, h1, h2;
2035 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2036 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2038 /* cleanup */
2039 smb2_util_unlink(tree1, fname);
2041 tree1->session->transport->oplock.handler = torture_oplock_handler;
2042 tree1->session->transport->oplock.private_data = tree1;
2044 tree2->session->transport->oplock.handler = torture_oplock_handler;
2045 tree2->session->transport->oplock.private_data = tree2;
2048 base ntcreatex parms
2050 ZERO_STRUCT(io.smb2);
2051 io.generic.level = RAW_OPEN_SMB2;
2052 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2053 io.smb2.in.alloc_size = 0;
2054 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2055 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2056 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2057 io.smb2.in.create_options = 0;
2058 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2059 io.smb2.in.security_flags = 0;
2060 io.smb2.in.fname = fname;
2062 torture_comment(tctx, "BATCH16: open with batch oplock\n");
2063 ZERO_STRUCT(break_info);
2065 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2066 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2067 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2068 NTCREATEX_SHARE_ACCESS_WRITE|
2069 NTCREATEX_SHARE_ACCESS_DELETE;
2070 status = smb2_create(tree1, tctx, &(io.smb2));
2071 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2072 h1 = io.smb2.out.file.handle;
2073 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2075 ZERO_STRUCT(break_info);
2077 torture_comment(tctx, "second open with attributes only and "
2078 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
2079 "oplock break\n");
2081 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2082 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2083 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2084 SEC_FILE_WRITE_ATTRIBUTE |
2085 SEC_STD_SYNCHRONIZE;
2086 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2087 NTCREATEX_SHARE_ACCESS_WRITE|
2088 NTCREATEX_SHARE_ACCESS_DELETE;
2089 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
2090 status = smb2_create(tree2, tctx, &(io.smb2));
2091 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2092 h2 = io.smb2.out.file.handle;
2093 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2095 torture_wait_for_oplock_break(tctx);
2096 CHECK_VAL(break_info.count, 1);
2097 CHECK_VAL(break_info.failures, 0);
2099 smb2_util_close(tree1, h1);
2100 smb2_util_close(tree2, h2);
2101 smb2_util_close(tree1, h);
2103 smb2_deltree(tree1, BASEDIR);
2104 return ret;
2107 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH17 test. Since
2108 * SMB2 doesn't have a RENAME command this test isn't applicable. However,
2109 * it's much less confusing, when comparing test, to keep the SMB1 and SMB2
2110 * test numbers in sync. */
2111 #if 0
2112 static bool test_raw_oplock_batch17(struct torture_context *tctx,
2113 struct smb2_tree *tree1,
2114 struct smb2_tree *tree2)
2116 return true;
2118 #endif
2120 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH18 test. Since
2121 * SMB2 doesn't have an NTRENAME command this test isn't applicable. However,
2122 * it's much less confusing, when comparing tests, to keep the SMB1 and SMB2
2123 * test numbers in sync. */
2124 #if 0
2125 static bool test_raw_oplock_batch18(struct torture_context *tctx,
2126 struct smb2_tree *tree1,
2127 struct smb2_tree *tree2)
2129 return true;
2131 #endif
2133 static bool test_smb2_oplock_batch19(struct torture_context *tctx,
2134 struct smb2_tree *tree1)
2136 const char *fname1 = BASEDIR "\\test_batch19_1.dat";
2137 const char *fname2 = BASEDIR "\\test_batch19_2.dat";
2138 NTSTATUS status;
2139 bool ret = true;
2140 union smb_open io;
2141 union smb_fileinfo qfi;
2142 union smb_setfileinfo sfi;
2143 struct smb2_handle h, h1;
2145 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2146 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2148 /* cleanup */
2149 smb2_util_unlink(tree1, fname1);
2150 smb2_util_unlink(tree1, fname2);
2152 tree1->session->transport->oplock.handler = torture_oplock_handler;
2153 tree1->session->transport->oplock.private_data = tree1;
2156 base ntcreatex parms
2158 ZERO_STRUCT(io.smb2);
2159 io.generic.level = RAW_OPEN_SMB2;
2160 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2161 io.smb2.in.alloc_size = 0;
2162 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2163 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2164 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2165 io.smb2.in.create_options = 0;
2166 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2167 io.smb2.in.security_flags = 0;
2168 io.smb2.in.fname = fname1;
2170 torture_comment(tctx, "BATCH19: open a file with an batch oplock "
2171 "(share mode: none)\n");
2172 ZERO_STRUCT(break_info);
2173 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2174 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2175 status = smb2_create(tree1, tctx, &(io.smb2));
2176 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2177 h1 = io.smb2.out.file.handle;
2178 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2180 torture_comment(tctx, "setfileinfo rename info should not trigger "
2181 "a break but should cause a sharing violation\n");
2182 ZERO_STRUCT(sfi);
2183 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2184 sfi.generic.in.file.path = fname1;
2185 sfi.rename_information.in.file.handle = h1;
2186 sfi.rename_information.in.overwrite = 0;
2187 sfi.rename_information.in.root_fid = 0;
2188 sfi.rename_information.in.new_name = fname2;
2190 status = smb2_setinfo_file(tree1, &sfi);
2192 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2193 "Incorrect status");
2195 torture_wait_for_oplock_break(tctx);
2196 CHECK_VAL(break_info.count, 0);
2198 ZERO_STRUCT(qfi);
2199 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2200 qfi.generic.in.file.handle = h1;
2202 status = smb2_getinfo_file(tree1, tctx, &qfi);
2203 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2204 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2206 smb2_util_close(tree1, h1);
2207 smb2_util_close(tree1, h);
2209 smb2_deltree(tree1, fname1);
2210 smb2_deltree(tree1, fname2);
2211 return ret;
2214 static bool test_smb2_oplock_batch20(struct torture_context *tctx,
2215 struct smb2_tree *tree1,
2216 struct smb2_tree *tree2)
2218 const char *fname1 = BASEDIR "\\test_batch20_1.dat";
2219 const char *fname2 = BASEDIR "\\test_batch20_2.dat";
2220 NTSTATUS status;
2221 bool ret = true;
2222 union smb_open io;
2223 union smb_fileinfo qfi;
2224 union smb_setfileinfo sfi;
2225 struct smb2_handle h, h1, h2;
2227 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2228 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2230 /* cleanup */
2231 smb2_util_unlink(tree1, fname1);
2232 smb2_util_unlink(tree1, fname2);
2234 tree1->session->transport->oplock.handler = torture_oplock_handler;
2235 tree1->session->transport->oplock.private_data = tree1;
2238 base ntcreatex parms
2240 ZERO_STRUCT(io.smb2);
2241 io.generic.level = RAW_OPEN_SMB2;
2242 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2243 io.smb2.in.alloc_size = 0;
2244 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2245 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2246 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2247 io.smb2.in.create_options = 0;
2248 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2249 io.smb2.in.security_flags = 0;
2250 io.smb2.in.fname = fname1;
2252 torture_comment(tctx, "BATCH20: open a file with an batch oplock "
2253 "(share mode: all)\n");
2254 ZERO_STRUCT(break_info);
2255 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2256 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2257 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2258 NTCREATEX_SHARE_ACCESS_WRITE|
2259 NTCREATEX_SHARE_ACCESS_DELETE;
2260 status = smb2_create(tree1, tctx, &(io.smb2));
2261 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2262 h1 = io.smb2.out.file.handle;
2263 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2265 torture_comment(tctx, "setfileinfo rename info should not trigger "
2266 "a break but should cause a sharing violation\n");
2267 ZERO_STRUCT(sfi);
2268 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2269 sfi.rename_information.in.file.handle = h1;
2270 sfi.rename_information.in.overwrite = 0;
2271 sfi.rename_information.in.new_name = fname2;
2273 status = smb2_setinfo_file(tree1, &sfi);
2274 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2275 "Incorrect status");
2277 torture_wait_for_oplock_break(tctx);
2278 CHECK_VAL(break_info.count, 0);
2280 ZERO_STRUCT(qfi);
2281 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2282 qfi.generic.in.file.handle = h1;
2284 status = smb2_getinfo_file(tree1, tctx, &qfi);
2285 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2286 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2288 torture_comment(tctx, "open the file a second time requesting batch "
2289 "(share mode: all)\n");
2290 ZERO_STRUCT(break_info);
2291 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2292 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2293 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2294 NTCREATEX_SHARE_ACCESS_WRITE|
2295 NTCREATEX_SHARE_ACCESS_DELETE;
2296 io.smb2.in.fname = fname1;
2297 status = smb2_create(tree2, tctx, &(io.smb2));
2298 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2299 h2 = io.smb2.out.file.handle;
2300 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2302 torture_wait_for_oplock_break(tctx);
2303 CHECK_VAL(break_info.count, 1);
2304 CHECK_VAL(break_info.failures, 0);
2305 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2307 torture_comment(tctx, "setfileinfo rename info should not trigger "
2308 "a break but should cause a sharing violation\n");
2309 ZERO_STRUCT(break_info);
2310 ZERO_STRUCT(sfi);
2311 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2312 sfi.rename_information.in.file.handle = h2;
2313 sfi.rename_information.in.overwrite = 0;
2314 sfi.rename_information.in.new_name = fname2;
2316 status = smb2_setinfo_file(tree2, &sfi);
2317 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2318 "Incorrect status");
2320 torture_wait_for_oplock_break(tctx);
2321 CHECK_VAL(break_info.count, 0);
2323 ZERO_STRUCT(qfi);
2324 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2325 qfi.generic.in.file.handle = h1;
2327 status = smb2_getinfo_file(tree1, tctx, &qfi);
2328 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2329 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2331 ZERO_STRUCT(qfi);
2332 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2333 qfi.generic.in.file.handle = h2;
2335 status = smb2_getinfo_file(tree2, tctx, &qfi);
2336 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2337 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2339 smb2_util_close(tree1, h1);
2340 smb2_util_close(tree2, h2);
2341 smb2_util_close(tree1, h);
2343 smb2_deltree(tree1, fname1);
2344 return ret;
2347 static bool test_smb2_oplock_batch21(struct torture_context *tctx,
2348 struct smb2_tree *tree1)
2350 const char *fname = BASEDIR "\\test_batch21.dat";
2351 NTSTATUS status;
2352 bool ret = true;
2353 union smb_open io;
2354 struct smb2_handle h, h1;
2355 char c = 0;
2357 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2358 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2360 /* cleanup */
2361 smb2_util_unlink(tree1, fname);
2363 tree1->session->transport->oplock.handler = torture_oplock_handler;
2364 tree1->session->transport->oplock.private_data = tree1;
2367 base ntcreatex parms
2369 ZERO_STRUCT(io.smb2);
2370 io.generic.level = RAW_OPEN_SMB2;
2371 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2372 io.smb2.in.alloc_size = 0;
2373 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2374 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2375 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2376 io.smb2.in.create_options = 0;
2377 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2378 io.smb2.in.security_flags = 0;
2379 io.smb2.in.fname = fname;
2382 with a batch oplock we get a break
2384 torture_comment(tctx, "BATCH21: open with batch oplock\n");
2385 ZERO_STRUCT(break_info);
2386 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2387 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2388 status = smb2_create(tree1, tctx, &(io.smb2));
2389 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2390 h1 = io.smb2.out.file.handle;
2391 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2393 torture_comment(tctx, "writing should not generate a break\n");
2394 status = smb2_util_write(tree1, h1, &c, 0, 1);
2395 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2397 torture_wait_for_oplock_break(tctx);
2398 CHECK_VAL(break_info.count, 0);
2400 smb2_util_close(tree1, h1);
2401 smb2_util_close(tree1, h);
2403 smb2_deltree(tree1, BASEDIR);
2404 return ret;
2407 static bool test_smb2_oplock_batch22(struct torture_context *tctx,
2408 struct smb2_tree *tree1)
2410 const char *fname = BASEDIR "\\test_batch22.dat";
2411 NTSTATUS status;
2412 bool ret = true;
2413 union smb_open io;
2414 struct smb2_handle h, h1, h2;
2415 struct timeval tv;
2416 int timeout = torture_setting_int(tctx, "oplocktimeout", 30);
2417 int te;
2419 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2420 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2422 /* cleanup */
2423 smb2_util_unlink(tree1, fname);
2425 tree1->session->transport->oplock.handler = torture_oplock_handler;
2426 tree1->session->transport->oplock.private_data = tree1;
2428 base ntcreatex parms
2430 ZERO_STRUCT(io.smb2);
2431 io.generic.level = RAW_OPEN_SMB2;
2432 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2433 io.smb2.in.alloc_size = 0;
2434 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2435 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2436 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2437 io.smb2.in.create_options = 0;
2438 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2439 io.smb2.in.security_flags = 0;
2440 io.smb2.in.fname = fname;
2443 with a batch oplock we get a break
2445 torture_comment(tctx, "BATCH22: open with batch oplock\n");
2446 ZERO_STRUCT(break_info);
2447 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2448 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2449 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2450 NTCREATEX_SHARE_ACCESS_WRITE|
2451 NTCREATEX_SHARE_ACCESS_DELETE;
2452 status = smb2_create(tree1, tctx, &(io.smb2));
2453 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2454 h1 = io.smb2.out.file.handle;
2455 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2457 torture_comment(tctx, "a 2nd open should succeed after the oplock "
2458 "break timeout\n");
2459 tv = timeval_current();
2460 tree1->session->transport->oplock.handler =
2461 torture_oplock_handler_timeout;
2462 status = smb2_create(tree1, tctx, &(io.smb2));
2463 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2464 h2 = io.smb2.out.file.handle;
2465 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2467 torture_wait_for_oplock_break(tctx);
2468 te = (int)timeval_elapsed(&tv);
2469 CHECK_RANGE(te, timeout - 1, timeout + 15);
2470 torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
2472 CHECK_VAL(break_info.count, 1);
2473 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2474 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2475 CHECK_VAL(break_info.failures, 0);
2477 smb2_util_close(tree1, h1);
2478 smb2_util_close(tree1, h2);
2479 smb2_util_close(tree1, h);
2481 smb2_deltree(tree1, BASEDIR);
2482 return ret;
2485 static bool test_smb2_oplock_batch23(struct torture_context *tctx,
2486 struct smb2_tree *tree1,
2487 struct smb2_tree *tree2)
2489 const char *fname = BASEDIR "\\test_batch23.dat";
2490 NTSTATUS status;
2491 bool ret = true;
2492 union smb_open io;
2493 struct smb2_handle h, h1, h2, h3;
2494 struct smb2_tree *tree3 = NULL;
2496 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2497 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2499 /* cleanup */
2500 smb2_util_unlink(tree1, fname);
2502 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2503 CHECK_VAL(ret, true);
2505 tree1->session->transport->oplock.handler = torture_oplock_handler;
2506 tree1->session->transport->oplock.private_data = tree1;
2508 tree2->session->transport->oplock.handler = torture_oplock_handler;
2509 tree2->session->transport->oplock.private_data = tree2;
2511 tree3->session->transport->oplock.handler = torture_oplock_handler;
2512 tree3->session->transport->oplock.private_data = tree3;
2515 base ntcreatex parms
2517 ZERO_STRUCT(io.smb2);
2518 io.generic.level = RAW_OPEN_SMB2;
2519 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2520 io.smb2.in.alloc_size = 0;
2521 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2522 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2523 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2524 io.smb2.in.create_options = 0;
2525 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2526 io.smb2.in.security_flags = 0;
2527 io.smb2.in.fname = fname;
2529 torture_comment(tctx, "BATCH23: an open and ask for a batch oplock\n");
2530 ZERO_STRUCT(break_info);
2532 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2533 SEC_RIGHTS_FILE_WRITE;
2534 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2535 NTCREATEX_SHARE_ACCESS_WRITE;
2536 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2537 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2538 status = smb2_create(tree1, tctx, &(io.smb2));
2539 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2540 h1 = io.smb2.out.file.handle;
2541 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2543 ZERO_STRUCT(break_info);
2545 torture_comment(tctx, "a 2nd open without level2 oplock support "
2546 "should generate a break to level2\n");
2547 status = smb2_create(tree3, tctx, &(io.smb2));
2548 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2549 h3 = io.smb2.out.file.handle;
2551 torture_wait_for_oplock_break(tctx);
2552 CHECK_VAL(break_info.count, 1);
2553 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2554 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2555 CHECK_VAL(break_info.failures, 0);
2557 ZERO_STRUCT(break_info);
2559 torture_comment(tctx, "a 3rd open with level2 oplock support should "
2560 "not generate a break\n");
2561 status = smb2_create(tree2, tctx, &(io.smb2));
2562 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2563 h2 = io.smb2.out.file.handle;
2564 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2566 torture_wait_for_oplock_break(tctx);
2567 CHECK_VAL(break_info.count, 0);
2569 smb2_util_close(tree1, h1);
2570 smb2_util_close(tree2, h2);
2571 smb2_util_close(tree3, h3);
2572 smb2_util_close(tree1, h);
2574 smb2_deltree(tree1, BASEDIR);
2575 return ret;
2578 static bool test_smb2_oplock_batch24(struct torture_context *tctx,
2579 struct smb2_tree *tree1,
2580 struct smb2_tree *tree2)
2582 const char *fname = BASEDIR "\\test_batch24.dat";
2583 NTSTATUS status;
2584 bool ret = true;
2585 union smb_open io;
2586 struct smb2_handle h, h1, h2;
2587 struct smb2_tree *tree3 = NULL;
2589 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2590 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2592 /* cleanup */
2593 smb2_util_unlink(tree1, fname);
2595 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2596 CHECK_VAL(ret, true);
2598 tree1->session->transport->oplock.handler = torture_oplock_handler;
2599 tree1->session->transport->oplock.private_data = tree1;
2601 tree2->session->transport->oplock.handler = torture_oplock_handler;
2602 tree2->session->transport->oplock.private_data = tree2;
2604 tree3->session->transport->oplock.handler = torture_oplock_handler;
2605 tree3->session->transport->oplock.private_data = tree3;
2608 base ntcreatex parms
2610 ZERO_STRUCT(io.smb2);
2611 io.generic.level = RAW_OPEN_SMB2;
2612 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2613 io.smb2.in.alloc_size = 0;
2614 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2615 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2616 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2617 io.smb2.in.create_options = 0;
2618 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2619 io.smb2.in.security_flags = 0;
2620 io.smb2.in.fname = fname;
2622 torture_comment(tctx, "BATCH24: a open without level support and "
2623 "ask for a batch oplock\n");
2624 ZERO_STRUCT(break_info);
2626 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2627 SEC_RIGHTS_FILE_WRITE;
2628 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2629 NTCREATEX_SHARE_ACCESS_WRITE;
2630 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2631 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2633 status = smb2_create(tree3, tctx, &(io.smb2));
2634 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2635 h2 = io.smb2.out.file.handle;
2636 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2638 ZERO_STRUCT(break_info);
2640 torture_comment(tctx, "a 2nd open with level2 oplock support should "
2641 "generate a break\n");
2642 status = smb2_create(tree2, tctx, &(io.smb2));
2643 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2644 h1 = io.smb2.out.file.handle;
2645 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2647 torture_wait_for_oplock_break(tctx);
2648 CHECK_VAL(break_info.count, 1);
2649 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
2650 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2651 CHECK_VAL(break_info.failures, 0);
2653 smb2_util_close(tree3, h2);
2654 smb2_util_close(tree2, h1);
2655 smb2_util_close(tree1, h);
2657 smb2_deltree(tree1, BASEDIR);
2658 return ret;
2661 static bool test_smb2_oplock_batch25(struct torture_context *tctx,
2662 struct smb2_tree *tree1)
2664 const char *fname = BASEDIR "\\test_batch25.dat";
2665 NTSTATUS status;
2666 bool ret = true;
2667 union smb_open io;
2668 struct smb2_handle h, h1;
2670 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2671 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2673 /* cleanup */
2674 smb2_util_unlink(tree1, fname);
2676 tree1->session->transport->oplock.handler = torture_oplock_handler;
2677 tree1->session->transport->oplock.private_data = tree1;
2680 base ntcreatex parms
2682 ZERO_STRUCT(io.smb2);
2683 io.generic.level = RAW_OPEN_SMB2;
2684 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2685 io.smb2.in.alloc_size = 0;
2686 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2687 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2688 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2689 io.smb2.in.create_options = 0;
2690 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2691 io.smb2.in.security_flags = 0;
2692 io.smb2.in.fname = fname;
2694 torture_comment(tctx, "BATCH25: open a file with an batch oplock "
2695 "(share mode: none)\n");
2697 ZERO_STRUCT(break_info);
2698 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2699 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2701 status = smb2_create(tree1, tctx, &(io.smb2));
2702 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2703 h1 = io.smb2.out.file.handle;
2704 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2706 torture_comment(tctx, "changing the file attribute info should trigger "
2707 "a break and a violation\n");
2709 status = smb2_util_setatr(tree1, fname, FILE_ATTRIBUTE_HIDDEN);
2710 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2711 "Incorrect status");
2713 torture_wait_for_oplock_break(tctx);
2714 CHECK_VAL(break_info.count, 1);
2716 smb2_util_close(tree1, h1);
2717 smb2_util_close(tree1, h);
2719 smb2_deltree(tree1, fname);
2720 return ret;
2723 /* Test how oplocks work on streams. */
2724 static bool test_raw_oplock_stream1(struct torture_context *tctx,
2725 struct smb2_tree *tree1,
2726 struct smb2_tree *tree2)
2728 NTSTATUS status;
2729 union smb_open io;
2730 const char *fname_base = BASEDIR "\\test_stream1.txt";
2731 const char *fname_stream, *fname_default_stream;
2732 const char *default_stream = "::$DATA";
2733 const char *stream = "Stream One:$DATA";
2734 bool ret = true;
2735 struct smb2_handle h, h_base, h_stream;
2736 int i;
2738 #define NSTREAM_OPLOCK_RESULTS 8
2739 struct {
2740 const char **fname;
2741 bool open_base_file;
2742 uint32_t oplock_req;
2743 uint32_t oplock_granted;
2744 } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
2745 /* Request oplock on stream without the base file open. */
2746 {&fname_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2747 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2748 {&fname_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2749 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2751 /* Request oplock on stream with the base file open. */
2752 {&fname_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2753 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_II},
2754 {&fname_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2755 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_II},
2758 fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
2759 fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
2760 default_stream);
2762 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2763 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2765 /* Initialize handles to "closed". Using -1 in the first 64-bytes
2766 * as the sentry for this */
2767 h_stream.data[0] = -1;
2769 /* cleanup */
2770 smb2_util_unlink(tree1, fname_base);
2772 tree1->session->transport->oplock.handler = torture_oplock_handler;
2773 tree1->session->transport->oplock.private_data = tree1;
2775 tree2->session->transport->oplock.handler = torture_oplock_handler;
2776 tree2->session->transport->oplock.private_data = tree2;
2778 /* Setup generic open parameters. */
2779 ZERO_STRUCT(io.smb2);
2780 io.generic.level = RAW_OPEN_SMB2;
2781 io.smb2.in.desired_access = (SEC_FILE_READ_DATA |
2782 SEC_FILE_WRITE_DATA |
2783 SEC_FILE_APPEND_DATA |
2784 SEC_STD_READ_CONTROL);
2785 io.smb2.in.alloc_size = 0;
2786 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2787 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2788 NTCREATEX_SHARE_ACCESS_WRITE;
2789 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2790 io.smb2.in.create_options = 0;
2791 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2792 io.smb2.in.security_flags = 0;
2794 /* Create the file with a stream */
2795 io.smb2.in.fname = fname_stream;
2796 io.smb2.in.create_flags = 0;
2797 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2798 status = smb2_create(tree1, tctx, &(io.smb2));
2799 torture_assert_ntstatus_ok(tctx, status, "Error creating file");
2800 smb2_util_close(tree1, io.smb2.out.file.handle);
2802 /* Change the disposition to open now that the file has been created. */
2803 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2805 /* Try some permutations of taking oplocks on streams. */
2806 for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
2807 const char *fname = *stream_oplock_results[i].fname;
2808 bool open_base_file = stream_oplock_results[i].open_base_file;
2809 uint32_t oplock_req = stream_oplock_results[i].oplock_req;
2810 uint32_t oplock_granted =
2811 stream_oplock_results[i].oplock_granted;
2813 if (open_base_file) {
2814 torture_comment(tctx, "Opening base file: %s with "
2815 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2816 io.smb2.in.fname = fname_base;
2817 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2818 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2819 status = smb2_create(tree2, tctx, &(io.smb2));
2820 torture_assert_ntstatus_ok(tctx, status,
2821 "Error opening file");
2822 CHECK_VAL(io.smb2.out.oplock_level,
2823 SMB2_OPLOCK_LEVEL_BATCH);
2824 h_base = io.smb2.out.file.handle;
2827 torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
2828 fname, oplock_req);
2829 io.smb2.in.fname = fname;
2830 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2831 io.smb2.in.oplock_level = oplock_req;
2833 /* Do the open with the desired oplock on the stream. */
2834 status = smb2_create(tree1, tctx, &(io.smb2));
2835 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2836 CHECK_VAL(io.smb2.out.oplock_level, oplock_granted);
2837 smb2_util_close(tree1, io.smb2.out.file.handle);
2839 /* Cleanup the base file if it was opened. */
2840 if (open_base_file)
2841 smb2_util_close(tree2, h_base);
2844 /* Open the stream with an exclusive oplock. */
2845 torture_comment(tctx, "Opening stream: %s with %d\n",
2846 fname_stream, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
2847 io.smb2.in.fname = fname_stream;
2848 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2849 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
2850 status = smb2_create(tree1, tctx, &(io.smb2));
2851 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2852 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
2853 h_stream = io.smb2.out.file.handle;
2855 /* Open the base file and see if it contends. */
2856 ZERO_STRUCT(break_info);
2857 torture_comment(tctx, "Opening base file: %s with %d\n",
2858 fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2859 io.smb2.in.fname = fname_base;
2860 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2861 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2862 status = smb2_create(tree2, tctx, &(io.smb2));
2863 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2864 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2865 smb2_util_close(tree2, io.smb2.out.file.handle);
2867 torture_wait_for_oplock_break(tctx);
2868 CHECK_VAL(break_info.count, 0);
2869 CHECK_VAL(break_info.failures, 0);
2871 /* Open the stream again to see if it contends. */
2872 ZERO_STRUCT(break_info);
2873 torture_comment(tctx, "Opening stream again: %s with "
2874 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2875 io.smb2.in.fname = fname_stream;
2876 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2877 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
2878 status = smb2_create(tree2, tctx, &(io.smb2));
2879 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2880 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2881 smb2_util_close(tree2, io.smb2.out.file.handle);
2883 torture_wait_for_oplock_break(tctx);
2884 CHECK_VAL(break_info.count, 1);
2885 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
2886 CHECK_VAL(break_info.failures, 0);
2888 /* Close the stream. */
2889 if (h_stream.data[0] != -1) {
2890 smb2_util_close(tree1, h_stream);
2893 smb2_util_close(tree1, h);
2895 smb2_deltree(tree1, BASEDIR);
2896 return ret;
2899 static bool test_smb2_oplock_doc(struct torture_context *tctx, struct smb2_tree *tree)
2901 const char *fname = BASEDIR "\\test_oplock_doc.dat";
2902 NTSTATUS status;
2903 bool ret = true;
2904 union smb_open io;
2905 struct smb2_handle h, h1;
2907 status = torture_smb2_testdir(tree, BASEDIR, &h);
2908 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2910 /* cleanup */
2911 smb2_util_unlink(tree, fname);
2912 tree->session->transport->oplock.handler = torture_oplock_handler;
2913 tree->session->transport->oplock.private_data = tree;
2916 base ntcreatex parms
2918 ZERO_STRUCT(io.smb2);
2919 io.generic.level = RAW_OPEN_SMB2;
2920 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2921 io.smb2.in.alloc_size = 0;
2922 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2923 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2924 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2925 io.smb2.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
2926 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2927 io.smb2.in.security_flags = 0;
2928 io.smb2.in.fname = fname;
2930 torture_comment(tctx, "open a delete-on-close file with a batch "
2931 "oplock\n");
2932 ZERO_STRUCT(break_info);
2933 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2934 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2936 status = smb2_create(tree, tctx, &(io.smb2));
2937 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2938 h1 = io.smb2.out.file.handle;
2939 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2941 smb2_util_close(tree, h1);
2943 smb2_util_unlink(tree, fname);
2944 smb2_deltree(tree, BASEDIR);
2945 return ret;
2948 /* Open a file with a batch oplock, then open it again from a second client
2949 * requesting no oplock. Having two open file handles should break our own
2950 * oplock during BRL acquisition.
2952 static bool test_smb2_oplock_brl1(struct torture_context *tctx,
2953 struct smb2_tree *tree1,
2954 struct smb2_tree *tree2)
2956 const char *fname = BASEDIR "\\test_batch_brl.dat";
2957 /*int fname, f;*/
2958 bool ret = true;
2959 uint8_t buf[1000];
2960 union smb_open io;
2961 NTSTATUS status;
2962 struct smb2_lock lck;
2963 struct smb2_lock_element lock[1];
2964 struct smb2_handle h, h1, h2;
2966 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2967 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2969 /* cleanup */
2970 smb2_util_unlink(tree1, fname);
2972 tree1->session->transport->oplock.handler =
2973 torture_oplock_handler_two_notifications;
2974 tree1->session->transport->oplock.private_data = tree1;
2977 base ntcreatex parms
2979 ZERO_STRUCT(io.smb2);
2980 io.generic.level = RAW_OPEN_SMB2;
2981 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2982 SEC_RIGHTS_FILE_WRITE;
2983 io.smb2.in.alloc_size = 0;
2984 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2985 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2986 NTCREATEX_SHARE_ACCESS_WRITE;
2987 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2988 io.smb2.in.create_options = 0;
2989 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2990 io.smb2.in.security_flags = 0;
2991 io.smb2.in.fname = fname;
2994 with a batch oplock we get a break
2996 torture_comment(tctx, "open with batch oplock\n");
2997 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2998 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3000 status = smb2_create(tree1, tctx, &(io.smb2));
3001 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3002 h1 = io.smb2.out.file.handle;
3003 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3005 /* create a file with bogus data */
3006 memset(buf, 0, sizeof(buf));
3008 status = smb2_util_write(tree1, h1,buf, 0, sizeof(buf));
3009 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3010 torture_comment(tctx, "Failed to create file\n");
3011 ret = false;
3012 goto done;
3015 torture_comment(tctx, "a 2nd open should give a break\n");
3016 ZERO_STRUCT(break_info);
3018 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3019 io.smb2.in.oplock_level = 0;
3020 status = smb2_create(tree2, tctx, &(io.smb2));
3021 h2 = io.smb2.out.file.handle;
3022 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3024 torture_wait_for_oplock_break(tctx);
3025 CHECK_VAL(break_info.count, 1);
3026 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3027 CHECK_VAL(break_info.failures, 0);
3028 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3030 ZERO_STRUCT(break_info);
3032 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3033 lock[0].offset = 0;
3034 lock[0].length = 4;
3035 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3036 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3038 ZERO_STRUCT(lck);
3039 lck.in.file.handle = h1;
3040 lck.in.locks = &lock[0];
3041 lck.in.lock_count = 1;
3042 status = smb2_lock(tree1, &lck);
3043 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3045 torture_wait_for_oplock_break(tctx);
3046 CHECK_VAL(break_info.count, 1);
3047 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3048 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3049 CHECK_VAL(break_info.failures, 0);
3051 /* expect no oplock break */
3052 ZERO_STRUCT(break_info);
3053 lock[0].offset = 2;
3054 status = smb2_lock(tree1, &lck);
3055 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3056 "Incorrect status");
3058 torture_wait_for_oplock_break(tctx);
3059 CHECK_VAL(break_info.count, 0);
3060 CHECK_VAL(break_info.level, 0);
3061 CHECK_VAL(break_info.failures, 0);
3063 smb2_util_close(tree1, h1);
3064 smb2_util_close(tree2, h2);
3065 smb2_util_close(tree1, h);
3067 done:
3068 smb2_deltree(tree1, BASEDIR);
3069 return ret;
3073 /* Open a file with a batch oplock on one tree and then acquire a brl.
3074 * We should not contend our own oplock.
3076 static bool test_smb2_oplock_brl2(struct torture_context *tctx, struct smb2_tree *tree1)
3078 const char *fname = BASEDIR "\\test_batch_brl.dat";
3079 /*int fname, f;*/
3080 bool ret = true;
3081 uint8_t buf[1000];
3082 union smb_open io;
3083 NTSTATUS status;
3084 struct smb2_handle h, h1;
3085 struct smb2_lock lck;
3086 struct smb2_lock_element lock[1];
3088 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3089 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3091 /* cleanup */
3092 smb2_util_unlink(tree1, fname);
3094 tree1->session->transport->oplock.handler = torture_oplock_handler;
3095 tree1->session->transport->oplock.private_data = tree1;
3098 base ntcreatex parms
3100 ZERO_STRUCT(io.smb2);
3101 io.generic.level = RAW_OPEN_SMB2;
3102 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3103 SEC_RIGHTS_FILE_WRITE;
3104 io.smb2.in.alloc_size = 0;
3105 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3106 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3107 NTCREATEX_SHARE_ACCESS_WRITE;
3108 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3109 io.smb2.in.create_options = 0;
3110 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3111 io.smb2.in.security_flags = 0;
3112 io.smb2.in.fname = fname;
3115 with a batch oplock we get a break
3117 torture_comment(tctx, "open with batch oplock\n");
3118 ZERO_STRUCT(break_info);
3119 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3120 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3122 status = smb2_create(tree1, tctx, &(io.smb2));
3123 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3124 h1 = io.smb2.out.file.handle;
3125 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3127 /* create a file with bogus data */
3128 memset(buf, 0, sizeof(buf));
3130 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3131 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3132 torture_comment(tctx, "Failed to create file\n");
3133 ret = false;
3134 goto done;
3137 ZERO_STRUCT(break_info);
3139 torture_comment(tctx, "a self BRL acquisition should not break to "
3140 "none\n");
3142 lock[0].offset = 0;
3143 lock[0].length = 4;
3144 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3145 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3147 ZERO_STRUCT(lck);
3148 lck.in.file.handle = h1;
3149 lck.in.locks = &lock[0];
3150 lck.in.lock_count = 1;
3151 status = smb2_lock(tree1, &lck);
3152 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3154 lock[0].offset = 2;
3155 status = smb2_lock(tree1, &lck);
3156 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3157 "Incorrect status");
3159 /* With one file handle open a BRL should not contend our oplock.
3160 * Thus, no oplock break will be received and the entire break_info
3161 * struct will be 0 */
3162 torture_wait_for_oplock_break(tctx);
3163 CHECK_VAL(break_info.count, 0);
3164 CHECK_VAL(break_info.level, 0);
3165 CHECK_VAL(break_info.failures, 0);
3167 smb2_util_close(tree1, h1);
3168 smb2_util_close(tree1, h);
3170 done:
3171 smb2_deltree(tree1, BASEDIR);
3172 return ret;
3175 /* Open a file with a batch oplock twice from one tree and then acquire a
3176 * brl. BRL acquisition should break our own oplock.
3178 static bool test_smb2_oplock_brl3(struct torture_context *tctx, struct smb2_tree *tree1)
3180 const char *fname = BASEDIR "\\test_batch_brl.dat";
3181 bool ret = true;
3182 uint8_t buf[1000];
3183 union smb_open io;
3184 NTSTATUS status;
3185 struct smb2_handle h, h1, h2;
3186 struct smb2_lock lck;
3187 struct smb2_lock_element lock[1];
3189 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3190 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3192 /* cleanup */
3193 smb2_util_unlink(tree1, fname);
3194 tree1->session->transport->oplock.handler =
3195 torture_oplock_handler_two_notifications;
3196 tree1->session->transport->oplock.private_data = tree1;
3199 base ntcreatex parms
3201 ZERO_STRUCT(io.smb2);
3202 io.generic.level = RAW_OPEN_SMB2;
3203 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3204 SEC_RIGHTS_FILE_WRITE;
3205 io.smb2.in.alloc_size = 0;
3206 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3207 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3208 NTCREATEX_SHARE_ACCESS_WRITE;
3209 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3210 io.smb2.in.create_options = 0;
3211 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3212 io.smb2.in.security_flags = 0;
3213 io.smb2.in.fname = fname;
3216 with a batch oplock we get a break
3218 torture_comment(tctx, "open with batch oplock\n");
3219 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3220 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3222 status = smb2_create(tree1, tctx, &(io.smb2));
3223 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3224 h1 = io.smb2.out.file.handle;
3225 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3227 /* create a file with bogus data */
3228 memset(buf, 0, sizeof(buf));
3229 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3231 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3232 torture_comment(tctx, "Failed to create file\n");
3233 ret = false;
3234 goto done;
3237 torture_comment(tctx, "a 2nd open should give a break\n");
3238 ZERO_STRUCT(break_info);
3240 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3241 io.smb2.in.oplock_level = 0;
3242 status = smb2_create(tree1, tctx, &(io.smb2));
3243 h2 = io.smb2.out.file.handle;
3244 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3245 CHECK_VAL(break_info.count, 1);
3246 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3247 CHECK_VAL(break_info.failures, 0);
3248 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3250 ZERO_STRUCT(break_info);
3252 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3254 lock[0].offset = 0;
3255 lock[0].length = 4;
3256 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3257 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3259 ZERO_STRUCT(lck);
3260 lck.in.file.handle = h1;
3261 lck.in.locks = &lock[0];
3262 lck.in.lock_count = 1;
3263 status = smb2_lock(tree1, &lck);
3264 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3266 torture_wait_for_oplock_break(tctx);
3267 CHECK_VAL(break_info.count, 1);
3268 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3269 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3270 CHECK_VAL(break_info.failures, 0);
3272 /* expect no oplock break */
3273 ZERO_STRUCT(break_info);
3274 lock[0].offset = 2;
3275 status = smb2_lock(tree1, &lck);
3276 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3277 "Incorrect status");
3279 torture_wait_for_oplock_break(tctx);
3280 CHECK_VAL(break_info.count, 0);
3281 CHECK_VAL(break_info.level, 0);
3282 CHECK_VAL(break_info.failures, 0);
3284 smb2_util_close(tree1, h1);
3285 smb2_util_close(tree1, h2);
3286 smb2_util_close(tree1, h);
3288 done:
3289 smb2_deltree(tree1, BASEDIR);
3290 return ret;
3294 /* Starting the SMB2 specific oplock tests at 500 so we can keep the SMB1
3295 * tests in sync with an identically numbered SMB2 test */
3297 /* Test whether the server correctly returns an error when we send
3298 * a response to a levelII to none oplock notification. */
3299 static bool test_smb2_oplock_levelII500(struct torture_context *tctx,
3300 struct smb2_tree *tree1)
3302 const char *fname = BASEDIR "\\test_levelII500.dat";
3303 NTSTATUS status;
3304 bool ret = true;
3305 union smb_open io;
3306 struct smb2_handle h, h1;
3307 char c = 0;
3309 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3310 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3312 /* cleanup */
3313 smb2_util_unlink(tree1, fname);
3315 tree1->session->transport->oplock.handler = torture_oplock_handler;
3316 tree1->session->transport->oplock.private_data = tree1;
3319 base ntcreatex parms
3321 ZERO_STRUCT(io.smb2);
3322 io.generic.level = RAW_OPEN_SMB2;
3323 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3324 io.smb2.in.alloc_size = 0;
3325 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3326 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3327 io.smb2.in.create_options = 0;
3328 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3329 io.smb2.in.security_flags = 0;
3330 io.smb2.in.fname = fname;
3332 torture_comment(tctx, "LEVELII500: acknowledging a break from II to "
3333 "none should return an error\n");
3334 ZERO_STRUCT(break_info);
3336 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3337 SEC_RIGHTS_FILE_WRITE;
3338 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3339 NTCREATEX_SHARE_ACCESS_WRITE;
3340 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3341 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
3342 status = smb2_create(tree1, tctx, &(io.smb2));
3343 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3344 h1 = io.smb2.out.file.handle;
3345 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3347 ZERO_STRUCT(break_info);
3349 torture_comment(tctx, "write should trigger a break to none and when "
3350 "we reply, an oplock break failure\n");
3351 smb2_util_write(tree1, h1, &c, 0, 1);
3353 /* Wait several times to receive both the break notification, and the
3354 * NT_STATUS_INVALID_OPLOCK_PROTOCOL error in the break response */
3355 torture_wait_for_oplock_break(tctx);
3356 torture_wait_for_oplock_break(tctx);
3357 torture_wait_for_oplock_break(tctx);
3358 torture_wait_for_oplock_break(tctx);
3360 /* There appears to be a race condition in W2K8 and W2K8R2 where
3361 * sometimes the server will happily reply to our break response with
3362 * NT_STATUS_OK, and sometimes it will return the OPLOCK_PROTOCOL
3363 * error. As the MS-SMB2 doc states that a client should not reply to
3364 * a level2 to none break notification, I'm leaving the protocol error
3365 * as the expected behavior. */
3366 CHECK_VAL(break_info.count, 1);
3367 CHECK_VAL(break_info.level, 0);
3368 CHECK_VAL(break_info.failures, 1);
3369 torture_assert_ntstatus_equal(tctx, break_info.failure_status,
3370 NT_STATUS_INVALID_OPLOCK_PROTOCOL,
3371 "Incorrect status");
3373 smb2_util_close(tree1, h1);
3374 smb2_util_close(tree1, h);
3376 smb2_deltree(tree1, BASEDIR);
3377 return ret;
3380 struct torture_suite *torture_smb2_oplocks_init(void)
3382 struct torture_suite *suite =
3383 torture_suite_create(talloc_autofree_context(), "oplock");
3385 torture_suite_add_2smb2_test(suite, "exclusive1", test_smb2_oplock_exclusive1);
3386 torture_suite_add_2smb2_test(suite, "exclusive2", test_smb2_oplock_exclusive2);
3387 torture_suite_add_2smb2_test(suite, "exclusive3", test_smb2_oplock_exclusive3);
3388 torture_suite_add_2smb2_test(suite, "exclusive4", test_smb2_oplock_exclusive4);
3389 torture_suite_add_2smb2_test(suite, "exclusive5", test_smb2_oplock_exclusive5);
3390 torture_suite_add_2smb2_test(suite, "exclusive6", test_smb2_oplock_exclusive6);
3391 torture_suite_add_2smb2_test(suite, "batch1", test_smb2_oplock_batch1);
3392 torture_suite_add_2smb2_test(suite, "batch2", test_smb2_oplock_batch2);
3393 torture_suite_add_2smb2_test(suite, "batch3", test_smb2_oplock_batch3);
3394 torture_suite_add_2smb2_test(suite, "batch4", test_smb2_oplock_batch4);
3395 torture_suite_add_2smb2_test(suite, "batch5", test_smb2_oplock_batch5);
3396 torture_suite_add_2smb2_test(suite, "batch6", test_smb2_oplock_batch6);
3397 torture_suite_add_2smb2_test(suite, "batch7", test_smb2_oplock_batch7);
3398 torture_suite_add_2smb2_test(suite, "batch8", test_smb2_oplock_batch8);
3399 torture_suite_add_2smb2_test(suite, "batch9", test_smb2_oplock_batch9);
3400 torture_suite_add_2smb2_test(suite, "batch10", test_smb2_oplock_batch10);
3401 torture_suite_add_2smb2_test(suite, "batch11", test_smb2_oplock_batch11);
3402 torture_suite_add_2smb2_test(suite, "batch12", test_smb2_oplock_batch12);
3403 torture_suite_add_2smb2_test(suite, "batch13", test_smb2_oplock_batch13);
3404 torture_suite_add_2smb2_test(suite, "batch14", test_smb2_oplock_batch14);
3405 torture_suite_add_2smb2_test(suite, "batch15", test_smb2_oplock_batch15);
3406 torture_suite_add_2smb2_test(suite, "batch16", test_smb2_oplock_batch16);
3407 torture_suite_add_1smb2_test(suite, "batch19", test_smb2_oplock_batch19);
3408 torture_suite_add_2smb2_test(suite, "batch20", test_smb2_oplock_batch20);
3409 torture_suite_add_1smb2_test(suite, "batch21", test_smb2_oplock_batch21);
3410 torture_suite_add_1smb2_test(suite, "batch22", test_smb2_oplock_batch22);
3411 torture_suite_add_2smb2_test(suite, "batch23", test_smb2_oplock_batch23);
3412 torture_suite_add_2smb2_test(suite, "batch24", test_smb2_oplock_batch24);
3413 torture_suite_add_1smb2_test(suite, "batch25", test_smb2_oplock_batch25);
3414 torture_suite_add_2smb2_test(suite, "stream1", test_raw_oplock_stream1);
3415 torture_suite_add_1smb2_test(suite, "doc", test_smb2_oplock_doc);
3416 torture_suite_add_2smb2_test(suite, "brl1", test_smb2_oplock_brl1);
3417 torture_suite_add_1smb2_test(suite, "brl2", test_smb2_oplock_brl2);
3418 torture_suite_add_1smb2_test(suite, "brl3", test_smb2_oplock_brl3);
3419 torture_suite_add_1smb2_test(suite, "levelii500", test_smb2_oplock_levelII500);
3421 suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
3423 return suite;
3427 stress testing of oplocks
3429 bool test_smb2_bench_oplock(struct torture_context *tctx,
3430 struct smb2_tree *tree)
3432 struct smb2_tree **trees;
3433 bool ret = true;
3434 NTSTATUS status;
3435 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3436 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
3437 int i, count=0;
3438 int timelimit = torture_setting_int(tctx, "timelimit", 10);
3439 union smb_open io;
3440 struct timeval tv;
3441 struct smb2_handle h;
3443 trees = talloc_array(mem_ctx, struct smb2_tree *, torture_nprocs);
3445 torture_comment(tctx, "Opening %d connections\n", torture_nprocs);
3446 for (i=0;i<torture_nprocs;i++) {
3447 if (!torture_smb2_connection(tctx, &trees[i])) {
3448 return false;
3450 talloc_steal(mem_ctx, trees[i]);
3451 trees[i]->session->transport->oplock.handler =
3452 torture_oplock_handler_close;
3453 trees[i]->session->transport->oplock.private_data = trees[i];
3456 status = torture_smb2_testdir(trees[0], BASEDIR, &h);
3457 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3459 ZERO_STRUCT(io.smb2);
3460 io.smb2.level = RAW_OPEN_SMB2;
3461 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3462 io.smb2.in.alloc_size = 0;
3463 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3464 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
3465 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3466 io.smb2.in.create_options = 0;
3467 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3468 io.smb2.in.security_flags = 0;
3469 io.smb2.in.fname = BASEDIR "\\test.dat";
3470 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3471 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3473 tv = timeval_current();
3476 we open the same file with SHARE_ACCESS_NONE from all the
3477 connections in a round robin fashion. Each open causes an
3478 oplock break on the previous connection, which is answered
3479 by the oplock_handler_close() to close the file.
3481 This measures how fast we can pass on oplocks, and stresses
3482 the oplock handling code
3484 torture_comment(tctx, "Running for %d seconds\n", timelimit);
3485 while (timeval_elapsed(&tv) < timelimit) {
3486 for (i=0;i<torture_nprocs;i++) {
3487 status = smb2_create(trees[i], mem_ctx, &(io.smb2));
3488 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3489 count++;
3492 if (torture_setting_bool(tctx, "progress", true)) {
3493 torture_comment(tctx, "%.2f ops/second\r",
3494 count/timeval_elapsed(&tv));
3498 torture_comment(tctx, "%.2f ops/second\n", count/timeval_elapsed(&tv));
3499 smb2_util_close(trees[0], io.smb2.out.file.handle);
3500 smb2_util_unlink(trees[0], BASEDIR "\\test.dat");
3501 smb2_deltree(trees[0], BASEDIR);
3502 talloc_free(mem_ctx);
3503 return ret;
3506 static struct hold_oplock_info {
3507 const char *fname;
3508 bool close_on_break;
3509 uint32_t share_access;
3510 struct smb2_handle handle;
3511 } hold_info[] = {
3512 { BASEDIR "\\notshared_close", true,
3513 NTCREATEX_SHARE_ACCESS_NONE, },
3514 { BASEDIR "\\notshared_noclose", false,
3515 NTCREATEX_SHARE_ACCESS_NONE, },
3516 { BASEDIR "\\shared_close", true,
3517 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, },
3518 { BASEDIR "\\shared_noclose", false,
3519 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, },
3522 static bool torture_oplock_handler_hold(struct smb2_transport *transport,
3523 const struct smb2_handle *handle,
3524 uint8_t level, void *private_data)
3526 struct hold_oplock_info *info;
3527 int i;
3529 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
3530 if (smb2_util_handle_equal(hold_info[i].handle, *handle))
3531 break;
3534 if (i == ARRAY_SIZE(hold_info)) {
3535 printf("oplock break for unknown handle 0x%llx%llx\n",
3536 (unsigned long long) handle->data[0],
3537 (unsigned long long) handle->data[1]);
3538 return false;
3541 info = &hold_info[i];
3543 if (info->close_on_break) {
3544 printf("oplock break on %s - closing\n", info->fname);
3545 torture_oplock_handler_close(transport, handle,
3546 level, private_data);
3547 return true;
3550 printf("oplock break on %s - acking break\n", info->fname);
3551 printf("Acking to none in oplock handler\n");
3553 torture_oplock_handler_ack_to_none(transport, handle,
3554 level, private_data);
3555 return true;
3559 used for manual testing of oplocks - especially interaction with
3560 other filesystems (such as NFS and local access)
3562 bool test_smb2_hold_oplock(struct torture_context *tctx,
3563 struct smb2_tree *tree)
3565 struct torture_context *mem_ctx = talloc_new(tctx);
3566 struct tevent_context *ev = tctx->ev;
3567 int i;
3568 struct smb2_handle h;
3569 NTSTATUS status;
3571 torture_comment(tctx, "Setting up open files with oplocks in %s\n",
3572 BASEDIR);
3574 status = torture_smb2_testdir(tree, BASEDIR, &h);
3575 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3577 tree->session->transport->oplock.handler = torture_oplock_handler_hold;
3578 tree->session->transport->oplock.private_data = tree;
3580 /* setup the files */
3581 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
3582 union smb_open io;
3583 char c = 1;
3585 ZERO_STRUCT(io.smb2);
3586 io.generic.level = RAW_OPEN_SMB2;
3587 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3588 io.smb2.in.alloc_size = 0;
3589 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3590 io.smb2.in.share_access = hold_info[i].share_access;
3591 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3592 io.smb2.in.create_options = 0;
3593 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3594 io.smb2.in.security_flags = 0;
3595 io.smb2.in.fname = hold_info[i].fname;
3596 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3597 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3599 torture_comment(tctx, "opening %s\n", hold_info[i].fname);
3601 status = smb2_create(tree, mem_ctx, &(io.smb2));
3602 if (!NT_STATUS_IS_OK(status)) {
3603 torture_comment(tctx, "Failed to open %s - %s\n",
3604 hold_info[i].fname, nt_errstr(status));
3605 return false;
3608 if (io.smb2.out.oplock_level != SMB2_OPLOCK_LEVEL_BATCH) {
3609 torture_comment(tctx, "Oplock not granted for %s - "
3610 "expected %d but got %d\n",
3611 hold_info[i].fname,
3612 SMB2_OPLOCK_LEVEL_BATCH,
3613 io.smb2.out.oplock_level);
3614 return false;
3616 hold_info[i].handle = io.smb2.out.file.handle;
3618 /* make the file non-zero size */
3619 status = smb2_util_write(tree, hold_info[i].handle, &c, 0, 1);
3620 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3621 torture_comment(tctx, "Failed to write to file\n");
3622 return false;
3626 torture_comment(tctx, "Waiting for oplock events\n");
3627 tevent_loop_wait(ev);
3628 smb2_deltree(tree, BASEDIR);
3629 talloc_free(mem_ctx);
3630 return true;