LCOV - code coverage report
Current view: top level - source4/torture/smb2 - delete-on-close.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 382 421 90.7 %
Date: 2024-04-21 15:09:00 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          49 : static bool create_dir(struct torture_context *tctx, struct smb2_tree *tree)
      43             : {
      44           0 :         NTSTATUS status;
      45           0 :         struct smb2_create io;
      46           0 :         struct smb2_handle handle;
      47           0 :         union smb_fileinfo q;
      48           0 :         union smb_setfileinfo set;
      49           0 :         struct security_descriptor *sd, *sd_orig;
      50           0 :         const char *owner_sid;
      51          49 :         uint32_t perms = 0;
      52             : 
      53          49 :         torture_comment(tctx, "Creating Directory for testing: %s\n", DNAME);
      54             : 
      55          49 :         ZERO_STRUCT(io);
      56          49 :         io.level = RAW_OPEN_SMB2;
      57          49 :         io.in.create_flags = 0;
      58          49 :         io.in.desired_access =
      59             :                 SEC_STD_READ_CONTROL |
      60             :                 SEC_STD_WRITE_DAC |
      61             :                 SEC_STD_WRITE_OWNER;
      62          49 :         io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
      63          49 :         io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
      64          49 :         io.in.share_access =
      65             :                 NTCREATEX_SHARE_ACCESS_READ |
      66             :                 NTCREATEX_SHARE_ACCESS_WRITE;
      67          49 :         io.in.alloc_size = 0;
      68          49 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
      69          49 :         io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
      70          49 :         io.in.security_flags = 0;
      71          49 :         io.in.fname = DNAME;
      72          49 :         status = smb2_create(tree, tctx, &io);
      73          49 :         CHECK_STATUS(status, NT_STATUS_OK);
      74          49 :         handle = io.out.file.handle;
      75             : 
      76          49 :         torture_comment(tctx, "get the original sd\n");
      77          49 :         q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
      78          49 :         q.query_secdesc.in.file.handle = handle;
      79          49 :         q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
      80          49 :         status = smb2_getinfo_file(tree, tctx, &q);
      81          49 :         CHECK_STATUS(status, NT_STATUS_OK);
      82          49 :         sd_orig = q.query_secdesc.out.sd;
      83             : 
      84          49 :         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          49 :         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          49 :         torture_comment(tctx, "Setting permissions on dir to 0x1e01bf\n");
      99          49 :         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          49 :         set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
     108          49 :         set.set_secdesc.in.file.handle = handle;
     109          49 :         set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
     110          49 :         set.set_secdesc.in.sd = sd;
     111             : 
     112          49 :         status = smb2_setinfo_file(tree, &set);
     113          49 :         CHECK_STATUS(status, NT_STATUS_OK);
     114             : 
     115          49 :         status = smb2_util_close(tree, handle);
     116             : 
     117          49 :         return true;
     118             : }
     119             : 
     120          49 : static bool set_dir_delete_perms(struct torture_context *tctx, struct smb2_tree *tree)
     121             : {
     122           0 :         NTSTATUS status;
     123           0 :         struct smb2_create io;
     124           0 :         struct smb2_handle handle;
     125           0 :         union smb_fileinfo q;
     126           0 :         union smb_setfileinfo set;
     127           0 :         struct security_descriptor *sd, *sd_orig;
     128           0 :         const char *owner_sid;
     129          49 :         uint32_t perms = 0;
     130             : 
     131          49 :         torture_comment(tctx, "Opening Directory for setting new SD: %s\n", DNAME);
     132             : 
     133          49 :         ZERO_STRUCT(io);
     134          49 :         io.level = RAW_OPEN_SMB2;
     135          49 :         io.in.create_flags = 0;
     136          49 :         io.in.desired_access =
     137             :                 SEC_STD_READ_CONTROL |
     138             :                 SEC_STD_WRITE_DAC |
     139             :                 SEC_STD_WRITE_OWNER;
     140          49 :         io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     141          49 :         io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
     142          49 :         io.in.share_access =
     143             :                 NTCREATEX_SHARE_ACCESS_READ |
     144             :                 NTCREATEX_SHARE_ACCESS_WRITE;
     145          49 :         io.in.alloc_size = 0;
     146          49 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     147          49 :         io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
     148          49 :         io.in.security_flags = 0;
     149          49 :         io.in.fname = DNAME;
     150          49 :         status = smb2_create(tree, tctx, &io);
     151          49 :         CHECK_STATUS(status, NT_STATUS_OK);
     152          49 :         handle = io.out.file.handle;
     153             : 
     154          49 :         torture_comment(tctx, "get the original sd\n");
     155          49 :         q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
     156          49 :         q.query_secdesc.in.file.handle = handle;
     157          49 :         q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
     158          49 :         status = smb2_getinfo_file(tree, tctx, &q);
     159          49 :         CHECK_STATUS(status, NT_STATUS_OK);
     160          49 :         sd_orig = q.query_secdesc.out.sd;
     161             : 
     162          49 :         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          49 :         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          49 :         torture_comment(tctx, "Setting permissions on dir to 0x%0x\n", perms);
     178          49 :         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          49 :         set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
     187          49 :         set.set_secdesc.in.file.handle = handle;
     188          49 :         set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
     189          49 :         set.set_secdesc.in.sd = sd;
     190             : 
     191          49 :         status = smb2_setinfo_file(tree, &set);
     192          49 :         CHECK_STATUS(status, NT_STATUS_OK);
     193             : 
     194          49 :         status = smb2_util_close(tree, handle);
     195             : 
     196          49 :         return true;
     197             : }
     198             : 
     199           7 : static bool test_doc_overwrite_if(struct torture_context *tctx, struct smb2_tree *tree)
     200             : {
     201           0 :         struct smb2_create io;
     202           0 :         NTSTATUS status;
     203           7 :         uint32_t perms = 0;
     204             : 
     205             :         /* File should not exist for this first test, so make sure */
     206           7 :         set_dir_delete_perms(tctx, tree);
     207             : 
     208           7 :         smb2_deltree(tree, DNAME);
     209             : 
     210           7 :         create_dir(tctx, tree);
     211             : 
     212           7 :         torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (OVERWRITE_IF)\n");
     213           7 :         torture_comment(tctx, "We expect NT_STATUS_OK\n");
     214             : 
     215           7 :         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           7 :         ZERO_STRUCT(io);
     221           7 :         io.in.desired_access     = perms;
     222           7 :         io.in.file_attributes    = 0;
     223           7 :         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
     224           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     225           7 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     226             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     227           7 :         io.in.fname              = FNAME;
     228             : 
     229           7 :         status = smb2_create(tree, tctx, &io);
     230           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     231             : 
     232           7 :         status = smb2_util_close(tree, io.out.file.handle);
     233             : 
     234             :         /* Check it was deleted */
     235           7 :         ZERO_STRUCT(io);
     236           7 :         io.in.desired_access     = perms;
     237           7 :         io.in.file_attributes    = 0;
     238           7 :         io.in.create_disposition = NTCREATEX_DISP_OPEN;
     239           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     240           7 :         io.in.create_options     = 0;
     241           7 :         io.in.fname              = FNAME;
     242             : 
     243           7 :         torture_comment(tctx, "Testing if the file was deleted when closed\n");
     244           7 :         torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_NOT_FOUND\n");
     245             : 
     246           7 :         status = smb2_create(tree, tctx, &io);
     247           7 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     248             : 
     249           7 :         return true;
     250             : }
     251             : 
     252           7 : static bool test_doc_overwrite_if_exist(struct torture_context *tctx, struct smb2_tree *tree)
     253             : {
     254           0 :         struct smb2_create io;
     255           0 :         NTSTATUS status;
     256           7 :         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           7 :         set_dir_delete_perms(tctx, tree);
     261             : 
     262           7 :         smb2_deltree(tree, DNAME);
     263             : 
     264           7 :         create_dir(tctx, tree);
     265             : 
     266           7 :         torture_comment(tctx, "Create file with DeleteOnClose on existing file (OVERWRITE_IF)\n");
     267           7 :         torture_comment(tctx, "We expect NT_STATUS_ACCESS_DENIED\n");
     268             : 
     269           7 :         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           7 :         ZERO_STRUCT(io);
     276           7 :         io.in.desired_access     = perms;
     277           7 :         io.in.file_attributes    = 0;
     278           7 :         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
     279           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     280           7 :         io.in.create_options     = 0x0;
     281           7 :         io.in.fname              = FNAME;
     282             : 
     283           7 :         status = smb2_create(tree, tctx, &io);
     284           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     285             : 
     286           7 :         status = smb2_util_close(tree, io.out.file.handle);
     287             : 
     288             :         /* Next, try to open it for Delete On Close */
     289           7 :         ZERO_STRUCT(io);
     290           7 :         io.in.desired_access     = perms;
     291           7 :         io.in.file_attributes    = 0;
     292           7 :         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
     293           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     294           7 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     295             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     296           7 :         io.in.fname              = FNAME;
     297             : 
     298           7 :         status = smb2_create(tree, tctx, &io);
     299           7 :         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
     300             : 
     301           7 :         status = smb2_util_close(tree, io.out.file.handle);
     302             : 
     303           7 :         return true;
     304             : }
     305             : 
     306           7 : static bool test_doc_create(struct torture_context *tctx, struct smb2_tree *tree)
     307             : {
     308           0 :         struct smb2_create io;
     309           0 :         NTSTATUS status;
     310           7 :         uint32_t perms = 0;
     311             : 
     312             :         /* File should not exist for this first test, so make sure */
     313           7 :         set_dir_delete_perms(tctx, tree);
     314             : 
     315           7 :         smb2_deltree(tree, DNAME);
     316             : 
     317           7 :         create_dir(tctx, tree);
     318             : 
     319           7 :         torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (CREATE) \n");
     320           7 :         torture_comment(tctx, "We expect NT_STATUS_OK\n");
     321             : 
     322           7 :         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           7 :         ZERO_STRUCT(io);
     328           7 :         io.in.desired_access     = perms;
     329           7 :         io.in.file_attributes    = 0;
     330           7 :         io.in.create_disposition = NTCREATEX_DISP_CREATE;
     331           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     332           7 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     333             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     334           7 :         io.in.fname              = FNAME;
     335             : 
     336           7 :         status = smb2_create(tree, tctx, &io);
     337           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     338             : 
     339           7 :         status = smb2_util_close(tree, io.out.file.handle);
     340             : 
     341             :         /* Check it was deleted */
     342           7 :         ZERO_STRUCT(io);
     343           7 :         io.in.desired_access     = perms;
     344           7 :         io.in.file_attributes    = 0;
     345           7 :         io.in.create_disposition = NTCREATEX_DISP_OPEN;
     346           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     347           7 :         io.in.create_options     = 0;
     348           7 :         io.in.fname              = FNAME;
     349             : 
     350           7 :         torture_comment(tctx, "Testing if the file was deleted when closed\n");
     351           7 :         torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_NOT_FOUND\n");
     352             : 
     353           7 :         status = smb2_create(tree, tctx, &io);
     354           7 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     355             : 
     356           7 :         return true;
     357             : }
     358             : 
     359           7 : static bool test_doc_create_exist(struct torture_context *tctx, struct smb2_tree *tree)
     360             : {
     361           0 :         struct smb2_create io;
     362           0 :         NTSTATUS status;
     363           7 :         uint32_t perms = 0;
     364             : 
     365             :         /* File should not exist for this first test, so make sure */
     366           7 :         set_dir_delete_perms(tctx, tree);
     367             : 
     368           7 :         smb2_deltree(tree, DNAME);
     369             : 
     370           7 :         create_dir(tctx, tree);
     371             : 
     372           7 :         torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (CREATE) \n");
     373           7 :         torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_COLLISION\n");
     374             : 
     375           7 :         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           7 :         ZERO_STRUCT(io);
     382           7 :         io.in.desired_access     = perms;
     383           7 :         io.in.file_attributes    = 0;
     384           7 :         io.in.create_disposition = NTCREATEX_DISP_CREATE;
     385           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     386           7 :         io.in.create_options     = 0x0;
     387           7 :         io.in.fname              = FNAME;
     388             : 
     389           7 :         status = smb2_create(tree, tctx, &io);
     390           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     391             : 
     392           7 :         status = smb2_util_close(tree, io.out.file.handle);
     393             : 
     394             :         /* Next, try to open it for Delete on Close */
     395           7 :         status = smb2_util_close(tree, io.out.file.handle);
     396           7 :         ZERO_STRUCT(io);
     397           7 :         io.in.desired_access     = perms;
     398           7 :         io.in.file_attributes    = 0;
     399           7 :         io.in.create_disposition = NTCREATEX_DISP_CREATE;
     400           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     401           7 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     402             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     403           7 :         io.in.fname              = FNAME;
     404             : 
     405           7 :         status = smb2_create(tree, tctx, &io);
     406           7 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
     407             : 
     408           7 :         status = smb2_util_close(tree, io.out.file.handle);
     409             : 
     410           7 :         return true;
     411             : }
     412             : 
     413           7 : static bool test_doc_create_if(struct torture_context *tctx, struct smb2_tree *tree)
     414             : {
     415           0 :         struct smb2_create io;
     416           0 :         NTSTATUS status;
     417           7 :         uint32_t perms = 0;
     418             : 
     419             :         /* File should not exist for this first test, so make sure */
     420           7 :         set_dir_delete_perms(tctx, tree);
     421             : 
     422           7 :         smb2_deltree(tree, DNAME);
     423             : 
     424           7 :         create_dir(tctx, tree);
     425             : 
     426           7 :         torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (OPEN_IF)\n");
     427           7 :         torture_comment(tctx, "We expect NT_STATUS_OK\n");
     428             : 
     429           7 :         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           7 :         ZERO_STRUCT(io);
     435           7 :         io.in.desired_access     = perms;
     436           7 :         io.in.file_attributes    = 0;
     437           7 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     438           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     439           7 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     440             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     441           7 :         io.in.fname              = FNAME;
     442             : 
     443           7 :         status = smb2_create(tree, tctx, &io);
     444           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     445             : 
     446           7 :         status = smb2_util_close(tree, io.out.file.handle);
     447             : 
     448             :         /* Check it was deleted */
     449           7 :         ZERO_STRUCT(io);
     450           7 :         io.in.desired_access     = perms;
     451           7 :         io.in.file_attributes    = 0;
     452           7 :         io.in.create_disposition = NTCREATEX_DISP_OPEN;
     453           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     454           7 :         io.in.create_options     = 0;
     455           7 :         io.in.fname              = FNAME;
     456             : 
     457           7 :         torture_comment(tctx, "Testing if the file was deleted when closed\n");
     458           7 :         torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_NOT_FOUND\n");
     459             : 
     460           7 :         status = smb2_create(tree, tctx, &io);
     461           7 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     462             : 
     463           7 :         return true;
     464             : }
     465             : 
     466           7 : static bool test_doc_create_if_exist(struct torture_context *tctx, struct smb2_tree *tree)
     467             : {
     468           0 :         struct smb2_create io;
     469           0 :         NTSTATUS status;
     470           7 :         uint32_t perms = 0;
     471             : 
     472             :         /* File should not exist for this first test, so make sure */
     473           7 :         set_dir_delete_perms(tctx, tree);
     474             : 
     475           7 :         smb2_deltree(tree, DNAME);
     476             : 
     477           7 :         create_dir(tctx, tree);
     478             : 
     479           7 :         torture_comment(tctx, "Create file with DeleteOnClose on existing file (OPEN_IF)\n");
     480           7 :         torture_comment(tctx, "We expect NT_STATUS_ACCESS_DENIED\n");
     481             : 
     482           7 :         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           7 :         ZERO_STRUCT(io);
     489           7 :         io.in.desired_access     = perms;
     490           7 :         io.in.file_attributes    = 0;
     491           7 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     492           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     493           7 :         io.in.create_options     = 0x0;
     494           7 :         io.in.fname              = FNAME;
     495             : 
     496           7 :         status = smb2_create(tree, tctx, &io);
     497           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     498             : 
     499           7 :         status = smb2_util_close(tree, io.out.file.handle);
     500             : 
     501             :         /* Now try to create it for delete on close */
     502           7 :         ZERO_STRUCT(io);
     503           7 :         io.in.desired_access     = 0x130196;
     504           7 :         io.in.file_attributes    = 0;
     505           7 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     506           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE;
     507           7 :         io.in.create_options     = NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 
     508             :                                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     509           7 :         io.in.fname              = FNAME;
     510             : 
     511           7 :         status = smb2_create(tree, tctx, &io);
     512           7 :         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
     513             : 
     514           7 :         status = smb2_util_close(tree, io.out.file.handle);
     515             : 
     516           7 :         return true;
     517             : }
     518             : 
     519           7 : static bool test_doc_find_and_set_doc(struct torture_context *tctx, struct smb2_tree *tree)
     520             : {
     521           0 :         struct smb2_create io;
     522           0 :         struct smb2_find find;
     523           0 :         NTSTATUS status;
     524           0 :         union smb_search_data *d;
     525           0 :         union smb_setfileinfo sfinfo;
     526           0 :         unsigned int count;
     527           7 :         uint32_t perms = 0;
     528             : 
     529           7 :         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           7 :         set_dir_delete_perms(tctx, tree);
     536             : 
     537           7 :         smb2_deltree(tree, DNAME);
     538             : 
     539           7 :         create_dir(tctx, tree);
     540             : 
     541           7 :         torture_comment(tctx, "FIND and delete directory\n");
     542           7 :         torture_comment(tctx, "We expect NT_STATUS_OK\n");
     543             : 
     544             :         /* open the directory first */
     545           7 :         ZERO_STRUCT(io);
     546           7 :         io.in.desired_access     = perms;
     547           7 :         io.in.file_attributes    = FILE_ATTRIBUTE_DIRECTORY;
     548           7 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     549           7 :         io.in.share_access       = NTCREATEX_SHARE_ACCESS_READ |
     550             :                                    NTCREATEX_SHARE_ACCESS_DELETE;
     551           7 :         io.in.create_options     = NTCREATEX_OPTIONS_DIRECTORY;
     552           7 :         io.in.fname              = DNAME;
     553             : 
     554           7 :         status = smb2_create(tree, tctx, &io);
     555           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     556             : 
     557             :         /* list directory */
     558           7 :         ZERO_STRUCT(find);
     559           7 :         find.in.file.handle        = io.out.file.handle;
     560           7 :         find.in.pattern            = "*";
     561           7 :         find.in.continue_flags     = SMB2_CONTINUE_FLAG_SINGLE;
     562           7 :         find.in.max_response_size  = 0x100;
     563           7 :         find.in.level              = SMB2_FIND_BOTH_DIRECTORY_INFO;
     564             : 
     565             :         /* start enumeration on directory */
     566           7 :         status = smb2_find_level(tree, tree, &find, &count, &d);
     567           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     568             : 
     569             :         /* set delete-on-close */
     570           7 :         ZERO_STRUCT(sfinfo);
     571           7 :         sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
     572           7 :         sfinfo.disposition_info.in.delete_on_close = 1;
     573           7 :         sfinfo.generic.in.file.handle = io.out.file.handle;
     574           7 :         status = smb2_setinfo_file(tree, &sfinfo);
     575           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     576             : 
     577             :         /* close directory */
     578           7 :         status = smb2_util_close(tree, io.out.file.handle);
     579           7 :         CHECK_STATUS(status, NT_STATUS_OK);
     580           7 :         return true;
     581             : }
     582             : 
     583           7 : static bool test_doc_read_only(struct torture_context *tctx,
     584             :                                struct smb2_tree *tree)
     585             : {
     586           0 :         struct smb2_handle dir_handle;
     587           7 :         union smb_setfileinfo sfinfo = {{0}};
     588           7 :         struct smb2_create create = {0};
     589           7 :         struct smb2_close close = {0};
     590           0 :         NTSTATUS status, expected_status;
     591           7 :         bool ret = true, delete_readonly;
     592             : 
     593             :         /*
     594             :          * Allow testing of the Samba 'delete readonly' option.
     595             :          */
     596           7 :         delete_readonly = torture_setting_bool(tctx, "delete_readonly", false);
     597           7 :         expected_status = delete_readonly ?
     598           1 :                 NT_STATUS_OK : NT_STATUS_CANNOT_DELETE;
     599             : 
     600           7 :         smb2_deltree(tree, DNAME);
     601             : 
     602           7 :         status = torture_smb2_testdir(tree, DNAME, &dir_handle);
     603           7 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     604             :                                         "CREATE directory failed\n");
     605             : 
     606           7 :         create = (struct smb2_create) {0};
     607           7 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
     608           7 :         create.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
     609             :                 NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
     610           7 :         create.in.file_attributes = FILE_ATTRIBUTE_READONLY;
     611           7 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     612             :                 NTCREATEX_SHARE_ACCESS_WRITE |
     613             :                 NTCREATEX_SHARE_ACCESS_DELETE;
     614           7 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
     615           7 :         create.in.fname = FNAME;
     616           7 :         status = smb2_create(tree, tctx, &create);
     617           7 :         torture_assert_ntstatus_equal_goto(tctx, status, expected_status, ret,
     618             :                                            done, "Unexpected status for CREATE "
     619             :                                            "of new file.\n");
     620             : 
     621           7 :         if (delete_readonly) {
     622           2 :                 close.in.file.handle = create.out.file.handle;
     623           2 :                 status = smb2_close(tree, &close);
     624           2 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     625             :                                                 "CLOSE of READONLY file "
     626             :                                                 "failed.\n");
     627             :         }
     628             : 
     629           7 :         torture_comment(tctx, "Creating file with READ_ONLY attribute.\n");
     630             : 
     631           7 :         create = (struct smb2_create) {0};
     632           7 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
     633           7 :         create.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     634           7 :         create.in.file_attributes = FILE_ATTRIBUTE_READONLY;
     635           7 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     636             :                 NTCREATEX_SHARE_ACCESS_WRITE |
     637             :                 NTCREATEX_SHARE_ACCESS_DELETE;
     638           7 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
     639           7 :         create.in.fname = FNAME;
     640           7 :         status = smb2_create(tree, tctx, &create);
     641           7 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     642             :                                         "CREATE of READONLY file failed.\n");
     643             : 
     644           7 :         close.in.file.handle = create.out.file.handle;
     645           7 :         status = smb2_close(tree, &close);
     646           7 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     647             :                                         "CLOSE of READONLY file failed.\n");
     648             : 
     649           7 :         torture_comment(tctx, "Testing CREATE with DELETE_ON_CLOSE on "
     650             :                         "READ_ONLY attribute file.\n");
     651             : 
     652           7 :         create = (struct smb2_create) {0};
     653           7 :         create.in.desired_access = SEC_RIGHTS_FILE_READ | SEC_STD_DELETE;
     654           7 :         create.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
     655           7 :         create.in.file_attributes = 0;
     656           7 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     657             :                 NTCREATEX_SHARE_ACCESS_WRITE |
     658             :                 NTCREATEX_SHARE_ACCESS_DELETE;
     659           7 :         create.in.create_disposition = NTCREATEX_DISP_OPEN;
     660           7 :         create.in.fname = FNAME;
     661           7 :         status = smb2_create(tree, tctx, &create);
     662           7 :         torture_assert_ntstatus_equal_goto(tctx, status,
     663             :                                            expected_status, ret, done,
     664             :                                            "CREATE returned unexpected "
     665             :                                            "status.\n");
     666             : 
     667           7 :         torture_comment(tctx, "Testing setting DELETE_ON_CLOSE disposition on "
     668             :                         " file with READONLY attribute.\n");
     669             : 
     670           7 :         create = (struct smb2_create) {0};
     671           7 :         create.in.desired_access = SEC_RIGHTS_FILE_READ | SEC_STD_DELETE;;
     672           7 :         create.in.create_options = 0;
     673           7 :         create.in.file_attributes = 0;
     674           7 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     675             :                 NTCREATEX_SHARE_ACCESS_WRITE |
     676             :                 NTCREATEX_SHARE_ACCESS_DELETE;
     677           7 :         create.in.create_disposition = NTCREATEX_DISP_OPEN;
     678           7 :         create.in.fname = FNAME;
     679           7 :         status = smb2_create(tree, tctx, &create);
     680           7 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     681             :                                         "Opening file failed.\n");
     682             : 
     683           7 :         sfinfo.disposition_info.in.delete_on_close = 1;
     684           7 :         sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
     685           7 :         sfinfo.generic.in.file.handle = create.out.file.handle;
     686             : 
     687           7 :         status = smb2_setinfo_file(tree, &sfinfo);
     688           7 :         torture_assert_ntstatus_equal(tctx, status, expected_status,
     689             :                                       "Set DELETE_ON_CLOSE disposition "
     690             :                                       "returned un expected status.\n");
     691             : 
     692           7 :         status = smb2_util_close(tree, create.out.file.handle);
     693           7 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     694             :                                         "CLOSE failed\n");
     695             : 
     696           7 : done:
     697           7 :         smb2_deltree(tree, DNAME);
     698           7 :         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           7 : static bool test_doc_bug14427(struct torture_context *tctx, struct smb2_tree *tree1)
     708             : {
     709           7 :         struct smb2_tree *tree2 = NULL;
     710           0 :         NTSTATUS status;
     711           0 :         char fname[256];
     712           7 :         bool ret = false;
     713           0 :         bool ok;
     714             : 
     715             :         /* Add some random component to the file name. */
     716           7 :         snprintf(fname, sizeof(fname), "doc_bug14427_%s.dat",
     717             :                  generate_random_str(tctx, 8));
     718             : 
     719           7 :         ok = torture_smb2_tree_connect(tctx, tree1->session, tctx, &tree2);
     720           7 :         torture_assert_goto(tctx, ok, ret, done,
     721             :                 "torture_smb2_tree_connect() failed.\n");
     722             : 
     723           7 :         status = torture_setup_simple_file(tctx, tree1, fname);
     724           7 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     725             :                 "torture_setup_simple_file() failed on tree1.\n");
     726             : 
     727           7 :         status = smb2_util_unlink(tree2, fname);
     728           7 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     729             :                 "smb2_util_unlink() failed on tree2.\n");
     730           7 :         TALLOC_FREE(tree2);
     731           7 :         ret = true;
     732           7 : done:
     733           7 :         if (tree2 != NULL) {
     734           0 :                 TALLOC_FREE(tree2);
     735           0 :                 smb2_util_unlink(tree1, fname);
     736             :         }
     737             : 
     738           7 :         TALLOC_FREE(tree1);
     739           7 :         return ret;
     740             : }
     741             : 
     742             : /*
     743             :  *  Extreme testing of Delete On Close and permissions
     744             :  */
     745        2354 : struct torture_suite *torture_smb2_doc_init(TALLOC_CTX *ctx)
     746             : {
     747        2354 :         struct torture_suite *suite = torture_suite_create(ctx, "delete-on-close-perms");
     748             : 
     749        2354 :         torture_suite_add_1smb2_test(suite, "OVERWRITE_IF", test_doc_overwrite_if);
     750        2354 :         torture_suite_add_1smb2_test(suite, "OVERWRITE_IF Existing", test_doc_overwrite_if_exist);
     751        2354 :         torture_suite_add_1smb2_test(suite, "CREATE", test_doc_create);
     752        2354 :         torture_suite_add_1smb2_test(suite, "CREATE Existing", test_doc_create_exist);
     753        2354 :         torture_suite_add_1smb2_test(suite, "CREATE_IF", test_doc_create_if);
     754        2354 :         torture_suite_add_1smb2_test(suite, "CREATE_IF Existing", test_doc_create_if_exist);
     755        2354 :         torture_suite_add_1smb2_test(suite, "FIND_and_set_DOC", test_doc_find_and_set_doc);
     756        2354 :         torture_suite_add_1smb2_test(suite, "READONLY", test_doc_read_only);
     757        2354 :         torture_suite_add_1smb2_test(suite, "BUG14427", test_doc_bug14427);
     758             : 
     759        2354 :         suite->description = talloc_strdup(suite, "SMB2-Delete-on-Close-Perms tests");
     760             : 
     761        2354 :         return suite;
     762             : }

Generated by: LCOV version 1.14