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/security/security.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "../libcli/smb/smbXcli_base.h"
31 #define CHECK_STATUS(status, correct) do { \
32 if (!NT_STATUS_EQUAL(status, correct)) { \
33 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
34 nt_errstr(status), nt_errstr(correct)); \
39 #define CHECK_VALUE(v, correct) do { \
40 if ((v) != (correct)) { \
41 torture_result(tctx, TORTURE_FAIL, \
42 "(%s) Incorrect value %s=%d - should be %d\n", \
43 __location__, #v, (int)v, (int)correct); \
48 struct smb2_handle handle
;
53 NTSTATUS failure_status
;
56 static void torture_oplock_break_callback(struct smb2_request
*req
)
62 status
= smb2_break_recv(req
, &break_info
.br
);
63 if (!NT_STATUS_IS_OK(status
)) {
64 break_info
.failures
++;
65 break_info
.failure_status
= status
;
71 /* A general oplock break notification handler. This should be used when a
72 * test expects to break from batch or exclusive to a lower level. */
73 static bool torture_oplock_handler(struct smb2_transport
*transport
,
74 const struct smb2_handle
*handle
,
78 struct smb2_tree
*tree
= private_data
;
80 struct smb2_request
*req
;
81 ZERO_STRUCT(break_info
.br
);
83 break_info
.handle
= *handle
;
84 break_info
.level
= level
;
88 case SMB2_OPLOCK_LEVEL_II
:
91 case SMB2_OPLOCK_LEVEL_NONE
:
96 break_info
.failures
++;
98 printf("Acking to %s [0x%02X] in oplock handler\n", name
, level
);
100 break_info
.br
.in
.file
.handle
= *handle
;
101 break_info
.br
.in
.oplock_level
= level
;
102 break_info
.br
.in
.reserved
= 0;
103 break_info
.br
.in
.reserved2
= 0;
105 req
= smb2_break_send(tree
, &break_info
.br
);
106 req
->async
.fn
= torture_oplock_break_callback
;
107 req
->async
.private_data
= NULL
;
111 static bool test_compound_break(struct torture_context
*tctx
,
112 struct smb2_tree
*tree
)
114 const char *fname1
= "some-file.pptx";
118 struct smb2_create io2
;
119 struct smb2_getinfo gf
;
120 struct smb2_request
*req
[2];
121 struct smb2_handle h1
;
122 struct smb2_handle h
;
124 tree
->session
->transport
->oplock
.handler
= torture_oplock_handler
;
125 tree
->session
->transport
->oplock
.private_data
= tree
;
127 ZERO_STRUCT(break_info
);
132 ZERO_STRUCT(io1
.smb2
);
133 io1
.generic
.level
= RAW_OPEN_SMB2
;
134 io1
.smb2
.in
.desired_access
= (SEC_STD_SYNCHRONIZE
|
135 SEC_STD_READ_CONTROL
|
136 SEC_FILE_READ_ATTRIBUTE
|
139 io1
.smb2
.in
.alloc_size
= 0;
140 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
141 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
142 NTCREATEX_SHARE_ACCESS_WRITE
|
143 NTCREATEX_SHARE_ACCESS_DELETE
;
144 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
145 io1
.smb2
.in
.create_options
= 0;
146 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
147 io1
.smb2
.in
.security_flags
= 0;
148 io1
.smb2
.in
.fname
= fname1
;
150 torture_comment(tctx
, "TEST2: open a file with an batch "
151 "oplock (share mode: all)\n");
152 io1
.smb2
.in
.oplock_level
= SMB2_OPLOCK_LEVEL_BATCH
;
154 status
= smb2_create(tree
, tctx
, &(io1
.smb2
));
155 torture_assert_ntstatus_ok(tctx
, status
, "Error opening the file");
157 h1
= io1
.smb2
.out
.file
.handle
;
159 torture_comment(tctx
, "TEST2: Opening second time with compound\n");
163 io2
.in
.desired_access
= (SEC_STD_SYNCHRONIZE
|
164 SEC_FILE_READ_ATTRIBUTE
|
166 io2
.in
.alloc_size
= 0;
167 io2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
168 io2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
169 NTCREATEX_SHARE_ACCESS_WRITE
|
170 NTCREATEX_SHARE_ACCESS_DELETE
;
171 io2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
172 io2
.in
.create_options
= 0;
173 io2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
174 io2
.in
.security_flags
= 0;
175 io2
.in
.fname
= fname1
;
176 io2
.in
.oplock_level
= 0;
178 smb2_transport_compound_start(tree
->session
->transport
, 2);
180 req
[0] = smb2_create_send(tree
, &io2
);
182 smb2_transport_compound_set_related(tree
->session
->transport
, true);
184 h
.data
[0] = UINT64_MAX
;
185 h
.data
[1] = UINT64_MAX
;
188 gf
.in
.file
.handle
= h
;
189 gf
.in
.info_type
= SMB2_0_INFO_FILE
;
190 gf
.in
.info_class
= 0x16;
191 gf
.in
.output_buffer_length
= 0x1000;
192 gf
.in
.input_buffer
= data_blob_null
;
194 req
[1] = smb2_getinfo_send(tree
, &gf
);
196 status
= smb2_create_recv(req
[0], tree
, &io2
);
197 CHECK_STATUS(status
, NT_STATUS_OK
);
199 status
= smb2_getinfo_recv(req
[1], tree
, &gf
);
200 CHECK_STATUS(status
, NT_STATUS_OK
);
204 smb2_util_close(tree
, h1
);
205 smb2_util_unlink(tree
, fname1
);
209 static bool test_compound_related1(struct torture_context
*tctx
,
210 struct smb2_tree
*tree
)
212 struct smb2_handle hd
;
213 struct smb2_create cr
;
215 const char *fname
= "compound_related1.dat";
216 struct smb2_close cl
;
218 struct smb2_request
*req
[2];
219 struct smbXcli_tcon
*saved_tcon
= tree
->smbXcli
;
220 struct smbXcli_session
*saved_session
= tree
->session
->smbXcli
;
222 smb2_transport_credits_ask_num(tree
->session
->transport
, 2);
224 smb2_util_unlink(tree
, fname
);
226 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
229 cr
.in
.security_flags
= 0x00;
230 cr
.in
.oplock_level
= 0;
231 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
232 cr
.in
.create_flags
= 0x00000000;
233 cr
.in
.reserved
= 0x00000000;
234 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
235 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
236 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
237 NTCREATEX_SHARE_ACCESS_WRITE
|
238 NTCREATEX_SHARE_ACCESS_DELETE
;
239 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
240 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
241 NTCREATEX_OPTIONS_ASYNC_ALERT
|
242 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
246 smb2_transport_compound_start(tree
->session
->transport
, 2);
248 req
[0] = smb2_create_send(tree
, &cr
);
250 smb2_transport_compound_set_related(tree
->session
->transport
, true);
252 hd
.data
[0] = UINT64_MAX
;
253 hd
.data
[1] = UINT64_MAX
;
256 cl
.in
.file
.handle
= hd
;
258 tree
->smbXcli
= smbXcli_tcon_create(tree
);
259 smb2cli_tcon_set_values(tree
->smbXcli
,
261 0xFFFFFFFF, /* tcon_id */
264 0, /* capabilities */
265 0 /* maximal_access */);
267 tree
->session
->smbXcli
= smbXcli_session_shallow_copy(tree
->session
,
268 tree
->session
->smbXcli
);
269 smb2cli_session_set_id_and_flags(tree
->session
->smbXcli
, UINT64_MAX
, 0);
271 req
[1] = smb2_close_send(tree
, &cl
);
273 status
= smb2_create_recv(req
[0], tree
, &cr
);
274 CHECK_STATUS(status
, NT_STATUS_OK
);
275 status
= smb2_close_recv(req
[1], &cl
);
276 CHECK_STATUS(status
, NT_STATUS_OK
);
278 TALLOC_FREE(tree
->smbXcli
);
279 tree
->smbXcli
= saved_tcon
;
280 TALLOC_FREE(tree
->session
->smbXcli
);
281 tree
->session
->smbXcli
= saved_session
;
283 smb2_util_unlink(tree
, fname
);
288 static bool test_compound_related2(struct torture_context
*tctx
,
289 struct smb2_tree
*tree
)
291 struct smb2_handle hd
;
292 struct smb2_create cr
;
294 const char *fname
= "compound_related2.dat";
295 struct smb2_close cl
;
297 struct smb2_request
*req
[5];
298 struct smbXcli_tcon
*saved_tcon
= tree
->smbXcli
;
299 struct smbXcli_session
*saved_session
= tree
->session
->smbXcli
;
301 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
303 smb2_util_unlink(tree
, fname
);
305 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
308 cr
.in
.security_flags
= 0x00;
309 cr
.in
.oplock_level
= 0;
310 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
311 cr
.in
.create_flags
= 0x00000000;
312 cr
.in
.reserved
= 0x00000000;
313 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
314 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
315 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
316 NTCREATEX_SHARE_ACCESS_WRITE
|
317 NTCREATEX_SHARE_ACCESS_DELETE
;
318 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
319 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
320 NTCREATEX_OPTIONS_ASYNC_ALERT
|
321 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
325 smb2_transport_compound_start(tree
->session
->transport
, 5);
327 req
[0] = smb2_create_send(tree
, &cr
);
329 hd
.data
[0] = UINT64_MAX
;
330 hd
.data
[1] = UINT64_MAX
;
332 smb2_transport_compound_set_related(tree
->session
->transport
, true);
335 cl
.in
.file
.handle
= hd
;
337 tree
->smbXcli
= smbXcli_tcon_create(tree
);
338 smb2cli_tcon_set_values(tree
->smbXcli
,
340 0xFFFFFFFF, /* tcon_id */
343 0, /* capabilities */
344 0 /* maximal_access */);
346 tree
->session
->smbXcli
= smbXcli_session_shallow_copy(tree
->session
,
347 tree
->session
->smbXcli
);
348 smb2cli_session_set_id_and_flags(tree
->session
->smbXcli
, UINT64_MAX
, 0);
350 req
[1] = smb2_close_send(tree
, &cl
);
351 req
[2] = smb2_close_send(tree
, &cl
);
352 req
[3] = smb2_close_send(tree
, &cl
);
353 req
[4] = smb2_close_send(tree
, &cl
);
355 status
= smb2_create_recv(req
[0], tree
, &cr
);
356 CHECK_STATUS(status
, NT_STATUS_OK
);
357 status
= smb2_close_recv(req
[1], &cl
);
358 CHECK_STATUS(status
, NT_STATUS_OK
);
359 status
= smb2_close_recv(req
[2], &cl
);
360 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
361 status
= smb2_close_recv(req
[3], &cl
);
362 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
363 status
= smb2_close_recv(req
[4], &cl
);
364 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
366 TALLOC_FREE(tree
->smbXcli
);
367 tree
->smbXcli
= saved_tcon
;
368 TALLOC_FREE(tree
->session
->smbXcli
);
369 tree
->session
->smbXcli
= saved_session
;
371 smb2_util_unlink(tree
, fname
);
376 static bool test_compound_related3(struct torture_context
*tctx
,
377 struct smb2_tree
*tree
)
379 struct smb2_handle hd
;
380 struct smb2_ioctl io
;
381 struct smb2_create cr
;
382 struct smb2_close cl
;
383 const char *fname
= "compound_related3.dat";
384 struct smb2_request
*req
[3];
388 smb2_util_unlink(tree
, fname
);
391 cr
.in
.security_flags
= 0x00;
392 cr
.in
.oplock_level
= 0;
393 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
394 cr
.in
.create_flags
= 0x00000000;
395 cr
.in
.reserved
= 0x00000000;
396 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
397 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
398 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
399 NTCREATEX_SHARE_ACCESS_WRITE
|
400 NTCREATEX_SHARE_ACCESS_DELETE
;
401 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
402 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
403 NTCREATEX_OPTIONS_ASYNC_ALERT
|
404 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
408 smb2_transport_compound_start(tree
->session
->transport
, 3);
410 req
[0] = smb2_create_send(tree
, &cr
);
412 hd
.data
[0] = UINT64_MAX
;
413 hd
.data
[1] = UINT64_MAX
;
415 smb2_transport_compound_set_related(tree
->session
->transport
, true);
418 io
.in
.function
= FSCTL_CREATE_OR_GET_OBJECT_ID
;
419 io
.in
.file
.handle
= hd
;
421 io
.in
.max_output_response
= 64;
424 req
[1] = smb2_ioctl_send(tree
, &io
);
427 cl
.in
.file
.handle
= hd
;
429 req
[2] = smb2_close_send(tree
, &cl
);
431 status
= smb2_create_recv(req
[0], tree
, &cr
);
432 CHECK_STATUS(status
, NT_STATUS_OK
);
433 status
= smb2_ioctl_recv(req
[1], tree
, &io
);
434 CHECK_STATUS(status
, NT_STATUS_OK
);
435 status
= smb2_close_recv(req
[2], &cl
);
436 CHECK_STATUS(status
, NT_STATUS_OK
);
438 status
= smb2_util_unlink(tree
, fname
);
439 CHECK_STATUS(status
, NT_STATUS_OK
);
446 static bool test_compound_related4(struct torture_context
*tctx
,
447 struct smb2_tree
*tree
)
449 const char *fname
= "compound_related4.dat";
450 struct security_descriptor
*sd
= NULL
;
451 struct smb2_handle hd
;
452 struct smb2_create cr
;
453 union smb_setfileinfo set
;
454 struct smb2_ioctl io
;
455 struct smb2_close cl
;
456 struct smb2_request
*req
[4];
460 smb2_util_unlink(tree
, fname
);
463 cr
.level
= RAW_OPEN_SMB2
;
464 cr
.in
.create_flags
= 0;
465 cr
.in
.desired_access
= SEC_STD_READ_CONTROL
|
468 cr
.in
.create_options
= 0;
469 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
470 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
471 NTCREATEX_SHARE_ACCESS_READ
|
472 NTCREATEX_SHARE_ACCESS_WRITE
;
473 cr
.in
.alloc_size
= 0;
474 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
475 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
476 cr
.in
.security_flags
= 0;
479 status
= smb2_create(tree
, tctx
, &cr
);
480 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_create failed\n");
482 hd
= cr
.out
.file
.handle
;
483 torture_comment(tctx
, "set a sec desc allowing no write by CREATOR_OWNER\n");
485 sd
= security_descriptor_dacl_create(tctx
,
488 SEC_ACE_TYPE_ACCESS_ALLOWED
,
489 SEC_RIGHTS_FILE_READ
| SEC_STD_ALL
,
492 torture_assert_not_null_goto(tctx
, sd
, ret
, done
,
493 "security_descriptor_dacl_create failed\n");
495 set
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
496 set
.set_secdesc
.in
.file
.handle
= hd
;
497 set
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
498 set
.set_secdesc
.in
.sd
= sd
;
500 status
= smb2_setinfo_file(tree
, &set
);
501 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
502 "smb2_setinfo_file failed\n");
504 torture_comment(tctx
, "try open for write\n");
505 cr
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
506 smb2_transport_compound_start(tree
->session
->transport
, 4);
508 req
[0] = smb2_create_send(tree
, &cr
);
509 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
510 "smb2_create_send failed\n");
512 hd
.data
[0] = UINT64_MAX
;
513 hd
.data
[1] = UINT64_MAX
;
515 smb2_transport_compound_set_related(tree
->session
->transport
, true);
517 io
.in
.function
= FSCTL_CREATE_OR_GET_OBJECT_ID
;
518 io
.in
.file
.handle
= hd
;
521 req
[1] = smb2_ioctl_send(tree
, &io
);
522 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
523 "smb2_ioctl_send failed\n");
526 cl
.in
.file
.handle
= hd
;
528 req
[2] = smb2_close_send(tree
, &cl
);
529 torture_assert_not_null_goto(tctx
, req
[2], ret
, done
,
530 "smb2_create_send failed\n");
532 set
.set_secdesc
.in
.file
.handle
= hd
;
534 req
[3] = smb2_setinfo_file_send(tree
, &set
);
535 torture_assert_not_null_goto(tctx
, req
[3], ret
, done
,
536 "smb2_create_send failed\n");
538 status
= smb2_create_recv(req
[0], tree
, &cr
);
539 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
541 "smb2_create_recv failed\n");
543 status
= smb2_ioctl_recv(req
[1], tree
, &io
);
544 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
546 "smb2_ioctl_recv failed\n");
548 status
= smb2_close_recv(req
[2], &cl
);
549 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
551 "smb2_close_recv failed\n");
553 status
= smb2_setinfo_recv(req
[3]);
554 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
556 "smb2_setinfo_recv failed\n");
559 smb2_util_unlink(tree
, fname
);
561 smb2_logoff(tree
->session
);
565 static bool test_compound_related5(struct torture_context
*tctx
,
566 struct smb2_tree
*tree
)
568 struct smb2_handle hd
;
569 struct smb2_ioctl io
;
570 struct smb2_close cl
;
571 struct smb2_request
*req
[2];
575 smb2_transport_compound_start(tree
->session
->transport
, 2);
577 hd
.data
[0] = UINT64_MAX
;
578 hd
.data
[1] = UINT64_MAX
;
581 io
.in
.function
= FSCTL_CREATE_OR_GET_OBJECT_ID
;
582 io
.in
.file
.handle
= hd
;
585 req
[0] = smb2_ioctl_send(tree
, &io
);
586 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
587 "smb2_ioctl_send failed\n");
589 smb2_transport_compound_set_related(tree
->session
->transport
, true);
592 cl
.in
.file
.handle
= hd
;
594 req
[1] = smb2_close_send(tree
, &cl
);
595 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
596 "smb2_create_send failed\n");
598 status
= smb2_ioctl_recv(req
[0], tree
, &io
);
599 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_FILE_CLOSED
,
601 "smb2_ioctl_recv failed\n");
603 status
= smb2_close_recv(req
[1], &cl
);
604 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_FILE_CLOSED
,
606 "smb2_close_recv failed\n");
612 smb2_logoff(tree
->session
);
616 static bool test_compound_related6(struct torture_context
*tctx
,
617 struct smb2_tree
*tree
)
619 struct smb2_handle hd
;
620 struct smb2_create cr
;
622 struct smb2_write wr
;
623 struct smb2_close cl
;
625 const char *fname
= "compound_related6.dat";
626 struct smb2_request
*req
[5];
630 smb2_util_unlink(tree
, fname
);
633 cr
.level
= RAW_OPEN_SMB2
;
634 cr
.in
.create_flags
= 0;
635 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
636 cr
.in
.create_options
= 0;
637 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
638 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
639 NTCREATEX_SHARE_ACCESS_READ
|
640 NTCREATEX_SHARE_ACCESS_WRITE
;
641 cr
.in
.alloc_size
= 0;
642 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
643 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
644 cr
.in
.security_flags
= 0;
647 status
= smb2_create(tree
, tctx
, &cr
);
648 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
649 "smb2_create failed\n");
651 hd
= cr
.out
.file
.handle
;
654 status
= smb2_util_write(tree
, hd
, buf
, 0, ARRAY_SIZE(buf
));
655 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
656 "smb2_util_write failed\n");
658 torture_comment(tctx
, "try open for read\n");
659 cr
.in
.desired_access
= SEC_FILE_READ_DATA
;
660 smb2_transport_compound_start(tree
->session
->transport
, 5);
662 req
[0] = smb2_create_send(tree
, &cr
);
663 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
664 "smb2_create_send failed\n");
666 hd
.data
[0] = UINT64_MAX
;
667 hd
.data
[1] = UINT64_MAX
;
669 smb2_transport_compound_set_related(tree
->session
->transport
, true);
672 rd
.in
.file
.handle
= hd
;
676 req
[1] = smb2_read_send(tree
, &rd
);
677 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
678 "smb2_read_send failed\n");
681 wr
.in
.file
.handle
= hd
;
683 wr
.in
.data
= data_blob_talloc(tctx
, NULL
, 64);
685 req
[2] = smb2_write_send(tree
, &wr
);
686 torture_assert_not_null_goto(tctx
, req
[2], ret
, done
,
687 "smb2_write_send failed\n");
690 rd
.in
.file
.handle
= hd
;
694 req
[3] = smb2_read_send(tree
, &rd
);
695 torture_assert_not_null_goto(tctx
, req
[3], ret
, done
,
696 "smb2_read_send failed\n");
699 cl
.in
.file
.handle
= hd
;
701 req
[4] = smb2_close_send(tree
, &cl
);
702 torture_assert_not_null_goto(tctx
, req
[4], ret
, done
,
703 "smb2_close_send failed\n");
705 status
= smb2_create_recv(req
[0], tree
, &cr
);
706 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
707 "smb2_create_recv failed\n");
709 status
= smb2_read_recv(req
[1], tree
, &rd
);
710 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
711 "smb2_read_recv failed\n");
713 status
= smb2_write_recv(req
[2], &wr
);
714 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
716 "smb2_write_recv failed\n");
718 status
= smb2_read_recv(req
[3], tree
, &rd
);
719 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
720 "smb2_read_recv failed\n");
722 status
= smb2_close_recv(req
[4], &cl
);
723 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
724 "smb2_close_recv failed\n");
727 smb2_util_unlink(tree
, fname
);
729 smb2_logoff(tree
->session
);
733 static bool test_compound_related7(struct torture_context
*tctx
,
734 struct smb2_tree
*tree
)
736 const char *fname
= "compound_related4.dat";
737 struct security_descriptor
*sd
= NULL
;
738 struct smb2_handle hd
;
739 struct smb2_create cr
;
740 union smb_setfileinfo set
;
741 struct smb2_notify nt
;
742 struct smb2_close cl
;
744 struct smb2_request
*req
[4];
747 smb2_util_unlink(tree
, fname
);
750 cr
.level
= RAW_OPEN_SMB2
;
751 cr
.in
.create_flags
= 0;
752 cr
.in
.desired_access
= SEC_STD_READ_CONTROL
|
755 cr
.in
.create_options
= 0;
756 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
757 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
758 NTCREATEX_SHARE_ACCESS_READ
|
759 NTCREATEX_SHARE_ACCESS_WRITE
;
760 cr
.in
.alloc_size
= 0;
761 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
762 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
763 cr
.in
.security_flags
= 0;
766 status
= smb2_create(tree
, tctx
, &cr
);
767 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
768 "smb2_create failed\n");
770 hd
= cr
.out
.file
.handle
;
771 torture_comment(tctx
, "set a sec desc allowing no write by CREATOR_OWNER\n");
772 sd
= security_descriptor_dacl_create(tctx
,
775 SEC_ACE_TYPE_ACCESS_ALLOWED
,
776 SEC_RIGHTS_FILE_READ
| SEC_STD_ALL
,
779 torture_assert_not_null_goto(tctx
, sd
, ret
, done
,
780 "security_descriptor_dacl_create failed\n");
782 set
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
783 set
.set_secdesc
.in
.file
.handle
= hd
;
784 set
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
785 set
.set_secdesc
.in
.sd
= sd
;
787 status
= smb2_setinfo_file(tree
, &set
);
788 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
789 "smb2_setinfo_file failed\n");
791 torture_comment(tctx
, "try open for write\n");
792 cr
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
793 smb2_transport_compound_start(tree
->session
->transport
, 4);
795 req
[0] = smb2_create_send(tree
, &cr
);
796 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
797 "smb2_create_send failed\n");
799 hd
.data
[0] = UINT64_MAX
;
800 hd
.data
[1] = UINT64_MAX
;
802 smb2_transport_compound_set_related(tree
->session
->transport
, true);
805 nt
.in
.recursive
= true;
806 nt
.in
.buffer_size
= 0x1000;
807 nt
.in
.file
.handle
= hd
;
808 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
809 nt
.in
.unknown
= 0x00000000;
811 req
[1] = smb2_notify_send(tree
, &nt
);
812 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
813 "smb2_notify_send failed\n");
816 cl
.in
.file
.handle
= hd
;
818 req
[2] = smb2_close_send(tree
, &cl
);
819 torture_assert_not_null_goto(tctx
, req
[2], ret
, done
,
820 "smb2_close_send failed\n");
822 set
.set_secdesc
.in
.file
.handle
= hd
;
824 req
[3] = smb2_setinfo_file_send(tree
, &set
);
825 torture_assert_not_null_goto(tctx
, req
[3], ret
, done
,
826 "smb2_setinfo_file_send failed\n");
828 status
= smb2_create_recv(req
[0], tree
, &cr
);
829 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
831 "smb2_create_recv failed\n");
833 status
= smb2_notify_recv(req
[1], tree
, &nt
);
834 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
836 "smb2_notify_recv failed\n");
838 status
= smb2_close_recv(req
[2], &cl
);
839 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
841 "smb2_close_recv failed\n");
843 status
= smb2_setinfo_recv(req
[3]);
844 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
846 "smb2_setinfo_recv failed\n");
849 smb2_util_unlink(tree
, fname
);
851 smb2_logoff(tree
->session
);
855 static bool test_compound_related8(struct torture_context
*tctx
,
856 struct smb2_tree
*tree
)
858 const char *fname
= "compound_related8.dat";
859 const char *fname_nonexisting
= "compound_related8.dat.void";
860 struct security_descriptor
*sd
= NULL
;
861 struct smb2_handle hd
;
862 struct smb2_create cr
;
863 union smb_setfileinfo set
;
864 struct smb2_notify nt
;
865 struct smb2_close cl
;
867 struct smb2_request
*req
[4];
870 smb2_util_unlink(tree
, fname
);
873 cr
.level
= RAW_OPEN_SMB2
;
874 cr
.in
.create_flags
= 0;
875 cr
.in
.desired_access
= SEC_STD_READ_CONTROL
|
878 cr
.in
.create_options
= 0;
879 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
880 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
881 NTCREATEX_SHARE_ACCESS_READ
|
882 NTCREATEX_SHARE_ACCESS_WRITE
;
883 cr
.in
.alloc_size
= 0;
884 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
885 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
886 cr
.in
.security_flags
= 0;
889 status
= smb2_create(tree
, tctx
, &cr
);
890 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
891 "smb2_create failed\n");
893 hd
= cr
.out
.file
.handle
;
895 smb2_transport_compound_start(tree
->session
->transport
, 4);
897 torture_comment(tctx
, "try open for write\n");
898 cr
.in
.fname
= fname_nonexisting
;
899 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
901 req
[0] = smb2_create_send(tree
, &cr
);
902 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
903 "smb2_create_send failed\n");
905 hd
.data
[0] = UINT64_MAX
;
906 hd
.data
[1] = UINT64_MAX
;
908 smb2_transport_compound_set_related(tree
->session
->transport
, true);
911 nt
.in
.recursive
= true;
912 nt
.in
.buffer_size
= 0x1000;
913 nt
.in
.file
.handle
= hd
;
914 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
915 nt
.in
.unknown
= 0x00000000;
917 req
[1] = smb2_notify_send(tree
, &nt
);
918 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
919 "smb2_notify_send failed\n");
922 cl
.in
.file
.handle
= hd
;
924 req
[2] = smb2_close_send(tree
, &cl
);
925 torture_assert_not_null_goto(tctx
, req
[2], ret
, done
,
926 "smb2_close_send failed\n");
928 sd
= security_descriptor_dacl_create(tctx
,
931 SEC_ACE_TYPE_ACCESS_ALLOWED
,
932 SEC_RIGHTS_FILE_READ
| SEC_STD_ALL
,
935 torture_assert_not_null_goto(tctx
, sd
, ret
, done
,
936 "security_descriptor_dacl_create failed\n");
938 set
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
939 set
.set_secdesc
.in
.file
.handle
= hd
;
940 set
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
941 set
.set_secdesc
.in
.sd
= sd
;
943 req
[3] = smb2_setinfo_file_send(tree
, &set
);
944 torture_assert_not_null_goto(tctx
, req
[3], ret
, done
,
945 "smb2_setinfo_file_send failed\n");
947 status
= smb2_create_recv(req
[0], tree
, &cr
);
948 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
,
950 "smb2_create_recv failed\n");
952 status
= smb2_notify_recv(req
[1], tree
, &nt
);
953 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
,
955 "smb2_notify_recv failed\n");
957 status
= smb2_close_recv(req
[2], &cl
);
958 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
,
960 "smb2_close_recv failed\n");
962 status
= smb2_setinfo_recv(req
[3]);
963 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
,
965 "smb2_setinfo_recv failed\n");
968 smb2_util_unlink(tree
, fname
);
970 smb2_logoff(tree
->session
);
974 static bool test_compound_related9(struct torture_context
*tctx
,
975 struct smb2_tree
*tree
)
977 const char *fname
= "compound_related9.dat";
978 struct security_descriptor
*sd
= NULL
;
979 struct smb2_handle hd
;
980 struct smb2_create cr
;
981 union smb_setfileinfo set
;
982 struct smb2_notify nt
;
983 struct smb2_close cl
;
985 struct smb2_request
*req
[3];
988 smb2_util_unlink(tree
, fname
);
991 cr
.level
= RAW_OPEN_SMB2
;
992 cr
.in
.create_flags
= 0;
993 cr
.in
.desired_access
= SEC_STD_READ_CONTROL
|
996 cr
.in
.create_options
= 0;
997 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
998 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
999 NTCREATEX_SHARE_ACCESS_READ
|
1000 NTCREATEX_SHARE_ACCESS_WRITE
;
1001 cr
.in
.alloc_size
= 0;
1002 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1003 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1004 cr
.in
.security_flags
= 0;
1005 cr
.in
.fname
= fname
;
1007 status
= smb2_create(tree
, tctx
, &cr
);
1008 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1009 "smb2_create failed\n");
1011 hd
= cr
.out
.file
.handle
;
1013 smb2_transport_compound_start(tree
->session
->transport
, 3);
1014 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1017 nt
.in
.recursive
= true;
1018 nt
.in
.buffer_size
= 0x1000;
1019 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1021 req
[0] = smb2_notify_send(tree
, &nt
);
1022 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
1023 "smb2_notify_send failed\n");
1026 cl
.in
.file
.handle
= hd
;
1028 req
[1] = smb2_close_send(tree
, &cl
);
1029 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
1030 "smb2_close_send failed\n");
1032 sd
= security_descriptor_dacl_create(tctx
,
1035 SEC_ACE_TYPE_ACCESS_ALLOWED
,
1036 SEC_RIGHTS_FILE_READ
| SEC_STD_ALL
,
1039 torture_assert_not_null_goto(tctx
, sd
, ret
, done
,
1040 "security_descriptor_dacl_create failed\n");
1042 set
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
1043 set
.set_secdesc
.in
.file
.handle
= hd
;
1044 set
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
1045 set
.set_secdesc
.in
.sd
= sd
;
1047 req
[2] = smb2_setinfo_file_send(tree
, &set
);
1048 torture_assert_not_null_goto(tctx
, req
[2], ret
, done
,
1049 "smb2_setinfo_file_send failed\n");
1051 status
= smb2_notify_recv(req
[0], tree
, &nt
);
1052 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_INVALID_PARAMETER
,
1054 "smb2_notify_recv failed\n");
1056 status
= smb2_close_recv(req
[1], &cl
);
1057 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_INVALID_PARAMETER
,
1059 "smb2_close_recv failed\n");
1061 status
= smb2_setinfo_recv(req
[2]);
1062 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_INVALID_PARAMETER
,
1064 "smb2_setinfo_recv failed\n");
1067 smb2_util_unlink(tree
, fname
);
1069 smb2_logoff(tree
->session
);
1073 static bool test_compound_padding(struct torture_context
*tctx
,
1074 struct smb2_tree
*tree
)
1076 struct smb2_handle h
;
1077 struct smb2_create cr
;
1079 struct smb2_read r2
;
1080 const char *fname
= "compound_read.dat";
1081 const char *sname
= "compound_read.dat:foo";
1082 struct smb2_request
*req
[3];
1086 smb2_util_unlink(tree
, fname
);
1090 cr
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
1091 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1092 cr
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1093 cr
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1094 cr
.in
.fname
= fname
;
1095 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1096 NTCREATEX_SHARE_ACCESS_WRITE
|
1097 NTCREATEX_SHARE_ACCESS_DELETE
;
1098 status
= smb2_create(tree
, tctx
, &cr
);
1099 CHECK_STATUS(status
, NT_STATUS_OK
);
1100 h
= cr
.out
.file
.handle
;
1102 status
= smb2_util_write(tree
, h
, "123", 0, 3);
1103 CHECK_STATUS(status
, NT_STATUS_OK
);
1105 smb2_util_close(tree
, h
);
1109 cr
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
1110 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1111 cr
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1112 cr
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1113 cr
.in
.fname
= sname
;
1114 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1115 NTCREATEX_SHARE_ACCESS_WRITE
|
1116 NTCREATEX_SHARE_ACCESS_DELETE
;
1117 status
= smb2_create(tree
, tctx
, &cr
);
1118 CHECK_STATUS(status
, NT_STATUS_OK
);
1119 h
= cr
.out
.file
.handle
;
1121 status
= smb2_util_write(tree
, h
, "456", 0, 3);
1122 CHECK_STATUS(status
, NT_STATUS_OK
);
1124 smb2_util_close(tree
, h
);
1126 /* Check compound read from basefile */
1127 smb2_transport_compound_start(tree
->session
->transport
, 3);
1130 cr
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1131 cr
.in
.desired_access
= SEC_FILE_READ_DATA
;
1132 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1133 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1134 cr
.in
.fname
= fname
;
1135 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1136 NTCREATEX_SHARE_ACCESS_WRITE
|
1137 NTCREATEX_SHARE_ACCESS_DELETE
;
1138 req
[0] = smb2_create_send(tree
, &cr
);
1140 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1143 * We send 2 reads in the compound here as the protocol
1144 * allows the last read to be split off and possibly
1145 * go async. Check the padding on the first read returned,
1146 * not the second as the second may not be part of the
1147 * returned compound.
1151 h
.data
[0] = UINT64_MAX
;
1152 h
.data
[1] = UINT64_MAX
;
1153 r
.in
.file
.handle
= h
;
1157 req
[1] = smb2_read_send(tree
, &r
);
1160 h
.data
[0] = UINT64_MAX
;
1161 h
.data
[1] = UINT64_MAX
;
1162 r2
.in
.file
.handle
= h
;
1165 r2
.in
.min_count
= 1;
1166 req
[2] = smb2_read_send(tree
, &r2
);
1168 status
= smb2_create_recv(req
[0], tree
, &cr
);
1169 CHECK_STATUS(status
, NT_STATUS_OK
);
1172 * We must do a manual smb2_request_receive() in order to be
1173 * able to check the transport layer info, as smb2_read_recv()
1174 * will destroy the req. smb2_read_recv() will call
1175 * smb2_request_receive() again, but that's ok.
1177 if (!smb2_request_receive(req
[1]) ||
1178 !smb2_request_is_ok(req
[1])) {
1179 torture_fail(tctx
, "failed to receive read request");
1183 * size must be 24: 16 byte read response header plus 3
1184 * requested bytes padded to an 8 byte boundary.
1186 CHECK_VALUE(req
[1]->in
.body_size
, 24);
1188 status
= smb2_read_recv(req
[1], tree
, &r
);
1189 CHECK_STATUS(status
, NT_STATUS_OK
);
1191 /* Pick up the second, possibly async, read. */
1192 status
= smb2_read_recv(req
[2], tree
, &r2
);
1193 CHECK_STATUS(status
, NT_STATUS_OK
);
1195 smb2_util_close(tree
, cr
.out
.file
.handle
);
1197 /* Check compound read from stream */
1198 smb2_transport_compound_start(tree
->session
->transport
, 3);
1201 cr
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1202 cr
.in
.desired_access
= SEC_FILE_READ_DATA
;
1203 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1204 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1205 cr
.in
.fname
= sname
;
1206 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1207 NTCREATEX_SHARE_ACCESS_WRITE
|
1208 NTCREATEX_SHARE_ACCESS_DELETE
;
1209 req
[0] = smb2_create_send(tree
, &cr
);
1211 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1214 * We send 2 reads in the compound here as the protocol
1215 * allows the last read to be split off and possibly
1216 * go async. Check the padding on the first read returned,
1217 * not the second as the second may not be part of the
1218 * returned compound.
1222 h
.data
[0] = UINT64_MAX
;
1223 h
.data
[1] = UINT64_MAX
;
1224 r
.in
.file
.handle
= h
;
1228 req
[1] = smb2_read_send(tree
, &r
);
1231 h
.data
[0] = UINT64_MAX
;
1232 h
.data
[1] = UINT64_MAX
;
1233 r2
.in
.file
.handle
= h
;
1236 r2
.in
.min_count
= 1;
1237 req
[2] = smb2_read_send(tree
, &r2
);
1239 status
= smb2_create_recv(req
[0], tree
, &cr
);
1240 CHECK_STATUS(status
, NT_STATUS_OK
);
1243 * We must do a manual smb2_request_receive() in order to be
1244 * able to check the transport layer info, as smb2_read_recv()
1245 * will destroy the req. smb2_read_recv() will call
1246 * smb2_request_receive() again, but that's ok.
1248 if (!smb2_request_receive(req
[1]) ||
1249 !smb2_request_is_ok(req
[1])) {
1250 torture_fail(tctx
, "failed to receive read request");
1254 * size must be 24: 16 byte read response header plus 3
1255 * requested bytes padded to an 8 byte boundary.
1257 CHECK_VALUE(req
[1]->in
.body_size
, 24);
1259 status
= smb2_read_recv(req
[1], tree
, &r
);
1260 CHECK_STATUS(status
, NT_STATUS_OK
);
1262 /* Pick up the second, possibly async, read. */
1263 status
= smb2_read_recv(req
[2], tree
, &r2
);
1264 CHECK_STATUS(status
, NT_STATUS_OK
);
1266 h
= cr
.out
.file
.handle
;
1268 /* Check 2 compound (unrelateated) reads from existing stream handle */
1269 smb2_transport_compound_start(tree
->session
->transport
, 2);
1272 r
.in
.file
.handle
= h
;
1276 req
[0] = smb2_read_send(tree
, &r
);
1277 req
[1] = smb2_read_send(tree
, &r
);
1280 * We must do a manual smb2_request_receive() in order to be
1281 * able to check the transport layer info, as smb2_read_recv()
1282 * will destroy the req. smb2_read_recv() will call
1283 * smb2_request_receive() again, but that's ok.
1285 if (!smb2_request_receive(req
[0]) ||
1286 !smb2_request_is_ok(req
[0])) {
1287 torture_fail(tctx
, "failed to receive read request");
1289 if (!smb2_request_receive(req
[1]) ||
1290 !smb2_request_is_ok(req
[1])) {
1291 torture_fail(tctx
, "failed to receive read request");
1295 * size must be 24: 16 byte read response header plus 3
1296 * requested bytes padded to an 8 byte boundary.
1298 CHECK_VALUE(req
[0]->in
.body_size
, 24);
1299 CHECK_VALUE(req
[1]->in
.body_size
, 24);
1301 status
= smb2_read_recv(req
[0], tree
, &r
);
1302 CHECK_STATUS(status
, NT_STATUS_OK
);
1303 status
= smb2_read_recv(req
[1], tree
, &r
);
1304 CHECK_STATUS(status
, NT_STATUS_OK
);
1307 * now try a single read from the stream and verify there's no padding
1310 r
.in
.file
.handle
= h
;
1314 req
[0] = smb2_read_send(tree
, &r
);
1317 * We must do a manual smb2_request_receive() in order to be
1318 * able to check the transport layer info, as smb2_read_recv()
1319 * will destroy the req. smb2_read_recv() will call
1320 * smb2_request_receive() again, but that's ok.
1322 if (!smb2_request_receive(req
[0]) ||
1323 !smb2_request_is_ok(req
[0])) {
1324 torture_fail(tctx
, "failed to receive read request");
1328 * size must be 19: 16 byte read response header plus 3
1329 * requested bytes without padding.
1331 CHECK_VALUE(req
[0]->in
.body_size
, 19);
1333 status
= smb2_read_recv(req
[0], tree
, &r
);
1334 CHECK_STATUS(status
, NT_STATUS_OK
);
1336 smb2_util_close(tree
, h
);
1338 status
= smb2_util_unlink(tree
, fname
);
1339 CHECK_STATUS(status
, NT_STATUS_OK
);
1346 static bool test_compound_create_write_close(struct torture_context
*tctx
,
1347 struct smb2_tree
*tree
)
1349 struct smb2_handle handle
= { .data
= { UINT64_MAX
, UINT64_MAX
} };
1350 struct smb2_create create
;
1351 struct smb2_write write
;
1352 struct smb2_close close
;
1353 const char *fname
= "compound_create_write_close.dat";
1354 struct smb2_request
*req
[3];
1358 smb2_util_unlink(tree
, fname
);
1360 ZERO_STRUCT(create
);
1361 create
.in
.security_flags
= 0x00;
1362 create
.in
.oplock_level
= 0;
1363 create
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1364 create
.in
.create_flags
= 0x00000000;
1365 create
.in
.reserved
= 0x00000000;
1366 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1367 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1368 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1369 NTCREATEX_SHARE_ACCESS_WRITE
|
1370 NTCREATEX_SHARE_ACCESS_DELETE
;
1371 create
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1372 create
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1373 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1374 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1376 create
.in
.fname
= fname
;
1378 smb2_transport_compound_start(tree
->session
->transport
, 3);
1380 req
[0] = smb2_create_send(tree
, &create
);
1382 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1385 write
.in
.file
.handle
= handle
;
1386 write
.in
.offset
= 0;
1387 write
.in
.data
= data_blob_talloc(tctx
, NULL
, 1024);
1389 req
[1] = smb2_write_send(tree
, &write
);
1392 close
.in
.file
.handle
= handle
;
1394 req
[2] = smb2_close_send(tree
, &close
);
1396 status
= smb2_create_recv(req
[0], tree
, &create
);
1397 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1400 status
= smb2_write_recv(req
[1], &write
);
1401 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1404 status
= smb2_close_recv(req
[2], &close
);
1405 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1408 status
= smb2_util_unlink(tree
, fname
);
1409 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1410 "File deletion failed.");
1417 static bool test_compound_unrelated1(struct torture_context
*tctx
,
1418 struct smb2_tree
*tree
)
1420 struct smb2_handle hd
;
1421 struct smb2_create cr
;
1423 const char *fname
= "compound_unrelated1.dat";
1424 struct smb2_close cl
;
1426 struct smb2_request
*req
[5];
1428 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
1430 smb2_util_unlink(tree
, fname
);
1432 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1435 cr
.in
.security_flags
= 0x00;
1436 cr
.in
.oplock_level
= 0;
1437 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1438 cr
.in
.create_flags
= 0x00000000;
1439 cr
.in
.reserved
= 0x00000000;
1440 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1441 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1442 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1443 NTCREATEX_SHARE_ACCESS_WRITE
|
1444 NTCREATEX_SHARE_ACCESS_DELETE
;
1445 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1446 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1447 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1448 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1450 cr
.in
.fname
= fname
;
1452 smb2_transport_compound_start(tree
->session
->transport
, 5);
1454 req
[0] = smb2_create_send(tree
, &cr
);
1456 hd
.data
[0] = UINT64_MAX
;
1457 hd
.data
[1] = UINT64_MAX
;
1460 cl
.in
.file
.handle
= hd
;
1461 req
[1] = smb2_close_send(tree
, &cl
);
1462 req
[2] = smb2_close_send(tree
, &cl
);
1463 req
[3] = smb2_close_send(tree
, &cl
);
1464 req
[4] = smb2_close_send(tree
, &cl
);
1466 status
= smb2_create_recv(req
[0], tree
, &cr
);
1467 CHECK_STATUS(status
, NT_STATUS_OK
);
1468 status
= smb2_close_recv(req
[1], &cl
);
1469 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1470 status
= smb2_close_recv(req
[2], &cl
);
1471 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1472 status
= smb2_close_recv(req
[3], &cl
);
1473 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1474 status
= smb2_close_recv(req
[4], &cl
);
1475 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1477 smb2_util_unlink(tree
, fname
);
1482 static bool test_compound_invalid1(struct torture_context
*tctx
,
1483 struct smb2_tree
*tree
)
1485 struct smb2_handle hd
;
1486 struct smb2_create cr
;
1488 const char *fname
= "compound_invalid1.dat";
1489 struct smb2_close cl
;
1491 struct smb2_request
*req
[3];
1493 smb2_transport_credits_ask_num(tree
->session
->transport
, 3);
1495 smb2_util_unlink(tree
, fname
);
1497 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1500 cr
.in
.security_flags
= 0x00;
1501 cr
.in
.oplock_level
= 0;
1502 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1503 cr
.in
.create_flags
= 0x00000000;
1504 cr
.in
.reserved
= 0x00000000;
1505 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1506 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1507 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1508 NTCREATEX_SHARE_ACCESS_WRITE
|
1509 NTCREATEX_SHARE_ACCESS_DELETE
;
1510 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1511 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1512 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1513 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1515 cr
.in
.fname
= fname
;
1517 smb2_transport_compound_start(tree
->session
->transport
, 3);
1519 /* passing the first request with the related flag is invalid */
1520 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1522 req
[0] = smb2_create_send(tree
, &cr
);
1524 hd
.data
[0] = UINT64_MAX
;
1525 hd
.data
[1] = UINT64_MAX
;
1528 cl
.in
.file
.handle
= hd
;
1529 req
[1] = smb2_close_send(tree
, &cl
);
1531 smb2_transport_compound_set_related(tree
->session
->transport
, false);
1532 req
[2] = smb2_close_send(tree
, &cl
);
1534 status
= smb2_create_recv(req
[0], tree
, &cr
);
1535 /* TODO: check why this fails with --signing=required */
1536 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1537 status
= smb2_close_recv(req
[1], &cl
);
1538 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1539 status
= smb2_close_recv(req
[2], &cl
);
1540 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1542 smb2_util_unlink(tree
, fname
);
1547 static bool test_compound_invalid2(struct torture_context
*tctx
,
1548 struct smb2_tree
*tree
)
1550 struct smb2_handle hd
;
1551 struct smb2_create cr
;
1553 const char *fname
= "compound_invalid2.dat";
1554 struct smb2_close cl
;
1556 struct smb2_request
*req
[5];
1557 struct smbXcli_tcon
*saved_tcon
= tree
->smbXcli
;
1558 struct smbXcli_session
*saved_session
= tree
->session
->smbXcli
;
1560 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
1562 smb2_util_unlink(tree
, fname
);
1564 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1567 cr
.in
.security_flags
= 0x00;
1568 cr
.in
.oplock_level
= 0;
1569 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1570 cr
.in
.create_flags
= 0x00000000;
1571 cr
.in
.reserved
= 0x00000000;
1572 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1573 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1574 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1575 NTCREATEX_SHARE_ACCESS_WRITE
|
1576 NTCREATEX_SHARE_ACCESS_DELETE
;
1577 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1578 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1579 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1580 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1582 cr
.in
.fname
= fname
;
1584 smb2_transport_compound_start(tree
->session
->transport
, 5);
1586 req
[0] = smb2_create_send(tree
, &cr
);
1588 hd
.data
[0] = UINT64_MAX
;
1589 hd
.data
[1] = UINT64_MAX
;
1591 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1594 cl
.in
.file
.handle
= hd
;
1596 tree
->smbXcli
= smbXcli_tcon_create(tree
);
1597 smb2cli_tcon_set_values(tree
->smbXcli
,
1599 0xFFFFFFFF, /* tcon_id */
1602 0, /* capabilities */
1603 0 /* maximal_access */);
1605 tree
->session
->smbXcli
= smbXcli_session_shallow_copy(tree
->session
,
1606 tree
->session
->smbXcli
);
1607 smb2cli_session_set_id_and_flags(tree
->session
->smbXcli
, UINT64_MAX
, 0);
1609 req
[1] = smb2_close_send(tree
, &cl
);
1610 /* strange that this is not generating invalid parameter */
1611 smb2_transport_compound_set_related(tree
->session
->transport
, false);
1612 req
[2] = smb2_close_send(tree
, &cl
);
1613 req
[3] = smb2_close_send(tree
, &cl
);
1614 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1615 req
[4] = smb2_close_send(tree
, &cl
);
1617 status
= smb2_create_recv(req
[0], tree
, &cr
);
1618 CHECK_STATUS(status
, NT_STATUS_OK
);
1619 status
= smb2_close_recv(req
[1], &cl
);
1620 CHECK_STATUS(status
, NT_STATUS_OK
);
1621 status
= smb2_close_recv(req
[2], &cl
);
1622 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
1623 status
= smb2_close_recv(req
[3], &cl
);
1624 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
1625 status
= smb2_close_recv(req
[4], &cl
);
1626 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1628 TALLOC_FREE(tree
->smbXcli
);
1629 tree
->smbXcli
= saved_tcon
;
1630 TALLOC_FREE(tree
->session
->smbXcli
);
1631 tree
->session
->smbXcli
= saved_session
;
1633 smb2_util_unlink(tree
, fname
);
1638 static bool test_compound_invalid3(struct torture_context
*tctx
,
1639 struct smb2_tree
*tree
)
1641 struct smb2_handle hd
;
1642 struct smb2_create cr
;
1644 const char *fname
= "compound_invalid3.dat";
1645 struct smb2_close cl
;
1647 struct smb2_request
*req
[5];
1649 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
1651 smb2_util_unlink(tree
, fname
);
1653 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1656 cr
.in
.security_flags
= 0x00;
1657 cr
.in
.oplock_level
= 0;
1658 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1659 cr
.in
.create_flags
= 0x00000000;
1660 cr
.in
.reserved
= 0x00000000;
1661 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1662 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1663 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1664 NTCREATEX_SHARE_ACCESS_WRITE
|
1665 NTCREATEX_SHARE_ACCESS_DELETE
;
1666 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1667 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1668 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1669 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1671 cr
.in
.fname
= fname
;
1673 smb2_transport_compound_start(tree
->session
->transport
, 5);
1675 req
[0] = smb2_create_send(tree
, &cr
);
1677 hd
.data
[0] = UINT64_MAX
;
1678 hd
.data
[1] = UINT64_MAX
;
1681 cl
.in
.file
.handle
= hd
;
1682 req
[1] = smb2_close_send(tree
, &cl
);
1683 req
[2] = smb2_close_send(tree
, &cl
);
1684 /* flipping the related flag is invalid */
1685 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1686 req
[3] = smb2_close_send(tree
, &cl
);
1687 req
[4] = smb2_close_send(tree
, &cl
);
1689 status
= smb2_create_recv(req
[0], tree
, &cr
);
1690 CHECK_STATUS(status
, NT_STATUS_OK
);
1691 status
= smb2_close_recv(req
[1], &cl
);
1692 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1693 status
= smb2_close_recv(req
[2], &cl
);
1694 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1695 status
= smb2_close_recv(req
[3], &cl
);
1696 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1697 status
= smb2_close_recv(req
[4], &cl
);
1698 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1700 smb2_util_unlink(tree
, fname
);
1705 static bool test_compound_invalid4(struct torture_context
*tctx
,
1706 struct smb2_tree
*tree
)
1708 struct smb2_create cr
;
1709 struct smb2_read rd
;
1711 const char *fname
= "compound_invalid4.dat";
1712 struct smb2_close cl
;
1715 struct smb2_request
*req
[2];
1717 smb2_transport_credits_ask_num(tree
->session
->transport
, 2);
1719 smb2_util_unlink(tree
, fname
);
1722 cr
.in
.security_flags
= 0x00;
1723 cr
.in
.oplock_level
= 0;
1724 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1725 cr
.in
.create_flags
= 0x00000000;
1726 cr
.in
.reserved
= 0x00000000;
1727 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1728 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1729 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1730 NTCREATEX_SHARE_ACCESS_WRITE
|
1731 NTCREATEX_SHARE_ACCESS_DELETE
;
1732 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1733 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1734 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1735 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1737 cr
.in
.fname
= fname
;
1739 status
= smb2_create(tree
, tctx
, &cr
);
1740 CHECK_STATUS(status
, NT_STATUS_OK
);
1742 smb2_transport_compound_start(tree
->session
->transport
, 2);
1745 rd
.in
.file
.handle
= cr
.out
.file
.handle
;
1748 req
[0] = smb2_read_send(tree
, &rd
);
1750 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1753 * Send a completely bogus request as second compound
1754 * element. This triggers smbd_smb2_request_error() in in
1755 * smbd_smb2_request_dispatch() before calling
1756 * smbd_smb2_request_dispatch_update_counts().
1759 req
[1] = smb2_request_init_tree(tree
, 0xff, 0x04, false, 0);
1760 smb2_transport_send(req
[1]);
1762 status
= smb2_read_recv(req
[0], tctx
, &rd
);
1763 CHECK_STATUS(status
, NT_STATUS_END_OF_FILE
);
1765 ok
= smb2_request_receive(req
[1]);
1766 torture_assert(tctx
, ok
, "Invalid request failed\n");
1767 CHECK_STATUS(req
[1]->status
, NT_STATUS_INVALID_PARAMETER
);
1770 cl
.in
.file
.handle
= cr
.out
.file
.handle
;
1772 status
= smb2_close(tree
, &cl
);
1773 CHECK_STATUS(status
, NT_STATUS_OK
);
1775 smb2_util_unlink(tree
, fname
);
1780 /* Send a compound request where we expect the last request (Create, Notify)
1781 * to go asynchronous. This works against a Win7 server and the reply is
1782 * sent in two different packets. */
1783 static bool test_compound_interim1(struct torture_context
*tctx
,
1784 struct smb2_tree
*tree
)
1786 struct smb2_handle hd
;
1787 struct smb2_create cr
;
1788 NTSTATUS status
= NT_STATUS_OK
;
1789 const char *dname
= "compound_interim_dir";
1790 struct smb2_notify nt
;
1792 struct smb2_request
*req
[2];
1794 /* Win7 compound request implementation deviates substantially from the
1795 * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
1796 * verifies the Windows behavior, not the general spec behavior. */
1798 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
1800 smb2_deltree(tree
, dname
);
1802 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1805 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1806 cr
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1807 cr
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
1808 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1809 NTCREATEX_SHARE_ACCESS_WRITE
|
1810 NTCREATEX_SHARE_ACCESS_DELETE
;
1811 cr
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1812 cr
.in
.fname
= dname
;
1814 smb2_transport_compound_start(tree
->session
->transport
, 2);
1816 req
[0] = smb2_create_send(tree
, &cr
);
1818 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1820 hd
.data
[0] = UINT64_MAX
;
1821 hd
.data
[1] = UINT64_MAX
;
1824 nt
.in
.recursive
= true;
1825 nt
.in
.buffer_size
= 0x1000;
1826 nt
.in
.file
.handle
= hd
;
1827 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1828 nt
.in
.unknown
= 0x00000000;
1830 req
[1] = smb2_notify_send(tree
, &nt
);
1832 status
= smb2_create_recv(req
[0], tree
, &cr
);
1833 CHECK_STATUS(status
, NT_STATUS_OK
);
1835 smb2_cancel(req
[1]);
1836 status
= smb2_notify_recv(req
[1], tree
, &nt
);
1837 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1839 smb2_util_close(tree
, cr
.out
.file
.handle
);
1841 smb2_deltree(tree
, dname
);
1846 /* Send a compound request where we expect the middle request (Create, Notify,
1847 * GetInfo) to go asynchronous. Against Win7 the sync request succeed while
1848 * the async fails. All are returned in the same compound response. */
1849 static bool test_compound_interim2(struct torture_context
*tctx
,
1850 struct smb2_tree
*tree
)
1852 struct smb2_handle hd
;
1853 struct smb2_create cr
;
1854 NTSTATUS status
= NT_STATUS_OK
;
1855 const char *dname
= "compound_interim_dir";
1856 struct smb2_getinfo gf
;
1857 struct smb2_notify nt
;
1859 struct smb2_request
*req
[3];
1861 /* Win7 compound request implementation deviates substantially from the
1862 * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
1863 * verifies the Windows behavior, not the general spec behavior. */
1865 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
1867 smb2_deltree(tree
, dname
);
1869 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1872 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1873 cr
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1874 cr
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
1875 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1876 NTCREATEX_SHARE_ACCESS_WRITE
|
1877 NTCREATEX_SHARE_ACCESS_DELETE
;
1878 cr
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1879 cr
.in
.fname
= dname
;
1881 smb2_transport_compound_start(tree
->session
->transport
, 3);
1883 req
[0] = smb2_create_send(tree
, &cr
);
1885 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1887 hd
.data
[0] = UINT64_MAX
;
1888 hd
.data
[1] = UINT64_MAX
;
1891 nt
.in
.recursive
= true;
1892 nt
.in
.buffer_size
= 0x1000;
1893 nt
.in
.file
.handle
= hd
;
1894 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1895 nt
.in
.unknown
= 0x00000000;
1897 req
[1] = smb2_notify_send(tree
, &nt
);
1900 gf
.in
.file
.handle
= hd
;
1901 gf
.in
.info_type
= SMB2_0_INFO_FILE
;
1902 gf
.in
.info_class
= 0x04; /* FILE_BASIC_INFORMATION */
1903 gf
.in
.output_buffer_length
= 0x1000;
1904 gf
.in
.input_buffer
= data_blob_null
;
1906 req
[2] = smb2_getinfo_send(tree
, &gf
);
1908 status
= smb2_create_recv(req
[0], tree
, &cr
);
1909 CHECK_STATUS(status
, NT_STATUS_OK
);
1911 status
= smb2_notify_recv(req
[1], tree
, &nt
);
1912 CHECK_STATUS(status
, NT_STATUS_INTERNAL_ERROR
);
1914 status
= smb2_getinfo_recv(req
[2], tree
, &gf
);
1915 CHECK_STATUS(status
, NT_STATUS_OK
);
1917 smb2_util_close(tree
, cr
.out
.file
.handle
);
1919 smb2_deltree(tree
, dname
);
1924 /* Test compound related finds */
1925 static bool test_compound_find_related(struct torture_context
*tctx
,
1926 struct smb2_tree
*tree
)
1928 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1929 const char *dname
= "compound_find_dir";
1930 struct smb2_create create
;
1932 struct smb2_handle h
;
1933 struct smb2_request
*req
[2];
1937 smb2_deltree(tree
, dname
);
1939 ZERO_STRUCT(create
);
1940 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
1941 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1942 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
1943 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1944 NTCREATEX_SHARE_ACCESS_WRITE
|
1945 NTCREATEX_SHARE_ACCESS_DELETE
;
1946 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1947 create
.in
.fname
= dname
;
1949 status
= smb2_create(tree
, mem_ctx
, &create
);
1950 h
= create
.out
.file
.handle
;
1952 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_create failed\n");
1954 smb2_transport_compound_start(tree
->session
->transport
, 2);
1957 f
.in
.file
.handle
= h
;
1959 f
.in
.max_response_size
= 0x100;
1960 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
1962 req
[0] = smb2_find_send(tree
, &f
);
1964 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1966 req
[1] = smb2_find_send(tree
, &f
);
1968 status
= smb2_find_recv(req
[0], mem_ctx
, &f
);
1969 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_find_recv failed\n");
1971 status
= smb2_find_recv(req
[1], mem_ctx
, &f
);
1972 torture_assert_ntstatus_equal_goto(tctx
, status
, STATUS_NO_MORE_FILES
, ret
, done
, "smb2_find_recv failed\n");
1975 smb2_util_close(tree
, h
);
1976 smb2_deltree(tree
, dname
);
1977 TALLOC_FREE(mem_ctx
);
1981 /* Test compound related finds */
1982 static bool test_compound_find_close(struct torture_context
*tctx
,
1983 struct smb2_tree
*tree
)
1985 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1986 const char *dname
= "compound_find_dir";
1987 struct smb2_create create
;
1989 struct smb2_handle h
;
1990 struct smb2_request
*req
= NULL
;
1991 const int num_files
= 5000;
1996 smb2_deltree(tree
, dname
);
1998 ZERO_STRUCT(create
);
1999 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
2000 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2001 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2002 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2003 NTCREATEX_SHARE_ACCESS_WRITE
|
2004 NTCREATEX_SHARE_ACCESS_DELETE
;
2005 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2006 create
.in
.fname
= dname
;
2008 smb2cli_conn_set_max_credits(tree
->session
->transport
->conn
, 256);
2010 status
= smb2_create(tree
, mem_ctx
, &create
);
2011 h
= create
.out
.file
.handle
;
2013 ZERO_STRUCT(create
);
2014 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2015 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2016 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2018 for (i
= 0; i
< num_files
; i
++) {
2019 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\file%d",
2021 status
= smb2_create(tree
, mem_ctx
, &create
);
2022 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
2023 smb2_util_close(tree
, create
.out
.file
.handle
);
2026 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_create failed\n");
2029 f
.in
.file
.handle
= h
;
2031 f
.in
.max_response_size
= 8*1024*1024;
2032 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
2034 req
= smb2_find_send(tree
, &f
);
2036 status
= smb2_util_close(tree
, h
);
2037 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_util_close failed\n");
2039 status
= smb2_find_recv(req
, mem_ctx
, &f
);
2040 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_find_recv failed\n");
2043 smb2_util_close(tree
, h
);
2044 smb2_deltree(tree
, dname
);
2045 TALLOC_FREE(mem_ctx
);
2049 /* Test compound unrelated finds */
2050 static bool test_compound_find_unrelated(struct torture_context
*tctx
,
2051 struct smb2_tree
*tree
)
2053 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
2054 const char *dname
= "compound_find_dir";
2055 struct smb2_create create
;
2057 struct smb2_handle h
;
2058 struct smb2_request
*req
[2];
2062 smb2_deltree(tree
, dname
);
2064 ZERO_STRUCT(create
);
2065 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
2066 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2067 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2068 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2069 NTCREATEX_SHARE_ACCESS_WRITE
|
2070 NTCREATEX_SHARE_ACCESS_DELETE
;
2071 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2072 create
.in
.fname
= dname
;
2074 status
= smb2_create(tree
, mem_ctx
, &create
);
2075 h
= create
.out
.file
.handle
;
2077 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_create failed\n");
2079 smb2_transport_compound_start(tree
->session
->transport
, 2);
2082 f
.in
.file
.handle
= h
;
2084 f
.in
.max_response_size
= 0x100;
2085 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
2087 req
[0] = smb2_find_send(tree
, &f
);
2088 req
[1] = smb2_find_send(tree
, &f
);
2090 status
= smb2_find_recv(req
[0], mem_ctx
, &f
);
2091 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_find_recv failed\n");
2093 status
= smb2_find_recv(req
[1], mem_ctx
, &f
);
2094 torture_assert_ntstatus_equal_goto(tctx
, status
, STATUS_NO_MORE_FILES
, ret
, done
, "smb2_find_recv failed\n");
2097 smb2_util_close(tree
, h
);
2098 smb2_deltree(tree
, dname
);
2099 TALLOC_FREE(mem_ctx
);
2103 static bool test_compound_async_flush_close(struct torture_context
*tctx
,
2104 struct smb2_tree
*tree
)
2106 struct smb2_handle fhandle
= { .data
= { 0, 0 } };
2107 struct smb2_handle relhandle
= { .data
= { UINT64_MAX
, UINT64_MAX
} };
2108 struct smb2_close cl
;
2109 struct smb2_flush fl
;
2110 const char *fname
= "compound_async_flush_close";
2111 struct smb2_request
*req
[2];
2116 smb2_util_unlink(tree
, fname
);
2118 /* Create a file. */
2119 status
= torture_smb2_testfile_access(tree
,
2122 SEC_RIGHTS_FILE_ALL
);
2123 CHECK_STATUS(status
, NT_STATUS_OK
);
2125 /* Now do a compound flush + close handle. */
2126 smb2_transport_compound_start(tree
->session
->transport
, 2);
2129 fl
.in
.file
.handle
= fhandle
;
2131 req
[0] = smb2_flush_send(tree
, &fl
);
2132 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
2133 "smb2_flush_send failed\n");
2135 smb2_transport_compound_set_related(tree
->session
->transport
, true);
2138 cl
.in
.file
.handle
= relhandle
;
2139 req
[1] = smb2_close_send(tree
, &cl
);
2140 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
2141 "smb2_close_send failed\n");
2143 status
= smb2_flush_recv(req
[0], &fl
);
2145 * On Windows, this flush will usually
2146 * succeed as we have nothing to flush,
2147 * so allow NT_STATUS_OK. Once bug #15172
2148 * is fixed Samba will do the flush synchronously
2149 * so allow NT_STATUS_OK.
2151 if (!NT_STATUS_IS_OK(status
)) {
2153 * If we didn't get NT_STATUS_OK, we *must*
2154 * get NT_STATUS_INTERNAL_ERROR if the flush
2157 * For pre-bugfix #15172 Samba, the flush goes async and
2158 * we should get NT_STATUS_INTERNAL_ERROR.
2160 torture_assert_ntstatus_equal_goto(tctx
,
2162 NT_STATUS_INTERNAL_ERROR
,
2165 "smb2_flush_recv didn't return "
2166 "NT_STATUS_INTERNAL_ERROR.\n");
2168 status
= smb2_close_recv(req
[1], &cl
);
2169 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2170 "smb2_close_recv failed.");
2172 ZERO_STRUCT(fhandle
);
2175 * Do several more operations on the tree, spaced
2176 * out by 1 sec sleeps to make sure the server didn't
2177 * crash on the close. The sleeps are required to
2178 * make test test for a crash reliable, as we ensure
2179 * the pthread fsync internally finishes and accesses
2180 * freed memory. Without them the test occassionally
2181 * passes as we disconnect before the pthread fsync
2184 status
= smb2_util_unlink(tree
, fname
);
2185 CHECK_STATUS(status
, NT_STATUS_OK
);
2188 status
= smb2_util_unlink(tree
, fname
);
2189 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
2192 status
= smb2_util_unlink(tree
, fname
);
2193 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
2199 if (fhandle
.data
[0] != 0) {
2200 smb2_util_close(tree
, fhandle
);
2203 smb2_util_unlink(tree
, fname
);
2207 static bool test_compound_async_flush_flush(struct torture_context
*tctx
,
2208 struct smb2_tree
*tree
)
2210 struct smb2_handle fhandle
= { .data
= { 0, 0 } };
2211 struct smb2_handle relhandle
= { .data
= { UINT64_MAX
, UINT64_MAX
} };
2212 struct smb2_flush fl1
;
2213 struct smb2_flush fl2
;
2214 const char *fname
= "compound_async_flush_flush";
2215 struct smb2_request
*req
[2];
2220 smb2_util_unlink(tree
, fname
);
2222 /* Create a file. */
2223 status
= torture_smb2_testfile_access(tree
,
2226 SEC_RIGHTS_FILE_ALL
);
2227 CHECK_STATUS(status
, NT_STATUS_OK
);
2229 /* Now do a compound flush + flush handle. */
2230 smb2_transport_compound_start(tree
->session
->transport
, 2);
2233 fl1
.in
.file
.handle
= fhandle
;
2235 req
[0] = smb2_flush_send(tree
, &fl1
);
2236 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
2237 "smb2_flush_send (1) failed\n");
2239 smb2_transport_compound_set_related(tree
->session
->transport
, true);
2242 fl2
.in
.file
.handle
= relhandle
;
2244 req
[1] = smb2_flush_send(tree
, &fl2
);
2245 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
2246 "smb2_flush_send (2) failed\n");
2248 status
= smb2_flush_recv(req
[0], &fl1
);
2250 * On Windows, this flush will usually
2251 * succeed as we have nothing to flush,
2252 * so allow NT_STATUS_OK. Once bug #15172
2253 * is fixed Samba will do the flush synchronously
2254 * so allow NT_STATUS_OK.
2256 if (!NT_STATUS_IS_OK(status
)) {
2258 * If we didn't get NT_STATUS_OK, we *must*
2259 * get NT_STATUS_INTERNAL_ERROR if the flush
2262 * For pre-bugfix #15172 Samba, the flush goes async and
2263 * we should get NT_STATUS_INTERNAL_ERROR.
2265 torture_assert_ntstatus_equal_goto(tctx
,
2267 NT_STATUS_INTERNAL_ERROR
,
2270 "smb2_flush_recv (1) didn't return "
2271 "NT_STATUS_INTERNAL_ERROR.\n");
2275 * If the flush is the last entry in a compound,
2276 * it should always succeed even if it goes async.
2278 status
= smb2_flush_recv(req
[1], &fl2
);
2279 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2280 "smb2_flush_recv (2) failed.");
2282 status
= smb2_util_close(tree
, fhandle
);
2283 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2284 "smb2_util_close failed.");
2285 ZERO_STRUCT(fhandle
);
2288 * Do several more operations on the tree, spaced
2289 * out by 1 sec sleeps to make sure the server didn't
2290 * crash on the close. The sleeps are required to
2291 * make test test for a crash reliable, as we ensure
2292 * the pthread fsync internally finishes and accesses
2293 * freed memory. Without them the test occassionally
2294 * passes as we disconnect before the pthread fsync
2297 status
= smb2_util_unlink(tree
, fname
);
2298 CHECK_STATUS(status
, NT_STATUS_OK
);
2301 status
= smb2_util_unlink(tree
, fname
);
2302 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
2305 status
= smb2_util_unlink(tree
, fname
);
2306 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
2312 if (fhandle
.data
[0] != 0) {
2313 smb2_util_close(tree
, fhandle
);
2316 smb2_util_unlink(tree
, fname
);
2320 struct torture_suite
*torture_smb2_compound_init(TALLOC_CTX
*ctx
)
2322 struct torture_suite
*suite
= torture_suite_create(ctx
, "compound");
2324 torture_suite_add_1smb2_test(suite
, "related1", test_compound_related1
);
2325 torture_suite_add_1smb2_test(suite
, "related2", test_compound_related2
);
2326 torture_suite_add_1smb2_test(suite
, "related3",
2327 test_compound_related3
);
2328 torture_suite_add_1smb2_test(suite
, "related4",
2329 test_compound_related4
);
2330 torture_suite_add_1smb2_test(suite
, "related5",
2331 test_compound_related5
);
2332 torture_suite_add_1smb2_test(suite
, "related6",
2333 test_compound_related6
);
2334 torture_suite_add_1smb2_test(suite
, "related7",
2335 test_compound_related7
);
2336 torture_suite_add_1smb2_test(suite
, "related8",
2337 test_compound_related8
);
2338 torture_suite_add_1smb2_test(suite
, "related9",
2339 test_compound_related9
);
2340 torture_suite_add_1smb2_test(suite
, "unrelated1", test_compound_unrelated1
);
2341 torture_suite_add_1smb2_test(suite
, "invalid1", test_compound_invalid1
);
2342 torture_suite_add_1smb2_test(suite
, "invalid2", test_compound_invalid2
);
2343 torture_suite_add_1smb2_test(suite
, "invalid3", test_compound_invalid3
);
2344 torture_suite_add_1smb2_test(
2345 suite
, "invalid4", test_compound_invalid4
);
2346 torture_suite_add_1smb2_test(suite
, "interim1", test_compound_interim1
);
2347 torture_suite_add_1smb2_test(suite
, "interim2", test_compound_interim2
);
2348 torture_suite_add_1smb2_test(suite
, "compound-break", test_compound_break
);
2349 torture_suite_add_1smb2_test(suite
, "compound-padding", test_compound_padding
);
2350 torture_suite_add_1smb2_test(suite
, "create-write-close",
2351 test_compound_create_write_close
);
2353 suite
->description
= talloc_strdup(suite
, "SMB2-COMPOUND tests");
2358 struct torture_suite
*torture_smb2_compound_find_init(TALLOC_CTX
*ctx
)
2360 struct torture_suite
*suite
= torture_suite_create(ctx
, "compound_find");
2362 torture_suite_add_1smb2_test(suite
, "compound_find_related", test_compound_find_related
);
2363 torture_suite_add_1smb2_test(suite
, "compound_find_unrelated", test_compound_find_unrelated
);
2364 torture_suite_add_1smb2_test(suite
, "compound_find_close", test_compound_find_close
);
2366 suite
->description
= talloc_strdup(suite
, "SMB2-COMPOUND-FIND tests");
2371 struct torture_suite
*torture_smb2_compound_async_init(TALLOC_CTX
*ctx
)
2373 struct torture_suite
*suite
= torture_suite_create(ctx
,
2376 torture_suite_add_1smb2_test(suite
, "flush_close",
2377 test_compound_async_flush_close
);
2378 torture_suite_add_1smb2_test(suite
, "flush_flush",
2379 test_compound_async_flush_flush
);
2381 suite
->description
= talloc_strdup(suite
, "SMB2-COMPOUND-ASYNC tests");