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