Line data Source code
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/security/security.h"
28 : #include "librpc/gen_ndr/ndr_security.h"
29 : #include "../libcli/smb/smbXcli_base.h"
30 :
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)
38 :
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)
46 :
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;
55 :
56 0 : static void torture_oplock_break_callback(struct smb2_request *req)
57 : {
58 : NTSTATUS status;
59 : struct smb2_break br;
60 :
61 0 : ZERO_STRUCT(br);
62 0 : status = smb2_break_recv(req, &break_info.br);
63 0 : if (!NT_STATUS_IS_OK(status)) {
64 0 : break_info.failures++;
65 0 : break_info.failure_status = status;
66 : }
67 :
68 0 : return;
69 : }
70 :
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 0 : static bool torture_oplock_handler(struct smb2_transport *transport,
74 : const struct smb2_handle *handle,
75 : uint8_t level,
76 : void *private_data)
77 : {
78 0 : struct smb2_tree *tree = private_data;
79 : const char *name;
80 : struct smb2_request *req;
81 0 : ZERO_STRUCT(break_info.br);
82 :
83 0 : break_info.handle = *handle;
84 0 : break_info.level = level;
85 0 : break_info.count++;
86 :
87 0 : switch (level) {
88 0 : case SMB2_OPLOCK_LEVEL_II:
89 0 : name = "level II";
90 0 : break;
91 0 : case SMB2_OPLOCK_LEVEL_NONE:
92 0 : name = "none";
93 0 : break;
94 0 : default:
95 0 : name = "unknown";
96 0 : break_info.failures++;
97 : }
98 0 : printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
99 :
100 0 : break_info.br.in.file.handle = *handle;
101 0 : break_info.br.in.oplock_level = level;
102 0 : break_info.br.in.reserved = 0;
103 0 : break_info.br.in.reserved2 = 0;
104 :
105 0 : req = smb2_break_send(tree, &break_info.br);
106 0 : req->async.fn = torture_oplock_break_callback;
107 0 : req->async.private_data = NULL;
108 0 : return true;
109 : }
110 :
111 0 : static bool test_compound_break(struct torture_context *tctx,
112 : struct smb2_tree *tree)
113 : {
114 0 : const char *fname1 = "some-file.pptx";
115 : NTSTATUS status;
116 0 : 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;
123 :
124 0 : tree->session->transport->oplock.handler = torture_oplock_handler;
125 0 : tree->session->transport->oplock.private_data = tree;
126 :
127 0 : ZERO_STRUCT(break_info);
128 :
129 : /*
130 : base ntcreatex parms
131 : */
132 0 : ZERO_STRUCT(io1.smb2);
133 0 : io1.generic.level = RAW_OPEN_SMB2;
134 0 : 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 0 : io1.smb2.in.alloc_size = 0;
140 0 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
141 0 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
142 : NTCREATEX_SHARE_ACCESS_WRITE|
143 : NTCREATEX_SHARE_ACCESS_DELETE;
144 0 : io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
145 0 : io1.smb2.in.create_options = 0;
146 0 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
147 0 : io1.smb2.in.security_flags = 0;
148 0 : io1.smb2.in.fname = fname1;
149 :
150 0 : torture_comment(tctx, "TEST2: open a file with an batch "
151 : "oplock (share mode: all)\n");
152 0 : io1.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
153 :
154 0 : status = smb2_create(tree, tctx, &(io1.smb2));
155 0 : torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
156 :
157 0 : h1 = io1.smb2.out.file.handle;
158 :
159 0 : torture_comment(tctx, "TEST2: Opening second time with compound\n");
160 :
161 0 : ZERO_STRUCT(io2);
162 :
163 0 : io2.in.desired_access = (SEC_STD_SYNCHRONIZE|
164 : SEC_FILE_READ_ATTRIBUTE|
165 : SEC_FILE_READ_EA);
166 0 : io2.in.alloc_size = 0;
167 0 : io2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
168 0 : io2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
169 : NTCREATEX_SHARE_ACCESS_WRITE|
170 : NTCREATEX_SHARE_ACCESS_DELETE;
171 0 : io2.in.create_disposition = NTCREATEX_DISP_OPEN;
172 0 : io2.in.create_options = 0;
173 0 : io2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
174 0 : io2.in.security_flags = 0;
175 0 : io2.in.fname = fname1;
176 0 : io2.in.oplock_level = 0;
177 :
178 0 : smb2_transport_compound_start(tree->session->transport, 2);
179 :
180 0 : req[0] = smb2_create_send(tree, &io2);
181 :
182 0 : smb2_transport_compound_set_related(tree->session->transport, true);
183 :
184 0 : h.data[0] = UINT64_MAX;
185 0 : h.data[1] = UINT64_MAX;
186 :
187 0 : ZERO_STRUCT(gf);
188 0 : gf.in.file.handle = h;
189 0 : gf.in.info_type = SMB2_0_INFO_FILE;
190 0 : gf.in.info_class = 0x16;
191 0 : gf.in.output_buffer_length = 0x1000;
192 0 : gf.in.input_buffer = data_blob_null;
193 :
194 0 : req[1] = smb2_getinfo_send(tree, &gf);
195 :
196 0 : status = smb2_create_recv(req[0], tree, &io2);
197 0 : CHECK_STATUS(status, NT_STATUS_OK);
198 :
199 0 : status = smb2_getinfo_recv(req[1], tree, &gf);
200 0 : CHECK_STATUS(status, NT_STATUS_OK);
201 :
202 0 : done:
203 :
204 0 : smb2_util_close(tree, h1);
205 0 : smb2_util_unlink(tree, fname1);
206 0 : return ret;
207 : }
208 :
209 0 : static bool test_compound_related1(struct torture_context *tctx,
210 : struct smb2_tree *tree)
211 : {
212 : struct smb2_handle hd;
213 : struct smb2_create cr;
214 : NTSTATUS status;
215 0 : const char *fname = "compound_related1.dat";
216 : struct smb2_close cl;
217 0 : bool ret = true;
218 : struct smb2_request *req[2];
219 0 : struct smbXcli_tcon *saved_tcon = tree->smbXcli;
220 0 : struct smbXcli_session *saved_session = tree->session->smbXcli;
221 :
222 0 : smb2_transport_credits_ask_num(tree->session->transport, 2);
223 :
224 0 : smb2_util_unlink(tree, fname);
225 :
226 0 : smb2_transport_credits_ask_num(tree->session->transport, 1);
227 :
228 0 : ZERO_STRUCT(cr);
229 0 : cr.in.security_flags = 0x00;
230 0 : cr.in.oplock_level = 0;
231 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
232 0 : cr.in.create_flags = 0x00000000;
233 0 : cr.in.reserved = 0x00000000;
234 0 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
235 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
236 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
237 : NTCREATEX_SHARE_ACCESS_WRITE |
238 : NTCREATEX_SHARE_ACCESS_DELETE;
239 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
240 0 : cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
241 : NTCREATEX_OPTIONS_ASYNC_ALERT |
242 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
243 : 0x00200000;
244 0 : cr.in.fname = fname;
245 :
246 0 : smb2_transport_compound_start(tree->session->transport, 2);
247 :
248 0 : req[0] = smb2_create_send(tree, &cr);
249 :
250 0 : smb2_transport_compound_set_related(tree->session->transport, true);
251 :
252 0 : hd.data[0] = UINT64_MAX;
253 0 : hd.data[1] = UINT64_MAX;
254 :
255 0 : ZERO_STRUCT(cl);
256 0 : cl.in.file.handle = hd;
257 :
258 0 : tree->smbXcli = smbXcli_tcon_create(tree);
259 0 : 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 */);
266 :
267 0 : tree->session->smbXcli = smbXcli_session_shallow_copy(tree->session,
268 0 : tree->session->smbXcli);
269 0 : smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
270 :
271 0 : req[1] = smb2_close_send(tree, &cl);
272 :
273 0 : status = smb2_create_recv(req[0], tree, &cr);
274 0 : CHECK_STATUS(status, NT_STATUS_OK);
275 0 : status = smb2_close_recv(req[1], &cl);
276 0 : CHECK_STATUS(status, NT_STATUS_OK);
277 :
278 0 : TALLOC_FREE(tree->smbXcli);
279 0 : tree->smbXcli = saved_tcon;
280 0 : TALLOC_FREE(tree->session->smbXcli);
281 0 : tree->session->smbXcli = saved_session;
282 :
283 0 : smb2_util_unlink(tree, fname);
284 0 : done:
285 0 : return ret;
286 : }
287 :
288 0 : static bool test_compound_related2(struct torture_context *tctx,
289 : struct smb2_tree *tree)
290 : {
291 : struct smb2_handle hd;
292 : struct smb2_create cr;
293 : NTSTATUS status;
294 0 : const char *fname = "compound_related2.dat";
295 : struct smb2_close cl;
296 0 : bool ret = true;
297 : struct smb2_request *req[5];
298 0 : struct smbXcli_tcon *saved_tcon = tree->smbXcli;
299 0 : struct smbXcli_session *saved_session = tree->session->smbXcli;
300 :
301 0 : smb2_transport_credits_ask_num(tree->session->transport, 5);
302 :
303 0 : smb2_util_unlink(tree, fname);
304 :
305 0 : smb2_transport_credits_ask_num(tree->session->transport, 1);
306 :
307 0 : ZERO_STRUCT(cr);
308 0 : cr.in.security_flags = 0x00;
309 0 : cr.in.oplock_level = 0;
310 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
311 0 : cr.in.create_flags = 0x00000000;
312 0 : cr.in.reserved = 0x00000000;
313 0 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
314 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
315 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
316 : NTCREATEX_SHARE_ACCESS_WRITE |
317 : NTCREATEX_SHARE_ACCESS_DELETE;
318 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
319 0 : cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
320 : NTCREATEX_OPTIONS_ASYNC_ALERT |
321 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
322 : 0x00200000;
323 0 : cr.in.fname = fname;
324 :
325 0 : smb2_transport_compound_start(tree->session->transport, 5);
326 :
327 0 : req[0] = smb2_create_send(tree, &cr);
328 :
329 0 : hd.data[0] = UINT64_MAX;
330 0 : hd.data[1] = UINT64_MAX;
331 :
332 0 : smb2_transport_compound_set_related(tree->session->transport, true);
333 :
334 0 : ZERO_STRUCT(cl);
335 0 : cl.in.file.handle = hd;
336 :
337 0 : tree->smbXcli = smbXcli_tcon_create(tree);
338 0 : 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 */);
345 :
346 0 : tree->session->smbXcli = smbXcli_session_shallow_copy(tree->session,
347 0 : tree->session->smbXcli);
348 0 : smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
349 :
350 0 : req[1] = smb2_close_send(tree, &cl);
351 0 : req[2] = smb2_close_send(tree, &cl);
352 0 : req[3] = smb2_close_send(tree, &cl);
353 0 : req[4] = smb2_close_send(tree, &cl);
354 :
355 0 : status = smb2_create_recv(req[0], tree, &cr);
356 0 : CHECK_STATUS(status, NT_STATUS_OK);
357 0 : status = smb2_close_recv(req[1], &cl);
358 0 : CHECK_STATUS(status, NT_STATUS_OK);
359 0 : status = smb2_close_recv(req[2], &cl);
360 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
361 0 : status = smb2_close_recv(req[3], &cl);
362 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
363 0 : status = smb2_close_recv(req[4], &cl);
364 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
365 :
366 0 : TALLOC_FREE(tree->smbXcli);
367 0 : tree->smbXcli = saved_tcon;
368 0 : TALLOC_FREE(tree->session->smbXcli);
369 0 : tree->session->smbXcli = saved_session;
370 :
371 0 : smb2_util_unlink(tree, fname);
372 0 : done:
373 0 : return ret;
374 : }
375 :
376 0 : static bool test_compound_related3(struct torture_context *tctx,
377 : struct smb2_tree *tree)
378 : {
379 : struct smb2_handle hd;
380 : struct smb2_ioctl io;
381 : struct smb2_create cr;
382 : struct smb2_close cl;
383 0 : const char *fname = "compound_related3.dat";
384 : struct smb2_request *req[3];
385 : NTSTATUS status;
386 0 : bool ret = false;
387 :
388 0 : smb2_util_unlink(tree, fname);
389 :
390 0 : ZERO_STRUCT(cr);
391 0 : cr.in.security_flags = 0x00;
392 0 : cr.in.oplock_level = 0;
393 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
394 0 : cr.in.create_flags = 0x00000000;
395 0 : cr.in.reserved = 0x00000000;
396 0 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
397 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
398 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
399 : NTCREATEX_SHARE_ACCESS_WRITE |
400 : NTCREATEX_SHARE_ACCESS_DELETE;
401 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
402 0 : cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
403 : NTCREATEX_OPTIONS_ASYNC_ALERT |
404 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
405 : 0x00200000;
406 0 : cr.in.fname = fname;
407 :
408 0 : smb2_transport_compound_start(tree->session->transport, 3);
409 :
410 0 : req[0] = smb2_create_send(tree, &cr);
411 :
412 0 : hd.data[0] = UINT64_MAX;
413 0 : hd.data[1] = UINT64_MAX;
414 :
415 0 : smb2_transport_compound_set_related(tree->session->transport, true);
416 :
417 0 : ZERO_STRUCT(io);
418 0 : io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID;
419 0 : io.in.file.handle = hd;
420 0 : io.in.reserved2 = 0;
421 0 : io.in.max_output_response = 64;
422 0 : io.in.flags = 1;
423 :
424 0 : req[1] = smb2_ioctl_send(tree, &io);
425 :
426 0 : ZERO_STRUCT(cl);
427 0 : cl.in.file.handle = hd;
428 :
429 0 : req[2] = smb2_close_send(tree, &cl);
430 :
431 0 : status = smb2_create_recv(req[0], tree, &cr);
432 0 : CHECK_STATUS(status, NT_STATUS_OK);
433 0 : status = smb2_ioctl_recv(req[1], tree, &io);
434 0 : CHECK_STATUS(status, NT_STATUS_OK);
435 0 : status = smb2_close_recv(req[2], &cl);
436 0 : CHECK_STATUS(status, NT_STATUS_OK);
437 :
438 0 : status = smb2_util_unlink(tree, fname);
439 0 : CHECK_STATUS(status, NT_STATUS_OK);
440 :
441 0 : ret = true;
442 0 : done:
443 0 : return ret;
444 : }
445 :
446 0 : static bool test_compound_related4(struct torture_context *tctx,
447 : struct smb2_tree *tree)
448 : {
449 0 : const char *fname = "compound_related4.dat";
450 0 : 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 0 : bool ret = true;
459 :
460 0 : smb2_util_unlink(tree, fname);
461 :
462 0 : ZERO_STRUCT(cr);
463 0 : cr.level = RAW_OPEN_SMB2;
464 0 : cr.in.create_flags = 0;
465 0 : cr.in.desired_access = SEC_STD_READ_CONTROL |
466 : SEC_STD_WRITE_DAC |
467 : SEC_STD_WRITE_OWNER;
468 0 : cr.in.create_options = 0;
469 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
470 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
471 : NTCREATEX_SHARE_ACCESS_READ |
472 : NTCREATEX_SHARE_ACCESS_WRITE;
473 0 : cr.in.alloc_size = 0;
474 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
475 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
476 0 : cr.in.security_flags = 0;
477 0 : cr.in.fname = fname;
478 :
479 0 : status = smb2_create(tree, tctx, &cr);
480 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
481 :
482 0 : hd = cr.out.file.handle;
483 0 : torture_comment(tctx, "set a sec desc allowing no write by CREATOR_OWNER\n");
484 :
485 0 : 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,
490 : 0,
491 : NULL);
492 0 : torture_assert_not_null_goto(tctx, sd, ret, done,
493 : "security_descriptor_dacl_create failed\n");
494 :
495 0 : set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
496 0 : set.set_secdesc.in.file.handle = hd;
497 0 : set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
498 0 : set.set_secdesc.in.sd = sd;
499 :
500 0 : status = smb2_setinfo_file(tree, &set);
501 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
502 : "smb2_setinfo_file failed\n");
503 :
504 0 : torture_comment(tctx, "try open for write\n");
505 0 : cr.in.desired_access = SEC_FILE_WRITE_DATA;
506 0 : smb2_transport_compound_start(tree->session->transport, 4);
507 :
508 0 : req[0] = smb2_create_send(tree, &cr);
509 0 : torture_assert_not_null_goto(tctx, req[0], ret, done,
510 : "smb2_create_send failed\n");
511 :
512 0 : hd.data[0] = UINT64_MAX;
513 0 : hd.data[1] = UINT64_MAX;
514 :
515 0 : smb2_transport_compound_set_related(tree->session->transport, true);
516 0 : ZERO_STRUCT(io);
517 0 : io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID;
518 0 : io.in.file.handle = hd;
519 0 : io.in.flags = 1;
520 :
521 0 : req[1] = smb2_ioctl_send(tree, &io);
522 0 : torture_assert_not_null_goto(tctx, req[1], ret, done,
523 : "smb2_ioctl_send failed\n");
524 :
525 0 : ZERO_STRUCT(cl);
526 0 : cl.in.file.handle = hd;
527 :
528 0 : req[2] = smb2_close_send(tree, &cl);
529 0 : torture_assert_not_null_goto(tctx, req[2], ret, done,
530 : "smb2_create_send failed\n");
531 :
532 0 : set.set_secdesc.in.file.handle = hd;
533 :
534 0 : req[3] = smb2_setinfo_file_send(tree, &set);
535 0 : torture_assert_not_null_goto(tctx, req[3], ret, done,
536 : "smb2_create_send failed\n");
537 :
538 0 : status = smb2_create_recv(req[0], tree, &cr);
539 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
540 : ret, done,
541 : "smb2_create_recv failed\n");
542 :
543 0 : status = smb2_ioctl_recv(req[1], tree, &io);
544 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
545 : ret, done,
546 : "smb2_ioctl_recv failed\n");
547 :
548 0 : status = smb2_close_recv(req[2], &cl);
549 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
550 : ret, done,
551 : "smb2_close_recv failed\n");
552 :
553 0 : status = smb2_setinfo_recv(req[3]);
554 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
555 : ret, done,
556 : "smb2_setinfo_recv failed\n");
557 :
558 0 : done:
559 0 : smb2_util_unlink(tree, fname);
560 0 : smb2_tdis(tree);
561 0 : smb2_logoff(tree->session);
562 0 : return ret;
563 : }
564 :
565 0 : static bool test_compound_related5(struct torture_context *tctx,
566 : struct smb2_tree *tree)
567 : {
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 0 : bool ret = false;
574 :
575 0 : smb2_transport_compound_start(tree->session->transport, 2);
576 :
577 0 : hd.data[0] = UINT64_MAX;
578 0 : hd.data[1] = UINT64_MAX;
579 :
580 0 : ZERO_STRUCT(io);
581 0 : io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID;
582 0 : io.in.file.handle = hd;
583 0 : io.in.flags = 1;
584 :
585 0 : req[0] = smb2_ioctl_send(tree, &io);
586 0 : torture_assert_not_null_goto(tctx, req[0], ret, done,
587 : "smb2_ioctl_send failed\n");
588 :
589 0 : smb2_transport_compound_set_related(tree->session->transport, true);
590 :
591 0 : ZERO_STRUCT(cl);
592 0 : cl.in.file.handle = hd;
593 :
594 0 : req[1] = smb2_close_send(tree, &cl);
595 0 : torture_assert_not_null_goto(tctx, req[1], ret, done,
596 : "smb2_create_send failed\n");
597 :
598 0 : status = smb2_ioctl_recv(req[0], tree, &io);
599 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_FILE_CLOSED,
600 : ret, done,
601 : "smb2_ioctl_recv failed\n");
602 :
603 0 : status = smb2_close_recv(req[1], &cl);
604 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_FILE_CLOSED,
605 : ret, done,
606 : "smb2_close_recv failed\n");
607 :
608 0 : ret = true;
609 :
610 0 : done:
611 0 : smb2_tdis(tree);
612 0 : smb2_logoff(tree->session);
613 0 : return ret;
614 : }
615 :
616 0 : static bool test_compound_related6(struct torture_context *tctx,
617 : struct smb2_tree *tree)
618 : {
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 0 : const char *fname = "compound_related6.dat";
626 : struct smb2_request *req[5];
627 : uint8_t buf[64];
628 0 : bool ret = true;
629 :
630 0 : smb2_util_unlink(tree, fname);
631 :
632 0 : ZERO_STRUCT(cr);
633 0 : cr.level = RAW_OPEN_SMB2;
634 0 : cr.in.create_flags = 0;
635 0 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
636 0 : cr.in.create_options = 0;
637 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
638 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
639 : NTCREATEX_SHARE_ACCESS_READ |
640 : NTCREATEX_SHARE_ACCESS_WRITE;
641 0 : cr.in.alloc_size = 0;
642 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
643 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
644 0 : cr.in.security_flags = 0;
645 0 : cr.in.fname = fname;
646 :
647 0 : status = smb2_create(tree, tctx, &cr);
648 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
649 : "smb2_create failed\n");
650 :
651 0 : hd = cr.out.file.handle;
652 :
653 0 : ZERO_STRUCT(buf);
654 0 : status = smb2_util_write(tree, hd, buf, 0, ARRAY_SIZE(buf));
655 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
656 : "smb2_util_write failed\n");
657 :
658 0 : torture_comment(tctx, "try open for read\n");
659 0 : cr.in.desired_access = SEC_FILE_READ_DATA;
660 0 : smb2_transport_compound_start(tree->session->transport, 5);
661 :
662 0 : req[0] = smb2_create_send(tree, &cr);
663 0 : torture_assert_not_null_goto(tctx, req[0], ret, done,
664 : "smb2_create_send failed\n");
665 :
666 0 : hd.data[0] = UINT64_MAX;
667 0 : hd.data[1] = UINT64_MAX;
668 :
669 0 : smb2_transport_compound_set_related(tree->session->transport, true);
670 :
671 0 : ZERO_STRUCT(rd);
672 0 : rd.in.file.handle = hd;
673 0 : rd.in.length = 1;
674 0 : rd.in.offset = 0;
675 :
676 0 : req[1] = smb2_read_send(tree, &rd);
677 0 : torture_assert_not_null_goto(tctx, req[1], ret, done,
678 : "smb2_read_send failed\n");
679 :
680 0 : ZERO_STRUCT(wr);
681 0 : wr.in.file.handle = hd;
682 0 : wr.in.offset = 0;
683 0 : wr.in.data = data_blob_talloc(tctx, NULL, 64);
684 :
685 0 : req[2] = smb2_write_send(tree, &wr);
686 0 : torture_assert_not_null_goto(tctx, req[2], ret, done,
687 : "smb2_write_send failed\n");
688 :
689 0 : ZERO_STRUCT(rd);
690 0 : rd.in.file.handle = hd;
691 0 : rd.in.length = 1;
692 0 : rd.in.offset = 0;
693 :
694 0 : req[3] = smb2_read_send(tree, &rd);
695 0 : torture_assert_not_null_goto(tctx, req[3], ret, done,
696 : "smb2_read_send failed\n");
697 :
698 0 : ZERO_STRUCT(cl);
699 0 : cl.in.file.handle = hd;
700 :
701 0 : req[4] = smb2_close_send(tree, &cl);
702 0 : torture_assert_not_null_goto(tctx, req[4], ret, done,
703 : "smb2_close_send failed\n");
704 :
705 0 : status = smb2_create_recv(req[0], tree, &cr);
706 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
707 : "smb2_create_recv failed\n");
708 :
709 0 : status = smb2_read_recv(req[1], tree, &rd);
710 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
711 : "smb2_read_recv failed\n");
712 :
713 0 : status = smb2_write_recv(req[2], &wr);
714 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
715 : ret, done,
716 : "smb2_write_recv failed\n");
717 :
718 0 : status = smb2_read_recv(req[3], tree, &rd);
719 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
720 : "smb2_read_recv failed\n");
721 :
722 0 : status = smb2_close_recv(req[4], &cl);
723 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
724 : "smb2_close_recv failed\n");
725 :
726 0 : done:
727 0 : smb2_util_unlink(tree, fname);
728 0 : smb2_tdis(tree);
729 0 : smb2_logoff(tree->session);
730 0 : return ret;
731 : }
732 :
733 0 : static bool test_compound_related7(struct torture_context *tctx,
734 : struct smb2_tree *tree)
735 : {
736 0 : const char *fname = "compound_related4.dat";
737 0 : 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 0 : bool ret = true;
746 :
747 0 : smb2_util_unlink(tree, fname);
748 :
749 0 : ZERO_STRUCT(cr);
750 0 : cr.level = RAW_OPEN_SMB2;
751 0 : cr.in.create_flags = 0;
752 0 : cr.in.desired_access = SEC_STD_READ_CONTROL |
753 : SEC_STD_WRITE_DAC |
754 : SEC_STD_WRITE_OWNER;
755 0 : cr.in.create_options = 0;
756 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
757 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
758 : NTCREATEX_SHARE_ACCESS_READ |
759 : NTCREATEX_SHARE_ACCESS_WRITE;
760 0 : cr.in.alloc_size = 0;
761 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
762 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
763 0 : cr.in.security_flags = 0;
764 0 : cr.in.fname = fname;
765 :
766 0 : status = smb2_create(tree, tctx, &cr);
767 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
768 : "smb2_create failed\n");
769 :
770 0 : hd = cr.out.file.handle;
771 0 : torture_comment(tctx, "set a sec desc allowing no write by CREATOR_OWNER\n");
772 0 : 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,
777 : 0,
778 : NULL);
779 0 : torture_assert_not_null_goto(tctx, sd, ret, done,
780 : "security_descriptor_dacl_create failed\n");
781 :
782 0 : set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
783 0 : set.set_secdesc.in.file.handle = hd;
784 0 : set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
785 0 : set.set_secdesc.in.sd = sd;
786 :
787 0 : status = smb2_setinfo_file(tree, &set);
788 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
789 : "smb2_setinfo_file failed\n");
790 :
791 0 : torture_comment(tctx, "try open for write\n");
792 0 : cr.in.desired_access = SEC_FILE_WRITE_DATA;
793 0 : smb2_transport_compound_start(tree->session->transport, 4);
794 :
795 0 : req[0] = smb2_create_send(tree, &cr);
796 0 : torture_assert_not_null_goto(tctx, req[0], ret, done,
797 : "smb2_create_send failed\n");
798 :
799 0 : hd.data[0] = UINT64_MAX;
800 0 : hd.data[1] = UINT64_MAX;
801 :
802 0 : smb2_transport_compound_set_related(tree->session->transport, true);
803 :
804 0 : ZERO_STRUCT(nt);
805 0 : nt.in.recursive = true;
806 0 : nt.in.buffer_size = 0x1000;
807 0 : nt.in.file.handle = hd;
808 0 : nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
809 0 : nt.in.unknown = 0x00000000;
810 :
811 0 : req[1] = smb2_notify_send(tree, &nt);
812 0 : torture_assert_not_null_goto(tctx, req[1], ret, done,
813 : "smb2_notify_send failed\n");
814 :
815 0 : ZERO_STRUCT(cl);
816 0 : cl.in.file.handle = hd;
817 :
818 0 : req[2] = smb2_close_send(tree, &cl);
819 0 : torture_assert_not_null_goto(tctx, req[2], ret, done,
820 : "smb2_close_send failed\n");
821 :
822 0 : set.set_secdesc.in.file.handle = hd;
823 :
824 0 : req[3] = smb2_setinfo_file_send(tree, &set);
825 0 : torture_assert_not_null_goto(tctx, req[3], ret, done,
826 : "smb2_setinfo_file_send failed\n");
827 :
828 0 : status = smb2_create_recv(req[0], tree, &cr);
829 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
830 : ret, done,
831 : "smb2_create_recv failed\n");
832 :
833 0 : status = smb2_notify_recv(req[1], tree, &nt);
834 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
835 : ret, done,
836 : "smb2_notify_recv failed\n");
837 :
838 0 : status = smb2_close_recv(req[2], &cl);
839 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
840 : ret, done,
841 : "smb2_close_recv failed\n");
842 :
843 0 : status = smb2_setinfo_recv(req[3]);
844 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
845 : ret, done,
846 : "smb2_setinfo_recv failed\n");
847 :
848 0 : done:
849 0 : smb2_util_unlink(tree, fname);
850 0 : smb2_tdis(tree);
851 0 : smb2_logoff(tree->session);
852 0 : return ret;
853 : }
854 :
855 0 : static bool test_compound_related8(struct torture_context *tctx,
856 : struct smb2_tree *tree)
857 : {
858 0 : const char *fname = "compound_related8.dat";
859 0 : const char *fname_nonexisting = "compound_related8.dat.void";
860 0 : 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 0 : bool ret = true;
869 :
870 0 : smb2_util_unlink(tree, fname);
871 :
872 0 : ZERO_STRUCT(cr);
873 0 : cr.level = RAW_OPEN_SMB2;
874 0 : cr.in.create_flags = 0;
875 0 : cr.in.desired_access = SEC_STD_READ_CONTROL |
876 : SEC_STD_WRITE_DAC |
877 : SEC_STD_WRITE_OWNER;
878 0 : cr.in.create_options = 0;
879 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
880 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
881 : NTCREATEX_SHARE_ACCESS_READ |
882 : NTCREATEX_SHARE_ACCESS_WRITE;
883 0 : cr.in.alloc_size = 0;
884 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
885 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
886 0 : cr.in.security_flags = 0;
887 0 : cr.in.fname = fname;
888 :
889 0 : status = smb2_create(tree, tctx, &cr);
890 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
891 : "smb2_create failed\n");
892 :
893 0 : hd = cr.out.file.handle;
894 :
895 0 : smb2_transport_compound_start(tree->session->transport, 4);
896 :
897 0 : torture_comment(tctx, "try open for write\n");
898 0 : cr.in.fname = fname_nonexisting;
899 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN;
900 :
901 0 : req[0] = smb2_create_send(tree, &cr);
902 0 : torture_assert_not_null_goto(tctx, req[0], ret, done,
903 : "smb2_create_send failed\n");
904 :
905 0 : hd.data[0] = UINT64_MAX;
906 0 : hd.data[1] = UINT64_MAX;
907 :
908 0 : smb2_transport_compound_set_related(tree->session->transport, true);
909 :
910 0 : ZERO_STRUCT(nt);
911 0 : nt.in.recursive = true;
912 0 : nt.in.buffer_size = 0x1000;
913 0 : nt.in.file.handle = hd;
914 0 : nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
915 0 : nt.in.unknown = 0x00000000;
916 :
917 0 : req[1] = smb2_notify_send(tree, &nt);
918 0 : torture_assert_not_null_goto(tctx, req[1], ret, done,
919 : "smb2_notify_send failed\n");
920 :
921 0 : ZERO_STRUCT(cl);
922 0 : cl.in.file.handle = hd;
923 :
924 0 : req[2] = smb2_close_send(tree, &cl);
925 0 : torture_assert_not_null_goto(tctx, req[2], ret, done,
926 : "smb2_close_send failed\n");
927 :
928 0 : 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,
933 : 0,
934 : NULL);
935 0 : torture_assert_not_null_goto(tctx, sd, ret, done,
936 : "security_descriptor_dacl_create failed\n");
937 :
938 0 : set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
939 0 : set.set_secdesc.in.file.handle = hd;
940 0 : set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
941 0 : set.set_secdesc.in.sd = sd;
942 :
943 0 : req[3] = smb2_setinfo_file_send(tree, &set);
944 0 : torture_assert_not_null_goto(tctx, req[3], ret, done,
945 : "smb2_setinfo_file_send failed\n");
946 :
947 0 : status = smb2_create_recv(req[0], tree, &cr);
948 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
949 : ret, done,
950 : "smb2_create_recv failed\n");
951 :
952 0 : status = smb2_notify_recv(req[1], tree, &nt);
953 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
954 : ret, done,
955 : "smb2_notify_recv failed\n");
956 :
957 0 : status = smb2_close_recv(req[2], &cl);
958 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
959 : ret, done,
960 : "smb2_close_recv failed\n");
961 :
962 0 : status = smb2_setinfo_recv(req[3]);
963 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
964 : ret, done,
965 : "smb2_setinfo_recv failed\n");
966 :
967 0 : done:
968 0 : smb2_util_unlink(tree, fname);
969 0 : smb2_tdis(tree);
970 0 : smb2_logoff(tree->session);
971 0 : return ret;
972 : }
973 :
974 0 : static bool test_compound_related9(struct torture_context *tctx,
975 : struct smb2_tree *tree)
976 : {
977 0 : const char *fname = "compound_related9.dat";
978 0 : 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 0 : bool ret = true;
987 :
988 0 : smb2_util_unlink(tree, fname);
989 :
990 0 : ZERO_STRUCT(cr);
991 0 : cr.level = RAW_OPEN_SMB2;
992 0 : cr.in.create_flags = 0;
993 0 : cr.in.desired_access = SEC_STD_READ_CONTROL |
994 : SEC_STD_WRITE_DAC |
995 : SEC_STD_WRITE_OWNER;
996 0 : cr.in.create_options = 0;
997 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
998 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
999 : NTCREATEX_SHARE_ACCESS_READ |
1000 : NTCREATEX_SHARE_ACCESS_WRITE;
1001 0 : cr.in.alloc_size = 0;
1002 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1003 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
1004 0 : cr.in.security_flags = 0;
1005 0 : cr.in.fname = fname;
1006 :
1007 0 : status = smb2_create(tree, tctx, &cr);
1008 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1009 : "smb2_create failed\n");
1010 :
1011 0 : hd = cr.out.file.handle;
1012 :
1013 0 : smb2_transport_compound_start(tree->session->transport, 3);
1014 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1015 :
1016 0 : ZERO_STRUCT(nt);
1017 0 : nt.in.recursive = true;
1018 0 : nt.in.buffer_size = 0x1000;
1019 0 : nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1020 :
1021 0 : req[0] = smb2_notify_send(tree, &nt);
1022 0 : torture_assert_not_null_goto(tctx, req[0], ret, done,
1023 : "smb2_notify_send failed\n");
1024 :
1025 0 : ZERO_STRUCT(cl);
1026 0 : cl.in.file.handle = hd;
1027 :
1028 0 : req[1] = smb2_close_send(tree, &cl);
1029 0 : torture_assert_not_null_goto(tctx, req[1], ret, done,
1030 : "smb2_close_send failed\n");
1031 :
1032 0 : 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,
1037 : 0,
1038 : NULL);
1039 0 : torture_assert_not_null_goto(tctx, sd, ret, done,
1040 : "security_descriptor_dacl_create failed\n");
1041 :
1042 0 : set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
1043 0 : set.set_secdesc.in.file.handle = hd;
1044 0 : set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
1045 0 : set.set_secdesc.in.sd = sd;
1046 :
1047 0 : req[2] = smb2_setinfo_file_send(tree, &set);
1048 0 : torture_assert_not_null_goto(tctx, req[2], ret, done,
1049 : "smb2_setinfo_file_send failed\n");
1050 :
1051 0 : status = smb2_notify_recv(req[0], tree, &nt);
1052 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INVALID_PARAMETER,
1053 : ret, done,
1054 : "smb2_notify_recv failed\n");
1055 :
1056 0 : status = smb2_close_recv(req[1], &cl);
1057 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INVALID_PARAMETER,
1058 : ret, done,
1059 : "smb2_close_recv failed\n");
1060 :
1061 0 : status = smb2_setinfo_recv(req[2]);
1062 0 : torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INVALID_PARAMETER,
1063 : ret, done,
1064 : "smb2_setinfo_recv failed\n");
1065 :
1066 0 : done:
1067 0 : smb2_util_unlink(tree, fname);
1068 0 : smb2_tdis(tree);
1069 0 : smb2_logoff(tree->session);
1070 0 : return ret;
1071 : }
1072 :
1073 0 : static bool test_compound_padding(struct torture_context *tctx,
1074 : struct smb2_tree *tree)
1075 : {
1076 : struct smb2_handle h;
1077 : struct smb2_create cr;
1078 : struct smb2_read r;
1079 0 : const char *fname = "compound_read.dat";
1080 0 : const char *sname = "compound_read.dat:foo";
1081 : struct smb2_request *req[3];
1082 : NTSTATUS status;
1083 0 : bool ret = false;
1084 :
1085 0 : smb2_util_unlink(tree, fname);
1086 :
1087 : /* Write file */
1088 0 : ZERO_STRUCT(cr);
1089 0 : cr.in.desired_access = SEC_FILE_WRITE_DATA;
1090 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1091 0 : cr.in.create_disposition = NTCREATEX_DISP_CREATE;
1092 0 : cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1093 0 : cr.in.fname = fname;
1094 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1095 : NTCREATEX_SHARE_ACCESS_WRITE|
1096 : NTCREATEX_SHARE_ACCESS_DELETE;
1097 0 : status = smb2_create(tree, tctx, &cr);
1098 0 : CHECK_STATUS(status, NT_STATUS_OK);
1099 0 : h = cr.out.file.handle;
1100 :
1101 0 : status = smb2_util_write(tree, h, "123", 0, 3);
1102 0 : CHECK_STATUS(status, NT_STATUS_OK);
1103 :
1104 0 : smb2_util_close(tree, h);
1105 :
1106 : /* Write stream */
1107 0 : ZERO_STRUCT(cr);
1108 0 : cr.in.desired_access = SEC_FILE_WRITE_DATA;
1109 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1110 0 : cr.in.create_disposition = NTCREATEX_DISP_CREATE;
1111 0 : cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1112 0 : cr.in.fname = sname;
1113 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1114 : NTCREATEX_SHARE_ACCESS_WRITE|
1115 : NTCREATEX_SHARE_ACCESS_DELETE;
1116 0 : status = smb2_create(tree, tctx, &cr);
1117 0 : CHECK_STATUS(status, NT_STATUS_OK);
1118 0 : h = cr.out.file.handle;
1119 :
1120 0 : status = smb2_util_write(tree, h, "456", 0, 3);
1121 0 : CHECK_STATUS(status, NT_STATUS_OK);
1122 :
1123 0 : smb2_util_close(tree, h);
1124 :
1125 : /* Check compound read from basefile */
1126 0 : smb2_transport_compound_start(tree->session->transport, 2);
1127 :
1128 0 : ZERO_STRUCT(cr);
1129 0 : cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1130 0 : cr.in.desired_access = SEC_FILE_READ_DATA;
1131 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1132 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN;
1133 0 : cr.in.fname = fname;
1134 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1135 : NTCREATEX_SHARE_ACCESS_WRITE|
1136 : NTCREATEX_SHARE_ACCESS_DELETE;
1137 0 : req[0] = smb2_create_send(tree, &cr);
1138 :
1139 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1140 :
1141 0 : ZERO_STRUCT(r);
1142 0 : h.data[0] = UINT64_MAX;
1143 0 : h.data[1] = UINT64_MAX;
1144 0 : r.in.file.handle = h;
1145 0 : r.in.length = 3;
1146 0 : r.in.offset = 0;
1147 0 : r.in.min_count = 1;
1148 0 : req[1] = smb2_read_send(tree, &r);
1149 :
1150 0 : status = smb2_create_recv(req[0], tree, &cr);
1151 0 : CHECK_STATUS(status, NT_STATUS_OK);
1152 :
1153 : /*
1154 : * We must do a manual smb2_request_receive() in order to be
1155 : * able to check the transport layer info, as smb2_read_recv()
1156 : * will destroy the req. smb2_read_recv() will call
1157 : * smb2_request_receive() again, but that's ok.
1158 : */
1159 0 : if (!smb2_request_receive(req[1]) ||
1160 0 : !smb2_request_is_ok(req[1])) {
1161 0 : torture_fail(tctx, "failed to receive read request");
1162 : }
1163 :
1164 : /*
1165 : * size must be 24: 16 byte read response header plus 3
1166 : * requested bytes padded to an 8 byte boundary.
1167 : */
1168 0 : CHECK_VALUE(req[1]->in.body_size, 24);
1169 :
1170 0 : status = smb2_read_recv(req[1], tree, &r);
1171 0 : CHECK_STATUS(status, NT_STATUS_OK);
1172 :
1173 0 : smb2_util_close(tree, cr.out.file.handle);
1174 :
1175 : /* Check compound read from stream */
1176 0 : smb2_transport_compound_start(tree->session->transport, 2);
1177 :
1178 0 : ZERO_STRUCT(cr);
1179 0 : cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1180 0 : cr.in.desired_access = SEC_FILE_READ_DATA;
1181 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1182 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN;
1183 0 : cr.in.fname = sname;
1184 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1185 : NTCREATEX_SHARE_ACCESS_WRITE|
1186 : NTCREATEX_SHARE_ACCESS_DELETE;
1187 0 : req[0] = smb2_create_send(tree, &cr);
1188 :
1189 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1190 :
1191 0 : ZERO_STRUCT(r);
1192 0 : h.data[0] = UINT64_MAX;
1193 0 : h.data[1] = UINT64_MAX;
1194 0 : r.in.file.handle = h;
1195 0 : r.in.length = 3;
1196 0 : r.in.offset = 0;
1197 0 : r.in.min_count = 1;
1198 0 : req[1] = smb2_read_send(tree, &r);
1199 :
1200 0 : status = smb2_create_recv(req[0], tree, &cr);
1201 0 : CHECK_STATUS(status, NT_STATUS_OK);
1202 :
1203 : /*
1204 : * We must do a manual smb2_request_receive() in order to be
1205 : * able to check the transport layer info, as smb2_read_recv()
1206 : * will destroy the req. smb2_read_recv() will call
1207 : * smb2_request_receive() again, but that's ok.
1208 : */
1209 0 : if (!smb2_request_receive(req[1]) ||
1210 0 : !smb2_request_is_ok(req[1])) {
1211 0 : torture_fail(tctx, "failed to receive read request");
1212 : }
1213 :
1214 : /*
1215 : * size must be 24: 16 byte read response header plus 3
1216 : * requested bytes padded to an 8 byte boundary.
1217 : */
1218 0 : CHECK_VALUE(req[1]->in.body_size, 24);
1219 :
1220 0 : status = smb2_read_recv(req[1], tree, &r);
1221 0 : CHECK_STATUS(status, NT_STATUS_OK);
1222 :
1223 0 : h = cr.out.file.handle;
1224 :
1225 : /* Check 2 compound (unrelateated) reads from existing stream handle */
1226 0 : smb2_transport_compound_start(tree->session->transport, 2);
1227 :
1228 0 : ZERO_STRUCT(r);
1229 0 : r.in.file.handle = h;
1230 0 : r.in.length = 3;
1231 0 : r.in.offset = 0;
1232 0 : r.in.min_count = 1;
1233 0 : req[0] = smb2_read_send(tree, &r);
1234 0 : req[1] = smb2_read_send(tree, &r);
1235 :
1236 : /*
1237 : * We must do a manual smb2_request_receive() in order to be
1238 : * able to check the transport layer info, as smb2_read_recv()
1239 : * will destroy the req. smb2_read_recv() will call
1240 : * smb2_request_receive() again, but that's ok.
1241 : */
1242 0 : if (!smb2_request_receive(req[0]) ||
1243 0 : !smb2_request_is_ok(req[0])) {
1244 0 : torture_fail(tctx, "failed to receive read request");
1245 : }
1246 0 : if (!smb2_request_receive(req[1]) ||
1247 0 : !smb2_request_is_ok(req[1])) {
1248 0 : torture_fail(tctx, "failed to receive read request");
1249 : }
1250 :
1251 : /*
1252 : * size must be 24: 16 byte read response header plus 3
1253 : * requested bytes padded to an 8 byte boundary.
1254 : */
1255 0 : CHECK_VALUE(req[0]->in.body_size, 24);
1256 0 : CHECK_VALUE(req[1]->in.body_size, 24);
1257 :
1258 0 : status = smb2_read_recv(req[0], tree, &r);
1259 0 : CHECK_STATUS(status, NT_STATUS_OK);
1260 0 : status = smb2_read_recv(req[1], tree, &r);
1261 0 : CHECK_STATUS(status, NT_STATUS_OK);
1262 :
1263 : /*
1264 : * now try a single read from the stream and verify there's no padding
1265 : */
1266 0 : ZERO_STRUCT(r);
1267 0 : r.in.file.handle = h;
1268 0 : r.in.length = 3;
1269 0 : r.in.offset = 0;
1270 0 : r.in.min_count = 1;
1271 0 : req[0] = smb2_read_send(tree, &r);
1272 :
1273 : /*
1274 : * We must do a manual smb2_request_receive() in order to be
1275 : * able to check the transport layer info, as smb2_read_recv()
1276 : * will destroy the req. smb2_read_recv() will call
1277 : * smb2_request_receive() again, but that's ok.
1278 : */
1279 0 : if (!smb2_request_receive(req[0]) ||
1280 0 : !smb2_request_is_ok(req[0])) {
1281 0 : torture_fail(tctx, "failed to receive read request");
1282 : }
1283 :
1284 : /*
1285 : * size must be 19: 16 byte read response header plus 3
1286 : * requested bytes without padding.
1287 : */
1288 0 : CHECK_VALUE(req[0]->in.body_size, 19);
1289 :
1290 0 : status = smb2_read_recv(req[0], tree, &r);
1291 0 : CHECK_STATUS(status, NT_STATUS_OK);
1292 :
1293 0 : smb2_util_close(tree, h);
1294 :
1295 0 : status = smb2_util_unlink(tree, fname);
1296 0 : CHECK_STATUS(status, NT_STATUS_OK);
1297 :
1298 0 : ret = true;
1299 0 : done:
1300 0 : return ret;
1301 : }
1302 :
1303 0 : static bool test_compound_create_write_close(struct torture_context *tctx,
1304 : struct smb2_tree *tree)
1305 : {
1306 0 : struct smb2_handle handle = { .data = { UINT64_MAX, UINT64_MAX } };
1307 : struct smb2_create create;
1308 : struct smb2_write write;
1309 : struct smb2_close close;
1310 0 : const char *fname = "compound_create_write_close.dat";
1311 : struct smb2_request *req[3];
1312 : NTSTATUS status;
1313 0 : bool ret = false;
1314 :
1315 0 : smb2_util_unlink(tree, fname);
1316 :
1317 0 : ZERO_STRUCT(create);
1318 0 : create.in.security_flags = 0x00;
1319 0 : create.in.oplock_level = 0;
1320 0 : create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
1321 0 : create.in.create_flags = 0x00000000;
1322 0 : create.in.reserved = 0x00000000;
1323 0 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
1324 0 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1325 0 : create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1326 : NTCREATEX_SHARE_ACCESS_WRITE |
1327 : NTCREATEX_SHARE_ACCESS_DELETE;
1328 0 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1329 0 : create.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
1330 : NTCREATEX_OPTIONS_ASYNC_ALERT |
1331 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
1332 : 0x00200000;
1333 0 : create.in.fname = fname;
1334 :
1335 0 : smb2_transport_compound_start(tree->session->transport, 3);
1336 :
1337 0 : req[0] = smb2_create_send(tree, &create);
1338 :
1339 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1340 :
1341 0 : ZERO_STRUCT(write);
1342 0 : write.in.file.handle = handle;
1343 0 : write.in.offset = 0;
1344 0 : write.in.data = data_blob_talloc(tctx, NULL, 1024);
1345 :
1346 0 : req[1] = smb2_write_send(tree, &write);
1347 :
1348 0 : ZERO_STRUCT(close);
1349 0 : close.in.file.handle = handle;
1350 :
1351 0 : req[2] = smb2_close_send(tree, &close);
1352 :
1353 0 : status = smb2_create_recv(req[0], tree, &create);
1354 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1355 : "CREATE failed.");
1356 :
1357 0 : status = smb2_write_recv(req[1], &write);
1358 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1359 : "WRITE failed.");
1360 :
1361 0 : status = smb2_close_recv(req[2], &close);
1362 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1363 : "CLOSE failed.");
1364 :
1365 0 : status = smb2_util_unlink(tree, fname);
1366 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1367 : "File deletion failed.");
1368 :
1369 0 : ret = true;
1370 0 : done:
1371 0 : return ret;
1372 : }
1373 :
1374 0 : static bool test_compound_unrelated1(struct torture_context *tctx,
1375 : struct smb2_tree *tree)
1376 : {
1377 : struct smb2_handle hd;
1378 : struct smb2_create cr;
1379 : NTSTATUS status;
1380 0 : const char *fname = "compound_unrelated1.dat";
1381 : struct smb2_close cl;
1382 0 : bool ret = true;
1383 : struct smb2_request *req[5];
1384 :
1385 0 : smb2_transport_credits_ask_num(tree->session->transport, 5);
1386 :
1387 0 : smb2_util_unlink(tree, fname);
1388 :
1389 0 : smb2_transport_credits_ask_num(tree->session->transport, 1);
1390 :
1391 0 : ZERO_STRUCT(cr);
1392 0 : cr.in.security_flags = 0x00;
1393 0 : cr.in.oplock_level = 0;
1394 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
1395 0 : cr.in.create_flags = 0x00000000;
1396 0 : cr.in.reserved = 0x00000000;
1397 0 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
1398 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1399 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1400 : NTCREATEX_SHARE_ACCESS_WRITE |
1401 : NTCREATEX_SHARE_ACCESS_DELETE;
1402 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1403 0 : cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
1404 : NTCREATEX_OPTIONS_ASYNC_ALERT |
1405 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
1406 : 0x00200000;
1407 0 : cr.in.fname = fname;
1408 :
1409 0 : smb2_transport_compound_start(tree->session->transport, 5);
1410 :
1411 0 : req[0] = smb2_create_send(tree, &cr);
1412 :
1413 0 : hd.data[0] = UINT64_MAX;
1414 0 : hd.data[1] = UINT64_MAX;
1415 :
1416 0 : ZERO_STRUCT(cl);
1417 0 : cl.in.file.handle = hd;
1418 0 : req[1] = smb2_close_send(tree, &cl);
1419 0 : req[2] = smb2_close_send(tree, &cl);
1420 0 : req[3] = smb2_close_send(tree, &cl);
1421 0 : req[4] = smb2_close_send(tree, &cl);
1422 :
1423 0 : status = smb2_create_recv(req[0], tree, &cr);
1424 0 : CHECK_STATUS(status, NT_STATUS_OK);
1425 0 : status = smb2_close_recv(req[1], &cl);
1426 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1427 0 : status = smb2_close_recv(req[2], &cl);
1428 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1429 0 : status = smb2_close_recv(req[3], &cl);
1430 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1431 0 : status = smb2_close_recv(req[4], &cl);
1432 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1433 :
1434 0 : smb2_util_unlink(tree, fname);
1435 0 : done:
1436 0 : return ret;
1437 : }
1438 :
1439 0 : static bool test_compound_invalid1(struct torture_context *tctx,
1440 : struct smb2_tree *tree)
1441 : {
1442 : struct smb2_handle hd;
1443 : struct smb2_create cr;
1444 : NTSTATUS status;
1445 0 : const char *fname = "compound_invalid1.dat";
1446 : struct smb2_close cl;
1447 0 : bool ret = true;
1448 : struct smb2_request *req[3];
1449 :
1450 0 : smb2_transport_credits_ask_num(tree->session->transport, 3);
1451 :
1452 0 : smb2_util_unlink(tree, fname);
1453 :
1454 0 : smb2_transport_credits_ask_num(tree->session->transport, 1);
1455 :
1456 0 : ZERO_STRUCT(cr);
1457 0 : cr.in.security_flags = 0x00;
1458 0 : cr.in.oplock_level = 0;
1459 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
1460 0 : cr.in.create_flags = 0x00000000;
1461 0 : cr.in.reserved = 0x00000000;
1462 0 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
1463 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1464 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1465 : NTCREATEX_SHARE_ACCESS_WRITE |
1466 : NTCREATEX_SHARE_ACCESS_DELETE;
1467 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1468 0 : cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
1469 : NTCREATEX_OPTIONS_ASYNC_ALERT |
1470 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
1471 : 0x00200000;
1472 0 : cr.in.fname = fname;
1473 :
1474 0 : smb2_transport_compound_start(tree->session->transport, 3);
1475 :
1476 : /* passing the first request with the related flag is invalid */
1477 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1478 :
1479 0 : req[0] = smb2_create_send(tree, &cr);
1480 :
1481 0 : hd.data[0] = UINT64_MAX;
1482 0 : hd.data[1] = UINT64_MAX;
1483 :
1484 0 : ZERO_STRUCT(cl);
1485 0 : cl.in.file.handle = hd;
1486 0 : req[1] = smb2_close_send(tree, &cl);
1487 :
1488 0 : smb2_transport_compound_set_related(tree->session->transport, false);
1489 0 : req[2] = smb2_close_send(tree, &cl);
1490 :
1491 0 : status = smb2_create_recv(req[0], tree, &cr);
1492 : /* TODO: check why this fails with --signing=required */
1493 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1494 0 : status = smb2_close_recv(req[1], &cl);
1495 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1496 0 : status = smb2_close_recv(req[2], &cl);
1497 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1498 :
1499 0 : smb2_util_unlink(tree, fname);
1500 0 : done:
1501 0 : return ret;
1502 : }
1503 :
1504 0 : static bool test_compound_invalid2(struct torture_context *tctx,
1505 : struct smb2_tree *tree)
1506 : {
1507 : struct smb2_handle hd;
1508 : struct smb2_create cr;
1509 : NTSTATUS status;
1510 0 : const char *fname = "compound_invalid2.dat";
1511 : struct smb2_close cl;
1512 0 : bool ret = true;
1513 : struct smb2_request *req[5];
1514 0 : struct smbXcli_tcon *saved_tcon = tree->smbXcli;
1515 0 : struct smbXcli_session *saved_session = tree->session->smbXcli;
1516 :
1517 0 : smb2_transport_credits_ask_num(tree->session->transport, 5);
1518 :
1519 0 : smb2_util_unlink(tree, fname);
1520 :
1521 0 : smb2_transport_credits_ask_num(tree->session->transport, 1);
1522 :
1523 0 : ZERO_STRUCT(cr);
1524 0 : cr.in.security_flags = 0x00;
1525 0 : cr.in.oplock_level = 0;
1526 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
1527 0 : cr.in.create_flags = 0x00000000;
1528 0 : cr.in.reserved = 0x00000000;
1529 0 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
1530 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1531 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1532 : NTCREATEX_SHARE_ACCESS_WRITE |
1533 : NTCREATEX_SHARE_ACCESS_DELETE;
1534 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1535 0 : cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
1536 : NTCREATEX_OPTIONS_ASYNC_ALERT |
1537 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
1538 : 0x00200000;
1539 0 : cr.in.fname = fname;
1540 :
1541 0 : smb2_transport_compound_start(tree->session->transport, 5);
1542 :
1543 0 : req[0] = smb2_create_send(tree, &cr);
1544 :
1545 0 : hd.data[0] = UINT64_MAX;
1546 0 : hd.data[1] = UINT64_MAX;
1547 :
1548 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1549 :
1550 0 : ZERO_STRUCT(cl);
1551 0 : cl.in.file.handle = hd;
1552 :
1553 0 : tree->smbXcli = smbXcli_tcon_create(tree);
1554 0 : smb2cli_tcon_set_values(tree->smbXcli,
1555 : NULL, /* session */
1556 : 0xFFFFFFFF, /* tcon_id */
1557 : 0, /* type */
1558 : 0, /* flags */
1559 : 0, /* capabilities */
1560 : 0 /* maximal_access */);
1561 :
1562 0 : tree->session->smbXcli = smbXcli_session_shallow_copy(tree->session,
1563 0 : tree->session->smbXcli);
1564 0 : smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
1565 :
1566 0 : req[1] = smb2_close_send(tree, &cl);
1567 : /* strange that this is not generating invalid parameter */
1568 0 : smb2_transport_compound_set_related(tree->session->transport, false);
1569 0 : req[2] = smb2_close_send(tree, &cl);
1570 0 : req[3] = smb2_close_send(tree, &cl);
1571 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1572 0 : req[4] = smb2_close_send(tree, &cl);
1573 :
1574 0 : status = smb2_create_recv(req[0], tree, &cr);
1575 0 : CHECK_STATUS(status, NT_STATUS_OK);
1576 0 : status = smb2_close_recv(req[1], &cl);
1577 0 : CHECK_STATUS(status, NT_STATUS_OK);
1578 0 : status = smb2_close_recv(req[2], &cl);
1579 0 : CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
1580 0 : status = smb2_close_recv(req[3], &cl);
1581 0 : CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
1582 0 : status = smb2_close_recv(req[4], &cl);
1583 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1584 :
1585 0 : TALLOC_FREE(tree->smbXcli);
1586 0 : tree->smbXcli = saved_tcon;
1587 0 : TALLOC_FREE(tree->session->smbXcli);
1588 0 : tree->session->smbXcli = saved_session;
1589 :
1590 0 : smb2_util_unlink(tree, fname);
1591 0 : done:
1592 0 : return ret;
1593 : }
1594 :
1595 0 : static bool test_compound_invalid3(struct torture_context *tctx,
1596 : struct smb2_tree *tree)
1597 : {
1598 : struct smb2_handle hd;
1599 : struct smb2_create cr;
1600 : NTSTATUS status;
1601 0 : const char *fname = "compound_invalid3.dat";
1602 : struct smb2_close cl;
1603 0 : bool ret = true;
1604 : struct smb2_request *req[5];
1605 :
1606 0 : smb2_transport_credits_ask_num(tree->session->transport, 5);
1607 :
1608 0 : smb2_util_unlink(tree, fname);
1609 :
1610 0 : smb2_transport_credits_ask_num(tree->session->transport, 1);
1611 :
1612 0 : ZERO_STRUCT(cr);
1613 0 : cr.in.security_flags = 0x00;
1614 0 : cr.in.oplock_level = 0;
1615 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
1616 0 : cr.in.create_flags = 0x00000000;
1617 0 : cr.in.reserved = 0x00000000;
1618 0 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
1619 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1620 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1621 : NTCREATEX_SHARE_ACCESS_WRITE |
1622 : NTCREATEX_SHARE_ACCESS_DELETE;
1623 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1624 0 : cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
1625 : NTCREATEX_OPTIONS_ASYNC_ALERT |
1626 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
1627 : 0x00200000;
1628 0 : cr.in.fname = fname;
1629 :
1630 0 : smb2_transport_compound_start(tree->session->transport, 5);
1631 :
1632 0 : req[0] = smb2_create_send(tree, &cr);
1633 :
1634 0 : hd.data[0] = UINT64_MAX;
1635 0 : hd.data[1] = UINT64_MAX;
1636 :
1637 0 : ZERO_STRUCT(cl);
1638 0 : cl.in.file.handle = hd;
1639 0 : req[1] = smb2_close_send(tree, &cl);
1640 0 : req[2] = smb2_close_send(tree, &cl);
1641 : /* flipping the related flag is invalid */
1642 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1643 0 : req[3] = smb2_close_send(tree, &cl);
1644 0 : req[4] = smb2_close_send(tree, &cl);
1645 :
1646 0 : status = smb2_create_recv(req[0], tree, &cr);
1647 0 : CHECK_STATUS(status, NT_STATUS_OK);
1648 0 : status = smb2_close_recv(req[1], &cl);
1649 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1650 0 : status = smb2_close_recv(req[2], &cl);
1651 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1652 0 : status = smb2_close_recv(req[3], &cl);
1653 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1654 0 : status = smb2_close_recv(req[4], &cl);
1655 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1656 :
1657 0 : smb2_util_unlink(tree, fname);
1658 0 : done:
1659 0 : return ret;
1660 : }
1661 :
1662 0 : static bool test_compound_invalid4(struct torture_context *tctx,
1663 : struct smb2_tree *tree)
1664 : {
1665 : struct smb2_create cr;
1666 : struct smb2_read rd;
1667 : NTSTATUS status;
1668 0 : const char *fname = "compound_invalid4.dat";
1669 : struct smb2_close cl;
1670 0 : bool ret = true;
1671 : bool ok;
1672 : struct smb2_request *req[2];
1673 :
1674 0 : smb2_transport_credits_ask_num(tree->session->transport, 2);
1675 :
1676 0 : smb2_util_unlink(tree, fname);
1677 :
1678 0 : ZERO_STRUCT(cr);
1679 0 : cr.in.security_flags = 0x00;
1680 0 : cr.in.oplock_level = 0;
1681 0 : cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
1682 0 : cr.in.create_flags = 0x00000000;
1683 0 : cr.in.reserved = 0x00000000;
1684 0 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
1685 0 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1686 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1687 : NTCREATEX_SHARE_ACCESS_WRITE |
1688 : NTCREATEX_SHARE_ACCESS_DELETE;
1689 0 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1690 0 : cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
1691 : NTCREATEX_OPTIONS_ASYNC_ALERT |
1692 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
1693 : 0x00200000;
1694 0 : cr.in.fname = fname;
1695 :
1696 0 : status = smb2_create(tree, tctx, &cr);
1697 0 : CHECK_STATUS(status, NT_STATUS_OK);
1698 :
1699 0 : smb2_transport_compound_start(tree->session->transport, 2);
1700 :
1701 0 : ZERO_STRUCT(rd);
1702 0 : rd.in.file.handle = cr.out.file.handle;
1703 0 : rd.in.length = 1;
1704 0 : rd.in.offset = 0;
1705 0 : req[0] = smb2_read_send(tree, &rd);
1706 :
1707 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1708 :
1709 : /*
1710 : * Send a completely bogus request as second compound
1711 : * element. This triggers smbd_smb2_request_error() in in
1712 : * smbd_smb2_request_dispatch() before calling
1713 : * smbd_smb2_request_dispatch_update_counts().
1714 : */
1715 :
1716 0 : req[1] = smb2_request_init_tree(tree, 0xff, 0x04, false, 0);
1717 0 : smb2_transport_send(req[1]);
1718 :
1719 0 : status = smb2_read_recv(req[0], tctx, &rd);
1720 0 : CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
1721 :
1722 0 : ok = smb2_request_receive(req[1]);
1723 0 : torture_assert(tctx, ok, "Invalid request failed\n");
1724 0 : CHECK_STATUS(req[1]->status, NT_STATUS_INVALID_PARAMETER);
1725 :
1726 0 : ZERO_STRUCT(cl);
1727 0 : cl.in.file.handle = cr.out.file.handle;
1728 :
1729 0 : status = smb2_close(tree, &cl);
1730 0 : CHECK_STATUS(status, NT_STATUS_OK);
1731 :
1732 0 : smb2_util_unlink(tree, fname);
1733 0 : done:
1734 0 : return ret;
1735 : }
1736 :
1737 : /* Send a compound request where we expect the last request (Create, Notify)
1738 : * to go asynchronous. This works against a Win7 server and the reply is
1739 : * sent in two different packets. */
1740 0 : static bool test_compound_interim1(struct torture_context *tctx,
1741 : struct smb2_tree *tree)
1742 : {
1743 : struct smb2_handle hd;
1744 : struct smb2_create cr;
1745 0 : NTSTATUS status = NT_STATUS_OK;
1746 0 : const char *dname = "compound_interim_dir";
1747 : struct smb2_notify nt;
1748 0 : bool ret = true;
1749 : struct smb2_request *req[2];
1750 :
1751 : /* Win7 compound request implementation deviates substantially from the
1752 : * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
1753 : * verifies the Windows behavior, not the general spec behavior. */
1754 :
1755 0 : smb2_transport_credits_ask_num(tree->session->transport, 5);
1756 :
1757 0 : smb2_deltree(tree, dname);
1758 :
1759 0 : smb2_transport_credits_ask_num(tree->session->transport, 1);
1760 :
1761 0 : ZERO_STRUCT(cr);
1762 0 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
1763 0 : cr.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1764 0 : cr.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1765 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1766 : NTCREATEX_SHARE_ACCESS_WRITE |
1767 : NTCREATEX_SHARE_ACCESS_DELETE;
1768 0 : cr.in.create_disposition = NTCREATEX_DISP_CREATE;
1769 0 : cr.in.fname = dname;
1770 :
1771 0 : smb2_transport_compound_start(tree->session->transport, 2);
1772 :
1773 0 : req[0] = smb2_create_send(tree, &cr);
1774 :
1775 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1776 :
1777 0 : hd.data[0] = UINT64_MAX;
1778 0 : hd.data[1] = UINT64_MAX;
1779 :
1780 0 : ZERO_STRUCT(nt);
1781 0 : nt.in.recursive = true;
1782 0 : nt.in.buffer_size = 0x1000;
1783 0 : nt.in.file.handle = hd;
1784 0 : nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1785 0 : nt.in.unknown = 0x00000000;
1786 :
1787 0 : req[1] = smb2_notify_send(tree, &nt);
1788 :
1789 0 : status = smb2_create_recv(req[0], tree, &cr);
1790 0 : CHECK_STATUS(status, NT_STATUS_OK);
1791 :
1792 0 : smb2_cancel(req[1]);
1793 0 : status = smb2_notify_recv(req[1], tree, &nt);
1794 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
1795 :
1796 0 : smb2_util_close(tree, cr.out.file.handle);
1797 :
1798 0 : smb2_deltree(tree, dname);
1799 0 : done:
1800 0 : return ret;
1801 : }
1802 :
1803 : /* Send a compound request where we expect the middle request (Create, Notify,
1804 : * GetInfo) to go asynchronous. Against Win7 the sync request succeed while
1805 : * the async fails. All are returned in the same compound response. */
1806 0 : static bool test_compound_interim2(struct torture_context *tctx,
1807 : struct smb2_tree *tree)
1808 : {
1809 : struct smb2_handle hd;
1810 : struct smb2_create cr;
1811 0 : NTSTATUS status = NT_STATUS_OK;
1812 0 : const char *dname = "compound_interim_dir";
1813 : struct smb2_getinfo gf;
1814 : struct smb2_notify nt;
1815 0 : bool ret = true;
1816 : struct smb2_request *req[3];
1817 :
1818 : /* Win7 compound request implementation deviates substantially from the
1819 : * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
1820 : * verifies the Windows behavior, not the general spec behavior. */
1821 :
1822 0 : smb2_transport_credits_ask_num(tree->session->transport, 5);
1823 :
1824 0 : smb2_deltree(tree, dname);
1825 :
1826 0 : smb2_transport_credits_ask_num(tree->session->transport, 1);
1827 :
1828 0 : ZERO_STRUCT(cr);
1829 0 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
1830 0 : cr.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1831 0 : cr.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1832 0 : cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1833 : NTCREATEX_SHARE_ACCESS_WRITE |
1834 : NTCREATEX_SHARE_ACCESS_DELETE;
1835 0 : cr.in.create_disposition = NTCREATEX_DISP_CREATE;
1836 0 : cr.in.fname = dname;
1837 :
1838 0 : smb2_transport_compound_start(tree->session->transport, 3);
1839 :
1840 0 : req[0] = smb2_create_send(tree, &cr);
1841 :
1842 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1843 :
1844 0 : hd.data[0] = UINT64_MAX;
1845 0 : hd.data[1] = UINT64_MAX;
1846 :
1847 0 : ZERO_STRUCT(nt);
1848 0 : nt.in.recursive = true;
1849 0 : nt.in.buffer_size = 0x1000;
1850 0 : nt.in.file.handle = hd;
1851 0 : nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1852 0 : nt.in.unknown = 0x00000000;
1853 :
1854 0 : req[1] = smb2_notify_send(tree, &nt);
1855 :
1856 0 : ZERO_STRUCT(gf);
1857 0 : gf.in.file.handle = hd;
1858 0 : gf.in.info_type = SMB2_0_INFO_FILE;
1859 0 : gf.in.info_class = 0x04; /* FILE_BASIC_INFORMATION */
1860 0 : gf.in.output_buffer_length = 0x1000;
1861 0 : gf.in.input_buffer = data_blob_null;
1862 :
1863 0 : req[2] = smb2_getinfo_send(tree, &gf);
1864 :
1865 0 : status = smb2_create_recv(req[0], tree, &cr);
1866 0 : CHECK_STATUS(status, NT_STATUS_OK);
1867 :
1868 0 : status = smb2_notify_recv(req[1], tree, &nt);
1869 0 : CHECK_STATUS(status, NT_STATUS_INTERNAL_ERROR);
1870 :
1871 0 : status = smb2_getinfo_recv(req[2], tree, &gf);
1872 0 : CHECK_STATUS(status, NT_STATUS_OK);
1873 :
1874 0 : smb2_util_close(tree, cr.out.file.handle);
1875 :
1876 0 : smb2_deltree(tree, dname);
1877 0 : done:
1878 0 : return ret;
1879 : }
1880 :
1881 : /* Test compound related finds */
1882 0 : static bool test_compound_find_related(struct torture_context *tctx,
1883 : struct smb2_tree *tree)
1884 : {
1885 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1886 0 : const char *dname = "compound_find_dir";
1887 : struct smb2_create create;
1888 : struct smb2_find f;
1889 : struct smb2_handle h;
1890 : struct smb2_request *req[2];
1891 : NTSTATUS status;
1892 0 : bool ret = true;
1893 :
1894 0 : smb2_deltree(tree, dname);
1895 :
1896 0 : ZERO_STRUCT(create);
1897 0 : create.in.desired_access = SEC_RIGHTS_DIR_ALL;
1898 0 : create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1899 0 : create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1900 0 : create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1901 : NTCREATEX_SHARE_ACCESS_WRITE |
1902 : NTCREATEX_SHARE_ACCESS_DELETE;
1903 0 : create.in.create_disposition = NTCREATEX_DISP_CREATE;
1904 0 : create.in.fname = dname;
1905 :
1906 0 : status = smb2_create(tree, mem_ctx, &create);
1907 0 : h = create.out.file.handle;
1908 :
1909 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
1910 :
1911 0 : smb2_transport_compound_start(tree->session->transport, 2);
1912 :
1913 0 : ZERO_STRUCT(f);
1914 0 : f.in.file.handle = h;
1915 0 : f.in.pattern = "*";
1916 0 : f.in.max_response_size = 0x100;
1917 0 : f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
1918 :
1919 0 : req[0] = smb2_find_send(tree, &f);
1920 :
1921 0 : smb2_transport_compound_set_related(tree->session->transport, true);
1922 :
1923 0 : req[1] = smb2_find_send(tree, &f);
1924 :
1925 0 : status = smb2_find_recv(req[0], mem_ctx, &f);
1926 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
1927 :
1928 0 : status = smb2_find_recv(req[1], mem_ctx, &f);
1929 0 : torture_assert_ntstatus_equal_goto(tctx, status, STATUS_NO_MORE_FILES, ret, done, "smb2_find_recv failed\n");
1930 :
1931 0 : done:
1932 0 : smb2_util_close(tree, h);
1933 0 : smb2_deltree(tree, dname);
1934 0 : TALLOC_FREE(mem_ctx);
1935 0 : return ret;
1936 : }
1937 :
1938 : /* Test compound related finds */
1939 0 : static bool test_compound_find_close(struct torture_context *tctx,
1940 : struct smb2_tree *tree)
1941 : {
1942 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1943 0 : const char *dname = "compound_find_dir";
1944 : struct smb2_create create;
1945 : struct smb2_find f;
1946 : struct smb2_handle h;
1947 0 : struct smb2_request *req = NULL;
1948 0 : const int num_files = 5000;
1949 : int i;
1950 : NTSTATUS status;
1951 0 : bool ret = true;
1952 :
1953 0 : smb2_deltree(tree, dname);
1954 :
1955 0 : ZERO_STRUCT(create);
1956 0 : create.in.desired_access = SEC_RIGHTS_DIR_ALL;
1957 0 : create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1958 0 : create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1959 0 : create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1960 : NTCREATEX_SHARE_ACCESS_WRITE |
1961 : NTCREATEX_SHARE_ACCESS_DELETE;
1962 0 : create.in.create_disposition = NTCREATEX_DISP_CREATE;
1963 0 : create.in.fname = dname;
1964 :
1965 0 : smb2cli_conn_set_max_credits(tree->session->transport->conn, 256);
1966 :
1967 0 : status = smb2_create(tree, mem_ctx, &create);
1968 0 : h = create.out.file.handle;
1969 :
1970 0 : ZERO_STRUCT(create);
1971 0 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
1972 0 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1973 0 : create.in.create_disposition = NTCREATEX_DISP_CREATE;
1974 :
1975 0 : for (i = 0; i < num_files; i++) {
1976 0 : create.in.fname = talloc_asprintf(mem_ctx, "%s\\file%d",
1977 : dname, i);
1978 0 : status = smb2_create(tree, mem_ctx, &create);
1979 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
1980 0 : smb2_util_close(tree, create.out.file.handle);
1981 : }
1982 :
1983 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
1984 :
1985 0 : ZERO_STRUCT(f);
1986 0 : f.in.file.handle = h;
1987 0 : f.in.pattern = "*";
1988 0 : f.in.max_response_size = 8*1024*1024;
1989 0 : f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
1990 :
1991 0 : req = smb2_find_send(tree, &f);
1992 :
1993 0 : status = smb2_util_close(tree, h);
1994 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed\n");
1995 :
1996 0 : status = smb2_find_recv(req, mem_ctx, &f);
1997 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
1998 :
1999 0 : done:
2000 0 : smb2_util_close(tree, h);
2001 0 : smb2_deltree(tree, dname);
2002 0 : TALLOC_FREE(mem_ctx);
2003 0 : return ret;
2004 : }
2005 :
2006 : /* Test compound unrelated finds */
2007 0 : static bool test_compound_find_unrelated(struct torture_context *tctx,
2008 : struct smb2_tree *tree)
2009 : {
2010 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2011 0 : const char *dname = "compound_find_dir";
2012 : struct smb2_create create;
2013 : struct smb2_find f;
2014 : struct smb2_handle h;
2015 : struct smb2_request *req[2];
2016 : NTSTATUS status;
2017 0 : bool ret = true;
2018 :
2019 0 : smb2_deltree(tree, dname);
2020 :
2021 0 : ZERO_STRUCT(create);
2022 0 : create.in.desired_access = SEC_RIGHTS_DIR_ALL;
2023 0 : create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2024 0 : create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
2025 0 : create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2026 : NTCREATEX_SHARE_ACCESS_WRITE |
2027 : NTCREATEX_SHARE_ACCESS_DELETE;
2028 0 : create.in.create_disposition = NTCREATEX_DISP_CREATE;
2029 0 : create.in.fname = dname;
2030 :
2031 0 : status = smb2_create(tree, mem_ctx, &create);
2032 0 : h = create.out.file.handle;
2033 :
2034 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
2035 :
2036 0 : smb2_transport_compound_start(tree->session->transport, 2);
2037 :
2038 0 : ZERO_STRUCT(f);
2039 0 : f.in.file.handle = h;
2040 0 : f.in.pattern = "*";
2041 0 : f.in.max_response_size = 0x100;
2042 0 : f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
2043 :
2044 0 : req[0] = smb2_find_send(tree, &f);
2045 0 : req[1] = smb2_find_send(tree, &f);
2046 :
2047 0 : status = smb2_find_recv(req[0], mem_ctx, &f);
2048 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
2049 :
2050 0 : status = smb2_find_recv(req[1], mem_ctx, &f);
2051 0 : torture_assert_ntstatus_equal_goto(tctx, status, STATUS_NO_MORE_FILES, ret, done, "smb2_find_recv failed\n");
2052 :
2053 0 : done:
2054 0 : smb2_util_close(tree, h);
2055 0 : smb2_deltree(tree, dname);
2056 0 : TALLOC_FREE(mem_ctx);
2057 0 : return ret;
2058 : }
2059 :
2060 0 : static bool test_compound_async_flush_close(struct torture_context *tctx,
2061 : struct smb2_tree *tree)
2062 : {
2063 0 : struct smb2_handle fhandle = { .data = { 0, 0 } };
2064 0 : struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
2065 : struct smb2_close cl;
2066 : struct smb2_flush fl;
2067 0 : const char *fname = "compound_async_flush_close";
2068 : struct smb2_request *req[2];
2069 : NTSTATUS status;
2070 0 : bool ret = false;
2071 :
2072 : /* Start clean. */
2073 0 : smb2_util_unlink(tree, fname);
2074 :
2075 : /* Create a file. */
2076 0 : status = torture_smb2_testfile_access(tree,
2077 : fname,
2078 : &fhandle,
2079 : SEC_RIGHTS_FILE_ALL);
2080 0 : CHECK_STATUS(status, NT_STATUS_OK);
2081 :
2082 : /* Now do a compound flush + close handle. */
2083 0 : smb2_transport_compound_start(tree->session->transport, 2);
2084 :
2085 0 : ZERO_STRUCT(fl);
2086 0 : fl.in.file.handle = fhandle;
2087 :
2088 0 : req[0] = smb2_flush_send(tree, &fl);
2089 0 : torture_assert_not_null_goto(tctx, req[0], ret, done,
2090 : "smb2_flush_send failed\n");
2091 :
2092 0 : smb2_transport_compound_set_related(tree->session->transport, true);
2093 :
2094 0 : ZERO_STRUCT(cl);
2095 0 : cl.in.file.handle = relhandle;
2096 0 : req[1] = smb2_close_send(tree, &cl);
2097 0 : torture_assert_not_null_goto(tctx, req[1], ret, done,
2098 : "smb2_close_send failed\n");
2099 :
2100 0 : status = smb2_flush_recv(req[0], &fl);
2101 : /*
2102 : * On Windows, this flush will usually
2103 : * succeed as we have nothing to flush,
2104 : * so allow NT_STATUS_OK. Once bug #15172
2105 : * is fixed Samba will do the flush synchronously
2106 : * so allow NT_STATUS_OK.
2107 : */
2108 0 : if (!NT_STATUS_IS_OK(status)) {
2109 : /*
2110 : * If we didn't get NT_STATUS_OK, we *must*
2111 : * get NT_STATUS_INTERNAL_ERROR if the flush
2112 : * goes async.
2113 : *
2114 : * For pre-bugfix #15172 Samba, the flush goes async and
2115 : * we should get NT_STATUS_INTERNAL_ERROR.
2116 : */
2117 0 : torture_assert_ntstatus_equal_goto(tctx,
2118 : status,
2119 : NT_STATUS_INTERNAL_ERROR,
2120 : ret,
2121 : done,
2122 : "smb2_flush_recv didn't return "
2123 : "NT_STATUS_INTERNAL_ERROR.\n");
2124 : }
2125 0 : status = smb2_close_recv(req[1], &cl);
2126 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2127 : "smb2_close_recv failed.");
2128 :
2129 0 : ZERO_STRUCT(fhandle);
2130 :
2131 : /*
2132 : * Do several more operations on the tree, spaced
2133 : * out by 1 sec sleeps to make sure the server didn't
2134 : * crash on the close. The sleeps are required to
2135 : * make test test for a crash reliable, as we ensure
2136 : * the pthread fsync internally finishes and accesses
2137 : * freed memory. Without them the test occassionally
2138 : * passes as we disconnect before the pthread fsync
2139 : * finishes.
2140 : */
2141 0 : status = smb2_util_unlink(tree, fname);
2142 0 : CHECK_STATUS(status, NT_STATUS_OK);
2143 :
2144 0 : sleep(1);
2145 0 : status = smb2_util_unlink(tree, fname);
2146 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
2147 :
2148 0 : sleep(1);
2149 0 : status = smb2_util_unlink(tree, fname);
2150 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
2151 :
2152 0 : ret = true;
2153 :
2154 0 : done:
2155 :
2156 0 : if (fhandle.data[0] != 0) {
2157 0 : smb2_util_close(tree, fhandle);
2158 : }
2159 :
2160 0 : smb2_util_unlink(tree, fname);
2161 0 : return ret;
2162 : }
2163 :
2164 0 : static bool test_compound_async_flush_flush(struct torture_context *tctx,
2165 : struct smb2_tree *tree)
2166 : {
2167 0 : struct smb2_handle fhandle = { .data = { 0, 0 } };
2168 0 : struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
2169 : struct smb2_flush fl1;
2170 : struct smb2_flush fl2;
2171 0 : const char *fname = "compound_async_flush_flush";
2172 : struct smb2_request *req[2];
2173 : NTSTATUS status;
2174 0 : bool ret = false;
2175 :
2176 : /* Start clean. */
2177 0 : smb2_util_unlink(tree, fname);
2178 :
2179 : /* Create a file. */
2180 0 : status = torture_smb2_testfile_access(tree,
2181 : fname,
2182 : &fhandle,
2183 : SEC_RIGHTS_FILE_ALL);
2184 0 : CHECK_STATUS(status, NT_STATUS_OK);
2185 :
2186 : /* Now do a compound flush + flush handle. */
2187 0 : smb2_transport_compound_start(tree->session->transport, 2);
2188 :
2189 0 : ZERO_STRUCT(fl1);
2190 0 : fl1.in.file.handle = fhandle;
2191 :
2192 0 : req[0] = smb2_flush_send(tree, &fl1);
2193 0 : torture_assert_not_null_goto(tctx, req[0], ret, done,
2194 : "smb2_flush_send (1) failed\n");
2195 :
2196 0 : smb2_transport_compound_set_related(tree->session->transport, true);
2197 :
2198 0 : ZERO_STRUCT(fl2);
2199 0 : fl2.in.file.handle = relhandle;
2200 :
2201 0 : req[1] = smb2_flush_send(tree, &fl2);
2202 0 : torture_assert_not_null_goto(tctx, req[1], ret, done,
2203 : "smb2_flush_send (2) failed\n");
2204 :
2205 0 : status = smb2_flush_recv(req[0], &fl1);
2206 : /*
2207 : * On Windows, this flush will usually
2208 : * succeed as we have nothing to flush,
2209 : * so allow NT_STATUS_OK. Once bug #15172
2210 : * is fixed Samba will do the flush synchronously
2211 : * so allow NT_STATUS_OK.
2212 : */
2213 0 : if (!NT_STATUS_IS_OK(status)) {
2214 : /*
2215 : * If we didn't get NT_STATUS_OK, we *must*
2216 : * get NT_STATUS_INTERNAL_ERROR if the flush
2217 : * goes async.
2218 : *
2219 : * For pre-bugfix #15172 Samba, the flush goes async and
2220 : * we should get NT_STATUS_INTERNAL_ERROR.
2221 : */
2222 0 : torture_assert_ntstatus_equal_goto(tctx,
2223 : status,
2224 : NT_STATUS_INTERNAL_ERROR,
2225 : ret,
2226 : done,
2227 : "smb2_flush_recv (1) didn't return "
2228 : "NT_STATUS_INTERNAL_ERROR.\n");
2229 : }
2230 :
2231 : /*
2232 : * If the flush is the last entry in a compound,
2233 : * it should always succeed even if it goes async.
2234 : */
2235 0 : status = smb2_flush_recv(req[1], &fl2);
2236 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2237 : "smb2_flush_recv (2) failed.");
2238 :
2239 0 : status = smb2_util_close(tree, fhandle);
2240 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2241 : "smb2_util_close failed.");
2242 0 : ZERO_STRUCT(fhandle);
2243 :
2244 : /*
2245 : * Do several more operations on the tree, spaced
2246 : * out by 1 sec sleeps to make sure the server didn't
2247 : * crash on the close. The sleeps are required to
2248 : * make test test for a crash reliable, as we ensure
2249 : * the pthread fsync internally finishes and accesses
2250 : * freed memory. Without them the test occassionally
2251 : * passes as we disconnect before the pthread fsync
2252 : * finishes.
2253 : */
2254 0 : status = smb2_util_unlink(tree, fname);
2255 0 : CHECK_STATUS(status, NT_STATUS_OK);
2256 :
2257 0 : sleep(1);
2258 0 : status = smb2_util_unlink(tree, fname);
2259 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
2260 :
2261 0 : sleep(1);
2262 0 : status = smb2_util_unlink(tree, fname);
2263 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
2264 :
2265 0 : ret = true;
2266 :
2267 0 : done:
2268 :
2269 0 : if (fhandle.data[0] != 0) {
2270 0 : smb2_util_close(tree, fhandle);
2271 : }
2272 :
2273 0 : smb2_util_unlink(tree, fname);
2274 0 : return ret;
2275 : }
2276 :
2277 964 : struct torture_suite *torture_smb2_compound_init(TALLOC_CTX *ctx)
2278 : {
2279 964 : struct torture_suite *suite = torture_suite_create(ctx, "compound");
2280 :
2281 964 : torture_suite_add_1smb2_test(suite, "related1", test_compound_related1);
2282 964 : torture_suite_add_1smb2_test(suite, "related2", test_compound_related2);
2283 964 : torture_suite_add_1smb2_test(suite, "related3",
2284 : test_compound_related3);
2285 964 : torture_suite_add_1smb2_test(suite, "related4",
2286 : test_compound_related4);
2287 964 : torture_suite_add_1smb2_test(suite, "related5",
2288 : test_compound_related5);
2289 964 : torture_suite_add_1smb2_test(suite, "related6",
2290 : test_compound_related6);
2291 964 : torture_suite_add_1smb2_test(suite, "related7",
2292 : test_compound_related7);
2293 964 : torture_suite_add_1smb2_test(suite, "related8",
2294 : test_compound_related8);
2295 964 : torture_suite_add_1smb2_test(suite, "related9",
2296 : test_compound_related9);
2297 964 : torture_suite_add_1smb2_test(suite, "unrelated1", test_compound_unrelated1);
2298 964 : torture_suite_add_1smb2_test(suite, "invalid1", test_compound_invalid1);
2299 964 : torture_suite_add_1smb2_test(suite, "invalid2", test_compound_invalid2);
2300 964 : torture_suite_add_1smb2_test(suite, "invalid3", test_compound_invalid3);
2301 964 : torture_suite_add_1smb2_test(
2302 : suite, "invalid4", test_compound_invalid4);
2303 964 : torture_suite_add_1smb2_test(suite, "interim1", test_compound_interim1);
2304 964 : torture_suite_add_1smb2_test(suite, "interim2", test_compound_interim2);
2305 964 : torture_suite_add_1smb2_test(suite, "compound-break", test_compound_break);
2306 964 : torture_suite_add_1smb2_test(suite, "compound-padding", test_compound_padding);
2307 964 : torture_suite_add_1smb2_test(suite, "create-write-close",
2308 : test_compound_create_write_close);
2309 :
2310 964 : suite->description = talloc_strdup(suite, "SMB2-COMPOUND tests");
2311 :
2312 964 : return suite;
2313 : }
2314 :
2315 964 : struct torture_suite *torture_smb2_compound_find_init(TALLOC_CTX *ctx)
2316 : {
2317 964 : struct torture_suite *suite = torture_suite_create(ctx, "compound_find");
2318 :
2319 964 : torture_suite_add_1smb2_test(suite, "compound_find_related", test_compound_find_related);
2320 964 : torture_suite_add_1smb2_test(suite, "compound_find_unrelated", test_compound_find_unrelated);
2321 964 : torture_suite_add_1smb2_test(suite, "compound_find_close", test_compound_find_close);
2322 :
2323 964 : suite->description = talloc_strdup(suite, "SMB2-COMPOUND-FIND tests");
2324 :
2325 964 : return suite;
2326 : }
2327 :
2328 964 : struct torture_suite *torture_smb2_compound_async_init(TALLOC_CTX *ctx)
2329 : {
2330 964 : struct torture_suite *suite = torture_suite_create(ctx,
2331 : "compound_async");
2332 :
2333 964 : torture_suite_add_1smb2_test(suite, "flush_close",
2334 : test_compound_async_flush_close);
2335 964 : torture_suite_add_1smb2_test(suite, "flush_flush",
2336 : test_compound_async_flush_flush);
2337 :
2338 964 : suite->description = talloc_strdup(suite, "SMB2-COMPOUND-ASYNC tests");
2339 :
2340 964 : return suite;
2341 : }
|