s4:torture: send the TCONX_FLAG_EXTENDED_RESPONSE flag
[Samba/gebeck_regimport.git] / source4 / torture / smb2 / oplock.c
blobd4899439860ad0ea7b6530aa7a1152c7ec02f44e
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 union smb_unlink unl;
368 struct smb2_handle h1;
369 struct smb2_handle h;
371 status = torture_smb2_testdir(tree1, BASEDIR, &h);
372 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
374 /* cleanup */
375 smb2_util_unlink(tree1, fname);
377 tree1->session->transport->oplock.handler = torture_oplock_handler;
378 tree1->session->transport->oplock.private_data = tree1;
381 base ntcreatex parms
383 ZERO_STRUCT(io.smb2);
384 io.generic.level = RAW_OPEN_SMB2;
385 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
386 io.smb2.in.alloc_size = 0;
387 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
388 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
389 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
390 io.smb2.in.create_options = 0;
391 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
392 io.smb2.in.security_flags = 0;
393 io.smb2.in.fname = fname;
395 torture_comment(tctx, "EXCLUSIVE1: open a file with an exclusive "
396 "oplock (share mode: none)\n");
397 ZERO_STRUCT(break_info);
398 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
400 status = smb2_create(tree1, tctx, &(io.smb2));
401 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
402 h1 = io.smb2.out.file.handle;
403 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
405 torture_comment(tctx, "a 2nd open should not cause a break\n");
406 status = smb2_create(tree2, tctx, &(io.smb2));
407 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
408 "Incorrect status");
409 torture_wait_for_oplock_break(tctx);
410 CHECK_VAL(break_info.count, 0);
411 CHECK_VAL(break_info.failures, 0);
413 torture_comment(tctx, "unlink it - should also be no break\n");
414 unl.unlink.in.pattern = fname;
415 unl.unlink.in.attrib = 0;
416 status = smb2_util_unlink(tree2, fname);
417 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
418 "Incorrect status");
419 torture_wait_for_oplock_break(tctx);
420 CHECK_VAL(break_info.count, 0);
421 CHECK_VAL(break_info.failures, 0);
423 smb2_util_close(tree1, h1);
424 smb2_util_close(tree1, h);
426 smb2_deltree(tree1, BASEDIR);
427 return ret;
430 static bool test_smb2_oplock_exclusive2(struct torture_context *tctx,
431 struct smb2_tree *tree1,
432 struct smb2_tree *tree2)
434 const char *fname = BASEDIR "\\test_exclusive2.dat";
435 NTSTATUS status;
436 bool ret = true;
437 union smb_open io;
438 union smb_unlink unl;
439 struct smb2_handle h, h1, h2;
441 status = torture_smb2_testdir(tree1, BASEDIR, &h);
442 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
444 /* cleanup */
445 smb2_util_unlink(tree1, fname);
447 tree1->session->transport->oplock.handler = torture_oplock_handler;
448 tree1->session->transport->oplock.private_data = tree1;
451 base ntcreatex parms
453 ZERO_STRUCT(io.smb2);
454 io.generic.level = RAW_OPEN_SMB2;
455 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
456 io.smb2.in.alloc_size = 0;
457 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
458 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
459 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
460 io.smb2.in.create_options = 0;
461 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
462 io.smb2.in.security_flags = 0;
463 io.smb2.in.fname = fname;
465 torture_comment(tctx, "EXCLUSIVE2: open a file with an exclusive "
466 "oplock (share mode: all)\n");
467 ZERO_STRUCT(break_info);
468 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
469 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
470 NTCREATEX_SHARE_ACCESS_WRITE|
471 NTCREATEX_SHARE_ACCESS_DELETE;
472 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
474 status = smb2_create(tree1, tctx, &(io.smb2));
475 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
476 h1 = io.smb2.out.file.handle;
477 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
479 torture_comment(tctx, "a 2nd open should cause a break to level 2\n");
480 status = smb2_create(tree2, tctx, &(io.smb2));
481 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
482 h2 = io.smb2.out.file.handle;
483 torture_wait_for_oplock_break(tctx);
484 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
485 CHECK_VAL(break_info.count, 1);
486 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
487 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
488 CHECK_VAL(break_info.failures, 0);
489 ZERO_STRUCT(break_info);
491 /* now we have 2 level II oplocks... */
492 torture_comment(tctx, "try to unlink it - should cause a break\n");
493 unl.unlink.in.pattern = fname;
494 unl.unlink.in.attrib = 0;
495 status = smb2_util_unlink(tree2, fname);
496 torture_assert_ntstatus_ok(tctx, status, "Error unlinking the file");
497 torture_wait_for_oplock_break(tctx);
498 CHECK_VAL(break_info.count, 0);
499 CHECK_VAL(break_info.failures, 0);
501 torture_comment(tctx, "close both handles\n");
502 smb2_util_close(tree1, h1);
503 smb2_util_close(tree1, h2);
504 smb2_util_close(tree1, h);
506 smb2_deltree(tree1, BASEDIR);
507 return ret;
510 static bool test_smb2_oplock_exclusive3(struct torture_context *tctx,
511 struct smb2_tree *tree1,
512 struct smb2_tree *tree2)
514 const char *fname = BASEDIR "\\test_exclusive3.dat";
515 NTSTATUS status;
516 bool ret = true;
517 union smb_open io;
518 union smb_setfileinfo sfi;
519 struct smb2_handle h, h1;
521 status = torture_smb2_testdir(tree1, BASEDIR, &h);
522 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
524 /* cleanup */
525 smb2_util_unlink(tree1, fname);
527 tree1->session->transport->oplock.handler = torture_oplock_handler;
528 tree1->session->transport->oplock.private_data = tree1;
531 base ntcreatex parms
533 ZERO_STRUCT(io.smb2);
534 io.generic.level = RAW_OPEN_SMB2;
535 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
536 io.smb2.in.alloc_size = 0;
537 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
538 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
539 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
540 io.smb2.in.create_options = 0;
541 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
542 io.smb2.in.security_flags = 0;
543 io.smb2.in.fname = fname;
545 torture_comment(tctx, "EXCLUSIVE3: open a file with an exclusive "
546 "oplock (share mode: none)\n");
548 ZERO_STRUCT(break_info);
549 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
550 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
552 status = smb2_create(tree1, tctx, &(io.smb2));
553 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
554 h1 = io.smb2.out.file.handle;
555 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
557 torture_comment(tctx, "setpathinfo EOF should trigger a break to "
558 "none\n");
559 ZERO_STRUCT(sfi);
560 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
561 sfi.generic.in.file.path = fname;
562 sfi.end_of_file_info.in.size = 100;
564 status = smb2_composite_setpathinfo(tree2, &sfi);
566 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
567 "Incorrect status");
568 torture_wait_for_oplock_break(tctx);
569 CHECK_VAL(break_info.count, 0);
570 CHECK_VAL(break_info.failures, 0);
571 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
573 smb2_util_close(tree1, h1);
574 smb2_util_close(tree1, h);
576 smb2_deltree(tree1, BASEDIR);
577 return ret;
580 static bool test_smb2_oplock_exclusive4(struct torture_context *tctx,
581 struct smb2_tree *tree1,
582 struct smb2_tree *tree2)
584 const char *fname = BASEDIR "\\test_exclusive4.dat";
585 NTSTATUS status;
586 bool ret = true;
587 union smb_open io;
588 struct smb2_handle h, h1, h2;
590 status = torture_smb2_testdir(tree1, BASEDIR, &h);
591 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
593 /* cleanup */
594 smb2_util_unlink(tree1, fname);
596 tree1->session->transport->oplock.handler = torture_oplock_handler;
597 tree1->session->transport->oplock.private_data = tree1;
600 base ntcreatex parms
602 ZERO_STRUCT(io.smb2);
603 io.generic.level = RAW_OPEN_SMB2;
604 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
605 io.smb2.in.alloc_size = 0;
606 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
607 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
608 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
609 io.smb2.in.create_options = 0;
610 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
611 io.smb2.in.security_flags = 0;
612 io.smb2.in.fname = fname;
614 torture_comment(tctx, "EXCLUSIVE4: open with exclusive oplock\n");
615 ZERO_STRUCT(break_info);
617 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
618 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
619 status = smb2_create(tree1, tctx, &(io.smb2));
620 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
621 h1 = io.smb2.out.file.handle;
622 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
624 ZERO_STRUCT(break_info);
625 torture_comment(tctx, "second open with attributes only shouldn't "
626 "cause oplock break\n");
628 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
629 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
630 SEC_FILE_WRITE_ATTRIBUTE |
631 SEC_STD_SYNCHRONIZE;
632 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
633 status = smb2_create(tree2, tctx, &(io.smb2));
634 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
635 h2 = io.smb2.out.file.handle;
636 CHECK_VAL(io.smb2.out.oplock_level, NO_OPLOCK_RETURN);
637 torture_wait_for_oplock_break(tctx);
638 CHECK_VAL(break_info.count, 0);
639 CHECK_VAL(break_info.failures, 0);
641 smb2_util_close(tree1, h1);
642 smb2_util_close(tree2, h2);
643 smb2_util_close(tree1, h);
645 smb2_deltree(tree1, BASEDIR);
646 return ret;
649 static bool test_smb2_oplock_exclusive5(struct torture_context *tctx,
650 struct smb2_tree *tree1,
651 struct smb2_tree *tree2)
653 const char *fname = BASEDIR "\\test_exclusive5.dat";
654 NTSTATUS status;
655 bool ret = true;
656 union smb_open io;
657 struct smb2_handle h, h1, h2;
659 status = torture_smb2_testdir(tree1, BASEDIR, &h);
660 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
662 /* cleanup */
663 smb2_util_unlink(tree1, fname);
665 tree1->session->transport->oplock.handler = torture_oplock_handler;
666 tree1->session->transport->oplock.private_data = tree1;
668 tree2->session->transport->oplock.handler = torture_oplock_handler;
669 tree2->session->transport->oplock.private_data = tree2;
672 base ntcreatex parms
674 ZERO_STRUCT(io.smb2);
675 io.generic.level = RAW_OPEN_SMB2;
676 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
677 io.smb2.in.alloc_size = 0;
678 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
679 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
680 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
681 io.smb2.in.create_options = 0;
682 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
683 io.smb2.in.security_flags = 0;
684 io.smb2.in.fname = fname;
686 torture_comment(tctx, "EXCLUSIVE5: open with exclusive oplock\n");
687 ZERO_STRUCT(break_info);
689 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
690 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
691 NTCREATEX_SHARE_ACCESS_WRITE|
692 NTCREATEX_SHARE_ACCESS_DELETE;
693 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
694 status = smb2_create(tree1, tctx, &(io.smb2));
695 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
696 h1 = io.smb2.out.file.handle;
697 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
699 ZERO_STRUCT(break_info);
701 torture_comment(tctx, "second open with attributes only and "
702 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
703 "oplock break\n");
705 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
706 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
707 SEC_FILE_WRITE_ATTRIBUTE |
708 SEC_STD_SYNCHRONIZE;
709 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
710 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
711 status = smb2_create(tree2, tctx, &(io.smb2));
712 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
713 h2 = io.smb2.out.file.handle;
714 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
715 torture_wait_for_oplock_break(tctx);
716 CHECK_VAL(break_info.count, 1);
717 CHECK_VAL(break_info.failures, 0);
719 smb2_util_close(tree1, h1);
720 smb2_util_close(tree2, h2);
721 smb2_util_close(tree1, h);
723 smb2_deltree(tree1, BASEDIR);
724 return ret;
727 static bool test_smb2_oplock_exclusive6(struct torture_context *tctx,
728 struct smb2_tree *tree1,
729 struct smb2_tree *tree2)
731 const char *fname1 = BASEDIR "\\test_exclusive6_1.dat";
732 const char *fname2 = BASEDIR "\\test_exclusive6_2.dat";
733 NTSTATUS status;
734 bool ret = true;
735 union smb_open io;
736 union smb_setfileinfo sinfo;
737 struct smb2_close closeio;
738 struct smb2_handle h, h1;
740 status = torture_smb2_testdir(tree1, BASEDIR, &h);
741 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
743 /* cleanup */
744 smb2_util_unlink(tree1, fname1);
745 smb2_util_unlink(tree2, fname2);
747 tree1->session->transport->oplock.handler = torture_oplock_handler;
748 tree1->session->transport->oplock.private_data = tree1;
751 base ntcreatex parms
753 ZERO_STRUCT(io.smb2);
754 io.generic.level = RAW_OPEN_SMB2;
755 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
756 io.smb2.in.alloc_size = 0;
757 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
758 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
759 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
760 io.smb2.in.create_options = 0;
761 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
762 io.smb2.in.security_flags = 0;
763 io.smb2.in.fname = fname1;
765 torture_comment(tctx, "EXCLUSIVE6: open a file with an exclusive "
766 "oplock (share mode: none)\n");
767 ZERO_STRUCT(break_info);
768 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
769 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
771 status = smb2_create(tree1, tctx, &(io.smb2));
772 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
773 h1 = io.smb2.out.file.handle;
774 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
776 torture_comment(tctx, "rename with the parent directory handle open "
777 "for DELETE should not generate a break but get "
778 "a sharing violation\n");
779 ZERO_STRUCT(sinfo);
780 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
781 sinfo.rename_information.in.file.handle = h1;
782 sinfo.rename_information.in.overwrite = true;
783 sinfo.rename_information.in.new_name = fname2;
784 status = smb2_setinfo_file(tree1, &sinfo);
786 torture_comment(tctx, "trying rename while parent handle open for delete.\n");
787 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
788 "Incorrect status");
789 torture_wait_for_oplock_break(tctx);
790 CHECK_VAL(break_info.count, 0);
791 CHECK_VAL(break_info.failures, 0);
793 /* Close the parent directory handle. */
794 ZERO_STRUCT(closeio);
795 closeio.in.file.handle = h;
796 status = smb2_close(tree1, &closeio);
797 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
798 "Incorrect status");
800 /* Re-open without DELETE access. */
801 ZERO_STRUCT(io);
802 io.smb2.in.oplock_level = 0;
803 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL & (~SEC_STD_DELETE);
804 io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
805 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
806 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
807 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
808 io.smb2.in.fname = BASEDIR;
810 status = smb2_create(tree1, tctx, &(io.smb2));
811 torture_assert_ntstatus_ok(tctx, status, "Error opening the base directory");
813 torture_comment(tctx, "rename with the parent directory handle open "
814 "without DELETE should succeed without a break\n");
815 ZERO_STRUCT(sinfo);
816 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
817 sinfo.rename_information.in.file.handle = h1;
818 sinfo.rename_information.in.overwrite = true;
819 sinfo.rename_information.in.new_name = fname2;
820 status = smb2_setinfo_file(tree1, &sinfo);
822 torture_comment(tctx, "trying rename while parent handle open without delete\n");
823 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
824 "Incorrect status");
825 torture_wait_for_oplock_break(tctx);
826 CHECK_VAL(break_info.count, 0);
827 CHECK_VAL(break_info.failures, 0);
829 smb2_util_close(tree1, h1);
830 smb2_util_close(tree1, h);
832 smb2_deltree(tree1, BASEDIR);
833 return ret;
836 static bool test_smb2_oplock_batch1(struct torture_context *tctx,
837 struct smb2_tree *tree1,
838 struct smb2_tree *tree2)
840 const char *fname = BASEDIR "\\test_batch1.dat";
841 NTSTATUS status;
842 bool ret = true;
843 union smb_open io;
844 struct smb2_handle h, h1;
845 char c = 0;
847 status = torture_smb2_testdir(tree1, BASEDIR, &h);
848 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
850 /* cleanup */
851 smb2_util_unlink(tree1, fname);
853 tree1->session->transport->oplock.handler = torture_oplock_handler;
854 tree1->session->transport->oplock.private_data = tree1;
857 base ntcreatex parms
859 ZERO_STRUCT(io.smb2);
860 io.generic.level = RAW_OPEN_SMB2;
861 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
862 io.smb2.in.alloc_size = 0;
863 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
864 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
865 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
866 io.smb2.in.create_options = 0;
867 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
868 io.smb2.in.security_flags = 0;
869 io.smb2.in.fname = fname;
872 with a batch oplock we get a break
874 torture_comment(tctx, "BATCH1: open with batch oplock\n");
875 ZERO_STRUCT(break_info);
876 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
877 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
878 status = smb2_create(tree1, tctx, &(io.smb2));
879 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
880 h1 = io.smb2.out.file.handle;
881 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
883 torture_comment(tctx, "unlink should generate a break\n");
884 status = smb2_util_unlink(tree2, fname);
885 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
886 "Incorrect status");
888 torture_wait_for_oplock_break(tctx);
889 CHECK_VAL(break_info.count, 1);
890 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
891 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
892 CHECK_VAL(break_info.failures, 0);
894 torture_comment(tctx, "2nd unlink should not generate a break\n");
895 ZERO_STRUCT(break_info);
896 status = smb2_util_unlink(tree2, fname);
897 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
898 "Incorrect status");
900 torture_wait_for_oplock_break(tctx);
901 CHECK_VAL(break_info.count, 0);
903 torture_comment(tctx, "writing should generate a self break to none\n");
904 tree1->session->transport->oplock.handler =
905 torture_oplock_handler_level2_to_none;
906 smb2_util_write(tree1, h1, &c, 0, 1);
908 torture_wait_for_oplock_break(tctx);
910 CHECK_VAL(break_info.count, 1);
911 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
912 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
913 CHECK_VAL(break_info.failures, 0);
915 smb2_util_close(tree1, h1);
916 smb2_util_close(tree1, h);
918 smb2_deltree(tree1, BASEDIR);
919 return ret;
922 static bool test_smb2_oplock_batch2(struct torture_context *tctx,
923 struct smb2_tree *tree1,
924 struct smb2_tree *tree2)
926 const char *fname = BASEDIR "\\test_batch2.dat";
927 NTSTATUS status;
928 bool ret = true;
929 union smb_open io;
930 char c = 0;
931 struct smb2_handle h, h1;
933 status = torture_smb2_testdir(tree1, BASEDIR, &h);
934 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
936 /* cleanup */
937 smb2_util_unlink(tree1, fname);
939 tree1->session->transport->oplock.handler = torture_oplock_handler;
940 tree1->session->transport->oplock.private_data = tree1;
943 base ntcreatex parms
945 ZERO_STRUCT(io.smb2);
946 io.generic.level = RAW_OPEN_SMB2;
947 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
948 io.smb2.in.alloc_size = 0;
949 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
950 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
951 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
952 io.smb2.in.create_options = 0;
953 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
954 io.smb2.in.security_flags = 0;
955 io.smb2.in.fname = fname;
957 torture_comment(tctx, "BATCH2: open with batch oplock\n");
958 ZERO_STRUCT(break_info);
959 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
960 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
961 status = smb2_create(tree1, tctx, &(io.smb2));
962 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
963 h1 = io.smb2.out.file.handle;
964 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
966 torture_comment(tctx, "unlink should generate a break, which we ack "
967 "as break to none\n");
968 tree1->session->transport->oplock.handler =
969 torture_oplock_handler_ack_to_none;
970 tree1->session->transport->oplock.private_data = tree1;
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, 1);
977 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
978 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
979 CHECK_VAL(break_info.failures, 0);
981 torture_comment(tctx, "2nd unlink should not generate a break\n");
982 ZERO_STRUCT(break_info);
983 status = smb2_util_unlink(tree2, fname);
984 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
985 "Incorrect status");
987 torture_wait_for_oplock_break(tctx);
988 CHECK_VAL(break_info.count, 0);
990 torture_comment(tctx, "writing should not generate a break\n");
991 smb2_util_write(tree1, h1, &c, 0, 1);
993 torture_wait_for_oplock_break(tctx);
994 CHECK_VAL(break_info.count, 0);
996 smb2_util_close(tree1, h1);
997 smb2_util_close(tree1, h);
999 smb2_deltree(tree1, BASEDIR);
1000 return ret;
1003 static bool test_smb2_oplock_batch3(struct torture_context *tctx,
1004 struct smb2_tree *tree1,
1005 struct smb2_tree *tree2)
1007 const char *fname = BASEDIR "\\test_batch3.dat";
1008 NTSTATUS status;
1009 bool ret = true;
1010 union smb_open io;
1011 struct smb2_handle h, h1;
1013 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1014 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1016 /* cleanup */
1017 smb2_util_unlink(tree1, fname);
1018 tree1->session->transport->oplock.handler = torture_oplock_handler;
1019 tree1->session->transport->oplock.private_data = tree1;
1022 base ntcreatex parms
1024 ZERO_STRUCT(io.smb2);
1025 io.generic.level = RAW_OPEN_SMB2;
1026 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1027 io.smb2.in.alloc_size = 0;
1028 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1029 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1030 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1031 io.smb2.in.create_options = 0;
1032 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1033 io.smb2.in.security_flags = 0;
1034 io.smb2.in.fname = fname;
1036 torture_comment(tctx, "BATCH3: if we close on break then the unlink "
1037 "can succeed\n");
1038 ZERO_STRUCT(break_info);
1039 tree1->session->transport->oplock.handler =
1040 torture_oplock_handler_close;
1041 tree1->session->transport->oplock.private_data = tree1;
1043 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1044 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1045 status = smb2_create(tree1, tctx, &(io.smb2));
1046 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1047 h1 = io.smb2.out.file.handle;
1048 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1050 ZERO_STRUCT(break_info);
1051 status = smb2_util_unlink(tree2, fname);
1052 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1054 torture_wait_for_oplock_break(tctx);
1055 CHECK_VAL(break_info.count, 1);
1056 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1057 CHECK_VAL(break_info.level, 1);
1058 CHECK_VAL(break_info.failures, 0);
1060 smb2_util_close(tree1, h1);
1061 smb2_util_close(tree1, h);
1063 smb2_deltree(tree1, BASEDIR);
1064 return ret;
1067 static bool test_smb2_oplock_batch4(struct torture_context *tctx,
1068 struct smb2_tree *tree1,
1069 struct smb2_tree *tree2)
1071 const char *fname = BASEDIR "\\test_batch4.dat";
1072 NTSTATUS status;
1073 bool ret = true;
1074 union smb_open io;
1075 struct smb2_read r;
1076 struct smb2_handle h, h1;
1078 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1079 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1081 /* cleanup */
1082 smb2_util_unlink(tree1, fname);
1084 tree1->session->transport->oplock.handler = torture_oplock_handler;
1085 tree1->session->transport->oplock.private_data = tree1;
1088 base ntcreatex parms
1090 ZERO_STRUCT(io.smb2);
1091 io.generic.level = RAW_OPEN_SMB2;
1092 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1093 io.smb2.in.alloc_size = 0;
1094 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1095 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1096 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1097 io.smb2.in.create_options = 0;
1098 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1099 io.smb2.in.security_flags = 0;
1100 io.smb2.in.fname = fname;
1102 torture_comment(tctx, "BATCH4: a self read should not cause a break\n");
1103 ZERO_STRUCT(break_info);
1105 tree1->session->transport->oplock.handler = torture_oplock_handler;
1106 tree1->session->transport->oplock.private_data = tree1;
1108 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1109 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1110 status = smb2_create(tree1, tctx, &(io.smb2));
1111 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1112 h1 = io.smb2.out.file.handle;
1113 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1115 ZERO_STRUCT(r);
1116 r.in.file.handle = h1;
1117 r.in.offset = 0;
1119 status = smb2_read(tree1, tree1, &r);
1120 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1121 torture_wait_for_oplock_break(tctx);
1122 CHECK_VAL(break_info.count, 0);
1123 CHECK_VAL(break_info.failures, 0);
1125 smb2_util_close(tree1, h1);
1126 smb2_util_close(tree1, h);
1128 smb2_deltree(tree1, BASEDIR);
1129 return ret;
1132 static bool test_smb2_oplock_batch5(struct torture_context *tctx,
1133 struct smb2_tree *tree1,
1134 struct smb2_tree *tree2)
1136 const char *fname = BASEDIR "\\test_batch5.dat";
1137 NTSTATUS status;
1138 bool ret = true;
1139 union smb_open io;
1140 struct smb2_handle h, h1;
1142 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1143 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1145 /* cleanup */
1146 smb2_util_unlink(tree1, fname);
1148 tree1->session->transport->oplock.handler = torture_oplock_handler;
1149 tree1->session->transport->oplock.private_data = tree1;
1152 base ntcreatex parms
1154 ZERO_STRUCT(io.smb2);
1155 io.generic.level = RAW_OPEN_SMB2;
1156 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1157 io.smb2.in.alloc_size = 0;
1158 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1159 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1160 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1161 io.smb2.in.create_options = 0;
1162 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1163 io.smb2.in.security_flags = 0;
1164 io.smb2.in.fname = fname;
1166 torture_comment(tctx, "BATCH5: a 2nd open should give a break\n");
1167 ZERO_STRUCT(break_info);
1169 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1170 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1171 status = smb2_create(tree1, tctx, &(io.smb2));
1172 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1173 h1 = io.smb2.out.file.handle;
1174 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1176 ZERO_STRUCT(break_info);
1178 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1179 status = smb2_create(tree2, tctx, &(io.smb2));
1180 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1181 "Incorrect status");
1183 torture_wait_for_oplock_break(tctx);
1184 CHECK_VAL(break_info.count, 1);
1185 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1186 CHECK_VAL(break_info.level, 1);
1187 CHECK_VAL(break_info.failures, 0);
1189 smb2_util_close(tree1, h1);
1190 smb2_util_close(tree1, h);
1192 smb2_deltree(tree1, BASEDIR);
1193 return ret;
1196 static bool test_smb2_oplock_batch6(struct torture_context *tctx,
1197 struct smb2_tree *tree1,
1198 struct smb2_tree *tree2)
1200 const char *fname = BASEDIR "\\test_batch6.dat";
1201 NTSTATUS status;
1202 bool ret = true;
1203 union smb_open io;
1204 struct smb2_handle h, h1, h2;
1205 char c = 0;
1207 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1208 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1210 /* cleanup */
1211 smb2_util_unlink(tree1, fname);
1213 tree1->session->transport->oplock.handler = torture_oplock_handler;
1214 tree1->session->transport->oplock.private_data = tree1;
1217 base ntcreatex parms
1219 ZERO_STRUCT(io.smb2);
1220 io.generic.level = RAW_OPEN_SMB2;
1221 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1222 io.smb2.in.alloc_size = 0;
1223 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1224 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1225 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1226 io.smb2.in.create_options = 0;
1227 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1228 io.smb2.in.security_flags = 0;
1229 io.smb2.in.fname = fname;
1231 torture_comment(tctx, "BATCH6: a 2nd open should give a break to "
1232 "level II if the first open allowed shared read\n");
1233 ZERO_STRUCT(break_info);
1234 tree2->session->transport->oplock.handler = torture_oplock_handler;
1235 tree2->session->transport->oplock.private_data = tree2;
1237 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
1238 SEC_RIGHTS_FILE_WRITE;
1239 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1240 NTCREATEX_SHARE_ACCESS_WRITE;
1241 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1242 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1243 status = smb2_create(tree1, tctx, &(io.smb2));
1244 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1245 h1 = io.smb2.out.file.handle;
1246 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1248 ZERO_STRUCT(break_info);
1250 status = smb2_create(tree2, tctx, &(io.smb2));
1251 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1252 h2 = io.smb2.out.file.handle;
1253 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1255 torture_wait_for_oplock_break(tctx);
1256 CHECK_VAL(break_info.count, 1);
1257 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1258 CHECK_VAL(break_info.level, 1);
1259 CHECK_VAL(break_info.failures, 0);
1260 ZERO_STRUCT(break_info);
1262 torture_comment(tctx, "write should trigger a break to none on both\n");
1263 tree1->session->transport->oplock.handler =
1264 torture_oplock_handler_level2_to_none;
1265 tree2->session->transport->oplock.handler =
1266 torture_oplock_handler_level2_to_none;
1267 smb2_util_write(tree1, h1, &c, 0, 1);
1269 /* We expect two breaks */
1270 torture_wait_for_oplock_break(tctx);
1271 torture_wait_for_oplock_break(tctx);
1273 CHECK_VAL(break_info.count, 2);
1274 CHECK_VAL(break_info.level, 0);
1275 CHECK_VAL(break_info.failures, 0);
1277 smb2_util_close(tree1, h1);
1278 smb2_util_close(tree2, h2);
1279 smb2_util_close(tree1, h);
1281 smb2_deltree(tree1, BASEDIR);
1282 return ret;
1285 static bool test_smb2_oplock_batch7(struct torture_context *tctx,
1286 struct smb2_tree *tree1,
1287 struct smb2_tree *tree2)
1289 const char *fname = BASEDIR "\\test_batch7.dat";
1290 NTSTATUS status;
1291 bool ret = true;
1292 union smb_open io;
1293 struct smb2_handle h, h1, h2;
1295 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1296 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1298 /* cleanup */
1299 smb2_util_unlink(tree1, fname);
1301 tree1->session->transport->oplock.handler = torture_oplock_handler;
1302 tree1->session->transport->oplock.private_data = tree1;
1305 base ntcreatex parms
1307 ZERO_STRUCT(io.smb2);
1308 io.generic.level = RAW_OPEN_SMB2;
1309 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1310 io.smb2.in.alloc_size = 0;
1311 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1312 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1313 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1314 io.smb2.in.create_options = 0;
1315 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1316 io.smb2.in.security_flags = 0;
1317 io.smb2.in.fname = fname;
1319 torture_comment(tctx, "BATCH7: a 2nd open should get an oplock when "
1320 "we close instead of ack\n");
1321 ZERO_STRUCT(break_info);
1322 tree1->session->transport->oplock.handler =
1323 torture_oplock_handler_close;
1324 tree1->session->transport->oplock.private_data = tree1;
1326 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1327 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1328 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1329 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1330 status = smb2_create(tree1, tctx, &(io.smb2));
1331 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1332 h2 = io.smb2.out.file.handle;
1333 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1335 ZERO_STRUCT(break_info);
1337 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1338 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1339 status = smb2_create(tree2, tctx, &(io.smb2));
1340 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1341 h1 = io.smb2.out.file.handle;
1342 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1344 torture_wait_for_oplock_break(tctx);
1345 CHECK_VAL(break_info.count, 1);
1346 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1347 CHECK_VAL(break_info.level, 1);
1348 CHECK_VAL(break_info.failures, 0);
1350 smb2_util_close(tree2, h1);
1351 smb2_util_close(tree2, h);
1353 smb2_deltree(tree1, BASEDIR);
1354 return ret;
1357 static bool test_smb2_oplock_batch8(struct torture_context *tctx,
1358 struct smb2_tree *tree1,
1359 struct smb2_tree *tree2)
1361 const char *fname = BASEDIR "\\test_batch8.dat";
1362 NTSTATUS status;
1363 bool ret = true;
1364 union smb_open io;
1365 struct smb2_handle h, h1, h2;
1367 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1368 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1370 /* cleanup */
1371 smb2_util_unlink(tree1, fname);
1373 tree1->session->transport->oplock.handler = torture_oplock_handler;
1374 tree1->session->transport->oplock.private_data = tree1;
1377 base ntcreatex parms
1379 ZERO_STRUCT(io.smb2);
1380 io.generic.level = RAW_OPEN_SMB2;
1381 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1382 io.smb2.in.alloc_size = 0;
1383 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1384 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1385 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1386 io.smb2.in.create_options = 0;
1387 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1388 io.smb2.in.security_flags = 0;
1389 io.smb2.in.fname = fname;
1391 torture_comment(tctx, "BATCH8: open with batch oplock\n");
1392 ZERO_STRUCT(break_info);
1394 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1395 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1396 status = smb2_create(tree1, tctx, &(io.smb2));
1397 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1398 h1 = io.smb2.out.file.handle;
1399 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1401 ZERO_STRUCT(break_info);
1402 torture_comment(tctx, "second open with attributes only shouldn't "
1403 "cause oplock break\n");
1405 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1406 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1407 SEC_FILE_WRITE_ATTRIBUTE |
1408 SEC_STD_SYNCHRONIZE;
1409 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1410 status = smb2_create(tree2, tctx, &(io.smb2));
1411 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1412 h2 = io.smb2.out.file.handle;
1413 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1414 torture_wait_for_oplock_break(tctx);
1415 CHECK_VAL(break_info.count, 0);
1416 CHECK_VAL(break_info.failures, 0);
1418 smb2_util_close(tree1, h1);
1419 smb2_util_close(tree2, h2);
1420 smb2_util_close(tree1, h);
1422 smb2_deltree(tree1, BASEDIR);
1423 return ret;
1426 static bool test_smb2_oplock_batch9(struct torture_context *tctx,
1427 struct smb2_tree *tree1,
1428 struct smb2_tree *tree2)
1430 const char *fname = BASEDIR "\\test_batch9.dat";
1431 NTSTATUS status;
1432 bool ret = true;
1433 union smb_open io;
1434 struct smb2_handle h, h1, h2;
1435 char c = 0;
1437 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1438 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1440 /* cleanup */
1441 smb2_util_unlink(tree1, fname);
1443 tree1->session->transport->oplock.handler = torture_oplock_handler;
1444 tree1->session->transport->oplock.private_data = tree1;
1447 base ntcreatex parms
1449 ZERO_STRUCT(io.smb2);
1450 io.generic.level = RAW_OPEN_SMB2;
1451 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1452 io.smb2.in.alloc_size = 0;
1453 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1454 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1455 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1456 io.smb2.in.create_options = 0;
1457 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1458 io.smb2.in.security_flags = 0;
1459 io.smb2.in.fname = fname;
1461 torture_comment(tctx, "BATCH9: open with attributes only can create "
1462 "file\n");
1464 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1465 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1466 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1467 SEC_FILE_WRITE_ATTRIBUTE |
1468 SEC_STD_SYNCHRONIZE;
1469 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1470 status = smb2_create(tree1, tctx, &(io.smb2));
1471 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1472 h1 = io.smb2.out.file.handle;
1473 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1475 torture_comment(tctx, "Subsequent normal open should break oplock on "
1476 "attribute only open to level II\n");
1478 ZERO_STRUCT(break_info);
1480 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1481 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1482 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1483 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1484 status = smb2_create(tree2, tctx, &(io.smb2));
1485 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1486 h2 = io.smb2.out.file.handle;
1487 torture_wait_for_oplock_break(tctx);
1488 CHECK_VAL(break_info.count, 1);
1489 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1490 CHECK_VAL(break_info.failures, 0);
1491 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1492 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1493 smb2_util_close(tree2, h2);
1495 torture_comment(tctx, "third oplocked open should grant level2 without "
1496 "break\n");
1497 ZERO_STRUCT(break_info);
1499 tree2->session->transport->oplock.handler = torture_oplock_handler;
1500 tree2->session->transport->oplock.private_data = tree2;
1502 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1503 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1504 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1505 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1506 status = smb2_create(tree2, tctx, &(io.smb2));
1507 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1508 h2 = io.smb2.out.file.handle;
1509 torture_wait_for_oplock_break(tctx);
1510 CHECK_VAL(break_info.count, 0);
1511 CHECK_VAL(break_info.failures, 0);
1512 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1514 ZERO_STRUCT(break_info);
1516 torture_comment(tctx, "write should trigger a break to none on both\n");
1517 tree1->session->transport->oplock.handler =
1518 torture_oplock_handler_level2_to_none;
1519 tree2->session->transport->oplock.handler =
1520 torture_oplock_handler_level2_to_none;
1521 smb2_util_write(tree2, h2, &c, 0, 1);
1523 /* We expect two breaks */
1524 torture_wait_for_oplock_break(tctx);
1525 torture_wait_for_oplock_break(tctx);
1527 CHECK_VAL(break_info.count, 2);
1528 CHECK_VAL(break_info.level, 0);
1529 CHECK_VAL(break_info.failures, 0);
1531 smb2_util_close(tree1, h1);
1532 smb2_util_close(tree2, h2);
1533 smb2_util_close(tree1, h);
1535 smb2_deltree(tree1, BASEDIR);
1536 return ret;
1539 static bool test_smb2_oplock_batch10(struct torture_context *tctx,
1540 struct smb2_tree *tree1,
1541 struct smb2_tree *tree2)
1543 const char *fname = BASEDIR "\\test_batch10.dat";
1544 NTSTATUS status;
1545 bool ret = true;
1546 union smb_open io;
1547 struct smb2_handle h, h1, h2;
1549 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1550 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1552 /* cleanup */
1553 smb2_util_unlink(tree1, fname);
1555 tree1->session->transport->oplock.handler = torture_oplock_handler;
1556 tree1->session->transport->oplock.private_data = tree1;
1559 base ntcreatex parms
1561 ZERO_STRUCT(io.smb2);
1562 io.generic.level = RAW_OPEN_SMB2;
1563 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1564 io.smb2.in.alloc_size = 0;
1565 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1566 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1567 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1568 io.smb2.in.create_options = 0;
1569 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1570 io.smb2.in.security_flags = 0;
1571 io.smb2.in.fname = fname;
1573 torture_comment(tctx, "BATCH10: Open with oplock after a non-oplock "
1574 "open should grant level2\n");
1575 ZERO_STRUCT(break_info);
1576 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1577 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1578 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1579 NTCREATEX_SHARE_ACCESS_WRITE|
1580 NTCREATEX_SHARE_ACCESS_DELETE;
1581 status = smb2_create(tree1, tctx, &(io.smb2));
1582 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1583 h1 = 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, 0);
1589 tree2->session->transport->oplock.handler =
1590 torture_oplock_handler_level2_to_none;
1591 tree2->session->transport->oplock.private_data = tree2;
1593 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1594 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1595 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1596 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1597 NTCREATEX_SHARE_ACCESS_WRITE|
1598 NTCREATEX_SHARE_ACCESS_DELETE;
1599 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1600 status = smb2_create(tree2, tctx, &(io.smb2));
1601 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1602 h2 = io.smb2.out.file.handle;
1603 torture_wait_for_oplock_break(tctx);
1604 CHECK_VAL(break_info.count, 0);
1605 CHECK_VAL(break_info.failures, 0);
1606 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1608 torture_comment(tctx, "write should trigger a break to none\n");
1610 struct smb2_write wr;
1611 DATA_BLOB data;
1612 data = data_blob_talloc(tree1, NULL, UINT16_MAX);
1613 data.data[0] = (const uint8_t)'x';
1614 ZERO_STRUCT(wr);
1615 wr.in.file.handle = h1;
1616 wr.in.offset = 0;
1617 wr.in.data = data;
1618 status = smb2_write(tree1, &wr);
1619 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1622 torture_wait_for_oplock_break(tctx);
1624 CHECK_VAL(break_info.count, 1);
1625 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1626 CHECK_VAL(break_info.level, 0);
1627 CHECK_VAL(break_info.failures, 0);
1629 smb2_util_close(tree1, h1);
1630 smb2_util_close(tree2, h2);
1631 smb2_util_close(tree1, h);
1633 smb2_deltree(tree1, BASEDIR);
1634 return ret;
1637 static bool test_smb2_oplock_batch11(struct torture_context *tctx,
1638 struct smb2_tree *tree1,
1639 struct smb2_tree *tree2)
1641 const char *fname = BASEDIR "\\test_batch11.dat";
1642 NTSTATUS status;
1643 bool ret = true;
1644 union smb_open io;
1645 union smb_setfileinfo sfi;
1646 struct smb2_handle h, h1;
1648 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1649 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1651 /* cleanup */
1652 smb2_util_unlink(tree1, fname);
1654 tree1->session->transport->oplock.handler =
1655 torture_oplock_handler_two_notifications;
1656 tree1->session->transport->oplock.private_data = tree1;
1659 base ntcreatex parms
1661 ZERO_STRUCT(io.smb2);
1662 io.generic.level = RAW_OPEN_SMB2;
1663 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1664 io.smb2.in.alloc_size = 0;
1665 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1666 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1667 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1668 io.smb2.in.create_options = 0;
1669 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1670 io.smb2.in.security_flags = 0;
1671 io.smb2.in.fname = fname;
1673 /* Test if a set-eof on pathname breaks an exclusive oplock. */
1674 torture_comment(tctx, "BATCH11: Test if setpathinfo set EOF breaks "
1675 "oplocks.\n");
1677 ZERO_STRUCT(break_info);
1679 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1680 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1681 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1682 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1683 NTCREATEX_SHARE_ACCESS_WRITE|
1684 NTCREATEX_SHARE_ACCESS_DELETE;
1685 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1686 status = smb2_create(tree1, tctx, &(io.smb2));
1687 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1688 h1 = io.smb2.out.file.handle;
1689 torture_wait_for_oplock_break(tctx);
1690 CHECK_VAL(break_info.count, 0);
1691 CHECK_VAL(break_info.failures, 0);
1692 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1694 ZERO_STRUCT(sfi);
1695 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1696 sfi.generic.in.file.path = fname;
1697 sfi.end_of_file_info.in.size = 100;
1699 status = smb2_composite_setpathinfo(tree2, &sfi);
1700 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1702 /* We expect two breaks */
1703 torture_wait_for_oplock_break(tctx);
1704 torture_wait_for_oplock_break(tctx);
1706 CHECK_VAL(break_info.count, 2);
1707 CHECK_VAL(break_info.failures, 0);
1708 CHECK_VAL(break_info.level, 0);
1710 smb2_util_close(tree1, h1);
1711 smb2_util_close(tree1, h);
1713 smb2_deltree(tree1, BASEDIR);
1714 return ret;
1717 static bool test_smb2_oplock_batch12(struct torture_context *tctx,
1718 struct smb2_tree *tree1,
1719 struct smb2_tree *tree2)
1721 const char *fname = BASEDIR "\\test_batch12.dat";
1722 NTSTATUS status;
1723 bool ret = true;
1724 union smb_open io;
1725 union smb_setfileinfo sfi;
1726 struct smb2_handle h, h1;
1728 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1729 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1731 /* cleanup */
1732 smb2_util_unlink(tree1, fname);
1734 tree1->session->transport->oplock.handler =
1735 torture_oplock_handler_two_notifications;
1736 tree1->session->transport->oplock.private_data = tree1;
1739 base ntcreatex parms
1741 ZERO_STRUCT(io.smb2);
1742 io.generic.level = RAW_OPEN_SMB2;
1743 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1744 io.smb2.in.alloc_size = 0;
1745 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1746 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1747 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1748 io.smb2.in.create_options = 0;
1749 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1750 io.smb2.in.security_flags = 0;
1751 io.smb2.in.fname = fname;
1753 /* Test if a set-allocation size on pathname breaks an exclusive
1754 * oplock. */
1755 torture_comment(tctx, "BATCH12: Test if setpathinfo allocation size "
1756 "breaks oplocks.\n");
1758 ZERO_STRUCT(break_info);
1760 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1761 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1762 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1763 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1764 NTCREATEX_SHARE_ACCESS_WRITE|
1765 NTCREATEX_SHARE_ACCESS_DELETE;
1766 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1767 status = smb2_create(tree1, tctx, &(io.smb2));
1768 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1769 h1 = io.smb2.out.file.handle;
1770 torture_wait_for_oplock_break(tctx);
1771 CHECK_VAL(break_info.count, 0);
1772 CHECK_VAL(break_info.failures, 0);
1773 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1775 ZERO_STRUCT(sfi);
1776 sfi.generic.level = RAW_SFILEINFO_ALLOCATION_INFORMATION;
1777 sfi.generic.in.file.path = fname;
1778 sfi.allocation_info.in.alloc_size = 65536 * 8;
1780 status = smb2_composite_setpathinfo(tree2, &sfi);
1781 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1783 /* We expect two breaks */
1784 torture_wait_for_oplock_break(tctx);
1785 torture_wait_for_oplock_break(tctx);
1787 CHECK_VAL(break_info.count, 2);
1788 CHECK_VAL(break_info.failures, 0);
1789 CHECK_VAL(break_info.level, 0);
1791 smb2_util_close(tree1, h1);
1792 smb2_util_close(tree1, h);
1794 smb2_deltree(tree1, BASEDIR);
1795 return ret;
1798 static bool test_smb2_oplock_batch13(struct torture_context *tctx,
1799 struct smb2_tree *tree1,
1800 struct smb2_tree *tree2)
1802 const char *fname = BASEDIR "\\test_batch13.dat";
1803 NTSTATUS status;
1804 bool ret = true;
1805 union smb_open io;
1806 struct smb2_handle h, h1, h2;
1808 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1809 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1811 /* cleanup */
1812 smb2_util_unlink(tree1, fname);
1814 tree1->session->transport->oplock.handler = torture_oplock_handler;
1815 tree1->session->transport->oplock.private_data = tree1;
1817 tree2->session->transport->oplock.handler = torture_oplock_handler;
1818 tree2->session->transport->oplock.private_data = tree2;
1821 base ntcreatex parms
1823 ZERO_STRUCT(io.smb2);
1824 io.generic.level = RAW_OPEN_SMB2;
1825 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1826 io.smb2.in.alloc_size = 0;
1827 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1828 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1829 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1830 io.smb2.in.create_options = 0;
1831 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1832 io.smb2.in.security_flags = 0;
1833 io.smb2.in.fname = fname;
1835 torture_comment(tctx, "BATCH13: open with batch oplock\n");
1836 ZERO_STRUCT(break_info);
1838 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1839 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1840 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1841 NTCREATEX_SHARE_ACCESS_WRITE|
1842 NTCREATEX_SHARE_ACCESS_DELETE;
1843 status = smb2_create(tree1, tctx, &(io.smb2));
1844 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1845 h1 = io.smb2.out.file.handle;
1846 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1848 ZERO_STRUCT(break_info);
1850 torture_comment(tctx, "second open with attributes only and "
1851 "NTCREATEX_DISP_OVERWRITE dispostion causes "
1852 "oplock break\n");
1854 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1855 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1856 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1857 SEC_FILE_WRITE_ATTRIBUTE |
1858 SEC_STD_SYNCHRONIZE;
1859 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1860 NTCREATEX_SHARE_ACCESS_WRITE|
1861 NTCREATEX_SHARE_ACCESS_DELETE;
1862 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1863 status = smb2_create(tree2, tctx, &(io.smb2));
1864 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1865 h2 = io.smb2.out.file.handle;
1866 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1867 torture_wait_for_oplock_break(tctx);
1868 CHECK_VAL(break_info.count, 1);
1869 CHECK_VAL(break_info.failures, 0);
1871 smb2_util_close(tree1, h1);
1872 smb2_util_close(tree2, h2);
1873 smb2_util_close(tree1, h);
1875 smb2_deltree(tree1, BASEDIR);
1877 return ret;
1880 static bool test_smb2_oplock_batch14(struct torture_context *tctx,
1881 struct smb2_tree *tree1,
1882 struct smb2_tree *tree2)
1884 const char *fname = BASEDIR "\\test_batch14.dat";
1885 NTSTATUS status;
1886 bool ret = true;
1887 union smb_open io;
1888 struct smb2_handle h, h1, h2;
1890 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1891 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1893 /* cleanup */
1894 smb2_util_unlink(tree1, fname);
1896 tree1->session->transport->oplock.handler = torture_oplock_handler;
1897 tree1->session->transport->oplock.private_data = tree1;
1900 base ntcreatex parms
1902 ZERO_STRUCT(io.smb2);
1903 io.generic.level = RAW_OPEN_SMB2;
1904 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1905 io.smb2.in.alloc_size = 0;
1906 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1907 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1908 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1909 io.smb2.in.create_options = 0;
1910 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1911 io.smb2.in.security_flags = 0;
1912 io.smb2.in.fname = fname;
1914 torture_comment(tctx, "BATCH14: open with batch oplock\n");
1915 ZERO_STRUCT(break_info);
1917 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1918 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1919 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1920 NTCREATEX_SHARE_ACCESS_WRITE|
1921 NTCREATEX_SHARE_ACCESS_DELETE;
1922 status = smb2_create(tree1, tctx, &(io.smb2));
1923 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1924 h1 = io.smb2.out.file.handle;
1925 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1927 ZERO_STRUCT(break_info);
1929 torture_comment(tctx, "second open with attributes only and "
1930 "NTCREATEX_DISP_SUPERSEDE dispostion causes "
1931 "oplock break\n");
1933 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1934 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1935 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1936 SEC_FILE_WRITE_ATTRIBUTE |
1937 SEC_STD_SYNCHRONIZE;
1938 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1939 NTCREATEX_SHARE_ACCESS_WRITE|
1940 NTCREATEX_SHARE_ACCESS_DELETE;
1941 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1942 status = smb2_create(tree2, tctx, &(io.smb2));
1943 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1944 h2 = io.smb2.out.file.handle;
1945 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1947 torture_wait_for_oplock_break(tctx);
1948 CHECK_VAL(break_info.count, 1);
1949 CHECK_VAL(break_info.failures, 0);
1951 smb2_util_close(tree1, h1);
1952 smb2_util_close(tree2, h2);
1953 smb2_util_close(tree1, h);
1955 smb2_deltree(tree1, BASEDIR);
1956 return ret;
1959 static bool test_smb2_oplock_batch15(struct torture_context *tctx,
1960 struct smb2_tree *tree1,
1961 struct smb2_tree *tree2)
1963 const char *fname = BASEDIR "\\test_batch15.dat";
1964 NTSTATUS status;
1965 bool ret = true;
1966 union smb_open io;
1967 union smb_fileinfo qfi;
1968 struct smb2_handle h, h1;
1970 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1971 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1973 /* cleanup */
1974 smb2_util_unlink(tree1, fname);
1976 tree1->session->transport->oplock.handler = torture_oplock_handler;
1977 tree1->session->transport->oplock.private_data = tree1;
1980 base ntcreatex parms
1982 ZERO_STRUCT(io.smb2);
1983 io.generic.level = RAW_OPEN_SMB2;
1984 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1985 io.smb2.in.alloc_size = 0;
1986 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1987 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1988 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1989 io.smb2.in.create_options = 0;
1990 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1991 io.smb2.in.security_flags = 0;
1992 io.smb2.in.fname = fname;
1994 /* Test if a qpathinfo all info on pathname breaks a batch oplock. */
1995 torture_comment(tctx, "BATCH15: Test if qpathinfo all info breaks "
1996 "a batch oplock (should not).\n");
1998 ZERO_STRUCT(break_info);
2000 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2001 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2002 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2003 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2004 NTCREATEX_SHARE_ACCESS_WRITE|
2005 NTCREATEX_SHARE_ACCESS_DELETE;
2006 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2007 status = smb2_create(tree1, tctx, &(io.smb2));
2008 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2009 h1 = io.smb2.out.file.handle;
2011 torture_wait_for_oplock_break(tctx);
2012 CHECK_VAL(break_info.count, 0);
2013 CHECK_VAL(break_info.failures, 0);
2014 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2016 ZERO_STRUCT(qfi);
2017 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2018 qfi.generic.in.file.handle = h1;
2019 status = smb2_getinfo_file(tree2, tctx, &qfi);
2021 torture_wait_for_oplock_break(tctx);
2022 CHECK_VAL(break_info.count, 0);
2024 smb2_util_close(tree1, h1);
2025 smb2_util_close(tree1, h);
2027 smb2_deltree(tree1, BASEDIR);
2028 return ret;
2031 static bool test_smb2_oplock_batch16(struct torture_context *tctx,
2032 struct smb2_tree *tree1,
2033 struct smb2_tree *tree2)
2035 const char *fname = BASEDIR "\\test_batch16.dat";
2036 NTSTATUS status;
2037 bool ret = true;
2038 union smb_open io;
2039 struct smb2_handle h, h1, h2;
2041 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2042 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2044 /* cleanup */
2045 smb2_util_unlink(tree1, fname);
2047 tree1->session->transport->oplock.handler = torture_oplock_handler;
2048 tree1->session->transport->oplock.private_data = tree1;
2050 tree2->session->transport->oplock.handler = torture_oplock_handler;
2051 tree2->session->transport->oplock.private_data = tree2;
2054 base ntcreatex parms
2056 ZERO_STRUCT(io.smb2);
2057 io.generic.level = RAW_OPEN_SMB2;
2058 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2059 io.smb2.in.alloc_size = 0;
2060 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2061 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2062 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2063 io.smb2.in.create_options = 0;
2064 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2065 io.smb2.in.security_flags = 0;
2066 io.smb2.in.fname = fname;
2068 torture_comment(tctx, "BATCH16: open with batch oplock\n");
2069 ZERO_STRUCT(break_info);
2071 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2072 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2073 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2074 NTCREATEX_SHARE_ACCESS_WRITE|
2075 NTCREATEX_SHARE_ACCESS_DELETE;
2076 status = smb2_create(tree1, tctx, &(io.smb2));
2077 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2078 h1 = io.smb2.out.file.handle;
2079 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2081 ZERO_STRUCT(break_info);
2083 torture_comment(tctx, "second open with attributes only and "
2084 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
2085 "oplock break\n");
2087 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2088 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2089 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2090 SEC_FILE_WRITE_ATTRIBUTE |
2091 SEC_STD_SYNCHRONIZE;
2092 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2093 NTCREATEX_SHARE_ACCESS_WRITE|
2094 NTCREATEX_SHARE_ACCESS_DELETE;
2095 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
2096 status = smb2_create(tree2, tctx, &(io.smb2));
2097 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2098 h2 = io.smb2.out.file.handle;
2099 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2101 torture_wait_for_oplock_break(tctx);
2102 CHECK_VAL(break_info.count, 1);
2103 CHECK_VAL(break_info.failures, 0);
2105 smb2_util_close(tree1, h1);
2106 smb2_util_close(tree2, h2);
2107 smb2_util_close(tree1, h);
2109 smb2_deltree(tree1, BASEDIR);
2110 return ret;
2113 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH17 test. Since
2114 * SMB2 doesn't have a RENAME command this test isn't applicable. However,
2115 * it's much less confusing, when comparing test, to keep the SMB1 and SMB2
2116 * test numbers in sync. */
2117 #if 0
2118 static bool test_raw_oplock_batch17(struct torture_context *tctx,
2119 struct smb2_tree *tree1,
2120 struct smb2_tree *tree2)
2122 return true;
2124 #endif
2126 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH18 test. Since
2127 * SMB2 doesn't have an NTRENAME command this test isn't applicable. However,
2128 * it's much less confusing, when comparing tests, to keep the SMB1 and SMB2
2129 * test numbers in sync. */
2130 #if 0
2131 static bool test_raw_oplock_batch18(struct torture_context *tctx,
2132 struct smb2_tree *tree1,
2133 struct smb2_tree *tree2)
2135 return true;
2137 #endif
2139 static bool test_smb2_oplock_batch19(struct torture_context *tctx,
2140 struct smb2_tree *tree1)
2142 const char *fname1 = BASEDIR "\\test_batch19_1.dat";
2143 const char *fname2 = BASEDIR "\\test_batch19_2.dat";
2144 NTSTATUS status;
2145 bool ret = true;
2146 union smb_open io;
2147 union smb_fileinfo qfi;
2148 union smb_setfileinfo sfi;
2149 struct smb2_handle h, h1;
2151 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2152 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2154 /* cleanup */
2155 smb2_util_unlink(tree1, fname1);
2156 smb2_util_unlink(tree1, fname2);
2158 tree1->session->transport->oplock.handler = torture_oplock_handler;
2159 tree1->session->transport->oplock.private_data = tree1;
2162 base ntcreatex parms
2164 ZERO_STRUCT(io.smb2);
2165 io.generic.level = RAW_OPEN_SMB2;
2166 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2167 io.smb2.in.alloc_size = 0;
2168 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2169 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2170 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2171 io.smb2.in.create_options = 0;
2172 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2173 io.smb2.in.security_flags = 0;
2174 io.smb2.in.fname = fname1;
2176 torture_comment(tctx, "BATCH19: open a file with an batch oplock "
2177 "(share mode: none)\n");
2178 ZERO_STRUCT(break_info);
2179 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2180 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2181 status = smb2_create(tree1, tctx, &(io.smb2));
2182 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2183 h1 = io.smb2.out.file.handle;
2184 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2186 torture_comment(tctx, "setfileinfo rename info should not trigger "
2187 "a break but should cause a sharing violation\n");
2188 ZERO_STRUCT(sfi);
2189 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2190 sfi.generic.in.file.path = fname1;
2191 sfi.rename_information.in.file.handle = h1;
2192 sfi.rename_information.in.overwrite = 0;
2193 sfi.rename_information.in.root_fid = 0;
2194 sfi.rename_information.in.new_name = fname2;
2196 status = smb2_setinfo_file(tree1, &sfi);
2198 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2199 "Incorrect status");
2201 torture_wait_for_oplock_break(tctx);
2202 CHECK_VAL(break_info.count, 0);
2204 ZERO_STRUCT(qfi);
2205 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2206 qfi.generic.in.file.handle = h1;
2208 status = smb2_getinfo_file(tree1, tctx, &qfi);
2209 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2210 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2212 smb2_util_close(tree1, h1);
2213 smb2_util_close(tree1, h);
2215 smb2_deltree(tree1, fname1);
2216 smb2_deltree(tree1, fname2);
2217 return ret;
2220 static bool test_smb2_oplock_batch20(struct torture_context *tctx,
2221 struct smb2_tree *tree1,
2222 struct smb2_tree *tree2)
2224 const char *fname1 = BASEDIR "\\test_batch20_1.dat";
2225 const char *fname2 = BASEDIR "\\test_batch20_2.dat";
2226 NTSTATUS status;
2227 bool ret = true;
2228 union smb_open io;
2229 union smb_fileinfo qfi;
2230 union smb_setfileinfo sfi;
2231 struct smb2_handle h, h1, h2;
2233 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2234 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2236 /* cleanup */
2237 smb2_util_unlink(tree1, fname1);
2238 smb2_util_unlink(tree1, fname2);
2240 tree1->session->transport->oplock.handler = torture_oplock_handler;
2241 tree1->session->transport->oplock.private_data = tree1;
2244 base ntcreatex parms
2246 ZERO_STRUCT(io.smb2);
2247 io.generic.level = RAW_OPEN_SMB2;
2248 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2249 io.smb2.in.alloc_size = 0;
2250 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2251 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2252 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2253 io.smb2.in.create_options = 0;
2254 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2255 io.smb2.in.security_flags = 0;
2256 io.smb2.in.fname = fname1;
2258 torture_comment(tctx, "BATCH20: open a file with an batch oplock "
2259 "(share mode: all)\n");
2260 ZERO_STRUCT(break_info);
2261 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2262 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2263 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2264 NTCREATEX_SHARE_ACCESS_WRITE|
2265 NTCREATEX_SHARE_ACCESS_DELETE;
2266 status = smb2_create(tree1, tctx, &(io.smb2));
2267 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2268 h1 = io.smb2.out.file.handle;
2269 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2271 torture_comment(tctx, "setfileinfo rename info should not trigger "
2272 "a break but should cause a sharing violation\n");
2273 ZERO_STRUCT(sfi);
2274 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2275 sfi.rename_information.in.file.handle = h1;
2276 sfi.rename_information.in.overwrite = 0;
2277 sfi.rename_information.in.new_name = fname2;
2279 status = smb2_setinfo_file(tree1, &sfi);
2280 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2281 "Incorrect status");
2283 torture_wait_for_oplock_break(tctx);
2284 CHECK_VAL(break_info.count, 0);
2286 ZERO_STRUCT(qfi);
2287 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2288 qfi.generic.in.file.handle = h1;
2290 status = smb2_getinfo_file(tree1, tctx, &qfi);
2291 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2292 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2294 torture_comment(tctx, "open the file a second time requesting batch "
2295 "(share mode: all)\n");
2296 ZERO_STRUCT(break_info);
2297 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2298 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2299 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2300 NTCREATEX_SHARE_ACCESS_WRITE|
2301 NTCREATEX_SHARE_ACCESS_DELETE;
2302 io.smb2.in.fname = fname1;
2303 status = smb2_create(tree2, tctx, &(io.smb2));
2304 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2305 h2 = io.smb2.out.file.handle;
2306 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2308 torture_wait_for_oplock_break(tctx);
2309 CHECK_VAL(break_info.count, 1);
2310 CHECK_VAL(break_info.failures, 0);
2311 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2313 torture_comment(tctx, "setfileinfo rename info should not trigger "
2314 "a break but should cause a sharing violation\n");
2315 ZERO_STRUCT(break_info);
2316 ZERO_STRUCT(sfi);
2317 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2318 sfi.rename_information.in.file.handle = h2;
2319 sfi.rename_information.in.overwrite = 0;
2320 sfi.rename_information.in.new_name = fname2;
2322 status = smb2_setinfo_file(tree2, &sfi);
2323 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2324 "Incorrect status");
2326 torture_wait_for_oplock_break(tctx);
2327 CHECK_VAL(break_info.count, 0);
2329 ZERO_STRUCT(qfi);
2330 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2331 qfi.generic.in.file.handle = h1;
2333 status = smb2_getinfo_file(tree1, tctx, &qfi);
2334 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2335 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2337 ZERO_STRUCT(qfi);
2338 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2339 qfi.generic.in.file.handle = h2;
2341 status = smb2_getinfo_file(tree2, tctx, &qfi);
2342 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2343 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2345 smb2_util_close(tree1, h1);
2346 smb2_util_close(tree2, h2);
2347 smb2_util_close(tree1, h);
2349 smb2_deltree(tree1, fname1);
2350 return ret;
2353 static bool test_smb2_oplock_batch21(struct torture_context *tctx,
2354 struct smb2_tree *tree1)
2356 const char *fname = BASEDIR "\\test_batch21.dat";
2357 NTSTATUS status;
2358 bool ret = true;
2359 union smb_open io;
2360 struct smb2_handle h, h1;
2361 char c = 0;
2363 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2364 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2366 /* cleanup */
2367 smb2_util_unlink(tree1, fname);
2369 tree1->session->transport->oplock.handler = torture_oplock_handler;
2370 tree1->session->transport->oplock.private_data = tree1;
2373 base ntcreatex parms
2375 ZERO_STRUCT(io.smb2);
2376 io.generic.level = RAW_OPEN_SMB2;
2377 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2378 io.smb2.in.alloc_size = 0;
2379 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2380 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2381 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2382 io.smb2.in.create_options = 0;
2383 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2384 io.smb2.in.security_flags = 0;
2385 io.smb2.in.fname = fname;
2388 with a batch oplock we get a break
2390 torture_comment(tctx, "BATCH21: open with batch oplock\n");
2391 ZERO_STRUCT(break_info);
2392 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2393 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2394 status = smb2_create(tree1, tctx, &(io.smb2));
2395 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2396 h1 = io.smb2.out.file.handle;
2397 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2399 torture_comment(tctx, "writing should not generate a break\n");
2400 status = smb2_util_write(tree1, h1, &c, 0, 1);
2401 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2403 torture_wait_for_oplock_break(tctx);
2404 CHECK_VAL(break_info.count, 0);
2406 smb2_util_close(tree1, h1);
2407 smb2_util_close(tree1, h);
2409 smb2_deltree(tree1, BASEDIR);
2410 return ret;
2413 static bool test_smb2_oplock_batch22(struct torture_context *tctx,
2414 struct smb2_tree *tree1)
2416 const char *fname = BASEDIR "\\test_batch22.dat";
2417 NTSTATUS status;
2418 bool ret = true;
2419 union smb_open io;
2420 struct smb2_handle h, h1, h2;
2421 struct timeval tv;
2422 int timeout = torture_setting_int(tctx, "oplocktimeout", 30);
2423 int te;
2425 if (torture_setting_bool(tctx, "samba3", false)) {
2426 torture_skip(tctx, "BATCH22 disabled against samba3\n");
2429 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2430 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2432 /* cleanup */
2433 smb2_util_unlink(tree1, fname);
2435 tree1->session->transport->oplock.handler = torture_oplock_handler;
2436 tree1->session->transport->oplock.private_data = tree1;
2438 base ntcreatex parms
2440 ZERO_STRUCT(io.smb2);
2441 io.generic.level = RAW_OPEN_SMB2;
2442 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2443 io.smb2.in.alloc_size = 0;
2444 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2445 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2446 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2447 io.smb2.in.create_options = 0;
2448 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2449 io.smb2.in.security_flags = 0;
2450 io.smb2.in.fname = fname;
2453 with a batch oplock we get a break
2455 torture_comment(tctx, "BATCH22: open with batch oplock\n");
2456 ZERO_STRUCT(break_info);
2457 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2458 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2459 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2460 NTCREATEX_SHARE_ACCESS_WRITE|
2461 NTCREATEX_SHARE_ACCESS_DELETE;
2462 status = smb2_create(tree1, tctx, &(io.smb2));
2463 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2464 h1 = io.smb2.out.file.handle;
2465 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2467 torture_comment(tctx, "a 2nd open should succeed after the oplock "
2468 "break timeout\n");
2469 tv = timeval_current();
2470 tree1->session->transport->oplock.handler =
2471 torture_oplock_handler_timeout;
2472 status = smb2_create(tree1, tctx, &(io.smb2));
2473 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2474 h2 = io.smb2.out.file.handle;
2475 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2477 torture_wait_for_oplock_break(tctx);
2478 te = (int)timeval_elapsed(&tv);
2479 CHECK_RANGE(te, timeout - 1, timeout + 15);
2480 torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
2482 CHECK_VAL(break_info.count, 1);
2483 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2484 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2485 CHECK_VAL(break_info.failures, 0);
2487 smb2_util_close(tree1, h1);
2488 smb2_util_close(tree1, h2);
2489 smb2_util_close(tree1, h);
2491 smb2_deltree(tree1, BASEDIR);
2492 return ret;
2495 static bool test_smb2_oplock_batch23(struct torture_context *tctx,
2496 struct smb2_tree *tree1,
2497 struct smb2_tree *tree2)
2499 const char *fname = BASEDIR "\\test_batch23.dat";
2500 NTSTATUS status;
2501 bool ret = true;
2502 union smb_open io;
2503 struct smb2_handle h, h1, h2, h3;
2504 struct smb2_tree *tree3 = NULL;
2506 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2507 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2509 /* cleanup */
2510 smb2_util_unlink(tree1, fname);
2512 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2513 CHECK_VAL(ret, true);
2515 tree1->session->transport->oplock.handler = torture_oplock_handler;
2516 tree1->session->transport->oplock.private_data = tree1;
2518 tree2->session->transport->oplock.handler = torture_oplock_handler;
2519 tree2->session->transport->oplock.private_data = tree2;
2521 tree3->session->transport->oplock.handler = torture_oplock_handler;
2522 tree3->session->transport->oplock.private_data = tree3;
2525 base ntcreatex parms
2527 ZERO_STRUCT(io.smb2);
2528 io.generic.level = RAW_OPEN_SMB2;
2529 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2530 io.smb2.in.alloc_size = 0;
2531 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2532 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2533 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2534 io.smb2.in.create_options = 0;
2535 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2536 io.smb2.in.security_flags = 0;
2537 io.smb2.in.fname = fname;
2539 torture_comment(tctx, "BATCH23: an open and ask for a batch oplock\n");
2540 ZERO_STRUCT(break_info);
2542 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2543 SEC_RIGHTS_FILE_WRITE;
2544 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2545 NTCREATEX_SHARE_ACCESS_WRITE;
2546 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2547 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2548 status = smb2_create(tree1, tctx, &(io.smb2));
2549 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2550 h1 = io.smb2.out.file.handle;
2551 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2553 ZERO_STRUCT(break_info);
2555 torture_comment(tctx, "a 2nd open without level2 oplock support "
2556 "should generate a break to level2\n");
2557 status = smb2_create(tree3, tctx, &(io.smb2));
2558 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2559 h3 = io.smb2.out.file.handle;
2561 torture_wait_for_oplock_break(tctx);
2562 CHECK_VAL(break_info.count, 1);
2563 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2564 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2565 CHECK_VAL(break_info.failures, 0);
2567 ZERO_STRUCT(break_info);
2569 torture_comment(tctx, "a 3rd open with level2 oplock support should "
2570 "not generate a break\n");
2571 status = smb2_create(tree2, tctx, &(io.smb2));
2572 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2573 h2 = io.smb2.out.file.handle;
2574 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2576 torture_wait_for_oplock_break(tctx);
2577 CHECK_VAL(break_info.count, 0);
2579 smb2_util_close(tree1, h1);
2580 smb2_util_close(tree2, h2);
2581 smb2_util_close(tree3, h3);
2582 smb2_util_close(tree1, h);
2584 smb2_deltree(tree1, BASEDIR);
2585 return ret;
2588 static bool test_smb2_oplock_batch24(struct torture_context *tctx,
2589 struct smb2_tree *tree1,
2590 struct smb2_tree *tree2)
2592 const char *fname = BASEDIR "\\test_batch24.dat";
2593 NTSTATUS status;
2594 bool ret = true;
2595 union smb_open io;
2596 struct smb2_handle h, h1, h2;
2597 struct smb2_tree *tree3 = NULL;
2599 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2600 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2602 /* cleanup */
2603 smb2_util_unlink(tree1, fname);
2605 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2606 CHECK_VAL(ret, true);
2608 tree1->session->transport->oplock.handler = torture_oplock_handler;
2609 tree1->session->transport->oplock.private_data = tree1;
2611 tree2->session->transport->oplock.handler = torture_oplock_handler;
2612 tree2->session->transport->oplock.private_data = tree2;
2614 tree3->session->transport->oplock.handler = torture_oplock_handler;
2615 tree3->session->transport->oplock.private_data = tree3;
2618 base ntcreatex parms
2620 ZERO_STRUCT(io.smb2);
2621 io.generic.level = RAW_OPEN_SMB2;
2622 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2623 io.smb2.in.alloc_size = 0;
2624 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2625 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2626 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2627 io.smb2.in.create_options = 0;
2628 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2629 io.smb2.in.security_flags = 0;
2630 io.smb2.in.fname = fname;
2632 torture_comment(tctx, "BATCH24: a open without level support and "
2633 "ask for a batch oplock\n");
2634 ZERO_STRUCT(break_info);
2636 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2637 SEC_RIGHTS_FILE_WRITE;
2638 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2639 NTCREATEX_SHARE_ACCESS_WRITE;
2640 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2641 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2643 status = smb2_create(tree3, tctx, &(io.smb2));
2644 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2645 h2 = io.smb2.out.file.handle;
2646 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2648 ZERO_STRUCT(break_info);
2650 torture_comment(tctx, "a 2nd open with level2 oplock support should "
2651 "generate a break\n");
2652 status = smb2_create(tree2, tctx, &(io.smb2));
2653 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2654 h1 = io.smb2.out.file.handle;
2655 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2657 torture_wait_for_oplock_break(tctx);
2658 CHECK_VAL(break_info.count, 1);
2659 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
2660 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2661 CHECK_VAL(break_info.failures, 0);
2663 smb2_util_close(tree3, h2);
2664 smb2_util_close(tree2, h1);
2665 smb2_util_close(tree1, h);
2667 smb2_deltree(tree1, BASEDIR);
2668 return ret;
2671 static bool test_smb2_oplock_batch25(struct torture_context *tctx,
2672 struct smb2_tree *tree1)
2674 const char *fname = BASEDIR "\\test_batch25.dat";
2675 NTSTATUS status;
2676 bool ret = true;
2677 union smb_open io;
2678 struct smb2_handle h, h1;
2680 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2681 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2683 /* cleanup */
2684 smb2_util_unlink(tree1, fname);
2686 tree1->session->transport->oplock.handler = torture_oplock_handler;
2687 tree1->session->transport->oplock.private_data = tree1;
2690 base ntcreatex parms
2692 ZERO_STRUCT(io.smb2);
2693 io.generic.level = RAW_OPEN_SMB2;
2694 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2695 io.smb2.in.alloc_size = 0;
2696 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2697 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2698 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2699 io.smb2.in.create_options = 0;
2700 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2701 io.smb2.in.security_flags = 0;
2702 io.smb2.in.fname = fname;
2704 torture_comment(tctx, "BATCH25: open a file with an batch oplock "
2705 "(share mode: none)\n");
2707 ZERO_STRUCT(break_info);
2708 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2709 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2711 status = smb2_create(tree1, tctx, &(io.smb2));
2712 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2713 h1 = io.smb2.out.file.handle;
2714 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2716 torture_comment(tctx, "changing the file attribute info should trigger "
2717 "a break and a violation\n");
2719 status = smb2_util_setatr(tree1, fname, FILE_ATTRIBUTE_HIDDEN);
2720 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2721 "Incorrect status");
2723 torture_wait_for_oplock_break(tctx);
2724 CHECK_VAL(break_info.count, 1);
2726 smb2_util_close(tree1, h1);
2727 smb2_util_close(tree1, h);
2729 smb2_deltree(tree1, fname);
2730 return ret;
2733 /* Test how oplocks work on streams. */
2734 static bool test_raw_oplock_stream1(struct torture_context *tctx,
2735 struct smb2_tree *tree1,
2736 struct smb2_tree *tree2)
2738 NTSTATUS status;
2739 union smb_open io;
2740 const char *fname_base = BASEDIR "\\test_stream1.txt";
2741 const char *fname_stream, *fname_default_stream;
2742 const char *default_stream = "::$DATA";
2743 const char *stream = "Stream One:$DATA";
2744 bool ret = true;
2745 struct smb2_handle h, h_base, h_stream;
2746 int i;
2748 #define NSTREAM_OPLOCK_RESULTS 8
2749 struct {
2750 const char **fname;
2751 bool open_base_file;
2752 uint32_t oplock_req;
2753 uint32_t oplock_granted;
2754 } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
2755 /* Request oplock on stream without the base file open. */
2756 {&fname_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2757 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2758 {&fname_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2759 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2761 /* Request oplock on stream with the base file open. */
2762 {&fname_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2763 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_II},
2764 {&fname_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2765 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_II},
2768 /* Only passes against windows at the moment. */
2769 if (torture_setting_bool(tctx, "samba3", false) ||
2770 torture_setting_bool(tctx, "samba4", false)) {
2771 torture_skip(tctx, "STREAM1 disabled against samba3+4\n");
2774 fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
2775 fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
2776 default_stream);
2778 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2779 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2781 /* Initialize handles to "closed". Using -1 in the first 64-bytes
2782 * as the sentry for this */
2783 h_stream.data[0] = -1;
2785 /* cleanup */
2786 smb2_util_unlink(tree1, fname_base);
2788 tree1->session->transport->oplock.handler = torture_oplock_handler;
2789 tree1->session->transport->oplock.private_data = tree1;
2791 tree2->session->transport->oplock.handler = torture_oplock_handler;
2792 tree2->session->transport->oplock.private_data = tree2;
2794 /* Setup generic open parameters. */
2795 ZERO_STRUCT(io.smb2);
2796 io.generic.level = RAW_OPEN_SMB2;
2797 io.smb2.in.desired_access = (SEC_FILE_READ_DATA |
2798 SEC_FILE_WRITE_DATA |
2799 SEC_FILE_APPEND_DATA |
2800 SEC_STD_READ_CONTROL);
2801 io.smb2.in.alloc_size = 0;
2802 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2803 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2804 NTCREATEX_SHARE_ACCESS_WRITE;
2805 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2806 io.smb2.in.create_options = 0;
2807 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2808 io.smb2.in.security_flags = 0;
2810 /* Create the file with a stream */
2811 io.smb2.in.fname = fname_stream;
2812 io.smb2.in.create_flags = 0;
2813 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2814 status = smb2_create(tree1, tctx, &(io.smb2));
2815 torture_assert_ntstatus_ok(tctx, status, "Error creating file");
2816 smb2_util_close(tree1, io.smb2.out.file.handle);
2818 /* Change the disposition to open now that the file has been created. */
2819 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2821 /* Try some permutations of taking oplocks on streams. */
2822 for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
2823 const char *fname = *stream_oplock_results[i].fname;
2824 bool open_base_file = stream_oplock_results[i].open_base_file;
2825 uint32_t oplock_req = stream_oplock_results[i].oplock_req;
2826 uint32_t oplock_granted =
2827 stream_oplock_results[i].oplock_granted;
2829 if (open_base_file) {
2830 torture_comment(tctx, "Opening base file: %s with "
2831 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2832 io.smb2.in.fname = fname_base;
2833 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2834 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2835 status = smb2_create(tree2, tctx, &(io.smb2));
2836 torture_assert_ntstatus_ok(tctx, status,
2837 "Error opening file");
2838 CHECK_VAL(io.smb2.out.oplock_level,
2839 SMB2_OPLOCK_LEVEL_BATCH);
2840 h_base = io.smb2.out.file.handle;
2843 torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
2844 fname, oplock_req);
2845 io.smb2.in.fname = fname;
2846 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2847 io.smb2.in.oplock_level = oplock_req;
2849 /* Do the open with the desired oplock on the stream. */
2850 status = smb2_create(tree1, tctx, &(io.smb2));
2851 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2852 CHECK_VAL(io.smb2.out.oplock_level, oplock_granted);
2853 smb2_util_close(tree1, io.smb2.out.file.handle);
2855 /* Cleanup the base file if it was opened. */
2856 if (open_base_file)
2857 smb2_util_close(tree2, h_base);
2860 /* Open the stream with an exclusive oplock. */
2861 torture_comment(tctx, "Opening stream: %s with %d\n",
2862 fname_stream, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
2863 io.smb2.in.fname = fname_stream;
2864 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2865 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
2866 status = smb2_create(tree1, tctx, &(io.smb2));
2867 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2868 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
2869 h_stream = io.smb2.out.file.handle;
2871 /* Open the base file and see if it contends. */
2872 ZERO_STRUCT(break_info);
2873 torture_comment(tctx, "Opening base file: %s with %d\n",
2874 fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2875 io.smb2.in.fname = fname_base;
2876 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2877 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2878 status = smb2_create(tree2, tctx, &(io.smb2));
2879 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2880 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2881 smb2_util_close(tree2, io.smb2.out.file.handle);
2883 torture_wait_for_oplock_break(tctx);
2884 CHECK_VAL(break_info.count, 0);
2885 CHECK_VAL(break_info.failures, 0);
2887 /* Open the stream again to see if it contends. */
2888 ZERO_STRUCT(break_info);
2889 torture_comment(tctx, "Opening stream again: %s with "
2890 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2891 io.smb2.in.fname = fname_stream;
2892 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2893 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
2894 status = smb2_create(tree2, tctx, &(io.smb2));
2895 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2896 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2897 smb2_util_close(tree2, io.smb2.out.file.handle);
2899 torture_wait_for_oplock_break(tctx);
2900 CHECK_VAL(break_info.count, 1);
2901 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
2902 CHECK_VAL(break_info.failures, 0);
2904 /* Close the stream. */
2905 if (h_stream.data[0] != -1) {
2906 smb2_util_close(tree1, h_stream);
2909 smb2_util_close(tree1, h);
2911 smb2_deltree(tree1, BASEDIR);
2912 return ret;
2915 static bool test_smb2_oplock_doc(struct torture_context *tctx, struct smb2_tree *tree)
2917 const char *fname = BASEDIR "\\test_oplock_doc.dat";
2918 NTSTATUS status;
2919 bool ret = true;
2920 union smb_open io;
2921 struct smb2_handle h, h1;
2923 status = torture_smb2_testdir(tree, BASEDIR, &h);
2924 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2926 /* cleanup */
2927 smb2_util_unlink(tree, fname);
2928 tree->session->transport->oplock.handler = torture_oplock_handler;
2929 tree->session->transport->oplock.private_data = tree;
2932 base ntcreatex parms
2934 ZERO_STRUCT(io.smb2);
2935 io.generic.level = RAW_OPEN_SMB2;
2936 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2937 io.smb2.in.alloc_size = 0;
2938 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2939 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2940 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2941 io.smb2.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
2942 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2943 io.smb2.in.security_flags = 0;
2944 io.smb2.in.fname = fname;
2946 torture_comment(tctx, "open a delete-on-close file with a batch "
2947 "oplock\n");
2948 ZERO_STRUCT(break_info);
2949 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2950 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2952 status = smb2_create(tree, tctx, &(io.smb2));
2953 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2954 h1 = io.smb2.out.file.handle;
2955 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2957 smb2_util_close(tree, h1);
2959 smb2_util_unlink(tree, fname);
2960 smb2_deltree(tree, BASEDIR);
2961 return ret;
2964 /* Open a file with a batch oplock, then open it again from a second client
2965 * requesting no oplock. Having two open file handles should break our own
2966 * oplock during BRL acquisition.
2968 static bool test_smb2_oplock_brl1(struct torture_context *tctx,
2969 struct smb2_tree *tree1,
2970 struct smb2_tree *tree2)
2972 const char *fname = BASEDIR "\\test_batch_brl.dat";
2973 /*int fname, f;*/
2974 bool ret = true;
2975 uint8_t buf[1000];
2976 bool correct = true;
2977 union smb_open io;
2978 NTSTATUS status;
2979 struct smb2_lock lck;
2980 struct smb2_lock_element lock[1];
2981 struct smb2_handle h, h1, h2;
2983 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2984 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2986 /* cleanup */
2987 smb2_util_unlink(tree1, fname);
2989 tree1->session->transport->oplock.handler =
2990 torture_oplock_handler_two_notifications;
2991 tree1->session->transport->oplock.private_data = tree1;
2994 base ntcreatex parms
2996 ZERO_STRUCT(io.smb2);
2997 io.generic.level = RAW_OPEN_SMB2;
2998 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2999 SEC_RIGHTS_FILE_WRITE;
3000 io.smb2.in.alloc_size = 0;
3001 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3002 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3003 NTCREATEX_SHARE_ACCESS_WRITE;
3004 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3005 io.smb2.in.create_options = 0;
3006 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3007 io.smb2.in.security_flags = 0;
3008 io.smb2.in.fname = fname;
3011 with a batch oplock we get a break
3013 torture_comment(tctx, "open with batch oplock\n");
3014 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3015 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3017 status = smb2_create(tree1, tctx, &(io.smb2));
3018 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3019 h1 = io.smb2.out.file.handle;
3020 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3022 /* create a file with bogus data */
3023 memset(buf, 0, sizeof(buf));
3025 status = smb2_util_write(tree1, h1,buf, 0, sizeof(buf));
3026 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3027 torture_comment(tctx, "Failed to create file\n");
3028 correct = false;
3029 goto done;
3032 torture_comment(tctx, "a 2nd open should give a break\n");
3033 ZERO_STRUCT(break_info);
3035 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3036 io.smb2.in.oplock_level = 0;
3037 status = smb2_create(tree2, tctx, &(io.smb2));
3038 h2 = io.smb2.out.file.handle;
3039 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3041 torture_wait_for_oplock_break(tctx);
3042 CHECK_VAL(break_info.count, 1);
3043 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3044 CHECK_VAL(break_info.failures, 0);
3045 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3047 ZERO_STRUCT(break_info);
3049 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3050 lock[0].offset = 0;
3051 lock[0].length = 4;
3052 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3053 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3055 ZERO_STRUCT(lck);
3056 lck.in.file.handle = h1;
3057 lck.in.locks = &lock[0];
3058 lck.in.lock_count = 1;
3059 status = smb2_lock(tree1, &lck);
3060 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3062 torture_wait_for_oplock_break(tctx);
3063 CHECK_VAL(break_info.count, 1);
3064 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3065 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3066 CHECK_VAL(break_info.failures, 0);
3068 /* expect no oplock break */
3069 ZERO_STRUCT(break_info);
3070 lock[0].offset = 2;
3071 status = smb2_lock(tree1, &lck);
3072 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3073 "Incorrect status");
3075 torture_wait_for_oplock_break(tctx);
3076 CHECK_VAL(break_info.count, 0);
3077 CHECK_VAL(break_info.level, 0);
3078 CHECK_VAL(break_info.failures, 0);
3080 smb2_util_close(tree1, h1);
3081 smb2_util_close(tree2, h2);
3082 smb2_util_close(tree1, h);
3084 done:
3085 smb2_deltree(tree1, BASEDIR);
3086 return ret;
3090 /* Open a file with a batch oplock on one tree and then acquire a brl.
3091 * We should not contend our own oplock.
3093 static bool test_smb2_oplock_brl2(struct torture_context *tctx, struct smb2_tree *tree1)
3095 const char *fname = BASEDIR "\\test_batch_brl.dat";
3096 /*int fname, f;*/
3097 bool ret = true;
3098 uint8_t buf[1000];
3099 bool correct = true;
3100 union smb_open io;
3101 NTSTATUS status;
3102 struct smb2_handle h, h1;
3103 struct smb2_lock lck;
3104 struct smb2_lock_element lock[1];
3106 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3107 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3109 /* cleanup */
3110 smb2_util_unlink(tree1, fname);
3112 tree1->session->transport->oplock.handler = torture_oplock_handler;
3113 tree1->session->transport->oplock.private_data = tree1;
3116 base ntcreatex parms
3118 ZERO_STRUCT(io.smb2);
3119 io.generic.level = RAW_OPEN_SMB2;
3120 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3121 SEC_RIGHTS_FILE_WRITE;
3122 io.smb2.in.alloc_size = 0;
3123 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3124 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3125 NTCREATEX_SHARE_ACCESS_WRITE;
3126 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3127 io.smb2.in.create_options = 0;
3128 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3129 io.smb2.in.security_flags = 0;
3130 io.smb2.in.fname = fname;
3133 with a batch oplock we get a break
3135 torture_comment(tctx, "open with batch oplock\n");
3136 ZERO_STRUCT(break_info);
3137 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3138 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3140 status = smb2_create(tree1, tctx, &(io.smb2));
3141 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3142 h1 = io.smb2.out.file.handle;
3143 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3145 /* create a file with bogus data */
3146 memset(buf, 0, sizeof(buf));
3148 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3149 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3150 torture_comment(tctx, "Failed to create file\n");
3151 correct = false;
3152 goto done;
3155 ZERO_STRUCT(break_info);
3157 torture_comment(tctx, "a self BRL acquisition should not break to "
3158 "none\n");
3160 lock[0].offset = 0;
3161 lock[0].length = 4;
3162 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3163 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3165 ZERO_STRUCT(lck);
3166 lck.in.file.handle = h1;
3167 lck.in.locks = &lock[0];
3168 lck.in.lock_count = 1;
3169 status = smb2_lock(tree1, &lck);
3170 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3172 lock[0].offset = 2;
3173 status = smb2_lock(tree1, &lck);
3174 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3175 "Incorrect status");
3177 /* With one file handle open a BRL should not contend our oplock.
3178 * Thus, no oplock break will be received and the entire break_info
3179 * struct will be 0 */
3180 torture_wait_for_oplock_break(tctx);
3181 CHECK_VAL(break_info.count, 0);
3182 CHECK_VAL(break_info.level, 0);
3183 CHECK_VAL(break_info.failures, 0);
3185 smb2_util_close(tree1, h1);
3186 smb2_util_close(tree1, h);
3188 done:
3189 smb2_deltree(tree1, BASEDIR);
3190 return ret;
3193 /* Open a file with a batch oplock twice from one tree and then acquire a
3194 * brl. BRL acquisition should break our own oplock.
3196 static bool test_smb2_oplock_brl3(struct torture_context *tctx, struct smb2_tree *tree1)
3198 const char *fname = BASEDIR "\\test_batch_brl.dat";
3199 bool ret = true;
3200 uint8_t buf[1000];
3201 bool correct = true;
3202 union smb_open io;
3203 NTSTATUS status;
3204 struct smb2_handle h, h1, h2;
3205 struct smb2_lock lck;
3206 struct smb2_lock_element lock[1];
3208 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3209 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3211 /* cleanup */
3212 smb2_util_unlink(tree1, fname);
3213 tree1->session->transport->oplock.handler =
3214 torture_oplock_handler_two_notifications;
3215 tree1->session->transport->oplock.private_data = tree1;
3218 base ntcreatex parms
3220 ZERO_STRUCT(io.smb2);
3221 io.generic.level = RAW_OPEN_SMB2;
3222 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3223 SEC_RIGHTS_FILE_WRITE;
3224 io.smb2.in.alloc_size = 0;
3225 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3226 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3227 NTCREATEX_SHARE_ACCESS_WRITE;
3228 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3229 io.smb2.in.create_options = 0;
3230 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3231 io.smb2.in.security_flags = 0;
3232 io.smb2.in.fname = fname;
3235 with a batch oplock we get a break
3237 torture_comment(tctx, "open with batch oplock\n");
3238 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3239 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3241 status = smb2_create(tree1, tctx, &(io.smb2));
3242 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3243 h1 = io.smb2.out.file.handle;
3244 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3246 /* create a file with bogus data */
3247 memset(buf, 0, sizeof(buf));
3248 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3250 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3251 torture_comment(tctx, "Failed to create file\n");
3252 correct = false;
3253 goto done;
3256 torture_comment(tctx, "a 2nd open should give a break\n");
3257 ZERO_STRUCT(break_info);
3259 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3260 io.smb2.in.oplock_level = 0;
3261 status = smb2_create(tree1, tctx, &(io.smb2));
3262 h2 = io.smb2.out.file.handle;
3263 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3264 CHECK_VAL(break_info.count, 1);
3265 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3266 CHECK_VAL(break_info.failures, 0);
3267 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3269 ZERO_STRUCT(break_info);
3271 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3273 lock[0].offset = 0;
3274 lock[0].length = 4;
3275 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3276 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3278 ZERO_STRUCT(lck);
3279 lck.in.file.handle = h1;
3280 lck.in.locks = &lock[0];
3281 lck.in.lock_count = 1;
3282 status = smb2_lock(tree1, &lck);
3283 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3285 torture_wait_for_oplock_break(tctx);
3286 CHECK_VAL(break_info.count, 1);
3287 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3288 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3289 CHECK_VAL(break_info.failures, 0);
3291 /* expect no oplock break */
3292 ZERO_STRUCT(break_info);
3293 lock[0].offset = 2;
3294 status = smb2_lock(tree1, &lck);
3295 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3296 "Incorrect status");
3298 torture_wait_for_oplock_break(tctx);
3299 CHECK_VAL(break_info.count, 0);
3300 CHECK_VAL(break_info.level, 0);
3301 CHECK_VAL(break_info.failures, 0);
3303 smb2_util_close(tree1, h1);
3304 smb2_util_close(tree1, h2);
3305 smb2_util_close(tree1, h);
3307 done:
3308 smb2_deltree(tree1, BASEDIR);
3309 return ret;
3313 /* Starting the SMB2 specific oplock tests at 500 so we can keep the SMB1
3314 * tests in sync with an identically numbered SMB2 test */
3316 /* Test whether the server correctly returns an error when we send
3317 * a response to a levelII to none oplock notification. */
3318 static bool test_smb2_oplock_levelII500(struct torture_context *tctx,
3319 struct smb2_tree *tree1)
3321 const char *fname = BASEDIR "\\test_levelII500.dat";
3322 NTSTATUS status;
3323 bool ret = true;
3324 union smb_open io;
3325 struct smb2_handle h, h1;
3326 char c = 0;
3328 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3329 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3331 /* cleanup */
3332 smb2_util_unlink(tree1, fname);
3334 tree1->session->transport->oplock.handler = torture_oplock_handler;
3335 tree1->session->transport->oplock.private_data = tree1;
3338 base ntcreatex parms
3340 ZERO_STRUCT(io.smb2);
3341 io.generic.level = RAW_OPEN_SMB2;
3342 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3343 io.smb2.in.alloc_size = 0;
3344 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3345 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3346 io.smb2.in.create_options = 0;
3347 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3348 io.smb2.in.security_flags = 0;
3349 io.smb2.in.fname = fname;
3351 torture_comment(tctx, "LEVELII500: acknowledging a break from II to "
3352 "none should return an error\n");
3353 ZERO_STRUCT(break_info);
3355 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3356 SEC_RIGHTS_FILE_WRITE;
3357 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3358 NTCREATEX_SHARE_ACCESS_WRITE;
3359 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3360 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
3361 status = smb2_create(tree1, tctx, &(io.smb2));
3362 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3363 h1 = io.smb2.out.file.handle;
3364 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3366 ZERO_STRUCT(break_info);
3368 torture_comment(tctx, "write should trigger a break to none and when "
3369 "we reply, an oplock break failure\n");
3370 smb2_util_write(tree1, h1, &c, 0, 1);
3372 /* Wait several times to receive both the break notification, and the
3373 * NT_STATUS_INVALID_OPLOCK_PROTOCOL error in the break response */
3374 torture_wait_for_oplock_break(tctx);
3375 torture_wait_for_oplock_break(tctx);
3376 torture_wait_for_oplock_break(tctx);
3377 torture_wait_for_oplock_break(tctx);
3379 /* There appears to be a race condition in W2K8 and W2K8R2 where
3380 * sometimes the server will happily reply to our break response with
3381 * NT_STATUS_OK, and sometimes it will return the OPLOCK_PROTOCOL
3382 * error. As the MS-SMB2 doc states that a client should not reply to
3383 * a level2 to none break notification, I'm leaving the protocol error
3384 * as the expected behavior. */
3385 CHECK_VAL(break_info.count, 1);
3386 CHECK_VAL(break_info.level, 0);
3387 CHECK_VAL(break_info.failures, 1);
3388 torture_assert_ntstatus_equal(tctx, break_info.failure_status,
3389 NT_STATUS_INVALID_OPLOCK_PROTOCOL,
3390 "Incorrect status");
3392 smb2_util_close(tree1, h1);
3393 smb2_util_close(tree1, h);
3395 smb2_deltree(tree1, BASEDIR);
3396 return ret;
3399 struct torture_suite *torture_smb2_oplocks_init(void)
3401 struct torture_suite *suite =
3402 torture_suite_create(talloc_autofree_context(), "oplock");
3404 torture_suite_add_2smb2_test(suite, "exclusive1", test_smb2_oplock_exclusive1);
3405 torture_suite_add_2smb2_test(suite, "exclusive2", test_smb2_oplock_exclusive2);
3406 torture_suite_add_2smb2_test(suite, "exclusive3", test_smb2_oplock_exclusive3);
3407 torture_suite_add_2smb2_test(suite, "exclusive4", test_smb2_oplock_exclusive4);
3408 torture_suite_add_2smb2_test(suite, "exclusive5", test_smb2_oplock_exclusive5);
3409 torture_suite_add_2smb2_test(suite, "exclusive6", test_smb2_oplock_exclusive6);
3410 torture_suite_add_2smb2_test(suite, "batch1", test_smb2_oplock_batch1);
3411 torture_suite_add_2smb2_test(suite, "batch2", test_smb2_oplock_batch2);
3412 torture_suite_add_2smb2_test(suite, "batch3", test_smb2_oplock_batch3);
3413 torture_suite_add_2smb2_test(suite, "batch4", test_smb2_oplock_batch4);
3414 torture_suite_add_2smb2_test(suite, "batch5", test_smb2_oplock_batch5);
3415 torture_suite_add_2smb2_test(suite, "batch6", test_smb2_oplock_batch6);
3416 torture_suite_add_2smb2_test(suite, "batch7", test_smb2_oplock_batch7);
3417 torture_suite_add_2smb2_test(suite, "batch8", test_smb2_oplock_batch8);
3418 torture_suite_add_2smb2_test(suite, "batch9", test_smb2_oplock_batch9);
3419 torture_suite_add_2smb2_test(suite, "batch10", test_smb2_oplock_batch10);
3420 torture_suite_add_2smb2_test(suite, "batch11", test_smb2_oplock_batch11);
3421 torture_suite_add_2smb2_test(suite, "batch12", test_smb2_oplock_batch12);
3422 torture_suite_add_2smb2_test(suite, "batch13", test_smb2_oplock_batch13);
3423 torture_suite_add_2smb2_test(suite, "batch14", test_smb2_oplock_batch14);
3424 torture_suite_add_2smb2_test(suite, "batch15", test_smb2_oplock_batch15);
3425 torture_suite_add_2smb2_test(suite, "batch16", test_smb2_oplock_batch16);
3426 torture_suite_add_1smb2_test(suite, "batch19", test_smb2_oplock_batch19);
3427 torture_suite_add_2smb2_test(suite, "batch20", test_smb2_oplock_batch20);
3428 torture_suite_add_1smb2_test(suite, "batch21", test_smb2_oplock_batch21);
3429 torture_suite_add_1smb2_test(suite, "batch22", test_smb2_oplock_batch22);
3430 torture_suite_add_2smb2_test(suite, "batch23", test_smb2_oplock_batch23);
3431 torture_suite_add_2smb2_test(suite, "batch24", test_smb2_oplock_batch24);
3432 torture_suite_add_1smb2_test(suite, "batch25", test_smb2_oplock_batch25);
3433 torture_suite_add_2smb2_test(suite, "stream1", test_raw_oplock_stream1);
3434 torture_suite_add_1smb2_test(suite, "doc", test_smb2_oplock_doc);
3435 torture_suite_add_2smb2_test(suite, "brl1", test_smb2_oplock_brl1);
3436 torture_suite_add_1smb2_test(suite, "brl2", test_smb2_oplock_brl2);
3437 torture_suite_add_1smb2_test(suite, "brl3", test_smb2_oplock_brl3);
3438 torture_suite_add_1smb2_test(suite, "levelii500", test_smb2_oplock_levelII500);
3440 suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
3442 return suite;
3446 stress testing of oplocks
3448 bool test_smb2_bench_oplock(struct torture_context *tctx,
3449 struct smb2_tree *tree)
3451 struct smb2_tree **trees;
3452 bool ret = true;
3453 NTSTATUS status;
3454 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3455 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
3456 int i, count=0;
3457 int timelimit = torture_setting_int(tctx, "timelimit", 10);
3458 union smb_open io;
3459 struct timeval tv;
3460 struct smb2_handle h;
3462 trees = talloc_array(mem_ctx, struct smb2_tree *, torture_nprocs);
3464 torture_comment(tctx, "Opening %d connections\n", torture_nprocs);
3465 for (i=0;i<torture_nprocs;i++) {
3466 if (!torture_smb2_connection(tctx, &trees[i])) {
3467 return false;
3469 talloc_steal(mem_ctx, trees[i]);
3470 trees[i]->session->transport->oplock.handler =
3471 torture_oplock_handler_close;
3472 trees[i]->session->transport->oplock.private_data = trees[i];
3475 status = torture_smb2_testdir(trees[0], BASEDIR, &h);
3476 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3478 ZERO_STRUCT(io.smb2);
3479 io.smb2.level = RAW_OPEN_SMB2;
3480 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3481 io.smb2.in.alloc_size = 0;
3482 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3483 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
3484 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3485 io.smb2.in.create_options = 0;
3486 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3487 io.smb2.in.security_flags = 0;
3488 io.smb2.in.fname = BASEDIR "\\test.dat";
3489 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3490 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3492 tv = timeval_current();
3495 we open the same file with SHARE_ACCESS_NONE from all the
3496 connections in a round robin fashion. Each open causes an
3497 oplock break on the previous connection, which is answered
3498 by the oplock_handler_close() to close the file.
3500 This measures how fast we can pass on oplocks, and stresses
3501 the oplock handling code
3503 torture_comment(tctx, "Running for %d seconds\n", timelimit);
3504 while (timeval_elapsed(&tv) < timelimit) {
3505 for (i=0;i<torture_nprocs;i++) {
3506 status = smb2_create(trees[i], mem_ctx, &(io.smb2));
3507 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3508 count++;
3511 if (torture_setting_bool(tctx, "progress", true)) {
3512 torture_comment(tctx, "%.2f ops/second\r",
3513 count/timeval_elapsed(&tv));
3517 torture_comment(tctx, "%.2f ops/second\n", count/timeval_elapsed(&tv));
3518 smb2_util_close(trees[0], io.smb2.out.file.handle);
3519 smb2_util_unlink(trees[0], BASEDIR "\\test.dat");
3520 smb2_deltree(trees[0], BASEDIR);
3521 talloc_free(mem_ctx);
3522 return ret;
3525 static struct hold_oplock_info {
3526 const char *fname;
3527 bool close_on_break;
3528 uint32_t share_access;
3529 struct smb2_handle handle;
3530 } hold_info[] = {
3531 { BASEDIR "\\notshared_close", true,
3532 NTCREATEX_SHARE_ACCESS_NONE, },
3533 { BASEDIR "\\notshared_noclose", false,
3534 NTCREATEX_SHARE_ACCESS_NONE, },
3535 { BASEDIR "\\shared_close", true,
3536 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, },
3537 { BASEDIR "\\shared_noclose", false,
3538 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, },
3541 static bool torture_oplock_handler_hold(struct smb2_transport *transport,
3542 const struct smb2_handle *handle,
3543 uint8_t level, void *private_data)
3545 struct hold_oplock_info *info;
3546 int i;
3548 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
3549 if (smb2_util_handle_equal(hold_info[i].handle, *handle))
3550 break;
3553 if (i == ARRAY_SIZE(hold_info)) {
3554 printf("oplock break for unknown handle 0x%llx%llx\n",
3555 (unsigned long long) handle->data[0],
3556 (unsigned long long) handle->data[1]);
3557 return false;
3560 info = &hold_info[i];
3562 if (info->close_on_break) {
3563 printf("oplock break on %s - closing\n", info->fname);
3564 torture_oplock_handler_close(transport, handle,
3565 level, private_data);
3566 return true;
3569 printf("oplock break on %s - acking break\n", info->fname);
3570 printf("Acking to none in oplock handler\n");
3572 torture_oplock_handler_ack_to_none(transport, handle,
3573 level, private_data);
3574 return true;
3578 used for manual testing of oplocks - especially interaction with
3579 other filesystems (such as NFS and local access)
3581 bool test_smb2_hold_oplock(struct torture_context *tctx,
3582 struct smb2_tree *tree)
3584 struct torture_context *mem_ctx = talloc_new(tctx);
3585 struct tevent_context *ev = tctx->ev;
3586 int i;
3587 struct smb2_handle h;
3588 NTSTATUS status;
3590 torture_comment(tctx, "Setting up open files with oplocks in %s\n",
3591 BASEDIR);
3593 status = torture_smb2_testdir(tree, BASEDIR, &h);
3594 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3596 tree->session->transport->oplock.handler = torture_oplock_handler_hold;
3597 tree->session->transport->oplock.private_data = tree;
3599 /* setup the files */
3600 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
3601 union smb_open io;
3602 char c = 1;
3604 ZERO_STRUCT(io.smb2);
3605 io.generic.level = RAW_OPEN_SMB2;
3606 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3607 io.smb2.in.alloc_size = 0;
3608 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3609 io.smb2.in.share_access = hold_info[i].share_access;
3610 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3611 io.smb2.in.create_options = 0;
3612 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3613 io.smb2.in.security_flags = 0;
3614 io.smb2.in.fname = hold_info[i].fname;
3615 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3616 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3618 torture_comment(tctx, "opening %s\n", hold_info[i].fname);
3620 status = smb2_create(tree, mem_ctx, &(io.smb2));
3621 if (!NT_STATUS_IS_OK(status)) {
3622 torture_comment(tctx, "Failed to open %s - %s\n",
3623 hold_info[i].fname, nt_errstr(status));
3624 return false;
3627 if (io.smb2.out.oplock_level != SMB2_OPLOCK_LEVEL_BATCH) {
3628 torture_comment(tctx, "Oplock not granted for %s - "
3629 "expected %d but got %d\n",
3630 hold_info[i].fname,
3631 SMB2_OPLOCK_LEVEL_BATCH,
3632 io.smb2.out.oplock_level);
3633 return false;
3635 hold_info[i].handle = io.smb2.out.file.handle;
3637 /* make the file non-zero size */
3638 status = smb2_util_write(tree, hold_info[i].handle, &c, 0, 1);
3639 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3640 torture_comment(tctx, "Failed to write to file\n");
3641 return false;
3645 torture_comment(tctx, "Waiting for oplock events\n");
3646 tevent_loop_wait(ev);
3647 smb2_deltree(tree, BASEDIR);
3648 talloc_free(mem_ctx);
3649 return true;