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 120 : static void torture_oplock_break_callback(struct smb2_request *req)
80 : {
81 : NTSTATUS status;
82 : struct smb2_break br;
83 :
84 120 : ZERO_STRUCT(br);
85 120 : status = smb2_break_recv(req, &break_info.br);
86 120 : if (!NT_STATUS_IS_OK(status)) {
87 2 : break_info.failures++;
88 2 : break_info.failure_status = status;
89 : }
90 :
91 120 : 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 101 : 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 101 : struct smb2_tree *tree = private_data;
102 : const char *name;
103 : struct smb2_request *req;
104 101 : ZERO_STRUCT(break_info.br);
105 :
106 101 : break_info.handle = *handle;
107 101 : break_info.level = level;
108 101 : break_info.count++;
109 :
110 101 : switch (level) {
111 83 : case SMB2_OPLOCK_LEVEL_II:
112 83 : name = "level II";
113 83 : 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 101 : printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
122 :
123 101 : break_info.br.in.file.handle = *handle;
124 101 : break_info.br.in.oplock_level = level;
125 101 : break_info.br.in.reserved = 0;
126 101 : break_info.br.in.reserved2 = 0;
127 :
128 101 : req = smb2_break_send(tree, &break_info.br);
129 101 : req->async.fn = torture_oplock_break_callback;
130 101 : req->async.private_data = NULL;
131 101 : 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 : 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 : const char *name;
195 : 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 : struct smb2_close io;
245 7 : struct smb2_tree *tree = private_data;
246 : 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 : 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 : 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 : NTSTATUS status;
316 3 : bool ret = true;
317 : union smb_open io;
318 : struct smb2_handle h1;
319 : 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 : NTSTATUS status;
384 3 : bool ret = true;
385 : union smb_open io;
386 : 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 : NTSTATUS status;
461 3 : bool ret = true;
462 : union smb_open io;
463 : union smb_setfileinfo sfi;
464 : 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 : NTSTATUS status;
531 3 : bool ret = true;
532 : union smb_open io;
533 : 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 : NTSTATUS status;
600 3 : bool ret = true;
601 : union smb_open io;
602 : 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 dispostion 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 : NTSTATUS status;
679 3 : bool ret = true;
680 : union smb_open io;
681 : union smb_setfileinfo sinfo;
682 : struct smb2_close closeio;
683 : 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 : NTSTATUS status;
787 3 : bool ret = true;
788 : union smb_open io;
789 : struct smb2_handle h1, h2;
790 : int i;
791 :
792 : 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 : NTSTATUS status;
868 3 : bool ret = true;
869 : union smb_open io;
870 : 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 : NTSTATUS status;
954 3 : bool ret = true;
955 : union smb_open io;
956 3 : char c = 0;
957 : 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 : NTSTATUS status;
1035 3 : bool ret = true;
1036 : union smb_open io;
1037 : 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 : NTSTATUS status;
1099 3 : bool ret = true;
1100 : union smb_open io;
1101 : struct smb2_read r;
1102 : 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 : NTSTATUS status;
1164 3 : bool ret = true;
1165 : union smb_open io;
1166 : 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 : NTSTATUS status;
1228 3 : bool ret = true;
1229 : union smb_open io;
1230 : 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 : NTSTATUS status;
1317 3 : bool ret = true;
1318 : union smb_open io;
1319 : 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 : NTSTATUS status;
1389 3 : bool ret = true;
1390 : union smb_open io;
1391 : 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 : NTSTATUS status;
1458 3 : bool ret = true;
1459 : union smb_open io;
1460 : 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 : NTSTATUS status;
1571 3 : bool ret = true;
1572 : union smb_open io;
1573 : 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 : NTSTATUS status;
1698 3 : bool ret = true;
1699 : union smb_open io;
1700 : 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 : struct smb2_write wr;
1764 : 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 : NTSTATUS status;
1796 3 : bool ret = true;
1797 : union smb_open io;
1798 : union smb_setfileinfo sfi;
1799 : 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 : NTSTATUS status;
1876 3 : bool ret = true;
1877 : union smb_open io;
1878 : union smb_setfileinfo sfi;
1879 : 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 : NTSTATUS status;
1957 3 : bool ret = true;
1958 : union smb_open io;
1959 : 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 dispostion 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 : NTSTATUS status;
2039 3 : bool ret = true;
2040 : union smb_open io;
2041 : 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 dispostion 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 : NTSTATUS status;
2118 3 : bool ret = true;
2119 : union smb_open io;
2120 : union smb_fileinfo qfi;
2121 : 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 : NTSTATUS status;
2190 3 : bool ret = true;
2191 : union smb_open io;
2192 : 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 dispostion 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 : NTSTATUS status;
2298 3 : bool ret = true;
2299 : union smb_open io;
2300 : union smb_fileinfo qfi;
2301 : union smb_setfileinfo sfi;
2302 : 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 : NTSTATUS status;
2380 3 : bool ret = true;
2381 : union smb_open io;
2382 : union smb_fileinfo qfi;
2383 : union smb_setfileinfo sfi;
2384 : 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 : NTSTATUS status;
2511 3 : bool ret = true;
2512 : union smb_open io;
2513 : 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 : NTSTATUS status;
2571 3 : bool ret = true;
2572 : union smb_open io;
2573 : struct smb2_handle h, h1, h2;
2574 : struct timeval tv;
2575 3 : int timeout = torture_setting_int(tctx, "oplocktimeout", 35);
2576 : 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 : NTSTATUS status;
2650 3 : bool ret = true;
2651 : union smb_open io;
2652 3 : struct smb2_handle h, h1, h2 = {{0}};
2653 : 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 : 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 4 : 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 : NTSTATUS status;
2745 3 : bool ret = true;
2746 : union smb_open io;
2747 : 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 : NTSTATUS status;
2838 3 : bool ret = true;
2839 : union smb_open io;
2840 : 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 : NTSTATUS status;
2920 3 : bool ret = true;
2921 : union smb_open io;
2922 : 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 : torture_comment(tctx, "changing the file attribute info should trigger "
2961 : "a break and a violation\n");
2962 :
2963 3 : status = smb2_util_setatr(tree1, fname, FILE_ATTRIBUTE_HIDDEN);
2964 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2965 : "Incorrect status");
2966 :
2967 3 : torture_wait_for_oplock_break(tctx);
2968 3 : CHECK_VAL(break_info.count, 1);
2969 :
2970 3 : smb2_util_close(tree1, h1);
2971 3 : smb2_util_close(tree1, h);
2972 :
2973 3 : smb2_deltree(tree1, fname);
2974 3 : return ret;
2975 : }
2976 :
2977 3 : static bool test_smb2_oplock_batch26(struct torture_context *tctx,
2978 : struct smb2_tree *tree1)
2979 : {
2980 :
2981 : NTSTATUS status;
2982 3 : bool ret = true;
2983 : union smb_open io;
2984 : struct smb2_handle h, h1, h2, h3;
2985 3 : const char *fname_base = BASEDIR "\\test_oplock.txt";
2986 3 : const char *stream = "Stream One:$DATA";
2987 : const char *fname_stream;
2988 :
2989 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
2990 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2991 :
2992 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
2993 3 : tree1->session->transport->oplock.private_data = tree1;
2994 :
2995 3 : fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
2996 :
2997 : /*
2998 : base ntcreatex parms
2999 : */
3000 3 : ZERO_STRUCT(io.smb2);
3001 3 : io.generic.level = RAW_OPEN_SMB2;
3002 3 : io.smb2.in.desired_access = 0x120089;
3003 3 : io.smb2.in.alloc_size = 0;
3004 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3005 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE |
3006 : NTCREATEX_SHARE_ACCESS_WRITE;
3007 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3008 3 : io.smb2.in.create_options = 0;
3009 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3010 3 : io.smb2.in.security_flags = 0;
3011 3 : io.smb2.in.fname = fname_base;
3012 :
3013 : /*
3014 : Open base file with a batch oplock.
3015 : */
3016 3 : torture_comment(tctx, "Open the base file with batch oplock\n");
3017 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3018 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3019 :
3020 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3021 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening base file");
3022 3 : h1 = io.smb2.out.file.handle;
3023 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3024 :
3025 3 : torture_comment(tctx, "Got batch oplock on base file\n");
3026 :
3027 3 : torture_comment(tctx, "Opening stream file with batch oplock..\n");
3028 :
3029 3 : io.smb2.in.fname = fname_stream;
3030 :
3031 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3032 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening stream file");
3033 3 : h2 = io.smb2.out.file.handle;
3034 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3035 :
3036 3 : torture_comment(tctx, "Got batch oplock on stream file\n");
3037 :
3038 3 : torture_comment(tctx, "Open base file again with batch oplock\n");
3039 :
3040 3 : io.smb2.in.fname = fname_base;
3041 :
3042 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3043 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3044 3 : h3 = io.smb2.out.file.handle;
3045 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3046 :
3047 3 : smb2_util_close(tree1, h1);
3048 3 : smb2_util_close(tree1, h2);
3049 3 : smb2_util_close(tree1, h3);
3050 3 : smb2_util_close(tree1, h);
3051 3 : smb2_deltree(tree1, BASEDIR);
3052 3 : return ret;
3053 :
3054 : }
3055 :
3056 : /* Test how oplocks work on streams. */
3057 3 : static bool test_raw_oplock_stream1(struct torture_context *tctx,
3058 : struct smb2_tree *tree1,
3059 : struct smb2_tree *tree2)
3060 : {
3061 : NTSTATUS status;
3062 : union smb_open io;
3063 3 : const char *fname_base = BASEDIR "\\test_stream1.txt";
3064 : const char *fname_stream, *fname_default_stream;
3065 3 : const char *default_stream = "::$DATA";
3066 3 : const char *stream = "Stream One:$DATA";
3067 3 : bool ret = true;
3068 : struct smb2_handle h, h_base, h_stream;
3069 : int i;
3070 :
3071 : #define NSTREAM_OPLOCK_RESULTS 8
3072 : struct {
3073 : const char **fname;
3074 : bool open_base_file;
3075 : uint32_t oplock_req;
3076 : uint32_t oplock_granted;
3077 3 : } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
3078 : /* Request oplock on stream without the base file open. */
3079 : {&fname_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3080 : {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3081 : {&fname_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3082 : {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3083 :
3084 : /* Request oplock on stream with the base file open. */
3085 : {&fname_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
3086 : {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_II},
3087 : {&fname_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
3088 : {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_II},
3089 : };
3090 :
3091 3 : fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
3092 3 : fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
3093 : default_stream);
3094 :
3095 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
3096 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3097 :
3098 : /* Initialize handles to "closed". Using -1 in the first 64-bytes
3099 : * as the sentry for this */
3100 3 : h_stream.data[0] = -1;
3101 :
3102 : /* cleanup */
3103 3 : smb2_util_unlink(tree1, fname_base);
3104 :
3105 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
3106 3 : tree1->session->transport->oplock.private_data = tree1;
3107 :
3108 3 : tree2->session->transport->oplock.handler = torture_oplock_handler;
3109 3 : tree2->session->transport->oplock.private_data = tree2;
3110 :
3111 : /* Setup generic open parameters. */
3112 3 : ZERO_STRUCT(io.smb2);
3113 3 : io.generic.level = RAW_OPEN_SMB2;
3114 3 : io.smb2.in.desired_access = (SEC_FILE_READ_DATA |
3115 : SEC_FILE_WRITE_DATA |
3116 : SEC_FILE_APPEND_DATA |
3117 : SEC_STD_READ_CONTROL);
3118 3 : io.smb2.in.alloc_size = 0;
3119 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3120 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3121 : NTCREATEX_SHARE_ACCESS_WRITE;
3122 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3123 3 : io.smb2.in.create_options = 0;
3124 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3125 3 : io.smb2.in.security_flags = 0;
3126 :
3127 : /* Create the file with a stream */
3128 3 : io.smb2.in.fname = fname_stream;
3129 3 : io.smb2.in.create_flags = 0;
3130 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
3131 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3132 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating file");
3133 3 : smb2_util_close(tree1, io.smb2.out.file.handle);
3134 :
3135 : /* Change the disposition to open now that the file has been created. */
3136 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
3137 :
3138 : /* Try some permutations of taking oplocks on streams. */
3139 27 : for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
3140 24 : const char *fname = *stream_oplock_results[i].fname;
3141 24 : bool open_base_file = stream_oplock_results[i].open_base_file;
3142 24 : uint32_t oplock_req = stream_oplock_results[i].oplock_req;
3143 24 : uint32_t oplock_granted =
3144 : stream_oplock_results[i].oplock_granted;
3145 :
3146 24 : if (open_base_file) {
3147 12 : torture_comment(tctx, "Opening base file: %s with "
3148 : "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3149 12 : io.smb2.in.fname = fname_base;
3150 12 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3151 12 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3152 12 : status = smb2_create(tree2, tctx, &(io.smb2));
3153 12 : torture_assert_ntstatus_ok(tctx, status,
3154 : "Error opening file");
3155 12 : CHECK_VAL(io.smb2.out.oplock_level,
3156 : SMB2_OPLOCK_LEVEL_BATCH);
3157 12 : h_base = io.smb2.out.file.handle;
3158 : }
3159 :
3160 24 : torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
3161 : fname, oplock_req);
3162 24 : io.smb2.in.fname = fname;
3163 24 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3164 24 : io.smb2.in.oplock_level = oplock_req;
3165 :
3166 : /* Do the open with the desired oplock on the stream. */
3167 24 : status = smb2_create(tree1, tctx, &(io.smb2));
3168 24 : torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3169 24 : CHECK_VAL(io.smb2.out.oplock_level, oplock_granted);
3170 24 : smb2_util_close(tree1, io.smb2.out.file.handle);
3171 :
3172 : /* Cleanup the base file if it was opened. */
3173 24 : if (open_base_file)
3174 12 : smb2_util_close(tree2, h_base);
3175 : }
3176 :
3177 : /* Open the stream with an exclusive oplock. */
3178 3 : torture_comment(tctx, "Opening stream: %s with %d\n",
3179 : fname_stream, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3180 3 : io.smb2.in.fname = fname_stream;
3181 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3182 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3183 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3184 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3185 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3186 3 : h_stream = io.smb2.out.file.handle;
3187 :
3188 : /* Open the base file and see if it contends. */
3189 3 : ZERO_STRUCT(break_info);
3190 3 : torture_comment(tctx, "Opening base file: %s with %d\n",
3191 : fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3192 3 : io.smb2.in.fname = fname_base;
3193 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3194 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3195 3 : status = smb2_create(tree2, tctx, &(io.smb2));
3196 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3197 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3198 3 : smb2_util_close(tree2, io.smb2.out.file.handle);
3199 :
3200 3 : torture_wait_for_oplock_break(tctx);
3201 3 : CHECK_VAL(break_info.count, 0);
3202 3 : CHECK_VAL(break_info.failures, 0);
3203 :
3204 : /* Open the stream again to see if it contends. */
3205 3 : ZERO_STRUCT(break_info);
3206 3 : torture_comment(tctx, "Opening stream again: %s with "
3207 : "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
3208 3 : io.smb2.in.fname = fname_stream;
3209 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3210 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3211 3 : status = smb2_create(tree2, tctx, &(io.smb2));
3212 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening file");
3213 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3214 3 : smb2_util_close(tree2, io.smb2.out.file.handle);
3215 :
3216 3 : torture_wait_for_oplock_break(tctx);
3217 3 : CHECK_VAL(break_info.count, 1);
3218 3 : CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
3219 3 : CHECK_VAL(break_info.failures, 0);
3220 :
3221 : /* Close the stream. */
3222 3 : if (h_stream.data[0] != -1) {
3223 3 : smb2_util_close(tree1, h_stream);
3224 : }
3225 :
3226 3 : smb2_util_close(tree1, h);
3227 :
3228 3 : smb2_deltree(tree1, BASEDIR);
3229 3 : return ret;
3230 : }
3231 :
3232 3 : static bool test_smb2_oplock_doc(struct torture_context *tctx, struct smb2_tree *tree,
3233 : struct smb2_tree *tree2)
3234 : {
3235 3 : const char *fname = BASEDIR "\\test_oplock_doc.dat";
3236 : NTSTATUS status;
3237 3 : bool ret = true;
3238 : union smb_open io;
3239 : struct smb2_handle h, h1;
3240 : union smb_setfileinfo sfinfo;
3241 :
3242 3 : status = torture_smb2_testdir(tree, BASEDIR, &h);
3243 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3244 3 : smb2_util_close(tree, h);
3245 :
3246 : /* cleanup */
3247 3 : smb2_util_unlink(tree, fname);
3248 3 : tree->session->transport->oplock.handler = torture_oplock_handler;
3249 3 : tree->session->transport->oplock.private_data = tree;
3250 :
3251 : /*
3252 : base ntcreatex parms
3253 : */
3254 3 : ZERO_STRUCT(io.smb2);
3255 3 : io.generic.level = RAW_OPEN_SMB2;
3256 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3257 3 : io.smb2.in.alloc_size = 0;
3258 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3259 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
3260 : NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
3261 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3262 3 : io.smb2.in.create_options = 0;
3263 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3264 3 : io.smb2.in.security_flags = 0;
3265 3 : io.smb2.in.fname = fname;
3266 :
3267 3 : torture_comment(tctx, "open a file with a batch oplock\n");
3268 3 : ZERO_STRUCT(break_info);
3269 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3270 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3271 :
3272 3 : status = smb2_create(tree, tctx, &(io.smb2));
3273 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3274 3 : h1 = io.smb2.out.file.handle;
3275 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3276 :
3277 3 : torture_comment(tctx, "Set delete on close\n");
3278 3 : ZERO_STRUCT(sfinfo);
3279 3 : sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
3280 3 : sfinfo.generic.in.file.handle = h1;
3281 3 : sfinfo.disposition_info.in.delete_on_close = 1;
3282 3 : status = smb2_setinfo_file(tree, &sfinfo);
3283 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3284 :
3285 3 : torture_comment(tctx, "2nd open should not break and get "
3286 : "DELETE_PENDING\n");
3287 3 : ZERO_STRUCT(break_info);
3288 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
3289 3 : io.smb2.in.create_options = 0;
3290 3 : io.smb2.in.desired_access = SEC_FILE_READ_DATA;
3291 3 : status = smb2_create(tree2, tctx, &io.smb2);
3292 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DELETE_PENDING,
3293 : "Incorrect status");
3294 3 : CHECK_VAL(break_info.count, 0);
3295 :
3296 3 : smb2_util_close(tree, h1);
3297 :
3298 3 : smb2_util_unlink(tree, fname);
3299 3 : smb2_deltree(tree, BASEDIR);
3300 3 : return ret;
3301 : }
3302 :
3303 : /* Open a file with a batch oplock, then open it again from a second client
3304 : * requesting no oplock. Having two open file handles should break our own
3305 : * oplock during BRL acquisition.
3306 : */
3307 3 : static bool test_smb2_oplock_brl1(struct torture_context *tctx,
3308 : struct smb2_tree *tree1,
3309 : struct smb2_tree *tree2)
3310 : {
3311 3 : const char *fname = BASEDIR "\\test_batch_brl.dat";
3312 : /*int fname, f;*/
3313 3 : bool ret = true;
3314 : uint8_t buf[1000];
3315 : union smb_open io;
3316 : NTSTATUS status;
3317 : struct smb2_lock lck;
3318 : struct smb2_lock_element lock[1];
3319 : struct smb2_handle h, h1, h2;
3320 :
3321 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
3322 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3323 :
3324 : /* cleanup */
3325 3 : smb2_util_unlink(tree1, fname);
3326 :
3327 3 : tree1->session->transport->oplock.handler =
3328 : torture_oplock_handler_two_notifications;
3329 3 : tree1->session->transport->oplock.private_data = tree1;
3330 :
3331 : /*
3332 : base ntcreatex parms
3333 : */
3334 3 : ZERO_STRUCT(io.smb2);
3335 3 : io.generic.level = RAW_OPEN_SMB2;
3336 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3337 : SEC_RIGHTS_FILE_WRITE;
3338 3 : io.smb2.in.alloc_size = 0;
3339 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3340 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3341 : NTCREATEX_SHARE_ACCESS_WRITE;
3342 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3343 3 : io.smb2.in.create_options = 0;
3344 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3345 3 : io.smb2.in.security_flags = 0;
3346 3 : io.smb2.in.fname = fname;
3347 :
3348 : /*
3349 : with a batch oplock we get a break
3350 : */
3351 3 : torture_comment(tctx, "open with batch oplock\n");
3352 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3353 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3354 :
3355 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3356 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3357 3 : h1 = io.smb2.out.file.handle;
3358 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3359 :
3360 : /* create a file with bogus data */
3361 3 : memset(buf, 0, sizeof(buf));
3362 :
3363 3 : status = smb2_util_write(tree1, h1,buf, 0, sizeof(buf));
3364 3 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3365 0 : torture_comment(tctx, "Failed to create file\n");
3366 0 : ret = false;
3367 0 : goto done;
3368 : }
3369 :
3370 3 : torture_comment(tctx, "a 2nd open should give a break\n");
3371 3 : ZERO_STRUCT(break_info);
3372 :
3373 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3374 3 : io.smb2.in.oplock_level = 0;
3375 3 : status = smb2_create(tree2, tctx, &(io.smb2));
3376 3 : h2 = io.smb2.out.file.handle;
3377 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3378 :
3379 3 : torture_wait_for_oplock_break(tctx);
3380 3 : CHECK_VAL(break_info.count, 1);
3381 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3382 3 : CHECK_VAL(break_info.failures, 0);
3383 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3384 :
3385 3 : ZERO_STRUCT(break_info);
3386 :
3387 3 : torture_comment(tctx, "a self BRL acquisition should break to none\n");
3388 :
3389 3 : ZERO_STRUCT(lock);
3390 :
3391 3 : lock[0].offset = 0;
3392 3 : lock[0].length = 4;
3393 3 : lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3394 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3395 :
3396 3 : ZERO_STRUCT(lck);
3397 3 : lck.in.file.handle = h1;
3398 3 : lck.in.locks = &lock[0];
3399 3 : lck.in.lock_count = 1;
3400 3 : status = smb2_lock(tree1, &lck);
3401 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3402 :
3403 3 : torture_wait_for_oplock_break(tctx);
3404 3 : CHECK_VAL(break_info.count, 1);
3405 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3406 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3407 3 : CHECK_VAL(break_info.failures, 0);
3408 :
3409 : /* expect no oplock break */
3410 3 : ZERO_STRUCT(break_info);
3411 3 : lock[0].offset = 2;
3412 3 : status = smb2_lock(tree1, &lck);
3413 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3414 : "Incorrect status");
3415 :
3416 3 : torture_wait_for_oplock_break(tctx);
3417 3 : CHECK_VAL(break_info.count, 0);
3418 3 : CHECK_VAL(break_info.level, 0);
3419 3 : CHECK_VAL(break_info.failures, 0);
3420 :
3421 3 : smb2_util_close(tree1, h1);
3422 3 : smb2_util_close(tree2, h2);
3423 3 : smb2_util_close(tree1, h);
3424 :
3425 3 : done:
3426 3 : smb2_deltree(tree1, BASEDIR);
3427 3 : return ret;
3428 :
3429 : }
3430 :
3431 : /* Open a file with a batch oplock on one tree and then acquire a brl.
3432 : * We should not contend our own oplock.
3433 : */
3434 3 : static bool test_smb2_oplock_brl2(struct torture_context *tctx, struct smb2_tree *tree1)
3435 : {
3436 3 : const char *fname = BASEDIR "\\test_batch_brl.dat";
3437 : /*int fname, f;*/
3438 3 : bool ret = true;
3439 : uint8_t buf[1000];
3440 : union smb_open io;
3441 : NTSTATUS status;
3442 : struct smb2_handle h, h1;
3443 : struct smb2_lock lck;
3444 : struct smb2_lock_element lock[1];
3445 :
3446 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
3447 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3448 :
3449 : /* cleanup */
3450 3 : smb2_util_unlink(tree1, fname);
3451 :
3452 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
3453 3 : tree1->session->transport->oplock.private_data = tree1;
3454 :
3455 : /*
3456 : base ntcreatex parms
3457 : */
3458 3 : ZERO_STRUCT(io.smb2);
3459 3 : io.generic.level = RAW_OPEN_SMB2;
3460 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3461 : SEC_RIGHTS_FILE_WRITE;
3462 3 : io.smb2.in.alloc_size = 0;
3463 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3464 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3465 : NTCREATEX_SHARE_ACCESS_WRITE;
3466 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3467 3 : io.smb2.in.create_options = 0;
3468 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3469 3 : io.smb2.in.security_flags = 0;
3470 3 : io.smb2.in.fname = fname;
3471 :
3472 : /*
3473 : with a batch oplock we get a break
3474 : */
3475 3 : torture_comment(tctx, "open with batch oplock\n");
3476 3 : ZERO_STRUCT(break_info);
3477 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3478 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3479 :
3480 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3481 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3482 3 : h1 = io.smb2.out.file.handle;
3483 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3484 :
3485 : /* create a file with bogus data */
3486 3 : memset(buf, 0, sizeof(buf));
3487 :
3488 3 : status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3489 3 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3490 0 : torture_comment(tctx, "Failed to create file\n");
3491 0 : ret = false;
3492 0 : goto done;
3493 : }
3494 :
3495 3 : ZERO_STRUCT(break_info);
3496 :
3497 3 : torture_comment(tctx, "a self BRL acquisition should not break to "
3498 : "none\n");
3499 :
3500 3 : ZERO_STRUCT(lock);
3501 :
3502 3 : lock[0].offset = 0;
3503 3 : lock[0].length = 4;
3504 3 : lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3505 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3506 :
3507 3 : ZERO_STRUCT(lck);
3508 3 : lck.in.file.handle = h1;
3509 3 : lck.in.locks = &lock[0];
3510 3 : lck.in.lock_count = 1;
3511 3 : status = smb2_lock(tree1, &lck);
3512 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3513 :
3514 3 : lock[0].offset = 2;
3515 3 : status = smb2_lock(tree1, &lck);
3516 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3517 : "Incorrect status");
3518 :
3519 : /* With one file handle open a BRL should not contend our oplock.
3520 : * Thus, no oplock break will be received and the entire break_info
3521 : * struct will be 0 */
3522 3 : torture_wait_for_oplock_break(tctx);
3523 3 : CHECK_VAL(break_info.count, 0);
3524 3 : CHECK_VAL(break_info.level, 0);
3525 3 : CHECK_VAL(break_info.failures, 0);
3526 :
3527 3 : smb2_util_close(tree1, h1);
3528 3 : smb2_util_close(tree1, h);
3529 :
3530 3 : done:
3531 3 : smb2_deltree(tree1, BASEDIR);
3532 3 : return ret;
3533 : }
3534 :
3535 : /* Open a file with a batch oplock twice from one tree and then acquire a
3536 : * brl. BRL acquisition should break our own oplock.
3537 : */
3538 3 : static bool test_smb2_oplock_brl3(struct torture_context *tctx, struct smb2_tree *tree1)
3539 : {
3540 3 : const char *fname = BASEDIR "\\test_batch_brl.dat";
3541 3 : bool ret = true;
3542 : uint8_t buf[1000];
3543 : union smb_open io;
3544 : NTSTATUS status;
3545 : struct smb2_handle h, h1, h2;
3546 : struct smb2_lock lck;
3547 : struct smb2_lock_element lock[1];
3548 :
3549 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
3550 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3551 :
3552 : /* cleanup */
3553 3 : smb2_util_unlink(tree1, fname);
3554 3 : tree1->session->transport->oplock.handler =
3555 : torture_oplock_handler_two_notifications;
3556 3 : tree1->session->transport->oplock.private_data = tree1;
3557 :
3558 : /*
3559 : base ntcreatex parms
3560 : */
3561 3 : ZERO_STRUCT(io.smb2);
3562 3 : io.generic.level = RAW_OPEN_SMB2;
3563 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3564 : SEC_RIGHTS_FILE_WRITE;
3565 3 : io.smb2.in.alloc_size = 0;
3566 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3567 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3568 : NTCREATEX_SHARE_ACCESS_WRITE;
3569 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3570 3 : io.smb2.in.create_options = 0;
3571 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3572 3 : io.smb2.in.security_flags = 0;
3573 3 : io.smb2.in.fname = fname;
3574 :
3575 : /*
3576 : with a batch oplock we get a break
3577 : */
3578 3 : torture_comment(tctx, "open with batch oplock\n");
3579 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3580 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3581 :
3582 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3583 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3584 3 : h1 = io.smb2.out.file.handle;
3585 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3586 :
3587 : /* create a file with bogus data */
3588 3 : memset(buf, 0, sizeof(buf));
3589 3 : status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3590 :
3591 3 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3592 0 : torture_comment(tctx, "Failed to create file\n");
3593 0 : ret = false;
3594 0 : goto done;
3595 : }
3596 :
3597 3 : torture_comment(tctx, "a 2nd open should give a break\n");
3598 3 : ZERO_STRUCT(break_info);
3599 :
3600 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3601 3 : io.smb2.in.oplock_level = 0;
3602 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3603 3 : h2 = io.smb2.out.file.handle;
3604 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3605 3 : CHECK_VAL(break_info.count, 1);
3606 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3607 3 : CHECK_VAL(break_info.failures, 0);
3608 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3609 :
3610 3 : ZERO_STRUCT(break_info);
3611 :
3612 3 : torture_comment(tctx, "a self BRL acquisition should break to none\n");
3613 :
3614 3 : ZERO_STRUCT(lock);
3615 :
3616 3 : lock[0].offset = 0;
3617 3 : lock[0].length = 4;
3618 3 : lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3619 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3620 :
3621 3 : ZERO_STRUCT(lck);
3622 3 : lck.in.file.handle = h1;
3623 3 : lck.in.locks = &lock[0];
3624 3 : lck.in.lock_count = 1;
3625 3 : status = smb2_lock(tree1, &lck);
3626 3 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3627 :
3628 3 : torture_wait_for_oplock_break(tctx);
3629 3 : CHECK_VAL(break_info.count, 1);
3630 3 : CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3631 3 : CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3632 3 : CHECK_VAL(break_info.failures, 0);
3633 :
3634 : /* expect no oplock break */
3635 3 : ZERO_STRUCT(break_info);
3636 3 : lock[0].offset = 2;
3637 3 : status = smb2_lock(tree1, &lck);
3638 3 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3639 : "Incorrect status");
3640 :
3641 3 : torture_wait_for_oplock_break(tctx);
3642 3 : CHECK_VAL(break_info.count, 0);
3643 3 : CHECK_VAL(break_info.level, 0);
3644 3 : CHECK_VAL(break_info.failures, 0);
3645 :
3646 3 : smb2_util_close(tree1, h1);
3647 3 : smb2_util_close(tree1, h2);
3648 3 : smb2_util_close(tree1, h);
3649 :
3650 3 : done:
3651 3 : smb2_deltree(tree1, BASEDIR);
3652 3 : return ret;
3653 :
3654 : }
3655 :
3656 : /* Starting the SMB2 specific oplock tests at 500 so we can keep the SMB1
3657 : * tests in sync with an identically numbered SMB2 test */
3658 :
3659 : /* Test whether the server correctly returns an error when we send
3660 : * a response to a levelII to none oplock notification. */
3661 3 : static bool test_smb2_oplock_levelII500(struct torture_context *tctx,
3662 : struct smb2_tree *tree1)
3663 : {
3664 3 : const char *fname = BASEDIR "\\test_levelII500.dat";
3665 : NTSTATUS status;
3666 3 : bool ret = true;
3667 : union smb_open io;
3668 : struct smb2_handle h, h1;
3669 3 : char c = 0;
3670 :
3671 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
3672 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3673 :
3674 : /* cleanup */
3675 3 : smb2_util_unlink(tree1, fname);
3676 :
3677 3 : tree1->session->transport->oplock.handler = torture_oplock_handler;
3678 3 : tree1->session->transport->oplock.private_data = tree1;
3679 :
3680 : /*
3681 : base ntcreatex parms
3682 : */
3683 3 : ZERO_STRUCT(io.smb2);
3684 3 : io.generic.level = RAW_OPEN_SMB2;
3685 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3686 3 : io.smb2.in.alloc_size = 0;
3687 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3688 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3689 3 : io.smb2.in.create_options = 0;
3690 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3691 3 : io.smb2.in.security_flags = 0;
3692 3 : io.smb2.in.fname = fname;
3693 :
3694 3 : torture_comment(tctx, "LEVELII500: acknowledging a break from II to "
3695 : "none should return an error\n");
3696 3 : ZERO_STRUCT(break_info);
3697 :
3698 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3699 : SEC_RIGHTS_FILE_WRITE;
3700 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3701 : NTCREATEX_SHARE_ACCESS_WRITE;
3702 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3703 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
3704 3 : status = smb2_create(tree1, tctx, &(io.smb2));
3705 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3706 3 : h1 = io.smb2.out.file.handle;
3707 3 : CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3708 :
3709 3 : ZERO_STRUCT(break_info);
3710 :
3711 3 : torture_comment(tctx, "write should trigger a break to none and when "
3712 : "we reply, an oplock break failure\n");
3713 3 : smb2_util_write(tree1, h1, &c, 0, 1);
3714 :
3715 : /* Wait several times to receive both the break notification, and the
3716 : * NT_STATUS_INVALID_OPLOCK_PROTOCOL error in the break response */
3717 3 : torture_wait_for_oplock_break(tctx);
3718 3 : torture_wait_for_oplock_break(tctx);
3719 3 : torture_wait_for_oplock_break(tctx);
3720 3 : torture_wait_for_oplock_break(tctx);
3721 :
3722 : /* There appears to be a race condition in W2K8 and W2K8R2 where
3723 : * sometimes the server will happily reply to our break response with
3724 : * NT_STATUS_OK, and sometimes it will return the OPLOCK_PROTOCOL
3725 : * error. As the MS-SMB2 doc states that a client should not reply to
3726 : * a level2 to none break notification, I'm leaving the protocol error
3727 : * as the expected behavior. */
3728 3 : CHECK_VAL(break_info.count, 1);
3729 3 : CHECK_VAL(break_info.level, 0);
3730 3 : CHECK_VAL(break_info.failures, 1);
3731 3 : torture_assert_ntstatus_equal(tctx, break_info.failure_status,
3732 : NT_STATUS_INVALID_OPLOCK_PROTOCOL,
3733 : "Incorrect status");
3734 :
3735 2 : smb2_util_close(tree1, h1);
3736 2 : smb2_util_close(tree1, h);
3737 :
3738 2 : smb2_deltree(tree1, BASEDIR);
3739 2 : return ret;
3740 : }
3741 :
3742 : /*
3743 : * Test a double-break. Open a file with exclusive. Send off a second open
3744 : * request with OPEN_IF, triggering a break to level2. This should respond
3745 : * with level2. Before replying to the break to level2, fire off a third open
3746 : * with OVERWRITE_IF. The expected sequence would be that the 3rd opener gets
3747 : * a level2 immediately triggered by a break to none, but that seems not the
3748 : * case. Still investigating what the right behaviour should be.
3749 : */
3750 :
3751 : struct levelII501_state {
3752 : struct torture_context *tctx;
3753 : struct smb2_tree *tree1;
3754 : struct smb2_tree *tree2;
3755 : struct smb2_tree *tree3;
3756 : struct smb2_handle h;
3757 : struct smb2_handle h1;
3758 : union smb_open io;
3759 :
3760 : struct smb2_handle break_handle;
3761 : uint8_t break_to;
3762 : struct smb2_break br;
3763 :
3764 : bool done;
3765 : };
3766 :
3767 : static bool torture_oplock_break_delay(struct smb2_transport *transport,
3768 : const struct smb2_handle *handle,
3769 : uint8_t level, void *private_data);
3770 : static void levelII501_break_done(struct smb2_request *req);
3771 : static void levelII501_open1_done(struct smb2_request *req);
3772 : static void levelII501_open2_done(struct smb2_request *req);
3773 : static void levelII501_2ndopen_cb(struct tevent_context *ev,
3774 : struct tevent_timer *te,
3775 : struct timeval current_time,
3776 : void *private_data);
3777 : static void levelII501_break_timeout_cb(struct tevent_context *ev,
3778 : struct tevent_timer *te,
3779 : struct timeval current_time,
3780 : void *private_data);
3781 : static void levelII501_timeout_cb(struct tevent_context *ev,
3782 : struct tevent_timer *te,
3783 : struct timeval current_time,
3784 : void *private_data);
3785 :
3786 3 : static bool test_smb2_oplock_levelII501(struct torture_context *tctx,
3787 : struct smb2_tree *tree1,
3788 : struct smb2_tree *tree2)
3789 : {
3790 3 : const char *fname = BASEDIR "\\test_levelII501.dat";
3791 : NTSTATUS status;
3792 3 : bool ret = true;
3793 : struct levelII501_state *state;
3794 : struct smb2_request *req;
3795 : struct tevent_timer *te;
3796 :
3797 3 : state = talloc(tctx, struct levelII501_state);
3798 3 : state->tctx = tctx;
3799 3 : state->done = false;
3800 3 : state->tree1 = tree1;
3801 3 : state->tree2 = tree2;
3802 :
3803 3 : if (!torture_smb2_connection(tctx, &state->tree3)) {
3804 0 : torture_fail(tctx, "Establishing SMB2 connection failed\n");
3805 : return false;
3806 : }
3807 :
3808 3 : status = torture_smb2_testdir(tree1, BASEDIR, &state->h);
3809 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3810 :
3811 : /* cleanup */
3812 3 : smb2_util_unlink(tree1, fname);
3813 :
3814 : /*
3815 : base ntcreatex parms
3816 : */
3817 3 : ZERO_STRUCT(state->io.smb2);
3818 3 : state->io.generic.level = RAW_OPEN_SMB2;
3819 3 : state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3820 3 : state->io.smb2.in.alloc_size = 0;
3821 3 : state->io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3822 3 : state->io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3823 3 : state->io.smb2.in.create_options = 0;
3824 3 : state->io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3825 3 : state->io.smb2.in.security_flags = 0;
3826 3 : state->io.smb2.in.fname = fname;
3827 :
3828 3 : torture_comment(tctx, "LEVELII501: Test double break sequence\n");
3829 3 : ZERO_STRUCT(break_info);
3830 :
3831 3 : state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3832 : SEC_RIGHTS_FILE_WRITE;
3833 3 : state->io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3834 : NTCREATEX_SHARE_ACCESS_WRITE;
3835 3 : state->io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3836 3 : state->io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
3837 :
3838 3 : tree1->session->transport->oplock.handler = torture_oplock_break_delay;
3839 3 : tree1->session->transport->oplock.private_data = state;
3840 :
3841 3 : status = smb2_create(tree1, tctx, &(state->io.smb2));
3842 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3843 3 : state->h1 = state->io.smb2.out.file.handle;
3844 3 : CHECK_VAL(state->io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
3845 :
3846 : /*
3847 : * Trigger a break to level2
3848 : */
3849 :
3850 3 : req = smb2_create_send(tree2, &state->io.smb2);
3851 3 : req->async.fn = levelII501_open1_done;
3852 3 : req->async.private_data = state;
3853 :
3854 3 : te = tevent_add_timer(
3855 : tctx->ev, tctx, tevent_timeval_current_ofs(0, 200000),
3856 : levelII501_2ndopen_cb, state);
3857 3 : torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
3858 :
3859 3 : te = tevent_add_timer(
3860 : tctx->ev, tctx, tevent_timeval_current_ofs(2, 0),
3861 : levelII501_timeout_cb, state);
3862 3 : torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
3863 :
3864 94 : while (!state->done) {
3865 88 : if (tevent_loop_once(tctx->ev) != 0) {
3866 0 : torture_comment(tctx, "tevent_loop_once failed\n");
3867 : }
3868 : }
3869 :
3870 3 : return ret;
3871 : }
3872 :
3873 : /*
3874 : * Fire off a second open after a little timeout
3875 : */
3876 :
3877 3 : static void levelII501_2ndopen_cb(struct tevent_context *ev,
3878 : struct tevent_timer *te,
3879 : struct timeval current_time,
3880 : void *private_data)
3881 : {
3882 3 : struct levelII501_state *state = talloc_get_type_abort(
3883 : private_data, struct levelII501_state);
3884 : struct smb2_request *req;
3885 :
3886 3 : state->io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
3887 3 : req = smb2_create_send(state->tree3, &state->io.smb2);
3888 3 : req->async.fn = levelII501_open2_done;
3889 3 : req->async.private_data = state;
3890 3 : }
3891 :
3892 : /*
3893 : * Postpone the break response by 500 msec
3894 : */
3895 5 : static bool torture_oplock_break_delay(struct smb2_transport *transport,
3896 : const struct smb2_handle *handle,
3897 : uint8_t level, void *private_data)
3898 : {
3899 5 : struct levelII501_state *state = talloc_get_type_abort(
3900 : private_data, struct levelII501_state);
3901 : const char *name;
3902 : struct tevent_timer *te;
3903 :
3904 5 : break_info.handle = *handle;
3905 5 : break_info.level = level;
3906 5 : break_info.count++;
3907 :
3908 5 : state->break_handle = *handle;
3909 5 : state->break_to = level;
3910 :
3911 5 : switch(level) {
3912 3 : case SMB2_OPLOCK_LEVEL_II:
3913 3 : name = "level II";
3914 3 : break;
3915 2 : case SMB2_OPLOCK_LEVEL_NONE:
3916 2 : name = "none";
3917 2 : break;
3918 0 : default:
3919 0 : name = "unknown";
3920 0 : break;
3921 : }
3922 5 : printf("Got break to %s [0x%02X] in oplock handler, postponing "
3923 : "break response for 500msec\n", name, level);
3924 :
3925 5 : te = tevent_add_timer(
3926 : state->tctx->ev, state->tctx,
3927 : tevent_timeval_current_ofs(0, 500000),
3928 : levelII501_break_timeout_cb, state);
3929 5 : torture_assert(state->tctx, te != NULL, "tevent_add_timer failed\n");
3930 :
3931 5 : return true;
3932 : }
3933 :
3934 5 : static void levelII501_break_timeout_cb(struct tevent_context *ev,
3935 : struct tevent_timer *te,
3936 : struct timeval current_time,
3937 : void *private_data)
3938 : {
3939 5 : struct levelII501_state *state = talloc_get_type_abort(
3940 : private_data, struct levelII501_state);
3941 : struct smb2_request *req;
3942 :
3943 5 : talloc_free(te);
3944 :
3945 5 : ZERO_STRUCT(state->br);
3946 5 : state->br.in.file.handle = state->break_handle;
3947 5 : state->br.in.oplock_level = state->break_to;
3948 :
3949 5 : req = smb2_break_send(state->tree1, &state->br);
3950 5 : req->async.fn = levelII501_break_done;
3951 5 : req->async.private_data = state;
3952 5 : }
3953 :
3954 5 : static void levelII501_break_done(struct smb2_request *req)
3955 : {
3956 : struct smb2_break io;
3957 : NTSTATUS status;
3958 :
3959 5 : status = smb2_break_recv(req, &io);
3960 5 : printf("break done: %s\n", nt_errstr(status));
3961 5 : }
3962 :
3963 3 : static void levelII501_open1_done(struct smb2_request *req)
3964 : {
3965 3 : struct levelII501_state *state = talloc_get_type_abort(
3966 : req->async.private_data, struct levelII501_state);
3967 : struct smb2_create io;
3968 : NTSTATUS status;
3969 :
3970 3 : status = smb2_create_recv(req, state, &io);
3971 3 : printf("open1 done: %s\n", nt_errstr(status));
3972 3 : }
3973 :
3974 3 : static void levelII501_open2_done(struct smb2_request *req)
3975 : {
3976 3 : struct levelII501_state *state = talloc_get_type_abort(
3977 : req->async.private_data, struct levelII501_state);
3978 : struct smb2_create io;
3979 : NTSTATUS status;
3980 :
3981 3 : status = smb2_create_recv(req, state, &io);
3982 3 : printf("open2 done: %s\n", nt_errstr(status));
3983 3 : }
3984 :
3985 3 : static void levelII501_timeout_cb(struct tevent_context *ev,
3986 : struct tevent_timer *te,
3987 : struct timeval current_time,
3988 : void *private_data)
3989 : {
3990 3 : struct levelII501_state *state = talloc_get_type_abort(
3991 : private_data, struct levelII501_state);
3992 3 : talloc_free(te);
3993 3 : state->done = true;
3994 3 : }
3995 :
3996 3 : static bool test_smb2_oplock_levelII502(struct torture_context *tctx,
3997 : struct smb2_tree *tree1,
3998 : struct smb2_tree *tree2)
3999 :
4000 : {
4001 3 : const char *fname = BASEDIR "\\test_levelII502.dat";
4002 : NTSTATUS status;
4003 : union smb_open io;
4004 : struct smb2_close closeio;
4005 : struct smb2_handle h;
4006 :
4007 3 : status = torture_smb2_testdir(tree1, BASEDIR, &h);
4008 3 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4009 :
4010 : /* cleanup */
4011 3 : smb2_util_unlink(tree1, fname);
4012 :
4013 : /*
4014 : base ntcreatex parms
4015 : */
4016 3 : ZERO_STRUCT(io.smb2);
4017 3 : io.generic.level = RAW_OPEN_SMB2;
4018 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4019 3 : io.smb2.in.alloc_size = 0;
4020 3 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4021 3 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4022 3 : io.smb2.in.create_options = 0;
4023 3 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4024 3 : io.smb2.in.security_flags = 0;
4025 3 : io.smb2.in.fname = fname;
4026 :
4027 3 : torture_comment(
4028 : tctx,
4029 : "LEVELII502: Open a stale LEVEL2 oplock with OVERWRITE");
4030 :
4031 3 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
4032 : SEC_RIGHTS_FILE_WRITE;
4033 3 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
4034 : NTCREATEX_SHARE_ACCESS_WRITE;
4035 3 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4036 3 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
4037 3 : status = smb2_create(tree1, tctx, &(io.smb2));
4038 3 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
4039 3 : torture_assert(tctx,
4040 : io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_II,
4041 : "Did not get LEVEL_II oplock\n");
4042 :
4043 2 : status = smbXcli_conn_samba_suicide(
4044 2 : tree1->session->transport->conn, 93);
4045 2 : torture_assert_ntstatus_ok(tctx, status, "suicide failed");
4046 :
4047 2 : sleep(1);
4048 :
4049 2 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4050 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
4051 :
4052 2 : status = smb2_create(tree2, tctx, &(io.smb2));
4053 2 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
4054 2 : torture_assert(tctx,
4055 : io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_BATCH,
4056 : "Did not get BATCH oplock\n");
4057 :
4058 2 : closeio = (struct smb2_close) {
4059 : .in.file.handle = io.smb2.out.file.handle,
4060 : };
4061 2 : status = smb2_close(tree2, &closeio);
4062 2 : torture_assert_ntstatus_equal(
4063 : tctx, status, NT_STATUS_OK, "close failed");
4064 :
4065 2 : return true;
4066 : }
4067 :
4068 36 : static bool test_oplock_statopen1_do(struct torture_context *tctx,
4069 : struct smb2_tree *tree,
4070 : uint32_t access_mask,
4071 : bool expect_stat_open)
4072 : {
4073 36 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
4074 : struct smb2_create cr;
4075 36 : struct smb2_handle h1 = {{0}};
4076 36 : struct smb2_handle h2 = {{0}};
4077 : NTSTATUS status;
4078 36 : const char *fname = "oplock_statopen1.dat";
4079 36 : bool ret = true;
4080 :
4081 : /* Open file with exclusive oplock. */
4082 36 : cr = (struct smb2_create) {
4083 : .in.desired_access = SEC_FILE_ALL,
4084 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
4085 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
4086 : .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
4087 : .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
4088 : .in.fname = fname,
4089 : .in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH,
4090 : };
4091 36 : status = smb2_create(tree, mem_ctx, &cr);
4092 36 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4093 : "smb2_create failed\n");
4094 36 : h1 = cr.out.file.handle;
4095 36 : CHECK_VAL(cr.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
4096 :
4097 : /* Stat open */
4098 36 : cr = (struct smb2_create) {
4099 : .in.desired_access = access_mask,
4100 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
4101 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
4102 : .in.create_disposition = NTCREATEX_DISP_OPEN,
4103 : .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
4104 : .in.fname = fname,
4105 : };
4106 36 : status = smb2_create(tree, mem_ctx, &cr);
4107 36 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4108 : "smb2_create failed\n");
4109 35 : h2 = cr.out.file.handle;
4110 :
4111 35 : if (expect_stat_open) {
4112 8 : torture_wait_for_oplock_break(tctx);
4113 8 : CHECK_VAL(break_info.count, 0);
4114 8 : CHECK_VAL(break_info.level, 0);
4115 8 : CHECK_VAL(break_info.failures, 0);
4116 8 : if (!ret) {
4117 0 : goto done;
4118 : }
4119 : } else {
4120 27 : CHECK_VAL(break_info.count, 1);
4121 : }
4122 :
4123 63 : done:
4124 36 : if (!smb2_util_handle_empty(h2)) {
4125 35 : smb2_util_close(tree, h2);
4126 : }
4127 36 : if (!smb2_util_handle_empty(h1)) {
4128 36 : smb2_util_close(tree, h1);
4129 : }
4130 36 : talloc_free(mem_ctx);
4131 36 : return ret;
4132 : }
4133 :
4134 3 : static bool test_smb2_oplock_statopen1(struct torture_context *tctx,
4135 : struct smb2_tree *tree)
4136 : {
4137 3 : const char *fname = "oplock_statopen1.dat";
4138 : size_t i;
4139 3 : bool ret = true;
4140 : struct {
4141 : uint32_t access_mask;
4142 : bool expect_stat_open;
4143 3 : } tests[] = {
4144 : {
4145 : .access_mask = FILE_READ_DATA,
4146 : .expect_stat_open = false,
4147 : },
4148 : {
4149 : .access_mask = FILE_WRITE_DATA,
4150 : .expect_stat_open = false,
4151 : },
4152 : {
4153 : .access_mask = FILE_READ_EA,
4154 : .expect_stat_open = false,
4155 : },
4156 : {
4157 : .access_mask = FILE_WRITE_EA,
4158 : .expect_stat_open = false,
4159 : },
4160 : {
4161 : .access_mask = FILE_EXECUTE,
4162 : .expect_stat_open = false,
4163 : },
4164 : {
4165 : .access_mask = FILE_READ_ATTRIBUTES,
4166 : .expect_stat_open = true,
4167 : },
4168 : {
4169 : .access_mask = FILE_WRITE_ATTRIBUTES,
4170 : .expect_stat_open = true,
4171 : },
4172 : {
4173 : .access_mask = DELETE_ACCESS,
4174 : .expect_stat_open = false,
4175 : },
4176 : {
4177 : .access_mask = READ_CONTROL_ACCESS,
4178 : .expect_stat_open = false,
4179 : },
4180 : {
4181 : .access_mask = WRITE_DAC_ACCESS,
4182 : .expect_stat_open = false,
4183 : },
4184 : {
4185 : .access_mask = WRITE_OWNER_ACCESS,
4186 : .expect_stat_open = false,
4187 : },
4188 : {
4189 : .access_mask = SYNCHRONIZE_ACCESS,
4190 : .expect_stat_open = true,
4191 : },
4192 : };
4193 :
4194 3 : tree->session->transport->oplock.handler = torture_oplock_handler;
4195 3 : tree->session->transport->oplock.private_data = tree;
4196 :
4197 76 : for (i = 0; i < ARRAY_SIZE(tests); i++) {
4198 36 : ZERO_STRUCT(break_info);
4199 :
4200 36 : ret = test_oplock_statopen1_do(tctx,
4201 : tree,
4202 : tests[i].access_mask,
4203 36 : tests[i].expect_stat_open);
4204 36 : if (ret == true) {
4205 35 : continue;
4206 : }
4207 1 : torture_result(tctx, TORTURE_FAIL,
4208 : "test %zu: access_mask: %s, "
4209 : "expect_stat_open: %s\n",
4210 : i,
4211 : get_sec_mask_str(tree, tests[i].access_mask),
4212 1 : tests[i].expect_stat_open ? "yes" : "no");
4213 1 : goto done;
4214 : }
4215 :
4216 2 : done:
4217 3 : smb2_util_unlink(tree, fname);
4218 3 : return ret;
4219 : }
4220 :
4221 2355 : struct torture_suite *torture_smb2_oplocks_init(TALLOC_CTX *ctx)
4222 : {
4223 1897 : struct torture_suite *suite =
4224 458 : torture_suite_create(ctx, "oplock");
4225 :
4226 2355 : torture_suite_add_2smb2_test(suite, "exclusive1", test_smb2_oplock_exclusive1);
4227 2355 : torture_suite_add_2smb2_test(suite, "exclusive2", test_smb2_oplock_exclusive2);
4228 2355 : torture_suite_add_2smb2_test(suite, "exclusive3", test_smb2_oplock_exclusive3);
4229 2355 : torture_suite_add_2smb2_test(suite, "exclusive4", test_smb2_oplock_exclusive4);
4230 2355 : torture_suite_add_2smb2_test(suite, "exclusive5", test_smb2_oplock_exclusive5);
4231 2355 : torture_suite_add_2smb2_test(suite, "exclusive6", test_smb2_oplock_exclusive6);
4232 2355 : torture_suite_add_2smb2_test(suite, "exclusive9",
4233 : test_smb2_oplock_exclusive9);
4234 2355 : torture_suite_add_2smb2_test(suite, "batch1", test_smb2_oplock_batch1);
4235 2355 : torture_suite_add_2smb2_test(suite, "batch2", test_smb2_oplock_batch2);
4236 2355 : torture_suite_add_2smb2_test(suite, "batch3", test_smb2_oplock_batch3);
4237 2355 : torture_suite_add_2smb2_test(suite, "batch4", test_smb2_oplock_batch4);
4238 2355 : torture_suite_add_2smb2_test(suite, "batch5", test_smb2_oplock_batch5);
4239 2355 : torture_suite_add_2smb2_test(suite, "batch6", test_smb2_oplock_batch6);
4240 2355 : torture_suite_add_2smb2_test(suite, "batch7", test_smb2_oplock_batch7);
4241 2355 : torture_suite_add_2smb2_test(suite, "batch8", test_smb2_oplock_batch8);
4242 2355 : torture_suite_add_2smb2_test(suite, "batch9", test_smb2_oplock_batch9);
4243 2355 : torture_suite_add_2smb2_test(suite, "batch9a", test_smb2_oplock_batch9a);
4244 2355 : torture_suite_add_2smb2_test(suite, "batch10", test_smb2_oplock_batch10);
4245 2355 : torture_suite_add_2smb2_test(suite, "batch11", test_smb2_oplock_batch11);
4246 2355 : torture_suite_add_2smb2_test(suite, "batch12", test_smb2_oplock_batch12);
4247 2355 : torture_suite_add_2smb2_test(suite, "batch13", test_smb2_oplock_batch13);
4248 2355 : torture_suite_add_2smb2_test(suite, "batch14", test_smb2_oplock_batch14);
4249 2355 : torture_suite_add_2smb2_test(suite, "batch15", test_smb2_oplock_batch15);
4250 2355 : torture_suite_add_2smb2_test(suite, "batch16", test_smb2_oplock_batch16);
4251 2355 : torture_suite_add_1smb2_test(suite, "batch19", test_smb2_oplock_batch19);
4252 2355 : torture_suite_add_2smb2_test(suite, "batch20", test_smb2_oplock_batch20);
4253 2355 : torture_suite_add_1smb2_test(suite, "batch21", test_smb2_oplock_batch21);
4254 2355 : torture_suite_add_1smb2_test(suite, "batch22a", test_smb2_oplock_batch22a);
4255 2355 : torture_suite_add_2smb2_test(suite, "batch22b", test_smb2_oplock_batch22b);
4256 2355 : torture_suite_add_2smb2_test(suite, "batch23", test_smb2_oplock_batch23);
4257 2355 : torture_suite_add_2smb2_test(suite, "batch24", test_smb2_oplock_batch24);
4258 2355 : torture_suite_add_1smb2_test(suite, "batch25", test_smb2_oplock_batch25);
4259 2355 : torture_suite_add_1smb2_test(suite, "batch26", test_smb2_oplock_batch26);
4260 2355 : torture_suite_add_2smb2_test(suite, "stream1", test_raw_oplock_stream1);
4261 2355 : torture_suite_add_2smb2_test(suite, "doc", test_smb2_oplock_doc);
4262 2355 : torture_suite_add_2smb2_test(suite, "brl1", test_smb2_oplock_brl1);
4263 2355 : torture_suite_add_1smb2_test(suite, "brl2", test_smb2_oplock_brl2);
4264 2355 : torture_suite_add_1smb2_test(suite, "brl3", test_smb2_oplock_brl3);
4265 2355 : torture_suite_add_1smb2_test(suite, "levelii500", test_smb2_oplock_levelII500);
4266 2355 : torture_suite_add_2smb2_test(suite, "levelii501",
4267 : test_smb2_oplock_levelII501);
4268 2355 : torture_suite_add_2smb2_test(suite, "levelii502",
4269 : test_smb2_oplock_levelII502);
4270 2355 : torture_suite_add_1smb2_test(suite, "statopen1", test_smb2_oplock_statopen1);
4271 2355 : suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
4272 :
4273 2355 : return suite;
4274 : }
4275 :
4276 : /*
4277 : stress testing of oplocks
4278 : */
4279 0 : bool test_smb2_bench_oplock(struct torture_context *tctx,
4280 : struct smb2_tree *tree)
4281 : {
4282 : struct smb2_tree **trees;
4283 0 : bool ret = true;
4284 : NTSTATUS status;
4285 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
4286 0 : int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
4287 0 : int i, count=0;
4288 0 : int timelimit = torture_setting_int(tctx, "timelimit", 10);
4289 : union smb_open io;
4290 : struct timeval tv;
4291 : struct smb2_handle h;
4292 :
4293 0 : trees = talloc_array(mem_ctx, struct smb2_tree *, torture_nprocs);
4294 :
4295 0 : torture_comment(tctx, "Opening %d connections\n", torture_nprocs);
4296 0 : for (i=0;i<torture_nprocs;i++) {
4297 0 : if (!torture_smb2_connection(tctx, &trees[i])) {
4298 0 : return false;
4299 : }
4300 0 : talloc_steal(mem_ctx, trees[i]);
4301 0 : trees[i]->session->transport->oplock.handler =
4302 : torture_oplock_handler_close;
4303 0 : trees[i]->session->transport->oplock.private_data = trees[i];
4304 : }
4305 :
4306 0 : status = torture_smb2_testdir(trees[0], BASEDIR, &h);
4307 0 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4308 :
4309 0 : ZERO_STRUCT(io.smb2);
4310 0 : io.smb2.level = RAW_OPEN_SMB2;
4311 0 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4312 0 : io.smb2.in.alloc_size = 0;
4313 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4314 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4315 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4316 0 : io.smb2.in.create_options = 0;
4317 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4318 0 : io.smb2.in.security_flags = 0;
4319 0 : io.smb2.in.fname = BASEDIR "\\test.dat";
4320 0 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4321 0 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4322 :
4323 0 : tv = timeval_current();
4324 :
4325 : /*
4326 : we open the same file with SHARE_ACCESS_NONE from all the
4327 : connections in a round robin fashion. Each open causes an
4328 : oplock break on the previous connection, which is answered
4329 : by the oplock_handler_close() to close the file.
4330 :
4331 : This measures how fast we can pass on oplocks, and stresses
4332 : the oplock handling code
4333 : */
4334 0 : torture_comment(tctx, "Running for %d seconds\n", timelimit);
4335 0 : while (timeval_elapsed(&tv) < timelimit) {
4336 0 : for (i=0;i<torture_nprocs;i++) {
4337 0 : status = smb2_create(trees[i], mem_ctx, &(io.smb2));
4338 0 : torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
4339 0 : count++;
4340 : }
4341 :
4342 0 : if (torture_setting_bool(tctx, "progress", true)) {
4343 0 : torture_comment(tctx, "%.2f ops/second\r",
4344 0 : count/timeval_elapsed(&tv));
4345 : }
4346 : }
4347 :
4348 0 : torture_comment(tctx, "%.2f ops/second\n", count/timeval_elapsed(&tv));
4349 0 : smb2_util_close(trees[0], io.smb2.out.file.handle);
4350 0 : smb2_util_unlink(trees[0], BASEDIR "\\test.dat");
4351 0 : smb2_deltree(trees[0], BASEDIR);
4352 0 : talloc_free(mem_ctx);
4353 0 : return ret;
4354 : }
4355 :
4356 : static struct hold_oplock_info {
4357 : const char *fname;
4358 : bool close_on_break;
4359 : uint32_t share_access;
4360 : struct smb2_handle handle;
4361 : } hold_info[] = {
4362 : {
4363 : .fname = BASEDIR "\\notshared_close",
4364 : .close_on_break = true,
4365 : .share_access = NTCREATEX_SHARE_ACCESS_NONE,
4366 : },
4367 : {
4368 : .fname = BASEDIR "\\notshared_noclose",
4369 : .close_on_break = false,
4370 : .share_access = NTCREATEX_SHARE_ACCESS_NONE,
4371 : },
4372 : {
4373 : .fname = BASEDIR "\\shared_close",
4374 : .close_on_break = true,
4375 : .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
4376 : },
4377 : {
4378 : .fname = BASEDIR "\\shared_noclose",
4379 : .close_on_break = false,
4380 : .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
4381 : },
4382 : };
4383 :
4384 0 : static bool torture_oplock_handler_hold(struct smb2_transport *transport,
4385 : const struct smb2_handle *handle,
4386 : uint8_t level, void *private_data)
4387 : {
4388 : struct hold_oplock_info *info;
4389 : int i;
4390 :
4391 0 : for (i=0;i<ARRAY_SIZE(hold_info);i++) {
4392 0 : if (smb2_util_handle_equal(hold_info[i].handle, *handle))
4393 0 : break;
4394 : }
4395 :
4396 0 : if (i == ARRAY_SIZE(hold_info)) {
4397 0 : printf("oplock break for unknown handle 0x%llx%llx\n",
4398 0 : (unsigned long long) handle->data[0],
4399 0 : (unsigned long long) handle->data[1]);
4400 0 : return false;
4401 : }
4402 :
4403 0 : info = &hold_info[i];
4404 :
4405 0 : if (info->close_on_break) {
4406 0 : printf("oplock break on %s - closing\n", info->fname);
4407 0 : torture_oplock_handler_close(transport, handle,
4408 : level, private_data);
4409 0 : return true;
4410 : }
4411 :
4412 0 : printf("oplock break on %s - acking break\n", info->fname);
4413 0 : printf("Acking to none in oplock handler\n");
4414 :
4415 0 : torture_oplock_handler_ack_to_none(transport, handle,
4416 : level, private_data);
4417 0 : return true;
4418 : }
4419 :
4420 : /*
4421 : used for manual testing of oplocks - especially interaction with
4422 : other filesystems (such as NFS and local access)
4423 : */
4424 0 : bool test_smb2_hold_oplock(struct torture_context *tctx,
4425 : struct smb2_tree *tree)
4426 : {
4427 0 : struct torture_context *mem_ctx = talloc_new(tctx);
4428 0 : struct tevent_context *ev = tctx->ev;
4429 : int i;
4430 : struct smb2_handle h;
4431 : NTSTATUS status;
4432 :
4433 0 : torture_comment(tctx, "Setting up open files with oplocks in %s\n",
4434 : BASEDIR);
4435 :
4436 0 : status = torture_smb2_testdir(tree, BASEDIR, &h);
4437 0 : torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
4438 :
4439 0 : tree->session->transport->oplock.handler = torture_oplock_handler_hold;
4440 0 : tree->session->transport->oplock.private_data = tree;
4441 :
4442 : /* setup the files */
4443 0 : for (i=0;i<ARRAY_SIZE(hold_info);i++) {
4444 : union smb_open io;
4445 0 : char c = 1;
4446 :
4447 0 : ZERO_STRUCT(io.smb2);
4448 0 : io.generic.level = RAW_OPEN_SMB2;
4449 0 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
4450 0 : io.smb2.in.alloc_size = 0;
4451 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4452 0 : io.smb2.in.share_access = hold_info[i].share_access;
4453 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4454 0 : io.smb2.in.create_options = 0;
4455 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4456 0 : io.smb2.in.security_flags = 0;
4457 0 : io.smb2.in.fname = hold_info[i].fname;
4458 0 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4459 0 : io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4460 :
4461 0 : torture_comment(tctx, "opening %s\n", hold_info[i].fname);
4462 :
4463 0 : status = smb2_create(tree, mem_ctx, &(io.smb2));
4464 0 : if (!NT_STATUS_IS_OK(status)) {
4465 0 : torture_comment(tctx, "Failed to open %s - %s\n",
4466 : hold_info[i].fname, nt_errstr(status));
4467 0 : return false;
4468 : }
4469 :
4470 0 : if (io.smb2.out.oplock_level != SMB2_OPLOCK_LEVEL_BATCH) {
4471 0 : torture_comment(tctx, "Oplock not granted for %s - "
4472 : "expected %d but got %d\n",
4473 : hold_info[i].fname,
4474 : SMB2_OPLOCK_LEVEL_BATCH,
4475 0 : io.smb2.out.oplock_level);
4476 0 : return false;
4477 : }
4478 0 : hold_info[i].handle = io.smb2.out.file.handle;
4479 :
4480 : /* make the file non-zero size */
4481 0 : status = smb2_util_write(tree, hold_info[i].handle, &c, 0, 1);
4482 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
4483 0 : torture_comment(tctx, "Failed to write to file\n");
4484 0 : return false;
4485 : }
4486 : }
4487 :
4488 0 : torture_comment(tctx, "Waiting for oplock events\n");
4489 0 : tevent_loop_wait(ev);
4490 0 : smb2_deltree(tree, BASEDIR);
4491 0 : talloc_free(mem_ctx);
4492 0 : return true;
4493 : }
4494 :
4495 :
4496 1 : static bool test_smb2_kernel_oplocks1(struct torture_context *tctx,
4497 : struct smb2_tree *tree)
4498 : {
4499 1 : const char *fname = "test_kernel_oplock1.dat";
4500 : NTSTATUS status;
4501 1 : bool ret = true;
4502 : struct smb2_create create;
4503 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4504 :
4505 1 : smb2_util_unlink(tree, fname);
4506 :
4507 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4508 1 : tree->session->transport->oplock.private_data = tree;
4509 1 : ZERO_STRUCT(break_info);
4510 :
4511 1 : ZERO_STRUCT(create);
4512 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4513 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4514 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4515 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4516 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4517 1 : create.in.fname = fname;
4518 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4519 :
4520 1 : status = smb2_create(tree, tctx, &create);
4521 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4522 1 : h1 = create.out.file.handle;
4523 :
4524 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4525 : "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4526 :
4527 1 : ZERO_STRUCT(create);
4528 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4529 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4530 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4531 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4532 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4533 1 : create.in.fname = fname;
4534 :
4535 1 : status = smb2_create(tree, tctx, &create);
4536 1 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done,
4537 : "Open didn't return NT_STATUS_SHARING_VIOLATION\n");
4538 1 : h2 = create.out.file.handle;
4539 :
4540 1 : torture_wait_for_oplock_break(tctx);
4541 1 : if (break_info.count != 0) {
4542 1 : torture_warning(tctx, "Open caused oplock break\n");
4543 : }
4544 :
4545 1 : smb2_util_close(tree, h1);
4546 1 : smb2_util_close(tree, h2);
4547 :
4548 1 : done:
4549 1 : if (!smb2_util_handle_empty(h1)) {
4550 1 : smb2_util_close(tree, h1);
4551 : }
4552 1 : if (!smb2_util_handle_empty(h2)) {
4553 0 : smb2_util_close(tree, h2);
4554 : }
4555 1 : smb2_util_unlink(tree, fname);
4556 1 : return ret;
4557 : }
4558 :
4559 1 : static bool test_smb2_kernel_oplocks2(struct torture_context *tctx,
4560 : struct smb2_tree *tree)
4561 : {
4562 1 : const char *fname = "test_kernel_oplock2.dat";
4563 1 : const char *sname = "test_kernel_oplock2.dat:foo";
4564 : NTSTATUS status;
4565 1 : bool ret = true;
4566 : struct smb2_create create;
4567 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4568 :
4569 1 : smb2_util_unlink(tree, fname);
4570 :
4571 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4572 1 : tree->session->transport->oplock.private_data = tree;
4573 1 : ZERO_STRUCT(break_info);
4574 :
4575 1 : ZERO_STRUCT(create);
4576 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4577 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4578 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
4579 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4580 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4581 1 : create.in.fname = fname;
4582 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4583 :
4584 1 : status = smb2_create(tree, tctx, &create);
4585 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4586 1 : h1 = create.out.file.handle;
4587 :
4588 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4589 : "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4590 :
4591 1 : ZERO_STRUCT(create);
4592 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4593 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4594 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4595 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4596 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4597 1 : create.in.fname = sname;
4598 :
4599 1 : status = smb2_create(tree, tctx, &create);
4600 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4601 1 : h2 = create.out.file.handle;
4602 :
4603 1 : torture_wait_for_oplock_break(tctx);
4604 1 : if (break_info.count != 0) {
4605 0 : torture_warning(tctx, "Stream open caused oplock break\n");
4606 : }
4607 :
4608 1 : smb2_util_close(tree, h1);
4609 1 : smb2_util_close(tree, h2);
4610 :
4611 1 : done:
4612 1 : if (!smb2_util_handle_empty(h1)) {
4613 1 : smb2_util_close(tree, h1);
4614 : }
4615 1 : if (!smb2_util_handle_empty(h2)) {
4616 1 : smb2_util_close(tree, h2);
4617 : }
4618 1 : smb2_util_unlink(tree, fname);
4619 1 : return ret;
4620 : }
4621 :
4622 : /**
4623 : * 1. 1st client opens file with oplock
4624 : * 2. 2nd client opens file
4625 : *
4626 : * Verify 2 triggers an oplock break
4627 : **/
4628 1 : static bool test_smb2_kernel_oplocks3(struct torture_context *tctx,
4629 : struct smb2_tree *tree,
4630 : struct smb2_tree *tree2)
4631 : {
4632 1 : const char *fname = "test_kernel_oplock3.dat";
4633 : NTSTATUS status;
4634 1 : bool ret = true;
4635 : struct smb2_create create;
4636 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4637 :
4638 1 : smb2_util_unlink(tree, fname);
4639 1 : status = torture_smb2_testfile(tree, fname, &h1);
4640 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4641 : "Error creating testfile\n");
4642 1 : smb2_util_close(tree, h1);
4643 1 : ZERO_STRUCT(h1);
4644 :
4645 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4646 1 : tree->session->transport->oplock.private_data = tree;
4647 1 : ZERO_STRUCT(break_info);
4648 :
4649 : /* 1 */
4650 1 : ZERO_STRUCT(create);
4651 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4652 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4653 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4654 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4655 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4656 1 : create.in.fname = fname;
4657 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4658 :
4659 1 : status = smb2_create(tree, tctx, &create);
4660 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4661 1 : h1 = create.out.file.handle;
4662 :
4663 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4664 : "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4665 :
4666 : /* 2 */
4667 1 : ZERO_STRUCT(create);
4668 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4669 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4670 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4671 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4672 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4673 1 : create.in.fname = fname;
4674 :
4675 1 : status = smb2_create(tree2, tctx, &create);
4676 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4677 1 : h2 = create.out.file.handle;
4678 :
4679 1 : torture_wait_for_oplock_break(tctx);
4680 1 : torture_assert_goto(tctx, break_info.count == 1, ret, done, "Expected 1 oplock break\n");
4681 :
4682 2 : done:
4683 1 : if (!smb2_util_handle_empty(h1)) {
4684 1 : smb2_util_close(tree, h1);
4685 : }
4686 1 : if (!smb2_util_handle_empty(h2)) {
4687 1 : smb2_util_close(tree, h2);
4688 : }
4689 1 : smb2_util_unlink(tree, fname);
4690 1 : return ret;
4691 : }
4692 :
4693 : /**
4694 : * 1) create testfile with stream
4695 : * 2) open file r/w with batch oplock, sharing read/delete
4696 : * 3) open stream on file for reading
4697 : *
4698 : * Verify 3) doesn't trigger an oplock break
4699 : **/
4700 1 : static bool test_smb2_kernel_oplocks4(struct torture_context *tctx,
4701 : struct smb2_tree *tree)
4702 : {
4703 1 : const char *fname = "test_kernel_oplock4.dat";
4704 1 : const char *sname = "test_kernel_oplock4.dat:foo";
4705 : NTSTATUS status;
4706 1 : bool ret = true;
4707 : struct smb2_create create;
4708 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4709 :
4710 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4711 1 : tree->session->transport->oplock.private_data = tree;
4712 1 : ZERO_STRUCT(break_info);
4713 1 : smb2_util_unlink(tree, fname);
4714 :
4715 : /* 1 */
4716 1 : status = torture_smb2_testfile(tree, fname, &h1);
4717 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4718 : "Error creating testfile\n");
4719 1 : smb2_util_close(tree, h1);
4720 1 : ZERO_STRUCT(h1);
4721 :
4722 1 : ZERO_STRUCT(create);
4723 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4724 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4725 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4726 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4727 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4728 1 : create.in.fname = sname;
4729 :
4730 1 : status = smb2_create(tree, tctx, &create);
4731 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4732 1 : h1 = create.out.file.handle;
4733 1 : smb2_util_close(tree, h1);
4734 1 : ZERO_STRUCT(h1);
4735 :
4736 : /* 2 */
4737 1 : ZERO_STRUCT(create);
4738 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4739 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4740 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
4741 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4742 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4743 1 : create.in.fname = fname;
4744 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4745 :
4746 1 : status = smb2_create(tree, tctx, &create);
4747 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4748 1 : h1 = create.out.file.handle;
4749 :
4750 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_BATCH, ret, done,
4751 : "Oplock level is not SMB2_OPLOCK_LEVEL_BATCH\n");
4752 :
4753 1 : ZERO_STRUCT(create);
4754 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4755 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4756 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
4757 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4758 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4759 1 : create.in.fname = sname;
4760 :
4761 1 : status = smb2_create(tree, tctx, &create);
4762 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4763 1 : h2 = create.out.file.handle;
4764 :
4765 1 : torture_wait_for_oplock_break(tctx);
4766 1 : if (break_info.count != 0) {
4767 0 : torture_warning(tctx, "Stream open caused oplock break\n");
4768 : }
4769 :
4770 2 : done:
4771 1 : if (!smb2_util_handle_empty(h1)) {
4772 1 : smb2_util_close(tree, h1);
4773 : }
4774 1 : if (!smb2_util_handle_empty(h2)) {
4775 1 : smb2_util_close(tree, h2);
4776 : }
4777 1 : smb2_util_unlink(tree, fname);
4778 1 : return ret;
4779 : }
4780 :
4781 : /**
4782 : * 1) create testfile with stream
4783 : * 2) open stream r/w with batch oplock -> batch oplock granted
4784 : * 3) open stream r/o with batch oplock
4785 : *
4786 : * Verify 3) does trigger an oplock break
4787 : **/
4788 1 : static bool test_smb2_kernel_oplocks5(struct torture_context *tctx,
4789 : struct smb2_tree *tree)
4790 : {
4791 1 : const char *fname = "test_kernel_oplock4.dat";
4792 1 : const char *sname = "test_kernel_oplock4.dat:foo";
4793 : NTSTATUS status;
4794 1 : bool ret = true;
4795 : struct smb2_create create;
4796 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4797 :
4798 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4799 1 : tree->session->transport->oplock.private_data = tree;
4800 1 : ZERO_STRUCT(break_info);
4801 1 : smb2_util_unlink(tree, fname);
4802 :
4803 : /* 1 */
4804 1 : status = torture_smb2_testfile(tree, fname, &h1);
4805 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4806 : "Error creating testfile\n");
4807 1 : smb2_util_close(tree, h1);
4808 1 : ZERO_STRUCT(h1);
4809 :
4810 1 : ZERO_STRUCT(create);
4811 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4812 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4813 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4814 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4815 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4816 1 : create.in.fname = sname;
4817 :
4818 1 : status = smb2_create(tree, tctx, &create);
4819 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4820 1 : h1 = create.out.file.handle;
4821 1 : smb2_util_close(tree, h1);
4822 1 : ZERO_STRUCT(h1);
4823 :
4824 : /* 2 */
4825 1 : ZERO_STRUCT(create);
4826 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4827 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4828 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4829 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4830 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4831 1 : create.in.fname = sname;
4832 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4833 :
4834 1 : status = smb2_create(tree, tctx, &create);
4835 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4836 1 : h1 = create.out.file.handle;
4837 :
4838 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_BATCH, ret, done,
4839 : "Oplock level is not SMB2_OPLOCK_LEVEL_BATCH\n");
4840 :
4841 1 : ZERO_STRUCT(create);
4842 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4843 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4844 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4845 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4846 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4847 1 : create.in.fname = sname;
4848 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
4849 :
4850 1 : status = smb2_create(tree, tctx, &create);
4851 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4852 1 : h2 = create.out.file.handle;
4853 :
4854 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_NONE, ret, done,
4855 : "Oplock level is not SMB2_OPLOCK_LEVEL_NONE\n");
4856 :
4857 1 : torture_wait_for_oplock_break(tctx);
4858 1 : if (break_info.count != 1) {
4859 0 : torture_warning(tctx, "Stream open didn't cause oplock break\n");
4860 : }
4861 :
4862 2 : done:
4863 1 : if (!smb2_util_handle_empty(h1)) {
4864 1 : smb2_util_close(tree, h1);
4865 : }
4866 1 : if (!smb2_util_handle_empty(h2)) {
4867 1 : smb2_util_close(tree, h2);
4868 : }
4869 1 : smb2_util_unlink(tree, fname);
4870 1 : return ret;
4871 : }
4872 :
4873 : /**
4874 : * 1) create testfile with stream
4875 : * 2) 1st client opens stream r/w with batch oplock -> batch oplock granted
4876 : * 3) 2nd client opens stream r/o with batch oplock
4877 : *
4878 : * Verify 3) does trigger an oplock break
4879 : **/
4880 1 : static bool test_smb2_kernel_oplocks6(struct torture_context *tctx,
4881 : struct smb2_tree *tree,
4882 : struct smb2_tree *tree2)
4883 : {
4884 1 : const char *fname = "test_kernel_oplock6.dat";
4885 1 : const char *sname = "test_kernel_oplock6.dat:foo";
4886 : NTSTATUS status;
4887 1 : bool ret = true;
4888 : struct smb2_create create;
4889 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4890 :
4891 1 : smb2_util_unlink(tree, fname);
4892 1 : status = torture_smb2_testfile(tree, fname, &h1);
4893 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4894 : "Error creating testfile\n");
4895 1 : smb2_util_close(tree, h1);
4896 1 : ZERO_STRUCT(h1);
4897 :
4898 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
4899 1 : tree->session->transport->oplock.private_data = tree;
4900 1 : ZERO_STRUCT(break_info);
4901 :
4902 : /* 1 */
4903 1 : ZERO_STRUCT(create);
4904 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4905 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4906 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4907 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4908 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4909 1 : create.in.fname = sname;
4910 :
4911 1 : status = smb2_create(tree, tctx, &create);
4912 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4913 1 : h1 = create.out.file.handle;
4914 1 : smb2_util_close(tree, h1);
4915 1 : ZERO_STRUCT(h1);
4916 :
4917 : /* 2 */
4918 1 : ZERO_STRUCT(create);
4919 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
4920 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4921 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4922 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
4923 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4924 1 : create.in.fname = fname;
4925 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
4926 :
4927 1 : status = smb2_create(tree, tctx, &create);
4928 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4929 1 : h1 = create.out.file.handle;
4930 :
4931 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
4932 : "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
4933 :
4934 : /* 3 */
4935 1 : ZERO_STRUCT(create);
4936 1 : create.in.desired_access = SEC_RIGHTS_FILE_READ;
4937 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
4938 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
4939 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
4940 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4941 1 : create.in.fname = fname;
4942 :
4943 1 : status = smb2_create(tree2, tctx, &create);
4944 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
4945 1 : h2 = create.out.file.handle;
4946 :
4947 1 : torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_NONE, ret, done,
4948 : "Oplock level is not SMB2_OPLOCK_LEVEL_NONE\n");
4949 :
4950 1 : torture_wait_for_oplock_break(tctx);
4951 1 : torture_assert_goto(tctx, break_info.count == 1, ret, done, "Expected 1 oplock break\n");
4952 :
4953 2 : done:
4954 1 : if (!smb2_util_handle_empty(h1)) {
4955 1 : smb2_util_close(tree, h1);
4956 : }
4957 1 : if (!smb2_util_handle_empty(h2)) {
4958 1 : smb2_util_close(tree, h2);
4959 : }
4960 1 : smb2_util_unlink(tree, fname);
4961 1 : return ret;
4962 : }
4963 :
4964 : /**
4965 : * Recreate regression test from bug:
4966 : *
4967 : * https://bugzilla.samba.org/show_bug.cgi?id=13058
4968 : *
4969 : * 1. smbd-1 opens the file and sets the oplock
4970 : * 2. smbd-2 tries to open the file. open() fails(EAGAIN) and open is deferred.
4971 : * 3. smbd-1 sends oplock break request to the client.
4972 : * 4. smbd-1 closes the file.
4973 : * 5. smbd-1 opens the file and sets the oplock.
4974 : * 6. smbd-2 calls defer_open_done(), and should re-break the oplock.
4975 : **/
4976 :
4977 1 : static bool test_smb2_kernel_oplocks7(struct torture_context *tctx,
4978 : struct smb2_tree *tree,
4979 : struct smb2_tree *tree2)
4980 : {
4981 1 : const char *fname = "test_kernel_oplock7.dat";
4982 : NTSTATUS status;
4983 1 : bool ret = true;
4984 : struct smb2_create create;
4985 1 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
4986 : struct smb2_create create_2;
4987 : struct smb2_create io;
4988 : struct smb2_request *req;
4989 :
4990 1 : smb2_util_unlink(tree, fname);
4991 1 : status = torture_smb2_testfile(tree, fname, &h1);
4992 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
4993 : "Error creating testfile\n");
4994 1 : smb2_util_close(tree, h1);
4995 1 : ZERO_STRUCT(h1);
4996 :
4997 : /* Close the open file on break. */
4998 1 : tree->session->transport->oplock.handler = torture_oplock_handler_close;
4999 1 : tree->session->transport->oplock.private_data = tree;
5000 1 : ZERO_STRUCT(break_info);
5001 :
5002 : /* 1 - open file with oplock */
5003 1 : ZERO_STRUCT(create);
5004 1 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
5005 1 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
5006 1 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
5007 1 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
5008 1 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
5009 1 : create.in.fname = fname;
5010 1 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
5011 :
5012 1 : status = smb2_create(tree, tctx, &create);
5013 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5014 : "Error opening the file\n");
5015 1 : CHECK_VAL(create.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
5016 :
5017 : /* 2 - open file to break oplock */
5018 1 : ZERO_STRUCT(create_2);
5019 1 : create_2.in.desired_access = SEC_RIGHTS_FILE_ALL;
5020 1 : create_2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
5021 1 : create_2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
5022 1 : create_2.in.create_disposition = NTCREATEX_DISP_OPEN;
5023 1 : create_2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
5024 1 : create_2.in.fname = fname;
5025 1 : create_2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
5026 :
5027 : /* Open on tree2 - should cause a break on tree */
5028 1 : req = smb2_create_send(tree2, &create_2);
5029 1 : torture_assert(tctx, req != NULL, "smb2_create_send");
5030 :
5031 : /* The oplock break handler should close the file. */
5032 : /* Steps 3 & 4. */
5033 1 : torture_wait_for_oplock_break(tctx);
5034 :
5035 1 : tree->session->transport->oplock.handler = torture_oplock_handler;
5036 :
5037 : /*
5038 : * 5 - re-open on tree. NB. There is a race here
5039 : * depending on which smbd goes first. We either get
5040 : * an oplock level of SMB2_OPLOCK_LEVEL_EXCLUSIVE if
5041 : * the close and re-open on tree is processed first, or
5042 : * SMB2_OPLOCK_LEVEL_NONE if the pending create on
5043 : * tree2 is processed first.
5044 : */
5045 1 : status = smb2_create(tree, tctx, &create);
5046 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5047 : "Error opening the file\n");
5048 :
5049 1 : h1 = create.out.file.handle;
5050 2 : if (create.out.oplock_level != SMB2_OPLOCK_LEVEL_EXCLUSIVE &&
5051 1 : create.out.oplock_level != SMB2_OPLOCK_LEVEL_NONE) {
5052 0 : torture_result(tctx,
5053 : TORTURE_FAIL,
5054 : "(%s): wrong value for oplock got 0x%x\n",
5055 : __location__,
5056 0 : (unsigned int)create.out.oplock_level);
5057 0 : ret = false;
5058 0 : goto done;
5059 :
5060 : }
5061 :
5062 : /* 6 - retrieve the second open. */
5063 1 : status = smb2_create_recv(req, tctx, &io);
5064 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5065 : "Error opening the file\n");
5066 1 : h2 = io.out.file.handle;
5067 1 : CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
5068 :
5069 2 : done:
5070 1 : if (!smb2_util_handle_empty(h1)) {
5071 1 : smb2_util_close(tree, h1);
5072 : }
5073 1 : if (!smb2_util_handle_empty(h2)) {
5074 1 : smb2_util_close(tree2, h2);
5075 : }
5076 1 : smb2_util_unlink(tree, fname);
5077 1 : return ret;
5078 : }
5079 :
5080 : #ifdef HAVE_KERNEL_OPLOCKS_LINUX
5081 :
5082 : #ifndef RT_SIGNAL_LEASE
5083 : #define RT_SIGNAL_LEASE (SIGRTMIN+1)
5084 : #endif
5085 :
5086 : static int got_break;
5087 :
5088 : /*
5089 : * Signal handler.
5090 : */
5091 :
5092 0 : static void got_rt_break(int sig)
5093 : {
5094 0 : got_break = 1;
5095 0 : }
5096 :
5097 : static int got_alarm;
5098 :
5099 : /*
5100 : * Signal handler.
5101 : */
5102 :
5103 0 : static void got_alarm_fn(int sig)
5104 : {
5105 0 : got_alarm = 1;
5106 0 : }
5107 :
5108 : /*
5109 : * Child process function.
5110 : */
5111 :
5112 0 : static int do_child_process(int pipefd, const char *name)
5113 : {
5114 0 : int ret = 0;
5115 0 : int fd = -1;
5116 0 : char c = 0;
5117 : struct sigaction act;
5118 : sigset_t set;
5119 : sigset_t empty_set;
5120 :
5121 : /* Block RT_SIGNAL_LEASE and SIGALRM. */
5122 0 : sigemptyset(&set);
5123 0 : sigemptyset(&empty_set);
5124 0 : sigaddset(&set, RT_SIGNAL_LEASE);
5125 0 : sigaddset(&set, SIGALRM);
5126 0 : ret = sigprocmask(SIG_SETMASK, &set, NULL);
5127 0 : if (ret == -1) {
5128 0 : return 11;
5129 : }
5130 :
5131 : /* Set up a signal handler for RT_SIGNAL_LEASE. */
5132 0 : ZERO_STRUCT(act);
5133 0 : act.sa_handler = got_rt_break;
5134 0 : ret = sigaction(RT_SIGNAL_LEASE, &act, NULL);
5135 0 : if (ret == -1) {
5136 0 : return 1;
5137 : }
5138 : /* Set up a signal handler for SIGALRM. */
5139 0 : ZERO_STRUCT(act);
5140 0 : act.sa_handler = got_alarm_fn;
5141 0 : ret = sigaction(SIGALRM, &act, NULL);
5142 0 : if (ret == -1) {
5143 0 : return 1;
5144 : }
5145 : /* Open the passed in file and get a kernel oplock. */
5146 0 : fd = open(name, O_RDWR, 0666);
5147 0 : if (fd == -1) {
5148 0 : return 2;
5149 : }
5150 :
5151 0 : ret = fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE);
5152 0 : if (ret == -1) {
5153 0 : close(fd);
5154 0 : return 3;
5155 : }
5156 :
5157 0 : ret = fcntl(fd, F_SETLEASE, F_WRLCK);
5158 0 : if (ret == -1) {
5159 0 : close(fd);
5160 0 : return 4;
5161 : }
5162 :
5163 : /* Tell the parent we're ready. */
5164 0 : ret = sys_write(pipefd, &c, 1);
5165 0 : if (ret != 1) {
5166 0 : close(fd);
5167 0 : return 5;
5168 : }
5169 :
5170 : /* Ensure the pause doesn't hang forever. */
5171 0 : alarm(5);
5172 :
5173 : /* Wait for RT_SIGNAL_LEASE or SIGALRM. */
5174 0 : ret = sigsuspend(&empty_set);
5175 0 : if (ret != -1 || errno != EINTR) {
5176 0 : close(fd);
5177 0 : return 6;
5178 : }
5179 :
5180 0 : if (got_alarm == 1) {
5181 0 : close(fd);
5182 0 : return 10;
5183 : }
5184 :
5185 0 : if (got_break != 1) {
5186 0 : close(fd);
5187 0 : return 7;
5188 : }
5189 :
5190 : /* Cancel any pending alarm. */
5191 0 : alarm(0);
5192 :
5193 : /* Force the server to wait for 3 seconds. */
5194 0 : sleep(3);
5195 :
5196 : /* Remove our lease. */
5197 0 : ret = fcntl(fd, F_SETLEASE, F_UNLCK);
5198 0 : if (ret == -1) {
5199 0 : close(fd);
5200 0 : return 8;
5201 : }
5202 :
5203 0 : ret = close(fd);
5204 0 : if (ret == -1) {
5205 0 : return 9;
5206 : }
5207 :
5208 : /* All is well. */
5209 0 : return 0;
5210 : }
5211 :
5212 1 : static bool wait_for_child_oplock(struct torture_context *tctx,
5213 : const char *localdir,
5214 : const char *fname)
5215 : {
5216 : int fds[2];
5217 : int ret;
5218 : pid_t pid;
5219 1 : char *name = talloc_asprintf(tctx,
5220 : "%s/%s",
5221 : localdir,
5222 : fname);
5223 :
5224 1 : torture_assert(tctx, name != NULL, "talloc failed");
5225 :
5226 1 : ret = pipe(fds);
5227 1 : torture_assert(tctx, ret != -1, "pipe failed");
5228 :
5229 1 : pid = fork();
5230 1 : torture_assert(tctx, pid != (pid_t)-1, "fork failed");
5231 :
5232 1 : if (pid != (pid_t)0) {
5233 : char c;
5234 : /* Parent. */
5235 1 : TALLOC_FREE(name);
5236 1 : close(fds[1]);
5237 1 : ret = sys_read(fds[0], &c, 1);
5238 1 : torture_assert(tctx, ret == 1, "read failed");
5239 1 : return true;
5240 : }
5241 :
5242 : /* Child process. */
5243 0 : close(fds[0]);
5244 0 : ret = do_child_process(fds[1], name);
5245 0 : _exit(ret);
5246 : /* Notreached. */
5247 : }
5248 : #else
5249 : static bool wait_for_child_oplock(struct torture_context *tctx,
5250 : const char *localdir,
5251 : const char *fname)
5252 : {
5253 : return false;
5254 : }
5255 : #endif
5256 :
5257 1 : static void child_sig_term_handler(struct tevent_context *ev,
5258 : struct tevent_signal *se,
5259 : int signum,
5260 : int count,
5261 : void *siginfo,
5262 : void *private_data)
5263 : {
5264 1 : int *pstatus = (int *)private_data;
5265 1 : int status = 0;
5266 :
5267 1 : wait(&status);
5268 1 : if (WIFEXITED(status)) {
5269 1 : *pstatus = WEXITSTATUS(status);
5270 : } else {
5271 0 : *pstatus = status;
5272 : }
5273 1 : }
5274 :
5275 : /*
5276 : * Deal with a non-smbd process holding a kernel oplock.
5277 : */
5278 :
5279 1 : static bool test_smb2_kernel_oplocks8(struct torture_context *tctx,
5280 : struct smb2_tree *tree)
5281 : {
5282 1 : const char *fname = "test_kernel_oplock8.dat";
5283 1 : const char *fname1 = "tmp_test_kernel_oplock8.dat";
5284 : NTSTATUS status;
5285 1 : bool ret = true;
5286 : struct smb2_create io;
5287 1 : struct smb2_request *req = NULL;
5288 1 : struct smb2_handle h1 = {{0}};
5289 1 : struct smb2_handle h2 = {{0}};
5290 1 : const char *localdir = torture_setting_string(tctx, "localdir", NULL);
5291 1 : struct tevent_signal *se = NULL;
5292 1 : int child_exit_code = -1;
5293 : time_t start;
5294 : time_t end;
5295 :
5296 : #ifndef HAVE_KERNEL_OPLOCKS_LINUX
5297 : torture_skip(tctx, "Need kernel oplocks for test");
5298 : #endif
5299 :
5300 1 : if (localdir == NULL) {
5301 0 : torture_skip(tctx, "Need localdir for test");
5302 : }
5303 :
5304 1 : smb2_util_unlink(tree, fname);
5305 1 : smb2_util_unlink(tree, fname1);
5306 1 : status = torture_smb2_testfile(tree, fname, &h1);
5307 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5308 : "Error creating testfile\n");
5309 1 : smb2_util_close(tree, h1);
5310 1 : ZERO_STRUCT(h1);
5311 :
5312 1 : se = tevent_add_signal(tctx->ev,
5313 : tctx,
5314 : SIGCHLD,
5315 : 0,
5316 : child_sig_term_handler,
5317 : &child_exit_code);
5318 1 : torture_assert(tctx, se != NULL, "tevent_add_signal failed\n");
5319 :
5320 : /* Take the oplock locally in a sub-process. */
5321 1 : ret = wait_for_child_oplock(tctx, localdir, fname);
5322 1 : torture_assert_goto(tctx, ret, ret, done,
5323 : "Wait for child process failed.\n");
5324 :
5325 : /*
5326 : * Now try and open. This should block for 3 seconds.
5327 : * while the child process is still alive.
5328 : */
5329 :
5330 1 : ZERO_STRUCT(io);
5331 1 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
5332 1 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
5333 1 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
5334 1 : io.in.share_access =
5335 : NTCREATEX_SHARE_ACCESS_DELETE|
5336 : NTCREATEX_SHARE_ACCESS_READ|
5337 : NTCREATEX_SHARE_ACCESS_WRITE;
5338 1 : io.in.create_options = 0;
5339 1 : io.in.fname = fname;
5340 :
5341 1 : req = smb2_create_send(tree, &io);
5342 1 : torture_assert_goto(tctx, req != NULL,
5343 : ret, done, "smb2_create_send");
5344 :
5345 : /* Ensure while the open is blocked the smbd is
5346 : still serving other requests. */
5347 1 : io.in.fname = fname1;
5348 1 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
5349 :
5350 : /* Time the start -> end of the request. */
5351 1 : start = time(NULL);
5352 1 : status = smb2_create(tree, tctx, &io);
5353 1 : end = time(NULL);
5354 :
5355 : /* Should succeed. */
5356 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5357 : "Error opening the second file\n");
5358 1 : h1 = io.out.file.handle;
5359 :
5360 : /* in less than 2 seconds. Otherwise the server blocks. */
5361 1 : torture_assert_goto(tctx, end - start < 2,
5362 : ret, done, "server was blocked !");
5363 :
5364 : /* Pick up the return for the initial blocking open. */
5365 1 : status = smb2_create_recv(req, tctx, &io);
5366 :
5367 : /* Which should also have succeeded. */
5368 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
5369 : "Error opening the file\n");
5370 1 : h2 = io.out.file.handle;
5371 :
5372 : /* Wait for the exit code from the child. */
5373 2 : while (child_exit_code == -1) {
5374 0 : int rval = tevent_loop_once(tctx->ev);
5375 0 : torture_assert_goto(tctx, rval == 0, ret,
5376 : done, "tevent_loop_once error\n");
5377 : }
5378 :
5379 1 : torture_assert_int_equal_goto(tctx, child_exit_code, 0,
5380 : ret, done, "Bad child exit code");
5381 :
5382 2 : done:
5383 1 : if (!smb2_util_handle_empty(h1)) {
5384 1 : smb2_util_close(tree, h1);
5385 : }
5386 1 : if (!smb2_util_handle_empty(h2)) {
5387 1 : smb2_util_close(tree, h2);
5388 : }
5389 1 : smb2_util_unlink(tree, fname);
5390 1 : smb2_util_unlink(tree, fname1);
5391 1 : return ret;
5392 : }
5393 :
5394 2355 : struct torture_suite *torture_smb2_kernel_oplocks_init(TALLOC_CTX *ctx)
5395 : {
5396 1897 : struct torture_suite *suite =
5397 458 : torture_suite_create(ctx, "kernel-oplocks");
5398 :
5399 2355 : torture_suite_add_1smb2_test(suite, "kernel_oplocks1", test_smb2_kernel_oplocks1);
5400 2355 : torture_suite_add_1smb2_test(suite, "kernel_oplocks2", test_smb2_kernel_oplocks2);
5401 2355 : torture_suite_add_2smb2_test(suite, "kernel_oplocks3", test_smb2_kernel_oplocks3);
5402 2355 : torture_suite_add_1smb2_test(suite, "kernel_oplocks4", test_smb2_kernel_oplocks4);
5403 2355 : torture_suite_add_1smb2_test(suite, "kernel_oplocks5", test_smb2_kernel_oplocks5);
5404 2355 : torture_suite_add_2smb2_test(suite, "kernel_oplocks6", test_smb2_kernel_oplocks6);
5405 2355 : torture_suite_add_2smb2_test(suite, "kernel_oplocks7", test_smb2_kernel_oplocks7);
5406 2355 : torture_suite_add_1smb2_test(suite, "kernel_oplocks8", test_smb2_kernel_oplocks8);
5407 :
5408 2355 : suite->description = talloc_strdup(suite, "SMB2-KERNEL-OPLOCK tests");
5409 :
5410 2355 : return suite;
5411 : }
|