wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+269
View File
@@ -0,0 +1,269 @@
/*
Unix SMB/CIFS implementation.
chkpath individual test suite
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define BASEDIR "\\rawchkpath"
#define CHECK_STATUS(status, correct, dos_correct) do { \
if (!NT_STATUS_EQUAL(status, correct) && !NT_STATUS_EQUAL(status, dos_correct)) { \
printf("(%d) Incorrect status %s - should be %s\n", \
__LINE__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
static NTSTATUS single_search(struct smbcli_state *cli,
TALLOC_CTX *mem_ctx, const char *pattern)
{
union smb_search_first io;
NTSTATUS status;
io.t2ffirst.level = RAW_SEARCH_TRANS2;
io.t2ffirst.data_level = RAW_SEARCH_DATA_STANDARD;
io.t2ffirst.in.search_attrib = 0;
io.t2ffirst.in.max_count = 1;
io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
io.t2ffirst.in.storage_type = 0;
io.t2ffirst.in.pattern = pattern;
status = smb_raw_search_first(cli->tree, mem_ctx,
&io, NULL, NULL);
return status;
}
static BOOL test_path(struct smbcli_state *cli, const char *path, NTSTATUS expected, NTSTATUS dos_expected)
{
union smb_chkpath io;
NTSTATUS status;
io.chkpath.in.path = path;
status = smb_raw_chkpath(cli->tree, &io);
if (!NT_STATUS_EQUAL(status, expected) && !NT_STATUS_EQUAL(status, dos_expected)) {
printf("%-40s FAILED %s should be %s or %s\n",
path, nt_errstr(status), nt_errstr(expected), nt_errstr(dos_expected));
return False;
} else {
printf("%-40s correct (%s)\n", path, nt_errstr(status));
}
return True;
}
static BOOL test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_chkpath io;
NTSTATUS status;
BOOL ret = True;
int fnum = -1;
int fnum1 = -1;
io.chkpath.in.path = BASEDIR;
status = smb_raw_chkpath(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK, NT_STATUS_OK);
ret &= test_path(cli, BASEDIR "\\nodir", NT_STATUS_OBJECT_NAME_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
fnum = create_complex_file(cli, mem_ctx, BASEDIR "\\test.txt..");
if (fnum == -1) {
printf("failed to open test.txt - %s\n", smbcli_errstr(cli->tree));
ret = False;
goto done;
}
ret &= test_path(cli, BASEDIR "\\test.txt..", NT_STATUS_NOT_A_DIRECTORY, NT_STATUS_DOS(ERRDOS,ERRbadpath));
if (!torture_set_file_attribute(cli->tree, BASEDIR, FILE_ATTRIBUTE_HIDDEN)) {
printf("failed to set basedir hidden\n");
ret = False;
goto done;
}
ret &= test_path(cli, BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
ret &= test_path(cli, BASEDIR "\\foo\\..\\test.txt..", NT_STATUS_NOT_A_DIRECTORY, NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, "", NT_STATUS_OK, NT_STATUS_OK);
ret &= test_path(cli, ".", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, ".\\", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, "\\\\\\.\\", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, ".\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, "." BASEDIR, NT_STATUS_OBJECT_PATH_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR "\\.", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR "\\.\\test.txt..", NT_STATUS_OBJECT_PATH_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, ".\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, ".\\.\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, ".\\.\\.aaaaa", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, "\\.\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, "\\.\\\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, "\\.\\\\\\\\\\\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
/* Note that the two following paths are identical but
give different NT status returns for chkpth and findfirst. */
printf("testing findfirst on %s\n", "\\.\\\\\\\\\\\\.");
status = single_search(cli, mem_ctx, "\\.\\\\\\\\\\\\.");
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRinvalidname));
ret &= test_path(cli, "\\.\\\\\\\\\\\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
/* We expect this open to fail with the same error code as the chkpath below. */
printf("testing Open on %s\n", "\\.\\\\\\\\\\\\.");
/* findfirst seems to fail with a different error. */
fnum1 = smbcli_nt_create_full(cli->tree, "\\.\\\\\\\\\\\\.",
0, SEC_RIGHTS_FILE_ALL,
FILE_ATTRIBUTE_NORMAL,
NTCREATEX_SHARE_ACCESS_DELETE|
NTCREATEX_SHARE_ACCESS_READ|
NTCREATEX_SHARE_ACCESS_WRITE,
NTCREATEX_DISP_OVERWRITE_IF,
0, 0);
status = smbcli_nt_error(cli->tree);
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, "\\.\\\\xxx", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, "..\\..\\..", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
ret &= test_path(cli, "\\..", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
ret &= test_path(cli, "\\.\\\\\\\\\\\\xxx", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR"\\.\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR"\\.\\\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR"\\.\\nt", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR"\\.\\.\\nt", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR"\\nt", NT_STATUS_OK, NT_STATUS_OK);
ret &= test_path(cli, BASEDIR".\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR"xx\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, ".\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, ".\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, ".\\.\\.\\.\\foo\\.\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR".\\.\\.\\.\\foo\\.\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR".\\.\\.\\.\\foo\\..\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR".", NT_STATUS_OBJECT_NAME_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, "\\", NT_STATUS_OK,NT_STATUS_OK);
ret &= test_path(cli, "\\.", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, "\\..\\", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
ret &= test_path(cli, "\\..", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
ret &= test_path(cli, BASEDIR "\\.", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR "\\..", NT_STATUS_OK,NT_STATUS_OK);
ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb600", NT_STATUS_OBJECT_NAME_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb6.exe", NT_STATUS_NOT_A_DIRECTORY,NT_STATUS_DOS(ERRDOS,ERRbadpath));
/* We expect this open to fail with the same error code as the chkpath below. */
printf("testing Open on %s\n", BASEDIR".\\.\\.\\.\\foo\\..\\.\\");
/* findfirst seems to fail with a different error. */
fnum1 = smbcli_nt_create_full(cli->tree, BASEDIR".\\.\\.\\.\\foo\\..\\.\\",
0, SEC_RIGHTS_FILE_ALL,
FILE_ATTRIBUTE_NORMAL,
NTCREATEX_SHARE_ACCESS_DELETE|
NTCREATEX_SHARE_ACCESS_READ|
NTCREATEX_SHARE_ACCESS_WRITE,
NTCREATEX_DISP_OVERWRITE_IF,
0, 0);
status = smbcli_nt_error(cli->tree);
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
printf("testing findfirst on %s\n", BASEDIR".\\.\\.\\.\\foo\\..\\.\\");
status = single_search(cli, mem_ctx, BASEDIR".\\.\\.\\.\\foo\\..\\.\\");
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
/* We expect this open to fail with the same error code as the chkpath below. */
/* findfirst seems to fail with a different error. */
printf("testing Open on %s\n", BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3");
fnum1 = smbcli_nt_create_full(cli->tree, BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3",
0, SEC_RIGHTS_FILE_ALL,
FILE_ATTRIBUTE_NORMAL,
NTCREATEX_SHARE_ACCESS_DELETE|
NTCREATEX_SHARE_ACCESS_READ|
NTCREATEX_SHARE_ACCESS_WRITE,
NTCREATEX_DISP_OVERWRITE_IF,
0, 0);
status = smbcli_nt_error(cli->tree);
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR "\\nt\\3\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR "\\nt\\V S\\*\\vb6.exe\\3", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
ret &= test_path(cli, BASEDIR "\\nt\\V S\\*\\*\\vb6.exe\\3", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
done:
smbcli_close(cli->tree, fnum);
return ret;
}
/*
basic testing of chkpath calls
*/
BOOL torture_raw_chkpath(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
int fnum;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_chkpath");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR "\\nt"))) {
printf("Failed to create " BASEDIR " - %s\n", smbcli_errstr(cli->tree));
return False;
}
if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR "\\nt\\V S"))) {
printf("Failed to create " BASEDIR " - %s\n", smbcli_errstr(cli->tree));
return False;
}
if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR "\\nt\\V S\\VB98"))) {
printf("Failed to create " BASEDIR " - %s\n", smbcli_errstr(cli->tree));
return False;
}
fnum = create_complex_file(cli, mem_ctx, BASEDIR "\\nt\\V S\\VB98\\vb6.exe");
if (fnum == -1) {
printf("failed to open \\nt\\V S\\VB98\\vb6.exe - %s\n", smbcli_errstr(cli->tree));
ret = False;
goto done;
}
if (!test_chkpath(cli, mem_ctx)) {
ret = False;
}
done:
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+178
View File
@@ -0,0 +1,178 @@
/*
Unix SMB/CIFS implementation.
RAW_CLOSE_* individual test suite
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "system/time.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
/* basic testing of all RAW_CLOSE_* calls
*/
BOOL torture_raw_close(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
union smb_close io;
union smb_flush io_flush;
int fnum;
const char *fname = "\\torture_close.txt";
time_t basetime = (time(NULL) + 3*86400) & ~1;
union smb_fileinfo finfo, finfo2;
NTSTATUS status;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_close");
#define REOPEN do { \
fnum = create_complex_file(cli, mem_ctx, fname); \
if (fnum == -1) { \
printf("(%d) Failed to create %s\n", __LINE__, fname); \
ret = False; \
goto done; \
}} while (0)
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%d) Incorrect status %s - should be %s\n", \
__LINE__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
REOPEN;
io.close.level = RAW_CLOSE_CLOSE;
io.close.in.file.fnum = fnum;
io.close.in.write_time = basetime;
status = smb_raw_close(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
status = smb_raw_close(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("testing close.in.write_time\n");
/* the file should have the write time set */
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
finfo.generic.in.file.path = fname;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
if (basetime != nt_time_to_unix(finfo.all_info.out.write_time)) {
printf("Incorrect write time on file - %s - %s\n",
timestring(mem_ctx, basetime),
nt_time_string(mem_ctx, finfo.all_info.out.write_time));
dump_all_info(mem_ctx, &finfo);
ret = False;
}
printf("testing other times\n");
/* none of the other times should be set to that time */
if (nt_time_equal(&finfo.all_info.out.write_time,
&finfo.all_info.out.access_time) ||
nt_time_equal(&finfo.all_info.out.write_time,
&finfo.all_info.out.create_time) ||
nt_time_equal(&finfo.all_info.out.write_time,
&finfo.all_info.out.change_time)) {
printf("Incorrect times after close - only write time should be set\n");
dump_all_info(mem_ctx, &finfo);
ret = False;
}
smbcli_unlink(cli->tree, fname);
REOPEN;
finfo2.generic.level = RAW_FILEINFO_ALL_INFO;
finfo2.generic.in.file.path = fname;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2);
CHECK_STATUS(status, NT_STATUS_OK);
io.close.level = RAW_CLOSE_CLOSE;
io.close.in.file.fnum = fnum;
io.close.in.write_time = 0;
status = smb_raw_close(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
/* the file should have the write time set equal to access time */
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
finfo.generic.in.file.path = fname;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
if (!nt_time_equal(&finfo.all_info.out.write_time,
&finfo2.all_info.out.write_time)) {
printf("Incorrect write time on file - 0 time should be ignored\n");
dump_all_info(mem_ctx, &finfo);
ret = False;
}
printf("testing splclose\n");
/* check splclose on a file */
REOPEN;
io.splclose.level = RAW_CLOSE_SPLCLOSE;
io.splclose.in.file.fnum = fnum;
status = smb_raw_close(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
printf("testing flush\n");
smbcli_close(cli->tree, fnum);
io_flush.flush.level = RAW_FLUSH_FLUSH;
io_flush.flush.in.file.fnum = fnum;
status = smb_raw_flush(cli->tree, &io_flush);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
io_flush.flush_all.level = RAW_FLUSH_ALL;
status = smb_raw_flush(cli->tree, &io_flush);
CHECK_STATUS(status, NT_STATUS_OK);
REOPEN;
io_flush.flush.level = RAW_FLUSH_FLUSH;
io_flush.flush.in.file.fnum = fnum;
status = smb_raw_flush(cli->tree, &io_flush);
CHECK_STATUS(status, NT_STATUS_OK);
printf("Testing SMBexit\n");
smb_raw_exit(cli->session);
io_flush.flush.level = RAW_FLUSH_FLUSH;
io_flush.flush.in.file.fnum = fnum;
status = smb_raw_flush(cli->tree, &io_flush);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
done:
smbcli_close(cli->tree, fnum);
smbcli_unlink(cli->tree, fname);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+422
View File
@@ -0,0 +1,422 @@
/*
Unix SMB/CIFS implementation.
libcli composite function testing
Copyright (C) Andrew Tridgell 2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "lib/events/events.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "libcli/security/security.h"
#include "libcli/composite/composite.h"
#include "libcli/smb_composite/smb_composite.h"
#include "librpc/gen_ndr/ndr_misc.h"
#include "lib/cmdline/popt_common.h"
#include "torture/util.h"
#define BASEDIR "\\composite"
static void loadfile_complete(struct composite_context *c)
{
int *count = talloc_get_type(c->async.private_data, int);
(*count)++;
}
/*
test a simple savefile/loadfile combination
*/
static BOOL test_loadfile(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
const char *fname = BASEDIR "\\test.txt";
NTSTATUS status;
struct smb_composite_savefile io1;
struct smb_composite_loadfile io2;
struct composite_context **c;
uint8_t *data;
size_t len = random() % 100000;
const int num_ops = 50;
int i;
int *count = talloc_zero(mem_ctx, int);
data = talloc_array(mem_ctx, uint8_t, len);
generate_random_buffer(data, len);
io1.in.fname = fname;
io1.in.data = data;
io1.in.size = len;
printf("testing savefile\n");
status = smb_composite_savefile(cli->tree, &io1);
if (!NT_STATUS_IS_OK(status)) {
printf("savefile failed: %s\n", nt_errstr(status));
return False;
}
io2.in.fname = fname;
printf("testing parallel loadfile with %d ops\n", num_ops);
c = talloc_array(mem_ctx, struct composite_context *, num_ops);
for (i=0;i<num_ops;i++) {
c[i] = smb_composite_loadfile_send(cli->tree, &io2);
c[i]->async.fn = loadfile_complete;
c[i]->async.private_data = count;
}
printf("waiting for completion\n");
while (*count != num_ops) {
event_loop_once(cli->transport->socket->event.ctx);
printf("count=%d\r", *count);
fflush(stdout);
}
printf("count=%d\n", *count);
for (i=0;i<num_ops;i++) {
status = smb_composite_loadfile_recv(c[i], mem_ctx);
if (!NT_STATUS_IS_OK(status)) {
printf("loadfile[%d] failed - %s\n", i, nt_errstr(status));
return False;
}
if (io2.out.size != len) {
printf("wrong length in returned data - %d should be %d\n",
io2.out.size, (int)len);
return False;
}
if (memcmp(io2.out.data, data, len) != 0) {
printf("wrong data in loadfile!\n");
return False;
}
}
talloc_free(data);
return True;
}
/*
test a simple savefile/loadfile combination
*/
static BOOL test_fetchfile(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
const char *fname = BASEDIR "\\test.txt";
NTSTATUS status;
struct smb_composite_savefile io1;
struct smb_composite_fetchfile io2;
struct composite_context **c;
uint8_t *data;
int i;
size_t len = random() % 10000;
extern int torture_numops;
struct event_context *event_ctx;
int *count = talloc_zero(mem_ctx, int);
BOOL ret = True;
data = talloc_array(mem_ctx, uint8_t, len);
generate_random_buffer(data, len);
io1.in.fname = fname;
io1.in.data = data;
io1.in.size = len;
printf("testing savefile\n");
status = smb_composite_savefile(cli->tree, &io1);
if (!NT_STATUS_IS_OK(status)) {
printf("savefile failed: %s\n", nt_errstr(status));
return False;
}
io2.in.dest_host = lp_parm_string(-1, "torture", "host");
io2.in.port = 0;
io2.in.called_name = lp_parm_string(-1, "torture", "host");
io2.in.service = lp_parm_string(-1, "torture", "share");
io2.in.service_type = "A:";
io2.in.credentials = cmdline_credentials;
io2.in.workgroup = lp_workgroup();
io2.in.filename = fname;
printf("testing parallel fetchfile with %d ops\n", torture_numops);
event_ctx = event_context_init(mem_ctx);
c = talloc_array(mem_ctx, struct composite_context *, torture_numops);
for (i=0; i<torture_numops; i++) {
c[i] = smb_composite_fetchfile_send(&io2, event_ctx);
c[i]->async.fn = loadfile_complete;
c[i]->async.private_data = count;
}
printf("waiting for completion\n");
while (*count != torture_numops) {
event_loop_once(event_ctx);
printf("count=%d\r", *count);
fflush(stdout);
}
printf("count=%d\n", *count);
for (i=0;i<torture_numops;i++) {
status = smb_composite_fetchfile_recv(c[i], mem_ctx);
if (!NT_STATUS_IS_OK(status)) {
printf("loadfile[%d] failed - %s\n", i,
nt_errstr(status));
ret = False;
continue;
}
if (io2.out.size != len) {
printf("wrong length in returned data - %d "
"should be %d\n",
io2.out.size, (int)len);
ret = False;
continue;
}
if (memcmp(io2.out.data, data, len) != 0) {
printf("wrong data in loadfile!\n");
ret = False;
continue;
}
}
return ret;
}
/*
test setfileacl
*/
static BOOL test_appendacl(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
struct smb_composite_appendacl **io;
struct smb_composite_appendacl **io_orig;
struct composite_context **c;
struct event_context *event_ctx;
struct security_descriptor *test_sd;
struct security_ace *ace;
struct dom_sid *test_sid;
const int num_ops = 50;
int *count = talloc_zero(mem_ctx, int);
struct smb_composite_savefile io1;
NTSTATUS status;
int i;
io_orig = talloc_array(mem_ctx, struct smb_composite_appendacl *, num_ops);
printf ("creating %d empty files and getting their acls with appendacl\n", num_ops);
for (i = 0; i < num_ops; i++) {
io1.in.fname = talloc_asprintf(io_orig, BASEDIR "\\test%d.txt", i);
io1.in.data = NULL;
io1.in.size = 0;
status = smb_composite_savefile(cli->tree, &io1);
if (!NT_STATUS_IS_OK(status)) {
printf("savefile failed: %s\n", nt_errstr(status));
return False;
}
io_orig[i] = talloc (io_orig, struct smb_composite_appendacl);
io_orig[i]->in.fname = talloc_steal(io_orig[i], io1.in.fname);
io_orig[i]->in.sd = security_descriptor_initialise(io_orig[i]);
status = smb_composite_appendacl(cli->tree, io_orig[i], io_orig[i]);
if (!NT_STATUS_IS_OK(status)) {
printf("appendacl failed: %s\n", nt_errstr(status));
return False;
}
}
/* fill Security Descriptor with aces to be added */
test_sd = security_descriptor_initialise(mem_ctx);
test_sid = dom_sid_parse_talloc (mem_ctx, "S-1-5-32-1234-5432");
ace = talloc_zero(mem_ctx, struct security_ace);
ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
ace->flags = 0;
ace->access_mask = SEC_STD_ALL;
ace->trustee = *test_sid;
status = security_descriptor_dacl_add(test_sd, ace);
if (!NT_STATUS_IS_OK(status)) {
printf("appendacl failed: %s\n", nt_errstr(status));
return False;
}
/* set parameters for appendacl async call */
printf("testing parallel appendacl with %d ops\n", num_ops);
c = talloc_array(mem_ctx, struct composite_context *, num_ops);
io = talloc_array(mem_ctx, struct smb_composite_appendacl *, num_ops);
for (i=0; i < num_ops; i++) {
io[i] = talloc (io, struct smb_composite_appendacl);
io[i]->in.sd = test_sd;
io[i]->in.fname = talloc_asprintf(io[i], BASEDIR "\\test%d.txt", i);
c[i] = smb_composite_appendacl_send(cli->tree, io[i]);
c[i]->async.fn = loadfile_complete;
c[i]->async.private_data = count;
}
event_ctx = talloc_reference(mem_ctx, cli->tree->session->transport->socket->event.ctx);
printf("waiting for completion\n");
while (*count != num_ops) {
event_loop_once(event_ctx);
printf("count=%d\r", *count);
fflush(stdout);
}
printf("count=%d\n", *count);
for (i=0; i < num_ops; i++) {
status = smb_composite_appendacl_recv(c[i], io[i]);
if (!NT_STATUS_IS_OK(status)) {
printf("appendacl[%d] failed - %s\n", i, nt_errstr(status));
return False;
}
security_descriptor_dacl_add(io_orig[i]->out.sd, ace);
if (!security_acl_equal(io_orig[i]->out.sd->dacl, io[i]->out.sd->dacl)) {
printf("appendacl[%d] failed - needed acl isn't set\n", i);
return False;
}
}
talloc_free (ace);
talloc_free (test_sid);
talloc_free (test_sd);
return True;
}
/* test a query FS info by asking for share's GUID */
static BOOL test_fsinfo(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
char *guid = NULL;
NTSTATUS status;
struct smb_composite_fsinfo io1;
struct composite_context **c;
int i;
extern int torture_numops;
struct event_context *event_ctx;
int *count = talloc_zero(mem_ctx, int);
BOOL ret = True;
io1.in.dest_host = lp_parm_string(-1, "torture", "host");
io1.in.port = 0;
io1.in.called_name = lp_parm_string(-1, "torture", "host");
io1.in.service = lp_parm_string(-1, "torture", "share");
io1.in.service_type = "A:";
io1.in.credentials = cmdline_credentials;
io1.in.workgroup = lp_workgroup();
io1.in.level = RAW_QFS_OBJECTID_INFORMATION;
printf("testing parallel queryfsinfo [Object ID] with %d ops\n", torture_numops);
event_ctx = talloc_reference(mem_ctx, cli->tree->session->transport->socket->event.ctx);
c = talloc_array(mem_ctx, struct composite_context *, torture_numops);
for (i=0; i<torture_numops; i++) {
c[i] = smb_composite_fsinfo_send(cli->tree,&io1);
c[i]->async.fn = loadfile_complete;
c[i]->async.private_data = count;
}
printf("waiting for completion\n");
while (*count < torture_numops) {
event_loop_once(event_ctx);
printf("count=%d\r", *count);
fflush(stdout);
}
printf("count=%d\n", *count);
for (i=0;i<torture_numops;i++) {
status = smb_composite_fsinfo_recv(c[i], mem_ctx);
if (!NT_STATUS_IS_OK(status)) {
printf("fsinfo[%d] failed - %s\n", i, nt_errstr(status));
ret = False;
continue;
}
if (io1.out.fsinfo->generic.level != RAW_QFS_OBJECTID_INFORMATION) {
printf("wrong level in returned info - %d "
"should be %d\n",
io1.out.fsinfo->generic.level, RAW_QFS_OBJECTID_INFORMATION);
ret = False;
continue;
}
guid=GUID_string(mem_ctx, &io1.out.fsinfo->objectid_information.out.guid);
printf("[%d] GUID: %s\n", i, guid);
}
return ret;
}
/*
basic testing of libcli composite calls
*/
BOOL torture_raw_composite(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_composite");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
ret &= test_fetchfile(cli, mem_ctx);
ret &= test_loadfile(cli, mem_ctx);
ret &= test_appendacl(cli, mem_ctx);
ret &= test_fsinfo(cli, mem_ctx);
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+915
View File
@@ -0,0 +1,915 @@
/*
Unix SMB/CIFS implementation.
test suite for session setup operations
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/composite/composite.h"
#include "libcli/smb_composite/smb_composite.h"
#include "lib/cmdline/popt_common.h"
#include "lib/events/events.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#include "auth/credentials/credentials.h"
#define BASEDIR "\\rawcontext"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
#define CHECK_VALUE(v, correct) do { \
if ((v) != (correct)) { \
printf("(%s) Incorrect value %s=%d - should be %d\n", \
__location__, #v, v, correct); \
ret = False; \
goto done; \
}} while (0)
#define CHECK_NOT_VALUE(v, correct) do { \
if ((v) == (correct)) { \
printf("(%s) Incorrect value %s=%d - should not be %d\n", \
__location__, #v, v, correct); \
ret = False; \
goto done; \
}} while (0)
/*
test session ops
*/
static BOOL test_session(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
BOOL ret = True;
struct smbcli_session *session;
struct smbcli_session *session2;
struct smbcli_session *session3;
struct smbcli_session *session4;
struct cli_credentials *anon_creds;
struct smbcli_session *sessions[15];
struct composite_context *composite_contexts[15];
struct smbcli_tree *tree;
struct smb_composite_sesssetup setup;
struct smb_composite_sesssetup setups[15];
union smb_open io;
union smb_write wr;
union smb_close cl;
int fnum;
const char *fname = BASEDIR "\\test.txt";
uint8_t c = 1;
int i;
printf("TESTING SESSION HANDLING\n");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("create a second security context on the same transport\n");
session = smbcli_session_init(cli->transport, mem_ctx, False);
setup.in.sesskey = cli->transport->negotiate.sesskey;
setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
setup.in.workgroup = lp_workgroup();
setup.in.credentials = cmdline_credentials;
status = smb_composite_sesssetup(session, &setup);
CHECK_STATUS(status, NT_STATUS_OK);
session->vuid = setup.out.vuid;
printf("create a third security context on the same transport, with vuid set\n");
session2 = smbcli_session_init(cli->transport, mem_ctx, False);
session2->vuid = session->vuid;
setup.in.sesskey = cli->transport->negotiate.sesskey;
setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
setup.in.workgroup = lp_workgroup();
setup.in.credentials = cmdline_credentials;
status = smb_composite_sesssetup(session2, &setup);
CHECK_STATUS(status, NT_STATUS_OK);
session2->vuid = setup.out.vuid;
printf("vuid1=%d vuid2=%d vuid3=%d\n", cli->session->vuid, session->vuid, session2->vuid);
if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
/* Samba4 currently fails this - we need to determine if this insane behaviour is important */
if (session2->vuid == session->vuid) {
printf("server allows the user to re-use an existing vuid in session setup \n");
}
} else {
CHECK_NOT_VALUE(session2->vuid, session->vuid);
}
talloc_free(session2);
if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
printf("create a fourth security context on the same transport, without extended security\n");
session3 = smbcli_session_init(cli->transport, mem_ctx, False);
session3->vuid = session->vuid;
setup.in.sesskey = cli->transport->negotiate.sesskey;
setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
setup.in.workgroup = lp_workgroup();
setup.in.credentials = cmdline_credentials;
status = smb_composite_sesssetup(session3, &setup);
CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
printf("create a fouth anonymous security context on the same transport, without extended security\n");
session4 = smbcli_session_init(cli->transport, mem_ctx, False);
session4->vuid = session->vuid;
setup.in.sesskey = cli->transport->negotiate.sesskey;
setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
setup.in.workgroup = lp_workgroup();
anon_creds = cli_credentials_init(mem_ctx);
cli_credentials_set_conf(anon_creds);
cli_credentials_set_anonymous(anon_creds);
setup.in.credentials = anon_creds;
status = smb_composite_sesssetup(session3, &setup);
CHECK_STATUS(status, NT_STATUS_OK);
talloc_free(session4);
}
printf("use the same tree as the existing connection\n");
tree = smbcli_tree_init(session, mem_ctx, False);
tree->tid = cli->tree->tid;
printf("create a file using the new vuid\n");
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname;
status = smb_raw_open(tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
printf("write using the old vuid\n");
wr.generic.level = RAW_WRITE_WRITEX;
wr.writex.in.file.fnum = fnum;
wr.writex.in.offset = 0;
wr.writex.in.wmode = 0;
wr.writex.in.remaining = 0;
wr.writex.in.count = 1;
wr.writex.in.data = &c;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("write with the new vuid\n");
status = smb_raw_write(tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
printf("logoff the new vuid\n");
status = smb_raw_ulogoff(session);
CHECK_STATUS(status, NT_STATUS_OK);
printf("the new vuid should not now be accessible\n");
status = smb_raw_write(tree, &wr);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("second logoff for the new vuid should fail\n");
status = smb_raw_ulogoff(session);
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRbaduid));
talloc_free(session);
printf("the fnum should have been auto-closed\n");
cl.close.level = RAW_CLOSE_CLOSE;
cl.close.in.file.fnum = fnum;
cl.close.in.write_time = 0;
status = smb_raw_close(cli->tree, &cl);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("create %d secondary security contexts on the same transport\n",
(int)ARRAY_SIZE(sessions));
for (i=0; i <ARRAY_SIZE(sessions); i++) {
setups[i].in.sesskey = cli->transport->negotiate.sesskey;
setups[i].in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
setups[i].in.workgroup = lp_workgroup();
setups[i].in.credentials = cmdline_credentials;
sessions[i] = smbcli_session_init(cli->transport, mem_ctx, False);
composite_contexts[i] = smb_composite_sesssetup_send(sessions[i], &setups[i]);
}
/* flush the queue */
for (i=0; i < ARRAY_SIZE(sessions); i++) {
event_loop_once(composite_contexts[0]->event_ctx);
}
printf("finishing %d secondary security contexts on the same transport\n",
(int)ARRAY_SIZE(sessions));
for (i=0; i< ARRAY_SIZE(sessions); i++) {
status = smb_composite_sesssetup_recv(composite_contexts[i]);
CHECK_STATUS(status, NT_STATUS_OK);
sessions[i]->vuid = setups[i].out.vuid;
printf("VUID: %d\n", sessions[i]->vuid);
status = smb_raw_ulogoff(sessions[i]);
CHECK_STATUS(status, NT_STATUS_OK);
}
talloc_free(tree);
done:
return ret;
}
/*
test tree ops
*/
static BOOL test_tree(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
BOOL ret = True;
const char *share, *host;
struct smbcli_tree *tree;
union smb_tcon tcon;
union smb_open io;
union smb_write wr;
union smb_close cl;
int fnum;
const char *fname = BASEDIR "\\test.txt";
uint8_t c = 1;
printf("TESTING TREE HANDLING\n");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
share = lp_parm_string(-1, "torture", "share");
host = lp_parm_string(-1, "torture", "host");
printf("create a second tree context on the same session\n");
tree = smbcli_tree_init(cli->session, mem_ctx, False);
tcon.generic.level = RAW_TCON_TCONX;
tcon.tconx.in.flags = 0;
tcon.tconx.in.password = data_blob(NULL, 0);
tcon.tconx.in.path = talloc_asprintf(mem_ctx, "\\\\%s\\%s", host, share);
tcon.tconx.in.device = "A:";
status = smb_raw_tcon(tree, mem_ctx, &tcon);
CHECK_STATUS(status, NT_STATUS_OK);
tree->tid = tcon.tconx.out.tid;
printf("tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
printf("try a tconx with a bad device type\n");
tcon.tconx.in.device = "FOO";
status = smb_raw_tcon(tree, mem_ctx, &tcon);
CHECK_STATUS(status, NT_STATUS_BAD_DEVICE_TYPE);
printf("create a file using the new tid\n");
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname;
status = smb_raw_open(tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
printf("write using the old tid\n");
wr.generic.level = RAW_WRITE_WRITEX;
wr.writex.in.file.fnum = fnum;
wr.writex.in.offset = 0;
wr.writex.in.wmode = 0;
wr.writex.in.remaining = 0;
wr.writex.in.count = 1;
wr.writex.in.data = &c;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("write with the new tid\n");
status = smb_raw_write(tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
printf("disconnect the new tid\n");
status = smb_tree_disconnect(tree);
CHECK_STATUS(status, NT_STATUS_OK);
printf("the new tid should not now be accessible\n");
status = smb_raw_write(tree, &wr);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("the fnum should have been auto-closed\n");
cl.close.level = RAW_CLOSE_CLOSE;
cl.close.in.file.fnum = fnum;
cl.close.in.write_time = 0;
status = smb_raw_close(cli->tree, &cl);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
/* close down the new tree */
talloc_free(tree);
done:
return ret;
}
/*
test tree with ulogoff
this demonstrates that a tcon isn't autoclosed by a ulogoff
the tcon can be reused using any other valid session later
*/
static BOOL test_tree_ulogoff(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
BOOL ret = True;
const char *share, *host;
struct smbcli_session *session1;
struct smbcli_session *session2;
struct smb_composite_sesssetup setup;
struct smbcli_tree *tree;
union smb_tcon tcon;
union smb_open io;
union smb_write wr;
int fnum1, fnum2;
const char *fname1 = BASEDIR "\\test1.txt";
const char *fname2 = BASEDIR "\\test2.txt";
uint8_t c = 1;
printf("TESTING TREE with ulogoff\n");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
share = lp_parm_string(-1, "torture", "share");
host = lp_parm_string(-1, "torture", "host");
printf("create the first new sessions\n");
session1 = smbcli_session_init(cli->transport, mem_ctx, False);
setup.in.sesskey = cli->transport->negotiate.sesskey;
setup.in.capabilities = cli->transport->negotiate.capabilities;
setup.in.workgroup = lp_workgroup();
setup.in.credentials = cmdline_credentials;
status = smb_composite_sesssetup(session1, &setup);
CHECK_STATUS(status, NT_STATUS_OK);
session1->vuid = setup.out.vuid;
printf("vuid1=%d\n", session1->vuid);
printf("create a tree context on the with vuid1\n");
tree = smbcli_tree_init(session1, mem_ctx, False);
tcon.generic.level = RAW_TCON_TCONX;
tcon.tconx.in.flags = 0;
tcon.tconx.in.password = data_blob(NULL, 0);
tcon.tconx.in.path = talloc_asprintf(mem_ctx, "\\\\%s\\%s", host, share);
tcon.tconx.in.device = "A:";
status = smb_raw_tcon(tree, mem_ctx, &tcon);
CHECK_STATUS(status, NT_STATUS_OK);
tree->tid = tcon.tconx.out.tid;
printf("tid=%d\n", tree->tid);
printf("create a file using vuid1\n");
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname1;
status = smb_raw_open(tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum1 = io.ntcreatex.out.file.fnum;
printf("write using vuid1\n");
wr.generic.level = RAW_WRITE_WRITEX;
wr.writex.in.file.fnum = fnum1;
wr.writex.in.offset = 0;
wr.writex.in.wmode = 0;
wr.writex.in.remaining = 0;
wr.writex.in.count = 1;
wr.writex.in.data = &c;
status = smb_raw_write(tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
printf("ulogoff the vuid1\n");
status = smb_raw_ulogoff(session1);
CHECK_STATUS(status, NT_STATUS_OK);
printf("create the second new sessions\n");
session2 = smbcli_session_init(cli->transport, mem_ctx, False);
setup.in.sesskey = cli->transport->negotiate.sesskey;
setup.in.capabilities = cli->transport->negotiate.capabilities;
setup.in.workgroup = lp_workgroup();
setup.in.credentials = cmdline_credentials;
status = smb_composite_sesssetup(session2, &setup);
CHECK_STATUS(status, NT_STATUS_OK);
session2->vuid = setup.out.vuid;
printf("vuid2=%d\n", session2->vuid);
printf("use the existing tree with vuid2\n");
tree->session = session2;
printf("create a file using vuid2\n");
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname2;
status = smb_raw_open(tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
printf("write using vuid2\n");
wr.generic.level = RAW_WRITE_WRITEX;
wr.writex.in.file.fnum = fnum2;
wr.writex.in.offset = 0;
wr.writex.in.wmode = 0;
wr.writex.in.remaining = 0;
wr.writex.in.count = 1;
wr.writex.in.data = &c;
status = smb_raw_write(tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
printf("ulogoff the vuid2\n");
status = smb_raw_ulogoff(session2);
CHECK_STATUS(status, NT_STATUS_OK);
/* this also demonstrates that SMBtdis doesn't need a valid vuid */
printf("disconnect the existing tree connection\n");
status = smb_tree_disconnect(tree);
CHECK_STATUS(status, NT_STATUS_OK);
printf("disconnect the existing tree connection\n");
status = smb_tree_disconnect(tree);
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV,ERRinvnid));
/* close down the new tree */
talloc_free(tree);
done:
return ret;
}
/*
test pid ops
this test demonstrates that exit() only sees the PID
used for the open() calls
*/
static BOOL test_pid_exit_only_sees_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
BOOL ret = True;
union smb_open io;
union smb_write wr;
union smb_close cl;
int fnum;
const char *fname = BASEDIR "\\test.txt";
uint8_t c = 1;
uint16_t pid1, pid2;
printf("TESTING PID HANDLING exit() only cares about open() PID\n");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
pid1 = cli->session->pid;
pid2 = pid1 + 1;
printf("pid1=%d pid2=%d\n", pid1, pid2);
printf("create a file using pid1\n");
cli->session->pid = pid1;
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
printf("write using pid2\n");
cli->session->pid = pid2;
wr.generic.level = RAW_WRITE_WRITEX;
wr.writex.in.file.fnum = fnum;
wr.writex.in.offset = 0;
wr.writex.in.wmode = 0;
wr.writex.in.remaining = 0;
wr.writex.in.count = 1;
wr.writex.in.data = &c;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
printf("exit pid2\n");
cli->session->pid = pid2;
status = smb_raw_exit(cli->session);
CHECK_STATUS(status, NT_STATUS_OK);
printf("the fnum should still be accessible via pid2\n");
cli->session->pid = pid2;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
printf("exit pid2\n");
cli->session->pid = pid2;
status = smb_raw_exit(cli->session);
CHECK_STATUS(status, NT_STATUS_OK);
printf("the fnum should still be accessible via pid1 and pid2\n");
cli->session->pid = pid1;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
cli->session->pid = pid2;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
printf("exit pid1\n");
cli->session->pid = pid1;
status = smb_raw_exit(cli->session);
CHECK_STATUS(status, NT_STATUS_OK);
printf("the fnum should not now be accessible via pid1 or pid2\n");
cli->session->pid = pid1;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
cli->session->pid = pid2;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("the fnum should have been auto-closed\n");
cli->session->pid = pid1;
cl.close.level = RAW_CLOSE_CLOSE;
cl.close.in.file.fnum = fnum;
cl.close.in.write_time = 0;
status = smb_raw_close(cli->tree, &cl);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
done:
return ret;
}
/*
test pid ops with 2 sessions
*/
static BOOL test_pid_2sess(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
BOOL ret = True;
struct smbcli_session *session;
struct smb_composite_sesssetup setup;
union smb_open io;
union smb_write wr;
union smb_close cl;
int fnum;
const char *fname = BASEDIR "\\test.txt";
uint8_t c = 1;
uint16_t vuid1, vuid2;
printf("TESTING PID HANDLING WITH 2 SESSIONS\n");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("create a second security context on the same transport\n");
session = smbcli_session_init(cli->transport, mem_ctx, False);
setup.in.sesskey = cli->transport->negotiate.sesskey;
setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
setup.in.workgroup = lp_workgroup();
setup.in.credentials = cmdline_credentials;
status = smb_composite_sesssetup(session, &setup);
CHECK_STATUS(status, NT_STATUS_OK);
session->vuid = setup.out.vuid;
vuid1 = cli->session->vuid;
vuid2 = session->vuid;
printf("vuid1=%d vuid2=%d\n", vuid1, vuid2);
printf("create a file using the vuid1\n");
cli->session->vuid = vuid1;
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
printf("write using the vuid1 (fnum=%d)\n", fnum);
cli->session->vuid = vuid1;
wr.generic.level = RAW_WRITE_WRITEX;
wr.writex.in.file.fnum = fnum;
wr.writex.in.offset = 0;
wr.writex.in.wmode = 0;
wr.writex.in.remaining = 0;
wr.writex.in.count = 1;
wr.writex.in.data = &c;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
printf("exit the pid with vuid2\n");
cli->session->vuid = vuid2;
status = smb_raw_exit(cli->session);
CHECK_STATUS(status, NT_STATUS_OK);
printf("the fnum should still be accessible\n");
cli->session->vuid = vuid1;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
printf("exit the pid with vuid1\n");
cli->session->vuid = vuid1;
status = smb_raw_exit(cli->session);
CHECK_STATUS(status, NT_STATUS_OK);
printf("the fnum should not now be accessible\n");
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("the fnum should have been auto-closed\n");
cl.close.level = RAW_CLOSE_CLOSE;
cl.close.in.file.fnum = fnum;
cl.close.in.write_time = 0;
status = smb_raw_close(cli->tree, &cl);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
done:
return ret;
}
/*
test pid ops with 2 tcons
*/
static BOOL test_pid_2tcon(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
BOOL ret = True;
const char *share, *host;
struct smbcli_tree *tree;
union smb_tcon tcon;
union smb_open io;
union smb_write wr;
union smb_close cl;
int fnum1, fnum2;
const char *fname1 = BASEDIR "\\test1.txt";
const char *fname2 = BASEDIR "\\test2.txt";
uint8_t c = 1;
uint16_t tid1, tid2;
printf("TESTING PID HANDLING WITH 2 TCONS\n");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
share = lp_parm_string(-1, "torture", "share");
host = lp_parm_string(-1, "torture", "host");
printf("create a second tree context on the same session\n");
tree = smbcli_tree_init(cli->session, mem_ctx, False);
tcon.generic.level = RAW_TCON_TCONX;
tcon.tconx.in.flags = 0;
tcon.tconx.in.password = data_blob(NULL, 0);
tcon.tconx.in.path = talloc_asprintf(mem_ctx, "\\\\%s\\%s", host, share);
tcon.tconx.in.device = "A:";
status = smb_raw_tcon(tree, mem_ctx, &tcon);
CHECK_STATUS(status, NT_STATUS_OK);
tree->tid = tcon.tconx.out.tid;
tid1 = cli->tree->tid;
tid2 = tree->tid;
printf("tid1=%d tid2=%d\n", tid1, tid2);
printf("create a file using the tid1\n");
cli->tree->tid = tid1;
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname1;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum1 = io.ntcreatex.out.file.fnum;
printf("write using the tid1\n");
wr.generic.level = RAW_WRITE_WRITEX;
wr.writex.in.file.fnum = fnum1;
wr.writex.in.offset = 0;
wr.writex.in.wmode = 0;
wr.writex.in.remaining = 0;
wr.writex.in.count = 1;
wr.writex.in.data = &c;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
printf("create a file using the tid2\n");
cli->tree->tid = tid2;
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname2;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
printf("write using the tid2\n");
wr.generic.level = RAW_WRITE_WRITEX;
wr.writex.in.file.fnum = fnum2;
wr.writex.in.offset = 0;
wr.writex.in.wmode = 0;
wr.writex.in.remaining = 0;
wr.writex.in.count = 1;
wr.writex.in.data = &c;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, 1);
printf("exit the pid\n");
status = smb_raw_exit(cli->session);
CHECK_STATUS(status, NT_STATUS_OK);
printf("the fnum1 on tid1 should not be accessible\n");
cli->tree->tid = tid1;
wr.writex.in.file.fnum = fnum1;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("the fnum1 on tid1 should have been auto-closed\n");
cl.close.level = RAW_CLOSE_CLOSE;
cl.close.in.file.fnum = fnum1;
cl.close.in.write_time = 0;
status = smb_raw_close(cli->tree, &cl);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("the fnum2 on tid2 should not be accessible\n");
cli->tree->tid = tid2;
wr.writex.in.file.fnum = fnum2;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("the fnum2 on tid2 should have been auto-closed\n");
cl.close.level = RAW_CLOSE_CLOSE;
cl.close.in.file.fnum = fnum2;
cl.close.in.write_time = 0;
status = smb_raw_close(cli->tree, &cl);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
done:
return ret;
}
/*
basic testing of session/tree context calls
*/
static BOOL torture_raw_context_int(void)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_context");
ret &= test_session(cli, mem_ctx);
ret &= test_tree(cli, mem_ctx);
ret &= test_tree_ulogoff(cli, mem_ctx);
ret &= test_pid_exit_only_sees_open(cli, mem_ctx);
ret &= test_pid_2sess(cli, mem_ctx);
ret &= test_pid_2tcon(cli, mem_ctx);
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
/*
basic testing of session/tree context calls
*/
BOOL torture_raw_context(struct torture_context *torture)
{
BOOL ret = True;
if (lp_use_spnego()) {
ret &= torture_raw_context_int();
lp_set_cmdline("use spnego", "False");
}
ret &= torture_raw_context_int();
return ret;
}
+504
View File
@@ -0,0 +1,504 @@
/*
Unix SMB/CIFS implementation.
test DOS extended attributes
Copyright (C) Andrew Tridgell 2004
Copyright (C) Guenter Kukkukk 2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define BASEDIR "\\testeas"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
static BOOL maxeadebug; /* need that here, to allow no file delete in debug case */
static BOOL check_ea(struct smbcli_state *cli,
const char *fname, const char *eaname, const char *value)
{
NTSTATUS status = torture_check_ea(cli, fname, eaname, value);
return NT_STATUS_IS_OK(status);
}
static BOOL test_eas(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
union smb_setfileinfo setfile;
union smb_open io;
const char *fname = BASEDIR "\\ea.txt";
BOOL ret = True;
int fnum = -1;
printf("TESTING SETFILEINFO EA_SET\n");
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access =
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
ret &= check_ea(cli, fname, "EAONE", NULL);
printf("Adding first two EAs\n");
setfile.generic.level = RAW_SFILEINFO_EA_SET;
setfile.generic.in.file.fnum = fnum;
setfile.ea_set.in.num_eas = 2;
setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
setfile.ea_set.in.eas[0].flags = 0;
setfile.ea_set.in.eas[0].name.s = "EAONE";
setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE1");
setfile.ea_set.in.eas[1].flags = 0;
setfile.ea_set.in.eas[1].name.s = "SECONDEA";
setfile.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo");
status = smb_raw_setfileinfo(cli->tree, &setfile);
CHECK_STATUS(status, NT_STATUS_OK);
ret &= check_ea(cli, fname, "EAONE", "VALUE1");
ret &= check_ea(cli, fname, "SECONDEA", "ValueTwo");
printf("Modifying 2nd EA\n");
setfile.ea_set.in.num_eas = 1;
setfile.ea_set.in.eas[0].name.s = "SECONDEA";
setfile.ea_set.in.eas[0].value = data_blob_string_const(" Changed Value");
status = smb_raw_setfileinfo(cli->tree, &setfile);
CHECK_STATUS(status, NT_STATUS_OK);
ret &= check_ea(cli, fname, "EAONE", "VALUE1");
ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
printf("Setting a NULL EA\n");
setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
setfile.ea_set.in.eas[0].name.s = "NULLEA";
status = smb_raw_setfileinfo(cli->tree, &setfile);
CHECK_STATUS(status, NT_STATUS_OK);
ret &= check_ea(cli, fname, "EAONE", "VALUE1");
ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
ret &= check_ea(cli, fname, "NULLEA", NULL);
printf("Deleting first EA\n");
setfile.ea_set.in.eas[0].flags = 0;
setfile.ea_set.in.eas[0].name.s = "EAONE";
setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
status = smb_raw_setfileinfo(cli->tree, &setfile);
CHECK_STATUS(status, NT_STATUS_OK);
ret &= check_ea(cli, fname, "EAONE", NULL);
ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
printf("Deleting second EA\n");
setfile.ea_set.in.eas[0].flags = 0;
setfile.ea_set.in.eas[0].name.s = "SECONDEA";
setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
status = smb_raw_setfileinfo(cli->tree, &setfile);
CHECK_STATUS(status, NT_STATUS_OK);
ret &= check_ea(cli, fname, "EAONE", NULL);
ret &= check_ea(cli, fname, "SECONDEA", NULL);
done:
smbcli_close(cli->tree, fnum);
return ret;
}
/*
* Helper function to retrieve the max. ea size for one ea name
*/
static int test_one_eamax(struct smbcli_state *cli, const int fnum,
const char *eaname, DATA_BLOB eablob,
const int eastart, const int eadebug)
{
NTSTATUS status;
struct ea_struct eastruct;
union smb_setfileinfo setfile;
int i, high, low, maxeasize;
setfile.generic.level = RAW_SFILEINFO_EA_SET;
setfile.generic.in.file.fnum = fnum;
setfile.ea_set.in.num_eas = 1;
setfile.ea_set.in.eas = &eastruct;
setfile.ea_set.in.eas->flags = 0;
setfile.ea_set.in.eas->name.s = eaname;
setfile.ea_set.in.eas->value = eablob;
maxeasize = eablob.length;
i = eastart;
low = 0;
high = maxeasize;
do {
if (eadebug) {
printf ("Testing EA size: %d\n", i);
}
setfile.ea_set.in.eas->value.length = i;
status = smb_raw_setfileinfo(cli->tree, &setfile);
if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
if (eadebug) {
printf ("[%s] EA size %d succeeded! "
"(high=%d low=%d)\n",
eaname, i, high, low);
}
low = i;
if (low == maxeasize) {
printf ("Max. EA size for \"%s\"=%d "
"[but could be possibly larger]\n",
eaname, low);
break;
}
if (high - low == 1 && high != maxeasize) {
printf ("Max. EA size for \"%s\"=%d\n",
eaname, low);
break;
}
i += (high - low + 1) / 2;
} else {
if (eadebug) {
printf ("[%s] EA size %d failed! "
"(high=%d low=%d) [%s]\n",
eaname, i, high, low,
nt_errstr(status));
}
high = i;
if (high - low <= 1) {
printf ("Max. EA size for \"%s\"=%d\n",
eaname, low);
break;
}
i -= (high - low + 1) / 2;
}
} while (True);
return low;
}
/*
* Test for maximum ea size - more than one ea name is checked.
*
* Additional parameters can be passed, to allow further testing:
*
* default
* maxeasize 65536 limit the max. size for a single EA name
* maxeanames 101 limit of the number of tested names
* maxeastart 1 this EA size is used to test for the 1st EA (atm)
* maxeadebug 0 if set True, further debug output is done - in addition
* the testfile is not deleted for further inspection!
*
* Set some/all of these options on the cmdline with:
* --option torture:maxeasize=1024 --option torture:maxeadebug=1 ...
*
*/
static BOOL test_max_eas(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
union smb_open io;
const char *fname = BASEDIR "\\ea_max.txt";
int fnum = -1;
BOOL ret = True;
BOOL err = False;
int i, j, k, last, total;
DATA_BLOB eablob;
char *eaname = NULL;
int maxeasize;
int maxeanames;
int maxeastart;
printf("TESTING SETFILEINFO MAX. EA_SET\n");
maxeasize = lp_parm_int(-1, "torture", "maxeasize", 65536);
maxeanames = lp_parm_int(-1, "torture", "maxeanames", 101);
maxeastart = lp_parm_int(-1, "torture", "maxeastart", 1);
maxeadebug = lp_parm_int(-1, "torture", "maxeadebug", 0);
/* Do some sanity check on possibly passed parms */
if (maxeasize <= 0) {
printf("Invalid parameter 'maxeasize=%d'",maxeasize);
err = True;
}
if (maxeanames <= 0) {
printf("Invalid parameter 'maxeanames=%d'",maxeanames);
err = True;
}
if (maxeastart <= 0) {
printf("Invalid parameter 'maxeastart=%d'",maxeastart);
err = True;
}
if (maxeadebug < 0) {
printf("Invalid parameter 'maxeadebug=%d'",maxeadebug);
err = True;
}
if (err) {
printf("\n\n");
goto done;
}
if (maxeastart > maxeasize) {
maxeastart = maxeasize;
printf ("'maxeastart' outside range - corrected to %d\n",
maxeastart);
}
printf("MAXEA parms: maxeasize=%d maxeanames=%d maxeastart=%d"
" maxeadebug=%d\n", maxeasize, maxeanames, maxeastart,
maxeadebug);
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access =
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
eablob = data_blob_talloc(mem_ctx, NULL, maxeasize);
if (eablob.data == NULL) {
goto done;
}
/*
* Fill in some EA data - the offset could be easily checked
* during a hexdump.
*/
for (i = 0, k = 0; i < eablob.length / 4; i++, k+=4) {
eablob.data[k] = k & 0xff;
eablob.data[k+1] = (k >> 8) & 0xff;
eablob.data[k+2] = (k >> 16) & 0xff;
eablob.data[k+3] = (k >> 24) & 0xff;
}
i = eablob.length % 4;
if (i-- > 0) {
eablob.data[k] = k & 0xff;
if (i-- > 0) {
eablob.data[k+1] = (k >> 8) & 0xff;
if (i-- > 0) {
eablob.data[k+2] = (k >> 16) & 0xff;
}
}
}
/*
* Filesystems might allow max. EAs data for different EA names.
* So more than one EA name should be checked.
*/
total = 0;
last = maxeastart;
for (i = 0; i < maxeanames; i++) {
if (eaname != NULL) {
talloc_free(eaname);
}
eaname = talloc_asprintf(mem_ctx, "MAX%d", i);
if(eaname == NULL) {
goto done;
}
j = test_one_eamax(cli, fnum, eaname, eablob, last, maxeadebug);
if (j <= 0) {
break;
}
total += j;
last = j;
}
printf("Total EA size:%d\n", total);
if (i == maxeanames) {
printf ("NOTE: More EAs could be available!\n");
}
if (total == 0) {
ret = False;
}
done:
smbcli_close(cli->tree, fnum);
return ret;
}
/*
test using NTTRANS CREATE to create a file with an initial EA set
*/
static BOOL test_nttrans_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
union smb_open io;
const char *fname = BASEDIR "\\ea2.txt";
BOOL ret = True;
int fnum = -1;
struct ea_struct eas[3];
struct smb_ea_list ea_list;
printf("TESTING NTTRANS CREATE WITH EAS\n");
io.generic.level = RAW_OPEN_NTTRANS_CREATE;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access =
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname;
ea_list.num_eas = 3;
ea_list.eas = eas;
eas[0].flags = 0;
eas[0].name.s = "1st EA";
eas[0].value = data_blob_string_const("Value One");
eas[1].flags = 0;
eas[1].name.s = "2nd EA";
eas[1].value = data_blob_string_const("Second Value");
eas[2].flags = 0;
eas[2].name.s = "and 3rd";
eas[2].value = data_blob_string_const("final value");
io.ntcreatex.in.ea_list = &ea_list;
io.ntcreatex.in.sec_desc = NULL;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
ret &= check_ea(cli, fname, "EAONE", NULL);
ret &= check_ea(cli, fname, "1st EA", "Value One");
ret &= check_ea(cli, fname, "2nd EA", "Second Value");
ret &= check_ea(cli, fname, "and 3rd", "final value");
smbcli_close(cli->tree, fnum);
printf("Trying to add EAs on non-create\n");
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
io.ntcreatex.in.fname = fname;
ea_list.num_eas = 1;
eas[0].flags = 0;
eas[0].name.s = "Fourth EA";
eas[0].value = data_blob_string_const("Value Four");
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
ret &= check_ea(cli, fname, "1st EA", "Value One");
ret &= check_ea(cli, fname, "2nd EA", "Second Value");
ret &= check_ea(cli, fname, "and 3rd", "final value");
ret &= check_ea(cli, fname, "Fourth EA", NULL);
done:
smbcli_close(cli->tree, fnum);
return ret;
}
/*
basic testing of EA calls
*/
BOOL torture_raw_eas(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_eas");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
ret &= test_eas(cli, mem_ctx);
ret &= test_nttrans_create(cli, mem_ctx);
smb_raw_exit(cli->session);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
/*
test max EA size
*/
BOOL torture_max_eas(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_eas");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
ret &= test_max_eas(cli, mem_ctx);
smb_raw_exit(cli->session);
if (!maxeadebug) {
/* in no ea debug case, all files are gone now */
smbcli_deltree(cli->tree, BASEDIR);
}
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+185
View File
@@ -0,0 +1,185 @@
/*
Unix SMB/CIFS implementation.
ioctl individual test suite
Copyright (C) Andrew Tridgell 2003
Copyright (C) James J Myers 2003 <myersjj@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/ioctl.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define BASEDIR "\\rawioctl"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%d) Incorrect status %s - should be %s\n", \
__LINE__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
/* test some ioctls */
static BOOL test_ioctl(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_ioctl ctl;
int fnum;
NTSTATUS status;
BOOL ret = True;
const char *fname = BASEDIR "\\test.dat";
printf("TESTING IOCTL FUNCTIONS\n");
fnum = create_complex_file(cli, mem_ctx, fname);
if (fnum == -1) {
printf("Failed to create test.dat - %s\n", smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("Trying 0xFFFF\n");
ctl.ioctl.level = RAW_IOCTL_IOCTL;
ctl.ioctl.in.file.fnum = fnum;
ctl.ioctl.in.request = 0xFFFF;
status = smb_raw_ioctl(cli->tree, mem_ctx, &ctl);
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
printf("Trying QUERY_JOB_INFO\n");
ctl.ioctl.level = RAW_IOCTL_IOCTL;
ctl.ioctl.in.file.fnum = fnum;
ctl.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
status = smb_raw_ioctl(cli->tree, mem_ctx, &ctl);
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
printf("Trying bad handle\n");
ctl.ioctl.in.file.fnum = fnum+1;
status = smb_raw_ioctl(cli->tree, mem_ctx, &ctl);
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
done:
smbcli_close(cli->tree, fnum);
return ret;
}
/* test some filesystem control functions */
static BOOL test_fsctl(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
int fnum;
NTSTATUS status;
BOOL ret = True;
const char *fname = BASEDIR "\\test.dat";
union smb_ioctl nt;
printf("\nTESTING FSCTL FUNCTIONS\n");
fnum = create_complex_file(cli, mem_ctx, fname);
if (fnum == -1) {
printf("Failed to create test.dat - %s\n", smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("trying sparse file\n");
nt.ioctl.level = RAW_IOCTL_NTIOCTL;
nt.ntioctl.in.function = FSCTL_SET_SPARSE;
nt.ntioctl.in.file.fnum = fnum;
nt.ntioctl.in.fsctl = True;
nt.ntioctl.in.filter = 0;
nt.ntioctl.in.max_data = 0;
nt.ntioctl.in.blob = data_blob(NULL, 0);
status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
CHECK_STATUS(status, NT_STATUS_OK);
printf("trying batch oplock\n");
nt.ioctl.level = RAW_IOCTL_NTIOCTL;
nt.ntioctl.in.function = FSCTL_REQUEST_BATCH_OPLOCK;
nt.ntioctl.in.file.fnum = fnum;
nt.ntioctl.in.fsctl = True;
nt.ntioctl.in.filter = 0;
nt.ntioctl.in.max_data = 0;
nt.ntioctl.in.blob = data_blob(NULL, 0);
status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
if (NT_STATUS_IS_OK(status)) {
printf("Server supports batch oplock upgrades on open files\n");
} else {
printf("Server does not support batch oplock upgrades on open files\n");
}
printf("Trying bad handle\n");
nt.ntioctl.in.file.fnum = fnum+1;
status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
#if 0
nt.ntioctl.in.file.fnum = fnum;
for (i=0;i<100;i++) {
nt.ntioctl.in.function = FSCTL_FILESYSTEM + (i<<2);
status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
printf("filesystem fsctl 0x%x - %s\n",
i, nt_errstr(status));
}
}
#endif
done:
smbcli_close(cli->tree, fnum);
return ret;
}
/*
basic testing of some ioctl calls
*/
BOOL torture_raw_ioctl(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_ioctl");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
if (!test_ioctl(cli, mem_ctx)) {
ret = False;
}
if (!test_fsctl(cli, mem_ctx)) {
ret = False;
}
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
File diff suppressed because it is too large Load Diff
+196
View File
@@ -0,0 +1,196 @@
/*
Unix SMB/CIFS implementation.
locking benchmark
Copyright (C) Andrew Tridgell 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "system/time.h"
#include "system/filesys.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#include "lib/events/events.h"
#include "lib/cmdline/popt_common.h"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
goto failed; \
}} while (0)
#define BASEDIR "\\benchlock"
#define FNAME BASEDIR "\\lock.dat"
static int nprocs;
static int lock_failed;
struct benchlock_state {
struct smbcli_state *cli;
int fnum;
int offset;
int count;
union smb_lock io;
struct smb_lock_entry lock[2];
struct smbcli_request *req;
};
static void lock_completion(struct smbcli_request *);
/*
send the next lock request
*/
static void lock_send(struct benchlock_state *state)
{
state->io.lockx.in.file.fnum = state->fnum;
state->io.lockx.in.ulock_cnt = 1;
state->lock[0].pid = state->cli->session->pid;
state->lock[1].pid = state->cli->session->pid;
state->lock[0].offset = state->offset;
state->lock[1].offset = (state->offset+1)%nprocs;
state->req = smb_raw_lock_send(state->cli->tree, &state->io);
if (state->req == NULL) {
DEBUG(0,("Failed to setup lock\n"));
lock_failed++;
}
state->req->async.private = state;
state->req->async.fn = lock_completion;
state->offset = (state->offset+1)%nprocs;
}
/*
called when a lock completes
*/
static void lock_completion(struct smbcli_request *req)
{
struct benchlock_state *state = (struct benchlock_state *)req->async.private;
NTSTATUS status = smbcli_request_simple_recv(req);
if (!NT_STATUS_IS_OK(status)) {
lock_failed++;
DEBUG(0,("Lock failed - %s\n", nt_errstr(status)));
} else {
state->count++;
lock_send(state);
}
}
/*
benchmark locking calls
*/
BOOL torture_bench_lock(struct torture_context *torture)
{
BOOL ret = True;
TALLOC_CTX *mem_ctx = talloc_new(torture);
int i;
int timelimit = torture_setting_int(torture, "timelimit", 10);
struct timeval tv;
struct event_context *ev = event_context_find(mem_ctx);
struct benchlock_state *state;
int total = 0, loops=0;
NTSTATUS status;
nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
state = talloc_zero_array(mem_ctx, struct benchlock_state, nprocs);
printf("Opening %d connections\n", nprocs);
for (i=0;i<nprocs;i++) {
if (!torture_open_connection_ev(&state[i].cli, i, ev)) {
return False;
}
talloc_steal(mem_ctx, state);
}
if (!torture_setup_dir(state[0].cli, BASEDIR)) {
goto failed;
}
for (i=0;i<nprocs;i++) {
state[i].fnum = smbcli_open(state[i].cli->tree,
FNAME,
O_RDWR|O_CREAT, DENY_NONE);
if (state[i].fnum == -1) {
printf("Failed to open %s on connection %d\n", FNAME, i);
goto failed;
}
state[i].io.lockx.level = RAW_LOCK_LOCKX;
state[i].io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
state[i].io.lockx.in.timeout = 100000;
state[i].io.lockx.in.ulock_cnt = 0;
state[i].io.lockx.in.lock_cnt = 1;
state[i].lock[0].count = 1;
state[i].lock[1].count = 1;
state[i].io.lockx.in.locks = &state[i].lock[0];
state[i].offset = i;
state[i].io.lockx.in.file.fnum = state[i].fnum;
state[i].lock[0].offset = state[i].offset;
state[i].lock[0].pid = state[i].cli->session->pid;
status = smb_raw_lock(state[i].cli->tree, &state[i].io);
CHECK_STATUS(status, NT_STATUS_OK);
}
for (i=0;i<nprocs;i++) {
lock_send(&state[i]);
}
tv = timeval_current();
printf("Running for %d seconds\n", timelimit);
while (timeval_elapsed(&tv) < timelimit) {
event_loop_once(ev);
if (lock_failed) {
DEBUG(0,("locking failed\n"));
goto failed;
}
if (loops++ % 10 != 0) continue;
total = 0;
for (i=0;i<nprocs;i++) {
total += state[i].count;
}
printf("%.2f ops/second\r", total/timeval_elapsed(&tv));
fflush(stdout);
}
printf("%.2f ops/second\n", total/timeval_elapsed(&tv));
for (i=0;i<nprocs;i++) {
talloc_free(state[i].req);
smb_raw_exit(state[i].cli->session);
}
smbcli_deltree(state[0].cli->tree, BASEDIR);
talloc_free(mem_ctx);
return ret;
failed:
for (i=0;i<nprocs;i++) {
talloc_free(state[i].req);
smb_raw_exit(state[i].cli->session);
}
smbcli_deltree(state[0].cli->tree, BASEDIR);
talloc_free(mem_ctx);
return False;
}
+160
View File
@@ -0,0 +1,160 @@
- RAW-CONTEXT passes on nt4 but TCON doesn't !!??
- all messaging commands
- writebraw
- writebmpx
- acl ops
- readbmpx
- rap commands
- rpc commands
- SMBcopy
- SMBtcon
- SMBecho
- SMBfunique
- SMBsearch vs SMBffirst?
- SMBfclose
- SMBkeepalive
- secondary trans2 and nttrans
- trans2 ioctl
- trans2 session setup
- trans2 DFS ops
- unix ops
--------------
done:
mkdir
rmdir
open
create
close
flush
unlink
mv
getatr
setatr
read
write
lock
unlock
ctemp
mknew
chkpath
exit
lseek
tconX
tdis
negprot
dskattr
search
lockread
writeunlock
readbraw
setattrE
getattrE
lockingX
ioctl
openX
readX
writeX
sesssetupX
trans2
findclose
ulogoffX
nttrans
ntcreateX
ntcancel
trans2_open
trans2_findfirst
trans2_findnext?
trans2_qfsinfo
trans2_setfsinfo
trans2_qpathinfo
trans2_setpathinfo
trans2_qfileinfo
trans2_setfileinfo
trans2_fsctl
trans2_mkdir
trans2_findnext
NTrename
SMB_QFS_ALLOCATION
SMB_QFS_VOLUME
SMB_QFS_VOLUME_INFO
SMB_QFS_SIZE_INFO
SMB_QFS_DEVICE_INFO
SMB_QFS_ATTRIBUTE_INFO
SMB_QFS_VOLUME_INFORMATION
SMB_QFS_SIZE_INFORMATION
SMB_QFS_DEVICE_INFORMATION
SMB_QFS_ATTRIBUTE_INFORMATION
SMB_QFS_QUOTA_INFORMATION
SMB_QFS_FULL_SIZE_INFORMATION
SMB_QFS_OBJECTID_INFORMATION
SMB_QFILEINFO_STANDARD
SMB_QFILEINFO_EA_SIZE
SMB_QFILEINFO_ALL_EAS
SMB_QFILEINFO_IS_NAME_VALID
SMB_QFILEINFO_BASIC_INFO
SMB_QFILEINFO_STANDARD_INFO
SMB_QFILEINFO_EA_INFO
SMB_QFILEINFO_NAME_INFO
SMB_QFILEINFO_ALL_INFO
SMB_QFILEINFO_ALT_NAME_INFO
SMB_QFILEINFO_STREAM_INFO
SMB_QFILEINFO_COMPRESSION_INFO
SMB_QFILEINFO_BASIC_INFORMATION
SMB_QFILEINFO_STANDARD_INFORMATION
SMB_QFILEINFO_INTERNAL_INFORMATION
SMB_QFILEINFO_EA_INFORMATION
SMB_QFILEINFO_ACCESS_INFORMATION
SMB_QFILEINFO_NAME_INFORMATION
SMB_QFILEINFO_POSITION_INFORMATION
SMB_QFILEINFO_MODE_INFORMATION
SMB_QFILEINFO_ALIGNMENT_INFORMATION
SMB_QFILEINFO_ALL_INFORMATION
SMB_QFILEINFO_ALT_NAME_INFORMATION
SMB_QFILEINFO_STREAM_INFORMATION
SMB_QFILEINFO_COMPRESSION_INFORMATION
SMB_QFILEINFO_NETWORK_OPEN_INFORMATION
SMB_QFILEINFO_ATTRIBUTE_TAG_INFORMATION
SMB_SFILEINFO_STANDARD
SMB_SFILEINFO_EA_SET
SMB_SFILEINFO_BASIC_INFO
SMB_SFILEINFO_DISPOSITION_INFO
SMB_SFILEINFO_ALLOCATION_INFO
SMB_SFILEINFO_END_OF_FILE_INFO
SMB_SFILEINFO_UNIX_BASIC
SMB_SFILEINFO_UNIX_LINK
SMB_SFILEINFO_BASIC_INFORMATION
SMB_SFILEINFO_RENAME_INFORMATION
SMB_SFILEINFO_DISPOSITION_INFORMATION
SMB_SFILEINFO_POSITION_INFORMATION
SMB_SFILEINFO_MODE_INFORMATION
SMB_SFILEINFO_ALLOCATION_INFORMATION
SMB_SFILEINFO_END_OF_FILE_INFORMATION
SMB_FIND_STANDARD
SMB_FIND_EA_SIZE
SMB_FIND_DIRECTORY_INFO
SMB_FIND_FULL_DIRECTORY_INFO
SMB_FIND_NAME_INFO
SMB_FIND_BOTH_DIRECTORY_INFO
SMB_FIND_261
SMB_FIND_262
+167
View File
@@ -0,0 +1,167 @@
/*
Unix SMB/CIFS implementation.
RAW_MKDIR_* and RAW_RMDIR_* individual test suite
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define BASEDIR "\\mkdirtest"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
/*
test mkdir ops
*/
static BOOL test_mkdir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_mkdir md;
struct smb_rmdir rd;
const char *path = BASEDIR "\\mkdir.dir";
NTSTATUS status;
BOOL ret = True;
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
/*
basic mkdir
*/
md.mkdir.level = RAW_MKDIR_MKDIR;
md.mkdir.in.path = path;
status = smb_raw_mkdir(cli->tree, &md);
CHECK_STATUS(status, NT_STATUS_OK);
printf("testing mkdir collision\n");
/* 2nd create */
status = smb_raw_mkdir(cli->tree, &md);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
/* basic rmdir */
rd.in.path = path;
status = smb_raw_rmdir(cli->tree, &rd);
CHECK_STATUS(status, NT_STATUS_OK);
status = smb_raw_rmdir(cli->tree, &rd);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
printf("testing mkdir collision with file\n");
/* name collision with a file */
smbcli_close(cli->tree, create_complex_file(cli, mem_ctx, path));
status = smb_raw_mkdir(cli->tree, &md);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
printf("testing rmdir with file\n");
/* delete a file with rmdir */
status = smb_raw_rmdir(cli->tree, &rd);
CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
smbcli_unlink(cli->tree, path);
printf("testing invalid dir\n");
/* create an invalid dir */
md.mkdir.in.path = "..\\..\\..";
status = smb_raw_mkdir(cli->tree, &md);
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
printf("testing t2mkdir\n");
/* try a t2mkdir - need to work out why this fails! */
md.t2mkdir.level = RAW_MKDIR_T2MKDIR;
md.t2mkdir.in.path = path;
md.t2mkdir.in.num_eas = 0;
status = smb_raw_mkdir(cli->tree, &md);
CHECK_STATUS(status, NT_STATUS_OK);
status = smb_raw_rmdir(cli->tree, &rd);
CHECK_STATUS(status, NT_STATUS_OK);
printf("testing t2mkdir with EAs\n");
/* with EAs */
md.t2mkdir.level = RAW_MKDIR_T2MKDIR;
md.t2mkdir.in.path = path;
md.t2mkdir.in.num_eas = 3;
md.t2mkdir.in.eas = talloc_array(mem_ctx, struct ea_struct, md.t2mkdir.in.num_eas);
md.t2mkdir.in.eas[0].flags = 0;
md.t2mkdir.in.eas[0].name.s = "EAONE";
md.t2mkdir.in.eas[0].value = data_blob_talloc(mem_ctx, "blah", 4);
md.t2mkdir.in.eas[1].flags = 0;
md.t2mkdir.in.eas[1].name.s = "EA TWO";
md.t2mkdir.in.eas[1].value = data_blob_talloc(mem_ctx, "foo bar", 7);
md.t2mkdir.in.eas[2].flags = 0;
md.t2mkdir.in.eas[2].name.s = "EATHREE";
md.t2mkdir.in.eas[2].value = data_blob_talloc(mem_ctx, "xx1", 3);
status = smb_raw_mkdir(cli->tree, &md);
CHECK_STATUS(status, NT_STATUS_OK);
status = torture_check_ea(cli, path, "EAONE", "blah");
CHECK_STATUS(status, NT_STATUS_OK);
status = torture_check_ea(cli, path, "EA TWO", "foo bar");
CHECK_STATUS(status, NT_STATUS_OK);
status = torture_check_ea(cli, path, "EATHREE", "xx1");
CHECK_STATUS(status, NT_STATUS_OK);
status = smb_raw_rmdir(cli->tree, &rd);
CHECK_STATUS(status, NT_STATUS_OK);
done:
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
basic testing of all RAW_MKDIR_* calls
*/
BOOL torture_raw_mkdir(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_mkdir");
if (!test_mkdir(cli, mem_ctx)) {
ret = False;
}
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+343
View File
@@ -0,0 +1,343 @@
/*
Unix SMB/CIFS implementation.
basic raw test suite for multiplexing
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "system/filesys.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define BASEDIR "\\test_mux"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
/*
test the delayed reply to a open that leads to a sharing violation
*/
static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_open io;
NTSTATUS status;
int fnum1, fnum2;
BOOL ret = True;
struct smbcli_request *req1, *req2;
struct timeval tv;
double d;
printf("testing multiplexed open/open/close\n");
printf("send first open\n");
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = BASEDIR "\\open.dat";
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum1 = io.ntcreatex.out.file.fnum;
printf("send 2nd open, non-conflicting\n");
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
tv = timeval_current();
printf("send 3rd open, conflicting\n");
io.ntcreatex.in.share_access = 0;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
d = timeval_elapsed(&tv);
if (d < 0.5 || d > 1.5) {
printf("bad timeout for conflict - %.2f should be 1.0\n", d);
} else {
printf("open delay %.2f\n", d);
}
printf("send async open, conflicting\n");
tv = timeval_current();
req1 = smb_raw_open_send(cli->tree, &io);
printf("send 2nd async open, conflicting\n");
tv = timeval_current();
req2 = smb_raw_open_send(cli->tree, &io);
printf("close first sync open\n");
smbcli_close(cli->tree, fnum1);
printf("cancel 2nd async open (should be ignored)\n");
smb_raw_ntcancel(req2);
d = timeval_elapsed(&tv);
if (d > 0.25) {
printf("bad timeout after cancel - %.2f should be <0.25\n", d);
ret = False;
}
printf("close the 2nd sync open\n");
smbcli_close(cli->tree, fnum2);
printf("see if the 1st async open now succeeded\n");
status = smb_raw_open_recv(req1, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
d = timeval_elapsed(&tv);
if (d > 0.25) {
printf("bad timeout for async conflict - %.2f should be <0.25\n", d);
ret = False;
} else {
printf("async open delay %.2f\n", d);
}
printf("2nd async open should have timed out\n");
status = smb_raw_open_recv(req2, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
d = timeval_elapsed(&tv);
if (d < 0.8) {
printf("bad timeout for async conflict - %.2f should be 1.0\n", d);
}
printf("close the 1st async open\n");
smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
done:
return ret;
}
/*
test a write that hits a byte range lock and send the close after the write
*/
static BOOL test_mux_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_write io;
NTSTATUS status;
int fnum;
BOOL ret = True;
struct smbcli_request *req;
printf("testing multiplexed lock/write/close\n");
fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
if (fnum == -1) {
printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
ret = False;
goto done;
}
cli->session->pid = 1;
/* lock a range */
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 0, 4, 0, WRITE_LOCK))) {
printf("lock failed in mux_write - %s\n", smbcli_errstr(cli->tree));
ret = False;
goto done;
}
cli->session->pid = 2;
/* send an async write */
io.generic.level = RAW_WRITE_WRITEX;
io.writex.in.file.fnum = fnum;
io.writex.in.offset = 0;
io.writex.in.wmode = 0;
io.writex.in.remaining = 0;
io.writex.in.count = 4;
io.writex.in.data = (void *)&fnum;
req = smb_raw_write_send(cli->tree, &io);
/* unlock the range */
cli->session->pid = 1;
smbcli_unlock(cli->tree, fnum, 0, 4);
/* and recv the async write reply */
status = smb_raw_write_recv(req, &io);
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
smbcli_close(cli->tree, fnum);
done:
return ret;
}
/*
test a lock that conflicts with an existing lock
*/
static BOOL test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_lock io;
NTSTATUS status;
int fnum;
BOOL ret = True;
struct smbcli_request *req;
struct smb_lock_entry lock[1];
printf("TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n");
fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
if (fnum == -1) {
printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("establishing a lock\n");
io.lockx.level = RAW_LOCK_LOCKX;
io.lockx.in.file.fnum = fnum;
io.lockx.in.mode = 0;
io.lockx.in.timeout = 0;
io.lockx.in.lock_cnt = 1;
io.lockx.in.ulock_cnt = 0;
lock[0].pid = 1;
lock[0].offset = 0;
lock[0].count = 4;
io.lockx.in.locks = &lock[0];
status = smb_raw_lock(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
printf("the second lock will conflict with the first\n");
lock[0].pid = 2;
io.lockx.in.timeout = 1000;
status = smb_raw_lock(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
printf("this will too, but we'll unlock while waiting\n");
req = smb_raw_lock_send(cli->tree, &io);
printf("unlock the first range\n");
lock[0].pid = 1;
io.lockx.in.ulock_cnt = 1;
io.lockx.in.lock_cnt = 0;
io.lockx.in.timeout = 0;
status = smb_raw_lock(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
printf("recv the async reply\n");
status = smbcli_request_simple_recv(req);
CHECK_STATUS(status, NT_STATUS_OK);
printf("reopening with an exit\n");
smb_raw_exit(cli->session);
fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
printf("Now trying with a cancel\n");
io.lockx.level = RAW_LOCK_LOCKX;
io.lockx.in.file.fnum = fnum;
io.lockx.in.mode = 0;
io.lockx.in.timeout = 0;
io.lockx.in.lock_cnt = 1;
io.lockx.in.ulock_cnt = 0;
lock[0].pid = 1;
lock[0].offset = 0;
lock[0].count = 4;
io.lockx.in.locks = &lock[0];
status = smb_raw_lock(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
lock[0].pid = 2;
io.lockx.in.timeout = 1000;
status = smb_raw_lock(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
req = smb_raw_lock_send(cli->tree, &io);
/* cancel the blocking lock */
smb_raw_ntcancel(req);
/* the 2nd cancel is totally harmless, but tests the server trying to
cancel an already cancelled request */
smb_raw_ntcancel(req);
lock[0].pid = 1;
io.lockx.in.ulock_cnt = 1;
io.lockx.in.lock_cnt = 0;
io.lockx.in.timeout = 0;
status = smb_raw_lock(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
status = smbcli_request_simple_recv(req);
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
smbcli_close(cli->tree, fnum);
done:
return ret;
}
/*
basic testing of multiplexing notify
*/
BOOL torture_raw_mux(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_mux");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
if (!test_mux_open(cli, mem_ctx)) {
ret = False;
}
if (!test_mux_write(cli, mem_ctx)) {
ret = False;
}
if (!test_mux_lock(cli, mem_ctx)) {
ret = False;
}
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+841
View File
@@ -0,0 +1,841 @@
/*
Unix SMB/CIFS implementation.
basic raw test suite for oplocks
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "librpc/gen_ndr/security.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#include "lib/events/events.h"
#define CHECK_VAL(v, correct) do { \
if ((v) != (correct)) { \
printf("(%d) wrong value for %s got 0x%x - should be 0x%x\n", \
__LINE__, #v, (int)v, (int)correct); \
ret = False; \
}} while (0)
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%d) Incorrect status %s - should be %s\n", \
__LINE__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
static struct {
int fnum;
uint8_t level;
int count;
int failures;
} break_info;
#define BASEDIR "\\test_notify"
/*
a handler function for oplock break requests. Ack it as a break to level II if possible
*/
static BOOL oplock_handler_ack_to_levelII(struct smbcli_transport *transport, uint16_t tid,
uint16_t fnum, uint8_t level, void *private)
{
struct smbcli_tree *tree = private;
break_info.fnum = fnum;
break_info.level = level;
break_info.count++;
printf("Acking to level II in oplock handler\n");
return smbcli_oplock_ack(tree, fnum, level);
}
/*
a handler function for oplock break requests. Ack it as a break to none
*/
static BOOL oplock_handler_ack_to_none(struct smbcli_transport *transport, uint16_t tid,
uint16_t fnum, uint8_t level,
void *private)
{
struct smbcli_tree *tree = private;
break_info.fnum = fnum;
break_info.level = level;
break_info.count++;
printf("Acking to none in oplock handler\n");
return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
}
static void oplock_handler_close_recv(struct smbcli_request *req)
{
NTSTATUS status;
status = smbcli_request_simple_recv(req);
if (!NT_STATUS_IS_OK(status)) {
printf("close failed in oplock_handler_close\n");
break_info.failures++;
}
}
/*
a handler function for oplock break requests - close the file
*/
static BOOL oplock_handler_close(struct smbcli_transport *transport, uint16_t tid,
uint16_t fnum, uint8_t level, void *private)
{
union smb_close io;
struct smbcli_tree *tree = private;
struct smbcli_request *req;
break_info.fnum = fnum;
break_info.level = level;
break_info.count++;
io.close.level = RAW_CLOSE_CLOSE;
io.close.in.file.fnum = fnum;
io.close.in.write_time = 0;
req = smb_raw_close_send(tree, &io);
if (req == NULL) {
printf("failed to send close in oplock_handler_close\n");
return False;
}
req->async.fn = oplock_handler_close_recv;
req->async.private = NULL;
return True;
}
/*
test oplock ops
*/
static BOOL test_oplock(struct smbcli_state *cli1, struct smbcli_state *cli2, TALLOC_CTX *mem_ctx)
{
const char *fname = BASEDIR "\\test_oplock.dat";
NTSTATUS status;
BOOL ret = True;
union smb_open io;
union smb_unlink unl;
union smb_read rd;
union smb_setfileinfo sfi;
uint16_t fnum=0, fnum2=0;
char c = 0;
/* cleanup */
smbcli_unlink(cli1->tree, fname);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
/*
base ntcreatex parms
*/
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname;
printf("open a file with a normal oplock\n");
ZERO_STRUCT(break_info);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
printf("a 2nd open should not cause a break\n");
status = smb_raw_open(cli2->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
CHECK_VAL(break_info.count, 0);
CHECK_VAL(break_info.failures, 0);
printf("unlink it - should also be no break\n");
unl.unlink.in.pattern = fname;
unl.unlink.in.attrib = 0;
status = smb_raw_unlink(cli2->tree, &unl);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
CHECK_VAL(break_info.count, 0);
CHECK_VAL(break_info.failures, 0);
smbcli_close(cli1->tree, fnum);
/*
with a batch oplock we get a break
*/
printf("open with batch oplock\n");
ZERO_STRUCT(break_info);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
printf("unlink should generate a break\n");
unl.unlink.in.pattern = fname;
unl.unlink.in.attrib = 0;
status = smb_raw_unlink(cli2->tree, &unl);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.fnum, fnum);
CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
CHECK_VAL(break_info.failures, 0);
printf("2nd unlink should not generate a break\n");
ZERO_STRUCT(break_info);
status = smb_raw_unlink(cli2->tree, &unl);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
CHECK_VAL(break_info.count, 0);
printf("writing should generate a self break to none\n");
smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
msleep(100);
smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.fnum, fnum);
CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
CHECK_VAL(break_info.failures, 0);
smbcli_close(cli1->tree, fnum);
printf("open with batch oplock\n");
ZERO_STRUCT(break_info);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
printf("unlink should generate a break, which we ack as break to none\n");
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none, cli1->tree);
unl.unlink.in.pattern = fname;
unl.unlink.in.attrib = 0;
status = smb_raw_unlink(cli2->tree, &unl);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.fnum, fnum);
CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
CHECK_VAL(break_info.failures, 0);
printf("2nd unlink should not generate a break\n");
ZERO_STRUCT(break_info);
status = smb_raw_unlink(cli2->tree, &unl);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
CHECK_VAL(break_info.count, 0);
printf("writing should not generate a break\n");
smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
msleep(100);
smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
CHECK_VAL(break_info.count, 0);
smbcli_close(cli1->tree, fnum);
printf("if we close on break then the unlink can succeed\n");
ZERO_STRUCT(break_info);
smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
unl.unlink.in.pattern = fname;
unl.unlink.in.attrib = 0;
ZERO_STRUCT(break_info);
status = smb_raw_unlink(cli2->tree, &unl);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.fnum, fnum);
CHECK_VAL(break_info.level, 1);
CHECK_VAL(break_info.failures, 0);
printf("a self read should not cause a break\n");
ZERO_STRUCT(break_info);
smbcli_close(cli1->tree, fnum);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
rd.read.level = RAW_READ_READ;
rd.read.in.file.fnum = fnum;
rd.read.in.count = 1;
rd.read.in.offset = 0;
rd.read.in.remaining = 0;
status = smb_raw_read(cli1->tree, &rd);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VAL(break_info.count, 0);
CHECK_VAL(break_info.failures, 0);
printf("a 2nd open should give a break\n");
ZERO_STRUCT(break_info);
smbcli_close(cli1->tree, fnum);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
ZERO_STRUCT(break_info);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
status = smb_raw_open(cli2->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.fnum, fnum);
CHECK_VAL(break_info.level, 1);
CHECK_VAL(break_info.failures, 0);
printf("a 2nd open should give a break to level II if the first open allowed shared read\n");
ZERO_STRUCT(break_info);
smbcli_close(cli1->tree, fnum);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
ZERO_STRUCT(break_info);
status = smb_raw_open(cli2->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.fnum, fnum);
CHECK_VAL(break_info.level, 1);
CHECK_VAL(break_info.failures, 0);
ZERO_STRUCT(break_info);
printf("write should trigger a break to none on both\n");
smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
msleep(100);
smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
CHECK_VAL(break_info.count, 2);
CHECK_VAL(break_info.level, 0);
CHECK_VAL(break_info.failures, 0);
smbcli_close(cli1->tree, fnum);
smbcli_close(cli2->tree, fnum2);
printf("a 2nd open should get an oplock when we close instead of ack\n");
ZERO_STRUCT(break_info);
smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
ZERO_STRUCT(break_info);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
status = smb_raw_open(cli2->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.fnum, fnum2);
CHECK_VAL(break_info.level, 1);
CHECK_VAL(break_info.failures, 0);
smbcli_close(cli2->tree, fnum);
printf("open with batch oplock\n");
ZERO_STRUCT(break_info);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
ZERO_STRUCT(break_info);
printf("second open with attributes only shouldn't cause oplock break\n");
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
status = smb_raw_open(cli2->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
CHECK_VAL(break_info.count, 0);
CHECK_VAL(break_info.failures, 0);
smbcli_close(cli1->tree, fnum);
smbcli_close(cli2->tree, fnum2);
smbcli_unlink(cli1->tree, fname);
printf("open with attributes only can create file\n");
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
printf("Subsequent normal open should break oplock on attribute only open to level II\n");
ZERO_STRUCT(break_info);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
status = smb_raw_open(cli2->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.fnum, fnum);
CHECK_VAL(break_info.failures, 0);
CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
smbcli_close(cli2->tree, fnum2);
printf("third oplocked open should grant level2 without break\n");
ZERO_STRUCT(break_info);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
status = smb_raw_open(cli2->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
CHECK_VAL(break_info.count, 0);
CHECK_VAL(break_info.failures, 0);
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
ZERO_STRUCT(break_info);
printf("write should trigger a break to none on both\n");
smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
/* Now the oplock break request comes in. But right now we can't
* answer it. Do another write */
msleep(100);
smbcli_write(cli2->tree, fnum2, 0, &c, 1, 1);
CHECK_VAL(break_info.count, 2);
CHECK_VAL(break_info.level, 0);
CHECK_VAL(break_info.failures, 0);
smbcli_close(cli1->tree, fnum);
smbcli_close(cli2->tree, fnum2);
ZERO_STRUCT(break_info);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
printf("Open with oplock after a on-oplock open should grant level2\n");
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
NTCREATEX_SHARE_ACCESS_WRITE|
NTCREATEX_SHARE_ACCESS_DELETE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(break_info.count, 0);
CHECK_VAL(break_info.failures, 0);
CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
NTCREATEX_SHARE_ACCESS_WRITE|
NTCREATEX_SHARE_ACCESS_DELETE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
status = smb_raw_open(cli2->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
CHECK_VAL(break_info.count, 0);
CHECK_VAL(break_info.failures, 0);
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
printf("write should trigger a break to none\n");
{
union smb_write wr;
wr.write.level = RAW_WRITE_WRITE;
wr.write.in.file.fnum = fnum;
wr.write.in.count = 1;
wr.write.in.offset = 0;
wr.write.in.remaining = 0;
wr.write.in.data = (const uint8_t *)"x";
status = smb_raw_write(cli1->tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
}
/* Now the oplock break request comes in. But right now we can't
* answer it. Do another write */
msleep(100);
{
union smb_write wr;
wr.write.level = RAW_WRITE_WRITE;
wr.write.in.file.fnum = fnum;
wr.write.in.count = 1;
wr.write.in.offset = 0;
wr.write.in.remaining = 0;
wr.write.in.data = (const uint8_t *)"x";
status = smb_raw_write(cli1->tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
}
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.fnum, fnum2);
CHECK_VAL(break_info.level, 0);
CHECK_VAL(break_info.failures, 0);
smbcli_close(cli1->tree, fnum);
smbcli_close(cli2->tree, fnum2);
smbcli_unlink(cli1->tree, fname);
/* Test if a set-eof on pathname breaks an exclusive oplock. */
printf("Test if setpathinfo set EOF breaks oplocks.\n");
ZERO_STRUCT(break_info);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
NTCREATEX_SHARE_ACCESS_WRITE|
NTCREATEX_SHARE_ACCESS_DELETE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(break_info.count, 0);
CHECK_VAL(break_info.failures, 0);
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
ZERO_STRUCT(sfi);
sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
sfi.generic.in.file.path = fname;
sfi.end_of_file_info.in.size = 100;
status = smb_raw_setpathinfo(cli2->tree, &sfi);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.failures, 0);
CHECK_VAL(break_info.level, 0);
smbcli_close(cli1->tree, fnum);
smbcli_unlink(cli1->tree, fname);
/* Test if a set-allocation size on pathname breaks an exclusive oplock. */
printf("Test if setpathinfo allocation size breaks oplocks.\n");
ZERO_STRUCT(break_info);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
NTCREATEX_SHARE_ACCESS_WRITE|
NTCREATEX_SHARE_ACCESS_DELETE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(break_info.count, 0);
CHECK_VAL(break_info.failures, 0);
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
ZERO_STRUCT(sfi);
sfi.generic.level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
sfi.generic.in.file.path = fname;
sfi.allocation_info.in.alloc_size = 65536 * 8;
status = smb_raw_setpathinfo(cli2->tree, &sfi);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.failures, 0);
CHECK_VAL(break_info.level, 0);
smbcli_close(cli1->tree, fnum);
smbcli_close(cli2->tree, fnum2);
smbcli_unlink(cli1->tree, fname);
printf("open with batch oplock\n");
ZERO_STRUCT(break_info);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
ZERO_STRUCT(break_info);
printf("second open with attributes only and NTCREATEX_DISP_OVERWRITE dispostion causes oplock break\n");
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
status = smb_raw_open(cli2->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.failures, 0);
smbcli_close(cli1->tree, fnum);
smbcli_close(cli2->tree, fnum2);
smbcli_unlink(cli1->tree, fname);
printf("open with batch oplock\n");
ZERO_STRUCT(break_info);
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
status = smb_raw_open(cli1->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
ZERO_STRUCT(break_info);
printf("second open with attributes only and NTCREATEX_DISP_SUPERSEDE dispostion causes oplock break\n");
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
status = smb_raw_open(cli2->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
CHECK_VAL(break_info.count, 1);
CHECK_VAL(break_info.failures, 0);
smbcli_close(cli1->tree, fnum);
smbcli_close(cli2->tree, fnum2);
smbcli_unlink(cli1->tree, fname);
done:
smbcli_close(cli1->tree, fnum);
smbcli_close(cli2->tree, fnum2);
smbcli_unlink(cli1->tree, fname);
return ret;
}
/*
basic testing of oplocks
*/
BOOL torture_raw_oplock(struct torture_context *torture)
{
struct smbcli_state *cli1, *cli2;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli1, 0)) {
return False;
}
if (!torture_open_connection_ev(
&cli2, 1, cli1->transport->socket->event.ctx)) {
return False;
}
if (!torture_setup_dir(cli1, BASEDIR)) {
return False;
}
mem_ctx = talloc_init("torture_raw_oplock");
if (!test_oplock(cli1, cli2, mem_ctx)) {
ret = False;
}
smb_raw_exit(cli1->session);
smbcli_deltree(cli1->tree, BASEDIR);
torture_close_connection(cli1);
torture_close_connection(cli2);
talloc_free(mem_ctx);
return ret;
}
/*
stress testing of oplocks
*/
BOOL torture_bench_oplock(struct torture_context *torture)
{
struct smbcli_state **cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx = talloc_new(torture);
int torture_nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
int i, count=0;
int timelimit = torture_setting_int(torture, "timelimit", 10);
union smb_open io;
struct timeval tv;
struct event_context *ev = event_context_find(mem_ctx);
cli = talloc_array(mem_ctx, struct smbcli_state *, torture_nprocs);
printf("Opening %d connections\n", torture_nprocs);
for (i=0;i<torture_nprocs;i++) {
if (!torture_open_connection_ev(&cli[i], i, ev)) {
return False;
}
talloc_steal(mem_ctx, cli[i]);
smbcli_oplock_handler(cli[i]->transport, oplock_handler_close,
cli[i]->tree);
}
if (!torture_setup_dir(cli[0], BASEDIR)) {
ret = False;
goto done;
}
io.ntcreatex.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = BASEDIR "\\test.dat";
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
NTCREATEX_FLAGS_REQUEST_OPLOCK |
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
tv = timeval_current();
/*
we open the same file with SHARE_ACCESS_NONE from all the
connections in a round robin fashion. Each open causes an
oplock break on the previous connection, which is answered
by the oplock_handler_close() to close the file.
This measures how fast we can pass on oplocks, and stresses
the oplock handling code
*/
printf("Running for %d seconds\n", timelimit);
while (timeval_elapsed(&tv) < timelimit) {
for (i=0;i<torture_nprocs;i++) {
NTSTATUS status;
status = smb_raw_open(cli[i]->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
count++;
}
printf("%.2f ops/second\r", count/timeval_elapsed(&tv));
}
printf("%.2f ops/second\n", count/timeval_elapsed(&tv));
smb_raw_exit(cli[torture_nprocs-1]->session);
done:
smb_raw_exit(cli[0]->session);
smbcli_deltree(cli[0]->tree, BASEDIR);
talloc_free(mem_ctx);
return ret;
}
+723
View File
@@ -0,0 +1,723 @@
/*
Unix SMB/CIFS implementation.
RAW_FILEINFO_* individual test suite
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
static struct {
const char *name;
enum smb_fileinfo_level level;
uint_t only_paths:1;
uint_t only_handles:1;
uint32_t capability_mask;
NTSTATUS fnum_status, fname_status;
union smb_fileinfo fnum_finfo, fname_finfo;
} levels[] = {
{ "GETATTR", RAW_FILEINFO_GETATTR, 1, 0, },
{ "GETATTRE", RAW_FILEINFO_GETATTRE, 0, 1, },
{ "STANDARD", RAW_FILEINFO_STANDARD, },
{ "EA_SIZE", RAW_FILEINFO_EA_SIZE, },
{ "ALL_EAS", RAW_FILEINFO_ALL_EAS, },
{ "IS_NAME_VALID", RAW_FILEINFO_IS_NAME_VALID, 1, 0, },
{ "BASIC_INFO", RAW_FILEINFO_BASIC_INFO, },
{ "STANDARD_INFO", RAW_FILEINFO_STANDARD_INFO, },
{ "EA_INFO", RAW_FILEINFO_EA_INFO, },
{ "NAME_INFO", RAW_FILEINFO_NAME_INFO, },
{ "ALL_INFO", RAW_FILEINFO_ALL_INFO, },
{ "ALT_NAME_INFO", RAW_FILEINFO_ALT_NAME_INFO, },
{ "STREAM_INFO", RAW_FILEINFO_STREAM_INFO, },
{ "COMPRESSION_INFO", RAW_FILEINFO_COMPRESSION_INFO, },
{ "UNIX_BASIC_INFO", RAW_FILEINFO_UNIX_BASIC, 0, 0, CAP_UNIX},
{ "UNIX_LINK_INFO", RAW_FILEINFO_UNIX_LINK, 0, 0, CAP_UNIX},
{ "BASIC_INFORMATION", RAW_FILEINFO_BASIC_INFORMATION, },
{ "STANDARD_INFORMATION", RAW_FILEINFO_STANDARD_INFORMATION, },
{ "INTERNAL_INFORMATION", RAW_FILEINFO_INTERNAL_INFORMATION, },
{ "EA_INFORMATION", RAW_FILEINFO_EA_INFORMATION, },
{ "ACCESS_INFORMATION", RAW_FILEINFO_ACCESS_INFORMATION, },
{ "NAME_INFORMATION", RAW_FILEINFO_NAME_INFORMATION, },
{ "POSITION_INFORMATION", RAW_FILEINFO_POSITION_INFORMATION, },
{ "MODE_INFORMATION", RAW_FILEINFO_MODE_INFORMATION, },
{ "ALIGNMENT_INFORMATION", RAW_FILEINFO_ALIGNMENT_INFORMATION, },
{ "ALL_INFORMATION", RAW_FILEINFO_ALL_INFORMATION, },
{ "ALT_NAME_INFORMATION", RAW_FILEINFO_ALT_NAME_INFORMATION, },
{ "STREAM_INFORMATION", RAW_FILEINFO_STREAM_INFORMATION, },
{ "COMPRESSION_INFORMATION", RAW_FILEINFO_COMPRESSION_INFORMATION, },
{ "NETWORK_OPEN_INFORMATION", RAW_FILEINFO_NETWORK_OPEN_INFORMATION, },
{ "ATTRIBUTE_TAG_INFORMATION", RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, },
{ NULL, }
};
/*
compare a dos time (2 second resolution) to a nt time
*/
static int dos_nt_time_cmp(time_t t, NTTIME nt)
{
time_t t2 = nt_time_to_unix(nt);
if (abs(t2 - t) <= 2) return 0;
return t2 - t;
}
/*
find a level in the levels[] table
*/
static union smb_fileinfo *fnum_find(const char *name)
{
int i;
for (i=0; levels[i].name; i++) {
if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
strcmp(name, levels[i].name) == 0 &&
!levels[i].only_paths) {
return &levels[i].fnum_finfo;
}
}
return NULL;
}
/*
find a level in the levels[] table
*/
static union smb_fileinfo *fname_find(const char *name)
{
int i;
for (i=0; levels[i].name; i++) {
if (NT_STATUS_IS_OK(levels[i].fname_status) &&
strcmp(name, levels[i].name) == 0 &&
!levels[i].only_handles) {
return &levels[i].fname_finfo;
}
}
return NULL;
}
/* local macros to make the code below more readable */
#define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
#n1, #v1, (uint_t)s1->n1.out.v1, \
#n2, #v2, (uint_t)s2->n2.out.v2, \
__FILE__, __LINE__); \
ret = False; \
}} while(0)
#define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
#n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
#n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
__FILE__, __LINE__); \
ret = False; \
}} while(0)
#define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
printf("%s/%s != %s/%s at %s(%d)\n", \
#n1, #v1, \
#n2, #v2, \
__FILE__, __LINE__); \
ret = False; \
}} while(0)
/* used to find hints on unknown values - and to make sure
we zero-fill */
#if 0 /* unused */
#define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
#n1, #v1, \
(uint_t)s1->n1.out.v1, \
(uint_t)s1->n1.out.v1, \
__FILE__, __LINE__); \
ret = False; \
}} while(0)
#endif
/* basic testing of all RAW_FILEINFO_* calls
for each call we test that it succeeds, and where possible test
for consistency between the calls.
*/
BOOL torture_raw_qfileinfo(struct torture_context *torture)
{
struct smbcli_state *cli;
int i;
BOOL ret = True;
int count;
union smb_fileinfo *s1, *s2;
TALLOC_CTX *mem_ctx;
int fnum;
const char *fname = "\\torture_qfileinfo.txt";
NTTIME correct_time;
uint64_t correct_size;
uint32_t correct_attrib;
const char *correct_name;
BOOL skip_streams = False;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_qfileinfo");
fnum = create_complex_file(cli, mem_ctx, fname);
if (fnum == -1) {
printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
ret = False;
goto done;
}
/* scan all the fileinfo and pathinfo levels */
for (i=0; levels[i].name; i++) {
if (!levels[i].only_paths) {
levels[i].fnum_finfo.generic.level = levels[i].level;
levels[i].fnum_finfo.generic.in.file.fnum = fnum;
levels[i].fnum_status = smb_raw_fileinfo(cli->tree, mem_ctx,
&levels[i].fnum_finfo);
}
if (!levels[i].only_handles) {
levels[i].fname_finfo.generic.level = levels[i].level;
levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
levels[i].fname_status = smb_raw_pathinfo(cli->tree, mem_ctx,
&levels[i].fname_finfo);
}
}
/* check for completely broken levels */
for (count=i=0; levels[i].name; i++) {
uint32_t cap = cli->transport->negotiate.capabilities;
/* see if this server claims to support this level */
if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
continue;
}
if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
printf("ERROR: level %s failed - %s\n",
levels[i].name, nt_errstr(levels[i].fnum_status));
count++;
}
if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
printf("ERROR: level %s failed - %s\n",
levels[i].name, nt_errstr(levels[i].fname_status));
count++;
}
}
if (count != 0) {
ret = False;
printf("%d levels failed\n", count);
if (count > 35) {
printf("too many level failures - giving up\n");
goto done;
}
}
/* see if we can do streams */
s1 = fnum_find("STREAM_INFO");
if (!s1 || s1->stream_info.out.num_streams == 0) {
printf("STREAM_INFO broken (%d) - skipping streams checks\n",
s1 ? s1->stream_info.out.num_streams : -1);
skip_streams = True;
}
/* this code is incredibly repititive but doesn't lend itself to loops, so
we use lots of macros to make it less painful */
/* first off we check the levels that are supposed to be aliases. It will be quite rare for
this code to fail, but we need to check it for completeness */
#define ALIAS_CHECK(sname1, sname2) \
do { \
s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
if (s1 && s2) { INFO_CHECK } \
s1 = fname_find(sname1); s2 = fname_find(sname2); \
if (s1 && s2) { INFO_CHECK } \
s1 = fnum_find(sname1); s2 = fname_find(sname2); \
if (s1 && s2) { INFO_CHECK } \
} while (0)
#define INFO_CHECK \
STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
VAL_EQUAL (basic_info, attrib, basic_info, attrib);
ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
#undef INFO_CHECK
#define INFO_CHECK \
VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
VAL_EQUAL(standard_info, size, standard_info, size); \
VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
VAL_EQUAL(standard_info, directory, standard_info, directory);
ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
#undef INFO_CHECK
#define INFO_CHECK \
VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
#undef INFO_CHECK
#define INFO_CHECK \
STR_EQUAL(name_info, fname, name_info, fname);
ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
#undef INFO_CHECK
#define INFO_CHECK \
STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
VAL_EQUAL(all_info, attrib, all_info, attrib); \
VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
VAL_EQUAL(all_info, size, all_info, size); \
VAL_EQUAL(all_info, nlink, all_info, nlink); \
VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
VAL_EQUAL(all_info, directory, all_info, directory); \
VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
STR_EQUAL(all_info, fname, all_info, fname);
ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
#undef INFO_CHECK
#define INFO_CHECK \
VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
VAL_EQUAL(compression_info, format, compression_info, format); \
VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
#undef INFO_CHECK
#define INFO_CHECK \
STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
#define TIME_CHECK_NT(sname, stype, tfield) do { \
s1 = fnum_find(sname); \
if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
nt_time_string(mem_ctx, s1->stype.out.tfield), \
nt_time_string(mem_ctx, correct_time)); \
ret = False; \
} \
s1 = fname_find(sname); \
if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
nt_time_string(mem_ctx, s1->stype.out.tfield), \
nt_time_string(mem_ctx, correct_time)); \
ret = False; \
}} while (0)
#define TIME_CHECK_DOS(sname, stype, tfield) do { \
s1 = fnum_find(sname); \
if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
timestring(mem_ctx, s1->stype.out.tfield), \
nt_time_string(mem_ctx, correct_time)); \
ret = False; \
} \
s1 = fname_find(sname); \
if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
timestring(mem_ctx, s1->stype.out.tfield), \
nt_time_string(mem_ctx, correct_time)); \
ret = False; \
}} while (0)
#if 0 /* unused */
#define TIME_CHECK_UNX(sname, stype, tfield) do { \
s1 = fnum_find(sname); \
if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
timestring(mem_ctx, s1->stype.out.tfield), \
nt_time_string(mem_ctx, correct_time)); \
ret = False; \
} \
s1 = fname_find(sname); \
if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
timestring(mem_ctx, s1->stype.out.tfield), \
nt_time_string(mem_ctx, correct_time)); \
ret = False; \
}} while (0)
#endif
/* now check that all the times that are supposed to be equal are correct */
s1 = fnum_find("BASIC_INFO");
correct_time = s1->basic_info.out.create_time;
printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
TIME_CHECK_DOS("GETATTRE", getattre, create_time);
TIME_CHECK_DOS("STANDARD", standard, create_time);
TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
s1 = fnum_find("BASIC_INFO");
correct_time = s1->basic_info.out.access_time;
printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
TIME_CHECK_DOS("GETATTRE", getattre, access_time);
TIME_CHECK_DOS("STANDARD", standard, access_time);
TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
s1 = fnum_find("BASIC_INFO");
correct_time = s1->basic_info.out.write_time;
printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
TIME_CHECK_DOS("GETATTR", getattr, write_time);
TIME_CHECK_DOS("GETATTRE", getattre, write_time);
TIME_CHECK_DOS("STANDARD", standard, write_time);
TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
s1 = fnum_find("BASIC_INFO");
correct_time = s1->basic_info.out.change_time;
printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
#define SIZE_CHECK(sname, stype, tfield) do { \
s1 = fnum_find(sname); \
if (s1 && s1->stype.out.tfield != correct_size) { \
printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
(uint_t)s1->stype.out.tfield, \
(uint_t)correct_size); \
ret = False; \
} \
s1 = fname_find(sname); \
if (s1 && s1->stype.out.tfield != correct_size) { \
printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
(uint_t)s1->stype.out.tfield, \
(uint_t)correct_size); \
ret = False; \
}} while (0)
s1 = fnum_find("STANDARD_INFO");
correct_size = s1->standard_info.out.size;
printf("size: %u\n", (uint_t)correct_size);
SIZE_CHECK("GETATTR", getattr, size);
SIZE_CHECK("GETATTRE", getattre, size);
SIZE_CHECK("STANDARD", standard, size);
SIZE_CHECK("EA_SIZE", ea_size, size);
SIZE_CHECK("STANDARD_INFO", standard_info, size);
SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
SIZE_CHECK("ALL_INFO", all_info, size);
SIZE_CHECK("ALL_INFORMATION", all_info, size);
SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
if (!skip_streams) {
SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
}
s1 = fnum_find("STANDARD_INFO");
correct_size = s1->standard_info.out.alloc_size;
printf("alloc_size: %u\n", (uint_t)correct_size);
SIZE_CHECK("GETATTRE", getattre, alloc_size);
SIZE_CHECK("STANDARD", standard, alloc_size);
SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
SIZE_CHECK("ALL_INFO", all_info, alloc_size);
SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
if (!skip_streams) {
SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
}
#define ATTRIB_CHECK(sname, stype, tfield) do { \
s1 = fnum_find(sname); \
if (s1 && s1->stype.out.tfield != correct_attrib) { \
printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
(uint_t)s1->stype.out.tfield, \
(uint_t)correct_attrib); \
ret = False; \
} \
s1 = fname_find(sname); \
if (s1 && s1->stype.out.tfield != correct_attrib) { \
printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
(uint_t)s1->stype.out.tfield, \
(uint_t)correct_attrib); \
ret = False; \
}} while (0)
s1 = fnum_find("BASIC_INFO");
correct_attrib = s1->basic_info.out.attrib;
printf("attrib: 0x%x\n", (uint_t)correct_attrib);
ATTRIB_CHECK("GETATTR", getattr, attrib);
ATTRIB_CHECK("GETATTRE", getattre, attrib);
ATTRIB_CHECK("STANDARD", standard, attrib);
ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
ATTRIB_CHECK("ALL_INFO", all_info, attrib);
ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
correct_name = fname;
printf("name: %s\n", correct_name);
#define NAME_CHECK(sname, stype, tfield, flags) do { \
s1 = fnum_find(sname); \
if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
ret = False; \
} \
s1 = fname_find(sname); \
if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
ret = False; \
}} while (0)
NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
/* the ALL_INFO file name is the full path on the filesystem */
s1 = fnum_find("ALL_INFO");
if (s1 && !s1->all_info.out.fname.s) {
printf("ALL_INFO didn't give a filename\n");
ret = False;
}
if (s1 && s1->all_info.out.fname.s) {
char *p = strrchr(s1->all_info.out.fname.s, '\\');
if (!p) {
printf("Not a full path in all_info/fname? - '%s'\n",
s1->all_info.out.fname.s);
ret = False;
} else {
if (strcmp_safe(correct_name, p) != 0) {
printf("incorrect basename in all_info/fname - '%s'\n",
s1->all_info.out.fname.s);
ret = False;
}
}
if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, cli)) {
printf("Should not null terminate all_info/fname\n");
ret = False;
}
}
s1 = fnum_find("ALT_NAME_INFO");
correct_name = s1->alt_name_info.out.fname.s;
printf("alt_name: %s\n", correct_name);
NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
/* and make sure we can open by alternate name */
smbcli_close(cli->tree, fnum);
fnum = smbcli_nt_create_full(cli->tree, correct_name, 0,
SEC_RIGHTS_FILE_ALL,
FILE_ATTRIBUTE_NORMAL,
NTCREATEX_SHARE_ACCESS_DELETE|
NTCREATEX_SHARE_ACCESS_READ|
NTCREATEX_SHARE_ACCESS_WRITE,
NTCREATEX_DISP_OVERWRITE_IF,
0, 0);
if (fnum == -1) {
printf("Unable to open by alt_name - %s\n", smbcli_errstr(cli->tree));
ret = False;
}
if (!skip_streams) {
correct_name = "::$DATA";
printf("stream_name: %s\n", correct_name);
NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
}
/* make sure the EAs look right */
s1 = fnum_find("ALL_EAS");
s2 = fnum_find("ALL_INFO");
if (s1) {
for (i=0;i<s1->all_eas.out.num_eas;i++) {
printf(" flags=%d %s=%*.*s\n",
s1->all_eas.out.eas[i].flags,
s1->all_eas.out.eas[i].name.s,
(int)s1->all_eas.out.eas[i].value.length,
(int)s1->all_eas.out.eas[i].value.length,
s1->all_eas.out.eas[i].value.data);
}
}
if (s1 && s2) {
if (s1->all_eas.out.num_eas == 0) {
if (s2->all_info.out.ea_size != 0) {
printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
s2->all_info.out.ea_size);
}
} else {
if (s2->all_info.out.ea_size !=
ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
(int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
(int)s2->all_info.out.ea_size);
}
}
}
s2 = fname_find("ALL_EAS");
if (s2) {
VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
for (i=0;i<s1->all_eas.out.num_eas;i++) {
VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
}
}
#define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
#stype1, #tfield1, #stype2, #tfield2, \
s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
ret = False; \
} \
s1 = fname_find(sname1); s2 = fname_find(sname2); \
if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
#stype1, #tfield1, #stype2, #tfield2, \
s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
ret = False; \
} \
s1 = fnum_find(sname1); s2 = fname_find(sname2); \
if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
#stype1, #tfield1, #stype2, #tfield2, \
s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
ret = False; \
} \
s1 = fname_find(sname1); s2 = fnum_find(sname2); \
if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
#stype1, #tfield1, #stype2, #tfield2, \
s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
ret = False; \
}} while (0)
VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
"ALL_INFO", all_info, delete_pending);
VAL_CHECK("STANDARD_INFO", standard_info, directory,
"ALL_INFO", all_info, directory);
VAL_CHECK("STANDARD_INFO", standard_info, nlink,
"ALL_INFO", all_info, nlink);
VAL_CHECK("EA_INFO", ea_info, ea_size,
"ALL_INFO", all_info, ea_size);
VAL_CHECK("EA_SIZE", ea_size, ea_size,
"ALL_INFO", all_info, ea_size);
#define NAME_PATH_CHECK(sname, stype, field) do { \
s1 = fname_find(sname); s2 = fnum_find(sname); \
if (s1 && s2) { \
VAL_EQUAL(stype, field, stype, field); \
} \
} while (0)
s1 = fnum_find("INTERNAL_INFORMATION");
if (s1) {
printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
}
NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
if (s1 && s2) {
printf("fnum pos = %.0f, fname pos = %.0f\n",
(double)s2->position_information.out.position,
(double)s1->position_information.out.position );
}
NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
#if 0
/* these are expected to differ */
NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
#endif
#if 0 /* unused */
#define UNKNOWN_CHECK(sname, stype, tfield) do { \
s1 = fnum_find(sname); \
if (s1 && s1->stype.out.tfield != 0) { \
printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
#stype, #tfield, \
(uint_t)s1->stype.out.tfield); \
} \
s1 = fname_find(sname); \
if (s1 && s1->stype.out.tfield != 0) { \
printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
#stype, #tfield, \
(uint_t)s1->stype.out.tfield); \
}} while (0)
#endif
/* now get a bit fancier .... */
/* when we set the delete disposition then the link count should drop
to 0 and delete_pending should be 1 */
done:
smbcli_close(cli->tree, fnum);
smbcli_unlink(cli->tree, fname);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+311
View File
@@ -0,0 +1,311 @@
/*
Unix SMB/CIFS implementation.
RAW_QFS_* individual test suite
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
static struct {
const char *name;
enum smb_fsinfo_level level;
uint32_t capability_mask;
NTSTATUS status;
union smb_fsinfo fsinfo;
} levels[] = {
{"DSKATTR", RAW_QFS_DSKATTR, },
{"ALLOCATION", RAW_QFS_ALLOCATION, },
{"VOLUME", RAW_QFS_VOLUME, },
{"VOLUME_INFO", RAW_QFS_VOLUME_INFO, },
{"SIZE_INFO", RAW_QFS_SIZE_INFO, },
{"DEVICE_INFO", RAW_QFS_DEVICE_INFO, },
{"ATTRIBUTE_INFO", RAW_QFS_ATTRIBUTE_INFO, },
{"UNIX_INFO", RAW_QFS_UNIX_INFO, CAP_UNIX},
{"VOLUME_INFORMATION", RAW_QFS_VOLUME_INFORMATION, },
{"SIZE_INFORMATION", RAW_QFS_SIZE_INFORMATION, },
{"DEVICE_INFORMATION", RAW_QFS_DEVICE_INFORMATION, },
{"ATTRIBUTE_INFORMATION", RAW_QFS_ATTRIBUTE_INFORMATION, },
{"QUOTA_INFORMATION", RAW_QFS_QUOTA_INFORMATION, },
{"FULL_SIZE_INFORMATION", RAW_QFS_FULL_SIZE_INFORMATION, },
#if 0
/* w2k3 seems to no longer support this */
{"OBJECTID_INFORMATION", RAW_QFS_OBJECTID_INFORMATION, },
#endif
{ NULL, }
};
/*
find a level in the levels[] table
*/
static union smb_fsinfo *find(const char *name)
{
int i;
for (i=0; levels[i].name; i++) {
if (strcmp(name, levels[i].name) == 0 &&
NT_STATUS_IS_OK(levels[i].status)) {
return &levels[i].fsinfo;
}
}
return NULL;
}
/* local macros to make the code below more readable */
#define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
#n1, #v1, (uint_t)s1->n1.out.v1, \
#n2, #v2, (uint_t)s2->n2.out.v2, \
__FILE__, __LINE__); \
ret = False; \
}} while(0)
#define VAL_APPROX_EQUAL(n1, v1, n2, v2) do {if (abs((int)(s1->n1.out.v1) - (int)(s2->n2.out.v2)) > 0.1*s1->n1.out.v1) { \
printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
#n1, #v1, (uint_t)s1->n1.out.v1, \
#n2, #v2, (uint_t)s2->n2.out.v2, \
__FILE__, __LINE__); \
ret = False; \
}} while(0)
#define STR_EQUAL(n1, v1, n2, v2) do { \
if (strcmp_safe(s1->n1.out.v1, s2->n2.out.v2)) { \
printf("%s/%s [%s] != %s/%s [%s] at %s(%d)\n", \
#n1, #v1, s1->n1.out.v1, \
#n2, #v2, s2->n2.out.v2, \
__FILE__, __LINE__); \
ret = False; \
}} while(0)
#define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
printf("%s/%s != %s/%s at %s(%d)\n", \
#n1, #v1, \
#n2, #v2, \
__FILE__, __LINE__); \
ret = False; \
}} while(0)
/* used to find hints on unknown values - and to make sure
we zero-fill */
#define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
#n1, #v1, \
(uint_t)s1->n1.out.v1, \
(uint_t)s1->n1.out.v1, \
__FILE__, __LINE__); \
ret = False; \
}} while(0)
/* basic testing of all RAW_QFS_* calls
for each call we test that it succeeds, and where possible test
for consistency between the calls.
Some of the consistency tests assume that the target filesystem is
quiescent, which is sometimes hard to achieve
*/
BOOL torture_raw_qfsinfo(struct torture_context *torture)
{
struct smbcli_state *cli;
int i;
BOOL ret = True;
int count;
union smb_fsinfo *s1, *s2;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_qfsinfo");
/* scan all the levels, pulling the results */
for (i=0; levels[i].name; i++) {
printf("Running level %s\n", levels[i].name);
levels[i].fsinfo.generic.level = levels[i].level;
levels[i].status = smb_raw_fsinfo(cli->tree, mem_ctx, &levels[i].fsinfo);
}
/* check for completely broken levels */
for (count=i=0; levels[i].name; i++) {
uint32_t cap = cli->transport->negotiate.capabilities;
/* see if this server claims to support this level */
if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
continue;
}
if (!NT_STATUS_IS_OK(levels[i].status)) {
printf("ERROR: level %s failed - %s\n",
levels[i].name, nt_errstr(levels[i].status));
count++;
}
}
if (count != 0) {
ret = False;
printf("%d levels failed\n", count);
if (count > 13) {
printf("too many level failures - giving up\n");
goto done;
}
}
printf("check for correct aliases\n");
s1 = find("SIZE_INFO");
s2 = find("SIZE_INFORMATION");
if (s1 && s2) {
VAL_EQUAL(size_info, total_alloc_units, size_info, total_alloc_units);
VAL_APPROX_EQUAL(size_info, avail_alloc_units, size_info, avail_alloc_units);
VAL_EQUAL(size_info, sectors_per_unit, size_info, sectors_per_unit);
VAL_EQUAL(size_info, bytes_per_sector, size_info, bytes_per_sector);
}
s1 = find("DEVICE_INFO");
s2 = find("DEVICE_INFORMATION");
if (s1 && s2) {
VAL_EQUAL(device_info, device_type, device_info, device_type);
VAL_EQUAL(device_info, characteristics, device_info, characteristics);
}
s1 = find("VOLUME_INFO");
s2 = find("VOLUME_INFORMATION");
if (s1 && s2) {
STRUCT_EQUAL(volume_info, create_time, volume_info, create_time);
VAL_EQUAL (volume_info, serial_number, volume_info, serial_number);
STR_EQUAL (volume_info, volume_name.s, volume_info, volume_name.s);
printf("volume_info.volume_name = '%s'\n", s1->volume_info.out.volume_name.s);
}
s1 = find("ATTRIBUTE_INFO");
s2 = find("ATTRIBUTE_INFORMATION");
if (s1 && s2) {
VAL_EQUAL(attribute_info, fs_attr,
attribute_info, fs_attr);
VAL_EQUAL(attribute_info, max_file_component_length,
attribute_info, max_file_component_length);
STR_EQUAL(attribute_info, fs_type.s, attribute_info, fs_type.s);
printf("attribute_info.fs_type = '%s'\n", s1->attribute_info.out.fs_type.s);
}
printf("check for consistent disk sizes\n");
s1 = find("DSKATTR");
s2 = find("ALLOCATION");
if (s1 && s2) {
double size1, size2;
double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
size1 = 1.0 *
s1->dskattr.out.units_total *
s1->dskattr.out.blocks_per_unit *
s1->dskattr.out.block_size / scale;
size2 = 1.0 *
s2->allocation.out.sectors_per_unit *
s2->allocation.out.total_alloc_units *
s2->allocation.out.bytes_per_sector / scale;
if (abs(size1 - size2) > 1) {
printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
size1, size2);
ret = False;
}
printf("total disk = %.0f MB\n", size1*scale/1.0e6);
}
printf("check consistent free disk space\n");
s1 = find("DSKATTR");
s2 = find("ALLOCATION");
if (s1 && s2) {
double size1, size2;
double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
size1 = 1.0 *
s1->dskattr.out.units_free *
s1->dskattr.out.blocks_per_unit *
s1->dskattr.out.block_size / scale;
size2 = 1.0 *
s2->allocation.out.sectors_per_unit *
s2->allocation.out.avail_alloc_units *
s2->allocation.out.bytes_per_sector / scale;
if (abs(size1 - size2) > 1) {
printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
size1, size2);
ret = False;
}
printf("free disk = %.0f MB\n", size1*scale/1.0e6);
}
printf("volume info consistency\n");
s1 = find("VOLUME");
s2 = find("VOLUME_INFO");
if (s1 && s2) {
VAL_EQUAL(volume, serial_number, volume_info, serial_number);
STR_EQUAL(volume, volume_name.s, volume_info, volume_name.s);
}
/* disk size consistency - notice that 'avail_alloc_units' maps to the caller
available allocation units, not the total */
s1 = find("SIZE_INFO");
s2 = find("FULL_SIZE_INFORMATION");
if (s1 && s2) {
VAL_EQUAL(size_info, total_alloc_units, full_size_information, total_alloc_units);
VAL_APPROX_EQUAL(size_info, avail_alloc_units, full_size_information, call_avail_alloc_units);
VAL_EQUAL(size_info, sectors_per_unit, full_size_information, sectors_per_unit);
VAL_EQUAL(size_info, bytes_per_sector, full_size_information, bytes_per_sector);
}
printf("check for non-zero unknown fields\n");
s1 = find("QUOTA_INFORMATION");
if (s1) {
VAL_UNKNOWN(quota_information, unknown[0]);
VAL_UNKNOWN(quota_information, unknown[1]);
VAL_UNKNOWN(quota_information, unknown[2]);
}
s1 = find("OBJECTID_INFORMATION");
if (s1) {
VAL_UNKNOWN(objectid_information, unknown[0]);
VAL_UNKNOWN(objectid_information, unknown[1]);
VAL_UNKNOWN(objectid_information, unknown[2]);
VAL_UNKNOWN(objectid_information, unknown[3]);
VAL_UNKNOWN(objectid_information, unknown[4]);
VAL_UNKNOWN(objectid_information, unknown[5]);
}
#define STR_CHECK(sname, stype, field, flags) do { \
s1 = find(sname); \
if (s1) { \
if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli)) { \
printf("(%d) incorrect string termination in %s/%s\n", \
__LINE__, #stype, #field); \
ret = False; \
} \
}} while (0)
printf("check for correct termination\n");
STR_CHECK("VOLUME", volume, volume_name, 0);
STR_CHECK("VOLUME_INFO", volume_info, volume_name, STR_UNICODE);
STR_CHECK("VOLUME_INFORMATION", volume_info, volume_name, STR_UNICODE);
STR_CHECK("ATTRIBUTE_INFO", attribute_info, fs_type, STR_UNICODE);
STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info, fs_type, STR_UNICODE);
done:
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+69
View File
@@ -0,0 +1,69 @@
/*
Unix SMB/CIFS implementation.
SMB torture tester
Copyright (C) Jelmer Vernooij 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "torture/raw/proto.h"
NTSTATUS torture_raw_init(void)
{
struct torture_suite *suite = torture_suite_create(
talloc_autofree_context(),
"RAW");
/* RAW smb tests */
torture_suite_add_simple_test(suite, "BENCH-OPLOCK", torture_bench_oplock);
torture_suite_add_simple_test(suite, "BENCH-LOCK", torture_bench_lock);
torture_suite_add_simple_test(suite, "QFSINFO", torture_raw_qfsinfo);
torture_suite_add_simple_test(suite, "QFILEINFO", torture_raw_qfileinfo);
torture_suite_add_simple_test(suite, "SFILEINFO", torture_raw_sfileinfo);
torture_suite_add_simple_test(suite, "SFILEINFO-BUG", torture_raw_sfileinfo_bug);
torture_suite_add_simple_test(suite, "SEARCH", torture_raw_search);
torture_suite_add_simple_test(suite, "CLOSE", torture_raw_close);
torture_suite_add_simple_test(suite, "OPEN", torture_raw_open);
torture_suite_add_simple_test(suite, "MKDIR", torture_raw_mkdir);
torture_suite_add_simple_test(suite, "OPLOCK", torture_raw_oplock);
torture_suite_add_simple_test(suite, "NOTIFY", torture_raw_notify);
torture_suite_add_simple_test(suite, "MUX", torture_raw_mux);
torture_suite_add_simple_test(suite, "IOCTL", torture_raw_ioctl);
torture_suite_add_simple_test(suite, "CHKPATH", torture_raw_chkpath);
torture_suite_add_simple_test(suite, "UNLINK", torture_raw_unlink);
torture_suite_add_simple_test(suite, "READ", torture_raw_read);
torture_suite_add_simple_test(suite, "WRITE", torture_raw_write);
torture_suite_add_simple_test(suite, "LOCK", torture_raw_lock);
torture_suite_add_simple_test(suite, "CONTEXT", torture_raw_context);
torture_suite_add_simple_test(suite, "RENAME", torture_raw_rename);
torture_suite_add_simple_test(suite, "SEEK", torture_raw_seek);
torture_suite_add_simple_test(suite, "EAS", torture_raw_eas);
torture_suite_add_simple_test(suite, "STREAMS", torture_raw_streams);
torture_suite_add_simple_test(suite, "ACLS", torture_raw_acls);
torture_suite_add_simple_test(suite, "COMPOSITE", torture_raw_composite);
torture_suite_add_simple_test(suite, "SAMBA3HIDE", torture_samba3_hide);
torture_suite_add_simple_test(suite, "SAMBA3CHECKFSP", torture_samba3_checkfsp);
torture_suite_add_simple_test(suite, "SAMBA3BADPATH", torture_samba3_badpath);
torture_suite_add_simple_test(suite, "SCAN-EAMAX", torture_max_eas);
suite->description = talloc_strdup(suite,
"Tests for the raw SMB interface");
torture_register_suite(suite);
return NT_STATUS_OK;
}
+942
View File
@@ -0,0 +1,942 @@
/*
Unix SMB/CIFS implementation.
test suite for various read operations
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "system/time.h"
#include "system/filesys.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
#define CHECK_VALUE(v, correct) do { \
if ((v) != (correct)) { \
printf("(%s) Incorrect value %s=%ld - should be %ld\n", \
__location__, #v, (long)v, (long)correct); \
ret = False; \
goto done; \
}} while (0)
#define CHECK_BUFFER(buf, seed, len) do { \
if (!check_buffer(buf, seed, len, __LINE__)) { \
ret = False; \
goto done; \
}} while (0)
#define BASEDIR "\\testread"
/*
setup a random buffer based on a seed
*/
static void setup_buffer(uint8_t *buf, uint_t seed, int len)
{
int i;
srandom(seed);
for (i=0;i<len;i++) buf[i] = random();
}
/*
check a random buffer based on a seed
*/
static BOOL check_buffer(uint8_t *buf, uint_t seed, int len, int line)
{
int i;
srandom(seed);
for (i=0;i<len;i++) {
uint8_t v = random();
if (buf[i] != v) {
printf("Buffer incorrect at line %d! ofs=%d v1=0x%x v2=0x%x\n",
line, i, buf[i], v);
return False;
}
}
return True;
}
/*
test read ops
*/
static BOOL test_read(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_read io;
NTSTATUS status;
BOOL ret = True;
int fnum;
uint8_t *buf;
const int maxsize = 90000;
const char *fname = BASEDIR "\\test.txt";
const char *test_data = "TEST DATA";
uint_t seed = time(NULL);
buf = talloc_zero_size(mem_ctx, maxsize);
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Testing RAW_READ_READ\n");
io.generic.level = RAW_READ_READ;
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum == -1) {
printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("Trying empty file read\n");
io.read.in.file.fnum = fnum;
io.read.in.count = 1;
io.read.in.offset = 0;
io.read.in.remaining = 0;
io.read.out.data = buf;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.read.out.nread, 0);
printf("Trying zero file read\n");
io.read.in.count = 0;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.read.out.nread, 0);
printf("Trying bad fnum\n");
io.read.in.file.fnum = fnum+1;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
io.read.in.file.fnum = fnum;
smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
printf("Trying small read\n");
io.read.in.file.fnum = fnum;
io.read.in.offset = 0;
io.read.in.remaining = 0;
io.read.in.count = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.read.out.nread, strlen(test_data));
if (memcmp(buf, test_data, strlen(test_data)) != 0) {
ret = False;
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
goto done;
}
printf("Trying short read\n");
io.read.in.offset = 1;
io.read.in.count = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.read.out.nread, strlen(test_data)-1);
if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
ret = False;
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
goto done;
}
if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
printf("Trying max offset\n");
io.read.in.offset = ~0;
io.read.in.count = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.read.out.nread, 0);
}
setup_buffer(buf, seed, maxsize);
smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
memset(buf, 0, maxsize);
printf("Trying large read\n");
io.read.in.offset = 0;
io.read.in.count = ~0;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_BUFFER(buf, seed, io.read.out.nread);
printf("Trying locked region\n");
cli->session->pid++;
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
printf("Failed to lock file at %d\n", __LINE__);
ret = False;
goto done;
}
cli->session->pid--;
memset(buf, 0, maxsize);
io.read.in.offset = 0;
io.read.in.count = ~0;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
done:
smbcli_close(cli->tree, fnum);
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
test lockread ops
*/
static BOOL test_lockread(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_read io;
NTSTATUS status;
BOOL ret = True;
int fnum;
uint8_t *buf;
const int maxsize = 90000;
const char *fname = BASEDIR "\\test.txt";
const char *test_data = "TEST DATA";
uint_t seed = time(NULL);
buf = talloc_zero_size(mem_ctx, maxsize);
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Testing RAW_READ_LOCKREAD\n");
io.generic.level = RAW_READ_LOCKREAD;
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum == -1) {
printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("Trying empty file read\n");
io.lockread.in.file.fnum = fnum;
io.lockread.in.count = 1;
io.lockread.in.offset = 1;
io.lockread.in.remaining = 0;
io.lockread.out.data = buf;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.lockread.out.nread, 0);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
printf("Trying zero file read\n");
io.lockread.in.count = 0;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
smbcli_unlock(cli->tree, fnum, 1, 1);
printf("Trying bad fnum\n");
io.lockread.in.file.fnum = fnum+1;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
io.lockread.in.file.fnum = fnum;
smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
printf("Trying small read\n");
io.lockread.in.file.fnum = fnum;
io.lockread.in.offset = 0;
io.lockread.in.remaining = 0;
io.lockread.in.count = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
smbcli_unlock(cli->tree, fnum, 1, 0);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.lockread.out.nread, strlen(test_data));
if (memcmp(buf, test_data, strlen(test_data)) != 0) {
ret = False;
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
goto done;
}
printf("Trying short read\n");
io.lockread.in.offset = 1;
io.lockread.in.count = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
smbcli_unlock(cli->tree, fnum, 0, strlen(test_data));
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.lockread.out.nread, strlen(test_data)-1);
if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
ret = False;
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
goto done;
}
if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
printf("Trying max offset\n");
io.lockread.in.offset = ~0;
io.lockread.in.count = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.lockread.out.nread, 0);
}
setup_buffer(buf, seed, maxsize);
smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
memset(buf, 0, maxsize);
printf("Trying large read\n");
io.lockread.in.offset = 0;
io.lockread.in.count = ~0;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
smbcli_unlock(cli->tree, fnum, 1, strlen(test_data));
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_BUFFER(buf, seed, io.lockread.out.nread);
smbcli_unlock(cli->tree, fnum, 0, 0xFFFF);
printf("Trying locked region\n");
cli->session->pid++;
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
printf("Failed to lock file at %d\n", __LINE__);
ret = False;
goto done;
}
cli->session->pid--;
memset(buf, 0, maxsize);
io.lockread.in.offset = 0;
io.lockread.in.count = ~0;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
done:
smbcli_close(cli->tree, fnum);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
test readx ops
*/
static BOOL test_readx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_read io;
NTSTATUS status;
BOOL ret = True;
int fnum;
uint8_t *buf;
const int maxsize = 90000;
const char *fname = BASEDIR "\\test.txt";
const char *test_data = "TEST DATA";
uint_t seed = time(NULL);
buf = talloc_zero_size(mem_ctx, maxsize);
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Testing RAW_READ_READX\n");
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum == -1) {
printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("Trying empty file read\n");
io.generic.level = RAW_READ_READX;
io.readx.in.file.fnum = fnum;
io.readx.in.mincnt = 1;
io.readx.in.maxcnt = 1;
io.readx.in.offset = 0;
io.readx.in.remaining = 0;
io.readx.in.read_for_execute = False;
io.readx.out.data = buf;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.nread, 0);
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
CHECK_VALUE(io.readx.out.compaction_mode, 0);
printf("Trying zero file read\n");
io.readx.in.mincnt = 0;
io.readx.in.maxcnt = 0;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.nread, 0);
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
CHECK_VALUE(io.readx.out.compaction_mode, 0);
printf("Trying bad fnum\n");
io.readx.in.file.fnum = fnum+1;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
io.readx.in.file.fnum = fnum;
smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
printf("Trying small read\n");
io.readx.in.file.fnum = fnum;
io.readx.in.offset = 0;
io.readx.in.remaining = 0;
io.readx.in.read_for_execute = False;
io.readx.in.mincnt = strlen(test_data);
io.readx.in.maxcnt = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.nread, strlen(test_data));
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
CHECK_VALUE(io.readx.out.compaction_mode, 0);
if (memcmp(buf, test_data, strlen(test_data)) != 0) {
ret = False;
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
goto done;
}
printf("Trying short read\n");
io.readx.in.offset = 1;
io.readx.in.mincnt = strlen(test_data);
io.readx.in.maxcnt = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.nread, strlen(test_data)-1);
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
CHECK_VALUE(io.readx.out.compaction_mode, 0);
if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
ret = False;
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
goto done;
}
if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
printf("Trying max offset\n");
io.readx.in.offset = 0xffffffff;
io.readx.in.mincnt = strlen(test_data);
io.readx.in.maxcnt = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.nread, 0);
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
CHECK_VALUE(io.readx.out.compaction_mode, 0);
}
setup_buffer(buf, seed, maxsize);
smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
memset(buf, 0, maxsize);
printf("Trying large read\n");
io.readx.in.offset = 0;
io.readx.in.mincnt = 0xFFFF;
io.readx.in.maxcnt = 0xFFFF;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
CHECK_VALUE(io.readx.out.compaction_mode, 0);
CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
CHECK_BUFFER(buf, seed, io.readx.out.nread);
printf("Trying extra large read\n");
io.readx.in.offset = 0;
io.readx.in.mincnt = 100;
io.readx.in.maxcnt = 80000;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
CHECK_VALUE(io.readx.out.compaction_mode, 0);
if (lp_parm_bool(-1, "torture", "samba3", False)) {
printf("SAMBA3: large read extension\n");
CHECK_VALUE(io.readx.out.nread, 80000);
} else {
CHECK_VALUE(io.readx.out.nread, 0);
}
CHECK_BUFFER(buf, seed, io.readx.out.nread);
printf("Trying mincnt > maxcnt\n");
memset(buf, 0, maxsize);
io.readx.in.offset = 0;
io.readx.in.mincnt = 30000;
io.readx.in.maxcnt = 20000;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
CHECK_VALUE(io.readx.out.compaction_mode, 0);
CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
CHECK_BUFFER(buf, seed, io.readx.out.nread);
printf("Trying mincnt < maxcnt\n");
memset(buf, 0, maxsize);
io.readx.in.offset = 0;
io.readx.in.mincnt = 20000;
io.readx.in.maxcnt = 30000;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
CHECK_VALUE(io.readx.out.compaction_mode, 0);
CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
CHECK_BUFFER(buf, seed, io.readx.out.nread);
if (cli->transport->negotiate.capabilities & CAP_LARGE_READX) {
printf("Trying large readx\n");
io.readx.in.offset = 0;
io.readx.in.mincnt = 0;
io.readx.in.maxcnt = 0x10000 - 1;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.nread, 0xFFFF);
io.readx.in.maxcnt = 0x10000;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
if (lp_parm_bool(-1, "torture", "samba3", False)) {
printf("SAMBA3: large read extension\n");
CHECK_VALUE(io.readx.out.nread, 0x10000);
} else {
CHECK_VALUE(io.readx.out.nread, 0);
}
io.readx.in.maxcnt = 0x10001;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
if (lp_parm_bool(-1, "torture", "samba3", False)) {
printf("SAMBA3: large read extension\n");
CHECK_VALUE(io.readx.out.nread, 0x10001);
} else {
CHECK_VALUE(io.readx.out.nread, 0);
}
}
printf("Trying locked region\n");
cli->session->pid++;
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
printf("Failed to lock file at %d\n", __LINE__);
ret = False;
goto done;
}
cli->session->pid--;
memset(buf, 0, maxsize);
io.readx.in.offset = 0;
io.readx.in.mincnt = 100;
io.readx.in.maxcnt = 200;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
goto done;
}
printf("Trying large offset read\n");
io.readx.in.offset = ((uint64_t)0x2) << 32;
io.readx.in.mincnt = 10;
io.readx.in.maxcnt = 10;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.nread, 0);
if (NT_STATUS_IS_ERR(smbcli_lock64(cli->tree, fnum, io.readx.in.offset, 1, 0, WRITE_LOCK))) {
printf("Failed to lock file at %d\n", __LINE__);
ret = False;
goto done;
}
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readx.out.nread, 0);
done:
smbcli_close(cli->tree, fnum);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
test readbraw ops
*/
static BOOL test_readbraw(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_read io;
NTSTATUS status;
BOOL ret = True;
int fnum;
uint8_t *buf;
const int maxsize = 90000;
const char *fname = BASEDIR "\\test.txt";
const char *test_data = "TEST DATA";
uint_t seed = time(NULL);
buf = talloc_zero_size(mem_ctx, maxsize);
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Testing RAW_READ_READBRAW\n");
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum == -1) {
printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("Trying empty file read\n");
io.generic.level = RAW_READ_READBRAW;
io.readbraw.in.file.fnum = fnum;
io.readbraw.in.mincnt = 1;
io.readbraw.in.maxcnt = 1;
io.readbraw.in.offset = 0;
io.readbraw.in.timeout = 0;
io.readbraw.out.data = buf;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, 0);
printf("Trying zero file read\n");
io.readbraw.in.mincnt = 0;
io.readbraw.in.maxcnt = 0;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, 0);
printf("Trying bad fnum\n");
io.readbraw.in.file.fnum = fnum+1;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, 0);
io.readbraw.in.file.fnum = fnum;
smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
printf("Trying small read\n");
io.readbraw.in.file.fnum = fnum;
io.readbraw.in.offset = 0;
io.readbraw.in.mincnt = strlen(test_data);
io.readbraw.in.maxcnt = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, strlen(test_data));
if (memcmp(buf, test_data, strlen(test_data)) != 0) {
ret = False;
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
goto done;
}
printf("Trying short read\n");
io.readbraw.in.offset = 1;
io.readbraw.in.mincnt = strlen(test_data);
io.readbraw.in.maxcnt = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, strlen(test_data)-1);
if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
ret = False;
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
goto done;
}
if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
printf("Trying max offset\n");
io.readbraw.in.offset = ~0;
io.readbraw.in.mincnt = strlen(test_data);
io.readbraw.in.maxcnt = strlen(test_data);
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, 0);
}
setup_buffer(buf, seed, maxsize);
smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
memset(buf, 0, maxsize);
printf("Trying large read\n");
io.readbraw.in.offset = 0;
io.readbraw.in.mincnt = ~0;
io.readbraw.in.maxcnt = ~0;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, 0xFFFF);
CHECK_BUFFER(buf, seed, io.readbraw.out.nread);
printf("Trying mincnt > maxcnt\n");
memset(buf, 0, maxsize);
io.readbraw.in.offset = 0;
io.readbraw.in.mincnt = 30000;
io.readbraw.in.maxcnt = 20000;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, io.readbraw.in.maxcnt);
CHECK_BUFFER(buf, seed, io.readbraw.out.nread);
printf("Trying mincnt < maxcnt\n");
memset(buf, 0, maxsize);
io.readbraw.in.offset = 0;
io.readbraw.in.mincnt = 20000;
io.readbraw.in.maxcnt = 30000;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, io.readbraw.in.maxcnt);
CHECK_BUFFER(buf, seed, io.readbraw.out.nread);
printf("Trying locked region\n");
cli->session->pid++;
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
printf("Failed to lock file at %d\n", __LINE__);
ret = False;
goto done;
}
cli->session->pid--;
memset(buf, 0, maxsize);
io.readbraw.in.offset = 0;
io.readbraw.in.mincnt = 100;
io.readbraw.in.maxcnt = 200;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, 0);
printf("Trying locked region with timeout\n");
memset(buf, 0, maxsize);
io.readbraw.in.offset = 0;
io.readbraw.in.mincnt = 100;
io.readbraw.in.maxcnt = 200;
io.readbraw.in.timeout = 10000;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, 0);
if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
printf("Trying large offset read\n");
io.readbraw.in.offset = ((uint64_t)0x2) << 32;
io.readbraw.in.mincnt = 10;
io.readbraw.in.maxcnt = 10;
io.readbraw.in.timeout = 0;
status = smb_raw_read(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.readbraw.out.nread, 0);
}
done:
smbcli_close(cli->tree, fnum);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
test read for execute
*/
static BOOL test_read_for_execute(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_open op;
union smb_write wr;
union smb_read rd;
NTSTATUS status;
BOOL ret = True;
int fnum=0;
uint8_t *buf;
const int maxsize = 900;
const char *fname = BASEDIR "\\test.txt";
const uint8_t data[] = "TEST DATA";
buf = talloc_zero_size(mem_ctx, maxsize);
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Testing RAW_READ_READX with read_for_execute\n");
op.generic.level = RAW_OPEN_NTCREATEX;
op.ntcreatex.in.root_fid = 0;
op.ntcreatex.in.flags = 0;
op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
op.ntcreatex.in.create_options = 0;
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
op.ntcreatex.in.alloc_size = 0;
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
op.ntcreatex.in.security_flags = 0;
op.ntcreatex.in.fname = fname;
status = smb_raw_open(cli->tree, mem_ctx, &op);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = op.ntcreatex.out.file.fnum;
wr.generic.level = RAW_WRITE_WRITEX;
wr.writex.in.file.fnum = fnum;
wr.writex.in.offset = 0;
wr.writex.in.wmode = 0;
wr.writex.in.remaining = 0;
wr.writex.in.count = ARRAY_SIZE(data);
wr.writex.in.data = data;
status = smb_raw_write(cli->tree, &wr);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(wr.writex.out.nwritten, ARRAY_SIZE(data));
status = smbcli_close(cli->tree, fnum);
CHECK_STATUS(status, NT_STATUS_OK);
printf("open file with SEC_FILE_EXECUTE\n");
op.generic.level = RAW_OPEN_NTCREATEX;
op.ntcreatex.in.root_fid = 0;
op.ntcreatex.in.flags = 0;
op.ntcreatex.in.access_mask = SEC_FILE_EXECUTE;
op.ntcreatex.in.create_options = 0;
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
op.ntcreatex.in.alloc_size = 0;
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
op.ntcreatex.in.security_flags = 0;
op.ntcreatex.in.fname = fname;
status = smb_raw_open(cli->tree, mem_ctx, &op);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = op.ntcreatex.out.file.fnum;
printf("read with FLAGS2_READ_PERMIT_EXECUTE\n");
rd.generic.level = RAW_READ_READX;
rd.readx.in.file.fnum = fnum;
rd.readx.in.mincnt = 0;
rd.readx.in.maxcnt = maxsize;
rd.readx.in.offset = 0;
rd.readx.in.remaining = 0;
rd.readx.in.read_for_execute = True;
rd.readx.out.data = buf;
status = smb_raw_read(cli->tree, &rd);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
CHECK_VALUE(rd.readx.out.compaction_mode, 0);
printf("read without FLAGS2_READ_PERMIT_EXECUTE (should fail)\n");
rd.generic.level = RAW_READ_READX;
rd.readx.in.file.fnum = fnum;
rd.readx.in.mincnt = 0;
rd.readx.in.maxcnt = maxsize;
rd.readx.in.offset = 0;
rd.readx.in.remaining = 0;
rd.readx.in.read_for_execute = False;
rd.readx.out.data = buf;
status = smb_raw_read(cli->tree, &rd);
CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
status = smbcli_close(cli->tree, fnum);
CHECK_STATUS(status, NT_STATUS_OK);
printf("open file with SEC_FILE_READ_DATA\n");
op.generic.level = RAW_OPEN_NTCREATEX;
op.ntcreatex.in.root_fid = 0;
op.ntcreatex.in.flags = 0;
op.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
op.ntcreatex.in.create_options = 0;
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
op.ntcreatex.in.alloc_size = 0;
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
op.ntcreatex.in.security_flags = 0;
op.ntcreatex.in.fname = fname;
status = smb_raw_open(cli->tree, mem_ctx, &op);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = op.ntcreatex.out.file.fnum;
printf("read with FLAGS2_READ_PERMIT_EXECUTE\n");
rd.generic.level = RAW_READ_READX;
rd.readx.in.file.fnum = fnum;
rd.readx.in.mincnt = 0;
rd.readx.in.maxcnt = maxsize;
rd.readx.in.offset = 0;
rd.readx.in.remaining = 0;
rd.readx.in.read_for_execute = True;
rd.readx.out.data = buf;
status = smb_raw_read(cli->tree, &rd);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
CHECK_VALUE(rd.readx.out.compaction_mode, 0);
printf("read without FLAGS2_READ_PERMIT_EXECUTE\n");
rd.generic.level = RAW_READ_READX;
rd.readx.in.file.fnum = fnum;
rd.readx.in.mincnt = 0;
rd.readx.in.maxcnt = maxsize;
rd.readx.in.offset = 0;
rd.readx.in.remaining = 0;
rd.readx.in.read_for_execute = False;
rd.readx.out.data = buf;
status = smb_raw_read(cli->tree, &rd);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
CHECK_VALUE(rd.readx.out.compaction_mode, 0);
done:
smbcli_close(cli->tree, fnum);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
basic testing of read calls
*/
BOOL torture_raw_read(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_read");
ret &= test_read(cli, mem_ctx);
ret &= test_readx(cli, mem_ctx);
ret &= test_lockread(cli, mem_ctx);
ret &= test_readbraw(cli, mem_ctx);
ret &= test_read_for_execute(cli, mem_ctx);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+445
View File
@@ -0,0 +1,445 @@
/*
Unix SMB/CIFS implementation.
rename test suite
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
#define CHECK_VALUE(v, correct) do { \
if ((v) != (correct)) { \
printf("(%s) Incorrect %s %d - should be %d\n", \
__location__, #v, (int)v, (int)correct); \
ret = False; \
}} while (0)
#define BASEDIR "\\testrename"
/*
test SMBmv ops
*/
static BOOL test_mv(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_rename io;
NTSTATUS status;
BOOL ret = True;
int fnum = -1;
const char *fname1 = BASEDIR "\\test1.txt";
const char *fname2 = BASEDIR "\\test2.txt";
union smb_open op;
printf("Testing SMBmv\n");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Trying simple rename\n");
op.generic.level = RAW_OPEN_NTCREATEX;
op.ntcreatex.in.root_fid = 0;
op.ntcreatex.in.flags = 0;
op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
op.ntcreatex.in.create_options = 0;
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
op.ntcreatex.in.share_access =
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE;
op.ntcreatex.in.alloc_size = 0;
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
op.ntcreatex.in.security_flags = 0;
op.ntcreatex.in.fname = fname1;
status = smb_raw_open(cli->tree, mem_ctx, &op);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = op.ntcreatex.out.file.fnum;
io.generic.level = RAW_RENAME_RENAME;
io.rename.in.pattern1 = fname1;
io.rename.in.pattern2 = fname2;
io.rename.in.attrib = 0;
printf("trying rename while first file open\n");
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
smbcli_close(cli->tree, fnum);
op.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
op.ntcreatex.in.share_access =
NTCREATEX_SHARE_ACCESS_DELETE |
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE;
status = smb_raw_open(cli->tree, mem_ctx, &op);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = op.ntcreatex.out.file.fnum;
printf("trying rename while first file open with SHARE_ACCESS_DELETE\n");
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
io.rename.in.pattern1 = fname2;
io.rename.in.pattern2 = fname1;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
io.rename.in.pattern1 = fname1;
io.rename.in.pattern2 = fname2;
printf("trying rename while not open\n");
smb_raw_exit(cli->session);
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
printf("Trying self rename\n");
io.rename.in.pattern1 = fname2;
io.rename.in.pattern2 = fname2;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
io.rename.in.pattern1 = fname1;
io.rename.in.pattern2 = fname1;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
printf("trying wildcard rename\n");
io.rename.in.pattern1 = BASEDIR "\\*.txt";
io.rename.in.pattern2 = fname1;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
printf("and again\n");
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
printf("Trying extension change\n");
io.rename.in.pattern1 = BASEDIR "\\*.txt";
io.rename.in.pattern2 = BASEDIR "\\*.bak";
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
printf("Checking attrib handling\n");
torture_set_file_attribute(cli->tree, BASEDIR "\\test1.bak", FILE_ATTRIBUTE_HIDDEN);
io.rename.in.pattern1 = BASEDIR "\\test1.bak";
io.rename.in.pattern2 = BASEDIR "\\*.txt";
io.rename.in.attrib = 0;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
io.rename.in.attrib = FILE_ATTRIBUTE_HIDDEN;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
done:
smbcli_close(cli->tree, fnum);
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
test SMBntrename ops
*/
static BOOL test_ntrename(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_rename io;
NTSTATUS status;
BOOL ret = True;
int fnum, i;
const char *fname1 = BASEDIR "\\test1.txt";
const char *fname2 = BASEDIR "\\test2.txt";
union smb_fileinfo finfo;
printf("Testing SMBntrename\n");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Trying simple rename\n");
fnum = create_complex_file(cli, mem_ctx, fname1);
io.generic.level = RAW_RENAME_NTRENAME;
io.ntrename.in.old_name = fname1;
io.ntrename.in.new_name = fname2;
io.ntrename.in.attrib = 0;
io.ntrename.in.cluster_size = 0;
io.ntrename.in.flags = RENAME_FLAG_RENAME;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
smb_raw_exit(cli->session);
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
printf("Trying self rename\n");
io.ntrename.in.old_name = fname2;
io.ntrename.in.new_name = fname2;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
io.ntrename.in.old_name = fname1;
io.ntrename.in.new_name = fname1;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
printf("trying wildcard rename\n");
io.ntrename.in.old_name = BASEDIR "\\*.txt";
io.ntrename.in.new_name = fname1;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
printf("Checking attrib handling\n");
torture_set_file_attribute(cli->tree, fname2, FILE_ATTRIBUTE_HIDDEN);
io.ntrename.in.old_name = fname2;
io.ntrename.in.new_name = fname1;
io.ntrename.in.attrib = 0;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
io.ntrename.in.attrib = FILE_ATTRIBUTE_HIDDEN;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
printf("Checking hard link\n");
io.ntrename.in.old_name = fname1;
io.ntrename.in.new_name = fname2;
io.ntrename.in.attrib = 0;
io.ntrename.in.flags = RENAME_FLAG_HARD_LINK;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
finfo.generic.in.file.path = fname2;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.all_info.out.nlink, 2);
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
finfo.generic.in.file.path = fname1;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.all_info.out.nlink, 2);
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
smbcli_unlink(cli->tree, fname2);
finfo.generic.in.file.path = fname1;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.all_info.out.nlink, 1);
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
printf("Checking copy\n");
io.ntrename.in.old_name = fname1;
io.ntrename.in.new_name = fname2;
io.ntrename.in.attrib = 0;
io.ntrename.in.flags = RENAME_FLAG_COPY;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
finfo.generic.in.file.path = fname1;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.all_info.out.nlink, 1);
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
finfo.generic.in.file.path = fname2;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.all_info.out.nlink, 1);
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
finfo.generic.in.file.path = fname2;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.all_info.out.nlink, 1);
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
finfo.generic.in.file.path = fname1;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.all_info.out.nlink, 1);
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
smbcli_unlink(cli->tree, fname2);
finfo.generic.in.file.path = fname1;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.all_info.out.nlink, 1);
printf("Checking invalid flags\n");
io.ntrename.in.old_name = fname1;
io.ntrename.in.new_name = fname2;
io.ntrename.in.attrib = 0;
io.ntrename.in.flags = 0;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
io.ntrename.in.flags = 300;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
io.ntrename.in.flags = 0x106;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
printf("Checking unknown field\n");
io.ntrename.in.old_name = fname1;
io.ntrename.in.new_name = fname2;
io.ntrename.in.attrib = 0;
io.ntrename.in.flags = RENAME_FLAG_RENAME;
io.ntrename.in.cluster_size = 0xff;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
printf("Trying RENAME_FLAG_MOVE_CLUSTER_INFORMATION\n");
io.ntrename.in.old_name = fname2;
io.ntrename.in.new_name = fname1;
io.ntrename.in.attrib = 0;
io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION;
io.ntrename.in.cluster_size = 1;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
io.ntrename.in.flags = RENAME_FLAG_COPY;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
#if 0
{
char buf[16384];
fnum = smbcli_open(cli->tree, fname1, O_RDWR, DENY_NONE);
memset(buf, 1, sizeof(buf));
smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
smbcli_close(cli->tree, fnum);
fnum = smbcli_open(cli->tree, fname2, O_RDWR, DENY_NONE);
memset(buf, 1, sizeof(buf));
smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf)-1);
smbcli_close(cli->tree, fnum);
torture_all_info(cli->tree, fname1);
torture_all_info(cli->tree, fname2);
}
io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION;
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
for (i=0;i<20000;i++) {
io.ntrename.in.cluster_size = i;
status = smb_raw_rename(cli->tree, &io);
if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
printf("i=%d status=%s\n", i, nt_errstr(status));
}
}
#endif
printf("Checking other flags\n");
for (i=0;i<0xFFF;i++) {
if (i == RENAME_FLAG_RENAME ||
i == RENAME_FLAG_HARD_LINK ||
i == RENAME_FLAG_COPY) {
continue;
}
io.ntrename.in.old_name = fname2;
io.ntrename.in.new_name = fname1;
io.ntrename.in.flags = i;
io.ntrename.in.attrib = 0;
io.ntrename.in.cluster_size = 0;
status = smb_raw_rename(cli->tree, &io);
if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
printf("flags=0x%x status=%s\n", i, nt_errstr(status));
}
}
done:
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
basic testing of rename calls
*/
BOOL torture_raw_rename(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_rename");
if (!test_mv(cli, mem_ctx)) {
ret = False;
}
if (!test_ntrename(cli, mem_ctx)) {
ret = False;
}
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+267
View File
@@ -0,0 +1,267 @@
/*
Unix SMB/CIFS implementation.
Test samba3 hide unreadable/unwriteable
Copyright (C) Volker Lendecke 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "system/time.h"
#include "system/filesys.h"
#include "libcli/libcli.h"
#include "torture/util.h"
static void init_unixinfo_nochange(union smb_setfileinfo *info)
{
ZERO_STRUCTP(info);
info->unix_basic.level = RAW_SFILEINFO_UNIX_BASIC;
info->unix_basic.in.mode = SMB_MODE_NO_CHANGE;
info->unix_basic.in.end_of_file = SMB_SIZE_NO_CHANGE_HI;
info->unix_basic.in.end_of_file <<= 32;
info->unix_basic.in.end_of_file |= SMB_SIZE_NO_CHANGE_LO;
info->unix_basic.in.num_bytes = SMB_SIZE_NO_CHANGE_HI;
info->unix_basic.in.num_bytes <<= 32;
info->unix_basic.in.num_bytes |= SMB_SIZE_NO_CHANGE_LO;
info->unix_basic.in.status_change_time = SMB_TIME_NO_CHANGE_HI;
info->unix_basic.in.status_change_time <<= 32;
info->unix_basic.in.status_change_time = SMB_TIME_NO_CHANGE_LO;
info->unix_basic.in.access_time = SMB_TIME_NO_CHANGE_HI;
info->unix_basic.in.access_time <<= 32;
info->unix_basic.in.access_time |= SMB_TIME_NO_CHANGE_LO;
info->unix_basic.in.change_time = SMB_TIME_NO_CHANGE_HI;
info->unix_basic.in.change_time <<= 32;
info->unix_basic.in.change_time |= SMB_TIME_NO_CHANGE_LO;
info->unix_basic.in.uid = SMB_UID_NO_CHANGE;
info->unix_basic.in.gid = SMB_GID_NO_CHANGE;
}
struct list_state {
const char *fname;
BOOL visible;
};
static void set_visible(struct clilist_file_info *i, const char *mask,
void *priv)
{
struct list_state *state = priv;
if (strcasecmp_m(state->fname, i->name) == 0)
state->visible = True;
}
static BOOL is_visible(struct smbcli_tree *tree, const char *fname)
{
struct list_state state;
state.visible = False;
state.fname = fname;
if (smbcli_list(tree, "*.*", 0, set_visible, &state) < 0) {
return False;
}
return state.visible;
}
static BOOL is_readable(struct smbcli_tree *tree, const char *fname)
{
int fnum;
fnum = smbcli_open(tree, fname, O_RDONLY, DENY_NONE);
if (fnum < 0) {
return False;
}
smbcli_close(tree, fnum);
return True;
}
static BOOL is_writeable(TALLOC_CTX *mem_ctx, struct smbcli_tree *tree,
const char *fname)
{
int fnum;
fnum = smbcli_open(tree, fname, O_WRONLY, DENY_NONE);
if (fnum < 0) {
return False;
}
smbcli_close(tree, fnum);
return True;
}
/*
* This is not an exact method because there's a ton of reasons why a getatr
* might fail. But for our purposes it's sufficient.
*/
static BOOL smbcli_file_exists(struct smbcli_tree *tree, const char *fname)
{
return NT_STATUS_IS_OK(smbcli_getatr(tree, fname, NULL, NULL, NULL));
}
static NTSTATUS smbcli_chmod(struct smbcli_tree *tree, const char *fname,
uint64_t permissions)
{
union smb_setfileinfo sfinfo;
init_unixinfo_nochange(&sfinfo);
sfinfo.unix_basic.in.file.path = fname;
sfinfo.unix_basic.in.permissions = permissions;
return smb_raw_setpathinfo(tree, &sfinfo);
}
BOOL torture_samba3_hide(struct torture_context *torture)
{
struct smbcli_state *cli;
const char *fname = "test.txt";
int fnum;
NTSTATUS status;
struct smbcli_tree *hideunread;
struct smbcli_tree *hideunwrite;
if (!torture_open_connection_share(
torture, &cli, torture_setting_string(torture, "host", NULL),
torture_setting_string(torture, "share", NULL), NULL)) {
d_printf("torture_open_connection_share failed\n");
return False;
}
status = torture_second_tcon(torture, cli->session, "hideunread",
&hideunread);
if (!NT_STATUS_IS_OK(status)) {
d_printf("second_tcon(hideunread) failed: %s\n",
nt_errstr(status));
return False;
}
status = torture_second_tcon(torture, cli->session, "hideunwrite",
&hideunwrite);
if (!NT_STATUS_IS_OK(status)) {
d_printf("second_tcon(hideunwrite) failed: %s\n",
nt_errstr(status));
return False;
}
status = smbcli_unlink(cli->tree, fname);
if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
smbcli_setatr(cli->tree, fname, 0, -1);
smbcli_unlink(cli->tree, fname);
}
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum == -1) {
d_printf("Failed to create %s - %s\n", fname,
smbcli_errstr(cli->tree));
return False;
}
smbcli_close(cli->tree, fnum);
if (!smbcli_file_exists(cli->tree, fname)) {
d_printf("%s does not exist\n", fname);
return False;
}
/* R/W file should be visible everywhere */
status = smbcli_chmod(cli->tree, fname, UNIX_R_USR|UNIX_W_USR);
if (!NT_STATUS_IS_OK(status)) {
d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
return False;
}
if (!is_writeable(torture, cli->tree, fname)) {
d_printf("File not writable\n");
return False;
}
if (!is_readable(cli->tree, fname)) {
d_printf("File not readable\n");
return False;
}
if (!is_visible(cli->tree, fname)) {
d_printf("r/w file not visible via normal share\n");
return False;
}
if (!is_visible(hideunread, fname)) {
d_printf("r/w file not visible via hide unreadable\n");
return False;
}
if (!is_visible(hideunwrite, fname)) {
d_printf("r/w file not visible via hide unwriteable\n");
return False;
}
/* R/O file should not be visible via hide unwriteable files */
status = smbcli_chmod(cli->tree, fname, UNIX_R_USR);
if (!NT_STATUS_IS_OK(status)) {
d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
return False;
}
if (is_writeable(torture, cli->tree, fname)) {
d_printf("r/o is writable\n");
return False;
}
if (!is_readable(cli->tree, fname)) {
d_printf("r/o not readable\n");
return False;
}
if (!is_visible(cli->tree, fname)) {
d_printf("r/o file not visible via normal share\n");
return False;
}
if (!is_visible(hideunread, fname)) {
d_printf("r/o file not visible via hide unreadable\n");
return False;
}
if (is_visible(hideunwrite, fname)) {
d_printf("r/o file visible via hide unwriteable\n");
return False;
}
/* inaccessible file should be only visible on normal share */
status = smbcli_chmod(cli->tree, fname, 0);
if (!NT_STATUS_IS_OK(status)) {
d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
return False;
}
if (is_writeable(torture, cli->tree, fname)) {
d_printf("inaccessible file is writable\n");
return False;
}
if (is_readable(cli->tree, fname)) {
d_printf("inaccessible file is readable\n");
return False;
}
if (!is_visible(cli->tree, fname)) {
d_printf("inaccessible file not visible via normal share\n");
return False;
}
if (is_visible(hideunread, fname)) {
d_printf("inaccessible file visible via hide unreadable\n");
return False;
}
if (is_visible(hideunwrite, fname)) {
d_printf("inaccessible file visible via hide unwriteable\n");
return False;
}
return True;
}
+431
View File
@@ -0,0 +1,431 @@
/*
Unix SMB/CIFS implementation.
Test some misc Samba3 code paths
Copyright (C) Volker Lendecke 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "system/time.h"
#include "system/filesys.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
} \
} while (0)
BOOL torture_samba3_checkfsp(struct torture_context *torture)
{
struct smbcli_state *cli;
const char *fname = "test.txt";
const char *dirname = "testdir";
int fnum;
NTSTATUS status;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
ssize_t nread;
char buf[16];
struct smbcli_tree *tree2;
if ((mem_ctx = talloc_init("torture_samba3_checkfsp")) == NULL) {
d_printf("talloc_init failed\n");
return False;
}
if (!torture_open_connection_share(
torture, &cli, torture_setting_string(torture, "host", NULL),
torture_setting_string(torture, "share", NULL), NULL)) {
d_printf("torture_open_connection_share failed\n");
ret = False;
goto done;
}
smbcli_deltree(cli->tree, dirname);
status = torture_second_tcon(torture, cli->session,
torture_setting_string(torture, "share", NULL),
&tree2);
CHECK_STATUS(status, NT_STATUS_OK);
if (!NT_STATUS_IS_OK(status))
goto done;
/* Try a read on an invalid FID */
nread = smbcli_read(cli->tree, 4711, buf, 0, sizeof(buf));
CHECK_STATUS(smbcli_nt_error(cli->tree), NT_STATUS_INVALID_HANDLE);
/* Try a read on a directory handle */
status = smbcli_mkdir(cli->tree, dirname);
if (!NT_STATUS_IS_OK(status)) {
d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status));
ret = False;
goto done;
}
/* Open the directory */
{
union smb_open io;
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.fname = dirname;
status = smb_raw_open(cli->tree, mem_ctx, &io);
if (!NT_STATUS_IS_OK(status)) {
d_printf("smb_open on the directory failed: %s\n",
nt_errstr(status));
ret = False;
goto done;
}
fnum = io.ntcreatex.out.file.fnum;
}
/* Try a read on the directory */
nread = smbcli_read(cli->tree, fnum, buf, 0, sizeof(buf));
if (nread >= 0) {
d_printf("smbcli_read on a directory succeeded, expected "
"failure\n");
ret = False;
}
CHECK_STATUS(smbcli_nt_error(cli->tree),
NT_STATUS_INVALID_DEVICE_REQUEST);
/* Same test on the second tcon */
nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf));
if (nread >= 0) {
d_printf("smbcli_read on a directory succeeded, expected "
"failure\n");
ret = False;
}
CHECK_STATUS(smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE);
smbcli_close(cli->tree, fnum);
/* Try a normal file read on a second tcon */
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum == -1) {
d_printf("Failed to create %s - %s\n", fname,
smbcli_errstr(cli->tree));
ret = False;
goto done;
}
nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf));
CHECK_STATUS(smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE);
smbcli_close(cli->tree, fnum);
done:
smbcli_deltree(cli->tree, dirname);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
static NTSTATUS raw_smbcli_open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum)
{
union smb_open open_parms;
uint_t openfn=0;
uint_t accessmode=0;
TALLOC_CTX *mem_ctx;
NTSTATUS status;
mem_ctx = talloc_init("raw_open");
if (!mem_ctx) return NT_STATUS_NO_MEMORY;
if (flags & O_CREAT) {
openfn |= OPENX_OPEN_FUNC_CREATE;
}
if (!(flags & O_EXCL)) {
if (flags & O_TRUNC) {
openfn |= OPENX_OPEN_FUNC_TRUNC;
} else {
openfn |= OPENX_OPEN_FUNC_OPEN;
}
}
accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
if ((flags & O_ACCMODE) == O_RDWR) {
accessmode |= OPENX_MODE_ACCESS_RDWR;
} else if ((flags & O_ACCMODE) == O_WRONLY) {
accessmode |= OPENX_MODE_ACCESS_WRITE;
}
#if defined(O_SYNC)
if ((flags & O_SYNC) == O_SYNC) {
accessmode |= OPENX_MODE_WRITE_THRU;
}
#endif
if (share_mode == DENY_FCB) {
accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
}
open_parms.openx.level = RAW_OPEN_OPENX;
open_parms.openx.in.flags = 0;
open_parms.openx.in.open_mode = accessmode;
open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
open_parms.openx.in.file_attrs = 0;
open_parms.openx.in.write_time = 0;
open_parms.openx.in.open_func = openfn;
open_parms.openx.in.size = 0;
open_parms.openx.in.timeout = 0;
open_parms.openx.in.fname = fname;
status = smb_raw_open(tree, mem_ctx, &open_parms);
talloc_free(mem_ctx);
if (fnum && NT_STATUS_IS_OK(status)) {
*fnum = open_parms.openx.out.file.fnum;
}
return status;
}
BOOL torture_samba3_badpath(struct torture_context *torture)
{
struct smbcli_state *cli_nt;
struct smbcli_state *cli_dos;
const char *fname = "test.txt";
const char *dirname = "testdir";
char *fpath;
int fnum;
NTSTATUS status;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
BOOL nt_status_support;
if (!(mem_ctx = talloc_init("torture_samba3_badpath"))) {
d_printf("talloc_init failed\n");
return False;
}
nt_status_support = lp_nt_status_support();
if (!lp_set_cmdline("nt status support", "yes")) {
printf("Could not set 'nt status support = yes'\n");
goto fail;
}
if (!torture_open_connection(&cli_nt, 0)) {
goto fail;
}
if (!lp_set_cmdline("nt status support", "no")) {
printf("Could not set 'nt status support = yes'\n");
goto fail;
}
if (!torture_open_connection(&cli_dos, 1)) {
goto fail;
}
if (!lp_set_cmdline("nt status support",
nt_status_support ? "yes":"no")) {
printf("Could not reset 'nt status support = yes'");
goto fail;
}
smbcli_deltree(cli_nt->tree, dirname);
status = smbcli_mkdir(cli_nt->tree, dirname);
if (!NT_STATUS_IS_OK(status)) {
d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status));
ret = False;
goto done;
}
status = smbcli_chkpath(cli_nt->tree, dirname);
CHECK_STATUS(status, NT_STATUS_OK);
status = smbcli_chkpath(cli_nt->tree,
talloc_asprintf(mem_ctx, "%s\\bla", dirname));
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
status = smbcli_chkpath(cli_dos->tree,
talloc_asprintf(mem_ctx, "%s\\bla", dirname));
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
status = smbcli_chkpath(cli_nt->tree,
talloc_asprintf(mem_ctx, "%s\\bla\\blub",
dirname));
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND);
status = smbcli_chkpath(cli_dos->tree,
talloc_asprintf(mem_ctx, "%s\\bla\\blub",
dirname));
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
if (!(fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname))) {
goto fail;
}
fnum = smbcli_open(cli_nt->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
if (fnum == -1) {
d_printf("Could not create file %s: %s\n", fpath,
smbcli_errstr(cli_nt->tree));
goto fail;
}
smbcli_close(cli_nt->tree, fnum);
/*
* Do a whole bunch of error code checks on chkpath
*/
status = smbcli_chkpath(cli_nt->tree, fpath);
CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
status = smbcli_chkpath(cli_dos->tree, fpath);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
status = smbcli_chkpath(cli_nt->tree, "..");
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
status = smbcli_chkpath(cli_dos->tree, "..");
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
status = smbcli_chkpath(cli_nt->tree, ".");
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = smbcli_chkpath(cli_dos->tree, ".");
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
status = smbcli_chkpath(cli_nt->tree, "\t");
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = smbcli_chkpath(cli_dos->tree, "\t");
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
status = smbcli_chkpath(cli_nt->tree, "\t\\bla");
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = smbcli_chkpath(cli_dos->tree, "\t\\bla");
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
status = smbcli_chkpath(cli_nt->tree, "<");
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = smbcli_chkpath(cli_dos->tree, "<");
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
status = smbcli_chkpath(cli_nt->tree, "<\\bla");
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = smbcli_chkpath(cli_dos->tree, "<\\bla");
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
/*
* .... And the same gang against getatr. Note that the DOS error codes
* differ....
*/
status = smbcli_getatr(cli_nt->tree, fpath, NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_OK);
status = smbcli_getatr(cli_dos->tree, fpath, NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_OK);
status = smbcli_getatr(cli_nt->tree, "..", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
status = smbcli_getatr(cli_dos->tree, "..", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
status = smbcli_getatr(cli_nt->tree, ".", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = smbcli_getatr(cli_dos->tree, ".", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
status = smbcli_getatr(cli_nt->tree, "\t", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = smbcli_getatr(cli_dos->tree, "\t", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
status = smbcli_getatr(cli_nt->tree, "\t\\bla", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = smbcli_getatr(cli_dos->tree, "\t\\bla", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
status = smbcli_getatr(cli_nt->tree, "<", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = smbcli_getatr(cli_dos->tree, "<", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
status = smbcli_getatr(cli_nt->tree, "<\\bla", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = smbcli_getatr(cli_dos->tree, "<\\bla", NULL, NULL, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
/* Try the same set with openX. */
status = raw_smbcli_open(cli_nt->tree, "..", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
status = raw_smbcli_open(cli_dos->tree, "..", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
status = raw_smbcli_open(cli_nt->tree, ".", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = raw_smbcli_open(cli_dos->tree, ".", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
status = raw_smbcli_open(cli_nt->tree, "\t", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = raw_smbcli_open(cli_dos->tree, "\t", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
status = raw_smbcli_open(cli_nt->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = raw_smbcli_open(cli_dos->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
status = raw_smbcli_open(cli_nt->tree, "<", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = raw_smbcli_open(cli_dos->tree, "<", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
status = raw_smbcli_open(cli_nt->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
status = raw_smbcli_open(cli_dos->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL);
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
goto done;
fail:
ret = False;
done:
if (cli_nt != NULL) {
smbcli_deltree(cli_nt->tree, dirname);
torture_close_connection(cli_nt);
}
if (cli_dos != NULL) {
torture_close_connection(cli_dos);
}
talloc_free(mem_ctx);
return ret;
}
File diff suppressed because it is too large Load Diff
+256
View File
@@ -0,0 +1,256 @@
/*
Unix SMB/CIFS implementation.
seek test suite
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "system/filesys.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%d) Incorrect status %s - should be %s\n", \
__LINE__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
#define CHECK_VALUE(v, correct) do { \
if ((v) != (correct)) { \
printf("(%d) Incorrect value %s=%d - should be %d\n", \
__LINE__, #v, (int)v, (int)correct); \
ret = False; \
goto done; \
}} while (0)
#define BASEDIR "\\testseek"
/*
test seek ops
*/
static BOOL test_seek(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_seek io;
union smb_fileinfo finfo;
union smb_setfileinfo sfinfo;
NTSTATUS status;
BOOL ret = True;
int fnum, fnum2;
const char *fname = BASEDIR "\\test.txt";
uint8_t c[2];
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
if (fnum == -1) {
printf("Failed to open test.txt - %s\n", smbcli_errstr(cli->tree));
ret = False;
goto done;
}
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
finfo.position_information.in.file.fnum = fnum;
printf("Trying bad handle\n");
io.lseek.in.file.fnum = fnum+1;
io.lseek.in.mode = SEEK_MODE_START;
io.lseek.in.offset = 0;
status = smb_raw_seek(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("Trying simple seek\n");
io.lseek.in.file.fnum = fnum;
io.lseek.in.mode = SEEK_MODE_START;
io.lseek.in.offset = 17;
status = smb_raw_seek(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.lseek.out.offset, 17);
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.position_information.out.position, 0);
printf("Trying relative seek\n");
io.lseek.in.file.fnum = fnum;
io.lseek.in.mode = SEEK_MODE_CURRENT;
io.lseek.in.offset = -3;
status = smb_raw_seek(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.lseek.out.offset, 14);
printf("Trying end seek\n");
io.lseek.in.file.fnum = fnum;
io.lseek.in.mode = SEEK_MODE_END;
io.lseek.in.offset = 0;
status = smb_raw_seek(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
finfo.all_info.in.file.fnum = fnum;
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.lseek.out.offset, finfo.all_info.out.size);
printf("Trying max seek\n");
io.lseek.in.file.fnum = fnum;
io.lseek.in.mode = SEEK_MODE_START;
io.lseek.in.offset = -1;
status = smb_raw_seek(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.lseek.out.offset, 0xffffffff);
printf("Testing position information change\n");
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
finfo.position_information.in.file.fnum = fnum;
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.position_information.out.position, 0);
printf("Trying max overflow\n");
io.lseek.in.file.fnum = fnum;
io.lseek.in.mode = SEEK_MODE_CURRENT;
io.lseek.in.offset = 1000;
status = smb_raw_seek(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.lseek.out.offset, 999);
printf("Testing position information change\n");
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
finfo.position_information.in.file.fnum = fnum;
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.position_information.out.position, 0);
printf("trying write to update offset\n");
ZERO_STRUCT(c);
if (smbcli_write(cli->tree, fnum, 0, c, 0, 2) != 2) {
printf("Write failed - %s\n", smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("Testing position information change\n");
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
finfo.position_information.in.file.fnum = fnum;
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.position_information.out.position, 0);
io.lseek.in.file.fnum = fnum;
io.lseek.in.mode = SEEK_MODE_CURRENT;
io.lseek.in.offset = 0;
status = smb_raw_seek(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.lseek.out.offset, 2);
if (smbcli_read(cli->tree, fnum, c, 0, 1) != 1) {
printf("Read failed - %s\n", smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("Testing position information change\n");
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
finfo.position_information.in.file.fnum = fnum;
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.position_information.out.position, 1);
status = smb_raw_seek(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.lseek.out.offset, 1);
printf("Testing position information\n");
fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
if (fnum2 == -1) {
printf("2nd open failed - %s\n", smbcli_errstr(cli->tree));
ret = False;
goto done;
}
sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
sfinfo.position_information.in.file.fnum = fnum2;
sfinfo.position_information.in.position = 25;
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
CHECK_STATUS(status, NT_STATUS_OK);
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
finfo.position_information.in.file.fnum = fnum2;
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.position_information.out.position, 25);
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
finfo.position_information.in.file.fnum = fnum;
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.position_information.out.position, 1);
printf("position_information via paths\n");
sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
sfinfo.position_information.in.file.path = fname;
sfinfo.position_information.in.position = 32;
status = smb_raw_setpathinfo(cli->tree, &sfinfo);
CHECK_STATUS(status, NT_STATUS_OK);
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
finfo.position_information.in.file.fnum = fnum2;
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.position_information.out.position, 25);
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
finfo.position_information.in.file.path = fname;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(finfo.position_information.out.position, 0);
done:
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
basic testing of seek calls
*/
BOOL torture_raw_seek(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_seek");
if (!test_seek(cli, mem_ctx)) {
ret = False;
}
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+576
View File
@@ -0,0 +1,576 @@
/*
Unix SMB/CIFS implementation.
RAW_SFILEINFO_* individual test suite
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "system/time.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define BASEDIR "\\testsfileinfo"
/* basic testing of all RAW_SFILEINFO_* calls
for each call we test that it succeeds, and where possible test
for consistency between the calls.
*/
BOOL torture_raw_sfileinfo(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
int fnum_saved, d_fnum, fnum2, fnum = -1;
char *fnum_fname;
char *fnum_fname_new;
char *path_fname;
char *path_fname_new;
union smb_fileinfo finfo1, finfo2;
union smb_setfileinfo sfinfo;
NTSTATUS status, status2;
const char *call_name;
time_t basetime = (time(NULL) - 86400) & ~1;
BOOL check_fnum;
int n = time(NULL) % 100;
asprintf(&path_fname, BASEDIR "\\fname_test_%d.txt", n);
asprintf(&path_fname_new, BASEDIR "\\fname_test_new_%d.txt", n);
asprintf(&fnum_fname, BASEDIR "\\fnum_test_%d.txt", n);
asprintf(&fnum_fname_new, BASEDIR "\\fnum_test_new_%d.txt", n);
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_sfileinfo");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
#define RECREATE_FILE(fname) do { \
if (fnum != -1) smbcli_close(cli->tree, fnum); \
fnum = create_complex_file(cli, mem_ctx, fname); \
if (fnum == -1) { \
printf("(%s) ERROR: open of %s failed (%s)\n", \
__location__, fname, smbcli_errstr(cli->tree)); \
ret = False; \
goto done; \
}} while (0)
#define RECREATE_BOTH do { \
RECREATE_FILE(path_fname); \
smbcli_close(cli->tree, fnum); \
RECREATE_FILE(fnum_fname); \
} while (0)
RECREATE_BOTH;
#define CHECK_CALL_FNUM(call, rightstatus) do { \
check_fnum = True; \
call_name = #call; \
sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
sfinfo.generic.in.file.fnum = fnum; \
status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
if (!NT_STATUS_EQUAL(status, rightstatus)) { \
printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
nt_errstr(status), nt_errstr(rightstatus)); \
ret = False; \
} \
finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
finfo1.generic.in.file.fnum = fnum; \
status2 = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1); \
if (!NT_STATUS_IS_OK(status2)) { \
printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
ret = False; \
}} while (0)
#define CHECK_CALL_PATH(call, rightstatus) do { \
check_fnum = False; \
call_name = #call; \
sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
sfinfo.generic.in.file.path = path_fname; \
status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \
sfinfo.generic.in.file.path = path_fname_new; \
status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
} \
if (!NT_STATUS_EQUAL(status, rightstatus)) { \
printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
nt_errstr(status), nt_errstr(rightstatus)); \
ret = False; \
} \
finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
finfo1.generic.in.file.path = path_fname; \
status2 = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo1); \
if (NT_STATUS_EQUAL(status2, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \
finfo1.generic.in.file.path = path_fname_new; \
status2 = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo1); \
} \
if (!NT_STATUS_IS_OK(status2)) { \
printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status2)); \
ret = False; \
}} while (0)
#define CHECK1(call) \
do { if (NT_STATUS_IS_OK(status)) { \
finfo2.generic.level = RAW_FILEINFO_ ## call; \
if (check_fnum) { \
finfo2.generic.in.file.fnum = fnum; \
status2 = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo2); \
} else { \
finfo2.generic.in.file.path = path_fname; \
status2 = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2); \
if (NT_STATUS_EQUAL(status2, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \
finfo2.generic.in.file.path = path_fname_new; \
status2 = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2); \
} \
} \
if (!NT_STATUS_IS_OK(status2)) { \
printf("%s - %s\n", #call, nt_errstr(status2)); \
ret = False; \
} \
}} while (0)
#define CHECK_VALUE(call, stype, field, value) do { \
CHECK1(call); \
if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && finfo2.stype.out.field != value) { \
printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
call_name, #stype, #field, \
(uint_t)value, (uint_t)finfo2.stype.out.field); \
dump_all_info(mem_ctx, &finfo1); \
ret = False; \
}} while (0)
#define CHECK_TIME(call, stype, field, value) do { \
CHECK1(call); \
if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && nt_time_to_unix(finfo2.stype.out.field) != value) { \
printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
call_name, #stype, #field, \
(uint_t)value, \
(uint_t)nt_time_to_unix(finfo2.stype.out.field)); \
printf("\t%s", timestring(mem_ctx, value)); \
printf("\t%s\n", nt_time_string(mem_ctx, finfo2.stype.out.field)); \
dump_all_info(mem_ctx, &finfo1); \
ret = False; \
}} while (0)
#define CHECK_STR(call, stype, field, value) do { \
CHECK1(call); \
if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && strcmp(finfo2.stype.out.field, value) != 0) { \
printf("(%s) %s - %s/%s should be '%s' - '%s'\n", __location__, \
call_name, #stype, #field, \
value, \
finfo2.stype.out.field); \
dump_all_info(mem_ctx, &finfo1); \
ret = False; \
}} while (0)
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
printf("test setattr\n");
sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_READONLY;
sfinfo.setattr.in.write_time = basetime;
CHECK_CALL_PATH(SETATTR, NT_STATUS_OK);
CHECK_VALUE (ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
CHECK_TIME (ALL_INFO, all_info, write_time, basetime);
printf("setting to NORMAL doesn't do anything\n");
sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_NORMAL;
sfinfo.setattr.in.write_time = 0;
CHECK_CALL_PATH(SETATTR, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
CHECK_TIME (ALL_INFO, all_info, write_time, basetime);
printf("a zero write_time means don't change\n");
sfinfo.setattr.in.attrib = 0;
sfinfo.setattr.in.write_time = 0;
CHECK_CALL_PATH(SETATTR, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
CHECK_TIME (ALL_INFO, all_info, write_time, basetime);
printf("test setattre\n");
sfinfo.setattre.in.create_time = basetime + 20;
sfinfo.setattre.in.access_time = basetime + 30;
sfinfo.setattre.in.write_time = basetime + 40;
CHECK_CALL_FNUM(SETATTRE, NT_STATUS_OK);
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 20);
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 30);
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 40);
sfinfo.setattre.in.create_time = 0;
sfinfo.setattre.in.access_time = 0;
sfinfo.setattre.in.write_time = 0;
CHECK_CALL_FNUM(SETATTRE, NT_STATUS_OK);
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 20);
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 30);
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 40);
printf("test standard level\n");
sfinfo.standard.in.create_time = basetime + 100;
sfinfo.standard.in.access_time = basetime + 200;
sfinfo.standard.in.write_time = basetime + 300;
CHECK_CALL_FNUM(STANDARD, NT_STATUS_OK);
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
printf("test basic_info level\n");
basetime += 86400;
unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100);
unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200);
unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300);
unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400);
sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_OK);
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
printf("a zero time means don't change\n");
unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0);
unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0);
unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0);
unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0);
sfinfo.basic_info.in.attrib = 0;
CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_OK);
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
printf("test basic_information level\n");
basetime += 86400;
unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100);
unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200);
unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300);
unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400);
sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
CHECK_CALL_FNUM(BASIC_INFORMATION, NT_STATUS_OK);
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
CHECK_CALL_PATH(BASIC_INFORMATION, NT_STATUS_OK);
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
printf("a zero time means don't change\n");
unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0);
unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0);
unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0);
unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0);
sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
CHECK_CALL_FNUM(BASIC_INFORMATION, NT_STATUS_OK);
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
CHECK_CALL_PATH(BASIC_INFORMATION, NT_STATUS_OK);
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
/* interesting - w2k3 leaves change_time as current time for 0 change time
in setpathinfo
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
*/
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
printf("test disposition_info level\n");
sfinfo.disposition_info.in.delete_on_close = 1;
CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1);
CHECK_VALUE(ALL_INFO, all_info, nlink, 0);
sfinfo.disposition_info.in.delete_on_close = 0;
CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0);
CHECK_VALUE(ALL_INFO, all_info, nlink, 1);
printf("test disposition_information level\n");
sfinfo.disposition_info.in.delete_on_close = 1;
CHECK_CALL_FNUM(DISPOSITION_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1);
CHECK_VALUE(ALL_INFO, all_info, nlink, 0);
/* this would delete the file! */
/*
CHECK_CALL_PATH(DISPOSITION_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1);
CHECK_VALUE(ALL_INFO, all_info, nlink, 0);
*/
sfinfo.disposition_info.in.delete_on_close = 0;
CHECK_CALL_FNUM(DISPOSITION_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0);
CHECK_VALUE(ALL_INFO, all_info, nlink, 1);
CHECK_CALL_PATH(DISPOSITION_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0);
CHECK_VALUE(ALL_INFO, all_info, nlink, 1);
printf("test allocation_info level\n");
sfinfo.allocation_info.in.alloc_size = 0;
CHECK_CALL_FNUM(ALLOCATION_INFO, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, size, 0);
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
sfinfo.allocation_info.in.alloc_size = 4096;
CHECK_CALL_FNUM(ALLOCATION_INFO, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 4096);
CHECK_VALUE(ALL_INFO, all_info, size, 0);
RECREATE_BOTH;
sfinfo.allocation_info.in.alloc_size = 0;
CHECK_CALL_FNUM(ALLOCATION_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, size, 0);
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
CHECK_CALL_PATH(ALLOCATION_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, size, 0);
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
sfinfo.allocation_info.in.alloc_size = 4096;
CHECK_CALL_FNUM(ALLOCATION_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 4096);
CHECK_VALUE(ALL_INFO, all_info, size, 0);
/* setting the allocation size up via setpathinfo seems
to be broken in w2k3 */
CHECK_CALL_PATH(ALLOCATION_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
CHECK_VALUE(ALL_INFO, all_info, size, 0);
printf("test end_of_file_info level\n");
sfinfo.end_of_file_info.in.size = 37;
CHECK_CALL_FNUM(END_OF_FILE_INFO, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, size, 37);
sfinfo.end_of_file_info.in.size = 7;
CHECK_CALL_FNUM(END_OF_FILE_INFO, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, size, 7);
sfinfo.end_of_file_info.in.size = 37;
CHECK_CALL_FNUM(END_OF_FILE_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, size, 37);
CHECK_CALL_PATH(END_OF_FILE_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, size, 37);
sfinfo.end_of_file_info.in.size = 7;
CHECK_CALL_FNUM(END_OF_FILE_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, size, 7);
CHECK_CALL_PATH(END_OF_FILE_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(ALL_INFO, all_info, size, 7);
printf("test position_information level\n");
sfinfo.position_information.in.position = 123456;
CHECK_CALL_FNUM(POSITION_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(POSITION_INFORMATION, position_information, position, 123456);
CHECK_CALL_PATH(POSITION_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(POSITION_INFORMATION, position_information, position, 0);
printf("test mode_information level\n");
sfinfo.mode_information.in.mode = 2;
CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 2);
CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);
sfinfo.mode_information.in.mode = 1;
CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER);
CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER);
sfinfo.mode_information.in.mode = 0;
CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);
CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_OK);
CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);
#if 1
printf("finally the rename_information level\n");
smbcli_close(cli->tree, create_complex_file(cli, mem_ctx, fnum_fname_new));
smbcli_close(cli->tree, create_complex_file(cli, mem_ctx, path_fname_new));
sfinfo.rename_information.in.overwrite = 0;
sfinfo.rename_information.in.root_fid = 0;
sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OBJECT_NAME_COLLISION);
sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1;
CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OBJECT_NAME_COLLISION);
sfinfo.rename_information.in.new_name = fnum_fname_new;
sfinfo.rename_information.in.overwrite = 1;
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_NOT_SUPPORTED);
sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
sfinfo.rename_information.in.overwrite = 1;
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new);
printf("Trying rename with dest file open\n");
fnum2 = create_complex_file(cli, mem_ctx, fnum_fname);
sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
sfinfo.rename_information.in.overwrite = 1;
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_ACCESS_DENIED);
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new);
fnum_saved = fnum;
fnum = fnum2;
sfinfo.disposition_info.in.delete_on_close = 1;
CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK);
fnum = fnum_saved;
printf("Trying rename with dest file open and delete_on_close\n");
sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
sfinfo.rename_information.in.overwrite = 1;
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_ACCESS_DENIED);
smbcli_close(cli->tree, fnum2);
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
printf("Trying rename with source file open twice\n");
sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
sfinfo.rename_information.in.overwrite = 1;
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
fnum2 = create_complex_file(cli, mem_ctx, fnum_fname);
sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
sfinfo.rename_information.in.overwrite = 0;
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new);
smbcli_close(cli->tree, fnum2);
sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
sfinfo.rename_information.in.overwrite = 0;
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1;
sfinfo.rename_information.in.overwrite = 1;
CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK);
CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new);
sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
sfinfo.rename_information.in.new_name = path_fname+strlen(BASEDIR)+1;
CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK);
CHECK_STR(NAME_INFO, name_info, fname.s, path_fname);
printf("Trying rename with a root fid\n");
status = create_directory_handle(cli->tree, BASEDIR, &d_fnum);
CHECK_STATUS(status, NT_STATUS_OK);
sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
sfinfo.rename_information.in.root_fid = d_fnum;
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_INVALID_PARAMETER);
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
#endif
#if 0
printf("test unix_basic level\n");
CHECK_CALL_FNUM(UNIX_BASIC, NT_STATUS_OK);
CHECK_CALL_PATH(UNIX_BASIC, NT_STATUS_OK);
printf("test unix_link level\n");
CHECK_CALL_FNUM(UNIX_LINK, NT_STATUS_OK);
CHECK_CALL_PATH(UNIX_LINK, NT_STATUS_OK);
#endif
done:
smb_raw_exit(cli->session);
smbcli_close(cli->tree, fnum);
if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fnum_fname))) {
printf("Failed to delete %s - %s\n", fnum_fname, smbcli_errstr(cli->tree));
}
if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, path_fname))) {
printf("Failed to delete %s - %s\n", path_fname, smbcli_errstr(cli->tree));
}
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
/*
look for the w2k3 setpathinfo STANDARD bug
*/
BOOL torture_raw_sfileinfo_bug(struct torture_context *torture)
{
struct smbcli_state *cli;
TALLOC_CTX *mem_ctx;
const char *fname = "\\bug3.txt";
union smb_setfileinfo sfinfo;
NTSTATUS status;
int fnum;
if (!torture_setting_bool(torture, "dangerous", False)) {
printf("torture_raw_sfileinfo_bug disabled - enable dangerous tests to use\n");
return True;
}
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_sfileinfo");
fnum = create_complex_file(cli, mem_ctx, fname);
smbcli_close(cli->tree, fnum);
sfinfo.generic.level = RAW_SFILEINFO_STANDARD;
sfinfo.generic.in.file.path = fname;
sfinfo.standard.in.create_time = 0;
sfinfo.standard.in.access_time = 0;
sfinfo.standard.in.write_time = 0;
status = smb_raw_setpathinfo(cli->tree, &sfinfo);
printf("%s - %s\n", fname, nt_errstr(status));
printf("now try and delete %s\n", fname);
return True;
}
+241
View File
@@ -0,0 +1,241 @@
/*
Unix SMB/CIFS implementation.
test alternate data streams
Copyright (C) Andrew Tridgell 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "system/filesys.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define BASEDIR "\\teststreams"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
#define CHECK_VALUE(v, correct) do { \
if ((v) != (correct)) { \
printf("(%s) Incorrect value %s=%d - should be %d\n", \
__location__, #v, (int)v, (int)correct); \
ret = False; \
}} while (0)
/*
check that a stream has the right contents
*/
static BOOL check_stream(struct smbcli_state *cli, TALLOC_CTX *mem_ctx,
const char *fname, const char *sname,
const char *value)
{
int fnum;
const char *full_name;
uint8_t *buf;
ssize_t ret;
full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
fnum = smbcli_open(cli->tree, full_name, O_RDONLY, DENY_NONE);
if (value == NULL) {
if (fnum != -1) {
printf("should have failed stream open of %s\n", full_name);
return False;
}
return True;
}
if (fnum == -1) {
printf("Failed to open stream '%s' - %s\n",
full_name, smbcli_errstr(cli->tree));
return False;
}
buf = talloc_size(mem_ctx, strlen(value)+11);
ret = smbcli_read(cli->tree, fnum, buf, 0, strlen(value)+11);
if (ret != strlen(value)) {
printf("Failed to read %lu bytes from stream '%s' - got %d\n",
(long)strlen(value), full_name, (int)ret);
return False;
}
if (memcmp(buf, value, strlen(value)) != 0) {
printf("Bad data in stream\n");
return False;
}
smbcli_close(cli->tree, fnum);
return True;
}
/*
test basic io on streams
*/
static BOOL test_stream_io(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
union smb_open io;
const char *fname = BASEDIR "\\stream.txt";
const char *sname1, *sname2;
BOOL ret = True;
int fnum = -1;
ssize_t retsize;
sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "Second Stream");
printf("opening non-existant directory stream\n");
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = 0;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = sname1;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
printf("creating a stream on a non-existant file\n");
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.fname = sname1;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
ret &= check_stream(cli, mem_ctx, fname, "Stream One", NULL);
printf("check that open of base file is allowed\n");
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
io.ntcreatex.in.fname = fname;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
printf("writing to stream\n");
retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
CHECK_VALUE(retsize, 9);
smbcli_close(cli->tree, fnum);
ret &= check_stream(cli, mem_ctx, fname, "Stream One", "test data");
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
io.ntcreatex.in.fname = sname1;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
printf("modifying stream\n");
retsize = smbcli_write(cli->tree, fnum, 0, "MORE DATA ", 5, 10);
CHECK_VALUE(retsize, 10);
smbcli_close(cli->tree, fnum);
ret &= check_stream(cli, mem_ctx, fname, "Stream One:$FOO", NULL);
printf("creating a stream2 on a existing file\n");
io.ntcreatex.in.fname = sname2;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
printf("modifying stream\n");
retsize = smbcli_write(cli->tree, fnum, 0, "SECOND STREAM", 0, 13);
CHECK_VALUE(retsize, 13);
smbcli_close(cli->tree, fnum);
ret &= check_stream(cli, mem_ctx, fname, "Stream One", "test MORE DATA ");
ret &= check_stream(cli, mem_ctx, fname, "Stream One:$DATA", "test MORE DATA ");
ret &= check_stream(cli, mem_ctx, fname, "Stream One:", NULL);
ret &= check_stream(cli, mem_ctx, fname, "Second Stream", "SECOND STREAM");
ret &= check_stream(cli, mem_ctx, fname, "Second Stream:$DATA", "SECOND STREAM");
ret &= check_stream(cli, mem_ctx, fname, "Second Stream:", NULL);
ret &= check_stream(cli, mem_ctx, fname, "Second Stream:$FOO", NULL);
printf("deleting stream\n");
status = smbcli_unlink(cli->tree, sname1);
CHECK_STATUS(status, NT_STATUS_OK);
printf("delete a stream via delete-on-close\n");
io.ntcreatex.in.fname = sname2;
io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
smbcli_close(cli->tree, fnum);
status = smbcli_unlink(cli->tree, sname2);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
printf("deleting file\n");
status = smbcli_unlink(cli->tree, fname);
CHECK_STATUS(status, NT_STATUS_OK);
done:
smbcli_close(cli->tree, fnum);
return ret;
}
/*
basic testing of streams calls
*/
BOOL torture_raw_streams(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_streams");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
ret &= test_stream_io(cli, mem_ctx);
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+422
View File
@@ -0,0 +1,422 @@
/*
Unix SMB/CIFS implementation.
unlink test suite
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "system/filesys.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
#define BASEDIR "\\testunlink"
/*
test unlink ops
*/
static BOOL test_unlink(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_unlink io;
NTSTATUS status;
BOOL ret = True;
const char *fname = BASEDIR "\\test.txt";
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Trying non-existant file\n");
io.unlink.in.pattern = fname;
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
io.unlink.in.pattern = fname;
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
printf("Trying a hidden file\n");
smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
torture_set_file_attribute(cli->tree, fname, FILE_ATTRIBUTE_HIDDEN);
io.unlink.in.pattern = fname;
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
io.unlink.in.pattern = fname;
io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
io.unlink.in.pattern = fname;
io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
printf("Trying a directory\n");
io.unlink.in.pattern = BASEDIR;
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
io.unlink.in.pattern = BASEDIR;
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
printf("Trying a bad path\n");
io.unlink.in.pattern = "..";
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
io.unlink.in.pattern = "\\..";
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
io.unlink.in.pattern = BASEDIR "\\..\\..";
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
io.unlink.in.pattern = BASEDIR "\\..";
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
printf("Trying wildcards\n");
smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
io.unlink.in.pattern = BASEDIR "\\t*.t";
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
io.unlink.in.pattern = BASEDIR "\\z*";
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
io.unlink.in.pattern = BASEDIR "\\z*";
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
io.unlink.in.pattern = BASEDIR "\\*";
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
io.unlink.in.pattern = BASEDIR "\\?";
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
io.unlink.in.pattern = BASEDIR "\\t*";
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
io.unlink.in.pattern = BASEDIR "\\*.dat";
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
io.unlink.in.pattern = BASEDIR "\\*.tx?";
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
done:
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
test delete on close
*/
static BOOL test_delete_on_close(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_open op;
union smb_unlink io;
struct smb_rmdir dio;
NTSTATUS status;
BOOL ret = True;
int fnum, fnum2;
const char *fname = BASEDIR "\\test.txt";
const char *dname = BASEDIR "\\test.dir";
const char *inside = BASEDIR "\\test.dir\\test.txt";
union smb_setfileinfo sfinfo;
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
dio.in.path = dname;
io.unlink.in.pattern = fname;
io.unlink.in.attrib = 0;
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
printf("Testing with delete_on_close 0\n");
fnum = create_complex_file(cli, mem_ctx, fname);
sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
sfinfo.disposition_info.in.file.fnum = fnum;
sfinfo.disposition_info.in.delete_on_close = 0;
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
CHECK_STATUS(status, NT_STATUS_OK);
smbcli_close(cli->tree, fnum);
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
printf("Testing with delete_on_close 1\n");
fnum = create_complex_file(cli, mem_ctx, fname);
sfinfo.disposition_info.in.file.fnum = fnum;
sfinfo.disposition_info.in.delete_on_close = 1;
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
CHECK_STATUS(status, NT_STATUS_OK);
smbcli_close(cli->tree, fnum);
status = smb_raw_unlink(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
printf("Testing with directory and delete_on_close 0\n");
status = create_directory_handle(cli->tree, dname, &fnum);
CHECK_STATUS(status, NT_STATUS_OK);
sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
sfinfo.disposition_info.in.file.fnum = fnum;
sfinfo.disposition_info.in.delete_on_close = 0;
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
CHECK_STATUS(status, NT_STATUS_OK);
smbcli_close(cli->tree, fnum);
status = smb_raw_rmdir(cli->tree, &dio);
CHECK_STATUS(status, NT_STATUS_OK);
printf("Testing with directory delete_on_close 1\n");
status = create_directory_handle(cli->tree, dname, &fnum);
CHECK_STATUS(status, NT_STATUS_OK);
sfinfo.disposition_info.in.file.fnum = fnum;
sfinfo.disposition_info.in.delete_on_close = 1;
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
CHECK_STATUS(status, NT_STATUS_OK);
smbcli_close(cli->tree, fnum);
status = smb_raw_rmdir(cli->tree, &dio);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
printf("Testing with non-empty directory delete_on_close\n");
status = create_directory_handle(cli->tree, dname, &fnum);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = create_complex_file(cli, mem_ctx, inside);
sfinfo.disposition_info.in.file.fnum = fnum;
sfinfo.disposition_info.in.delete_on_close = 1;
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
sfinfo.disposition_info.in.file.fnum = fnum2;
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
CHECK_STATUS(status, NT_STATUS_OK);
sfinfo.disposition_info.in.file.fnum = fnum;
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
smbcli_close(cli->tree, fnum2);
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
CHECK_STATUS(status, NT_STATUS_OK);
smbcli_close(cli->tree, fnum);
status = smb_raw_rmdir(cli->tree, &dio);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
printf("Testing open dir with delete_on_close\n");
status = create_directory_handle(cli->tree, dname, &fnum);
CHECK_STATUS(status, NT_STATUS_OK);
smbcli_close(cli->tree, fnum);
fnum2 = create_complex_file(cli, mem_ctx, inside);
smbcli_close(cli->tree, fnum2);
op.generic.level = RAW_OPEN_NTCREATEX;
op.ntcreatex.in.root_fid = 0;
op.ntcreatex.in.flags = 0;
op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
op.ntcreatex.in.alloc_size = 0;
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
op.ntcreatex.in.security_flags = 0;
op.ntcreatex.in.fname = dname;
status = smb_raw_open(cli->tree, mem_ctx, &op);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = op.ntcreatex.out.file.fnum;
smbcli_close(cli->tree, fnum);
status = smb_raw_rmdir(cli->tree, &dio);
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
smbcli_deltree(cli->tree, dname);
printf("Testing double open dir with second delete_on_close\n");
status = create_directory_handle(cli->tree, dname, &fnum);
CHECK_STATUS(status, NT_STATUS_OK);
smbcli_close(cli->tree, fnum);
fnum2 = create_complex_file(cli, mem_ctx, inside);
smbcli_close(cli->tree, fnum2);
op.generic.level = RAW_OPEN_NTCREATEX;
op.ntcreatex.in.root_fid = 0;
op.ntcreatex.in.flags = 0;
op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
op.ntcreatex.in.alloc_size = 0;
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
op.ntcreatex.in.security_flags = 0;
op.ntcreatex.in.fname = dname;
status = smb_raw_open(cli->tree, mem_ctx, &op);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = op.ntcreatex.out.file.fnum;
smbcli_close(cli->tree, fnum2);
status = smb_raw_rmdir(cli->tree, &dio);
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
smbcli_deltree(cli->tree, dname);
printf("Testing pre-existing open dir with second delete_on_close\n");
status = create_directory_handle(cli->tree, dname, &fnum);
CHECK_STATUS(status, NT_STATUS_OK);
smbcli_close(cli->tree, fnum);
fnum = create_complex_file(cli, mem_ctx, inside);
smbcli_close(cli->tree, fnum);
/* we have a dir with a file in it, no handles open */
op.generic.level = RAW_OPEN_NTCREATEX;
op.ntcreatex.in.root_fid = 0;
op.ntcreatex.in.flags = 0;
op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
op.ntcreatex.in.alloc_size = 0;
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
op.ntcreatex.in.security_flags = 0;
op.ntcreatex.in.fname = dname;
status = smb_raw_open(cli->tree, mem_ctx, &op);
CHECK_STATUS(status, NT_STATUS_OK);
fnum = op.ntcreatex.out.file.fnum;
/* open without delete on close */
op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
status = smb_raw_open(cli->tree, mem_ctx, &op);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = op.ntcreatex.out.file.fnum;
/* close 2nd file handle */
smbcli_close(cli->tree, fnum2);
status = smb_raw_rmdir(cli->tree, &dio);
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
smbcli_close(cli->tree, fnum);
status = smb_raw_rmdir(cli->tree, &dio);
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
done:
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
basic testing of unlink calls
*/
BOOL torture_raw_unlink(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_unlink");
ret &= test_unlink(cli, mem_ctx);
ret &= test_delete_on_close(cli, mem_ctx);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}
+730
View File
@@ -0,0 +1,730 @@
/*
Unix SMB/CIFS implementation.
test suite for various write operations
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "system/time.h"
#include "system/filesys.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
printf("(%s) Incorrect status %s - should be %s\n", \
__location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
#define CHECK_VALUE(v, correct) do { \
if ((v) != (correct)) { \
printf("(%s) Incorrect value %s=%d - should be %d\n", \
__location__, #v, v, correct); \
ret = False; \
goto done; \
}} while (0)
#define CHECK_BUFFER(buf, seed, len) do { \
if (!check_buffer(buf, seed, len, __location__)) { \
ret = False; \
goto done; \
}} while (0)
#define CHECK_ALL_INFO(v, field) do { \
finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
finfo.all_info.in.file.path = fname; \
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
CHECK_STATUS(status, NT_STATUS_OK); \
if ((v) != finfo.all_info.out.field) { \
printf("(%s) wrong value for field %s %.0f - %.0f\n", \
__location__, #field, (double)v, (double)finfo.all_info.out.field); \
dump_all_info(mem_ctx, &finfo); \
ret = False; \
}} while (0)
#define BASEDIR "\\testwrite"
/*
setup a random buffer based on a seed
*/
static void setup_buffer(uint8_t *buf, uint_t seed, int len)
{
int i;
srandom(seed);
for (i=0;i<len;i++) buf[i] = random();
}
/*
check a random buffer based on a seed
*/
static BOOL check_buffer(uint8_t *buf, uint_t seed, int len, const char *location)
{
int i;
srandom(seed);
for (i=0;i<len;i++) {
uint8_t v = random();
if (buf[i] != v) {
printf("Buffer incorrect at %s! ofs=%d buf=0x%x correct=0x%x\n",
location, i, buf[i], v);
return False;
}
}
return True;
}
/*
test write ops
*/
static BOOL test_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_write io;
NTSTATUS status;
BOOL ret = True;
int fnum;
uint8_t *buf;
const int maxsize = 90000;
const char *fname = BASEDIR "\\test.txt";
uint_t seed = time(NULL);
union smb_fileinfo finfo;
buf = talloc_zero_size(mem_ctx, maxsize);
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Testing RAW_WRITE_WRITE\n");
io.generic.level = RAW_WRITE_WRITE;
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum == -1) {
printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("Trying zero write\n");
io.write.in.file.fnum = fnum;
io.write.in.count = 0;
io.write.in.offset = 0;
io.write.in.remaining = 0;
io.write.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.write.out.nwritten, 0);
setup_buffer(buf, seed, maxsize);
printf("Trying small write\n");
io.write.in.count = 9;
io.write.in.offset = 4;
io.write.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.write.out.nwritten, io.write.in.count);
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf+4, seed, 9);
CHECK_VALUE(IVAL(buf,0), 0);
setup_buffer(buf, seed, maxsize);
printf("Trying large write\n");
io.write.in.count = 4000;
io.write.in.offset = 0;
io.write.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.write.out.nwritten, 4000);
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf, seed, 4000);
printf("Trying bad fnum\n");
io.write.in.file.fnum = fnum+1;
io.write.in.count = 4000;
io.write.in.offset = 0;
io.write.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("Setting file as sparse\n");
status = torture_set_sparse(cli->tree, fnum);
CHECK_STATUS(status, NT_STATUS_OK);
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
goto done;
}
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
goto done;
}
printf("Trying 2^32 offset\n");
setup_buffer(buf, seed, maxsize);
io.write.in.file.fnum = fnum;
io.write.in.count = 4000;
io.write.in.offset = 0xFFFFFFFF - 2000;
io.write.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.write.out.nwritten, 4000);
CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size);
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf, seed, 4000);
done:
smbcli_close(cli->tree, fnum);
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
test writex ops
*/
static BOOL test_writex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_write io;
NTSTATUS status;
BOOL ret = True;
int fnum, i;
uint8_t *buf;
const int maxsize = 90000;
const char *fname = BASEDIR "\\test.txt";
uint_t seed = time(NULL);
union smb_fileinfo finfo;
int max_bits=63;
if (!lp_parm_bool(-1, "torture", "dangerous", False)) {
max_bits=33;
printf("dangerous not set - limiting range of test to 2^%d\n", max_bits);
}
buf = talloc_zero_size(mem_ctx, maxsize);
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Testing RAW_WRITE_WRITEX\n");
io.generic.level = RAW_WRITE_WRITEX;
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum == -1) {
printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("Trying zero write\n");
io.writex.in.file.fnum = fnum;
io.writex.in.offset = 0;
io.writex.in.wmode = 0;
io.writex.in.remaining = 0;
io.writex.in.count = 0;
io.writex.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writex.out.nwritten, 0);
setup_buffer(buf, seed, maxsize);
printf("Trying small write\n");
io.writex.in.count = 9;
io.writex.in.offset = 4;
io.writex.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf+4, seed, 9);
CHECK_VALUE(IVAL(buf,0), 0);
setup_buffer(buf, seed, maxsize);
printf("Trying large write\n");
io.writex.in.count = 4000;
io.writex.in.offset = 0;
io.writex.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writex.out.nwritten, 4000);
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf, seed, 4000);
printf("Trying bad fnum\n");
io.writex.in.file.fnum = fnum+1;
io.writex.in.count = 4000;
io.writex.in.offset = 0;
io.writex.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("Testing wmode\n");
io.writex.in.file.fnum = fnum;
io.writex.in.count = 1;
io.writex.in.offset = 0;
io.writex.in.wmode = 1;
io.writex.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
io.writex.in.wmode = 2;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
printf("Trying locked region\n");
cli->session->pid++;
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) {
printf("Failed to lock file at %s\n", __location__);
ret = False;
goto done;
}
cli->session->pid--;
io.writex.in.wmode = 0;
io.writex.in.count = 4;
io.writex.in.offset = 0;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
printf("Setting file as sparse\n");
status = torture_set_sparse(cli->tree, fnum);
CHECK_STATUS(status, NT_STATUS_OK);
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
goto done;
}
printf("Trying 2^32 offset\n");
setup_buffer(buf, seed, maxsize);
io.writex.in.file.fnum = fnum;
io.writex.in.count = 4000;
io.writex.in.offset = 0xFFFFFFFF - 2000;
io.writex.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writex.out.nwritten, 4000);
CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf, seed, 4000);
for (i=33;i<max_bits;i++) {
printf("Trying 2^%d offset\n", i);
setup_buffer(buf, seed+1, maxsize);
io.writex.in.file.fnum = fnum;
io.writex.in.count = 4000;
io.writex.in.offset = ((uint64_t)1) << i;
io.writex.in.data = buf;
status = smb_raw_write(cli->tree, &io);
if (i>33 &&
NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
break;
}
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writex.out.nwritten, 4000);
CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf, seed+1, 4000);
}
printf("limit is 2^%d\n", i);
setup_buffer(buf, seed, maxsize);
done:
smbcli_close(cli->tree, fnum);
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
test write unlock ops
*/
static BOOL test_writeunlock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_write io;
NTSTATUS status;
BOOL ret = True;
int fnum;
uint8_t *buf;
const int maxsize = 90000;
const char *fname = BASEDIR "\\test.txt";
uint_t seed = time(NULL);
union smb_fileinfo finfo;
buf = talloc_zero_size(mem_ctx, maxsize);
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Testing RAW_WRITE_WRITEUNLOCK\n");
io.generic.level = RAW_WRITE_WRITEUNLOCK;
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum == -1) {
printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("Trying zero write\n");
io.writeunlock.in.file.fnum = fnum;
io.writeunlock.in.count = 0;
io.writeunlock.in.offset = 0;
io.writeunlock.in.remaining = 0;
io.writeunlock.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
setup_buffer(buf, seed, maxsize);
printf("Trying small write\n");
io.writeunlock.in.count = 9;
io.writeunlock.in.offset = 4;
io.writeunlock.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf+4, seed, 9);
CHECK_VALUE(IVAL(buf,0), 0);
setup_buffer(buf, seed, maxsize);
smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
0, WRITE_LOCK);
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf+4, seed, 9);
CHECK_VALUE(IVAL(buf,0), 0);
setup_buffer(buf, seed, maxsize);
printf("Trying large write\n");
io.writeunlock.in.count = 4000;
io.writeunlock.in.offset = 0;
io.writeunlock.in.data = buf;
smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
0, WRITE_LOCK);
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf, seed, 4000);
printf("Trying bad fnum\n");
io.writeunlock.in.file.fnum = fnum+1;
io.writeunlock.in.count = 4000;
io.writeunlock.in.offset = 0;
io.writeunlock.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("Setting file as sparse\n");
status = torture_set_sparse(cli->tree, fnum);
CHECK_STATUS(status, NT_STATUS_OK);
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
goto done;
}
printf("Trying 2^32 offset\n");
setup_buffer(buf, seed, maxsize);
io.writeunlock.in.file.fnum = fnum;
io.writeunlock.in.count = 4000;
io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
io.writeunlock.in.data = buf;
smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
0, WRITE_LOCK);
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf, seed, 4000);
done:
smbcli_close(cli->tree, fnum);
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
test write close ops
*/
static BOOL test_writeclose(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_write io;
NTSTATUS status;
BOOL ret = True;
int fnum;
uint8_t *buf;
const int maxsize = 90000;
const char *fname = BASEDIR "\\test.txt";
uint_t seed = time(NULL);
union smb_fileinfo finfo;
buf = talloc_zero_size(mem_ctx, maxsize);
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
printf("Testing RAW_WRITE_WRITECLOSE\n");
io.generic.level = RAW_WRITE_WRITECLOSE;
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum == -1) {
printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
ret = False;
goto done;
}
printf("Trying zero write\n");
io.writeclose.in.file.fnum = fnum;
io.writeclose.in.count = 0;
io.writeclose.in.offset = 0;
io.writeclose.in.mtime = 0;
io.writeclose.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
setup_buffer(buf, seed, maxsize);
printf("Trying small write\n");
io.writeclose.in.count = 9;
io.writeclose.in.offset = 4;
io.writeclose.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
io.writeclose.in.file.fnum = fnum;
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf+4, seed, 9);
CHECK_VALUE(IVAL(buf,0), 0);
setup_buffer(buf, seed, maxsize);
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
io.writeclose.in.file.fnum = fnum;
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf+4, seed, 9);
CHECK_VALUE(IVAL(buf,0), 0);
setup_buffer(buf, seed, maxsize);
printf("Trying large write\n");
io.writeclose.in.count = 4000;
io.writeclose.in.offset = 0;
io.writeclose.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writeclose.out.nwritten, 4000);
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
io.writeclose.in.file.fnum = fnum;
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf, seed, 4000);
printf("Trying bad fnum\n");
io.writeclose.in.file.fnum = fnum+1;
io.writeclose.in.count = 4000;
io.writeclose.in.offset = 0;
io.writeclose.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
printf("Setting file as sparse\n");
status = torture_set_sparse(cli->tree, fnum);
CHECK_STATUS(status, NT_STATUS_OK);
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
goto done;
}
printf("Trying 2^32 offset\n");
setup_buffer(buf, seed, maxsize);
io.writeclose.in.file.fnum = fnum;
io.writeclose.in.count = 4000;
io.writeclose.in.offset = 0xFFFFFFFF - 2000;
io.writeclose.in.data = buf;
status = smb_raw_write(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_VALUE(io.writeclose.out.nwritten, 4000);
CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
io.writeclose.in.file.fnum = fnum;
memset(buf, 0, maxsize);
if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
printf("read failed at %s\n", __location__);
ret = False;
goto done;
}
CHECK_BUFFER(buf, seed, 4000);
done:
smbcli_close(cli->tree, fnum);
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
basic testing of write calls
*/
BOOL torture_raw_write(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_write");
ret &= test_write(cli, mem_ctx);
ret &= test_writeunlock(cli, mem_ctx);
ret &= test_writeclose(cli, mem_ctx);
ret &= test_writex(cli, mem_ctx);
torture_close_connection(cli);
talloc_free(mem_ctx);
return ret;
}