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

Generated by: LCOV version 1.14