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