s3: Fix bug #9085.
[Samba.git] / source4 / torture / raw / samba3misc.c
blob6d6eabce2d75b0f67f534fc6f37b329543e0e59c
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 = 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 uint_t openfn=0;
166 uint_t 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 uint_t openfn=0;
229 uint_t 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 = 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 = lp_nt_status_support(torture->lp_ctx);
351 if (!lp_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 (!lp_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 (!lp_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 = true;
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 if (!NT_STATUS_IS_OK(status)) {
639 d_printf("smbcli_mkdir failed: %s\n", nt_errstr(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 d_printf("Could not create file %s: %s\n", fpath,
649 smbcli_errstr(cli->tree));
650 goto done;
652 smbcli_close(cli->tree, fnum);
654 smbcli_list(cli->tree, talloc_asprintf(
655 mem_ctx, "%s\\*", ucase_dirname),
656 FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN
657 |FILE_ATTRIBUTE_SYSTEM,
658 count_fn, (void *)&counter);
660 if (counter == 3) {
661 ret = true;
663 else {
664 d_fprintf(stderr, "expected 3 entries, got %d\n", counter);
665 ret = false;
668 done:
669 talloc_free(mem_ctx);
670 return ret;
673 static void close_locked_file(struct tevent_context *ev,
674 struct tevent_timer *te,
675 struct timeval now,
676 void *private_data)
678 int *pfd = (int *)private_data;
680 TALLOC_FREE(te);
682 if (*pfd != -1) {
683 close(*pfd);
684 *pfd = -1;
688 struct lock_result_state {
689 NTSTATUS status;
690 bool done;
693 static void receive_lock_result(struct smbcli_request *req)
695 struct lock_result_state *state =
696 (struct lock_result_state *)req->async.private_data;
698 state->status = smbcli_request_simple_recv(req);
699 state->done = true;
703 * Check that Samba3 correctly deals with conflicting posix byte range locks
704 * on an underlying file
706 * Note: This test depends on "posix locking = yes".
707 * Note: To run this test, use "--option=torture:localdir=<LOCALDIR>"
710 bool torture_samba3_posixtimedlock(struct torture_context *tctx)
712 struct smbcli_state *cli;
713 NTSTATUS status;
714 bool ret = true;
715 const char *dirname = "posixlock";
716 const char *fname = "locked";
717 const char *fpath;
718 const char *localdir;
719 const char *localname;
720 int fnum = -1;
722 int fd = -1;
723 struct flock posix_lock;
725 union smb_lock io;
726 struct smb_lock_entry lock_entry;
727 struct smbcli_request *req;
728 struct lock_result_state lock_result;
730 struct tevent_timer *te;
732 if (!torture_open_connection(&cli, tctx, 0)) {
733 ret = false;
734 goto done;
737 smbcli_deltree(cli->tree, dirname);
739 status = smbcli_mkdir(cli->tree, dirname);
740 if (!NT_STATUS_IS_OK(status)) {
741 torture_warning(tctx, "smbcli_mkdir failed: %s\n",
742 nt_errstr(status));
743 ret = false;
744 goto done;
747 if (!(fpath = talloc_asprintf(tctx, "%s\\%s", dirname, fname))) {
748 torture_warning(tctx, "talloc failed\n");
749 ret = false;
750 goto done;
752 fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
753 if (fnum == -1) {
754 torture_warning(tctx, "Could not create file %s: %s\n", fpath,
755 smbcli_errstr(cli->tree));
756 ret = false;
757 goto done;
760 if (!(localdir = torture_setting_string(tctx, "localdir", NULL))) {
761 torture_warning(tctx, "Need 'localdir' setting\n");
762 ret = false;
763 goto done;
766 if (!(localname = talloc_asprintf(tctx, "%s/%s/%s", localdir, dirname,
767 fname))) {
768 torture_warning(tctx, "talloc failed\n");
769 ret = false;
770 goto done;
774 * Lock a byte range from posix
777 fd = open(localname, O_RDWR);
778 if (fd == -1) {
779 torture_warning(tctx, "open(%s) failed: %s\n",
780 localname, strerror(errno));
781 goto done;
784 posix_lock.l_type = F_WRLCK;
785 posix_lock.l_whence = SEEK_SET;
786 posix_lock.l_start = 0;
787 posix_lock.l_len = 1;
789 if (fcntl(fd, F_SETLK, &posix_lock) == -1) {
790 torture_warning(tctx, "fcntl failed: %s\n", strerror(errno));
791 ret = false;
792 goto done;
796 * Try a cifs brlock without timeout to see if posix locking = yes
799 io.lockx.in.ulock_cnt = 0;
800 io.lockx.in.lock_cnt = 1;
802 lock_entry.count = 1;
803 lock_entry.offset = 0;
804 lock_entry.pid = cli->tree->session->pid;
806 io.lockx.level = RAW_LOCK_LOCKX;
807 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
808 io.lockx.in.timeout = 0;
809 io.lockx.in.locks = &lock_entry;
810 io.lockx.in.file.fnum = fnum;
812 status = smb_raw_lock(cli->tree, &io);
814 ret = true;
815 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
817 if (!ret) {
818 goto done;
822 * Now fire off a timed brlock, unlock the posix lock and see if the
823 * timed lock gets through.
826 io.lockx.in.timeout = 5000;
828 req = smb_raw_lock_send(cli->tree, &io);
829 if (req == NULL) {
830 torture_warning(tctx, "smb_raw_lock_send failed\n");
831 ret = false;
832 goto done;
835 lock_result.done = false;
836 req->async.fn = receive_lock_result;
837 req->async.private_data = &lock_result;
839 te = tevent_add_timer(req->transport->socket->event.ctx,
840 tctx, timeval_current_ofs(1, 0),
841 close_locked_file, &fd);
842 if (te == NULL) {
843 torture_warning(tctx, "tevent_add_timer failed\n");
844 ret = false;
845 goto done;
848 while ((fd != -1) || (!lock_result.done)) {
849 if (tevent_loop_once(req->transport->socket->event.ctx)
850 == -1) {
851 torture_warning(tctx, "tevent_loop_once failed: %s\n",
852 strerror(errno));
853 ret = false;
854 goto done;
858 CHECK_STATUS(lock_result.status, NT_STATUS_OK);
860 done:
861 if (fnum != -1) {
862 smbcli_close(cli->tree, fnum);
864 if (fd != -1) {
865 close(fd);
867 smbcli_deltree(cli->tree, dirname);
868 return ret;
871 bool torture_samba3_rootdirfid(struct torture_context *tctx)
873 struct smbcli_state *cli;
874 NTSTATUS status;
875 uint16_t dnum;
876 union smb_open io;
877 const char *fname = "testfile";
878 bool ret = false;
880 if (!torture_open_connection(&cli, tctx, 0)) {
881 ret = false;
882 goto done;
885 smbcli_unlink(cli->tree, fname);
887 ZERO_STRUCT(io);
888 io.generic.level = RAW_OPEN_NTCREATEX;
889 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
890 io.ntcreatex.in.root_fid = 0;
891 io.ntcreatex.in.security_flags = 0;
892 io.ntcreatex.in.access_mask =
893 SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE;
894 io.ntcreatex.in.alloc_size = 0;
895 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
896 io.ntcreatex.in.share_access =
897 NTCREATEX_SHARE_ACCESS_READ
898 | NTCREATEX_SHARE_ACCESS_READ;
899 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
900 io.ntcreatex.in.create_options = 0;
901 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
902 io.ntcreatex.in.fname = "\\";
903 status = smb_raw_open(cli->tree, tctx, &io);
904 if (!NT_STATUS_IS_OK(status)) {
905 d_printf("smb_open on the directory failed: %s\n",
906 nt_errstr(status));
907 ret = false;
908 goto done;
910 dnum = io.ntcreatex.out.file.fnum;
912 io.ntcreatex.in.flags =
913 NTCREATEX_FLAGS_REQUEST_OPLOCK
914 | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
915 io.ntcreatex.in.root_fid = dnum;
916 io.ntcreatex.in.security_flags = 0;
917 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
918 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
919 io.ntcreatex.in.alloc_size = 0;
920 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
921 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
922 io.ntcreatex.in.create_options = 0;
923 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
924 io.ntcreatex.in.fname = fname;
926 status = smb_raw_open(cli->tree, tctx, &io);
927 if (!NT_STATUS_IS_OK(status)) {
928 d_printf("smb_open on the file %s failed: %s\n",
929 fname, nt_errstr(status));
930 ret = false;
931 goto done;
934 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
935 smbcli_close(cli->tree, dnum);
936 smbcli_unlink(cli->tree, fname);
938 ret = true;
939 done:
940 return ret;
943 bool torture_samba3_oplock_logoff(struct torture_context *tctx)
945 struct smbcli_state *cli;
946 NTSTATUS status;
947 uint16_t fnum1;
948 union smb_open io;
949 const char *fname = "testfile";
950 bool ret = false;
951 struct smbcli_request *req;
952 struct smb_echo echo_req;
954 if (!torture_open_connection(&cli, tctx, 0)) {
955 ret = false;
956 goto done;
959 smbcli_unlink(cli->tree, fname);
961 ZERO_STRUCT(io);
962 io.generic.level = RAW_OPEN_NTCREATEX;
963 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
964 io.ntcreatex.in.root_fid = 0;
965 io.ntcreatex.in.security_flags = 0;
966 io.ntcreatex.in.access_mask =
967 SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE;
968 io.ntcreatex.in.alloc_size = 0;
969 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
970 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
971 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
972 io.ntcreatex.in.create_options = 0;
973 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
974 io.ntcreatex.in.fname = "testfile";
975 status = smb_raw_open(cli->tree, tctx, &io);
976 if (!NT_STATUS_IS_OK(status)) {
977 d_printf("first smb_open failed: %s\n", nt_errstr(status));
978 ret = false;
979 goto done;
981 fnum1 = io.ntcreatex.out.file.fnum;
984 * Create a conflicting open, causing the one-second delay
987 req = smb_raw_open_send(cli->tree, &io);
988 if (req == NULL) {
989 d_printf("smb_raw_open_send failed\n");
990 ret = false;
991 goto done;
995 * Pull the VUID from under that request. As of Nov 3, 2008 all Samba3
996 * versions (3.0, 3.2 and master) would spin sending ERRinvuid errors
997 * as long as the client is still connected.
1000 status = smb_raw_ulogoff(cli->session);
1002 if (!NT_STATUS_IS_OK(status)) {
1003 d_printf("ulogoff failed: %s\n", nt_errstr(status));
1004 ret = false;
1005 goto done;
1008 echo_req.in.repeat_count = 1;
1009 echo_req.in.size = 1;
1010 echo_req.in.data = (uint8_t *)"";
1012 status = smb_raw_echo(cli->session->transport, &echo_req);
1013 if (!NT_STATUS_IS_OK(status)) {
1014 d_printf("smb_raw_echo returned %s\n",
1015 nt_errstr(status));
1016 ret = false;
1017 goto done;
1020 ret = true;
1021 done:
1022 return ret;