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