1 /*
2 Unix SMB/CIFS implementation.
3 unlink test suite
4 Copyright (C) Andrew Tridgell 2003
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "system/filesys.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/libcli.h"
26 #include "torture/util.h"
27
28 #define CHECK_STATUS(status, correct) do { \
29 if (!NT_STATUS_EQUAL(status, correct)) { \
30 printf("(%s) Incorrect status %s - should be %s\n", \
31 __location__, nt_errstr(status), nt_errstr(correct)); \
32 ret = False; \
33 goto done; \
34 }} while (0)
35
36 #define BASEDIR "\\testunlink"
37
38 /*
39 test unlink ops
40 */
test_unlink(struct smbcli_state * cli,TALLOC_CTX * mem_ctx)41 static BOOL test_unlink(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
42 {
43 union smb_unlink io;
44 NTSTATUS status;
45 BOOL ret = True;
46 const char *fname = BASEDIR "\\test.txt";
47
48 if (!torture_setup_dir(cli, BASEDIR)) {
49 return False;
50 }
51
52 printf("Trying non-existant file\n");
53 io.unlink.in.pattern = fname;
54 io.unlink.in.attrib = 0;
55 status = smb_raw_unlink(cli->tree, &io);
56 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
57
58 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
59
60 io.unlink.in.pattern = fname;
61 io.unlink.in.attrib = 0;
62 status = smb_raw_unlink(cli->tree, &io);
63 CHECK_STATUS(status, NT_STATUS_OK);
64
65 printf("Trying a hidden file\n");
66 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
67 torture_set_file_attribute(cli->tree, fname, FILE_ATTRIBUTE_HIDDEN);
68
69 io.unlink.in.pattern = fname;
70 io.unlink.in.attrib = 0;
71 status = smb_raw_unlink(cli->tree, &io);
72 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
73
74 io.unlink.in.pattern = fname;
75 io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
76 status = smb_raw_unlink(cli->tree, &io);
77 CHECK_STATUS(status, NT_STATUS_OK);
78
79 io.unlink.in.pattern = fname;
80 io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
81 status = smb_raw_unlink(cli->tree, &io);
82 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
83
84 printf("Trying a directory\n");
85 io.unlink.in.pattern = BASEDIR;
86 io.unlink.in.attrib = 0;
87 status = smb_raw_unlink(cli->tree, &io);
88 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
89
90 io.unlink.in.pattern = BASEDIR;
91 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
92 status = smb_raw_unlink(cli->tree, &io);
93 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
94
95 printf("Trying a bad path\n");
96 io.unlink.in.pattern = "..";
97 io.unlink.in.attrib = 0;
98 status = smb_raw_unlink(cli->tree, &io);
99 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
100
101 io.unlink.in.pattern = "\\..";
102 io.unlink.in.attrib = 0;
103 status = smb_raw_unlink(cli->tree, &io);
104 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
105
106 io.unlink.in.pattern = BASEDIR "\\..\\..";
107 io.unlink.in.attrib = 0;
108 status = smb_raw_unlink(cli->tree, &io);
109 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
110
111 io.unlink.in.pattern = BASEDIR "\\..";
112 io.unlink.in.attrib = 0;
113 status = smb_raw_unlink(cli->tree, &io);
114 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
115
116 printf("Trying wildcards\n");
117 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
118 io.unlink.in.pattern = BASEDIR "\\t*.t";
119 io.unlink.in.attrib = 0;
120 status = smb_raw_unlink(cli->tree, &io);
121 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
122
123 io.unlink.in.pattern = BASEDIR "\\z*";
124 io.unlink.in.attrib = 0;
125 status = smb_raw_unlink(cli->tree, &io);
126 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
127
128 io.unlink.in.pattern = BASEDIR "\\z*";
129 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
130 status = smb_raw_unlink(cli->tree, &io);
131 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
132
133 io.unlink.in.pattern = BASEDIR "\\*";
134 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
135 status = smb_raw_unlink(cli->tree, &io);
136 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
137
138 io.unlink.in.pattern = BASEDIR "\\?";
139 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
140 status = smb_raw_unlink(cli->tree, &io);
141 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
142
143 io.unlink.in.pattern = BASEDIR "\\t*";
144 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
145 status = smb_raw_unlink(cli->tree, &io);
146 CHECK_STATUS(status, NT_STATUS_OK);
147
148 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
149
150 io.unlink.in.pattern = BASEDIR "\\*.dat";
151 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
152 status = smb_raw_unlink(cli->tree, &io);
153 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
154
155 io.unlink.in.pattern = BASEDIR "\\*.tx?";
156 io.unlink.in.attrib = 0;
157 status = smb_raw_unlink(cli->tree, &io);
158 CHECK_STATUS(status, NT_STATUS_OK);
159
160 status = smb_raw_unlink(cli->tree, &io);
161 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
162
163
164 done:
165 smb_raw_exit(cli->session);
166 smbcli_deltree(cli->tree, BASEDIR);
167 return ret;
168 }
169
170
171 /*
172 test delete on close
173 */
test_delete_on_close(struct smbcli_state * cli,TALLOC_CTX * mem_ctx)174 static BOOL test_delete_on_close(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
175 {
176 union smb_open op;
177 union smb_unlink io;
178 struct smb_rmdir dio;
179 NTSTATUS status;
180 BOOL ret = True;
181 int fnum, fnum2;
182 const char *fname = BASEDIR "\\test.txt";
183 const char *dname = BASEDIR "\\test.dir";
184 const char *inside = BASEDIR "\\test.dir\\test.txt";
185 union smb_setfileinfo sfinfo;
186
187 if (!torture_setup_dir(cli, BASEDIR)) {
188 return False;
189 }
190
191 dio.in.path = dname;
192
193 io.unlink.in.pattern = fname;
194 io.unlink.in.attrib = 0;
195 status = smb_raw_unlink(cli->tree, &io);
196 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
197
198 printf("Testing with delete_on_close 0\n");
199 fnum = create_complex_file(cli, mem_ctx, fname);
200
201 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
202 sfinfo.disposition_info.in.file.fnum = fnum;
203 sfinfo.disposition_info.in.delete_on_close = 0;
204 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
205 CHECK_STATUS(status, NT_STATUS_OK);
206
207 smbcli_close(cli->tree, fnum);
208
209 status = smb_raw_unlink(cli->tree, &io);
210 CHECK_STATUS(status, NT_STATUS_OK);
211
212 printf("Testing with delete_on_close 1\n");
213 fnum = create_complex_file(cli, mem_ctx, fname);
214 sfinfo.disposition_info.in.file.fnum = fnum;
215 sfinfo.disposition_info.in.delete_on_close = 1;
216 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
217 CHECK_STATUS(status, NT_STATUS_OK);
218
219 smbcli_close(cli->tree, fnum);
220
221 status = smb_raw_unlink(cli->tree, &io);
222 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
223
224
225 printf("Testing with directory and delete_on_close 0\n");
226 status = create_directory_handle(cli->tree, dname, &fnum);
227 CHECK_STATUS(status, NT_STATUS_OK);
228
229 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
230 sfinfo.disposition_info.in.file.fnum = fnum;
231 sfinfo.disposition_info.in.delete_on_close = 0;
232 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
233 CHECK_STATUS(status, NT_STATUS_OK);
234
235 smbcli_close(cli->tree, fnum);
236
237 status = smb_raw_rmdir(cli->tree, &dio);
238 CHECK_STATUS(status, NT_STATUS_OK);
239
240 printf("Testing with directory delete_on_close 1\n");
241 status = create_directory_handle(cli->tree, dname, &fnum);
242 CHECK_STATUS(status, NT_STATUS_OK);
243
244 sfinfo.disposition_info.in.file.fnum = fnum;
245 sfinfo.disposition_info.in.delete_on_close = 1;
246 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
247 CHECK_STATUS(status, NT_STATUS_OK);
248
249 smbcli_close(cli->tree, fnum);
250
251 status = smb_raw_rmdir(cli->tree, &dio);
252 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
253
254
255 printf("Testing with non-empty directory delete_on_close\n");
256 status = create_directory_handle(cli->tree, dname, &fnum);
257 CHECK_STATUS(status, NT_STATUS_OK);
258
259 fnum2 = create_complex_file(cli, mem_ctx, inside);
260
261 sfinfo.disposition_info.in.file.fnum = fnum;
262 sfinfo.disposition_info.in.delete_on_close = 1;
263 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
264 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
265
266 sfinfo.disposition_info.in.file.fnum = fnum2;
267 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
268 CHECK_STATUS(status, NT_STATUS_OK);
269
270 sfinfo.disposition_info.in.file.fnum = fnum;
271 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
272 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
273
274 smbcli_close(cli->tree, fnum2);
275
276 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
277 CHECK_STATUS(status, NT_STATUS_OK);
278
279 smbcli_close(cli->tree, fnum);
280
281 status = smb_raw_rmdir(cli->tree, &dio);
282 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
283
284 printf("Testing open dir with delete_on_close\n");
285 status = create_directory_handle(cli->tree, dname, &fnum);
286 CHECK_STATUS(status, NT_STATUS_OK);
287
288 smbcli_close(cli->tree, fnum);
289 fnum2 = create_complex_file(cli, mem_ctx, inside);
290 smbcli_close(cli->tree, fnum2);
291
292 op.generic.level = RAW_OPEN_NTCREATEX;
293 op.ntcreatex.in.root_fid = 0;
294 op.ntcreatex.in.flags = 0;
295 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
296 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
297 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
298 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
299 op.ntcreatex.in.alloc_size = 0;
300 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
301 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
302 op.ntcreatex.in.security_flags = 0;
303 op.ntcreatex.in.fname = dname;
304
305 status = smb_raw_open(cli->tree, mem_ctx, &op);
306 CHECK_STATUS(status, NT_STATUS_OK);
307 fnum = op.ntcreatex.out.file.fnum;
308
309 smbcli_close(cli->tree, fnum);
310
311 status = smb_raw_rmdir(cli->tree, &dio);
312 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
313
314 smbcli_deltree(cli->tree, dname);
315
316 printf("Testing double open dir with second delete_on_close\n");
317 status = create_directory_handle(cli->tree, dname, &fnum);
318 CHECK_STATUS(status, NT_STATUS_OK);
319 smbcli_close(cli->tree, fnum);
320
321 fnum2 = create_complex_file(cli, mem_ctx, inside);
322 smbcli_close(cli->tree, fnum2);
323
324 op.generic.level = RAW_OPEN_NTCREATEX;
325 op.ntcreatex.in.root_fid = 0;
326 op.ntcreatex.in.flags = 0;
327 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
328 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
329 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
330 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
331 op.ntcreatex.in.alloc_size = 0;
332 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
333 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
334 op.ntcreatex.in.security_flags = 0;
335 op.ntcreatex.in.fname = dname;
336
337 status = smb_raw_open(cli->tree, mem_ctx, &op);
338 CHECK_STATUS(status, NT_STATUS_OK);
339 fnum2 = op.ntcreatex.out.file.fnum;
340
341 smbcli_close(cli->tree, fnum2);
342
343 status = smb_raw_rmdir(cli->tree, &dio);
344 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
345
346 smbcli_deltree(cli->tree, dname);
347
348 printf("Testing pre-existing open dir with second delete_on_close\n");
349 status = create_directory_handle(cli->tree, dname, &fnum);
350 CHECK_STATUS(status, NT_STATUS_OK);
351
352 smbcli_close(cli->tree, fnum);
353
354 fnum = create_complex_file(cli, mem_ctx, inside);
355 smbcli_close(cli->tree, fnum);
356
357 /* we have a dir with a file in it, no handles open */
358
359 op.generic.level = RAW_OPEN_NTCREATEX;
360 op.ntcreatex.in.root_fid = 0;
361 op.ntcreatex.in.flags = 0;
362 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
363 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
364 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
365 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
366 op.ntcreatex.in.alloc_size = 0;
367 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
368 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
369 op.ntcreatex.in.security_flags = 0;
370 op.ntcreatex.in.fname = dname;
371
372 status = smb_raw_open(cli->tree, mem_ctx, &op);
373 CHECK_STATUS(status, NT_STATUS_OK);
374 fnum = op.ntcreatex.out.file.fnum;
375
376 /* open without delete on close */
377 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
378 status = smb_raw_open(cli->tree, mem_ctx, &op);
379 CHECK_STATUS(status, NT_STATUS_OK);
380 fnum2 = op.ntcreatex.out.file.fnum;
381
382 /* close 2nd file handle */
383 smbcli_close(cli->tree, fnum2);
384
385 status = smb_raw_rmdir(cli->tree, &dio);
386 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
387
388
389 smbcli_close(cli->tree, fnum);
390
391 status = smb_raw_rmdir(cli->tree, &dio);
392 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
393
394 done:
395 smb_raw_exit(cli->session);
396 smbcli_deltree(cli->tree, BASEDIR);
397 return ret;
398 }
399
400
401 /*
402 basic testing of unlink calls
403 */
torture_raw_unlink(struct torture_context * torture)404 BOOL torture_raw_unlink(struct torture_context *torture)
405 {
406 struct smbcli_state *cli;
407 BOOL ret = True;
408 TALLOC_CTX *mem_ctx;
409
410 if (!torture_open_connection(&cli, 0)) {
411 return False;
412 }
413
414 mem_ctx = talloc_init("torture_raw_unlink");
415
416 ret &= test_unlink(cli, mem_ctx);
417 ret &= test_delete_on_close(cli, mem_ctx);
418
419 torture_close_connection(cli);
420 talloc_free(mem_ctx);
421 return ret;
422 }
423