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