LCOV - code coverage report
Current view: top level - source4/torture/raw - streams.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 964 1172 82.3 %
Date: 2024-06-13 04:01:37 Functions: 19 19 100.0 %

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

Generated by: LCOV version 1.13