s4:torture:smb2:compound: remove two unused macros
[metze/samba/wip.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 #include "../libcli/smb/smbXcli_base.h"
28
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)
36
37 static bool test_compound_related1(struct torture_context *tctx,
38                                    struct smb2_tree *tree)
39 {
40         struct smb2_handle hd;
41         struct smb2_create cr;
42         NTSTATUS status;
43         const char *fname = "compound_related1.dat";
44         struct smb2_close cl;
45         bool ret = true;
46         struct smb2_request *req[2];
47         struct smbXcli_tcon *saved_tcon = tree->smbXcli;
48         struct smbXcli_session *saved_session = tree->session->smbXcli;
49
50         smb2_transport_credits_ask_num(tree->session->transport, 2);
51
52         smb2_util_unlink(tree, fname);
53
54         smb2_transport_credits_ask_num(tree->session->transport, 1);
55
56         ZERO_STRUCT(cr);
57         cr.in.security_flags            = 0x00;
58         cr.in.oplock_level              = 0;
59         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
60         cr.in.create_flags              = 0x00000000;
61         cr.in.reserved                  = 0x00000000;
62         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
63         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
64         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
65                                           NTCREATEX_SHARE_ACCESS_WRITE |
66                                           NTCREATEX_SHARE_ACCESS_DELETE;
67         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
68         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
69                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
70                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
71                                           0x00200000;
72         cr.in.fname                     = fname;
73
74         smb2_transport_compound_start(tree->session->transport, 2);
75
76         req[0] = smb2_create_send(tree, &cr);
77
78         smb2_transport_compound_set_related(tree->session->transport, true);
79
80         hd.data[0] = UINT64_MAX;
81         hd.data[1] = UINT64_MAX;
82
83         ZERO_STRUCT(cl);
84         cl.in.file.handle = hd;
85
86         tree->smbXcli = smbXcli_tcon_create(tree);
87         smb2cli_tcon_set_values(tree->smbXcli,
88                                 NULL, /* session */
89                                 0xFFFFFFFF, /* tcon_id */
90                                 0, /* type */
91                                 0, /* flags */
92                                 0, /* capabilities */
93                                 0 /* maximal_access */);
94
95         tree->session->smbXcli = smbXcli_session_create(tree->session,
96                                                         tree->session->transport->conn);
97         smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
98
99         req[1] = smb2_close_send(tree, &cl);
100
101         status = smb2_create_recv(req[0], tree, &cr);
102         CHECK_STATUS(status, NT_STATUS_OK);
103         status = smb2_close_recv(req[1], &cl);
104         CHECK_STATUS(status, NT_STATUS_OK);
105
106         TALLOC_FREE(tree->smbXcli);
107         tree->smbXcli = saved_tcon;
108         TALLOC_FREE(tree->session->smbXcli);
109         tree->session->smbXcli = saved_session;
110
111         smb2_util_unlink(tree, fname);
112 done:
113         return ret;
114 }
115
116 static bool test_compound_related2(struct torture_context *tctx,
117                                    struct smb2_tree *tree)
118 {
119         struct smb2_handle hd;
120         struct smb2_create cr;
121         NTSTATUS status;
122         const char *fname = "compound_related2.dat";
123         struct smb2_close cl;
124         bool ret = true;
125         struct smb2_request *req[5];
126         struct smbXcli_tcon *saved_tcon = tree->smbXcli;
127         struct smbXcli_session *saved_session = tree->session->smbXcli;
128
129         smb2_transport_credits_ask_num(tree->session->transport, 5);
130
131         smb2_util_unlink(tree, fname);
132
133         smb2_transport_credits_ask_num(tree->session->transport, 1);
134
135         ZERO_STRUCT(cr);
136         cr.in.security_flags            = 0x00;
137         cr.in.oplock_level              = 0;
138         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
139         cr.in.create_flags              = 0x00000000;
140         cr.in.reserved                  = 0x00000000;
141         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
142         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
143         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
144                                           NTCREATEX_SHARE_ACCESS_WRITE |
145                                           NTCREATEX_SHARE_ACCESS_DELETE;
146         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
147         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
148                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
149                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
150                                           0x00200000;
151         cr.in.fname                     = fname;
152
153         smb2_transport_compound_start(tree->session->transport, 5);
154
155         req[0] = smb2_create_send(tree, &cr);
156
157         hd.data[0] = UINT64_MAX;
158         hd.data[1] = UINT64_MAX;
159
160         smb2_transport_compound_set_related(tree->session->transport, true);
161
162         ZERO_STRUCT(cl);
163         cl.in.file.handle = hd;
164
165         tree->smbXcli = smbXcli_tcon_create(tree);
166         smb2cli_tcon_set_values(tree->smbXcli,
167                                 NULL, /* session */
168                                 0xFFFFFFFF, /* tcon_id */
169                                 0, /* type */
170                                 0, /* flags */
171                                 0, /* capabilities */
172                                 0 /* maximal_access */);
173
174         tree->session->smbXcli = smbXcli_session_create(tree->session,
175                                                         tree->session->transport->conn);
176         smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
177
178         req[1] = smb2_close_send(tree, &cl);
179         req[2] = smb2_close_send(tree, &cl);
180         req[3] = smb2_close_send(tree, &cl);
181         req[4] = smb2_close_send(tree, &cl);
182
183         status = smb2_create_recv(req[0], tree, &cr);
184         CHECK_STATUS(status, NT_STATUS_OK);
185         status = smb2_close_recv(req[1], &cl);
186         CHECK_STATUS(status, NT_STATUS_OK);
187         status = smb2_close_recv(req[2], &cl);
188         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
189         status = smb2_close_recv(req[3], &cl);
190         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
191         status = smb2_close_recv(req[4], &cl);
192         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
193
194         TALLOC_FREE(tree->smbXcli);
195         tree->smbXcli = saved_tcon;
196         TALLOC_FREE(tree->session->smbXcli);
197         tree->session->smbXcli = saved_session;
198
199         smb2_util_unlink(tree, fname);
200 done:
201         return ret;
202 }
203
204 static bool test_compound_related3(struct torture_context *tctx,
205                                    struct smb2_tree *tree)
206 {
207         struct smb2_handle hd;
208         struct smb2_ioctl io;
209         struct smb2_create cr;
210         struct smb2_close cl;
211         const char *fname = "compound_related3.dat";
212         struct smb2_request *req[3];
213         NTSTATUS status;
214         bool ret = false;
215
216         smb2_util_unlink(tree, fname);
217
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;
235
236         smb2_transport_compound_start(tree->session->transport, 3);
237
238         req[0] = smb2_create_send(tree, &cr);
239
240         hd.data[0] = UINT64_MAX;
241         hd.data[1] = UINT64_MAX;
242
243         smb2_transport_compound_set_related(tree->session->transport, true);
244
245         ZERO_STRUCT(io);
246         io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID;
247         io.in.file.handle = hd;
248         io.in.unknown2 = 0;
249         io.in.max_response_size = 64;
250         io.in.flags = 1;
251
252         req[1] = smb2_ioctl_send(tree, &io);
253
254         ZERO_STRUCT(cl);
255         cl.in.file.handle = hd;
256
257         req[2] = smb2_close_send(tree, &cl);
258
259         status = smb2_create_recv(req[0], tree, &cr);
260         CHECK_STATUS(status, NT_STATUS_OK);
261         status = smb2_ioctl_recv(req[1], tree, &io);
262         CHECK_STATUS(status, NT_STATUS_OK);
263         status = smb2_close_recv(req[2], &cl);
264         CHECK_STATUS(status, NT_STATUS_OK);
265
266         status = smb2_util_unlink(tree, fname);
267         CHECK_STATUS(status, NT_STATUS_OK);
268
269         ret = true;
270 done:
271         return ret;
272 }
273
274 static bool test_compound_unrelated1(struct torture_context *tctx,
275                                      struct smb2_tree *tree)
276 {
277         struct smb2_handle hd;
278         struct smb2_create cr;
279         NTSTATUS status;
280         const char *fname = "compound_unrelated1.dat";
281         struct smb2_close cl;
282         bool ret = true;
283         struct smb2_request *req[5];
284
285         smb2_transport_credits_ask_num(tree->session->transport, 5);
286
287         smb2_util_unlink(tree, fname);
288
289         smb2_transport_credits_ask_num(tree->session->transport, 1);
290
291         ZERO_STRUCT(cr);
292         cr.in.security_flags            = 0x00;
293         cr.in.oplock_level              = 0;
294         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
295         cr.in.create_flags              = 0x00000000;
296         cr.in.reserved                  = 0x00000000;
297         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
298         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
299         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
300                                           NTCREATEX_SHARE_ACCESS_WRITE |
301                                           NTCREATEX_SHARE_ACCESS_DELETE;
302         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
303         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
304                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
305                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
306                                           0x00200000;
307         cr.in.fname                     = fname;
308
309         smb2_transport_compound_start(tree->session->transport, 5);
310
311         req[0] = smb2_create_send(tree, &cr);
312
313         hd.data[0] = UINT64_MAX;
314         hd.data[1] = UINT64_MAX;
315
316         ZERO_STRUCT(cl);
317         cl.in.file.handle = hd;
318         req[1] = smb2_close_send(tree, &cl);
319         req[2] = smb2_close_send(tree, &cl);
320         req[3] = smb2_close_send(tree, &cl);
321         req[4] = smb2_close_send(tree, &cl);
322
323         status = smb2_create_recv(req[0], tree, &cr);
324         CHECK_STATUS(status, NT_STATUS_OK);
325         status = smb2_close_recv(req[1], &cl);
326         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
327         status = smb2_close_recv(req[2], &cl);
328         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
329         status = smb2_close_recv(req[3], &cl);
330         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
331         status = smb2_close_recv(req[4], &cl);
332         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
333
334         smb2_util_unlink(tree, fname);
335 done:
336         return ret;
337 }
338
339 static bool test_compound_invalid1(struct torture_context *tctx,
340                                    struct smb2_tree *tree)
341 {
342         struct smb2_handle hd;
343         struct smb2_create cr;
344         NTSTATUS status;
345         const char *fname = "compound_invalid1.dat";
346         struct smb2_close cl;
347         bool ret = true;
348         struct smb2_request *req[3];
349
350         smb2_transport_credits_ask_num(tree->session->transport, 3);
351
352         smb2_util_unlink(tree, fname);
353
354         smb2_transport_credits_ask_num(tree->session->transport, 1);
355
356         ZERO_STRUCT(cr);
357         cr.in.security_flags            = 0x00;
358         cr.in.oplock_level              = 0;
359         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
360         cr.in.create_flags              = 0x00000000;
361         cr.in.reserved                  = 0x00000000;
362         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
363         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
364         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
365                                           NTCREATEX_SHARE_ACCESS_WRITE |
366                                           NTCREATEX_SHARE_ACCESS_DELETE;
367         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
368         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
369                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
370                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
371                                           0x00200000;
372         cr.in.fname                     = fname;
373
374         smb2_transport_compound_start(tree->session->transport, 3);
375
376         /* passing the first request with the related flag is invalid */
377         smb2_transport_compound_set_related(tree->session->transport, true);
378
379         req[0] = smb2_create_send(tree, &cr);
380
381         hd.data[0] = UINT64_MAX;
382         hd.data[1] = UINT64_MAX;
383
384         ZERO_STRUCT(cl);
385         cl.in.file.handle = hd;
386         req[1] = smb2_close_send(tree, &cl);
387
388         smb2_transport_compound_set_related(tree->session->transport, false);
389         req[2] = smb2_close_send(tree, &cl);
390
391         status = smb2_create_recv(req[0], tree, &cr);
392         /* TODO: check why this fails with --signing=required */
393         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
394         status = smb2_close_recv(req[1], &cl);
395         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
396         status = smb2_close_recv(req[2], &cl);
397         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
398
399         smb2_util_unlink(tree, fname);
400 done:
401         return ret;
402 }
403
404 static bool test_compound_invalid2(struct torture_context *tctx,
405                                    struct smb2_tree *tree)
406 {
407         struct smb2_handle hd;
408         struct smb2_create cr;
409         NTSTATUS status;
410         const char *fname = "compound_invalid2.dat";
411         struct smb2_close cl;
412         bool ret = true;
413         struct smb2_request *req[5];
414         struct smbXcli_tcon *saved_tcon = tree->smbXcli;
415         struct smbXcli_session *saved_session = tree->session->smbXcli;
416
417         smb2_transport_credits_ask_num(tree->session->transport, 5);
418
419         smb2_util_unlink(tree, fname);
420
421         smb2_transport_credits_ask_num(tree->session->transport, 1);
422
423         ZERO_STRUCT(cr);
424         cr.in.security_flags            = 0x00;
425         cr.in.oplock_level              = 0;
426         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
427         cr.in.create_flags              = 0x00000000;
428         cr.in.reserved                  = 0x00000000;
429         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
430         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
431         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
432                                           NTCREATEX_SHARE_ACCESS_WRITE |
433                                           NTCREATEX_SHARE_ACCESS_DELETE;
434         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
435         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
436                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
437                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
438                                           0x00200000;
439         cr.in.fname                     = fname;
440
441         smb2_transport_compound_start(tree->session->transport, 5);
442
443         req[0] = smb2_create_send(tree, &cr);
444
445         hd.data[0] = UINT64_MAX;
446         hd.data[1] = UINT64_MAX;
447
448         smb2_transport_compound_set_related(tree->session->transport, true);
449
450         ZERO_STRUCT(cl);
451         cl.in.file.handle = hd;
452
453         tree->smbXcli = smbXcli_tcon_create(tree);
454         smb2cli_tcon_set_values(tree->smbXcli,
455                                 NULL, /* session */
456                                 0xFFFFFFFF, /* tcon_id */
457                                 0, /* type */
458                                 0, /* flags */
459                                 0, /* capabilities */
460                                 0 /* maximal_access */);
461
462         tree->session->smbXcli = smbXcli_session_create(tree->session,
463                                                         tree->session->transport->conn);
464         smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
465
466         req[1] = smb2_close_send(tree, &cl);
467         /* strange that this is not generating invalid parameter */
468         smb2_transport_compound_set_related(tree->session->transport, false);
469         req[2] = smb2_close_send(tree, &cl);
470         req[3] = smb2_close_send(tree, &cl);
471         smb2_transport_compound_set_related(tree->session->transport, true);
472         req[4] = smb2_close_send(tree, &cl);
473
474         status = smb2_create_recv(req[0], tree, &cr);
475         CHECK_STATUS(status, NT_STATUS_OK);
476         status = smb2_close_recv(req[1], &cl);
477         CHECK_STATUS(status, NT_STATUS_OK);
478         status = smb2_close_recv(req[2], &cl);
479         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
480         status = smb2_close_recv(req[3], &cl);
481         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
482         status = smb2_close_recv(req[4], &cl);
483         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
484
485         TALLOC_FREE(tree->smbXcli);
486         tree->smbXcli = saved_tcon;
487         TALLOC_FREE(tree->session->smbXcli);
488         tree->session->smbXcli = saved_session;
489
490         smb2_util_unlink(tree, fname);
491 done:
492         return ret;
493 }
494
495 static bool test_compound_invalid3(struct torture_context *tctx,
496                                    struct smb2_tree *tree)
497 {
498         struct smb2_handle hd;
499         struct smb2_create cr;
500         NTSTATUS status;
501         const char *fname = "compound_invalid3.dat";
502         struct smb2_close cl;
503         bool ret = true;
504         struct smb2_request *req[5];
505
506         smb2_transport_credits_ask_num(tree->session->transport, 5);
507
508         smb2_util_unlink(tree, fname);
509
510         smb2_transport_credits_ask_num(tree->session->transport, 1);
511
512         ZERO_STRUCT(cr);
513         cr.in.security_flags            = 0x00;
514         cr.in.oplock_level              = 0;
515         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
516         cr.in.create_flags              = 0x00000000;
517         cr.in.reserved                  = 0x00000000;
518         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
519         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
520         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
521                                           NTCREATEX_SHARE_ACCESS_WRITE |
522                                           NTCREATEX_SHARE_ACCESS_DELETE;
523         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
524         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
525                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
526                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
527                                           0x00200000;
528         cr.in.fname                     = fname;
529
530         smb2_transport_compound_start(tree->session->transport, 5);
531
532         req[0] = smb2_create_send(tree, &cr);
533
534         hd.data[0] = UINT64_MAX;
535         hd.data[1] = UINT64_MAX;
536
537         ZERO_STRUCT(cl);
538         cl.in.file.handle = hd;
539         req[1] = smb2_close_send(tree, &cl);
540         req[2] = smb2_close_send(tree, &cl);
541         /* flipping the related flag is invalid */
542         smb2_transport_compound_set_related(tree->session->transport, true);
543         req[3] = smb2_close_send(tree, &cl);
544         req[4] = smb2_close_send(tree, &cl);
545
546         status = smb2_create_recv(req[0], tree, &cr);
547         CHECK_STATUS(status, NT_STATUS_OK);
548         status = smb2_close_recv(req[1], &cl);
549         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
550         status = smb2_close_recv(req[2], &cl);
551         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
552         status = smb2_close_recv(req[3], &cl);
553         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
554         status = smb2_close_recv(req[4], &cl);
555         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
556
557         smb2_util_unlink(tree, fname);
558 done:
559         return ret;
560 }
561
562 /* Send a compound request where we expect the last request (Create, Notify)
563  * to go asynchronous. This works against a Win7 server and the reply is
564  * sent in two different packets. */
565 static bool test_compound_interim1(struct torture_context *tctx,
566                                    struct smb2_tree *tree)
567 {
568     struct smb2_handle hd;
569     struct smb2_create cr;
570     NTSTATUS status = NT_STATUS_OK;
571     const char *dname = "compound_interim_dir";
572     struct smb2_notify nt;
573     bool ret = true;
574     struct smb2_request *req[2];
575
576     /* Win7 compound request implementation deviates substantially from the
577      * SMB2 spec as noted in MS-SMB2 <159>, <162>.  This, test currently
578      * verifies the Windows behavior, not the general spec behavior. */
579
580     smb2_transport_credits_ask_num(tree->session->transport, 5);
581
582     smb2_deltree(tree, dname);
583
584     smb2_transport_credits_ask_num(tree->session->transport, 1);
585
586     ZERO_STRUCT(cr);
587     cr.in.desired_access        = SEC_RIGHTS_FILE_ALL;
588     cr.in.create_options        = NTCREATEX_OPTIONS_DIRECTORY;
589     cr.in.file_attributes       = FILE_ATTRIBUTE_DIRECTORY;
590     cr.in.share_access          = NTCREATEX_SHARE_ACCESS_READ |
591                                   NTCREATEX_SHARE_ACCESS_WRITE |
592                                   NTCREATEX_SHARE_ACCESS_DELETE;
593     cr.in.create_disposition    = NTCREATEX_DISP_CREATE;
594     cr.in.fname                 = dname;
595
596     smb2_transport_compound_start(tree->session->transport, 2);
597
598     req[0] = smb2_create_send(tree, &cr);
599
600     smb2_transport_compound_set_related(tree->session->transport, true);
601
602     hd.data[0] = UINT64_MAX;
603     hd.data[1] = UINT64_MAX;
604
605     ZERO_STRUCT(nt);
606     nt.in.recursive          = true;
607     nt.in.buffer_size        = 0x1000;
608     nt.in.file.handle        = hd;
609     nt.in.completion_filter  = FILE_NOTIFY_CHANGE_NAME;
610     nt.in.unknown            = 0x00000000;
611
612     req[1] = smb2_notify_send(tree, &nt);
613
614     status = smb2_create_recv(req[0], tree, &cr);
615     CHECK_STATUS(status, NT_STATUS_OK);
616
617     smb2_cancel(req[1]);
618     status = smb2_notify_recv(req[1], tree, &nt);
619     CHECK_STATUS(status, NT_STATUS_CANCELLED);
620
621     smb2_util_close(tree, cr.out.file.handle);
622
623     smb2_deltree(tree, dname);
624 done:
625     return ret;
626 }
627
628 /* Send a compound request where we expect the middle request (Create, Notify,
629  * GetInfo) to go asynchronous. Against Win7 the sync request succeed while
630  * the async fails. All are returned in the same compound response. */
631 static bool test_compound_interim2(struct torture_context *tctx,
632                                    struct smb2_tree *tree)
633 {
634     struct smb2_handle hd;
635     struct smb2_create cr;
636     NTSTATUS status = NT_STATUS_OK;
637     const char *dname = "compound_interim_dir";
638     struct smb2_getinfo gf;
639     struct smb2_notify  nt;
640     bool ret = true;
641     struct smb2_request *req[3];
642
643     /* Win7 compound request implementation deviates substantially from the
644      * SMB2 spec as noted in MS-SMB2 <159>, <162>.  This, test currently
645      * verifies the Windows behavior, not the general spec behavior. */
646
647     smb2_transport_credits_ask_num(tree->session->transport, 5);
648
649     smb2_deltree(tree, dname);
650
651     smb2_transport_credits_ask_num(tree->session->transport, 1);
652
653     ZERO_STRUCT(cr);
654     cr.in.desired_access        = SEC_RIGHTS_FILE_ALL;
655     cr.in.create_options        = NTCREATEX_OPTIONS_DIRECTORY;
656     cr.in.file_attributes       = FILE_ATTRIBUTE_DIRECTORY;
657     cr.in.share_access      = NTCREATEX_SHARE_ACCESS_READ |
658                       NTCREATEX_SHARE_ACCESS_WRITE |
659                       NTCREATEX_SHARE_ACCESS_DELETE;
660     cr.in.create_disposition    = NTCREATEX_DISP_CREATE;
661     cr.in.fname         = dname;
662
663     smb2_transport_compound_start(tree->session->transport, 3);
664
665     req[0] = smb2_create_send(tree, &cr);
666
667     smb2_transport_compound_set_related(tree->session->transport, true);
668
669     hd.data[0] = UINT64_MAX;
670     hd.data[1] = UINT64_MAX;
671
672     ZERO_STRUCT(nt);
673     nt.in.recursive          = true;
674     nt.in.buffer_size        = 0x1000;
675     nt.in.file.handle        = hd;
676     nt.in.completion_filter  = FILE_NOTIFY_CHANGE_NAME;
677     nt.in.unknown            = 0x00000000;
678
679     req[1] = smb2_notify_send(tree, &nt);
680
681     ZERO_STRUCT(gf);
682     gf.in.file.handle = hd;
683     gf.in.info_type   = SMB2_GETINFO_FILE;
684     gf.in.info_class  = 0x04; /* FILE_BASIC_INFORMATION */
685     gf.in.output_buffer_length = 0x1000;
686     gf.in.input_buffer_length = 0;
687
688     req[2] = smb2_getinfo_send(tree, &gf);
689
690     status = smb2_create_recv(req[0], tree, &cr);
691     CHECK_STATUS(status, NT_STATUS_OK);
692
693     status = smb2_notify_recv(req[1], tree, &nt);
694     CHECK_STATUS(status, NT_STATUS_INTERNAL_ERROR);
695
696     status = smb2_getinfo_recv(req[2], tree, &gf);
697     CHECK_STATUS(status, NT_STATUS_OK);
698
699     smb2_util_close(tree, cr.out.file.handle);
700
701     smb2_deltree(tree, dname);
702 done:
703     return ret;
704 }
705
706 struct torture_suite *torture_smb2_compound_init(void)
707 {
708         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "compound");
709
710         torture_suite_add_1smb2_test(suite, "related1", test_compound_related1);
711         torture_suite_add_1smb2_test(suite, "related2", test_compound_related2);
712         torture_suite_add_1smb2_test(suite, "related3",
713                                      test_compound_related3);
714         torture_suite_add_1smb2_test(suite, "unrelated1", test_compound_unrelated1);
715         torture_suite_add_1smb2_test(suite, "invalid1", test_compound_invalid1);
716         torture_suite_add_1smb2_test(suite, "invalid2", test_compound_invalid2);
717         torture_suite_add_1smb2_test(suite, "invalid3", test_compound_invalid3);
718         torture_suite_add_1smb2_test(suite, "interim1",  test_compound_interim1);
719         torture_suite_add_1smb2_test(suite, "interim2",  test_compound_interim2);
720
721         suite->description = talloc_strdup(suite, "SMB2-COMPOUND tests");
722
723         return suite;
724 }