lib/util: Build iov_buf library only when building samba
[Samba.git] / source4 / torture / raw / streams.c
blobc1e502ff23760f2a26f65aebc179445ace2e1d97
1 /*
2 Unix SMB/CIFS implementation.
4 test alternate data streams
6 Copyright (C) Andrew Tridgell 2004
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.
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.
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/>.
22 #include "includes.h"
23 #include "system/locale.h"
24 #include "torture/torture.h"
25 #include "libcli/raw/libcliraw.h"
26 #include "libcli/security/dom_sid.h"
27 #include "libcli/security/security_descriptor.h"
28 #include "system/filesys.h"
29 #include "libcli/libcli.h"
30 #include "torture/util.h"
31 #include "lib/util/tsort.h"
32 #include "torture/raw/proto.h"
34 #define BASEDIR "\\teststreams"
36 #define CHECK_STATUS(status, correct) \
37 torture_assert_ntstatus_equal_goto(tctx,status,correct,ret,done,"CHECK_STATUS")
39 #define CHECK_VALUE(v, correct) \
40 torture_assert_int_equal(tctx,v,correct,"CHECK_VALUE")
42 #define CHECK_NTTIME(v, correct) \
43 torture_assert_u64_equal(tctx,v,correct,"CHECK_NTTIME")
45 #define CHECK_STR(v, correct) do { \
46 bool ok; \
47 if ((v) && !(correct)) { \
48 ok = false; \
49 } else if (!(v) && (correct)) { \
50 ok = false; \
51 } else if (!(v) && !(correct)) { \
52 ok = true; \
53 } else if (strcmp((v), (correct)) == 0) { \
54 ok = true; \
55 } else { \
56 ok = false; \
57 } \
58 torture_assert(tctx,ok,\
59 talloc_asprintf(tctx, "got '%s', expected '%s'",\
60 (v)?(v):"NULL", (correct)?(correct):"NULL")); \
61 } while (0)
64 check that a stream has the right contents
66 static bool check_stream(struct smbcli_state *cli, const char *location,
67 TALLOC_CTX *mem_ctx,
68 const char *fname, const char *sname,
69 const char *value)
71 int fnum;
72 const char *full_name;
73 uint8_t *buf;
74 ssize_t ret;
76 full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
78 fnum = smbcli_open(cli->tree, full_name, O_RDONLY, DENY_NONE);
80 if (value == NULL) {
81 if (fnum != -1) {
82 printf("(%s) should have failed stream open of %s\n",
83 location, full_name);
84 return false;
86 return true;
89 if (fnum == -1) {
90 printf("(%s) Failed to open stream '%s' - %s\n",
91 location, full_name, smbcli_errstr(cli->tree));
92 return false;
95 buf = talloc_array(mem_ctx, uint8_t, strlen(value)+11);
97 ret = smbcli_read(cli->tree, fnum, buf, 0, strlen(value)+11);
98 if (ret != strlen(value)) {
99 printf("(%s) Failed to read %lu bytes from stream '%s' - got %d\n",
100 location, (long)strlen(value), full_name, (int)ret);
101 return false;
104 if (memcmp(buf, value, strlen(value)) != 0) {
105 printf("(%s) Bad data in stream\n", location);
106 return false;
109 smbcli_close(cli->tree, fnum);
110 return true;
113 static int qsort_string(char * const *s1, char * const *s2)
115 return strcmp(*s1, *s2);
118 static int qsort_stream(const struct stream_struct *s1, const struct stream_struct *s2)
120 return strcmp(s1->stream_name.s, s2->stream_name.s);
123 static bool check_stream_list(struct torture_context *tctx,
124 struct smbcli_state *cli, const char *fname,
125 int num_exp, const char **exp)
127 union smb_fileinfo finfo;
128 NTSTATUS status;
129 int i;
130 TALLOC_CTX *tmp_ctx = talloc_new(cli);
131 char **exp_sort;
132 struct stream_struct *stream_sort;
133 bool ret = false;
134 int fail = -1;
136 finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
137 finfo.generic.in.file.path = fname;
139 status = smb_raw_pathinfo(cli->tree, tmp_ctx, &finfo);
140 CHECK_STATUS(status, NT_STATUS_OK);
142 CHECK_VALUE(finfo.stream_info.out.num_streams, num_exp);
144 if (num_exp == 0) {
145 ret = true;
146 goto done;
149 exp_sort = (char **)talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
151 if (exp_sort == NULL) {
152 goto done;
155 TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
157 stream_sort = (struct stream_struct *)talloc_memdup(tmp_ctx,
158 finfo.stream_info.out.streams,
159 finfo.stream_info.out.num_streams *
160 sizeof(*stream_sort));
162 if (stream_sort == NULL) {
163 goto done;
166 TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
168 for (i=0; i<num_exp; i++) {
169 if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
170 fail = i;
171 goto show_streams;
175 ret = true;
176 done:
177 talloc_free(tmp_ctx);
178 return ret;
180 show_streams:
181 for (i=0; i<num_exp; i++) {
182 torture_comment(tctx, "stream names '%s' '%s'\n",
183 exp_sort[i], stream_sort[i].stream_name.s);
185 CHECK_STR(stream_sort[fail].stream_name.s, exp_sort[fail]);
186 talloc_free(tmp_ctx);
187 return ret;
191 test bahavior of streams on directories
193 static bool test_stream_dir(struct torture_context *tctx,
194 struct smbcli_state *cli)
196 NTSTATUS status;
197 union smb_open io;
198 const char *fname = BASEDIR "\\stream.txt";
199 const char *sname1;
200 bool ret = true;
201 const char *basedir_data;
203 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
205 basedir_data = talloc_asprintf(tctx, "%s::$DATA", BASEDIR);
206 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
208 printf("(%s) opening non-existent directory stream\n", __location__);
209 io.generic.level = RAW_OPEN_NTCREATEX;
210 io.ntcreatex.in.root_fid.fnum = 0;
211 io.ntcreatex.in.flags = 0;
212 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
213 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
214 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
215 io.ntcreatex.in.share_access = 0;
216 io.ntcreatex.in.alloc_size = 0;
217 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
218 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
219 io.ntcreatex.in.security_flags = 0;
220 io.ntcreatex.in.fname = sname1;
221 status = smb_raw_open(cli->tree, tctx, &io);
222 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
224 printf("(%s) opening basedir stream\n", __location__);
225 io.generic.level = RAW_OPEN_NTCREATEX;
226 io.ntcreatex.in.root_fid.fnum = 0;
227 io.ntcreatex.in.flags = 0;
228 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
229 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
230 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
231 io.ntcreatex.in.share_access = 0;
232 io.ntcreatex.in.alloc_size = 0;
233 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
234 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
235 io.ntcreatex.in.security_flags = 0;
236 io.ntcreatex.in.fname = basedir_data;
237 status = smb_raw_open(cli->tree, tctx, &io);
238 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
240 printf("(%s) opening basedir ::$DATA stream\n", __location__);
241 io.generic.level = RAW_OPEN_NTCREATEX;
242 io.ntcreatex.in.root_fid.fnum = 0;
243 io.ntcreatex.in.flags = 0x10;
244 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
245 io.ntcreatex.in.create_options = 0;
246 io.ntcreatex.in.file_attr = 0;
247 io.ntcreatex.in.share_access = 0;
248 io.ntcreatex.in.alloc_size = 0;
249 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
250 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
251 io.ntcreatex.in.security_flags = 0;
252 io.ntcreatex.in.fname = basedir_data;
253 status = smb_raw_open(cli->tree, tctx, &io);
254 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
256 printf("(%s) list the streams on the basedir\n", __location__);
257 ret &= check_stream_list(tctx, cli, BASEDIR, 0, NULL);
258 done:
259 smbcli_deltree(cli->tree, BASEDIR);
260 return ret;
264 test basic behavior of streams on directories
266 static bool test_stream_io(struct torture_context *tctx,
267 struct smbcli_state *cli)
269 NTSTATUS status;
270 union smb_open io;
271 const char *fname = BASEDIR "\\stream.txt";
272 const char *sname1, *sname2;
273 bool ret = true;
274 int fnum = -1;
275 ssize_t retsize;
277 const char *one[] = { "::$DATA" };
278 const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
279 const char *three[] = { "::$DATA", ":Stream One:$DATA",
280 ":Second Stream:$DATA" };
282 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
284 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
285 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
287 printf("(%s) creating a stream on a non-existent file\n", __location__);
288 io.generic.level = RAW_OPEN_NTCREATEX;
289 io.ntcreatex.in.root_fid.fnum = 0;
290 io.ntcreatex.in.flags = 0;
291 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
292 io.ntcreatex.in.create_options = 0;
293 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
294 io.ntcreatex.in.share_access = 0;
295 io.ntcreatex.in.alloc_size = 0;
296 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
297 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
298 io.ntcreatex.in.security_flags = 0;
299 io.ntcreatex.in.fname = sname1;
300 status = smb_raw_open(cli->tree, tctx, &io);
301 CHECK_STATUS(status, NT_STATUS_OK);
302 fnum = io.ntcreatex.out.file.fnum;
304 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", NULL);
306 printf("(%s) check that open of base file is allowed\n", __location__);
307 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
308 io.ntcreatex.in.fname = fname;
309 status = smb_raw_open(cli->tree, tctx, &io);
310 CHECK_STATUS(status, NT_STATUS_OK);
311 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
313 printf("(%s) writing to stream\n", __location__);
314 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
315 CHECK_VALUE(retsize, 9);
317 smbcli_close(cli->tree, fnum);
319 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test data");
321 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
322 io.ntcreatex.in.fname = sname1;
323 status = smb_raw_open(cli->tree, tctx, &io);
324 CHECK_STATUS(status, NT_STATUS_OK);
325 fnum = io.ntcreatex.out.file.fnum;
327 printf("(%s) modifying stream\n", __location__);
328 retsize = smbcli_write(cli->tree, fnum, 0, "MORE DATA ", 5, 10);
329 CHECK_VALUE(retsize, 10);
331 smbcli_close(cli->tree, fnum);
333 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$FOO", NULL);
335 printf("(%s) creating a stream2 on a existing file\n", __location__);
336 io.ntcreatex.in.fname = sname2;
337 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
338 status = smb_raw_open(cli->tree, tctx, &io);
339 CHECK_STATUS(status, NT_STATUS_OK);
340 fnum = io.ntcreatex.out.file.fnum;
342 printf("(%s) modifying stream\n", __location__);
343 retsize = smbcli_write(cli->tree, fnum, 0, "SECOND STREAM", 0, 13);
344 CHECK_VALUE(retsize, 13);
346 smbcli_close(cli->tree, fnum);
348 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test MORE DATA ");
349 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$DATA", "test MORE DATA ");
350 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:", NULL);
351 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream", "SECOND STREAM");
352 ret &= check_stream(cli, __location__, tctx, fname,
353 "SECOND STREAM:$DATA", "SECOND STREAM");
354 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$DATA", "SECOND STREAM");
355 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:", NULL);
356 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$FOO", NULL);
358 check_stream_list(tctx, cli, fname, 3, three);
360 printf("(%s) deleting stream\n", __location__);
361 status = smbcli_unlink(cli->tree, sname1);
362 CHECK_STATUS(status, NT_STATUS_OK);
364 check_stream_list(tctx, cli, fname, 2, two);
366 printf("(%s) delete a stream via delete-on-close\n", __location__);
367 io.ntcreatex.in.fname = sname2;
368 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
369 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
370 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
371 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
373 status = smb_raw_open(cli->tree, tctx, &io);
374 CHECK_STATUS(status, NT_STATUS_OK);
375 fnum = io.ntcreatex.out.file.fnum;
377 smbcli_close(cli->tree, fnum);
378 status = smbcli_unlink(cli->tree, sname2);
379 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
381 check_stream_list(tctx, cli, fname, 1, one);
383 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
384 io.ntcreatex.in.fname = sname1;
385 status = smb_raw_open(cli->tree, tctx, &io);
386 CHECK_STATUS(status, NT_STATUS_OK);
387 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
388 io.ntcreatex.in.fname = sname2;
389 status = smb_raw_open(cli->tree, tctx, &io);
390 CHECK_STATUS(status, NT_STATUS_OK);
391 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
393 printf("(%s) deleting file\n", __location__);
394 status = smbcli_unlink(cli->tree, fname);
395 CHECK_STATUS(status, NT_STATUS_OK);
397 done:
398 smbcli_close(cli->tree, fnum);
399 smbcli_deltree(cli->tree, BASEDIR);
400 return ret;
404 test stream sharemodes
406 static bool test_stream_sharemodes(struct torture_context *tctx,
407 struct smbcli_state *cli)
409 NTSTATUS status;
410 union smb_open io;
411 const char *fname = BASEDIR "\\stream.txt";
412 const char *sname1, *sname2;
413 bool ret = true;
414 int fnum1 = -1;
415 int fnum2 = -1;
417 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
419 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
420 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
422 printf("(%s) testing stream share mode conflicts\n", __location__);
423 io.generic.level = RAW_OPEN_NTCREATEX;
424 io.ntcreatex.in.root_fid.fnum = 0;
425 io.ntcreatex.in.flags = 0;
426 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
427 io.ntcreatex.in.create_options = 0;
428 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
429 io.ntcreatex.in.share_access = 0;
430 io.ntcreatex.in.alloc_size = 0;
431 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
432 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
433 io.ntcreatex.in.security_flags = 0;
434 io.ntcreatex.in.fname = sname1;
436 status = smb_raw_open(cli->tree, tctx, &io);
437 CHECK_STATUS(status, NT_STATUS_OK);
438 fnum1 = io.ntcreatex.out.file.fnum;
441 * A different stream does not give a sharing violation
444 io.ntcreatex.in.fname = sname2;
445 status = smb_raw_open(cli->tree, tctx, &io);
446 CHECK_STATUS(status, NT_STATUS_OK);
447 fnum2 = io.ntcreatex.out.file.fnum;
450 * ... whereas the same stream does with unchanged access/share_access
451 * flags
454 io.ntcreatex.in.fname = sname1;
455 io.ntcreatex.in.open_disposition = 0;
456 status = smb_raw_open(cli->tree, tctx, &io);
457 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
459 io.ntcreatex.in.fname = sname2;
460 status = smb_raw_open(cli->tree, tctx, &io);
461 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
463 done:
464 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
465 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
466 status = smbcli_unlink(cli->tree, fname);
467 smbcli_deltree(cli->tree, BASEDIR);
468 return ret;
472 * Test FILE_SHARE_DELETE on streams
474 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
475 * with SEC_STD_DELETE.
477 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
478 * be opened with SEC_STD_DELETE.
480 * A stream held open with FILE_SHARE_DELETE allows the file to be
481 * deleted. After the main file is deleted, access to the open file descriptor
482 * still works, but all name-based access to both the main file as well as the
483 * stream is denied with DELETE pending.
485 * This means, an open of the main file with SEC_STD_DELETE should walk all
486 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
487 * SHARING_VIOLATION, the main open fails.
489 * Closing the main file after delete_on_close has been set does not really
490 * unlink it but leaves the corresponding share mode entry with
491 * delete_on_close being set around until all streams are closed.
493 * Opening a stream must also look at the main file's share mode entry, look
494 * at the delete_on_close bit and potentially return DELETE_PENDING.
497 static bool test_stream_delete(struct torture_context *tctx,
498 struct smbcli_state *cli)
500 NTSTATUS status;
501 union smb_open io;
502 const char *fname = BASEDIR "\\stream.txt";
503 const char *sname1;
504 bool ret = true;
505 int fnum = -1;
506 uint8_t buf[9];
507 ssize_t retsize;
508 union smb_fileinfo finfo;
510 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
512 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
514 printf("(%s) opening non-existent file stream\n", __location__);
515 io.generic.level = RAW_OPEN_NTCREATEX;
516 io.ntcreatex.in.root_fid.fnum = 0;
517 io.ntcreatex.in.flags = 0;
518 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
519 io.ntcreatex.in.create_options = 0;
520 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
521 io.ntcreatex.in.share_access = 0;
522 io.ntcreatex.in.alloc_size = 0;
523 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
524 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
525 io.ntcreatex.in.security_flags = 0;
526 io.ntcreatex.in.fname = sname1;
528 status = smb_raw_open(cli->tree, tctx, &io);
529 CHECK_STATUS(status, NT_STATUS_OK);
530 fnum = io.ntcreatex.out.file.fnum;
532 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
533 CHECK_VALUE(retsize, 9);
536 * One stream opened without FILE_SHARE_DELETE prevents the main file
537 * to be deleted or even opened with DELETE access
540 status = smbcli_unlink(cli->tree, fname);
541 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
543 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
544 io.ntcreatex.in.fname = fname;
545 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
546 status = smb_raw_open(cli->tree, tctx, &io);
547 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
549 smbcli_close(cli->tree, fnum);
552 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
555 io.ntcreatex.in.fname = sname1;
556 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
557 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
558 status = smb_raw_open(cli->tree, tctx, &io);
559 CHECK_STATUS(status, NT_STATUS_OK);
560 fnum = io.ntcreatex.out.file.fnum;
562 status = smbcli_unlink(cli->tree, fname);
563 CHECK_STATUS(status, NT_STATUS_OK);
566 * file access still works on the stream while the main file is closed
569 retsize = smbcli_read(cli->tree, fnum, buf, 0, 9);
570 CHECK_VALUE(retsize, 9);
572 finfo.generic.level = RAW_FILEINFO_STANDARD;
573 finfo.generic.in.file.path = fname;
576 * name-based access to both the main file and the stream does not
577 * work anymore but gives DELETE_PENDING
580 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
581 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
584 * older S3 doesn't do this
586 finfo.generic.in.file.path = sname1;
587 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
588 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
591 * fd-based qfileinfo on the stream still works, the stream does not
592 * have the delete-on-close bit set. This could mean that open on the
593 * stream first opens the main file
596 finfo.all_info.level = RAW_FILEINFO_ALL_INFO;
597 finfo.all_info.in.file.fnum = fnum;
599 status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
600 CHECK_STATUS(status, NT_STATUS_OK);
602 /* w2k and w2k3 return 0 and w2k8 returns 1 */
603 if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K3(tctx) ||
604 TARGET_IS_SAMBA3(tctx)) {
605 CHECK_VALUE(finfo.all_info.out.delete_pending, 0);
606 } else {
607 CHECK_VALUE(finfo.all_info.out.delete_pending, 1);
610 smbcli_close(cli->tree, fnum);
613 * After closing the stream the file is really gone.
616 finfo.generic.in.file.path = fname;
617 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
618 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
620 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA
621 |SEC_STD_DELETE;
622 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
623 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
624 status = smb_raw_open(cli->tree, tctx, &io);
625 CHECK_STATUS(status, NT_STATUS_OK);
626 fnum = io.ntcreatex.out.file.fnum;
628 finfo.generic.in.file.path = fname;
629 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
630 CHECK_STATUS(status, NT_STATUS_OK);
632 smbcli_close(cli->tree, fnum);
634 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
635 CHECK_STATUS(status, NT_STATUS_OK);
636 done:
637 smbcli_close(cli->tree, fnum);
638 smbcli_unlink(cli->tree, fname);
639 smbcli_deltree(cli->tree, BASEDIR);
640 return ret;
644 test stream names
646 static bool test_stream_names(struct torture_context *tctx,
647 struct smbcli_state *cli)
649 NTSTATUS status;
650 union smb_open io;
651 union smb_fileinfo info;
652 union smb_fileinfo finfo;
653 union smb_fileinfo stinfo;
654 union smb_setfileinfo sinfo;
655 const char *fname = BASEDIR "\\stream_names.txt";
656 const char *sname1, *sname1b, *sname1c, *sname1d;
657 const char *sname2, *snamew, *snamew2;
658 const char *snamer1, *snamer2;
659 bool ret = true;
660 int fnum1 = -1;
661 int fnum2 = -1;
662 int fnum3 = -1;
663 int i;
664 const char *four[4] = {
665 "::$DATA",
666 ":\x05Stream\n One:$DATA",
667 ":MStream Two:$DATA",
668 ":?Stream*:$DATA"
670 const char *five1[5] = {
671 "::$DATA",
672 ":\x05Stream\n One:$DATA",
673 ":BeforeRename:$DATA",
674 ":MStream Two:$DATA",
675 ":?Stream*:$DATA"
677 const char *five2[5] = {
678 "::$DATA",
679 ":\x05Stream\n One:$DATA",
680 ":AfterRename:$DATA",
681 ":MStream Two:$DATA",
682 ":?Stream*:$DATA"
685 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
687 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "\x05Stream\n One");
688 sname1b = talloc_asprintf(tctx, "%s:", sname1);
689 sname1c = talloc_asprintf(tctx, "%s:$FOO", sname1);
690 sname1d = talloc_asprintf(tctx, "%s:?D*a", sname1);
691 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "MStream Two");
692 snamew = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "?Stream*");
693 snamew2 = talloc_asprintf(tctx, "%s\\stream*:%s:$DATA", BASEDIR, "?Stream*");
694 snamer1 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "BeforeRename");
695 snamer2 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "AfterRename");
697 printf("(%s) testing stream names\n", __location__);
698 io.generic.level = RAW_OPEN_NTCREATEX;
699 io.ntcreatex.in.root_fid.fnum = 0;
700 io.ntcreatex.in.flags = 0;
701 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
702 io.ntcreatex.in.create_options = 0;
703 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
704 io.ntcreatex.in.share_access =
705 NTCREATEX_SHARE_ACCESS_READ |
706 NTCREATEX_SHARE_ACCESS_WRITE;
707 io.ntcreatex.in.alloc_size = 0;
708 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
709 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
710 io.ntcreatex.in.security_flags = 0;
711 io.ntcreatex.in.fname = fname;
713 status = smb_raw_open(cli->tree, tctx, &io);
714 CHECK_STATUS(status, NT_STATUS_OK);
715 fnum1 = io.ntcreatex.out.file.fnum;
717 torture_comment(tctx, "Adding two EAs to base file\n");
718 ZERO_STRUCT(sinfo);
719 sinfo.generic.level = RAW_SFILEINFO_EA_SET;
720 sinfo.generic.in.file.fnum = fnum1;
721 sinfo.ea_set.in.num_eas = 2;
722 sinfo.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 2);
723 sinfo.ea_set.in.eas[0].flags = 0;
724 sinfo.ea_set.in.eas[0].name.s = "EAONE";
725 sinfo.ea_set.in.eas[0].value = data_blob_string_const("VALUE1");
726 sinfo.ea_set.in.eas[1].flags = 0;
727 sinfo.ea_set.in.eas[1].name.s = "SECONDEA";
728 sinfo.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo");
730 status = smb_raw_setfileinfo(cli->tree, &sinfo);
731 CHECK_STATUS(status, NT_STATUS_OK);
734 * Make sure the create time of the streams are different from the
735 * base file.
737 sleep(2);
738 smbcli_close(cli->tree, fnum1);
740 io.generic.level = RAW_OPEN_NTCREATEX;
741 io.ntcreatex.in.root_fid.fnum = 0;
742 io.ntcreatex.in.flags = 0;
743 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
744 io.ntcreatex.in.create_options = 0;
745 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
746 io.ntcreatex.in.share_access =
747 NTCREATEX_SHARE_ACCESS_READ |
748 NTCREATEX_SHARE_ACCESS_WRITE;
749 io.ntcreatex.in.alloc_size = 0;
750 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
751 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
752 io.ntcreatex.in.security_flags = 0;
753 io.ntcreatex.in.fname = sname1;
755 status = smb_raw_open(cli->tree, tctx, &io);
756 CHECK_STATUS(status, NT_STATUS_OK);
757 fnum1 = io.ntcreatex.out.file.fnum;
759 torture_comment(tctx, "Adding one EAs to first stream file\n");
760 ZERO_STRUCT(sinfo);
761 sinfo.generic.level = RAW_SFILEINFO_EA_SET;
762 sinfo.generic.in.file.fnum = fnum1;
763 sinfo.ea_set.in.num_eas = 1;
764 sinfo.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 1);
765 sinfo.ea_set.in.eas[0].flags = 0;
766 sinfo.ea_set.in.eas[0].name.s = "STREAMEA";
767 sinfo.ea_set.in.eas[0].value = data_blob_string_const("EA_VALUE1");
769 status = smb_raw_setfileinfo(cli->tree, &sinfo);
770 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
772 status = torture_check_ea(cli, sname1, "STREAMEA", "EA_VALUE1");
773 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
775 ZERO_STRUCT(info);
776 info.generic.level = RAW_FILEINFO_ALL_EAS;
777 info.all_eas.in.file.path = sname1;
779 status = smb_raw_pathinfo(cli->tree, tctx, &info);
780 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
783 * A different stream does not give a sharing violation
786 io.ntcreatex.in.fname = sname2;
787 status = smb_raw_open(cli->tree, tctx, &io);
788 CHECK_STATUS(status, NT_STATUS_OK);
789 fnum2 = io.ntcreatex.out.file.fnum;
792 * ... whereas the same stream does with unchanged access/share_access
793 * flags
796 io.ntcreatex.in.fname = sname1;
797 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
798 status = smb_raw_open(cli->tree, tctx, &io);
799 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
801 io.ntcreatex.in.fname = sname1b;
802 status = smb_raw_open(cli->tree, tctx, &io);
803 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
805 io.ntcreatex.in.fname = sname1c;
806 status = smb_raw_open(cli->tree, tctx, &io);
807 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
808 /* w2k returns INVALID_PARAMETER */
809 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
810 } else {
811 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
814 io.ntcreatex.in.fname = sname1d;
815 status = smb_raw_open(cli->tree, tctx, &io);
816 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
817 /* w2k returns INVALID_PARAMETER */
818 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
819 } else {
820 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
823 io.ntcreatex.in.fname = sname2;
824 status = smb_raw_open(cli->tree, tctx, &io);
825 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
827 io.ntcreatex.in.fname = snamew;
828 status = smb_raw_open(cli->tree, tctx, &io);
829 CHECK_STATUS(status, NT_STATUS_OK);
830 fnum3 = io.ntcreatex.out.file.fnum;
832 io.ntcreatex.in.fname = snamew2;
833 status = smb_raw_open(cli->tree, tctx, &io);
834 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
836 ret &= check_stream_list(tctx, cli, fname, 4, four);
838 smbcli_close(cli->tree, fnum1);
839 smbcli_close(cli->tree, fnum2);
840 smbcli_close(cli->tree, fnum3);
842 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
843 finfo.generic.in.file.path = fname;
844 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
845 CHECK_STATUS(status, NT_STATUS_OK);
847 ret &= check_stream_list(tctx, cli, fname, 4, four);
849 for (i=0; i < 4; i++) {
850 NTTIME write_time;
851 uint64_t stream_size;
852 char *path = talloc_asprintf(tctx, "%s%s",
853 fname, four[i]);
855 char *rpath = talloc_strdup(path, path);
856 char *p = strrchr(rpath, ':');
857 /* eat :$DATA */
858 *p = 0;
859 p--;
860 if (*p == ':') {
861 /* eat ::$DATA */
862 *p = 0;
864 printf("(%s): i[%u][%s]\n", __location__, i, path);
865 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
866 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
867 SEC_FILE_WRITE_ATTRIBUTE |
868 SEC_RIGHTS_FILE_ALL;
869 io.ntcreatex.in.fname = path;
870 status = smb_raw_open(cli->tree, tctx, &io);
871 CHECK_STATUS(status, NT_STATUS_OK);
872 fnum1 = io.ntcreatex.out.file.fnum;
874 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
875 finfo.generic.in.file.path = fname;
876 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
877 CHECK_STATUS(status, NT_STATUS_OK);
879 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
880 stinfo.generic.in.file.fnum = fnum1;
881 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
882 CHECK_STATUS(status, NT_STATUS_OK);
883 if (!torture_setting_bool(tctx, "samba3", false)) {
884 CHECK_NTTIME(stinfo.all_info.out.create_time,
885 finfo.all_info.out.create_time);
886 CHECK_NTTIME(stinfo.all_info.out.access_time,
887 finfo.all_info.out.access_time);
888 CHECK_NTTIME(stinfo.all_info.out.write_time,
889 finfo.all_info.out.write_time);
890 CHECK_NTTIME(stinfo.all_info.out.change_time,
891 finfo.all_info.out.change_time);
893 CHECK_VALUE(stinfo.all_info.out.attrib,
894 finfo.all_info.out.attrib);
895 CHECK_VALUE(stinfo.all_info.out.size,
896 finfo.all_info.out.size);
897 CHECK_VALUE(stinfo.all_info.out.delete_pending,
898 finfo.all_info.out.delete_pending);
899 CHECK_VALUE(stinfo.all_info.out.directory,
900 finfo.all_info.out.directory);
901 CHECK_VALUE(stinfo.all_info.out.ea_size,
902 finfo.all_info.out.ea_size);
904 stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
905 stinfo.generic.in.file.fnum = fnum1;
906 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
907 CHECK_STATUS(status, NT_STATUS_OK);
908 if (!torture_setting_bool(tctx, "samba3", false)) {
909 CHECK_STR(stinfo.name_info.out.fname.s, rpath);
912 write_time = finfo.all_info.out.write_time;
913 write_time += i*1000000;
914 write_time /= 1000000;
915 write_time *= 1000000;
917 ZERO_STRUCT(sinfo);
918 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
919 sinfo.basic_info.in.file.fnum = fnum1;
920 sinfo.basic_info.in.write_time = write_time;
921 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
922 status = smb_raw_setfileinfo(cli->tree, &sinfo);
923 CHECK_STATUS(status, NT_STATUS_OK);
925 stream_size = i*8192;
927 ZERO_STRUCT(sinfo);
928 sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
929 sinfo.end_of_file_info.in.file.fnum = fnum1;
930 sinfo.end_of_file_info.in.size = stream_size;
931 status = smb_raw_setfileinfo(cli->tree, &sinfo);
932 CHECK_STATUS(status, NT_STATUS_OK);
934 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
935 stinfo.generic.in.file.fnum = fnum1;
936 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
937 CHECK_STATUS(status, NT_STATUS_OK);
938 if (!torture_setting_bool(tctx, "samba3", false)) {
939 CHECK_NTTIME(stinfo.all_info.out.write_time,
940 write_time);
941 CHECK_VALUE(stinfo.all_info.out.attrib,
942 finfo.all_info.out.attrib);
944 CHECK_VALUE(stinfo.all_info.out.size,
945 stream_size);
946 CHECK_VALUE(stinfo.all_info.out.delete_pending,
947 finfo.all_info.out.delete_pending);
948 CHECK_VALUE(stinfo.all_info.out.directory,
949 finfo.all_info.out.directory);
950 CHECK_VALUE(stinfo.all_info.out.ea_size,
951 finfo.all_info.out.ea_size);
953 ret &= check_stream_list(tctx, cli, fname, 4, four);
955 smbcli_close(cli->tree, fnum1);
956 talloc_free(path);
959 printf("(%s): testing stream renames\n", __location__);
960 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
961 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
962 SEC_FILE_WRITE_ATTRIBUTE |
963 SEC_RIGHTS_FILE_ALL;
964 io.ntcreatex.in.fname = snamer1;
965 status = smb_raw_open(cli->tree, tctx, &io);
966 CHECK_STATUS(status, NT_STATUS_OK);
967 fnum1 = io.ntcreatex.out.file.fnum;
969 ret &= check_stream_list(tctx, cli, fname, 5, five1);
971 ZERO_STRUCT(sinfo);
972 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
973 sinfo.rename_information.in.file.fnum = fnum1;
974 sinfo.rename_information.in.overwrite = true;
975 sinfo.rename_information.in.root_fid = 0;
976 sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
977 status = smb_raw_setfileinfo(cli->tree, &sinfo);
978 CHECK_STATUS(status, NT_STATUS_OK);
980 ret &= check_stream_list(tctx, cli, fname, 5, five2);
982 ZERO_STRUCT(sinfo);
983 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
984 sinfo.rename_information.in.file.fnum = fnum1;
985 sinfo.rename_information.in.overwrite = false;
986 sinfo.rename_information.in.root_fid = 0;
987 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
988 status = smb_raw_setfileinfo(cli->tree, &sinfo);
989 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
991 ret &= check_stream_list(tctx, cli, fname, 5, five2);
993 ZERO_STRUCT(sinfo);
994 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
995 sinfo.rename_information.in.file.fnum = fnum1;
996 sinfo.rename_information.in.overwrite = true;
997 sinfo.rename_information.in.root_fid = 0;
998 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
999 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1000 if (torture_setting_bool(tctx, "samba4", false) ||
1001 torture_setting_bool(tctx, "samba3", false)) {
1002 /* why should this rename be considered invalid?? */
1003 CHECK_STATUS(status, NT_STATUS_OK);
1004 ret &= check_stream_list(tctx, cli, fname, 4, four);
1005 } else {
1006 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1007 ret &= check_stream_list(tctx, cli, fname, 5, five2);
1011 /* TODO: we need to test more rename combinations */
1013 done:
1014 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1015 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1016 if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
1017 status = smbcli_unlink(cli->tree, fname);
1018 smbcli_deltree(cli->tree, BASEDIR);
1019 return ret;
1023 test stream names
1025 static bool test_stream_names2(struct torture_context *tctx,
1026 struct smbcli_state *cli)
1028 NTSTATUS status;
1029 union smb_open io;
1030 const char *fname = BASEDIR "\\stream_names2.txt";
1031 bool ret = true;
1032 int fnum1 = -1;
1033 uint8_t i;
1035 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1037 printf("(%s) testing stream names\n", __location__);
1038 io.generic.level = RAW_OPEN_NTCREATEX;
1039 io.ntcreatex.in.root_fid.fnum = 0;
1040 io.ntcreatex.in.flags = 0;
1041 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
1042 io.ntcreatex.in.create_options = 0;
1043 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1044 io.ntcreatex.in.share_access = 0;
1045 io.ntcreatex.in.alloc_size = 0;
1046 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1047 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1048 io.ntcreatex.in.security_flags = 0;
1049 io.ntcreatex.in.fname = fname;
1050 status = smb_raw_open(cli->tree, tctx, &io);
1051 CHECK_STATUS(status, NT_STATUS_OK);
1052 fnum1 = io.ntcreatex.out.file.fnum;
1054 for (i=0x01; i < 0x7F; i++) {
1055 char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
1056 fname, i, i);
1057 NTSTATUS expected;
1059 switch (i) {
1060 case '/':/*0x2F*/
1061 case ':':/*0x3A*/
1062 case '\\':/*0x5C*/
1063 expected = NT_STATUS_OBJECT_NAME_INVALID;
1064 break;
1065 default:
1066 expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1067 break;
1071 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1072 io.ntcreatex.in.fname = path;
1073 status = smb_raw_open(cli->tree, tctx, &io);
1074 if (!NT_STATUS_EQUAL(status, expected)) {
1075 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1076 __location__, fname, isprint(i)?(char)i:' ', i,
1077 isprint(i)?"":" (not printable)",
1078 nt_errstr(expected));
1080 CHECK_STATUS(status, expected);
1082 talloc_free(path);
1085 done:
1086 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1087 status = smbcli_unlink(cli->tree, fname);
1088 smbcli_deltree(cli->tree, BASEDIR);
1089 return ret;
1092 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1093 check_fnum = true; \
1094 call_name = #call; \
1095 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1096 sfinfo.generic.in.file.fnum = fnum; \
1097 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1098 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1099 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1100 nt_errstr(status), nt_errstr(rightstatus)); \
1101 ret = false; \
1103 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1104 finfo1.generic.in.file.fnum = fnum; \
1105 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1106 if (!NT_STATUS_IS_OK(status2)) { \
1107 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1108 ret = false; \
1109 }} while (0)
1112 test stream renames
1114 static bool test_stream_rename(struct torture_context *tctx,
1115 struct smbcli_state *cli)
1117 NTSTATUS status, status2;
1118 union smb_open io;
1119 const char *fname = BASEDIR "\\stream_rename.txt";
1120 const char *sname1, *sname2;
1121 union smb_fileinfo finfo1;
1122 union smb_setfileinfo sfinfo;
1123 bool ret = true;
1124 int fnum = -1;
1125 bool check_fnum;
1126 const char *call_name;
1128 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1130 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
1131 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1133 printf("(%s) testing stream renames\n", __location__);
1134 io.generic.level = RAW_OPEN_NTCREATEX;
1135 io.ntcreatex.in.root_fid.fnum = 0;
1136 io.ntcreatex.in.flags = 0;
1137 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1138 SEC_FILE_WRITE_ATTRIBUTE |
1139 SEC_RIGHTS_FILE_ALL;
1140 io.ntcreatex.in.create_options = 0;
1141 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1142 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1143 io.ntcreatex.in.alloc_size = 0;
1144 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1145 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1146 io.ntcreatex.in.security_flags = 0;
1147 io.ntcreatex.in.fname = sname1;
1149 /* Create two streams. */
1150 status = smb_raw_open(cli->tree, tctx, &io);
1151 CHECK_STATUS(status, NT_STATUS_OK);
1152 fnum = io.ntcreatex.out.file.fnum;
1153 if (fnum != -1) smbcli_close(cli->tree, fnum);
1155 io.ntcreatex.in.fname = sname2;
1156 status = smb_raw_open(cli->tree, tctx, &io);
1157 CHECK_STATUS(status, NT_STATUS_OK);
1158 fnum = io.ntcreatex.out.file.fnum;
1160 if (fnum != -1) smbcli_close(cli->tree, fnum);
1163 * Open the second stream.
1166 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1167 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1168 status = smb_raw_open(cli->tree, tctx, &io);
1169 CHECK_STATUS(status, NT_STATUS_OK);
1170 fnum = io.ntcreatex.out.file.fnum;
1173 * Now rename the second stream onto the first.
1176 ZERO_STRUCT(sfinfo);
1178 sfinfo.rename_information.in.overwrite = 1;
1179 sfinfo.rename_information.in.root_fid = 0;
1180 sfinfo.rename_information.in.new_name = ":Stream One";
1181 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1183 done:
1184 if (fnum != -1) smbcli_close(cli->tree, fnum);
1185 status = smbcli_unlink(cli->tree, fname);
1186 smbcli_deltree(cli->tree, BASEDIR);
1187 return ret;
1190 static bool test_stream_rename2(struct torture_context *tctx,
1191 struct smbcli_state *cli)
1193 NTSTATUS status;
1194 union smb_open io;
1195 const char *fname1 = BASEDIR "\\stream.txt";
1196 const char *fname2 = BASEDIR "\\stream2.txt";
1197 const char *stream_name1 = ":Stream One:$DATA";
1198 const char *stream_name2 = ":Stream Two:$DATA";
1199 const char *stream_name_default = "::$DATA";
1200 const char *sname1;
1201 const char *sname2;
1202 bool ret = true;
1203 int fnum = -1;
1204 union smb_setfileinfo sinfo;
1205 union smb_rename rio;
1207 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1209 sname1 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream One");
1210 sname2 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream Two");
1212 io.generic.level = RAW_OPEN_NTCREATEX;
1213 io.ntcreatex.in.root_fid.fnum = 0;
1214 io.ntcreatex.in.flags = 0;
1215 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1216 SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1217 io.ntcreatex.in.create_options = 0;
1218 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1219 io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
1220 NTCREATEX_SHARE_ACCESS_WRITE |
1221 NTCREATEX_SHARE_ACCESS_DELETE);
1222 io.ntcreatex.in.alloc_size = 0;
1223 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1224 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1225 io.ntcreatex.in.security_flags = 0;
1226 io.ntcreatex.in.fname = sname1;
1228 /* Open/create new stream. */
1229 status = smb_raw_open(cli->tree, tctx, &io);
1230 CHECK_STATUS(status, NT_STATUS_OK);
1232 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1235 * Check raw rename with <base>:<stream>.
1237 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1238 __location__);
1239 rio.generic.level = RAW_RENAME_NTRENAME;
1240 rio.ntrename.in.old_name = sname1;
1241 rio.ntrename.in.new_name = sname2;
1242 rio.ntrename.in.attrib = 0;
1243 rio.ntrename.in.cluster_size = 0;
1244 rio.ntrename.in.flags = RENAME_FLAG_RENAME;
1245 status = smb_raw_rename(cli->tree, &rio);
1246 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1249 * Check raw rename to the default stream using :<stream>.
1251 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1252 __location__);
1253 rio.ntrename.in.new_name = stream_name_default;
1254 status = smb_raw_rename(cli->tree, &rio);
1255 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1258 * Check raw rename using :<stream>.
1260 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1261 __location__);
1262 rio.ntrename.in.new_name = stream_name2;
1263 status = smb_raw_rename(cli->tree, &rio);
1264 CHECK_STATUS(status, NT_STATUS_OK);
1267 * Check raw rename of a stream to a file.
1269 printf("(%s) Checking NTRENAME of a stream to a file\n",
1270 __location__);
1271 rio.ntrename.in.old_name = sname2;
1272 rio.ntrename.in.new_name = fname2;
1273 status = smb_raw_rename(cli->tree, &rio);
1274 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1277 * Check raw rename of a file to a stream.
1279 printf("(%s) Checking NTRENAME of a file to a stream\n",
1280 __location__);
1282 /* Create the file. */
1283 io.ntcreatex.in.fname = fname2;
1284 status = smb_raw_open(cli->tree, tctx, &io);
1285 CHECK_STATUS(status, NT_STATUS_OK);
1286 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1288 /* Try the rename. */
1289 rio.ntrename.in.old_name = fname2;
1290 rio.ntrename.in.new_name = sname1;
1291 status = smb_raw_rename(cli->tree, &rio);
1292 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
1295 * Reopen the stream for trans2 renames.
1297 io.ntcreatex.in.fname = sname2;
1298 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1299 status = smb_raw_open(cli->tree, tctx, &io);
1300 CHECK_STATUS(status, NT_STATUS_OK);
1301 fnum = io.ntcreatex.out.file.fnum;
1304 * Check trans2 rename of a stream using :<stream>.
1306 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1307 __location__);
1308 ZERO_STRUCT(sinfo);
1309 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1310 sinfo.rename_information.in.file.fnum = fnum;
1311 sinfo.rename_information.in.overwrite = 1;
1312 sinfo.rename_information.in.root_fid = 0;
1313 sinfo.rename_information.in.new_name = stream_name1;
1314 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1315 CHECK_STATUS(status, NT_STATUS_OK);
1318 * Check trans2 rename of an overwriting stream using :<stream>.
1320 printf("(%s) Checking trans2 rename of an overwriting stream using "
1321 ":<stream>\n", __location__);
1323 /* Create second stream. */
1324 io.ntcreatex.in.fname = sname2;
1325 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1326 status = smb_raw_open(cli->tree, tctx, &io);
1327 CHECK_STATUS(status, NT_STATUS_OK);
1328 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1330 /* Rename the first stream onto the second. */
1331 sinfo.rename_information.in.file.fnum = fnum;
1332 sinfo.rename_information.in.new_name = stream_name2;
1333 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1334 CHECK_STATUS(status, NT_STATUS_OK);
1336 smbcli_close(cli->tree, fnum);
1339 * Reopen the stream with the new name.
1341 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1342 io.ntcreatex.in.fname = sname2;
1343 status = smb_raw_open(cli->tree, tctx, &io);
1344 CHECK_STATUS(status, NT_STATUS_OK);
1345 fnum = io.ntcreatex.out.file.fnum;
1348 * Check trans2 rename of a stream using <base>:<stream>.
1350 printf("(%s) Checking trans2 rename of a stream using "
1351 "<base>:<stream>\n", __location__);
1352 sinfo.rename_information.in.file.fnum = fnum;
1353 sinfo.rename_information.in.new_name = sname1;
1354 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1355 CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
1358 * Samba3 doesn't currently support renaming a stream to the default
1359 * stream. This test does pass on windows.
1361 if (torture_setting_bool(tctx, "samba3", false) ||
1362 torture_setting_bool(tctx, "samba4", false)) {
1363 goto done;
1367 * Check trans2 rename to the default stream using :<stream>.
1369 printf("(%s) Checking trans2 rename to defaualt stream using "
1370 ":<stream>\n", __location__);
1371 sinfo.rename_information.in.file.fnum = fnum;
1372 sinfo.rename_information.in.new_name = stream_name_default;
1373 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1374 CHECK_STATUS(status, NT_STATUS_OK);
1376 smbcli_close(cli->tree, fnum);
1378 done:
1379 smbcli_close(cli->tree, fnum);
1380 status = smbcli_unlink(cli->tree, fname1);
1381 status = smbcli_unlink(cli->tree, fname2);
1382 smbcli_deltree(cli->tree, BASEDIR);
1383 return ret;
1387 test stream renames
1389 static bool test_stream_rename3(struct torture_context *tctx,
1390 struct smbcli_state *cli)
1392 NTSTATUS status, status2;
1393 union smb_open io;
1394 const char *fname = BASEDIR "\\stream_rename.txt";
1395 const char *sname1, *sname2;
1396 union smb_fileinfo finfo1;
1397 union smb_setfileinfo sfinfo;
1398 bool ret = true;
1399 int fnum = -1;
1400 int fnum2 = -1;
1401 bool check_fnum;
1402 const char *call_name;
1404 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1406 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "MStream Two:$DATA");
1407 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1409 printf("(%s) testing stream renames\n", __location__);
1410 io.generic.level = RAW_OPEN_NTCREATEX;
1411 io.ntcreatex.in.root_fid.fnum = 0;
1412 io.ntcreatex.in.flags = 0;
1413 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1414 SEC_FILE_WRITE_ATTRIBUTE |
1415 SEC_RIGHTS_FILE_ALL;
1416 io.ntcreatex.in.create_options = 0;
1417 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1418 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1419 NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1420 io.ntcreatex.in.alloc_size = 0;
1421 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1422 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1423 io.ntcreatex.in.security_flags = 0;
1424 io.ntcreatex.in.fname = sname1;
1426 /* Create two streams. */
1427 status = smb_raw_open(cli->tree, tctx, &io);
1428 CHECK_STATUS(status, NT_STATUS_OK);
1429 fnum = io.ntcreatex.out.file.fnum;
1430 if (fnum != -1) smbcli_close(cli->tree, fnum);
1432 io.ntcreatex.in.fname = sname2;
1433 status = smb_raw_open(cli->tree, tctx, &io);
1434 CHECK_STATUS(status, NT_STATUS_OK);
1435 fnum = io.ntcreatex.out.file.fnum;
1437 if (fnum != -1) smbcli_close(cli->tree, fnum);
1439 /* open the second stream. */
1440 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1441 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1442 status = smb_raw_open(cli->tree, tctx, &io);
1443 CHECK_STATUS(status, NT_STATUS_OK);
1444 fnum = io.ntcreatex.out.file.fnum;
1446 /* Keep a handle to the first stream open. */
1447 io.ntcreatex.in.fname = sname1;
1448 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1449 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1450 status = smb_raw_open(cli->tree, tctx, &io);
1451 CHECK_STATUS(status, NT_STATUS_OK);
1452 fnum2 = io.ntcreatex.out.file.fnum;
1454 ZERO_STRUCT(sfinfo);
1455 sfinfo.rename_information.in.overwrite = 1;
1456 sfinfo.rename_information.in.root_fid = 0;
1457 sfinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1458 if (torture_setting_bool(tctx, "samba4", false) ||
1459 torture_setting_bool(tctx, "samba3", false)) {
1460 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1461 } else {
1462 CHECK_CALL_FNUM(RENAME_INFORMATION,
1463 NT_STATUS_INVALID_PARAMETER);
1467 done:
1468 if (fnum != -1) smbcli_close(cli->tree, fnum);
1469 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1470 status = smbcli_unlink(cli->tree, fname);
1471 smbcli_deltree(cli->tree, BASEDIR);
1472 return ret;
1475 static bool create_file_with_stream(struct torture_context *tctx,
1476 struct smbcli_state *cli,
1477 const char *stream)
1479 NTSTATUS status;
1480 bool ret = true;
1481 union smb_open io;
1483 /* Create a file with a stream */
1484 io.generic.level = RAW_OPEN_NTCREATEX;
1485 io.ntcreatex.in.root_fid.fnum = 0;
1486 io.ntcreatex.in.flags = 0;
1487 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1488 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1489 io.ntcreatex.in.create_options = 0;
1490 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1491 io.ntcreatex.in.share_access = 0;
1492 io.ntcreatex.in.alloc_size = 0;
1493 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1494 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1495 io.ntcreatex.in.security_flags = 0;
1496 io.ntcreatex.in.fname = stream;
1498 status = smb_raw_open(cli->tree, tctx, &io);
1499 CHECK_STATUS(status, NT_STATUS_OK);
1501 done:
1502 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1503 return ret;
1506 /* Test how streams interact with create dispositions */
1507 static bool test_stream_create_disposition(struct torture_context *tctx,
1508 struct smbcli_state *cli)
1510 NTSTATUS status;
1511 union smb_open io;
1512 const char *fname = BASEDIR "\\stream.txt";
1513 const char *stream = "Stream One:$DATA";
1514 const char *fname_stream;
1515 const char *default_stream_name = "::$DATA";
1516 const char *stream_list[2];
1517 bool ret = false;
1518 int fnum = -1;
1520 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1522 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1524 stream_list[0] = talloc_asprintf(tctx, ":%s", stream);
1525 stream_list[1] = default_stream_name;
1527 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1528 goto done;
1531 /* Open the base file with OPEN */
1532 io.generic.level = RAW_OPEN_NTCREATEX;
1533 io.ntcreatex.in.root_fid.fnum = 0;
1534 io.ntcreatex.in.flags = 0;
1535 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1536 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1537 io.ntcreatex.in.create_options = 0;
1538 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1539 io.ntcreatex.in.share_access = 0;
1540 io.ntcreatex.in.alloc_size = 0;
1541 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1542 io.ntcreatex.in.security_flags = 0;
1543 io.ntcreatex.in.fname = fname;
1546 * check ntcreatex open: sanity check
1548 printf("(%s) Checking ntcreatex disp: open\n", __location__);
1549 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1550 status = smb_raw_open(cli->tree, tctx, &io);
1551 CHECK_STATUS(status, NT_STATUS_OK);
1552 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1553 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1554 goto done;
1558 * check ntcreatex overwrite
1560 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
1561 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
1562 status = smb_raw_open(cli->tree, tctx, &io);
1563 CHECK_STATUS(status, NT_STATUS_OK);
1564 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1565 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1566 goto done;
1570 * check ntcreatex overwrite_if
1572 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
1573 smbcli_unlink(cli->tree, fname);
1574 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1575 goto done;
1578 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1579 status = smb_raw_open(cli->tree, tctx, &io);
1580 CHECK_STATUS(status, NT_STATUS_OK);
1581 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1582 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1583 goto done;
1587 * check ntcreatex supersede
1589 printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
1590 smbcli_unlink(cli->tree, fname);
1591 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1592 goto done;
1595 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
1596 status = smb_raw_open(cli->tree, tctx, &io);
1597 CHECK_STATUS(status, NT_STATUS_OK);
1598 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1599 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1600 goto done;
1604 * check ntcreatex overwrite_if on a stream.
1606 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1607 __location__);
1608 smbcli_unlink(cli->tree, fname);
1609 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1610 goto done;
1613 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1614 io.ntcreatex.in.fname = fname_stream;
1615 status = smb_raw_open(cli->tree, tctx, &io);
1616 CHECK_STATUS(status, NT_STATUS_OK);
1617 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1618 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1619 goto done;
1623 * check openx overwrite_if
1625 printf("(%s) Checking openx disp: overwrite_if\n", __location__);
1626 smbcli_unlink(cli->tree, fname);
1627 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1628 goto done;
1631 io.openx.level = RAW_OPEN_OPENX;
1632 io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1633 io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPEN_FLAGS_DENY_NONE;
1634 io.openx.in.search_attrs = 0;
1635 io.openx.in.file_attrs = 0;
1636 io.openx.in.write_time = 0;
1637 io.openx.in.size = 1024*1024;
1638 io.openx.in.timeout = 0;
1639 io.openx.in.fname = fname;
1641 io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
1642 status = smb_raw_open(cli->tree, tctx, &io);
1643 CHECK_STATUS(status, NT_STATUS_OK);
1644 smbcli_close(cli->tree, io.openx.out.file.fnum);
1645 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1646 goto done;
1649 ret = true;
1651 done:
1652 smbcli_close(cli->tree, fnum);
1653 smbcli_unlink(cli->tree, fname);
1654 smbcli_deltree(cli->tree, BASEDIR);
1655 return ret;
1658 #if 0
1659 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1660 static bool test_stream_large_streaminfo(struct torture_context *tctx,
1661 struct smbcli_state *cli)
1663 #define LONG_STREAM_SIZE 2
1664 char *lstream_name;
1665 const char *fname = BASEDIR "\\stream.txt";
1666 const char *fname_stream;
1667 NTSTATUS status;
1668 bool ret = true;
1669 int i;
1670 union smb_fileinfo finfo;
1672 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1674 lstream_name = talloc_array(tctx, char, LONG_STREAM_SIZE);
1676 for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
1677 lstream_name[i] = (char)('a' + i%26);
1679 lstream_name[LONG_STREAM_SIZE - 1] = '\0';
1681 torture_comment(tctx, "(%s) Creating a file with a lot of streams\n", __location__);
1682 for (i = 0; i < 10000; i++) {
1683 fname_stream = talloc_asprintf(tctx, "%s:%s%d", fname,
1684 lstream_name, i);
1685 ret = create_file_with_stream(tctx, cli, fname_stream);
1686 if (!ret) {
1687 goto done;
1691 finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1692 finfo.generic.in.file.path = fname;
1694 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1695 CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
1697 done:
1698 smbcli_unlink(cli->tree, fname);
1699 smbcli_deltree(cli->tree, BASEDIR);
1700 return ret;
1702 #endif
1704 /* Test the effect of setting attributes on a stream. */
1705 static bool test_stream_attributes(struct torture_context *tctx,
1706 struct smbcli_state *cli)
1708 bool ret = true;
1709 NTSTATUS status;
1710 union smb_open io;
1711 const char *fname = BASEDIR "\\stream_attr.txt";
1712 const char *stream = "Stream One:$DATA";
1713 const char *fname_stream;
1714 int fnum = -1;
1715 union smb_fileinfo finfo;
1716 union smb_setfileinfo sfinfo;
1717 time_t basetime = (time(NULL) - 86400) & ~1;
1719 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1721 torture_comment(tctx, "(%s) testing attribute setting on stream\n", __location__);
1723 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1725 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1726 ret = create_file_with_stream(tctx, cli, fname_stream);
1727 if (!ret) {
1728 goto done;
1731 ZERO_STRUCT(finfo);
1732 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1733 finfo.generic.in.file.path = fname;
1734 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1735 CHECK_STATUS(status, NT_STATUS_OK);
1737 torture_assert_int_equal_goto(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_ARCHIVE, ret, done, "attrib incorrect");
1739 /* Now open the stream name. */
1741 io.generic.level = RAW_OPEN_NTCREATEX;
1742 io.ntcreatex.in.root_fid.fnum = 0;
1743 io.ntcreatex.in.flags = 0;
1744 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1745 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
1746 io.ntcreatex.in.create_options = 0;
1747 io.ntcreatex.in.file_attr = 0;
1748 io.ntcreatex.in.share_access = 0;
1749 io.ntcreatex.in.alloc_size = 0;
1750 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1751 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1752 io.ntcreatex.in.security_flags = 0;
1753 io.ntcreatex.in.fname = fname_stream;
1755 status = smb_raw_open(cli->tree, tctx, &io);
1756 CHECK_STATUS(status, NT_STATUS_OK);
1758 fnum = io.ntcreatex.out.file.fnum;
1760 /* Change the attributes + time on the stream fnum. */
1761 ZERO_STRUCT(sfinfo);
1762 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1763 unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1765 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1766 sfinfo.generic.in.file.fnum = fnum;
1767 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
1768 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "smb_raw_setfileinfo failed");
1770 smbcli_close(cli->tree, fnum);
1771 fnum = -1;
1773 ZERO_STRUCT(finfo);
1774 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1775 finfo.generic.in.file.path = fname;
1776 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1777 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "smb_raw_pathinfo failed");
1779 torture_assert_int_equal_goto(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_READONLY, ret, done, "attrib incorrect");
1781 torture_assert_int_equal_goto(tctx, nt_time_to_unix(finfo.all_info.out.write_time), basetime, ret, done, "time incorrect");
1783 done:
1785 if (fnum != -1) {
1786 smbcli_close(cli->tree, fnum);
1788 smbcli_unlink(cli->tree, fname);
1789 smbcli_deltree(cli->tree, BASEDIR);
1790 return ret;
1794 * A rough approximation of how a windows client creates the streams for use
1795 * in the summary tab.
1797 static bool test_stream_summary_tab(struct torture_context *tctx,
1798 struct smbcli_state *cli)
1800 bool ret = true;
1801 NTSTATUS status;
1802 union smb_open io;
1803 const char *fname = BASEDIR "\\stream_summary.txt";
1804 const char *stream = ":\005SummaryInformation:$DATA";
1805 const char *fname_stream = NULL;
1806 const char *tmp_stream = ":Updt_\005SummaryInformation:$DATA";
1807 const char *fname_tmp_stream = NULL;
1808 int fnum = -1;
1809 union smb_fileinfo finfo;
1810 union smb_rename rio;
1811 ssize_t retsize;
1813 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1815 fname_stream = talloc_asprintf(tctx, "%s%s", fname, stream);
1816 fname_tmp_stream = talloc_asprintf(tctx, "%s%s", fname,
1817 tmp_stream);
1819 /* Create summary info stream */
1820 ret = create_file_with_stream(tctx, cli, fname_stream);
1821 if (!ret) {
1822 goto done;
1825 /* Create summary info tmp update stream */
1826 ret = create_file_with_stream(tctx, cli, fname_tmp_stream);
1827 if (!ret) {
1828 goto done;
1831 /* Open tmp stream and write to it */
1832 io.generic.level = RAW_OPEN_NTCREATEX;
1833 io.ntcreatex.in.root_fid.fnum = 0;
1834 io.ntcreatex.in.flags = 0;
1835 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
1836 io.ntcreatex.in.create_options = 0;
1837 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1838 io.ntcreatex.in.share_access = 0;
1839 io.ntcreatex.in.alloc_size = 0;
1840 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1841 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1842 io.ntcreatex.in.security_flags = 0;
1843 io.ntcreatex.in.fname = fname_tmp_stream;
1845 status = smb_raw_open(cli->tree, tctx, &io);
1846 CHECK_STATUS(status, NT_STATUS_OK);
1847 fnum = io.ntcreatex.out.file.fnum;
1849 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
1850 CHECK_VALUE(retsize, 9);
1852 /* close the tmp stream. */
1853 smbcli_close(cli->tree, fnum);
1854 fnum = -1;
1856 /* Delete the current stream */
1857 smbcli_unlink(cli->tree, fname_stream);
1859 /* Do the rename. */
1860 rio.generic.level = RAW_RENAME_RENAME;
1861 rio.rename.in.pattern1 = fname_tmp_stream;
1862 rio.rename.in.pattern2 = stream;
1863 rio.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM |
1864 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1865 status = smb_raw_rename(cli->tree, &rio);
1866 CHECK_STATUS(status, NT_STATUS_OK);
1868 /* Try to open the tmp stream that we just renamed away. */
1869 status = smb_raw_open(cli->tree, tctx, &io);
1870 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1872 /* Query the base file to make sure it's still there. */
1873 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1874 finfo.generic.in.file.path = fname;
1876 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1877 CHECK_STATUS(status, NT_STATUS_OK);
1879 done:
1881 if (fnum != -1) {
1882 smbcli_close(cli->tree, fnum);
1884 smbcli_unlink(cli->tree, fname);
1886 smbcli_deltree(cli->tree, BASEDIR);
1887 return ret;
1890 /* Test how streams interact with base file permissions */
1891 /* Regression test for bug:
1892 https://bugzilla.samba.org/show_bug.cgi?id=10229
1893 bug #10229 - No access check verification on stream files.
1895 static bool test_stream_permissions(struct torture_context *tctx,
1896 struct smbcli_state *cli)
1898 NTSTATUS status;
1899 bool ret = true;
1900 union smb_open io;
1901 const char *fname = BASEDIR "\\stream_permissions.txt";
1902 const char *stream = "Stream One:$DATA";
1903 const char *fname_stream;
1904 union smb_fileinfo finfo;
1905 union smb_setfileinfo sfinfo;
1906 int fnum = -1;
1907 union smb_fileinfo q;
1908 union smb_setfileinfo set;
1909 struct security_ace ace;
1910 struct security_descriptor *sd;
1912 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1913 "Failed to setup up test directory: " BASEDIR);
1915 torture_comment(tctx, "(%s) testing permissions on streams\n", __location__);
1917 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1919 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1920 ret = create_file_with_stream(tctx, cli, fname_stream);
1921 if (!ret) {
1922 goto done;
1925 ZERO_STRUCT(finfo);
1926 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1927 finfo.generic.in.file.path = fname;
1928 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1929 CHECK_STATUS(status, NT_STATUS_OK);
1931 torture_assert_int_equal_goto(tctx,
1932 finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
1933 FILE_ATTRIBUTE_ARCHIVE, ret, done, "attrib incorrect");
1935 /* Change the attributes on the base file name. */
1936 ZERO_STRUCT(sfinfo);
1937 sfinfo.generic.level = RAW_SFILEINFO_SETATTR;
1938 sfinfo.generic.in.file.path = fname;
1939 sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_READONLY;
1941 status = smb_raw_setpathinfo(cli->tree, &sfinfo);
1942 CHECK_STATUS(status, NT_STATUS_OK);
1944 /* Try and open the stream name for WRITE_DATA. Should
1945 fail with ACCESS_DENIED. */
1947 ZERO_STRUCT(io);
1948 io.generic.level = RAW_OPEN_NTCREATEX;
1949 io.ntcreatex.in.root_fid.fnum = 0;
1950 io.ntcreatex.in.flags = 0;
1951 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
1952 io.ntcreatex.in.create_options = 0;
1953 io.ntcreatex.in.file_attr = 0;
1954 io.ntcreatex.in.share_access = 0;
1955 io.ntcreatex.in.alloc_size = 0;
1956 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1957 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1958 io.ntcreatex.in.security_flags = 0;
1959 io.ntcreatex.in.fname = fname_stream;
1961 status = smb_raw_open(cli->tree, tctx, &io);
1962 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1964 /* Change the attributes on the base file back. */
1965 ZERO_STRUCT(sfinfo);
1966 sfinfo.generic.level = RAW_SFILEINFO_SETATTR;
1967 sfinfo.generic.in.file.path = fname;
1968 sfinfo.setattr.in.attrib = 0;
1970 status = smb_raw_setpathinfo(cli->tree, &sfinfo);
1971 CHECK_STATUS(status, NT_STATUS_OK);
1973 /* Re-open the file name. */
1975 ZERO_STRUCT(io);
1976 io.generic.level = RAW_OPEN_NTCREATEX;
1977 io.ntcreatex.in.root_fid.fnum = 0;
1978 io.ntcreatex.in.flags = 0;
1979 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1980 SEC_STD_READ_CONTROL|SEC_STD_WRITE_DAC|
1981 SEC_FILE_WRITE_ATTRIBUTE);
1982 io.ntcreatex.in.create_options = 0;
1983 io.ntcreatex.in.file_attr = 0;
1984 io.ntcreatex.in.share_access = 0;
1985 io.ntcreatex.in.alloc_size = 0;
1986 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1987 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1988 io.ntcreatex.in.security_flags = 0;
1989 io.ntcreatex.in.fname = fname;
1991 status = smb_raw_open(cli->tree, tctx, &io);
1992 CHECK_STATUS(status, NT_STATUS_OK);
1994 fnum = io.ntcreatex.out.file.fnum;
1996 /* Get the existing security descriptor. */
1997 ZERO_STRUCT(q);
1998 q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1999 q.query_secdesc.in.file.fnum = fnum;
2000 q.query_secdesc.in.secinfo_flags =
2001 SECINFO_OWNER |
2002 SECINFO_GROUP |
2003 SECINFO_DACL;
2004 status = smb_raw_fileinfo(cli->tree, tctx, &q);
2005 CHECK_STATUS(status, NT_STATUS_OK);
2006 sd = q.query_secdesc.out.sd;
2008 /* Now add a DENY WRITE security descriptor for Everyone. */
2009 torture_comment(tctx, "add a new ACE to the DACL\n");
2011 ace.type = SEC_ACE_TYPE_ACCESS_DENIED;
2012 ace.flags = 0;
2013 ace.access_mask = SEC_FILE_WRITE_DATA;
2014 ace.trustee = *dom_sid_parse_talloc(tctx, SID_WORLD);
2016 status = security_descriptor_dacl_add(sd, &ace);
2017 CHECK_STATUS(status, NT_STATUS_OK);
2019 /* security_descriptor_dacl_add adds to the *end* of
2020 the ace array, we need it at the start. Swap.. */
2021 ace = sd->dacl->aces[0];
2022 sd->dacl->aces[0] = sd->dacl->aces[sd->dacl->num_aces-1];
2023 sd->dacl->aces[sd->dacl->num_aces-1] = ace;
2025 ZERO_STRUCT(set);
2026 set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
2027 set.set_secdesc.in.file.fnum = fnum;
2028 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
2029 set.set_secdesc.in.sd = sd;
2031 status = smb_raw_setfileinfo(cli->tree, &set);
2032 CHECK_STATUS(status, NT_STATUS_OK);
2034 smbcli_close(cli->tree, fnum);
2035 fnum = -1;
2037 /* Try and open the stream name for WRITE_DATA. Should
2038 fail with ACCESS_DENIED. */
2040 ZERO_STRUCT(io);
2041 io.generic.level = RAW_OPEN_NTCREATEX;
2042 io.ntcreatex.in.root_fid.fnum = 0;
2043 io.ntcreatex.in.flags = 0;
2044 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
2045 io.ntcreatex.in.create_options = 0;
2046 io.ntcreatex.in.file_attr = 0;
2047 io.ntcreatex.in.share_access = 0;
2048 io.ntcreatex.in.alloc_size = 0;
2049 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2050 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
2051 io.ntcreatex.in.security_flags = 0;
2052 io.ntcreatex.in.fname = fname_stream;
2054 status = smb_raw_open(cli->tree, tctx, &io);
2055 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
2057 done:
2059 if (fnum != -1) {
2060 smbcli_close(cli->tree, fnum);
2062 smbcli_unlink(cli->tree, fname);
2064 smbcli_deltree(cli->tree, BASEDIR);
2065 return ret;
2069 basic testing of streams calls
2071 struct torture_suite *torture_raw_streams(TALLOC_CTX *tctx)
2073 struct torture_suite *suite = torture_suite_create(tctx, "streams");
2075 torture_suite_add_1smb_test(suite, "dir", test_stream_dir);
2076 torture_suite_add_1smb_test(suite, "io", test_stream_io);
2077 torture_suite_add_1smb_test(suite, "sharemodes", test_stream_sharemodes);
2078 torture_suite_add_1smb_test(suite, "delete", test_stream_delete);
2079 torture_suite_add_1smb_test(suite, "names", test_stream_names);
2080 torture_suite_add_1smb_test(suite, "names2", test_stream_names2);
2081 torture_suite_add_1smb_test(suite, "rename", test_stream_rename);
2082 torture_suite_add_1smb_test(suite, "rename2", test_stream_rename2);
2083 torture_suite_add_1smb_test(suite, "rename3", test_stream_rename3);
2084 torture_suite_add_1smb_test(suite, "createdisp",
2085 test_stream_create_disposition);
2086 torture_suite_add_1smb_test(suite, "attr", test_stream_attributes);
2087 torture_suite_add_1smb_test(suite, "sumtab", test_stream_summary_tab);
2088 torture_suite_add_1smb_test(suite, "perms", test_stream_permissions);
2090 #if 0
2091 torture_suite_add_1smb_test(suite, "LARGESTREAMINFO",
2092 test_stream_large_streaminfo);
2093 #endif
2095 return suite;