s4-smbtorture: Make test names lowercase and dot-separated.
[sfrench/samba-autobuild/.git] / source4 / torture / smb2 / compound.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    test suite for SMB2 compounded requests
5
6    Copyright (C) Stefan Metzmacher 2009
7
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.
12
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.
17
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/>.
20 */
21
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
28 #define CHECK_STATUS(status, correct) do { \
29         if (!NT_STATUS_EQUAL(status, correct)) { \
30                 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
31                        nt_errstr(status), nt_errstr(correct)); \
32                 ret = false; \
33                 goto done; \
34         }} while (0)
35
36 #define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
37 #define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
38
39 static bool test_compound_related1(struct torture_context *tctx,
40                                    struct smb2_tree *tree)
41 {
42         struct smb2_handle hd;
43         struct smb2_create cr;
44         NTSTATUS status;
45         const char *fname = "compound_related1.dat";
46         struct smb2_close cl;
47         bool ret = true;
48         struct smb2_request *req[2];
49         uint32_t saved_tid = tree->tid;
50         uint64_t saved_uid = tree->session->uid;
51
52         smb2_transport_credits_ask_num(tree->session->transport, 2);
53
54         smb2_util_unlink(tree, fname);
55
56         smb2_transport_credits_ask_num(tree->session->transport, 1);
57
58         ZERO_STRUCT(cr);
59         cr.in.security_flags            = 0x00;
60         cr.in.oplock_level              = 0;
61         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
62         cr.in.create_flags              = 0x00000000;
63         cr.in.reserved                  = 0x00000000;
64         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
65         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
66         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
67                                           NTCREATEX_SHARE_ACCESS_WRITE |
68                                           NTCREATEX_SHARE_ACCESS_DELETE;
69         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
70         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
71                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
72                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
73                                           0x00200000;
74         cr.in.fname                     = fname;
75
76         smb2_transport_compound_start(tree->session->transport, 2);
77
78         req[0] = smb2_create_send(tree, &cr);
79
80         smb2_transport_compound_set_related(tree->session->transport, true);
81
82         hd.data[0] = UINT64_MAX;
83         hd.data[1] = UINT64_MAX;
84
85         ZERO_STRUCT(cl);
86         cl.in.file.handle = hd;
87
88         tree->tid = 0xFFFFFFFF;
89         tree->session->uid = UINT64_MAX;
90
91         req[1] = smb2_close_send(tree, &cl);
92
93         status = smb2_create_recv(req[0], tree, &cr);
94         CHECK_STATUS(status, NT_STATUS_OK);
95         status = smb2_close_recv(req[1], &cl);
96         CHECK_STATUS(status, NT_STATUS_OK);
97
98         tree->tid = saved_tid;
99         tree->session->uid = saved_uid;
100
101         smb2_util_unlink(tree, fname);
102 done:
103         return ret;
104 }
105
106 static bool test_compound_related2(struct torture_context *tctx,
107                                    struct smb2_tree *tree)
108 {
109         struct smb2_handle hd;
110         struct smb2_create cr;
111         NTSTATUS status;
112         const char *fname = "compound_related2.dat";
113         struct smb2_close cl;
114         bool ret = true;
115         struct smb2_request *req[5];
116         uint32_t saved_tid = tree->tid;
117         uint64_t saved_uid = tree->session->uid;
118
119         smb2_transport_credits_ask_num(tree->session->transport, 5);
120
121         smb2_util_unlink(tree, fname);
122
123         smb2_transport_credits_ask_num(tree->session->transport, 1);
124
125         ZERO_STRUCT(cr);
126         cr.in.security_flags            = 0x00;
127         cr.in.oplock_level              = 0;
128         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
129         cr.in.create_flags              = 0x00000000;
130         cr.in.reserved                  = 0x00000000;
131         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
132         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
133         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
134                                           NTCREATEX_SHARE_ACCESS_WRITE |
135                                           NTCREATEX_SHARE_ACCESS_DELETE;
136         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
137         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
138                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
139                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
140                                           0x00200000;
141         cr.in.fname                     = fname;
142
143         smb2_transport_compound_start(tree->session->transport, 5);
144
145         req[0] = smb2_create_send(tree, &cr);
146
147         hd.data[0] = UINT64_MAX;
148         hd.data[1] = UINT64_MAX;
149
150         smb2_transport_compound_set_related(tree->session->transport, true);
151
152         ZERO_STRUCT(cl);
153         cl.in.file.handle = hd;
154         tree->tid = 0xFFFFFFFF;
155         tree->session->uid = UINT64_MAX;
156
157         req[1] = smb2_close_send(tree, &cl);
158         req[2] = smb2_close_send(tree, &cl);
159         req[3] = smb2_close_send(tree, &cl);
160         req[4] = smb2_close_send(tree, &cl);
161
162         status = smb2_create_recv(req[0], tree, &cr);
163         CHECK_STATUS(status, NT_STATUS_OK);
164         status = smb2_close_recv(req[1], &cl);
165         CHECK_STATUS(status, NT_STATUS_OK);
166         status = smb2_close_recv(req[2], &cl);
167         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
168         status = smb2_close_recv(req[3], &cl);
169         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
170         status = smb2_close_recv(req[4], &cl);
171         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
172
173         tree->tid = saved_tid;
174         tree->session->uid = saved_uid;
175
176         smb2_util_unlink(tree, fname);
177 done:
178         return ret;
179 }
180
181 static bool test_compound_unrelated1(struct torture_context *tctx,
182                                      struct smb2_tree *tree)
183 {
184         struct smb2_handle hd;
185         struct smb2_create cr;
186         NTSTATUS status;
187         const char *fname = "compound_unrelated1.dat";
188         struct smb2_close cl;
189         bool ret = true;
190         struct smb2_request *req[5];
191
192         smb2_transport_credits_ask_num(tree->session->transport, 5);
193
194         smb2_util_unlink(tree, fname);
195
196         smb2_transport_credits_ask_num(tree->session->transport, 1);
197
198         ZERO_STRUCT(cr);
199         cr.in.security_flags            = 0x00;
200         cr.in.oplock_level              = 0;
201         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
202         cr.in.create_flags              = 0x00000000;
203         cr.in.reserved                  = 0x00000000;
204         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
205         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
206         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
207                                           NTCREATEX_SHARE_ACCESS_WRITE |
208                                           NTCREATEX_SHARE_ACCESS_DELETE;
209         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
210         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
211                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
212                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
213                                           0x00200000;
214         cr.in.fname                     = fname;
215
216         smb2_transport_compound_start(tree->session->transport, 5);
217
218         req[0] = smb2_create_send(tree, &cr);
219
220         hd.data[0] = UINT64_MAX;
221         hd.data[1] = UINT64_MAX;
222
223         ZERO_STRUCT(cl);
224         cl.in.file.handle = hd;
225         req[1] = smb2_close_send(tree, &cl);
226         req[2] = smb2_close_send(tree, &cl);
227         req[3] = smb2_close_send(tree, &cl);
228         req[4] = smb2_close_send(tree, &cl);
229
230         status = smb2_create_recv(req[0], tree, &cr);
231         CHECK_STATUS(status, NT_STATUS_OK);
232         status = smb2_close_recv(req[1], &cl);
233         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
234         status = smb2_close_recv(req[2], &cl);
235         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
236         status = smb2_close_recv(req[3], &cl);
237         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
238         status = smb2_close_recv(req[4], &cl);
239         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
240
241         smb2_util_unlink(tree, fname);
242 done:
243         return ret;
244 }
245
246 static bool test_compound_invalid1(struct torture_context *tctx,
247                                    struct smb2_tree *tree)
248 {
249         struct smb2_handle hd;
250         struct smb2_create cr;
251         NTSTATUS status;
252         const char *fname = "compound_invalid1.dat";
253         struct smb2_close cl;
254         bool ret = true;
255         struct smb2_request *req[2];
256
257         smb2_transport_credits_ask_num(tree->session->transport, 2);
258
259         smb2_util_unlink(tree, fname);
260
261         smb2_transport_credits_ask_num(tree->session->transport, 1);
262
263         ZERO_STRUCT(cr);
264         cr.in.security_flags            = 0x00;
265         cr.in.oplock_level              = 0;
266         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
267         cr.in.create_flags              = 0x00000000;
268         cr.in.reserved                  = 0x00000000;
269         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
270         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
271         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
272                                           NTCREATEX_SHARE_ACCESS_WRITE |
273                                           NTCREATEX_SHARE_ACCESS_DELETE;
274         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
275         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
276                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
277                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
278                                           0x00200000;
279         cr.in.fname                     = fname;
280
281         smb2_transport_compound_start(tree->session->transport, 2);
282
283         /* passing the first request with the related flag is invalid */
284         smb2_transport_compound_set_related(tree->session->transport, true);
285
286         req[0] = smb2_create_send(tree, &cr);
287
288         hd.data[0] = UINT64_MAX;
289         hd.data[1] = UINT64_MAX;
290
291         ZERO_STRUCT(cl);
292         cl.in.file.handle = hd;
293         req[1] = smb2_close_send(tree, &cl);
294
295         status = smb2_create_recv(req[0], tree, &cr);
296         /* TODO: check why this fails with --signing=required */
297         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
298         status = smb2_close_recv(req[1], &cl);
299         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
300
301         smb2_util_unlink(tree, fname);
302 done:
303         return ret;
304 }
305
306 static bool test_compound_invalid2(struct torture_context *tctx,
307                                    struct smb2_tree *tree)
308 {
309         struct smb2_handle hd;
310         struct smb2_create cr;
311         NTSTATUS status;
312         const char *fname = "compound_invalid2.dat";
313         struct smb2_close cl;
314         bool ret = true;
315         struct smb2_request *req[5];
316         uint32_t saved_tid = tree->tid;
317         uint64_t saved_uid = tree->session->uid;
318
319         smb2_transport_credits_ask_num(tree->session->transport, 5);
320
321         smb2_util_unlink(tree, fname);
322
323         smb2_transport_credits_ask_num(tree->session->transport, 1);
324
325         ZERO_STRUCT(cr);
326         cr.in.security_flags            = 0x00;
327         cr.in.oplock_level              = 0;
328         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
329         cr.in.create_flags              = 0x00000000;
330         cr.in.reserved                  = 0x00000000;
331         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
332         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
333         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
334                                           NTCREATEX_SHARE_ACCESS_WRITE |
335                                           NTCREATEX_SHARE_ACCESS_DELETE;
336         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
337         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
338                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
339                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
340                                           0x00200000;
341         cr.in.fname                     = fname;
342
343         smb2_transport_compound_start(tree->session->transport, 5);
344
345         req[0] = smb2_create_send(tree, &cr);
346
347         hd.data[0] = UINT64_MAX;
348         hd.data[1] = UINT64_MAX;
349
350         smb2_transport_compound_set_related(tree->session->transport, true);
351
352         ZERO_STRUCT(cl);
353         cl.in.file.handle = hd;
354         tree->tid = 0xFFFFFFFF;
355         tree->session->uid = UINT64_MAX;
356
357         req[1] = smb2_close_send(tree, &cl);
358         /* strange that this is not generating invalid parameter */
359         smb2_transport_compound_set_related(tree->session->transport, false);
360         req[2] = smb2_close_send(tree, &cl);
361         req[3] = smb2_close_send(tree, &cl);
362         smb2_transport_compound_set_related(tree->session->transport, true);
363         req[4] = smb2_close_send(tree, &cl);
364
365         status = smb2_create_recv(req[0], tree, &cr);
366         CHECK_STATUS(status, NT_STATUS_OK);
367         status = smb2_close_recv(req[1], &cl);
368         CHECK_STATUS(status, NT_STATUS_OK);
369         status = smb2_close_recv(req[2], &cl);
370         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
371         status = smb2_close_recv(req[3], &cl);
372         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
373         status = smb2_close_recv(req[4], &cl);
374         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
375
376         tree->tid = saved_tid;
377         tree->session->uid = saved_uid;
378
379         smb2_util_unlink(tree, fname);
380 done:
381         return ret;
382 }
383
384 static bool test_compound_invalid3(struct torture_context *tctx,
385                                    struct smb2_tree *tree)
386 {
387         struct smb2_handle hd;
388         struct smb2_create cr;
389         NTSTATUS status;
390         const char *fname = "compound_invalid3.dat";
391         struct smb2_close cl;
392         bool ret = true;
393         struct smb2_request *req[5];
394
395         smb2_transport_credits_ask_num(tree->session->transport, 5);
396
397         smb2_util_unlink(tree, fname);
398
399         smb2_transport_credits_ask_num(tree->session->transport, 1);
400
401         ZERO_STRUCT(cr);
402         cr.in.security_flags            = 0x00;
403         cr.in.oplock_level              = 0;
404         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
405         cr.in.create_flags              = 0x00000000;
406         cr.in.reserved                  = 0x00000000;
407         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
408         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
409         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
410                                           NTCREATEX_SHARE_ACCESS_WRITE |
411                                           NTCREATEX_SHARE_ACCESS_DELETE;
412         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
413         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
414                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
415                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
416                                           0x00200000;
417         cr.in.fname                     = fname;
418
419         smb2_transport_compound_start(tree->session->transport, 5);
420
421         req[0] = smb2_create_send(tree, &cr);
422
423         hd.data[0] = UINT64_MAX;
424         hd.data[1] = UINT64_MAX;
425
426         ZERO_STRUCT(cl);
427         cl.in.file.handle = hd;
428         req[1] = smb2_close_send(tree, &cl);
429         req[2] = smb2_close_send(tree, &cl);
430         /* flipping the related flag is invalid */
431         smb2_transport_compound_set_related(tree->session->transport, true);
432         req[3] = smb2_close_send(tree, &cl);
433         req[4] = smb2_close_send(tree, &cl);
434
435         status = smb2_create_recv(req[0], tree, &cr);
436         CHECK_STATUS(status, NT_STATUS_OK);
437         status = smb2_close_recv(req[1], &cl);
438         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
439         status = smb2_close_recv(req[2], &cl);
440         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
441         status = smb2_close_recv(req[3], &cl);
442         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
443         status = smb2_close_recv(req[4], &cl);
444         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
445
446         smb2_util_unlink(tree, fname);
447 done:
448         return ret;
449 }
450
451 /* Send a compound request where we expect the last request (Create, Notify)
452  * to go asynchronous. This works against a Win7 server and the reply is
453  * sent in two different packets. */
454 static bool test_compound_interim1(struct torture_context *tctx,
455                                    struct smb2_tree *tree)
456 {
457     struct smb2_handle hd;
458     struct smb2_create cr;
459     NTSTATUS status = NT_STATUS_OK;
460     const char *dname = "compound_interim_dir";
461     struct smb2_notify nt;
462     bool ret = true;
463     struct smb2_request *req[2];
464
465     /* Win7 compound request implementation deviates substantially from the
466      * SMB2 spec as noted in MS-SMB2 <159>, <162>.  This, test currently
467      * verifies the Windows behavior, not the general spec behavior. */
468     if (!TARGET_IS_WIN7(tctx) && !TARGET_IS_W2K8(tctx)) {
469             torture_skip(tctx, "Interim test is specific to Windows server "
470                                "behavior.\n");
471     }
472
473     smb2_transport_credits_ask_num(tree->session->transport, 5);
474
475     smb2_deltree(tree, dname);
476
477     smb2_transport_credits_ask_num(tree->session->transport, 1);
478
479     ZERO_STRUCT(cr);
480     cr.in.desired_access        = SEC_RIGHTS_FILE_ALL;
481     cr.in.create_options        = NTCREATEX_OPTIONS_DIRECTORY;
482     cr.in.file_attributes       = FILE_ATTRIBUTE_DIRECTORY;
483     cr.in.share_access          = NTCREATEX_SHARE_ACCESS_READ |
484                                   NTCREATEX_SHARE_ACCESS_WRITE |
485                                   NTCREATEX_SHARE_ACCESS_DELETE;
486     cr.in.create_disposition    = NTCREATEX_DISP_CREATE;
487     cr.in.fname                 = dname;
488
489     smb2_transport_compound_start(tree->session->transport, 2);
490
491     req[0] = smb2_create_send(tree, &cr);
492
493     smb2_transport_compound_set_related(tree->session->transport, true);
494
495     hd.data[0] = UINT64_MAX;
496     hd.data[1] = UINT64_MAX;
497
498     ZERO_STRUCT(nt);
499     nt.in.recursive          = true;
500     nt.in.buffer_size        = 0x1000;
501     nt.in.file.handle        = hd;
502     nt.in.completion_filter  = FILE_NOTIFY_CHANGE_NAME;
503     nt.in.unknown            = 0x00000000;
504
505     req[1] = smb2_notify_send(tree, &nt);
506
507     status = smb2_create_recv(req[0], tree, &cr);
508     CHECK_STATUS(status, NT_STATUS_OK);
509
510     smb2_cancel(req[1]);
511     status = smb2_notify_recv(req[1], tree, &nt);
512     CHECK_STATUS(status, NT_STATUS_CANCELLED);
513
514     smb2_util_close(tree, cr.out.file.handle);
515
516     smb2_deltree(tree, dname);
517 done:
518     return ret;
519 }
520
521 /* Send a compound request where we expect the middle request (Create, Notify,
522  * GetInfo) to go asynchronous. Against Win7 the sync request succeed while
523  * the async fails. All are returned in the same compound response. */
524 static bool test_compound_interim2(struct torture_context *tctx,
525                                    struct smb2_tree *tree)
526 {
527     struct smb2_handle hd;
528     struct smb2_create cr;
529     NTSTATUS status = NT_STATUS_OK;
530     const char *dname = "compound_interim_dir";
531     struct smb2_getinfo gf;
532     struct smb2_notify  nt;
533     bool ret = true;
534     struct smb2_request *req[3];
535
536     /* Win7 compound request implementation deviates substantially from the
537      * SMB2 spec as noted in MS-SMB2 <159>, <162>.  This, test currently
538      * verifies the Windows behavior, not the general spec behavior. */
539     if (!TARGET_IS_WIN7(tctx) && !TARGET_IS_W2K8(tctx)) {
540             torture_skip(tctx, "Interim test is specific to Windows server "
541                                "behavior.\n");
542     }
543
544     smb2_transport_credits_ask_num(tree->session->transport, 5);
545
546     smb2_deltree(tree, dname);
547
548     smb2_transport_credits_ask_num(tree->session->transport, 1);
549
550     ZERO_STRUCT(cr);
551     cr.in.desired_access        = SEC_RIGHTS_FILE_ALL;
552     cr.in.create_options        = NTCREATEX_OPTIONS_DIRECTORY;
553     cr.in.file_attributes       = FILE_ATTRIBUTE_DIRECTORY;
554     cr.in.share_access      = NTCREATEX_SHARE_ACCESS_READ |
555                       NTCREATEX_SHARE_ACCESS_WRITE |
556                       NTCREATEX_SHARE_ACCESS_DELETE;
557     cr.in.create_disposition    = NTCREATEX_DISP_CREATE;
558     cr.in.fname         = dname;
559
560     smb2_transport_compound_start(tree->session->transport, 3);
561
562     req[0] = smb2_create_send(tree, &cr);
563
564     smb2_transport_compound_set_related(tree->session->transport, true);
565
566     hd.data[0] = UINT64_MAX;
567     hd.data[1] = UINT64_MAX;
568
569     ZERO_STRUCT(nt);
570     nt.in.recursive          = true;
571     nt.in.buffer_size        = 0x1000;
572     nt.in.file.handle        = hd;
573     nt.in.completion_filter  = FILE_NOTIFY_CHANGE_NAME;
574     nt.in.unknown            = 0x00000000;
575
576     req[1] = smb2_notify_send(tree, &nt);
577
578     ZERO_STRUCT(gf);
579     gf.in.file.handle = hd;
580     gf.in.info_type   = SMB2_GETINFO_FILE;
581     gf.in.info_class  = 0x04; // FILE_BASIC_INFORMATION
582     gf.in.output_buffer_length = 0x1000;
583     gf.in.input_buffer_length = 0;
584
585     req[2] = smb2_getinfo_send(tree, &gf);
586
587     status = smb2_create_recv(req[0], tree, &cr);
588     CHECK_STATUS(status, NT_STATUS_OK);
589
590     status = smb2_notify_recv(req[1], tree, &nt);
591     CHECK_STATUS(status, NT_STATUS_INTERNAL_ERROR);
592
593     status = smb2_getinfo_recv(req[2], tree, &gf);
594     CHECK_STATUS(status, NT_STATUS_OK);
595
596     smb2_util_close(tree, cr.out.file.handle);
597
598     smb2_deltree(tree, dname);
599 done:
600     return ret;
601 }
602
603 struct torture_suite *torture_smb2_compound_init(void)
604 {
605         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "compound");
606
607         torture_suite_add_1smb2_test(suite, "related1", test_compound_related1);
608         torture_suite_add_1smb2_test(suite, "related2", test_compound_related2);
609         torture_suite_add_1smb2_test(suite, "unrelated1", test_compound_unrelated1);
610         torture_suite_add_1smb2_test(suite, "invalid1", test_compound_invalid1);
611         torture_suite_add_1smb2_test(suite, "invalid2", test_compound_invalid2);
612         torture_suite_add_1smb2_test(suite, "invalid3", test_compound_invalid3);
613         torture_suite_add_1smb2_test(suite, "interim1",  test_compound_interim1);
614         torture_suite_add_1smb2_test(suite, "interim2",  test_compound_interim2);
615
616         suite->description = talloc_strdup(suite, "SMB2-COMPOUND tests");
617
618         return suite;
619 }