summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libcli/raw/rawfileinfo.c74
-rw-r--r--source4/libcli/smb2/getinfo.c142
-rw-r--r--source4/libcli/smb2/smb2_calls.h30
-rw-r--r--source4/torture/smb2/config.mk4
-rw-r--r--source4/torture/smb2/connect.c23
-rw-r--r--source4/torture/smb2/getinfo.c116
-rw-r--r--source4/torture/smb2/scan.c64
-rw-r--r--source4/torture/smb2/util.c199
-rw-r--r--source4/torture/torture.c1
-rw-r--r--source4/torture/torture_util.c101
10 files changed, 626 insertions, 128 deletions
diff --git a/source4/libcli/raw/rawfileinfo.c b/source4/libcli/raw/rawfileinfo.c
index ede4391824..f631522182 100644
--- a/source4/libcli/raw/rawfileinfo.c
+++ b/source4/libcli/raw/rawfileinfo.c
@@ -34,6 +34,51 @@
return NT_STATUS_INFO_LENGTH_MISMATCH; \
}
+/*
+ parse a stream information structure
+*/
+NTSTATUS smbcli_parse_stream_info(DATA_BLOB blob, TALLOC_CTX *mem_ctx,
+ struct stream_information *io)
+{
+ uint32_t ofs = 0;
+ io->num_streams = 0;
+ io->streams = NULL;
+
+ while (blob.length - ofs >= 24) {
+ uint_t n = io->num_streams;
+ uint32_t nlen, len;
+ ssize_t size;
+ void *vstr;
+ io->streams =
+ talloc_realloc(mem_ctx, io->streams, struct stream_struct, n+1);
+ if (!io->streams) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ nlen = IVAL(blob.data, ofs + 0x04);
+ io->streams[n].size = BVAL(blob.data, ofs + 0x08);
+ io->streams[n].alloc_size = BVAL(blob.data, ofs + 0x10);
+ if (nlen > blob.length - (ofs + 24)) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+ size = convert_string_talloc(io->streams, CH_UTF16, CH_UNIX,
+ blob.data+ofs+24, nlen, &vstr);
+ if (size == -1) {
+ return NT_STATUS_ILLEGAL_CHARACTER;
+ }
+ io->streams[n].stream_name.s = vstr;
+ io->streams[n].stream_name.private_length = nlen;
+ io->num_streams++;
+ len = IVAL(blob.data, ofs);
+ if (len > blob.length - ofs) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+ if (len == 0) break;
+ ofs += len;
+ }
+
+ return NT_STATUS_OK;
+}
+
/****************************************************************************
Handle qfileinfo/qpathinfo trans2 backend.
****************************************************************************/
@@ -42,8 +87,6 @@ static NTSTATUS smb_raw_info_backend(struct smbcli_session *session,
union smb_fileinfo *parms,
DATA_BLOB *blob)
{
- uint_t len, ofs;
-
switch (parms->generic.level) {
case RAW_FILEINFO_GENERIC:
case RAW_FILEINFO_GETATTR:
@@ -175,32 +218,7 @@ static NTSTATUS smb_raw_info_backend(struct smbcli_session *session,
case RAW_FILEINFO_STREAM_INFO:
case RAW_FILEINFO_STREAM_INFORMATION:
- ofs = 0;
- parms->stream_info.out.num_streams = 0;
- parms->stream_info.out.streams = NULL;
-
- while (blob->length - ofs >= 24) {
- uint_t n = parms->stream_info.out.num_streams;
- parms->stream_info.out.streams =
- talloc_realloc(mem_ctx,
- parms->stream_info.out.streams,
- struct stream_struct,
- n+1);
- if (!parms->stream_info.out.streams) {
- return NT_STATUS_NO_MEMORY;
- }
- parms->stream_info.out.streams[n].size = BVAL(blob->data, ofs + 8);
- parms->stream_info.out.streams[n].alloc_size = BVAL(blob->data, ofs + 16);
- smbcli_blob_pull_string(session, mem_ctx, blob,
- &parms->stream_info.out.streams[n].stream_name,
- ofs+4, ofs+24, STR_UNICODE);
- parms->stream_info.out.num_streams++;
- len = IVAL(blob->data, ofs);
- if (len > blob->length - ofs) return NT_STATUS_INFO_LENGTH_MISMATCH;
- if (len == 0) break;
- ofs += len;
- }
- return NT_STATUS_OK;
+ return smbcli_parse_stream_info(*blob, mem_ctx, &parms->stream_info.out);
case RAW_FILEINFO_INTERNAL_INFORMATION:
FINFO_CHECK_SIZE(8);
diff --git a/source4/libcli/smb2/getinfo.c b/source4/libcli/smb2/getinfo.c
index 9ad2b77310..7a362b24d9 100644
--- a/source4/libcli/smb2/getinfo.c
+++ b/source4/libcli/smb2/getinfo.c
@@ -113,18 +113,18 @@ NTSTATUS smb2_getinfo_parse(TALLOC_CTX *mem_ctx,
if (blob.length != 0x18) {
return NT_STATUS_INFO_LENGTH_MISMATCH;
}
- io->size_info.alloc_size = BVAL(blob.data, 0x00);
- io->size_info.size = BVAL(blob.data, 0x08);
- io->size_info.nlink = IVAL(blob.data, 0x10);
- io->size_info.unknown = IVAL(blob.data, 0x14);
+ io->size_info.alloc_size = BVAL(blob.data, 0x00);
+ io->size_info.size = BVAL(blob.data, 0x08);
+ io->size_info.nlink = IVAL(blob.data, 0x10);
+ io->size_info.delete_pending = CVAL(blob.data, 0x14);
+ io->size_info.directory = CVAL(blob.data, 0x15);
break;
- case SMB2_GETINFO_FILE_06:
+ case SMB2_GETINFO_FILE_ID:
if (blob.length != 0x8) {
return NT_STATUS_INFO_LENGTH_MISMATCH;
}
- io->unknown06.unknown1 = IVAL(blob.data, 0x00);
- io->unknown06.unknown2 = IVAL(blob.data, 0x04);
+ io->file_id.file_id = BVAL(blob.data, 0x00);
break;
case SMB2_GETINFO_FILE_EA_SIZE:
@@ -172,37 +172,105 @@ NTSTATUS smb2_getinfo_parse(TALLOC_CTX *mem_ctx,
uint32_t nlen;
ssize_t size;
void *vstr;
- if (blob.length != 0x60) {
+ if (blob.length < 0x64) {
return NT_STATUS_INFO_LENGTH_MISMATCH;
}
- io->all_info.create_time = smbcli_pull_nttime(blob.data, 0x00);
- io->all_info.access_time = smbcli_pull_nttime(blob.data, 0x08);
- io->all_info.write_time = smbcli_pull_nttime(blob.data, 0x10);
- io->all_info.change_time = smbcli_pull_nttime(blob.data, 0x18);
- io->all_info.file_attr = IVAL(blob.data, 0x20);
- io->all_info.unknown1 = IVAL(blob.data, 0x24);
- io->all_info.alloc_size = BVAL(blob.data, 0x28);
- io->all_info.size = BVAL(blob.data, 0x30);
- io->all_info.nlink = IVAL(blob.data, 0x38);
- io->all_info.unknown2 = IVAL(blob.data, 0x3C);
- io->all_info.unknown3 = IVAL(blob.data, 0x40);
- io->all_info.unknown4 = IVAL(blob.data, 0x44);
- io->all_info.ea_size = IVAL(blob.data, 0x48);
- io->all_info.access_mask = IVAL(blob.data, 0x4C);
- io->all_info.unknown5 = BVAL(blob.data, 0x50);
- io->all_info.unknown6 = BVAL(blob.data, 0x58);
- nlen = IVAL(blob.data, 0x5C);
- if (nlen > blob.length - 0x60) {
+ io->all_info.create_time = smbcli_pull_nttime(blob.data, 0x00);
+ io->all_info.access_time = smbcli_pull_nttime(blob.data, 0x08);
+ io->all_info.write_time = smbcli_pull_nttime(blob.data, 0x10);
+ io->all_info.change_time = smbcli_pull_nttime(blob.data, 0x18);
+ io->all_info.file_attr = IVAL(blob.data, 0x20);
+ io->all_info.alloc_size = BVAL(blob.data, 0x28);
+ io->all_info.size = BVAL(blob.data, 0x30);
+ io->all_info.nlink = IVAL(blob.data, 0x38);
+ io->all_info.delete_pending = CVAL(blob.data, 0x3C);
+ io->all_info.directory = CVAL(blob.data, 0x3D);
+ io->all_info.file_id = BVAL(blob.data, 0x40);
+ io->all_info.ea_size = IVAL(blob.data, 0x48);
+ io->all_info.access_mask = IVAL(blob.data, 0x4C);
+ io->all_info.unknown5 = BVAL(blob.data, 0x50);
+ io->all_info.unknown6 = BVAL(blob.data, 0x58);
+ nlen = IVAL(blob.data, 0x60);
+ if (nlen > blob.length - 0x64) {
return NT_STATUS_INFO_LENGTH_MISMATCH;
}
size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
- blob.data+0x60, nlen, &vstr);
+ blob.data+0x64, nlen, &vstr);
if (size == -1) {
return NT_STATUS_ILLEGAL_CHARACTER;
}
io->all_info.fname = vstr;
break;
}
+
+ case SMB2_GETINFO_FILE_SHORT_INFO: {
+ uint32_t nlen;
+ ssize_t size;
+ void *vstr;
+ if (blob.length < 0x04) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+ nlen = IVAL(blob.data, 0x00);
+ if (nlen > blob.length - 0x04) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+ size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
+ blob.data+0x04, nlen, &vstr);
+ if (size == -1) {
+ return NT_STATUS_ILLEGAL_CHARACTER;
+ }
+ io->short_info.short_name = vstr;
+ break;
+ }
+
+ case SMB2_GETINFO_FILE_STREAM_INFO:
+ return smbcli_parse_stream_info(blob, mem_ctx, &io->stream_info);
+
+ case SMB2_GETINFO_FILE_EOF_INFO:
+ if (blob.length != 0x10) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+ io->eof_info.size = BVAL(blob.data, 0x00);
+ io->eof_info.unknown = BVAL(blob.data, 0x08);
+ break;
+
+ case SMB2_GETINFO_FILE_STANDARD_INFO:
+ if (blob.length != 0x38) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+ io->standard_info.create_time = smbcli_pull_nttime(blob.data, 0x00);
+ io->standard_info.access_time = smbcli_pull_nttime(blob.data, 0x08);
+ io->standard_info.write_time = smbcli_pull_nttime(blob.data, 0x10);
+ io->standard_info.change_time = smbcli_pull_nttime(blob.data, 0x18);
+ io->standard_info.alloc_size = BVAL(blob.data, 0x20);
+ io->standard_info.size = BVAL(blob.data, 0x28);
+ io->standard_info.file_attr = IVAL(blob.data, 0x30);
+ io->standard_info.unknown = IVAL(blob.data, 0x34);
+ break;
+
+ case SMB2_GETINFO_FILE_ATTRIB_INFO:
+ if (blob.length != 0x08) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+ io->standard_info.file_attr = IVAL(blob.data, 0x00);
+ io->standard_info.unknown = IVAL(blob.data, 0x04);
+ break;
+
+ case SMB2_GETINFO_SECURITY: {
+ struct ndr_pull *ndr;
+ NTSTATUS status;
+ ndr = ndr_pull_init_blob(&blob, mem_ctx);
+ if (!ndr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ io->security.sd = talloc(mem_ctx, struct security_descriptor);
+ if (io->security.sd == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = ndr_pull_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, io->security.sd);
+ talloc_free(ndr);
+ return status;
+ }
default:
return NT_STATUS_INVALID_INFO_CLASS;
@@ -230,3 +298,23 @@ NTSTATUS smb2_getinfo_level_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
return status;
}
+/*
+ level specific getinfo call
+*/
+NTSTATUS smb2_getinfo_level(struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ struct smb2_handle handle,
+ uint16_t level, union smb2_fileinfo *io)
+{
+ struct smb2_getinfo b;
+ struct smb2_request *req;
+
+ ZERO_STRUCT(b);
+ b.in.buffer_code = 0x29;
+ b.in.max_response_size = 0x10000;
+ b.in.handle = handle;
+ b.in.level = level;
+
+ req = smb2_getinfo_send(tree, &b);
+
+ return smb2_getinfo_level_recv(req, mem_ctx, level, io);
+}
diff --git a/source4/libcli/smb2/smb2_calls.h b/source4/libcli/smb2/smb2_calls.h
index aa2fb717b2..127a9d229c 100644
--- a/source4/libcli/smb2/smb2_calls.h
+++ b/source4/libcli/smb2/smb2_calls.h
@@ -170,7 +170,7 @@ struct smb2_close {
/* file information levels */
#define SMB2_GETINFO_FILE_BASIC_INFO 0x0401
#define SMB2_GETINFO_FILE_SIZE_INFO 0x0501
-#define SMB2_GETINFO_FILE_06 0x0601
+#define SMB2_GETINFO_FILE_ID 0x0601
#define SMB2_GETINFO_FILE_EA_SIZE 0x0701
#define SMB2_GETINFO_FILE_ACCESS_INFO 0x0801
#define SMB2_GETINFO_FILE_0E 0x0e01
@@ -217,13 +217,13 @@ union smb2_fileinfo {
uint64_t alloc_size;
uint64_t size;
uint32_t nlink;
- uint32_t unknown;
+ uint8_t delete_pending;
+ uint8_t directory;
} size_info;
struct {
- uint32_t unknown1;
- uint32_t unknown2;
- } unknown06;
+ uint64_t file_id;
+ } file_id;
struct {
uint32_t ea_size;
@@ -256,13 +256,14 @@ union smb2_fileinfo {
NTTIME write_time;
NTTIME change_time;
uint32_t file_attr;
- uint32_t unknown1;
+ /* uint32_t _pad; */
uint64_t alloc_size;
uint64_t size;
uint32_t nlink;
- uint32_t unknown2;
- uint32_t unknown3;
- uint32_t unknown4;
+ uint8_t delete_pending;
+ uint8_t directory;
+ /* uint16_t _pad; */
+ uint64_t file_id;
uint32_t ea_size;
uint32_t access_mask;
uint64_t unknown5;
@@ -274,12 +275,7 @@ union smb2_fileinfo {
const char *short_name;
} short_info;
- struct {
- uint32_t unknown;
- uint64_t size;
- uint64_t alloc_size;
- const char *stream_name;
- } stream_info;
+ struct stream_information stream_info;
struct {
uint64_t size;
@@ -301,6 +297,10 @@ union smb2_fileinfo {
uint32_t file_attr;
uint32_t unknown;
} attrib_info;
+
+ struct {
+ struct security_descriptor *sd;
+ } security;
};
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