r11715: added SMB2 read and write requests
authorAndrew Tridgell <tridge@samba.org>
Mon, 14 Nov 2005 05:09:26 +0000 (05:09 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:46:17 +0000 (13:46 -0500)
(This used to be commit d3556cbfa38447d2d385b697c1855b3c13d42744)

source4/libcli/smb2/close.c
source4/libcli/smb2/config.mk
source4/libcli/smb2/getinfo.c
source4/libcli/smb2/read.c [new file with mode: 0644]
source4/libcli/smb2/request.c
source4/libcli/smb2/smb2_calls.h
source4/libcli/smb2/write.c [new file with mode: 0644]

index 2802e2f27e181f7943508dd360622a562c0b234d..d5a2c4d422fe57bb19b697da5a98644159077914 100644 (file)
@@ -38,8 +38,7 @@ struct smb2_request *smb2_close_send(struct smb2_tree *tree, struct smb2_close *
        SSVAL(req->out.body, 0x00, io->in.buffer_code);
        SSVAL(req->out.body, 0x02, io->in.flags);
        SIVAL(req->out.body, 0x04, io->in._pad);
-       SBVAL(req->out.body, 0x08, io->in.handle.data[0]);
-       SBVAL(req->out.body, 0x10, io->in.handle.data[1]);
+       smb2_put_handle(req->out.body+0x08, io->in.handle);
 
        smb2_transport_send(req);
 
index b7ecdcb98db657b53c6582a05e12de54ecd28fc8..15f49ba88ecf5cbe1de2457838aecd47b0300785 100644 (file)
@@ -8,5 +8,7 @@ OBJ_FILES = \
        create.o \
        close.o \
        connect.o \
-       getinfo.o
+       getinfo.o \
+       write.o \
+       read.o
 REQUIRED_SUBSYSTEMS = LIBCLI_RAW LIBPACKET
index c8976e423076b411e77ec86d158338a1ef755d72..a7935526e5d82f44186979424f85f1066d3ab070 100644 (file)
@@ -39,11 +39,10 @@ struct smb2_request *smb2_getinfo_send(struct smb2_tree *tree, struct smb2_getin
        SSVAL(req->out.body, 0x02, io->in.level);
        SIVAL(req->out.body, 0x04, io->in.max_response_size);
        SIVAL(req->out.body, 0x08, io->in.unknown1);
-       SIVAL(req->out.body, 0x0C, io->in.unknown2);
+       SIVAL(req->out.body, 0x0C, io->in.flags);
        SIVAL(req->out.body, 0x10, io->in.unknown3);
        SIVAL(req->out.body, 0x14, io->in.unknown4);
-       SBVAL(req->out.body, 0x18, io->in.handle.data[0]);
-       SBVAL(req->out.body, 0x20, io->in.handle.data[1]);
+       smb2_put_handle(req->out.body+0x18, io->in.handle);
 
        smb2_transport_send(req);
 
@@ -88,3 +87,147 @@ NTSTATUS smb2_getinfo(struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
        struct smb2_request *req = smb2_getinfo_send(tree, io);
        return smb2_getinfo_recv(req, mem_ctx, io);
 }
+
+
+/*
+  parse a returned getinfo data blob
+*/
+NTSTATUS smb2_getinfo_parse(TALLOC_CTX *mem_ctx, 
+                           uint16_t level,
+                           DATA_BLOB blob,
+                           union smb2_fileinfo *io)
+{
+       switch (level) {
+       case SMB2_GETINFO_FILE_BASIC_INFO:
+               if (blob.length != 0x28) {
+                       return NT_STATUS_INFO_LENGTH_MISMATCH;
+               }
+               io->basic_info.create_time = smbcli_pull_nttime(blob.data, 0x00);
+               io->basic_info.access_time = smbcli_pull_nttime(blob.data, 0x08);
+               io->basic_info.write_time  = smbcli_pull_nttime(blob.data, 0x10);
+               io->basic_info.change_time = smbcli_pull_nttime(blob.data, 0x18);
+               io->basic_info.file_attr   = IVAL(blob.data, 0x20);
+               io->basic_info.unknown     = IVAL(blob.data, 0x24);
+               break;
+
+       case SMB2_GETINFO_FILE_SIZE_INFO:
+               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);
+               break;
+
+       case SMB2_GETINFO_FILE_06:
+               if (blob.length != 0x8) {
+                       return NT_STATUS_INFO_LENGTH_MISMATCH;
+               }
+               io->unknown06.unknown1     = IVAL(blob.data, 0x00);
+               io->unknown06.unknown2     = IVAL(blob.data, 0x04);
+               break;
+
+       case SMB2_GETINFO_FILE_EA_SIZE:
+               if (blob.length != 0x4) {
+                       return NT_STATUS_INFO_LENGTH_MISMATCH;
+               }
+               io->ea_size.ea_size = IVAL(blob.data, 0x00);
+               break;
+
+       case SMB2_GETINFO_FILE_ACCESS_INFO:
+               if (blob.length != 0x4) {
+                       return NT_STATUS_INFO_LENGTH_MISMATCH;
+               }
+               io->access_info.access_mask = IVAL(blob.data, 0x00);
+               break;
+
+       case SMB2_GETINFO_FILE_0E:
+               if (blob.length != 0x8) {
+                       return NT_STATUS_INFO_LENGTH_MISMATCH;
+               }
+               io->unknown0e.unknown1     = IVAL(blob.data, 0x00);
+               io->unknown0e.unknown2     = IVAL(blob.data, 0x04);
+               break;
+
+       case SMB2_GETINFO_FILE_ALL_EAS:
+               return ea_pull_list(&blob, mem_ctx, 
+                                   &io->all_eas.eas.num_eas,
+                                   &io->all_eas.eas.eas);
+
+       case SMB2_GETINFO_FILE_10:
+               if (blob.length != 0x4) {
+                       return NT_STATUS_INFO_LENGTH_MISMATCH;
+               }
+               io->unknown10.unknown     = IVAL(blob.data, 0x00);
+               break;
+
+       case SMB2_GETINFO_FILE_11:
+               if (blob.length != 0x4) {
+                       return NT_STATUS_INFO_LENGTH_MISMATCH;
+               }
+               io->unknown11.unknown     = IVAL(blob.data, 0x00);
+               break;
+
+       case SMB2_GETINFO_FILE_ALL_INFO: {
+               uint32_t nlen;
+               ssize_t size;
+               void *vstr;
+               if (blob.length != 0x60) {
+                       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) {
+                       return NT_STATUS_INFO_LENGTH_MISMATCH;
+               }
+               size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, 
+                                            blob.data+0x60, nlen, &vstr);
+               if (size == -1) {
+                       return NT_STATUS_ILLEGAL_CHARACTER;
+               }
+               io->all_info.fname = vstr;
+               break;
+       }
+               
+       default:
+               return NT_STATUS_INVALID_INFO_CLASS;
+       }
+
+       return NT_STATUS_OK;
+}
+
+
+/*
+  recv a getinfo reply and parse the level info
+*/
+NTSTATUS smb2_getinfo_level_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
+                                uint16_t level, union smb2_fileinfo *io)
+{
+       struct smb2_getinfo b;
+       NTSTATUS status;
+
+       status = smb2_getinfo_recv(req, mem_ctx, &b);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       status = smb2_getinfo_parse(mem_ctx, level, b.out.blob, io);
+       data_blob_free(&b.out.blob);
+
+       return status;
+}
+
diff --git a/source4/libcli/smb2/read.c b/source4/libcli/smb2/read.c
new file mode 100644 (file)
index 0000000..cbb3f74
--- /dev/null
@@ -0,0 +1,95 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   SMB2 client read call
+
+   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"
+
+/*
+  send a read request
+*/
+struct smb2_request *smb2_read_send(struct smb2_tree *tree, struct smb2_read *io)
+{
+       struct smb2_request *req;
+
+       req = smb2_request_init_tree(tree, SMB2_OP_READ, 0x31);
+       if (req == NULL) return NULL;
+
+       SSVAL(req->out.body, 0x00, io->in.buffer_code);
+       SSVAL(req->out.body, 0x02, 0);
+       SIVAL(req->out.body, 0x04, io->in.length);
+       SBVAL(req->out.body, 0x08, io->in.offset);
+       smb2_put_handle(req->out.body+0x10, io->in.handle);
+       memcpy(req->out.body+0x20, io->in._pad, 17);
+
+       smb2_transport_send(req);
+
+       return req;
+}
+
+
+/*
+  recv a read reply
+*/
+NTSTATUS smb2_read_recv(struct smb2_request *req, 
+                       TALLOC_CTX *mem_ctx, struct smb2_read *io)
+{
+       uint16_t ofs;
+       uint32_t nread;
+
+       if (!smb2_request_receive(req) || 
+           smb2_request_is_error(req)) {
+               return smb2_request_destroy(req);
+       }
+
+       if (req->in.body_size < 16) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+       SMB2_CHECK_BUFFER_CODE(req, 0x11);
+
+       ofs = SVAL(req->in.body, 0x02);
+
+       nread = IVAL(req->in.body, 0x04);
+       memcpy(io->out.unknown, req->in.body+0x08, 8);
+
+       if (smb2_oob_in(req, req->in.hdr+ofs, nread)) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+       io->out.data = data_blob_talloc(mem_ctx, req->in.hdr+ofs, nread);
+       if (io->out.data.data == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       return smb2_request_destroy(req);
+}
+
+/*
+  sync read request
+*/
+NTSTATUS smb2_read(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, struct smb2_read *io)
+{
+       struct smb2_request *req = smb2_read_send(tree, io);
+       return smb2_read_recv(req, mem_ctx, io);
+}
index 4b95d141a388ad88ac7e872dfca147131b69b6f0..a06121df051eaf91082ec318f32585649fef1ac0 100644 (file)
@@ -23,6 +23,7 @@
 #include "includes.h"
 #include "libcli/raw/libcliraw.h"
 #include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
 #include "include/dlinklist.h"
 #include "lib/events/events.h"
 
@@ -261,3 +262,14 @@ NTSTATUS smb2_string_blob(TALLOC_CTX *mem_ctx, const char *str, DATA_BLOB *blob)
        blob->length = size;
        return NT_STATUS_OK;    
 }
+
+
+/*
+  put a file handle into a buffer
+*/
+void smb2_put_handle(uint8_t *data, struct smb2_handle h)
+{
+       SBVAL(data, 0, h.data[0]);
+       SBVAL(data, 8, h.data[1]);
+}
+
index 22cdcef14f0c454509c3b8f7c63427797b7ac616..aa2fb717b2f87b0e57f762cbb1f22a00e7a0e7c2 100644 (file)
@@ -156,16 +156,16 @@ struct smb2_close {
 };
 
 /* fs information levels */
-#define SMB2_GETINFO_FS_01            0x0102
-#define SMB2_GETINFO_FS_03            0x0302
-#define SMB2_GETINFO_FS_04            0x0402
-#define SMB2_GETINFO_FS_ATTRIB_INFO   0x0502
-#define SMB2_GETINFO_FS_06            0x0602
-#define SMB2_GETINFO_FS_07            0x0702
-#define SMB2_GETINFO_FS_08            0x0802
+#define SMB2_GETINFO_FS_01              0x0102
+#define SMB2_GETINFO_FS_03              0x0302
+#define SMB2_GETINFO_FS_04              0x0402
+#define SMB2_GETINFO_FS_ATTRIB_INFO     0x0502
+#define SMB2_GETINFO_FS_06              0x0602
+#define SMB2_GETINFO_FS_07              0x0702
+#define SMB2_GETINFO_FS_08              0x0802
 
 /* class 3 levels */
-#define SMB2_GETINFO_3_00            0x0003
+#define SMB2_GETINFO_SECURITY           0x0003
 
 /* file information levels */
 #define SMB2_GETINFO_FILE_BASIC_INFO    0x0401
@@ -174,7 +174,7 @@ struct smb2_close {
 #define SMB2_GETINFO_FILE_EA_SIZE       0x0701
 #define SMB2_GETINFO_FILE_ACCESS_INFO   0x0801
 #define SMB2_GETINFO_FILE_0E            0x0e01
-#define SMB2_GETINFO_FILE_EA_INFO       0x0f01
+#define SMB2_GETINFO_FILE_ALL_EAS       0x0f01
 #define SMB2_GETINFO_FILE_10            0x1001
 #define SMB2_GETINFO_FILE_11            0x1101
 #define SMB2_GETINFO_FILE_ALL_INFO      0x1201
@@ -191,7 +191,7 @@ struct smb2_getinfo {
                uint16_t level;
                uint32_t max_response_size;
                uint32_t unknown1;
-               uint32_t unknown2;
+               uint32_t flags; /* level specific */
                uint32_t unknown3;
                uint32_t unknown4;
                struct smb2_handle handle;
@@ -227,7 +227,7 @@ union smb2_fileinfo {
 
        struct {
                uint32_t ea_size;
-       } ea_info;
+       } ea_size;
 
        struct {
                uint32_t access_mask;
@@ -239,8 +239,8 @@ union smb2_fileinfo {
        } unknown0e;
 
        struct {
-               struct smb_ea_list all_eas;
-       } all_ea_info;
+               struct smb_ea_list eas;
+       } all_eas;
 
        struct {
                uint32_t unknown; /* 2 */
@@ -302,3 +302,37 @@ union smb2_fileinfo {
                uint32_t unknown;
        } attrib_info;
 };
+
+
+struct smb2_write {
+       struct {
+               uint16_t buffer_code;
+               uint64_t offset;
+               struct smb2_handle handle;
+               uint8_t _pad[16];
+               DATA_BLOB data;
+       } in;
+
+       struct {
+               uint16_t buffer_code;
+               uint16_t _pad;
+               uint32_t nwritten;
+               uint8_t unknown[9];
+       } out;
+};
+
+struct smb2_read {
+       struct {
+               uint16_t buffer_code;
+               uint32_t length;
+               uint64_t offset;
+               struct smb2_handle handle;
+               uint8_t _pad[17];
+       } in;
+
+       struct {
+               uint16_t buffer_code;
+               uint8_t unknown[8];
+               DATA_BLOB data;
+       } out;
+};
diff --git a/source4/libcli/smb2/write.c b/source4/libcli/smb2/write.c
new file mode 100644 (file)
index 0000000..f842969
--- /dev/null
@@ -0,0 +1,82 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   SMB2 client write call
+
+   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"
+
+/*
+  send a write request
+*/
+struct smb2_request *smb2_write_send(struct smb2_tree *tree, struct smb2_write *io)
+{
+       struct smb2_request *req;
+
+       req = smb2_request_init_tree(tree, SMB2_OP_WRITE, io->in.data.length + 0x30);
+       if (req == NULL) return NULL;
+
+       SSVAL(req->out.body, 0x00, io->in.buffer_code);
+       SSVAL(req->out.body, 0x02, req->out.body+0x30 - req->out.hdr);
+       SIVAL(req->out.body, 0x04, io->in.data.length);
+       SBVAL(req->out.body, 0x08, io->in.offset);
+       smb2_put_handle(req->out.body+0x10, io->in.handle);
+       memcpy(req->out.body+0x20, io->in._pad, 0x10);
+       memcpy(req->out.body+0x30, io->in.data.data, io->in.data.length);
+
+       smb2_transport_send(req);
+
+       return req;
+}
+
+
+/*
+  recv a write reply
+*/
+NTSTATUS smb2_write_recv(struct smb2_request *req, struct smb2_write *io)
+{
+       if (!smb2_request_receive(req) || 
+           smb2_request_is_error(req)) {
+               return smb2_request_destroy(req);
+       }
+
+       if (req->in.body_size < 17) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+       SMB2_CHECK_BUFFER_CODE(req, 0x11);
+
+       io->out._pad     = SVAL(req->in.body, 0x02);
+       io->out.nwritten = IVAL(req->in.body, 0x04);
+       memcpy(io->out.unknown, req->in.body+0x08, 9);
+
+       return smb2_request_destroy(req);
+}
+
+/*
+  sync write request
+*/
+NTSTATUS smb2_write(struct smb2_tree *tree, struct smb2_write *io)
+{
+       struct smb2_request *req = smb2_write_send(tree, io);
+       return smb2_write_recv(req, io);
+}