LCOV - code coverage report
Current view: top level - source4/torture/smb2 - streams.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 979 1156 84.7 %
Date: 2021-09-23 10:06:22 Functions: 20 22 90.9 %

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

Generated by: LCOV version 1.13