diff options
Diffstat (limited to 'source4/torture')
-rw-r--r-- | source4/torture/smb2/config.mk | 4 | ||||
-rw-r--r-- | source4/torture/smb2/connect.c | 23 | ||||
-rw-r--r-- | source4/torture/smb2/getinfo.c | 116 | ||||
-rw-r--r-- | source4/torture/smb2/scan.c | 64 | ||||
-rw-r--r-- | source4/torture/smb2/util.c | 199 | ||||
-rw-r--r-- | source4/torture/torture.c | 1 | ||||
-rw-r--r-- | source4/torture/torture_util.c | 101 |
7 files changed, 450 insertions, 58 deletions
diff --git a/source4/torture/smb2/config.mk b/source4/torture/smb2/config.mk index 2c6dfd4fc9..7c7cdeab62 100644 --- a/source4/torture/smb2/config.mk +++ b/source4/torture/smb2/config.mk @@ -4,7 +4,9 @@ [SUBSYSTEM::TORTURE_SMB2] ADD_OBJ_FILES = \ connect.o \ - scan.o + scan.o \ + util.o \ + getinfo.o REQUIRED_SUBSYSTEMS = \ LIBCLI_SMB2 # End SUBSYSTEM TORTURE_SMB2 diff --git a/source4/torture/smb2/connect.c b/source4/torture/smb2/connect.c index 4907aadecb..077c873d08 100644 --- a/source4/torture/smb2/connect.c +++ b/source4/torture/smb2/connect.c @@ -82,12 +82,26 @@ static NTSTATUS torture_smb2_write(struct smb2_tree *tree, struct smb2_handle ha w.in.handle = handle; w.in.data = data; + memset(w.in._pad, 0xff, 16); + + status = smb2_write(tree, &w); + if (!NT_STATUS_IS_OK(status)) { + printf("write failed - %s\n", nt_errstr(status)); + return status; + } + + torture_smb2_all_info(tree, handle); + + memset(w.in._pad, 0xff, 16); + status = smb2_write(tree, &w); if (!NT_STATUS_IS_OK(status)) { printf("write failed - %s\n", nt_errstr(status)); return status; } + torture_smb2_all_info(tree, handle); + ZERO_STRUCT(r); r.in.buffer_code = 0x31; r.in.length = data.length; @@ -168,16 +182,9 @@ BOOL torture_smb2_connect(void) { TALLOC_CTX *mem_ctx = talloc_new(NULL); struct smb2_tree *tree; - const char *host = lp_parm_string(-1, "torture", "host"); - const char *share = lp_parm_string(-1, "torture", "share"); - struct cli_credentials *credentials = cmdline_credentials; struct smb2_handle h1, h2; - NTSTATUS status; - status = smb2_connect(mem_ctx, host, share, credentials, &tree, - event_context_find(mem_ctx)); - if (!NT_STATUS_IS_OK(status)) { - printf("Connection failed - %s\n", nt_errstr(status)); + if (!torture_smb2_connection(mem_ctx, &tree)) { return False; } diff --git a/source4/torture/smb2/getinfo.c b/source4/torture/smb2/getinfo.c new file mode 100644 index 0000000000..843ef5b5d0 --- /dev/null +++ b/source4/torture/smb2/getinfo.c @@ -0,0 +1,116 @@ +/* + Unix SMB/CIFS implementation. + + SMB2 getinfo test suite + + 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 "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" + +static struct { + const char *name; + uint16_t level; + NTSTATUS fstatus; + NTSTATUS dstatus; + union smb2_fileinfo finfo; + union smb2_fileinfo dinfo; +} levels[] = { +#define LEVEL(x) #x, x + { LEVEL(SMB2_GETINFO_FS_01) }, + { LEVEL(SMB2_GETINFO_FS_03) }, + { LEVEL(SMB2_GETINFO_FS_04) }, + { LEVEL(SMB2_GETINFO_FS_ATTRIB_INFO) }, + { LEVEL(SMB2_GETINFO_FS_06) }, + { LEVEL(SMB2_GETINFO_FS_07) }, + { LEVEL(SMB2_GETINFO_FS_08) }, + { LEVEL(SMB2_GETINFO_SECURITY) }, + { LEVEL(SMB2_GETINFO_FILE_BASIC_INFO) }, + { LEVEL(SMB2_GETINFO_FILE_SIZE_INFO) }, + { LEVEL(SMB2_GETINFO_FILE_ID) }, + { LEVEL(SMB2_GETINFO_FILE_EA_SIZE) }, + { LEVEL(SMB2_GETINFO_FILE_ACCESS_INFO) }, + { LEVEL(SMB2_GETINFO_FILE_0E) }, + { LEVEL(SMB2_GETINFO_FILE_ALL_EAS) }, + { LEVEL(SMB2_GETINFO_FILE_10) }, + { LEVEL(SMB2_GETINFO_FILE_11) }, + { LEVEL(SMB2_GETINFO_FILE_ALL_INFO) }, + { LEVEL(SMB2_GETINFO_FILE_SHORT_INFO) }, + { LEVEL(SMB2_GETINFO_FILE_STREAM_INFO) }, + { LEVEL(SMB2_GETINFO_FILE_EOF_INFO) }, + { LEVEL(SMB2_GETINFO_FILE_STANDARD_INFO) }, + { LEVEL(SMB2_GETINFO_FILE_ATTRIB_INFO) } +}; + +#define FNAME "testsmb2_file.dat" +#define DNAME "testsmb2_dir" + +/* basic testing of all SMB2 getinfo levels +*/ +BOOL torture_smb2_getinfo(void) +{ + TALLOC_CTX *mem_ctx = talloc_new(NULL); + struct smb2_handle hfile, hdir; + struct smb2_tree *tree; + NTSTATUS status; + int i; + + if (!torture_smb2_connection(mem_ctx, &tree)) { + goto failed; + } + + torture_setup_complex_file(FNAME); + torture_setup_complex_file(FNAME ":streamtwo"); + torture_setup_complex_dir(DNAME); + torture_setup_complex_file(DNAME ":streamtwo"); + + status = torture_smb2_testfile(tree, FNAME, &hfile); + if (!NT_STATUS_IS_OK(status)) { + printf("Unable to create test file '%s' - %s\n", FNAME, nt_errstr(status)); + goto failed; + } + + status = torture_smb2_testdir(tree, DNAME, &hdir); + if (!NT_STATUS_IS_OK(status)) { + printf("Unable to create test directory '%s' - %s\n", DNAME, nt_errstr(status)); + goto failed; + } + + torture_smb2_all_info(tree, hfile); + torture_smb2_all_info(tree, hdir); + + for (i=0;i<ARRAY_SIZE(levels);i++) { + levels[i].fstatus = smb2_getinfo_level(tree, mem_ctx, hfile, + levels[i].level, &levels[i].finfo); + if (!NT_STATUS_IS_OK(levels[i].fstatus)) { + printf("%s failed on file - %s\n", levels[i].name, nt_errstr(levels[i].fstatus)); + } + levels[i].dstatus = smb2_getinfo_level(tree, mem_ctx, hdir, + levels[i].level, &levels[i].dinfo); + if (!NT_STATUS_IS_OK(levels[i].dstatus)) { + printf("%s failed on dir - %s\n", levels[i].name, nt_errstr(levels[i].dstatus)); + } + } + + return True; + +failed: + talloc_free(mem_ctx); + return False; +} diff --git a/source4/torture/smb2/scan.c b/source4/torture/smb2/scan.c index 22d17d530c..2f2ab82d0f 100644 --- a/source4/torture/smb2/scan.c +++ b/source4/torture/smb2/scan.c @@ -28,31 +28,6 @@ #include "lib/events/events.h" -/* - create a complex file using the old SMB protocol, to make it easier to - find fields in SMB2 getinfo levels -*/ -static BOOL setup_complex_file(const char *fname) -{ - struct smbcli_state *cli; - int fnum; - - if (!torture_open_connection(&cli)) { - return False; - } - - fnum = create_complex_file(cli, cli, fname); - - if (DEBUGLVL(1)) { - torture_all_info(cli->tree, fname); - } - - talloc_free(cli); - return fnum != -1; -} - - - /* scan for valid SMB2 getinfo levels */ @@ -60,9 +35,6 @@ BOOL torture_smb2_getinfo_scan(void) { TALLOC_CTX *mem_ctx = talloc_new(NULL); struct smb2_tree *tree; - const char *host = lp_parm_string(-1, "torture", "host"); - const char *share = lp_parm_string(-1, "torture", "share"); - struct cli_credentials *credentials = cmdline_credentials; NTSTATUS status; struct smb2_getinfo io; struct smb2_create cr; @@ -70,14 +42,11 @@ BOOL torture_smb2_getinfo_scan(void) int c, i; const char *fname = "scan-getinfo.dat"; - status = smb2_connect(mem_ctx, host, share, credentials, &tree, - event_context_find(mem_ctx)); - if (!NT_STATUS_IS_OK(status)) { - printf("Connection failed - %s\n", nt_errstr(status)); + if (!torture_smb2_connection(mem_ctx, &tree)) { return False; } - if (!setup_complex_file(fname)) { + if (!torture_setup_complex_file(fname)) { printf("Failed to setup complex file '%s'\n", fname); } @@ -108,6 +77,27 @@ BOOL torture_smb2_getinfo_scan(void) io.in.max_response_size = 0xFFFF; io.in.handle = handle; + io.in.max_response_size = 128; + io.in.unknown1 = 0; + io.in.level = SMB2_GETINFO_FILE_ALL_INFO; + status = smb2_getinfo(tree, mem_ctx, &io); + + io.in.max_response_size = 128; + io.in.unknown1 = 64; + io.in.flags = 64; + io.in.unknown3 = 64; + io.in.unknown4 = 64; + io.in.level = SMB2_GETINFO_FILE_ALL_INFO; + status = smb2_getinfo(tree, mem_ctx, &io); + + if (!NT_STATUS_IS_OK(status)) { + printf("level 0x%04x is %d bytes - %s\n", + io.in.level, io.out.blob.length, nt_errstr(status)); + dump_data(1, io.out.blob.data, io.out.blob.length); + } + + return True; + for (c=0;c<5;c++) { for (i=0;i<0x100;i++) { io.in.level = (i<<8) | c; @@ -117,11 +107,9 @@ BOOL torture_smb2_getinfo_scan(void) NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { continue; } - if (NT_STATUS_IS_OK(status)) { - printf("level 0x%04x is %d bytes\n", - io.in.level, io.out.blob.length); - dump_data(1, io.out.blob.data, io.out.blob.length); - } + printf("level 0x%04x is %d bytes - %s\n", + io.in.level, io.out.blob.length, nt_errstr(status)); + dump_data(1, io.out.blob.data, io.out.blob.length); } } diff --git a/source4/torture/smb2/util.c b/source4/torture/smb2/util.c new file mode 100644 index 0000000000..7c4c99e777 --- /dev/null +++ b/source4/torture/smb2/util.c @@ -0,0 +1,199 @@ +/* + Unix SMB/CIFS implementation. + + helper functions for SMB2 test suite + + 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 "libcli/raw/libcliraw.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "lib/cmdline/popt_common.h" +#include "lib/events/events.h" + +/* + show lots of information about a file +*/ +void torture_smb2_all_info(struct smb2_tree *tree, struct smb2_handle handle) +{ + NTSTATUS status; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + union smb2_fileinfo io; + + status = smb2_getinfo_level(tree, tmp_ctx, handle, SMB2_GETINFO_FILE_ALL_INFO, &io); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("getinfo failed - %s\n", nt_errstr(status))); + talloc_free(tmp_ctx); + return; + } + + d_printf("\tcreate_time: %s\n", nt_time_string(tmp_ctx, io.all_info.create_time)); + d_printf("\taccess_time: %s\n", nt_time_string(tmp_ctx, io.all_info.access_time)); + d_printf("\twrite_time: %s\n", nt_time_string(tmp_ctx, io.all_info.write_time)); + d_printf("\tchange_time: %s\n", nt_time_string(tmp_ctx, io.all_info.change_time)); + d_printf("\tattrib: 0x%x\n", io.all_info.file_attr); + d_printf("\talloc_size: %llu\n", (uint64_t)io.all_info.alloc_size); + d_printf("\tsize: %llu\n", (uint64_t)io.all_info.size); + d_printf("\tnlink: %u\n", io.all_info.nlink); + d_printf("\tdelete_pending: %u\n", io.all_info.delete_pending); + d_printf("\tdirectory: %u\n", io.all_info.directory); + d_printf("\tfile_id: %llu\n", io.all_info.file_id); + d_printf("\tea_size: %u\n", io.all_info.ea_size); + d_printf("\taccess_mask: 0x%08x\n", io.all_info.access_mask); + d_printf("\tunknown5: 0x%llx\n", io.all_info.unknown5); + d_printf("\tunknown6: 0x%llx\n", io.all_info.unknown6); + d_printf("\tfname: '%s'\n", io.all_info.fname); + + talloc_free(tmp_ctx); +} + + +/* + open a smb2 connection +*/ +BOOL torture_smb2_connection(TALLOC_CTX *mem_ctx, struct smb2_tree **tree) +{ + NTSTATUS status; + const char *host = lp_parm_string(-1, "torture", "host"); + const char *share = lp_parm_string(-1, "torture", "share"); + struct cli_credentials *credentials = cmdline_credentials; + + status = smb2_connect(mem_ctx, host, share, credentials, tree, + event_context_find(mem_ctx)); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to connect to SMB2 share \\\\%s\\%s - %s\n", + host, share, nt_errstr(status)); + return False; + } + return True; +} + + +/* + create and return a handle to a test file +*/ +NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname, + struct smb2_handle *handle) +{ + struct smb2_create io; + struct smb2_read r; + NTSTATUS status; + + ZERO_STRUCT(io); + io.in.buffer_code = 0x39; + io.in.oplock_flags = 0; + io.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE; + io.in.fname = fname; + + status = smb2_create(tree, &io); + NT_STATUS_NOT_OK_RETURN(status); + + *handle = io.out.handle; + + ZERO_STRUCT(r); + r.in.buffer_code = 0x31; + r.in.length = 5; + r.in.offset = 0; + r.in.handle = *handle; + + smb2_read(tree, tree, &r); + + return NT_STATUS_OK; +} + +/* + create and return a handle to a test directory +*/ +NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname, + struct smb2_handle *handle) +{ + struct smb2_create io; + NTSTATUS status; + + ZERO_STRUCT(io); + io.in.buffer_code = 0x39; + io.in.oplock_flags = 0; + io.in.access_mask = SEC_RIGHTS_DIR_ALL; + io.in.file_attr = FILE_ATTRIBUTE_DIRECTORY; + io.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE; + io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.in.fname = fname; + + status = smb2_create(tree, &io); + NT_STATUS_NOT_OK_RETURN(status); + + *handle = io.out.handle; + + return NT_STATUS_OK; +} + + +/* + create a complex file using the old SMB protocol, to make it easier to + find fields in SMB2 getinfo levels +*/ +BOOL torture_setup_complex_file(const char *fname) +{ + struct smbcli_state *cli; + int fnum; + + if (!torture_open_connection(&cli)) { + return False; + } + + fnum = create_complex_file(cli, cli, fname); + + if (DEBUGLVL(1)) { + torture_all_info(cli->tree, fname); + } + + talloc_free(cli); + return fnum != -1; +} + +/* + create a complex directory using the old SMB protocol, to make it easier to + find fields in SMB2 getinfo levels +*/ +BOOL torture_setup_complex_dir(const char *dname) +{ + struct smbcli_state *cli; + int fnum; + + if (!torture_open_connection(&cli)) { + return False; + } + + fnum = create_complex_dir(cli, cli, dname); + + if (DEBUGLVL(1)) { + torture_all_info(cli->tree, dname); + } + + talloc_free(cli); + return fnum != -1; +} diff --git a/source4/torture/torture.c b/source4/torture/torture.c index ff9584ed5c..3c4c916b0f 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -2255,6 +2255,7 @@ static struct { {"SMB2-CONNECT", torture_smb2_connect, 0}, {"SMB2-SCAN", torture_smb2_scan, 0}, {"SMB2-SCANGETINFO", torture_smb2_getinfo_scan, 0}, + {"SMB2-GETINFO", torture_smb2_getinfo, 0}, /* protocol scanners */ {"SCAN-TRANS2", torture_trans2_scan, 0}, diff --git a/source4/torture/torture_util.c b/source4/torture/torture_util.c index 59eef81569..4606ec6840 100644 --- a/source4/torture/torture_util.c +++ b/source4/torture/torture_util.c @@ -100,20 +100,99 @@ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const cha smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf)); - /* setup some EAs */ - setfile.generic.level = RAW_SFILEINFO_EA_SET; + if (strchr(fname, ':') == NULL) { + /* setup some EAs */ + setfile.generic.level = RAW_SFILEINFO_EA_SET; + setfile.generic.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_talloc(mem_ctx, "VALUE1", 6); + 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_talloc(mem_ctx, "ValueTwo", 8); + status = smb_raw_setfileinfo(cli->tree, &setfile); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to setup EAs\n"); + } + } + + /* make sure all the timestamps aren't the same, and are also + in different DST zones*/ + setfile.generic.level = RAW_SFILEINFO_SETATTRE; setfile.generic.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_talloc(mem_ctx, "VALUE1", 6); - 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_talloc(mem_ctx, "ValueTwo", 8); + + setfile.setattre.in.create_time = t + 9*30*24*60*60; + setfile.setattre.in.access_time = t + 6*30*24*60*60; + setfile.setattre.in.write_time = t + 3*30*24*60*60; + status = smb_raw_setfileinfo(cli->tree, &setfile); if (!NT_STATUS_IS_OK(status)) { - printf("Failed to setup EAs\n"); + printf("Failed to setup file times - %s\n", nt_errstr(status)); + } + + /* make sure all the timestamps aren't the same */ + fileinfo.generic.level = RAW_FILEINFO_GETATTRE; + fileinfo.generic.in.fnum = fnum; + + status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to query file times - %s\n", nt_errstr(status)); + } + + if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) { + printf("create_time not setup correctly\n"); + } + if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) { + printf("access_time not setup correctly\n"); + } + if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) { + printf("write_time not setup correctly\n"); + } + + return fnum; +} + + +/* + sometimes we need a fairly complex directory to work with, so we can test + all possible attributes. +*/ +int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname) +{ + int fnum; + union smb_setfileinfo setfile; + union smb_fileinfo fileinfo; + time_t t = (time(NULL) & ~1); + NTSTATUS status; + + smbcli_deltree(cli->tree, dname); + fnum = smbcli_nt_create_full(cli->tree, dname, 0, + SEC_RIGHTS_DIR_ALL, + FILE_ATTRIBUTE_DIRECTORY, + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE, + NTCREATEX_DISP_OPEN_IF, + NTCREATEX_OPTIONS_DIRECTORY, 0); + if (fnum == -1) return -1; + + if (strchr(dname, ':') == NULL) { + /* setup some EAs */ + setfile.generic.level = RAW_SFILEINFO_EA_SET; + setfile.generic.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_talloc(mem_ctx, "VALUE1", 6); + 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_talloc(mem_ctx, "ValueTwo", 8); + status = smb_raw_setfileinfo(cli->tree, &setfile); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to setup EAs\n"); + } } /* make sure all the timestamps aren't the same, and are also |