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