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_unrelated1(struct torture_context
*tctx
,
675 struct smb2_tree
*tree
)
677 struct smb2_handle hd
;
678 struct smb2_create cr
;
680 const char *fname
= "compound_unrelated1.dat";
681 struct smb2_close cl
;
683 struct smb2_request
*req
[5];
685 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
687 smb2_util_unlink(tree
, fname
);
689 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
692 cr
.in
.security_flags
= 0x00;
693 cr
.in
.oplock_level
= 0;
694 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
695 cr
.in
.create_flags
= 0x00000000;
696 cr
.in
.reserved
= 0x00000000;
697 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
698 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
699 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
700 NTCREATEX_SHARE_ACCESS_WRITE
|
701 NTCREATEX_SHARE_ACCESS_DELETE
;
702 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
703 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
704 NTCREATEX_OPTIONS_ASYNC_ALERT
|
705 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
709 smb2_transport_compound_start(tree
->session
->transport
, 5);
711 req
[0] = smb2_create_send(tree
, &cr
);
713 hd
.data
[0] = UINT64_MAX
;
714 hd
.data
[1] = UINT64_MAX
;
717 cl
.in
.file
.handle
= hd
;
718 req
[1] = smb2_close_send(tree
, &cl
);
719 req
[2] = smb2_close_send(tree
, &cl
);
720 req
[3] = smb2_close_send(tree
, &cl
);
721 req
[4] = smb2_close_send(tree
, &cl
);
723 status
= smb2_create_recv(req
[0], tree
, &cr
);
724 CHECK_STATUS(status
, NT_STATUS_OK
);
725 status
= smb2_close_recv(req
[1], &cl
);
726 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
727 status
= smb2_close_recv(req
[2], &cl
);
728 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
729 status
= smb2_close_recv(req
[3], &cl
);
730 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
731 status
= smb2_close_recv(req
[4], &cl
);
732 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
734 smb2_util_unlink(tree
, fname
);
739 static bool test_compound_invalid1(struct torture_context
*tctx
,
740 struct smb2_tree
*tree
)
742 struct smb2_handle hd
;
743 struct smb2_create cr
;
745 const char *fname
= "compound_invalid1.dat";
746 struct smb2_close cl
;
748 struct smb2_request
*req
[3];
750 smb2_transport_credits_ask_num(tree
->session
->transport
, 3);
752 smb2_util_unlink(tree
, fname
);
754 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
757 cr
.in
.security_flags
= 0x00;
758 cr
.in
.oplock_level
= 0;
759 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
760 cr
.in
.create_flags
= 0x00000000;
761 cr
.in
.reserved
= 0x00000000;
762 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
763 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
764 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
765 NTCREATEX_SHARE_ACCESS_WRITE
|
766 NTCREATEX_SHARE_ACCESS_DELETE
;
767 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
768 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
769 NTCREATEX_OPTIONS_ASYNC_ALERT
|
770 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
774 smb2_transport_compound_start(tree
->session
->transport
, 3);
776 /* passing the first request with the related flag is invalid */
777 smb2_transport_compound_set_related(tree
->session
->transport
, true);
779 req
[0] = smb2_create_send(tree
, &cr
);
781 hd
.data
[0] = UINT64_MAX
;
782 hd
.data
[1] = UINT64_MAX
;
785 cl
.in
.file
.handle
= hd
;
786 req
[1] = smb2_close_send(tree
, &cl
);
788 smb2_transport_compound_set_related(tree
->session
->transport
, false);
789 req
[2] = smb2_close_send(tree
, &cl
);
791 status
= smb2_create_recv(req
[0], tree
, &cr
);
792 /* TODO: check why this fails with --signing=required */
793 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
794 status
= smb2_close_recv(req
[1], &cl
);
795 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
796 status
= smb2_close_recv(req
[2], &cl
);
797 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
799 smb2_util_unlink(tree
, fname
);
804 static bool test_compound_invalid2(struct torture_context
*tctx
,
805 struct smb2_tree
*tree
)
807 struct smb2_handle hd
;
808 struct smb2_create cr
;
810 const char *fname
= "compound_invalid2.dat";
811 struct smb2_close cl
;
813 struct smb2_request
*req
[5];
814 struct smbXcli_tcon
*saved_tcon
= tree
->smbXcli
;
815 struct smbXcli_session
*saved_session
= tree
->session
->smbXcli
;
817 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
819 smb2_util_unlink(tree
, fname
);
821 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
824 cr
.in
.security_flags
= 0x00;
825 cr
.in
.oplock_level
= 0;
826 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
827 cr
.in
.create_flags
= 0x00000000;
828 cr
.in
.reserved
= 0x00000000;
829 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
830 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
831 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
832 NTCREATEX_SHARE_ACCESS_WRITE
|
833 NTCREATEX_SHARE_ACCESS_DELETE
;
834 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
835 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
836 NTCREATEX_OPTIONS_ASYNC_ALERT
|
837 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
841 smb2_transport_compound_start(tree
->session
->transport
, 5);
843 req
[0] = smb2_create_send(tree
, &cr
);
845 hd
.data
[0] = UINT64_MAX
;
846 hd
.data
[1] = UINT64_MAX
;
848 smb2_transport_compound_set_related(tree
->session
->transport
, true);
851 cl
.in
.file
.handle
= hd
;
853 tree
->smbXcli
= smbXcli_tcon_create(tree
);
854 smb2cli_tcon_set_values(tree
->smbXcli
,
856 0xFFFFFFFF, /* tcon_id */
859 0, /* capabilities */
860 0 /* maximal_access */);
862 tree
->session
->smbXcli
= smbXcli_session_copy(tree
->session
,
863 tree
->session
->smbXcli
);
864 smb2cli_session_set_id_and_flags(tree
->session
->smbXcli
, UINT64_MAX
, 0);
866 req
[1] = smb2_close_send(tree
, &cl
);
867 /* strange that this is not generating invalid parameter */
868 smb2_transport_compound_set_related(tree
->session
->transport
, false);
869 req
[2] = smb2_close_send(tree
, &cl
);
870 req
[3] = smb2_close_send(tree
, &cl
);
871 smb2_transport_compound_set_related(tree
->session
->transport
, true);
872 req
[4] = smb2_close_send(tree
, &cl
);
874 status
= smb2_create_recv(req
[0], tree
, &cr
);
875 CHECK_STATUS(status
, NT_STATUS_OK
);
876 status
= smb2_close_recv(req
[1], &cl
);
877 CHECK_STATUS(status
, NT_STATUS_OK
);
878 status
= smb2_close_recv(req
[2], &cl
);
879 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
880 status
= smb2_close_recv(req
[3], &cl
);
881 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
882 status
= smb2_close_recv(req
[4], &cl
);
883 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
885 TALLOC_FREE(tree
->smbXcli
);
886 tree
->smbXcli
= saved_tcon
;
887 TALLOC_FREE(tree
->session
->smbXcli
);
888 tree
->session
->smbXcli
= saved_session
;
890 smb2_util_unlink(tree
, fname
);
895 static bool test_compound_invalid3(struct torture_context
*tctx
,
896 struct smb2_tree
*tree
)
898 struct smb2_handle hd
;
899 struct smb2_create cr
;
901 const char *fname
= "compound_invalid3.dat";
902 struct smb2_close cl
;
904 struct smb2_request
*req
[5];
906 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
908 smb2_util_unlink(tree
, fname
);
910 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
913 cr
.in
.security_flags
= 0x00;
914 cr
.in
.oplock_level
= 0;
915 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
916 cr
.in
.create_flags
= 0x00000000;
917 cr
.in
.reserved
= 0x00000000;
918 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
919 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
920 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
921 NTCREATEX_SHARE_ACCESS_WRITE
|
922 NTCREATEX_SHARE_ACCESS_DELETE
;
923 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
924 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
925 NTCREATEX_OPTIONS_ASYNC_ALERT
|
926 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
930 smb2_transport_compound_start(tree
->session
->transport
, 5);
932 req
[0] = smb2_create_send(tree
, &cr
);
934 hd
.data
[0] = UINT64_MAX
;
935 hd
.data
[1] = UINT64_MAX
;
938 cl
.in
.file
.handle
= hd
;
939 req
[1] = smb2_close_send(tree
, &cl
);
940 req
[2] = smb2_close_send(tree
, &cl
);
941 /* flipping the related flag is invalid */
942 smb2_transport_compound_set_related(tree
->session
->transport
, true);
943 req
[3] = smb2_close_send(tree
, &cl
);
944 req
[4] = smb2_close_send(tree
, &cl
);
946 status
= smb2_create_recv(req
[0], tree
, &cr
);
947 CHECK_STATUS(status
, NT_STATUS_OK
);
948 status
= smb2_close_recv(req
[1], &cl
);
949 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
950 status
= smb2_close_recv(req
[2], &cl
);
951 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
952 status
= smb2_close_recv(req
[3], &cl
);
953 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
954 status
= smb2_close_recv(req
[4], &cl
);
955 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
957 smb2_util_unlink(tree
, fname
);
962 /* Send a compound request where we expect the last request (Create, Notify)
963 * to go asynchronous. This works against a Win7 server and the reply is
964 * sent in two different packets. */
965 static bool test_compound_interim1(struct torture_context
*tctx
,
966 struct smb2_tree
*tree
)
968 struct smb2_handle hd
;
969 struct smb2_create cr
;
970 NTSTATUS status
= NT_STATUS_OK
;
971 const char *dname
= "compound_interim_dir";
972 struct smb2_notify nt
;
974 struct smb2_request
*req
[2];
976 /* Win7 compound request implementation deviates substantially from the
977 * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
978 * verifies the Windows behavior, not the general spec behavior. */
980 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
982 smb2_deltree(tree
, dname
);
984 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
987 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
988 cr
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
989 cr
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
990 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
991 NTCREATEX_SHARE_ACCESS_WRITE
|
992 NTCREATEX_SHARE_ACCESS_DELETE
;
993 cr
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
996 smb2_transport_compound_start(tree
->session
->transport
, 2);
998 req
[0] = smb2_create_send(tree
, &cr
);
1000 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1002 hd
.data
[0] = UINT64_MAX
;
1003 hd
.data
[1] = UINT64_MAX
;
1006 nt
.in
.recursive
= true;
1007 nt
.in
.buffer_size
= 0x1000;
1008 nt
.in
.file
.handle
= hd
;
1009 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1010 nt
.in
.unknown
= 0x00000000;
1012 req
[1] = smb2_notify_send(tree
, &nt
);
1014 status
= smb2_create_recv(req
[0], tree
, &cr
);
1015 CHECK_STATUS(status
, NT_STATUS_OK
);
1017 smb2_cancel(req
[1]);
1018 status
= smb2_notify_recv(req
[1], tree
, &nt
);
1019 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1021 smb2_util_close(tree
, cr
.out
.file
.handle
);
1023 smb2_deltree(tree
, dname
);
1028 /* Send a compound request where we expect the middle request (Create, Notify,
1029 * GetInfo) to go asynchronous. Against Win7 the sync request succeed while
1030 * the async fails. All are returned in the same compound response. */
1031 static bool test_compound_interim2(struct torture_context
*tctx
,
1032 struct smb2_tree
*tree
)
1034 struct smb2_handle hd
;
1035 struct smb2_create cr
;
1036 NTSTATUS status
= NT_STATUS_OK
;
1037 const char *dname
= "compound_interim_dir";
1038 struct smb2_getinfo gf
;
1039 struct smb2_notify nt
;
1041 struct smb2_request
*req
[3];
1043 /* Win7 compound request implementation deviates substantially from the
1044 * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
1045 * verifies the Windows behavior, not the general spec behavior. */
1047 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
1049 smb2_deltree(tree
, dname
);
1051 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1054 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1055 cr
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1056 cr
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
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_CREATE
;
1061 cr
.in
.fname
= dname
;
1063 smb2_transport_compound_start(tree
->session
->transport
, 3);
1065 req
[0] = smb2_create_send(tree
, &cr
);
1067 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1069 hd
.data
[0] = UINT64_MAX
;
1070 hd
.data
[1] = UINT64_MAX
;
1073 nt
.in
.recursive
= true;
1074 nt
.in
.buffer_size
= 0x1000;
1075 nt
.in
.file
.handle
= hd
;
1076 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1077 nt
.in
.unknown
= 0x00000000;
1079 req
[1] = smb2_notify_send(tree
, &nt
);
1082 gf
.in
.file
.handle
= hd
;
1083 gf
.in
.info_type
= SMB2_GETINFO_FILE
;
1084 gf
.in
.info_class
= 0x04; /* FILE_BASIC_INFORMATION */
1085 gf
.in
.output_buffer_length
= 0x1000;
1086 gf
.in
.input_buffer_length
= 0;
1088 req
[2] = smb2_getinfo_send(tree
, &gf
);
1090 status
= smb2_create_recv(req
[0], tree
, &cr
);
1091 CHECK_STATUS(status
, NT_STATUS_OK
);
1093 status
= smb2_notify_recv(req
[1], tree
, &nt
);
1094 CHECK_STATUS(status
, NT_STATUS_INTERNAL_ERROR
);
1096 status
= smb2_getinfo_recv(req
[2], tree
, &gf
);
1097 CHECK_STATUS(status
, NT_STATUS_OK
);
1099 smb2_util_close(tree
, cr
.out
.file
.handle
);
1101 smb2_deltree(tree
, dname
);
1106 struct torture_suite
*torture_smb2_compound_init(void)
1108 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "compound");
1110 torture_suite_add_1smb2_test(suite
, "related1", test_compound_related1
);
1111 torture_suite_add_1smb2_test(suite
, "related2", test_compound_related2
);
1112 torture_suite_add_1smb2_test(suite
, "related3",
1113 test_compound_related3
);
1114 torture_suite_add_1smb2_test(suite
, "unrelated1", test_compound_unrelated1
);
1115 torture_suite_add_1smb2_test(suite
, "invalid1", test_compound_invalid1
);
1116 torture_suite_add_1smb2_test(suite
, "invalid2", test_compound_invalid2
);
1117 torture_suite_add_1smb2_test(suite
, "invalid3", test_compound_invalid3
);
1118 torture_suite_add_1smb2_test(suite
, "interim1", test_compound_interim1
);
1119 torture_suite_add_1smb2_test(suite
, "interim2", test_compound_interim2
);
1120 torture_suite_add_1smb2_test(suite
, "compound-break", test_compound_break
);
1121 torture_suite_add_1smb2_test(suite
, "compound-padding", test_compound_padding
);
1123 suite
->description
= talloc_strdup(suite
, "SMB2-COMPOUND tests");