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 : }
|