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/>.
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"
30 #include "torture/raw/proto.h"
33 The next 2 functions are stolen from source4/libcli/raw/rawfile.c
34 but allow us to send a raw data blob instead of an OpenX name.
37 #define SETUP_REQUEST(cmd, wct, buflen) do { \
38 req = smbcli_request_setup(tree, cmd, wct, buflen); \
39 if (!req) return NULL; \
42 static struct smbcli_request
*smb_raw_openX_name_blob_send(struct smbcli_tree
*tree
,
43 union smb_open
*parms
,
44 const DATA_BLOB
*pname_blob
)
46 struct smbcli_request
*req
= NULL
;
48 if (parms
->generic
.level
!= RAW_OPEN_OPENX
) {
52 SETUP_REQUEST(SMBopenX
, 15, 0);
53 SSVAL(req
->out
.vwv
, VWV(0), SMB_CHAIN_NONE
);
54 SSVAL(req
->out
.vwv
, VWV(1), 0);
55 SSVAL(req
->out
.vwv
, VWV(2), parms
->openx
.in
.flags
);
56 SSVAL(req
->out
.vwv
, VWV(3), parms
->openx
.in
.open_mode
);
57 SSVAL(req
->out
.vwv
, VWV(4), parms
->openx
.in
.search_attrs
);
58 SSVAL(req
->out
.vwv
, VWV(5), parms
->openx
.in
.file_attrs
);
59 raw_push_dos_date3(tree
->session
->transport
,
60 req
->out
.vwv
, VWV(6), parms
->openx
.in
.write_time
);
61 SSVAL(req
->out
.vwv
, VWV(8), parms
->openx
.in
.open_func
);
62 SIVAL(req
->out
.vwv
, VWV(9), parms
->openx
.in
.size
);
63 SIVAL(req
->out
.vwv
, VWV(11),parms
->openx
.in
.timeout
);
64 SIVAL(req
->out
.vwv
, VWV(13),0); /* reserved */
65 smbcli_req_append_blob(req
, pname_blob
);
67 if (!smbcli_request_send(req
)) {
68 smbcli_request_destroy(req
);
75 static NTSTATUS
smb_raw_openX_name_blob(struct smbcli_tree
*tree
,
77 union smb_open
*parms
,
78 const DATA_BLOB
*pname_blob
)
80 struct smbcli_request
*req
= smb_raw_openX_name_blob_send(tree
, parms
, pname_blob
);
81 return smb_raw_open_recv(req
, mem_ctx
, parms
);
84 static NTSTATUS
raw_smbcli_openX_name_blob(struct smbcli_tree
*tree
,
85 const DATA_BLOB
*pname_blob
,
90 union smb_open open_parms
;
91 unsigned int openfn
=0;
92 unsigned int accessmode
=0;
96 mem_ctx
= talloc_init("raw_openX_name_blob");
97 if (!mem_ctx
) return NT_STATUS_NO_MEMORY
;
99 if (flags
& O_CREAT
) {
100 openfn
|= OPENX_OPEN_FUNC_CREATE
;
102 if (!(flags
& O_EXCL
)) {
103 if (flags
& O_TRUNC
) {
104 openfn
|= OPENX_OPEN_FUNC_TRUNC
;
106 openfn
|= OPENX_OPEN_FUNC_OPEN
;
110 accessmode
= (share_mode
<<OPENX_MODE_DENY_SHIFT
);
112 if ((flags
& O_ACCMODE
) == O_RDWR
) {
113 accessmode
|= OPENX_MODE_ACCESS_RDWR
;
114 } else if ((flags
& O_ACCMODE
) == O_WRONLY
) {
115 accessmode
|= OPENX_MODE_ACCESS_WRITE
;
116 } else if ((flags
& O_ACCMODE
) == O_RDONLY
) {
117 accessmode
|= OPENX_MODE_ACCESS_READ
;
121 if ((flags
& O_SYNC
) == O_SYNC
) {
122 accessmode
|= OPENX_MODE_WRITE_THRU
;
126 if (share_mode
== DENY_FCB
) {
127 accessmode
= OPENX_MODE_ACCESS_FCB
| OPENX_MODE_DENY_FCB
;
130 open_parms
.openx
.level
= RAW_OPEN_OPENX
;
131 open_parms
.openx
.in
.flags
= 0;
132 open_parms
.openx
.in
.open_mode
= accessmode
;
133 open_parms
.openx
.in
.search_attrs
= FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
;
134 open_parms
.openx
.in
.file_attrs
= 0;
135 open_parms
.openx
.in
.write_time
= 0;
136 open_parms
.openx
.in
.open_func
= openfn
;
137 open_parms
.openx
.in
.size
= 0;
138 open_parms
.openx
.in
.timeout
= 0;
139 open_parms
.openx
.in
.fname
= NULL
;
141 status
= smb_raw_openX_name_blob(tree
, mem_ctx
, &open_parms
, pname_blob
);
142 talloc_free(mem_ctx
);
144 if (fnum
&& NT_STATUS_IS_OK(status
)) {
145 *fnum
= open_parms
.openx
.out
.file
.fnum
;
152 #define CHECK_STATUS(torture, status, correct) do { \
153 if (!NT_STATUS_EQUAL(status, correct)) { \
154 torture_result(torture, TORTURE_FAIL, "%s: Incorrect status %s - should be %s\n", \
155 __location__, nt_errstr(status), nt_errstr(correct)); \
160 bool torture_samba3_checkfsp(struct torture_context
*torture
, struct smbcli_state
*cli
)
162 const char *fname
= "test.txt";
163 const char *dirname
= "testdir";
170 struct smbcli_tree
*tree2
;
172 torture_assert(torture
, mem_ctx
= talloc_init("torture_samba3_checkfsp"), "talloc_init failed\n");
174 torture_assert_ntstatus_equal(torture
, torture_second_tcon(torture
, cli
->session
,
175 torture_setting_string(torture
, "share", NULL
),
178 "creating second tcon");
180 /* Try a read on an invalid FID */
182 nread
= smbcli_read(cli
->tree
, 4711, buf
, 0, sizeof(buf
));
183 CHECK_STATUS(torture
, smbcli_nt_error(cli
->tree
), NT_STATUS_INVALID_HANDLE
);
185 /* Try a read on a directory handle */
187 torture_assert(torture
, torture_setup_dir(cli
, dirname
), "creating test directory");
189 /* Open the directory */
192 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
193 io
.ntcreatex
.in
.flags
= NTCREATEX_FLAGS_EXTENDED
;
194 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
195 io
.ntcreatex
.in
.security_flags
= 0;
196 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
197 io
.ntcreatex
.in
.access_mask
= SEC_RIGHTS_FILE_ALL
;
198 io
.ntcreatex
.in
.alloc_size
= 0;
199 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_DIRECTORY
;
200 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
201 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
202 io
.ntcreatex
.in
.create_options
= 0;
203 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
204 io
.ntcreatex
.in
.fname
= dirname
;
205 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
206 if (!NT_STATUS_IS_OK(status
)) {
207 torture_result(torture
, TORTURE_FAIL
, "smb_open on the directory failed: %s\n",
212 fnum
= io
.ntcreatex
.out
.file
.fnum
;
215 /* Try a read on the directory */
217 nread
= smbcli_read(cli
->tree
, fnum
, buf
, 0, sizeof(buf
));
219 torture_result(torture
, TORTURE_FAIL
, "smbcli_read on a directory succeeded, expected "
224 CHECK_STATUS(torture
, smbcli_nt_error(cli
->tree
),
225 NT_STATUS_INVALID_DEVICE_REQUEST
);
227 /* Same test on the second tcon */
229 nread
= smbcli_read(tree2
, fnum
, buf
, 0, sizeof(buf
));
231 torture_result(torture
, TORTURE_FAIL
, "smbcli_read on a directory succeeded, expected "
236 CHECK_STATUS(torture
, smbcli_nt_error(tree2
), NT_STATUS_INVALID_HANDLE
);
238 smbcli_close(cli
->tree
, fnum
);
240 /* Try a normal file read on a second tcon */
242 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
244 torture_result(torture
, TORTURE_FAIL
, "Failed to create %s - %s\n", fname
,
245 smbcli_errstr(cli
->tree
));
250 nread
= smbcli_read(tree2
, fnum
, buf
, 0, sizeof(buf
));
251 CHECK_STATUS(torture
, smbcli_nt_error(tree2
), NT_STATUS_INVALID_HANDLE
);
253 smbcli_close(cli
->tree
, fnum
);
256 smbcli_deltree(cli
->tree
, dirname
);
257 talloc_free(mem_ctx
);
262 static NTSTATUS
raw_smbcli_open(struct smbcli_tree
*tree
, const char *fname
, int flags
, int share_mode
, int *fnum
)
264 union smb_open open_parms
;
265 unsigned int openfn
=0;
266 unsigned int accessmode
=0;
270 mem_ctx
= talloc_init("raw_open");
271 if (!mem_ctx
) return NT_STATUS_NO_MEMORY
;
273 if (flags
& O_CREAT
) {
274 openfn
|= OPENX_OPEN_FUNC_CREATE
;
276 if (!(flags
& O_EXCL
)) {
277 if (flags
& O_TRUNC
) {
278 openfn
|= OPENX_OPEN_FUNC_TRUNC
;
280 openfn
|= OPENX_OPEN_FUNC_OPEN
;
284 accessmode
= (share_mode
<<OPENX_MODE_DENY_SHIFT
);
286 if ((flags
& O_ACCMODE
) == O_RDWR
) {
287 accessmode
|= OPENX_MODE_ACCESS_RDWR
;
288 } else if ((flags
& O_ACCMODE
) == O_WRONLY
) {
289 accessmode
|= OPENX_MODE_ACCESS_WRITE
;
290 } else if ((flags
& O_ACCMODE
) == O_RDONLY
) {
291 accessmode
|= OPENX_MODE_ACCESS_READ
;
295 if ((flags
& O_SYNC
) == O_SYNC
) {
296 accessmode
|= OPENX_MODE_WRITE_THRU
;
300 if (share_mode
== DENY_FCB
) {
301 accessmode
= OPENX_MODE_ACCESS_FCB
| OPENX_MODE_DENY_FCB
;
304 open_parms
.openx
.level
= RAW_OPEN_OPENX
;
305 open_parms
.openx
.in
.flags
= 0;
306 open_parms
.openx
.in
.open_mode
= accessmode
;
307 open_parms
.openx
.in
.search_attrs
= FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
;
308 open_parms
.openx
.in
.file_attrs
= 0;
309 open_parms
.openx
.in
.write_time
= 0;
310 open_parms
.openx
.in
.open_func
= openfn
;
311 open_parms
.openx
.in
.size
= 0;
312 open_parms
.openx
.in
.timeout
= 0;
313 open_parms
.openx
.in
.fname
= fname
;
315 status
= smb_raw_open(tree
, mem_ctx
, &open_parms
);
316 talloc_free(mem_ctx
);
318 if (fnum
&& NT_STATUS_IS_OK(status
)) {
319 *fnum
= open_parms
.openx
.out
.file
.fnum
;
325 static NTSTATUS
raw_smbcli_t2open(struct smbcli_tree
*tree
, const char *fname
, int flags
, int share_mode
, int *fnum
)
328 unsigned int openfn
=0;
329 unsigned int accessmode
=0;
333 mem_ctx
= talloc_init("raw_t2open");
334 if (!mem_ctx
) return NT_STATUS_NO_MEMORY
;
336 if (flags
& O_CREAT
) {
337 openfn
|= OPENX_OPEN_FUNC_CREATE
;
339 if (!(flags
& O_EXCL
)) {
340 if (flags
& O_TRUNC
) {
341 openfn
|= OPENX_OPEN_FUNC_TRUNC
;
343 openfn
|= OPENX_OPEN_FUNC_OPEN
;
347 accessmode
= (share_mode
<<OPENX_MODE_DENY_SHIFT
);
349 if ((flags
& O_ACCMODE
) == O_RDWR
) {
350 accessmode
|= OPENX_MODE_ACCESS_RDWR
;
351 } else if ((flags
& O_ACCMODE
) == O_WRONLY
) {
352 accessmode
|= OPENX_MODE_ACCESS_WRITE
;
353 } else if ((flags
& O_ACCMODE
) == O_RDONLY
) {
354 accessmode
|= OPENX_MODE_ACCESS_READ
;
358 if ((flags
& O_SYNC
) == O_SYNC
) {
359 accessmode
|= OPENX_MODE_WRITE_THRU
;
363 if (share_mode
== DENY_FCB
) {
364 accessmode
= OPENX_MODE_ACCESS_FCB
| OPENX_MODE_DENY_FCB
;
367 memset(&io
, '\0', sizeof(io
));
368 io
.t2open
.level
= RAW_OPEN_T2OPEN
;
369 io
.t2open
.in
.flags
= 0;
370 io
.t2open
.in
.open_mode
= accessmode
;
371 io
.t2open
.in
.search_attrs
= FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
;
372 io
.t2open
.in
.file_attrs
= 0;
373 io
.t2open
.in
.write_time
= 0;
374 io
.t2open
.in
.open_func
= openfn
;
375 io
.t2open
.in
.size
= 0;
376 io
.t2open
.in
.timeout
= 0;
377 io
.t2open
.in
.fname
= fname
;
379 io
.t2open
.in
.num_eas
= 1;
380 io
.t2open
.in
.eas
= talloc_array(mem_ctx
, struct ea_struct
, io
.t2open
.in
.num_eas
);
381 io
.t2open
.in
.eas
[0].flags
= 0;
382 io
.t2open
.in
.eas
[0].name
.s
= ".CLASSINFO";
383 io
.t2open
.in
.eas
[0].value
= data_blob_talloc(mem_ctx
, "first value", 11);
385 status
= smb_raw_open(tree
, mem_ctx
, &io
);
386 talloc_free(mem_ctx
);
388 if (fnum
&& NT_STATUS_IS_OK(status
)) {
389 *fnum
= io
.openx
.out
.file
.fnum
;
395 static NTSTATUS
raw_smbcli_ntcreate(struct smbcli_tree
*tree
, const char *fname
, int *fnum
)
401 mem_ctx
= talloc_init("raw_t2open");
402 if (!mem_ctx
) return NT_STATUS_NO_MEMORY
;
404 memset(&io
, '\0', sizeof(io
));
405 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
406 io
.ntcreatex
.in
.flags
= NTCREATEX_FLAGS_EXTENDED
;
407 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
408 io
.ntcreatex
.in
.access_mask
= SEC_RIGHTS_FILE_ALL
;
409 io
.ntcreatex
.in
.alloc_size
= 0;
410 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
411 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
412 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
413 io
.ntcreatex
.in
.create_options
= 0;
414 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
415 io
.ntcreatex
.in
.security_flags
= 0;
416 io
.ntcreatex
.in
.fname
= fname
;
418 status
= smb_raw_open(tree
, mem_ctx
, &io
);
419 talloc_free(mem_ctx
);
421 if (fnum
&& NT_STATUS_IS_OK(status
)) {
422 *fnum
= io
.openx
.out
.file
.fnum
;
429 bool torture_samba3_badpath(struct torture_context
*torture
)
431 struct smbcli_state
*cli_nt
;
432 struct smbcli_state
*cli_dos
;
433 const char *fname
= "test.txt";
434 const char *fname1
= "test1.txt";
435 const char *dirname
= "testdir";
442 bool nt_status_support
;
444 torture_assert(torture
, mem_ctx
= talloc_init("torture_samba3_badpath"), "talloc_init failed");
446 nt_status_support
= lpcfg_nt_status_support(torture
->lp_ctx
);
448 torture_assert_goto(torture
, lpcfg_set_cmdline(torture
->lp_ctx
, "nt status support", "yes"), ret
, fail
, "Could not set 'nt status support = yes'\n");
450 torture_assert_goto(torture
, torture_open_connection(&cli_nt
, torture
, 0), ret
, fail
, "Could not open NTSTATUS connection\n");
452 torture_assert_goto(torture
, lpcfg_set_cmdline(torture
->lp_ctx
, "nt status support", "no"), ret
, fail
, "Could not set 'nt status support = no'\n");
454 torture_assert_goto(torture
, torture_open_connection(&cli_dos
, torture
, 1), ret
, fail
, "Could not open DOS connection\n");
456 torture_assert_goto(torture
, lpcfg_set_cmdline(torture
->lp_ctx
, "nt status support",
457 nt_status_support
? "yes":"no"),
458 ret
, fail
, "Could not set 'nt status support' back to where it was\n");
460 torture_assert(torture
, torture_setup_dir(cli_nt
, dirname
), "creating test directory");
462 status
= smbcli_chkpath(cli_nt
->tree
, dirname
);
463 CHECK_STATUS(torture
, status
, NT_STATUS_OK
);
465 status
= smbcli_chkpath(cli_nt
->tree
,
466 talloc_asprintf(mem_ctx
, "%s\\bla", dirname
));
467 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
469 status
= smbcli_chkpath(cli_dos
->tree
,
470 talloc_asprintf(mem_ctx
, "%s\\bla", dirname
));
471 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRbadpath
));
473 status
= smbcli_chkpath(cli_nt
->tree
,
474 talloc_asprintf(mem_ctx
, "%s\\bla\\blub",
476 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_PATH_NOT_FOUND
);
477 status
= smbcli_chkpath(cli_dos
->tree
,
478 talloc_asprintf(mem_ctx
, "%s\\bla\\blub",
480 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRbadpath
));
482 torture_assert_goto(torture
, fpath
= talloc_asprintf(mem_ctx
, "%s\\%s", dirname
, fname
),
483 ret
, fail
, "Could not allocate fpath\n");
485 fnum
= smbcli_open(cli_nt
->tree
, fpath
, O_RDWR
| O_CREAT
, DENY_NONE
);
487 torture_result(torture
, TORTURE_FAIL
, "Could not create file %s: %s\n", fpath
,
488 smbcli_errstr(cli_nt
->tree
));
491 smbcli_close(cli_nt
->tree
, fnum
);
493 if (!(fpath1
= talloc_asprintf(mem_ctx
, "%s\\%s", dirname
, fname1
))) {
496 fnum
= smbcli_open(cli_nt
->tree
, fpath1
, O_RDWR
| O_CREAT
, DENY_NONE
);
498 torture_result(torture
, TORTURE_FAIL
, "Could not create file %s: %s\n", fpath1
,
499 smbcli_errstr(cli_nt
->tree
));
502 smbcli_close(cli_nt
->tree
, fnum
);
505 * Do a whole bunch of error code checks on chkpath
508 status
= smbcli_chkpath(cli_nt
->tree
, fpath
);
509 CHECK_STATUS(torture
, status
, NT_STATUS_NOT_A_DIRECTORY
);
510 status
= smbcli_chkpath(cli_dos
->tree
, fpath
);
511 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRbadpath
));
513 status
= smbcli_chkpath(cli_nt
->tree
, "..");
514 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_PATH_SYNTAX_BAD
);
515 status
= smbcli_chkpath(cli_dos
->tree
, "..");
516 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidpath
));
518 status
= smbcli_chkpath(cli_nt
->tree
, ".");
519 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
520 status
= smbcli_chkpath(cli_dos
->tree
, ".");
521 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRbadpath
));
523 status
= smbcli_chkpath(cli_nt
->tree
, "\t");
524 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
525 status
= smbcli_chkpath(cli_dos
->tree
, "\t");
526 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRbadpath
));
528 status
= smbcli_chkpath(cli_nt
->tree
, "\t\\bla");
529 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
530 status
= smbcli_chkpath(cli_dos
->tree
, "\t\\bla");
531 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRbadpath
));
533 status
= smbcli_chkpath(cli_nt
->tree
, "<");
534 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
535 status
= smbcli_chkpath(cli_dos
->tree
, "<");
536 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRbadpath
));
538 status
= smbcli_chkpath(cli_nt
->tree
, "<\\bla");
539 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
540 status
= smbcli_chkpath(cli_dos
->tree
, "<\\bla");
541 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRbadpath
));
544 * .... And the same gang against getatr. Note that the DOS error codes
548 status
= smbcli_getatr(cli_nt
->tree
, fpath
, NULL
, NULL
, NULL
);
549 CHECK_STATUS(torture
, status
, NT_STATUS_OK
);
550 status
= smbcli_getatr(cli_dos
->tree
, fpath
, NULL
, NULL
, NULL
);
551 CHECK_STATUS(torture
, status
, NT_STATUS_OK
);
553 status
= smbcli_getatr(cli_nt
->tree
, "..", NULL
, NULL
, NULL
);
554 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_PATH_SYNTAX_BAD
);
555 status
= smbcli_getatr(cli_dos
->tree
, "..", NULL
, NULL
, NULL
);
556 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidpath
));
558 status
= smbcli_getatr(cli_nt
->tree
, ".", NULL
, NULL
, NULL
);
559 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
560 status
= smbcli_getatr(cli_dos
->tree
, ".", NULL
, NULL
, NULL
);
561 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidname
));
563 status
= smbcli_getatr(cli_nt
->tree
, "\t", NULL
, NULL
, NULL
);
564 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
565 status
= smbcli_getatr(cli_dos
->tree
, "\t", NULL
, NULL
, NULL
);
566 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidname
));
568 status
= smbcli_getatr(cli_nt
->tree
, "\t\\bla", NULL
, NULL
, NULL
);
569 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
570 status
= smbcli_getatr(cli_dos
->tree
, "\t\\bla", NULL
, NULL
, NULL
);
571 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidname
));
573 status
= smbcli_getatr(cli_nt
->tree
, "<", NULL
, NULL
, NULL
);
574 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
575 status
= smbcli_getatr(cli_dos
->tree
, "<", NULL
, NULL
, NULL
);
576 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidname
));
578 status
= smbcli_getatr(cli_nt
->tree
, "<\\bla", NULL
, NULL
, NULL
);
579 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
580 status
= smbcli_getatr(cli_dos
->tree
, "<\\bla", NULL
, NULL
, NULL
);
581 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidname
));
583 /* Try the same set with openX. */
585 status
= raw_smbcli_open(cli_nt
->tree
, "..", O_RDONLY
, DENY_NONE
, NULL
);
586 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_PATH_SYNTAX_BAD
);
587 status
= raw_smbcli_open(cli_dos
->tree
, "..", O_RDONLY
, DENY_NONE
, NULL
);
588 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidpath
));
590 status
= raw_smbcli_open(cli_nt
->tree
, ".", O_RDONLY
, DENY_NONE
, NULL
);
591 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
592 status
= raw_smbcli_open(cli_dos
->tree
, ".", O_RDONLY
, DENY_NONE
, NULL
);
593 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidname
));
595 status
= raw_smbcli_open(cli_nt
->tree
, "\t", O_RDONLY
, DENY_NONE
, NULL
);
596 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
597 status
= raw_smbcli_open(cli_dos
->tree
, "\t", O_RDONLY
, DENY_NONE
, NULL
);
598 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidname
));
600 status
= raw_smbcli_open(cli_nt
->tree
, "\t\\bla", O_RDONLY
, DENY_NONE
, NULL
);
601 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
602 status
= raw_smbcli_open(cli_dos
->tree
, "\t\\bla", O_RDONLY
, DENY_NONE
, NULL
);
603 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidname
));
605 status
= raw_smbcli_open(cli_nt
->tree
, "<", O_RDONLY
, DENY_NONE
, NULL
);
606 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
607 status
= raw_smbcli_open(cli_dos
->tree
, "<", O_RDONLY
, DENY_NONE
, NULL
);
608 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidname
));
610 status
= raw_smbcli_open(cli_nt
->tree
, "<\\bla", O_RDONLY
, DENY_NONE
, NULL
);
611 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_INVALID
);
612 status
= raw_smbcli_open(cli_dos
->tree
, "<\\bla", O_RDONLY
, DENY_NONE
, NULL
);
613 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
, ERRinvalidname
));
615 /* Let's test EEXIST error code mapping. */
616 status
= raw_smbcli_open(cli_nt
->tree
, fpath
, O_RDONLY
| O_CREAT
| O_EXCL
, DENY_NONE
, NULL
);
617 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_COLLISION
);
618 status
= raw_smbcli_open(cli_dos
->tree
, fpath
, O_RDONLY
| O_CREAT
| O_EXCL
, DENY_NONE
, NULL
);
619 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
,ERRfilexists
));
621 status
= raw_smbcli_t2open(cli_nt
->tree
, fpath
, O_RDONLY
| O_CREAT
| O_EXCL
, DENY_NONE
, NULL
);
622 if (!NT_STATUS_EQUAL(status
, NT_STATUS_EAS_NOT_SUPPORTED
)
623 || !torture_setting_bool(torture
, "samba3", false)) {
624 /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */
625 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_COLLISION
);
627 status
= raw_smbcli_t2open(cli_dos
->tree
, fpath
, O_RDONLY
| O_CREAT
| O_EXCL
, DENY_NONE
, NULL
);
628 if (!NT_STATUS_EQUAL(status
, NT_STATUS_DOS(ERRDOS
,ERReasnotsupported
))
629 || !torture_setting_bool(torture
, "samba3", false)) {
630 /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */
631 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
,ERRfilexists
));
634 status
= raw_smbcli_ntcreate(cli_nt
->tree
, fpath
, NULL
);
635 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_COLLISION
);
636 status
= raw_smbcli_ntcreate(cli_dos
->tree
, fpath
, NULL
);
637 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
,ERRfilexists
));
639 /* Try the rename test. */
642 memset(&io
, '\0', sizeof(io
));
643 io
.rename
.in
.pattern1
= fpath1
;
644 io
.rename
.in
.pattern2
= fpath
;
646 /* Try with SMBmv rename. */
647 status
= smb_raw_rename(cli_nt
->tree
, &io
);
648 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_COLLISION
);
649 status
= smb_raw_rename(cli_dos
->tree
, &io
);
650 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
,ERRrename
));
652 /* Try with NT rename. */
653 io
.generic
.level
= RAW_RENAME_NTRENAME
;
654 io
.ntrename
.in
.old_name
= fpath1
;
655 io
.ntrename
.in
.new_name
= fpath
;
656 io
.ntrename
.in
.attrib
= 0;
657 io
.ntrename
.in
.cluster_size
= 0;
658 io
.ntrename
.in
.flags
= RENAME_FLAG_RENAME
;
660 status
= smb_raw_rename(cli_nt
->tree
, &io
);
661 CHECK_STATUS(torture
, status
, NT_STATUS_OBJECT_NAME_COLLISION
);
662 status
= smb_raw_rename(cli_dos
->tree
, &io
);
663 CHECK_STATUS(torture
, status
, NT_STATUS_DOS(ERRDOS
,ERRrename
));
672 if (cli_nt
!= NULL
) {
673 smbcli_deltree(cli_nt
->tree
, dirname
);
674 torture_close_connection(cli_nt
);
676 if (cli_dos
!= NULL
) {
677 torture_close_connection(cli_dos
);
679 talloc_free(mem_ctx
);
684 static void count_fn(struct clilist_file_info
*info
, const char *name
,
687 int *counter
= (int *)private_data
;
691 bool torture_samba3_caseinsensitive(struct torture_context
*torture
, struct smbcli_state
*cli
)
694 const char *dirname
= "insensitive";
695 const char *ucase_dirname
= "InSeNsItIvE";
696 const char *fname
= "foo";
702 if (!(mem_ctx
= talloc_init("torture_samba3_caseinsensitive"))) {
703 torture_result(torture
, TORTURE_FAIL
, "talloc_init failed\n");
707 torture_assert(torture
, torture_setup_dir(cli
, dirname
), "creating test directory");
709 if (!(fpath
= talloc_asprintf(mem_ctx
, "%s\\%s", dirname
, fname
))) {
712 fnum
= smbcli_open(cli
->tree
, fpath
, O_RDWR
| O_CREAT
, DENY_NONE
);
714 torture_result(torture
, TORTURE_FAIL
,
715 "Could not create file %s: %s", fpath
,
716 smbcli_errstr(cli
->tree
));
719 smbcli_close(cli
->tree
, fnum
);
721 smbcli_list(cli
->tree
, talloc_asprintf(
722 mem_ctx
, "%s\\*", ucase_dirname
),
723 FILE_ATTRIBUTE_DIRECTORY
|FILE_ATTRIBUTE_HIDDEN
724 |FILE_ATTRIBUTE_SYSTEM
,
725 count_fn
, (void *)&counter
);
731 torture_result(torture
, TORTURE_FAIL
,
732 "expected 3 entries, got %d", counter
);
737 talloc_free(mem_ctx
);
741 static void close_locked_file(struct tevent_context
*ev
,
742 struct tevent_timer
*te
,
746 int *pfd
= (int *)private_data
;
756 struct lock_result_state
{
761 static void receive_lock_result(struct smbcli_request
*req
)
763 struct lock_result_state
*state
=
764 (struct lock_result_state
*)req
->async
.private_data
;
766 state
->status
= smbcli_request_simple_recv(req
);
771 * Check that Samba3 correctly deals with conflicting posix byte range locks
772 * on an underlying file
774 * Note: This test depends on "posix locking = yes".
775 * Note: To run this test, use "--option=torture:localdir=<LOCALDIR>"
778 bool torture_samba3_posixtimedlock(struct torture_context
*tctx
, struct smbcli_state
*cli
)
782 const char *dirname
= "posixlock";
783 const char *fname
= "locked";
785 const char *localdir
;
786 const char *localname
;
790 struct flock posix_lock
;
793 struct smb_lock_entry lock_entry
;
794 struct smbcli_request
*req
;
795 struct lock_result_state lock_result
;
797 struct tevent_timer
*te
;
799 torture_assert(tctx
, torture_setup_dir(cli
, dirname
), "creating test directory");
801 if (!(fpath
= talloc_asprintf(tctx
, "%s\\%s", dirname
, fname
))) {
802 torture_warning(tctx
, "talloc failed\n");
806 fnum
= smbcli_open(cli
->tree
, fpath
, O_RDWR
| O_CREAT
, DENY_NONE
);
808 torture_warning(tctx
, "Could not create file %s: %s\n", fpath
,
809 smbcli_errstr(cli
->tree
));
814 if (!(localdir
= torture_setting_string(tctx
, "localdir", NULL
))) {
815 torture_warning(tctx
, "Need 'localdir' setting\n");
820 if (!(localname
= talloc_asprintf(tctx
, "%s/%s/%s", localdir
, dirname
,
822 torture_warning(tctx
, "talloc failed\n");
828 * Lock a byte range from posix
831 fd
= open(localname
, O_RDWR
);
833 torture_warning(tctx
, "open(%s) failed: %s\n",
834 localname
, strerror(errno
));
838 posix_lock
.l_type
= F_WRLCK
;
839 posix_lock
.l_whence
= SEEK_SET
;
840 posix_lock
.l_start
= 0;
841 posix_lock
.l_len
= 1;
843 if (fcntl(fd
, F_SETLK
, &posix_lock
) == -1) {
844 torture_warning(tctx
, "fcntl failed: %s\n", strerror(errno
));
850 * Try a cifs brlock without timeout to see if posix locking = yes
853 io
.lockx
.in
.ulock_cnt
= 0;
854 io
.lockx
.in
.lock_cnt
= 1;
856 lock_entry
.count
= 1;
857 lock_entry
.offset
= 0;
858 lock_entry
.pid
= cli
->tree
->session
->pid
;
860 io
.lockx
.level
= RAW_LOCK_LOCKX
;
861 io
.lockx
.in
.mode
= LOCKING_ANDX_LARGE_FILES
;
862 io
.lockx
.in
.timeout
= 0;
863 io
.lockx
.in
.locks
= &lock_entry
;
864 io
.lockx
.in
.file
.fnum
= fnum
;
866 status
= smb_raw_lock(cli
->tree
, &io
);
869 CHECK_STATUS(tctx
, status
, NT_STATUS_FILE_LOCK_CONFLICT
);
876 * Now fire off a timed brlock, unlock the posix lock and see if the
877 * timed lock gets through.
880 io
.lockx
.in
.timeout
= 5000;
882 req
= smb_raw_lock_send(cli
->tree
, &io
);
884 torture_warning(tctx
, "smb_raw_lock_send failed\n");
889 lock_result
.done
= false;
890 req
->async
.fn
= receive_lock_result
;
891 req
->async
.private_data
= &lock_result
;
893 te
= tevent_add_timer(tctx
->ev
,
894 tctx
, timeval_current_ofs(1, 0),
895 close_locked_file
, &fd
);
897 torture_warning(tctx
, "tevent_add_timer failed\n");
902 while ((fd
!= -1) || (!lock_result
.done
)) {
903 if (tevent_loop_once(tctx
->ev
) == -1) {
904 torture_warning(tctx
, "tevent_loop_once failed: %s\n",
911 CHECK_STATUS(tctx
, lock_result
.status
, NT_STATUS_OK
);
915 smbcli_close(cli
->tree
, fnum
);
920 smbcli_deltree(cli
->tree
, dirname
);
924 bool torture_samba3_rootdirfid(struct torture_context
*tctx
, struct smbcli_state
*cli
)
928 const char *fname
= "testfile";
931 smbcli_unlink(cli
->tree
, fname
);
934 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
935 io
.ntcreatex
.in
.flags
= NTCREATEX_FLAGS_EXTENDED
;
936 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
937 io
.ntcreatex
.in
.security_flags
= 0;
938 io
.ntcreatex
.in
.access_mask
=
939 SEC_STD_SYNCHRONIZE
| SEC_FILE_EXECUTE
;
940 io
.ntcreatex
.in
.alloc_size
= 0;
941 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_DIRECTORY
;
942 io
.ntcreatex
.in
.share_access
=
943 NTCREATEX_SHARE_ACCESS_READ
944 | NTCREATEX_SHARE_ACCESS_READ
;
945 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
946 io
.ntcreatex
.in
.create_options
= 0;
947 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
948 io
.ntcreatex
.in
.fname
= "\\";
949 torture_assert_ntstatus_equal_goto(tctx
, smb_raw_open(cli
->tree
, tctx
, &io
),
951 ret
, done
, "smb_open on the directory failed: %s\n");
953 dnum
= io
.ntcreatex
.out
.file
.fnum
;
955 io
.ntcreatex
.in
.flags
=
956 NTCREATEX_FLAGS_REQUEST_OPLOCK
957 | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
;
958 io
.ntcreatex
.in
.root_fid
.fnum
= dnum
;
959 io
.ntcreatex
.in
.security_flags
= 0;
960 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
961 io
.ntcreatex
.in
.access_mask
= SEC_RIGHTS_FILE_ALL
;
962 io
.ntcreatex
.in
.alloc_size
= 0;
963 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
964 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
965 io
.ntcreatex
.in
.create_options
= 0;
966 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
967 io
.ntcreatex
.in
.fname
= fname
;
969 torture_assert_ntstatus_equal_goto(tctx
, smb_raw_open(cli
->tree
, tctx
, &io
),
971 ret
, done
, "smb_open on the file failed");
973 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
974 smbcli_close(cli
->tree
, dnum
);
975 smbcli_unlink(cli
->tree
, fname
);
982 bool torture_samba3_oplock_logoff(struct torture_context
*tctx
, struct smbcli_state
*cli
)
986 const char *fname
= "testfile";
988 struct smbcli_request
*req
;
989 struct smb_echo echo_req
;
991 smbcli_unlink(cli
->tree
, fname
);
994 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
995 io
.ntcreatex
.in
.flags
= NTCREATEX_FLAGS_EXTENDED
;
996 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
997 io
.ntcreatex
.in
.security_flags
= 0;
998 io
.ntcreatex
.in
.access_mask
=
999 SEC_STD_SYNCHRONIZE
| SEC_FILE_EXECUTE
;
1000 io
.ntcreatex
.in
.alloc_size
= 0;
1001 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1002 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
1003 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1004 io
.ntcreatex
.in
.create_options
= 0;
1005 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1006 io
.ntcreatex
.in
.fname
= "testfile";
1007 torture_assert_ntstatus_equal_goto(tctx
, smb_raw_open(cli
->tree
, tctx
, &io
),
1009 ret
, done
, "first smb_open on the file failed");
1010 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
1013 * Create a conflicting open, causing the one-second delay
1016 torture_assert_goto(tctx
, req
= smb_raw_open_send(cli
->tree
, &io
),
1017 ret
, done
, "smb_raw_open_send on the file failed");
1020 * Pull the VUID from under that request. As of Nov 3, 2008 all Samba3
1021 * versions (3.0, 3.2 and master) would spin sending ERRinvuid errors
1022 * as long as the client is still connected.
1025 torture_assert_ntstatus_equal_goto(tctx
, smb_raw_ulogoff(cli
->session
),
1027 ret
, done
, "ulogoff failed failed");
1029 echo_req
.in
.repeat_count
= 1;
1030 echo_req
.in
.size
= 1;
1031 echo_req
.in
.data
= discard_const_p(uint8_t, "");
1033 torture_assert_ntstatus_equal_goto(tctx
, smb_raw_echo(cli
->session
->transport
, &echo_req
),
1035 ret
, done
, "smb_raw_echo failed");
1042 bool torture_samba3_check_openX_badname(struct torture_context
*tctx
, struct smbcli_state
*cli
)
1047 DATA_BLOB name_blob
= data_blob_talloc(cli
->tree
, NULL
, 65535);
1049 if (name_blob
.data
== NULL
) {
1052 memset(name_blob
.data
, 0xcc, 65535);
1053 status
= raw_smbcli_openX_name_blob(cli
->tree
, &name_blob
, O_RDWR
, DENY_NONE
, &fnum
);
1054 CHECK_STATUS(tctx
, status
, NT_STATUS_OBJECT_NAME_INVALID
);