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)); \
38 struct smb2_handle handle
;
43 NTSTATUS failure_status
;
46 static void torture_oplock_break_callback(struct smb2_request
*req
)
52 status
= smb2_break_recv(req
, &break_info
.br
);
53 if (!NT_STATUS_IS_OK(status
)) {
54 break_info
.failures
++;
55 break_info
.failure_status
= status
;
61 /* A general oplock break notification handler. This should be used when a
62 * test expects to break from batch or exclusive to a lower level. */
63 static bool torture_oplock_handler(struct smb2_transport
*transport
,
64 const struct smb2_handle
*handle
,
68 struct smb2_tree
*tree
= private_data
;
70 struct smb2_request
*req
;
71 ZERO_STRUCT(break_info
.br
);
73 break_info
.handle
= *handle
;
74 break_info
.level
= level
;
78 case SMB2_OPLOCK_LEVEL_II
:
81 case SMB2_OPLOCK_LEVEL_NONE
:
86 break_info
.failures
++;
88 printf("Acking to %s [0x%02X] in oplock handler\n", name
, level
);
90 break_info
.br
.in
.file
.handle
= *handle
;
91 break_info
.br
.in
.oplock_level
= level
;
92 break_info
.br
.in
.reserved
= 0;
93 break_info
.br
.in
.reserved2
= 0;
95 req
= smb2_break_send(tree
, &break_info
.br
);
96 req
->async
.fn
= torture_oplock_break_callback
;
97 req
->async
.private_data
= NULL
;
101 static bool test_compound_break(struct torture_context
*tctx
,
102 struct smb2_tree
*tree
)
104 const char *fname1
= "some-file.pptx";
108 struct smb2_create io2
;
109 struct smb2_getinfo gf
;
110 struct smb2_request
*req
[2];
111 struct smb2_handle h1
;
112 struct smb2_handle h
;
114 tree
->session
->transport
->oplock
.handler
= torture_oplock_handler
;
115 tree
->session
->transport
->oplock
.private_data
= tree
;
117 ZERO_STRUCT(break_info
);
122 ZERO_STRUCT(io1
.smb2
);
123 io1
.generic
.level
= RAW_OPEN_SMB2
;
124 io1
.smb2
.in
.desired_access
= (SEC_STD_SYNCHRONIZE
|
125 SEC_STD_READ_CONTROL
|
126 SEC_FILE_READ_ATTRIBUTE
|
129 io1
.smb2
.in
.alloc_size
= 0;
130 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
131 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
132 NTCREATEX_SHARE_ACCESS_WRITE
|
133 NTCREATEX_SHARE_ACCESS_DELETE
;
134 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
135 io1
.smb2
.in
.create_options
= 0;
136 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
137 io1
.smb2
.in
.security_flags
= 0;
138 io1
.smb2
.in
.fname
= fname1
;
140 torture_comment(tctx
, "TEST2: open a file with an batch "
141 "oplock (share mode: all)\n");
142 io1
.smb2
.in
.oplock_level
= SMB2_OPLOCK_LEVEL_BATCH
;
144 status
= smb2_create(tree
, tctx
, &(io1
.smb2
));
145 torture_assert_ntstatus_ok(tctx
, status
, "Error opening the file");
147 h1
= io1
.smb2
.out
.file
.handle
;
149 torture_comment(tctx
, "TEST2: Opening second time with compound\n");
153 io2
.in
.desired_access
= (SEC_STD_SYNCHRONIZE
|
154 SEC_FILE_READ_ATTRIBUTE
|
156 io2
.in
.alloc_size
= 0;
157 io2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
158 io2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
159 NTCREATEX_SHARE_ACCESS_WRITE
|
160 NTCREATEX_SHARE_ACCESS_DELETE
;
161 io2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
162 io2
.in
.create_options
= 0;
163 io2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
164 io2
.in
.security_flags
= 0;
165 io2
.in
.fname
= fname1
;
166 io2
.in
.oplock_level
= 0;
168 smb2_transport_compound_start(tree
->session
->transport
, 2);
170 req
[0] = smb2_create_send(tree
, &io2
);
172 smb2_transport_compound_set_related(tree
->session
->transport
, true);
174 h
.data
[0] = UINT64_MAX
;
175 h
.data
[1] = UINT64_MAX
;
178 gf
.in
.file
.handle
= h
;
179 gf
.in
.info_type
= SMB2_GETINFO_FILE
;
180 gf
.in
.info_class
= 0x16;
181 gf
.in
.output_buffer_length
= 0x1000;
182 gf
.in
.input_buffer_length
= 0;
184 req
[1] = smb2_getinfo_send(tree
, &gf
);
186 status
= smb2_create_recv(req
[0], tree
, &io2
);
187 CHECK_STATUS(status
, NT_STATUS_OK
);
189 status
= smb2_getinfo_recv(req
[1], tree
, &gf
);
190 CHECK_STATUS(status
, NT_STATUS_OK
);
194 smb2_util_close(tree
, h1
);
195 smb2_util_unlink(tree
, fname1
);
199 static bool test_compound_related1(struct torture_context
*tctx
,
200 struct smb2_tree
*tree
)
202 struct smb2_handle hd
;
203 struct smb2_create cr
;
205 const char *fname
= "compound_related1.dat";
206 struct smb2_close cl
;
208 struct smb2_request
*req
[2];
209 struct smbXcli_tcon
*saved_tcon
= tree
->smbXcli
;
210 struct smbXcli_session
*saved_session
= tree
->session
->smbXcli
;
212 smb2_transport_credits_ask_num(tree
->session
->transport
, 2);
214 smb2_util_unlink(tree
, fname
);
216 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
219 cr
.in
.security_flags
= 0x00;
220 cr
.in
.oplock_level
= 0;
221 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
222 cr
.in
.create_flags
= 0x00000000;
223 cr
.in
.reserved
= 0x00000000;
224 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
225 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
226 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
227 NTCREATEX_SHARE_ACCESS_WRITE
|
228 NTCREATEX_SHARE_ACCESS_DELETE
;
229 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
230 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
231 NTCREATEX_OPTIONS_ASYNC_ALERT
|
232 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
236 smb2_transport_compound_start(tree
->session
->transport
, 2);
238 req
[0] = smb2_create_send(tree
, &cr
);
240 smb2_transport_compound_set_related(tree
->session
->transport
, true);
242 hd
.data
[0] = UINT64_MAX
;
243 hd
.data
[1] = UINT64_MAX
;
246 cl
.in
.file
.handle
= hd
;
248 tree
->smbXcli
= smbXcli_tcon_create(tree
);
249 smb2cli_tcon_set_values(tree
->smbXcli
,
251 0xFFFFFFFF, /* tcon_id */
254 0, /* capabilities */
255 0 /* maximal_access */);
257 tree
->session
->smbXcli
= smbXcli_session_copy(tree
->session
,
258 tree
->session
->smbXcli
);
259 smb2cli_session_set_id_and_flags(tree
->session
->smbXcli
, UINT64_MAX
, 0);
261 req
[1] = smb2_close_send(tree
, &cl
);
263 status
= smb2_create_recv(req
[0], tree
, &cr
);
264 CHECK_STATUS(status
, NT_STATUS_OK
);
265 status
= smb2_close_recv(req
[1], &cl
);
266 CHECK_STATUS(status
, NT_STATUS_OK
);
268 TALLOC_FREE(tree
->smbXcli
);
269 tree
->smbXcli
= saved_tcon
;
270 TALLOC_FREE(tree
->session
->smbXcli
);
271 tree
->session
->smbXcli
= saved_session
;
273 smb2_util_unlink(tree
, fname
);
278 static bool test_compound_related2(struct torture_context
*tctx
,
279 struct smb2_tree
*tree
)
281 struct smb2_handle hd
;
282 struct smb2_create cr
;
284 const char *fname
= "compound_related2.dat";
285 struct smb2_close cl
;
287 struct smb2_request
*req
[5];
288 struct smbXcli_tcon
*saved_tcon
= tree
->smbXcli
;
289 struct smbXcli_session
*saved_session
= tree
->session
->smbXcli
;
291 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
293 smb2_util_unlink(tree
, fname
);
295 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
298 cr
.in
.security_flags
= 0x00;
299 cr
.in
.oplock_level
= 0;
300 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
301 cr
.in
.create_flags
= 0x00000000;
302 cr
.in
.reserved
= 0x00000000;
303 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
304 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
305 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
306 NTCREATEX_SHARE_ACCESS_WRITE
|
307 NTCREATEX_SHARE_ACCESS_DELETE
;
308 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
309 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
310 NTCREATEX_OPTIONS_ASYNC_ALERT
|
311 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
315 smb2_transport_compound_start(tree
->session
->transport
, 5);
317 req
[0] = smb2_create_send(tree
, &cr
);
319 hd
.data
[0] = UINT64_MAX
;
320 hd
.data
[1] = UINT64_MAX
;
322 smb2_transport_compound_set_related(tree
->session
->transport
, true);
325 cl
.in
.file
.handle
= hd
;
327 tree
->smbXcli
= smbXcli_tcon_create(tree
);
328 smb2cli_tcon_set_values(tree
->smbXcli
,
330 0xFFFFFFFF, /* tcon_id */
333 0, /* capabilities */
334 0 /* maximal_access */);
336 tree
->session
->smbXcli
= smbXcli_session_copy(tree
->session
,
337 tree
->session
->smbXcli
);
338 smb2cli_session_set_id_and_flags(tree
->session
->smbXcli
, UINT64_MAX
, 0);
340 req
[1] = smb2_close_send(tree
, &cl
);
341 req
[2] = smb2_close_send(tree
, &cl
);
342 req
[3] = smb2_close_send(tree
, &cl
);
343 req
[4] = smb2_close_send(tree
, &cl
);
345 status
= smb2_create_recv(req
[0], tree
, &cr
);
346 CHECK_STATUS(status
, NT_STATUS_OK
);
347 status
= smb2_close_recv(req
[1], &cl
);
348 CHECK_STATUS(status
, NT_STATUS_OK
);
349 status
= smb2_close_recv(req
[2], &cl
);
350 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
351 status
= smb2_close_recv(req
[3], &cl
);
352 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
353 status
= smb2_close_recv(req
[4], &cl
);
354 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
356 TALLOC_FREE(tree
->smbXcli
);
357 tree
->smbXcli
= saved_tcon
;
358 TALLOC_FREE(tree
->session
->smbXcli
);
359 tree
->session
->smbXcli
= saved_session
;
361 smb2_util_unlink(tree
, fname
);
366 static bool test_compound_related3(struct torture_context
*tctx
,
367 struct smb2_tree
*tree
)
369 struct smb2_handle hd
;
370 struct smb2_ioctl io
;
371 struct smb2_create cr
;
372 struct smb2_close cl
;
373 const char *fname
= "compound_related3.dat";
374 struct smb2_request
*req
[3];
378 smb2_util_unlink(tree
, fname
);
381 cr
.in
.security_flags
= 0x00;
382 cr
.in
.oplock_level
= 0;
383 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
384 cr
.in
.create_flags
= 0x00000000;
385 cr
.in
.reserved
= 0x00000000;
386 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
387 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
388 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
389 NTCREATEX_SHARE_ACCESS_WRITE
|
390 NTCREATEX_SHARE_ACCESS_DELETE
;
391 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
392 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
393 NTCREATEX_OPTIONS_ASYNC_ALERT
|
394 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
398 smb2_transport_compound_start(tree
->session
->transport
, 3);
400 req
[0] = smb2_create_send(tree
, &cr
);
402 hd
.data
[0] = UINT64_MAX
;
403 hd
.data
[1] = UINT64_MAX
;
405 smb2_transport_compound_set_related(tree
->session
->transport
, true);
408 io
.in
.function
= FSCTL_CREATE_OR_GET_OBJECT_ID
;
409 io
.in
.file
.handle
= hd
;
411 io
.in
.max_response_size
= 64;
414 req
[1] = smb2_ioctl_send(tree
, &io
);
417 cl
.in
.file
.handle
= hd
;
419 req
[2] = smb2_close_send(tree
, &cl
);
421 status
= smb2_create_recv(req
[0], tree
, &cr
);
422 CHECK_STATUS(status
, NT_STATUS_OK
);
423 status
= smb2_ioctl_recv(req
[1], tree
, &io
);
424 CHECK_STATUS(status
, NT_STATUS_OK
);
425 status
= smb2_close_recv(req
[2], &cl
);
426 CHECK_STATUS(status
, NT_STATUS_OK
);
428 status
= smb2_util_unlink(tree
, fname
);
429 CHECK_STATUS(status
, NT_STATUS_OK
);
436 static bool test_compound_unrelated1(struct torture_context
*tctx
,
437 struct smb2_tree
*tree
)
439 struct smb2_handle hd
;
440 struct smb2_create cr
;
442 const char *fname
= "compound_unrelated1.dat";
443 struct smb2_close cl
;
445 struct smb2_request
*req
[5];
447 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
449 smb2_util_unlink(tree
, fname
);
451 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
454 cr
.in
.security_flags
= 0x00;
455 cr
.in
.oplock_level
= 0;
456 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
457 cr
.in
.create_flags
= 0x00000000;
458 cr
.in
.reserved
= 0x00000000;
459 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
460 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
461 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
462 NTCREATEX_SHARE_ACCESS_WRITE
|
463 NTCREATEX_SHARE_ACCESS_DELETE
;
464 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
465 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
466 NTCREATEX_OPTIONS_ASYNC_ALERT
|
467 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
471 smb2_transport_compound_start(tree
->session
->transport
, 5);
473 req
[0] = smb2_create_send(tree
, &cr
);
475 hd
.data
[0] = UINT64_MAX
;
476 hd
.data
[1] = UINT64_MAX
;
479 cl
.in
.file
.handle
= hd
;
480 req
[1] = smb2_close_send(tree
, &cl
);
481 req
[2] = smb2_close_send(tree
, &cl
);
482 req
[3] = smb2_close_send(tree
, &cl
);
483 req
[4] = smb2_close_send(tree
, &cl
);
485 status
= smb2_create_recv(req
[0], tree
, &cr
);
486 CHECK_STATUS(status
, NT_STATUS_OK
);
487 status
= smb2_close_recv(req
[1], &cl
);
488 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
489 status
= smb2_close_recv(req
[2], &cl
);
490 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
491 status
= smb2_close_recv(req
[3], &cl
);
492 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
493 status
= smb2_close_recv(req
[4], &cl
);
494 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
496 smb2_util_unlink(tree
, fname
);
501 static bool test_compound_invalid1(struct torture_context
*tctx
,
502 struct smb2_tree
*tree
)
504 struct smb2_handle hd
;
505 struct smb2_create cr
;
507 const char *fname
= "compound_invalid1.dat";
508 struct smb2_close cl
;
510 struct smb2_request
*req
[3];
512 smb2_transport_credits_ask_num(tree
->session
->transport
, 3);
514 smb2_util_unlink(tree
, fname
);
516 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
519 cr
.in
.security_flags
= 0x00;
520 cr
.in
.oplock_level
= 0;
521 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
522 cr
.in
.create_flags
= 0x00000000;
523 cr
.in
.reserved
= 0x00000000;
524 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
525 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
526 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
527 NTCREATEX_SHARE_ACCESS_WRITE
|
528 NTCREATEX_SHARE_ACCESS_DELETE
;
529 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
530 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
531 NTCREATEX_OPTIONS_ASYNC_ALERT
|
532 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
536 smb2_transport_compound_start(tree
->session
->transport
, 3);
538 /* passing the first request with the related flag is invalid */
539 smb2_transport_compound_set_related(tree
->session
->transport
, true);
541 req
[0] = smb2_create_send(tree
, &cr
);
543 hd
.data
[0] = UINT64_MAX
;
544 hd
.data
[1] = UINT64_MAX
;
547 cl
.in
.file
.handle
= hd
;
548 req
[1] = smb2_close_send(tree
, &cl
);
550 smb2_transport_compound_set_related(tree
->session
->transport
, false);
551 req
[2] = smb2_close_send(tree
, &cl
);
553 status
= smb2_create_recv(req
[0], tree
, &cr
);
554 /* TODO: check why this fails with --signing=required */
555 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
556 status
= smb2_close_recv(req
[1], &cl
);
557 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
558 status
= smb2_close_recv(req
[2], &cl
);
559 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
561 smb2_util_unlink(tree
, fname
);
566 static bool test_compound_invalid2(struct torture_context
*tctx
,
567 struct smb2_tree
*tree
)
569 struct smb2_handle hd
;
570 struct smb2_create cr
;
572 const char *fname
= "compound_invalid2.dat";
573 struct smb2_close cl
;
575 struct smb2_request
*req
[5];
576 struct smbXcli_tcon
*saved_tcon
= tree
->smbXcli
;
577 struct smbXcli_session
*saved_session
= tree
->session
->smbXcli
;
579 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
581 smb2_util_unlink(tree
, fname
);
583 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
586 cr
.in
.security_flags
= 0x00;
587 cr
.in
.oplock_level
= 0;
588 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
589 cr
.in
.create_flags
= 0x00000000;
590 cr
.in
.reserved
= 0x00000000;
591 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
592 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
593 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
594 NTCREATEX_SHARE_ACCESS_WRITE
|
595 NTCREATEX_SHARE_ACCESS_DELETE
;
596 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
597 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
598 NTCREATEX_OPTIONS_ASYNC_ALERT
|
599 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
603 smb2_transport_compound_start(tree
->session
->transport
, 5);
605 req
[0] = smb2_create_send(tree
, &cr
);
607 hd
.data
[0] = UINT64_MAX
;
608 hd
.data
[1] = UINT64_MAX
;
610 smb2_transport_compound_set_related(tree
->session
->transport
, true);
613 cl
.in
.file
.handle
= hd
;
615 tree
->smbXcli
= smbXcli_tcon_create(tree
);
616 smb2cli_tcon_set_values(tree
->smbXcli
,
618 0xFFFFFFFF, /* tcon_id */
621 0, /* capabilities */
622 0 /* maximal_access */);
624 tree
->session
->smbXcli
= smbXcli_session_copy(tree
->session
,
625 tree
->session
->smbXcli
);
626 smb2cli_session_set_id_and_flags(tree
->session
->smbXcli
, UINT64_MAX
, 0);
628 req
[1] = smb2_close_send(tree
, &cl
);
629 /* strange that this is not generating invalid parameter */
630 smb2_transport_compound_set_related(tree
->session
->transport
, false);
631 req
[2] = smb2_close_send(tree
, &cl
);
632 req
[3] = smb2_close_send(tree
, &cl
);
633 smb2_transport_compound_set_related(tree
->session
->transport
, true);
634 req
[4] = smb2_close_send(tree
, &cl
);
636 status
= smb2_create_recv(req
[0], tree
, &cr
);
637 CHECK_STATUS(status
, NT_STATUS_OK
);
638 status
= smb2_close_recv(req
[1], &cl
);
639 CHECK_STATUS(status
, NT_STATUS_OK
);
640 status
= smb2_close_recv(req
[2], &cl
);
641 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
642 status
= smb2_close_recv(req
[3], &cl
);
643 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
644 status
= smb2_close_recv(req
[4], &cl
);
645 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
647 TALLOC_FREE(tree
->smbXcli
);
648 tree
->smbXcli
= saved_tcon
;
649 TALLOC_FREE(tree
->session
->smbXcli
);
650 tree
->session
->smbXcli
= saved_session
;
652 smb2_util_unlink(tree
, fname
);
657 static bool test_compound_invalid3(struct torture_context
*tctx
,
658 struct smb2_tree
*tree
)
660 struct smb2_handle hd
;
661 struct smb2_create cr
;
663 const char *fname
= "compound_invalid3.dat";
664 struct smb2_close cl
;
666 struct smb2_request
*req
[5];
668 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
670 smb2_util_unlink(tree
, fname
);
672 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
675 cr
.in
.security_flags
= 0x00;
676 cr
.in
.oplock_level
= 0;
677 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
678 cr
.in
.create_flags
= 0x00000000;
679 cr
.in
.reserved
= 0x00000000;
680 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
681 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
682 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
683 NTCREATEX_SHARE_ACCESS_WRITE
|
684 NTCREATEX_SHARE_ACCESS_DELETE
;
685 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
686 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
687 NTCREATEX_OPTIONS_ASYNC_ALERT
|
688 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
692 smb2_transport_compound_start(tree
->session
->transport
, 5);
694 req
[0] = smb2_create_send(tree
, &cr
);
696 hd
.data
[0] = UINT64_MAX
;
697 hd
.data
[1] = UINT64_MAX
;
700 cl
.in
.file
.handle
= hd
;
701 req
[1] = smb2_close_send(tree
, &cl
);
702 req
[2] = smb2_close_send(tree
, &cl
);
703 /* flipping the related flag is invalid */
704 smb2_transport_compound_set_related(tree
->session
->transport
, true);
705 req
[3] = smb2_close_send(tree
, &cl
);
706 req
[4] = smb2_close_send(tree
, &cl
);
708 status
= smb2_create_recv(req
[0], tree
, &cr
);
709 CHECK_STATUS(status
, NT_STATUS_OK
);
710 status
= smb2_close_recv(req
[1], &cl
);
711 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
712 status
= smb2_close_recv(req
[2], &cl
);
713 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
714 status
= smb2_close_recv(req
[3], &cl
);
715 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
716 status
= smb2_close_recv(req
[4], &cl
);
717 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
719 smb2_util_unlink(tree
, fname
);
724 /* Send a compound request where we expect the last request (Create, Notify)
725 * to go asynchronous. This works against a Win7 server and the reply is
726 * sent in two different packets. */
727 static bool test_compound_interim1(struct torture_context
*tctx
,
728 struct smb2_tree
*tree
)
730 struct smb2_handle hd
;
731 struct smb2_create cr
;
732 NTSTATUS status
= NT_STATUS_OK
;
733 const char *dname
= "compound_interim_dir";
734 struct smb2_notify nt
;
736 struct smb2_request
*req
[2];
738 /* Win7 compound request implementation deviates substantially from the
739 * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
740 * verifies the Windows behavior, not the general spec behavior. */
742 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
744 smb2_deltree(tree
, dname
);
746 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
749 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
750 cr
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
751 cr
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
752 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
753 NTCREATEX_SHARE_ACCESS_WRITE
|
754 NTCREATEX_SHARE_ACCESS_DELETE
;
755 cr
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
758 smb2_transport_compound_start(tree
->session
->transport
, 2);
760 req
[0] = smb2_create_send(tree
, &cr
);
762 smb2_transport_compound_set_related(tree
->session
->transport
, true);
764 hd
.data
[0] = UINT64_MAX
;
765 hd
.data
[1] = UINT64_MAX
;
768 nt
.in
.recursive
= true;
769 nt
.in
.buffer_size
= 0x1000;
770 nt
.in
.file
.handle
= hd
;
771 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
772 nt
.in
.unknown
= 0x00000000;
774 req
[1] = smb2_notify_send(tree
, &nt
);
776 status
= smb2_create_recv(req
[0], tree
, &cr
);
777 CHECK_STATUS(status
, NT_STATUS_OK
);
780 status
= smb2_notify_recv(req
[1], tree
, &nt
);
781 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
783 smb2_util_close(tree
, cr
.out
.file
.handle
);
785 smb2_deltree(tree
, dname
);
790 /* Send a compound request where we expect the middle request (Create, Notify,
791 * GetInfo) to go asynchronous. Against Win7 the sync request succeed while
792 * the async fails. All are returned in the same compound response. */
793 static bool test_compound_interim2(struct torture_context
*tctx
,
794 struct smb2_tree
*tree
)
796 struct smb2_handle hd
;
797 struct smb2_create cr
;
798 NTSTATUS status
= NT_STATUS_OK
;
799 const char *dname
= "compound_interim_dir";
800 struct smb2_getinfo gf
;
801 struct smb2_notify nt
;
803 struct smb2_request
*req
[3];
805 /* Win7 compound request implementation deviates substantially from the
806 * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
807 * verifies the Windows behavior, not the general spec behavior. */
809 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
811 smb2_deltree(tree
, dname
);
813 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
816 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
817 cr
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
818 cr
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
819 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
820 NTCREATEX_SHARE_ACCESS_WRITE
|
821 NTCREATEX_SHARE_ACCESS_DELETE
;
822 cr
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
825 smb2_transport_compound_start(tree
->session
->transport
, 3);
827 req
[0] = smb2_create_send(tree
, &cr
);
829 smb2_transport_compound_set_related(tree
->session
->transport
, true);
831 hd
.data
[0] = UINT64_MAX
;
832 hd
.data
[1] = UINT64_MAX
;
835 nt
.in
.recursive
= true;
836 nt
.in
.buffer_size
= 0x1000;
837 nt
.in
.file
.handle
= hd
;
838 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
839 nt
.in
.unknown
= 0x00000000;
841 req
[1] = smb2_notify_send(tree
, &nt
);
844 gf
.in
.file
.handle
= hd
;
845 gf
.in
.info_type
= SMB2_GETINFO_FILE
;
846 gf
.in
.info_class
= 0x04; /* FILE_BASIC_INFORMATION */
847 gf
.in
.output_buffer_length
= 0x1000;
848 gf
.in
.input_buffer_length
= 0;
850 req
[2] = smb2_getinfo_send(tree
, &gf
);
852 status
= smb2_create_recv(req
[0], tree
, &cr
);
853 CHECK_STATUS(status
, NT_STATUS_OK
);
855 status
= smb2_notify_recv(req
[1], tree
, &nt
);
856 CHECK_STATUS(status
, NT_STATUS_INTERNAL_ERROR
);
858 status
= smb2_getinfo_recv(req
[2], tree
, &gf
);
859 CHECK_STATUS(status
, NT_STATUS_OK
);
861 smb2_util_close(tree
, cr
.out
.file
.handle
);
863 smb2_deltree(tree
, dname
);
868 struct torture_suite
*torture_smb2_compound_init(void)
870 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "compound");
872 torture_suite_add_1smb2_test(suite
, "related1", test_compound_related1
);
873 torture_suite_add_1smb2_test(suite
, "related2", test_compound_related2
);
874 torture_suite_add_1smb2_test(suite
, "related3",
875 test_compound_related3
);
876 torture_suite_add_1smb2_test(suite
, "unrelated1", test_compound_unrelated1
);
877 torture_suite_add_1smb2_test(suite
, "invalid1", test_compound_invalid1
);
878 torture_suite_add_1smb2_test(suite
, "invalid2", test_compound_invalid2
);
879 torture_suite_add_1smb2_test(suite
, "invalid3", test_compound_invalid3
);
880 torture_suite_add_1smb2_test(suite
, "interim1", test_compound_interim1
);
881 torture_suite_add_1smb2_test(suite
, "interim2", test_compound_interim2
);
882 torture_suite_add_1smb2_test(suite
, "compound-break", test_compound_break
);
884 suite
->description
= talloc_strdup(suite
, "SMB2-COMPOUND tests");