Convert mtime from a time_t to a struct timespec.
[Samba.git] / source4 / torture / raw / samba3misc.c
bloba603111fa2d2518d07932bd58456c1908d3a0e70
1 /*
2 Unix SMB/CIFS implementation.
3 Test some misc Samba3 code paths
4 Copyright (C) Volker Lendecke 2006
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 3 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "torture/torture.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/raw/raw_proto.h"
24 #include "system/time.h"
25 #include "system/filesys.h"
26 #include "libcli/libcli.h"
27 #include "torture/util.h"
28 #include "lib/events/events.h"
29 #include "param/param.h"
31 #define CHECK_STATUS(status, correct) do { \
32 if (!NT_STATUS_EQUAL(status, correct)) { \
33 printf("(%s) Incorrect status %s - should be %s\n", \
34 __location__, nt_errstr(status), nt_errstr(correct)); \
35 ret = false; \
36 } \
37 } while (0)
39 bool torture_samba3_checkfsp(struct torture_context *torture)
41 struct smbcli_state *cli;
42 const char *fname = "test.txt";
43 const char *dirname = "testdir";
44 int fnum;
45 NTSTATUS status;
46 bool ret = true;
47 TALLOC_CTX *mem_ctx;
48 ssize_t nread;
49 char buf[16];
50 struct smbcli_tree *tree2;
52 if ((mem_ctx = talloc_init("torture_samba3_checkfsp")) == NULL) {
53 d_printf("talloc_init failed\n");
54 return false;
57 if (!torture_open_connection_share(
58 torture, &cli, torture, torture_setting_string(torture, "host", NULL),
59 torture_setting_string(torture, "share", NULL), torture->ev)) {
60 d_printf("torture_open_connection_share failed\n");
61 ret = false;
62 goto done;
65 smbcli_deltree(cli->tree, dirname);
67 status = torture_second_tcon(torture, cli->session,
68 torture_setting_string(torture, "share", NULL),
69 &tree2);
70 CHECK_STATUS(status, NT_STATUS_OK);
71 if (!NT_STATUS_IS_OK(status))
72 goto done;
74 /* Try a read on an invalid FID */
76 nread = smbcli_read(cli->tree, 4711, buf, 0, sizeof(buf));
77 CHECK_STATUS(smbcli_nt_error(cli->tree), NT_STATUS_INVALID_HANDLE);
79 /* Try a read on a directory handle */
81 status = smbcli_mkdir(cli->tree, dirname);
82 if (!NT_STATUS_IS_OK(status)) {
83 d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status));
84 ret = false;
85 goto done;
88 /* Open the directory */
90 union smb_open io;
91 io.generic.level = RAW_OPEN_NTCREATEX;
92 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
93 io.ntcreatex.in.root_fid.fnum = 0;
94 io.ntcreatex.in.security_flags = 0;
95 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
96 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
97 io.ntcreatex.in.alloc_size = 0;
98 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
99 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
100 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
101 io.ntcreatex.in.create_options = 0;
102 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
103 io.ntcreatex.in.fname = dirname;
104 status = smb_raw_open(cli->tree, mem_ctx, &io);
105 if (!NT_STATUS_IS_OK(status)) {
106 d_printf("smb_open on the directory failed: %s\n",
107 nt_errstr(status));
108 ret = false;
109 goto done;
111 fnum = io.ntcreatex.out.file.fnum;
114 /* Try a read on the directory */
116 nread = smbcli_read(cli->tree, fnum, buf, 0, sizeof(buf));
117 if (nread >= 0) {
118 d_printf("smbcli_read on a directory succeeded, expected "
119 "failure\n");
120 ret = false;
123 CHECK_STATUS(smbcli_nt_error(cli->tree),
124 NT_STATUS_INVALID_DEVICE_REQUEST);
126 /* Same test on the second tcon */
128 nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf));
129 if (nread >= 0) {
130 d_printf("smbcli_read on a directory succeeded, expected "
131 "failure\n");
132 ret = false;
135 CHECK_STATUS(smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE);
137 smbcli_close(cli->tree, fnum);
139 /* Try a normal file read on a second tcon */
141 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
142 if (fnum == -1) {
143 d_printf("Failed to create %s - %s\n", fname,
144 smbcli_errstr(cli->tree));
145 ret = false;
146 goto done;
149 nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf));
150 CHECK_STATUS(smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE);
152 smbcli_close(cli->tree, fnum);
154 done:
155 smbcli_deltree(cli->tree, dirname);
156 torture_close_connection(cli);
157 talloc_free(mem_ctx);
159 return ret;
162 static NTSTATUS raw_smbcli_open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum)
164 union smb_open open_parms;
165 unsigned int openfn=0;
166 unsigned int accessmode=0;
167 TALLOC_CTX *mem_ctx;
168 NTSTATUS status;
170 mem_ctx = talloc_init("raw_open");
171 if (!mem_ctx) return NT_STATUS_NO_MEMORY;
173 if (flags & O_CREAT) {
174 openfn |= OPENX_OPEN_FUNC_CREATE;
176 if (!(flags & O_EXCL)) {
177 if (flags & O_TRUNC) {
178 openfn |= OPENX_OPEN_FUNC_TRUNC;
179 } else {
180 openfn |= OPENX_OPEN_FUNC_OPEN;
184 accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
186 if ((flags & O_ACCMODE) == O_RDWR) {
187 accessmode |= OPENX_MODE_ACCESS_RDWR;
188 } else if ((flags & O_ACCMODE) == O_WRONLY) {
189 accessmode |= OPENX_MODE_ACCESS_WRITE;
190 } else if ((flags & O_ACCMODE) == O_RDONLY) {
191 accessmode |= OPENX_MODE_ACCESS_READ;
194 #if defined(O_SYNC)
195 if ((flags & O_SYNC) == O_SYNC) {
196 accessmode |= OPENX_MODE_WRITE_THRU;
198 #endif
200 if (share_mode == DENY_FCB) {
201 accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
204 open_parms.openx.level = RAW_OPEN_OPENX;
205 open_parms.openx.in.flags = 0;
206 open_parms.openx.in.open_mode = accessmode;
207 open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
208 open_parms.openx.in.file_attrs = 0;
209 open_parms.openx.in.write_time = 0;
210 open_parms.openx.in.open_func = openfn;
211 open_parms.openx.in.size = 0;
212 open_parms.openx.in.timeout = 0;
213 open_parms.openx.in.fname = fname;
215 status = smb_raw_open(tree, mem_ctx, &open_parms);
216 talloc_free(mem_ctx);
218 if (fnum && NT_STATUS_IS_OK(status)) {
219 *fnum = open_parms.openx.out.file.fnum;
222 return status;
225 static NTSTATUS raw_smbcli_t2open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum)
227 union smb_open io;
228 unsigned int openfn=0;
229 unsigned int accessmode=0;
230 TALLOC_CTX *mem_ctx;
231 NTSTATUS status;
233 mem_ctx = talloc_init("raw_t2open");
234 if (!mem_ctx) return NT_STATUS_NO_MEMORY;
236 if (flags & O_CREAT) {
237 openfn |= OPENX_OPEN_FUNC_CREATE;
239 if (!(flags & O_EXCL)) {
240 if (flags & O_TRUNC) {
241 openfn |= OPENX_OPEN_FUNC_TRUNC;
242 } else {
243 openfn |= OPENX_OPEN_FUNC_OPEN;
247 accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
249 if ((flags & O_ACCMODE) == O_RDWR) {
250 accessmode |= OPENX_MODE_ACCESS_RDWR;
251 } else if ((flags & O_ACCMODE) == O_WRONLY) {
252 accessmode |= OPENX_MODE_ACCESS_WRITE;
253 } else if ((flags & O_ACCMODE) == O_RDONLY) {
254 accessmode |= OPENX_MODE_ACCESS_READ;
257 #if defined(O_SYNC)
258 if ((flags & O_SYNC) == O_SYNC) {
259 accessmode |= OPENX_MODE_WRITE_THRU;
261 #endif
263 if (share_mode == DENY_FCB) {
264 accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
267 memset(&io, '\0', sizeof(io));
268 io.t2open.level = RAW_OPEN_T2OPEN;
269 io.t2open.in.flags = 0;
270 io.t2open.in.open_mode = accessmode;
271 io.t2open.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
272 io.t2open.in.file_attrs = 0;
273 io.t2open.in.write_time = 0;
274 io.t2open.in.open_func = openfn;
275 io.t2open.in.size = 0;
276 io.t2open.in.timeout = 0;
277 io.t2open.in.fname = fname;
279 io.t2open.in.num_eas = 1;
280 io.t2open.in.eas = talloc_array(mem_ctx, struct ea_struct, io.t2open.in.num_eas);
281 io.t2open.in.eas[0].flags = 0;
282 io.t2open.in.eas[0].name.s = ".CLASSINFO";
283 io.t2open.in.eas[0].value = data_blob_talloc(mem_ctx, "first value", 11);
285 status = smb_raw_open(tree, mem_ctx, &io);
286 talloc_free(mem_ctx);
288 if (fnum && NT_STATUS_IS_OK(status)) {
289 *fnum = io.openx.out.file.fnum;
292 return status;
295 static NTSTATUS raw_smbcli_ntcreate(struct smbcli_tree *tree, const char *fname, int *fnum)
297 union smb_open io;
298 TALLOC_CTX *mem_ctx;
299 NTSTATUS status;
301 mem_ctx = talloc_init("raw_t2open");
302 if (!mem_ctx) return NT_STATUS_NO_MEMORY;
304 memset(&io, '\0', sizeof(io));
305 io.generic.level = RAW_OPEN_NTCREATEX;
306 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
307 io.ntcreatex.in.root_fid.fnum = 0;
308 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
309 io.ntcreatex.in.alloc_size = 0;
310 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
311 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
312 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
313 io.ntcreatex.in.create_options = 0;
314 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
315 io.ntcreatex.in.security_flags = 0;
316 io.ntcreatex.in.fname = fname;
318 status = smb_raw_open(tree, mem_ctx, &io);
319 talloc_free(mem_ctx);
321 if (fnum && NT_STATUS_IS_OK(status)) {
322 *fnum = io.openx.out.file.fnum;
325 return status;
329 bool torture_samba3_badpath(struct torture_context *torture)
331 struct smbcli_state *cli_nt;
332 struct smbcli_state *cli_dos;
333 const char *fname = "test.txt";
334 const char *fname1 = "test1.txt";
335 const char *dirname = "testdir";
336 char *fpath;
337 char *fpath1;
338 int fnum;
339 NTSTATUS status;
340 bool ret = true;
341 TALLOC_CTX *mem_ctx;
342 bool nt_status_support;
344 if (!(mem_ctx = talloc_init("torture_samba3_badpath"))) {
345 d_printf("talloc_init failed\n");
346 return false;
349 nt_status_support = lpcfg_nt_status_support(torture->lp_ctx);
351 if (!lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "yes")) {
352 printf("Could not set 'nt status support = yes'\n");
353 goto fail;
356 if (!torture_open_connection(&cli_nt, torture, 0)) {
357 goto fail;
360 if (!lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "no")) {
361 printf("Could not set 'nt status support = yes'\n");
362 goto fail;
365 if (!torture_open_connection(&cli_dos, torture, 1)) {
366 goto fail;
369 if (!lpcfg_set_cmdline(torture->lp_ctx, "nt status support",
370 nt_status_support ? "yes":"no")) {
371 printf("Could not reset 'nt status support = yes'");
372 goto fail;
375 smbcli_deltree(cli_nt->tree, dirname);
377 status = smbcli_mkdir(cli_nt->tree, dirname);
378 if (!NT_STATUS_IS_OK(status)) {
379 d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status));
380 ret = false;
381 goto done;
384 status = smbcli_chkpath(cli_nt->tree, dirname);
385 CHECK_STATUS(status, NT_STATUS_OK);
387 status = smbcli_chkpath(cli_nt->tree,
388 talloc_asprintf(mem_ctx, "%s\\bla", dirname));
389 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
391 status = smbcli_chkpath(cli_dos->tree,
392 talloc_asprintf(mem_ctx, "%s\\bla", dirname));
393 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
395 status = smbcli_chkpath(cli_nt->tree,
396 talloc_asprintf(mem_ctx, "%s\\bla\\blub",
397 dirname));
398 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND);
399 status = smbcli_chkpath(cli_dos->tree,
400 talloc_asprintf(mem_ctx, "%s\\bla\\blub",
401 dirname));
402 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
404 if (!(fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname))) {
405 goto fail;
407 fnum = smbcli_open(cli_nt->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
408 if (fnum == -1) {
409 d_printf("Could not create file %s: %s\n", fpath,
410 smbcli_errstr(cli_nt->tree));
411 goto fail;
413 smbcli_close(cli_nt->tree, fnum);
415 if (!(fpath1 = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname1))) {
416 goto fail;
418 fnum = smbcli_open(cli_nt->tree, fpath1, O_RDWR | O_CREAT, DENY_NONE);
419 if (fnum == -1) {
420 d_printf("Could not create file %s: %s\n", fpath1,
421 smbcli_errstr(cli_nt->tree));
422 goto fail;
424 smbcli_close(cli_nt->tree, fnum);
427 * Do a whole bunch of error code checks on chkpath
430 status = smbcli_chkpath(cli_nt->tree, fpath);
431 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
432 status = smbcli_chkpath(cli_dos->tree, fpath);
433 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
435 status = smbcli_chkpath(cli_nt->tree, "..");
436 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
437 status = smbcli_chkpath(cli_dos->tree, "..");
438 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
440 status = smbcli_chkpath(cli_nt->tree, ".");
441 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
442 status = smbcli_chkpath(cli_dos->tree, ".");
443 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
445 status = smbcli_chkpath(cli_nt->tree, "\t");
446 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
447 status = smbcli_chkpath(cli_dos->tree, "\t");
448 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
450 status = smbcli_chkpath(cli_nt->tree, "\t\\bla");
451 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
452 status = smbcli_chkpath(cli_dos->tree, "\t\\bla");
453 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
455 status = smbcli_chkpath(cli_nt->tree, "<");
456 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
457 status = smbcli_chkpath(cli_dos->tree, "<");
458 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
460 status = smbcli_chkpath(cli_nt->tree, "<\\bla");
461 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
462 status = smbcli_chkpath(cli_dos->tree, "<\\bla");
463 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
466 * .... And the same gang against getatr. Note that the DOS error codes
467 * differ....
470 status = smbcli_getatr(cli_nt->tree, fpath, NULL, NULL, NULL);
471 CHECK_STATUS(status, NT_STATUS_OK);
472 status = smbcli_getatr(cli_dos->tree, fpath, NULL, NULL, NULL);
473 CHECK_STATUS(status, NT_STATUS_OK);
475 status = smbcli_getatr(cli_nt->tree, "..", NULL, NULL, NULL);
476 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
477 status = smbcli_getatr(cli_dos->tree, "..", NULL, NULL, NULL);
478 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
480 status = smbcli_getatr(cli_nt->tree, ".", NULL, NULL, NULL);
481 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
482 status = smbcli_getatr(cli_dos->tree, ".", NULL, NULL, NULL);
483 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
485 status = smbcli_getatr(cli_nt->tree, "\t", NULL, NULL, NULL);
486 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
487 status = smbcli_getatr(cli_dos->tree, "\t", NULL, NULL, NULL);
488 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
490 status = smbcli_getatr(cli_nt->tree, "\t\\bla", NULL, NULL, NULL);
491 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
492 status = smbcli_getatr(cli_dos->tree, "\t\\bla", NULL, NULL, NULL);
493 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
495 status = smbcli_getatr(cli_nt->tree, "<", NULL, NULL, NULL);
496 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
497 status = smbcli_getatr(cli_dos->tree, "<", NULL, NULL, NULL);
498 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
500 status = smbcli_getatr(cli_nt->tree, "<\\bla", NULL, NULL, NULL);
501 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
502 status = smbcli_getatr(cli_dos->tree, "<\\bla", NULL, NULL, NULL);
503 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
505 /* Try the same set with openX. */
507 status = raw_smbcli_open(cli_nt->tree, "..", O_RDONLY, DENY_NONE, NULL);
508 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
509 status = raw_smbcli_open(cli_dos->tree, "..", O_RDONLY, DENY_NONE, NULL);
510 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
512 status = raw_smbcli_open(cli_nt->tree, ".", O_RDONLY, DENY_NONE, NULL);
513 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
514 status = raw_smbcli_open(cli_dos->tree, ".", O_RDONLY, DENY_NONE, NULL);
515 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
517 status = raw_smbcli_open(cli_nt->tree, "\t", O_RDONLY, DENY_NONE, NULL);
518 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
519 status = raw_smbcli_open(cli_dos->tree, "\t", O_RDONLY, DENY_NONE, NULL);
520 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
522 status = raw_smbcli_open(cli_nt->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL);
523 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
524 status = raw_smbcli_open(cli_dos->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL);
525 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
527 status = raw_smbcli_open(cli_nt->tree, "<", O_RDONLY, DENY_NONE, NULL);
528 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
529 status = raw_smbcli_open(cli_dos->tree, "<", O_RDONLY, DENY_NONE, NULL);
530 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
532 status = raw_smbcli_open(cli_nt->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL);
533 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
534 status = raw_smbcli_open(cli_dos->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL);
535 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
537 /* Let's test EEXIST error code mapping. */
538 status = raw_smbcli_open(cli_nt->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
539 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
540 status = raw_smbcli_open(cli_dos->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
541 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRfilexists));
543 status = raw_smbcli_t2open(cli_nt->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
544 if (!NT_STATUS_EQUAL(status, NT_STATUS_EAS_NOT_SUPPORTED)
545 || !torture_setting_bool(torture, "samba3", false)) {
546 /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */
547 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
549 status = raw_smbcli_t2open(cli_dos->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
550 if (!NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS,ERReasnotsupported))
551 || !torture_setting_bool(torture, "samba3", false)) {
552 /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */
553 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRfilexists));
556 status = raw_smbcli_ntcreate(cli_nt->tree, fpath, NULL);
557 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
558 status = raw_smbcli_ntcreate(cli_dos->tree, fpath, NULL);
559 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRfilexists));
561 /* Try the rename test. */
563 union smb_rename io;
564 memset(&io, '\0', sizeof(io));
565 io.rename.in.pattern1 = fpath1;
566 io.rename.in.pattern2 = fpath;
568 /* Try with SMBmv rename. */
569 status = smb_raw_rename(cli_nt->tree, &io);
570 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
571 status = smb_raw_rename(cli_dos->tree, &io);
572 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRrename));
574 /* Try with NT rename. */
575 io.generic.level = RAW_RENAME_NTRENAME;
576 io.ntrename.in.old_name = fpath1;
577 io.ntrename.in.new_name = fpath;
578 io.ntrename.in.attrib = 0;
579 io.ntrename.in.cluster_size = 0;
580 io.ntrename.in.flags = RENAME_FLAG_RENAME;
582 status = smb_raw_rename(cli_nt->tree, &io);
583 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
584 status = smb_raw_rename(cli_dos->tree, &io);
585 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRrename));
588 goto done;
590 fail:
591 ret = false;
593 done:
594 if (cli_nt != NULL) {
595 smbcli_deltree(cli_nt->tree, dirname);
596 torture_close_connection(cli_nt);
598 if (cli_dos != NULL) {
599 torture_close_connection(cli_dos);
601 talloc_free(mem_ctx);
603 return ret;
606 static void count_fn(struct clilist_file_info *info, const char *name,
607 void *private_data)
609 int *counter = (int *)private_data;
610 *counter += 1;
613 bool torture_samba3_caseinsensitive(struct torture_context *torture)
615 struct smbcli_state *cli;
616 TALLOC_CTX *mem_ctx;
617 NTSTATUS status;
618 const char *dirname = "insensitive";
619 const char *ucase_dirname = "InSeNsItIvE";
620 const char *fname = "foo";
621 char *fpath;
622 int fnum;
623 int counter = 0;
624 bool ret = false;
626 if (!(mem_ctx = talloc_init("torture_samba3_caseinsensitive"))) {
627 d_printf("talloc_init failed\n");
628 return false;
631 if (!torture_open_connection(&cli, torture, 0)) {
632 goto done;
635 smbcli_deltree(cli->tree, dirname);
637 status = smbcli_mkdir(cli->tree, dirname);
638 torture_assert_ntstatus_ok(torture, status, "smbcli_mkdir failed");
639 if (!NT_STATUS_IS_OK(status)) {
640 goto done;
643 if (!(fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname))) {
644 goto done;
646 fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
647 if (fnum == -1) {
648 torture_result(torture, TORTURE_FAIL,
649 "Could not create file %s: %s", fpath,
650 smbcli_errstr(cli->tree));
651 goto done;
653 smbcli_close(cli->tree, fnum);
655 smbcli_list(cli->tree, talloc_asprintf(
656 mem_ctx, "%s\\*", ucase_dirname),
657 FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN
658 |FILE_ATTRIBUTE_SYSTEM,
659 count_fn, (void *)&counter);
661 if (counter == 3) {
662 ret = true;
664 else {
665 torture_result(torture, TORTURE_FAIL,
666 "expected 3 entries, got %d", counter);
667 ret = false;
670 done:
671 talloc_free(mem_ctx);
672 return ret;
675 static void close_locked_file(struct tevent_context *ev,
676 struct tevent_timer *te,
677 struct timeval now,
678 void *private_data)
680 int *pfd = (int *)private_data;
682 TALLOC_FREE(te);
684 if (*pfd != -1) {
685 close(*pfd);
686 *pfd = -1;
690 struct lock_result_state {
691 NTSTATUS status;
692 bool done;
695 static void receive_lock_result(struct smbcli_request *req)
697 struct lock_result_state *state =
698 (struct lock_result_state *)req->async.private_data;
700 state->status = smbcli_request_simple_recv(req);
701 state->done = true;
705 * Check that Samba3 correctly deals with conflicting posix byte range locks
706 * on an underlying file
708 * Note: This test depends on "posix locking = yes".
709 * Note: To run this test, use "--option=torture:localdir=<LOCALDIR>"
712 bool torture_samba3_posixtimedlock(struct torture_context *tctx)
714 struct smbcli_state *cli;
715 NTSTATUS status;
716 bool ret = true;
717 const char *dirname = "posixlock";
718 const char *fname = "locked";
719 const char *fpath;
720 const char *localdir;
721 const char *localname;
722 int fnum = -1;
724 int fd = -1;
725 struct flock posix_lock;
727 union smb_lock io;
728 struct smb_lock_entry lock_entry;
729 struct smbcli_request *req;
730 struct lock_result_state lock_result;
732 struct tevent_timer *te;
734 if (!torture_open_connection(&cli, tctx, 0)) {
735 ret = false;
736 goto done;
739 smbcli_deltree(cli->tree, dirname);
741 status = smbcli_mkdir(cli->tree, dirname);
742 if (!NT_STATUS_IS_OK(status)) {
743 torture_warning(tctx, "smbcli_mkdir failed: %s\n",
744 nt_errstr(status));
745 ret = false;
746 goto done;
749 if (!(fpath = talloc_asprintf(tctx, "%s\\%s", dirname, fname))) {
750 torture_warning(tctx, "talloc failed\n");
751 ret = false;
752 goto done;
754 fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
755 if (fnum == -1) {
756 torture_warning(tctx, "Could not create file %s: %s\n", fpath,
757 smbcli_errstr(cli->tree));
758 ret = false;
759 goto done;
762 if (!(localdir = torture_setting_string(tctx, "localdir", NULL))) {
763 torture_warning(tctx, "Need 'localdir' setting\n");
764 ret = false;
765 goto done;
768 if (!(localname = talloc_asprintf(tctx, "%s/%s/%s", localdir, dirname,
769 fname))) {
770 torture_warning(tctx, "talloc failed\n");
771 ret = false;
772 goto done;
776 * Lock a byte range from posix
779 fd = open(localname, O_RDWR);
780 if (fd == -1) {
781 torture_warning(tctx, "open(%s) failed: %s\n",
782 localname, strerror(errno));
783 goto done;
786 posix_lock.l_type = F_WRLCK;
787 posix_lock.l_whence = SEEK_SET;
788 posix_lock.l_start = 0;
789 posix_lock.l_len = 1;
791 if (fcntl(fd, F_SETLK, &posix_lock) == -1) {
792 torture_warning(tctx, "fcntl failed: %s\n", strerror(errno));
793 ret = false;
794 goto done;
798 * Try a cifs brlock without timeout to see if posix locking = yes
801 io.lockx.in.ulock_cnt = 0;
802 io.lockx.in.lock_cnt = 1;
804 lock_entry.count = 1;
805 lock_entry.offset = 0;
806 lock_entry.pid = cli->tree->session->pid;
808 io.lockx.level = RAW_LOCK_LOCKX;
809 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
810 io.lockx.in.timeout = 0;
811 io.lockx.in.locks = &lock_entry;
812 io.lockx.in.file.fnum = fnum;
814 status = smb_raw_lock(cli->tree, &io);
816 ret = true;
817 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
819 if (!ret) {
820 goto done;
824 * Now fire off a timed brlock, unlock the posix lock and see if the
825 * timed lock gets through.
828 io.lockx.in.timeout = 5000;
830 req = smb_raw_lock_send(cli->tree, &io);
831 if (req == NULL) {
832 torture_warning(tctx, "smb_raw_lock_send failed\n");
833 ret = false;
834 goto done;
837 lock_result.done = false;
838 req->async.fn = receive_lock_result;
839 req->async.private_data = &lock_result;
841 te = tevent_add_timer(req->transport->socket->event.ctx,
842 tctx, timeval_current_ofs(1, 0),
843 close_locked_file, &fd);
844 if (te == NULL) {
845 torture_warning(tctx, "tevent_add_timer failed\n");
846 ret = false;
847 goto done;
850 while ((fd != -1) || (!lock_result.done)) {
851 if (tevent_loop_once(req->transport->socket->event.ctx)
852 == -1) {
853 torture_warning(tctx, "tevent_loop_once failed: %s\n",
854 strerror(errno));
855 ret = false;
856 goto done;
860 CHECK_STATUS(lock_result.status, NT_STATUS_OK);
862 done:
863 if (fnum != -1) {
864 smbcli_close(cli->tree, fnum);
866 if (fd != -1) {
867 close(fd);
869 smbcli_deltree(cli->tree, dirname);
870 return ret;
873 bool torture_samba3_rootdirfid(struct torture_context *tctx)
875 struct smbcli_state *cli;
876 NTSTATUS status;
877 uint16_t dnum;
878 union smb_open io;
879 const char *fname = "testfile";
880 bool ret = false;
882 if (!torture_open_connection(&cli, tctx, 0)) {
883 ret = false;
884 goto done;
887 smbcli_unlink(cli->tree, fname);
889 ZERO_STRUCT(io);
890 io.generic.level = RAW_OPEN_NTCREATEX;
891 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
892 io.ntcreatex.in.root_fid.fnum = 0;
893 io.ntcreatex.in.security_flags = 0;
894 io.ntcreatex.in.access_mask =
895 SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE;
896 io.ntcreatex.in.alloc_size = 0;
897 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
898 io.ntcreatex.in.share_access =
899 NTCREATEX_SHARE_ACCESS_READ
900 | NTCREATEX_SHARE_ACCESS_READ;
901 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
902 io.ntcreatex.in.create_options = 0;
903 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
904 io.ntcreatex.in.fname = "\\";
905 status = smb_raw_open(cli->tree, tctx, &io);
906 if (!NT_STATUS_IS_OK(status)) {
907 d_printf("smb_open on the directory failed: %s\n",
908 nt_errstr(status));
909 ret = false;
910 goto done;
912 dnum = io.ntcreatex.out.file.fnum;
914 io.ntcreatex.in.flags =
915 NTCREATEX_FLAGS_REQUEST_OPLOCK
916 | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
917 io.ntcreatex.in.root_fid.fnum = dnum;
918 io.ntcreatex.in.security_flags = 0;
919 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
920 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
921 io.ntcreatex.in.alloc_size = 0;
922 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
923 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
924 io.ntcreatex.in.create_options = 0;
925 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
926 io.ntcreatex.in.fname = fname;
928 status = smb_raw_open(cli->tree, tctx, &io);
929 if (!NT_STATUS_IS_OK(status)) {
930 d_printf("smb_open on the file %s failed: %s\n",
931 fname, nt_errstr(status));
932 ret = false;
933 goto done;
936 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
937 smbcli_close(cli->tree, dnum);
938 smbcli_unlink(cli->tree, fname);
940 ret = true;
941 done:
942 return ret;
945 bool torture_samba3_oplock_logoff(struct torture_context *tctx)
947 struct smbcli_state *cli;
948 NTSTATUS status;
949 uint16_t fnum1;
950 union smb_open io;
951 const char *fname = "testfile";
952 bool ret = false;
953 struct smbcli_request *req;
954 struct smb_echo echo_req;
956 if (!torture_open_connection(&cli, tctx, 0)) {
957 ret = false;
958 goto done;
961 smbcli_unlink(cli->tree, fname);
963 ZERO_STRUCT(io);
964 io.generic.level = RAW_OPEN_NTCREATEX;
965 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
966 io.ntcreatex.in.root_fid.fnum = 0;
967 io.ntcreatex.in.security_flags = 0;
968 io.ntcreatex.in.access_mask =
969 SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE;
970 io.ntcreatex.in.alloc_size = 0;
971 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
972 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
973 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
974 io.ntcreatex.in.create_options = 0;
975 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
976 io.ntcreatex.in.fname = "testfile";
977 status = smb_raw_open(cli->tree, tctx, &io);
978 if (!NT_STATUS_IS_OK(status)) {
979 d_printf("first smb_open failed: %s\n", nt_errstr(status));
980 ret = false;
981 goto done;
983 fnum1 = io.ntcreatex.out.file.fnum;
986 * Create a conflicting open, causing the one-second delay
989 req = smb_raw_open_send(cli->tree, &io);
990 if (req == NULL) {
991 d_printf("smb_raw_open_send failed\n");
992 ret = false;
993 goto done;
997 * Pull the VUID from under that request. As of Nov 3, 2008 all Samba3
998 * versions (3.0, 3.2 and master) would spin sending ERRinvuid errors
999 * as long as the client is still connected.
1002 status = smb_raw_ulogoff(cli->session);
1004 if (!NT_STATUS_IS_OK(status)) {
1005 d_printf("ulogoff failed: %s\n", nt_errstr(status));
1006 ret = false;
1007 goto done;
1010 echo_req.in.repeat_count = 1;
1011 echo_req.in.size = 1;
1012 echo_req.in.data = discard_const_p(uint8_t, "");
1014 status = smb_raw_echo(cli->session->transport, &echo_req);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 d_printf("smb_raw_echo returned %s\n",
1017 nt_errstr(status));
1018 ret = false;
1019 goto done;
1022 ret = true;
1023 done:
1024 return ret;