LCOV - code coverage report
Current view: top level - source4/torture/smb2 - streams.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 1106 1373 80.6 %
Date: 2024-05-31 13:13:24 Functions: 22 22 100.0 %

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

Generated by: LCOV version 1.14