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