summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libcli/smb2/close.c3
-rw-r--r--source4/libcli/smb2/config.mk4
-rw-r--r--source4/libcli/smb2/getinfo.c149
-rw-r--r--source4/libcli/smb2/read.c95
-rw-r--r--source4/libcli/smb2/request.c12
-rw-r--r--source4/libcli/smb2/smb2_calls.h60
-rw-r--r--source4/libcli/smb2/write.c82
7 files changed, 386 insertions, 19 deletions
diff --git a/source4/libcli/smb2/close.c b/source4/libcli/smb2/close.c
index 2802e2f27e..d5a2c4d422 100644
--- a/source4/libcli/smb2/close.c
+++ b/source4/libcli/smb2/close.c
@@ -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);
diff --git a/source4/libcli/smb2/config.mk b/source4/libcli/smb2/config.mk
index b7ecdcb98d..15f49ba88e 100644
--- a/source4/libcli/smb2/config.mk
+++ b/source4/libcli/smb2/config.mk
@@ -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
diff --git a/source4/libcli/smb2/getinfo.c b/source4/libcli/smb2/getinfo.c
index c8976e4230..a7935526e5 100644
--- a/source4/libcli/smb2/getinfo.c
+++ b/source4/libcli/smb2/getinfo.c
@@ -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
index 0000000000..cbb3f74fa4
--- /dev/null
+++ b/source4/libcli/smb2/read.c
@@ -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);
+}
diff --git a/source4/libcli/smb2/request.c b/source4/libcli/smb2/request.c
index 4b95d141a3..a06121df05 100644
--- a/source4/libcli/smb2/request.c
+++ b/source4/libcli/smb2/request.c
@@ -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]);
+}
+
diff --git a/source4/libcli/smb2/smb2_calls.h b/source4/libcli/smb2/smb2_calls.h
index 22cdcef14f..aa2fb717b2 100644
--- a/source4/libcli/smb2/smb2_calls.h
+++ b/source4/libcli/smb2/smb2_calls.h
@@ -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
index 0000000000..f842969b93
--- /dev/null
+++ b/source4/libcli/smb2/write.c
@@ -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);
+}