LCOV - code coverage report
Current view: top level - source4/torture/smb2 - delete-on-close.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 378 384 98.4 %
Date: 2024-06-13 04:01:37 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    test delete-on-close in more detail
       5             : 
       6             :    Copyright (C) Richard Sharpe, 2013
       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             : #include "torture/torture.h"
      26             : #include "torture/util.h"
      27             : #include "torture/smb2/proto.h"
      28             : #include "libcli/security/security.h"
      29             : #include "librpc/gen_ndr/ndr_security.h"
      30             : 
      31             : #define DNAME "test_dir"
      32             : #define FNAME DNAME "\\test_create.dat"
      33             : 
      34             : #define CHECK_STATUS(status, correct) do { \
      35             :         if (!NT_STATUS_EQUAL(status, correct)) { \
      36             :                 torture_result(tctx, TORTURE_FAIL, \
      37             :                         "(%s) Incorrect status %s - should be %s\n", \
      38             :                          __location__, nt_errstr(status), nt_errstr(correct)); \
      39             :                 return false; \
      40             :         }} while (0)
      41             : 
      42           7 : static bool create_dir(struct torture_context *tctx, struct smb2_tree *tree)
      43             : {
      44             :         NTSTATUS status;
      45             :         struct smb2_create io;
      46             :         struct smb2_handle handle;
      47             :         union smb_fileinfo q;
      48             :         union smb_setfileinfo set;
      49             :         struct security_descriptor *sd, *sd_orig;
      50             :         const char *owner_sid;
      51           7 :         uint32_t perms = 0;
      52             : 
      53           7 :         torture_comment(tctx, "Creating Directory for testing: %s\n", DNAME);
      54             : 
      55           7 :         ZERO_STRUCT(io);
      56           7 :         io.level = RAW_OPEN_SMB2;
      57           7 :         io.in.create_flags = 0;
      58           7 :         io.in.desired_access =
      59             :                 SEC_STD_READ_CONTROL |
      60             :                 SEC_STD_WRITE_DAC |
      61             :                 SEC_STD_WRITE_OWNER;
      62           7 :         io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
      63           7 :         io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
      64           7 :         io.in.share_access =
      65             :                 NTCREATEX_SHARE_ACCESS_READ |
      66             :                 NTCREATEX_SHARE_ACCESS_WRITE;
      67           7 :         io.in.alloc_size = 0;
      68           7 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
      69           7 :         io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
      70           7 :         io.in.security_flags = 0;
      71           7 :         io.in.fname = DNAME;
      72           7 :         status = smb2_create(tree, tctx, &io);
      73           7 :         CHECK_STATUS(status, NT_STATUS_OK);
      74           7 :         handle = io.out.file.handle;
      75             : 
      76           7 :         torture_comment(tctx, "get the original sd\n");
      77           7 :         q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
      78           7 :         q.query_secdesc.in.file.handle = handle;
      79           7 :         q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
      80           7 :         status = smb2_getinfo_file(tree, tctx, &q);
      81           7 :         CHECK_STATUS(status, NT_STATUS_OK);
      82           7 :         sd_orig = q.query_secdesc.out.sd;
      83             : 
      84           7 :         owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
      85             : 
      86             :         /*
      87             :          * We create an SD that allows us to do most things but we do not
      88             :          * get DELETE and DELETE CHILD access!
      89             :          */
      90             : 
      91           7 :         perms = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_OWNER |
      92             :                 SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL | 
      93             :                 SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE | 
      94             :                 SEC_DIR_TRAVERSE | SEC_DIR_WRITE_EA | 
      95             :                 SEC_FILE_READ_EA | SEC_FILE_APPEND_DATA |
      96             :                 SEC_FILE_WRITE_DATA | SEC_FILE_READ_DATA;
      97             : 
      98           7 :         torture_comment(tctx, "Setting permissions on dir to 0x1e01bf\n");
      99           7 :         sd = security_descriptor_dacl_create(tctx,
     100             :                                         0, owner_sid, NULL,
     101             :                                         owner_sid,
     102             :                                         SEC_ACE_TYPE_ACCESS_ALLOWED,
     103             :                                         perms,
     104             :                                         SEC_ACE_FLAG_OBJECT_INHERIT,
     105             :                                         NULL);
     106             : 
     107           7 :         set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
     108           7 :         set.set_secdesc.in.file.handle = handle;
     109           7 :         set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
     110           7 :         set.set_secdesc.in.sd = sd;
     111             : 
     112           7 :         status = smb2_setinfo_file(tree, &set);
     113           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     114             : 
     115           7 :         status = smb2_util_close(tree, handle);
     116             : 
     117           7 :         return true;
     118             : }
     119             : 
     120           7 : static bool set_dir_delete_perms(struct torture_context *tctx, struct smb2_tree *tree)
     121             : {
     122             :         NTSTATUS status;
     123             :         struct smb2_create io;
     124             :         struct smb2_handle handle;
     125             :         union smb_fileinfo q;
     126             :         union smb_setfileinfo set;
     127             :         struct security_descriptor *sd, *sd_orig;
     128             :         const char *owner_sid;
     129           7 :         uint32_t perms = 0;
     130             : 
     131           7 :         torture_comment(tctx, "Opening Directory for setting new SD: %s\n", DNAME);
     132             : 
     133           7 :         ZERO_STRUCT(io);
     134           7 :         io.level = RAW_OPEN_SMB2;
     135           7 :         io.in.create_flags = 0;
     136           7 :         io.in.desired_access =
     137             :                 SEC_STD_READ_CONTROL |
     138             :                 SEC_STD_WRITE_DAC |
     139             :                 SEC_STD_WRITE_OWNER;
     140           7 :         io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     141           7 :         io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
     142           7 :         io.in.share_access =
     143             :                 NTCREATEX_SHARE_ACCESS_READ |
     144             :                 NTCREATEX_SHARE_ACCESS_WRITE;
     145           7 :         io.in.alloc_size = 0;
     146           7 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     147           7 :         io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
     148           7 :         io.in.security_flags = 0;
     149           7 :         io.in.fname = DNAME;
     150           7 :         status = smb2_create(tree, tctx, &io);
     151           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     152           7 :         handle = io.out.file.handle;
     153             : 
     154           7 :         torture_comment(tctx, "get the original sd\n");
     155           7 :         q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
     156           7 :         q.query_secdesc.in.file.handle = handle;
     157           7 :         q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
     158           7 :         status = smb2_getinfo_file(tree, tctx, &q);
     159           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     160           7 :         sd_orig = q.query_secdesc.out.sd;
     161             : 
     162           7 :         owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
     163             : 
     164             :         /*
     165             :          * We create an SD that allows us to do most things including
     166             :          * get DELETE and DELETE CHILD access!
     167             :          */
     168             : 
     169           7 :         perms = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_OWNER |
     170             :                 SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL | 
     171             :                 SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE | 
     172             :                 SEC_DIR_TRAVERSE | SEC_DIR_WRITE_EA | 
     173             :                 SEC_FILE_READ_EA | SEC_FILE_APPEND_DATA |
     174             :                 SEC_DIR_DELETE_CHILD | SEC_STD_DELETE |
     175             :                 SEC_FILE_WRITE_DATA | SEC_FILE_READ_DATA;
     176             : 
     177           7 :         torture_comment(tctx, "Setting permissions on dir to 0x%0x\n", perms);
     178           7 :         sd = security_descriptor_dacl_create(tctx,
     179             :                                         0, owner_sid, NULL,
     180             :                                         owner_sid,
     181             :                                         SEC_ACE_TYPE_ACCESS_ALLOWED,
     182             :                                         perms,
     183             :                                         0,
     184             :                                         NULL);
     185             : 
     186           7 :         set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
     187           7 :         set.set_secdesc.in.file.handle = handle;
     188           7 :         set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
     189           7 :         set.set_secdesc.in.sd = sd;
     190             : 
     191           7 :         status = smb2_setinfo_file(tree, &set);
     192           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     193             : 
     194           7 :         status = smb2_util_close(tree, handle);
     195             : 
     196           7 :         return true;
     197             : }
     198             : 
     199           1 : static bool test_doc_overwrite_if(struct torture_context *tctx, struct smb2_tree *tree)
     200             : {
     201             :         struct smb2_create io;
     202             :         NTSTATUS status;
     203           1 :         uint32_t perms = 0;
     204             : 
     205             :         /* File should not exist for this first test, so make sure */
     206           1 :         set_dir_delete_perms(tctx, tree);
     207             : 
     208           1 :         smb2_deltree(tree, DNAME);
     209             : 
     210           1 :         create_dir(tctx, tree);
     211             : 
     212           1 :         torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (OVERWRITE_IF)\n");
     213           1 :         torture_comment(tctx, "We expect NT_STATUS_OK\n");
     214             : 
     215           1 :         perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE | 
     216             :                 SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE | 
     217             :                 SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
     218             :                 SEC_FILE_WRITE_DATA;
     219             : 
     220           1 :         ZERO_STRUCT(io);
     221           1 :         io.in.desired_access     = perms;
     222           1 :         io.in.file_attributes    = 0;
     223           1 :         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
     224           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     225           1 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     226             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     227           1 :         io.in.fname              = FNAME;
     228             : 
     229           1 :         status = smb2_create(tree, tctx, &io);
     230           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     231             : 
     232           1 :         status = smb2_util_close(tree, io.out.file.handle);
     233             : 
     234             :         /* Check it was deleted */
     235           1 :         ZERO_STRUCT(io);
     236           1 :         io.in.desired_access     = perms;
     237           1 :         io.in.file_attributes    = 0;
     238           1 :         io.in.create_disposition = NTCREATEX_DISP_OPEN;
     239           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     240           1 :         io.in.create_options     = 0;
     241           1 :         io.in.fname              = FNAME;
     242             : 
     243           1 :         torture_comment(tctx, "Testing if the file was deleted when closed\n");
     244           1 :         torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_NOT_FOUND\n");
     245             : 
     246           1 :         status = smb2_create(tree, tctx, &io);
     247           1 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     248             : 
     249           1 :         return true;
     250             : }
     251             : 
     252           1 : static bool test_doc_overwrite_if_exist(struct torture_context *tctx, struct smb2_tree *tree)
     253             : {
     254             :         struct smb2_create io;
     255             :         NTSTATUS status;
     256           1 :         uint32_t perms = 0;
     257             : 
     258             :         /* File should not exist for this first test, so make sure */
     259             :         /* And set the SEC Descriptor appropriately */
     260           1 :         set_dir_delete_perms(tctx, tree);
     261             : 
     262           1 :         smb2_deltree(tree, DNAME);
     263             : 
     264           1 :         create_dir(tctx, tree);
     265             : 
     266           1 :         torture_comment(tctx, "Create file with DeleteOnClose on existing file (OVERWRITE_IF)\n");
     267           1 :         torture_comment(tctx, "We expect NT_STATUS_ACCESS_DENIED\n");
     268             : 
     269           1 :         perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE | 
     270             :                 SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE | 
     271             :                 SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
     272             :                 SEC_FILE_WRITE_DATA;
     273             : 
     274             :         /* First, create this file ... */
     275           1 :         ZERO_STRUCT(io);
     276           1 :         io.in.desired_access     = perms;
     277           1 :         io.in.file_attributes    = 0;
     278           1 :         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
     279           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     280           1 :         io.in.create_options     = 0x0;
     281           1 :         io.in.fname              = FNAME;
     282             : 
     283           1 :         status = smb2_create(tree, tctx, &io);
     284           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     285             : 
     286           1 :         status = smb2_util_close(tree, io.out.file.handle);
     287             : 
     288             :         /* Next, try to open it for Delete On Close */
     289           1 :         ZERO_STRUCT(io);
     290           1 :         io.in.desired_access     = perms;
     291           1 :         io.in.file_attributes    = 0;
     292           1 :         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
     293           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     294           1 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     295             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     296           1 :         io.in.fname              = FNAME;
     297             : 
     298           1 :         status = smb2_create(tree, tctx, &io);
     299           1 :         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
     300             : 
     301           1 :         status = smb2_util_close(tree, io.out.file.handle);
     302             : 
     303           1 :         return true;
     304             : }
     305             : 
     306           1 : static bool test_doc_create(struct torture_context *tctx, struct smb2_tree *tree)
     307             : {
     308             :         struct smb2_create io;
     309             :         NTSTATUS status;
     310           1 :         uint32_t perms = 0;
     311             : 
     312             :         /* File should not exist for this first test, so make sure */
     313           1 :         set_dir_delete_perms(tctx, tree);
     314             : 
     315           1 :         smb2_deltree(tree, DNAME);
     316             : 
     317           1 :         create_dir(tctx, tree);
     318             : 
     319           1 :         torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (CREATE) \n");
     320           1 :         torture_comment(tctx, "We expect NT_STATUS_OK\n");
     321             : 
     322           1 :         perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE | 
     323             :                 SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE | 
     324             :                 SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
     325             :                 SEC_FILE_WRITE_DATA;
     326             : 
     327           1 :         ZERO_STRUCT(io);
     328           1 :         io.in.desired_access     = perms;
     329           1 :         io.in.file_attributes    = 0;
     330           1 :         io.in.create_disposition = NTCREATEX_DISP_CREATE;
     331           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     332           1 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     333             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     334           1 :         io.in.fname              = FNAME;
     335             : 
     336           1 :         status = smb2_create(tree, tctx, &io);
     337           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     338             : 
     339           1 :         status = smb2_util_close(tree, io.out.file.handle);
     340             : 
     341             :         /* Check it was deleted */
     342           1 :         ZERO_STRUCT(io);
     343           1 :         io.in.desired_access     = perms;
     344           1 :         io.in.file_attributes    = 0;
     345           1 :         io.in.create_disposition = NTCREATEX_DISP_OPEN;
     346           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     347           1 :         io.in.create_options     = 0;
     348           1 :         io.in.fname              = FNAME;
     349             : 
     350           1 :         torture_comment(tctx, "Testing if the file was deleted when closed\n");
     351           1 :         torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_NOT_FOUND\n");
     352             : 
     353           1 :         status = smb2_create(tree, tctx, &io);
     354           1 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     355             : 
     356           1 :         return true;
     357             : }
     358             : 
     359           1 : static bool test_doc_create_exist(struct torture_context *tctx, struct smb2_tree *tree)
     360             : {
     361             :         struct smb2_create io;
     362             :         NTSTATUS status;
     363           1 :         uint32_t perms = 0;
     364             : 
     365             :         /* File should not exist for this first test, so make sure */
     366           1 :         set_dir_delete_perms(tctx, tree);
     367             : 
     368           1 :         smb2_deltree(tree, DNAME);
     369             : 
     370           1 :         create_dir(tctx, tree);
     371             : 
     372           1 :         torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (CREATE) \n");
     373           1 :         torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_COLLISION\n");
     374             : 
     375           1 :         perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE | 
     376             :                 SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE | 
     377             :                 SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
     378             :                 SEC_FILE_WRITE_DATA;
     379             : 
     380             :         /* First, create the file */
     381           1 :         ZERO_STRUCT(io);
     382           1 :         io.in.desired_access     = perms;
     383           1 :         io.in.file_attributes    = 0;
     384           1 :         io.in.create_disposition = NTCREATEX_DISP_CREATE;
     385           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     386           1 :         io.in.create_options     = 0x0;
     387           1 :         io.in.fname              = FNAME;
     388             : 
     389           1 :         status = smb2_create(tree, tctx, &io);
     390           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     391             : 
     392           1 :         status = smb2_util_close(tree, io.out.file.handle);
     393             : 
     394             :         /* Next, try to open it for Delete on Close */
     395           1 :         status = smb2_util_close(tree, io.out.file.handle);
     396           1 :         ZERO_STRUCT(io);
     397           1 :         io.in.desired_access     = perms;
     398           1 :         io.in.file_attributes    = 0;
     399           1 :         io.in.create_disposition = NTCREATEX_DISP_CREATE;
     400           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     401           1 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     402             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     403           1 :         io.in.fname              = FNAME;
     404             : 
     405           1 :         status = smb2_create(tree, tctx, &io);
     406           1 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
     407             : 
     408           1 :         status = smb2_util_close(tree, io.out.file.handle);
     409             : 
     410           1 :         return true;
     411             : }
     412             : 
     413           1 : static bool test_doc_create_if(struct torture_context *tctx, struct smb2_tree *tree)
     414             : {
     415             :         struct smb2_create io;
     416             :         NTSTATUS status;
     417           1 :         uint32_t perms = 0;
     418             : 
     419             :         /* File should not exist for this first test, so make sure */
     420           1 :         set_dir_delete_perms(tctx, tree);
     421             : 
     422           1 :         smb2_deltree(tree, DNAME);
     423             : 
     424           1 :         create_dir(tctx, tree);
     425             : 
     426           1 :         torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (OPEN_IF)\n");
     427           1 :         torture_comment(tctx, "We expect NT_STATUS_OK\n");
     428             : 
     429           1 :         perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE | 
     430             :                 SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE | 
     431             :                 SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
     432             :                 SEC_FILE_WRITE_DATA;
     433             : 
     434           1 :         ZERO_STRUCT(io);
     435           1 :         io.in.desired_access     = perms;
     436           1 :         io.in.file_attributes    = 0;
     437           1 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     438           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     439           1 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     440             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     441           1 :         io.in.fname              = FNAME;
     442             : 
     443           1 :         status = smb2_create(tree, tctx, &io);
     444           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     445             : 
     446           1 :         status = smb2_util_close(tree, io.out.file.handle);
     447             : 
     448             :         /* Check it was deleted */
     449           1 :         ZERO_STRUCT(io);
     450           1 :         io.in.desired_access     = perms;
     451           1 :         io.in.file_attributes    = 0;
     452           1 :         io.in.create_disposition = NTCREATEX_DISP_OPEN;
     453           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     454           1 :         io.in.create_options     = 0;
     455           1 :         io.in.fname              = FNAME;
     456             : 
     457           1 :         torture_comment(tctx, "Testing if the file was deleted when closed\n");
     458           1 :         torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_NOT_FOUND\n");
     459             : 
     460           1 :         status = smb2_create(tree, tctx, &io);
     461           1 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     462             : 
     463           1 :         return true;
     464             : }
     465             : 
     466           1 : static bool test_doc_create_if_exist(struct torture_context *tctx, struct smb2_tree *tree)
     467             : {
     468             :         struct smb2_create io;
     469             :         NTSTATUS status;
     470           1 :         uint32_t perms = 0;
     471             : 
     472             :         /* File should not exist for this first test, so make sure */
     473           1 :         set_dir_delete_perms(tctx, tree);
     474             : 
     475           1 :         smb2_deltree(tree, DNAME);
     476             : 
     477           1 :         create_dir(tctx, tree);
     478             : 
     479           1 :         torture_comment(tctx, "Create file with DeleteOnClose on existing file (OPEN_IF)\n");
     480           1 :         torture_comment(tctx, "We expect NT_STATUS_ACCESS_DENIED\n");
     481             : 
     482           1 :         perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE | 
     483             :                 SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE | 
     484             :                 SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
     485             :                 SEC_FILE_WRITE_DATA;
     486             : 
     487             :         /* Create the file first */
     488           1 :         ZERO_STRUCT(io);
     489           1 :         io.in.desired_access     = perms;
     490           1 :         io.in.file_attributes    = 0;
     491           1 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     492           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     493           1 :         io.in.create_options     = 0x0;
     494           1 :         io.in.fname              = FNAME;
     495             : 
     496           1 :         status = smb2_create(tree, tctx, &io);
     497           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     498             : 
     499           1 :         status = smb2_util_close(tree, io.out.file.handle);
     500             : 
     501             :         /* Now try to create it for delete on close */
     502           1 :         ZERO_STRUCT(io);
     503           1 :         io.in.desired_access     = 0x130196;
     504           1 :         io.in.file_attributes    = 0;
     505           1 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     506           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     507           1 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     508             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     509           1 :         io.in.fname              = FNAME;
     510             : 
     511           1 :         status = smb2_create(tree, tctx, &io);
     512           1 :         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
     513             : 
     514           1 :         status = smb2_util_close(tree, io.out.file.handle);
     515             : 
     516           1 :         return true;
     517             : }
     518             : 
     519           1 : static bool test_doc_find_and_set_doc(struct torture_context *tctx, struct smb2_tree *tree)
     520             : {
     521             :         struct smb2_create io;
     522             :         struct smb2_find find;
     523             :         NTSTATUS status;
     524             :         union smb_search_data *d;
     525             :         union smb_setfileinfo sfinfo;
     526             :         unsigned int count;
     527           1 :         uint32_t perms = 0;
     528             : 
     529           1 :         perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
     530             :                 SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
     531             :                 SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
     532             :                 SEC_FILE_WRITE_DATA | SEC_DIR_LIST;
     533             : 
     534             :         /* File should not exist for this first test, so make sure */
     535           1 :         set_dir_delete_perms(tctx, tree);
     536             : 
     537           1 :         smb2_deltree(tree, DNAME);
     538             : 
     539           1 :         create_dir(tctx, tree);
     540             : 
     541           1 :         torture_comment(tctx, "FIND and delete directory\n");
     542           1 :         torture_comment(tctx, "We expect NT_STATUS_OK\n");
     543             : 
     544             :         /* open the directory first */
     545           1 :         ZERO_STRUCT(io);
     546           1 :         io.in.desired_access     = perms;
     547           1 :         io.in.file_attributes    = FILE_ATTRIBUTE_DIRECTORY;
     548           1 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     549           1 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_READ |
     550             :                                    NTCREATEX_SHARE_ACCESS_DELETE;
     551           1 :         io.in.create_options     = NTCREATEX_OPTIONS_DIRECTORY;
     552           1 :         io.in.fname              = DNAME;
     553             : 
     554           1 :         status = smb2_create(tree, tctx, &io);
     555           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     556             : 
     557             :         /* list directory */
     558           1 :         ZERO_STRUCT(find);
     559           1 :         find.in.file.handle        = io.out.file.handle;
     560           1 :         find.in.pattern            = "*";
     561           1 :         find.in.continue_flags     = SMB2_CONTINUE_FLAG_SINGLE;
     562           1 :         find.in.max_response_size  = 0x100;
     563           1 :         find.in.level              = SMB2_FIND_BOTH_DIRECTORY_INFO;
     564             : 
     565             :         /* start enumeration on directory */
     566           1 :         status = smb2_find_level(tree, tree, &find, &count, &d);
     567           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     568             : 
     569             :         /* set delete-on-close */
     570           1 :         ZERO_STRUCT(sfinfo);
     571           1 :         sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
     572           1 :         sfinfo.disposition_info.in.delete_on_close = 1;
     573           1 :         sfinfo.generic.in.file.handle = io.out.file.handle;
     574           1 :         status = smb2_setinfo_file(tree, &sfinfo);
     575           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     576             : 
     577             :         /* close directory */
     578           1 :         status = smb2_util_close(tree, io.out.file.handle);
     579           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     580           1 :         return true;
     581             : }
     582             : 
     583           1 : static bool test_doc_read_only(struct torture_context *tctx,
     584             :                                struct smb2_tree *tree)
     585             : {
     586             :         struct smb2_handle dir_handle;
     587           1 :         union smb_setfileinfo sfinfo = {{0}};
     588           1 :         struct smb2_create create = {0};
     589           1 :         struct smb2_close close = {0};
     590             :         NTSTATUS status, expected_status;
     591           1 :         bool ret = true, delete_readonly;
     592             : 
     593             :         /*
     594             :          * Allow testing of the Samba 'delete readonly' option.
     595             :          */
     596           1 :         delete_readonly = torture_setting_bool(tctx, "delete_readonly", false);
     597           1 :         expected_status = delete_readonly ?
     598           0 :                 NT_STATUS_OK : NT_STATUS_CANNOT_DELETE;
     599             : 
     600           1 :         smb2_deltree(tree, DNAME);
     601             : 
     602           1 :         status = torture_smb2_testdir(tree, DNAME, &dir_handle);
     603           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     604             :                                         "CREATE directory failed\n");
     605             : 
     606           1 :         create = (struct smb2_create) {0};
     607           1 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
     608           1 :         create.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
     609             :                 NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
     610           1 :         create.in.file_attributes = FILE_ATTRIBUTE_READONLY;
     611           1 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     612             :                 NTCREATEX_SHARE_ACCESS_WRITE |
     613             :                 NTCREATEX_SHARE_ACCESS_DELETE;
     614           1 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
     615           1 :         create.in.fname = FNAME;
     616           1 :         status = smb2_create(tree, tctx, &create);
     617           1 :         torture_assert_ntstatus_equal_goto(tctx, status, expected_status, ret,
     618             :                                            done, "Unexpected status for CREATE "
     619             :                                            "of new file.\n");
     620             : 
     621           1 :         if (delete_readonly) {
     622           0 :                 close.in.file.handle = create.out.file.handle;
     623           0 :                 status = smb2_close(tree, &close);
     624           0 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     625             :                                                 "CLOSE of READONLY file "
     626             :                                                 "failed.\n");
     627             :         }
     628             : 
     629           1 :         torture_comment(tctx, "Creating file with READ_ONLY attribute.\n");
     630             : 
     631           1 :         create = (struct smb2_create) {0};
     632           1 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
     633           1 :         create.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     634           1 :         create.in.file_attributes = FILE_ATTRIBUTE_READONLY;
     635           1 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     636             :                 NTCREATEX_SHARE_ACCESS_WRITE |
     637             :                 NTCREATEX_SHARE_ACCESS_DELETE;
     638           1 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
     639           1 :         create.in.fname = FNAME;
     640           1 :         status = smb2_create(tree, tctx, &create);
     641           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     642             :                                         "CREATE of READONLY file failed.\n");
     643             : 
     644           1 :         close.in.file.handle = create.out.file.handle;
     645           1 :         status = smb2_close(tree, &close);
     646           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     647             :                                         "CLOSE of READONLY file failed.\n");
     648             : 
     649           1 :         torture_comment(tctx, "Testing CREATE with DELETE_ON_CLOSE on "
     650             :                         "READ_ONLY attribute file.\n");
     651             : 
     652           1 :         create = (struct smb2_create) {0};
     653           1 :         create.in.desired_access = SEC_RIGHTS_FILE_READ | SEC_STD_DELETE;
     654           1 :         create.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
     655           1 :         create.in.file_attributes = 0;
     656           1 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     657             :                 NTCREATEX_SHARE_ACCESS_WRITE |
     658             :                 NTCREATEX_SHARE_ACCESS_DELETE;
     659           1 :         create.in.create_disposition = NTCREATEX_DISP_OPEN;
     660           1 :         create.in.fname = FNAME;
     661           1 :         status = smb2_create(tree, tctx, &create);
     662           1 :         torture_assert_ntstatus_equal_goto(tctx, status,
     663             :                                            expected_status, ret, done,
     664             :                                            "CREATE returned unexpected "
     665             :                                            "status.\n");
     666             : 
     667           1 :         torture_comment(tctx, "Testing setting DELETE_ON_CLOSE disposition on "
     668             :                         " file with READONLY attribute.\n");
     669             : 
     670           1 :         create = (struct smb2_create) {0};
     671           1 :         create.in.desired_access = SEC_RIGHTS_FILE_READ | SEC_STD_DELETE;;
     672           1 :         create.in.create_options = 0;
     673           1 :         create.in.file_attributes = 0;
     674           1 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     675             :                 NTCREATEX_SHARE_ACCESS_WRITE |
     676             :                 NTCREATEX_SHARE_ACCESS_DELETE;
     677           1 :         create.in.create_disposition = NTCREATEX_DISP_OPEN;
     678           1 :         create.in.fname = FNAME;
     679           1 :         status = smb2_create(tree, tctx, &create);
     680           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     681             :                                         "Opening file failed.\n");
     682             : 
     683           1 :         sfinfo.disposition_info.in.delete_on_close = 1;
     684           1 :         sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
     685           1 :         sfinfo.generic.in.file.handle = create.out.file.handle;
     686             : 
     687           1 :         status = smb2_setinfo_file(tree, &sfinfo);
     688           1 :         torture_assert_ntstatus_equal(tctx, status, expected_status,
     689             :                                       "Set DELETE_ON_CLOSE disposition "
     690             :                                       "returned un expected status.\n");
     691             : 
     692           1 :         status = smb2_util_close(tree, create.out.file.handle);
     693           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     694             :                                         "CLOSE failed\n");
     695             : 
     696           1 : done:
     697           1 :         smb2_deltree(tree, DNAME);
     698           1 :         return ret;
     699             : }
     700             : 
     701             : /*
     702             :  * This is a regression test for
     703             :  * https://bugzilla.samba.org/show_bug.cgi?id=14427
     704             :  *
     705             :  * It's not really a delete-on-close specific test.
     706             :  */
     707           1 : static bool test_doc_bug14427(struct torture_context *tctx, struct smb2_tree *tree1)
     708             : {
     709           1 :         struct smb2_tree *tree2 = NULL;
     710             :         NTSTATUS status;
     711             :         char fname[256];
     712           1 :         bool ret = false;
     713             :         bool ok;
     714             : 
     715             :         /* Add some random component to the file name. */
     716           1 :         snprintf(fname, sizeof(fname), "doc_bug14427_%s.dat",
     717             :                  generate_random_str(tctx, 8));
     718             : 
     719           1 :         ok = torture_smb2_tree_connect(tctx, tree1->session, tctx, &tree2);
     720           1 :         torture_assert_goto(tctx, ok, ret, done,
     721             :                 "torture_smb2_tree_connect() failed.\n");
     722             : 
     723           1 :         status = torture_setup_simple_file(tctx, tree1, fname);
     724           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     725             :                 "torture_setup_simple_file() failed on tree1.\n");
     726             : 
     727           1 :         status = smb2_util_unlink(tree2, fname);
     728           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     729             :                 "smb2_util_unlink() failed on tree2.\n");
     730           1 :         TALLOC_FREE(tree2);
     731           1 :         ret = true;
     732           1 : done:
     733           1 :         if (tree2 != NULL) {
     734           0 :                 TALLOC_FREE(tree2);
     735           0 :                 smb2_util_unlink(tree1, fname);
     736             :         }
     737             : 
     738           1 :         TALLOC_FREE(tree1);
     739           1 :         return ret;
     740             : }
     741             : 
     742             : /*
     743             :  *  Extreme testing of Delete On Close and permissions
     744             :  */
     745         964 : struct torture_suite *torture_smb2_doc_init(TALLOC_CTX *ctx)
     746             : {
     747         964 :         struct torture_suite *suite = torture_suite_create(ctx, "delete-on-close-perms");
     748             : 
     749         964 :         torture_suite_add_1smb2_test(suite, "OVERWRITE_IF", test_doc_overwrite_if);
     750         964 :         torture_suite_add_1smb2_test(suite, "OVERWRITE_IF Existing", test_doc_overwrite_if_exist);
     751         964 :         torture_suite_add_1smb2_test(suite, "CREATE", test_doc_create);
     752         964 :         torture_suite_add_1smb2_test(suite, "CREATE Existing", test_doc_create_exist);
     753         964 :         torture_suite_add_1smb2_test(suite, "CREATE_IF", test_doc_create_if);
     754         964 :         torture_suite_add_1smb2_test(suite, "CREATE_IF Existing", test_doc_create_if_exist);
     755         964 :         torture_suite_add_1smb2_test(suite, "FIND_and_set_DOC", test_doc_find_and_set_doc);
     756         964 :         torture_suite_add_1smb2_test(suite, "READONLY", test_doc_read_only);
     757         964 :         torture_suite_add_1smb2_test(suite, "BUG14427", test_doc_bug14427);
     758             : 
     759         964 :         suite->description = talloc_strdup(suite, "SMB2-Delete-on-Close-Perms tests");
     760             : 
     761         964 :         return suite;
     762             : }

Generated by: LCOV version 1.13