s4:torture: Add smb2.oplock test batch9a and raw.oplock test batch9a
[Samba.git] / source4 / torture / smb2 / oplock.c
blobbe1c5eb0f5af5e88d3fa2544f4e40253d15c1724
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_exclusive9(struct torture_context *tctx,
831 struct smb2_tree *tree1,
832 struct smb2_tree *tree2)
834 const char *fname = BASEDIR "\\test_exclusive9.dat";
835 NTSTATUS status;
836 bool ret = true;
837 union smb_open io;
838 struct smb2_handle h1, h2;
839 int i;
841 struct {
842 uint32_t create_disposition;
843 uint32_t break_level;
844 } levels[] = {
845 { NTCREATEX_DISP_SUPERSEDE, SMB2_OPLOCK_LEVEL_NONE },
846 { NTCREATEX_DISP_OPEN, SMB2_OPLOCK_LEVEL_II },
847 { NTCREATEX_DISP_OVERWRITE_IF, SMB2_OPLOCK_LEVEL_NONE },
848 { NTCREATEX_DISP_OPEN_IF, SMB2_OPLOCK_LEVEL_II },
852 status = torture_smb2_testdir(tree1, BASEDIR, &h1);
853 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
854 smb2_util_close(tree1, h1);
856 /* cleanup */
857 smb2_util_unlink(tree1, fname);
859 tree1->session->transport->oplock.handler = torture_oplock_handler;
860 tree1->session->transport->oplock.private_data = tree1;
863 base ntcreatex parms
865 ZERO_STRUCT(io.smb2);
866 io.generic.level = RAW_OPEN_SMB2;
867 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
868 io.smb2.in.alloc_size = 0;
869 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
870 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
871 NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
872 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
873 io.smb2.in.create_options = 0;
874 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
875 io.smb2.in.security_flags = 0;
876 io.smb2.in.fname = fname;
878 for (i=0; i<ARRAY_SIZE(levels); i++) {
880 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
881 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
883 status = smb2_create(tree1, tctx, &(io.smb2));
884 torture_assert_ntstatus_ok(tctx, status,
885 "Error opening the file");
886 h1 = io.smb2.out.file.handle;
887 CHECK_VAL(io.smb2.out.oplock_level,
888 SMB2_OPLOCK_LEVEL_EXCLUSIVE);
890 ZERO_STRUCT(break_info);
892 io.smb2.in.create_disposition = levels[i].create_disposition;
893 status = smb2_create(tree2, tctx, &(io.smb2));
894 torture_assert_ntstatus_ok(tctx, status,
895 "Error opening the file");
896 h2 = io.smb2.out.file.handle;
897 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
899 CHECK_VAL(break_info.count, 1);
900 CHECK_VAL(break_info.level, levels[i].break_level);
901 CHECK_VAL(break_info.failures, 0);
903 smb2_util_close(tree2, h2);
904 smb2_util_close(tree1, h1);
907 smb2_deltree(tree1, BASEDIR);
908 return ret;
911 static bool test_smb2_oplock_batch1(struct torture_context *tctx,
912 struct smb2_tree *tree1,
913 struct smb2_tree *tree2)
915 const char *fname = BASEDIR "\\test_batch1.dat";
916 NTSTATUS status;
917 bool ret = true;
918 union smb_open io;
919 struct smb2_handle h, h1;
920 char c = 0;
922 status = torture_smb2_testdir(tree1, BASEDIR, &h);
923 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
925 /* cleanup */
926 smb2_util_unlink(tree1, fname);
928 tree1->session->transport->oplock.handler = torture_oplock_handler;
929 tree1->session->transport->oplock.private_data = tree1;
932 base ntcreatex parms
934 ZERO_STRUCT(io.smb2);
935 io.generic.level = RAW_OPEN_SMB2;
936 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
937 io.smb2.in.alloc_size = 0;
938 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
939 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
940 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
941 io.smb2.in.create_options = 0;
942 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
943 io.smb2.in.security_flags = 0;
944 io.smb2.in.fname = fname;
947 with a batch oplock we get a break
949 torture_comment(tctx, "BATCH1: open with batch oplock\n");
950 ZERO_STRUCT(break_info);
951 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
952 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
953 status = smb2_create(tree1, tctx, &(io.smb2));
954 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
955 h1 = io.smb2.out.file.handle;
956 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
958 torture_comment(tctx, "unlink should generate a break\n");
959 status = smb2_util_unlink(tree2, fname);
960 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
961 "Incorrect status");
963 torture_wait_for_oplock_break(tctx);
964 CHECK_VAL(break_info.count, 1);
965 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
966 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
967 CHECK_VAL(break_info.failures, 0);
969 torture_comment(tctx, "2nd unlink should not generate a break\n");
970 ZERO_STRUCT(break_info);
971 status = smb2_util_unlink(tree2, fname);
972 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
973 "Incorrect status");
975 torture_wait_for_oplock_break(tctx);
976 CHECK_VAL(break_info.count, 0);
978 torture_comment(tctx, "writing should generate a self break to none\n");
979 tree1->session->transport->oplock.handler =
980 torture_oplock_handler_level2_to_none;
981 smb2_util_write(tree1, h1, &c, 0, 1);
983 torture_wait_for_oplock_break(tctx);
985 CHECK_VAL(break_info.count, 1);
986 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
987 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
988 CHECK_VAL(break_info.failures, 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_batch2(struct torture_context *tctx,
998 struct smb2_tree *tree1,
999 struct smb2_tree *tree2)
1001 const char *fname = BASEDIR "\\test_batch2.dat";
1002 NTSTATUS status;
1003 bool ret = true;
1004 union smb_open io;
1005 char c = 0;
1006 struct smb2_handle h, h1;
1008 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1009 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1011 /* cleanup */
1012 smb2_util_unlink(tree1, fname);
1014 tree1->session->transport->oplock.handler = torture_oplock_handler;
1015 tree1->session->transport->oplock.private_data = tree1;
1018 base ntcreatex parms
1020 ZERO_STRUCT(io.smb2);
1021 io.generic.level = RAW_OPEN_SMB2;
1022 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1023 io.smb2.in.alloc_size = 0;
1024 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1025 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1026 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1027 io.smb2.in.create_options = 0;
1028 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1029 io.smb2.in.security_flags = 0;
1030 io.smb2.in.fname = fname;
1032 torture_comment(tctx, "BATCH2: open with batch oplock\n");
1033 ZERO_STRUCT(break_info);
1034 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1035 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1036 status = smb2_create(tree1, tctx, &(io.smb2));
1037 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1038 h1 = io.smb2.out.file.handle;
1039 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1041 torture_comment(tctx, "unlink should generate a break, which we ack "
1042 "as break to none\n");
1043 tree1->session->transport->oplock.handler =
1044 torture_oplock_handler_ack_to_none;
1045 tree1->session->transport->oplock.private_data = tree1;
1046 status = smb2_util_unlink(tree2, fname);
1047 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1048 "Incorrect status");
1050 torture_wait_for_oplock_break(tctx);
1051 CHECK_VAL(break_info.count, 1);
1052 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1053 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1054 CHECK_VAL(break_info.failures, 0);
1056 torture_comment(tctx, "2nd unlink should not generate a break\n");
1057 ZERO_STRUCT(break_info);
1058 status = smb2_util_unlink(tree2, fname);
1059 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1060 "Incorrect status");
1062 torture_wait_for_oplock_break(tctx);
1063 CHECK_VAL(break_info.count, 0);
1065 torture_comment(tctx, "writing should not generate a break\n");
1066 smb2_util_write(tree1, h1, &c, 0, 1);
1068 torture_wait_for_oplock_break(tctx);
1069 CHECK_VAL(break_info.count, 0);
1071 smb2_util_close(tree1, h1);
1072 smb2_util_close(tree1, h);
1074 smb2_deltree(tree1, BASEDIR);
1075 return ret;
1078 static bool test_smb2_oplock_batch3(struct torture_context *tctx,
1079 struct smb2_tree *tree1,
1080 struct smb2_tree *tree2)
1082 const char *fname = BASEDIR "\\test_batch3.dat";
1083 NTSTATUS status;
1084 bool ret = true;
1085 union smb_open io;
1086 struct smb2_handle h, h1;
1088 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1089 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1091 /* cleanup */
1092 smb2_util_unlink(tree1, fname);
1093 tree1->session->transport->oplock.handler = torture_oplock_handler;
1094 tree1->session->transport->oplock.private_data = tree1;
1097 base ntcreatex parms
1099 ZERO_STRUCT(io.smb2);
1100 io.generic.level = RAW_OPEN_SMB2;
1101 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1102 io.smb2.in.alloc_size = 0;
1103 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1104 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1105 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1106 io.smb2.in.create_options = 0;
1107 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1108 io.smb2.in.security_flags = 0;
1109 io.smb2.in.fname = fname;
1111 torture_comment(tctx, "BATCH3: if we close on break then the unlink "
1112 "can succeed\n");
1113 ZERO_STRUCT(break_info);
1114 tree1->session->transport->oplock.handler =
1115 torture_oplock_handler_close;
1116 tree1->session->transport->oplock.private_data = tree1;
1118 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1119 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1120 status = smb2_create(tree1, tctx, &(io.smb2));
1121 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1122 h1 = io.smb2.out.file.handle;
1123 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1125 ZERO_STRUCT(break_info);
1126 status = smb2_util_unlink(tree2, fname);
1127 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1129 torture_wait_for_oplock_break(tctx);
1130 CHECK_VAL(break_info.count, 1);
1131 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1132 CHECK_VAL(break_info.level, 1);
1133 CHECK_VAL(break_info.failures, 0);
1135 smb2_util_close(tree1, h1);
1136 smb2_util_close(tree1, h);
1138 smb2_deltree(tree1, BASEDIR);
1139 return ret;
1142 static bool test_smb2_oplock_batch4(struct torture_context *tctx,
1143 struct smb2_tree *tree1,
1144 struct smb2_tree *tree2)
1146 const char *fname = BASEDIR "\\test_batch4.dat";
1147 NTSTATUS status;
1148 bool ret = true;
1149 union smb_open io;
1150 struct smb2_read r;
1151 struct smb2_handle h, h1;
1153 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1154 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1156 /* cleanup */
1157 smb2_util_unlink(tree1, fname);
1159 tree1->session->transport->oplock.handler = torture_oplock_handler;
1160 tree1->session->transport->oplock.private_data = tree1;
1163 base ntcreatex parms
1165 ZERO_STRUCT(io.smb2);
1166 io.generic.level = RAW_OPEN_SMB2;
1167 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1168 io.smb2.in.alloc_size = 0;
1169 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1170 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1171 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1172 io.smb2.in.create_options = 0;
1173 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1174 io.smb2.in.security_flags = 0;
1175 io.smb2.in.fname = fname;
1177 torture_comment(tctx, "BATCH4: a self read should not cause a break\n");
1178 ZERO_STRUCT(break_info);
1180 tree1->session->transport->oplock.handler = torture_oplock_handler;
1181 tree1->session->transport->oplock.private_data = tree1;
1183 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1184 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1185 status = smb2_create(tree1, tctx, &(io.smb2));
1186 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1187 h1 = io.smb2.out.file.handle;
1188 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1190 ZERO_STRUCT(r);
1191 r.in.file.handle = h1;
1192 r.in.offset = 0;
1194 status = smb2_read(tree1, tree1, &r);
1195 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1196 torture_wait_for_oplock_break(tctx);
1197 CHECK_VAL(break_info.count, 0);
1198 CHECK_VAL(break_info.failures, 0);
1200 smb2_util_close(tree1, h1);
1201 smb2_util_close(tree1, h);
1203 smb2_deltree(tree1, BASEDIR);
1204 return ret;
1207 static bool test_smb2_oplock_batch5(struct torture_context *tctx,
1208 struct smb2_tree *tree1,
1209 struct smb2_tree *tree2)
1211 const char *fname = BASEDIR "\\test_batch5.dat";
1212 NTSTATUS status;
1213 bool ret = true;
1214 union smb_open io;
1215 struct smb2_handle h, h1;
1217 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1218 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1220 /* cleanup */
1221 smb2_util_unlink(tree1, fname);
1223 tree1->session->transport->oplock.handler = torture_oplock_handler;
1224 tree1->session->transport->oplock.private_data = tree1;
1227 base ntcreatex parms
1229 ZERO_STRUCT(io.smb2);
1230 io.generic.level = RAW_OPEN_SMB2;
1231 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1232 io.smb2.in.alloc_size = 0;
1233 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1234 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1235 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1236 io.smb2.in.create_options = 0;
1237 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1238 io.smb2.in.security_flags = 0;
1239 io.smb2.in.fname = fname;
1241 torture_comment(tctx, "BATCH5: a 2nd open should give a break\n");
1242 ZERO_STRUCT(break_info);
1244 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1245 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1246 status = smb2_create(tree1, tctx, &(io.smb2));
1247 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1248 h1 = io.smb2.out.file.handle;
1249 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1251 ZERO_STRUCT(break_info);
1253 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1254 status = smb2_create(tree2, tctx, &(io.smb2));
1255 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1256 "Incorrect status");
1258 torture_wait_for_oplock_break(tctx);
1259 CHECK_VAL(break_info.count, 1);
1260 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1261 CHECK_VAL(break_info.level, 1);
1262 CHECK_VAL(break_info.failures, 0);
1264 smb2_util_close(tree1, h1);
1265 smb2_util_close(tree1, h);
1267 smb2_deltree(tree1, BASEDIR);
1268 return ret;
1271 static bool test_smb2_oplock_batch6(struct torture_context *tctx,
1272 struct smb2_tree *tree1,
1273 struct smb2_tree *tree2)
1275 const char *fname = BASEDIR "\\test_batch6.dat";
1276 NTSTATUS status;
1277 bool ret = true;
1278 union smb_open io;
1279 struct smb2_handle h, h1, h2;
1280 char c = 0;
1282 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1283 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1285 /* cleanup */
1286 smb2_util_unlink(tree1, fname);
1288 tree1->session->transport->oplock.handler = torture_oplock_handler;
1289 tree1->session->transport->oplock.private_data = tree1;
1292 base ntcreatex parms
1294 ZERO_STRUCT(io.smb2);
1295 io.generic.level = RAW_OPEN_SMB2;
1296 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1297 io.smb2.in.alloc_size = 0;
1298 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1299 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1300 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1301 io.smb2.in.create_options = 0;
1302 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1303 io.smb2.in.security_flags = 0;
1304 io.smb2.in.fname = fname;
1306 torture_comment(tctx, "BATCH6: a 2nd open should give a break to "
1307 "level II if the first open allowed shared read\n");
1308 ZERO_STRUCT(break_info);
1309 tree2->session->transport->oplock.handler = torture_oplock_handler;
1310 tree2->session->transport->oplock.private_data = tree2;
1312 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
1313 SEC_RIGHTS_FILE_WRITE;
1314 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1315 NTCREATEX_SHARE_ACCESS_WRITE;
1316 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1317 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1318 status = smb2_create(tree1, tctx, &(io.smb2));
1319 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1320 h1 = io.smb2.out.file.handle;
1321 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1323 ZERO_STRUCT(break_info);
1325 status = smb2_create(tree2, tctx, &(io.smb2));
1326 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1327 h2 = io.smb2.out.file.handle;
1328 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1330 torture_wait_for_oplock_break(tctx);
1331 CHECK_VAL(break_info.count, 1);
1332 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1333 CHECK_VAL(break_info.level, 1);
1334 CHECK_VAL(break_info.failures, 0);
1335 ZERO_STRUCT(break_info);
1337 torture_comment(tctx, "write should trigger a break to none on both\n");
1338 tree1->session->transport->oplock.handler =
1339 torture_oplock_handler_level2_to_none;
1340 tree2->session->transport->oplock.handler =
1341 torture_oplock_handler_level2_to_none;
1342 smb2_util_write(tree1, h1, &c, 0, 1);
1344 /* We expect two breaks */
1345 torture_wait_for_oplock_break(tctx);
1346 torture_wait_for_oplock_break(tctx);
1348 CHECK_VAL(break_info.count, 2);
1349 CHECK_VAL(break_info.level, 0);
1350 CHECK_VAL(break_info.failures, 0);
1352 smb2_util_close(tree1, h1);
1353 smb2_util_close(tree2, h2);
1354 smb2_util_close(tree1, h);
1356 smb2_deltree(tree1, BASEDIR);
1357 return ret;
1360 static bool test_smb2_oplock_batch7(struct torture_context *tctx,
1361 struct smb2_tree *tree1,
1362 struct smb2_tree *tree2)
1364 const char *fname = BASEDIR "\\test_batch7.dat";
1365 NTSTATUS status;
1366 bool ret = true;
1367 union smb_open io;
1368 struct smb2_handle h, h1, h2;
1370 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1371 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1373 /* cleanup */
1374 smb2_util_unlink(tree1, fname);
1376 tree1->session->transport->oplock.handler = torture_oplock_handler;
1377 tree1->session->transport->oplock.private_data = tree1;
1380 base ntcreatex parms
1382 ZERO_STRUCT(io.smb2);
1383 io.generic.level = RAW_OPEN_SMB2;
1384 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1385 io.smb2.in.alloc_size = 0;
1386 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1387 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1388 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1389 io.smb2.in.create_options = 0;
1390 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1391 io.smb2.in.security_flags = 0;
1392 io.smb2.in.fname = fname;
1394 torture_comment(tctx, "BATCH7: a 2nd open should get an oplock when "
1395 "we close instead of ack\n");
1396 ZERO_STRUCT(break_info);
1397 tree1->session->transport->oplock.handler =
1398 torture_oplock_handler_close;
1399 tree1->session->transport->oplock.private_data = tree1;
1401 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1402 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1403 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1404 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1405 status = smb2_create(tree1, tctx, &(io.smb2));
1406 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1407 h2 = io.smb2.out.file.handle;
1408 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1410 ZERO_STRUCT(break_info);
1412 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1413 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1414 status = smb2_create(tree2, tctx, &(io.smb2));
1415 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1416 h1 = io.smb2.out.file.handle;
1417 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1419 torture_wait_for_oplock_break(tctx);
1420 CHECK_VAL(break_info.count, 1);
1421 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1422 CHECK_VAL(break_info.level, 1);
1423 CHECK_VAL(break_info.failures, 0);
1425 smb2_util_close(tree2, h1);
1426 smb2_util_close(tree2, h);
1428 smb2_deltree(tree1, BASEDIR);
1429 return ret;
1432 static bool test_smb2_oplock_batch8(struct torture_context *tctx,
1433 struct smb2_tree *tree1,
1434 struct smb2_tree *tree2)
1436 const char *fname = BASEDIR "\\test_batch8.dat";
1437 NTSTATUS status;
1438 bool ret = true;
1439 union smb_open io;
1440 struct smb2_handle h, h1, h2;
1442 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1443 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1445 /* cleanup */
1446 smb2_util_unlink(tree1, fname);
1448 tree1->session->transport->oplock.handler = torture_oplock_handler;
1449 tree1->session->transport->oplock.private_data = tree1;
1452 base ntcreatex parms
1454 ZERO_STRUCT(io.smb2);
1455 io.generic.level = RAW_OPEN_SMB2;
1456 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1457 io.smb2.in.alloc_size = 0;
1458 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1459 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1460 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1461 io.smb2.in.create_options = 0;
1462 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1463 io.smb2.in.security_flags = 0;
1464 io.smb2.in.fname = fname;
1466 torture_comment(tctx, "BATCH8: open with batch oplock\n");
1467 ZERO_STRUCT(break_info);
1469 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1470 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1471 status = smb2_create(tree1, tctx, &(io.smb2));
1472 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1473 h1 = io.smb2.out.file.handle;
1474 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1476 ZERO_STRUCT(break_info);
1477 torture_comment(tctx, "second open with attributes only shouldn't "
1478 "cause oplock break\n");
1480 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1481 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1482 SEC_FILE_WRITE_ATTRIBUTE |
1483 SEC_STD_SYNCHRONIZE;
1484 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1485 status = smb2_create(tree2, tctx, &(io.smb2));
1486 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1487 h2 = io.smb2.out.file.handle;
1488 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1489 torture_wait_for_oplock_break(tctx);
1490 CHECK_VAL(break_info.count, 0);
1491 CHECK_VAL(break_info.failures, 0);
1493 smb2_util_close(tree1, h1);
1494 smb2_util_close(tree2, h2);
1495 smb2_util_close(tree1, h);
1497 smb2_deltree(tree1, BASEDIR);
1498 return ret;
1501 static bool test_smb2_oplock_batch9(struct torture_context *tctx,
1502 struct smb2_tree *tree1,
1503 struct smb2_tree *tree2)
1505 const char *fname = BASEDIR "\\test_batch9.dat";
1506 NTSTATUS status;
1507 bool ret = true;
1508 union smb_open io;
1509 struct smb2_handle h, h1, h2;
1510 char c = 0;
1512 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1513 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1515 /* cleanup */
1516 smb2_util_unlink(tree1, fname);
1518 tree1->session->transport->oplock.handler = torture_oplock_handler;
1519 tree1->session->transport->oplock.private_data = tree1;
1522 base ntcreatex parms
1524 ZERO_STRUCT(io.smb2);
1525 io.generic.level = RAW_OPEN_SMB2;
1526 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1527 io.smb2.in.alloc_size = 0;
1528 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1529 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1530 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1531 io.smb2.in.create_options = 0;
1532 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1533 io.smb2.in.security_flags = 0;
1534 io.smb2.in.fname = fname;
1536 torture_comment(tctx, "BATCH9: open with attributes only can create "
1537 "file\n");
1539 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1540 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1541 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1542 SEC_FILE_WRITE_ATTRIBUTE |
1543 SEC_STD_SYNCHRONIZE;
1544 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1545 status = smb2_create(tree1, tctx, &(io.smb2));
1546 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1547 h1 = io.smb2.out.file.handle;
1548 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1550 torture_comment(tctx, "Subsequent normal open should break oplock on "
1551 "attribute only open to level II\n");
1553 ZERO_STRUCT(break_info);
1555 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1556 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1557 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1558 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1559 status = smb2_create(tree2, tctx, &(io.smb2));
1560 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1561 h2 = io.smb2.out.file.handle;
1562 torture_wait_for_oplock_break(tctx);
1563 CHECK_VAL(break_info.count, 1);
1564 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1565 CHECK_VAL(break_info.failures, 0);
1566 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1567 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1568 smb2_util_close(tree2, h2);
1570 torture_comment(tctx, "third oplocked open should grant level2 without "
1571 "break\n");
1572 ZERO_STRUCT(break_info);
1574 tree2->session->transport->oplock.handler = torture_oplock_handler;
1575 tree2->session->transport->oplock.private_data = tree2;
1577 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1578 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1579 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1580 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1581 status = smb2_create(tree2, tctx, &(io.smb2));
1582 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1583 h2 = io.smb2.out.file.handle;
1584 torture_wait_for_oplock_break(tctx);
1585 CHECK_VAL(break_info.count, 0);
1586 CHECK_VAL(break_info.failures, 0);
1587 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1589 ZERO_STRUCT(break_info);
1591 torture_comment(tctx, "write should trigger a break to none on both\n");
1592 tree1->session->transport->oplock.handler =
1593 torture_oplock_handler_level2_to_none;
1594 tree2->session->transport->oplock.handler =
1595 torture_oplock_handler_level2_to_none;
1596 smb2_util_write(tree2, h2, &c, 0, 1);
1598 /* We expect two breaks */
1599 torture_wait_for_oplock_break(tctx);
1600 torture_wait_for_oplock_break(tctx);
1602 CHECK_VAL(break_info.count, 2);
1603 CHECK_VAL(break_info.level, 0);
1604 CHECK_VAL(break_info.failures, 0);
1606 smb2_util_close(tree1, h1);
1607 smb2_util_close(tree2, h2);
1608 smb2_util_close(tree1, h);
1610 smb2_deltree(tree1, BASEDIR);
1611 return ret;
1614 static bool test_smb2_oplock_batch9a(struct torture_context *tctx,
1615 struct smb2_tree *tree1,
1616 struct smb2_tree *tree2)
1618 const char *fname = BASEDIR "\\test_batch9a.dat";
1619 NTSTATUS status;
1620 bool ret = true;
1621 union smb_open io;
1622 struct smb2_handle h, h1, h2, h3;
1623 char c = 0;
1625 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1626 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1628 /* cleanup */
1629 smb2_util_unlink(tree1, fname);
1631 tree1->session->transport->oplock.handler = torture_oplock_handler;
1632 tree1->session->transport->oplock.private_data = tree1;
1635 base ntcreatex parms
1637 ZERO_STRUCT(io.smb2);
1638 io.generic.level = RAW_OPEN_SMB2;
1639 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1640 io.smb2.in.alloc_size = 0;
1641 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1642 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1643 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1644 io.smb2.in.create_options = 0;
1645 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1646 io.smb2.in.security_flags = 0;
1647 io.smb2.in.fname = fname;
1649 torture_comment(tctx, "BATCH9: open with attributes only can create "
1650 "file\n");
1652 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1653 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1654 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1655 SEC_FILE_WRITE_ATTRIBUTE |
1656 SEC_STD_SYNCHRONIZE;
1657 status = smb2_create(tree1, tctx, &(io.smb2));
1658 torture_assert_ntstatus_ok(tctx, status, "Error creating the file");
1659 h1 = io.smb2.out.file.handle;
1660 CHECK_VAL(io.smb2.out.create_action, FILE_WAS_CREATED);
1661 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1663 torture_comment(tctx, "Subsequent attributes open should not break\n");
1665 ZERO_STRUCT(break_info);
1667 status = smb2_create(tree2, tctx, &(io.smb2));
1668 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1669 h3 = io.smb2.out.file.handle;
1670 torture_wait_for_oplock_break(tctx);
1671 CHECK_VAL(break_info.count, 0);
1672 CHECK_VAL(io.smb2.out.create_action, FILE_WAS_OPENED);
1673 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1674 smb2_util_close(tree2, h3);
1676 torture_comment(tctx, "Subsequent normal open should break oplock on "
1677 "attribute only open to level II\n");
1679 ZERO_STRUCT(break_info);
1681 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1682 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1683 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1684 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1685 status = smb2_create(tree2, tctx, &(io.smb2));
1686 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1687 h2 = io.smb2.out.file.handle;
1688 torture_wait_for_oplock_break(tctx);
1689 CHECK_VAL(break_info.count, 1);
1690 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1691 CHECK_VAL(break_info.failures, 0);
1692 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1693 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1694 smb2_util_close(tree2, h2);
1696 torture_comment(tctx, "third oplocked open should grant level2 without "
1697 "break\n");
1698 ZERO_STRUCT(break_info);
1700 tree2->session->transport->oplock.handler = torture_oplock_handler;
1701 tree2->session->transport->oplock.private_data = tree2;
1703 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1704 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1705 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1706 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1707 status = smb2_create(tree2, tctx, &(io.smb2));
1708 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1709 h2 = io.smb2.out.file.handle;
1710 torture_wait_for_oplock_break(tctx);
1711 CHECK_VAL(break_info.count, 0);
1712 CHECK_VAL(break_info.failures, 0);
1713 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1715 ZERO_STRUCT(break_info);
1717 torture_comment(tctx, "write should trigger a break to none on both\n");
1718 tree1->session->transport->oplock.handler =
1719 torture_oplock_handler_level2_to_none;
1720 tree2->session->transport->oplock.handler =
1721 torture_oplock_handler_level2_to_none;
1722 smb2_util_write(tree2, h2, &c, 0, 1);
1724 /* We expect two breaks */
1725 torture_wait_for_oplock_break(tctx);
1726 torture_wait_for_oplock_break(tctx);
1728 CHECK_VAL(break_info.count, 2);
1729 CHECK_VAL(break_info.level, 0);
1730 CHECK_VAL(break_info.failures, 0);
1732 smb2_util_close(tree1, h1);
1733 smb2_util_close(tree2, h2);
1734 smb2_util_close(tree1, h);
1736 smb2_deltree(tree1, BASEDIR);
1737 return ret;
1741 static bool test_smb2_oplock_batch10(struct torture_context *tctx,
1742 struct smb2_tree *tree1,
1743 struct smb2_tree *tree2)
1745 const char *fname = BASEDIR "\\test_batch10.dat";
1746 NTSTATUS status;
1747 bool ret = true;
1748 union smb_open io;
1749 struct smb2_handle h, h1, h2;
1751 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1752 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1754 /* cleanup */
1755 smb2_util_unlink(tree1, fname);
1757 tree1->session->transport->oplock.handler = torture_oplock_handler;
1758 tree1->session->transport->oplock.private_data = tree1;
1761 base ntcreatex parms
1763 ZERO_STRUCT(io.smb2);
1764 io.generic.level = RAW_OPEN_SMB2;
1765 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1766 io.smb2.in.alloc_size = 0;
1767 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1768 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1769 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1770 io.smb2.in.create_options = 0;
1771 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1772 io.smb2.in.security_flags = 0;
1773 io.smb2.in.fname = fname;
1775 torture_comment(tctx, "BATCH10: Open with oplock after a non-oplock "
1776 "open should grant level2\n");
1777 ZERO_STRUCT(break_info);
1778 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1779 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1780 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1781 NTCREATEX_SHARE_ACCESS_WRITE|
1782 NTCREATEX_SHARE_ACCESS_DELETE;
1783 status = smb2_create(tree1, tctx, &(io.smb2));
1784 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1785 h1 = io.smb2.out.file.handle;
1786 torture_wait_for_oplock_break(tctx);
1787 CHECK_VAL(break_info.count, 0);
1788 CHECK_VAL(break_info.failures, 0);
1789 CHECK_VAL(io.smb2.out.oplock_level, 0);
1791 tree2->session->transport->oplock.handler =
1792 torture_oplock_handler_level2_to_none;
1793 tree2->session->transport->oplock.private_data = tree2;
1795 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1796 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1797 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1798 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1799 NTCREATEX_SHARE_ACCESS_WRITE|
1800 NTCREATEX_SHARE_ACCESS_DELETE;
1801 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1802 status = smb2_create(tree2, tctx, &(io.smb2));
1803 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1804 h2 = io.smb2.out.file.handle;
1805 torture_wait_for_oplock_break(tctx);
1806 CHECK_VAL(break_info.count, 0);
1807 CHECK_VAL(break_info.failures, 0);
1808 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1810 torture_comment(tctx, "write should trigger a break to none\n");
1812 struct smb2_write wr;
1813 DATA_BLOB data;
1814 data = data_blob_talloc(tree1, NULL, UINT16_MAX);
1815 data.data[0] = (const uint8_t)'x';
1816 ZERO_STRUCT(wr);
1817 wr.in.file.handle = h1;
1818 wr.in.offset = 0;
1819 wr.in.data = data;
1820 status = smb2_write(tree1, &wr);
1821 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1824 torture_wait_for_oplock_break(tctx);
1826 CHECK_VAL(break_info.count, 1);
1827 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1828 CHECK_VAL(break_info.level, 0);
1829 CHECK_VAL(break_info.failures, 0);
1831 smb2_util_close(tree1, h1);
1832 smb2_util_close(tree2, h2);
1833 smb2_util_close(tree1, h);
1835 smb2_deltree(tree1, BASEDIR);
1836 return ret;
1839 static bool test_smb2_oplock_batch11(struct torture_context *tctx,
1840 struct smb2_tree *tree1,
1841 struct smb2_tree *tree2)
1843 const char *fname = BASEDIR "\\test_batch11.dat";
1844 NTSTATUS status;
1845 bool ret = true;
1846 union smb_open io;
1847 union smb_setfileinfo sfi;
1848 struct smb2_handle h, h1;
1850 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1851 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1853 /* cleanup */
1854 smb2_util_unlink(tree1, fname);
1856 tree1->session->transport->oplock.handler =
1857 torture_oplock_handler_two_notifications;
1858 tree1->session->transport->oplock.private_data = tree1;
1861 base ntcreatex parms
1863 ZERO_STRUCT(io.smb2);
1864 io.generic.level = RAW_OPEN_SMB2;
1865 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1866 io.smb2.in.alloc_size = 0;
1867 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1868 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1869 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1870 io.smb2.in.create_options = 0;
1871 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1872 io.smb2.in.security_flags = 0;
1873 io.smb2.in.fname = fname;
1875 /* Test if a set-eof on pathname breaks an exclusive oplock. */
1876 torture_comment(tctx, "BATCH11: Test if setpathinfo set EOF breaks "
1877 "oplocks.\n");
1879 ZERO_STRUCT(break_info);
1881 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1882 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1883 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1884 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1885 NTCREATEX_SHARE_ACCESS_WRITE|
1886 NTCREATEX_SHARE_ACCESS_DELETE;
1887 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1888 status = smb2_create(tree1, tctx, &(io.smb2));
1889 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1890 h1 = io.smb2.out.file.handle;
1891 torture_wait_for_oplock_break(tctx);
1892 CHECK_VAL(break_info.count, 0);
1893 CHECK_VAL(break_info.failures, 0);
1894 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1896 ZERO_STRUCT(sfi);
1897 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1898 sfi.generic.in.file.path = fname;
1899 sfi.end_of_file_info.in.size = 100;
1901 status = smb2_composite_setpathinfo(tree2, &sfi);
1902 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1904 /* We expect two breaks */
1905 torture_wait_for_oplock_break(tctx);
1906 torture_wait_for_oplock_break(tctx);
1908 CHECK_VAL(break_info.count, 2);
1909 CHECK_VAL(break_info.failures, 0);
1910 CHECK_VAL(break_info.level, 0);
1912 smb2_util_close(tree1, h1);
1913 smb2_util_close(tree1, h);
1915 smb2_deltree(tree1, BASEDIR);
1916 return ret;
1919 static bool test_smb2_oplock_batch12(struct torture_context *tctx,
1920 struct smb2_tree *tree1,
1921 struct smb2_tree *tree2)
1923 const char *fname = BASEDIR "\\test_batch12.dat";
1924 NTSTATUS status;
1925 bool ret = true;
1926 union smb_open io;
1927 union smb_setfileinfo sfi;
1928 struct smb2_handle h, h1;
1930 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1931 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1933 /* cleanup */
1934 smb2_util_unlink(tree1, fname);
1936 tree1->session->transport->oplock.handler =
1937 torture_oplock_handler_two_notifications;
1938 tree1->session->transport->oplock.private_data = tree1;
1941 base ntcreatex parms
1943 ZERO_STRUCT(io.smb2);
1944 io.generic.level = RAW_OPEN_SMB2;
1945 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1946 io.smb2.in.alloc_size = 0;
1947 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1948 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1949 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1950 io.smb2.in.create_options = 0;
1951 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1952 io.smb2.in.security_flags = 0;
1953 io.smb2.in.fname = fname;
1955 /* Test if a set-allocation size on pathname breaks an exclusive
1956 * oplock. */
1957 torture_comment(tctx, "BATCH12: Test if setpathinfo allocation size "
1958 "breaks oplocks.\n");
1960 ZERO_STRUCT(break_info);
1962 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1963 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1964 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1965 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1966 NTCREATEX_SHARE_ACCESS_WRITE|
1967 NTCREATEX_SHARE_ACCESS_DELETE;
1968 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1969 status = smb2_create(tree1, tctx, &(io.smb2));
1970 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1971 h1 = io.smb2.out.file.handle;
1972 torture_wait_for_oplock_break(tctx);
1973 CHECK_VAL(break_info.count, 0);
1974 CHECK_VAL(break_info.failures, 0);
1975 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1977 ZERO_STRUCT(sfi);
1978 sfi.generic.level = RAW_SFILEINFO_ALLOCATION_INFORMATION;
1979 sfi.generic.in.file.path = fname;
1980 sfi.allocation_info.in.alloc_size = 65536 * 8;
1982 status = smb2_composite_setpathinfo(tree2, &sfi);
1983 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1985 /* We expect two breaks */
1986 torture_wait_for_oplock_break(tctx);
1987 torture_wait_for_oplock_break(tctx);
1989 CHECK_VAL(break_info.count, 2);
1990 CHECK_VAL(break_info.failures, 0);
1991 CHECK_VAL(break_info.level, 0);
1993 smb2_util_close(tree1, h1);
1994 smb2_util_close(tree1, h);
1996 smb2_deltree(tree1, BASEDIR);
1997 return ret;
2000 static bool test_smb2_oplock_batch13(struct torture_context *tctx,
2001 struct smb2_tree *tree1,
2002 struct smb2_tree *tree2)
2004 const char *fname = BASEDIR "\\test_batch13.dat";
2005 NTSTATUS status;
2006 bool ret = true;
2007 union smb_open io;
2008 struct smb2_handle h, h1, h2;
2010 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2011 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2013 /* cleanup */
2014 smb2_util_unlink(tree1, fname);
2016 tree1->session->transport->oplock.handler = torture_oplock_handler;
2017 tree1->session->transport->oplock.private_data = tree1;
2019 tree2->session->transport->oplock.handler = torture_oplock_handler;
2020 tree2->session->transport->oplock.private_data = tree2;
2023 base ntcreatex parms
2025 ZERO_STRUCT(io.smb2);
2026 io.generic.level = RAW_OPEN_SMB2;
2027 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2028 io.smb2.in.alloc_size = 0;
2029 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2030 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2031 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2032 io.smb2.in.create_options = 0;
2033 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2034 io.smb2.in.security_flags = 0;
2035 io.smb2.in.fname = fname;
2037 torture_comment(tctx, "BATCH13: open with batch oplock\n");
2038 ZERO_STRUCT(break_info);
2040 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2041 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2042 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2043 NTCREATEX_SHARE_ACCESS_WRITE|
2044 NTCREATEX_SHARE_ACCESS_DELETE;
2045 status = smb2_create(tree1, tctx, &(io.smb2));
2046 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2047 h1 = io.smb2.out.file.handle;
2048 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2050 ZERO_STRUCT(break_info);
2052 torture_comment(tctx, "second open with attributes only and "
2053 "NTCREATEX_DISP_OVERWRITE dispostion causes "
2054 "oplock break\n");
2056 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2057 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2058 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2059 SEC_FILE_WRITE_ATTRIBUTE |
2060 SEC_STD_SYNCHRONIZE;
2061 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2062 NTCREATEX_SHARE_ACCESS_WRITE|
2063 NTCREATEX_SHARE_ACCESS_DELETE;
2064 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2065 status = smb2_create(tree2, tctx, &(io.smb2));
2066 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2067 h2 = io.smb2.out.file.handle;
2068 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2069 torture_wait_for_oplock_break(tctx);
2070 CHECK_VAL(break_info.count, 1);
2071 CHECK_VAL(break_info.failures, 0);
2073 smb2_util_close(tree1, h1);
2074 smb2_util_close(tree2, h2);
2075 smb2_util_close(tree1, h);
2077 smb2_deltree(tree1, BASEDIR);
2079 return ret;
2082 static bool test_smb2_oplock_batch14(struct torture_context *tctx,
2083 struct smb2_tree *tree1,
2084 struct smb2_tree *tree2)
2086 const char *fname = BASEDIR "\\test_batch14.dat";
2087 NTSTATUS status;
2088 bool ret = true;
2089 union smb_open io;
2090 struct smb2_handle h, h1, h2;
2092 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2093 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2095 /* cleanup */
2096 smb2_util_unlink(tree1, fname);
2098 tree1->session->transport->oplock.handler = torture_oplock_handler;
2099 tree1->session->transport->oplock.private_data = tree1;
2102 base ntcreatex parms
2104 ZERO_STRUCT(io.smb2);
2105 io.generic.level = RAW_OPEN_SMB2;
2106 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2107 io.smb2.in.alloc_size = 0;
2108 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2109 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2110 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2111 io.smb2.in.create_options = 0;
2112 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2113 io.smb2.in.security_flags = 0;
2114 io.smb2.in.fname = fname;
2116 torture_comment(tctx, "BATCH14: open with batch oplock\n");
2117 ZERO_STRUCT(break_info);
2119 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2120 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2121 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2122 NTCREATEX_SHARE_ACCESS_WRITE|
2123 NTCREATEX_SHARE_ACCESS_DELETE;
2124 status = smb2_create(tree1, tctx, &(io.smb2));
2125 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2126 h1 = io.smb2.out.file.handle;
2127 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2129 ZERO_STRUCT(break_info);
2131 torture_comment(tctx, "second open with attributes only and "
2132 "NTCREATEX_DISP_SUPERSEDE dispostion causes "
2133 "oplock break\n");
2135 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2136 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2137 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2138 SEC_FILE_WRITE_ATTRIBUTE |
2139 SEC_STD_SYNCHRONIZE;
2140 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2141 NTCREATEX_SHARE_ACCESS_WRITE|
2142 NTCREATEX_SHARE_ACCESS_DELETE;
2143 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2144 status = smb2_create(tree2, tctx, &(io.smb2));
2145 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2146 h2 = io.smb2.out.file.handle;
2147 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2149 torture_wait_for_oplock_break(tctx);
2150 CHECK_VAL(break_info.count, 1);
2151 CHECK_VAL(break_info.failures, 0);
2153 smb2_util_close(tree1, h1);
2154 smb2_util_close(tree2, h2);
2155 smb2_util_close(tree1, h);
2157 smb2_deltree(tree1, BASEDIR);
2158 return ret;
2161 static bool test_smb2_oplock_batch15(struct torture_context *tctx,
2162 struct smb2_tree *tree1,
2163 struct smb2_tree *tree2)
2165 const char *fname = BASEDIR "\\test_batch15.dat";
2166 NTSTATUS status;
2167 bool ret = true;
2168 union smb_open io;
2169 union smb_fileinfo qfi;
2170 struct smb2_handle h, h1;
2172 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2173 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2175 /* cleanup */
2176 smb2_util_unlink(tree1, fname);
2178 tree1->session->transport->oplock.handler = torture_oplock_handler;
2179 tree1->session->transport->oplock.private_data = tree1;
2182 base ntcreatex parms
2184 ZERO_STRUCT(io.smb2);
2185 io.generic.level = RAW_OPEN_SMB2;
2186 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2187 io.smb2.in.alloc_size = 0;
2188 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2189 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2190 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2191 io.smb2.in.create_options = 0;
2192 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2193 io.smb2.in.security_flags = 0;
2194 io.smb2.in.fname = fname;
2196 /* Test if a qpathinfo all info on pathname breaks a batch oplock. */
2197 torture_comment(tctx, "BATCH15: Test if qpathinfo all info breaks "
2198 "a batch oplock (should not).\n");
2200 ZERO_STRUCT(break_info);
2202 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2203 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2204 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2205 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2206 NTCREATEX_SHARE_ACCESS_WRITE|
2207 NTCREATEX_SHARE_ACCESS_DELETE;
2208 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2209 status = smb2_create(tree1, tctx, &(io.smb2));
2210 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2211 h1 = io.smb2.out.file.handle;
2213 torture_wait_for_oplock_break(tctx);
2214 CHECK_VAL(break_info.count, 0);
2215 CHECK_VAL(break_info.failures, 0);
2216 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2218 ZERO_STRUCT(qfi);
2219 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2220 qfi.generic.in.file.handle = h1;
2221 status = smb2_getinfo_file(tree2, tctx, &qfi);
2223 torture_wait_for_oplock_break(tctx);
2224 CHECK_VAL(break_info.count, 0);
2226 smb2_util_close(tree1, h1);
2227 smb2_util_close(tree1, h);
2229 smb2_deltree(tree1, BASEDIR);
2230 return ret;
2233 static bool test_smb2_oplock_batch16(struct torture_context *tctx,
2234 struct smb2_tree *tree1,
2235 struct smb2_tree *tree2)
2237 const char *fname = BASEDIR "\\test_batch16.dat";
2238 NTSTATUS status;
2239 bool ret = true;
2240 union smb_open io;
2241 struct smb2_handle h, h1, h2;
2243 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2244 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2246 /* cleanup */
2247 smb2_util_unlink(tree1, fname);
2249 tree1->session->transport->oplock.handler = torture_oplock_handler;
2250 tree1->session->transport->oplock.private_data = tree1;
2252 tree2->session->transport->oplock.handler = torture_oplock_handler;
2253 tree2->session->transport->oplock.private_data = tree2;
2256 base ntcreatex parms
2258 ZERO_STRUCT(io.smb2);
2259 io.generic.level = RAW_OPEN_SMB2;
2260 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2261 io.smb2.in.alloc_size = 0;
2262 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2263 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2264 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2265 io.smb2.in.create_options = 0;
2266 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2267 io.smb2.in.security_flags = 0;
2268 io.smb2.in.fname = fname;
2270 torture_comment(tctx, "BATCH16: open with batch oplock\n");
2271 ZERO_STRUCT(break_info);
2273 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2274 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2275 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2276 NTCREATEX_SHARE_ACCESS_WRITE|
2277 NTCREATEX_SHARE_ACCESS_DELETE;
2278 status = smb2_create(tree1, tctx, &(io.smb2));
2279 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2280 h1 = io.smb2.out.file.handle;
2281 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2283 ZERO_STRUCT(break_info);
2285 torture_comment(tctx, "second open with attributes only and "
2286 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
2287 "oplock break\n");
2289 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2290 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2291 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2292 SEC_FILE_WRITE_ATTRIBUTE |
2293 SEC_STD_SYNCHRONIZE;
2294 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2295 NTCREATEX_SHARE_ACCESS_WRITE|
2296 NTCREATEX_SHARE_ACCESS_DELETE;
2297 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
2298 status = smb2_create(tree2, tctx, &(io.smb2));
2299 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2300 h2 = io.smb2.out.file.handle;
2301 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2303 torture_wait_for_oplock_break(tctx);
2304 CHECK_VAL(break_info.count, 1);
2305 CHECK_VAL(break_info.failures, 0);
2307 smb2_util_close(tree1, h1);
2308 smb2_util_close(tree2, h2);
2309 smb2_util_close(tree1, h);
2311 smb2_deltree(tree1, BASEDIR);
2312 return ret;
2315 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH17 test. Since
2316 * SMB2 doesn't have a RENAME command this test isn't applicable. However,
2317 * it's much less confusing, when comparing test, to keep the SMB1 and SMB2
2318 * test numbers in sync. */
2319 #if 0
2320 static bool test_raw_oplock_batch17(struct torture_context *tctx,
2321 struct smb2_tree *tree1,
2322 struct smb2_tree *tree2)
2324 return true;
2326 #endif
2328 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH18 test. Since
2329 * SMB2 doesn't have an NTRENAME command this test isn't applicable. However,
2330 * it's much less confusing, when comparing tests, to keep the SMB1 and SMB2
2331 * test numbers in sync. */
2332 #if 0
2333 static bool test_raw_oplock_batch18(struct torture_context *tctx,
2334 struct smb2_tree *tree1,
2335 struct smb2_tree *tree2)
2337 return true;
2339 #endif
2341 static bool test_smb2_oplock_batch19(struct torture_context *tctx,
2342 struct smb2_tree *tree1)
2344 const char *fname1 = BASEDIR "\\test_batch19_1.dat";
2345 const char *fname2 = BASEDIR "\\test_batch19_2.dat";
2346 NTSTATUS status;
2347 bool ret = true;
2348 union smb_open io;
2349 union smb_fileinfo qfi;
2350 union smb_setfileinfo sfi;
2351 struct smb2_handle h, h1;
2353 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2354 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2356 /* cleanup */
2357 smb2_util_unlink(tree1, fname1);
2358 smb2_util_unlink(tree1, fname2);
2360 tree1->session->transport->oplock.handler = torture_oplock_handler;
2361 tree1->session->transport->oplock.private_data = tree1;
2364 base ntcreatex parms
2366 ZERO_STRUCT(io.smb2);
2367 io.generic.level = RAW_OPEN_SMB2;
2368 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2369 io.smb2.in.alloc_size = 0;
2370 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2371 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2372 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2373 io.smb2.in.create_options = 0;
2374 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2375 io.smb2.in.security_flags = 0;
2376 io.smb2.in.fname = fname1;
2378 torture_comment(tctx, "BATCH19: open a file with an batch oplock "
2379 "(share mode: none)\n");
2380 ZERO_STRUCT(break_info);
2381 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2382 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2383 status = smb2_create(tree1, tctx, &(io.smb2));
2384 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2385 h1 = io.smb2.out.file.handle;
2386 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2388 torture_comment(tctx, "setfileinfo rename info should not trigger "
2389 "a break but should cause a sharing violation\n");
2390 ZERO_STRUCT(sfi);
2391 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2392 sfi.generic.in.file.path = fname1;
2393 sfi.rename_information.in.file.handle = h1;
2394 sfi.rename_information.in.overwrite = 0;
2395 sfi.rename_information.in.root_fid = 0;
2396 sfi.rename_information.in.new_name = fname2;
2398 status = smb2_setinfo_file(tree1, &sfi);
2400 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2401 "Incorrect status");
2403 torture_wait_for_oplock_break(tctx);
2404 CHECK_VAL(break_info.count, 0);
2406 ZERO_STRUCT(qfi);
2407 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2408 qfi.generic.in.file.handle = h1;
2410 status = smb2_getinfo_file(tree1, tctx, &qfi);
2411 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2412 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2414 smb2_util_close(tree1, h1);
2415 smb2_util_close(tree1, h);
2417 smb2_deltree(tree1, fname1);
2418 smb2_deltree(tree1, fname2);
2419 return ret;
2422 static bool test_smb2_oplock_batch20(struct torture_context *tctx,
2423 struct smb2_tree *tree1,
2424 struct smb2_tree *tree2)
2426 const char *fname1 = BASEDIR "\\test_batch20_1.dat";
2427 const char *fname2 = BASEDIR "\\test_batch20_2.dat";
2428 NTSTATUS status;
2429 bool ret = true;
2430 union smb_open io;
2431 union smb_fileinfo qfi;
2432 union smb_setfileinfo sfi;
2433 struct smb2_handle h, h1, h2;
2435 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2436 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2438 /* cleanup */
2439 smb2_util_unlink(tree1, fname1);
2440 smb2_util_unlink(tree1, fname2);
2442 tree1->session->transport->oplock.handler = torture_oplock_handler;
2443 tree1->session->transport->oplock.private_data = tree1;
2446 base ntcreatex parms
2448 ZERO_STRUCT(io.smb2);
2449 io.generic.level = RAW_OPEN_SMB2;
2450 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2451 io.smb2.in.alloc_size = 0;
2452 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2453 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2454 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2455 io.smb2.in.create_options = 0;
2456 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2457 io.smb2.in.security_flags = 0;
2458 io.smb2.in.fname = fname1;
2460 torture_comment(tctx, "BATCH20: open a file with an batch oplock "
2461 "(share mode: all)\n");
2462 ZERO_STRUCT(break_info);
2463 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2464 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2465 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2466 NTCREATEX_SHARE_ACCESS_WRITE|
2467 NTCREATEX_SHARE_ACCESS_DELETE;
2468 status = smb2_create(tree1, tctx, &(io.smb2));
2469 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2470 h1 = io.smb2.out.file.handle;
2471 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2473 torture_comment(tctx, "setfileinfo rename info should not trigger "
2474 "a break but should cause a sharing violation\n");
2475 ZERO_STRUCT(sfi);
2476 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2477 sfi.rename_information.in.file.handle = h1;
2478 sfi.rename_information.in.overwrite = 0;
2479 sfi.rename_information.in.new_name = fname2;
2481 status = smb2_setinfo_file(tree1, &sfi);
2482 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2483 "Incorrect status");
2485 torture_wait_for_oplock_break(tctx);
2486 CHECK_VAL(break_info.count, 0);
2488 ZERO_STRUCT(qfi);
2489 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2490 qfi.generic.in.file.handle = h1;
2492 status = smb2_getinfo_file(tree1, tctx, &qfi);
2493 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2494 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2496 torture_comment(tctx, "open the file a second time requesting batch "
2497 "(share mode: all)\n");
2498 ZERO_STRUCT(break_info);
2499 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2500 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2501 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2502 NTCREATEX_SHARE_ACCESS_WRITE|
2503 NTCREATEX_SHARE_ACCESS_DELETE;
2504 io.smb2.in.fname = fname1;
2505 status = smb2_create(tree2, tctx, &(io.smb2));
2506 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2507 h2 = io.smb2.out.file.handle;
2508 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2510 torture_wait_for_oplock_break(tctx);
2511 CHECK_VAL(break_info.count, 1);
2512 CHECK_VAL(break_info.failures, 0);
2513 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2515 torture_comment(tctx, "setfileinfo rename info should not trigger "
2516 "a break but should cause a sharing violation\n");
2517 ZERO_STRUCT(break_info);
2518 ZERO_STRUCT(sfi);
2519 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2520 sfi.rename_information.in.file.handle = h2;
2521 sfi.rename_information.in.overwrite = 0;
2522 sfi.rename_information.in.new_name = fname2;
2524 status = smb2_setinfo_file(tree2, &sfi);
2525 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2526 "Incorrect status");
2528 torture_wait_for_oplock_break(tctx);
2529 CHECK_VAL(break_info.count, 0);
2531 ZERO_STRUCT(qfi);
2532 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2533 qfi.generic.in.file.handle = h1;
2535 status = smb2_getinfo_file(tree1, tctx, &qfi);
2536 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2537 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2539 ZERO_STRUCT(qfi);
2540 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2541 qfi.generic.in.file.handle = h2;
2543 status = smb2_getinfo_file(tree2, tctx, &qfi);
2544 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2545 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2547 smb2_util_close(tree1, h1);
2548 smb2_util_close(tree2, h2);
2549 smb2_util_close(tree1, h);
2551 smb2_deltree(tree1, fname1);
2552 return ret;
2555 static bool test_smb2_oplock_batch21(struct torture_context *tctx,
2556 struct smb2_tree *tree1)
2558 const char *fname = BASEDIR "\\test_batch21.dat";
2559 NTSTATUS status;
2560 bool ret = true;
2561 union smb_open io;
2562 struct smb2_handle h, h1;
2563 char c = 0;
2565 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2566 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2568 /* cleanup */
2569 smb2_util_unlink(tree1, fname);
2571 tree1->session->transport->oplock.handler = torture_oplock_handler;
2572 tree1->session->transport->oplock.private_data = tree1;
2575 base ntcreatex parms
2577 ZERO_STRUCT(io.smb2);
2578 io.generic.level = RAW_OPEN_SMB2;
2579 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2580 io.smb2.in.alloc_size = 0;
2581 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2582 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2583 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2584 io.smb2.in.create_options = 0;
2585 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2586 io.smb2.in.security_flags = 0;
2587 io.smb2.in.fname = fname;
2590 with a batch oplock we get a break
2592 torture_comment(tctx, "BATCH21: open with batch oplock\n");
2593 ZERO_STRUCT(break_info);
2594 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2595 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2596 status = smb2_create(tree1, tctx, &(io.smb2));
2597 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2598 h1 = io.smb2.out.file.handle;
2599 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2601 torture_comment(tctx, "writing should not generate a break\n");
2602 status = smb2_util_write(tree1, h1, &c, 0, 1);
2603 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2605 torture_wait_for_oplock_break(tctx);
2606 CHECK_VAL(break_info.count, 0);
2608 smb2_util_close(tree1, h1);
2609 smb2_util_close(tree1, h);
2611 smb2_deltree(tree1, BASEDIR);
2612 return ret;
2615 static bool test_smb2_oplock_batch22(struct torture_context *tctx,
2616 struct smb2_tree *tree1)
2618 const char *fname = BASEDIR "\\test_batch22.dat";
2619 NTSTATUS status;
2620 bool ret = true;
2621 union smb_open io;
2622 struct smb2_handle h, h1, h2;
2623 struct timeval tv;
2624 int timeout = torture_setting_int(tctx, "oplocktimeout", 30);
2625 int te;
2627 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2628 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2630 /* cleanup */
2631 smb2_util_unlink(tree1, fname);
2633 tree1->session->transport->oplock.handler = torture_oplock_handler;
2634 tree1->session->transport->oplock.private_data = tree1;
2636 base ntcreatex parms
2638 ZERO_STRUCT(io.smb2);
2639 io.generic.level = RAW_OPEN_SMB2;
2640 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2641 io.smb2.in.alloc_size = 0;
2642 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2643 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2644 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2645 io.smb2.in.create_options = 0;
2646 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2647 io.smb2.in.security_flags = 0;
2648 io.smb2.in.fname = fname;
2651 with a batch oplock we get a break
2653 torture_comment(tctx, "BATCH22: open with batch oplock\n");
2654 ZERO_STRUCT(break_info);
2655 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2656 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2657 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2658 NTCREATEX_SHARE_ACCESS_WRITE|
2659 NTCREATEX_SHARE_ACCESS_DELETE;
2660 status = smb2_create(tree1, tctx, &(io.smb2));
2661 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2662 h1 = io.smb2.out.file.handle;
2663 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2665 torture_comment(tctx, "a 2nd open should succeed after the oplock "
2666 "break timeout\n");
2667 tv = timeval_current();
2668 tree1->session->transport->oplock.handler =
2669 torture_oplock_handler_timeout;
2670 status = smb2_create(tree1, tctx, &(io.smb2));
2671 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2672 h2 = io.smb2.out.file.handle;
2673 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2675 torture_wait_for_oplock_break(tctx);
2676 te = (int)timeval_elapsed(&tv);
2677 CHECK_RANGE(te, timeout - 1, timeout + 15);
2678 torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
2680 CHECK_VAL(break_info.count, 1);
2681 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2682 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2683 CHECK_VAL(break_info.failures, 0);
2685 smb2_util_close(tree1, h1);
2686 smb2_util_close(tree1, h2);
2687 smb2_util_close(tree1, h);
2689 smb2_deltree(tree1, BASEDIR);
2690 return ret;
2693 static bool test_smb2_oplock_batch23(struct torture_context *tctx,
2694 struct smb2_tree *tree1,
2695 struct smb2_tree *tree2)
2697 const char *fname = BASEDIR "\\test_batch23.dat";
2698 NTSTATUS status;
2699 bool ret = true;
2700 union smb_open io;
2701 struct smb2_handle h, h1, h2, h3;
2702 struct smb2_tree *tree3 = NULL;
2704 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2705 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2707 /* cleanup */
2708 smb2_util_unlink(tree1, fname);
2710 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2711 CHECK_VAL(ret, true);
2713 tree1->session->transport->oplock.handler = torture_oplock_handler;
2714 tree1->session->transport->oplock.private_data = tree1;
2716 tree2->session->transport->oplock.handler = torture_oplock_handler;
2717 tree2->session->transport->oplock.private_data = tree2;
2719 tree3->session->transport->oplock.handler = torture_oplock_handler;
2720 tree3->session->transport->oplock.private_data = tree3;
2723 base ntcreatex parms
2725 ZERO_STRUCT(io.smb2);
2726 io.generic.level = RAW_OPEN_SMB2;
2727 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2728 io.smb2.in.alloc_size = 0;
2729 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2730 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2731 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2732 io.smb2.in.create_options = 0;
2733 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2734 io.smb2.in.security_flags = 0;
2735 io.smb2.in.fname = fname;
2737 torture_comment(tctx, "BATCH23: an open and ask for a batch oplock\n");
2738 ZERO_STRUCT(break_info);
2740 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2741 SEC_RIGHTS_FILE_WRITE;
2742 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2743 NTCREATEX_SHARE_ACCESS_WRITE;
2744 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2745 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2746 status = smb2_create(tree1, tctx, &(io.smb2));
2747 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2748 h1 = io.smb2.out.file.handle;
2749 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2751 ZERO_STRUCT(break_info);
2753 torture_comment(tctx, "a 2nd open without level2 oplock support "
2754 "should generate a break to level2\n");
2755 status = smb2_create(tree3, tctx, &(io.smb2));
2756 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2757 h3 = io.smb2.out.file.handle;
2759 torture_wait_for_oplock_break(tctx);
2760 CHECK_VAL(break_info.count, 1);
2761 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2762 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2763 CHECK_VAL(break_info.failures, 0);
2765 ZERO_STRUCT(break_info);
2767 torture_comment(tctx, "a 3rd open with level2 oplock support should "
2768 "not generate a break\n");
2769 status = smb2_create(tree2, tctx, &(io.smb2));
2770 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2771 h2 = io.smb2.out.file.handle;
2772 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2774 torture_wait_for_oplock_break(tctx);
2775 CHECK_VAL(break_info.count, 0);
2777 smb2_util_close(tree1, h1);
2778 smb2_util_close(tree2, h2);
2779 smb2_util_close(tree3, h3);
2780 smb2_util_close(tree1, h);
2782 smb2_deltree(tree1, BASEDIR);
2783 return ret;
2786 static bool test_smb2_oplock_batch24(struct torture_context *tctx,
2787 struct smb2_tree *tree1,
2788 struct smb2_tree *tree2)
2790 const char *fname = BASEDIR "\\test_batch24.dat";
2791 NTSTATUS status;
2792 bool ret = true;
2793 union smb_open io;
2794 struct smb2_handle h, h1, h2;
2795 struct smb2_tree *tree3 = NULL;
2797 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2798 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2800 /* cleanup */
2801 smb2_util_unlink(tree1, fname);
2803 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2804 CHECK_VAL(ret, true);
2806 tree1->session->transport->oplock.handler = torture_oplock_handler;
2807 tree1->session->transport->oplock.private_data = tree1;
2809 tree2->session->transport->oplock.handler = torture_oplock_handler;
2810 tree2->session->transport->oplock.private_data = tree2;
2812 tree3->session->transport->oplock.handler = torture_oplock_handler;
2813 tree3->session->transport->oplock.private_data = tree3;
2816 base ntcreatex parms
2818 ZERO_STRUCT(io.smb2);
2819 io.generic.level = RAW_OPEN_SMB2;
2820 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2821 io.smb2.in.alloc_size = 0;
2822 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2823 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2824 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2825 io.smb2.in.create_options = 0;
2826 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2827 io.smb2.in.security_flags = 0;
2828 io.smb2.in.fname = fname;
2830 torture_comment(tctx, "BATCH24: a open without level support and "
2831 "ask for a batch oplock\n");
2832 ZERO_STRUCT(break_info);
2834 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2835 SEC_RIGHTS_FILE_WRITE;
2836 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2837 NTCREATEX_SHARE_ACCESS_WRITE;
2838 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2839 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2841 status = smb2_create(tree3, tctx, &(io.smb2));
2842 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2843 h2 = io.smb2.out.file.handle;
2844 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2846 ZERO_STRUCT(break_info);
2848 torture_comment(tctx, "a 2nd open with level2 oplock support should "
2849 "generate a break\n");
2850 status = smb2_create(tree2, tctx, &(io.smb2));
2851 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2852 h1 = io.smb2.out.file.handle;
2853 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2855 torture_wait_for_oplock_break(tctx);
2856 CHECK_VAL(break_info.count, 1);
2857 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
2858 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2859 CHECK_VAL(break_info.failures, 0);
2861 smb2_util_close(tree3, h2);
2862 smb2_util_close(tree2, h1);
2863 smb2_util_close(tree1, h);
2865 smb2_deltree(tree1, BASEDIR);
2866 return ret;
2869 static bool test_smb2_oplock_batch25(struct torture_context *tctx,
2870 struct smb2_tree *tree1)
2872 const char *fname = BASEDIR "\\test_batch25.dat";
2873 NTSTATUS status;
2874 bool ret = true;
2875 union smb_open io;
2876 struct smb2_handle h, h1;
2878 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2879 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2881 /* cleanup */
2882 smb2_util_unlink(tree1, fname);
2884 tree1->session->transport->oplock.handler = torture_oplock_handler;
2885 tree1->session->transport->oplock.private_data = tree1;
2888 base ntcreatex parms
2890 ZERO_STRUCT(io.smb2);
2891 io.generic.level = RAW_OPEN_SMB2;
2892 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2893 io.smb2.in.alloc_size = 0;
2894 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2895 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2896 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2897 io.smb2.in.create_options = 0;
2898 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2899 io.smb2.in.security_flags = 0;
2900 io.smb2.in.fname = fname;
2902 torture_comment(tctx, "BATCH25: open a file with an batch oplock "
2903 "(share mode: none)\n");
2905 ZERO_STRUCT(break_info);
2906 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2907 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2909 status = smb2_create(tree1, tctx, &(io.smb2));
2910 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2911 h1 = io.smb2.out.file.handle;
2912 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2914 torture_comment(tctx, "changing the file attribute info should trigger "
2915 "a break and a violation\n");
2917 status = smb2_util_setatr(tree1, fname, FILE_ATTRIBUTE_HIDDEN);
2918 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2919 "Incorrect status");
2921 torture_wait_for_oplock_break(tctx);
2922 CHECK_VAL(break_info.count, 1);
2924 smb2_util_close(tree1, h1);
2925 smb2_util_close(tree1, h);
2927 smb2_deltree(tree1, fname);
2928 return ret;
2931 static bool test_smb2_oplock_batch26(struct torture_context *tctx,
2932 struct smb2_tree *tree1)
2935 NTSTATUS status;
2936 bool ret = true;
2937 union smb_open io;
2938 struct smb2_handle h, h1, h2, h3;
2939 const char *fname_base = BASEDIR "\\test_oplock.txt";
2940 const char *stream = "Stream One:$DATA";
2941 const char *fname_stream;
2943 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2944 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2946 tree1->session->transport->oplock.handler = torture_oplock_handler;
2947 tree1->session->transport->oplock.private_data = tree1;
2949 fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
2952 base ntcreatex parms
2954 ZERO_STRUCT(io.smb2);
2955 io.generic.level = RAW_OPEN_SMB2;
2956 io.smb2.in.desired_access = 0x120089;
2957 io.smb2.in.alloc_size = 0;
2958 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2959 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE |
2960 NTCREATEX_SHARE_ACCESS_WRITE;
2961 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2962 io.smb2.in.create_options = 0;
2963 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2964 io.smb2.in.security_flags = 0;
2965 io.smb2.in.fname = fname_base;
2968 Open base file with a batch oplock.
2970 torture_comment(tctx, "Open the base file with batch oplock\n");
2971 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2972 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2974 status = smb2_create(tree1, tctx, &(io.smb2));
2975 torture_assert_ntstatus_ok(tctx, status, "Error opening base file");
2976 h1 = io.smb2.out.file.handle;
2977 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2979 torture_comment(tctx, "Got batch oplock on base file\n");
2981 torture_comment(tctx, "Opening stream file with batch oplock..\n");
2983 io.smb2.in.fname = fname_stream;
2985 status = smb2_create(tree1, tctx, &(io.smb2));
2986 torture_assert_ntstatus_ok(tctx, status, "Error opening stream file");
2987 h2 = io.smb2.out.file.handle;
2988 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2990 torture_comment(tctx, "Got batch oplock on stream file\n");
2992 torture_comment(tctx, "Open base file again with batch oplock\n");
2994 io.smb2.in.fname = fname_base;
2996 status = smb2_create(tree1, tctx, &(io.smb2));
2997 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2998 h3 = io.smb2.out.file.handle;
2999 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3001 smb2_util_close(tree1, h1);
3002 smb2_util_close(tree1, h2);
3003 smb2_util_close(tree1, h3);
3004 smb2_util_close(tree1, h);
3005 done:
3006 smb2_deltree(tree1, BASEDIR);
3007 return ret;
3011 /* Test how oplocks work on streams. */
3012 static bool test_raw_oplock_stream1(struct torture_context *tctx,
3013 struct smb2_tree *tree1,
3014 struct smb2_tree *tree2)
3016 NTSTATUS status;
3017 union smb_open io;
3018 const char *fname_base = BASEDIR "\\test_stream1.txt";
3019 const char *fname_stream, *fname_default_stream;
3020 const char *default_stream = "::$DATA";
3021 const char *stream = "Stream One:$DATA";
3022 bool ret = true;
3023 struct smb2_handle h, h_base, h_stream;
3024 int i;
3026 #define NSTREAM_OPLOCK_RESULTS 8
3027 struct {
3028 const char **fname;
3029 bool open_base_file;
3030 uint32_t oplock_req;
3031 uint32_t oplock_granted;
3032 } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
3033 /* Request oplock on stream without the base file open. */
3034 {&fname_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3035 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3036 {&fname_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3037 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3039 /* Request oplock on stream with the base file open. */
3040 {&fname_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3041 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_II},
3042 {&fname_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3043 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_II},
3046 fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
3047 fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
3048 default_stream);
3050 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3051 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3053 /* Initialize handles to "closed". Using -1 in the first 64-bytes
3054 * as the sentry for this */
3055 h_stream.data[0] = -1;
3057 /* cleanup */
3058 smb2_util_unlink(tree1, fname_base);
3060 tree1->session->transport->oplock.handler = torture_oplock_handler;
3061 tree1->session->transport->oplock.private_data = tree1;
3063 tree2->session->transport->oplock.handler = torture_oplock_handler;
3064 tree2->session->transport->oplock.private_data = tree2;
3066 /* Setup generic open parameters. */
3067 ZERO_STRUCT(io.smb2);
3068 io.generic.level = RAW_OPEN_SMB2;
3069 io.smb2.in.desired_access = (SEC_FILE_READ_DATA |
3070 SEC_FILE_WRITE_DATA |
3071 SEC_FILE_APPEND_DATA |
3072 SEC_STD_READ_CONTROL);
3073 io.smb2.in.alloc_size = 0;
3074 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3075 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3076 NTCREATEX_SHARE_ACCESS_WRITE;
3077 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3078 io.smb2.in.create_options = 0;
3079 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3080 io.smb2.in.security_flags = 0;
3082 /* Create the file with a stream */
3083 io.smb2.in.fname = fname_stream;
3084 io.smb2.in.create_flags = 0;
3085 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
3086 status = smb2_create(tree1, tctx, &(io.smb2));
3087 torture_assert_ntstatus_ok(tctx, status, "Error creating file");
3088 smb2_util_close(tree1, io.smb2.out.file.handle);
3090 /* Change the disposition to open now that the file has been created. */
3091 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
3093 /* Try some permutations of taking oplocks on streams. */
3094 for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
3095 const char *fname = *stream_oplock_results[i].fname;
3096 bool open_base_file = stream_oplock_results[i].open_base_file;
3097 uint32_t oplock_req = stream_oplock_results[i].oplock_req;
3098 uint32_t oplock_granted =
3099 stream_oplock_results[i].oplock_granted;
3101 if (open_base_file) {
3102 torture_comment(tctx, "Opening base file: %s with "
3103 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3104 io.smb2.in.fname = fname_base;
3105 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3106 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3107 status = smb2_create(tree2, tctx, &(io.smb2));
3108 torture_assert_ntstatus_ok(tctx, status,
3109 "Error opening file");
3110 CHECK_VAL(io.smb2.out.oplock_level,
3111 SMB2_OPLOCK_LEVEL_BATCH);
3112 h_base = io.smb2.out.file.handle;
3115 torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
3116 fname, oplock_req);
3117 io.smb2.in.fname = fname;
3118 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3119 io.smb2.in.oplock_level = oplock_req;
3121 /* Do the open with the desired oplock on the stream. */
3122 status = smb2_create(tree1, tctx, &(io.smb2));
3123 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3124 CHECK_VAL(io.smb2.out.oplock_level, oplock_granted);
3125 smb2_util_close(tree1, io.smb2.out.file.handle);
3127 /* Cleanup the base file if it was opened. */
3128 if (open_base_file)
3129 smb2_util_close(tree2, h_base);
3132 /* Open the stream with an exclusive oplock. */
3133 torture_comment(tctx, "Opening stream: %s with %d\n",
3134 fname_stream, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3135 io.smb2.in.fname = fname_stream;
3136 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3137 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3138 status = smb2_create(tree1, tctx, &(io.smb2));
3139 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3140 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3141 h_stream = io.smb2.out.file.handle;
3143 /* Open the base file and see if it contends. */
3144 ZERO_STRUCT(break_info);
3145 torture_comment(tctx, "Opening base file: %s with %d\n",
3146 fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3147 io.smb2.in.fname = fname_base;
3148 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3149 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3150 status = smb2_create(tree2, tctx, &(io.smb2));
3151 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3152 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3153 smb2_util_close(tree2, io.smb2.out.file.handle);
3155 torture_wait_for_oplock_break(tctx);
3156 CHECK_VAL(break_info.count, 0);
3157 CHECK_VAL(break_info.failures, 0);
3159 /* Open the stream again to see if it contends. */
3160 ZERO_STRUCT(break_info);
3161 torture_comment(tctx, "Opening stream again: %s with "
3162 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3163 io.smb2.in.fname = fname_stream;
3164 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3165 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3166 status = smb2_create(tree2, tctx, &(io.smb2));
3167 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3168 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3169 smb2_util_close(tree2, io.smb2.out.file.handle);
3171 torture_wait_for_oplock_break(tctx);
3172 CHECK_VAL(break_info.count, 1);
3173 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
3174 CHECK_VAL(break_info.failures, 0);
3176 /* Close the stream. */
3177 if (h_stream.data[0] != -1) {
3178 smb2_util_close(tree1, h_stream);
3181 smb2_util_close(tree1, h);
3183 smb2_deltree(tree1, BASEDIR);
3184 return ret;
3187 static bool test_smb2_oplock_doc(struct torture_context *tctx, struct smb2_tree *tree,
3188 struct smb2_tree *tree2)
3190 const char *fname = BASEDIR "\\test_oplock_doc.dat";
3191 NTSTATUS status;
3192 bool ret = true;
3193 union smb_open io;
3194 struct smb2_handle h, h1;
3195 union smb_setfileinfo sfinfo;
3197 status = torture_smb2_testdir(tree, BASEDIR, &h);
3198 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3199 smb2_util_close(tree, h);
3201 /* cleanup */
3202 smb2_util_unlink(tree, fname);
3203 tree->session->transport->oplock.handler = torture_oplock_handler;
3204 tree->session->transport->oplock.private_data = tree;
3207 base ntcreatex parms
3209 ZERO_STRUCT(io.smb2);
3210 io.generic.level = RAW_OPEN_SMB2;
3211 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3212 io.smb2.in.alloc_size = 0;
3213 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3214 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
3215 NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
3216 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3217 io.smb2.in.create_options = 0;
3218 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3219 io.smb2.in.security_flags = 0;
3220 io.smb2.in.fname = fname;
3222 torture_comment(tctx, "open a file with a batch oplock\n");
3223 ZERO_STRUCT(break_info);
3224 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3225 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3227 status = smb2_create(tree, tctx, &(io.smb2));
3228 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3229 h1 = io.smb2.out.file.handle;
3230 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3232 torture_comment(tctx, "Set delete on close\n");
3233 ZERO_STRUCT(sfinfo);
3234 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
3235 sfinfo.generic.in.file.handle = h1;
3236 sfinfo.disposition_info.in.delete_on_close = 1;
3237 status = smb2_setinfo_file(tree, &sfinfo);
3238 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3240 torture_comment(tctx, "2nd open should not break and get "
3241 "DELETE_PENDING\n");
3242 ZERO_STRUCT(break_info);
3243 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
3244 io.smb2.in.create_options = 0;
3245 io.smb2.in.desired_access = SEC_FILE_READ_DATA;
3246 status = smb2_create(tree2, tctx, &io.smb2);
3247 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DELETE_PENDING,
3248 "Incorrect status");
3249 CHECK_VAL(break_info.count, 0);
3251 smb2_util_close(tree, h1);
3253 smb2_util_unlink(tree, fname);
3254 smb2_deltree(tree, BASEDIR);
3255 return ret;
3258 /* Open a file with a batch oplock, then open it again from a second client
3259 * requesting no oplock. Having two open file handles should break our own
3260 * oplock during BRL acquisition.
3262 static bool test_smb2_oplock_brl1(struct torture_context *tctx,
3263 struct smb2_tree *tree1,
3264 struct smb2_tree *tree2)
3266 const char *fname = BASEDIR "\\test_batch_brl.dat";
3267 /*int fname, f;*/
3268 bool ret = true;
3269 uint8_t buf[1000];
3270 union smb_open io;
3271 NTSTATUS status;
3272 struct smb2_lock lck;
3273 struct smb2_lock_element lock[1];
3274 struct smb2_handle h, h1, h2;
3276 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3277 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3279 /* cleanup */
3280 smb2_util_unlink(tree1, fname);
3282 tree1->session->transport->oplock.handler =
3283 torture_oplock_handler_two_notifications;
3284 tree1->session->transport->oplock.private_data = tree1;
3287 base ntcreatex parms
3289 ZERO_STRUCT(io.smb2);
3290 io.generic.level = RAW_OPEN_SMB2;
3291 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3292 SEC_RIGHTS_FILE_WRITE;
3293 io.smb2.in.alloc_size = 0;
3294 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3295 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3296 NTCREATEX_SHARE_ACCESS_WRITE;
3297 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3298 io.smb2.in.create_options = 0;
3299 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3300 io.smb2.in.security_flags = 0;
3301 io.smb2.in.fname = fname;
3304 with a batch oplock we get a break
3306 torture_comment(tctx, "open with batch oplock\n");
3307 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3308 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3310 status = smb2_create(tree1, tctx, &(io.smb2));
3311 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3312 h1 = io.smb2.out.file.handle;
3313 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3315 /* create a file with bogus data */
3316 memset(buf, 0, sizeof(buf));
3318 status = smb2_util_write(tree1, h1,buf, 0, sizeof(buf));
3319 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3320 torture_comment(tctx, "Failed to create file\n");
3321 ret = false;
3322 goto done;
3325 torture_comment(tctx, "a 2nd open should give a break\n");
3326 ZERO_STRUCT(break_info);
3328 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3329 io.smb2.in.oplock_level = 0;
3330 status = smb2_create(tree2, tctx, &(io.smb2));
3331 h2 = io.smb2.out.file.handle;
3332 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3334 torture_wait_for_oplock_break(tctx);
3335 CHECK_VAL(break_info.count, 1);
3336 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3337 CHECK_VAL(break_info.failures, 0);
3338 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3340 ZERO_STRUCT(break_info);
3342 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3343 lock[0].offset = 0;
3344 lock[0].length = 4;
3345 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3346 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3348 ZERO_STRUCT(lck);
3349 lck.in.file.handle = h1;
3350 lck.in.locks = &lock[0];
3351 lck.in.lock_count = 1;
3352 status = smb2_lock(tree1, &lck);
3353 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3355 torture_wait_for_oplock_break(tctx);
3356 CHECK_VAL(break_info.count, 1);
3357 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3358 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3359 CHECK_VAL(break_info.failures, 0);
3361 /* expect no oplock break */
3362 ZERO_STRUCT(break_info);
3363 lock[0].offset = 2;
3364 status = smb2_lock(tree1, &lck);
3365 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3366 "Incorrect status");
3368 torture_wait_for_oplock_break(tctx);
3369 CHECK_VAL(break_info.count, 0);
3370 CHECK_VAL(break_info.level, 0);
3371 CHECK_VAL(break_info.failures, 0);
3373 smb2_util_close(tree1, h1);
3374 smb2_util_close(tree2, h2);
3375 smb2_util_close(tree1, h);
3377 done:
3378 smb2_deltree(tree1, BASEDIR);
3379 return ret;
3383 /* Open a file with a batch oplock on one tree and then acquire a brl.
3384 * We should not contend our own oplock.
3386 static bool test_smb2_oplock_brl2(struct torture_context *tctx, struct smb2_tree *tree1)
3388 const char *fname = BASEDIR "\\test_batch_brl.dat";
3389 /*int fname, f;*/
3390 bool ret = true;
3391 uint8_t buf[1000];
3392 union smb_open io;
3393 NTSTATUS status;
3394 struct smb2_handle h, h1;
3395 struct smb2_lock lck;
3396 struct smb2_lock_element lock[1];
3398 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3399 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3401 /* cleanup */
3402 smb2_util_unlink(tree1, fname);
3404 tree1->session->transport->oplock.handler = torture_oplock_handler;
3405 tree1->session->transport->oplock.private_data = tree1;
3408 base ntcreatex parms
3410 ZERO_STRUCT(io.smb2);
3411 io.generic.level = RAW_OPEN_SMB2;
3412 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3413 SEC_RIGHTS_FILE_WRITE;
3414 io.smb2.in.alloc_size = 0;
3415 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3416 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3417 NTCREATEX_SHARE_ACCESS_WRITE;
3418 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3419 io.smb2.in.create_options = 0;
3420 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3421 io.smb2.in.security_flags = 0;
3422 io.smb2.in.fname = fname;
3425 with a batch oplock we get a break
3427 torture_comment(tctx, "open with batch oplock\n");
3428 ZERO_STRUCT(break_info);
3429 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3430 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3432 status = smb2_create(tree1, tctx, &(io.smb2));
3433 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3434 h1 = io.smb2.out.file.handle;
3435 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3437 /* create a file with bogus data */
3438 memset(buf, 0, sizeof(buf));
3440 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3441 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3442 torture_comment(tctx, "Failed to create file\n");
3443 ret = false;
3444 goto done;
3447 ZERO_STRUCT(break_info);
3449 torture_comment(tctx, "a self BRL acquisition should not break to "
3450 "none\n");
3452 lock[0].offset = 0;
3453 lock[0].length = 4;
3454 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3455 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3457 ZERO_STRUCT(lck);
3458 lck.in.file.handle = h1;
3459 lck.in.locks = &lock[0];
3460 lck.in.lock_count = 1;
3461 status = smb2_lock(tree1, &lck);
3462 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3464 lock[0].offset = 2;
3465 status = smb2_lock(tree1, &lck);
3466 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3467 "Incorrect status");
3469 /* With one file handle open a BRL should not contend our oplock.
3470 * Thus, no oplock break will be received and the entire break_info
3471 * struct will be 0 */
3472 torture_wait_for_oplock_break(tctx);
3473 CHECK_VAL(break_info.count, 0);
3474 CHECK_VAL(break_info.level, 0);
3475 CHECK_VAL(break_info.failures, 0);
3477 smb2_util_close(tree1, h1);
3478 smb2_util_close(tree1, h);
3480 done:
3481 smb2_deltree(tree1, BASEDIR);
3482 return ret;
3485 /* Open a file with a batch oplock twice from one tree and then acquire a
3486 * brl. BRL acquisition should break our own oplock.
3488 static bool test_smb2_oplock_brl3(struct torture_context *tctx, struct smb2_tree *tree1)
3490 const char *fname = BASEDIR "\\test_batch_brl.dat";
3491 bool ret = true;
3492 uint8_t buf[1000];
3493 union smb_open io;
3494 NTSTATUS status;
3495 struct smb2_handle h, h1, h2;
3496 struct smb2_lock lck;
3497 struct smb2_lock_element lock[1];
3499 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3500 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3502 /* cleanup */
3503 smb2_util_unlink(tree1, fname);
3504 tree1->session->transport->oplock.handler =
3505 torture_oplock_handler_two_notifications;
3506 tree1->session->transport->oplock.private_data = tree1;
3509 base ntcreatex parms
3511 ZERO_STRUCT(io.smb2);
3512 io.generic.level = RAW_OPEN_SMB2;
3513 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3514 SEC_RIGHTS_FILE_WRITE;
3515 io.smb2.in.alloc_size = 0;
3516 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3517 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3518 NTCREATEX_SHARE_ACCESS_WRITE;
3519 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3520 io.smb2.in.create_options = 0;
3521 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3522 io.smb2.in.security_flags = 0;
3523 io.smb2.in.fname = fname;
3526 with a batch oplock we get a break
3528 torture_comment(tctx, "open with batch oplock\n");
3529 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3530 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3532 status = smb2_create(tree1, tctx, &(io.smb2));
3533 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3534 h1 = io.smb2.out.file.handle;
3535 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3537 /* create a file with bogus data */
3538 memset(buf, 0, sizeof(buf));
3539 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3541 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3542 torture_comment(tctx, "Failed to create file\n");
3543 ret = false;
3544 goto done;
3547 torture_comment(tctx, "a 2nd open should give a break\n");
3548 ZERO_STRUCT(break_info);
3550 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3551 io.smb2.in.oplock_level = 0;
3552 status = smb2_create(tree1, tctx, &(io.smb2));
3553 h2 = io.smb2.out.file.handle;
3554 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3555 CHECK_VAL(break_info.count, 1);
3556 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3557 CHECK_VAL(break_info.failures, 0);
3558 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3560 ZERO_STRUCT(break_info);
3562 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3564 lock[0].offset = 0;
3565 lock[0].length = 4;
3566 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3567 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3569 ZERO_STRUCT(lck);
3570 lck.in.file.handle = h1;
3571 lck.in.locks = &lock[0];
3572 lck.in.lock_count = 1;
3573 status = smb2_lock(tree1, &lck);
3574 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3576 torture_wait_for_oplock_break(tctx);
3577 CHECK_VAL(break_info.count, 1);
3578 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3579 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3580 CHECK_VAL(break_info.failures, 0);
3582 /* expect no oplock break */
3583 ZERO_STRUCT(break_info);
3584 lock[0].offset = 2;
3585 status = smb2_lock(tree1, &lck);
3586 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3587 "Incorrect status");
3589 torture_wait_for_oplock_break(tctx);
3590 CHECK_VAL(break_info.count, 0);
3591 CHECK_VAL(break_info.level, 0);
3592 CHECK_VAL(break_info.failures, 0);
3594 smb2_util_close(tree1, h1);
3595 smb2_util_close(tree1, h2);
3596 smb2_util_close(tree1, h);
3598 done:
3599 smb2_deltree(tree1, BASEDIR);
3600 return ret;
3604 /* Starting the SMB2 specific oplock tests at 500 so we can keep the SMB1
3605 * tests in sync with an identically numbered SMB2 test */
3607 /* Test whether the server correctly returns an error when we send
3608 * a response to a levelII to none oplock notification. */
3609 static bool test_smb2_oplock_levelII500(struct torture_context *tctx,
3610 struct smb2_tree *tree1)
3612 const char *fname = BASEDIR "\\test_levelII500.dat";
3613 NTSTATUS status;
3614 bool ret = true;
3615 union smb_open io;
3616 struct smb2_handle h, h1;
3617 char c = 0;
3619 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3620 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3622 /* cleanup */
3623 smb2_util_unlink(tree1, fname);
3625 tree1->session->transport->oplock.handler = torture_oplock_handler;
3626 tree1->session->transport->oplock.private_data = tree1;
3629 base ntcreatex parms
3631 ZERO_STRUCT(io.smb2);
3632 io.generic.level = RAW_OPEN_SMB2;
3633 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3634 io.smb2.in.alloc_size = 0;
3635 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3636 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3637 io.smb2.in.create_options = 0;
3638 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3639 io.smb2.in.security_flags = 0;
3640 io.smb2.in.fname = fname;
3642 torture_comment(tctx, "LEVELII500: acknowledging a break from II to "
3643 "none should return an error\n");
3644 ZERO_STRUCT(break_info);
3646 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3647 SEC_RIGHTS_FILE_WRITE;
3648 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3649 NTCREATEX_SHARE_ACCESS_WRITE;
3650 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3651 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
3652 status = smb2_create(tree1, tctx, &(io.smb2));
3653 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3654 h1 = io.smb2.out.file.handle;
3655 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3657 ZERO_STRUCT(break_info);
3659 torture_comment(tctx, "write should trigger a break to none and when "
3660 "we reply, an oplock break failure\n");
3661 smb2_util_write(tree1, h1, &c, 0, 1);
3663 /* Wait several times to receive both the break notification, and the
3664 * NT_STATUS_INVALID_OPLOCK_PROTOCOL error in the break response */
3665 torture_wait_for_oplock_break(tctx);
3666 torture_wait_for_oplock_break(tctx);
3667 torture_wait_for_oplock_break(tctx);
3668 torture_wait_for_oplock_break(tctx);
3670 /* There appears to be a race condition in W2K8 and W2K8R2 where
3671 * sometimes the server will happily reply to our break response with
3672 * NT_STATUS_OK, and sometimes it will return the OPLOCK_PROTOCOL
3673 * error. As the MS-SMB2 doc states that a client should not reply to
3674 * a level2 to none break notification, I'm leaving the protocol error
3675 * as the expected behavior. */
3676 CHECK_VAL(break_info.count, 1);
3677 CHECK_VAL(break_info.level, 0);
3678 CHECK_VAL(break_info.failures, 1);
3679 torture_assert_ntstatus_equal(tctx, break_info.failure_status,
3680 NT_STATUS_INVALID_OPLOCK_PROTOCOL,
3681 "Incorrect status");
3683 smb2_util_close(tree1, h1);
3684 smb2_util_close(tree1, h);
3686 smb2_deltree(tree1, BASEDIR);
3687 return ret;
3691 * Test a double-break. Open a file with exclusive. Send off a second open
3692 * request with OPEN_IF, triggering a break to level2. This should respond
3693 * with level2. Before replying to the break to level2, fire off a third open
3694 * with OVERWRITE_IF. The expected sequence would be that the 3rd opener gets
3695 * a level2 immediately triggered by a break to none, but that seems not the
3696 * case. Still investigating what the right behaviour should be.
3699 struct levelII501_state {
3700 struct torture_context *tctx;
3701 struct smb2_tree *tree1;
3702 struct smb2_tree *tree2;
3703 struct smb2_tree *tree3;
3704 struct smb2_handle h;
3705 struct smb2_handle h1;
3706 union smb_open io;
3708 struct smb2_handle break_handle;
3709 uint8_t break_to;
3710 struct smb2_break br;
3712 bool done;
3715 static bool torture_oplock_break_delay(struct smb2_transport *transport,
3716 const struct smb2_handle *handle,
3717 uint8_t level, void *private_data);
3718 static void levelII501_break_done(struct smb2_request *req);
3719 static void levelII501_open1_done(struct smb2_request *req);
3720 static void levelII501_open2_done(struct smb2_request *req);
3721 static void levelII501_2ndopen_cb(struct tevent_context *ev,
3722 struct tevent_timer *te,
3723 struct timeval current_time,
3724 void *private_data);
3725 static void levelII501_break_timeout_cb(struct tevent_context *ev,
3726 struct tevent_timer *te,
3727 struct timeval current_time,
3728 void *private_data);
3729 static void levelII501_timeout_cb(struct tevent_context *ev,
3730 struct tevent_timer *te,
3731 struct timeval current_time,
3732 void *private_data);
3734 static bool test_smb2_oplock_levelII501(struct torture_context *tctx,
3735 struct smb2_tree *tree1,
3736 struct smb2_tree *tree2)
3738 const char *fname = BASEDIR "\\test_levelII501.dat";
3739 NTSTATUS status;
3740 bool ret = true;
3741 struct levelII501_state *state;
3742 struct smb2_request *req;
3743 struct tevent_timer *te;
3745 state = talloc(tctx, struct levelII501_state);
3746 state->tctx = tctx;
3747 state->done = false;
3748 state->tree1 = tree1;
3749 state->tree2 = tree2;
3751 if (!torture_smb2_connection(tctx, &state->tree3)) {
3752 torture_fail(tctx, "Establishing SMB2 connection failed\n");
3753 return false;
3756 status = torture_smb2_testdir(tree1, BASEDIR, &state->h);
3757 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3759 /* cleanup */
3760 smb2_util_unlink(tree1, fname);
3763 base ntcreatex parms
3765 ZERO_STRUCT(state->io.smb2);
3766 state->io.generic.level = RAW_OPEN_SMB2;
3767 state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3768 state->io.smb2.in.alloc_size = 0;
3769 state->io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3770 state->io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3771 state->io.smb2.in.create_options = 0;
3772 state->io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3773 state->io.smb2.in.security_flags = 0;
3774 state->io.smb2.in.fname = fname;
3776 torture_comment(tctx, "LEVELII501: Test double break sequence\n");
3777 ZERO_STRUCT(break_info);
3779 state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3780 SEC_RIGHTS_FILE_WRITE;
3781 state->io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3782 NTCREATEX_SHARE_ACCESS_WRITE;
3783 state->io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3784 state->io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3786 tree1->session->transport->oplock.handler = torture_oplock_break_delay;
3787 tree1->session->transport->oplock.private_data = state;
3789 status = smb2_create(tree1, tctx, &(state->io.smb2));
3790 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3791 state->h1 = state->io.smb2.out.file.handle;
3792 CHECK_VAL(state->io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3795 * Trigger a break to level2
3798 req = smb2_create_send(tree2, &state->io.smb2);
3799 req->async.fn = levelII501_open1_done;
3800 req->async.private_data = state;
3802 te = tevent_add_timer(
3803 tctx->ev, tctx, tevent_timeval_current_ofs(0, 200000),
3804 levelII501_2ndopen_cb, state);
3805 torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
3807 te = tevent_add_timer(
3808 tctx->ev, tctx, tevent_timeval_current_ofs(2, 0),
3809 levelII501_timeout_cb, state);
3810 torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
3812 while (!state->done) {
3813 if (tevent_loop_once(tctx->ev) != 0) {
3814 torture_comment(tctx, "tevent_loop_once failed\n");
3818 return ret;
3822 * Fire off a second open after a little timeout
3825 static void levelII501_2ndopen_cb(struct tevent_context *ev,
3826 struct tevent_timer *te,
3827 struct timeval current_time,
3828 void *private_data)
3830 struct levelII501_state *state = talloc_get_type_abort(
3831 private_data, struct levelII501_state);
3832 struct smb2_request *req;
3834 state->io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
3835 req = smb2_create_send(state->tree3, &state->io.smb2);
3836 req->async.fn = levelII501_open2_done;
3837 req->async.private_data = state;
3841 * Postpone the break response by 500 msec
3843 static bool torture_oplock_break_delay(struct smb2_transport *transport,
3844 const struct smb2_handle *handle,
3845 uint8_t level, void *private_data)
3847 struct levelII501_state *state = talloc_get_type_abort(
3848 private_data, struct levelII501_state);
3849 const char *name;
3850 struct tevent_timer *te;
3852 break_info.handle = *handle;
3853 break_info.level = level;
3854 break_info.count++;
3856 state->break_handle = *handle;
3857 state->break_to = level;
3859 switch(level) {
3860 case SMB2_OPLOCK_LEVEL_II:
3861 name = "level II";
3862 break;
3863 case SMB2_OPLOCK_LEVEL_NONE:
3864 name = "none";
3865 break;
3866 default:
3867 name = "unknown";
3868 break;
3870 printf("Got break to %s [0x%02X] in oplock handler, postponing "
3871 "break response for 500msec\n", name, level);
3873 te = tevent_add_timer(
3874 state->tctx->ev, state->tctx,
3875 tevent_timeval_current_ofs(0, 500000),
3876 levelII501_break_timeout_cb, state);
3877 torture_assert(state->tctx, te != NULL, "tevent_add_timer failed\n");
3879 return true;
3882 static void levelII501_break_timeout_cb(struct tevent_context *ev,
3883 struct tevent_timer *te,
3884 struct timeval current_time,
3885 void *private_data)
3887 struct levelII501_state *state = talloc_get_type_abort(
3888 private_data, struct levelII501_state);
3889 struct smb2_request *req;
3891 talloc_free(te);
3893 ZERO_STRUCT(state->br);
3894 state->br.in.file.handle = state->break_handle;
3895 state->br.in.oplock_level = state->break_to;
3897 req = smb2_break_send(state->tree1, &state->br);
3898 req->async.fn = levelII501_break_done;
3899 req->async.private_data = state;
3902 static void levelII501_break_done(struct smb2_request *req)
3904 struct smb2_break io;
3905 NTSTATUS status;
3907 status = smb2_break_recv(req, &io);
3908 printf("break done: %s\n", nt_errstr(status));
3911 static void levelII501_open1_done(struct smb2_request *req)
3913 struct levelII501_state *state = talloc_get_type_abort(
3914 req->async.private_data, struct levelII501_state);
3915 struct smb2_create io;
3916 NTSTATUS status;
3918 status = smb2_create_recv(req, state, &io);
3919 printf("open1 done: %s\n", nt_errstr(status));
3922 static void levelII501_open2_done(struct smb2_request *req)
3924 struct levelII501_state *state = talloc_get_type_abort(
3925 req->async.private_data, struct levelII501_state);
3926 struct smb2_create io;
3927 NTSTATUS status;
3929 status = smb2_create_recv(req, state, &io);
3930 printf("open2 done: %s\n", nt_errstr(status));
3933 static void levelII501_timeout_cb(struct tevent_context *ev,
3934 struct tevent_timer *te,
3935 struct timeval current_time,
3936 void *private_data)
3938 struct levelII501_state *state = talloc_get_type_abort(
3939 private_data, struct levelII501_state);
3940 talloc_free(te);
3941 state->done = true;
3944 struct torture_suite *torture_smb2_oplocks_init(void)
3946 struct torture_suite *suite =
3947 torture_suite_create(talloc_autofree_context(), "oplock");
3949 torture_suite_add_2smb2_test(suite, "exclusive1", test_smb2_oplock_exclusive1);
3950 torture_suite_add_2smb2_test(suite, "exclusive2", test_smb2_oplock_exclusive2);
3951 torture_suite_add_2smb2_test(suite, "exclusive3", test_smb2_oplock_exclusive3);
3952 torture_suite_add_2smb2_test(suite, "exclusive4", test_smb2_oplock_exclusive4);
3953 torture_suite_add_2smb2_test(suite, "exclusive5", test_smb2_oplock_exclusive5);
3954 torture_suite_add_2smb2_test(suite, "exclusive6", test_smb2_oplock_exclusive6);
3955 torture_suite_add_2smb2_test(suite, "exclusive9",
3956 test_smb2_oplock_exclusive9);
3957 torture_suite_add_2smb2_test(suite, "batch1", test_smb2_oplock_batch1);
3958 torture_suite_add_2smb2_test(suite, "batch2", test_smb2_oplock_batch2);
3959 torture_suite_add_2smb2_test(suite, "batch3", test_smb2_oplock_batch3);
3960 torture_suite_add_2smb2_test(suite, "batch4", test_smb2_oplock_batch4);
3961 torture_suite_add_2smb2_test(suite, "batch5", test_smb2_oplock_batch5);
3962 torture_suite_add_2smb2_test(suite, "batch6", test_smb2_oplock_batch6);
3963 torture_suite_add_2smb2_test(suite, "batch7", test_smb2_oplock_batch7);
3964 torture_suite_add_2smb2_test(suite, "batch8", test_smb2_oplock_batch8);
3965 torture_suite_add_2smb2_test(suite, "batch9", test_smb2_oplock_batch9);
3966 torture_suite_add_2smb2_test(suite, "batch9a", test_smb2_oplock_batch9a);
3967 torture_suite_add_2smb2_test(suite, "batch10", test_smb2_oplock_batch10);
3968 torture_suite_add_2smb2_test(suite, "batch11", test_smb2_oplock_batch11);
3969 torture_suite_add_2smb2_test(suite, "batch12", test_smb2_oplock_batch12);
3970 torture_suite_add_2smb2_test(suite, "batch13", test_smb2_oplock_batch13);
3971 torture_suite_add_2smb2_test(suite, "batch14", test_smb2_oplock_batch14);
3972 torture_suite_add_2smb2_test(suite, "batch15", test_smb2_oplock_batch15);
3973 torture_suite_add_2smb2_test(suite, "batch16", test_smb2_oplock_batch16);
3974 torture_suite_add_1smb2_test(suite, "batch19", test_smb2_oplock_batch19);
3975 torture_suite_add_2smb2_test(suite, "batch20", test_smb2_oplock_batch20);
3976 torture_suite_add_1smb2_test(suite, "batch21", test_smb2_oplock_batch21);
3977 torture_suite_add_1smb2_test(suite, "batch22", test_smb2_oplock_batch22);
3978 torture_suite_add_2smb2_test(suite, "batch23", test_smb2_oplock_batch23);
3979 torture_suite_add_2smb2_test(suite, "batch24", test_smb2_oplock_batch24);
3980 torture_suite_add_1smb2_test(suite, "batch25", test_smb2_oplock_batch25);
3981 torture_suite_add_1smb2_test(suite, "batch26", test_smb2_oplock_batch26);
3982 torture_suite_add_2smb2_test(suite, "stream1", test_raw_oplock_stream1);
3983 torture_suite_add_2smb2_test(suite, "doc", test_smb2_oplock_doc);
3984 torture_suite_add_2smb2_test(suite, "brl1", test_smb2_oplock_brl1);
3985 torture_suite_add_1smb2_test(suite, "brl2", test_smb2_oplock_brl2);
3986 torture_suite_add_1smb2_test(suite, "brl3", test_smb2_oplock_brl3);
3987 torture_suite_add_1smb2_test(suite, "levelii500", test_smb2_oplock_levelII500);
3988 torture_suite_add_2smb2_test(suite, "levelii501",
3989 test_smb2_oplock_levelII501);
3990 suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
3992 return suite;
3996 stress testing of oplocks
3998 bool test_smb2_bench_oplock(struct torture_context *tctx,
3999 struct smb2_tree *tree)
4001 struct smb2_tree **trees;
4002 bool ret = true;
4003 NTSTATUS status;
4004 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4005 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
4006 int i, count=0;
4007 int timelimit = torture_setting_int(tctx, "timelimit", 10);
4008 union smb_open io;
4009 struct timeval tv;
4010 struct smb2_handle h;
4012 trees = talloc_array(mem_ctx, struct smb2_tree *, torture_nprocs);
4014 torture_comment(tctx, "Opening %d connections\n", torture_nprocs);
4015 for (i=0;i<torture_nprocs;i++) {
4016 if (!torture_smb2_connection(tctx, &trees[i])) {
4017 return false;
4019 talloc_steal(mem_ctx, trees[i]);
4020 trees[i]->session->transport->oplock.handler =
4021 torture_oplock_handler_close;
4022 trees[i]->session->transport->oplock.private_data = trees[i];
4025 status = torture_smb2_testdir(trees[0], BASEDIR, &h);
4026 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4028 ZERO_STRUCT(io.smb2);
4029 io.smb2.level = RAW_OPEN_SMB2;
4030 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4031 io.smb2.in.alloc_size = 0;
4032 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4033 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4034 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4035 io.smb2.in.create_options = 0;
4036 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4037 io.smb2.in.security_flags = 0;
4038 io.smb2.in.fname = BASEDIR "\\test.dat";
4039 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4040 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4042 tv = timeval_current();
4045 we open the same file with SHARE_ACCESS_NONE from all the
4046 connections in a round robin fashion. Each open causes an
4047 oplock break on the previous connection, which is answered
4048 by the oplock_handler_close() to close the file.
4050 This measures how fast we can pass on oplocks, and stresses
4051 the oplock handling code
4053 torture_comment(tctx, "Running for %d seconds\n", timelimit);
4054 while (timeval_elapsed(&tv) < timelimit) {
4055 for (i=0;i<torture_nprocs;i++) {
4056 status = smb2_create(trees[i], mem_ctx, &(io.smb2));
4057 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
4058 count++;
4061 if (torture_setting_bool(tctx, "progress", true)) {
4062 torture_comment(tctx, "%.2f ops/second\r",
4063 count/timeval_elapsed(&tv));
4067 torture_comment(tctx, "%.2f ops/second\n", count/timeval_elapsed(&tv));
4068 smb2_util_close(trees[0], io.smb2.out.file.handle);
4069 smb2_util_unlink(trees[0], BASEDIR "\\test.dat");
4070 smb2_deltree(trees[0], BASEDIR);
4071 talloc_free(mem_ctx);
4072 return ret;
4075 static struct hold_oplock_info {
4076 const char *fname;
4077 bool close_on_break;
4078 uint32_t share_access;
4079 struct smb2_handle handle;
4080 } hold_info[] = {
4081 { BASEDIR "\\notshared_close", true,
4082 NTCREATEX_SHARE_ACCESS_NONE, },
4083 { BASEDIR "\\notshared_noclose", false,
4084 NTCREATEX_SHARE_ACCESS_NONE, },
4085 { BASEDIR "\\shared_close", true,
4086 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, },
4087 { BASEDIR "\\shared_noclose", false,
4088 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, },
4091 static bool torture_oplock_handler_hold(struct smb2_transport *transport,
4092 const struct smb2_handle *handle,
4093 uint8_t level, void *private_data)
4095 struct hold_oplock_info *info;
4096 int i;
4098 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
4099 if (smb2_util_handle_equal(hold_info[i].handle, *handle))
4100 break;
4103 if (i == ARRAY_SIZE(hold_info)) {
4104 printf("oplock break for unknown handle 0x%llx%llx\n",
4105 (unsigned long long) handle->data[0],
4106 (unsigned long long) handle->data[1]);
4107 return false;
4110 info = &hold_info[i];
4112 if (info->close_on_break) {
4113 printf("oplock break on %s - closing\n", info->fname);
4114 torture_oplock_handler_close(transport, handle,
4115 level, private_data);
4116 return true;
4119 printf("oplock break on %s - acking break\n", info->fname);
4120 printf("Acking to none in oplock handler\n");
4122 torture_oplock_handler_ack_to_none(transport, handle,
4123 level, private_data);
4124 return true;
4128 used for manual testing of oplocks - especially interaction with
4129 other filesystems (such as NFS and local access)
4131 bool test_smb2_hold_oplock(struct torture_context *tctx,
4132 struct smb2_tree *tree)
4134 struct torture_context *mem_ctx = talloc_new(tctx);
4135 struct tevent_context *ev = tctx->ev;
4136 int i;
4137 struct smb2_handle h;
4138 NTSTATUS status;
4140 torture_comment(tctx, "Setting up open files with oplocks in %s\n",
4141 BASEDIR);
4143 status = torture_smb2_testdir(tree, BASEDIR, &h);
4144 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4146 tree->session->transport->oplock.handler = torture_oplock_handler_hold;
4147 tree->session->transport->oplock.private_data = tree;
4149 /* setup the files */
4150 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
4151 union smb_open io;
4152 char c = 1;
4154 ZERO_STRUCT(io.smb2);
4155 io.generic.level = RAW_OPEN_SMB2;
4156 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4157 io.smb2.in.alloc_size = 0;
4158 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4159 io.smb2.in.share_access = hold_info[i].share_access;
4160 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4161 io.smb2.in.create_options = 0;
4162 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4163 io.smb2.in.security_flags = 0;
4164 io.smb2.in.fname = hold_info[i].fname;
4165 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4166 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4168 torture_comment(tctx, "opening %s\n", hold_info[i].fname);
4170 status = smb2_create(tree, mem_ctx, &(io.smb2));
4171 if (!NT_STATUS_IS_OK(status)) {
4172 torture_comment(tctx, "Failed to open %s - %s\n",
4173 hold_info[i].fname, nt_errstr(status));
4174 return false;
4177 if (io.smb2.out.oplock_level != SMB2_OPLOCK_LEVEL_BATCH) {
4178 torture_comment(tctx, "Oplock not granted for %s - "
4179 "expected %d but got %d\n",
4180 hold_info[i].fname,
4181 SMB2_OPLOCK_LEVEL_BATCH,
4182 io.smb2.out.oplock_level);
4183 return false;
4185 hold_info[i].handle = io.smb2.out.file.handle;
4187 /* make the file non-zero size */
4188 status = smb2_util_write(tree, hold_info[i].handle, &c, 0, 1);
4189 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
4190 torture_comment(tctx, "Failed to write to file\n");
4191 return false;
4195 torture_comment(tctx, "Waiting for oplock events\n");
4196 tevent_loop_wait(ev);
4197 smb2_deltree(tree, BASEDIR);
4198 talloc_free(mem_ctx);
4199 return true;