Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : test alternate data streams
5 :
6 : Copyright (C) Andrew Tridgell 2004
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 :
26 : #include "torture/torture.h"
27 : #include "torture/smb2/proto.h"
28 :
29 : #include "system/filesys.h"
30 : #include "system/locale.h"
31 : #include "lib/util/tsort.h"
32 :
33 : #define DNAME "teststreams"
34 :
35 : #define CHECK_STATUS(status, correct) do { \
36 : if (!NT_STATUS_EQUAL(status, correct)) { \
37 : torture_result(tctx, TORTURE_FAIL, \
38 : "(%s) Incorrect status %s - should be %s\n", \
39 : __location__, nt_errstr(status), nt_errstr(correct)); \
40 : ret = false; \
41 : goto done; \
42 : }} while (0)
43 :
44 : #define CHECK_VALUE(v, correct) do { \
45 : if ((v) != (correct)) { \
46 : torture_result(tctx, TORTURE_FAIL, \
47 : "(%s) Incorrect value %s=%d - should be %d\n", \
48 : __location__, #v, (int)v, (int)correct); \
49 : ret = false; \
50 : }} while (0)
51 :
52 : #define CHECK_NTTIME(v, correct) do { \
53 : if ((v) != (correct)) { \
54 : torture_result(tctx, TORTURE_FAIL, \
55 : "(%s) Incorrect value %s=%llu - should be %llu\n", \
56 : __location__, #v, (unsigned long long)v, \
57 : (unsigned long long)correct); \
58 : ret = false; \
59 : }} while (0)
60 :
61 : #define CHECK_STR(v, correct) do { \
62 : bool ok; \
63 : if ((v) && !(correct)) { \
64 : ok = false; \
65 : } else if (!(v) && (correct)) { \
66 : ok = false; \
67 : } else if (!(v) && !(correct)) { \
68 : ok = true; \
69 : } else if (strcmp((v), (correct)) == 0) { \
70 : ok = true; \
71 : } else { \
72 : ok = false; \
73 : } \
74 : if (!ok) { \
75 : torture_result(tctx, TORTURE_FAIL, \
76 : "(%s) Incorrect value %s='%s' - " \
77 : "should be '%s'\n", \
78 : __location__, #v, (v)?(v):"NULL", \
79 : (correct)?(correct):"NULL"); \
80 : ret = false; \
81 : }} while (0)
82 :
83 :
84 104 : static int qsort_string(char * const *s1, char * const *s2)
85 : {
86 104 : return strcmp(*s1, *s2);
87 : }
88 :
89 112 : static int qsort_stream(const struct stream_struct * s1, const struct stream_struct *s2)
90 : {
91 112 : return strcmp(s1->stream_name.s, s2->stream_name.s);
92 : }
93 :
94 99 : static bool check_stream(struct torture_context *tctx,
95 : struct smb2_tree *tree,
96 : const char *location,
97 : TALLOC_CTX *mem_ctx,
98 : const char *fname,
99 : const char *sname,
100 : const char *value)
101 : {
102 : struct smb2_handle handle;
103 : struct smb2_create create;
104 : struct smb2_read r;
105 : NTSTATUS status;
106 : const char *full_name;
107 :
108 99 : full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
109 :
110 99 : ZERO_STRUCT(create);
111 99 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
112 99 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
113 99 : create.in.create_disposition = NTCREATEX_DISP_OPEN;
114 99 : create.in.fname = full_name;
115 :
116 99 : status = smb2_create(tree, mem_ctx, &create);
117 99 : if (!NT_STATUS_IS_OK(status)) {
118 45 : if (value == NULL) {
119 45 : return true;
120 : } else {
121 0 : torture_comment(tctx, "Unable to open stream %s\n",
122 : full_name);
123 0 : return false;
124 : }
125 : }
126 :
127 54 : handle = create.out.file.handle;
128 54 : if (value == NULL) {
129 0 : return true;
130 : }
131 :
132 :
133 54 : ZERO_STRUCT(r);
134 54 : r.in.file.handle = handle;
135 54 : r.in.length = strlen(value)+11;
136 54 : r.in.offset = 0;
137 :
138 54 : status = smb2_read(tree, tree, &r);
139 :
140 54 : if (!NT_STATUS_IS_OK(status)) {
141 0 : torture_comment(tctx, "(%s) Failed to read %lu bytes from "
142 0 : "stream '%s'\n", location, (long)strlen(value), full_name);
143 0 : return false;
144 : }
145 :
146 54 : if (memcmp(r.out.data.data, value, strlen(value)) != 0) {
147 0 : torture_comment(tctx, "(%s) Bad data in stream\n", location);
148 0 : return false;
149 : }
150 :
151 54 : smb2_util_close(tree, handle);
152 54 : return true;
153 : }
154 :
155 105 : static bool check_stream_list(struct smb2_tree *tree,
156 : struct torture_context *tctx,
157 : const char *fname,
158 : int num_exp,
159 : const char **exp,
160 : struct smb2_handle h)
161 : {
162 : union smb_fileinfo finfo;
163 : NTSTATUS status;
164 : int i;
165 105 : TALLOC_CTX *tmp_ctx = talloc_new(tctx);
166 : char **exp_sort;
167 : struct stream_struct *stream_sort;
168 105 : bool ret = false;
169 :
170 105 : finfo.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
171 105 : finfo.generic.in.file.handle = h;
172 :
173 105 : status = smb2_getinfo_file(tree, tctx, &finfo);
174 105 : if (!NT_STATUS_IS_OK(status)) {
175 24 : torture_comment(tctx, "(%s) smb_raw_pathinfo failed: %s\n",
176 : __location__, nt_errstr(status));
177 24 : goto fail;
178 : }
179 :
180 81 : if (finfo.stream_info.out.num_streams != num_exp) {
181 1 : torture_comment(tctx, "(%s) expected %d streams, got %d\n",
182 : __location__, num_exp, finfo.stream_info.out.num_streams);
183 1 : goto fail;
184 : }
185 :
186 80 : if (num_exp == 0) {
187 9 : ret = true;
188 9 : goto fail;
189 : }
190 :
191 71 : exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
192 :
193 71 : if (exp_sort == NULL) {
194 0 : goto fail;
195 : }
196 :
197 71 : TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
198 :
199 71 : stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams,
200 : finfo.stream_info.out.num_streams *
201 : sizeof(*stream_sort));
202 :
203 71 : if (stream_sort == NULL) {
204 0 : goto fail;
205 : }
206 :
207 71 : TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
208 :
209 199 : for (i=0; i<num_exp; i++) {
210 128 : if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
211 0 : torture_comment(tctx,
212 : "(%s) expected stream name %s, got %s\n",
213 0 : __location__, exp_sort[i],
214 0 : stream_sort[i].stream_name.s);
215 0 : goto fail;
216 : }
217 : }
218 :
219 71 : ret = true;
220 105 : fail:
221 105 : talloc_free(tmp_ctx);
222 105 : return ret;
223 : }
224 :
225 :
226 9 : static bool test_stream_dir(struct torture_context *tctx,
227 : struct smb2_tree *tree)
228 : {
229 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
230 : NTSTATUS status;
231 : union smb_open io;
232 9 : const char *fname = DNAME "\\stream.txt";
233 : const char *sname1;
234 9 : bool ret = true;
235 : const char *basedir_data;
236 : struct smb2_handle h;
237 :
238 9 : smb2_util_unlink(tree, fname);
239 9 : smb2_deltree(tree, DNAME);
240 :
241 9 : status = torture_smb2_testdir(tree, DNAME, &h);
242 9 : CHECK_STATUS(status, NT_STATUS_OK);
243 :
244 9 : basedir_data = talloc_asprintf(mem_ctx, "%s::$DATA", DNAME);
245 9 : sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
246 9 : torture_comment(tctx, "%s\n", sname1);
247 :
248 9 : torture_comment(tctx, "(%s) opening non-existent directory stream\n",
249 : __location__);
250 9 : ZERO_STRUCT(io.smb2);
251 9 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
252 9 : io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
253 9 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
254 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
255 9 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
256 9 : io.smb2.in.share_access = 0;
257 9 : io.smb2.in.alloc_size = 0;
258 9 : io.smb2.in.security_flags = 0;
259 9 : io.smb2.in.fname = sname1;
260 9 : io.smb2.in.create_flags = 0;
261 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
262 9 : CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
263 :
264 9 : torture_comment(tctx, "(%s) opening basedir stream\n", __location__);
265 9 : ZERO_STRUCT(io.smb2);
266 9 : io.smb2.in.create_flags = 0;
267 9 : io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
268 9 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
269 9 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
270 9 : io.smb2.in.share_access = 0;
271 9 : io.smb2.in.alloc_size = 0;
272 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
273 9 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
274 9 : io.smb2.in.security_flags = 0;
275 9 : io.smb2.in.fname = basedir_data;
276 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
277 9 : CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
278 :
279 9 : torture_comment(tctx, "(%s) opening basedir ::$DATA stream\n",
280 : __location__);
281 9 : ZERO_STRUCT(io.smb2);
282 9 : io.smb2.in.create_flags = 0x10;
283 9 : io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
284 9 : io.smb2.in.create_options = 0;
285 9 : io.smb2.in.file_attributes = 0;
286 9 : io.smb2.in.share_access = 0;
287 9 : io.smb2.in.alloc_size = 0;
288 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
289 9 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
290 9 : io.smb2.in.security_flags = 0;
291 9 : io.smb2.in.fname = basedir_data;
292 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
293 9 : CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
294 :
295 9 : torture_comment(tctx, "(%s) list the streams on the basedir\n",
296 : __location__);
297 9 : ret &= check_stream_list(tree, mem_ctx, DNAME, 0, NULL, h);
298 9 : done:
299 9 : smb2_util_unlink(tree, fname);
300 9 : smb2_deltree(tree, DNAME);
301 9 : talloc_free(mem_ctx);
302 :
303 9 : return ret;
304 : }
305 :
306 9 : static bool test_stream_io(struct torture_context *tctx,
307 : struct smb2_tree *tree)
308 : {
309 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
310 : NTSTATUS status;
311 : union smb_open io;
312 9 : const char *fname = DNAME "\\stream.txt";
313 : const char *sname1, *sname2;
314 9 : bool ret = true;
315 : struct smb2_handle h, h2;
316 :
317 9 : const char *one[] = { "::$DATA" };
318 9 : const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
319 9 : const char *three[] = { "::$DATA", ":Stream One:$DATA",
320 : ":Second Stream:$DATA" };
321 :
322 9 : ZERO_STRUCT(h);
323 9 : ZERO_STRUCT(h2);
324 :
325 9 : sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
326 9 : sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
327 : "Second Stream");
328 :
329 9 : smb2_util_unlink(tree, fname);
330 9 : smb2_deltree(tree, DNAME);
331 :
332 9 : status = torture_smb2_testdir(tree, DNAME, &h);
333 9 : CHECK_STATUS(status, NT_STATUS_OK);
334 :
335 9 : torture_comment(tctx, "(%s) creating a stream on a non-existent file\n",
336 : __location__);
337 :
338 9 : ZERO_STRUCT(io.smb2);
339 9 : io.smb2.in.create_flags = 0;
340 9 : io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
341 9 : io.smb2.in.create_options = 0;
342 9 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
343 9 : io.smb2.in.share_access = 0;
344 9 : io.smb2.in.alloc_size = 0;
345 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
346 9 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
347 9 : io.smb2.in.security_flags = 0;
348 9 : io.smb2.in.fname = sname1;
349 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
350 9 : CHECK_STATUS(status, NT_STATUS_OK);
351 9 : h2 = io.smb2.out.file.handle;
352 :
353 9 : ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
354 : "Stream One", NULL);
355 :
356 9 : torture_comment(tctx, "(%s) check that open of base file is allowed\n", __location__);
357 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
358 9 : io.smb2.in.fname = fname;
359 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
360 9 : CHECK_STATUS(status, NT_STATUS_OK);
361 9 : smb2_util_close(tree, io.smb2.out.file.handle);
362 :
363 9 : torture_comment(tctx, "(%s) writing to stream\n", __location__);
364 9 : status = smb2_util_write(tree, h2, "test data", 0, 9);
365 9 : CHECK_STATUS(status, NT_STATUS_OK);
366 :
367 9 : smb2_util_close(tree, h2);
368 :
369 9 : ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
370 : "Stream One", "test data");
371 :
372 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
373 9 : io.smb2.in.fname = sname1;
374 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
375 9 : CHECK_STATUS(status, NT_STATUS_OK);
376 9 : h2 = io.smb2.out.file.handle;
377 :
378 9 : torture_comment(tctx, "(%s) modifying stream\n", __location__);
379 9 : status = smb2_util_write(tree, h2, "MORE DATA ", 5, 10);
380 9 : CHECK_STATUS(status, NT_STATUS_OK);
381 :
382 9 : smb2_util_close(tree, h2);
383 :
384 9 : ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
385 : "Stream One:$FOO", NULL);
386 :
387 9 : torture_comment(tctx, "(%s) creating a stream2 on a existing file\n",
388 : __location__);
389 9 : io.smb2.in.fname = sname2;
390 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
391 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
392 9 : CHECK_STATUS(status, NT_STATUS_OK);
393 9 : h2 = io.smb2.out.file.handle;
394 :
395 9 : torture_comment(tctx, "(%s) modifying stream\n", __location__);
396 9 : status= smb2_util_write(tree, h2, "SECOND STREAM", 0, 13);
397 9 : CHECK_STATUS(status, NT_STATUS_OK);
398 9 : smb2_util_close(tree, h2);
399 :
400 9 : ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
401 : "Stream One", "test MORE DATA ");
402 :
403 9 : ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
404 : "Stream One:$DATA", "test MORE DATA ");
405 :
406 9 : ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
407 : "Stream One:", NULL);
408 :
409 9 : if (!ret) {
410 0 : torture_result(tctx, TORTURE_FAIL,
411 : "check_stream(\"Stream One:*\") failed\n");
412 0 : goto done;
413 : }
414 :
415 9 : ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
416 : "Second Stream", "SECOND STREAM");
417 :
418 9 : ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
419 : "SECOND STREAM:$DATA", "SECOND STREAM");
420 9 : ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
421 : "Second Stream:$DATA", "SECOND STREAM");
422 :
423 9 : ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
424 : "Second Stream:", NULL);
425 :
426 9 : ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
427 : "Second Stream:$FOO", NULL);
428 :
429 9 : if (!ret) {
430 0 : torture_result(tctx, TORTURE_FAIL,
431 : "check_stream(\"Second Stream:*\") failed\n");
432 0 : goto done;
433 : }
434 :
435 9 : io.smb2.in.fname = sname2;
436 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
437 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
438 9 : CHECK_STATUS(status, NT_STATUS_OK);
439 9 : h2 = io.smb2.out.file.handle;
440 9 : check_stream_list(tree, tctx, fname, 3, three, h2);
441 :
442 9 : smb2_util_close(tree, h2);
443 :
444 9 : torture_comment(tctx, "(%s) deleting stream\n", __location__);
445 9 : status = smb2_util_unlink(tree, sname1);
446 9 : CHECK_STATUS(status, NT_STATUS_OK);
447 :
448 9 : io.smb2.in.fname = sname2;
449 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
450 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
451 9 : CHECK_STATUS(status, NT_STATUS_OK);
452 9 : h2 = io.smb2.out.file.handle;
453 9 : check_stream_list(tree, tctx, fname, 2, two, h2);
454 9 : smb2_util_close(tree, h2);
455 :
456 9 : torture_comment(tctx, "(%s) delete a stream via delete-on-close\n",
457 : __location__);
458 9 : io.smb2.in.fname = sname2;
459 9 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
460 9 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
461 9 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
462 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
463 :
464 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
465 9 : CHECK_STATUS(status, NT_STATUS_OK);
466 9 : h2 = io.smb2.out.file.handle;
467 :
468 9 : smb2_util_close(tree, h2);
469 9 : status = smb2_util_unlink(tree, sname2);
470 9 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
471 :
472 9 : io.smb2.in.fname = fname;
473 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
474 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
475 9 : h2 = io.smb2.out.file.handle;
476 9 : check_stream_list(tree,tctx, fname, 1, one, h2);
477 9 : smb2_util_close(tree, h2);
478 :
479 9 : if (!torture_setting_bool(tctx, "samba4", false)) {
480 8 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
481 8 : io.smb2.in.fname = sname1;
482 8 : status = smb2_create(tree, mem_ctx, &(io.smb2));
483 8 : CHECK_STATUS(status, NT_STATUS_OK);
484 8 : smb2_util_close(tree, io.ntcreatex.out.file.handle);
485 8 : io.smb2.in.fname = sname2;
486 8 : status = smb2_create(tree, mem_ctx, &(io.smb2));
487 8 : CHECK_STATUS(status, NT_STATUS_OK);
488 8 : smb2_util_close(tree, io.ntcreatex.out.file.handle);
489 8 : torture_comment(tctx, "(%s) deleting file\n", __location__);
490 8 : status = smb2_util_unlink(tree, fname);
491 8 : CHECK_STATUS(status, NT_STATUS_OK);
492 : }
493 :
494 :
495 16 : done:
496 9 : smb2_util_close(tree, h2);
497 9 : smb2_deltree(tree, DNAME);
498 9 : talloc_free(mem_ctx);
499 :
500 9 : return ret;
501 : }
502 :
503 9 : static bool test_zero_byte_stream(struct torture_context *tctx,
504 : struct smb2_tree *tree)
505 : {
506 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
507 : NTSTATUS status;
508 : union smb_open io;
509 9 : const char *fname = DNAME "\\stream.txt";
510 : const char *sname;
511 9 : bool ret = true;
512 : struct smb2_handle h, bh;
513 9 : const char *streams[] = { "::$DATA", ":foo:$DATA" };
514 :
515 9 : sname = talloc_asprintf(mem_ctx, "%s:%s", fname, "foo");
516 :
517 9 : smb2_util_unlink(tree, fname);
518 9 : smb2_deltree(tree, DNAME);
519 :
520 9 : status = torture_smb2_testdir(tree, DNAME, &h);
521 9 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "testdir");
522 9 : smb2_util_close(tree, h);
523 :
524 9 : torture_comment(tctx, "(%s) Check 0 byte named stream\n",
525 : __location__);
526 :
527 : /* Create basefile */
528 9 : ZERO_STRUCT(io);
529 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
530 9 : io.smb2.in.fname = fname;
531 9 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
532 : SEC_FILE_WRITE_ATTRIBUTE |
533 : SEC_FILE_READ_DATA |
534 : SEC_FILE_WRITE_DATA;
535 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
536 9 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
537 9 : smb2_util_close(tree, io.smb2.out.file.handle);
538 :
539 : /* Create named stream and close it */
540 9 : ZERO_STRUCT(io);
541 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
542 9 : io.smb2.in.fname = sname;
543 9 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
544 : SEC_FILE_WRITE_ATTRIBUTE |
545 : SEC_FILE_READ_DATA |
546 : SEC_FILE_WRITE_DATA;
547 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
548 9 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
549 9 : smb2_util_close(tree, io.smb2.out.file.handle);
550 :
551 : /*
552 : * Check stream list, the 0 byte stream MUST be returned by
553 : * the server.
554 : */
555 9 : ZERO_STRUCT(io);
556 9 : io.smb2.in.fname = fname;
557 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
558 9 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
559 : SEC_FILE_WRITE_ATTRIBUTE |
560 : SEC_FILE_READ_DATA |
561 : SEC_FILE_WRITE_DATA;
562 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
563 9 : bh = io.smb2.out.file.handle;
564 :
565 9 : ret = check_stream_list(tree,tctx, fname, 2, streams, bh);
566 9 : torture_assert_goto(tctx, ret == true, ret, done, "smb2_create");
567 9 : smb2_util_close(tree, bh);
568 :
569 9 : done:
570 9 : smb2_deltree(tree, DNAME);
571 9 : talloc_free(mem_ctx);
572 :
573 9 : return ret;
574 : }
575 :
576 : /*
577 : test stream sharemodes
578 : */
579 9 : static bool test_stream_sharemodes(struct torture_context *tctx,
580 : struct smb2_tree *tree)
581 : {
582 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
583 : NTSTATUS status;
584 : union smb_open io;
585 9 : const char *fname = DNAME "\\stream_share.txt";
586 : const char *sname1, *sname2;
587 9 : bool ret = true;
588 : struct smb2_handle h, h1, h2;
589 :
590 9 : ZERO_STRUCT(h);
591 9 : ZERO_STRUCT(h1);
592 9 : ZERO_STRUCT(h2);
593 :
594 9 : sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
595 9 : sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
596 : "Second Stream");
597 :
598 9 : smb2_util_unlink(tree, fname);
599 9 : smb2_deltree(tree, DNAME);
600 :
601 9 : status = torture_smb2_testdir(tree, DNAME, &h);
602 9 : CHECK_STATUS(status, NT_STATUS_OK);
603 :
604 9 : torture_comment(tctx, "(%s) Testing stream share mode conflicts\n",
605 : __location__);
606 9 : ZERO_STRUCT(io.smb2);
607 9 : io.generic.level = RAW_OPEN_SMB2;
608 9 : io.smb2.in.create_flags = 0;
609 9 : io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
610 9 : io.smb2.in.create_options = 0;
611 9 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
612 9 : io.smb2.in.share_access = 0;
613 9 : io.smb2.in.alloc_size = 0;
614 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
615 9 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
616 9 : io.smb2.in.security_flags = 0;
617 9 : io.smb2.in.fname = sname1;
618 :
619 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
620 9 : CHECK_STATUS(status, NT_STATUS_OK);
621 9 : h1 = io.smb2.out.file.handle;
622 :
623 : /*
624 : * A different stream does not give a sharing violation
625 : */
626 :
627 9 : io.smb2.in.fname = sname2;
628 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
629 9 : CHECK_STATUS(status, NT_STATUS_OK);
630 9 : h2 = io.smb2.out.file.handle;
631 :
632 : /*
633 : * ... whereas the same stream does with unchanged access/share_access
634 : * flags
635 : */
636 :
637 9 : io.smb2.in.fname = sname1;
638 9 : io.smb2.in.create_disposition = 0;
639 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
640 9 : CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
641 :
642 9 : io.smb2.in.fname = sname2;
643 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
644 9 : CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
645 :
646 17 : done:
647 9 : smb2_util_close(tree, h1);
648 9 : smb2_util_close(tree, h2);
649 9 : status = smb2_util_unlink(tree, fname);
650 9 : smb2_deltree(tree, DNAME);
651 9 : talloc_free(mem_ctx);
652 :
653 9 : return ret;
654 : }
655 :
656 : /*
657 : * Test FILE_SHARE_DELETE on streams
658 : *
659 : * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
660 : * with SEC_STD_DELETE.
661 : *
662 : * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
663 : * be opened with SEC_STD_DELETE.
664 : *
665 : * A stream held open with FILE_SHARE_DELETE allows the file to be
666 : * deleted. After the main file is deleted, access to the open file descriptor
667 : * still works, but all name-based access to both the main file as well as the
668 : * stream is denied with DELETE pending.
669 : *
670 : * This means, an open of the main file with SEC_STD_DELETE should walk all
671 : * streams and also open them with SEC_STD_DELETE. If any of these opens gives
672 : * SHARING_VIOLATION, the main open fails.
673 : *
674 : * Closing the main file after delete_on_close has been set does not really
675 : * unlink it but leaves the corresponding share mode entry with
676 : * delete_on_close being set around until all streams are closed.
677 : *
678 : * Opening a stream must also look at the main file's share mode entry, look
679 : * at the delete_on_close bit and potentially return DELETE_PENDING.
680 : */
681 :
682 9 : static bool test_stream_delete(struct torture_context *tctx,
683 : struct smb2_tree *tree)
684 : {
685 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
686 : NTSTATUS status;
687 : union smb_open io;
688 9 : const char *fname = DNAME "\\stream_delete.txt";
689 : const char *sname1;
690 9 : bool ret = true;
691 9 : struct smb2_handle h = {{0}};
692 9 : struct smb2_handle h1 = {{0}};
693 : struct smb2_read r;
694 :
695 9 : if (torture_setting_bool(tctx, "samba4", false)) {
696 1 : torture_comment(tctx, "Skipping test as samba4 is enabled\n");
697 1 : goto done;
698 : }
699 :
700 8 : ZERO_STRUCT(h);
701 8 : ZERO_STRUCT(h1);
702 :
703 8 : sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
704 :
705 : /* clean slate .. */
706 8 : smb2_util_unlink(tree, fname);
707 8 : smb2_deltree(tree, fname);
708 8 : smb2_deltree(tree, DNAME);
709 :
710 8 : status = torture_smb2_testdir(tree, DNAME, &h);
711 8 : CHECK_STATUS(status, NT_STATUS_OK);
712 :
713 8 : torture_comment(tctx, "(%s) opening non-existent file stream\n",
714 : __location__);
715 8 : ZERO_STRUCT(io.smb2);
716 8 : io.smb2.in.create_flags = 0;
717 8 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
718 8 : io.smb2.in.create_options = 0;
719 8 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
720 8 : io.smb2.in.share_access = 0;
721 8 : io.smb2.in.alloc_size = 0;
722 8 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
723 8 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
724 8 : io.smb2.in.security_flags = 0;
725 8 : io.smb2.in.fname = sname1;
726 :
727 8 : status = smb2_create(tree, mem_ctx, &(io.smb2));
728 8 : CHECK_STATUS(status, NT_STATUS_OK);
729 8 : h1 = io.smb2.out.file.handle;
730 :
731 8 : status = smb2_util_write(tree, h1, "test data", 0, 9);
732 8 : CHECK_STATUS(status, NT_STATUS_OK);
733 :
734 : /*
735 : * One stream opened without FILE_SHARE_DELETE prevents the main file
736 : * to be deleted or even opened with DELETE access
737 : */
738 :
739 8 : status = smb2_util_unlink(tree, fname);
740 8 : CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
741 :
742 8 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
743 8 : io.smb2.in.fname = fname;
744 8 : io.smb2.in.desired_access = SEC_STD_DELETE;
745 8 : status = smb2_create(tree, mem_ctx, &(io.smb2));
746 8 : CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
747 :
748 8 : smb2_util_close(tree, h1);
749 :
750 : /*
751 : * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
752 : */
753 :
754 8 : io.smb2.in.fname = sname1;
755 8 : io.smb2.in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
756 8 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
757 : NTCREATEX_SHARE_ACCESS_READ |
758 : NTCREATEX_SHARE_ACCESS_WRITE;
759 8 : status = smb2_create(tree, mem_ctx, &(io.smb2));
760 8 : CHECK_STATUS(status, NT_STATUS_OK);
761 8 : h1 = io.smb2.out.file.handle;
762 :
763 8 : status = smb2_util_unlink(tree, fname);
764 8 : CHECK_STATUS(status, NT_STATUS_OK);
765 :
766 : /*
767 : * file access still works on the stream while the main file is closed
768 : */
769 8 : ZERO_STRUCT(r);
770 8 : r.in.file.handle = h1;
771 8 : r.in.length = 9;
772 8 : r.in.offset = 0;
773 :
774 8 : status = smb2_read(tree, tree, &r);
775 8 : CHECK_STATUS(status, NT_STATUS_OK);
776 :
777 : /*
778 : * name-based access to both the main file and the stream does not
779 : * work anymore but gives DELETE_PENDING
780 : */
781 :
782 8 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
783 8 : io.smb2.in.fname = fname;
784 8 : status = smb2_create(tree, mem_ctx, &(io.smb2));
785 8 : CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
786 :
787 : /*
788 : * older S3 doesn't do this
789 : */
790 :
791 8 : io.smb2.in.fname = sname1;
792 8 : status = smb2_create(tree, mem_ctx, &(io.smb2));
793 8 : CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
794 :
795 8 : smb2_util_close(tree, h1);
796 8 : ZERO_STRUCT(h1);
797 :
798 : /*
799 : * After closing the stream the file is really gone.
800 : */
801 :
802 8 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
803 8 : io.smb2.in.fname = fname;
804 8 : status = smb2_create(tree, mem_ctx, &(io.smb2));
805 8 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
806 :
807 16 : done:
808 9 : if (!smb2_util_handle_empty(h1)) {
809 0 : smb2_util_close(tree, h1);
810 : }
811 9 : smb2_util_unlink(tree, fname);
812 9 : smb2_deltree(tree, DNAME);
813 9 : talloc_free(mem_ctx);
814 :
815 9 : return ret;
816 : }
817 :
818 : /*
819 : test stream names
820 : */
821 9 : static bool test_stream_names(struct torture_context *tctx,
822 : struct smb2_tree *tree)
823 : {
824 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
825 : NTSTATUS status;
826 : union smb_open io;
827 : union smb_fileinfo finfo;
828 : union smb_fileinfo stinfo;
829 : union smb_setfileinfo sinfo;
830 9 : const char *fname = DNAME "\\stream_names.txt";
831 : const char *sname1, *sname1b, *sname1c, *sname1d;
832 : const char *sname2, *snamew, *snamew2;
833 : const char *snamer1;
834 9 : bool ret = true;
835 : struct smb2_handle h, h1, h2, h3;
836 : int i;
837 9 : const char *four[4] = {
838 : "::$DATA",
839 : ":\x05Stream\n One:$DATA",
840 : ":MStream Two:$DATA",
841 : ":?Stream*:$DATA"
842 : };
843 9 : const char *five1[5] = {
844 : "::$DATA",
845 : ":\x05Stream\n One:$DATA",
846 : ":BeforeRename:$DATA",
847 : ":MStream Two:$DATA",
848 : ":?Stream*:$DATA"
849 : };
850 9 : const char *five2[5] = {
851 : "::$DATA",
852 : ":\x05Stream\n One:$DATA",
853 : ":AfterRename:$DATA",
854 : ":MStream Two:$DATA",
855 : ":?Stream*:$DATA"
856 : };
857 :
858 9 : ZERO_STRUCT(h);
859 9 : ZERO_STRUCT(h1);
860 9 : ZERO_STRUCT(h2);
861 9 : ZERO_STRUCT(h3);
862 :
863 9 : sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "\x05Stream\n One");
864 9 : sname1b = talloc_asprintf(mem_ctx, "%s:", sname1);
865 9 : sname1c = talloc_asprintf(mem_ctx, "%s:$FOO", sname1);
866 9 : sname1d = talloc_asprintf(mem_ctx, "%s:?D*a", sname1);
867 9 : sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "MStream Two");
868 9 : snamew = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "?Stream*");
869 9 : snamew2 = talloc_asprintf(mem_ctx, "%s\\stream*:%s:$DATA", DNAME,
870 : "?Stream*");
871 9 : snamer1 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname,
872 : "BeforeRename");
873 :
874 : /* clean slate ...*/
875 9 : smb2_util_unlink(tree, fname);
876 9 : smb2_deltree(tree, fname);
877 9 : smb2_deltree(tree, DNAME);
878 :
879 9 : status = torture_smb2_testdir(tree, DNAME, &h);
880 9 : CHECK_STATUS(status, NT_STATUS_OK);
881 :
882 9 : torture_comment(tctx, "(%s) testing stream names\n", __location__);
883 9 : ZERO_STRUCT(io.smb2);
884 9 : io.smb2.in.create_flags = 0;
885 9 : io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
886 9 : io.smb2.in.create_options = 0;
887 9 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
888 9 : io.smb2.in.share_access = 0;
889 9 : io.smb2.in.alloc_size = 0;
890 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
891 9 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
892 9 : io.smb2.in.security_flags = 0;
893 9 : io.smb2.in.fname = sname1;
894 :
895 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
896 9 : CHECK_STATUS(status, NT_STATUS_OK);
897 9 : h1 = io.smb2.out.file.handle;
898 :
899 : /*
900 : * A different stream does not give a sharing violation
901 : */
902 :
903 9 : io.smb2.in.fname = sname2;
904 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
905 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
906 9 : CHECK_STATUS(status, NT_STATUS_OK);
907 9 : h2 = io.smb2.out.file.handle;
908 :
909 : /*
910 : * ... whereas the same stream does with unchanged access/share_access
911 : * flags
912 : */
913 :
914 9 : io.smb2.in.fname = sname1;
915 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
916 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
917 9 : CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
918 :
919 9 : io.smb2.in.fname = sname1b;
920 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
921 9 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
922 :
923 9 : io.smb2.in.fname = sname1c;
924 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
925 9 : if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
926 : /* w2k returns INVALID_PARAMETER */
927 9 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
928 : } else {
929 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
930 : }
931 :
932 9 : io.smb2.in.fname = sname1d;
933 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
934 9 : if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
935 : /* w2k returns INVALID_PARAMETER */
936 9 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
937 : } else {
938 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
939 : }
940 :
941 9 : io.smb2.in.fname = sname2;
942 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
943 9 : CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
944 :
945 9 : io.smb2.in.fname = snamew;
946 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
947 9 : CHECK_STATUS(status, NT_STATUS_OK);
948 9 : h3 = io.smb2.out.file.handle;
949 :
950 9 : io.smb2.in.fname = snamew2;
951 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
952 9 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
953 :
954 9 : io.smb2.in.fname = fname;
955 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
956 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
957 9 : CHECK_STATUS(status, NT_STATUS_OK);
958 9 : ret &= check_stream_list(tree, tctx, fname, 4, four,
959 : io.smb2.out.file.handle);
960 9 : CHECK_VALUE(ret, true);
961 9 : smb2_util_close(tree, h1);
962 9 : smb2_util_close(tree, h2);
963 9 : smb2_util_close(tree, h3);
964 :
965 9 : if (torture_setting_bool(tctx, "samba4", true)) {
966 9 : goto done;
967 : }
968 :
969 0 : finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
970 0 : finfo.generic.in.file.handle = io.smb2.out.file.handle;
971 0 : status = smb2_getinfo_file(tree, mem_ctx, &finfo);
972 0 : CHECK_STATUS(status, NT_STATUS_OK);
973 0 : ret &= check_stream_list(tree, tctx, fname, 4, four,
974 : io.smb2.out.file.handle);
975 :
976 0 : CHECK_VALUE(ret, true);
977 0 : for (i=0; i < 4; i++) {
978 : NTTIME write_time;
979 : uint64_t stream_size;
980 0 : char *path = talloc_asprintf(tctx, "%s%s",
981 : fname, four[i]);
982 :
983 0 : char *rpath = talloc_strdup(path, path);
984 0 : char *p = strrchr(rpath, ':');
985 : /* eat :$DATA */
986 0 : *p = 0;
987 0 : p--;
988 0 : if (*p == ':') {
989 : /* eat ::$DATA */
990 0 : *p = 0;
991 : }
992 0 : torture_comment(tctx, "(%s): i[%u][%s]\n",
993 : __location__, i,path);
994 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
995 0 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
996 : SEC_FILE_WRITE_ATTRIBUTE |
997 : SEC_RIGHTS_FILE_ALL;
998 0 : io.smb2.in.fname = path;
999 0 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1000 0 : CHECK_STATUS(status, NT_STATUS_OK);
1001 0 : h1 = io.smb2.out.file.handle;
1002 :
1003 0 : finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
1004 0 : finfo.generic.in.file.path = fname;
1005 0 : status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1006 0 : CHECK_STATUS(status, NT_STATUS_OK);
1007 :
1008 0 : stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
1009 0 : stinfo.generic.in.file.handle = h1;
1010 0 : status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
1011 0 : CHECK_STATUS(status, NT_STATUS_OK);
1012 0 : if (!torture_setting_bool(tctx, "samba3", false)) {
1013 0 : CHECK_NTTIME(stinfo.all_info.out.create_time,
1014 : finfo.all_info.out.create_time);
1015 0 : CHECK_NTTIME(stinfo.all_info.out.access_time,
1016 : finfo.all_info.out.access_time);
1017 0 : CHECK_NTTIME(stinfo.all_info.out.write_time,
1018 : finfo.all_info.out.write_time);
1019 0 : CHECK_NTTIME(stinfo.all_info.out.change_time,
1020 : finfo.all_info.out.change_time);
1021 : }
1022 0 : CHECK_VALUE(stinfo.all_info.out.attrib,
1023 : finfo.all_info.out.attrib);
1024 0 : CHECK_VALUE(stinfo.all_info.out.size,
1025 : finfo.all_info.out.size);
1026 0 : CHECK_VALUE(stinfo.all_info.out.delete_pending,
1027 : finfo.all_info.out.delete_pending);
1028 0 : CHECK_VALUE(stinfo.all_info.out.directory,
1029 : finfo.all_info.out.directory);
1030 0 : CHECK_VALUE(stinfo.all_info.out.ea_size,
1031 : finfo.all_info.out.ea_size);
1032 :
1033 0 : stinfo.generic.level = RAW_FILEINFO_NAME_INFORMATION;
1034 0 : stinfo.generic.in.file.handle = h1;
1035 0 : status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
1036 0 : CHECK_STATUS(status, NT_STATUS_OK);
1037 0 : if (!torture_setting_bool(tctx, "samba3", false)) {
1038 0 : CHECK_STR(rpath, stinfo.name_info.out.fname.s);
1039 : }
1040 :
1041 0 : write_time = finfo.all_info.out.write_time;
1042 0 : write_time += i*1000000;
1043 0 : write_time /= 1000000;
1044 0 : write_time *= 1000000;
1045 :
1046 0 : ZERO_STRUCT(sinfo);
1047 0 : sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
1048 0 : sinfo.basic_info.in.file.handle = h1;
1049 0 : sinfo.basic_info.in.write_time = write_time;
1050 0 : sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
1051 0 : status = smb2_setinfo_file(tree, &sinfo);
1052 0 : CHECK_STATUS(status, NT_STATUS_OK);
1053 :
1054 0 : stream_size = i*8192;
1055 :
1056 0 : ZERO_STRUCT(sinfo);
1057 0 : sinfo.end_of_file_info.level =
1058 : RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1059 0 : sinfo.end_of_file_info.in.file.handle = h1;
1060 0 : sinfo.end_of_file_info.in.size = stream_size;
1061 0 : status = smb2_setinfo_file(tree, &sinfo);
1062 0 : CHECK_STATUS(status, NT_STATUS_OK);
1063 :
1064 0 : stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
1065 0 : stinfo.generic.in.file.handle = h1;
1066 0 : status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
1067 0 : CHECK_STATUS(status, NT_STATUS_OK);
1068 0 : if (!torture_setting_bool(tctx, "samba3", false)) {
1069 0 : CHECK_NTTIME(stinfo.all_info.out.write_time,
1070 : write_time);
1071 0 : CHECK_VALUE(stinfo.all_info.out.attrib,
1072 : finfo.all_info.out.attrib);
1073 : }
1074 0 : CHECK_VALUE(stinfo.all_info.out.size,
1075 : stream_size);
1076 0 : CHECK_VALUE(stinfo.all_info.out.delete_pending,
1077 : finfo.all_info.out.delete_pending);
1078 0 : CHECK_VALUE(stinfo.all_info.out.directory,
1079 : finfo.all_info.out.directory);
1080 0 : CHECK_VALUE(stinfo.all_info.out.ea_size,
1081 : finfo.all_info.out.ea_size);
1082 :
1083 0 : io.smb2.in.fname = fname;
1084 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1085 0 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1086 0 : CHECK_STATUS(status, NT_STATUS_OK);
1087 0 : ret &= check_stream_list(tree, tctx, fname, 4, four,
1088 : io.smb2.out.file.handle);
1089 :
1090 0 : smb2_util_close(tree, h1);
1091 0 : talloc_free(path);
1092 : }
1093 :
1094 0 : torture_comment(tctx, "(%s): testing stream renames\n", __location__);
1095 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1096 0 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1097 : SEC_FILE_WRITE_ATTRIBUTE |
1098 : SEC_RIGHTS_FILE_ALL;
1099 0 : io.smb2.in.fname = snamer1;
1100 0 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1101 0 : CHECK_STATUS(status, NT_STATUS_OK);
1102 0 : h1 = io.smb2.out.file.handle;
1103 0 : ret &= check_stream_list(tree,tctx, fname, 5, five1,
1104 : io.smb2.out.file.handle);
1105 :
1106 0 : ZERO_STRUCT(sinfo);
1107 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1108 0 : sinfo.rename_information.in.file.handle = h1;
1109 0 : sinfo.rename_information.in.overwrite = true;
1110 0 : sinfo.rename_information.in.root_fid = 0;
1111 0 : sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
1112 0 : status = smb2_setinfo_file(tree, &sinfo);
1113 0 : CHECK_STATUS(status, NT_STATUS_OK);
1114 :
1115 0 : ret &= check_stream_list(tree,tctx, fname, 5, five2,
1116 : io.smb2.out.file.handle);
1117 :
1118 0 : CHECK_VALUE(ret, true);
1119 0 : ZERO_STRUCT(sinfo);
1120 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1121 0 : sinfo.rename_information.in.file.handle = h1;
1122 0 : sinfo.rename_information.in.overwrite = false;
1123 0 : sinfo.rename_information.in.root_fid = 0;
1124 0 : sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1125 0 : status = smb2_setinfo_file(tree, &sinfo);
1126 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1127 :
1128 0 : ret &= check_stream_list(tree,tctx, fname, 5, five2,
1129 : io.smb2.out.file.handle);
1130 :
1131 0 : ZERO_STRUCT(sinfo);
1132 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1133 0 : sinfo.rename_information.in.file.handle = h1;
1134 0 : sinfo.rename_information.in.overwrite = true;
1135 0 : sinfo.rename_information.in.root_fid = 0;
1136 0 : sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1137 0 : status = smb2_setinfo_file(tree, &sinfo);
1138 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1139 :
1140 0 : ret &= check_stream_list(tree,tctx, fname, 5, five2,
1141 : io.smb2.out.file.handle);
1142 :
1143 0 : CHECK_VALUE(ret, true);
1144 : /* TODO: we need to test more rename combinations */
1145 :
1146 8 : done:
1147 9 : smb2_util_close(tree, h1);
1148 9 : status = smb2_util_unlink(tree, fname);
1149 9 : smb2_deltree(tree, DNAME);
1150 9 : talloc_free(mem_ctx);
1151 :
1152 9 : return ret;
1153 : }
1154 :
1155 : /*
1156 : test stream names
1157 : */
1158 9 : static bool test_stream_names2(struct torture_context *tctx,
1159 : struct smb2_tree *tree)
1160 : {
1161 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1162 : NTSTATUS status;
1163 : union smb_open io;
1164 9 : const char *fname = DNAME "\\stream_names2.txt";
1165 9 : bool ret = true;
1166 9 : struct smb2_handle h = {{0}};
1167 9 : struct smb2_handle h1 = {{0}};
1168 : uint8_t i;
1169 :
1170 9 : smb2_util_unlink(tree, fname);
1171 9 : smb2_deltree(tree, DNAME);
1172 :
1173 9 : status = torture_smb2_testdir(tree, DNAME, &h);
1174 9 : CHECK_STATUS(status, NT_STATUS_OK);
1175 :
1176 9 : torture_comment(tctx, "(%s) testing stream names\n", __location__);
1177 9 : ZERO_STRUCT(io.smb2);
1178 9 : io.smb2.in.create_flags = 0;
1179 9 : io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
1180 9 : io.smb2.in.create_options = 0;
1181 9 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1182 9 : io.smb2.in.share_access = 0;
1183 9 : io.smb2.in.alloc_size = 0;
1184 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1185 9 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1186 9 : io.smb2.in.security_flags = 0;
1187 9 : io.smb2.in.fname = fname;
1188 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1189 9 : CHECK_STATUS(status, NT_STATUS_OK);
1190 9 : h1 = io.smb2.out.file.handle;
1191 :
1192 1143 : for (i=0x01; i < 0x7F; i++) {
1193 1134 : char *path = talloc_asprintf(mem_ctx, "%s:Stream%c0x%02X:$DATA",
1194 : fname, i, i);
1195 : NTSTATUS expected;
1196 :
1197 1134 : switch (i) {
1198 27 : case '/':/*0x2F*/
1199 : case ':':/*0x3A*/
1200 : case '\\':/*0x5C*/
1201 27 : expected = NT_STATUS_OBJECT_NAME_INVALID;
1202 27 : break;
1203 1107 : default:
1204 1107 : expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1205 1107 : break;
1206 : }
1207 :
1208 :
1209 1134 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1210 1134 : io.smb2.in.fname = path;
1211 1134 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1212 1134 : if (!NT_STATUS_EQUAL(status, expected)) {
1213 0 : torture_comment(tctx,
1214 : "(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1215 0 : __location__, fname, isprint(i)?(char)i:' ', i,
1216 0 : isprint(i)?"":" (not printable)",
1217 : nt_errstr(expected));
1218 : }
1219 1134 : CHECK_STATUS(status, expected);
1220 :
1221 1134 : talloc_free(path);
1222 : }
1223 :
1224 9 : done:
1225 9 : smb2_util_close(tree, h1);
1226 9 : status = smb2_util_unlink(tree, fname);
1227 9 : smb2_deltree(tree, DNAME);
1228 9 : talloc_free(mem_ctx);
1229 :
1230 9 : return ret;
1231 : }
1232 :
1233 : /*
1234 : test case insensitive stream names
1235 : */
1236 9 : static bool test_stream_names3(struct torture_context *tctx,
1237 : struct smb2_tree *tree)
1238 : {
1239 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1240 : NTSTATUS status;
1241 : union smb_fsinfo info;
1242 9 : const char *fname = DNAME "\\stream_names3.txt";
1243 9 : const char *sname = NULL;
1244 9 : const char *snamel = NULL;
1245 9 : const char *snameu = NULL;
1246 9 : const char *sdname = NULL;
1247 9 : const char *sdnamel = NULL;
1248 9 : const char *sdnameu = NULL;
1249 9 : bool ret = true;
1250 9 : struct smb2_handle h = {{0}};
1251 9 : struct smb2_handle hf = {{0}};
1252 9 : struct smb2_handle hs = {{0}};
1253 9 : struct smb2_handle hsl = {{0}};
1254 9 : struct smb2_handle hsu = {{0}};
1255 9 : struct smb2_handle hsd = {{0}};
1256 9 : struct smb2_handle hsdl = {{0}};
1257 9 : struct smb2_handle hsdu = {{0}};
1258 9 : const char *streams[] = { "::$DATA", ":StreamName:$DATA", };
1259 :
1260 9 : smb2_deltree(tree, DNAME);
1261 9 : status = torture_smb2_testdir(tree, DNAME, &h);
1262 9 : CHECK_STATUS(status, NT_STATUS_OK);
1263 :
1264 9 : ZERO_STRUCT(info);
1265 9 : info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION;
1266 9 : info.generic.handle = h;
1267 9 : status = smb2_getinfo_fs(tree, tree, &info);
1268 9 : CHECK_STATUS(status, NT_STATUS_OK);
1269 9 : if (!(info.attribute_info.out.fs_attr & FILE_CASE_SENSITIVE_SEARCH)) {
1270 0 : torture_skip(tctx, "No FILE_CASE_SENSITIVE_SEARCH supported");
1271 : }
1272 :
1273 : /*
1274 : * We create the following file:
1275 : *
1276 : * teststreams\\stream_names3.txt
1277 : *
1278 : * and add a stream named 'StreamName'
1279 : *
1280 : * Then we try to open the stream using the following names:
1281 : *
1282 : * teststreams\\stream_names3.txt:StreamName
1283 : * teststreams\\stream_names3.txt:streamname
1284 : * teststreams\\stream_names3.txt:STREAMNAME
1285 : * teststreams\\stream_names3.txt:StreamName:$dAtA
1286 : * teststreams\\stream_names3.txt:streamname:$data
1287 : * teststreams\\stream_names3.txt:STREAMNAME:$DATA
1288 : */
1289 9 : sname = talloc_asprintf(tctx, "%s:StreamName", fname);
1290 9 : torture_assert_not_null(tctx, sname, __location__);
1291 9 : snamel = strlower_talloc(tctx, sname);
1292 9 : torture_assert_not_null(tctx, snamel, __location__);
1293 9 : snameu = strupper_talloc(tctx, sname);
1294 9 : torture_assert_not_null(tctx, snameu, __location__);
1295 :
1296 9 : sdname = talloc_asprintf(tctx, "%s:$dAtA", sname);
1297 9 : torture_assert_not_null(tctx, sdname, __location__);
1298 9 : sdnamel = strlower_talloc(tctx, sdname);
1299 9 : torture_assert_not_null(tctx, sdnamel, __location__);
1300 9 : sdnameu = strupper_talloc(tctx, sdname);
1301 9 : torture_assert_not_null(tctx, sdnameu, __location__);
1302 :
1303 9 : torture_comment(tctx, "(%s) testing case insensitive stream names\n",
1304 : __location__);
1305 9 : status = torture_smb2_testfile(tree, fname, &hf);
1306 9 : CHECK_STATUS(status, NT_STATUS_OK);
1307 9 : status = torture_smb2_testfile(tree, sname, &hs);
1308 9 : CHECK_STATUS(status, NT_STATUS_OK);
1309 9 : smb2_util_close(tree, hs);
1310 :
1311 9 : torture_assert(tctx,
1312 : check_stream_list(tree, tctx, fname,
1313 : ARRAY_SIZE(streams),
1314 : streams,
1315 : hf),
1316 : "streams");
1317 :
1318 9 : status = torture_smb2_open(tree, sname, SEC_RIGHTS_FILE_ALL, &hs);
1319 9 : CHECK_STATUS(status, NT_STATUS_OK);
1320 9 : status = torture_smb2_open(tree, snamel, SEC_RIGHTS_FILE_ALL, &hsl);
1321 9 : CHECK_STATUS(status, NT_STATUS_OK);
1322 9 : status = torture_smb2_open(tree, snameu, SEC_RIGHTS_FILE_ALL, &hsu);
1323 9 : CHECK_STATUS(status, NT_STATUS_OK);
1324 9 : status = torture_smb2_open(tree, sdname, SEC_RIGHTS_FILE_ALL, &hsd);
1325 9 : CHECK_STATUS(status, NT_STATUS_OK);
1326 9 : status = torture_smb2_open(tree, sdnamel, SEC_RIGHTS_FILE_ALL, &hsdl);
1327 9 : CHECK_STATUS(status, NT_STATUS_OK);
1328 9 : status = torture_smb2_open(tree, sdnameu, SEC_RIGHTS_FILE_ALL, &hsdu);
1329 9 : CHECK_STATUS(status, NT_STATUS_OK);
1330 :
1331 17 : done:
1332 9 : smb2_util_close(tree, hsdu);
1333 9 : smb2_util_close(tree, hsdl);
1334 9 : smb2_util_close(tree, hsd);
1335 9 : smb2_util_close(tree, hsu);
1336 9 : smb2_util_close(tree, hsl);
1337 9 : smb2_util_close(tree, hs);
1338 9 : smb2_util_close(tree, hf);
1339 9 : smb2_util_close(tree, h);
1340 9 : status = smb2_util_unlink(tree, fname);
1341 9 : smb2_deltree(tree, DNAME);
1342 9 : talloc_free(mem_ctx);
1343 :
1344 9 : return ret;
1345 : }
1346 :
1347 : #define CHECK_CALL_HANDLE(call, rightstatus) do { \
1348 : sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1349 : sfinfo.generic.in.file.handle = h1; \
1350 : status = smb2_setinfo_file(tree, &sfinfo); \
1351 : if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1352 : torture_result(tctx, TORTURE_FAIL, \
1353 : "(%s) %s - %s (should be %s)\n", \
1354 : __location__, #call, \
1355 : nt_errstr(status), nt_errstr(rightstatus)); \
1356 : ret = false; \
1357 : } \
1358 : finfo1.generic.level = RAW_FILEINFO_ALL_INFORMATION; \
1359 : finfo1.generic.in.file.handle = h1; \
1360 : status2 = smb2_getinfo_file(tree, tctx, &finfo1); \
1361 : if (!NT_STATUS_IS_OK(status2)) { \
1362 : torture_result(tctx, TORTURE_FAIL, \
1363 : "(%s) %s pathinfo - %s\n", \
1364 : __location__, #call, nt_errstr(status)); \
1365 : ret = false; \
1366 : }} while (0)
1367 :
1368 : /*
1369 : test stream renames
1370 : */
1371 9 : static bool test_stream_rename(struct torture_context *tctx,
1372 : struct smb2_tree *tree)
1373 : {
1374 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1375 : NTSTATUS status, status2;
1376 : union smb_open io;
1377 9 : const char *fname = DNAME "\\stream_rename.txt";
1378 : const char *sname1, *sname2;
1379 : union smb_fileinfo finfo1;
1380 : union smb_setfileinfo sfinfo;
1381 9 : bool ret = true;
1382 9 : struct smb2_handle h = {{0}};
1383 9 : struct smb2_handle h1 = {{0}};
1384 :
1385 9 : sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
1386 9 : sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
1387 : "Second Stream");
1388 :
1389 9 : smb2_util_unlink(tree, fname);
1390 9 : smb2_deltree(tree, DNAME);
1391 :
1392 9 : status = torture_smb2_testdir(tree, DNAME, &h);
1393 9 : CHECK_STATUS(status, NT_STATUS_OK);
1394 :
1395 9 : torture_comment(tctx, "(%s) testing stream renames\n", __location__);
1396 9 : ZERO_STRUCT(io.smb2);
1397 9 : io.smb2.in.create_flags = 0;
1398 9 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1399 : SEC_FILE_WRITE_ATTRIBUTE |
1400 : SEC_RIGHTS_FILE_ALL;
1401 9 : io.smb2.in.create_options = 0;
1402 9 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1403 9 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1404 : NTCREATEX_SHARE_ACCESS_WRITE |
1405 : NTCREATEX_SHARE_ACCESS_DELETE;
1406 9 : io.smb2.in.alloc_size = 0;
1407 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1408 9 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1409 9 : io.smb2.in.security_flags = 0;
1410 9 : io.smb2.in.fname = sname1;
1411 :
1412 : /* Create two streams. */
1413 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1414 9 : CHECK_STATUS(status, NT_STATUS_OK);
1415 9 : h1 = io.smb2.out.file.handle;
1416 9 : smb2_util_close(tree, h1);
1417 :
1418 9 : io.smb2.in.fname = sname2;
1419 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1420 9 : CHECK_STATUS(status, NT_STATUS_OK);
1421 9 : h1 = io.smb2.out.file.handle;
1422 :
1423 9 : smb2_util_close(tree, h1);
1424 :
1425 : /*
1426 : * Open the second stream.
1427 : */
1428 :
1429 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1430 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1431 9 : CHECK_STATUS(status, NT_STATUS_OK);
1432 9 : h1 = io.smb2.out.file.handle;
1433 :
1434 : /*
1435 : * Now rename the second stream onto the first.
1436 : */
1437 :
1438 9 : ZERO_STRUCT(sfinfo);
1439 :
1440 9 : sfinfo.rename_information.in.overwrite = 1;
1441 9 : sfinfo.rename_information.in.root_fid = 0;
1442 9 : sfinfo.rename_information.in.new_name = ":Stream One";
1443 9 : CHECK_CALL_HANDLE(RENAME_INFORMATION, NT_STATUS_OK);
1444 17 : done:
1445 9 : smb2_util_close(tree, h1);
1446 9 : status = smb2_util_unlink(tree, fname);
1447 9 : smb2_deltree(tree, DNAME);
1448 9 : talloc_free(mem_ctx);
1449 :
1450 9 : return ret;
1451 : }
1452 :
1453 9 : static bool test_stream_rename2(struct torture_context *tctx,
1454 : struct smb2_tree *tree)
1455 : {
1456 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1457 : NTSTATUS status;
1458 : union smb_open io;
1459 9 : const char *fname1 = DNAME "\\stream_rename2.txt";
1460 9 : const char *fname2 = DNAME "\\stream2_rename2.txt";
1461 9 : const char *stream_name1 = ":Stream One:$DATA";
1462 9 : const char *stream_name2 = ":Stream Two:$DATA";
1463 9 : const char *stream_name_default = "::$DATA";
1464 : const char *sname1;
1465 : const char *sname2;
1466 9 : bool ret = true;
1467 : struct smb2_handle h, h1;
1468 : union smb_setfileinfo sinfo;
1469 :
1470 9 : ZERO_STRUCT(h);
1471 9 : ZERO_STRUCT(h1);
1472 :
1473 9 : sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream One");
1474 9 : sname2 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream Two");
1475 :
1476 9 : smb2_util_unlink(tree, fname1);
1477 9 : smb2_util_unlink(tree, fname2);
1478 9 : smb2_deltree(tree, DNAME);
1479 :
1480 9 : status = torture_smb2_testdir(tree, DNAME, &h);
1481 9 : CHECK_STATUS(status, NT_STATUS_OK);
1482 :
1483 9 : ZERO_STRUCT(io.smb2);
1484 9 : io.smb2.in.create_flags = 0;
1485 9 : io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1486 : SEC_FILE_WRITE_DATA |
1487 : SEC_STD_DELETE |
1488 : SEC_FILE_APPEND_DATA |
1489 : SEC_STD_READ_CONTROL;
1490 9 : io.smb2.in.create_options = 0;
1491 9 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1492 9 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1493 : NTCREATEX_SHARE_ACCESS_WRITE |
1494 : NTCREATEX_SHARE_ACCESS_DELETE;
1495 9 : io.smb2.in.alloc_size = 0;
1496 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1497 9 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1498 9 : io.smb2.in.security_flags = 0;
1499 9 : io.smb2.in.fname = sname1;
1500 :
1501 : /* Open/create new stream. */
1502 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1503 9 : CHECK_STATUS(status, NT_STATUS_OK);
1504 :
1505 9 : smb2_util_close(tree, io.smb2.out.file.handle);
1506 :
1507 : /*
1508 : * Reopen the stream for SMB2 renames.
1509 : */
1510 9 : io.smb2.in.fname = sname1;
1511 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1512 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1513 9 : CHECK_STATUS(status, NT_STATUS_OK);
1514 9 : h1 = io.smb2.out.file.handle;
1515 :
1516 : /*
1517 : * Check SMB2 rename of a stream using :<stream>.
1518 : */
1519 9 : torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
1520 : ":<stream>\n", __location__);
1521 9 : ZERO_STRUCT(sinfo);
1522 9 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION_SMB2;
1523 9 : sinfo.rename_information.in.file.handle = h1;
1524 9 : sinfo.rename_information.in.overwrite = 1;
1525 9 : sinfo.rename_information.in.root_fid = 0;
1526 9 : sinfo.rename_information.in.new_name = stream_name1;
1527 9 : status = smb2_setinfo_file(tree, &sinfo);
1528 9 : CHECK_STATUS(status, NT_STATUS_OK);
1529 :
1530 : /*
1531 : * Check SMB2 rename of an overwriting stream using :<stream>.
1532 : */
1533 1 : torture_comment(tctx, "(%s) Checking SMB2 rename of an overwriting "
1534 : "stream using :<stream>\n", __location__);
1535 :
1536 : /* Create second stream. */
1537 1 : io.smb2.in.fname = sname2;
1538 1 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1539 1 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1540 1 : CHECK_STATUS(status, NT_STATUS_OK);
1541 1 : smb2_util_close(tree, io.smb2.out.file.handle);
1542 :
1543 : /* Rename the first stream onto the second. */
1544 1 : sinfo.rename_information.in.file.handle = h1;
1545 1 : sinfo.rename_information.in.new_name = stream_name2;
1546 1 : status = smb2_setinfo_file(tree, &sinfo);
1547 1 : CHECK_STATUS(status, NT_STATUS_OK);
1548 :
1549 1 : smb2_util_close(tree, h1);
1550 :
1551 : /*
1552 : * Reopen the stream with the new name.
1553 : */
1554 1 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1555 1 : io.smb2.in.fname = sname2;
1556 1 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1557 1 : CHECK_STATUS(status, NT_STATUS_OK);
1558 1 : h1 = io.smb2.out.file.handle;
1559 :
1560 : /*
1561 : * Check SMB2 rename of a stream using <base>:<stream>.
1562 : */
1563 1 : torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
1564 : "<base>:<stream>\n", __location__);
1565 1 : sinfo.rename_information.in.file.handle = h1;
1566 1 : sinfo.rename_information.in.new_name = sname1;
1567 1 : status = smb2_setinfo_file(tree, &sinfo);
1568 1 : CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1569 :
1570 1 : if (!torture_setting_bool(tctx, "samba4", false)) {
1571 : /*
1572 : * Check SMB2 rename to the default stream using :<stream>.
1573 : */
1574 0 : torture_comment(tctx, "(%s) Checking SMB2 rename to default stream "
1575 : "using :<stream>\n", __location__);
1576 0 : sinfo.rename_information.in.file.handle = h1;
1577 0 : sinfo.rename_information.in.new_name = stream_name_default;
1578 0 : status = smb2_setinfo_file(tree, &sinfo);
1579 0 : CHECK_STATUS(status, NT_STATUS_OK);
1580 : }
1581 :
1582 1 : smb2_util_close(tree, h1);
1583 :
1584 9 : done:
1585 9 : smb2_util_close(tree, h1);
1586 9 : status = smb2_util_unlink(tree, fname1);
1587 9 : status = smb2_util_unlink(tree, fname2);
1588 9 : smb2_deltree(tree, DNAME);
1589 9 : talloc_free(mem_ctx);
1590 :
1591 9 : return ret;
1592 : }
1593 :
1594 42 : static bool create_file_with_stream(struct torture_context *tctx,
1595 : struct smb2_tree *tree,
1596 : TALLOC_CTX *mem_ctx,
1597 : const char *base_fname,
1598 : const char *stream)
1599 : {
1600 : NTSTATUS status;
1601 42 : bool ret = true;
1602 : union smb_open io;
1603 :
1604 : /* Create a file with a stream */
1605 42 : ZERO_STRUCT(io.smb2);
1606 42 : io.smb2.in.create_flags = 0;
1607 42 : io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1608 : SEC_FILE_WRITE_DATA |
1609 : SEC_FILE_APPEND_DATA |
1610 : SEC_STD_READ_CONTROL;
1611 42 : io.smb2.in.create_options = 0;
1612 42 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1613 42 : io.smb2.in.share_access = 0;
1614 42 : io.smb2.in.alloc_size = 0;
1615 42 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1616 42 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1617 42 : io.smb2.in.security_flags = 0;
1618 42 : io.smb2.in.fname = stream;
1619 :
1620 42 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1621 44 : CHECK_STATUS(status, NT_STATUS_OK);
1622 :
1623 77 : done:
1624 42 : smb2_util_close(tree, io.smb2.out.file.handle);
1625 42 : return ret;
1626 : }
1627 :
1628 :
1629 : /* Test how streams interact with create dispositions */
1630 9 : static bool test_stream_create_disposition(struct torture_context *tctx,
1631 : struct smb2_tree *tree)
1632 : {
1633 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1634 : NTSTATUS status;
1635 : union smb_open io;
1636 9 : const char *fname = DNAME "\\stream_create_disp.txt";
1637 9 : const char *stream = "Stream One:$DATA";
1638 : const char *fname_stream;
1639 9 : const char *default_stream_name = "::$DATA";
1640 : const char *stream_list[2];
1641 9 : bool ret = true;
1642 9 : struct smb2_handle h = {{0}};
1643 9 : struct smb2_handle h1 = {{0}};
1644 :
1645 : /* clean slate .. */
1646 9 : smb2_util_unlink(tree, fname);
1647 9 : smb2_deltree(tree, fname);
1648 9 : smb2_deltree(tree, DNAME);
1649 :
1650 9 : status = torture_smb2_testdir(tree, DNAME, &h);
1651 9 : CHECK_STATUS(status, NT_STATUS_OK);
1652 :
1653 9 : fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1654 :
1655 9 : stream_list[0] = talloc_asprintf(mem_ctx, ":%s", stream);
1656 9 : stream_list[1] = default_stream_name;
1657 :
1658 9 : if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1659 : fname_stream)) {
1660 0 : goto done;
1661 : }
1662 :
1663 : /* Open the base file with OPEN */
1664 9 : ZERO_STRUCT(io.smb2);
1665 9 : io.smb2.in.create_flags = 0;
1666 9 : io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1667 : SEC_FILE_WRITE_DATA |
1668 : SEC_FILE_APPEND_DATA |
1669 : SEC_STD_READ_CONTROL;
1670 9 : io.smb2.in.create_options = 0;
1671 9 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1672 9 : io.smb2.in.share_access = 0;
1673 9 : io.smb2.in.alloc_size = 0;
1674 9 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1675 9 : io.smb2.in.security_flags = 0;
1676 9 : io.smb2.in.fname = fname;
1677 :
1678 : /*
1679 : * check create open: sanity check
1680 : */
1681 9 : torture_comment(tctx, "(%s) Checking create disp: open\n",
1682 : __location__);
1683 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1684 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1685 9 : CHECK_STATUS(status, NT_STATUS_OK);
1686 9 : if (!check_stream_list(tree, tctx, fname, 2, stream_list,
1687 : io.smb2.out.file.handle)) {
1688 0 : goto done;
1689 : }
1690 9 : smb2_util_close(tree, io.smb2.out.file.handle);
1691 :
1692 : /*
1693 : * check create overwrite
1694 : */
1695 9 : torture_comment(tctx, "(%s) Checking create disp: overwrite\n",
1696 : __location__);
1697 9 : io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1698 9 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1699 9 : CHECK_STATUS(status, NT_STATUS_OK);
1700 9 : if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1701 : io.smb2.out.file.handle)) {
1702 1 : goto done;
1703 : }
1704 8 : smb2_util_close(tree, io.smb2.out.file.handle);
1705 :
1706 : /*
1707 : * check create overwrite_if
1708 : */
1709 8 : torture_comment(tctx, "(%s) Checking create disp: overwrite_if\n",
1710 : __location__);
1711 8 : smb2_util_unlink(tree, fname);
1712 8 : if (!create_file_with_stream(tctx, tree, mem_ctx, fname, fname_stream))
1713 0 : goto done;
1714 :
1715 8 : io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1716 8 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1717 8 : CHECK_STATUS(status, NT_STATUS_OK);
1718 8 : if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1719 : io.smb2.out.file.handle)) {
1720 0 : goto done;
1721 : }
1722 8 : smb2_util_close(tree, io.smb2.out.file.handle);
1723 :
1724 : /*
1725 : * check create supersede
1726 : */
1727 8 : torture_comment(tctx, "(%s) Checking create disp: supersede\n",
1728 : __location__);
1729 8 : smb2_util_unlink(tree, fname);
1730 8 : if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1731 : fname_stream)) {
1732 0 : goto done;
1733 : }
1734 :
1735 8 : io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
1736 8 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1737 8 : CHECK_STATUS(status, NT_STATUS_OK);
1738 8 : if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1739 : io.smb2.out.file.handle)) {
1740 0 : goto done;
1741 : }
1742 8 : smb2_util_close(tree, io.smb2.out.file.handle);
1743 :
1744 : /*
1745 : * check create overwrite_if on a stream.
1746 : */
1747 8 : torture_comment(tctx, "(%s) Checking create disp: overwrite_if on "
1748 : "stream\n", __location__);
1749 8 : smb2_util_unlink(tree, fname);
1750 8 : if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1751 : fname_stream)) {
1752 0 : goto done;
1753 : }
1754 :
1755 8 : io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1756 8 : io.smb2.in.fname = fname_stream;
1757 8 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1758 8 : CHECK_STATUS(status, NT_STATUS_OK);
1759 8 : if (!check_stream_list(tree, tctx, fname, 2, stream_list,
1760 : io.smb2.out.file.handle)) {
1761 8 : goto done;
1762 : }
1763 0 : smb2_util_close(tree, io.smb2.out.file.handle);
1764 9 : done:
1765 9 : smb2_util_close(tree, h1);
1766 9 : smb2_util_unlink(tree, fname);
1767 9 : smb2_deltree(tree, DNAME);
1768 9 : talloc_free(mem_ctx);
1769 :
1770 9 : return ret;
1771 : }
1772 :
1773 14 : static bool open_stream(struct smb2_tree *tree,
1774 : struct torture_context *mem_ctx,
1775 : const char *fname,
1776 : struct smb2_handle *h_out)
1777 : {
1778 : NTSTATUS status;
1779 : union smb_open io;
1780 :
1781 14 : ZERO_STRUCT(io.smb2);
1782 14 : io.smb2.in.create_flags = 0;
1783 14 : io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1784 : SEC_FILE_WRITE_DATA |
1785 : SEC_FILE_APPEND_DATA |
1786 : SEC_STD_READ_CONTROL |
1787 : SEC_FILE_WRITE_ATTRIBUTE;
1788 14 : io.smb2.in.create_options = 0;
1789 14 : io.smb2.in.file_attributes = 0;
1790 14 : io.smb2.in.share_access = 0;
1791 14 : io.smb2.in.alloc_size = 0;
1792 14 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1793 14 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1794 14 : io.smb2.in.security_flags = 0;
1795 14 : io.smb2.in.fname = fname;
1796 :
1797 14 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1798 14 : if (!NT_STATUS_IS_OK(status)) {
1799 0 : return false;
1800 : }
1801 14 : *h_out = io.smb2.out.file.handle;
1802 14 : return true;
1803 : }
1804 :
1805 :
1806 : /* Test the effect of setting attributes on a stream. */
1807 9 : static bool test_stream_attributes(struct torture_context *tctx,
1808 : struct smb2_tree *tree)
1809 : {
1810 9 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
1811 9 : bool ret = true;
1812 : NTSTATUS status;
1813 : union smb_open io;
1814 9 : const char *fname = DNAME "\\stream_attr.txt";
1815 9 : const char *stream = "Stream One:$DATA";
1816 : const char *fname_stream;
1817 : struct smb2_handle h, h1;
1818 : union smb_fileinfo finfo;
1819 : union smb_setfileinfo sfinfo;
1820 9 : time_t basetime = (time(NULL) - 86400) & ~1;
1821 :
1822 9 : ZERO_STRUCT(h);
1823 9 : ZERO_STRUCT(h1);
1824 :
1825 9 : torture_comment(tctx, "(%s) testing attribute setting on stream\n",
1826 : __location__);
1827 :
1828 : /* clean slate .. */
1829 9 : smb2_util_unlink(tree, fname);
1830 9 : smb2_deltree(tree, fname);
1831 9 : smb2_deltree(tree, DNAME);
1832 :
1833 9 : status = torture_smb2_testdir(tree, DNAME, &h);
1834 9 : CHECK_STATUS(status, NT_STATUS_OK);
1835 :
1836 9 : fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1837 :
1838 : /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1839 9 : ret = create_file_with_stream(tctx, tree, mem_ctx, fname,
1840 : fname_stream);
1841 9 : if (!ret) {
1842 2 : goto done;
1843 : }
1844 :
1845 7 : ZERO_STRUCT(io.smb2);
1846 7 : io.smb2.in.fname = fname;
1847 7 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1848 7 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1849 7 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1850 : NTCREATEX_SHARE_ACCESS_WRITE |
1851 : NTCREATEX_SHARE_ACCESS_DELETE;
1852 7 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1853 7 : CHECK_STATUS(status, NT_STATUS_OK);
1854 :
1855 7 : ZERO_STRUCT(finfo);
1856 7 : finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1857 7 : finfo.generic.in.file.handle = io.smb2.out.file.handle;
1858 7 : status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1859 7 : CHECK_STATUS(status, NT_STATUS_OK);
1860 :
1861 7 : if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
1862 0 : torture_comment(tctx, "(%s) Incorrect attrib %x - should be "
1863 : "%x\n", __location__,
1864 0 : (unsigned int)finfo.basic_info.out.attrib,
1865 : (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
1866 0 : ret = false;
1867 0 : goto done;
1868 : }
1869 :
1870 7 : smb2_util_close(tree, io.smb2.out.file.handle);
1871 : /* Now open the stream name. */
1872 :
1873 7 : if (!open_stream(tree, tctx, fname_stream, &h1)) {
1874 0 : goto done;
1875 : }
1876 :
1877 : /* Change the time on the stream. */
1878 7 : ZERO_STRUCT(sfinfo);
1879 7 : unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1880 7 : sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1881 7 : sfinfo.generic.in.file.handle = h1;
1882 7 : status = smb2_setinfo_file(tree, &sfinfo);
1883 7 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1884 0 : torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
1885 : __location__, "SETATTR",
1886 0 : nt_errstr(status), nt_errstr(NT_STATUS_OK));
1887 0 : ret = false;
1888 0 : goto done;
1889 : }
1890 :
1891 7 : smb2_util_close(tree, h1);
1892 :
1893 7 : ZERO_STRUCT(io.smb2);
1894 7 : io.smb2.in.fname = fname;
1895 7 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1896 7 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1897 7 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1898 7 : CHECK_STATUS(status, NT_STATUS_OK);
1899 7 : h1 = io.smb2.out.file.handle;
1900 :
1901 7 : ZERO_STRUCT(finfo);
1902 7 : finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1903 7 : finfo.generic.in.file.handle = h1;
1904 7 : status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1905 7 : if (!NT_STATUS_IS_OK(status)) {
1906 0 : torture_comment(tctx, "(%s) %s pathinfo - %s\n",
1907 : __location__, "SETATTRE", nt_errstr(status));
1908 0 : ret = false;
1909 0 : goto done;
1910 : }
1911 :
1912 7 : if (nt_time_to_unix(finfo.basic_info.out.write_time) != basetime) {
1913 0 : torture_comment(tctx, "(%s) time incorrect.\n", __location__);
1914 0 : ret = false;
1915 0 : goto done;
1916 : }
1917 7 : smb2_util_close(tree, h1);
1918 :
1919 7 : if (!open_stream(tree, tctx, fname_stream, &h1)) {
1920 0 : goto done;
1921 : }
1922 :
1923 : /* Changing attributes on stream */
1924 7 : ZERO_STRUCT(sfinfo);
1925 7 : sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1926 :
1927 7 : sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1928 7 : sfinfo.generic.in.file.handle = h1;
1929 7 : status = smb2_setinfo_file(tree, &sfinfo);
1930 7 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1931 0 : torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
1932 : __location__, "SETATTR",
1933 0 : nt_errstr(status), nt_errstr(NT_STATUS_OK));
1934 0 : ret = false;
1935 0 : goto done;
1936 : }
1937 :
1938 7 : smb2_util_close(tree, h1);
1939 :
1940 7 : ZERO_STRUCT(io.smb2);
1941 7 : io.smb2.in.fname = fname;
1942 7 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1943 7 : io.smb2.in.desired_access = SEC_FILE_READ_DATA;
1944 7 : status = smb2_create(tree, mem_ctx, &(io.smb2));
1945 7 : CHECK_STATUS(status, NT_STATUS_OK);
1946 7 : h1 = io.smb2.out.file.handle;
1947 :
1948 7 : ZERO_STRUCT(finfo);
1949 7 : finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1950 7 : finfo.generic.in.file.handle = h1;
1951 7 : status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1952 12 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1953 :
1954 10 : done:
1955 9 : smb2_util_close(tree, h1);
1956 9 : smb2_util_unlink(tree, fname);
1957 9 : smb2_deltree(tree, DNAME);
1958 9 : talloc_free(mem_ctx);
1959 :
1960 9 : return ret;
1961 : }
1962 :
1963 9 : static bool test_basefile_rename_with_open_stream(struct torture_context *tctx,
1964 : struct smb2_tree *tree)
1965 : {
1966 9 : bool ret = true;
1967 : NTSTATUS status;
1968 9 : struct smb2_tree *tree2 = NULL;
1969 : struct smb2_create create, create2;
1970 9 : struct smb2_handle h1 = {{0}}, h2 = {{0}};
1971 9 : const char *fname = "test_rename_openfile";
1972 9 : const char *sname = "test_rename_openfile:foo";
1973 9 : const char *fname_renamed = "test_rename_openfile_renamed";
1974 : union smb_setfileinfo sinfo;
1975 9 : const char *data = "test data";
1976 :
1977 9 : ret = torture_smb2_connection(tctx, &tree2);
1978 9 : torture_assert_goto(tctx, ret == true, ret, done,
1979 : "torture_smb2_connection failed\n");
1980 :
1981 9 : torture_comment(tctx, "Creating file with stream\n");
1982 :
1983 9 : ZERO_STRUCT(create);
1984 9 : create.in.desired_access = SEC_FILE_ALL;
1985 9 : create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
1986 9 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1987 9 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1988 9 : create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1989 9 : create.in.fname = sname;
1990 :
1991 9 : status = smb2_create(tree, tctx, &create);
1992 9 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1993 : "smb2_create failed\n");
1994 :
1995 9 : h1 = create.out.file.handle;
1996 :
1997 9 : torture_comment(tctx, "Writing to stream\n");
1998 :
1999 9 : status = smb2_util_write(tree, h1, data, 0, strlen(data));
2000 9 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2001 : "smb2_util_write failed\n");
2002 :
2003 9 : torture_comment(tctx, "Renaming base file\n");
2004 :
2005 9 : ZERO_STRUCT(create2);
2006 9 : create2.in.desired_access = SEC_FILE_ALL;
2007 9 : create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2008 9 : create2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
2009 9 : create2.in.create_disposition = NTCREATEX_DISP_OPEN;
2010 9 : create2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
2011 9 : create2.in.fname = fname;
2012 :
2013 9 : status = smb2_create(tree2, tctx, &create2);
2014 9 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2015 : "smb2_create failed\n");
2016 :
2017 9 : h2 = create2.out.file.handle;
2018 :
2019 9 : ZERO_STRUCT(sinfo);
2020 9 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
2021 9 : sinfo.rename_information.in.file.handle = h2;
2022 9 : sinfo.rename_information.in.new_name = fname_renamed;
2023 :
2024 9 : status = smb2_setinfo_file(tree2, &sinfo);
2025 9 : torture_assert_ntstatus_equal_goto(
2026 : tctx, status, NT_STATUS_ACCESS_DENIED, ret, done,
2027 : "smb2_setinfo_file didn't return NT_STATUS_ACCESS_DENIED\n");
2028 :
2029 9 : smb2_util_close(tree2, h2);
2030 :
2031 9 : done:
2032 9 : if (!smb2_util_handle_empty(h1)) {
2033 9 : smb2_util_close(tree, h1);
2034 : }
2035 9 : if (!smb2_util_handle_empty(h2)) {
2036 9 : smb2_util_close(tree2, h2);
2037 : }
2038 9 : smb2_util_unlink(tree, fname);
2039 9 : smb2_util_unlink(tree, fname_renamed);
2040 :
2041 9 : return ret;
2042 : }
2043 :
2044 : /*
2045 : basic testing of streams calls SMB2
2046 : */
2047 2355 : struct torture_suite *torture_smb2_streams_init(TALLOC_CTX *ctx)
2048 : {
2049 1897 : struct torture_suite *suite =
2050 458 : torture_suite_create(ctx, "streams");
2051 :
2052 2355 : torture_suite_add_1smb2_test(suite, "dir", test_stream_dir);
2053 2355 : torture_suite_add_1smb2_test(suite, "io", test_stream_io);
2054 2355 : torture_suite_add_1smb2_test(suite, "sharemodes", test_stream_sharemodes);
2055 2355 : torture_suite_add_1smb2_test(suite, "names", test_stream_names);
2056 2355 : torture_suite_add_1smb2_test(suite, "names2", test_stream_names2);
2057 2355 : torture_suite_add_1smb2_test(suite, "names3", test_stream_names3);
2058 2355 : torture_suite_add_1smb2_test(suite, "rename", test_stream_rename);
2059 2355 : torture_suite_add_1smb2_test(suite, "rename2", test_stream_rename2);
2060 2355 : torture_suite_add_1smb2_test(suite, "create-disposition", test_stream_create_disposition);
2061 2355 : torture_suite_add_1smb2_test(suite, "attributes", test_stream_attributes);
2062 2355 : torture_suite_add_1smb2_test(suite, "delete", test_stream_delete);
2063 2355 : torture_suite_add_1smb2_test(suite, "zero-byte", test_zero_byte_stream);
2064 2355 : torture_suite_add_1smb2_test(suite, "basefile-rename-with-open-stream",
2065 : test_basefile_rename_with_open_stream);
2066 :
2067 2355 : suite->description = talloc_strdup(suite, "SMB2-STREAM tests");
2068 2355 : return suite;
2069 : }
|