Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : test suite for SMB2 oplocks
5 :
6 : Copyright (C) Andrew Tridgell 2003
7 : Copyright (C) Stefan Metzmacher 2008
8 :
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.
13 :
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.
18 :
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/>.
21 : */
22 :
23 : #include "includes.h"
24 :
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"
29 : #include "libcli/smb/smbXcli_base.h"
30 :
31 : #include "lib/cmdline/cmdline.h"
32 : #include "lib/events/events.h"
33 :
34 : #include "param/param.h"
35 : #include "system/filesys.h"
36 :
37 : #include "torture/torture.h"
38 : #include "torture/smb2/proto.h"
39 : #include "torture/smb2/block.h"
40 :
41 : #include "lib/util/sys_rw.h"
42 : #include "libcli/security/security.h"
43 :
44 : #define CHECK_RANGE(v, min, max) do { \
45 : if ((v) < (min) || (v) > (max)) { \
46 : torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
47 : "got %d - should be between %d and %d\n", \
48 : __location__, #v, (int)v, (int)min, (int)max); \
49 : ret = false; \
50 : }} while (0)
51 :
52 : #define CHECK_STRMATCH(v, correct) do { \
53 : if (!v || strstr((v),(correct)) == NULL) { \
54 : torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s "\
55 : "got '%s' - should be '%s'\n", \
56 : __location__, #v, v?v:"NULL", correct); \
57 : ret = false; \
58 : }} while (0)
59 :
60 : #define CHECK_VAL(v, correct) do { \
61 : if ((v) != (correct)) { \
62 : torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
63 : "got 0x%x - should be 0x%x\n", \
64 : __location__, #v, (int)v, (int)correct); \
65 : ret = false; \
66 : }} while (0)
67 :
68 : #define BASEDIR "oplock_test"
69 :
70 : static struct {
71 : struct smb2_handle handle;
72 : uint8_t level;
73 : struct smb2_break br;
74 : int count;
75 : int failures;
76 : NTSTATUS failure_status;
77 : } break_info;
78 :
79 117 : static void torture_oplock_break_callback(struct smb2_request *req)
80 : {
81 0 : NTSTATUS status;
82 0 : struct smb2_break br;
83 :
84 117 : ZERO_STRUCT(br);
85 117 : status = smb2_break_recv(req, &break_info.br);
86 117 : if (!NT_STATUS_IS_OK(status)) {
87 2 : break_info.failures++;
88 2 : break_info.failure_status = status;
89 : }
90 :
91 117 : return;
92 : }
93 :
94 : /* A general oplock break notification handler. This should be used when a
95 : * test expects to break from batch or exclusive to a lower level. */
96 98 : static bool torture_oplock_handler(struct smb2_transport *transport,
97 : const struct smb2_handle *handle,
98 : uint8_t level,
99 : void *private_data)
100 : {
101 98 : struct smb2_tree *tree = private_data;
102 0 : const char *name;
103 0 : struct smb2_request *req;
104 98 : ZERO_STRUCT(break_info.br);
105 :
106 98 : break_info.handle = *handle;
107 98 : break_info.level = level;
108 98 : break_info.count++;
109 :
110 98 : switch (level) {
111 80 : case SMB2_OPLOCK_LEVEL_II:
112 80 : name = "level II";
113 80 : break;
114 18 : case SMB2_OPLOCK_LEVEL_NONE:
115 18 : name = "none";
116 18 : break;
117 0 : default:
118 0 : name = "unknown";
119 0 : break_info.failures++;
120 : }
121 98 : printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
122 :
123 98 : break_info.br.in.file.handle = *handle;
124 98 : break_info.br.in.oplock_level = level;
125 98 : break_info.br.in.reserved = 0;
126 98 : break_info.br.in.reserved2 = 0;
127 :
128 98 : req = smb2_break_send(tree, &break_info.br);
129 98 : req->async.fn = torture_oplock_break_callback;
130 98 : req->async.private_data = NULL;
131 98 : return true;
132 : }
133 :
134 : /*
135 : A handler function for oplock break notifications. Send a break to none
136 : request.
137 : */
138 3 : static bool torture_oplock_handler_ack_to_none(struct smb2_transport *transport,
139 : const struct smb2_handle *handle,
140 : uint8_t level,
141 : void *private_data)
142 : {
143 3 : struct smb2_tree *tree = private_data;
144 0 : struct smb2_request *req;
145 :
146 3 : break_info.handle = *handle;
147 3 : break_info.level = level;
148 3 : break_info.count++;
149 :
150 3 : printf("Acking to none in oplock handler\n");
151 :
152 3 : ZERO_STRUCT(break_info.br);
153 3 : break_info.br.in.file.handle = *handle;
154 3 : break_info.br.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
155 3 : break_info.br.in.reserved = 0;
156 3 : break_info.br.in.reserved2 = 0;
157 :
158 3 : req = smb2_break_send(tree, &break_info.br);
159 3 : req->async.fn = torture_oplock_break_callback;
160 3 : req->async.private_data = NULL;
161 :
162 3 : return true;
163 : }
164 :
165 : /*
166 : A handler function for oplock break notifications. Break from level II to
167 : none. SMB2 requires that the client does not send an oplock break request to
168 : the server in this case.
169 : */
170 24 : static bool torture_oplock_handler_level2_to_none(
171 : struct smb2_transport *transport,
172 : const struct smb2_handle *handle,
173 : uint8_t level,
174 : void *private_data)
175 : {
176 24 : break_info.handle = *handle;
177 24 : break_info.level = level;
178 24 : break_info.count++;
179 :
180 24 : printf("Break from level II to none in oplock handler\n");
181 :
182 24 : return true;
183 : }
184 :
185 : /* A handler function for oplock break notifications. This should be used when
186 : * test expects two break notifications, first to level II, then to none. */
187 24 : static bool torture_oplock_handler_two_notifications(
188 : struct smb2_transport *transport,
189 : const struct smb2_handle *handle,
190 : uint8_t level,
191 : void *private_data)
192 : {
193 24 : struct smb2_tree *tree = private_data;
194 0 : const char *name;
195 0 : struct smb2_request *req;
196 24 : ZERO_STRUCT(break_info.br);
197 :
198 24 : break_info.handle = *handle;
199 24 : break_info.level = level;
200 24 : break_info.count++;
201 :
202 24 : switch (level) {
203 16 : case SMB2_OPLOCK_LEVEL_II:
204 16 : name = "level II";
205 16 : break;
206 8 : case SMB2_OPLOCK_LEVEL_NONE:
207 8 : name = "none";
208 8 : break;
209 0 : default:
210 0 : name = "unknown";
211 0 : break_info.failures++;
212 : }
213 24 : printf("Breaking to %s [0x%02X] in oplock handler\n", name, level);
214 :
215 24 : if (level == SMB2_OPLOCK_LEVEL_NONE)
216 8 : return true;
217 :
218 16 : break_info.br.in.file.handle = *handle;
219 16 : break_info.br.in.oplock_level = level;
220 16 : break_info.br.in.reserved = 0;
221 16 : break_info.br.in.reserved2 = 0;
222 :
223 16 : req = smb2_break_send(tree, &break_info.br);
224 16 : req->async.fn = torture_oplock_break_callback;
225 16 : req->async.private_data = NULL;
226 16 : return true;
227 : }
228 7 : static void torture_oplock_handler_close_recv(struct smb2_request *req)
229 : {
230 7 : if (!smb2_request_receive(req)) {
231 0 : printf("close failed in oplock_handler_close\n");
232 0 : break_info.failures++;
233 : }
234 7 : }
235 :
236 : /*
237 : a handler function for oplock break requests - close the file
238 : */
239 7 : static bool torture_oplock_handler_close(struct smb2_transport *transport,
240 : const struct smb2_handle *handle,
241 : uint8_t level,
242 : void *private_data)
243 : {
244 0 : struct smb2_close io;
245 7 : struct smb2_tree *tree = private_data;
246 0 : struct smb2_request *req;
247 :
248 7 : break_info.handle = *handle;
249 7 : break_info.level = level;
250 7 : break_info.count++;
251 :
252 7 : ZERO_STRUCT(io);
253 7 : io.in.file.handle = *handle;
254 7 : io.in.flags = RAW_CLOSE_SMB2;
255 7 : req = smb2_close_send(tree, &io);
256 7 : if (req == NULL) {
257 0 : printf("failed to send close in oplock_handler_close\n");
258 0 : return false;
259 : }
260 :
261 7 : req->async.fn = torture_oplock_handler_close_recv;
262 7 : req->async.private_data = NULL;
263 :
264 7 : return true;
265 : }
266 :
267 : /*
268 : a handler function for oplock break requests. Let it timeout
269 : */
270 5 : static bool torture_oplock_handler_timeout(struct smb2_transport *transport,
271 : const struct smb2_handle *handle,
272 : uint8_t level,
273 : void *private_data)
274 : {
275 5 : break_info.handle = *handle;
276 5 : break_info.level = level;
277 5 : break_info.count++;
278 :
279 5 : printf("Let oplock break timeout\n");
280 5 : return true;
281 : }
282 :
283 6 : static bool open_smb2_connection_no_level2_oplocks(struct torture_context *tctx,
284 : struct smb2_tree **tree)
285 : {
286 0 : NTSTATUS status;
287 6 : const char *host = torture_setting_string(tctx, "host", NULL);
288 6 : const char *share = torture_setting_string(tctx, "share", NULL);
289 0 : struct smbcli_options options;
290 :
291 6 : lpcfg_smbcli_options(tctx->lp_ctx, &options);
292 6 : options.use_level2_oplocks = false;
293 :
294 6 : status = smb2_connect(tctx, host,
295 : lpcfg_smb_ports(tctx->lp_ctx), share,
296 : lpcfg_resolve_context(tctx->lp_ctx),
297 : samba_cmdline_get_creds(),
298 : tree, tctx->ev, &options,
299 : lpcfg_socket_options(tctx->lp_ctx),
300 : lpcfg_gensec_settings(tctx, tctx->lp_ctx));
301 6 : if (!NT_STATUS_IS_OK(status)) {
302 0 : torture_comment(tctx, "Failed to connect to SMB2 share "
303 : "\\\\%s\\%s - %s\n", host, share,
304 : nt_errstr(status));
305 0 : return false;
306 : }
307 6 : return true;
308 : }
309 :
310 3 : static bool test_smb2_oplock_exclusive1(struct torture_context *tctx,
311 : struct smb2_tree *tree1,
312 : struct smb2_tree *tree2)
313 : {
314 3 : const char *fname = BASEDIR "\\test_exclusive1.dat";
315 0 : NTSTATUS status;
316 3 : bool ret = true;
317 0 : union smb_open io;
318 0 : struct smb2_handle h1;
319 0 : struct smb2_handle h;
320 :
321 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
322 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
323 :
324 : /* cleanup */
325 3 : smb2_util_unlink(tree1, fname);
326 :
327 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
328 3 : tree1->session->transport->oplock.private_data = tree1;
329 :
330 : /*
331 : base ntcreatex parms
332 : */
333 3 : ZERO_STRUCT(io.smb2);
334 3 : io.generic.level = RAW_OPEN_SMB2;
335 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
336 3 : io.smb2.in.alloc_size = 0;
337 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
338 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
339 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
340 3 : io.smb2.in.create_options = 0;
341 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
342 3 : io.smb2.in.security_flags = 0;
343 3 : io.smb2.in.fname = fname;
344 :
345 3 : torture_comment(tctx, "EXCLUSIVE1: open a file with an exclusive "
346 : "oplock (share mode: none)\n");
347 3 : ZERO_STRUCT(break_info);
348 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
349 :
350 3 : status = smb2_create(tree1, tctx, &(io.smb2));
351 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
352 3 : h1 = io.smb2.out.file.handle;
353 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
354 :
355 3 : torture_comment(tctx, "a 2nd open should not cause a break\n");
356 3 : status = smb2_create(tree2, tctx, &(io.smb2));
357 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
358 : "Incorrect status");
359 3 : torture_wait_for_oplock_break(tctx);
360 3 : CHECK_VAL(break_info.count, 0);
361 3 : CHECK_VAL(break_info.failures, 0);
362 :
363 3 : torture_comment(tctx, "unlink it - should also be no break\n");
364 3 : status = smb2_util_unlink(tree2, fname);
365 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
366 : "Incorrect status");
367 3 : torture_wait_for_oplock_break(tctx);
368 3 : CHECK_VAL(break_info.count, 0);
369 3 : CHECK_VAL(break_info.failures, 0);
370 :
371 3 : smb2_util_close(tree1, h1);
372 3 : smb2_util_close(tree1, h);
373 :
374 3 : smb2_deltree(tree1, BASEDIR);
375 3 : return ret;
376 : }
377 :
378 3 : static bool test_smb2_oplock_exclusive2(struct torture_context *tctx,
379 : struct smb2_tree *tree1,
380 : struct smb2_tree *tree2)
381 : {
382 3 : const char *fname = BASEDIR "\\test_exclusive2.dat";
383 0 : NTSTATUS status;
384 3 : bool ret = true;
385 0 : union smb_open io;
386 0 : struct smb2_handle h, h1, h2;
387 :
388 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
389 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
390 :
391 : /* cleanup */
392 3 : smb2_util_unlink(tree1, fname);
393 :
394 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
395 3 : tree1->session->transport->oplock.private_data = tree1;
396 :
397 : /*
398 : base ntcreatex parms
399 : */
400 3 : ZERO_STRUCT(io.smb2);
401 3 : io.generic.level = RAW_OPEN_SMB2;
402 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
403 3 : io.smb2.in.alloc_size = 0;
404 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
405 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
406 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
407 3 : io.smb2.in.create_options = 0;
408 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
409 3 : io.smb2.in.security_flags = 0;
410 3 : io.smb2.in.fname = fname;
411 :
412 3 : torture_comment(tctx, "EXCLUSIVE2: open a file with an exclusive "
413 : "oplock (share mode: all)\n");
414 3 : ZERO_STRUCT(break_info);
415 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
416 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
417 : NTCREATEX_SHARE_ACCESS_WRITE|
418 : NTCREATEX_SHARE_ACCESS_DELETE;
419 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
420 :
421 3 : status = smb2_create(tree1, tctx, &(io.smb2));
422 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
423 3 : h1 = io.smb2.out.file.handle;
424 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
425 :
426 3 : torture_comment(tctx, "a 2nd open should cause a break to level 2\n");
427 3 : status = smb2_create(tree2, tctx, &(io.smb2));
428 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
429 3 : h2 = io.smb2.out.file.handle;
430 3 : torture_wait_for_oplock_break(tctx);
431 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
432 3 : CHECK_VAL(break_info.count, 1);
433 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
434 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
435 3 : CHECK_VAL(break_info.failures, 0);
436 3 : ZERO_STRUCT(break_info);
437 :
438 : /* now we have 2 level II oplocks... */
439 3 : torture_comment(tctx, "try to unlink it - should cause a break\n");
440 3 : status = smb2_util_unlink(tree2, fname);
441 3 : torture_assert_ntstatus_ok(tctx, status, "Error unlinking the file");
442 2 : torture_wait_for_oplock_break(tctx);
443 2 : CHECK_VAL(break_info.count, 0);
444 2 : CHECK_VAL(break_info.failures, 0);
445 :
446 2 : torture_comment(tctx, "close both handles\n");
447 2 : smb2_util_close(tree1, h1);
448 2 : smb2_util_close(tree1, h2);
449 2 : smb2_util_close(tree1, h);
450 :
451 2 : smb2_deltree(tree1, BASEDIR);
452 2 : return ret;
453 : }
454 :
455 3 : static bool test_smb2_oplock_exclusive3(struct torture_context *tctx,
456 : struct smb2_tree *tree1,
457 : struct smb2_tree *tree2)
458 : {
459 3 : const char *fname = BASEDIR "\\test_exclusive3.dat";
460 0 : NTSTATUS status;
461 3 : bool ret = true;
462 0 : union smb_open io;
463 0 : union smb_setfileinfo sfi;
464 0 : struct smb2_handle h, h1;
465 :
466 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
467 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
468 :
469 : /* cleanup */
470 3 : smb2_util_unlink(tree1, fname);
471 :
472 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
473 3 : tree1->session->transport->oplock.private_data = tree1;
474 :
475 : /*
476 : base ntcreatex parms
477 : */
478 3 : ZERO_STRUCT(io.smb2);
479 3 : io.generic.level = RAW_OPEN_SMB2;
480 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
481 3 : io.smb2.in.alloc_size = 0;
482 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
483 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
484 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
485 3 : io.smb2.in.create_options = 0;
486 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
487 3 : io.smb2.in.security_flags = 0;
488 3 : io.smb2.in.fname = fname;
489 :
490 3 : torture_comment(tctx, "EXCLUSIVE3: open a file with an exclusive "
491 : "oplock (share mode: none)\n");
492 :
493 3 : ZERO_STRUCT(break_info);
494 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
495 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
496 :
497 3 : status = smb2_create(tree1, tctx, &(io.smb2));
498 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
499 3 : h1 = io.smb2.out.file.handle;
500 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
501 :
502 3 : torture_comment(tctx, "setpathinfo EOF should trigger a break to "
503 : "none\n");
504 3 : ZERO_STRUCT(sfi);
505 3 : sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
506 3 : sfi.generic.in.file.path = fname;
507 3 : sfi.end_of_file_info.in.size = 100;
508 :
509 3 : status = smb2_composite_setpathinfo(tree2, &sfi);
510 :
511 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
512 : "Incorrect status");
513 3 : torture_wait_for_oplock_break(tctx);
514 3 : CHECK_VAL(break_info.count, 0);
515 3 : CHECK_VAL(break_info.failures, 0);
516 3 : CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
517 :
518 3 : smb2_util_close(tree1, h1);
519 3 : smb2_util_close(tree1, h);
520 :
521 3 : smb2_deltree(tree1, BASEDIR);
522 3 : return ret;
523 : }
524 :
525 3 : static bool test_smb2_oplock_exclusive4(struct torture_context *tctx,
526 : struct smb2_tree *tree1,
527 : struct smb2_tree *tree2)
528 : {
529 3 : const char *fname = BASEDIR "\\test_exclusive4.dat";
530 0 : NTSTATUS status;
531 3 : bool ret = true;
532 0 : union smb_open io;
533 0 : struct smb2_handle h, h1, h2;
534 :
535 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
536 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
537 :
538 : /* cleanup */
539 3 : smb2_util_unlink(tree1, fname);
540 :
541 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
542 3 : tree1->session->transport->oplock.private_data = tree1;
543 :
544 : /*
545 : base ntcreatex parms
546 : */
547 3 : ZERO_STRUCT(io.smb2);
548 3 : io.generic.level = RAW_OPEN_SMB2;
549 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
550 3 : io.smb2.in.alloc_size = 0;
551 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
552 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
553 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
554 3 : io.smb2.in.create_options = 0;
555 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
556 3 : io.smb2.in.security_flags = 0;
557 3 : io.smb2.in.fname = fname;
558 :
559 3 : torture_comment(tctx, "EXCLUSIVE4: open with exclusive oplock\n");
560 3 : ZERO_STRUCT(break_info);
561 :
562 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
563 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
564 3 : status = smb2_create(tree1, tctx, &(io.smb2));
565 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
566 3 : h1 = io.smb2.out.file.handle;
567 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
568 :
569 3 : ZERO_STRUCT(break_info);
570 3 : torture_comment(tctx, "second open with attributes only shouldn't "
571 : "cause oplock break\n");
572 :
573 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
574 3 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
575 : SEC_FILE_WRITE_ATTRIBUTE |
576 : SEC_STD_SYNCHRONIZE;
577 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
578 3 : status = smb2_create(tree2, tctx, &(io.smb2));
579 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
580 3 : h2 = io.smb2.out.file.handle;
581 3 : CHECK_VAL(io.smb2.out.oplock_level, NO_OPLOCK_RETURN);
582 3 : torture_wait_for_oplock_break(tctx);
583 3 : CHECK_VAL(break_info.count, 0);
584 3 : CHECK_VAL(break_info.failures, 0);
585 :
586 3 : smb2_util_close(tree1, h1);
587 3 : smb2_util_close(tree2, h2);
588 3 : smb2_util_close(tree1, h);
589 :
590 3 : smb2_deltree(tree1, BASEDIR);
591 3 : return ret;
592 : }
593 :
594 3 : static bool test_smb2_oplock_exclusive5(struct torture_context *tctx,
595 : struct smb2_tree *tree1,
596 : struct smb2_tree *tree2)
597 : {
598 3 : const char *fname = BASEDIR "\\test_exclusive5.dat";
599 0 : NTSTATUS status;
600 3 : bool ret = true;
601 0 : union smb_open io;
602 0 : struct smb2_handle h, h1, h2;
603 :
604 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
605 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
606 :
607 : /* cleanup */
608 3 : smb2_util_unlink(tree1, fname);
609 :
610 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
611 3 : tree1->session->transport->oplock.private_data = tree1;
612 :
613 3 : tree2->session->transport->oplock.handler = torture_oplock_handler;
614 3 : tree2->session->transport->oplock.private_data = tree2;
615 :
616 : /*
617 : base ntcreatex parms
618 : */
619 3 : ZERO_STRUCT(io.smb2);
620 3 : io.generic.level = RAW_OPEN_SMB2;
621 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
622 3 : io.smb2.in.alloc_size = 0;
623 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
624 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
625 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
626 3 : io.smb2.in.create_options = 0;
627 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
628 3 : io.smb2.in.security_flags = 0;
629 3 : io.smb2.in.fname = fname;
630 :
631 3 : torture_comment(tctx, "EXCLUSIVE5: open with exclusive oplock\n");
632 3 : ZERO_STRUCT(break_info);
633 :
634 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
635 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
636 : NTCREATEX_SHARE_ACCESS_WRITE|
637 : NTCREATEX_SHARE_ACCESS_DELETE;
638 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
639 3 : status = smb2_create(tree1, tctx, &(io.smb2));
640 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
641 3 : h1 = io.smb2.out.file.handle;
642 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
643 :
644 3 : ZERO_STRUCT(break_info);
645 :
646 3 : torture_comment(tctx, "second open with attributes only and "
647 : "NTCREATEX_DISP_OVERWRITE_IF disposition causes "
648 : "oplock break\n");
649 :
650 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
651 3 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
652 : SEC_FILE_WRITE_ATTRIBUTE |
653 : SEC_STD_SYNCHRONIZE;
654 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
655 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
656 3 : status = smb2_create(tree2, tctx, &(io.smb2));
657 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
658 3 : h2 = io.smb2.out.file.handle;
659 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
660 3 : torture_wait_for_oplock_break(tctx);
661 3 : CHECK_VAL(break_info.count, 1);
662 3 : CHECK_VAL(break_info.failures, 0);
663 :
664 3 : smb2_util_close(tree1, h1);
665 3 : smb2_util_close(tree2, h2);
666 3 : smb2_util_close(tree1, h);
667 :
668 3 : smb2_deltree(tree1, BASEDIR);
669 3 : return ret;
670 : }
671 :
672 3 : static bool test_smb2_oplock_exclusive6(struct torture_context *tctx,
673 : struct smb2_tree *tree1,
674 : struct smb2_tree *tree2)
675 : {
676 3 : const char *fname1 = BASEDIR "\\test_exclusive6_1.dat";
677 3 : const char *fname2 = BASEDIR "\\test_exclusive6_2.dat";
678 0 : NTSTATUS status;
679 3 : bool ret = true;
680 0 : union smb_open io;
681 0 : union smb_setfileinfo sinfo;
682 0 : struct smb2_close closeio;
683 0 : struct smb2_handle h, h1;
684 :
685 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
686 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
687 :
688 : /* cleanup */
689 3 : smb2_util_unlink(tree1, fname1);
690 3 : smb2_util_unlink(tree2, fname2);
691 :
692 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
693 3 : tree1->session->transport->oplock.private_data = tree1;
694 :
695 : /*
696 : base ntcreatex parms
697 : */
698 3 : ZERO_STRUCT(io.smb2);
699 3 : io.generic.level = RAW_OPEN_SMB2;
700 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
701 3 : io.smb2.in.alloc_size = 0;
702 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
703 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
704 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
705 3 : io.smb2.in.create_options = 0;
706 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
707 3 : io.smb2.in.security_flags = 0;
708 3 : io.smb2.in.fname = fname1;
709 :
710 3 : torture_comment(tctx, "EXCLUSIVE6: open a file with an exclusive "
711 : "oplock (share mode: none)\n");
712 3 : ZERO_STRUCT(break_info);
713 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
714 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
715 :
716 3 : status = smb2_create(tree1, tctx, &(io.smb2));
717 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
718 3 : h1 = io.smb2.out.file.handle;
719 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
720 :
721 3 : torture_comment(tctx, "rename with the parent directory handle open "
722 : "for DELETE should not generate a break but get "
723 : "a sharing violation\n");
724 3 : ZERO_STRUCT(sinfo);
725 3 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
726 3 : sinfo.rename_information.in.file.handle = h1;
727 3 : sinfo.rename_information.in.overwrite = true;
728 3 : sinfo.rename_information.in.new_name = fname2;
729 3 : status = smb2_setinfo_file(tree1, &sinfo);
730 :
731 3 : torture_comment(tctx, "trying rename while parent handle open for delete.\n");
732 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
733 : "Incorrect status");
734 2 : torture_wait_for_oplock_break(tctx);
735 2 : CHECK_VAL(break_info.count, 0);
736 2 : CHECK_VAL(break_info.failures, 0);
737 :
738 : /* Close the parent directory handle. */
739 2 : ZERO_STRUCT(closeio);
740 2 : closeio.in.file.handle = h;
741 2 : status = smb2_close(tree1, &closeio);
742 2 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
743 : "Incorrect status");
744 :
745 : /* Re-open without DELETE access. */
746 2 : ZERO_STRUCT(io);
747 2 : io.smb2.in.oplock_level = 0;
748 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL & (~SEC_STD_DELETE);
749 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
750 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
751 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
752 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
753 2 : io.smb2.in.fname = BASEDIR;
754 :
755 2 : status = smb2_create(tree1, tctx, &(io.smb2));
756 2 : torture_assert_ntstatus_ok(tctx, status, "Error opening the base directory");
757 :
758 2 : torture_comment(tctx, "rename with the parent directory handle open "
759 : "without DELETE should succeed without a break\n");
760 2 : ZERO_STRUCT(sinfo);
761 2 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
762 2 : sinfo.rename_information.in.file.handle = h1;
763 2 : sinfo.rename_information.in.overwrite = true;
764 2 : sinfo.rename_information.in.new_name = fname2;
765 2 : status = smb2_setinfo_file(tree1, &sinfo);
766 :
767 2 : torture_comment(tctx, "trying rename while parent handle open without delete\n");
768 2 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
769 : "Incorrect status");
770 2 : torture_wait_for_oplock_break(tctx);
771 2 : CHECK_VAL(break_info.count, 0);
772 2 : CHECK_VAL(break_info.failures, 0);
773 :
774 2 : smb2_util_close(tree1, h1);
775 2 : smb2_util_close(tree1, h);
776 :
777 2 : smb2_deltree(tree1, BASEDIR);
778 2 : return ret;
779 : }
780 :
781 3 : static bool test_smb2_oplock_exclusive9(struct torture_context *tctx,
782 : struct smb2_tree *tree1,
783 : struct smb2_tree *tree2)
784 : {
785 3 : const char *fname = BASEDIR "\\test_exclusive9.dat";
786 0 : NTSTATUS status;
787 3 : bool ret = true;
788 0 : union smb_open io;
789 0 : struct smb2_handle h1, h2;
790 0 : int i;
791 :
792 0 : struct {
793 : uint32_t create_disposition;
794 : uint32_t break_level;
795 3 : } levels[] = {
796 : { NTCREATEX_DISP_SUPERSEDE, SMB2_OPLOCK_LEVEL_NONE },
797 : { NTCREATEX_DISP_OPEN, SMB2_OPLOCK_LEVEL_II },
798 : { NTCREATEX_DISP_OVERWRITE_IF, SMB2_OPLOCK_LEVEL_NONE },
799 : { NTCREATEX_DISP_OPEN_IF, SMB2_OPLOCK_LEVEL_II },
800 : };
801 :
802 :
803 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h1);
804 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
805 3 : smb2_util_close(tree1, h1);
806 :
807 : /* cleanup */
808 3 : smb2_util_unlink(tree1, fname);
809 :
810 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
811 3 : tree1->session->transport->oplock.private_data = tree1;
812 :
813 : /*
814 : base ntcreatex parms
815 : */
816 3 : ZERO_STRUCT(io.smb2);
817 3 : io.generic.level = RAW_OPEN_SMB2;
818 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
819 3 : io.smb2.in.alloc_size = 0;
820 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
821 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
822 : NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
823 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
824 3 : io.smb2.in.create_options = 0;
825 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
826 3 : io.smb2.in.security_flags = 0;
827 3 : io.smb2.in.fname = fname;
828 :
829 15 : for (i=0; i<ARRAY_SIZE(levels); i++) {
830 :
831 12 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
832 12 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
833 :
834 12 : status = smb2_create(tree1, tctx, &(io.smb2));
835 12 : torture_assert_ntstatus_ok(tctx, status,
836 : "Error opening the file");
837 12 : h1 = io.smb2.out.file.handle;
838 12 : CHECK_VAL(io.smb2.out.oplock_level,
839 : SMB2_OPLOCK_LEVEL_EXCLUSIVE);
840 :
841 12 : ZERO_STRUCT(break_info);
842 :
843 12 : io.smb2.in.create_disposition = levels[i].create_disposition;
844 12 : status = smb2_create(tree2, tctx, &(io.smb2));
845 12 : torture_assert_ntstatus_ok(tctx, status,
846 : "Error opening the file");
847 12 : h2 = io.smb2.out.file.handle;
848 12 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
849 :
850 12 : CHECK_VAL(break_info.count, 1);
851 12 : CHECK_VAL(break_info.level, levels[i].break_level);
852 12 : CHECK_VAL(break_info.failures, 0);
853 :
854 12 : smb2_util_close(tree2, h2);
855 12 : smb2_util_close(tree1, h1);
856 : }
857 :
858 3 : smb2_deltree(tree1, BASEDIR);
859 3 : return ret;
860 : }
861 :
862 3 : static bool test_smb2_oplock_batch1(struct torture_context *tctx,
863 : struct smb2_tree *tree1,
864 : struct smb2_tree *tree2)
865 : {
866 3 : const char *fname = BASEDIR "\\test_batch1.dat";
867 0 : NTSTATUS status;
868 3 : bool ret = true;
869 0 : union smb_open io;
870 0 : struct smb2_handle h, h1;
871 3 : char c = 0;
872 :
873 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
874 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
875 :
876 : /* cleanup */
877 3 : smb2_util_unlink(tree1, fname);
878 :
879 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
880 3 : tree1->session->transport->oplock.private_data = tree1;
881 :
882 : /*
883 : base ntcreatex parms
884 : */
885 3 : ZERO_STRUCT(io.smb2);
886 3 : io.generic.level = RAW_OPEN_SMB2;
887 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
888 3 : io.smb2.in.alloc_size = 0;
889 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
890 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
891 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
892 3 : io.smb2.in.create_options = 0;
893 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
894 3 : io.smb2.in.security_flags = 0;
895 3 : io.smb2.in.fname = fname;
896 :
897 : /*
898 : with a batch oplock we get a break
899 : */
900 3 : torture_comment(tctx, "BATCH1: open with batch oplock\n");
901 3 : ZERO_STRUCT(break_info);
902 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
903 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
904 3 : status = smb2_create(tree1, tctx, &(io.smb2));
905 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
906 3 : h1 = io.smb2.out.file.handle;
907 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
908 :
909 3 : torture_comment(tctx, "unlink should generate a break\n");
910 3 : status = smb2_util_unlink(tree2, fname);
911 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
912 : "Incorrect status");
913 :
914 3 : torture_wait_for_oplock_break(tctx);
915 3 : CHECK_VAL(break_info.count, 1);
916 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
917 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
918 3 : CHECK_VAL(break_info.failures, 0);
919 :
920 3 : torture_comment(tctx, "2nd unlink should not generate a break\n");
921 3 : ZERO_STRUCT(break_info);
922 3 : status = smb2_util_unlink(tree2, fname);
923 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
924 : "Incorrect status");
925 :
926 3 : torture_wait_for_oplock_break(tctx);
927 3 : CHECK_VAL(break_info.count, 0);
928 :
929 3 : torture_comment(tctx, "writing should generate a self break to none\n");
930 3 : tree1->session->transport->oplock.handler =
931 : torture_oplock_handler_level2_to_none;
932 3 : smb2_util_write(tree1, h1, &c, 0, 1);
933 :
934 3 : torture_wait_for_oplock_break(tctx);
935 :
936 3 : CHECK_VAL(break_info.count, 1);
937 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
938 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
939 3 : CHECK_VAL(break_info.failures, 0);
940 :
941 3 : smb2_util_close(tree1, h1);
942 3 : smb2_util_close(tree1, h);
943 :
944 3 : smb2_deltree(tree1, BASEDIR);
945 3 : return ret;
946 : }
947 :
948 3 : static bool test_smb2_oplock_batch2(struct torture_context *tctx,
949 : struct smb2_tree *tree1,
950 : struct smb2_tree *tree2)
951 : {
952 3 : const char *fname = BASEDIR "\\test_batch2.dat";
953 0 : NTSTATUS status;
954 3 : bool ret = true;
955 0 : union smb_open io;
956 3 : char c = 0;
957 0 : struct smb2_handle h, h1;
958 :
959 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
960 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
961 :
962 : /* cleanup */
963 3 : smb2_util_unlink(tree1, fname);
964 :
965 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
966 3 : tree1->session->transport->oplock.private_data = tree1;
967 :
968 : /*
969 : base ntcreatex parms
970 : */
971 3 : ZERO_STRUCT(io.smb2);
972 3 : io.generic.level = RAW_OPEN_SMB2;
973 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
974 3 : io.smb2.in.alloc_size = 0;
975 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
976 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
977 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
978 3 : io.smb2.in.create_options = 0;
979 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
980 3 : io.smb2.in.security_flags = 0;
981 3 : io.smb2.in.fname = fname;
982 :
983 3 : torture_comment(tctx, "BATCH2: open with batch oplock\n");
984 3 : ZERO_STRUCT(break_info);
985 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
986 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
987 3 : status = smb2_create(tree1, tctx, &(io.smb2));
988 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
989 3 : h1 = io.smb2.out.file.handle;
990 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
991 :
992 3 : torture_comment(tctx, "unlink should generate a break, which we ack "
993 : "as break to none\n");
994 3 : tree1->session->transport->oplock.handler =
995 : torture_oplock_handler_ack_to_none;
996 3 : tree1->session->transport->oplock.private_data = tree1;
997 3 : status = smb2_util_unlink(tree2, fname);
998 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
999 : "Incorrect status");
1000 :
1001 3 : torture_wait_for_oplock_break(tctx);
1002 3 : CHECK_VAL(break_info.count, 1);
1003 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1004 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1005 3 : CHECK_VAL(break_info.failures, 0);
1006 :
1007 3 : torture_comment(tctx, "2nd unlink should not generate a break\n");
1008 3 : ZERO_STRUCT(break_info);
1009 3 : status = smb2_util_unlink(tree2, fname);
1010 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1011 : "Incorrect status");
1012 :
1013 3 : torture_wait_for_oplock_break(tctx);
1014 3 : CHECK_VAL(break_info.count, 0);
1015 :
1016 3 : torture_comment(tctx, "writing should not generate a break\n");
1017 3 : smb2_util_write(tree1, h1, &c, 0, 1);
1018 :
1019 3 : torture_wait_for_oplock_break(tctx);
1020 3 : CHECK_VAL(break_info.count, 0);
1021 :
1022 3 : smb2_util_close(tree1, h1);
1023 3 : smb2_util_close(tree1, h);
1024 :
1025 3 : smb2_deltree(tree1, BASEDIR);
1026 3 : return ret;
1027 : }
1028 :
1029 3 : static bool test_smb2_oplock_batch3(struct torture_context *tctx,
1030 : struct smb2_tree *tree1,
1031 : struct smb2_tree *tree2)
1032 : {
1033 3 : const char *fname = BASEDIR "\\test_batch3.dat";
1034 0 : NTSTATUS status;
1035 3 : bool ret = true;
1036 0 : union smb_open io;
1037 0 : struct smb2_handle h, h1;
1038 :
1039 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1040 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1041 :
1042 : /* cleanup */
1043 3 : smb2_util_unlink(tree1, fname);
1044 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
1045 3 : tree1->session->transport->oplock.private_data = tree1;
1046 :
1047 : /*
1048 : base ntcreatex parms
1049 : */
1050 3 : ZERO_STRUCT(io.smb2);
1051 3 : io.generic.level = RAW_OPEN_SMB2;
1052 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1053 3 : io.smb2.in.alloc_size = 0;
1054 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1055 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1056 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1057 3 : io.smb2.in.create_options = 0;
1058 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1059 3 : io.smb2.in.security_flags = 0;
1060 3 : io.smb2.in.fname = fname;
1061 :
1062 3 : torture_comment(tctx, "BATCH3: if we close on break then the unlink "
1063 : "can succeed\n");
1064 3 : ZERO_STRUCT(break_info);
1065 3 : tree1->session->transport->oplock.handler =
1066 : torture_oplock_handler_close;
1067 3 : tree1->session->transport->oplock.private_data = tree1;
1068 :
1069 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1070 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1071 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1072 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1073 3 : h1 = io.smb2.out.file.handle;
1074 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1075 :
1076 3 : ZERO_STRUCT(break_info);
1077 3 : status = smb2_util_unlink(tree2, fname);
1078 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1079 :
1080 3 : torture_wait_for_oplock_break(tctx);
1081 3 : CHECK_VAL(break_info.count, 1);
1082 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1083 3 : CHECK_VAL(break_info.level, 1);
1084 3 : CHECK_VAL(break_info.failures, 0);
1085 :
1086 3 : smb2_util_close(tree1, h1);
1087 3 : smb2_util_close(tree1, h);
1088 :
1089 3 : smb2_deltree(tree1, BASEDIR);
1090 3 : return ret;
1091 : }
1092 :
1093 3 : static bool test_smb2_oplock_batch4(struct torture_context *tctx,
1094 : struct smb2_tree *tree1,
1095 : struct smb2_tree *tree2)
1096 : {
1097 3 : const char *fname = BASEDIR "\\test_batch4.dat";
1098 0 : NTSTATUS status;
1099 3 : bool ret = true;
1100 0 : union smb_open io;
1101 0 : struct smb2_read r;
1102 0 : struct smb2_handle h, h1;
1103 :
1104 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1105 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1106 :
1107 : /* cleanup */
1108 3 : smb2_util_unlink(tree1, fname);
1109 :
1110 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
1111 3 : tree1->session->transport->oplock.private_data = tree1;
1112 :
1113 : /*
1114 : base ntcreatex parms
1115 : */
1116 3 : ZERO_STRUCT(io.smb2);
1117 3 : io.generic.level = RAW_OPEN_SMB2;
1118 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1119 3 : io.smb2.in.alloc_size = 0;
1120 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1121 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1122 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1123 3 : io.smb2.in.create_options = 0;
1124 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1125 3 : io.smb2.in.security_flags = 0;
1126 3 : io.smb2.in.fname = fname;
1127 :
1128 3 : torture_comment(tctx, "BATCH4: a self read should not cause a break\n");
1129 3 : ZERO_STRUCT(break_info);
1130 :
1131 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
1132 3 : tree1->session->transport->oplock.private_data = tree1;
1133 :
1134 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1135 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1136 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1137 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1138 3 : h1 = io.smb2.out.file.handle;
1139 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1140 :
1141 3 : ZERO_STRUCT(r);
1142 3 : r.in.file.handle = h1;
1143 3 : r.in.offset = 0;
1144 :
1145 3 : status = smb2_read(tree1, tree1, &r);
1146 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1147 3 : torture_wait_for_oplock_break(tctx);
1148 3 : CHECK_VAL(break_info.count, 0);
1149 3 : CHECK_VAL(break_info.failures, 0);
1150 :
1151 3 : smb2_util_close(tree1, h1);
1152 3 : smb2_util_close(tree1, h);
1153 :
1154 3 : smb2_deltree(tree1, BASEDIR);
1155 3 : return ret;
1156 : }
1157 :
1158 3 : static bool test_smb2_oplock_batch5(struct torture_context *tctx,
1159 : struct smb2_tree *tree1,
1160 : struct smb2_tree *tree2)
1161 : {
1162 3 : const char *fname = BASEDIR "\\test_batch5.dat";
1163 0 : NTSTATUS status;
1164 3 : bool ret = true;
1165 0 : union smb_open io;
1166 0 : struct smb2_handle h, h1;
1167 :
1168 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1169 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1170 :
1171 : /* cleanup */
1172 3 : smb2_util_unlink(tree1, fname);
1173 :
1174 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
1175 3 : tree1->session->transport->oplock.private_data = tree1;
1176 :
1177 : /*
1178 : base ntcreatex parms
1179 : */
1180 3 : ZERO_STRUCT(io.smb2);
1181 3 : io.generic.level = RAW_OPEN_SMB2;
1182 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1183 3 : io.smb2.in.alloc_size = 0;
1184 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1185 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1186 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1187 3 : io.smb2.in.create_options = 0;
1188 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1189 3 : io.smb2.in.security_flags = 0;
1190 3 : io.smb2.in.fname = fname;
1191 :
1192 3 : torture_comment(tctx, "BATCH5: a 2nd open should give a break\n");
1193 3 : ZERO_STRUCT(break_info);
1194 :
1195 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1196 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1197 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1198 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1199 3 : h1 = io.smb2.out.file.handle;
1200 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1201 :
1202 3 : ZERO_STRUCT(break_info);
1203 :
1204 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1205 3 : status = smb2_create(tree2, tctx, &(io.smb2));
1206 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1207 : "Incorrect status");
1208 :
1209 3 : torture_wait_for_oplock_break(tctx);
1210 3 : CHECK_VAL(break_info.count, 1);
1211 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1212 3 : CHECK_VAL(break_info.level, 1);
1213 3 : CHECK_VAL(break_info.failures, 0);
1214 :
1215 3 : smb2_util_close(tree1, h1);
1216 3 : smb2_util_close(tree1, h);
1217 :
1218 3 : smb2_deltree(tree1, BASEDIR);
1219 3 : return ret;
1220 : }
1221 :
1222 3 : static bool test_smb2_oplock_batch6(struct torture_context *tctx,
1223 : struct smb2_tree *tree1,
1224 : struct smb2_tree *tree2)
1225 : {
1226 3 : const char *fname = BASEDIR "\\test_batch6.dat";
1227 0 : NTSTATUS status;
1228 3 : bool ret = true;
1229 0 : union smb_open io;
1230 0 : struct smb2_handle h, h1, h2;
1231 3 : char c = 0;
1232 :
1233 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1234 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1235 :
1236 : /* cleanup */
1237 3 : smb2_util_unlink(tree1, fname);
1238 :
1239 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
1240 3 : tree1->session->transport->oplock.private_data = tree1;
1241 :
1242 : /*
1243 : base ntcreatex parms
1244 : */
1245 3 : ZERO_STRUCT(io.smb2);
1246 3 : io.generic.level = RAW_OPEN_SMB2;
1247 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1248 3 : io.smb2.in.alloc_size = 0;
1249 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1250 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1251 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1252 3 : io.smb2.in.create_options = 0;
1253 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1254 3 : io.smb2.in.security_flags = 0;
1255 3 : io.smb2.in.fname = fname;
1256 :
1257 3 : torture_comment(tctx, "BATCH6: a 2nd open should give a break to "
1258 : "level II if the first open allowed shared read\n");
1259 3 : ZERO_STRUCT(break_info);
1260 3 : tree2->session->transport->oplock.handler = torture_oplock_handler;
1261 3 : tree2->session->transport->oplock.private_data = tree2;
1262 :
1263 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
1264 : SEC_RIGHTS_FILE_WRITE;
1265 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1266 : NTCREATEX_SHARE_ACCESS_WRITE;
1267 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1268 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1269 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1270 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1271 3 : h1 = io.smb2.out.file.handle;
1272 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1273 :
1274 3 : ZERO_STRUCT(break_info);
1275 :
1276 3 : status = smb2_create(tree2, tctx, &(io.smb2));
1277 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1278 3 : h2 = io.smb2.out.file.handle;
1279 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1280 :
1281 3 : torture_wait_for_oplock_break(tctx);
1282 3 : CHECK_VAL(break_info.count, 1);
1283 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1284 3 : CHECK_VAL(break_info.level, 1);
1285 3 : CHECK_VAL(break_info.failures, 0);
1286 3 : ZERO_STRUCT(break_info);
1287 :
1288 3 : torture_comment(tctx, "write should trigger a break to none on both\n");
1289 3 : tree1->session->transport->oplock.handler =
1290 : torture_oplock_handler_level2_to_none;
1291 3 : tree2->session->transport->oplock.handler =
1292 : torture_oplock_handler_level2_to_none;
1293 3 : smb2_util_write(tree1, h1, &c, 0, 1);
1294 :
1295 : /* We expect two breaks */
1296 3 : torture_wait_for_oplock_break(tctx);
1297 3 : torture_wait_for_oplock_break(tctx);
1298 :
1299 3 : CHECK_VAL(break_info.count, 2);
1300 3 : CHECK_VAL(break_info.level, 0);
1301 3 : CHECK_VAL(break_info.failures, 0);
1302 :
1303 3 : smb2_util_close(tree1, h1);
1304 3 : smb2_util_close(tree2, h2);
1305 3 : smb2_util_close(tree1, h);
1306 :
1307 3 : smb2_deltree(tree1, BASEDIR);
1308 3 : return ret;
1309 : }
1310 :
1311 3 : static bool test_smb2_oplock_batch7(struct torture_context *tctx,
1312 : struct smb2_tree *tree1,
1313 : struct smb2_tree *tree2)
1314 : {
1315 3 : const char *fname = BASEDIR "\\test_batch7.dat";
1316 0 : NTSTATUS status;
1317 3 : bool ret = true;
1318 0 : union smb_open io;
1319 0 : struct smb2_handle h, h1, h2;
1320 :
1321 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1322 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1323 :
1324 : /* cleanup */
1325 3 : smb2_util_unlink(tree1, fname);
1326 :
1327 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
1328 3 : tree1->session->transport->oplock.private_data = tree1;
1329 :
1330 : /*
1331 : base ntcreatex parms
1332 : */
1333 3 : ZERO_STRUCT(io.smb2);
1334 3 : io.generic.level = RAW_OPEN_SMB2;
1335 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1336 3 : io.smb2.in.alloc_size = 0;
1337 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1338 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1339 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1340 3 : io.smb2.in.create_options = 0;
1341 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1342 3 : io.smb2.in.security_flags = 0;
1343 3 : io.smb2.in.fname = fname;
1344 :
1345 3 : torture_comment(tctx, "BATCH7: a 2nd open should get an oplock when "
1346 : "we close instead of ack\n");
1347 3 : ZERO_STRUCT(break_info);
1348 3 : tree1->session->transport->oplock.handler =
1349 : torture_oplock_handler_close;
1350 3 : tree1->session->transport->oplock.private_data = tree1;
1351 :
1352 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1353 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1354 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1355 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1356 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1357 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1358 3 : h2 = io.smb2.out.file.handle;
1359 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1360 :
1361 3 : ZERO_STRUCT(break_info);
1362 :
1363 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1364 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1365 3 : status = smb2_create(tree2, tctx, &(io.smb2));
1366 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1367 3 : h1 = io.smb2.out.file.handle;
1368 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1369 :
1370 3 : torture_wait_for_oplock_break(tctx);
1371 3 : CHECK_VAL(break_info.count, 1);
1372 3 : CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1373 3 : CHECK_VAL(break_info.level, 1);
1374 3 : CHECK_VAL(break_info.failures, 0);
1375 :
1376 3 : smb2_util_close(tree2, h1);
1377 3 : smb2_util_close(tree2, h);
1378 :
1379 3 : smb2_deltree(tree1, BASEDIR);
1380 3 : return ret;
1381 : }
1382 :
1383 3 : static bool test_smb2_oplock_batch8(struct torture_context *tctx,
1384 : struct smb2_tree *tree1,
1385 : struct smb2_tree *tree2)
1386 : {
1387 3 : const char *fname = BASEDIR "\\test_batch8.dat";
1388 0 : NTSTATUS status;
1389 3 : bool ret = true;
1390 0 : union smb_open io;
1391 0 : struct smb2_handle h, h1, h2;
1392 :
1393 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1394 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1395 :
1396 : /* cleanup */
1397 3 : smb2_util_unlink(tree1, fname);
1398 :
1399 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
1400 3 : tree1->session->transport->oplock.private_data = tree1;
1401 :
1402 : /*
1403 : base ntcreatex parms
1404 : */
1405 3 : ZERO_STRUCT(io.smb2);
1406 3 : io.generic.level = RAW_OPEN_SMB2;
1407 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1408 3 : io.smb2.in.alloc_size = 0;
1409 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1410 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1411 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1412 3 : io.smb2.in.create_options = 0;
1413 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1414 3 : io.smb2.in.security_flags = 0;
1415 3 : io.smb2.in.fname = fname;
1416 :
1417 3 : torture_comment(tctx, "BATCH8: open with batch oplock\n");
1418 3 : ZERO_STRUCT(break_info);
1419 :
1420 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1421 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1422 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1423 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1424 3 : h1 = io.smb2.out.file.handle;
1425 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1426 :
1427 3 : ZERO_STRUCT(break_info);
1428 3 : torture_comment(tctx, "second open with attributes only shouldn't "
1429 : "cause oplock break\n");
1430 :
1431 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1432 3 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1433 : SEC_FILE_WRITE_ATTRIBUTE |
1434 : SEC_STD_SYNCHRONIZE;
1435 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1436 3 : status = smb2_create(tree2, tctx, &(io.smb2));
1437 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1438 3 : h2 = io.smb2.out.file.handle;
1439 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1440 3 : torture_wait_for_oplock_break(tctx);
1441 3 : CHECK_VAL(break_info.count, 0);
1442 3 : CHECK_VAL(break_info.failures, 0);
1443 :
1444 3 : smb2_util_close(tree1, h1);
1445 3 : smb2_util_close(tree2, h2);
1446 3 : smb2_util_close(tree1, h);
1447 :
1448 3 : smb2_deltree(tree1, BASEDIR);
1449 3 : return ret;
1450 : }
1451 :
1452 3 : static bool test_smb2_oplock_batch9(struct torture_context *tctx,
1453 : struct smb2_tree *tree1,
1454 : struct smb2_tree *tree2)
1455 : {
1456 3 : const char *fname = BASEDIR "\\test_batch9.dat";
1457 0 : NTSTATUS status;
1458 3 : bool ret = true;
1459 0 : union smb_open io;
1460 0 : struct smb2_handle h, h1, h2;
1461 3 : char c = 0;
1462 :
1463 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1464 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1465 :
1466 : /* cleanup */
1467 3 : smb2_util_unlink(tree1, fname);
1468 :
1469 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
1470 3 : tree1->session->transport->oplock.private_data = tree1;
1471 :
1472 : /*
1473 : base ntcreatex parms
1474 : */
1475 3 : ZERO_STRUCT(io.smb2);
1476 3 : io.generic.level = RAW_OPEN_SMB2;
1477 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1478 3 : io.smb2.in.alloc_size = 0;
1479 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1480 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1481 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1482 3 : io.smb2.in.create_options = 0;
1483 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1484 3 : io.smb2.in.security_flags = 0;
1485 3 : io.smb2.in.fname = fname;
1486 :
1487 3 : torture_comment(tctx, "BATCH9: open with attributes only can create "
1488 : "file\n");
1489 :
1490 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1491 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1492 3 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1493 : SEC_FILE_WRITE_ATTRIBUTE |
1494 : SEC_STD_SYNCHRONIZE;
1495 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1496 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1497 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1498 3 : h1 = io.smb2.out.file.handle;
1499 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1500 :
1501 3 : torture_comment(tctx, "Subsequent normal open should break oplock on "
1502 : "attribute only open to level II\n");
1503 :
1504 3 : ZERO_STRUCT(break_info);
1505 :
1506 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1507 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1508 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1509 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1510 3 : status = smb2_create(tree2, tctx, &(io.smb2));
1511 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1512 3 : h2 = io.smb2.out.file.handle;
1513 3 : torture_wait_for_oplock_break(tctx);
1514 3 : CHECK_VAL(break_info.count, 1);
1515 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1516 3 : CHECK_VAL(break_info.failures, 0);
1517 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1518 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1519 3 : smb2_util_close(tree2, h2);
1520 :
1521 3 : torture_comment(tctx, "third oplocked open should grant level2 without "
1522 : "break\n");
1523 3 : ZERO_STRUCT(break_info);
1524 :
1525 3 : tree2->session->transport->oplock.handler = torture_oplock_handler;
1526 3 : tree2->session->transport->oplock.private_data = tree2;
1527 :
1528 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1529 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1530 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1531 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1532 3 : status = smb2_create(tree2, tctx, &(io.smb2));
1533 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1534 3 : h2 = io.smb2.out.file.handle;
1535 3 : torture_wait_for_oplock_break(tctx);
1536 3 : CHECK_VAL(break_info.count, 0);
1537 3 : CHECK_VAL(break_info.failures, 0);
1538 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1539 :
1540 3 : ZERO_STRUCT(break_info);
1541 :
1542 3 : torture_comment(tctx, "write should trigger a break to none on both\n");
1543 3 : tree1->session->transport->oplock.handler =
1544 : torture_oplock_handler_level2_to_none;
1545 3 : tree2->session->transport->oplock.handler =
1546 : torture_oplock_handler_level2_to_none;
1547 3 : smb2_util_write(tree2, h2, &c, 0, 1);
1548 :
1549 : /* We expect two breaks */
1550 3 : torture_wait_for_oplock_break(tctx);
1551 3 : torture_wait_for_oplock_break(tctx);
1552 :
1553 3 : CHECK_VAL(break_info.count, 2);
1554 3 : CHECK_VAL(break_info.level, 0);
1555 3 : CHECK_VAL(break_info.failures, 0);
1556 :
1557 3 : smb2_util_close(tree1, h1);
1558 3 : smb2_util_close(tree2, h2);
1559 3 : smb2_util_close(tree1, h);
1560 :
1561 3 : smb2_deltree(tree1, BASEDIR);
1562 3 : return ret;
1563 : }
1564 :
1565 3 : static bool test_smb2_oplock_batch9a(struct torture_context *tctx,
1566 : struct smb2_tree *tree1,
1567 : struct smb2_tree *tree2)
1568 : {
1569 3 : const char *fname = BASEDIR "\\test_batch9a.dat";
1570 0 : NTSTATUS status;
1571 3 : bool ret = true;
1572 0 : union smb_open io;
1573 0 : struct smb2_handle h, h1, h2, h3;
1574 3 : char c = 0;
1575 :
1576 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1577 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1578 :
1579 : /* cleanup */
1580 3 : smb2_util_unlink(tree1, fname);
1581 :
1582 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
1583 3 : tree1->session->transport->oplock.private_data = tree1;
1584 :
1585 : /*
1586 : base ntcreatex parms
1587 : */
1588 3 : ZERO_STRUCT(io.smb2);
1589 3 : io.generic.level = RAW_OPEN_SMB2;
1590 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1591 3 : io.smb2.in.alloc_size = 0;
1592 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1593 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1594 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1595 3 : io.smb2.in.create_options = 0;
1596 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1597 3 : io.smb2.in.security_flags = 0;
1598 3 : io.smb2.in.fname = fname;
1599 :
1600 3 : torture_comment(tctx, "BATCH9: open with attributes only can create "
1601 : "file\n");
1602 :
1603 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1604 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1605 3 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1606 : SEC_FILE_WRITE_ATTRIBUTE |
1607 : SEC_STD_SYNCHRONIZE;
1608 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1609 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating the file");
1610 3 : h1 = io.smb2.out.file.handle;
1611 3 : CHECK_VAL(io.smb2.out.create_action, FILE_WAS_CREATED);
1612 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1613 :
1614 3 : torture_comment(tctx, "Subsequent attributes open should not break\n");
1615 :
1616 3 : ZERO_STRUCT(break_info);
1617 :
1618 3 : status = smb2_create(tree2, tctx, &(io.smb2));
1619 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1620 3 : h3 = io.smb2.out.file.handle;
1621 3 : torture_wait_for_oplock_break(tctx);
1622 3 : CHECK_VAL(break_info.count, 0);
1623 3 : CHECK_VAL(io.smb2.out.create_action, FILE_WAS_OPENED);
1624 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1625 3 : smb2_util_close(tree2, h3);
1626 :
1627 3 : torture_comment(tctx, "Subsequent normal open should break oplock on "
1628 : "attribute only open to level II\n");
1629 :
1630 3 : ZERO_STRUCT(break_info);
1631 :
1632 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1633 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1634 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1635 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1636 3 : status = smb2_create(tree2, tctx, &(io.smb2));
1637 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1638 3 : h2 = io.smb2.out.file.handle;
1639 3 : torture_wait_for_oplock_break(tctx);
1640 3 : CHECK_VAL(break_info.count, 1);
1641 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1642 3 : CHECK_VAL(break_info.failures, 0);
1643 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1644 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1645 3 : smb2_util_close(tree2, h2);
1646 :
1647 3 : torture_comment(tctx, "third oplocked open should grant level2 without "
1648 : "break\n");
1649 3 : ZERO_STRUCT(break_info);
1650 :
1651 3 : tree2->session->transport->oplock.handler = torture_oplock_handler;
1652 3 : tree2->session->transport->oplock.private_data = tree2;
1653 :
1654 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1655 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1656 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1657 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1658 3 : status = smb2_create(tree2, tctx, &(io.smb2));
1659 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1660 3 : h2 = io.smb2.out.file.handle;
1661 3 : torture_wait_for_oplock_break(tctx);
1662 3 : CHECK_VAL(break_info.count, 0);
1663 3 : CHECK_VAL(break_info.failures, 0);
1664 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1665 :
1666 3 : ZERO_STRUCT(break_info);
1667 :
1668 3 : torture_comment(tctx, "write should trigger a break to none on both\n");
1669 3 : tree1->session->transport->oplock.handler =
1670 : torture_oplock_handler_level2_to_none;
1671 3 : tree2->session->transport->oplock.handler =
1672 : torture_oplock_handler_level2_to_none;
1673 3 : smb2_util_write(tree2, h2, &c, 0, 1);
1674 :
1675 : /* We expect two breaks */
1676 3 : torture_wait_for_oplock_break(tctx);
1677 3 : torture_wait_for_oplock_break(tctx);
1678 :
1679 3 : CHECK_VAL(break_info.count, 2);
1680 3 : CHECK_VAL(break_info.level, 0);
1681 3 : CHECK_VAL(break_info.failures, 0);
1682 :
1683 3 : smb2_util_close(tree1, h1);
1684 3 : smb2_util_close(tree2, h2);
1685 3 : smb2_util_close(tree1, h);
1686 :
1687 3 : smb2_deltree(tree1, BASEDIR);
1688 3 : return ret;
1689 : }
1690 :
1691 :
1692 3 : static bool test_smb2_oplock_batch10(struct torture_context *tctx,
1693 : struct smb2_tree *tree1,
1694 : struct smb2_tree *tree2)
1695 : {
1696 3 : const char *fname = BASEDIR "\\test_batch10.dat";
1697 0 : NTSTATUS status;
1698 3 : bool ret = true;
1699 0 : union smb_open io;
1700 0 : struct smb2_handle h, h1, h2;
1701 :
1702 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1703 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1704 :
1705 : /* cleanup */
1706 3 : smb2_util_unlink(tree1, fname);
1707 :
1708 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
1709 3 : tree1->session->transport->oplock.private_data = tree1;
1710 :
1711 : /*
1712 : base ntcreatex parms
1713 : */
1714 3 : ZERO_STRUCT(io.smb2);
1715 3 : io.generic.level = RAW_OPEN_SMB2;
1716 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1717 3 : io.smb2.in.alloc_size = 0;
1718 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1719 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1720 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1721 3 : io.smb2.in.create_options = 0;
1722 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1723 3 : io.smb2.in.security_flags = 0;
1724 3 : io.smb2.in.fname = fname;
1725 :
1726 3 : torture_comment(tctx, "BATCH10: Open with oplock after a non-oplock "
1727 : "open should grant level2\n");
1728 3 : ZERO_STRUCT(break_info);
1729 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1730 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1731 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1732 : NTCREATEX_SHARE_ACCESS_WRITE|
1733 : NTCREATEX_SHARE_ACCESS_DELETE;
1734 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1735 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1736 3 : h1 = io.smb2.out.file.handle;
1737 3 : torture_wait_for_oplock_break(tctx);
1738 3 : CHECK_VAL(break_info.count, 0);
1739 3 : CHECK_VAL(break_info.failures, 0);
1740 3 : CHECK_VAL(io.smb2.out.oplock_level, 0);
1741 :
1742 3 : tree2->session->transport->oplock.handler =
1743 : torture_oplock_handler_level2_to_none;
1744 3 : tree2->session->transport->oplock.private_data = tree2;
1745 :
1746 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1747 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1748 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1749 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1750 : NTCREATEX_SHARE_ACCESS_WRITE|
1751 : NTCREATEX_SHARE_ACCESS_DELETE;
1752 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1753 3 : status = smb2_create(tree2, tctx, &(io.smb2));
1754 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1755 3 : h2 = io.smb2.out.file.handle;
1756 3 : torture_wait_for_oplock_break(tctx);
1757 3 : CHECK_VAL(break_info.count, 0);
1758 3 : CHECK_VAL(break_info.failures, 0);
1759 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1760 :
1761 3 : torture_comment(tctx, "write should trigger a break to none\n");
1762 : {
1763 0 : struct smb2_write wr;
1764 0 : DATA_BLOB data;
1765 3 : data = data_blob_talloc_zero(tree1, UINT16_MAX);
1766 3 : data.data[0] = (const uint8_t)'x';
1767 3 : ZERO_STRUCT(wr);
1768 3 : wr.in.file.handle = h1;
1769 3 : wr.in.offset = 0;
1770 3 : wr.in.data = data;
1771 3 : status = smb2_write(tree1, &wr);
1772 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1773 : }
1774 :
1775 3 : torture_wait_for_oplock_break(tctx);
1776 :
1777 3 : CHECK_VAL(break_info.count, 1);
1778 3 : CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1779 3 : CHECK_VAL(break_info.level, 0);
1780 3 : CHECK_VAL(break_info.failures, 0);
1781 :
1782 3 : smb2_util_close(tree1, h1);
1783 3 : smb2_util_close(tree2, h2);
1784 3 : smb2_util_close(tree1, h);
1785 :
1786 3 : smb2_deltree(tree1, BASEDIR);
1787 3 : return ret;
1788 : }
1789 :
1790 3 : static bool test_smb2_oplock_batch11(struct torture_context *tctx,
1791 : struct smb2_tree *tree1,
1792 : struct smb2_tree *tree2)
1793 : {
1794 3 : const char *fname = BASEDIR "\\test_batch11.dat";
1795 0 : NTSTATUS status;
1796 3 : bool ret = true;
1797 0 : union smb_open io;
1798 0 : union smb_setfileinfo sfi;
1799 0 : struct smb2_handle h, h1;
1800 :
1801 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1802 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1803 :
1804 : /* cleanup */
1805 3 : smb2_util_unlink(tree1, fname);
1806 :
1807 3 : tree1->session->transport->oplock.handler =
1808 : torture_oplock_handler_two_notifications;
1809 3 : tree1->session->transport->oplock.private_data = tree1;
1810 :
1811 : /*
1812 : base ntcreatex parms
1813 : */
1814 3 : ZERO_STRUCT(io.smb2);
1815 3 : io.generic.level = RAW_OPEN_SMB2;
1816 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1817 3 : io.smb2.in.alloc_size = 0;
1818 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1819 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1820 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1821 3 : io.smb2.in.create_options = 0;
1822 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1823 3 : io.smb2.in.security_flags = 0;
1824 3 : io.smb2.in.fname = fname;
1825 :
1826 : /* Test if a set-eof on pathname breaks an exclusive oplock. */
1827 3 : torture_comment(tctx, "BATCH11: Test if setpathinfo set EOF breaks "
1828 : "oplocks.\n");
1829 :
1830 3 : ZERO_STRUCT(break_info);
1831 :
1832 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1833 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1834 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1835 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1836 : NTCREATEX_SHARE_ACCESS_WRITE|
1837 : NTCREATEX_SHARE_ACCESS_DELETE;
1838 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1839 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1840 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1841 3 : h1 = io.smb2.out.file.handle;
1842 3 : torture_wait_for_oplock_break(tctx);
1843 3 : CHECK_VAL(break_info.count, 0);
1844 3 : CHECK_VAL(break_info.failures, 0);
1845 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1846 :
1847 3 : ZERO_STRUCT(sfi);
1848 3 : sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1849 3 : sfi.generic.in.file.path = fname;
1850 3 : sfi.end_of_file_info.in.size = 100;
1851 :
1852 3 : status = smb2_composite_setpathinfo(tree2, &sfi);
1853 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1854 :
1855 : /* We expect two breaks */
1856 3 : torture_wait_for_oplock_break(tctx);
1857 3 : torture_wait_for_oplock_break(tctx);
1858 :
1859 3 : CHECK_VAL(break_info.count, 2);
1860 3 : CHECK_VAL(break_info.failures, 0);
1861 3 : CHECK_VAL(break_info.level, 0);
1862 :
1863 3 : smb2_util_close(tree1, h1);
1864 3 : smb2_util_close(tree1, h);
1865 :
1866 3 : smb2_deltree(tree1, BASEDIR);
1867 3 : return ret;
1868 : }
1869 :
1870 3 : static bool test_smb2_oplock_batch12(struct torture_context *tctx,
1871 : struct smb2_tree *tree1,
1872 : struct smb2_tree *tree2)
1873 : {
1874 3 : const char *fname = BASEDIR "\\test_batch12.dat";
1875 0 : NTSTATUS status;
1876 3 : bool ret = true;
1877 0 : union smb_open io;
1878 0 : union smb_setfileinfo sfi;
1879 0 : struct smb2_handle h, h1;
1880 :
1881 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1882 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1883 :
1884 : /* cleanup */
1885 3 : smb2_util_unlink(tree1, fname);
1886 :
1887 3 : tree1->session->transport->oplock.handler =
1888 : torture_oplock_handler_two_notifications;
1889 3 : tree1->session->transport->oplock.private_data = tree1;
1890 :
1891 : /*
1892 : base ntcreatex parms
1893 : */
1894 3 : ZERO_STRUCT(io.smb2);
1895 3 : io.generic.level = RAW_OPEN_SMB2;
1896 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1897 3 : io.smb2.in.alloc_size = 0;
1898 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1899 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1900 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1901 3 : io.smb2.in.create_options = 0;
1902 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1903 3 : io.smb2.in.security_flags = 0;
1904 3 : io.smb2.in.fname = fname;
1905 :
1906 : /* Test if a set-allocation size on pathname breaks an exclusive
1907 : * oplock. */
1908 3 : torture_comment(tctx, "BATCH12: Test if setpathinfo allocation size "
1909 : "breaks oplocks.\n");
1910 :
1911 3 : ZERO_STRUCT(break_info);
1912 :
1913 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1914 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1915 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1916 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1917 : NTCREATEX_SHARE_ACCESS_WRITE|
1918 : NTCREATEX_SHARE_ACCESS_DELETE;
1919 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1920 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1921 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1922 3 : h1 = io.smb2.out.file.handle;
1923 3 : torture_wait_for_oplock_break(tctx);
1924 3 : CHECK_VAL(break_info.count, 0);
1925 3 : CHECK_VAL(break_info.failures, 0);
1926 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1927 :
1928 3 : ZERO_STRUCT(sfi);
1929 3 : sfi.generic.level = RAW_SFILEINFO_ALLOCATION_INFORMATION;
1930 3 : sfi.generic.in.file.path = fname;
1931 3 : sfi.allocation_info.in.alloc_size = 65536 * 8;
1932 :
1933 3 : status = smb2_composite_setpathinfo(tree2, &sfi);
1934 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1935 :
1936 : /* We expect two breaks */
1937 3 : torture_wait_for_oplock_break(tctx);
1938 3 : torture_wait_for_oplock_break(tctx);
1939 :
1940 3 : CHECK_VAL(break_info.count, 2);
1941 3 : CHECK_VAL(break_info.failures, 0);
1942 3 : CHECK_VAL(break_info.level, 0);
1943 :
1944 3 : smb2_util_close(tree1, h1);
1945 3 : smb2_util_close(tree1, h);
1946 :
1947 3 : smb2_deltree(tree1, BASEDIR);
1948 3 : return ret;
1949 : }
1950 :
1951 3 : static bool test_smb2_oplock_batch13(struct torture_context *tctx,
1952 : struct smb2_tree *tree1,
1953 : struct smb2_tree *tree2)
1954 : {
1955 3 : const char *fname = BASEDIR "\\test_batch13.dat";
1956 0 : NTSTATUS status;
1957 3 : bool ret = true;
1958 0 : union smb_open io;
1959 0 : struct smb2_handle h, h1, h2;
1960 :
1961 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
1962 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1963 :
1964 : /* cleanup */
1965 3 : smb2_util_unlink(tree1, fname);
1966 :
1967 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
1968 3 : tree1->session->transport->oplock.private_data = tree1;
1969 :
1970 3 : tree2->session->transport->oplock.handler = torture_oplock_handler;
1971 3 : tree2->session->transport->oplock.private_data = tree2;
1972 :
1973 : /*
1974 : base ntcreatex parms
1975 : */
1976 3 : ZERO_STRUCT(io.smb2);
1977 3 : io.generic.level = RAW_OPEN_SMB2;
1978 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1979 3 : io.smb2.in.alloc_size = 0;
1980 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1981 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1982 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1983 3 : io.smb2.in.create_options = 0;
1984 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1985 3 : io.smb2.in.security_flags = 0;
1986 3 : io.smb2.in.fname = fname;
1987 :
1988 3 : torture_comment(tctx, "BATCH13: open with batch oplock\n");
1989 3 : ZERO_STRUCT(break_info);
1990 :
1991 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1992 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1993 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1994 : NTCREATEX_SHARE_ACCESS_WRITE|
1995 : NTCREATEX_SHARE_ACCESS_DELETE;
1996 3 : status = smb2_create(tree1, tctx, &(io.smb2));
1997 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1998 3 : h1 = io.smb2.out.file.handle;
1999 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2000 :
2001 3 : ZERO_STRUCT(break_info);
2002 :
2003 3 : torture_comment(tctx, "second open with attributes only and "
2004 : "NTCREATEX_DISP_OVERWRITE disposition causes "
2005 : "oplock break\n");
2006 :
2007 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2008 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2009 3 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2010 : SEC_FILE_WRITE_ATTRIBUTE |
2011 : SEC_STD_SYNCHRONIZE;
2012 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2013 : NTCREATEX_SHARE_ACCESS_WRITE|
2014 : NTCREATEX_SHARE_ACCESS_DELETE;
2015 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2016 3 : status = smb2_create(tree2, tctx, &(io.smb2));
2017 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2018 3 : h2 = io.smb2.out.file.handle;
2019 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2020 3 : torture_wait_for_oplock_break(tctx);
2021 3 : CHECK_VAL(break_info.count, 1);
2022 3 : CHECK_VAL(break_info.failures, 0);
2023 :
2024 3 : smb2_util_close(tree1, h1);
2025 3 : smb2_util_close(tree2, h2);
2026 3 : smb2_util_close(tree1, h);
2027 :
2028 3 : smb2_deltree(tree1, BASEDIR);
2029 :
2030 3 : return ret;
2031 : }
2032 :
2033 3 : static bool test_smb2_oplock_batch14(struct torture_context *tctx,
2034 : struct smb2_tree *tree1,
2035 : struct smb2_tree *tree2)
2036 : {
2037 3 : const char *fname = BASEDIR "\\test_batch14.dat";
2038 0 : NTSTATUS status;
2039 3 : bool ret = true;
2040 0 : union smb_open io;
2041 0 : struct smb2_handle h, h1, h2;
2042 :
2043 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2044 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2045 :
2046 : /* cleanup */
2047 3 : smb2_util_unlink(tree1, fname);
2048 :
2049 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2050 3 : tree1->session->transport->oplock.private_data = tree1;
2051 :
2052 : /*
2053 : base ntcreatex parms
2054 : */
2055 3 : ZERO_STRUCT(io.smb2);
2056 3 : io.generic.level = RAW_OPEN_SMB2;
2057 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2058 3 : io.smb2.in.alloc_size = 0;
2059 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2060 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2061 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2062 3 : io.smb2.in.create_options = 0;
2063 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2064 3 : io.smb2.in.security_flags = 0;
2065 3 : io.smb2.in.fname = fname;
2066 :
2067 3 : torture_comment(tctx, "BATCH14: open with batch oplock\n");
2068 3 : ZERO_STRUCT(break_info);
2069 :
2070 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2071 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2072 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2073 : NTCREATEX_SHARE_ACCESS_WRITE|
2074 : NTCREATEX_SHARE_ACCESS_DELETE;
2075 3 : status = smb2_create(tree1, tctx, &(io.smb2));
2076 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2077 3 : h1 = io.smb2.out.file.handle;
2078 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2079 :
2080 3 : ZERO_STRUCT(break_info);
2081 :
2082 3 : torture_comment(tctx, "second open with attributes only and "
2083 : "NTCREATEX_DISP_SUPERSEDE disposition causes "
2084 : "oplock break\n");
2085 :
2086 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2087 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2088 3 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2089 : SEC_FILE_WRITE_ATTRIBUTE |
2090 : SEC_STD_SYNCHRONIZE;
2091 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2092 : NTCREATEX_SHARE_ACCESS_WRITE|
2093 : NTCREATEX_SHARE_ACCESS_DELETE;
2094 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2095 3 : status = smb2_create(tree2, tctx, &(io.smb2));
2096 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2097 3 : h2 = io.smb2.out.file.handle;
2098 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2099 :
2100 3 : torture_wait_for_oplock_break(tctx);
2101 3 : CHECK_VAL(break_info.count, 1);
2102 3 : CHECK_VAL(break_info.failures, 0);
2103 :
2104 3 : smb2_util_close(tree1, h1);
2105 3 : smb2_util_close(tree2, h2);
2106 3 : smb2_util_close(tree1, h);
2107 :
2108 3 : smb2_deltree(tree1, BASEDIR);
2109 3 : return ret;
2110 : }
2111 :
2112 3 : static bool test_smb2_oplock_batch15(struct torture_context *tctx,
2113 : struct smb2_tree *tree1,
2114 : struct smb2_tree *tree2)
2115 : {
2116 3 : const char *fname = BASEDIR "\\test_batch15.dat";
2117 0 : NTSTATUS status;
2118 3 : bool ret = true;
2119 0 : union smb_open io;
2120 0 : union smb_fileinfo qfi;
2121 0 : struct smb2_handle h, h1;
2122 :
2123 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2124 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2125 :
2126 : /* cleanup */
2127 3 : smb2_util_unlink(tree1, fname);
2128 :
2129 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2130 3 : tree1->session->transport->oplock.private_data = tree1;
2131 :
2132 : /*
2133 : base ntcreatex parms
2134 : */
2135 3 : ZERO_STRUCT(io.smb2);
2136 3 : io.generic.level = RAW_OPEN_SMB2;
2137 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2138 3 : io.smb2.in.alloc_size = 0;
2139 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2140 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2141 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2142 3 : io.smb2.in.create_options = 0;
2143 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2144 3 : io.smb2.in.security_flags = 0;
2145 3 : io.smb2.in.fname = fname;
2146 :
2147 : /* Test if a qpathinfo all info on pathname breaks a batch oplock. */
2148 3 : torture_comment(tctx, "BATCH15: Test if qpathinfo all info breaks "
2149 : "a batch oplock (should not).\n");
2150 :
2151 3 : ZERO_STRUCT(break_info);
2152 :
2153 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2154 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2155 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2156 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2157 : NTCREATEX_SHARE_ACCESS_WRITE|
2158 : NTCREATEX_SHARE_ACCESS_DELETE;
2159 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2160 3 : status = smb2_create(tree1, tctx, &(io.smb2));
2161 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2162 3 : h1 = io.smb2.out.file.handle;
2163 :
2164 3 : torture_wait_for_oplock_break(tctx);
2165 3 : CHECK_VAL(break_info.count, 0);
2166 3 : CHECK_VAL(break_info.failures, 0);
2167 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2168 :
2169 3 : ZERO_STRUCT(qfi);
2170 3 : qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2171 3 : qfi.generic.in.file.handle = h1;
2172 3 : status = smb2_getinfo_file(tree2, tctx, &qfi);
2173 :
2174 3 : torture_wait_for_oplock_break(tctx);
2175 3 : CHECK_VAL(break_info.count, 0);
2176 :
2177 3 : smb2_util_close(tree1, h1);
2178 3 : smb2_util_close(tree1, h);
2179 :
2180 3 : smb2_deltree(tree1, BASEDIR);
2181 3 : return ret;
2182 : }
2183 :
2184 3 : static bool test_smb2_oplock_batch16(struct torture_context *tctx,
2185 : struct smb2_tree *tree1,
2186 : struct smb2_tree *tree2)
2187 : {
2188 3 : const char *fname = BASEDIR "\\test_batch16.dat";
2189 0 : NTSTATUS status;
2190 3 : bool ret = true;
2191 0 : union smb_open io;
2192 0 : struct smb2_handle h, h1, h2;
2193 :
2194 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2195 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2196 :
2197 : /* cleanup */
2198 3 : smb2_util_unlink(tree1, fname);
2199 :
2200 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2201 3 : tree1->session->transport->oplock.private_data = tree1;
2202 :
2203 3 : tree2->session->transport->oplock.handler = torture_oplock_handler;
2204 3 : tree2->session->transport->oplock.private_data = tree2;
2205 :
2206 : /*
2207 : base ntcreatex parms
2208 : */
2209 3 : ZERO_STRUCT(io.smb2);
2210 3 : io.generic.level = RAW_OPEN_SMB2;
2211 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2212 3 : io.smb2.in.alloc_size = 0;
2213 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2214 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2215 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2216 3 : io.smb2.in.create_options = 0;
2217 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2218 3 : io.smb2.in.security_flags = 0;
2219 3 : io.smb2.in.fname = fname;
2220 :
2221 3 : torture_comment(tctx, "BATCH16: open with batch oplock\n");
2222 3 : ZERO_STRUCT(break_info);
2223 :
2224 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2225 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2226 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2227 : NTCREATEX_SHARE_ACCESS_WRITE|
2228 : NTCREATEX_SHARE_ACCESS_DELETE;
2229 3 : status = smb2_create(tree1, tctx, &(io.smb2));
2230 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2231 3 : h1 = io.smb2.out.file.handle;
2232 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2233 :
2234 3 : ZERO_STRUCT(break_info);
2235 :
2236 3 : torture_comment(tctx, "second open with attributes only and "
2237 : "NTCREATEX_DISP_OVERWRITE_IF disposition causes "
2238 : "oplock break\n");
2239 :
2240 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2241 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2242 3 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2243 : SEC_FILE_WRITE_ATTRIBUTE |
2244 : SEC_STD_SYNCHRONIZE;
2245 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2246 : NTCREATEX_SHARE_ACCESS_WRITE|
2247 : NTCREATEX_SHARE_ACCESS_DELETE;
2248 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
2249 3 : status = smb2_create(tree2, tctx, &(io.smb2));
2250 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2251 3 : h2 = io.smb2.out.file.handle;
2252 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2253 :
2254 3 : torture_wait_for_oplock_break(tctx);
2255 3 : CHECK_VAL(break_info.count, 1);
2256 3 : CHECK_VAL(break_info.failures, 0);
2257 :
2258 3 : smb2_util_close(tree1, h1);
2259 3 : smb2_util_close(tree2, h2);
2260 3 : smb2_util_close(tree1, h);
2261 :
2262 3 : smb2_deltree(tree1, BASEDIR);
2263 3 : return ret;
2264 : }
2265 :
2266 : /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH17 test. Since
2267 : * SMB2 doesn't have a RENAME command this test isn't applicable. However,
2268 : * it's much less confusing, when comparing test, to keep the SMB1 and SMB2
2269 : * test numbers in sync. */
2270 : #if 0
2271 : static bool test_raw_oplock_batch17(struct torture_context *tctx,
2272 : struct smb2_tree *tree1,
2273 : struct smb2_tree *tree2)
2274 : {
2275 : return true;
2276 : }
2277 : #endif
2278 :
2279 : /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH18 test. Since
2280 : * SMB2 doesn't have an NTRENAME command this test isn't applicable. However,
2281 : * it's much less confusing, when comparing tests, to keep the SMB1 and SMB2
2282 : * test numbers in sync. */
2283 : #if 0
2284 : static bool test_raw_oplock_batch18(struct torture_context *tctx,
2285 : struct smb2_tree *tree1,
2286 : struct smb2_tree *tree2)
2287 : {
2288 : return true;
2289 : }
2290 : #endif
2291 :
2292 3 : static bool test_smb2_oplock_batch19(struct torture_context *tctx,
2293 : struct smb2_tree *tree1)
2294 : {
2295 3 : const char *fname1 = BASEDIR "\\test_batch19_1.dat";
2296 3 : const char *fname2 = BASEDIR "\\test_batch19_2.dat";
2297 0 : NTSTATUS status;
2298 3 : bool ret = true;
2299 0 : union smb_open io;
2300 0 : union smb_fileinfo qfi;
2301 0 : union smb_setfileinfo sfi;
2302 0 : struct smb2_handle h, h1;
2303 :
2304 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2305 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2306 :
2307 : /* cleanup */
2308 3 : smb2_util_unlink(tree1, fname1);
2309 3 : smb2_util_unlink(tree1, fname2);
2310 :
2311 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2312 3 : tree1->session->transport->oplock.private_data = tree1;
2313 :
2314 : /*
2315 : base ntcreatex parms
2316 : */
2317 3 : ZERO_STRUCT(io.smb2);
2318 3 : io.generic.level = RAW_OPEN_SMB2;
2319 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2320 3 : io.smb2.in.alloc_size = 0;
2321 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2322 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2323 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2324 3 : io.smb2.in.create_options = 0;
2325 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2326 3 : io.smb2.in.security_flags = 0;
2327 3 : io.smb2.in.fname = fname1;
2328 :
2329 3 : torture_comment(tctx, "BATCH19: open a file with an batch oplock "
2330 : "(share mode: none)\n");
2331 3 : ZERO_STRUCT(break_info);
2332 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2333 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2334 3 : status = smb2_create(tree1, tctx, &(io.smb2));
2335 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2336 3 : h1 = io.smb2.out.file.handle;
2337 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2338 :
2339 3 : torture_comment(tctx, "setfileinfo rename info should not trigger "
2340 : "a break but should cause a sharing violation\n");
2341 3 : ZERO_STRUCT(sfi);
2342 3 : sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2343 3 : sfi.generic.in.file.path = fname1;
2344 3 : sfi.rename_information.in.file.handle = h1;
2345 3 : sfi.rename_information.in.overwrite = 0;
2346 3 : sfi.rename_information.in.root_fid = 0;
2347 3 : sfi.rename_information.in.new_name = fname2;
2348 :
2349 3 : status = smb2_setinfo_file(tree1, &sfi);
2350 :
2351 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2352 : "Incorrect status");
2353 :
2354 2 : torture_wait_for_oplock_break(tctx);
2355 2 : CHECK_VAL(break_info.count, 0);
2356 :
2357 2 : ZERO_STRUCT(qfi);
2358 2 : qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2359 2 : qfi.generic.in.file.handle = h1;
2360 :
2361 2 : status = smb2_getinfo_file(tree1, tctx, &qfi);
2362 2 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2363 2 : CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2364 :
2365 2 : smb2_util_close(tree1, h1);
2366 2 : smb2_util_close(tree1, h);
2367 :
2368 2 : smb2_deltree(tree1, fname1);
2369 2 : smb2_deltree(tree1, fname2);
2370 2 : return ret;
2371 : }
2372 :
2373 3 : static bool test_smb2_oplock_batch20(struct torture_context *tctx,
2374 : struct smb2_tree *tree1,
2375 : struct smb2_tree *tree2)
2376 : {
2377 3 : const char *fname1 = BASEDIR "\\test_batch20_1.dat";
2378 3 : const char *fname2 = BASEDIR "\\test_batch20_2.dat";
2379 0 : NTSTATUS status;
2380 3 : bool ret = true;
2381 0 : union smb_open io;
2382 0 : union smb_fileinfo qfi;
2383 0 : union smb_setfileinfo sfi;
2384 0 : struct smb2_handle h, h1, h2;
2385 :
2386 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2387 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2388 :
2389 : /* cleanup */
2390 3 : smb2_util_unlink(tree1, fname1);
2391 3 : smb2_util_unlink(tree1, fname2);
2392 :
2393 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2394 3 : tree1->session->transport->oplock.private_data = tree1;
2395 :
2396 : /*
2397 : base ntcreatex parms
2398 : */
2399 3 : ZERO_STRUCT(io.smb2);
2400 3 : io.generic.level = RAW_OPEN_SMB2;
2401 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2402 3 : io.smb2.in.alloc_size = 0;
2403 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2404 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2405 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2406 3 : io.smb2.in.create_options = 0;
2407 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2408 3 : io.smb2.in.security_flags = 0;
2409 3 : io.smb2.in.fname = fname1;
2410 :
2411 3 : torture_comment(tctx, "BATCH20: open a file with an batch oplock "
2412 : "(share mode: all)\n");
2413 3 : ZERO_STRUCT(break_info);
2414 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2415 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2416 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2417 : NTCREATEX_SHARE_ACCESS_WRITE|
2418 : NTCREATEX_SHARE_ACCESS_DELETE;
2419 3 : status = smb2_create(tree1, tctx, &(io.smb2));
2420 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2421 3 : h1 = io.smb2.out.file.handle;
2422 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2423 :
2424 3 : torture_comment(tctx, "setfileinfo rename info should not trigger "
2425 : "a break but should cause a sharing violation\n");
2426 3 : ZERO_STRUCT(sfi);
2427 3 : sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2428 3 : sfi.rename_information.in.file.handle = h1;
2429 3 : sfi.rename_information.in.overwrite = 0;
2430 3 : sfi.rename_information.in.new_name = fname2;
2431 :
2432 3 : status = smb2_setinfo_file(tree1, &sfi);
2433 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2434 : "Incorrect status");
2435 :
2436 2 : torture_wait_for_oplock_break(tctx);
2437 2 : CHECK_VAL(break_info.count, 0);
2438 :
2439 2 : ZERO_STRUCT(qfi);
2440 2 : qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2441 2 : qfi.generic.in.file.handle = h1;
2442 :
2443 2 : status = smb2_getinfo_file(tree1, tctx, &qfi);
2444 2 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2445 2 : CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2446 :
2447 2 : torture_comment(tctx, "open the file a second time requesting batch "
2448 : "(share mode: all)\n");
2449 2 : ZERO_STRUCT(break_info);
2450 2 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2451 2 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2452 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2453 : NTCREATEX_SHARE_ACCESS_WRITE|
2454 : NTCREATEX_SHARE_ACCESS_DELETE;
2455 2 : io.smb2.in.fname = fname1;
2456 2 : status = smb2_create(tree2, tctx, &(io.smb2));
2457 2 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2458 2 : h2 = io.smb2.out.file.handle;
2459 2 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2460 :
2461 2 : torture_wait_for_oplock_break(tctx);
2462 2 : CHECK_VAL(break_info.count, 1);
2463 2 : CHECK_VAL(break_info.failures, 0);
2464 2 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2465 :
2466 2 : torture_comment(tctx, "setfileinfo rename info should not trigger "
2467 : "a break but should cause a sharing violation\n");
2468 2 : ZERO_STRUCT(break_info);
2469 2 : ZERO_STRUCT(sfi);
2470 2 : sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2471 2 : sfi.rename_information.in.file.handle = h2;
2472 2 : sfi.rename_information.in.overwrite = 0;
2473 2 : sfi.rename_information.in.new_name = fname2;
2474 :
2475 2 : status = smb2_setinfo_file(tree2, &sfi);
2476 2 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2477 : "Incorrect status");
2478 :
2479 0 : torture_wait_for_oplock_break(tctx);
2480 0 : CHECK_VAL(break_info.count, 0);
2481 :
2482 0 : ZERO_STRUCT(qfi);
2483 0 : qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2484 0 : qfi.generic.in.file.handle = h1;
2485 :
2486 0 : status = smb2_getinfo_file(tree1, tctx, &qfi);
2487 0 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2488 0 : CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2489 :
2490 0 : ZERO_STRUCT(qfi);
2491 0 : qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2492 0 : qfi.generic.in.file.handle = h2;
2493 :
2494 0 : status = smb2_getinfo_file(tree2, tctx, &qfi);
2495 0 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2496 0 : CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2497 :
2498 0 : smb2_util_close(tree1, h1);
2499 0 : smb2_util_close(tree2, h2);
2500 0 : smb2_util_close(tree1, h);
2501 :
2502 0 : smb2_deltree(tree1, fname1);
2503 0 : return ret;
2504 : }
2505 :
2506 3 : static bool test_smb2_oplock_batch21(struct torture_context *tctx,
2507 : struct smb2_tree *tree1)
2508 : {
2509 3 : const char *fname = BASEDIR "\\test_batch21.dat";
2510 0 : NTSTATUS status;
2511 3 : bool ret = true;
2512 0 : union smb_open io;
2513 0 : struct smb2_handle h, h1;
2514 3 : char c = 0;
2515 :
2516 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2517 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2518 :
2519 : /* cleanup */
2520 3 : smb2_util_unlink(tree1, fname);
2521 :
2522 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2523 3 : tree1->session->transport->oplock.private_data = tree1;
2524 :
2525 : /*
2526 : base ntcreatex parms
2527 : */
2528 3 : ZERO_STRUCT(io.smb2);
2529 3 : io.generic.level = RAW_OPEN_SMB2;
2530 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2531 3 : io.smb2.in.alloc_size = 0;
2532 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2533 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2534 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2535 3 : io.smb2.in.create_options = 0;
2536 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2537 3 : io.smb2.in.security_flags = 0;
2538 3 : io.smb2.in.fname = fname;
2539 :
2540 : /*
2541 : with a batch oplock we get a break
2542 : */
2543 3 : torture_comment(tctx, "BATCH21: open with batch oplock\n");
2544 3 : ZERO_STRUCT(break_info);
2545 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2546 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2547 3 : status = smb2_create(tree1, tctx, &(io.smb2));
2548 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2549 3 : h1 = io.smb2.out.file.handle;
2550 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2551 :
2552 3 : torture_comment(tctx, "writing should not generate a break\n");
2553 3 : status = smb2_util_write(tree1, h1, &c, 0, 1);
2554 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2555 :
2556 3 : torture_wait_for_oplock_break(tctx);
2557 3 : CHECK_VAL(break_info.count, 0);
2558 :
2559 3 : smb2_util_close(tree1, h1);
2560 3 : smb2_util_close(tree1, h);
2561 :
2562 3 : smb2_deltree(tree1, BASEDIR);
2563 3 : return ret;
2564 : }
2565 :
2566 3 : static bool test_smb2_oplock_batch22a(struct torture_context *tctx,
2567 : struct smb2_tree *tree1)
2568 : {
2569 3 : const char *fname = BASEDIR "\\test_batch22a.dat";
2570 0 : NTSTATUS status;
2571 3 : bool ret = true;
2572 0 : union smb_open io;
2573 0 : struct smb2_handle h, h1, h2;
2574 0 : struct timeval tv;
2575 3 : int timeout = torture_setting_int(tctx, "oplocktimeout", 35);
2576 0 : int te;
2577 :
2578 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2579 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2580 :
2581 : /* cleanup */
2582 3 : smb2_util_unlink(tree1, fname);
2583 :
2584 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2585 3 : tree1->session->transport->oplock.private_data = tree1;
2586 : /*
2587 : base ntcreatex parms
2588 : */
2589 3 : ZERO_STRUCT(io.smb2);
2590 3 : io.generic.level = RAW_OPEN_SMB2;
2591 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2592 3 : io.smb2.in.alloc_size = 0;
2593 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2594 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2595 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2596 3 : io.smb2.in.create_options = 0;
2597 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2598 3 : io.smb2.in.security_flags = 0;
2599 3 : io.smb2.in.fname = fname;
2600 :
2601 : /*
2602 : with a batch oplock we get a break
2603 : */
2604 3 : torture_comment(tctx, "BATCH22: open with batch oplock\n");
2605 3 : ZERO_STRUCT(break_info);
2606 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2607 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2608 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2609 : NTCREATEX_SHARE_ACCESS_WRITE|
2610 : NTCREATEX_SHARE_ACCESS_DELETE;
2611 3 : status = smb2_create(tree1, tctx, &(io.smb2));
2612 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2613 3 : h1 = io.smb2.out.file.handle;
2614 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2615 :
2616 3 : torture_comment(tctx, "a 2nd open should succeed after the oplock "
2617 : "break timeout\n");
2618 3 : tv = timeval_current();
2619 3 : tree1->session->transport->oplock.handler =
2620 : torture_oplock_handler_timeout;
2621 3 : status = smb2_create(tree1, tctx, &(io.smb2));
2622 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2623 2 : h2 = io.smb2.out.file.handle;
2624 2 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2625 :
2626 2 : torture_wait_for_oplock_break(tctx);
2627 2 : te = (int)timeval_elapsed(&tv);
2628 2 : CHECK_RANGE(te, timeout - 1, timeout + 15);
2629 2 : torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
2630 :
2631 2 : CHECK_VAL(break_info.count, 1);
2632 2 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2633 2 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2634 2 : CHECK_VAL(break_info.failures, 0);
2635 :
2636 2 : smb2_util_close(tree1, h1);
2637 2 : smb2_util_close(tree1, h2);
2638 2 : smb2_util_close(tree1, h);
2639 :
2640 2 : smb2_deltree(tree1, BASEDIR);
2641 2 : return ret;
2642 : }
2643 :
2644 3 : static bool test_smb2_oplock_batch22b(struct torture_context *tctx,
2645 : struct smb2_tree *tree1,
2646 : struct smb2_tree *tree2)
2647 : {
2648 3 : const char *fname = BASEDIR "\\test_batch22b.dat";
2649 0 : NTSTATUS status;
2650 3 : bool ret = true;
2651 0 : union smb_open io;
2652 3 : struct smb2_handle h, h1, h2 = {{0}};
2653 0 : struct timeval tv;
2654 3 : int timeout = torture_setting_int(tctx, "oplocktimeout", 35);
2655 3 : struct smb2_transport *transport1 = tree1->session->transport;
2656 3 : bool block_setup = false;
2657 3 : bool block_ok = false;
2658 0 : int te;
2659 :
2660 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2661 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2662 :
2663 : /* cleanup */
2664 3 : smb2_util_unlink(tree1, fname);
2665 :
2666 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2667 3 : tree1->session->transport->oplock.private_data = tree1;
2668 : /*
2669 : base ntcreatex parms
2670 : */
2671 3 : ZERO_STRUCT(io.smb2);
2672 3 : io.generic.level = RAW_OPEN_SMB2;
2673 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2674 3 : io.smb2.in.alloc_size = 0;
2675 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2676 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2677 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2678 3 : io.smb2.in.create_options = 0;
2679 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2680 3 : io.smb2.in.security_flags = 0;
2681 3 : io.smb2.in.fname = fname;
2682 :
2683 : /*
2684 : with a batch oplock we get a break
2685 : */
2686 3 : torture_comment(tctx, "BATCH22: open with batch oplock\n");
2687 3 : ZERO_STRUCT(break_info);
2688 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2689 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2690 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2691 : NTCREATEX_SHARE_ACCESS_WRITE|
2692 : NTCREATEX_SHARE_ACCESS_DELETE;
2693 3 : status = smb2_create(tree1, tctx, &(io.smb2));
2694 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2695 3 : h1 = io.smb2.out.file.handle;
2696 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2697 :
2698 3 : torture_comment(tctx, "a 2nd open should succeed after the oplock "
2699 : "break timeout\n");
2700 3 : tv = timeval_current();
2701 3 : tree1->session->transport->oplock.handler =
2702 : torture_oplock_handler_timeout;
2703 3 : block_setup = test_setup_blocked_transports(tctx);
2704 3 : torture_assert(tctx, block_setup, "test_setup_blocked_transports");
2705 3 : block_ok = test_block_smb2_transport(tctx, transport1);
2706 3 : torture_assert(tctx, block_ok, "test_block_smb2_transport");
2707 :
2708 2 : status = smb2_create(tree2, tctx, &(io.smb2));
2709 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Incorrect status");
2710 2 : h2 = io.smb2.out.file.handle;
2711 2 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2712 :
2713 2 : torture_wait_for_oplock_break(tctx);
2714 2 : te = (int)timeval_elapsed(&tv);
2715 2 : CHECK_RANGE(te, 0, timeout);
2716 2 : torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
2717 :
2718 2 : CHECK_VAL(break_info.count, 1);
2719 2 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2720 2 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2721 2 : CHECK_VAL(break_info.failures, 0);
2722 :
2723 2 : done:
2724 2 : if (block_ok) {
2725 2 : test_unblock_smb2_transport(tctx, transport1);
2726 : }
2727 2 : test_cleanup_blocked_transports(tctx);
2728 :
2729 2 : smb2_util_close(tree1, h1);
2730 2 : if (!smb2_util_handle_empty(h2)) {
2731 2 : smb2_util_close(tree1, h2);
2732 : }
2733 2 : smb2_util_close(tree1, h);
2734 :
2735 2 : smb2_deltree(tree1, BASEDIR);
2736 2 : return ret;
2737 : }
2738 :
2739 3 : static bool test_smb2_oplock_batch23(struct torture_context *tctx,
2740 : struct smb2_tree *tree1,
2741 : struct smb2_tree *tree2)
2742 : {
2743 3 : const char *fname = BASEDIR "\\test_batch23.dat";
2744 0 : NTSTATUS status;
2745 3 : bool ret = true;
2746 0 : union smb_open io;
2747 0 : struct smb2_handle h, h1, h2, h3;
2748 3 : struct smb2_tree *tree3 = NULL;
2749 :
2750 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2751 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2752 :
2753 : /* cleanup */
2754 3 : smb2_util_unlink(tree1, fname);
2755 :
2756 3 : ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2757 3 : CHECK_VAL(ret, true);
2758 :
2759 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2760 3 : tree1->session->transport->oplock.private_data = tree1;
2761 :
2762 3 : tree2->session->transport->oplock.handler = torture_oplock_handler;
2763 3 : tree2->session->transport->oplock.private_data = tree2;
2764 :
2765 3 : tree3->session->transport->oplock.handler = torture_oplock_handler;
2766 3 : tree3->session->transport->oplock.private_data = tree3;
2767 :
2768 : /*
2769 : base ntcreatex parms
2770 : */
2771 3 : ZERO_STRUCT(io.smb2);
2772 3 : io.generic.level = RAW_OPEN_SMB2;
2773 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2774 3 : io.smb2.in.alloc_size = 0;
2775 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2776 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2777 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2778 3 : io.smb2.in.create_options = 0;
2779 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2780 3 : io.smb2.in.security_flags = 0;
2781 3 : io.smb2.in.fname = fname;
2782 :
2783 3 : torture_comment(tctx, "BATCH23: an open and ask for a batch oplock\n");
2784 3 : ZERO_STRUCT(break_info);
2785 :
2786 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2787 : SEC_RIGHTS_FILE_WRITE;
2788 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2789 : NTCREATEX_SHARE_ACCESS_WRITE;
2790 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2791 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2792 3 : status = smb2_create(tree1, tctx, &(io.smb2));
2793 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2794 3 : h1 = io.smb2.out.file.handle;
2795 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2796 :
2797 3 : ZERO_STRUCT(break_info);
2798 :
2799 3 : torture_comment(tctx, "a 2nd open without level2 oplock support "
2800 : "should generate a break to level2\n");
2801 3 : status = smb2_create(tree3, tctx, &(io.smb2));
2802 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2803 3 : h3 = io.smb2.out.file.handle;
2804 :
2805 3 : torture_wait_for_oplock_break(tctx);
2806 3 : CHECK_VAL(break_info.count, 1);
2807 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2808 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2809 3 : CHECK_VAL(break_info.failures, 0);
2810 :
2811 3 : ZERO_STRUCT(break_info);
2812 :
2813 3 : torture_comment(tctx, "a 3rd open with level2 oplock support should "
2814 : "not generate a break\n");
2815 3 : status = smb2_create(tree2, tctx, &(io.smb2));
2816 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2817 3 : h2 = io.smb2.out.file.handle;
2818 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2819 :
2820 3 : torture_wait_for_oplock_break(tctx);
2821 3 : CHECK_VAL(break_info.count, 0);
2822 :
2823 3 : smb2_util_close(tree1, h1);
2824 3 : smb2_util_close(tree2, h2);
2825 3 : smb2_util_close(tree3, h3);
2826 3 : smb2_util_close(tree1, h);
2827 :
2828 3 : smb2_deltree(tree1, BASEDIR);
2829 3 : return ret;
2830 : }
2831 :
2832 3 : static bool test_smb2_oplock_batch24(struct torture_context *tctx,
2833 : struct smb2_tree *tree1,
2834 : struct smb2_tree *tree2)
2835 : {
2836 3 : const char *fname = BASEDIR "\\test_batch24.dat";
2837 0 : NTSTATUS status;
2838 3 : bool ret = true;
2839 0 : union smb_open io;
2840 0 : struct smb2_handle h, h1, h2;
2841 3 : struct smb2_tree *tree3 = NULL;
2842 :
2843 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2844 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2845 :
2846 : /* cleanup */
2847 3 : smb2_util_unlink(tree1, fname);
2848 :
2849 3 : ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2850 3 : CHECK_VAL(ret, true);
2851 :
2852 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2853 3 : tree1->session->transport->oplock.private_data = tree1;
2854 :
2855 3 : tree2->session->transport->oplock.handler = torture_oplock_handler;
2856 3 : tree2->session->transport->oplock.private_data = tree2;
2857 :
2858 3 : tree3->session->transport->oplock.handler = torture_oplock_handler;
2859 3 : tree3->session->transport->oplock.private_data = tree3;
2860 :
2861 : /*
2862 : base ntcreatex parms
2863 : */
2864 3 : ZERO_STRUCT(io.smb2);
2865 3 : io.generic.level = RAW_OPEN_SMB2;
2866 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2867 3 : io.smb2.in.alloc_size = 0;
2868 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2869 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2870 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2871 3 : io.smb2.in.create_options = 0;
2872 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2873 3 : io.smb2.in.security_flags = 0;
2874 3 : io.smb2.in.fname = fname;
2875 :
2876 3 : torture_comment(tctx, "BATCH24: a open without level support and "
2877 : "ask for a batch oplock\n");
2878 3 : ZERO_STRUCT(break_info);
2879 :
2880 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2881 : SEC_RIGHTS_FILE_WRITE;
2882 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2883 : NTCREATEX_SHARE_ACCESS_WRITE;
2884 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2885 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2886 :
2887 3 : status = smb2_create(tree3, tctx, &(io.smb2));
2888 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2889 3 : h2 = io.smb2.out.file.handle;
2890 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2891 :
2892 3 : ZERO_STRUCT(break_info);
2893 :
2894 3 : torture_comment(tctx, "a 2nd open with level2 oplock support should "
2895 : "generate a break\n");
2896 3 : status = smb2_create(tree2, tctx, &(io.smb2));
2897 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2898 3 : h1 = io.smb2.out.file.handle;
2899 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2900 :
2901 3 : torture_wait_for_oplock_break(tctx);
2902 3 : CHECK_VAL(break_info.count, 1);
2903 3 : CHECK_VAL(break_info.handle.data[0], h2.data[0]);
2904 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2905 3 : CHECK_VAL(break_info.failures, 0);
2906 :
2907 3 : smb2_util_close(tree3, h2);
2908 3 : smb2_util_close(tree2, h1);
2909 3 : smb2_util_close(tree1, h);
2910 :
2911 3 : smb2_deltree(tree1, BASEDIR);
2912 3 : return ret;
2913 : }
2914 :
2915 3 : static bool test_smb2_oplock_batch25(struct torture_context *tctx,
2916 : struct smb2_tree *tree1)
2917 : {
2918 3 : const char *fname = BASEDIR "\\test_batch25.dat";
2919 0 : NTSTATUS status;
2920 3 : bool ret = true;
2921 0 : union smb_open io;
2922 0 : struct smb2_handle h, h1;
2923 :
2924 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2925 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2926 :
2927 : /* cleanup */
2928 3 : smb2_util_unlink(tree1, fname);
2929 :
2930 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2931 3 : tree1->session->transport->oplock.private_data = tree1;
2932 :
2933 : /*
2934 : base ntcreatex parms
2935 : */
2936 3 : ZERO_STRUCT(io.smb2);
2937 3 : io.generic.level = RAW_OPEN_SMB2;
2938 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2939 3 : io.smb2.in.alloc_size = 0;
2940 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2941 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2942 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2943 3 : io.smb2.in.create_options = 0;
2944 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2945 3 : io.smb2.in.security_flags = 0;
2946 3 : io.smb2.in.fname = fname;
2947 :
2948 3 : torture_comment(tctx, "BATCH25: open a file with an batch oplock "
2949 : "(share mode: none)\n");
2950 :
2951 3 : ZERO_STRUCT(break_info);
2952 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2953 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2954 :
2955 3 : status = smb2_create(tree1, tctx, &(io.smb2));
2956 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2957 3 : h1 = io.smb2.out.file.handle;
2958 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2959 :
2960 3 : status = smb2_util_setatr(tree1, fname, FILE_ATTRIBUTE_HIDDEN);
2961 3 : torture_assert_ntstatus_ok(tctx, status, "Setting attributes "
2962 : "shouldn't trigger an oplock break");
2963 :
2964 3 : smb2_util_close(tree1, h1);
2965 3 : smb2_util_close(tree1, h);
2966 :
2967 3 : smb2_deltree(tree1, fname);
2968 3 : return ret;
2969 : }
2970 :
2971 3 : static bool test_smb2_oplock_batch26(struct torture_context *tctx,
2972 : struct smb2_tree *tree1)
2973 : {
2974 :
2975 0 : NTSTATUS status;
2976 3 : bool ret = true;
2977 0 : union smb_open io;
2978 0 : struct smb2_handle h, h1, h2, h3;
2979 3 : const char *fname_base = BASEDIR "\\test_oplock.txt";
2980 3 : const char *stream = "Stream One:$DATA";
2981 0 : const char *fname_stream;
2982 :
2983 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2984 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2985 :
2986 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2987 3 : tree1->session->transport->oplock.private_data = tree1;
2988 :
2989 3 : fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
2990 :
2991 : /*
2992 : base ntcreatex parms
2993 : */
2994 3 : ZERO_STRUCT(io.smb2);
2995 3 : io.generic.level = RAW_OPEN_SMB2;
2996 3 : io.smb2.in.desired_access = 0x120089;
2997 3 : io.smb2.in.alloc_size = 0;
2998 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2999 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE |
3000 : NTCREATEX_SHARE_ACCESS_WRITE;
3001 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3002 3 : io.smb2.in.create_options = 0;
3003 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3004 3 : io.smb2.in.security_flags = 0;
3005 3 : io.smb2.in.fname = fname_base;
3006 :
3007 : /*
3008 : Open base file with a batch oplock.
3009 : */
3010 3 : torture_comment(tctx, "Open the base file with batch oplock\n");
3011 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3012 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3013 :
3014 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3015 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening base file");
3016 3 : h1 = io.smb2.out.file.handle;
3017 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3018 :
3019 3 : torture_comment(tctx, "Got batch oplock on base file\n");
3020 :
3021 3 : torture_comment(tctx, "Opening stream file with batch oplock..\n");
3022 :
3023 3 : io.smb2.in.fname = fname_stream;
3024 :
3025 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3026 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening stream file");
3027 3 : h2 = io.smb2.out.file.handle;
3028 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3029 :
3030 3 : torture_comment(tctx, "Got batch oplock on stream file\n");
3031 :
3032 3 : torture_comment(tctx, "Open base file again with batch oplock\n");
3033 :
3034 3 : io.smb2.in.fname = fname_base;
3035 :
3036 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3037 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3038 3 : h3 = io.smb2.out.file.handle;
3039 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3040 :
3041 3 : smb2_util_close(tree1, h1);
3042 3 : smb2_util_close(tree1, h2);
3043 3 : smb2_util_close(tree1, h3);
3044 3 : smb2_util_close(tree1, h);
3045 3 : smb2_deltree(tree1, BASEDIR);
3046 3 : return ret;
3047 :
3048 : }
3049 :
3050 : /* Test how oplocks work on streams. */
3051 3 : static bool test_raw_oplock_stream1(struct torture_context *tctx,
3052 : struct smb2_tree *tree1,
3053 : struct smb2_tree *tree2)
3054 : {
3055 0 : NTSTATUS status;
3056 0 : union smb_open io;
3057 3 : const char *fname_base = BASEDIR "\\test_stream1.txt";
3058 0 : const char *fname_stream, *fname_default_stream;
3059 3 : const char *default_stream = "::$DATA";
3060 3 : const char *stream = "Stream One:$DATA";
3061 3 : bool ret = true;
3062 0 : struct smb2_handle h, h_base, h_stream;
3063 0 : int i;
3064 :
3065 : #define NSTREAM_OPLOCK_RESULTS 8
3066 0 : struct {
3067 : const char **fname;
3068 : bool open_base_file;
3069 : uint32_t oplock_req;
3070 : uint32_t oplock_granted;
3071 3 : } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
3072 : /* Request oplock on stream without the base file open. */
3073 : {&fname_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3074 : {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3075 : {&fname_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3076 : {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3077 :
3078 : /* Request oplock on stream with the base file open. */
3079 : {&fname_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3080 : {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_II},
3081 : {&fname_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3082 : {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_II},
3083 : };
3084 :
3085 3 : fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
3086 3 : fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
3087 : default_stream);
3088 :
3089 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
3090 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3091 :
3092 : /* Initialize handles to "closed". Using -1 in the first 64-bytes
3093 : * as the sentry for this */
3094 3 : h_stream.data[0] = -1;
3095 :
3096 : /* cleanup */
3097 3 : smb2_util_unlink(tree1, fname_base);
3098 :
3099 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
3100 3 : tree1->session->transport->oplock.private_data = tree1;
3101 :
3102 3 : tree2->session->transport->oplock.handler = torture_oplock_handler;
3103 3 : tree2->session->transport->oplock.private_data = tree2;
3104 :
3105 : /* Setup generic open parameters. */
3106 3 : ZERO_STRUCT(io.smb2);
3107 3 : io.generic.level = RAW_OPEN_SMB2;
3108 3 : io.smb2.in.desired_access = (SEC_FILE_READ_DATA |
3109 : SEC_FILE_WRITE_DATA |
3110 : SEC_FILE_APPEND_DATA |
3111 : SEC_STD_READ_CONTROL);
3112 3 : io.smb2.in.alloc_size = 0;
3113 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3114 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3115 : NTCREATEX_SHARE_ACCESS_WRITE;
3116 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3117 3 : io.smb2.in.create_options = 0;
3118 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3119 3 : io.smb2.in.security_flags = 0;
3120 :
3121 : /* Create the file with a stream */
3122 3 : io.smb2.in.fname = fname_stream;
3123 3 : io.smb2.in.create_flags = 0;
3124 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
3125 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3126 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating file");
3127 3 : smb2_util_close(tree1, io.smb2.out.file.handle);
3128 :
3129 : /* Change the disposition to open now that the file has been created. */
3130 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
3131 :
3132 : /* Try some permutations of taking oplocks on streams. */
3133 27 : for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
3134 24 : const char *fname = *stream_oplock_results[i].fname;
3135 24 : bool open_base_file = stream_oplock_results[i].open_base_file;
3136 24 : uint32_t oplock_req = stream_oplock_results[i].oplock_req;
3137 24 : uint32_t oplock_granted =
3138 : stream_oplock_results[i].oplock_granted;
3139 :
3140 24 : if (open_base_file) {
3141 12 : torture_comment(tctx, "Opening base file: %s with "
3142 : "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3143 12 : io.smb2.in.fname = fname_base;
3144 12 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3145 12 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3146 12 : status = smb2_create(tree2, tctx, &(io.smb2));
3147 12 : torture_assert_ntstatus_ok(tctx, status,
3148 : "Error opening file");
3149 12 : CHECK_VAL(io.smb2.out.oplock_level,
3150 : SMB2_OPLOCK_LEVEL_BATCH);
3151 12 : h_base = io.smb2.out.file.handle;
3152 : }
3153 :
3154 24 : torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
3155 : fname, oplock_req);
3156 24 : io.smb2.in.fname = fname;
3157 24 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3158 24 : io.smb2.in.oplock_level = oplock_req;
3159 :
3160 : /* Do the open with the desired oplock on the stream. */
3161 24 : status = smb2_create(tree1, tctx, &(io.smb2));
3162 24 : torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3163 24 : CHECK_VAL(io.smb2.out.oplock_level, oplock_granted);
3164 24 : smb2_util_close(tree1, io.smb2.out.file.handle);
3165 :
3166 : /* Cleanup the base file if it was opened. */
3167 24 : if (open_base_file)
3168 12 : smb2_util_close(tree2, h_base);
3169 : }
3170 :
3171 : /* Open the stream with an exclusive oplock. */
3172 3 : torture_comment(tctx, "Opening stream: %s with %d\n",
3173 : fname_stream, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3174 3 : io.smb2.in.fname = fname_stream;
3175 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3176 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3177 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3178 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3179 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3180 3 : h_stream = io.smb2.out.file.handle;
3181 :
3182 : /* Open the base file and see if it contends. */
3183 3 : ZERO_STRUCT(break_info);
3184 3 : torture_comment(tctx, "Opening base file: %s with %d\n",
3185 : fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3186 3 : io.smb2.in.fname = fname_base;
3187 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3188 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3189 3 : status = smb2_create(tree2, tctx, &(io.smb2));
3190 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3191 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3192 3 : smb2_util_close(tree2, io.smb2.out.file.handle);
3193 :
3194 3 : torture_wait_for_oplock_break(tctx);
3195 3 : CHECK_VAL(break_info.count, 0);
3196 3 : CHECK_VAL(break_info.failures, 0);
3197 :
3198 : /* Open the stream again to see if it contends. */
3199 3 : ZERO_STRUCT(break_info);
3200 3 : torture_comment(tctx, "Opening stream again: %s with "
3201 : "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3202 3 : io.smb2.in.fname = fname_stream;
3203 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3204 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3205 3 : status = smb2_create(tree2, tctx, &(io.smb2));
3206 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3207 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3208 3 : smb2_util_close(tree2, io.smb2.out.file.handle);
3209 :
3210 3 : torture_wait_for_oplock_break(tctx);
3211 3 : CHECK_VAL(break_info.count, 1);
3212 3 : CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
3213 3 : CHECK_VAL(break_info.failures, 0);
3214 :
3215 : /* Close the stream. */
3216 3 : if (h_stream.data[0] != -1) {
3217 3 : smb2_util_close(tree1, h_stream);
3218 : }
3219 :
3220 3 : smb2_util_close(tree1, h);
3221 :
3222 3 : smb2_deltree(tree1, BASEDIR);
3223 3 : return ret;
3224 : }
3225 :
3226 3 : static bool test_smb2_oplock_doc(struct torture_context *tctx, struct smb2_tree *tree,
3227 : struct smb2_tree *tree2)
3228 : {
3229 3 : const char *fname = BASEDIR "\\test_oplock_doc.dat";
3230 0 : NTSTATUS status;
3231 3 : bool ret = true;
3232 0 : union smb_open io;
3233 0 : struct smb2_handle h, h1;
3234 0 : union smb_setfileinfo sfinfo;
3235 :
3236 3 : status = torture_smb2_testdir(tree, BASEDIR, &h);
3237 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3238 3 : smb2_util_close(tree, h);
3239 :
3240 : /* cleanup */
3241 3 : smb2_util_unlink(tree, fname);
3242 3 : tree->session->transport->oplock.handler = torture_oplock_handler;
3243 3 : tree->session->transport->oplock.private_data = tree;
3244 :
3245 : /*
3246 : base ntcreatex parms
3247 : */
3248 3 : ZERO_STRUCT(io.smb2);
3249 3 : io.generic.level = RAW_OPEN_SMB2;
3250 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3251 3 : io.smb2.in.alloc_size = 0;
3252 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3253 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
3254 : NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
3255 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3256 3 : io.smb2.in.create_options = 0;
3257 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3258 3 : io.smb2.in.security_flags = 0;
3259 3 : io.smb2.in.fname = fname;
3260 :
3261 3 : torture_comment(tctx, "open a file with a batch oplock\n");
3262 3 : ZERO_STRUCT(break_info);
3263 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3264 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3265 :
3266 3 : status = smb2_create(tree, tctx, &(io.smb2));
3267 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3268 3 : h1 = io.smb2.out.file.handle;
3269 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3270 :
3271 3 : torture_comment(tctx, "Set delete on close\n");
3272 3 : ZERO_STRUCT(sfinfo);
3273 3 : sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
3274 3 : sfinfo.generic.in.file.handle = h1;
3275 3 : sfinfo.disposition_info.in.delete_on_close = 1;
3276 3 : status = smb2_setinfo_file(tree, &sfinfo);
3277 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3278 :
3279 3 : torture_comment(tctx, "2nd open should not break and get "
3280 : "DELETE_PENDING\n");
3281 3 : ZERO_STRUCT(break_info);
3282 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
3283 3 : io.smb2.in.create_options = 0;
3284 3 : io.smb2.in.desired_access = SEC_FILE_READ_DATA;
3285 3 : status = smb2_create(tree2, tctx, &io.smb2);
3286 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DELETE_PENDING,
3287 : "Incorrect status");
3288 3 : CHECK_VAL(break_info.count, 0);
3289 :
3290 3 : smb2_util_close(tree, h1);
3291 :
3292 3 : smb2_util_unlink(tree, fname);
3293 3 : smb2_deltree(tree, BASEDIR);
3294 3 : return ret;
3295 : }
3296 :
3297 : /* Open a file with a batch oplock, then open it again from a second client
3298 : * requesting no oplock. Having two open file handles should break our own
3299 : * oplock during BRL acquisition.
3300 : */
3301 3 : static bool test_smb2_oplock_brl1(struct torture_context *tctx,
3302 : struct smb2_tree *tree1,
3303 : struct smb2_tree *tree2)
3304 : {
3305 3 : const char *fname = BASEDIR "\\test_batch_brl.dat";
3306 : /*int fname, f;*/
3307 3 : bool ret = true;
3308 0 : uint8_t buf[1000];
3309 0 : union smb_open io;
3310 0 : NTSTATUS status;
3311 0 : struct smb2_lock lck;
3312 0 : struct smb2_lock_element lock[1];
3313 0 : struct smb2_handle h, h1, h2;
3314 :
3315 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
3316 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3317 :
3318 : /* cleanup */
3319 3 : smb2_util_unlink(tree1, fname);
3320 :
3321 3 : tree1->session->transport->oplock.handler =
3322 : torture_oplock_handler_two_notifications;
3323 3 : tree1->session->transport->oplock.private_data = tree1;
3324 :
3325 : /*
3326 : base ntcreatex parms
3327 : */
3328 3 : ZERO_STRUCT(io.smb2);
3329 3 : io.generic.level = RAW_OPEN_SMB2;
3330 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3331 : SEC_RIGHTS_FILE_WRITE;
3332 3 : io.smb2.in.alloc_size = 0;
3333 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3334 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3335 : NTCREATEX_SHARE_ACCESS_WRITE;
3336 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3337 3 : io.smb2.in.create_options = 0;
3338 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3339 3 : io.smb2.in.security_flags = 0;
3340 3 : io.smb2.in.fname = fname;
3341 :
3342 : /*
3343 : with a batch oplock we get a break
3344 : */
3345 3 : torture_comment(tctx, "open with batch oplock\n");
3346 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3347 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3348 :
3349 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3350 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3351 3 : h1 = io.smb2.out.file.handle;
3352 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3353 :
3354 : /* create a file with bogus data */
3355 3 : memset(buf, 0, sizeof(buf));
3356 :
3357 3 : status = smb2_util_write(tree1, h1,buf, 0, sizeof(buf));
3358 3 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3359 0 : torture_comment(tctx, "Failed to create file\n");
3360 0 : ret = false;
3361 0 : goto done;
3362 : }
3363 :
3364 3 : torture_comment(tctx, "a 2nd open should give a break\n");
3365 3 : ZERO_STRUCT(break_info);
3366 :
3367 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3368 3 : io.smb2.in.oplock_level = 0;
3369 3 : status = smb2_create(tree2, tctx, &(io.smb2));
3370 3 : h2 = io.smb2.out.file.handle;
3371 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3372 :
3373 3 : torture_wait_for_oplock_break(tctx);
3374 3 : CHECK_VAL(break_info.count, 1);
3375 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3376 3 : CHECK_VAL(break_info.failures, 0);
3377 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3378 :
3379 3 : ZERO_STRUCT(break_info);
3380 :
3381 3 : torture_comment(tctx, "a self BRL acquisition should break to none\n");
3382 :
3383 3 : ZERO_STRUCT(lock);
3384 :
3385 3 : lock[0].offset = 0;
3386 3 : lock[0].length = 4;
3387 3 : lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3388 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3389 :
3390 3 : ZERO_STRUCT(lck);
3391 3 : lck.in.file.handle = h1;
3392 3 : lck.in.locks = &lock[0];
3393 3 : lck.in.lock_count = 1;
3394 3 : status = smb2_lock(tree1, &lck);
3395 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3396 :
3397 3 : torture_wait_for_oplock_break(tctx);
3398 3 : CHECK_VAL(break_info.count, 1);
3399 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3400 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3401 3 : CHECK_VAL(break_info.failures, 0);
3402 :
3403 : /* expect no oplock break */
3404 3 : ZERO_STRUCT(break_info);
3405 3 : lock[0].offset = 2;
3406 3 : status = smb2_lock(tree1, &lck);
3407 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3408 : "Incorrect status");
3409 :
3410 3 : torture_wait_for_oplock_break(tctx);
3411 3 : CHECK_VAL(break_info.count, 0);
3412 3 : CHECK_VAL(break_info.level, 0);
3413 3 : CHECK_VAL(break_info.failures, 0);
3414 :
3415 3 : smb2_util_close(tree1, h1);
3416 3 : smb2_util_close(tree2, h2);
3417 3 : smb2_util_close(tree1, h);
3418 :
3419 3 : done:
3420 3 : smb2_deltree(tree1, BASEDIR);
3421 3 : return ret;
3422 :
3423 : }
3424 :
3425 : /* Open a file with a batch oplock on one tree and then acquire a brl.
3426 : * We should not contend our own oplock.
3427 : */
3428 3 : static bool test_smb2_oplock_brl2(struct torture_context *tctx, struct smb2_tree *tree1)
3429 : {
3430 3 : const char *fname = BASEDIR "\\test_batch_brl.dat";
3431 : /*int fname, f;*/
3432 3 : bool ret = true;
3433 0 : uint8_t buf[1000];
3434 0 : union smb_open io;
3435 0 : NTSTATUS status;
3436 0 : struct smb2_handle h, h1;
3437 0 : struct smb2_lock lck;
3438 0 : struct smb2_lock_element lock[1];
3439 :
3440 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
3441 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3442 :
3443 : /* cleanup */
3444 3 : smb2_util_unlink(tree1, fname);
3445 :
3446 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
3447 3 : tree1->session->transport->oplock.private_data = tree1;
3448 :
3449 : /*
3450 : base ntcreatex parms
3451 : */
3452 3 : ZERO_STRUCT(io.smb2);
3453 3 : io.generic.level = RAW_OPEN_SMB2;
3454 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3455 : SEC_RIGHTS_FILE_WRITE;
3456 3 : io.smb2.in.alloc_size = 0;
3457 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3458 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3459 : NTCREATEX_SHARE_ACCESS_WRITE;
3460 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3461 3 : io.smb2.in.create_options = 0;
3462 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3463 3 : io.smb2.in.security_flags = 0;
3464 3 : io.smb2.in.fname = fname;
3465 :
3466 : /*
3467 : with a batch oplock we get a break
3468 : */
3469 3 : torture_comment(tctx, "open with batch oplock\n");
3470 3 : ZERO_STRUCT(break_info);
3471 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3472 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3473 :
3474 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3475 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3476 3 : h1 = io.smb2.out.file.handle;
3477 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3478 :
3479 : /* create a file with bogus data */
3480 3 : memset(buf, 0, sizeof(buf));
3481 :
3482 3 : status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3483 3 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3484 0 : torture_comment(tctx, "Failed to create file\n");
3485 0 : ret = false;
3486 0 : goto done;
3487 : }
3488 :
3489 3 : ZERO_STRUCT(break_info);
3490 :
3491 3 : torture_comment(tctx, "a self BRL acquisition should not break to "
3492 : "none\n");
3493 :
3494 3 : ZERO_STRUCT(lock);
3495 :
3496 3 : lock[0].offset = 0;
3497 3 : lock[0].length = 4;
3498 3 : lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3499 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3500 :
3501 3 : ZERO_STRUCT(lck);
3502 3 : lck.in.file.handle = h1;
3503 3 : lck.in.locks = &lock[0];
3504 3 : lck.in.lock_count = 1;
3505 3 : status = smb2_lock(tree1, &lck);
3506 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3507 :
3508 3 : lock[0].offset = 2;
3509 3 : status = smb2_lock(tree1, &lck);
3510 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3511 : "Incorrect status");
3512 :
3513 : /* With one file handle open a BRL should not contend our oplock.
3514 : * Thus, no oplock break will be received and the entire break_info
3515 : * struct will be 0 */
3516 3 : torture_wait_for_oplock_break(tctx);
3517 3 : CHECK_VAL(break_info.count, 0);
3518 3 : CHECK_VAL(break_info.level, 0);
3519 3 : CHECK_VAL(break_info.failures, 0);
3520 :
3521 3 : smb2_util_close(tree1, h1);
3522 3 : smb2_util_close(tree1, h);
3523 :
3524 3 : done:
3525 3 : smb2_deltree(tree1, BASEDIR);
3526 3 : return ret;
3527 : }
3528 :
3529 : /* Open a file with a batch oplock twice from one tree and then acquire a
3530 : * brl. BRL acquisition should break our own oplock.
3531 : */
3532 3 : static bool test_smb2_oplock_brl3(struct torture_context *tctx, struct smb2_tree *tree1)
3533 : {
3534 3 : const char *fname = BASEDIR "\\test_batch_brl.dat";
3535 3 : bool ret = true;
3536 0 : uint8_t buf[1000];
3537 0 : union smb_open io;
3538 0 : NTSTATUS status;
3539 0 : struct smb2_handle h, h1, h2;
3540 0 : struct smb2_lock lck;
3541 0 : struct smb2_lock_element lock[1];
3542 :
3543 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
3544 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3545 :
3546 : /* cleanup */
3547 3 : smb2_util_unlink(tree1, fname);
3548 3 : tree1->session->transport->oplock.handler =
3549 : torture_oplock_handler_two_notifications;
3550 3 : tree1->session->transport->oplock.private_data = tree1;
3551 :
3552 : /*
3553 : base ntcreatex parms
3554 : */
3555 3 : ZERO_STRUCT(io.smb2);
3556 3 : io.generic.level = RAW_OPEN_SMB2;
3557 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3558 : SEC_RIGHTS_FILE_WRITE;
3559 3 : io.smb2.in.alloc_size = 0;
3560 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3561 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3562 : NTCREATEX_SHARE_ACCESS_WRITE;
3563 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3564 3 : io.smb2.in.create_options = 0;
3565 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3566 3 : io.smb2.in.security_flags = 0;
3567 3 : io.smb2.in.fname = fname;
3568 :
3569 : /*
3570 : with a batch oplock we get a break
3571 : */
3572 3 : torture_comment(tctx, "open with batch oplock\n");
3573 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3574 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3575 :
3576 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3577 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3578 3 : h1 = io.smb2.out.file.handle;
3579 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3580 :
3581 : /* create a file with bogus data */
3582 3 : memset(buf, 0, sizeof(buf));
3583 3 : status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3584 :
3585 3 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3586 0 : torture_comment(tctx, "Failed to create file\n");
3587 0 : ret = false;
3588 0 : goto done;
3589 : }
3590 :
3591 3 : torture_comment(tctx, "a 2nd open should give a break\n");
3592 3 : ZERO_STRUCT(break_info);
3593 :
3594 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3595 3 : io.smb2.in.oplock_level = 0;
3596 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3597 3 : h2 = io.smb2.out.file.handle;
3598 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3599 3 : CHECK_VAL(break_info.count, 1);
3600 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3601 3 : CHECK_VAL(break_info.failures, 0);
3602 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3603 :
3604 3 : ZERO_STRUCT(break_info);
3605 :
3606 3 : torture_comment(tctx, "a self BRL acquisition should break to none\n");
3607 :
3608 3 : ZERO_STRUCT(lock);
3609 :
3610 3 : lock[0].offset = 0;
3611 3 : lock[0].length = 4;
3612 3 : lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3613 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3614 :
3615 3 : ZERO_STRUCT(lck);
3616 3 : lck.in.file.handle = h1;
3617 3 : lck.in.locks = &lock[0];
3618 3 : lck.in.lock_count = 1;
3619 3 : status = smb2_lock(tree1, &lck);
3620 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3621 :
3622 3 : torture_wait_for_oplock_break(tctx);
3623 3 : CHECK_VAL(break_info.count, 1);
3624 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3625 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3626 3 : CHECK_VAL(break_info.failures, 0);
3627 :
3628 : /* expect no oplock break */
3629 3 : ZERO_STRUCT(break_info);
3630 3 : lock[0].offset = 2;
3631 3 : status = smb2_lock(tree1, &lck);
3632 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3633 : "Incorrect status");
3634 :
3635 3 : torture_wait_for_oplock_break(tctx);
3636 3 : CHECK_VAL(break_info.count, 0);
3637 3 : CHECK_VAL(break_info.level, 0);
3638 3 : CHECK_VAL(break_info.failures, 0);
3639 :
3640 3 : smb2_util_close(tree1, h1);
3641 3 : smb2_util_close(tree1, h2);
3642 3 : smb2_util_close(tree1, h);
3643 :
3644 3 : done:
3645 3 : smb2_deltree(tree1, BASEDIR);
3646 3 : return ret;
3647 :
3648 : }
3649 :
3650 : /* Starting the SMB2 specific oplock tests at 500 so we can keep the SMB1
3651 : * tests in sync with an identically numbered SMB2 test */
3652 :
3653 : /* Test whether the server correctly returns an error when we send
3654 : * a response to a levelII to none oplock notification. */
3655 3 : static bool test_smb2_oplock_levelII500(struct torture_context *tctx,
3656 : struct smb2_tree *tree1)
3657 : {
3658 3 : const char *fname = BASEDIR "\\test_levelII500.dat";
3659 0 : NTSTATUS status;
3660 3 : bool ret = true;
3661 0 : union smb_open io;
3662 0 : struct smb2_handle h, h1;
3663 3 : char c = 0;
3664 :
3665 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
3666 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3667 :
3668 : /* cleanup */
3669 3 : smb2_util_unlink(tree1, fname);
3670 :
3671 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
3672 3 : tree1->session->transport->oplock.private_data = tree1;
3673 :
3674 : /*
3675 : base ntcreatex parms
3676 : */
3677 3 : ZERO_STRUCT(io.smb2);
3678 3 : io.generic.level = RAW_OPEN_SMB2;
3679 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3680 3 : io.smb2.in.alloc_size = 0;
3681 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3682 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3683 3 : io.smb2.in.create_options = 0;
3684 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3685 3 : io.smb2.in.security_flags = 0;
3686 3 : io.smb2.in.fname = fname;
3687 :
3688 3 : torture_comment(tctx, "LEVELII500: acknowledging a break from II to "
3689 : "none should return an error\n");
3690 3 : ZERO_STRUCT(break_info);
3691 :
3692 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3693 : SEC_RIGHTS_FILE_WRITE;
3694 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3695 : NTCREATEX_SHARE_ACCESS_WRITE;
3696 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3697 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
3698 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3699 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3700 3 : h1 = io.smb2.out.file.handle;
3701 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3702 :
3703 3 : ZERO_STRUCT(break_info);
3704 :
3705 3 : torture_comment(tctx, "write should trigger a break to none and when "
3706 : "we reply, an oplock break failure\n");
3707 3 : smb2_util_write(tree1, h1, &c, 0, 1);
3708 :
3709 : /* Wait several times to receive both the break notification, and the
3710 : * NT_STATUS_INVALID_OPLOCK_PROTOCOL error in the break response */
3711 3 : torture_wait_for_oplock_break(tctx);
3712 3 : torture_wait_for_oplock_break(tctx);
3713 3 : torture_wait_for_oplock_break(tctx);
3714 3 : torture_wait_for_oplock_break(tctx);
3715 :
3716 : /* There appears to be a race condition in W2K8 and W2K8R2 where
3717 : * sometimes the server will happily reply to our break response with
3718 : * NT_STATUS_OK, and sometimes it will return the OPLOCK_PROTOCOL
3719 : * error. As the MS-SMB2 doc states that a client should not reply to
3720 : * a level2 to none break notification, I'm leaving the protocol error
3721 : * as the expected behavior. */
3722 3 : CHECK_VAL(break_info.count, 1);
3723 3 : CHECK_VAL(break_info.level, 0);
3724 3 : CHECK_VAL(break_info.failures, 1);
3725 3 : torture_assert_ntstatus_equal(tctx, break_info.failure_status,
3726 : NT_STATUS_INVALID_OPLOCK_PROTOCOL,
3727 : "Incorrect status");
3728 :
3729 2 : smb2_util_close(tree1, h1);
3730 2 : smb2_util_close(tree1, h);
3731 :
3732 2 : smb2_deltree(tree1, BASEDIR);
3733 2 : return ret;
3734 : }
3735 :
3736 : /*
3737 : * Test a double-break. Open a file with exclusive. Send off a second open
3738 : * request with OPEN_IF, triggering a break to level2. This should respond
3739 : * with level2. Before replying to the break to level2, fire off a third open
3740 : * with OVERWRITE_IF. The expected sequence would be that the 3rd opener gets
3741 : * a level2 immediately triggered by a break to none, but that seems not the
3742 : * case. Still investigating what the right behaviour should be.
3743 : */
3744 :
3745 : struct levelII501_state {
3746 : struct torture_context *tctx;
3747 : struct smb2_tree *tree1;
3748 : struct smb2_tree *tree2;
3749 : struct smb2_tree *tree3;
3750 : struct smb2_handle h;
3751 : struct smb2_handle h1;
3752 : union smb_open io;
3753 :
3754 : struct smb2_handle break_handle;
3755 : uint8_t break_to;
3756 : struct smb2_break br;
3757 :
3758 : bool done;
3759 : };
3760 :
3761 : static bool torture_oplock_break_delay(struct smb2_transport *transport,
3762 : const struct smb2_handle *handle,
3763 : uint8_t level, void *private_data);
3764 : static void levelII501_break_done(struct smb2_request *req);
3765 : static void levelII501_open1_done(struct smb2_request *req);
3766 : static void levelII501_open2_done(struct smb2_request *req);
3767 : static void levelII501_2ndopen_cb(struct tevent_context *ev,
3768 : struct tevent_timer *te,
3769 : struct timeval current_time,
3770 : void *private_data);
3771 : static void levelII501_break_timeout_cb(struct tevent_context *ev,
3772 : struct tevent_timer *te,
3773 : struct timeval current_time,
3774 : void *private_data);
3775 : static void levelII501_timeout_cb(struct tevent_context *ev,
3776 : struct tevent_timer *te,
3777 : struct timeval current_time,
3778 : void *private_data);
3779 :
3780 3 : static bool test_smb2_oplock_levelII501(struct torture_context *tctx,
3781 : struct smb2_tree *tree1,
3782 : struct smb2_tree *tree2)
3783 : {
3784 3 : const char *fname = BASEDIR "\\test_levelII501.dat";
3785 0 : NTSTATUS status;
3786 3 : bool ret = true;
3787 0 : struct levelII501_state *state;
3788 0 : struct smb2_request *req;
3789 0 : struct tevent_timer *te;
3790 :
3791 3 : state = talloc(tctx, struct levelII501_state);
3792 3 : state->tctx = tctx;
3793 3 : state->done = false;
3794 3 : state->tree1 = tree1;
3795 3 : state->tree2 = tree2;
3796 :
3797 3 : if (!torture_smb2_connection(tctx, &state->tree3)) {
3798 0 : torture_fail(tctx, "Establishing SMB2 connection failed\n");
3799 : return false;
3800 : }
3801 :
3802 3 : status = torture_smb2_testdir(tree1, BASEDIR, &state->h);
3803 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3804 :
3805 : /* cleanup */
3806 3 : smb2_util_unlink(tree1, fname);
3807 :
3808 : /*
3809 : base ntcreatex parms
3810 : */
3811 3 : ZERO_STRUCT(state->io.smb2);
3812 3 : state->io.generic.level = RAW_OPEN_SMB2;
3813 3 : state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3814 3 : state->io.smb2.in.alloc_size = 0;
3815 3 : state->io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3816 3 : state->io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3817 3 : state->io.smb2.in.create_options = 0;
3818 3 : state->io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3819 3 : state->io.smb2.in.security_flags = 0;
3820 3 : state->io.smb2.in.fname = fname;
3821 :
3822 3 : torture_comment(tctx, "LEVELII501: Test double break sequence\n");
3823 3 : ZERO_STRUCT(break_info);
3824 :
3825 3 : state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3826 : SEC_RIGHTS_FILE_WRITE;
3827 3 : state->io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3828 : NTCREATEX_SHARE_ACCESS_WRITE;
3829 3 : state->io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3830 3 : state->io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3831 :
3832 3 : tree1->session->transport->oplock.handler = torture_oplock_break_delay;
3833 3 : tree1->session->transport->oplock.private_data = state;
3834 :
3835 3 : status = smb2_create(tree1, tctx, &(state->io.smb2));
3836 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3837 3 : state->h1 = state->io.smb2.out.file.handle;
3838 3 : CHECK_VAL(state->io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3839 :
3840 : /*
3841 : * Trigger a break to level2
3842 : */
3843 :
3844 3 : req = smb2_create_send(tree2, &state->io.smb2);
3845 3 : req->async.fn = levelII501_open1_done;
3846 3 : req->async.private_data = state;
3847 :
3848 3 : te = tevent_add_timer(
3849 : tctx->ev, tctx, tevent_timeval_current_ofs(0, 200000),
3850 : levelII501_2ndopen_cb, state);
3851 3 : torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
3852 :
3853 3 : te = tevent_add_timer(
3854 : tctx->ev, tctx, tevent_timeval_current_ofs(2, 0),
3855 : levelII501_timeout_cb, state);
3856 3 : torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
3857 :
3858 91 : while (!state->done) {
3859 88 : if (tevent_loop_once(tctx->ev) != 0) {
3860 0 : torture_comment(tctx, "tevent_loop_once failed\n");
3861 : }
3862 : }
3863 :
3864 3 : return ret;
3865 : }
3866 :
3867 : /*
3868 : * Fire off a second open after a little timeout
3869 : */
3870 :
3871 3 : static void levelII501_2ndopen_cb(struct tevent_context *ev,
3872 : struct tevent_timer *te,
3873 : struct timeval current_time,
3874 : void *private_data)
3875 : {
3876 3 : struct levelII501_state *state = talloc_get_type_abort(
3877 : private_data, struct levelII501_state);
3878 0 : struct smb2_request *req;
3879 :
3880 3 : state->io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
3881 3 : req = smb2_create_send(state->tree3, &state->io.smb2);
3882 3 : req->async.fn = levelII501_open2_done;
3883 3 : req->async.private_data = state;
3884 3 : }
3885 :
3886 : /*
3887 : * Postpone the break response by 500 msec
3888 : */
3889 5 : static bool torture_oplock_break_delay(struct smb2_transport *transport,
3890 : const struct smb2_handle *handle,
3891 : uint8_t level, void *private_data)
3892 : {
3893 5 : struct levelII501_state *state = talloc_get_type_abort(
3894 : private_data, struct levelII501_state);
3895 0 : const char *name;
3896 0 : struct tevent_timer *te;
3897 :
3898 5 : break_info.handle = *handle;
3899 5 : break_info.level = level;
3900 5 : break_info.count++;
3901 :
3902 5 : state->break_handle = *handle;
3903 5 : state->break_to = level;
3904 :
3905 5 : switch(level) {
3906 3 : case SMB2_OPLOCK_LEVEL_II:
3907 3 : name = "level II";
3908 3 : break;
3909 2 : case SMB2_OPLOCK_LEVEL_NONE:
3910 2 : name = "none";
3911 2 : break;
3912 0 : default:
3913 0 : name = "unknown";
3914 0 : break;
3915 : }
3916 5 : printf("Got break to %s [0x%02X] in oplock handler, postponing "
3917 : "break response for 500msec\n", name, level);
3918 :
3919 5 : te = tevent_add_timer(
3920 : state->tctx->ev, state->tctx,
3921 : tevent_timeval_current_ofs(0, 500000),
3922 : levelII501_break_timeout_cb, state);
3923 5 : torture_assert(state->tctx, te != NULL, "tevent_add_timer failed\n");
3924 :
3925 5 : return true;
3926 : }
3927 :
3928 5 : static void levelII501_break_timeout_cb(struct tevent_context *ev,
3929 : struct tevent_timer *te,
3930 : struct timeval current_time,
3931 : void *private_data)
3932 : {
3933 5 : struct levelII501_state *state = talloc_get_type_abort(
3934 : private_data, struct levelII501_state);
3935 0 : struct smb2_request *req;
3936 :
3937 5 : talloc_free(te);
3938 :
3939 5 : ZERO_STRUCT(state->br);
3940 5 : state->br.in.file.handle = state->break_handle;
3941 5 : state->br.in.oplock_level = state->break_to;
3942 :
3943 5 : req = smb2_break_send(state->tree1, &state->br);
3944 5 : req->async.fn = levelII501_break_done;
3945 5 : req->async.private_data = state;
3946 5 : }
3947 :
3948 5 : static void levelII501_break_done(struct smb2_request *req)
3949 : {
3950 0 : struct smb2_break io;
3951 0 : NTSTATUS status;
3952 :
3953 5 : status = smb2_break_recv(req, &io);
3954 5 : printf("break done: %s\n", nt_errstr(status));
3955 5 : }
3956 :
3957 3 : static void levelII501_open1_done(struct smb2_request *req)
3958 : {
3959 3 : struct levelII501_state *state = talloc_get_type_abort(
3960 : req->async.private_data, struct levelII501_state);
3961 0 : struct smb2_create io;
3962 0 : NTSTATUS status;
3963 :
3964 3 : status = smb2_create_recv(req, state, &io);
3965 3 : printf("open1 done: %s\n", nt_errstr(status));
3966 3 : }
3967 :
3968 3 : static void levelII501_open2_done(struct smb2_request *req)
3969 : {
3970 3 : struct levelII501_state *state = talloc_get_type_abort(
3971 : req->async.private_data, struct levelII501_state);
3972 0 : struct smb2_create io;
3973 0 : NTSTATUS status;
3974 :
3975 3 : status = smb2_create_recv(req, state, &io);
3976 3 : printf("open2 done: %s\n", nt_errstr(status));
3977 3 : }
3978 :
3979 3 : static void levelII501_timeout_cb(struct tevent_context *ev,
3980 : struct tevent_timer *te,
3981 : struct timeval current_time,
3982 : void *private_data)
3983 : {
3984 3 : struct levelII501_state *state = talloc_get_type_abort(
3985 : private_data, struct levelII501_state);
3986 3 : talloc_free(te);
3987 3 : state->done = true;
3988 3 : }
3989 :
3990 3 : static bool test_smb2_oplock_levelII502(struct torture_context *tctx,
3991 : struct smb2_tree *tree1,
3992 : struct smb2_tree *tree2)
3993 :
3994 : {
3995 3 : const char *fname = BASEDIR "\\test_levelII502.dat";
3996 0 : NTSTATUS status;
3997 0 : union smb_open io;
3998 0 : struct smb2_close closeio;
3999 0 : struct smb2_handle h;
4000 :
4001 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
4002 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4003 :
4004 : /* cleanup */
4005 3 : smb2_util_unlink(tree1, fname);
4006 :
4007 : /*
4008 : base ntcreatex parms
4009 : */
4010 3 : ZERO_STRUCT(io.smb2);
4011 3 : io.generic.level = RAW_OPEN_SMB2;
4012 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4013 3 : io.smb2.in.alloc_size = 0;
4014 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4015 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4016 3 : io.smb2.in.create_options = 0;
4017 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4018 3 : io.smb2.in.security_flags = 0;
4019 3 : io.smb2.in.fname = fname;
4020 :
4021 3 : torture_comment(
4022 : tctx,
4023 : "LEVELII502: Open a stale LEVEL2 oplock with OVERWRITE");
4024 :
4025 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
4026 : SEC_RIGHTS_FILE_WRITE;
4027 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
4028 : NTCREATEX_SHARE_ACCESS_WRITE;
4029 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4030 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
4031 3 : status = smb2_create(tree1, tctx, &(io.smb2));
4032 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
4033 3 : torture_assert(tctx,
4034 : io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_II,
4035 : "Did not get LEVEL_II oplock\n");
4036 :
4037 2 : status = smbXcli_conn_samba_suicide(
4038 2 : tree1->session->transport->conn, 93);
4039 2 : torture_assert_ntstatus_ok(tctx, status, "suicide failed");
4040 :
4041 2 : sleep(1);
4042 :
4043 2 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4044 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
4045 :
4046 2 : status = smb2_create(tree2, tctx, &(io.smb2));
4047 2 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
4048 2 : torture_assert(tctx,
4049 : io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_BATCH,
4050 : "Did not get BATCH oplock\n");
4051 :
4052 2 : closeio = (struct smb2_close) {
4053 : .in.file.handle = io.smb2.out.file.handle,
4054 : };
4055 2 : status = smb2_close(tree2, &closeio);
4056 2 : torture_assert_ntstatus_equal(
4057 : tctx, status, NT_STATUS_OK, "close failed");
4058 :
4059 2 : return true;
4060 : }
4061 :
4062 36 : static bool test_oplock_statopen1_do(struct torture_context *tctx,
4063 : struct smb2_tree *tree,
4064 : uint32_t access_mask,
4065 : bool expect_stat_open)
4066 : {
4067 36 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
4068 0 : struct smb2_create cr;
4069 36 : struct smb2_handle h1 = {{0}};
4070 36 : struct smb2_handle h2 = {{0}};
4071 0 : NTSTATUS status;
4072 36 : const char *fname = "oplock_statopen1.dat";
4073 36 : bool ret = true;
4074 :
4075 : /* Open file with exclusive oplock. */
4076 36 : cr = (struct smb2_create) {
4077 : .in.desired_access = SEC_FILE_ALL,
4078 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
4079 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
4080 : .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
4081 : .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
4082 : .in.fname = fname,
4083 : .in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH,
4084 : };
4085 36 : status = smb2_create(tree, mem_ctx, &cr);
4086 36 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4087 : "smb2_create failed\n");
4088 36 : h1 = cr.out.file.handle;
4089 36 : CHECK_VAL(cr.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
4090 :
4091 : /* Stat open */
4092 36 : cr = (struct smb2_create) {
4093 : .in.desired_access = access_mask,
4094 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
4095 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
4096 : .in.create_disposition = NTCREATEX_DISP_OPEN,
4097 : .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
4098 : .in.fname = fname,
4099 : };
4100 36 : status = smb2_create(tree, mem_ctx, &cr);
4101 36 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4102 : "smb2_create failed\n");
4103 35 : h2 = cr.out.file.handle;
4104 :
4105 35 : if (expect_stat_open) {
4106 8 : torture_wait_for_oplock_break(tctx);
4107 8 : CHECK_VAL(break_info.count, 0);
4108 8 : CHECK_VAL(break_info.level, 0);
4109 8 : CHECK_VAL(break_info.failures, 0);
4110 8 : if (!ret) {
4111 0 : goto done;
4112 : }
4113 : } else {
4114 27 : CHECK_VAL(break_info.count, 1);
4115 : }
4116 :
4117 27 : done:
4118 36 : if (!smb2_util_handle_empty(h2)) {
4119 35 : smb2_util_close(tree, h2);
4120 : }
4121 36 : if (!smb2_util_handle_empty(h1)) {
4122 36 : smb2_util_close(tree, h1);
4123 : }
4124 36 : talloc_free(mem_ctx);
4125 36 : return ret;
4126 : }
4127 :
4128 3 : static bool test_smb2_oplock_statopen1(struct torture_context *tctx,
4129 : struct smb2_tree *tree)
4130 : {
4131 3 : const char *fname = "oplock_statopen1.dat";
4132 0 : size_t i;
4133 3 : bool ret = true;
4134 0 : struct {
4135 : uint32_t access_mask;
4136 : bool expect_stat_open;
4137 3 : } tests[] = {
4138 : {
4139 : .access_mask = FILE_READ_DATA,
4140 : .expect_stat_open = false,
4141 : },
4142 : {
4143 : .access_mask = FILE_WRITE_DATA,
4144 : .expect_stat_open = false,
4145 : },
4146 : {
4147 : .access_mask = FILE_READ_EA,
4148 : .expect_stat_open = false,
4149 : },
4150 : {
4151 : .access_mask = FILE_WRITE_EA,
4152 : .expect_stat_open = false,
4153 : },
4154 : {
4155 : .access_mask = FILE_EXECUTE,
4156 : .expect_stat_open = false,
4157 : },
4158 : {
4159 : .access_mask = FILE_READ_ATTRIBUTES,
4160 : .expect_stat_open = true,
4161 : },
4162 : {
4163 : .access_mask = FILE_WRITE_ATTRIBUTES,
4164 : .expect_stat_open = true,
4165 : },
4166 : {
4167 : .access_mask = DELETE_ACCESS,
4168 : .expect_stat_open = false,
4169 : },
4170 : {
4171 : .access_mask = READ_CONTROL_ACCESS,
4172 : .expect_stat_open = false,
4173 : },
4174 : {
4175 : .access_mask = WRITE_DAC_ACCESS,
4176 : .expect_stat_open = false,
4177 : },
4178 : {
4179 : .access_mask = WRITE_OWNER_ACCESS,
4180 : .expect_stat_open = false,
4181 : },
4182 : {
4183 : .access_mask = SYNCHRONIZE_ACCESS,
4184 : .expect_stat_open = true,
4185 : },
4186 : };
4187 :
4188 3 : tree->session->transport->oplock.handler = torture_oplock_handler;
4189 3 : tree->session->transport->oplock.private_data = tree;
4190 :
4191 38 : for (i = 0; i < ARRAY_SIZE(tests); i++) {
4192 36 : ZERO_STRUCT(break_info);
4193 :
4194 36 : ret = test_oplock_statopen1_do(tctx,
4195 : tree,
4196 : tests[i].access_mask,
4197 36 : tests[i].expect_stat_open);
4198 36 : if (ret == true) {
4199 35 : continue;
4200 : }
4201 1 : torture_result(tctx, TORTURE_FAIL,
4202 : "test %zu: access_mask: %s, "
4203 : "expect_stat_open: %s\n",
4204 : i,
4205 : get_sec_mask_str(tree, tests[i].access_mask),
4206 1 : tests[i].expect_stat_open ? "yes" : "no");
4207 1 : goto done;
4208 : }
4209 :
4210 2 : done:
4211 3 : smb2_util_unlink(tree, fname);
4212 3 : return ret;
4213 : }
4214 :
4215 2354 : struct torture_suite *torture_smb2_oplocks_init(TALLOC_CTX *ctx)
4216 : {
4217 125 : struct torture_suite *suite =
4218 2354 : torture_suite_create(ctx, "oplock");
4219 :
4220 2354 : torture_suite_add_2smb2_test(suite, "exclusive1", test_smb2_oplock_exclusive1);
4221 2354 : torture_suite_add_2smb2_test(suite, "exclusive2", test_smb2_oplock_exclusive2);
4222 2354 : torture_suite_add_2smb2_test(suite, "exclusive3", test_smb2_oplock_exclusive3);
4223 2354 : torture_suite_add_2smb2_test(suite, "exclusive4", test_smb2_oplock_exclusive4);
4224 2354 : torture_suite_add_2smb2_test(suite, "exclusive5", test_smb2_oplock_exclusive5);
4225 2354 : torture_suite_add_2smb2_test(suite, "exclusive6", test_smb2_oplock_exclusive6);
4226 2354 : torture_suite_add_2smb2_test(suite, "exclusive9",
4227 : test_smb2_oplock_exclusive9);
4228 2354 : torture_suite_add_2smb2_test(suite, "batch1", test_smb2_oplock_batch1);
4229 2354 : torture_suite_add_2smb2_test(suite, "batch2", test_smb2_oplock_batch2);
4230 2354 : torture_suite_add_2smb2_test(suite, "batch3", test_smb2_oplock_batch3);
4231 2354 : torture_suite_add_2smb2_test(suite, "batch4", test_smb2_oplock_batch4);
4232 2354 : torture_suite_add_2smb2_test(suite, "batch5", test_smb2_oplock_batch5);
4233 2354 : torture_suite_add_2smb2_test(suite, "batch6", test_smb2_oplock_batch6);
4234 2354 : torture_suite_add_2smb2_test(suite, "batch7", test_smb2_oplock_batch7);
4235 2354 : torture_suite_add_2smb2_test(suite, "batch8", test_smb2_oplock_batch8);
4236 2354 : torture_suite_add_2smb2_test(suite, "batch9", test_smb2_oplock_batch9);
4237 2354 : torture_suite_add_2smb2_test(suite, "batch9a", test_smb2_oplock_batch9a);
4238 2354 : torture_suite_add_2smb2_test(suite, "batch10", test_smb2_oplock_batch10);
4239 2354 : torture_suite_add_2smb2_test(suite, "batch11", test_smb2_oplock_batch11);
4240 2354 : torture_suite_add_2smb2_test(suite, "batch12", test_smb2_oplock_batch12);
4241 2354 : torture_suite_add_2smb2_test(suite, "batch13", test_smb2_oplock_batch13);
4242 2354 : torture_suite_add_2smb2_test(suite, "batch14", test_smb2_oplock_batch14);
4243 2354 : torture_suite_add_2smb2_test(suite, "batch15", test_smb2_oplock_batch15);
4244 2354 : torture_suite_add_2smb2_test(suite, "batch16", test_smb2_oplock_batch16);
4245 2354 : torture_suite_add_1smb2_test(suite, "batch19", test_smb2_oplock_batch19);
4246 2354 : torture_suite_add_2smb2_test(suite, "batch20", test_smb2_oplock_batch20);
4247 2354 : torture_suite_add_1smb2_test(suite, "batch21", test_smb2_oplock_batch21);
4248 2354 : torture_suite_add_1smb2_test(suite, "batch22a", test_smb2_oplock_batch22a);
4249 2354 : torture_suite_add_2smb2_test(suite, "batch22b", test_smb2_oplock_batch22b);
4250 2354 : torture_suite_add_2smb2_test(suite, "batch23", test_smb2_oplock_batch23);
4251 2354 : torture_suite_add_2smb2_test(suite, "batch24", test_smb2_oplock_batch24);
4252 2354 : torture_suite_add_1smb2_test(suite, "batch25", test_smb2_oplock_batch25);
4253 2354 : torture_suite_add_1smb2_test(suite, "batch26", test_smb2_oplock_batch26);
4254 2354 : torture_suite_add_2smb2_test(suite, "stream1", test_raw_oplock_stream1);
4255 2354 : torture_suite_add_2smb2_test(suite, "doc", test_smb2_oplock_doc);
4256 2354 : torture_suite_add_2smb2_test(suite, "brl1", test_smb2_oplock_brl1);
4257 2354 : torture_suite_add_1smb2_test(suite, "brl2", test_smb2_oplock_brl2);
4258 2354 : torture_suite_add_1smb2_test(suite, "brl3", test_smb2_oplock_brl3);
4259 2354 : torture_suite_add_1smb2_test(suite, "levelii500", test_smb2_oplock_levelII500);
4260 2354 : torture_suite_add_2smb2_test(suite, "levelii501",
4261 : test_smb2_oplock_levelII501);
4262 2354 : torture_suite_add_2smb2_test(suite, "levelii502",
4263 : test_smb2_oplock_levelII502);
4264 2354 : torture_suite_add_1smb2_test(suite, "statopen1", test_smb2_oplock_statopen1);
4265 2354 : suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
4266 :
4267 2354 : return suite;
4268 : }
4269 :
4270 : /*
4271 : stress testing of oplocks
4272 : */
4273 0 : bool test_smb2_bench_oplock(struct torture_context *tctx,
4274 : struct smb2_tree *tree)
4275 : {
4276 0 : struct smb2_tree **trees;
4277 0 : bool ret = true;
4278 0 : NTSTATUS status;
4279 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
4280 0 : int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
4281 0 : int i, count=0;
4282 0 : int timelimit = torture_setting_int(tctx, "timelimit", 10);
4283 0 : union smb_open io;
4284 0 : struct timeval tv;
4285 0 : struct smb2_handle h;
4286 :
4287 0 : trees = talloc_array(mem_ctx, struct smb2_tree *, torture_nprocs);
4288 :
4289 0 : torture_comment(tctx, "Opening %d connections\n", torture_nprocs);
4290 0 : for (i=0;i<torture_nprocs;i++) {
4291 0 : if (!torture_smb2_connection(tctx, &trees[i])) {
4292 0 : return false;
4293 : }
4294 0 : talloc_steal(mem_ctx, trees[i]);
4295 0 : trees[i]->session->transport->oplock.handler =
4296 : torture_oplock_handler_close;
4297 0 : trees[i]->session->transport->oplock.private_data = trees[i];
4298 : }
4299 :
4300 0 : status = torture_smb2_testdir(trees[0], BASEDIR, &h);
4301 0 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4302 :
4303 0 : ZERO_STRUCT(io.smb2);
4304 0 : io.smb2.level = RAW_OPEN_SMB2;
4305 0 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4306 0 : io.smb2.in.alloc_size = 0;
4307 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4308 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4309 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4310 0 : io.smb2.in.create_options = 0;
4311 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4312 0 : io.smb2.in.security_flags = 0;
4313 0 : io.smb2.in.fname = BASEDIR "\\test.dat";
4314 0 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4315 0 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4316 :
4317 0 : tv = timeval_current();
4318 :
4319 : /*
4320 : we open the same file with SHARE_ACCESS_NONE from all the
4321 : connections in a round robin fashion. Each open causes an
4322 : oplock break on the previous connection, which is answered
4323 : by the oplock_handler_close() to close the file.
4324 :
4325 : This measures how fast we can pass on oplocks, and stresses
4326 : the oplock handling code
4327 : */
4328 0 : torture_comment(tctx, "Running for %d seconds\n", timelimit);
4329 0 : while (timeval_elapsed(&tv) < timelimit) {
4330 0 : for (i=0;i<torture_nprocs;i++) {
4331 0 : status = smb2_create(trees[i], mem_ctx, &(io.smb2));
4332 0 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
4333 0 : count++;
4334 : }
4335 :
4336 0 : if (torture_setting_bool(tctx, "progress", true)) {
4337 0 : torture_comment(tctx, "%.2f ops/second\r",
4338 0 : count/timeval_elapsed(&tv));
4339 : }
4340 : }
4341 :
4342 0 : torture_comment(tctx, "%.2f ops/second\n", count/timeval_elapsed(&tv));
4343 0 : smb2_util_close(trees[0], io.smb2.out.file.handle);
4344 0 : smb2_util_unlink(trees[0], BASEDIR "\\test.dat");
4345 0 : smb2_deltree(trees[0], BASEDIR);
4346 0 : talloc_free(mem_ctx);
4347 0 : return ret;
4348 : }
4349 :
4350 : static struct hold_oplock_info {
4351 : const char *fname;
4352 : bool close_on_break;
4353 : uint32_t share_access;
4354 : struct smb2_handle handle;
4355 : } hold_info[] = {
4356 : {
4357 : .fname = BASEDIR "\\notshared_close",
4358 : .close_on_break = true,
4359 : .share_access = NTCREATEX_SHARE_ACCESS_NONE,
4360 : },
4361 : {
4362 : .fname = BASEDIR "\\notshared_noclose",
4363 : .close_on_break = false,
4364 : .share_access = NTCREATEX_SHARE_ACCESS_NONE,
4365 : },
4366 : {
4367 : .fname = BASEDIR "\\shared_close",
4368 : .close_on_break = true,
4369 : .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
4370 : },
4371 : {
4372 : .fname = BASEDIR "\\shared_noclose",
4373 : .close_on_break = false,
4374 : .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
4375 : },
4376 : };
4377 :
4378 0 : static bool torture_oplock_handler_hold(struct smb2_transport *transport,
4379 : const struct smb2_handle *handle,
4380 : uint8_t level, void *private_data)
4381 : {
4382 0 : struct hold_oplock_info *info;
4383 0 : int i;
4384 :
4385 0 : for (i=0;i<ARRAY_SIZE(hold_info);i++) {
4386 0 : if (smb2_util_handle_equal(hold_info[i].handle, *handle))
4387 0 : break;
4388 : }
4389 :
4390 0 : if (i == ARRAY_SIZE(hold_info)) {
4391 0 : printf("oplock break for unknown handle 0x%llx%llx\n",
4392 0 : (unsigned long long) handle->data[0],
4393 0 : (unsigned long long) handle->data[1]);
4394 0 : return false;
4395 : }
4396 :
4397 0 : info = &hold_info[i];
4398 :
4399 0 : if (info->close_on_break) {
4400 0 : printf("oplock break on %s - closing\n", info->fname);
4401 0 : torture_oplock_handler_close(transport, handle,
4402 : level, private_data);
4403 0 : return true;
4404 : }
4405 :
4406 0 : printf("oplock break on %s - acking break\n", info->fname);
4407 0 : printf("Acking to none in oplock handler\n");
4408 :
4409 0 : torture_oplock_handler_ack_to_none(transport, handle,
4410 : level, private_data);
4411 0 : return true;
4412 : }
4413 :
4414 : /*
4415 : used for manual testing of oplocks - especially interaction with
4416 : other filesystems (such as NFS and local access)
4417 : */
4418 0 : bool test_smb2_hold_oplock(struct torture_context *tctx,
4419 : struct smb2_tree *tree)
4420 : {
4421 0 : struct torture_context *mem_ctx = talloc_new(tctx);
4422 0 : struct tevent_context *ev = tctx->ev;
4423 0 : int i;
4424 0 : struct smb2_handle h;
4425 0 : NTSTATUS status;
4426 :
4427 0 : torture_comment(tctx, "Setting up open files with oplocks in %s\n",
4428 : BASEDIR);
4429 :
4430 0 : status = torture_smb2_testdir(tree, BASEDIR, &h);
4431 0 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4432 :
4433 0 : tree->session->transport->oplock.handler = torture_oplock_handler_hold;
4434 0 : tree->session->transport->oplock.private_data = tree;
4435 :
4436 : /* setup the files */
4437 0 : for (i=0;i<ARRAY_SIZE(hold_info);i++) {
4438 0 : union smb_open io;
4439 0 : char c = 1;
4440 :
4441 0 : ZERO_STRUCT(io.smb2);
4442 0 : io.generic.level = RAW_OPEN_SMB2;
4443 0 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4444 0 : io.smb2.in.alloc_size = 0;
4445 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4446 0 : io.smb2.in.share_access = hold_info[i].share_access;
4447 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4448 0 : io.smb2.in.create_options = 0;
4449 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4450 0 : io.smb2.in.security_flags = 0;
4451 0 : io.smb2.in.fname = hold_info[i].fname;
4452 0 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4453 0 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4454 :
4455 0 : torture_comment(tctx, "opening %s\n", hold_info[i].fname);
4456 :
4457 0 : status = smb2_create(tree, mem_ctx, &(io.smb2));
4458 0 : if (!NT_STATUS_IS_OK(status)) {
4459 0 : torture_comment(tctx, "Failed to open %s - %s\n",
4460 : hold_info[i].fname, nt_errstr(status));
4461 0 : return false;
4462 : }
4463 :
4464 0 : if (io.smb2.out.oplock_level != SMB2_OPLOCK_LEVEL_BATCH) {
4465 0 : torture_comment(tctx, "Oplock not granted for %s - "
4466 : "expected %d but got %d\n",
4467 : hold_info[i].fname,
4468 : SMB2_OPLOCK_LEVEL_BATCH,
4469 0 : io.smb2.out.oplock_level);
4470 0 : return false;
4471 : }
4472 0 : hold_info[i].handle = io.smb2.out.file.handle;
4473 :
4474 : /* make the file non-zero size */
4475 0 : status = smb2_util_write(tree, hold_info[i].handle, &c, 0, 1);
4476 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
4477 0 : torture_comment(tctx, "Failed to write to file\n");
4478 0 : return false;
4479 : }
4480 : }
4481 :
4482 0 : torture_comment(tctx, "Waiting for oplock events\n");
4483 0 : tevent_loop_wait(ev);
4484 0 : smb2_deltree(tree, BASEDIR);
4485 0 : talloc_free(mem_ctx);
4486 0 : return true;
4487 : }
4488 :
4489 :
4490 1 : static bool test_smb2_kernel_oplocks1(struct torture_context *tctx,
4491 : struct smb2_tree *tree)
4492 : {
4493 1 : const char *fname = "test_kernel_oplock1.dat";
4494 0 : NTSTATUS status;
4495 1 : bool ret = true;
4496 0 : struct smb2_create create;
4497 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4498 :
4499 1 : smb2_util_unlink(tree, fname);
4500 :
4501 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4502 1 : tree->session->transport->oplock.private_data = tree;
4503 1 : ZERO_STRUCT(break_info);
4504 :
4505 1 : ZERO_STRUCT(create);
4506 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4507 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4508 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4509 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4510 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4511 1 : create.in.fname = fname;
4512 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4513 :
4514 1 : status = smb2_create(tree, tctx, &create);
4515 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4516 1 : h1 = create.out.file.handle;
4517 :
4518 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4519 : "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4520 :
4521 1 : ZERO_STRUCT(create);
4522 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4523 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4524 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4525 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4526 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4527 1 : create.in.fname = fname;
4528 :
4529 1 : status = smb2_create(tree, tctx, &create);
4530 1 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done,
4531 : "Open didn't return NT_STATUS_SHARING_VIOLATION\n");
4532 1 : h2 = create.out.file.handle;
4533 :
4534 1 : torture_wait_for_oplock_break(tctx);
4535 1 : if (break_info.count != 0) {
4536 1 : torture_warning(tctx, "Open caused oplock break\n");
4537 : }
4538 :
4539 1 : smb2_util_close(tree, h1);
4540 1 : smb2_util_close(tree, h2);
4541 :
4542 1 : done:
4543 1 : if (!smb2_util_handle_empty(h1)) {
4544 1 : smb2_util_close(tree, h1);
4545 : }
4546 1 : if (!smb2_util_handle_empty(h2)) {
4547 0 : smb2_util_close(tree, h2);
4548 : }
4549 1 : smb2_util_unlink(tree, fname);
4550 1 : return ret;
4551 : }
4552 :
4553 1 : static bool test_smb2_kernel_oplocks2(struct torture_context *tctx,
4554 : struct smb2_tree *tree)
4555 : {
4556 1 : const char *fname = "test_kernel_oplock2.dat";
4557 1 : const char *sname = "test_kernel_oplock2.dat:foo";
4558 0 : NTSTATUS status;
4559 1 : bool ret = true;
4560 0 : struct smb2_create create;
4561 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4562 :
4563 1 : smb2_util_unlink(tree, fname);
4564 :
4565 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4566 1 : tree->session->transport->oplock.private_data = tree;
4567 1 : ZERO_STRUCT(break_info);
4568 :
4569 1 : ZERO_STRUCT(create);
4570 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4571 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4572 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4573 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4574 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4575 1 : create.in.fname = fname;
4576 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4577 :
4578 1 : status = smb2_create(tree, tctx, &create);
4579 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4580 1 : h1 = create.out.file.handle;
4581 :
4582 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4583 : "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4584 :
4585 1 : ZERO_STRUCT(create);
4586 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4587 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4588 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4589 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4590 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4591 1 : create.in.fname = sname;
4592 :
4593 1 : status = smb2_create(tree, tctx, &create);
4594 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4595 1 : h2 = create.out.file.handle;
4596 :
4597 1 : torture_wait_for_oplock_break(tctx);
4598 1 : if (break_info.count != 0) {
4599 0 : torture_warning(tctx, "Stream open caused oplock break\n");
4600 : }
4601 :
4602 1 : smb2_util_close(tree, h1);
4603 1 : smb2_util_close(tree, h2);
4604 :
4605 1 : done:
4606 1 : if (!smb2_util_handle_empty(h1)) {
4607 1 : smb2_util_close(tree, h1);
4608 : }
4609 1 : if (!smb2_util_handle_empty(h2)) {
4610 1 : smb2_util_close(tree, h2);
4611 : }
4612 1 : smb2_util_unlink(tree, fname);
4613 1 : return ret;
4614 : }
4615 :
4616 : /**
4617 : * 1. 1st client opens file with oplock
4618 : * 2. 2nd client opens file
4619 : *
4620 : * Verify 2 triggers an oplock break
4621 : **/
4622 1 : static bool test_smb2_kernel_oplocks3(struct torture_context *tctx,
4623 : struct smb2_tree *tree,
4624 : struct smb2_tree *tree2)
4625 : {
4626 1 : const char *fname = "test_kernel_oplock3.dat";
4627 0 : NTSTATUS status;
4628 1 : bool ret = true;
4629 0 : struct smb2_create create;
4630 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4631 :
4632 1 : smb2_util_unlink(tree, fname);
4633 1 : status = torture_smb2_testfile(tree, fname, &h1);
4634 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4635 : "Error creating testfile\n");
4636 1 : smb2_util_close(tree, h1);
4637 1 : ZERO_STRUCT(h1);
4638 :
4639 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4640 1 : tree->session->transport->oplock.private_data = tree;
4641 1 : ZERO_STRUCT(break_info);
4642 :
4643 : /* 1 */
4644 1 : ZERO_STRUCT(create);
4645 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4646 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4647 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4648 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4649 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4650 1 : create.in.fname = fname;
4651 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4652 :
4653 1 : status = smb2_create(tree, tctx, &create);
4654 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4655 1 : h1 = create.out.file.handle;
4656 :
4657 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4658 : "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4659 :
4660 : /* 2 */
4661 1 : ZERO_STRUCT(create);
4662 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4663 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4664 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4665 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4666 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4667 1 : create.in.fname = fname;
4668 :
4669 1 : status = smb2_create(tree2, tctx, &create);
4670 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4671 1 : h2 = create.out.file.handle;
4672 :
4673 1 : torture_wait_for_oplock_break(tctx);
4674 1 : torture_assert_goto(tctx, break_info.count == 1, ret, done, "Expected 1 oplock break\n");
4675 :
4676 1 : done:
4677 1 : if (!smb2_util_handle_empty(h1)) {
4678 1 : smb2_util_close(tree, h1);
4679 : }
4680 1 : if (!smb2_util_handle_empty(h2)) {
4681 1 : smb2_util_close(tree, h2);
4682 : }
4683 1 : smb2_util_unlink(tree, fname);
4684 1 : return ret;
4685 : }
4686 :
4687 : /**
4688 : * 1) create testfile with stream
4689 : * 2) open file r/w with batch oplock, sharing read/delete
4690 : * 3) open stream on file for reading
4691 : *
4692 : * Verify 3) doesn't trigger an oplock break
4693 : **/
4694 1 : static bool test_smb2_kernel_oplocks4(struct torture_context *tctx,
4695 : struct smb2_tree *tree)
4696 : {
4697 1 : const char *fname = "test_kernel_oplock4.dat";
4698 1 : const char *sname = "test_kernel_oplock4.dat:foo";
4699 0 : NTSTATUS status;
4700 1 : bool ret = true;
4701 0 : struct smb2_create create;
4702 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4703 :
4704 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4705 1 : tree->session->transport->oplock.private_data = tree;
4706 1 : ZERO_STRUCT(break_info);
4707 1 : smb2_util_unlink(tree, fname);
4708 :
4709 : /* 1 */
4710 1 : status = torture_smb2_testfile(tree, fname, &h1);
4711 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4712 : "Error creating testfile\n");
4713 1 : smb2_util_close(tree, h1);
4714 1 : ZERO_STRUCT(h1);
4715 :
4716 1 : ZERO_STRUCT(create);
4717 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4718 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4719 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4720 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4721 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4722 1 : create.in.fname = sname;
4723 :
4724 1 : status = smb2_create(tree, tctx, &create);
4725 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4726 1 : h1 = create.out.file.handle;
4727 1 : smb2_util_close(tree, h1);
4728 1 : ZERO_STRUCT(h1);
4729 :
4730 : /* 2 */
4731 1 : ZERO_STRUCT(create);
4732 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4733 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4734 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
4735 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4736 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4737 1 : create.in.fname = fname;
4738 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4739 :
4740 1 : status = smb2_create(tree, tctx, &create);
4741 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4742 1 : h1 = create.out.file.handle;
4743 :
4744 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_BATCH, ret, done,
4745 : "Oplock level is not SMB2_OPLOCK_LEVEL_BATCH\n");
4746 :
4747 1 : ZERO_STRUCT(create);
4748 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4749 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4750 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
4751 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4752 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4753 1 : create.in.fname = sname;
4754 :
4755 1 : status = smb2_create(tree, tctx, &create);
4756 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4757 1 : h2 = create.out.file.handle;
4758 :
4759 1 : torture_wait_for_oplock_break(tctx);
4760 1 : if (break_info.count != 0) {
4761 0 : torture_warning(tctx, "Stream open caused oplock break\n");
4762 : }
4763 :
4764 1 : done:
4765 1 : if (!smb2_util_handle_empty(h1)) {
4766 1 : smb2_util_close(tree, h1);
4767 : }
4768 1 : if (!smb2_util_handle_empty(h2)) {
4769 1 : smb2_util_close(tree, h2);
4770 : }
4771 1 : smb2_util_unlink(tree, fname);
4772 1 : return ret;
4773 : }
4774 :
4775 : /**
4776 : * 1) create testfile with stream
4777 : * 2) open stream r/w with batch oplock -> batch oplock granted
4778 : * 3) open stream r/o with batch oplock
4779 : *
4780 : * Verify 3) does trigger an oplock break
4781 : **/
4782 1 : static bool test_smb2_kernel_oplocks5(struct torture_context *tctx,
4783 : struct smb2_tree *tree)
4784 : {
4785 1 : const char *fname = "test_kernel_oplock4.dat";
4786 1 : const char *sname = "test_kernel_oplock4.dat:foo";
4787 0 : NTSTATUS status;
4788 1 : bool ret = true;
4789 0 : struct smb2_create create;
4790 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4791 :
4792 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4793 1 : tree->session->transport->oplock.private_data = tree;
4794 1 : ZERO_STRUCT(break_info);
4795 1 : smb2_util_unlink(tree, fname);
4796 :
4797 : /* 1 */
4798 1 : status = torture_smb2_testfile(tree, fname, &h1);
4799 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4800 : "Error creating testfile\n");
4801 1 : smb2_util_close(tree, h1);
4802 1 : ZERO_STRUCT(h1);
4803 :
4804 1 : ZERO_STRUCT(create);
4805 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4806 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4807 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4808 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4809 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4810 1 : create.in.fname = sname;
4811 :
4812 1 : status = smb2_create(tree, tctx, &create);
4813 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4814 1 : h1 = create.out.file.handle;
4815 1 : smb2_util_close(tree, h1);
4816 1 : ZERO_STRUCT(h1);
4817 :
4818 : /* 2 */
4819 1 : ZERO_STRUCT(create);
4820 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4821 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4822 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4823 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4824 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4825 1 : create.in.fname = sname;
4826 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4827 :
4828 1 : status = smb2_create(tree, tctx, &create);
4829 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4830 1 : h1 = create.out.file.handle;
4831 :
4832 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_BATCH, ret, done,
4833 : "Oplock level is not SMB2_OPLOCK_LEVEL_BATCH\n");
4834 :
4835 1 : ZERO_STRUCT(create);
4836 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4837 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4838 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4839 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4840 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4841 1 : create.in.fname = sname;
4842 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4843 :
4844 1 : status = smb2_create(tree, tctx, &create);
4845 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4846 1 : h2 = create.out.file.handle;
4847 :
4848 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_NONE, ret, done,
4849 : "Oplock level is not SMB2_OPLOCK_LEVEL_NONE\n");
4850 :
4851 1 : torture_wait_for_oplock_break(tctx);
4852 1 : if (break_info.count != 1) {
4853 0 : torture_warning(tctx, "Stream open didn't cause oplock break\n");
4854 : }
4855 :
4856 1 : done:
4857 1 : if (!smb2_util_handle_empty(h1)) {
4858 1 : smb2_util_close(tree, h1);
4859 : }
4860 1 : if (!smb2_util_handle_empty(h2)) {
4861 1 : smb2_util_close(tree, h2);
4862 : }
4863 1 : smb2_util_unlink(tree, fname);
4864 1 : return ret;
4865 : }
4866 :
4867 : /**
4868 : * 1) create testfile with stream
4869 : * 2) 1st client opens stream r/w with batch oplock -> batch oplock granted
4870 : * 3) 2nd client opens stream r/o with batch oplock
4871 : *
4872 : * Verify 3) does trigger an oplock break
4873 : **/
4874 1 : static bool test_smb2_kernel_oplocks6(struct torture_context *tctx,
4875 : struct smb2_tree *tree,
4876 : struct smb2_tree *tree2)
4877 : {
4878 1 : const char *fname = "test_kernel_oplock6.dat";
4879 1 : const char *sname = "test_kernel_oplock6.dat:foo";
4880 0 : NTSTATUS status;
4881 1 : bool ret = true;
4882 0 : struct smb2_create create;
4883 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4884 :
4885 1 : smb2_util_unlink(tree, fname);
4886 1 : status = torture_smb2_testfile(tree, fname, &h1);
4887 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4888 : "Error creating testfile\n");
4889 1 : smb2_util_close(tree, h1);
4890 1 : ZERO_STRUCT(h1);
4891 :
4892 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4893 1 : tree->session->transport->oplock.private_data = tree;
4894 1 : ZERO_STRUCT(break_info);
4895 :
4896 : /* 1 */
4897 1 : ZERO_STRUCT(create);
4898 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4899 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4900 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4901 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4902 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4903 1 : create.in.fname = sname;
4904 :
4905 1 : status = smb2_create(tree, tctx, &create);
4906 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4907 1 : h1 = create.out.file.handle;
4908 1 : smb2_util_close(tree, h1);
4909 1 : ZERO_STRUCT(h1);
4910 :
4911 : /* 2 */
4912 1 : ZERO_STRUCT(create);
4913 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4914 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4915 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4916 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4917 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4918 1 : create.in.fname = fname;
4919 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4920 :
4921 1 : status = smb2_create(tree, tctx, &create);
4922 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4923 1 : h1 = create.out.file.handle;
4924 :
4925 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4926 : "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4927 :
4928 : /* 3 */
4929 1 : ZERO_STRUCT(create);
4930 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4931 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4932 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4933 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4934 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4935 1 : create.in.fname = fname;
4936 :
4937 1 : status = smb2_create(tree2, tctx, &create);
4938 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4939 1 : h2 = create.out.file.handle;
4940 :
4941 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_NONE, ret, done,
4942 : "Oplock level is not SMB2_OPLOCK_LEVEL_NONE\n");
4943 :
4944 1 : torture_wait_for_oplock_break(tctx);
4945 1 : torture_assert_goto(tctx, break_info.count == 1, ret, done, "Expected 1 oplock break\n");
4946 :
4947 1 : done:
4948 1 : if (!smb2_util_handle_empty(h1)) {
4949 1 : smb2_util_close(tree, h1);
4950 : }
4951 1 : if (!smb2_util_handle_empty(h2)) {
4952 1 : smb2_util_close(tree, h2);
4953 : }
4954 1 : smb2_util_unlink(tree, fname);
4955 1 : return ret;
4956 : }
4957 :
4958 : /**
4959 : * Recreate regression test from bug:
4960 : *
4961 : * https://bugzilla.samba.org/show_bug.cgi?id=13058
4962 : *
4963 : * 1. smbd-1 opens the file and sets the oplock
4964 : * 2. smbd-2 tries to open the file. open() fails(EAGAIN) and open is deferred.
4965 : * 3. smbd-1 sends oplock break request to the client.
4966 : * 4. smbd-1 closes the file.
4967 : * 5. smbd-1 opens the file and sets the oplock.
4968 : * 6. smbd-2 calls defer_open_done(), and should re-break the oplock.
4969 : **/
4970 :
4971 1 : static bool test_smb2_kernel_oplocks7(struct torture_context *tctx,
4972 : struct smb2_tree *tree,
4973 : struct smb2_tree *tree2)
4974 : {
4975 1 : const char *fname = "test_kernel_oplock7.dat";
4976 0 : NTSTATUS status;
4977 1 : bool ret = true;
4978 0 : struct smb2_create create;
4979 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4980 0 : struct smb2_create create_2;
4981 0 : struct smb2_create io;
4982 0 : struct smb2_request *req;
4983 :
4984 1 : smb2_util_unlink(tree, fname);
4985 1 : status = torture_smb2_testfile(tree, fname, &h1);
4986 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4987 : "Error creating testfile\n");
4988 1 : smb2_util_close(tree, h1);
4989 1 : ZERO_STRUCT(h1);
4990 :
4991 : /* Close the open file on break. */
4992 1 : tree->session->transport->oplock.handler = torture_oplock_handler_close;
4993 1 : tree->session->transport->oplock.private_data = tree;
4994 1 : ZERO_STRUCT(break_info);
4995 :
4996 : /* 1 - open file with oplock */
4997 1 : ZERO_STRUCT(create);
4998 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4999 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
5000 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
5001 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
5002 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
5003 1 : create.in.fname = fname;
5004 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
5005 :
5006 1 : status = smb2_create(tree, tctx, &create);
5007 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5008 : "Error opening the file\n");
5009 1 : CHECK_VAL(create.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
5010 :
5011 : /* 2 - open file to break oplock */
5012 1 : ZERO_STRUCT(create_2);
5013 1 : create_2.in.desired_access = SEC_RIGHTS_FILE_ALL;
5014 1 : create_2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
5015 1 : create_2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
5016 1 : create_2.in.create_disposition = NTCREATEX_DISP_OPEN;
5017 1 : create_2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
5018 1 : create_2.in.fname = fname;
5019 1 : create_2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
5020 :
5021 : /* Open on tree2 - should cause a break on tree */
5022 1 : req = smb2_create_send(tree2, &create_2);
5023 1 : torture_assert(tctx, req != NULL, "smb2_create_send");
5024 :
5025 : /* The oplock break handler should close the file. */
5026 : /* Steps 3 & 4. */
5027 1 : torture_wait_for_oplock_break(tctx);
5028 :
5029 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
5030 :
5031 : /*
5032 : * 5 - re-open on tree. NB. There is a race here
5033 : * depending on which smbd goes first. We either get
5034 : * an oplock level of SMB2_OPLOCK_LEVEL_EXCLUSIVE if
5035 : * the close and re-open on tree is processed first, or
5036 : * SMB2_OPLOCK_LEVEL_NONE if the pending create on
5037 : * tree2 is processed first.
5038 : */
5039 1 : status = smb2_create(tree, tctx, &create);
5040 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5041 : "Error opening the file\n");
5042 :
5043 1 : h1 = create.out.file.handle;
5044 1 : if (create.out.oplock_level != SMB2_OPLOCK_LEVEL_EXCLUSIVE &&
5045 1 : create.out.oplock_level != SMB2_OPLOCK_LEVEL_NONE) {
5046 0 : torture_result(tctx,
5047 : TORTURE_FAIL,
5048 : "(%s): wrong value for oplock got 0x%x\n",
5049 : __location__,
5050 0 : (unsigned int)create.out.oplock_level);
5051 0 : ret = false;
5052 0 : goto done;
5053 :
5054 : }
5055 :
5056 : /* 6 - retrieve the second open. */
5057 1 : status = smb2_create_recv(req, tctx, &io);
5058 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5059 : "Error opening the file\n");
5060 1 : h2 = io.out.file.handle;
5061 1 : CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
5062 :
5063 1 : done:
5064 1 : if (!smb2_util_handle_empty(h1)) {
5065 1 : smb2_util_close(tree, h1);
5066 : }
5067 1 : if (!smb2_util_handle_empty(h2)) {
5068 1 : smb2_util_close(tree2, h2);
5069 : }
5070 1 : smb2_util_unlink(tree, fname);
5071 1 : return ret;
5072 : }
5073 :
5074 : #ifdef HAVE_KERNEL_OPLOCKS_LINUX
5075 :
5076 : #ifndef RT_SIGNAL_LEASE
5077 : #define RT_SIGNAL_LEASE (SIGRTMIN+1)
5078 : #endif
5079 :
5080 : static int got_break;
5081 :
5082 : /*
5083 : * Signal handler.
5084 : */
5085 :
5086 0 : static void got_rt_break(int sig)
5087 : {
5088 0 : got_break = 1;
5089 0 : }
5090 :
5091 : static int got_alarm;
5092 :
5093 : /*
5094 : * Signal handler.
5095 : */
5096 :
5097 0 : static void got_alarm_fn(int sig)
5098 : {
5099 0 : got_alarm = 1;
5100 0 : }
5101 :
5102 : /*
5103 : * Child process function.
5104 : */
5105 :
5106 0 : static int do_child_process(int pipefd, const char *name)
5107 : {
5108 0 : int ret = 0;
5109 0 : int fd = -1;
5110 0 : char c = 0;
5111 0 : struct sigaction act;
5112 0 : sigset_t set;
5113 0 : sigset_t empty_set;
5114 :
5115 : /* Block RT_SIGNAL_LEASE and SIGALRM. */
5116 0 : sigemptyset(&set);
5117 0 : sigemptyset(&empty_set);
5118 0 : sigaddset(&set, RT_SIGNAL_LEASE);
5119 0 : sigaddset(&set, SIGALRM);
5120 0 : ret = sigprocmask(SIG_SETMASK, &set, NULL);
5121 0 : if (ret == -1) {
5122 0 : return 11;
5123 : }
5124 :
5125 : /* Set up a signal handler for RT_SIGNAL_LEASE. */
5126 0 : ZERO_STRUCT(act);
5127 0 : act.sa_handler = got_rt_break;
5128 0 : ret = sigaction(RT_SIGNAL_LEASE, &act, NULL);
5129 0 : if (ret == -1) {
5130 0 : return 1;
5131 : }
5132 : /* Set up a signal handler for SIGALRM. */
5133 0 : ZERO_STRUCT(act);
5134 0 : act.sa_handler = got_alarm_fn;
5135 0 : ret = sigaction(SIGALRM, &act, NULL);
5136 0 : if (ret == -1) {
5137 0 : return 1;
5138 : }
5139 : /* Open the passed in file and get a kernel oplock. */
5140 0 : fd = open(name, O_RDWR, 0666);
5141 0 : if (fd == -1) {
5142 0 : return 2;
5143 : }
5144 :
5145 0 : ret = fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE);
5146 0 : if (ret == -1) {
5147 0 : close(fd);
5148 0 : return 3;
5149 : }
5150 :
5151 0 : ret = fcntl(fd, F_SETLEASE, F_WRLCK);
5152 0 : if (ret == -1) {
5153 0 : close(fd);
5154 0 : return 4;
5155 : }
5156 :
5157 : /* Tell the parent we're ready. */
5158 0 : ret = sys_write(pipefd, &c, 1);
5159 0 : if (ret != 1) {
5160 0 : close(fd);
5161 0 : return 5;
5162 : }
5163 :
5164 : /* Ensure the pause doesn't hang forever. */
5165 0 : alarm(5);
5166 :
5167 : /* Wait for RT_SIGNAL_LEASE or SIGALRM. */
5168 0 : ret = sigsuspend(&empty_set);
5169 0 : if (ret != -1 || errno != EINTR) {
5170 0 : close(fd);
5171 0 : return 6;
5172 : }
5173 :
5174 0 : if (got_alarm == 1) {
5175 0 : close(fd);
5176 0 : return 10;
5177 : }
5178 :
5179 0 : if (got_break != 1) {
5180 0 : close(fd);
5181 0 : return 7;
5182 : }
5183 :
5184 : /* Cancel any pending alarm. */
5185 0 : alarm(0);
5186 :
5187 : /* Force the server to wait for 3 seconds. */
5188 0 : sleep(3);
5189 :
5190 : /* Remove our lease. */
5191 0 : ret = fcntl(fd, F_SETLEASE, F_UNLCK);
5192 0 : if (ret == -1) {
5193 0 : close(fd);
5194 0 : return 8;
5195 : }
5196 :
5197 0 : ret = close(fd);
5198 0 : if (ret == -1) {
5199 0 : return 9;
5200 : }
5201 :
5202 : /* All is well. */
5203 0 : return 0;
5204 : }
5205 :
5206 1 : static bool wait_for_child_oplock(struct torture_context *tctx,
5207 : const char *localdir,
5208 : const char *fname)
5209 : {
5210 0 : int fds[2];
5211 0 : int ret;
5212 0 : pid_t pid;
5213 1 : char *name = talloc_asprintf(tctx,
5214 : "%s/%s",
5215 : localdir,
5216 : fname);
5217 :
5218 1 : torture_assert(tctx, name != NULL, "talloc failed");
5219 :
5220 1 : ret = pipe(fds);
5221 1 : torture_assert(tctx, ret != -1, "pipe failed");
5222 :
5223 1 : pid = fork();
5224 1 : torture_assert(tctx, pid != (pid_t)-1, "fork failed");
5225 :
5226 1 : if (pid != (pid_t)0) {
5227 0 : char c;
5228 : /* Parent. */
5229 1 : TALLOC_FREE(name);
5230 1 : close(fds[1]);
5231 1 : ret = sys_read(fds[0], &c, 1);
5232 1 : torture_assert(tctx, ret == 1, "read failed");
5233 1 : return true;
5234 : }
5235 :
5236 : /* Child process. */
5237 0 : close(fds[0]);
5238 0 : ret = do_child_process(fds[1], name);
5239 0 : _exit(ret);
5240 : /* Notreached. */
5241 : }
5242 : #else
5243 : static bool wait_for_child_oplock(struct torture_context *tctx,
5244 : const char *localdir,
5245 : const char *fname)
5246 : {
5247 : return false;
5248 : }
5249 : #endif
5250 :
5251 1 : static void child_sig_term_handler(struct tevent_context *ev,
5252 : struct tevent_signal *se,
5253 : int signum,
5254 : int count,
5255 : void *siginfo,
5256 : void *private_data)
5257 : {
5258 1 : int *pstatus = (int *)private_data;
5259 1 : int status = 0;
5260 :
5261 1 : wait(&status);
5262 1 : if (WIFEXITED(status)) {
5263 1 : *pstatus = WEXITSTATUS(status);
5264 : } else {
5265 0 : *pstatus = status;
5266 : }
5267 1 : }
5268 :
5269 : /*
5270 : * Deal with a non-smbd process holding a kernel oplock.
5271 : */
5272 :
5273 1 : static bool test_smb2_kernel_oplocks8(struct torture_context *tctx,
5274 : struct smb2_tree *tree)
5275 : {
5276 1 : const char *fname = "test_kernel_oplock8.dat";
5277 1 : const char *fname1 = "tmp_test_kernel_oplock8.dat";
5278 0 : NTSTATUS status;
5279 1 : bool ret = true;
5280 0 : struct smb2_create io;
5281 1 : struct smb2_request *req = NULL;
5282 1 : struct smb2_handle h1 = {{0}};
5283 1 : struct smb2_handle h2 = {{0}};
5284 1 : const char *localdir = torture_setting_string(tctx, "localdir", NULL);
5285 1 : struct tevent_signal *se = NULL;
5286 1 : int child_exit_code = -1;
5287 0 : time_t start;
5288 0 : time_t end;
5289 :
5290 : #ifndef HAVE_KERNEL_OPLOCKS_LINUX
5291 : torture_skip(tctx, "Need kernel oplocks for test");
5292 : #endif
5293 :
5294 1 : if (localdir == NULL) {
5295 0 : torture_skip(tctx, "Need localdir for test");
5296 : }
5297 :
5298 1 : smb2_util_unlink(tree, fname);
5299 1 : smb2_util_unlink(tree, fname1);
5300 1 : status = torture_smb2_testfile(tree, fname, &h1);
5301 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5302 : "Error creating testfile\n");
5303 1 : smb2_util_close(tree, h1);
5304 1 : ZERO_STRUCT(h1);
5305 :
5306 1 : se = tevent_add_signal(tctx->ev,
5307 : tctx,
5308 : SIGCHLD,
5309 : 0,
5310 : child_sig_term_handler,
5311 : &child_exit_code);
5312 1 : torture_assert(tctx, se != NULL, "tevent_add_signal failed\n");
5313 :
5314 : /* Take the oplock locally in a sub-process. */
5315 1 : ret = wait_for_child_oplock(tctx, localdir, fname);
5316 1 : torture_assert_goto(tctx, ret, ret, done,
5317 : "Wait for child process failed.\n");
5318 :
5319 : /*
5320 : * Now try and open. This should block for 3 seconds.
5321 : * while the child process is still alive.
5322 : */
5323 :
5324 1 : ZERO_STRUCT(io);
5325 1 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
5326 1 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
5327 1 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
5328 1 : io.in.share_access =
5329 : NTCREATEX_SHARE_ACCESS_DELETE|
5330 : NTCREATEX_SHARE_ACCESS_READ|
5331 : NTCREATEX_SHARE_ACCESS_WRITE;
5332 1 : io.in.create_options = 0;
5333 1 : io.in.fname = fname;
5334 :
5335 1 : req = smb2_create_send(tree, &io);
5336 1 : torture_assert_goto(tctx, req != NULL,
5337 : ret, done, "smb2_create_send");
5338 :
5339 : /* Ensure while the open is blocked the smbd is
5340 : still serving other requests. */
5341 1 : io.in.fname = fname1;
5342 1 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
5343 :
5344 : /* Time the start -> end of the request. */
5345 1 : start = time(NULL);
5346 1 : status = smb2_create(tree, tctx, &io);
5347 1 : end = time(NULL);
5348 :
5349 : /* Should succeed. */
5350 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5351 : "Error opening the second file\n");
5352 1 : h1 = io.out.file.handle;
5353 :
5354 : /* in less than 2 seconds. Otherwise the server blocks. */
5355 1 : torture_assert_goto(tctx, end - start < 2,
5356 : ret, done, "server was blocked !");
5357 :
5358 : /* Pick up the return for the initial blocking open. */
5359 1 : status = smb2_create_recv(req, tctx, &io);
5360 :
5361 : /* Which should also have succeeded. */
5362 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5363 : "Error opening the file\n");
5364 1 : h2 = io.out.file.handle;
5365 :
5366 : /* Wait for the exit code from the child. */
5367 1 : while (child_exit_code == -1) {
5368 0 : int rval = tevent_loop_once(tctx->ev);
5369 0 : torture_assert_goto(tctx, rval == 0, ret,
5370 : done, "tevent_loop_once error\n");
5371 : }
5372 :
5373 1 : torture_assert_int_equal_goto(tctx, child_exit_code, 0,
5374 : ret, done, "Bad child exit code");
5375 :
5376 1 : done:
5377 1 : if (!smb2_util_handle_empty(h1)) {
5378 1 : smb2_util_close(tree, h1);
5379 : }
5380 1 : if (!smb2_util_handle_empty(h2)) {
5381 1 : smb2_util_close(tree, h2);
5382 : }
5383 1 : smb2_util_unlink(tree, fname);
5384 1 : smb2_util_unlink(tree, fname1);
5385 1 : return ret;
5386 : }
5387 :
5388 2354 : struct torture_suite *torture_smb2_kernel_oplocks_init(TALLOC_CTX *ctx)
5389 : {
5390 125 : struct torture_suite *suite =
5391 2354 : torture_suite_create(ctx, "kernel-oplocks");
5392 :
5393 2354 : torture_suite_add_1smb2_test(suite, "kernel_oplocks1", test_smb2_kernel_oplocks1);
5394 2354 : torture_suite_add_1smb2_test(suite, "kernel_oplocks2", test_smb2_kernel_oplocks2);
5395 2354 : torture_suite_add_2smb2_test(suite, "kernel_oplocks3", test_smb2_kernel_oplocks3);
5396 2354 : torture_suite_add_1smb2_test(suite, "kernel_oplocks4", test_smb2_kernel_oplocks4);
5397 2354 : torture_suite_add_1smb2_test(suite, "kernel_oplocks5", test_smb2_kernel_oplocks5);
5398 2354 : torture_suite_add_2smb2_test(suite, "kernel_oplocks6", test_smb2_kernel_oplocks6);
5399 2354 : torture_suite_add_2smb2_test(suite, "kernel_oplocks7", test_smb2_kernel_oplocks7);
5400 2354 : torture_suite_add_1smb2_test(suite, "kernel_oplocks8", test_smb2_kernel_oplocks8);
5401 :
5402 2354 : suite->description = talloc_strdup(suite, "SMB2-KERNEL-OPLOCK tests");
5403 :
5404 2354 : return suite;
5405 : }
|