2 Unix SMB/CIFS implementation.
4 test suite for SMB2 compounded requests
6 Copyright (C) Stefan Metzmacher 2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25 #include "torture/torture.h"
26 #include "torture/smb2/proto.h"
27 #include "../libcli/smb/smbXcli_base.h"
29 #define CHECK_STATUS(status, correct) do { \
30 if (!NT_STATUS_EQUAL(status, correct)) { \
31 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
32 nt_errstr(status), nt_errstr(correct)); \
37 #define CHECK_VALUE(v, correct) do { \
38 if ((v) != (correct)) { \
39 torture_result(tctx, TORTURE_FAIL, \
40 "(%s) Incorrect value %s=%d - should be %d\n", \
41 __location__, #v, (int)v, (int)correct); \
46 struct smb2_handle handle;
51 NTSTATUS failure_status;
54 static void torture_oplock_break_callback(struct smb2_request *req)
60 status = smb2_break_recv(req, &break_info.br);
61 if (!NT_STATUS_IS_OK(status)) {
62 break_info.failures++;
63 break_info.failure_status = status;
69 /* A general oplock break notification handler. This should be used when a
70 * test expects to break from batch or exclusive to a lower level. */
71 static bool torture_oplock_handler(struct smb2_transport *transport,
72 const struct smb2_handle *handle,
76 struct smb2_tree *tree = private_data;
78 struct smb2_request *req;
79 ZERO_STRUCT(break_info.br);
81 break_info.handle = *handle;
82 break_info.level = level;
86 case SMB2_OPLOCK_LEVEL_II:
89 case SMB2_OPLOCK_LEVEL_NONE:
94 break_info.failures++;
96 printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
98 break_info.br.in.file.handle = *handle;
99 break_info.br.in.oplock_level = level;
100 break_info.br.in.reserved = 0;
101 break_info.br.in.reserved2 = 0;
103 req = smb2_break_send(tree, &break_info.br);
104 req->async.fn = torture_oplock_break_callback;
105 req->async.private_data = NULL;
109 static bool test_compound_break(struct torture_context *tctx,
110 struct smb2_tree *tree)
112 const char *fname1 = "some-file.pptx";
116 struct smb2_create io2;
117 struct smb2_getinfo gf;
118 struct smb2_request *req[2];
119 struct smb2_handle h1;
120 struct smb2_handle h;
122 tree->session->transport->oplock.handler = torture_oplock_handler;
123 tree->session->transport->oplock.private_data = tree;
125 ZERO_STRUCT(break_info);
130 ZERO_STRUCT(io1.smb2);
131 io1.generic.level = RAW_OPEN_SMB2;
132 io1.smb2.in.desired_access = (SEC_STD_SYNCHRONIZE|
133 SEC_STD_READ_CONTROL|
134 SEC_FILE_READ_ATTRIBUTE|
137 io1.smb2.in.alloc_size = 0;
138 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
139 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
140 NTCREATEX_SHARE_ACCESS_WRITE|
141 NTCREATEX_SHARE_ACCESS_DELETE;
142 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
143 io1.smb2.in.create_options = 0;
144 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
145 io1.smb2.in.security_flags = 0;
146 io1.smb2.in.fname = fname1;
148 torture_comment(tctx, "TEST2: open a file with an batch "
149 "oplock (share mode: all)\n");
150 io1.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
152 status = smb2_create(tree, tctx, &(io1.smb2));
153 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
155 h1 = io1.smb2.out.file.handle;
157 torture_comment(tctx, "TEST2: Opening second time with compound\n");
161 io2.in.desired_access = (SEC_STD_SYNCHRONIZE|
162 SEC_FILE_READ_ATTRIBUTE|
164 io2.in.alloc_size = 0;
165 io2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
166 io2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
167 NTCREATEX_SHARE_ACCESS_WRITE|
168 NTCREATEX_SHARE_ACCESS_DELETE;
169 io2.in.create_disposition = NTCREATEX_DISP_OPEN;
170 io2.in.create_options = 0;
171 io2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
172 io2.in.security_flags = 0;
173 io2.in.fname = fname1;
174 io2.in.oplock_level = 0;
176 smb2_transport_compound_start(tree->session->transport, 2);
178 req[0] = smb2_create_send(tree, &io2);
180 smb2_transport_compound_set_related(tree->session->transport, true);
182 h.data[0] = UINT64_MAX;
183 h.data[1] = UINT64_MAX;
186 gf.in.file.handle = h;
187 gf.in.info_type = SMB2_GETINFO_FILE;
188 gf.in.info_class = 0x16;
189 gf.in.output_buffer_length = 0x1000;
190 gf.in.input_buffer_length = 0;
192 req[1] = smb2_getinfo_send(tree, &gf);
194 status = smb2_create_recv(req[0], tree, &io2);
195 CHECK_STATUS(status, NT_STATUS_OK);
197 status = smb2_getinfo_recv(req[1], tree, &gf);
198 CHECK_STATUS(status, NT_STATUS_OK);
202 smb2_util_close(tree, h1);
203 smb2_util_unlink(tree, fname1);
207 static bool test_compound_related1(struct torture_context *tctx,
208 struct smb2_tree *tree)
210 struct smb2_handle hd;
211 struct smb2_create cr;
213 const char *fname = "compound_related1.dat";
214 struct smb2_close cl;
216 struct smb2_request *req[2];
217 struct smbXcli_tcon *saved_tcon = tree->smbXcli;
218 struct smbXcli_session *saved_session = tree->session->smbXcli;
220 smb2_transport_credits_ask_num(tree->session->transport, 2);
222 smb2_util_unlink(tree, fname);
224 smb2_transport_credits_ask_num(tree->session->transport, 1);
227 cr.in.security_flags = 0x00;
228 cr.in.oplock_level = 0;
229 cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
230 cr.in.create_flags = 0x00000000;
231 cr.in.reserved = 0x00000000;
232 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
233 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
234 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
235 NTCREATEX_SHARE_ACCESS_WRITE |
236 NTCREATEX_SHARE_ACCESS_DELETE;
237 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
238 cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
239 NTCREATEX_OPTIONS_ASYNC_ALERT |
240 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
244 smb2_transport_compound_start(tree->session->transport, 2);
246 req[0] = smb2_create_send(tree, &cr);
248 smb2_transport_compound_set_related(tree->session->transport, true);
250 hd.data[0] = UINT64_MAX;
251 hd.data[1] = UINT64_MAX;
254 cl.in.file.handle = hd;
256 tree->smbXcli = smbXcli_tcon_create(tree);
257 smb2cli_tcon_set_values(tree->smbXcli,
259 0xFFFFFFFF, /* tcon_id */
262 0, /* capabilities */
263 0 /* maximal_access */);
265 tree->session->smbXcli = smbXcli_session_copy(tree->session,
266 tree->session->smbXcli);
267 smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
269 req[1] = smb2_close_send(tree, &cl);
271 status = smb2_create_recv(req[0], tree, &cr);
272 CHECK_STATUS(status, NT_STATUS_OK);
273 status = smb2_close_recv(req[1], &cl);
274 CHECK_STATUS(status, NT_STATUS_OK);
276 TALLOC_FREE(tree->smbXcli);
277 tree->smbXcli = saved_tcon;
278 TALLOC_FREE(tree->session->smbXcli);
279 tree->session->smbXcli = saved_session;
281 smb2_util_unlink(tree, fname);
286 static bool test_compound_related2(struct torture_context *tctx,
287 struct smb2_tree *tree)
289 struct smb2_handle hd;
290 struct smb2_create cr;
292 const char *fname = "compound_related2.dat";
293 struct smb2_close cl;
295 struct smb2_request *req[5];
296 struct smbXcli_tcon *saved_tcon = tree->smbXcli;
297 struct smbXcli_session *saved_session = tree->session->smbXcli;
299 smb2_transport_credits_ask_num(tree->session->transport, 5);
301 smb2_util_unlink(tree, fname);
303 smb2_transport_credits_ask_num(tree->session->transport, 1);
306 cr.in.security_flags = 0x00;
307 cr.in.oplock_level = 0;
308 cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
309 cr.in.create_flags = 0x00000000;
310 cr.in.reserved = 0x00000000;
311 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
312 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
313 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
314 NTCREATEX_SHARE_ACCESS_WRITE |
315 NTCREATEX_SHARE_ACCESS_DELETE;
316 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
317 cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
318 NTCREATEX_OPTIONS_ASYNC_ALERT |
319 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
323 smb2_transport_compound_start(tree->session->transport, 5);
325 req[0] = smb2_create_send(tree, &cr);
327 hd.data[0] = UINT64_MAX;
328 hd.data[1] = UINT64_MAX;
330 smb2_transport_compound_set_related(tree->session->transport, true);
333 cl.in.file.handle = hd;
335 tree->smbXcli = smbXcli_tcon_create(tree);
336 smb2cli_tcon_set_values(tree->smbXcli,
338 0xFFFFFFFF, /* tcon_id */
341 0, /* capabilities */
342 0 /* maximal_access */);
344 tree->session->smbXcli = smbXcli_session_copy(tree->session,
345 tree->session->smbXcli);
346 smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
348 req[1] = smb2_close_send(tree, &cl);
349 req[2] = smb2_close_send(tree, &cl);
350 req[3] = smb2_close_send(tree, &cl);
351 req[4] = smb2_close_send(tree, &cl);
353 status = smb2_create_recv(req[0], tree, &cr);
354 CHECK_STATUS(status, NT_STATUS_OK);
355 status = smb2_close_recv(req[1], &cl);
356 CHECK_STATUS(status, NT_STATUS_OK);
357 status = smb2_close_recv(req[2], &cl);
358 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
359 status = smb2_close_recv(req[3], &cl);
360 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
361 status = smb2_close_recv(req[4], &cl);
362 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
364 TALLOC_FREE(tree->smbXcli);
365 tree->smbXcli = saved_tcon;
366 TALLOC_FREE(tree->session->smbXcli);
367 tree->session->smbXcli = saved_session;
369 smb2_util_unlink(tree, fname);
374 static bool test_compound_related3(struct torture_context *tctx,
375 struct smb2_tree *tree)
377 struct smb2_handle hd;
378 struct smb2_ioctl io;
379 struct smb2_create cr;
380 struct smb2_close cl;
381 const char *fname = "compound_related3.dat";
382 struct smb2_request *req[3];
386 smb2_util_unlink(tree, fname);
389 cr.in.security_flags = 0x00;
390 cr.in.oplock_level = 0;
391 cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
392 cr.in.create_flags = 0x00000000;
393 cr.in.reserved = 0x00000000;
394 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
395 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
396 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
397 NTCREATEX_SHARE_ACCESS_WRITE |
398 NTCREATEX_SHARE_ACCESS_DELETE;
399 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
400 cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
401 NTCREATEX_OPTIONS_ASYNC_ALERT |
402 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
406 smb2_transport_compound_start(tree->session->transport, 3);
408 req[0] = smb2_create_send(tree, &cr);
410 hd.data[0] = UINT64_MAX;
411 hd.data[1] = UINT64_MAX;
413 smb2_transport_compound_set_related(tree->session->transport, true);
416 io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID;
417 io.in.file.handle = hd;
419 io.in.max_response_size = 64;
422 req[1] = smb2_ioctl_send(tree, &io);
425 cl.in.file.handle = hd;
427 req[2] = smb2_close_send(tree, &cl);
429 status = smb2_create_recv(req[0], tree, &cr);
430 CHECK_STATUS(status, NT_STATUS_OK);
431 status = smb2_ioctl_recv(req[1], tree, &io);
432 CHECK_STATUS(status, NT_STATUS_OK);
433 status = smb2_close_recv(req[2], &cl);
434 CHECK_STATUS(status, NT_STATUS_OK);
436 status = smb2_util_unlink(tree, fname);
437 CHECK_STATUS(status, NT_STATUS_OK);
444 static bool test_compound_padding(struct torture_context *tctx,
445 struct smb2_tree *tree)
447 struct smb2_handle h;
448 struct smb2_create cr;
450 const char *fname = "compound_read.dat";
451 const char *sname = "compound_read.dat:foo";
452 struct smb2_request *req[3];
456 smb2_util_unlink(tree, fname);
460 cr.in.desired_access = SEC_FILE_WRITE_DATA;
461 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
462 cr.in.create_disposition = NTCREATEX_DISP_CREATE;
463 cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
465 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
466 NTCREATEX_SHARE_ACCESS_WRITE|
467 NTCREATEX_SHARE_ACCESS_DELETE;
468 status = smb2_create(tree, tctx, &cr);
469 CHECK_STATUS(status, NT_STATUS_OK);
470 h = cr.out.file.handle;
472 status = smb2_util_write(tree, h, "123", 0, 3);
473 CHECK_STATUS(status, NT_STATUS_OK);
475 smb2_util_close(tree, h);
479 cr.in.desired_access = SEC_FILE_WRITE_DATA;
480 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
481 cr.in.create_disposition = NTCREATEX_DISP_CREATE;
482 cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
484 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
485 NTCREATEX_SHARE_ACCESS_WRITE|
486 NTCREATEX_SHARE_ACCESS_DELETE;
487 status = smb2_create(tree, tctx, &cr);
488 CHECK_STATUS(status, NT_STATUS_OK);
489 h = cr.out.file.handle;
491 status = smb2_util_write(tree, h, "456", 0, 3);
492 CHECK_STATUS(status, NT_STATUS_OK);
494 smb2_util_close(tree, h);
496 /* Check compound read from basefile */
497 smb2_transport_compound_start(tree->session->transport, 2);
500 cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
501 cr.in.desired_access = SEC_FILE_READ_DATA;
502 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
503 cr.in.create_disposition = NTCREATEX_DISP_OPEN;
505 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
506 NTCREATEX_SHARE_ACCESS_WRITE|
507 NTCREATEX_SHARE_ACCESS_DELETE;
508 req[0] = smb2_create_send(tree, &cr);
510 smb2_transport_compound_set_related(tree->session->transport, true);
513 h.data[0] = UINT64_MAX;
514 h.data[1] = UINT64_MAX;
515 r.in.file.handle = h;
519 req[1] = smb2_read_send(tree, &r);
521 status = smb2_create_recv(req[0], tree, &cr);
522 CHECK_STATUS(status, NT_STATUS_OK);
525 * We must do a manual smb2_request_receive() in order to be
526 * able to check the transport layer info, as smb2_read_recv()
527 * will destroy the req. smb2_read_recv() will call
528 * smb2_request_receive() again, but that's ok.
530 if (!smb2_request_receive(req[1]) ||
531 !smb2_request_is_ok(req[1])) {
532 torture_fail(tctx, "failed to receive read request");
536 * size must be 24: 16 byte read response header plus 3
537 * requested bytes padded to an 8 byte boundary.
539 CHECK_VALUE(req[1]->in.body_size, 24);
541 status = smb2_read_recv(req[1], tree, &r);
542 CHECK_STATUS(status, NT_STATUS_OK);
544 smb2_util_close(tree, cr.out.file.handle);
546 /* Check compound read from stream */
547 smb2_transport_compound_start(tree->session->transport, 2);
550 cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
551 cr.in.desired_access = SEC_FILE_READ_DATA;
552 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
553 cr.in.create_disposition = NTCREATEX_DISP_OPEN;
555 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
556 NTCREATEX_SHARE_ACCESS_WRITE|
557 NTCREATEX_SHARE_ACCESS_DELETE;
558 req[0] = smb2_create_send(tree, &cr);
560 smb2_transport_compound_set_related(tree->session->transport, true);
563 h.data[0] = UINT64_MAX;
564 h.data[1] = UINT64_MAX;
565 r.in.file.handle = h;
569 req[1] = smb2_read_send(tree, &r);
571 status = smb2_create_recv(req[0], tree, &cr);
572 CHECK_STATUS(status, NT_STATUS_OK);
575 * We must do a manual smb2_request_receive() in order to be
576 * able to check the transport layer info, as smb2_read_recv()
577 * will destroy the req. smb2_read_recv() will call
578 * smb2_request_receive() again, but that's ok.
580 if (!smb2_request_receive(req[1]) ||
581 !smb2_request_is_ok(req[1])) {
582 torture_fail(tctx, "failed to receive read request");
586 * size must be 24: 16 byte read response header plus 3
587 * requested bytes padded to an 8 byte boundary.
589 CHECK_VALUE(req[1]->in.body_size, 24);
591 status = smb2_read_recv(req[1], tree, &r);
592 CHECK_STATUS(status, NT_STATUS_OK);
594 h = cr.out.file.handle;
596 /* Check 2 compound (unrelateated) reads from existing stream handle */
597 smb2_transport_compound_start(tree->session->transport, 2);
600 r.in.file.handle = h;
604 req[0] = smb2_read_send(tree, &r);
605 req[1] = smb2_read_send(tree, &r);
608 * We must do a manual smb2_request_receive() in order to be
609 * able to check the transport layer info, as smb2_read_recv()
610 * will destroy the req. smb2_read_recv() will call
611 * smb2_request_receive() again, but that's ok.
613 if (!smb2_request_receive(req[0]) ||
614 !smb2_request_is_ok(req[0])) {
615 torture_fail(tctx, "failed to receive read request");
617 if (!smb2_request_receive(req[1]) ||
618 !smb2_request_is_ok(req[1])) {
619 torture_fail(tctx, "failed to receive read request");
623 * size must be 24: 16 byte read response header plus 3
624 * requested bytes padded to an 8 byte boundary.
626 CHECK_VALUE(req[0]->in.body_size, 24);
627 CHECK_VALUE(req[1]->in.body_size, 24);
629 status = smb2_read_recv(req[0], tree, &r);
630 CHECK_STATUS(status, NT_STATUS_OK);
631 status = smb2_read_recv(req[1], tree, &r);
632 CHECK_STATUS(status, NT_STATUS_OK);
635 * now try a single read from the stream and verify there's no padding
638 r.in.file.handle = h;
642 req[0] = smb2_read_send(tree, &r);
645 * We must do a manual smb2_request_receive() in order to be
646 * able to check the transport layer info, as smb2_read_recv()
647 * will destroy the req. smb2_read_recv() will call
648 * smb2_request_receive() again, but that's ok.
650 if (!smb2_request_receive(req[0]) ||
651 !smb2_request_is_ok(req[0])) {
652 torture_fail(tctx, "failed to receive read request");
656 * size must be 19: 16 byte read response header plus 3
657 * requested bytes without padding.
659 CHECK_VALUE(req[0]->in.body_size, 19);
661 status = smb2_read_recv(req[0], tree, &r);
662 CHECK_STATUS(status, NT_STATUS_OK);
664 smb2_util_close(tree, h);
666 status = smb2_util_unlink(tree, fname);
667 CHECK_STATUS(status, NT_STATUS_OK);
674 static bool test_compound_create_write_close(struct torture_context *tctx,
675 struct smb2_tree *tree)
677 struct smb2_handle handle = { .data = { UINT64_MAX, UINT64_MAX } };
678 struct smb2_create create;
679 struct smb2_write write;
680 struct smb2_close close;
681 const char *fname = "compound_create_write_close.dat";
682 struct smb2_request *req[3];
686 smb2_util_unlink(tree, fname);
689 create.in.security_flags = 0x00;
690 create.in.oplock_level = 0;
691 create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
692 create.in.create_flags = 0x00000000;
693 create.in.reserved = 0x00000000;
694 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
695 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
696 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
697 NTCREATEX_SHARE_ACCESS_WRITE |
698 NTCREATEX_SHARE_ACCESS_DELETE;
699 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
700 create.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
701 NTCREATEX_OPTIONS_ASYNC_ALERT |
702 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
704 create.in.fname = fname;
706 smb2_transport_compound_start(tree->session->transport, 3);
708 req[0] = smb2_create_send(tree, &create);
710 smb2_transport_compound_set_related(tree->session->transport, true);
713 write.in.file.handle = handle;
715 write.in.data = data_blob_talloc(tctx, NULL, 1024);
717 req[1] = smb2_write_send(tree, &write);
720 close.in.file.handle = handle;
722 req[2] = smb2_close_send(tree, &close);
724 status = smb2_create_recv(req[0], tree, &create);
725 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
728 status = smb2_write_recv(req[1], &write);
729 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
732 status = smb2_close_recv(req[2], &close);
733 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
736 status = smb2_util_unlink(tree, fname);
737 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
738 "File deletion failed.");
745 static bool test_compound_unrelated1(struct torture_context *tctx,
746 struct smb2_tree *tree)
748 struct smb2_handle hd;
749 struct smb2_create cr;
751 const char *fname = "compound_unrelated1.dat";
752 struct smb2_close cl;
754 struct smb2_request *req[5];
756 smb2_transport_credits_ask_num(tree->session->transport, 5);
758 smb2_util_unlink(tree, fname);
760 smb2_transport_credits_ask_num(tree->session->transport, 1);
763 cr.in.security_flags = 0x00;
764 cr.in.oplock_level = 0;
765 cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
766 cr.in.create_flags = 0x00000000;
767 cr.in.reserved = 0x00000000;
768 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
769 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
770 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
771 NTCREATEX_SHARE_ACCESS_WRITE |
772 NTCREATEX_SHARE_ACCESS_DELETE;
773 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
774 cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
775 NTCREATEX_OPTIONS_ASYNC_ALERT |
776 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
780 smb2_transport_compound_start(tree->session->transport, 5);
782 req[0] = smb2_create_send(tree, &cr);
784 hd.data[0] = UINT64_MAX;
785 hd.data[1] = UINT64_MAX;
788 cl.in.file.handle = hd;
789 req[1] = smb2_close_send(tree, &cl);
790 req[2] = smb2_close_send(tree, &cl);
791 req[3] = smb2_close_send(tree, &cl);
792 req[4] = smb2_close_send(tree, &cl);
794 status = smb2_create_recv(req[0], tree, &cr);
795 CHECK_STATUS(status, NT_STATUS_OK);
796 status = smb2_close_recv(req[1], &cl);
797 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
798 status = smb2_close_recv(req[2], &cl);
799 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
800 status = smb2_close_recv(req[3], &cl);
801 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
802 status = smb2_close_recv(req[4], &cl);
803 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
805 smb2_util_unlink(tree, fname);
810 static bool test_compound_invalid1(struct torture_context *tctx,
811 struct smb2_tree *tree)
813 struct smb2_handle hd;
814 struct smb2_create cr;
816 const char *fname = "compound_invalid1.dat";
817 struct smb2_close cl;
819 struct smb2_request *req[3];
821 smb2_transport_credits_ask_num(tree->session->transport, 3);
823 smb2_util_unlink(tree, fname);
825 smb2_transport_credits_ask_num(tree->session->transport, 1);
828 cr.in.security_flags = 0x00;
829 cr.in.oplock_level = 0;
830 cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
831 cr.in.create_flags = 0x00000000;
832 cr.in.reserved = 0x00000000;
833 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
834 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
835 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
836 NTCREATEX_SHARE_ACCESS_WRITE |
837 NTCREATEX_SHARE_ACCESS_DELETE;
838 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
839 cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
840 NTCREATEX_OPTIONS_ASYNC_ALERT |
841 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
845 smb2_transport_compound_start(tree->session->transport, 3);
847 /* passing the first request with the related flag is invalid */
848 smb2_transport_compound_set_related(tree->session->transport, true);
850 req[0] = smb2_create_send(tree, &cr);
852 hd.data[0] = UINT64_MAX;
853 hd.data[1] = UINT64_MAX;
856 cl.in.file.handle = hd;
857 req[1] = smb2_close_send(tree, &cl);
859 smb2_transport_compound_set_related(tree->session->transport, false);
860 req[2] = smb2_close_send(tree, &cl);
862 status = smb2_create_recv(req[0], tree, &cr);
863 /* TODO: check why this fails with --signing=required */
864 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
865 status = smb2_close_recv(req[1], &cl);
866 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
867 status = smb2_close_recv(req[2], &cl);
868 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
870 smb2_util_unlink(tree, fname);
875 static bool test_compound_invalid2(struct torture_context *tctx,
876 struct smb2_tree *tree)
878 struct smb2_handle hd;
879 struct smb2_create cr;
881 const char *fname = "compound_invalid2.dat";
882 struct smb2_close cl;
884 struct smb2_request *req[5];
885 struct smbXcli_tcon *saved_tcon = tree->smbXcli;
886 struct smbXcli_session *saved_session = tree->session->smbXcli;
888 smb2_transport_credits_ask_num(tree->session->transport, 5);
890 smb2_util_unlink(tree, fname);
892 smb2_transport_credits_ask_num(tree->session->transport, 1);
895 cr.in.security_flags = 0x00;
896 cr.in.oplock_level = 0;
897 cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
898 cr.in.create_flags = 0x00000000;
899 cr.in.reserved = 0x00000000;
900 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
901 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
902 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
903 NTCREATEX_SHARE_ACCESS_WRITE |
904 NTCREATEX_SHARE_ACCESS_DELETE;
905 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
906 cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
907 NTCREATEX_OPTIONS_ASYNC_ALERT |
908 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
912 smb2_transport_compound_start(tree->session->transport, 5);
914 req[0] = smb2_create_send(tree, &cr);
916 hd.data[0] = UINT64_MAX;
917 hd.data[1] = UINT64_MAX;
919 smb2_transport_compound_set_related(tree->session->transport, true);
922 cl.in.file.handle = hd;
924 tree->smbXcli = smbXcli_tcon_create(tree);
925 smb2cli_tcon_set_values(tree->smbXcli,
927 0xFFFFFFFF, /* tcon_id */
930 0, /* capabilities */
931 0 /* maximal_access */);
933 tree->session->smbXcli = smbXcli_session_copy(tree->session,
934 tree->session->smbXcli);
935 smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
937 req[1] = smb2_close_send(tree, &cl);
938 /* strange that this is not generating invalid parameter */
939 smb2_transport_compound_set_related(tree->session->transport, false);
940 req[2] = smb2_close_send(tree, &cl);
941 req[3] = smb2_close_send(tree, &cl);
942 smb2_transport_compound_set_related(tree->session->transport, true);
943 req[4] = smb2_close_send(tree, &cl);
945 status = smb2_create_recv(req[0], tree, &cr);
946 CHECK_STATUS(status, NT_STATUS_OK);
947 status = smb2_close_recv(req[1], &cl);
948 CHECK_STATUS(status, NT_STATUS_OK);
949 status = smb2_close_recv(req[2], &cl);
950 CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
951 status = smb2_close_recv(req[3], &cl);
952 CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
953 status = smb2_close_recv(req[4], &cl);
954 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
956 TALLOC_FREE(tree->smbXcli);
957 tree->smbXcli = saved_tcon;
958 TALLOC_FREE(tree->session->smbXcli);
959 tree->session->smbXcli = saved_session;
961 smb2_util_unlink(tree, fname);
966 static bool test_compound_invalid3(struct torture_context *tctx,
967 struct smb2_tree *tree)
969 struct smb2_handle hd;
970 struct smb2_create cr;
972 const char *fname = "compound_invalid3.dat";
973 struct smb2_close cl;
975 struct smb2_request *req[5];
977 smb2_transport_credits_ask_num(tree->session->transport, 5);
979 smb2_util_unlink(tree, fname);
981 smb2_transport_credits_ask_num(tree->session->transport, 1);
984 cr.in.security_flags = 0x00;
985 cr.in.oplock_level = 0;
986 cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
987 cr.in.create_flags = 0x00000000;
988 cr.in.reserved = 0x00000000;
989 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
990 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
991 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
992 NTCREATEX_SHARE_ACCESS_WRITE |
993 NTCREATEX_SHARE_ACCESS_DELETE;
994 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
995 cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
996 NTCREATEX_OPTIONS_ASYNC_ALERT |
997 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
1001 smb2_transport_compound_start(tree->session->transport, 5);
1003 req[0] = smb2_create_send(tree, &cr);
1005 hd.data[0] = UINT64_MAX;
1006 hd.data[1] = UINT64_MAX;
1009 cl.in.file.handle = hd;
1010 req[1] = smb2_close_send(tree, &cl);
1011 req[2] = smb2_close_send(tree, &cl);
1012 /* flipping the related flag is invalid */
1013 smb2_transport_compound_set_related(tree->session->transport, true);
1014 req[3] = smb2_close_send(tree, &cl);
1015 req[4] = smb2_close_send(tree, &cl);
1017 status = smb2_create_recv(req[0], tree, &cr);
1018 CHECK_STATUS(status, NT_STATUS_OK);
1019 status = smb2_close_recv(req[1], &cl);
1020 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1021 status = smb2_close_recv(req[2], &cl);
1022 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1023 status = smb2_close_recv(req[3], &cl);
1024 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1025 status = smb2_close_recv(req[4], &cl);
1026 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1028 smb2_util_unlink(tree, fname);
1033 static bool test_compound_invalid4(struct torture_context *tctx,
1034 struct smb2_tree *tree)
1036 struct smb2_create cr;
1037 struct smb2_read rd;
1039 const char *fname = "compound_invalid4.dat";
1040 struct smb2_close cl;
1043 struct smb2_request *req[2];
1045 smb2_transport_credits_ask_num(tree->session->transport, 2);
1047 smb2_util_unlink(tree, fname);
1050 cr.in.security_flags = 0x00;
1051 cr.in.oplock_level = 0;
1052 cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
1053 cr.in.create_flags = 0x00000000;
1054 cr.in.reserved = 0x00000000;
1055 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
1056 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1057 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1058 NTCREATEX_SHARE_ACCESS_WRITE |
1059 NTCREATEX_SHARE_ACCESS_DELETE;
1060 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1061 cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
1062 NTCREATEX_OPTIONS_ASYNC_ALERT |
1063 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
1065 cr.in.fname = fname;
1067 status = smb2_create(tree, tctx, &cr);
1068 CHECK_STATUS(status, NT_STATUS_OK);
1070 smb2_transport_compound_start(tree->session->transport, 2);
1073 rd.in.file.handle = cr.out.file.handle;
1076 req[0] = smb2_read_send(tree, &rd);
1078 smb2_transport_compound_set_related(tree->session->transport, true);
1081 * Send a completely bogus request as second compound
1082 * element. This triggers smbd_smb2_request_error() in in
1083 * smbd_smb2_request_dispatch() before calling
1084 * smbd_smb2_request_dispatch_update_counts().
1087 req[1] = smb2_request_init_tree(tree, 0xff, 0x04, false, 0);
1088 smb2_transport_send(req[1]);
1090 status = smb2_read_recv(req[0], tctx, &rd);
1091 CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
1093 ok = smb2_request_receive(req[1]);
1094 torture_assert(tctx, ok, "Invalid request failed\n");
1095 CHECK_STATUS(req[1]->status, NT_STATUS_INVALID_PARAMETER);
1098 cl.in.file.handle = cr.out.file.handle;
1100 status = smb2_close(tree, &cl);
1101 CHECK_STATUS(status, NT_STATUS_OK);
1103 smb2_util_unlink(tree, fname);
1108 /* Send a compound request where we expect the last request (Create, Notify)
1109 * to go asynchronous. This works against a Win7 server and the reply is
1110 * sent in two different packets. */
1111 static bool test_compound_interim1(struct torture_context *tctx,
1112 struct smb2_tree *tree)
1114 struct smb2_handle hd;
1115 struct smb2_create cr;
1116 NTSTATUS status = NT_STATUS_OK;
1117 const char *dname = "compound_interim_dir";
1118 struct smb2_notify nt;
1120 struct smb2_request *req[2];
1122 /* Win7 compound request implementation deviates substantially from the
1123 * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
1124 * verifies the Windows behavior, not the general spec behavior. */
1126 smb2_transport_credits_ask_num(tree->session->transport, 5);
1128 smb2_deltree(tree, dname);
1130 smb2_transport_credits_ask_num(tree->session->transport, 1);
1133 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
1134 cr.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1135 cr.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1136 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1137 NTCREATEX_SHARE_ACCESS_WRITE |
1138 NTCREATEX_SHARE_ACCESS_DELETE;
1139 cr.in.create_disposition = NTCREATEX_DISP_CREATE;
1140 cr.in.fname = dname;
1142 smb2_transport_compound_start(tree->session->transport, 2);
1144 req[0] = smb2_create_send(tree, &cr);
1146 smb2_transport_compound_set_related(tree->session->transport, true);
1148 hd.data[0] = UINT64_MAX;
1149 hd.data[1] = UINT64_MAX;
1152 nt.in.recursive = true;
1153 nt.in.buffer_size = 0x1000;
1154 nt.in.file.handle = hd;
1155 nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1156 nt.in.unknown = 0x00000000;
1158 req[1] = smb2_notify_send(tree, &nt);
1160 status = smb2_create_recv(req[0], tree, &cr);
1161 CHECK_STATUS(status, NT_STATUS_OK);
1163 smb2_cancel(req[1]);
1164 status = smb2_notify_recv(req[1], tree, &nt);
1165 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1167 smb2_util_close(tree, cr.out.file.handle);
1169 smb2_deltree(tree, dname);
1174 /* Send a compound request where we expect the middle request (Create, Notify,
1175 * GetInfo) to go asynchronous. Against Win7 the sync request succeed while
1176 * the async fails. All are returned in the same compound response. */
1177 static bool test_compound_interim2(struct torture_context *tctx,
1178 struct smb2_tree *tree)
1180 struct smb2_handle hd;
1181 struct smb2_create cr;
1182 NTSTATUS status = NT_STATUS_OK;
1183 const char *dname = "compound_interim_dir";
1184 struct smb2_getinfo gf;
1185 struct smb2_notify nt;
1187 struct smb2_request *req[3];
1189 /* Win7 compound request implementation deviates substantially from the
1190 * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
1191 * verifies the Windows behavior, not the general spec behavior. */
1193 smb2_transport_credits_ask_num(tree->session->transport, 5);
1195 smb2_deltree(tree, dname);
1197 smb2_transport_credits_ask_num(tree->session->transport, 1);
1200 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
1201 cr.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1202 cr.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1203 cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1204 NTCREATEX_SHARE_ACCESS_WRITE |
1205 NTCREATEX_SHARE_ACCESS_DELETE;
1206 cr.in.create_disposition = NTCREATEX_DISP_CREATE;
1207 cr.in.fname = dname;
1209 smb2_transport_compound_start(tree->session->transport, 3);
1211 req[0] = smb2_create_send(tree, &cr);
1213 smb2_transport_compound_set_related(tree->session->transport, true);
1215 hd.data[0] = UINT64_MAX;
1216 hd.data[1] = UINT64_MAX;
1219 nt.in.recursive = true;
1220 nt.in.buffer_size = 0x1000;
1221 nt.in.file.handle = hd;
1222 nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1223 nt.in.unknown = 0x00000000;
1225 req[1] = smb2_notify_send(tree, &nt);
1228 gf.in.file.handle = hd;
1229 gf.in.info_type = SMB2_GETINFO_FILE;
1230 gf.in.info_class = 0x04; /* FILE_BASIC_INFORMATION */
1231 gf.in.output_buffer_length = 0x1000;
1232 gf.in.input_buffer_length = 0;
1234 req[2] = smb2_getinfo_send(tree, &gf);
1236 status = smb2_create_recv(req[0], tree, &cr);
1237 CHECK_STATUS(status, NT_STATUS_OK);
1239 status = smb2_notify_recv(req[1], tree, &nt);
1240 CHECK_STATUS(status, NT_STATUS_INTERNAL_ERROR);
1242 status = smb2_getinfo_recv(req[2], tree, &gf);
1243 CHECK_STATUS(status, NT_STATUS_OK);
1245 smb2_util_close(tree, cr.out.file.handle);
1247 smb2_deltree(tree, dname);
1252 /* Test compound related finds */
1253 static bool test_compound_find_related(struct torture_context *tctx,
1254 struct smb2_tree *tree)
1256 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1257 const char *dname = "compound_find_dir";
1258 struct smb2_create create;
1260 struct smb2_handle h;
1261 struct smb2_request *req[2];
1265 smb2_deltree(tree, dname);
1267 ZERO_STRUCT(create);
1268 create.in.desired_access = SEC_RIGHTS_DIR_ALL;
1269 create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1270 create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1271 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1272 NTCREATEX_SHARE_ACCESS_WRITE |
1273 NTCREATEX_SHARE_ACCESS_DELETE;
1274 create.in.create_disposition = NTCREATEX_DISP_CREATE;
1275 create.in.fname = dname;
1277 status = smb2_create(tree, mem_ctx, &create);
1278 h = create.out.file.handle;
1280 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
1282 smb2_transport_compound_start(tree->session->transport, 2);
1285 f.in.file.handle = h;
1287 f.in.max_response_size = 0x100;
1288 f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
1290 req[0] = smb2_find_send(tree, &f);
1292 smb2_transport_compound_set_related(tree->session->transport, true);
1294 req[1] = smb2_find_send(tree, &f);
1296 status = smb2_find_recv(req[0], mem_ctx, &f);
1297 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
1299 status = smb2_find_recv(req[1], mem_ctx, &f);
1300 torture_assert_ntstatus_equal_goto(tctx, status, STATUS_NO_MORE_FILES, ret, done, "smb2_find_recv failed\n");
1303 smb2_util_close(tree, h);
1304 smb2_deltree(tree, dname);
1305 TALLOC_FREE(mem_ctx);
1309 /* Test compound related finds */
1310 static bool test_compound_find_close(struct torture_context *tctx,
1311 struct smb2_tree *tree)
1313 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1314 const char *dname = "compound_find_dir";
1315 struct smb2_create create;
1317 struct smb2_handle h;
1318 struct smb2_request *req = NULL;
1319 const int num_files = 5000;
1324 smb2_deltree(tree, dname);
1326 ZERO_STRUCT(create);
1327 create.in.desired_access = SEC_RIGHTS_DIR_ALL;
1328 create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1329 create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1330 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1331 NTCREATEX_SHARE_ACCESS_WRITE |
1332 NTCREATEX_SHARE_ACCESS_DELETE;
1333 create.in.create_disposition = NTCREATEX_DISP_CREATE;
1334 create.in.fname = dname;
1336 smb2cli_conn_set_max_credits(tree->session->transport->conn, 256);
1338 status = smb2_create(tree, mem_ctx, &create);
1339 h = create.out.file.handle;
1341 ZERO_STRUCT(create);
1342 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
1343 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1344 create.in.create_disposition = NTCREATEX_DISP_CREATE;
1346 for (i = 0; i < num_files; i++) {
1347 create.in.fname = talloc_asprintf(mem_ctx, "%s\\file%d",
1349 status = smb2_create(tree, mem_ctx, &create);
1350 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
1351 smb2_util_close(tree, create.out.file.handle);
1354 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
1357 f.in.file.handle = h;
1359 f.in.max_response_size = 8*1024*1024;
1360 f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
1362 req = smb2_find_send(tree, &f);
1364 status = smb2_util_close(tree, h);
1365 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed\n");
1367 status = smb2_find_recv(req, mem_ctx, &f);
1368 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
1371 smb2_util_close(tree, h);
1372 smb2_deltree(tree, dname);
1373 TALLOC_FREE(mem_ctx);
1377 /* Test compound unrelated finds */
1378 static bool test_compound_find_unrelated(struct torture_context *tctx,
1379 struct smb2_tree *tree)
1381 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1382 const char *dname = "compound_find_dir";
1383 struct smb2_create create;
1385 struct smb2_handle h;
1386 struct smb2_request *req[2];
1390 smb2_deltree(tree, dname);
1392 ZERO_STRUCT(create);
1393 create.in.desired_access = SEC_RIGHTS_DIR_ALL;
1394 create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1395 create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1396 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1397 NTCREATEX_SHARE_ACCESS_WRITE |
1398 NTCREATEX_SHARE_ACCESS_DELETE;
1399 create.in.create_disposition = NTCREATEX_DISP_CREATE;
1400 create.in.fname = dname;
1402 status = smb2_create(tree, mem_ctx, &create);
1403 h = create.out.file.handle;
1405 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
1407 smb2_transport_compound_start(tree->session->transport, 2);
1410 f.in.file.handle = h;
1412 f.in.max_response_size = 0x100;
1413 f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
1415 req[0] = smb2_find_send(tree, &f);
1416 req[1] = smb2_find_send(tree, &f);
1418 status = smb2_find_recv(req[0], mem_ctx, &f);
1419 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
1421 status = smb2_find_recv(req[1], mem_ctx, &f);
1422 torture_assert_ntstatus_equal_goto(tctx, status, STATUS_NO_MORE_FILES, ret, done, "smb2_find_recv failed\n");
1425 smb2_util_close(tree, h);
1426 smb2_deltree(tree, dname);
1427 TALLOC_FREE(mem_ctx);
1431 struct torture_suite *torture_smb2_compound_init(TALLOC_CTX *ctx)
1433 struct torture_suite *suite = torture_suite_create(ctx, "compound");
1435 torture_suite_add_1smb2_test(suite, "related1", test_compound_related1);
1436 torture_suite_add_1smb2_test(suite, "related2", test_compound_related2);
1437 torture_suite_add_1smb2_test(suite, "related3",
1438 test_compound_related3);
1439 torture_suite_add_1smb2_test(suite, "unrelated1", test_compound_unrelated1);
1440 torture_suite_add_1smb2_test(suite, "invalid1", test_compound_invalid1);
1441 torture_suite_add_1smb2_test(suite, "invalid2", test_compound_invalid2);
1442 torture_suite_add_1smb2_test(suite, "invalid3", test_compound_invalid3);
1443 torture_suite_add_1smb2_test(
1444 suite, "invalid4", test_compound_invalid4);
1445 torture_suite_add_1smb2_test(suite, "interim1", test_compound_interim1);
1446 torture_suite_add_1smb2_test(suite, "interim2", test_compound_interim2);
1447 torture_suite_add_1smb2_test(suite, "compound-break", test_compound_break);
1448 torture_suite_add_1smb2_test(suite, "compound-padding", test_compound_padding);
1449 torture_suite_add_1smb2_test(suite, "create-write-close",
1450 test_compound_create_write_close);
1452 suite->description = talloc_strdup(suite, "SMB2-COMPOUND tests");
1457 struct torture_suite *torture_smb2_compound_find_init(TALLOC_CTX *ctx)
1459 struct torture_suite *suite = torture_suite_create(ctx, "compound_find");
1461 torture_suite_add_1smb2_test(suite, "compound_find_related", test_compound_find_related);
1462 torture_suite_add_1smb2_test(suite, "compound_find_unrelated", test_compound_find_unrelated);
1463 torture_suite_add_1smb2_test(suite, "compound_find_close", test_compound_find_close);
1465 suite->description = talloc_strdup(suite, "SMB2-COMPOUND-FIND tests");