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