1 /*
2    Unix SMB/CIFS implementation.
3    rename 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 "libcli/raw/libcliraw.h"
24 #include "libcli/libcli.h"
25 #include "torture/util.h"
26 
27 #define CHECK_STATUS(status, correct) do { \
28 	if (!NT_STATUS_EQUAL(status, correct)) { \
29 		printf("(%s) Incorrect status %s - should be %s\n", \
30 		       __location__, nt_errstr(status), nt_errstr(correct)); \
31 		ret = False; \
32 		goto done; \
33 	}} while (0)
34 
35 #define CHECK_VALUE(v, correct) do { \
36 	if ((v) != (correct)) { \
37 		printf("(%s) Incorrect %s %d - should be %d\n", \
38 		       __location__, #v, (int)v, (int)correct); \
39 		ret = False; \
40 	}} while (0)
41 
42 #define BASEDIR "\\testrename"
43 
44 /*
45   test SMBmv ops
46 */
test_mv(struct smbcli_state * cli,TALLOC_CTX * mem_ctx)47 static BOOL test_mv(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
48 {
49 	union smb_rename io;
50 	NTSTATUS status;
51 	BOOL ret = True;
52 	int fnum = -1;
53 	const char *fname1 = BASEDIR "\\test1.txt";
54 	const char *fname2 = BASEDIR "\\test2.txt";
55 	union smb_open op;
56 
57 	printf("Testing SMBmv\n");
58 
59 	if (!torture_setup_dir(cli, BASEDIR)) {
60 		return False;
61 	}
62 
63 	printf("Trying simple rename\n");
64 
65 	op.generic.level = RAW_OPEN_NTCREATEX;
66 	op.ntcreatex.in.root_fid = 0;
67 	op.ntcreatex.in.flags = 0;
68 	op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
69 	op.ntcreatex.in.create_options = 0;
70 	op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
71 	op.ntcreatex.in.share_access =
72 		NTCREATEX_SHARE_ACCESS_READ |
73 		NTCREATEX_SHARE_ACCESS_WRITE;
74 	op.ntcreatex.in.alloc_size = 0;
75 	op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
76 	op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
77 	op.ntcreatex.in.security_flags = 0;
78 	op.ntcreatex.in.fname = fname1;
79 
80 	status = smb_raw_open(cli->tree, mem_ctx, &op);
81 	CHECK_STATUS(status, NT_STATUS_OK);
82 	fnum = op.ntcreatex.out.file.fnum;
83 
84 	io.generic.level = RAW_RENAME_RENAME;
85 	io.rename.in.pattern1 = fname1;
86 	io.rename.in.pattern2 = fname2;
87 	io.rename.in.attrib = 0;
88 
89 	printf("trying rename while first file open\n");
90 	status = smb_raw_rename(cli->tree, &io);
91 	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
92 
93 	smbcli_close(cli->tree, fnum);
94 
95 	op.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
96 	op.ntcreatex.in.share_access =
97 		NTCREATEX_SHARE_ACCESS_DELETE |
98 		NTCREATEX_SHARE_ACCESS_READ |
99 		NTCREATEX_SHARE_ACCESS_WRITE;
100 	status = smb_raw_open(cli->tree, mem_ctx, &op);
101 	CHECK_STATUS(status, NT_STATUS_OK);
102 	fnum = op.ntcreatex.out.file.fnum;
103 
104 	printf("trying rename while first file open with SHARE_ACCESS_DELETE\n");
105 	status = smb_raw_rename(cli->tree, &io);
106 	CHECK_STATUS(status, NT_STATUS_OK);
107 
108 	io.rename.in.pattern1 = fname2;
109 	io.rename.in.pattern2 = fname1;
110 	status = smb_raw_rename(cli->tree, &io);
111 	CHECK_STATUS(status, NT_STATUS_OK);
112 
113 	io.rename.in.pattern1 = fname1;
114 	io.rename.in.pattern2 = fname2;
115 
116 	printf("trying rename while not open\n");
117 	smb_raw_exit(cli->session);
118 	status = smb_raw_rename(cli->tree, &io);
119 	CHECK_STATUS(status, NT_STATUS_OK);
120 
121 	printf("Trying self rename\n");
122 	io.rename.in.pattern1 = fname2;
123 	io.rename.in.pattern2 = fname2;
124 	status = smb_raw_rename(cli->tree, &io);
125 	CHECK_STATUS(status, NT_STATUS_OK);
126 
127 	io.rename.in.pattern1 = fname1;
128 	io.rename.in.pattern2 = fname1;
129 	status = smb_raw_rename(cli->tree, &io);
130 	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
131 
132 
133 	printf("trying wildcard rename\n");
134 	io.rename.in.pattern1 = BASEDIR "\\*.txt";
135 	io.rename.in.pattern2 = fname1;
136 
137 	status = smb_raw_rename(cli->tree, &io);
138 	CHECK_STATUS(status, NT_STATUS_OK);
139 
140 	printf("and again\n");
141 	status = smb_raw_rename(cli->tree, &io);
142 	CHECK_STATUS(status, NT_STATUS_OK);
143 
144 	printf("Trying extension change\n");
145 	io.rename.in.pattern1 = BASEDIR "\\*.txt";
146 	io.rename.in.pattern2 = BASEDIR "\\*.bak";
147 	status = smb_raw_rename(cli->tree, &io);
148 	CHECK_STATUS(status, NT_STATUS_OK);
149 
150 	status = smb_raw_rename(cli->tree, &io);
151 	CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
152 
153 	printf("Checking attrib handling\n");
154 	torture_set_file_attribute(cli->tree, BASEDIR "\\test1.bak", FILE_ATTRIBUTE_HIDDEN);
155 	io.rename.in.pattern1 = BASEDIR "\\test1.bak";
156 	io.rename.in.pattern2 = BASEDIR "\\*.txt";
157 	io.rename.in.attrib = 0;
158 	status = smb_raw_rename(cli->tree, &io);
159 	CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
160 
161 	io.rename.in.attrib = FILE_ATTRIBUTE_HIDDEN;
162 	status = smb_raw_rename(cli->tree, &io);
163 	CHECK_STATUS(status, NT_STATUS_OK);
164 
165 done:
166 	smbcli_close(cli->tree, fnum);
167 	smb_raw_exit(cli->session);
168 	smbcli_deltree(cli->tree, BASEDIR);
169 	return ret;
170 }
171 
172 
173 
174 /*
175   test SMBntrename ops
176 */
test_ntrename(struct smbcli_state * cli,TALLOC_CTX * mem_ctx)177 static BOOL test_ntrename(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
178 {
179 	union smb_rename io;
180 	NTSTATUS status;
181 	BOOL ret = True;
182 	int fnum, i;
183 	const char *fname1 = BASEDIR "\\test1.txt";
184 	const char *fname2 = BASEDIR "\\test2.txt";
185 	union smb_fileinfo finfo;
186 
187 	printf("Testing SMBntrename\n");
188 
189 	if (!torture_setup_dir(cli, BASEDIR)) {
190 		return False;
191 	}
192 
193 	printf("Trying simple rename\n");
194 
195 	fnum = create_complex_file(cli, mem_ctx, fname1);
196 
197 	io.generic.level = RAW_RENAME_NTRENAME;
198 	io.ntrename.in.old_name = fname1;
199 	io.ntrename.in.new_name = fname2;
200 	io.ntrename.in.attrib = 0;
201 	io.ntrename.in.cluster_size = 0;
202 	io.ntrename.in.flags = RENAME_FLAG_RENAME;
203 
204 	status = smb_raw_rename(cli->tree, &io);
205 	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
206 
207 	smb_raw_exit(cli->session);
208 	status = smb_raw_rename(cli->tree, &io);
209 	CHECK_STATUS(status, NT_STATUS_OK);
210 
211 	printf("Trying self rename\n");
212 	io.ntrename.in.old_name = fname2;
213 	io.ntrename.in.new_name = fname2;
214 	status = smb_raw_rename(cli->tree, &io);
215 	CHECK_STATUS(status, NT_STATUS_OK);
216 
217 	io.ntrename.in.old_name = fname1;
218 	io.ntrename.in.new_name = fname1;
219 	status = smb_raw_rename(cli->tree, &io);
220 	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
221 
222 	printf("trying wildcard rename\n");
223 	io.ntrename.in.old_name = BASEDIR "\\*.txt";
224 	io.ntrename.in.new_name = fname1;
225 
226 	status = smb_raw_rename(cli->tree, &io);
227 	CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
228 
229 	printf("Checking attrib handling\n");
230 	torture_set_file_attribute(cli->tree, fname2, FILE_ATTRIBUTE_HIDDEN);
231 	io.ntrename.in.old_name = fname2;
232 	io.ntrename.in.new_name = fname1;
233 	io.ntrename.in.attrib = 0;
234 	status = smb_raw_rename(cli->tree, &io);
235 	CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
236 
237 	io.ntrename.in.attrib = FILE_ATTRIBUTE_HIDDEN;
238 	status = smb_raw_rename(cli->tree, &io);
239 	CHECK_STATUS(status, NT_STATUS_OK);
240 
241 	torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
242 
243 	printf("Checking hard link\n");
244 	io.ntrename.in.old_name = fname1;
245 	io.ntrename.in.new_name = fname2;
246 	io.ntrename.in.attrib = 0;
247 	io.ntrename.in.flags = RENAME_FLAG_HARD_LINK;
248 	status = smb_raw_rename(cli->tree, &io);
249 	CHECK_STATUS(status, NT_STATUS_OK);
250 
251 	torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
252 
253 	finfo.generic.level = RAW_FILEINFO_ALL_INFO;
254 	finfo.generic.in.file.path = fname2;
255 	status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
256 	CHECK_STATUS(status, NT_STATUS_OK);
257 	CHECK_VALUE(finfo.all_info.out.nlink, 2);
258 	CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
259 
260 	finfo.generic.in.file.path = fname1;
261 	status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
262 	CHECK_STATUS(status, NT_STATUS_OK);
263 	CHECK_VALUE(finfo.all_info.out.nlink, 2);
264 	CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
265 
266 	torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
267 
268 	smbcli_unlink(cli->tree, fname2);
269 
270 	finfo.generic.in.file.path = fname1;
271 	status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
272 	CHECK_STATUS(status, NT_STATUS_OK);
273 	CHECK_VALUE(finfo.all_info.out.nlink, 1);
274 	CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
275 
276 	printf("Checking copy\n");
277 	io.ntrename.in.old_name = fname1;
278 	io.ntrename.in.new_name = fname2;
279 	io.ntrename.in.attrib = 0;
280 	io.ntrename.in.flags = RENAME_FLAG_COPY;
281 	status = smb_raw_rename(cli->tree, &io);
282 	CHECK_STATUS(status, NT_STATUS_OK);
283 
284 	finfo.generic.level = RAW_FILEINFO_ALL_INFO;
285 	finfo.generic.in.file.path = fname1;
286 	status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
287 	CHECK_STATUS(status, NT_STATUS_OK);
288 	CHECK_VALUE(finfo.all_info.out.nlink, 1);
289 	CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
290 
291 	finfo.generic.level = RAW_FILEINFO_ALL_INFO;
292 	finfo.generic.in.file.path = fname2;
293 	status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
294 	CHECK_STATUS(status, NT_STATUS_OK);
295 	CHECK_VALUE(finfo.all_info.out.nlink, 1);
296 	CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
297 
298 	torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
299 
300 	finfo.generic.level = RAW_FILEINFO_ALL_INFO;
301 	finfo.generic.in.file.path = fname2;
302 	status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
303 	CHECK_STATUS(status, NT_STATUS_OK);
304 	CHECK_VALUE(finfo.all_info.out.nlink, 1);
305 	CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
306 
307 	finfo.generic.in.file.path = fname1;
308 	status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
309 	CHECK_STATUS(status, NT_STATUS_OK);
310 	CHECK_VALUE(finfo.all_info.out.nlink, 1);
311 	CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
312 
313 	torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
314 
315 	smbcli_unlink(cli->tree, fname2);
316 
317 	finfo.generic.in.file.path = fname1;
318 	status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
319 	CHECK_STATUS(status, NT_STATUS_OK);
320 	CHECK_VALUE(finfo.all_info.out.nlink, 1);
321 
322 	printf("Checking invalid flags\n");
323 	io.ntrename.in.old_name = fname1;
324 	io.ntrename.in.new_name = fname2;
325 	io.ntrename.in.attrib = 0;
326 	io.ntrename.in.flags = 0;
327 	status = smb_raw_rename(cli->tree, &io);
328 	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
329 
330 	io.ntrename.in.flags = 300;
331 	status = smb_raw_rename(cli->tree, &io);
332 	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
333 
334 	io.ntrename.in.flags = 0x106;
335 	status = smb_raw_rename(cli->tree, &io);
336 	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
337 
338 	printf("Checking unknown field\n");
339 	io.ntrename.in.old_name = fname1;
340 	io.ntrename.in.new_name = fname2;
341 	io.ntrename.in.attrib = 0;
342 	io.ntrename.in.flags = RENAME_FLAG_RENAME;
343 	io.ntrename.in.cluster_size = 0xff;
344 	status = smb_raw_rename(cli->tree, &io);
345 	CHECK_STATUS(status, NT_STATUS_OK);
346 
347 	printf("Trying RENAME_FLAG_MOVE_CLUSTER_INFORMATION\n");
348 
349 	io.ntrename.in.old_name = fname2;
350 	io.ntrename.in.new_name = fname1;
351 	io.ntrename.in.attrib = 0;
352 	io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION;
353 	io.ntrename.in.cluster_size = 1;
354 	status = smb_raw_rename(cli->tree, &io);
355 	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
356 
357 	io.ntrename.in.flags = RENAME_FLAG_COPY;
358 	status = smb_raw_rename(cli->tree, &io);
359 	CHECK_STATUS(status, NT_STATUS_OK);
360 
361 #if 0
362 	{
363 		char buf[16384];
364 		fnum = smbcli_open(cli->tree, fname1, O_RDWR, DENY_NONE);
365 		memset(buf, 1, sizeof(buf));
366 		smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
367 		smbcli_close(cli->tree, fnum);
368 
369 		fnum = smbcli_open(cli->tree, fname2, O_RDWR, DENY_NONE);
370 		memset(buf, 1, sizeof(buf));
371 		smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf)-1);
372 		smbcli_close(cli->tree, fnum);
373 
374 		torture_all_info(cli->tree, fname1);
375 		torture_all_info(cli->tree, fname2);
376 	}
377 
378 
379 	io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION;
380 	status = smb_raw_rename(cli->tree, &io);
381 	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
382 
383 	for (i=0;i<20000;i++) {
384 		io.ntrename.in.cluster_size = i;
385 		status = smb_raw_rename(cli->tree, &io);
386 		if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
387 			printf("i=%d status=%s\n", i, nt_errstr(status));
388 		}
389 	}
390 #endif
391 
392 	printf("Checking other flags\n");
393 
394 	for (i=0;i<0xFFF;i++) {
395 		if (i == RENAME_FLAG_RENAME ||
396 		    i == RENAME_FLAG_HARD_LINK ||
397 		    i == RENAME_FLAG_COPY) {
398 			continue;
399 		}
400 
401 		io.ntrename.in.old_name = fname2;
402 		io.ntrename.in.new_name = fname1;
403 		io.ntrename.in.flags = i;
404 		io.ntrename.in.attrib = 0;
405 		io.ntrename.in.cluster_size = 0;
406 		status = smb_raw_rename(cli->tree, &io);
407 		if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
408 			printf("flags=0x%x status=%s\n", i, nt_errstr(status));
409 		}
410 	}
411 
412 done:
413 	smb_raw_exit(cli->session);
414 	smbcli_deltree(cli->tree, BASEDIR);
415 	return ret;
416 }
417 
418 
419 /*
420    basic testing of rename calls
421 */
torture_raw_rename(struct torture_context * torture)422 BOOL torture_raw_rename(struct torture_context *torture)
423 {
424 	struct smbcli_state *cli;
425 	BOOL ret = True;
426 	TALLOC_CTX *mem_ctx;
427 
428 	if (!torture_open_connection(&cli, 0)) {
429 		return False;
430 	}
431 
432 	mem_ctx = talloc_init("torture_raw_rename");
433 
434 	if (!test_mv(cli, mem_ctx)) {
435 		ret = False;
436 	}
437 
438 	if (!test_ntrename(cli, mem_ctx)) {
439 		ret = False;
440 	}
441 
442 	torture_close_connection(cli);
443 	talloc_free(mem_ctx);
444 	return ret;
445 }
446