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/>.
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28 #include "libcli/security/security.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "../libcli/smb/smbXcli_base.h"
31 #include "lease_break_handler.h"
33 #define CHECK_STATUS(status, correct) do { \
34 if (!NT_STATUS_EQUAL(status, correct)) { \
35 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
36 nt_errstr(status), nt_errstr(correct)); \
41 #define CHECK_VAL(v, correct) do { \
42 if ((v) != (correct)) { \
43 torture_result(tctx, TORTURE_FAIL, \
44 "(%s) Incorrect value %s=%d - should be %d\n", \
45 __location__, #v, (int)v, (int)correct); \
50 #define CHECK_LEASE(__io, __state, __oplevel, __key, __flags) \
52 CHECK_VAL((__io)->out.lease_response.lease_version, 1); \
54 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
55 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], (__key)); \
56 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], ~(__key)); \
57 CHECK_VAL((__io)->out.lease_response.lease_state, smb2_util_lease_state(__state)); \
59 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
60 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], 0); \
61 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], 0); \
62 CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
65 CHECK_VAL((__io)->out.lease_response.lease_flags, (__flags)); \
66 CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
67 CHECK_VAL((__io)->out.lease_response.lease_epoch, 0); \
70 #define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent, __epoch) \
72 CHECK_VAL((__io)->out.lease_response_v2.lease_version, 2); \
74 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
75 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], (__key)); \
76 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], ~(__key)); \
77 CHECK_VAL((__io)->out.lease_response_v2.lease_state, smb2_util_lease_state(__state)); \
79 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
80 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], 0); \
81 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], 0); \
82 CHECK_VAL((__io)->out.lease_response_v2.lease_state, 0); \
85 CHECK_VAL((__io)->out.lease_response_v2.lease_flags, __flags); \
86 if (__flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET) { \
87 CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[0], (__parent)); \
88 CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[1], ~(__parent)); \
90 CHECK_VAL((__io)->out.lease_response_v2.lease_duration, 0); \
91 CHECK_VAL((__io)->out.lease_response_v2.lease_epoch, (__epoch)); \
94 #define WAIT_FOR_ASYNC_RESPONSE(req) \
95 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
96 if (tevent_loop_once(tctx->ev) != 0) { \
101 static const uint64_t LEASE1
= 0xBADC0FFEE0DDF00Dull
;
102 static const uint64_t LEASE2
= 0xDEADBEEFFEEDBEADull
;
105 struct smb2_handle handle
;
107 struct smb2_break br
;
110 NTSTATUS failure_status
;
113 static void torture_oplock_break_callback(struct smb2_request
*req
)
116 struct smb2_break br
;
119 status
= smb2_break_recv(req
, &break_info
.br
);
120 if (!NT_STATUS_IS_OK(status
)) {
121 break_info
.failures
++;
122 break_info
.failure_status
= status
;
128 /* A general oplock break notification handler. This should be used when a
129 * test expects to break from batch or exclusive to a lower level. */
130 static bool torture_oplock_handler(struct smb2_transport
*transport
,
131 const struct smb2_handle
*handle
,
135 struct smb2_tree
*tree
= private_data
;
137 struct smb2_request
*req
;
138 ZERO_STRUCT(break_info
.br
);
140 break_info
.handle
= *handle
;
141 break_info
.level
= level
;
145 case SMB2_OPLOCK_LEVEL_II
:
148 case SMB2_OPLOCK_LEVEL_NONE
:
153 break_info
.failures
++;
155 printf("Acking to %s [0x%02X] in oplock handler\n", name
, level
);
157 break_info
.br
.in
.file
.handle
= *handle
;
158 break_info
.br
.in
.oplock_level
= level
;
159 break_info
.br
.in
.reserved
= 0;
160 break_info
.br
.in
.reserved2
= 0;
162 req
= smb2_break_send(tree
, &break_info
.br
);
163 req
->async
.fn
= torture_oplock_break_callback
;
164 req
->async
.private_data
= NULL
;
168 static bool test_compound_break(struct torture_context
*tctx
,
169 struct smb2_tree
*tree
)
171 const char *fname1
= "some-file.pptx";
175 struct smb2_create io2
;
176 struct smb2_getinfo gf
;
177 struct smb2_request
*req
[2];
178 struct smb2_handle h1
;
179 struct smb2_handle h
;
181 tree
->session
->transport
->oplock
.handler
= torture_oplock_handler
;
182 tree
->session
->transport
->oplock
.private_data
= tree
;
184 ZERO_STRUCT(break_info
);
189 ZERO_STRUCT(io1
.smb2
);
190 io1
.generic
.level
= RAW_OPEN_SMB2
;
191 io1
.smb2
.in
.desired_access
= (SEC_STD_SYNCHRONIZE
|
192 SEC_STD_READ_CONTROL
|
193 SEC_FILE_READ_ATTRIBUTE
|
196 io1
.smb2
.in
.alloc_size
= 0;
197 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
198 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
199 NTCREATEX_SHARE_ACCESS_WRITE
|
200 NTCREATEX_SHARE_ACCESS_DELETE
;
201 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
202 io1
.smb2
.in
.create_options
= 0;
203 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
204 io1
.smb2
.in
.security_flags
= 0;
205 io1
.smb2
.in
.fname
= fname1
;
207 torture_comment(tctx
, "TEST2: open a file with an batch "
208 "oplock (share mode: all)\n");
209 io1
.smb2
.in
.oplock_level
= SMB2_OPLOCK_LEVEL_BATCH
;
211 status
= smb2_create(tree
, tctx
, &(io1
.smb2
));
212 torture_assert_ntstatus_ok(tctx
, status
, "Error opening the file");
214 h1
= io1
.smb2
.out
.file
.handle
;
216 torture_comment(tctx
, "TEST2: Opening second time with compound\n");
220 io2
.in
.desired_access
= (SEC_STD_SYNCHRONIZE
|
221 SEC_FILE_READ_ATTRIBUTE
|
223 io2
.in
.alloc_size
= 0;
224 io2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
225 io2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
226 NTCREATEX_SHARE_ACCESS_WRITE
|
227 NTCREATEX_SHARE_ACCESS_DELETE
;
228 io2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
229 io2
.in
.create_options
= 0;
230 io2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
231 io2
.in
.security_flags
= 0;
232 io2
.in
.fname
= fname1
;
233 io2
.in
.oplock_level
= 0;
235 smb2_transport_compound_start(tree
->session
->transport
, 2);
237 req
[0] = smb2_create_send(tree
, &io2
);
239 smb2_transport_compound_set_related(tree
->session
->transport
, true);
241 h
.data
[0] = UINT64_MAX
;
242 h
.data
[1] = UINT64_MAX
;
245 gf
.in
.file
.handle
= h
;
246 gf
.in
.info_type
= SMB2_0_INFO_FILE
;
247 gf
.in
.info_class
= 0x16;
248 gf
.in
.output_buffer_length
= 0x1000;
249 gf
.in
.input_buffer
= data_blob_null
;
251 req
[1] = smb2_getinfo_send(tree
, &gf
);
253 status
= smb2_create_recv(req
[0], tree
, &io2
);
254 CHECK_STATUS(status
, NT_STATUS_OK
);
256 status
= smb2_getinfo_recv(req
[1], tree
, &gf
);
257 CHECK_STATUS(status
, NT_STATUS_OK
);
261 smb2_util_close(tree
, h1
);
262 smb2_util_unlink(tree
, fname1
);
266 static bool test_compound_related1(struct torture_context
*tctx
,
267 struct smb2_tree
*tree
)
269 struct smb2_handle hd
;
270 struct smb2_create cr
;
272 const char *fname
= "compound_related1.dat";
273 struct smb2_close cl
;
275 struct smb2_request
*req
[2];
276 struct smbXcli_tcon
*saved_tcon
= tree
->smbXcli
;
277 struct smbXcli_session
*saved_session
= tree
->session
->smbXcli
;
279 smb2_transport_credits_ask_num(tree
->session
->transport
, 2);
281 smb2_util_unlink(tree
, fname
);
283 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
286 cr
.in
.security_flags
= 0x00;
287 cr
.in
.oplock_level
= 0;
288 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
289 cr
.in
.create_flags
= 0x00000000;
290 cr
.in
.reserved
= 0x00000000;
291 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
292 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
293 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
294 NTCREATEX_SHARE_ACCESS_WRITE
|
295 NTCREATEX_SHARE_ACCESS_DELETE
;
296 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
297 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
298 NTCREATEX_OPTIONS_ASYNC_ALERT
|
299 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
303 smb2_transport_compound_start(tree
->session
->transport
, 2);
305 req
[0] = smb2_create_send(tree
, &cr
);
307 smb2_transport_compound_set_related(tree
->session
->transport
, true);
309 hd
.data
[0] = UINT64_MAX
;
310 hd
.data
[1] = UINT64_MAX
;
313 cl
.in
.file
.handle
= hd
;
315 tree
->smbXcli
= smbXcli_tcon_create(tree
);
316 smb2cli_tcon_set_values(tree
->smbXcli
,
318 0xFFFFFFFF, /* tcon_id */
321 0, /* capabilities */
322 0 /* maximal_access */);
324 tree
->session
->smbXcli
= smbXcli_session_shallow_copy(tree
->session
,
325 tree
->session
->smbXcli
);
326 smb2cli_session_set_id_and_flags(tree
->session
->smbXcli
, UINT64_MAX
, 0);
328 req
[1] = smb2_close_send(tree
, &cl
);
330 status
= smb2_create_recv(req
[0], tree
, &cr
);
331 CHECK_STATUS(status
, NT_STATUS_OK
);
332 status
= smb2_close_recv(req
[1], &cl
);
333 CHECK_STATUS(status
, NT_STATUS_OK
);
335 TALLOC_FREE(tree
->smbXcli
);
336 tree
->smbXcli
= saved_tcon
;
337 TALLOC_FREE(tree
->session
->smbXcli
);
338 tree
->session
->smbXcli
= saved_session
;
340 smb2_util_unlink(tree
, fname
);
345 static bool test_compound_related2(struct torture_context
*tctx
,
346 struct smb2_tree
*tree
)
348 struct smb2_handle hd
;
349 struct smb2_create cr
;
351 const char *fname
= "compound_related2.dat";
352 struct smb2_close cl
;
354 struct smb2_request
*req
[5];
355 struct smbXcli_tcon
*saved_tcon
= tree
->smbXcli
;
356 struct smbXcli_session
*saved_session
= tree
->session
->smbXcli
;
358 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
360 smb2_util_unlink(tree
, fname
);
362 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
365 cr
.in
.security_flags
= 0x00;
366 cr
.in
.oplock_level
= 0;
367 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
368 cr
.in
.create_flags
= 0x00000000;
369 cr
.in
.reserved
= 0x00000000;
370 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
371 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
372 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
373 NTCREATEX_SHARE_ACCESS_WRITE
|
374 NTCREATEX_SHARE_ACCESS_DELETE
;
375 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
376 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
377 NTCREATEX_OPTIONS_ASYNC_ALERT
|
378 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
382 smb2_transport_compound_start(tree
->session
->transport
, 5);
384 req
[0] = smb2_create_send(tree
, &cr
);
386 hd
.data
[0] = UINT64_MAX
;
387 hd
.data
[1] = UINT64_MAX
;
389 smb2_transport_compound_set_related(tree
->session
->transport
, true);
392 cl
.in
.file
.handle
= hd
;
394 tree
->smbXcli
= smbXcli_tcon_create(tree
);
395 smb2cli_tcon_set_values(tree
->smbXcli
,
397 0xFFFFFFFF, /* tcon_id */
400 0, /* capabilities */
401 0 /* maximal_access */);
403 tree
->session
->smbXcli
= smbXcli_session_shallow_copy(tree
->session
,
404 tree
->session
->smbXcli
);
405 smb2cli_session_set_id_and_flags(tree
->session
->smbXcli
, UINT64_MAX
, 0);
407 req
[1] = smb2_close_send(tree
, &cl
);
408 req
[2] = smb2_close_send(tree
, &cl
);
409 req
[3] = smb2_close_send(tree
, &cl
);
410 req
[4] = smb2_close_send(tree
, &cl
);
412 status
= smb2_create_recv(req
[0], tree
, &cr
);
413 CHECK_STATUS(status
, NT_STATUS_OK
);
414 status
= smb2_close_recv(req
[1], &cl
);
415 CHECK_STATUS(status
, NT_STATUS_OK
);
416 status
= smb2_close_recv(req
[2], &cl
);
417 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
418 status
= smb2_close_recv(req
[3], &cl
);
419 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
420 status
= smb2_close_recv(req
[4], &cl
);
421 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
423 TALLOC_FREE(tree
->smbXcli
);
424 tree
->smbXcli
= saved_tcon
;
425 TALLOC_FREE(tree
->session
->smbXcli
);
426 tree
->session
->smbXcli
= saved_session
;
428 smb2_util_unlink(tree
, fname
);
433 static bool test_compound_related3(struct torture_context
*tctx
,
434 struct smb2_tree
*tree
)
436 struct smb2_handle hd
;
437 struct smb2_ioctl io
;
438 struct smb2_create cr
;
439 struct smb2_close cl
;
440 const char *fname
= "compound_related3.dat";
441 struct smb2_request
*req
[3];
445 smb2_util_unlink(tree
, fname
);
448 cr
.in
.security_flags
= 0x00;
449 cr
.in
.oplock_level
= 0;
450 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
451 cr
.in
.create_flags
= 0x00000000;
452 cr
.in
.reserved
= 0x00000000;
453 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
454 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
455 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
456 NTCREATEX_SHARE_ACCESS_WRITE
|
457 NTCREATEX_SHARE_ACCESS_DELETE
;
458 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
459 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
460 NTCREATEX_OPTIONS_ASYNC_ALERT
|
461 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
465 smb2_transport_compound_start(tree
->session
->transport
, 3);
467 req
[0] = smb2_create_send(tree
, &cr
);
469 hd
.data
[0] = UINT64_MAX
;
470 hd
.data
[1] = UINT64_MAX
;
472 smb2_transport_compound_set_related(tree
->session
->transport
, true);
475 io
.in
.function
= FSCTL_CREATE_OR_GET_OBJECT_ID
;
476 io
.in
.file
.handle
= hd
;
478 io
.in
.max_output_response
= 64;
481 req
[1] = smb2_ioctl_send(tree
, &io
);
484 cl
.in
.file
.handle
= hd
;
486 req
[2] = smb2_close_send(tree
, &cl
);
488 status
= smb2_create_recv(req
[0], tree
, &cr
);
489 CHECK_STATUS(status
, NT_STATUS_OK
);
490 status
= smb2_ioctl_recv(req
[1], tree
, &io
);
491 CHECK_STATUS(status
, NT_STATUS_OK
);
492 status
= smb2_close_recv(req
[2], &cl
);
493 CHECK_STATUS(status
, NT_STATUS_OK
);
495 status
= smb2_util_unlink(tree
, fname
);
496 CHECK_STATUS(status
, NT_STATUS_OK
);
503 static bool test_compound_related4(struct torture_context
*tctx
,
504 struct smb2_tree
*tree
)
506 const char *fname
= "compound_related4.dat";
507 struct security_descriptor
*sd
= NULL
;
508 struct smb2_handle hd
;
509 struct smb2_create cr
;
510 union smb_setfileinfo set
;
511 struct smb2_ioctl io
;
512 struct smb2_close cl
;
513 struct smb2_request
*req
[4];
517 smb2_util_unlink(tree
, fname
);
520 cr
.level
= RAW_OPEN_SMB2
;
521 cr
.in
.create_flags
= 0;
522 cr
.in
.desired_access
= SEC_STD_READ_CONTROL
|
525 cr
.in
.create_options
= 0;
526 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
527 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
528 NTCREATEX_SHARE_ACCESS_READ
|
529 NTCREATEX_SHARE_ACCESS_WRITE
;
530 cr
.in
.alloc_size
= 0;
531 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
532 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
533 cr
.in
.security_flags
= 0;
536 status
= smb2_create(tree
, tctx
, &cr
);
537 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_create failed\n");
539 hd
= cr
.out
.file
.handle
;
540 torture_comment(tctx
, "set a sec desc allowing no write by CREATOR_OWNER\n");
542 sd
= security_descriptor_dacl_create(tctx
,
545 SEC_ACE_TYPE_ACCESS_ALLOWED
,
546 SEC_RIGHTS_FILE_READ
| SEC_STD_ALL
,
549 torture_assert_not_null_goto(tctx
, sd
, ret
, done
,
550 "security_descriptor_dacl_create failed\n");
552 set
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
553 set
.set_secdesc
.in
.file
.handle
= hd
;
554 set
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
555 set
.set_secdesc
.in
.sd
= sd
;
557 status
= smb2_setinfo_file(tree
, &set
);
558 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
559 "smb2_setinfo_file failed\n");
561 torture_comment(tctx
, "try open for write\n");
562 cr
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
563 smb2_transport_compound_start(tree
->session
->transport
, 4);
565 req
[0] = smb2_create_send(tree
, &cr
);
566 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
567 "smb2_create_send failed\n");
569 hd
.data
[0] = UINT64_MAX
;
570 hd
.data
[1] = UINT64_MAX
;
572 smb2_transport_compound_set_related(tree
->session
->transport
, true);
574 io
.in
.function
= FSCTL_CREATE_OR_GET_OBJECT_ID
;
575 io
.in
.file
.handle
= hd
;
578 req
[1] = smb2_ioctl_send(tree
, &io
);
579 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
580 "smb2_ioctl_send failed\n");
583 cl
.in
.file
.handle
= hd
;
585 req
[2] = smb2_close_send(tree
, &cl
);
586 torture_assert_not_null_goto(tctx
, req
[2], ret
, done
,
587 "smb2_create_send failed\n");
589 set
.set_secdesc
.in
.file
.handle
= hd
;
591 req
[3] = smb2_setinfo_file_send(tree
, &set
);
592 torture_assert_not_null_goto(tctx
, req
[3], ret
, done
,
593 "smb2_create_send failed\n");
595 status
= smb2_create_recv(req
[0], tree
, &cr
);
596 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
598 "smb2_create_recv failed\n");
600 status
= smb2_ioctl_recv(req
[1], tree
, &io
);
601 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
603 "smb2_ioctl_recv failed\n");
605 status
= smb2_close_recv(req
[2], &cl
);
606 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
608 "smb2_close_recv failed\n");
610 status
= smb2_setinfo_recv(req
[3]);
611 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
613 "smb2_setinfo_recv failed\n");
616 smb2_util_unlink(tree
, fname
);
618 smb2_logoff(tree
->session
);
622 static bool test_compound_related5(struct torture_context
*tctx
,
623 struct smb2_tree
*tree
)
625 struct smb2_handle hd
;
626 struct smb2_ioctl io
;
627 struct smb2_close cl
;
628 struct smb2_request
*req
[2];
632 smb2_transport_compound_start(tree
->session
->transport
, 2);
634 hd
.data
[0] = UINT64_MAX
;
635 hd
.data
[1] = UINT64_MAX
;
638 io
.in
.function
= FSCTL_CREATE_OR_GET_OBJECT_ID
;
639 io
.in
.file
.handle
= hd
;
642 req
[0] = smb2_ioctl_send(tree
, &io
);
643 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
644 "smb2_ioctl_send failed\n");
646 smb2_transport_compound_set_related(tree
->session
->transport
, true);
649 cl
.in
.file
.handle
= hd
;
651 req
[1] = smb2_close_send(tree
, &cl
);
652 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
653 "smb2_create_send failed\n");
655 status
= smb2_ioctl_recv(req
[0], tree
, &io
);
656 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_FILE_CLOSED
,
658 "smb2_ioctl_recv failed\n");
660 status
= smb2_close_recv(req
[1], &cl
);
661 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_FILE_CLOSED
,
663 "smb2_close_recv failed\n");
669 smb2_logoff(tree
->session
);
673 static bool test_compound_related6(struct torture_context
*tctx
,
674 struct smb2_tree
*tree
)
676 struct smb2_handle hd
;
677 struct smb2_create cr
;
679 struct smb2_write wr
;
680 struct smb2_close cl
;
682 const char *fname
= "compound_related6.dat";
683 struct smb2_request
*req
[5];
687 smb2_util_unlink(tree
, fname
);
690 cr
.level
= RAW_OPEN_SMB2
;
691 cr
.in
.create_flags
= 0;
692 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
693 cr
.in
.create_options
= 0;
694 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
695 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
696 NTCREATEX_SHARE_ACCESS_READ
|
697 NTCREATEX_SHARE_ACCESS_WRITE
;
698 cr
.in
.alloc_size
= 0;
699 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
700 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
701 cr
.in
.security_flags
= 0;
704 status
= smb2_create(tree
, tctx
, &cr
);
705 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
706 "smb2_create failed\n");
708 hd
= cr
.out
.file
.handle
;
711 status
= smb2_util_write(tree
, hd
, buf
, 0, ARRAY_SIZE(buf
));
712 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
713 "smb2_util_write failed\n");
715 torture_comment(tctx
, "try open for read\n");
716 cr
.in
.desired_access
= SEC_FILE_READ_DATA
;
717 smb2_transport_compound_start(tree
->session
->transport
, 5);
719 req
[0] = smb2_create_send(tree
, &cr
);
720 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
721 "smb2_create_send failed\n");
723 hd
.data
[0] = UINT64_MAX
;
724 hd
.data
[1] = UINT64_MAX
;
726 smb2_transport_compound_set_related(tree
->session
->transport
, true);
729 rd
.in
.file
.handle
= hd
;
733 req
[1] = smb2_read_send(tree
, &rd
);
734 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
735 "smb2_read_send failed\n");
738 wr
.in
.file
.handle
= hd
;
740 wr
.in
.data
= data_blob_talloc(tctx
, NULL
, 64);
742 req
[2] = smb2_write_send(tree
, &wr
);
743 torture_assert_not_null_goto(tctx
, req
[2], ret
, done
,
744 "smb2_write_send failed\n");
747 rd
.in
.file
.handle
= hd
;
751 req
[3] = smb2_read_send(tree
, &rd
);
752 torture_assert_not_null_goto(tctx
, req
[3], ret
, done
,
753 "smb2_read_send failed\n");
756 cl
.in
.file
.handle
= hd
;
758 req
[4] = smb2_close_send(tree
, &cl
);
759 torture_assert_not_null_goto(tctx
, req
[4], ret
, done
,
760 "smb2_close_send failed\n");
762 status
= smb2_create_recv(req
[0], tree
, &cr
);
763 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
764 "smb2_create_recv failed\n");
766 status
= smb2_read_recv(req
[1], tree
, &rd
);
767 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
768 "smb2_read_recv failed\n");
770 status
= smb2_write_recv(req
[2], &wr
);
771 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
773 "smb2_write_recv failed\n");
775 status
= smb2_read_recv(req
[3], tree
, &rd
);
776 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
777 "smb2_read_recv failed\n");
779 status
= smb2_close_recv(req
[4], &cl
);
780 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
781 "smb2_close_recv failed\n");
784 smb2_util_unlink(tree
, fname
);
786 smb2_logoff(tree
->session
);
790 static bool test_compound_related7(struct torture_context
*tctx
,
791 struct smb2_tree
*tree
)
793 const char *fname
= "compound_related4.dat";
794 struct security_descriptor
*sd
= NULL
;
795 struct smb2_handle hd
;
796 struct smb2_create cr
;
797 union smb_setfileinfo set
;
798 struct smb2_notify nt
;
799 struct smb2_close cl
;
801 struct smb2_request
*req
[4];
804 smb2_util_unlink(tree
, fname
);
807 cr
.level
= RAW_OPEN_SMB2
;
808 cr
.in
.create_flags
= 0;
809 cr
.in
.desired_access
= SEC_STD_READ_CONTROL
|
812 cr
.in
.create_options
= 0;
813 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
814 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
815 NTCREATEX_SHARE_ACCESS_READ
|
816 NTCREATEX_SHARE_ACCESS_WRITE
;
817 cr
.in
.alloc_size
= 0;
818 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
819 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
820 cr
.in
.security_flags
= 0;
823 status
= smb2_create(tree
, tctx
, &cr
);
824 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
825 "smb2_create failed\n");
827 hd
= cr
.out
.file
.handle
;
828 torture_comment(tctx
, "set a sec desc allowing no write by CREATOR_OWNER\n");
829 sd
= security_descriptor_dacl_create(tctx
,
832 SEC_ACE_TYPE_ACCESS_ALLOWED
,
833 SEC_RIGHTS_FILE_READ
| SEC_STD_ALL
,
836 torture_assert_not_null_goto(tctx
, sd
, ret
, done
,
837 "security_descriptor_dacl_create failed\n");
839 set
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
840 set
.set_secdesc
.in
.file
.handle
= hd
;
841 set
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
842 set
.set_secdesc
.in
.sd
= sd
;
844 status
= smb2_setinfo_file(tree
, &set
);
845 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
846 "smb2_setinfo_file failed\n");
848 torture_comment(tctx
, "try open for write\n");
849 cr
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
850 smb2_transport_compound_start(tree
->session
->transport
, 4);
852 req
[0] = smb2_create_send(tree
, &cr
);
853 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
854 "smb2_create_send failed\n");
856 hd
.data
[0] = UINT64_MAX
;
857 hd
.data
[1] = UINT64_MAX
;
859 smb2_transport_compound_set_related(tree
->session
->transport
, true);
862 nt
.in
.recursive
= true;
863 nt
.in
.buffer_size
= 0x1000;
864 nt
.in
.file
.handle
= hd
;
865 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
866 nt
.in
.unknown
= 0x00000000;
868 req
[1] = smb2_notify_send(tree
, &nt
);
869 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
870 "smb2_notify_send failed\n");
873 cl
.in
.file
.handle
= hd
;
875 req
[2] = smb2_close_send(tree
, &cl
);
876 torture_assert_not_null_goto(tctx
, req
[2], ret
, done
,
877 "smb2_close_send failed\n");
879 set
.set_secdesc
.in
.file
.handle
= hd
;
881 req
[3] = smb2_setinfo_file_send(tree
, &set
);
882 torture_assert_not_null_goto(tctx
, req
[3], ret
, done
,
883 "smb2_setinfo_file_send failed\n");
885 status
= smb2_create_recv(req
[0], tree
, &cr
);
886 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
888 "smb2_create_recv failed\n");
890 status
= smb2_notify_recv(req
[1], tree
, &nt
);
891 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
893 "smb2_notify_recv failed\n");
895 status
= smb2_close_recv(req
[2], &cl
);
896 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
898 "smb2_close_recv failed\n");
900 status
= smb2_setinfo_recv(req
[3]);
901 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_ACCESS_DENIED
,
903 "smb2_setinfo_recv failed\n");
906 smb2_util_unlink(tree
, fname
);
908 smb2_logoff(tree
->session
);
912 static bool test_compound_related8(struct torture_context
*tctx
,
913 struct smb2_tree
*tree
)
915 const char *fname
= "compound_related8.dat";
916 const char *fname_nonexisting
= "compound_related8.dat.void";
917 struct security_descriptor
*sd
= NULL
;
918 struct smb2_handle hd
;
919 struct smb2_create cr
;
920 union smb_setfileinfo set
;
921 struct smb2_notify nt
;
922 struct smb2_close cl
;
924 struct smb2_request
*req
[4];
927 smb2_util_unlink(tree
, fname
);
930 cr
.level
= RAW_OPEN_SMB2
;
931 cr
.in
.create_flags
= 0;
932 cr
.in
.desired_access
= SEC_STD_READ_CONTROL
|
935 cr
.in
.create_options
= 0;
936 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
937 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
938 NTCREATEX_SHARE_ACCESS_READ
|
939 NTCREATEX_SHARE_ACCESS_WRITE
;
940 cr
.in
.alloc_size
= 0;
941 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
942 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
943 cr
.in
.security_flags
= 0;
946 status
= smb2_create(tree
, tctx
, &cr
);
947 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
948 "smb2_create failed\n");
950 hd
= cr
.out
.file
.handle
;
952 smb2_transport_compound_start(tree
->session
->transport
, 4);
954 torture_comment(tctx
, "try open for write\n");
955 cr
.in
.fname
= fname_nonexisting
;
956 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
958 req
[0] = smb2_create_send(tree
, &cr
);
959 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
960 "smb2_create_send failed\n");
962 hd
.data
[0] = UINT64_MAX
;
963 hd
.data
[1] = UINT64_MAX
;
965 smb2_transport_compound_set_related(tree
->session
->transport
, true);
968 nt
.in
.recursive
= true;
969 nt
.in
.buffer_size
= 0x1000;
970 nt
.in
.file
.handle
= hd
;
971 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
972 nt
.in
.unknown
= 0x00000000;
974 req
[1] = smb2_notify_send(tree
, &nt
);
975 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
976 "smb2_notify_send failed\n");
979 cl
.in
.file
.handle
= hd
;
981 req
[2] = smb2_close_send(tree
, &cl
);
982 torture_assert_not_null_goto(tctx
, req
[2], ret
, done
,
983 "smb2_close_send failed\n");
985 sd
= security_descriptor_dacl_create(tctx
,
988 SEC_ACE_TYPE_ACCESS_ALLOWED
,
989 SEC_RIGHTS_FILE_READ
| SEC_STD_ALL
,
992 torture_assert_not_null_goto(tctx
, sd
, ret
, done
,
993 "security_descriptor_dacl_create failed\n");
995 set
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
996 set
.set_secdesc
.in
.file
.handle
= hd
;
997 set
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
998 set
.set_secdesc
.in
.sd
= sd
;
1000 req
[3] = smb2_setinfo_file_send(tree
, &set
);
1001 torture_assert_not_null_goto(tctx
, req
[3], ret
, done
,
1002 "smb2_setinfo_file_send failed\n");
1004 status
= smb2_create_recv(req
[0], tree
, &cr
);
1005 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
,
1007 "smb2_create_recv failed\n");
1009 status
= smb2_notify_recv(req
[1], tree
, &nt
);
1010 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
,
1012 "smb2_notify_recv failed\n");
1014 status
= smb2_close_recv(req
[2], &cl
);
1015 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
,
1017 "smb2_close_recv failed\n");
1019 status
= smb2_setinfo_recv(req
[3]);
1020 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
,
1022 "smb2_setinfo_recv failed\n");
1025 smb2_util_unlink(tree
, fname
);
1027 smb2_logoff(tree
->session
);
1031 static bool test_compound_related9(struct torture_context
*tctx
,
1032 struct smb2_tree
*tree
)
1034 const char *fname
= "compound_related9.dat";
1035 struct security_descriptor
*sd
= NULL
;
1036 struct smb2_handle hd
;
1037 struct smb2_create cr
;
1038 union smb_setfileinfo set
;
1039 struct smb2_notify nt
;
1040 struct smb2_close cl
;
1042 struct smb2_request
*req
[3];
1045 smb2_util_unlink(tree
, fname
);
1048 cr
.level
= RAW_OPEN_SMB2
;
1049 cr
.in
.create_flags
= 0;
1050 cr
.in
.desired_access
= SEC_STD_READ_CONTROL
|
1052 SEC_STD_WRITE_OWNER
;
1053 cr
.in
.create_options
= 0;
1054 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1055 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
1056 NTCREATEX_SHARE_ACCESS_READ
|
1057 NTCREATEX_SHARE_ACCESS_WRITE
;
1058 cr
.in
.alloc_size
= 0;
1059 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1060 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1061 cr
.in
.security_flags
= 0;
1062 cr
.in
.fname
= fname
;
1064 status
= smb2_create(tree
, tctx
, &cr
);
1065 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1066 "smb2_create failed\n");
1068 hd
= cr
.out
.file
.handle
;
1070 smb2_transport_compound_start(tree
->session
->transport
, 3);
1071 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1074 nt
.in
.recursive
= true;
1075 nt
.in
.buffer_size
= 0x1000;
1076 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1078 req
[0] = smb2_notify_send(tree
, &nt
);
1079 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
1080 "smb2_notify_send failed\n");
1083 cl
.in
.file
.handle
= hd
;
1085 req
[1] = smb2_close_send(tree
, &cl
);
1086 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
1087 "smb2_close_send failed\n");
1089 sd
= security_descriptor_dacl_create(tctx
,
1092 SEC_ACE_TYPE_ACCESS_ALLOWED
,
1093 SEC_RIGHTS_FILE_READ
| SEC_STD_ALL
,
1096 torture_assert_not_null_goto(tctx
, sd
, ret
, done
,
1097 "security_descriptor_dacl_create failed\n");
1099 set
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
1100 set
.set_secdesc
.in
.file
.handle
= hd
;
1101 set
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
1102 set
.set_secdesc
.in
.sd
= sd
;
1104 req
[2] = smb2_setinfo_file_send(tree
, &set
);
1105 torture_assert_not_null_goto(tctx
, req
[2], ret
, done
,
1106 "smb2_setinfo_file_send failed\n");
1108 status
= smb2_notify_recv(req
[0], tree
, &nt
);
1109 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_INVALID_PARAMETER
,
1111 "smb2_notify_recv failed\n");
1113 status
= smb2_close_recv(req
[1], &cl
);
1114 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_INVALID_PARAMETER
,
1116 "smb2_close_recv failed\n");
1118 status
= smb2_setinfo_recv(req
[2]);
1119 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_INVALID_PARAMETER
,
1121 "smb2_setinfo_recv failed\n");
1124 smb2_util_unlink(tree
, fname
);
1126 smb2_logoff(tree
->session
);
1130 static bool test_compound_padding(struct torture_context
*tctx
,
1131 struct smb2_tree
*tree
)
1133 struct smb2_handle h
;
1134 struct smb2_create cr
;
1136 struct smb2_read r2
;
1137 const char *fname
= "compound_read.dat";
1138 const char *sname
= "compound_read.dat:foo";
1139 struct smb2_request
*req
[3];
1143 smb2_util_unlink(tree
, fname
);
1147 cr
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
1148 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1149 cr
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1150 cr
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1151 cr
.in
.fname
= fname
;
1152 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1153 NTCREATEX_SHARE_ACCESS_WRITE
|
1154 NTCREATEX_SHARE_ACCESS_DELETE
;
1155 status
= smb2_create(tree
, tctx
, &cr
);
1156 CHECK_STATUS(status
, NT_STATUS_OK
);
1157 h
= cr
.out
.file
.handle
;
1159 status
= smb2_util_write(tree
, h
, "123", 0, 3);
1160 CHECK_STATUS(status
, NT_STATUS_OK
);
1162 smb2_util_close(tree
, h
);
1166 cr
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
1167 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1168 cr
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1169 cr
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1170 cr
.in
.fname
= sname
;
1171 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1172 NTCREATEX_SHARE_ACCESS_WRITE
|
1173 NTCREATEX_SHARE_ACCESS_DELETE
;
1174 status
= smb2_create(tree
, tctx
, &cr
);
1175 CHECK_STATUS(status
, NT_STATUS_OK
);
1176 h
= cr
.out
.file
.handle
;
1178 status
= smb2_util_write(tree
, h
, "456", 0, 3);
1179 CHECK_STATUS(status
, NT_STATUS_OK
);
1181 smb2_util_close(tree
, h
);
1183 /* Check compound read from basefile */
1184 smb2_transport_compound_start(tree
->session
->transport
, 3);
1187 cr
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1188 cr
.in
.desired_access
= SEC_FILE_READ_DATA
;
1189 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1190 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1191 cr
.in
.fname
= fname
;
1192 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1193 NTCREATEX_SHARE_ACCESS_WRITE
|
1194 NTCREATEX_SHARE_ACCESS_DELETE
;
1195 req
[0] = smb2_create_send(tree
, &cr
);
1197 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1200 * We send 2 reads in the compound here as the protocol
1201 * allows the last read to be split off and possibly
1202 * go async. Check the padding on the first read returned,
1203 * not the second as the second may not be part of the
1204 * returned compound.
1208 h
.data
[0] = UINT64_MAX
;
1209 h
.data
[1] = UINT64_MAX
;
1210 r
.in
.file
.handle
= h
;
1214 req
[1] = smb2_read_send(tree
, &r
);
1217 h
.data
[0] = UINT64_MAX
;
1218 h
.data
[1] = UINT64_MAX
;
1219 r2
.in
.file
.handle
= h
;
1222 r2
.in
.min_count
= 1;
1223 req
[2] = smb2_read_send(tree
, &r2
);
1225 status
= smb2_create_recv(req
[0], tree
, &cr
);
1226 CHECK_STATUS(status
, NT_STATUS_OK
);
1229 * We must do a manual smb2_request_receive() in order to be
1230 * able to check the transport layer info, as smb2_read_recv()
1231 * will destroy the req. smb2_read_recv() will call
1232 * smb2_request_receive() again, but that's ok.
1234 if (!smb2_request_receive(req
[1]) ||
1235 !smb2_request_is_ok(req
[1])) {
1236 torture_fail(tctx
, "failed to receive read request");
1240 * size must be 24: 16 byte read response header plus 3
1241 * requested bytes padded to an 8 byte boundary.
1243 CHECK_VAL(req
[1]->in
.body_size
, 24);
1245 status
= smb2_read_recv(req
[1], tree
, &r
);
1246 CHECK_STATUS(status
, NT_STATUS_OK
);
1248 /* Pick up the second, possibly async, read. */
1249 status
= smb2_read_recv(req
[2], tree
, &r2
);
1250 CHECK_STATUS(status
, NT_STATUS_OK
);
1252 smb2_util_close(tree
, cr
.out
.file
.handle
);
1254 /* Check compound read from stream */
1255 smb2_transport_compound_start(tree
->session
->transport
, 3);
1258 cr
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1259 cr
.in
.desired_access
= SEC_FILE_READ_DATA
;
1260 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1261 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1262 cr
.in
.fname
= sname
;
1263 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1264 NTCREATEX_SHARE_ACCESS_WRITE
|
1265 NTCREATEX_SHARE_ACCESS_DELETE
;
1266 req
[0] = smb2_create_send(tree
, &cr
);
1268 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1271 * We send 2 reads in the compound here as the protocol
1272 * allows the last read to be split off and possibly
1273 * go async. Check the padding on the first read returned,
1274 * not the second as the second may not be part of the
1275 * returned compound.
1279 h
.data
[0] = UINT64_MAX
;
1280 h
.data
[1] = UINT64_MAX
;
1281 r
.in
.file
.handle
= h
;
1285 req
[1] = smb2_read_send(tree
, &r
);
1288 h
.data
[0] = UINT64_MAX
;
1289 h
.data
[1] = UINT64_MAX
;
1290 r2
.in
.file
.handle
= h
;
1293 r2
.in
.min_count
= 1;
1294 req
[2] = smb2_read_send(tree
, &r2
);
1296 status
= smb2_create_recv(req
[0], tree
, &cr
);
1297 CHECK_STATUS(status
, NT_STATUS_OK
);
1300 * We must do a manual smb2_request_receive() in order to be
1301 * able to check the transport layer info, as smb2_read_recv()
1302 * will destroy the req. smb2_read_recv() will call
1303 * smb2_request_receive() again, but that's ok.
1305 if (!smb2_request_receive(req
[1]) ||
1306 !smb2_request_is_ok(req
[1])) {
1307 torture_fail(tctx
, "failed to receive read request");
1311 * size must be 24: 16 byte read response header plus 3
1312 * requested bytes padded to an 8 byte boundary.
1314 CHECK_VAL(req
[1]->in
.body_size
, 24);
1316 status
= smb2_read_recv(req
[1], tree
, &r
);
1317 CHECK_STATUS(status
, NT_STATUS_OK
);
1319 /* Pick up the second, possibly async, read. */
1320 status
= smb2_read_recv(req
[2], tree
, &r2
);
1321 CHECK_STATUS(status
, NT_STATUS_OK
);
1323 h
= cr
.out
.file
.handle
;
1325 /* Check 2 compound (unrelateated) reads from existing stream handle */
1326 smb2_transport_compound_start(tree
->session
->transport
, 2);
1329 r
.in
.file
.handle
= h
;
1333 req
[0] = smb2_read_send(tree
, &r
);
1334 req
[1] = smb2_read_send(tree
, &r
);
1337 * We must do a manual smb2_request_receive() in order to be
1338 * able to check the transport layer info, as smb2_read_recv()
1339 * will destroy the req. smb2_read_recv() will call
1340 * smb2_request_receive() again, but that's ok.
1342 if (!smb2_request_receive(req
[0]) ||
1343 !smb2_request_is_ok(req
[0])) {
1344 torture_fail(tctx
, "failed to receive read request");
1346 if (!smb2_request_receive(req
[1]) ||
1347 !smb2_request_is_ok(req
[1])) {
1348 torture_fail(tctx
, "failed to receive read request");
1352 * size must be 24: 16 byte read response header plus 3
1353 * requested bytes padded to an 8 byte boundary.
1355 CHECK_VAL(req
[0]->in
.body_size
, 24);
1356 CHECK_VAL(req
[1]->in
.body_size
, 24);
1358 status
= smb2_read_recv(req
[0], tree
, &r
);
1359 CHECK_STATUS(status
, NT_STATUS_OK
);
1360 status
= smb2_read_recv(req
[1], tree
, &r
);
1361 CHECK_STATUS(status
, NT_STATUS_OK
);
1364 * now try a single read from the stream and verify there's no padding
1367 r
.in
.file
.handle
= h
;
1371 req
[0] = smb2_read_send(tree
, &r
);
1374 * We must do a manual smb2_request_receive() in order to be
1375 * able to check the transport layer info, as smb2_read_recv()
1376 * will destroy the req. smb2_read_recv() will call
1377 * smb2_request_receive() again, but that's ok.
1379 if (!smb2_request_receive(req
[0]) ||
1380 !smb2_request_is_ok(req
[0])) {
1381 torture_fail(tctx
, "failed to receive read request");
1385 * size must be 19: 16 byte read response header plus 3
1386 * requested bytes without padding.
1388 CHECK_VAL(req
[0]->in
.body_size
, 19);
1390 status
= smb2_read_recv(req
[0], tree
, &r
);
1391 CHECK_STATUS(status
, NT_STATUS_OK
);
1393 smb2_util_close(tree
, h
);
1395 status
= smb2_util_unlink(tree
, fname
);
1396 CHECK_STATUS(status
, NT_STATUS_OK
);
1403 static bool test_compound_create_write_close(struct torture_context
*tctx
,
1404 struct smb2_tree
*tree
)
1406 struct smb2_handle handle
= { .data
= { UINT64_MAX
, UINT64_MAX
} };
1407 struct smb2_create create
;
1408 struct smb2_write write
;
1409 struct smb2_close close
;
1410 const char *fname
= "compound_create_write_close.dat";
1411 struct smb2_request
*req
[3];
1415 smb2_util_unlink(tree
, fname
);
1417 ZERO_STRUCT(create
);
1418 create
.in
.security_flags
= 0x00;
1419 create
.in
.oplock_level
= 0;
1420 create
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1421 create
.in
.create_flags
= 0x00000000;
1422 create
.in
.reserved
= 0x00000000;
1423 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1424 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1425 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1426 NTCREATEX_SHARE_ACCESS_WRITE
|
1427 NTCREATEX_SHARE_ACCESS_DELETE
;
1428 create
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1429 create
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1430 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1431 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1433 create
.in
.fname
= fname
;
1435 smb2_transport_compound_start(tree
->session
->transport
, 3);
1437 req
[0] = smb2_create_send(tree
, &create
);
1439 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1442 write
.in
.file
.handle
= handle
;
1443 write
.in
.offset
= 0;
1444 write
.in
.data
= data_blob_talloc(tctx
, NULL
, 1024);
1446 req
[1] = smb2_write_send(tree
, &write
);
1449 close
.in
.file
.handle
= handle
;
1451 req
[2] = smb2_close_send(tree
, &close
);
1453 status
= smb2_create_recv(req
[0], tree
, &create
);
1454 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1457 status
= smb2_write_recv(req
[1], &write
);
1458 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1461 status
= smb2_close_recv(req
[2], &close
);
1462 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1465 status
= smb2_util_unlink(tree
, fname
);
1466 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1467 "File deletion failed.");
1474 static bool test_compound_unrelated1(struct torture_context
*tctx
,
1475 struct smb2_tree
*tree
)
1477 struct smb2_handle hd
;
1478 struct smb2_create cr
;
1480 const char *fname
= "compound_unrelated1.dat";
1481 struct smb2_close cl
;
1483 struct smb2_request
*req
[5];
1485 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
1487 smb2_util_unlink(tree
, fname
);
1489 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1492 cr
.in
.security_flags
= 0x00;
1493 cr
.in
.oplock_level
= 0;
1494 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1495 cr
.in
.create_flags
= 0x00000000;
1496 cr
.in
.reserved
= 0x00000000;
1497 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1498 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1499 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1500 NTCREATEX_SHARE_ACCESS_WRITE
|
1501 NTCREATEX_SHARE_ACCESS_DELETE
;
1502 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1503 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1504 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1505 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1507 cr
.in
.fname
= fname
;
1509 smb2_transport_compound_start(tree
->session
->transport
, 5);
1511 req
[0] = smb2_create_send(tree
, &cr
);
1513 hd
.data
[0] = UINT64_MAX
;
1514 hd
.data
[1] = UINT64_MAX
;
1517 cl
.in
.file
.handle
= hd
;
1518 req
[1] = smb2_close_send(tree
, &cl
);
1519 req
[2] = smb2_close_send(tree
, &cl
);
1520 req
[3] = smb2_close_send(tree
, &cl
);
1521 req
[4] = smb2_close_send(tree
, &cl
);
1523 status
= smb2_create_recv(req
[0], tree
, &cr
);
1524 CHECK_STATUS(status
, NT_STATUS_OK
);
1525 status
= smb2_close_recv(req
[1], &cl
);
1526 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1527 status
= smb2_close_recv(req
[2], &cl
);
1528 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1529 status
= smb2_close_recv(req
[3], &cl
);
1530 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1531 status
= smb2_close_recv(req
[4], &cl
);
1532 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1534 smb2_util_unlink(tree
, fname
);
1539 static bool test_compound_invalid1(struct torture_context
*tctx
,
1540 struct smb2_tree
*tree
)
1542 struct smb2_handle hd
;
1543 struct smb2_create cr
;
1545 const char *fname
= "compound_invalid1.dat";
1546 struct smb2_close cl
;
1548 struct smb2_request
*req
[3];
1550 smb2_transport_credits_ask_num(tree
->session
->transport
, 3);
1552 smb2_util_unlink(tree
, fname
);
1554 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1557 cr
.in
.security_flags
= 0x00;
1558 cr
.in
.oplock_level
= 0;
1559 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1560 cr
.in
.create_flags
= 0x00000000;
1561 cr
.in
.reserved
= 0x00000000;
1562 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1563 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1564 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1565 NTCREATEX_SHARE_ACCESS_WRITE
|
1566 NTCREATEX_SHARE_ACCESS_DELETE
;
1567 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1568 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1569 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1570 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1572 cr
.in
.fname
= fname
;
1574 smb2_transport_compound_start(tree
->session
->transport
, 3);
1576 /* passing the first request with the related flag is invalid */
1577 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1579 req
[0] = smb2_create_send(tree
, &cr
);
1581 hd
.data
[0] = UINT64_MAX
;
1582 hd
.data
[1] = UINT64_MAX
;
1585 cl
.in
.file
.handle
= hd
;
1586 req
[1] = smb2_close_send(tree
, &cl
);
1588 smb2_transport_compound_set_related(tree
->session
->transport
, false);
1589 req
[2] = smb2_close_send(tree
, &cl
);
1591 status
= smb2_create_recv(req
[0], tree
, &cr
);
1592 /* TODO: check why this fails with --signing=required */
1593 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1594 status
= smb2_close_recv(req
[1], &cl
);
1595 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1596 status
= smb2_close_recv(req
[2], &cl
);
1597 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1599 smb2_util_unlink(tree
, fname
);
1604 static bool test_compound_invalid2(struct torture_context
*tctx
,
1605 struct smb2_tree
*tree
)
1607 struct smb2_handle hd
;
1608 struct smb2_create cr
;
1610 const char *fname
= "compound_invalid2.dat";
1611 struct smb2_close cl
;
1613 struct smb2_request
*req
[5];
1614 struct smbXcli_tcon
*saved_tcon
= tree
->smbXcli
;
1615 struct smbXcli_session
*saved_session
= tree
->session
->smbXcli
;
1617 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
1619 smb2_util_unlink(tree
, fname
);
1621 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1624 cr
.in
.security_flags
= 0x00;
1625 cr
.in
.oplock_level
= 0;
1626 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1627 cr
.in
.create_flags
= 0x00000000;
1628 cr
.in
.reserved
= 0x00000000;
1629 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1630 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1631 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1632 NTCREATEX_SHARE_ACCESS_WRITE
|
1633 NTCREATEX_SHARE_ACCESS_DELETE
;
1634 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1635 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1636 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1637 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1639 cr
.in
.fname
= fname
;
1641 smb2_transport_compound_start(tree
->session
->transport
, 5);
1643 req
[0] = smb2_create_send(tree
, &cr
);
1645 hd
.data
[0] = UINT64_MAX
;
1646 hd
.data
[1] = UINT64_MAX
;
1648 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1651 cl
.in
.file
.handle
= hd
;
1653 tree
->smbXcli
= smbXcli_tcon_create(tree
);
1654 smb2cli_tcon_set_values(tree
->smbXcli
,
1656 0xFFFFFFFF, /* tcon_id */
1659 0, /* capabilities */
1660 0 /* maximal_access */);
1662 tree
->session
->smbXcli
= smbXcli_session_shallow_copy(tree
->session
,
1663 tree
->session
->smbXcli
);
1664 smb2cli_session_set_id_and_flags(tree
->session
->smbXcli
, UINT64_MAX
, 0);
1666 req
[1] = smb2_close_send(tree
, &cl
);
1667 /* strange that this is not generating invalid parameter */
1668 smb2_transport_compound_set_related(tree
->session
->transport
, false);
1669 req
[2] = smb2_close_send(tree
, &cl
);
1670 req
[3] = smb2_close_send(tree
, &cl
);
1671 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1672 req
[4] = smb2_close_send(tree
, &cl
);
1674 status
= smb2_create_recv(req
[0], tree
, &cr
);
1675 CHECK_STATUS(status
, NT_STATUS_OK
);
1676 status
= smb2_close_recv(req
[1], &cl
);
1677 CHECK_STATUS(status
, NT_STATUS_OK
);
1678 status
= smb2_close_recv(req
[2], &cl
);
1679 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
1680 status
= smb2_close_recv(req
[3], &cl
);
1681 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
1682 status
= smb2_close_recv(req
[4], &cl
);
1683 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1685 TALLOC_FREE(tree
->smbXcli
);
1686 tree
->smbXcli
= saved_tcon
;
1687 TALLOC_FREE(tree
->session
->smbXcli
);
1688 tree
->session
->smbXcli
= saved_session
;
1690 smb2_util_unlink(tree
, fname
);
1695 static bool test_compound_invalid3(struct torture_context
*tctx
,
1696 struct smb2_tree
*tree
)
1698 struct smb2_handle hd
;
1699 struct smb2_create cr
;
1701 const char *fname
= "compound_invalid3.dat";
1702 struct smb2_close cl
;
1704 struct smb2_request
*req
[5];
1706 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
1708 smb2_util_unlink(tree
, fname
);
1710 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1713 cr
.in
.security_flags
= 0x00;
1714 cr
.in
.oplock_level
= 0;
1715 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1716 cr
.in
.create_flags
= 0x00000000;
1717 cr
.in
.reserved
= 0x00000000;
1718 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1719 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1720 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1721 NTCREATEX_SHARE_ACCESS_WRITE
|
1722 NTCREATEX_SHARE_ACCESS_DELETE
;
1723 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1724 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1725 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1726 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1728 cr
.in
.fname
= fname
;
1730 smb2_transport_compound_start(tree
->session
->transport
, 5);
1732 req
[0] = smb2_create_send(tree
, &cr
);
1734 hd
.data
[0] = UINT64_MAX
;
1735 hd
.data
[1] = UINT64_MAX
;
1738 cl
.in
.file
.handle
= hd
;
1739 req
[1] = smb2_close_send(tree
, &cl
);
1740 req
[2] = smb2_close_send(tree
, &cl
);
1741 /* flipping the related flag is invalid */
1742 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1743 req
[3] = smb2_close_send(tree
, &cl
);
1744 req
[4] = smb2_close_send(tree
, &cl
);
1746 status
= smb2_create_recv(req
[0], tree
, &cr
);
1747 CHECK_STATUS(status
, NT_STATUS_OK
);
1748 status
= smb2_close_recv(req
[1], &cl
);
1749 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1750 status
= smb2_close_recv(req
[2], &cl
);
1751 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1752 status
= smb2_close_recv(req
[3], &cl
);
1753 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1754 status
= smb2_close_recv(req
[4], &cl
);
1755 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
1757 smb2_util_unlink(tree
, fname
);
1762 static bool test_compound_invalid4(struct torture_context
*tctx
,
1763 struct smb2_tree
*tree
)
1765 struct smb2_create cr
;
1766 struct smb2_read rd
;
1768 const char *fname
= "compound_invalid4.dat";
1769 struct smb2_close cl
;
1772 struct smb2_request
*req
[2];
1774 smb2_transport_credits_ask_num(tree
->session
->transport
, 2);
1776 smb2_util_unlink(tree
, fname
);
1779 cr
.in
.security_flags
= 0x00;
1780 cr
.in
.oplock_level
= 0;
1781 cr
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
1782 cr
.in
.create_flags
= 0x00000000;
1783 cr
.in
.reserved
= 0x00000000;
1784 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1785 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1786 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1787 NTCREATEX_SHARE_ACCESS_WRITE
|
1788 NTCREATEX_SHARE_ACCESS_DELETE
;
1789 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1790 cr
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1791 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1792 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1794 cr
.in
.fname
= fname
;
1796 status
= smb2_create(tree
, tctx
, &cr
);
1797 CHECK_STATUS(status
, NT_STATUS_OK
);
1799 smb2_transport_compound_start(tree
->session
->transport
, 2);
1802 rd
.in
.file
.handle
= cr
.out
.file
.handle
;
1805 req
[0] = smb2_read_send(tree
, &rd
);
1807 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1810 * Send a completely bogus request as second compound
1811 * element. This triggers smbd_smb2_request_error() in in
1812 * smbd_smb2_request_dispatch() before calling
1813 * smbd_smb2_request_dispatch_update_counts().
1816 req
[1] = smb2_request_init_tree(tree
, 0xff, 0x04, false, 0);
1817 smb2_transport_send(req
[1]);
1819 status
= smb2_read_recv(req
[0], tctx
, &rd
);
1820 CHECK_STATUS(status
, NT_STATUS_END_OF_FILE
);
1822 ok
= smb2_request_receive(req
[1]);
1823 torture_assert(tctx
, ok
, "Invalid request failed\n");
1824 CHECK_STATUS(req
[1]->status
, NT_STATUS_INVALID_PARAMETER
);
1827 cl
.in
.file
.handle
= cr
.out
.file
.handle
;
1829 status
= smb2_close(tree
, &cl
);
1830 CHECK_STATUS(status
, NT_STATUS_OK
);
1832 smb2_util_unlink(tree
, fname
);
1837 /* Send a compound request where we expect the last request (Create, Notify)
1838 * to go asynchronous. This works against a Win7 server and the reply is
1839 * sent in two different packets. */
1840 static bool test_compound_interim1(struct torture_context
*tctx
,
1841 struct smb2_tree
*tree
)
1843 struct smb2_handle hd
;
1844 struct smb2_create cr
;
1845 NTSTATUS status
= NT_STATUS_OK
;
1846 const char *dname
= "compound_interim_dir";
1847 struct smb2_notify nt
;
1849 struct smb2_request
*req
[2];
1851 /* Win7 compound request implementation deviates substantially from the
1852 * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
1853 * verifies the Windows behavior, not the general spec behavior. */
1855 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
1857 smb2_deltree(tree
, dname
);
1859 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1862 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1863 cr
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1864 cr
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
1865 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1866 NTCREATEX_SHARE_ACCESS_WRITE
|
1867 NTCREATEX_SHARE_ACCESS_DELETE
;
1868 cr
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1869 cr
.in
.fname
= dname
;
1871 smb2_transport_compound_start(tree
->session
->transport
, 2);
1873 req
[0] = smb2_create_send(tree
, &cr
);
1875 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1877 hd
.data
[0] = UINT64_MAX
;
1878 hd
.data
[1] = UINT64_MAX
;
1881 nt
.in
.recursive
= true;
1882 nt
.in
.buffer_size
= 0x1000;
1883 nt
.in
.file
.handle
= hd
;
1884 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1885 nt
.in
.unknown
= 0x00000000;
1887 req
[1] = smb2_notify_send(tree
, &nt
);
1889 status
= smb2_create_recv(req
[0], tree
, &cr
);
1890 CHECK_STATUS(status
, NT_STATUS_OK
);
1892 smb2_cancel(req
[1]);
1893 status
= smb2_notify_recv(req
[1], tree
, &nt
);
1894 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1896 smb2_util_close(tree
, cr
.out
.file
.handle
);
1898 smb2_deltree(tree
, dname
);
1903 /* Send a compound request where we expect the middle request (Create, Notify,
1904 * GetInfo) to go asynchronous. Against Win7 the sync request succeed while
1905 * the async fails. All are returned in the same compound response. */
1906 static bool test_compound_interim2(struct torture_context
*tctx
,
1907 struct smb2_tree
*tree
)
1909 struct smb2_handle hd
;
1910 struct smb2_create cr
;
1911 NTSTATUS status
= NT_STATUS_OK
;
1912 const char *dname
= "compound_interim_dir";
1913 struct smb2_getinfo gf
;
1914 struct smb2_notify nt
;
1916 struct smb2_request
*req
[3];
1918 /* Win7 compound request implementation deviates substantially from the
1919 * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
1920 * verifies the Windows behavior, not the general spec behavior. */
1922 smb2_transport_credits_ask_num(tree
->session
->transport
, 5);
1924 smb2_deltree(tree
, dname
);
1926 smb2_transport_credits_ask_num(tree
->session
->transport
, 1);
1929 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1930 cr
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1931 cr
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
1932 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1933 NTCREATEX_SHARE_ACCESS_WRITE
|
1934 NTCREATEX_SHARE_ACCESS_DELETE
;
1935 cr
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1936 cr
.in
.fname
= dname
;
1938 smb2_transport_compound_start(tree
->session
->transport
, 3);
1940 req
[0] = smb2_create_send(tree
, &cr
);
1942 smb2_transport_compound_set_related(tree
->session
->transport
, true);
1944 hd
.data
[0] = UINT64_MAX
;
1945 hd
.data
[1] = UINT64_MAX
;
1948 nt
.in
.recursive
= true;
1949 nt
.in
.buffer_size
= 0x1000;
1950 nt
.in
.file
.handle
= hd
;
1951 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1952 nt
.in
.unknown
= 0x00000000;
1954 req
[1] = smb2_notify_send(tree
, &nt
);
1957 gf
.in
.file
.handle
= hd
;
1958 gf
.in
.info_type
= SMB2_0_INFO_FILE
;
1959 gf
.in
.info_class
= 0x04; /* FILE_BASIC_INFORMATION */
1960 gf
.in
.output_buffer_length
= 0x1000;
1961 gf
.in
.input_buffer
= data_blob_null
;
1963 req
[2] = smb2_getinfo_send(tree
, &gf
);
1965 status
= smb2_create_recv(req
[0], tree
, &cr
);
1966 CHECK_STATUS(status
, NT_STATUS_OK
);
1968 status
= smb2_notify_recv(req
[1], tree
, &nt
);
1969 CHECK_STATUS(status
, NT_STATUS_INTERNAL_ERROR
);
1971 status
= smb2_getinfo_recv(req
[2], tree
, &gf
);
1972 CHECK_STATUS(status
, NT_STATUS_OK
);
1974 smb2_util_close(tree
, cr
.out
.file
.handle
);
1976 smb2_deltree(tree
, dname
);
1982 * Send a compound related series of CREATE+CLOSE+CREATE+NOTIFY and check
1983 * CREATE+CLOSE+CREATE responses come in a separate compound response before the
1984 * STATUS_PENDING for the NOTIFY.
1986 static bool test_compound_interim3(struct torture_context
*tctx
,
1987 struct smb2_tree
*tree
)
1989 const char *dname
= "test_compound_interim3";
1990 struct smb2_handle hd
= {};
1991 struct smb2_create cr
= {};
1992 struct smb2_handle h1
= {};
1993 struct smb2_notify nt
= {};
1994 struct smb2_request
*req
[6] = {};
1995 struct smb2_close cl
= {};
2000 smb2_deltree(tree
, dname
);
2001 smb2_transport_compound_start(tree
->session
->transport
, 4);
2003 hd
.data
[0] = UINT64_MAX
;
2004 hd
.data
[1] = UINT64_MAX
;
2006 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2007 cr
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2008 cr
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2009 cr
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2010 NTCREATEX_SHARE_ACCESS_WRITE
|
2011 NTCREATEX_SHARE_ACCESS_DELETE
;
2012 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
2013 cr
.in
.fname
= dname
;
2015 nt
.in
.recursive
= true;
2016 nt
.in
.buffer_size
= 0x1000;
2017 nt
.in
.file
.handle
= hd
;
2018 nt
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2019 nt
.in
.unknown
= 0x00000000;
2021 req
[0] = smb2_create_send(tree
, &cr
);
2022 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
2023 "smb2_create_send failed\n");
2025 smb2_transport_compound_set_related(tree
->session
->transport
, true);
2027 cl
.in
.file
.handle
= hd
;
2029 req
[1] = smb2_close_send(tree
, &cl
);
2030 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
2031 "smb2_close_send failed\n");
2033 req
[2] = smb2_create_send(tree
, &cr
);
2034 torture_assert_not_null_goto(tctx
, req
[2], ret
, done
,
2035 "smb2_create_send failed\n");
2037 req
[3] = smb2_notify_send(tree
, &nt
);
2038 torture_assert_not_null_goto(tctx
, req
[3], ret
, done
,
2039 "smb2_create_send failed\n");
2041 while (req
[2]->state
< SMB2_REQUEST_DONE
) {
2042 rc
= tevent_loop_once(tctx
->ev
);
2043 torture_assert_goto(tctx
, rc
== 0, ret
, done
,
2044 "tevent_loop_once failed\n");
2047 torture_assert_goto(tctx
, req
[0]->state
== SMB2_REQUEST_DONE
, ret
, done
,
2048 "state not SMB2_REQUEST_DONE");
2049 torture_assert_goto(tctx
, req
[1]->state
== SMB2_REQUEST_DONE
, ret
, done
,
2050 "state not SMB2_REQUEST_DONE");
2051 torture_assert_goto(tctx
, req
[2]->state
== SMB2_REQUEST_DONE
, ret
, done
,
2052 "state not SMB2_REQUEST_DONE");
2053 torture_assert_goto(tctx
, req
[3]->state
== SMB2_REQUEST_RECV
, ret
, done
,
2054 "state not SMB2_REQUEST_RECV");
2056 WAIT_FOR_ASYNC_RESPONSE(req
[3]);
2057 torture_assert_goto(tctx
, req
[3]->state
== SMB2_REQUEST_RECV
, ret
, done
,
2058 "state not SMB2_REQUEST_RECV");
2059 torture_assert_goto(tctx
, req
[3]->cancel
.can_cancel
, ret
, done
, "pending");
2061 status
= smb2_create_recv(req
[0], tree
, &cr
);
2062 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2063 "smb2_setinfo_recv failed\n");
2065 status
= smb2_close_recv(req
[1], &cl
);
2066 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2067 "smb2_setinfo_recv failed\n");
2069 status
= smb2_create_recv(req
[2], tree
, &cr
);
2070 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2071 "smb2_create_recv failed\n");
2072 h1
= cr
.out
.file
.handle
;
2074 smb2_cancel(req
[3]);
2075 status
= smb2_notify_recv(req
[3], tree
, &nt
);
2076 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_CANCELLED
,
2078 "smb2_notify_recv failed\n");
2081 smb2_util_close(tree
, h1
);
2082 smb2_deltree(tree
, dname
);
2086 /* Test compound related finds */
2087 static bool test_compound_find_related(struct torture_context
*tctx
,
2088 struct smb2_tree
*tree
)
2090 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
2091 const char *dname
= "compound_find_dir";
2092 struct smb2_create create
;
2094 struct smb2_handle h
;
2095 struct smb2_request
*req
[2];
2099 smb2_deltree(tree
, dname
);
2101 ZERO_STRUCT(create
);
2102 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
2103 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2104 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2105 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2106 NTCREATEX_SHARE_ACCESS_WRITE
|
2107 NTCREATEX_SHARE_ACCESS_DELETE
;
2108 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2109 create
.in
.fname
= dname
;
2111 status
= smb2_create(tree
, mem_ctx
, &create
);
2112 h
= create
.out
.file
.handle
;
2114 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_create failed\n");
2116 smb2_transport_compound_start(tree
->session
->transport
, 2);
2119 f
.in
.file
.handle
= h
;
2121 f
.in
.max_response_size
= 0x100;
2122 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
2124 req
[0] = smb2_find_send(tree
, &f
);
2126 smb2_transport_compound_set_related(tree
->session
->transport
, true);
2128 req
[1] = smb2_find_send(tree
, &f
);
2130 status
= smb2_find_recv(req
[0], mem_ctx
, &f
);
2131 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_find_recv failed\n");
2133 status
= smb2_find_recv(req
[1], mem_ctx
, &f
);
2134 torture_assert_ntstatus_equal_goto(tctx
, status
, STATUS_NO_MORE_FILES
, ret
, done
, "smb2_find_recv failed\n");
2137 smb2_util_close(tree
, h
);
2138 smb2_deltree(tree
, dname
);
2139 TALLOC_FREE(mem_ctx
);
2143 /* Test compound related finds */
2144 static bool test_compound_find_close(struct torture_context
*tctx
,
2145 struct smb2_tree
*tree
)
2147 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
2148 const char *dname
= "compound_find_dir";
2149 struct smb2_create create
;
2151 struct smb2_handle h
;
2152 struct smb2_request
*req
= NULL
;
2153 const int num_files
= 5000;
2158 smb2_deltree(tree
, dname
);
2160 ZERO_STRUCT(create
);
2161 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
2162 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2163 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2164 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2165 NTCREATEX_SHARE_ACCESS_WRITE
|
2166 NTCREATEX_SHARE_ACCESS_DELETE
;
2167 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2168 create
.in
.fname
= dname
;
2170 smb2cli_conn_set_max_credits(tree
->session
->transport
->conn
, 256);
2172 status
= smb2_create(tree
, mem_ctx
, &create
);
2173 h
= create
.out
.file
.handle
;
2175 ZERO_STRUCT(create
);
2176 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2177 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2178 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2180 for (i
= 0; i
< num_files
; i
++) {
2181 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\file%d",
2183 status
= smb2_create(tree
, mem_ctx
, &create
);
2184 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
2185 smb2_util_close(tree
, create
.out
.file
.handle
);
2188 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_create failed\n");
2191 f
.in
.file
.handle
= h
;
2193 f
.in
.max_response_size
= 8*1024*1024;
2194 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
2196 req
= smb2_find_send(tree
, &f
);
2198 status
= smb2_util_close(tree
, h
);
2199 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_util_close failed\n");
2201 status
= smb2_find_recv(req
, mem_ctx
, &f
);
2202 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_find_recv failed\n");
2205 smb2_util_close(tree
, h
);
2206 smb2_deltree(tree
, dname
);
2207 TALLOC_FREE(mem_ctx
);
2211 /* Test compound unrelated finds */
2212 static bool test_compound_find_unrelated(struct torture_context
*tctx
,
2213 struct smb2_tree
*tree
)
2215 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
2216 const char *dname
= "compound_find_dir";
2217 struct smb2_create create
;
2219 struct smb2_handle h
;
2220 struct smb2_request
*req
[2];
2224 smb2_deltree(tree
, dname
);
2226 ZERO_STRUCT(create
);
2227 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
2228 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2229 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2230 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2231 NTCREATEX_SHARE_ACCESS_WRITE
|
2232 NTCREATEX_SHARE_ACCESS_DELETE
;
2233 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2234 create
.in
.fname
= dname
;
2236 status
= smb2_create(tree
, mem_ctx
, &create
);
2237 h
= create
.out
.file
.handle
;
2239 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_create failed\n");
2241 smb2_transport_compound_start(tree
->session
->transport
, 2);
2244 f
.in
.file
.handle
= h
;
2246 f
.in
.max_response_size
= 0x100;
2247 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
2249 req
[0] = smb2_find_send(tree
, &f
);
2250 req
[1] = smb2_find_send(tree
, &f
);
2252 status
= smb2_find_recv(req
[0], mem_ctx
, &f
);
2253 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_find_recv failed\n");
2255 status
= smb2_find_recv(req
[1], mem_ctx
, &f
);
2256 torture_assert_ntstatus_equal_goto(tctx
, status
, STATUS_NO_MORE_FILES
, ret
, done
, "smb2_find_recv failed\n");
2259 smb2_util_close(tree
, h
);
2260 smb2_deltree(tree
, dname
);
2261 TALLOC_FREE(mem_ctx
);
2265 static bool test_compound_async_flush_close(struct torture_context
*tctx
,
2266 struct smb2_tree
*tree
)
2268 struct smb2_handle fhandle
= { .data
= { 0, 0 } };
2269 struct smb2_handle relhandle
= { .data
= { UINT64_MAX
, UINT64_MAX
} };
2270 struct smb2_close cl
;
2271 struct smb2_flush fl
;
2272 const char *fname
= "compound_async_flush_close";
2273 struct smb2_request
*req
[2];
2278 smb2_util_unlink(tree
, fname
);
2280 /* Create a file. */
2281 status
= torture_smb2_testfile_access(tree
,
2284 SEC_RIGHTS_FILE_ALL
);
2285 CHECK_STATUS(status
, NT_STATUS_OK
);
2287 /* Now do a compound flush + close handle. */
2288 smb2_transport_compound_start(tree
->session
->transport
, 2);
2291 fl
.in
.file
.handle
= fhandle
;
2293 req
[0] = smb2_flush_send(tree
, &fl
);
2294 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
2295 "smb2_flush_send failed\n");
2297 smb2_transport_compound_set_related(tree
->session
->transport
, true);
2300 cl
.in
.file
.handle
= relhandle
;
2301 req
[1] = smb2_close_send(tree
, &cl
);
2302 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
2303 "smb2_close_send failed\n");
2305 status
= smb2_flush_recv(req
[0], &fl
);
2307 * On Windows, this flush will usually
2308 * succeed as we have nothing to flush,
2309 * so allow NT_STATUS_OK. Once bug #15172
2310 * is fixed Samba will do the flush synchronously
2311 * so allow NT_STATUS_OK.
2313 if (!NT_STATUS_IS_OK(status
)) {
2315 * If we didn't get NT_STATUS_OK, we *must*
2316 * get NT_STATUS_INTERNAL_ERROR if the flush
2319 * For pre-bugfix #15172 Samba, the flush goes async and
2320 * we should get NT_STATUS_INTERNAL_ERROR.
2322 torture_assert_ntstatus_equal_goto(tctx
,
2324 NT_STATUS_INTERNAL_ERROR
,
2327 "smb2_flush_recv didn't return "
2328 "NT_STATUS_INTERNAL_ERROR.\n");
2330 status
= smb2_close_recv(req
[1], &cl
);
2331 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2332 "smb2_close_recv failed.");
2334 ZERO_STRUCT(fhandle
);
2337 * Do several more operations on the tree, spaced
2338 * out by 1 sec sleeps to make sure the server didn't
2339 * crash on the close. The sleeps are required to
2340 * make test test for a crash reliable, as we ensure
2341 * the pthread fsync internally finishes and accesses
2342 * freed memory. Without them the test occasionally
2343 * passes as we disconnect before the pthread fsync
2346 status
= smb2_util_unlink(tree
, fname
);
2347 CHECK_STATUS(status
, NT_STATUS_OK
);
2350 status
= smb2_util_unlink(tree
, fname
);
2351 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
2354 status
= smb2_util_unlink(tree
, fname
);
2355 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
2361 if (fhandle
.data
[0] != 0) {
2362 smb2_util_close(tree
, fhandle
);
2365 smb2_util_unlink(tree
, fname
);
2369 static bool test_compound_async_flush_flush(struct torture_context
*tctx
,
2370 struct smb2_tree
*tree
)
2372 struct smb2_handle fhandle
= { .data
= { 0, 0 } };
2373 struct smb2_handle relhandle
= { .data
= { UINT64_MAX
, UINT64_MAX
} };
2374 struct smb2_flush fl1
;
2375 struct smb2_flush fl2
;
2376 const char *fname
= "compound_async_flush_flush";
2377 struct smb2_request
*req
[2];
2382 smb2_util_unlink(tree
, fname
);
2384 /* Create a file. */
2385 status
= torture_smb2_testfile_access(tree
,
2388 SEC_RIGHTS_FILE_ALL
);
2389 CHECK_STATUS(status
, NT_STATUS_OK
);
2391 /* Now do a compound flush + flush handle. */
2392 smb2_transport_compound_start(tree
->session
->transport
, 2);
2395 fl1
.in
.file
.handle
= fhandle
;
2397 req
[0] = smb2_flush_send(tree
, &fl1
);
2398 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
2399 "smb2_flush_send (1) failed\n");
2401 smb2_transport_compound_set_related(tree
->session
->transport
, true);
2404 fl2
.in
.file
.handle
= relhandle
;
2406 req
[1] = smb2_flush_send(tree
, &fl2
);
2407 torture_assert_not_null_goto(tctx
, req
[1], ret
, done
,
2408 "smb2_flush_send (2) failed\n");
2410 status
= smb2_flush_recv(req
[0], &fl1
);
2412 * On Windows, this flush will usually
2413 * succeed as we have nothing to flush,
2414 * so allow NT_STATUS_OK. Once bug #15172
2415 * is fixed Samba will do the flush synchronously
2416 * so allow NT_STATUS_OK.
2418 if (!NT_STATUS_IS_OK(status
)) {
2420 * If we didn't get NT_STATUS_OK, we *must*
2421 * get NT_STATUS_INTERNAL_ERROR if the flush
2424 * For pre-bugfix #15172 Samba, the flush goes async and
2425 * we should get NT_STATUS_INTERNAL_ERROR.
2427 torture_assert_ntstatus_equal_goto(tctx
,
2429 NT_STATUS_INTERNAL_ERROR
,
2432 "smb2_flush_recv (1) didn't return "
2433 "NT_STATUS_INTERNAL_ERROR.\n");
2437 * If the flush is the last entry in a compound,
2438 * it should always succeed even if it goes async.
2440 status
= smb2_flush_recv(req
[1], &fl2
);
2441 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2442 "smb2_flush_recv (2) failed.");
2444 status
= smb2_util_close(tree
, fhandle
);
2445 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2446 "smb2_util_close failed.");
2447 ZERO_STRUCT(fhandle
);
2450 * Do several more operations on the tree, spaced
2451 * out by 1 sec sleeps to make sure the server didn't
2452 * crash on the close. The sleeps are required to
2453 * make test test for a crash reliable, as we ensure
2454 * the pthread fsync internally finishes and accesses
2455 * freed memory. Without them the test occasionally
2456 * passes as we disconnect before the pthread fsync
2459 status
= smb2_util_unlink(tree
, fname
);
2460 CHECK_STATUS(status
, NT_STATUS_OK
);
2463 status
= smb2_util_unlink(tree
, fname
);
2464 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
2467 status
= smb2_util_unlink(tree
, fname
);
2468 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
2474 if (fhandle
.data
[0] != 0) {
2475 smb2_util_close(tree
, fhandle
);
2478 smb2_util_unlink(tree
, fname
);
2483 * For Samba/smbd this test must be run against the aio_delay_inject share
2484 * as we need to ensure the last write in the compound takes longer than
2485 * 500 us, which is the threshold for going async in smbd SMB2 writes.
2488 static bool test_compound_async_write_write(struct torture_context
*tctx
,
2489 struct smb2_tree
*tree
)
2491 struct smb2_handle fhandle
= { .data
= { 0, 0 } };
2492 struct smb2_handle relhandle
= { .data
= { UINT64_MAX
, UINT64_MAX
} };
2493 struct smb2_write w1
;
2494 struct smb2_write w2
;
2495 const char *fname
= "compound_async_write_write";
2496 struct smb2_request
*req
[2];
2498 bool is_smbd
= torture_setting_bool(tctx
, "smbd", true);
2502 smb2_util_unlink(tree
, fname
);
2504 /* Create a file. */
2505 status
= torture_smb2_testfile_access(tree
,
2508 SEC_RIGHTS_FILE_ALL
);
2509 CHECK_STATUS(status
, NT_STATUS_OK
);
2511 /* Now do a compound write + write handle. */
2512 smb2_transport_compound_start(tree
->session
->transport
, 2);
2515 w1
.in
.file
.handle
= fhandle
;
2517 w1
.in
.data
= data_blob_talloc_zero(tctx
, 64);
2518 req
[0] = smb2_write_send(tree
, &w1
);
2520 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
2521 "smb2_write_send (1) failed\n");
2523 smb2_transport_compound_set_related(tree
->session
->transport
, true);
2526 w2
.in
.file
.handle
= relhandle
;
2528 w2
.in
.data
= data_blob_talloc_zero(tctx
, 64);
2529 req
[1] = smb2_write_send(tree
, &w2
);
2531 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
2532 "smb2_write_send (2) failed\n");
2534 status
= smb2_write_recv(req
[0], &w1
);
2535 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2536 "smb2_write_recv (1) failed.");
2540 * Windows and other servers don't go async.
2542 status
= smb2_write_recv(req
[1], &w2
);
2545 * For smbd, the second write should go async
2546 * as it's the last element of a compound.
2548 WAIT_FOR_ASYNC_RESPONSE(req
[1]);
2549 CHECK_VAL(req
[1]->cancel
.can_cancel
, true);
2551 * Now pick up the real return.
2553 status
= smb2_write_recv(req
[1], &w2
);
2556 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2557 "smb2_write_recv (2) failed.");
2559 status
= smb2_util_close(tree
, fhandle
);
2560 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2561 "smb2_util_close failed.");
2562 ZERO_STRUCT(fhandle
);
2568 if (fhandle
.data
[0] != 0) {
2569 smb2_util_close(tree
, fhandle
);
2572 smb2_util_unlink(tree
, fname
);
2577 * For Samba/smbd this test must be run against the aio_delay_inject share
2578 * as we need to ensure the last read in the compound takes longer than
2579 * 500 us, which is the threshold for going async in smbd SMB2 reads.
2582 static bool test_compound_async_read_read(struct torture_context
*tctx
,
2583 struct smb2_tree
*tree
)
2585 struct smb2_handle fhandle
= { .data
= { 0, 0 } };
2586 struct smb2_handle relhandle
= { .data
= { UINT64_MAX
, UINT64_MAX
} };
2587 struct smb2_write w
;
2588 struct smb2_read r1
;
2589 struct smb2_read r2
;
2590 const char *fname
= "compound_async_read_read";
2591 struct smb2_request
*req
[2];
2593 bool is_smbd
= torture_setting_bool(tctx
, "smbd", true);
2597 smb2_util_unlink(tree
, fname
);
2599 /* Create a file. */
2600 status
= torture_smb2_testfile_access(tree
,
2603 SEC_RIGHTS_FILE_ALL
);
2604 CHECK_STATUS(status
, NT_STATUS_OK
);
2606 /* Write 128 bytes. */
2608 w
.in
.file
.handle
= fhandle
;
2610 w
.in
.data
= data_blob_talloc_zero(tctx
, 128);
2611 status
= smb2_write(tree
, &w
);
2612 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2613 "smb2_write_recv (1) failed.");
2615 /* Now do a compound read + read handle. */
2616 smb2_transport_compound_start(tree
->session
->transport
, 2);
2619 r1
.in
.file
.handle
= fhandle
;
2622 req
[0] = smb2_read_send(tree
, &r1
);
2624 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
2625 "smb2_read_send (1) failed\n");
2627 smb2_transport_compound_set_related(tree
->session
->transport
, true);
2630 r2
.in
.file
.handle
= relhandle
;
2633 req
[1] = smb2_read_send(tree
, &r2
);
2635 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
2636 "smb2_read_send (2) failed\n");
2638 status
= smb2_read_recv(req
[0], tree
, &r1
);
2639 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2640 "smb2_read_recv (1) failed.");
2644 * Windows and other servers don't go async.
2646 status
= smb2_read_recv(req
[1], tree
, &r2
);
2649 * For smbd, the second write should go async
2650 * as it's the last element of a compound.
2652 WAIT_FOR_ASYNC_RESPONSE(req
[1]);
2653 CHECK_VAL(req
[1]->cancel
.can_cancel
, true);
2655 * Now pick up the real return.
2657 status
= smb2_read_recv(req
[1], tree
, &r2
);
2660 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2661 "smb2_read_recv (2) failed.");
2663 status
= smb2_util_close(tree
, fhandle
);
2664 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2665 "smb2_util_close failed.");
2666 ZERO_STRUCT(fhandle
);
2672 if (fhandle
.data
[0] != 0) {
2673 smb2_util_close(tree
, fhandle
);
2676 smb2_util_unlink(tree
, fname
);
2681 * Checks a lease break by a create triggers an pending async response.
2683 static bool test_create_lease_break_async(struct torture_context
*tctx
,
2684 struct smb2_tree
*tree1
,
2685 struct smb2_tree
*tree2
)
2687 struct smb2_request
*req
= NULL
;
2688 struct smb2_create c1
= {};
2689 struct smb2_create c2
= {};
2690 struct smb2_lease ls1
= {};
2691 struct smb2_lease ls2
= {};
2692 struct smb2_handle h1
= {};
2693 struct smb2_handle h2
= {};
2694 struct smb2_lease_break_ack ack
= {};
2695 const char *fname_src
= "test_create_lease_break_async.dat";
2700 caps
= smb2cli_conn_server_capabilities(tree1
->session
->transport
->conn
);
2701 if (!(caps
& SMB2_CAP_LEASING
)) {
2702 torture_skip(tctx
, "leases are not supported");
2705 smb2_util_unlink(tree1
, fname_src
);
2707 tree1
->session
->transport
->lease
.handler
= torture_lease_handler
;
2708 tree1
->session
->transport
->lease
.private_data
= tree1
;
2709 torture_reset_lease_break_info(tctx
, &lease_break_info
);
2710 lease_break_info
.lease_skip_ack
= true;
2712 /* First open with a RWH lease. */
2713 smb2_lease_create(&c1
,
2718 smb2_util_lease_state("RWH"));
2720 status
= smb2_create(tree1
, tree1
, &c1
);
2721 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2722 "smb2_create failed\n");
2723 CHECK_LEASE(&c1
, "RWH", true, LEASE1
, 0);
2724 h1
= c1
.out
.file
.handle
;
2726 /* Second open, triggers lease break to "RH" */
2728 smb2_lease_create(&c2
,
2733 smb2_util_lease_state("RH"));
2735 req
= smb2_create_send(tree2
, &c2
);
2736 torture_assert_not_null_goto(tctx
, req
, ret
, done
,
2737 "smb2_create_send failed\n");
2740 * Check we got the lease break, but defer the ack.
2742 CHECK_BREAK_INFO("RWH", "RH", LEASE1
);
2744 ack
.in
.lease
.lease_key
=
2745 lease_break_info
.lease_break
.current_lease
.lease_key
;
2746 ack
.in
.lease
.lease_state
=
2747 lease_break_info
.lease_break
.new_lease_state
;
2748 torture_reset_lease_break_info(tctx
, &lease_break_info
);
2750 /* Wait for STATUS_PENDING response */
2751 WAIT_FOR_ASYNC_RESPONSE(req
);
2752 torture_assert_goto(tctx
, req
->cancel
.can_cancel
, ret
, done
, "pending");
2754 status
= smb2_lease_break_ack(tree1
, &ack
);
2755 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2756 "smb2_lease_break_ack failed\n");
2757 CHECK_LEASE_BREAK_ACK(&ack
, "RH", LEASE1
);
2760 status
= smb2_create_recv(req
, tree2
, &c2
);
2761 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2762 "smb2_create_recv failed\n");
2763 h2
= c2
.out
.file
.handle
;
2766 if (!smb2_util_handle_empty(h1
)) {
2767 smb2_util_close(tree1
, h1
);
2769 if (!smb2_util_handle_empty(h2
)) {
2770 smb2_util_close(tree2
, h2
);
2773 smb2_util_unlink(tree1
, fname_src
);
2779 * Basic test compound related CREATE+GETINFO+CLOSE where
2780 * the CREATE triggers a lease break. Verifies CREATE sees
2781 * an async interim response.
2783 static bool test_compound_getinfo_middle(struct torture_context
*tctx
,
2784 struct smb2_tree
*tree1
,
2785 struct smb2_tree
*tree2
)
2787 struct smb2_create c1
= {};
2788 struct smb2_create c2
= {};
2789 struct smb2_lease ls1
= {};
2790 struct smb2_handle h1
= {};
2791 struct smb2_request
*req
[3] = {};
2792 union smb_fileinfo info
= {};
2793 struct smb2_getinfo rinfo
= {};
2794 struct smb2_lease_break_ack ack
= {};
2795 struct smb2_close cl
= {};
2796 const char *fname_src
= "test_compound_getinfo_middle.dat";
2801 caps
= smb2cli_conn_server_capabilities(tree1
->session
->transport
->conn
);
2802 if (!(caps
& SMB2_CAP_LEASING
)) {
2803 torture_skip(tctx
, "leases are not supported");
2806 smb2_util_unlink(tree1
, fname_src
);
2808 tree1
->session
->transport
->lease
.handler
= torture_lease_handler
;
2809 tree1
->session
->transport
->lease
.private_data
= tree1
;
2810 torture_reset_lease_break_info(tctx
, &lease_break_info
);
2811 lease_break_info
.lease_skip_ack
= true;
2813 /* First open with a RWH lease. */
2814 smb2_lease_create(&c1
,
2819 smb2_util_lease_state("RWH"));
2821 status
= smb2_create(tree1
, tree1
, &c1
);
2822 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2823 "smb2_create failed\n");
2824 CHECK_LEASE(&c1
, "RWH", true, LEASE1
, 0);
2825 h1
= c1
.out
.file
.handle
;
2827 /* Second open, triggers a lease break */
2829 smb2_transport_compound_start(tree2
->session
->transport
, 3);
2831 smb2_lease_create(&c2
,
2836 smb2_util_lease_state(""));
2837 req
[0] = smb2_create_send(tree2
, &c2
);
2838 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
2839 "smb2_create_send failed\n");
2841 smb2_transport_compound_set_related(tree2
->session
->transport
, true);
2844 info
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2845 info
.generic
.in
.file
.handle
.data
[0] = UINT64_MAX
;
2846 info
.generic
.in
.file
.handle
.data
[0] = UINT64_MAX
;
2847 req
[1] = smb2_getinfo_file_send(tree2
, &info
);
2848 torture_assert(tctx
, req
[1] != NULL
, "smb2_setinfo_file_send");
2850 cl
.in
.file
.handle
.data
[0] = UINT64_MAX
;
2851 cl
.in
.file
.handle
.data
[1] = UINT64_MAX
;
2853 req
[2] = smb2_close_send(tree2
, &cl
);
2854 torture_assert(tctx
, req
[2] != NULL
, "smb2_close_send");
2857 * Check we got the lease break, but defer the ack.
2859 CHECK_BREAK_INFO("RWH", "RH", LEASE1
);
2861 ack
.in
.lease
.lease_key
=
2862 lease_break_info
.lease_break
.current_lease
.lease_key
;
2863 ack
.in
.lease
.lease_state
=
2864 lease_break_info
.lease_break
.new_lease_state
;
2865 torture_reset_lease_break_info(tctx
, &lease_break_info
);
2867 /* Wait for async response */
2868 WAIT_FOR_ASYNC_RESPONSE(req
[0]);
2870 torture_assert_goto(tctx
, req
[0]->state
== SMB2_REQUEST_RECV
, ret
, done
,
2871 "smb2_create finished");
2872 torture_assert_goto(tctx
, req
[1]->state
== SMB2_REQUEST_RECV
, ret
, done
,
2873 "smb2_getinfo finished");
2874 torture_assert_goto(tctx
, req
[2]->state
== SMB2_REQUEST_RECV
, ret
, done
,
2875 "smb2_close finished");
2876 torture_assert_goto(tctx
, req
[0]->cancel
.can_cancel
, ret
, done
, "pending");
2877 torture_assert_goto(tctx
, !req
[1]->cancel
.can_cancel
, ret
, done
, "pending");
2878 torture_assert_goto(tctx
, !req
[2]->cancel
.can_cancel
, ret
, done
, "pending");
2880 status
= smb2_lease_break_ack(tree1
, &ack
);
2881 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2882 "smb2_lease_break_ack failed\n");
2883 CHECK_LEASE_BREAK_ACK(&ack
, "RH", LEASE1
);
2885 status
= smb2_create_recv(req
[0], tree2
, &c2
);
2886 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2887 "smb2_create_recv failed\n");
2889 status
= smb2_getinfo_recv(req
[1], tree2
, &rinfo
);
2890 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2891 "smb2_getinfo_recv failed\n");
2893 status
= smb2_close_recv(req
[2], &cl
);
2894 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2895 "smb2_close_recv failed\n");
2898 if (!smb2_util_handle_empty(h1
)) {
2899 smb2_util_close(tree1
, h1
);
2901 smb2_util_unlink(tree1
, fname_src
);
2907 * Checks a lease break by a rename where src and dst name are the same does not
2908 * trigger a pending async response, but does trigger a h-lease break.
2910 static bool test_rename_same_srcdst_non_compound_no_async(
2911 struct torture_context
*tctx
,
2912 struct smb2_tree
*tree1
,
2913 struct smb2_tree
*tree2
)
2915 struct smb2_create c1
= {};
2916 struct smb2_create c2
= {};
2917 struct smb2_lease ls1
= {};
2918 struct smb2_lease ls2
= {};
2919 struct smb2_handle h1
= {};
2920 struct smb2_handle h2
= {};
2921 struct smb2_request
*req
= NULL
;
2922 struct smb2_lease_break_ack ack
= {};
2923 union smb_setfileinfo sinfo
= {};
2924 const char *fname_src
= "test_rename_non_compound_no_async.dat";
2925 const char *fname_dst
= "test_rename_non_compound_no_async.dat";
2930 caps
= smb2cli_conn_server_capabilities(tree1
->session
->transport
->conn
);
2931 if (!(caps
& SMB2_CAP_LEASING
)) {
2932 torture_skip(tctx
, "leases are not supported");
2935 smb2_util_unlink(tree1
, fname_src
);
2936 smb2_util_unlink(tree1
, fname_dst
);
2938 tree1
->session
->transport
->lease
.handler
= torture_lease_handler
;
2939 tree1
->session
->transport
->lease
.private_data
= tree1
;
2940 torture_reset_lease_break_info(tctx
, &lease_break_info
);
2941 lease_break_info
.lease_skip_ack
= true;
2943 /* First open with a RH lease. */
2944 smb2_lease_create(&c1
,
2949 smb2_util_lease_state("RH"));
2951 status
= smb2_create(tree1
, tree1
, &c1
);
2952 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2953 "smb2_create failed\n");
2954 CHECK_LEASE(&c1
, "RH", true, LEASE1
, 0);
2955 h1
= c1
.out
.file
.handle
;
2957 /* Second open, also with a RH lease, this will do the rename */
2959 smb2_lease_create(&c2
,
2964 smb2_util_lease_state("RH"));
2965 status
= smb2_create(tree2
, tree2
, &c2
);
2966 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2967 "smb2_create failed\n");
2968 CHECK_LEASE(&c2
, "RH", true, LEASE2
, 0);
2969 h2
= c2
.out
.file
.handle
;
2971 /* Break with a rename. */
2972 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
2973 sinfo
.rename_information
.in
.file
.handle
= h2
;
2974 sinfo
.rename_information
.in
.new_name
= fname_dst
;
2975 req
= smb2_setinfo_file_send(tree2
, &sinfo
);
2976 torture_assert(tctx
, req
!= NULL
, "smb2_setinfo_file_send");
2979 * Check we got the lease break, but defer the ack.
2981 CHECK_BREAK_INFO("RH", "R", LEASE1
);
2983 ack
.in
.lease
.lease_key
=
2984 lease_break_info
.lease_break
.current_lease
.lease_key
;
2985 ack
.in
.lease
.lease_state
=
2986 lease_break_info
.lease_break
.new_lease_state
;
2987 torture_reset_lease_break_info(tctx
, &lease_break_info
);
2989 /* Give the server enough time to possibly send a pending response */
2992 status
= smb2_lease_break_ack(tree1
, &ack
);
2993 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2994 "smb2_lease_break_ack failed\n");
2995 CHECK_LEASE_BREAK_ACK(&ack
, "R", LEASE1
);
2998 * Sending the lease break ACK would have also read the
2999 * NT_STATUS_PENDING interim response if any, but a Windows server
3000 * doesn't send one, check this. This is in contract to a lease break
3001 * triggered by an SMB2-CREATE.
3003 torture_assert_goto(tctx
, !req
->cancel
.can_cancel
, ret
, done
, "pending");
3005 /* Get the rename reply. */
3006 status
= smb2_setinfo_recv(req
);
3007 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3008 "smb2_setinfo_recv failed\n");
3011 if (!smb2_util_handle_empty(h1
)) {
3012 smb2_util_close(tree1
, h1
);
3014 if (!smb2_util_handle_empty(h2
)) {
3015 smb2_util_close(tree2
, h2
);
3018 smb2_util_unlink(tree1
, fname_src
);
3019 smb2_util_unlink(tree1
, fname_dst
);
3025 * Checks a lease break by a rename does not trigger a pending async response.
3027 static bool test_rename_non_compound_no_async(struct torture_context
*tctx
,
3028 struct smb2_tree
*tree1
,
3029 struct smb2_tree
*tree2
)
3031 struct smb2_create c1
= {};
3032 struct smb2_create c2
= {};
3033 struct smb2_lease ls1
= {};
3034 struct smb2_lease ls2
= {};
3035 struct smb2_handle h1
= {};
3036 struct smb2_handle h2
= {};
3037 struct smb2_request
*req
= NULL
;
3038 struct smb2_lease_break_ack ack
= {};
3039 union smb_setfileinfo sinfo
= {};
3040 const char *fname_src
= "test_rename_non_compound_no_async_src.dat";
3041 const char *fname_dst
= "test_rename_non_compound_no_async_dst.dat";
3046 caps
= smb2cli_conn_server_capabilities(tree1
->session
->transport
->conn
);
3047 if (!(caps
& SMB2_CAP_LEASING
)) {
3048 torture_skip(tctx
, "leases are not supported");
3051 smb2_util_unlink(tree1
, fname_src
);
3052 smb2_util_unlink(tree1
, fname_dst
);
3054 tree1
->session
->transport
->lease
.handler
= torture_lease_handler
;
3055 tree1
->session
->transport
->lease
.private_data
= tree1
;
3056 torture_reset_lease_break_info(tctx
, &lease_break_info
);
3057 lease_break_info
.lease_skip_ack
= true;
3059 /* First open with a RH lease. */
3060 smb2_lease_create(&c1
,
3065 smb2_util_lease_state("RH"));
3067 status
= smb2_create(tree1
, tree1
, &c1
);
3068 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3069 "smb2_create failed\n");
3070 CHECK_LEASE(&c1
, "RH", true, LEASE1
, 0);
3071 h1
= c1
.out
.file
.handle
;
3073 /* Second open, also with a RH lease, this will to the rename */
3075 smb2_lease_create(&c2
,
3080 smb2_util_lease_state("RH"));
3081 status
= smb2_create(tree2
, tree2
, &c2
);
3082 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3083 "smb2_create failed\n");
3084 CHECK_LEASE(&c2
, "RH", true, LEASE2
, 0);
3085 h2
= c2
.out
.file
.handle
;
3087 /* Break with a rename. */
3088 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
3089 sinfo
.rename_information
.in
.file
.handle
= h2
;
3090 sinfo
.rename_information
.in
.new_name
= fname_dst
;
3091 req
= smb2_setinfo_file_send(tree2
, &sinfo
);
3092 torture_assert(tctx
, req
!= NULL
, "smb2_setinfo_file_send");
3095 * Check we got the lease break, but defer the ack.
3097 CHECK_BREAK_INFO("RH", "R", LEASE1
);
3099 ack
.in
.lease
.lease_key
=
3100 lease_break_info
.lease_break
.current_lease
.lease_key
;
3101 ack
.in
.lease
.lease_state
=
3102 lease_break_info
.lease_break
.new_lease_state
;
3103 torture_reset_lease_break_info(tctx
, &lease_break_info
);
3105 /* Give the server enough time to possibly send a pending response */
3108 status
= smb2_lease_break_ack(tree1
, &ack
);
3109 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3110 "smb2_lease_break_ack failed\n");
3111 CHECK_LEASE_BREAK_ACK(&ack
, "R", LEASE1
);
3114 * Sending the lease break ACK would have also read the
3115 * NT_STATUS_PENDING interim response if any, but a Windows server
3116 * doesn't send one, check this. This is in contract to a lease break
3117 * triggered by an SMB2-CREATE.
3119 torture_assert_goto(tctx
, !req
->cancel
.can_cancel
, ret
, done
, "pending");
3121 /* Get the rename reply. */
3122 status
= smb2_setinfo_recv(req
);
3123 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3124 "smb2_setinfo_recv failed\n");
3127 if (!smb2_util_handle_empty(h1
)) {
3128 smb2_util_close(tree1
, h1
);
3130 if (!smb2_util_handle_empty(h2
)) {
3131 smb2_util_close(tree2
, h2
);
3134 smb2_util_unlink(tree1
, fname_src
);
3135 smb2_util_unlink(tree1
, fname_dst
);
3141 * Test a compound SMB2-CREATE+SMB2-SETINFO(rename) works and doesn't trigger a
3142 * pending async response.
3144 static bool test_compound_rename_last(struct torture_context
*tctx
,
3145 struct smb2_tree
*tree1
,
3146 struct smb2_tree
*tree2
)
3148 struct smb2_create c1
= {};
3149 struct smb2_create c2
= {};
3150 struct smb2_lease ls1
= {};
3151 struct smb2_lease ls2
= {};
3152 struct smb2_handle h1
= {};
3153 struct smb2_handle h2
= {};
3154 struct smb2_request
*req
[2] = {};
3155 union smb_setfileinfo sinfo
= {};
3156 struct smb2_lease_break_ack ack
= {};
3157 const char *fname_src
= "test_compound_rename_last_src.dat";
3158 const char *fname_dst
= "test_compound_rename_last_dst.dat";
3163 caps
= smb2cli_conn_server_capabilities(tree1
->session
->transport
->conn
);
3164 if (!(caps
& SMB2_CAP_LEASING
)) {
3165 torture_skip(tctx
, "leases are not supported");
3168 smb2_util_unlink(tree1
, fname_src
);
3169 smb2_util_unlink(tree1
, fname_dst
);
3171 tree1
->session
->transport
->lease
.handler
= torture_lease_handler
;
3172 tree1
->session
->transport
->lease
.private_data
= tree1
;
3173 torture_reset_lease_break_info(tctx
, &lease_break_info
);
3174 lease_break_info
.lease_skip_ack
= true;
3176 /* First open with a RH lease. */
3177 smb2_lease_create(&c1
,
3182 smb2_util_lease_state("RH"));
3184 status
= smb2_create(tree1
, tree1
, &c1
);
3185 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3186 "smb2_create failed\n");
3187 CHECK_LEASE(&c1
, "RH", true, LEASE1
, 0);
3188 h1
= c1
.out
.file
.handle
;
3190 /* Second open, also with a RH lease, this will to the rename */
3192 smb2_transport_compound_start(tree2
->session
->transport
, 2);
3194 smb2_lease_create(&c2
,
3199 smb2_util_lease_state(""));
3200 req
[0] = smb2_create_send(tree2
, &c2
);
3201 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
3202 "smb2_create_send failed\n");
3204 smb2_transport_compound_set_related(tree2
->session
->transport
, true);
3206 /* Break with a rename. */
3207 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
3208 sinfo
.rename_information
.in
.file
.handle
.data
[0] = UINT64_MAX
;
3209 sinfo
.rename_information
.in
.file
.handle
.data
[1] = UINT64_MAX
;
3210 sinfo
.rename_information
.in
.new_name
= fname_dst
;
3211 req
[1] = smb2_setinfo_file_send(tree2
, &sinfo
);
3212 torture_assert(tctx
, req
[1] != NULL
, "smb2_setinfo_file_send");
3215 * Check we got the lease break, but defer the ack.
3217 CHECK_BREAK_INFO("RH", "R", LEASE1
);
3219 ack
.in
.lease
.lease_key
=
3220 lease_break_info
.lease_break
.current_lease
.lease_key
;
3221 ack
.in
.lease
.lease_state
=
3222 lease_break_info
.lease_break
.new_lease_state
;
3223 torture_reset_lease_break_info(tctx
, &lease_break_info
);
3225 /* Give the server enough time to possibly send a pending response */
3228 status
= smb2_lease_break_ack(tree1
, &ack
);
3229 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3230 "smb2_lease_break_ack failed\n");
3231 CHECK_LEASE_BREAK_ACK(&ack
, "R", LEASE1
);
3234 * Sending the lease break ACK would have also read the
3235 * NT_STATUS_PENDING interim response if any, but a Windows server
3236 * doesn't send one, check this. This is in contract to a lease break
3237 * triggered by an SMB2-CREATE.
3239 torture_assert_goto(tctx
, req
[0]->state
== SMB2_REQUEST_RECV
, ret
, done
,
3240 "state not SMB2_REQUEST_RECV");
3241 torture_assert_goto(tctx
, req
[1]->state
== SMB2_REQUEST_RECV
, ret
, done
,
3242 "state not SMB2_REQUEST_RECV");
3243 torture_assert_goto(tctx
, !req
[1]->cancel
.can_cancel
, ret
, done
, "pending");
3245 status
= smb2_create_recv(req
[0], tree2
, &c2
);
3246 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3247 "smb2_setinfo_recv failed\n");
3248 h2
= c2
.out
.file
.handle
;
3250 /* Get the rename reply. */
3251 status
= smb2_setinfo_recv(req
[1]);
3252 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3253 "smb2_setinfo_recv failed\n");
3256 if (!smb2_util_handle_empty(h1
)) {
3257 smb2_util_close(tree1
, h1
);
3259 if (!smb2_util_handle_empty(h2
)) {
3260 smb2_util_close(tree2
, h2
);
3263 smb2_util_unlink(tree1
, fname_src
);
3264 smb2_util_unlink(tree1
, fname_dst
);
3270 * Compound related CREATE + SETINFO(rename) + CLOSE, rename triggers a lease
3271 * break. Verify we don't get an async interim response for the SETINFO and all
3272 * responses are received in a single compound response.
3274 static bool test_compound_rename_middle(struct torture_context
*tctx
,
3275 struct smb2_tree
*tree1
,
3276 struct smb2_tree
*tree2
)
3278 struct smb2_create c1
= {};
3279 struct smb2_create c2
= {};
3280 struct smb2_lease ls1
= {};
3281 struct smb2_handle h1
= {};
3282 struct smb2_request
*req
[3] = {};
3283 union smb_setfileinfo sinfo
= {};
3284 struct smb2_lease_break_ack ack
= {};
3285 struct smb2_close cl
= {};
3286 const char *fname_src
= "test_compound_rename_middle_src.dat";
3287 const char *fname_dst
= "test_compound_rename_middle_dst.dat";
3292 caps
= smb2cli_conn_server_capabilities(tree1
->session
->transport
->conn
);
3293 if (!(caps
& SMB2_CAP_LEASING
)) {
3294 torture_skip(tctx
, "leases are not supported");
3297 smb2_util_unlink(tree1
, fname_src
);
3298 smb2_util_unlink(tree1
, fname_dst
);
3300 tree1
->session
->transport
->lease
.handler
= torture_lease_handler
;
3301 tree1
->session
->transport
->lease
.private_data
= tree1
;
3302 torture_reset_lease_break_info(tctx
, &lease_break_info
);
3303 lease_break_info
.lease_skip_ack
= true;
3305 /* First open with a RH lease. */
3306 smb2_lease_create(&c1
,
3311 smb2_util_lease_state("RH"));
3313 status
= smb2_create(tree1
, tree1
, &c1
);
3314 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3315 "smb2_create failed\n");
3316 CHECK_LEASE(&c1
, "RH", true, LEASE1
, 0);
3317 h1
= c1
.out
.file
.handle
;
3319 /* Second open, this will to the rename */
3321 smb2_transport_compound_start(tree2
->session
->transport
, 3);
3323 smb2_lease_create(&c2
,
3328 smb2_util_lease_state(""));
3329 req
[0] = smb2_create_send(tree2
, &c2
);
3330 torture_assert_not_null_goto(tctx
, req
[0], ret
, done
,
3331 "smb2_create_send failed\n");
3333 smb2_transport_compound_set_related(tree2
->session
->transport
, true);
3335 /* Break with a rename. */
3336 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
3337 sinfo
.rename_information
.in
.file
.handle
.data
[0] = UINT64_MAX
;
3338 sinfo
.rename_information
.in
.file
.handle
.data
[1] = UINT64_MAX
;
3339 sinfo
.rename_information
.in
.new_name
= fname_dst
;
3340 req
[1] = smb2_setinfo_file_send(tree2
, &sinfo
);
3341 torture_assert(tctx
, req
[1] != NULL
, "smb2_setinfo_file_send");
3343 cl
.in
.file
.handle
.data
[0] = UINT64_MAX
;
3344 cl
.in
.file
.handle
.data
[1] = UINT64_MAX
;
3346 req
[2] = smb2_close_send(tree2
, &cl
);
3347 torture_assert(tctx
, req
[2] != NULL
, "smb2_close_send");
3349 /* Give the server enough time to possibly send a pending response */
3353 * Check we got the lease break, but defer the ack.
3355 CHECK_BREAK_INFO("RH", "R", LEASE1
);
3357 ack
.in
.lease
.lease_key
=
3358 lease_break_info
.lease_break
.current_lease
.lease_key
;
3359 ack
.in
.lease
.lease_state
=
3360 lease_break_info
.lease_break
.new_lease_state
;
3361 torture_reset_lease_break_info(tctx
, &lease_break_info
);
3363 torture_assert_goto(tctx
, !req
[0]->cancel
.can_cancel
, ret
, done
, "pending");
3364 torture_assert_goto(tctx
, !req
[1]->cancel
.can_cancel
, ret
, done
, "pending");
3365 torture_assert_goto(tctx
, !req
[2]->cancel
.can_cancel
, ret
, done
, "pending");
3366 torture_assert_goto(tctx
, req
[0]->state
== SMB2_REQUEST_RECV
, ret
, done
,
3367 "state not SMB2_REQUEST_RECV");
3368 torture_assert_goto(tctx
, req
[1]->state
== SMB2_REQUEST_RECV
, ret
, done
,
3369 "state not SMB2_REQUEST_RECV");
3370 torture_assert_goto(tctx
, req
[2]->state
== SMB2_REQUEST_RECV
, ret
, done
,
3371 "state not SMB2_REQUEST_RECV");
3373 status
= smb2_lease_break_ack(tree1
, &ack
);
3374 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3375 "smb2_lease_break_ack failed\n");
3376 CHECK_LEASE_BREAK_ACK(&ack
, "R", LEASE1
);
3379 status
= smb2_create_recv(req
[0], tree2
, &c2
);
3380 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3381 "smb2_setinfo_recv failed\n");
3383 /* Get the rename reply. */
3384 status
= smb2_setinfo_recv(req
[1]);
3385 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3386 "smb2_setinfo_recv failed\n");
3388 status
= smb2_close_recv(req
[2], &cl
);
3389 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3390 "smb2_setinfo_recv failed\n");
3393 if (!smb2_util_handle_empty(h1
)) {
3394 smb2_util_close(tree1
, h1
);
3397 smb2_util_unlink(tree1
, fname_src
);
3398 smb2_util_unlink(tree1
, fname_dst
);
3403 struct torture_suite
*torture_smb2_compound_init(TALLOC_CTX
*ctx
)
3405 struct torture_suite
*suite
= torture_suite_create(ctx
, "compound");
3407 torture_suite_add_1smb2_test(suite
, "related1", test_compound_related1
);
3408 torture_suite_add_1smb2_test(suite
, "related2", test_compound_related2
);
3409 torture_suite_add_1smb2_test(suite
, "related3",
3410 test_compound_related3
);
3411 torture_suite_add_1smb2_test(suite
, "related4",
3412 test_compound_related4
);
3413 torture_suite_add_1smb2_test(suite
, "related5",
3414 test_compound_related5
);
3415 torture_suite_add_1smb2_test(suite
, "related6",
3416 test_compound_related6
);
3417 torture_suite_add_1smb2_test(suite
, "related7",
3418 test_compound_related7
);
3419 torture_suite_add_1smb2_test(suite
, "related8",
3420 test_compound_related8
);
3421 torture_suite_add_1smb2_test(suite
, "related9",
3422 test_compound_related9
);
3423 torture_suite_add_1smb2_test(suite
, "unrelated1", test_compound_unrelated1
);
3424 torture_suite_add_1smb2_test(suite
, "invalid1", test_compound_invalid1
);
3425 torture_suite_add_1smb2_test(suite
, "invalid2", test_compound_invalid2
);
3426 torture_suite_add_1smb2_test(suite
, "invalid3", test_compound_invalid3
);
3427 torture_suite_add_1smb2_test(
3428 suite
, "invalid4", test_compound_invalid4
);
3429 torture_suite_add_1smb2_test(suite
, "interim1", test_compound_interim1
);
3430 torture_suite_add_1smb2_test(suite
, "interim2", test_compound_interim2
);
3431 torture_suite_add_1smb2_test(suite
, "interim3", test_compound_interim3
);
3432 torture_suite_add_1smb2_test(suite
, "compound-break", test_compound_break
);
3433 torture_suite_add_1smb2_test(suite
, "compound-padding", test_compound_padding
);
3434 torture_suite_add_1smb2_test(suite
, "create-write-close",
3435 test_compound_create_write_close
);
3437 suite
->description
= talloc_strdup(suite
, "SMB2-COMPOUND tests");
3442 struct torture_suite
*torture_smb2_compound_find_init(TALLOC_CTX
*ctx
)
3444 struct torture_suite
*suite
= torture_suite_create(ctx
, "compound_find");
3446 torture_suite_add_1smb2_test(suite
, "compound_find_related", test_compound_find_related
);
3447 torture_suite_add_1smb2_test(suite
, "compound_find_unrelated", test_compound_find_unrelated
);
3448 torture_suite_add_1smb2_test(suite
, "compound_find_close", test_compound_find_close
);
3450 suite
->description
= talloc_strdup(suite
, "SMB2-COMPOUND-FIND tests");
3455 struct torture_suite
*torture_smb2_compound_async_init(TALLOC_CTX
*ctx
)
3457 struct torture_suite
*suite
= torture_suite_create(ctx
,
3460 torture_suite_add_1smb2_test(suite
, "flush_close",
3461 test_compound_async_flush_close
);
3462 torture_suite_add_1smb2_test(suite
, "flush_flush",
3463 test_compound_async_flush_flush
);
3464 torture_suite_add_1smb2_test(suite
, "write_write",
3465 test_compound_async_write_write
);
3466 torture_suite_add_1smb2_test(suite
, "read_read",
3467 test_compound_async_read_read
);
3468 torture_suite_add_2smb2_test(suite
, "create_lease_break_async",
3469 test_create_lease_break_async
);
3470 torture_suite_add_2smb2_test(suite
, "getinfo_middle",
3471 test_compound_getinfo_middle
);
3472 torture_suite_add_2smb2_test(suite
, "rename_same_srcdst_non_compound_no_async",
3473 test_rename_same_srcdst_non_compound_no_async
);
3474 torture_suite_add_2smb2_test(suite
, "rename_non_compound_no_async",
3475 test_rename_non_compound_no_async
);
3476 torture_suite_add_2smb2_test(suite
, "rename_last",
3477 test_compound_rename_last
);
3478 torture_suite_add_2smb2_test(suite
, "rename_middle",
3479 test_compound_rename_middle
);
3481 suite
->description
= talloc_strdup(suite
, "SMB2-COMPOUND-ASYNC tests");