r11730: added parsing and tests for a bunch more SMB2 getinfo levels
authorAndrew Tridgell <tridge@samba.org>
Tue, 15 Nov 2005 04:38:59 +0000 (04:38 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:46:18 +0000 (13:46 -0500)
source/libcli/raw/rawfileinfo.c
source/libcli/smb2/getinfo.c
source/libcli/smb2/smb2_calls.h
source/torture/smb2/config.mk
source/torture/smb2/connect.c
source/torture/smb2/getinfo.c [new file with mode: 0644]
source/torture/smb2/scan.c
source/torture/smb2/util.c [new file with mode: 0644]
source/torture/torture.c
source/torture/torture_util.c

index ede4391824d95417b7c8f1cdb5e5c2c1f326e3a6..f6315221820ac5a4dafe70b82304f37a316c5b82 100644 (file)
       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);
index 9ad2b7731000093724018ba7f2fafd4c46277099..7a362b24d987150ccc4beee59f88f98ea549b820 100644 (file)
@@ -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);
+}
index aa2fb717b2f87b0e57f762cbb1f22a00e7a0e7c2..127a9d229c81b0454328ddf576bd35ada53608c7 100644 (file)
@@ -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;
 };
 
 
index 2c6dfd4fc9be7072fea63d1636e3ed4b7daf0db2..7c7cdeab62dc7888a5ff72b72a0d991a70aab1c9 100644 (file)
@@ -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
index 4907aadecb4c922c9cb18a2567b0089f64ae81c3..077c873d08279038cf4f864389fa4d1a2c9eac86 100644 (file)
@@ -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/source/torture/smb2/getinfo.c b/source/torture/smb2/getinfo.c
new file mode 100644 (file)
index 0000000..843ef5b
--- /dev/null
@@ -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;
+}
index 22d17d530cd4bc424bab9352e22a79edd44f7ee3..2f2ab82d0f70d4c7de21b7f7314fcd763a5abbcf 100644 (file)
 #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/source/torture/smb2/util.c b/source/torture/smb2/util.c
new file mode 100644 (file)
index 0000000..7c4c99e
--- /dev/null
@@ -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;
+}
index ff9584ed5cfdcb196f7e1f082c50046085213dd1..3c4c916b0fce9791cbd51c72c055140a4bddde20 100644 (file)
@@ -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},
index 59eef815694cabf71ad761a646005cab7351f136..4606ec68407fba2022b95c9d42ebcf72473016e3 100644 (file)
@@ -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