wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
/*
Unix SMB/CIFS implementation.
SMB2 client notify calls
Copyright (C) Stefan Metzmacher 2006
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 cancel request
*/
NTSTATUS smb2_cancel(struct smb2_request *r)
{
NTSTATUS status;
struct smb2_request *c;
uint32_t old_timeout;
uint64_t old_seqnum;
/*
* if we don't get a pending id yet, we just
* mark the request for pending, so that we directly
* send the cancel after getting the pending id
*/
if (!r->cancel.can_cancel) {
r->cancel.do_cancel++;
return NT_STATUS_OK;
}
/* we don't want a seqmun for a SMB2 Cancel */
old_seqnum = r->transport->seqnum;
c = smb2_request_init(r->transport, SMB2_OP_CANCEL, 0x04, False, 0);
r->transport->seqnum = old_seqnum;
NT_STATUS_HAVE_NO_MEMORY(c);
c->seqnum = 0;
SIVAL(c->out.hdr, SMB2_HDR_FLAGS, 0x00000002);
SSVAL(c->out.hdr, SMB2_HDR_UNKNOWN1, 0x0030);
SIVAL(c->out.hdr, SMB2_HDR_PID, r->cancel.pending_id);
SBVAL(c->out.hdr, SMB2_HDR_SEQNUM, c->seqnum);
if (r->session) {
SBVAL(c->out.hdr, SMB2_HDR_UID, r->session->uid);
}
SSVAL(c->out.body, 0x02, 0);
old_timeout = c->transport->options.timeout;
c->transport->options.timeout = 0;
smb2_transport_send(c);
c->transport->options.timeout = old_timeout;
if (c->state == SMB2_REQUEST_ERROR) {
status = c->status;
} else {
status = NT_STATUS_OK;
}
talloc_free(c);
return status;
}
+80
View File
@@ -0,0 +1,80 @@
/*
Unix SMB/CIFS implementation.
SMB2 client close handling
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 close request
*/
struct smb2_request *smb2_close_send(struct smb2_tree *tree, struct smb2_close *io)
{
struct smb2_request *req;
req = smb2_request_init_tree(tree, SMB2_OP_CLOSE, 0x18, False, 0);
if (req == NULL) return NULL;
SSVAL(req->out.body, 0x02, io->in.flags);
SIVAL(req->out.body, 0x04, 0); /* pad */
smb2_push_handle(req->out.body+0x08, &io->in.file.handle);
smb2_transport_send(req);
return req;
}
/*
recv a close reply
*/
NTSTATUS smb2_close_recv(struct smb2_request *req, struct smb2_close *io)
{
if (!smb2_request_receive(req) ||
!smb2_request_is_ok(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x3C, False);
io->out.flags = SVAL(req->in.body, 0x02);
io->out._pad = IVAL(req->in.body, 0x04);
io->out.create_time = smbcli_pull_nttime(req->in.body, 0x08);
io->out.access_time = smbcli_pull_nttime(req->in.body, 0x10);
io->out.write_time = smbcli_pull_nttime(req->in.body, 0x18);
io->out.change_time = smbcli_pull_nttime(req->in.body, 0x20);
io->out.alloc_size = BVAL(req->in.body, 0x28);
io->out.size = BVAL(req->in.body, 0x30);
io->out.file_attr = IVAL(req->in.body, 0x38);
return smb2_request_destroy(req);
}
/*
sync close request
*/
NTSTATUS smb2_close(struct smb2_tree *tree, struct smb2_close *io)
{
struct smb2_request *req = smb2_close_send(tree, io);
return smb2_close_recv(req, io);
}
+25
View File
@@ -0,0 +1,25 @@
[SUBSYSTEM::LIBCLI_SMB2]
PRIVATE_PROTO_HEADER = smb2_proto.h
OBJ_FILES = \
transport.o \
request.o \
negprot.o \
session.o \
tcon.o \
create.o \
close.o \
connect.o \
getinfo.o \
write.o \
read.o \
setinfo.o \
find.o \
ioctl.o \
logoff.o \
tdis.o \
flush.o \
lock.o \
notify.o \
cancel.o \
keepalive.o
PUBLIC_DEPENDENCIES = LIBCLI_RAW LIBPACKET gensec
+224
View File
@@ -0,0 +1,224 @@
/*
Unix SMB/CIFS implementation.
SMB2 composite connection setup
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 "libcli/composite/composite.h"
#include "libcli/resolve/resolve.h"
struct smb2_connect_state {
struct cli_credentials *credentials;
const char *host;
const char *share;
struct smb2_negprot negprot;
struct smb2_tree_connect tcon;
struct smb2_session *session;
struct smb2_tree *tree;
};
/*
continue after tcon reply
*/
static void continue_tcon(struct smb2_request *req)
{
struct composite_context *c = talloc_get_type(req->async.private,
struct composite_context);
struct smb2_connect_state *state = talloc_get_type(c->private_data,
struct smb2_connect_state);
c->status = smb2_tree_connect_recv(req, &state->tcon);
if (!composite_is_ok(c)) return;
state->tree->tid = state->tcon.out.tid;
composite_done(c);
}
/*
continue after a session setup
*/
static void continue_session(struct composite_context *creq)
{
struct composite_context *c = talloc_get_type(creq->async.private_data,
struct composite_context);
struct smb2_connect_state *state = talloc_get_type(c->private_data,
struct smb2_connect_state);
struct smb2_request *req;
c->status = smb2_session_setup_spnego_recv(creq);
if (!composite_is_ok(c)) return;
state->tree = smb2_tree_init(state->session, state, True);
if (composite_nomem(state->tree, c)) return;
state->tcon.in.unknown1 = 0x09;
state->tcon.in.path = talloc_asprintf(state, "\\\\%s\\%s",
state->host, state->share);
if (composite_nomem(state->tcon.in.path, c)) return;
req = smb2_tree_connect_send(state->tree, &state->tcon);
if (composite_nomem(req, c)) return;
req->async.fn = continue_tcon;
req->async.private = c;
}
/*
continue after negprot reply
*/
static void continue_negprot(struct smb2_request *req)
{
struct composite_context *c = talloc_get_type(req->async.private,
struct composite_context);
struct smb2_connect_state *state = talloc_get_type(c->private_data,
struct smb2_connect_state);
struct smb2_transport *transport = req->transport;
struct composite_context *creq;
c->status = smb2_negprot_recv(req, c, &state->negprot);
if (!composite_is_ok(c)) return;
state->session = smb2_session_init(transport, state, True);
if (composite_nomem(state->session, c)) return;
creq = smb2_session_setup_spnego_send(state->session, state->credentials);
composite_continue(c, creq, continue_session, c);
}
/*
continue after a socket connect completes
*/
static void continue_socket(struct composite_context *creq)
{
struct composite_context *c = talloc_get_type(creq->async.private_data,
struct composite_context);
struct smb2_connect_state *state = talloc_get_type(c->private_data,
struct smb2_connect_state);
struct smbcli_socket *sock;
struct smb2_transport *transport;
struct smb2_request *req;
c->status = smbcli_sock_connect_recv(creq, state, &sock);
if (!composite_is_ok(c)) return;
transport = smb2_transport_init(sock, state);
if (composite_nomem(transport, c)) return;
ZERO_STRUCT(state->negprot);
state->negprot.in.unknown1 = 0x0001;
req = smb2_negprot_send(transport, &state->negprot);
if (composite_nomem(req, c)) return;
req->async.fn = continue_negprot;
req->async.private = c;
}
/*
continue after a resolve finishes
*/
static void continue_resolve(struct composite_context *creq)
{
struct composite_context *c = talloc_get_type(creq->async.private_data,
struct composite_context);
struct smb2_connect_state *state = talloc_get_type(c->private_data,
struct smb2_connect_state);
const char *addr;
c->status = resolve_name_recv(creq, state, &addr);
if (!composite_is_ok(c)) return;
creq = smbcli_sock_connect_send(state, addr, 445, state->host, c->event_ctx);
composite_continue(c, creq, continue_socket, c);
}
/*
a composite function that does a full negprot/sesssetup/tcon, returning
a connected smb2_tree
*/
struct composite_context *smb2_connect_send(TALLOC_CTX *mem_ctx,
const char *host,
const char *share,
struct cli_credentials *credentials,
struct event_context *ev)
{
struct composite_context *c;
struct smb2_connect_state *state;
struct nbt_name name;
struct composite_context *creq;
c = composite_create(mem_ctx, ev);
if (c == NULL) return NULL;
state = talloc(c, struct smb2_connect_state);
if (composite_nomem(state, c)) return c;
c->private_data = state;
state->credentials = credentials;
state->host = talloc_strdup(c, host);
if (composite_nomem(state->host, c)) return c;
state->share = talloc_strdup(c, share);
if (composite_nomem(state->share, c)) return c;
ZERO_STRUCT(name);
name.name = host;
creq = resolve_name_send(&name, c->event_ctx, lp_name_resolve_order());
composite_continue(c, creq, continue_resolve, c);
return c;
}
/*
receive a connect reply
*/
NTSTATUS smb2_connect_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
struct smb2_tree **tree)
{
NTSTATUS status;
struct smb2_connect_state *state = talloc_get_type(c->private_data,
struct smb2_connect_state);
status = composite_wait(c);
if (NT_STATUS_IS_OK(status)) {
*tree = talloc_steal(mem_ctx, state->tree);
}
talloc_free(c);
return status;
}
/*
sync version of smb2_connect
*/
NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
const char *host, const char *share,
struct cli_credentials *credentials,
struct smb2_tree **tree,
struct event_context *ev)
{
struct composite_context *c = smb2_connect_send(mem_ctx, host, share,
credentials, ev);
return smb2_connect_recv(c, mem_ctx, tree);
}
+164
View File
@@ -0,0 +1,164 @@
/*
Unix SMB/CIFS implementation.
SMB2 client tree handling
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"
#define CREATE_TAG_EXTA 0x41747845 /* "ExtA" */
#define CREATE_TAG_MXAC 0x6341784D /* "MxAc" */
/*
add a blob to a smb2_create attribute blob
*/
static NTSTATUS smb2_create_blob_add(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
uint32_t tag,
DATA_BLOB add, BOOL last)
{
NTSTATUS status;
uint32_t ofs = blob->length;
uint8_t pad = smb2_padding_size(add.length, 8);
status = data_blob_realloc(mem_ctx, blob, blob->length + 0x18 + add.length + pad);
NT_STATUS_NOT_OK_RETURN(status);
if (last) {
SIVAL(blob->data, ofs+0x00, 0);
} else {
SIVAL(blob->data, ofs+0x00, 0x18 + add.length + pad);
}
SSVAL(blob->data, ofs+0x04, 0x10); /* offset of tag */
SIVAL(blob->data, ofs+0x06, 0x04); /* tag length */
SSVAL(blob->data, ofs+0x0A, 0x18); /* offset of data */
SIVAL(blob->data, ofs+0x0C, add.length);
SIVAL(blob->data, ofs+0x10, tag);
SIVAL(blob->data, ofs+0x14, 0); /* pad? */
memcpy(blob->data+ofs+0x18, add.data, add.length);
memset(blob->data+ofs+0x18+add.length, 0, pad);
return NT_STATUS_OK;
}
/*
send a create request
*/
struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create *io)
{
struct smb2_request *req;
NTSTATUS status;
DATA_BLOB blob = data_blob(NULL, 0);
req = smb2_request_init_tree(tree, SMB2_OP_CREATE, 0x38, True, 0);
if (req == NULL) return NULL;
SSVAL(req->out.body, 0x02, io->in.oplock_flags);
SIVAL(req->out.body, 0x04, io->in.impersonation);
SIVAL(req->out.body, 0x08, io->in.unknown3[0]);
SIVAL(req->out.body, 0x0C, io->in.unknown3[1]);
SIVAL(req->out.body, 0x10, io->in.unknown3[2]);
SIVAL(req->out.body, 0x14, io->in.unknown3[3]);
SIVAL(req->out.body, 0x18, io->in.access_mask);
SIVAL(req->out.body, 0x1C, io->in.file_attr);
SIVAL(req->out.body, 0x20, io->in.share_access);
SIVAL(req->out.body, 0x24, io->in.open_disposition);
SIVAL(req->out.body, 0x28, io->in.create_options);
status = smb2_push_o16s16_string(&req->out, 0x2C, io->in.fname);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(req);
return NULL;
}
if (io->in.eas.num_eas != 0) {
DATA_BLOB b = data_blob_talloc(req, NULL,
ea_list_size_chained(io->in.eas.num_eas, io->in.eas.eas));
ea_put_list_chained(b.data, io->in.eas.num_eas, io->in.eas.eas);
status = smb2_create_blob_add(req, &blob, CREATE_TAG_EXTA, b, False);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(req);
return NULL;
}
data_blob_free(&b);
}
/* an empty MxAc tag seems to be used to ask the server to
return the maximum access mask allowed on the file */
status = smb2_create_blob_add(req, &blob, CREATE_TAG_MXAC, data_blob(NULL, 0), True);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(req);
return NULL;
}
status = smb2_push_o32s32_blob(&req->out, 0x30, blob);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(req);
return NULL;
}
smb2_transport_send(req);
return req;
}
/*
recv a create reply
*/
NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_create *io)
{
NTSTATUS status;
if (!smb2_request_receive(req) ||
!smb2_request_is_ok(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x58, True);
io->out.oplock_flags = SVAL(req->in.body, 0x02);
io->out.create_action = IVAL(req->in.body, 0x04);
io->out.create_time = smbcli_pull_nttime(req->in.body, 0x08);
io->out.access_time = smbcli_pull_nttime(req->in.body, 0x10);
io->out.write_time = smbcli_pull_nttime(req->in.body, 0x18);
io->out.change_time = smbcli_pull_nttime(req->in.body, 0x20);
io->out.alloc_size = BVAL(req->in.body, 0x28);
io->out.size = BVAL(req->in.body, 0x30);
io->out.file_attr = IVAL(req->in.body, 0x38);
io->out._pad = IVAL(req->in.body, 0x3C);
smb2_pull_handle(req->in.body+0x40, &io->out.file.handle);
status = smb2_pull_o32s32_blob(&req->in, mem_ctx, req->in.body+0x50, &io->out.blob);
if (!NT_STATUS_IS_OK(status)) {
smb2_request_destroy(req);
return status;
}
return smb2_request_destroy(req);
}
/*
sync create request
*/
NTSTATUS smb2_create(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, struct smb2_create *io)
{
struct smb2_request *req = smb2_create_send(tree, io);
return smb2_create_recv(req, mem_ctx, io);
}
+180
View File
@@ -0,0 +1,180 @@
/*
Unix SMB/CIFS implementation.
SMB2 client find calls
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 find request
*/
struct smb2_request *smb2_find_send(struct smb2_tree *tree, struct smb2_find *io)
{
struct smb2_request *req;
NTSTATUS status;
req = smb2_request_init_tree(tree, SMB2_OP_FIND, 0x20, True, 0);
if (req == NULL) return NULL;
SCVAL(req->out.body, 0x02, io->in.level);
SCVAL(req->out.body, 0x03, io->in.continue_flags);
SIVAL(req->out.body, 0x04, io->in.unknown);
smb2_push_handle(req->out.body+0x08, &io->in.file.handle);
status = smb2_push_o16s16_string(&req->out, 0x18, io->in.pattern);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(req);
return NULL;
}
SIVAL(req->out.body, 0x1C, io->in.max_response_size);
smb2_transport_send(req);
return req;
}
/*
recv a find reply
*/
NTSTATUS smb2_find_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
struct smb2_find *io)
{
NTSTATUS status;
if (!smb2_request_receive(req) ||
smb2_request_is_error(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x08, True);
status = smb2_pull_o16s32_blob(&req->in, mem_ctx,
req->in.body+0x02, &io->out.blob);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return smb2_request_destroy(req);
}
/*
sync find request
*/
NTSTATUS smb2_find(struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
struct smb2_find *io)
{
struct smb2_request *req = smb2_find_send(tree, io);
return smb2_find_recv(req, mem_ctx, io);
}
/*
a varient of smb2_find_recv that parses the resulting blob into
smb_search_data structures
*/
NTSTATUS smb2_find_level_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
uint8_t level, uint_t *count,
union smb_search_data **io)
{
struct smb2_find f;
NTSTATUS status;
DATA_BLOB b;
enum smb_search_data_level smb_level;
uint_t next_ofs=0;
switch (level) {
case SMB2_FIND_DIRECTORY_INFO:
smb_level = RAW_SEARCH_DATA_DIRECTORY_INFO;
break;
case SMB2_FIND_FULL_DIRECTORY_INFO:
smb_level = RAW_SEARCH_DATA_FULL_DIRECTORY_INFO;
break;
case SMB2_FIND_BOTH_DIRECTORY_INFO:
smb_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
break;
case SMB2_FIND_NAME_INFO:
smb_level = RAW_SEARCH_DATA_NAME_INFO;
break;
case SMB2_FIND_ID_FULL_DIRECTORY_INFO:
smb_level = RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO;
break;
case SMB2_FIND_ID_BOTH_DIRECTORY_INFO:
smb_level = RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO;
break;
default:
return NT_STATUS_INVALID_INFO_CLASS;
}
status = smb2_find_recv(req, mem_ctx, &f);
NT_STATUS_NOT_OK_RETURN(status);
b = f.out.blob;
*io = NULL;
*count = 0;
do {
union smb_search_data *io2;
io2 = talloc_realloc(mem_ctx, *io, union smb_search_data, (*count)+1);
if (io2 == NULL) {
data_blob_free(&f.out.blob);
talloc_free(*io);
return NT_STATUS_NO_MEMORY;
}
*io = io2;
status = smb_raw_search_common(*io, smb_level, &b, (*io) + (*count),
&next_ofs, STR_UNICODE);
if (NT_STATUS_IS_OK(status) &&
next_ofs >= b.length) {
data_blob_free(&f.out.blob);
talloc_free(*io);
return NT_STATUS_INFO_LENGTH_MISMATCH;
}
(*count)++;
b = data_blob_const(b.data+next_ofs, b.length - next_ofs);
} while (NT_STATUS_IS_OK(status) && next_ofs != 0);
data_blob_free(&f.out.blob);
return NT_STATUS_OK;
}
/*
a varient of smb2_find that parses the resulting blob into
smb_search_data structures
*/
NTSTATUS smb2_find_level(struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
struct smb2_find *f,
uint_t *count, union smb_search_data **io)
{
struct smb2_request *req;
req = smb2_find_send(tree, f);
return smb2_find_level_recv(req, mem_ctx, f->in.level, count, io);
}
+69
View File
@@ -0,0 +1,69 @@
/*
Unix SMB/CIFS implementation.
SMB2 client flush handling
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"
/*
send a flush request
*/
struct smb2_request *smb2_flush_send(struct smb2_tree *tree, struct smb2_flush *io)
{
struct smb2_request *req;
req = smb2_request_init_tree(tree, SMB2_OP_FLUSH, 0x18, False, 0);
if (req == NULL) return NULL;
SSVAL(req->out.body, 0x02, 0); /* pad? */
SIVAL(req->out.body, 0x04, io->in.unknown);
smb2_push_handle(req->out.body+0x08, &io->in.file.handle);
smb2_transport_send(req);
return req;
}
/*
recv a flush reply
*/
NTSTATUS smb2_flush_recv(struct smb2_request *req, struct smb2_flush *io)
{
if (!smb2_request_receive(req) ||
!smb2_request_is_ok(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x04, False);
return smb2_request_destroy(req);
}
/*
sync flush request
*/
NTSTATUS smb2_flush(struct smb2_tree *tree, struct smb2_flush *io)
{
struct smb2_request *req = smb2_flush_send(tree, io);
return smb2_flush_recv(req, io);
}
+210
View File
@@ -0,0 +1,210 @@
/*
Unix SMB/CIFS implementation.
SMB2 client getinfo calls
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 getinfo request
*/
struct smb2_request *smb2_getinfo_send(struct smb2_tree *tree, struct smb2_getinfo *io)
{
struct smb2_request *req;
req = smb2_request_init_tree(tree, SMB2_OP_GETINFO, 0x28, False, 0);
if (req == NULL) return NULL;
/* this seems to be a bug, they use 0x29 but only send 0x28 bytes */
SSVAL(req->out.body, 0x00, 0x29);
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, 0x10, io->in.flags);
SIVAL(req->out.body, 0x14, io->in.flags2);
smb2_push_handle(req->out.body+0x18, &io->in.file.handle);
smb2_transport_send(req);
return req;
}
/*
recv a getinfo reply
*/
NTSTATUS smb2_getinfo_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
struct smb2_getinfo *io)
{
NTSTATUS status;
if (!smb2_request_receive(req) ||
smb2_request_is_error(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x08, True);
status = smb2_pull_o16s16_blob(&req->in, mem_ctx, req->in.body+0x02, &io->out.blob);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return smb2_request_destroy(req);
}
/*
sync getinfo request
*/
NTSTATUS smb2_getinfo(struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
struct smb2_getinfo *io)
{
struct smb2_request *req = smb2_getinfo_send(tree, io);
return smb2_getinfo_recv(req, mem_ctx, io);
}
/*
map a generic info level to a SMB2 info level
*/
uint16_t smb2_getinfo_map_level(uint16_t level, uint8_t class)
{
if (class == SMB2_GETINFO_FILE &&
level == RAW_FILEINFO_SEC_DESC) {
return SMB2_GETINFO_SECURITY;
}
if ((level & 0xFF) == class) {
return level;
} else if (level > 1000) {
return ((level-1000)<<8) | class;
}
DEBUG(0,("Unable to map SMB2 info level 0x%04x of class %d\n", level, class));
return 0;
}
/*
level specific getinfo call - async send
*/
struct smb2_request *smb2_getinfo_file_send(struct smb2_tree *tree, union smb_fileinfo *io)
{
struct smb2_getinfo b;
uint16_t smb2_level = smb2_getinfo_map_level(io->generic.level, SMB2_GETINFO_FILE);
if (smb2_level == 0) {
return NULL;
}
ZERO_STRUCT(b);
b.in.max_response_size = 0x10000;
b.in.file.handle = io->generic.in.file.handle;
b.in.level = smb2_level;
if (io->generic.level == RAW_FILEINFO_SEC_DESC) {
b.in.flags = io->query_secdesc.in.secinfo_flags;
}
if (io->generic.level == RAW_FILEINFO_SMB2_ALL_EAS) {
b.in.flags2 = io->all_eas.in.continue_flags;
}
return smb2_getinfo_send(tree, &b);
}
/*
recv a getinfo reply and parse the level info
*/
NTSTATUS smb2_getinfo_file_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
union smb_fileinfo *io)
{
struct smb2_getinfo b;
NTSTATUS status;
status = smb2_getinfo_recv(req, mem_ctx, &b);
NT_STATUS_NOT_OK_RETURN(status);
status = smb_raw_fileinfo_passthru_parse(&b.out.blob, mem_ctx, io->generic.level, io);
data_blob_free(&b.out.blob);
return status;
}
/*
level specific getinfo call
*/
NTSTATUS smb2_getinfo_file(struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
union smb_fileinfo *io)
{
struct smb2_request *req = smb2_getinfo_file_send(tree, io);
return smb2_getinfo_file_recv(req, mem_ctx, io);
}
/*
level specific getinfo call - async send
*/
struct smb2_request *smb2_getinfo_fs_send(struct smb2_tree *tree, union smb_fsinfo *io)
{
struct smb2_getinfo b;
uint16_t smb2_level = smb2_getinfo_map_level(io->generic.level, SMB2_GETINFO_FS);
if (smb2_level == 0) {
return NULL;
}
ZERO_STRUCT(b);
b.in.max_response_size = 0x10000;
b.in.file.handle = io->generic.handle;
b.in.level = smb2_level;
return smb2_getinfo_send(tree, &b);
}
/*
recv a getinfo reply and parse the level info
*/
NTSTATUS smb2_getinfo_fs_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
union smb_fsinfo *io)
{
struct smb2_getinfo b;
NTSTATUS status;
status = smb2_getinfo_recv(req, mem_ctx, &b);
NT_STATUS_NOT_OK_RETURN(status);
status = smb_raw_fsinfo_passthru_parse(b.out.blob, mem_ctx, io->generic.level, io);
data_blob_free(&b.out.blob);
return status;
}
/*
level specific getinfo call
*/
NTSTATUS smb2_getinfo_fs(struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
union smb_fsinfo *io)
{
struct smb2_request *req = smb2_getinfo_fs_send(tree, io);
return smb2_getinfo_fs_recv(req, mem_ctx, io);
}
+110
View File
@@ -0,0 +1,110 @@
/*
Unix SMB/CIFS implementation.
SMB2 client ioctl 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/smb2/smb2.h"
#include "libcli/smb2/smb2_calls.h"
/*
send a ioctl request
*/
struct smb2_request *smb2_ioctl_send(struct smb2_tree *tree, struct smb2_ioctl *io)
{
NTSTATUS status;
struct smb2_request *req;
req = smb2_request_init_tree(tree, SMB2_OP_IOCTL, 0x38, True,
io->in.in.length+io->in.out.length);
if (req == NULL) return NULL;
SSVAL(req->out.body, 0x02, 0); /* pad */
SIVAL(req->out.body, 0x04, io->in.function);
smb2_push_handle(req->out.body+0x08, &io->in.file.handle);
status = smb2_push_o32s32_blob(&req->out, 0x18, io->in.out);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(req);
return NULL;
}
SIVAL(req->out.body, 0x20, io->in.unknown2);
status = smb2_push_o32s32_blob(&req->out, 0x24, io->in.in);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(req);
return NULL;
}
SIVAL(req->out.body, 0x2C, io->in.max_response_size);
SBVAL(req->out.body, 0x30, io->in.flags);
smb2_transport_send(req);
return req;
}
/*
recv a ioctl reply
*/
NTSTATUS smb2_ioctl_recv(struct smb2_request *req,
TALLOC_CTX *mem_ctx, struct smb2_ioctl *io)
{
NTSTATUS status;
if (!smb2_request_receive(req) ||
smb2_request_is_error(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x30, True);
io->out._pad = SVAL(req->in.body, 0x02);
io->out.function = IVAL(req->in.body, 0x04);
smb2_pull_handle(req->in.body+0x08, &io->out.file.handle);
status = smb2_pull_o32s32_blob(&req->in, mem_ctx, req->in.body+0x18, &io->out.in);
if (!NT_STATUS_IS_OK(status)) {
smb2_request_destroy(req);
return status;
}
status = smb2_pull_o32s32_blob(&req->in, mem_ctx, req->in.body+0x20, &io->out.out);
if (!NT_STATUS_IS_OK(status)) {
smb2_request_destroy(req);
return status;
}
io->out.unknown2 = IVAL(req->in.body, 0x28);
io->out.unknown3 = IVAL(req->in.body, 0x2C);
return smb2_request_destroy(req);
}
/*
sync ioctl request
*/
NTSTATUS smb2_ioctl(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, struct smb2_ioctl *io)
{
struct smb2_request *req = smb2_ioctl_send(tree, io);
return smb2_ioctl_recv(req, mem_ctx, io);
}
+66
View File
@@ -0,0 +1,66 @@
/*
Unix SMB/CIFS implementation.
SMB2 client keepalive handling
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"
/*
send a keepalive request
*/
struct smb2_request *smb2_keepalive_send(struct smb2_transport *transport)
{
struct smb2_request *req;
req = smb2_request_init(transport, SMB2_OP_KEEPALIVE, 0x04, False, 0);
if (req == NULL) return NULL;
SSVAL(req->out.body, 0x02, 0);
smb2_transport_send(req);
return req;
}
/*
recv a keepalive reply
*/
NTSTATUS smb2_keepalive_recv(struct smb2_request *req)
{
if (!smb2_request_receive(req) ||
!smb2_request_is_ok(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x04, False);
return smb2_request_destroy(req);
}
/*
sync keepalive request
*/
NTSTATUS smb2_keepalive(struct smb2_transport *transport)
{
struct smb2_request *req = smb2_keepalive_send(transport);
return smb2_keepalive_recv(req);
}
+75
View File
@@ -0,0 +1,75 @@
/*
Unix SMB/CIFS implementation.
SMB2 client lock handling
Copyright (C) Stefan Metzmacher 2006
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"
/*
send a lock request
*/
struct smb2_request *smb2_lock_send(struct smb2_tree *tree, struct smb2_lock *io)
{
struct smb2_request *req;
req = smb2_request_init_tree(tree, SMB2_OP_LOCK, 0x30, False, 0);
if (req == NULL) return NULL;
SSVAL(req->out.body, 0x02, io->in.unknown1);
SIVAL(req->out.body, 0x04, io->in.unknown2);
smb2_push_handle(req->out.body+0x08, &io->in.file.handle);
SBVAL(req->out.body, 0x18, io->in.offset);
SBVAL(req->out.body, 0x20, io->in.count);
SIVAL(req->out.body, 0x28, io->in.unknown5);
SIVAL(req->out.body, 0x28, io->in.flags);
smb2_transport_send(req);
return req;
}
/*
recv a lock reply
*/
NTSTATUS smb2_lock_recv(struct smb2_request *req, struct smb2_lock *io)
{
if (!smb2_request_receive(req) ||
smb2_request_is_error(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x04, False);
io->out.unknown1 = SVAL(req->in.body, 0x02);
return smb2_request_destroy(req);
}
/*
sync lock request
*/
NTSTATUS smb2_lock(struct smb2_tree *tree, struct smb2_lock *io)
{
struct smb2_request *req = smb2_lock_send(tree, io);
return smb2_lock_recv(req, io);
}
+68
View File
@@ -0,0 +1,68 @@
/*
Unix SMB/CIFS implementation.
SMB2 client logoff handling
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"
/*
send a logoff request
*/
struct smb2_request *smb2_logoff_send(struct smb2_session *session)
{
struct smb2_request *req;
req = smb2_request_init(session->transport, SMB2_OP_LOGOFF, 0x04, False, 0);
if (req == NULL) return NULL;
SBVAL(req->out.hdr, SMB2_HDR_UID, session->uid);
SSVAL(req->out.body, 0x02, 0);
smb2_transport_send(req);
return req;
}
/*
recv a logoff reply
*/
NTSTATUS smb2_logoff_recv(struct smb2_request *req)
{
if (!smb2_request_receive(req) ||
!smb2_request_is_ok(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x04, False);
return smb2_request_destroy(req);
}
/*
sync logoff request
*/
NTSTATUS smb2_logoff(struct smb2_session *session)
{
struct smb2_request *req = smb2_logoff_send(session);
return smb2_logoff_recv(req);
}
+96
View File
@@ -0,0 +1,96 @@
/*
Unix SMB/CIFS implementation.
SMB2 client negprot handling
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 negprot request
*/
struct smb2_request *smb2_negprot_send(struct smb2_transport *transport,
struct smb2_negprot *io)
{
struct smb2_request *req;
req = smb2_request_init(transport, SMB2_OP_NEGPROT, 0x26, False, 0);
if (req == NULL) return NULL;
/* this seems to be a bug, they use 0x24 but the length is 0x26 */
SSVAL(req->out.body, 0x00, 0x24);
SSVAL(req->out.body, 0x02, io->in.unknown1);
memcpy(req->out.body+0x04, io->in.unknown2, 32);
SSVAL(req->out.body, 0x24, io->in.unknown3);
smb2_transport_send(req);
return req;
}
/*
recv a negprot reply
*/
NTSTATUS smb2_negprot_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
struct smb2_negprot *io)
{
NTSTATUS status;
if (!smb2_request_receive(req) ||
smb2_request_is_error(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x40, True);
io->out._pad = SVAL(req->in.body, 0x02);
io->out.unknown2 = IVAL(req->in.body, 0x04);
memcpy(io->out.sessid, req->in.body + 0x08, 16);
io->out.unknown3 = IVAL(req->in.body, 0x18);
io->out.unknown4 = SVAL(req->in.body, 0x1C);
io->out.unknown5 = IVAL(req->in.body, 0x1E);
io->out.unknown6 = IVAL(req->in.body, 0x22);
io->out.unknown7 = SVAL(req->in.body, 0x26);
io->out.current_time = smbcli_pull_nttime(req->in.body, 0x28);
io->out.boot_time = smbcli_pull_nttime(req->in.body, 0x30);
status = smb2_pull_o16s16_blob(&req->in, mem_ctx, req->in.body+0x38, &io->out.secblob);
if (!NT_STATUS_IS_OK(status)) {
smb2_request_destroy(req);
return status;
}
io->out.unknown9 = IVAL(req->in.body, 0x3C);
return smb2_request_destroy(req);
}
/*
sync negprot request
*/
NTSTATUS smb2_negprot(struct smb2_transport *transport,
TALLOC_CTX *mem_ctx, struct smb2_negprot *io)
{
struct smb2_request *req = smb2_negprot_send(transport, io);
return smb2_negprot_recv(req, mem_ctx, io);
}
+114
View File
@@ -0,0 +1,114 @@
/*
Unix SMB/CIFS implementation.
SMB2 client notify calls
Copyright (C) Stefan Metzmacher 2006
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 notify request
*/
struct smb2_request *smb2_notify_send(struct smb2_tree *tree, struct smb2_notify *io)
{
struct smb2_request *req;
uint32_t old_timeout;
req = smb2_request_init_tree(tree, SMB2_OP_NOTIFY, 0x20, False, 0);
if (req == NULL) return NULL;
SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, 0x0030);
SSVAL(req->out.body, 0x02, io->in.recursive);
SIVAL(req->out.body, 0x04, io->in.buffer_size);
smb2_push_handle(req->out.body+0x08, &io->in.file.handle);
SIVAL(req->out.body, 0x18, io->in.completion_filter);
SIVAL(req->out.body, 0x1C, io->in.unknown);
old_timeout = req->transport->options.timeout;
req->transport->options.timeout = 0;
smb2_transport_send(req);
req->transport->options.timeout = old_timeout;
return req;
}
/*
recv a notify reply
*/
NTSTATUS smb2_notify_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
struct smb2_notify *io)
{
NTSTATUS status;
DATA_BLOB blob;
uint32_t ofs, i;
if (!smb2_request_receive(req) ||
!smb2_request_is_ok(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x08, True);
status = smb2_pull_o16s32_blob(&req->in, mem_ctx, req->in.body+0x02, &blob);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
io->out.changes = NULL;
io->out.num_changes = 0;
/* count them */
for (ofs=0; blob.length - ofs > 12; ) {
uint32_t next = IVAL(blob.data, ofs);
io->out.num_changes++;
if (next == 0 || (ofs + next) >= blob.length) break;
ofs += next;
}
/* allocate array */
io->out.changes = talloc_array(mem_ctx, struct notify_changes, io->out.num_changes);
if (!io->out.changes) {
return NT_STATUS_NO_MEMORY;
}
for (i=ofs=0; i<io->out.num_changes; i++) {
io->out.changes[i].action = IVAL(blob.data, ofs+4);
smbcli_blob_pull_string(NULL, mem_ctx, &blob,
&io->out.changes[i].name,
ofs+8, ofs+12, STR_UNICODE);
ofs += IVAL(blob.data, ofs);
}
return smb2_request_destroy(req);
}
/*
sync notify request
*/
NTSTATUS smb2_notify(struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
struct smb2_notify *io)
{
struct smb2_request *req = smb2_notify_send(tree, io);
return smb2_notify_recv(req, mem_ctx, io);
}
+83
View File
@@ -0,0 +1,83 @@
/*
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/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, 0x30, True, 0);
if (req == NULL) return NULL;
SSVAL(req->out.body, 0x02, 0); /* pad */
SIVAL(req->out.body, 0x04, io->in.length);
SBVAL(req->out.body, 0x08, io->in.offset);
smb2_push_handle(req->out.body+0x10, &io->in.file.handle);
SBVAL(req->out.body, 0x20, io->in.unknown1);
SBVAL(req->out.body, 0x28, io->in.unknown2);
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)
{
NTSTATUS status;
if (!smb2_request_receive(req) ||
!smb2_request_is_ok(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x10, True);
status = smb2_pull_o16s32_blob(&req->in, mem_ctx, req->in.body+0x02, &io->out.data);
if (!NT_STATUS_IS_OK(status)) {
smb2_request_destroy(req);
return status;
}
io->out.unknown1 = BVAL(req->in.body, 0x08);
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);
}
+635
View File
@@ -0,0 +1,635 @@
/*
Unix SMB/CIFS implementation.
SMB2 client request handling
Copyright (C) Andrew Tridgell 2005
Copyright (C) Stefan Metzmacher 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 "lib/util/dlinklist.h"
#include "lib/events/events.h"
/*
initialise a smb2 request
*/
struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
uint16_t body_fixed_size, BOOL body_dynamic_present,
uint32_t body_dynamic_size)
{
struct smb2_request *req;
uint64_t seqnum;
if (body_dynamic_present) {
if (body_dynamic_size == 0) {
body_dynamic_size = 1;
}
} else {
body_dynamic_size = 0;
}
req = talloc(transport, struct smb2_request);
if (req == NULL) return NULL;
seqnum = transport->seqnum++;
if (seqnum == UINT64_MAX) {
seqnum = transport->seqnum++;
}
req->state = SMB2_REQUEST_INIT;
req->transport = transport;
req->session = NULL;
req->tree = NULL;
req->seqnum = seqnum;
req->status = NT_STATUS_OK;
req->async.fn = NULL;
req->next = req->prev = NULL;
ZERO_STRUCT(req->cancel);
ZERO_STRUCT(req->in);
req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
req->out.allocated = req->out.size + body_dynamic_size;
req->out.buffer = talloc_size(req, req->out.allocated);
if (req->out.buffer == NULL) {
talloc_free(req);
return NULL;
}
req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
req->out.body = req->out.hdr + SMB2_HDR_BODY;
req->out.body_fixed= body_fixed_size;
req->out.body_size = body_fixed_size;
req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
SIVAL(req->out.hdr, 0, SMB2_MAGIC);
SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,0);
SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN2,0);
SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
SBVAL(req->out.hdr, SMB2_HDR_UID, 0);
memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
/* set the length of the fixed body part and +1 if there's a dynamic part also */
SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
/*
* if we have a dynamic part, make sure the first byte
* which is always be part of the packet is initialized
*/
if (body_dynamic_size) {
req->out.size += 1;
SCVAL(req->out.dynamic, 0, 0);
}
return req;
}
/*
initialise a smb2 request for tree operations
*/
struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
uint16_t body_fixed_size, BOOL body_dynamic_present,
uint32_t body_dynamic_size)
{
struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
body_fixed_size, body_dynamic_present,
body_dynamic_size);
if (req == NULL) return NULL;
SBVAL(req->out.hdr, SMB2_HDR_UID, tree->session->uid);
SIVAL(req->out.hdr, SMB2_HDR_TID, tree->tid);
req->session = tree->session;
req->tree = tree;
return req;
}
/* destroy a request structure and return final status */
NTSTATUS smb2_request_destroy(struct smb2_request *req)
{
NTSTATUS status;
/* this is the error code we give the application for when a
_send() call fails completely */
if (!req) return NT_STATUS_UNSUCCESSFUL;
if (req->transport) {
/* remove it from the list of pending requests (a null op if
its not in the list) */
DLIST_REMOVE(req->transport->pending_recv, req);
}
if (req->state == SMB2_REQUEST_ERROR &&
NT_STATUS_IS_OK(req->status)) {
req->status = NT_STATUS_INTERNAL_ERROR;
}
status = req->status;
talloc_free(req);
return status;
}
/*
receive a response to a packet
*/
BOOL smb2_request_receive(struct smb2_request *req)
{
/* req can be NULL when a send has failed. This eliminates lots of NULL
checks in each module */
if (!req) return False;
/* keep receiving packets until this one is replied to */
while (req->state <= SMB2_REQUEST_RECV) {
if (event_loop_once(req->transport->socket->event.ctx) != 0) {
return False;
}
}
return req->state == SMB2_REQUEST_DONE;
}
/* Return true if the last packet was in error */
BOOL smb2_request_is_error(struct smb2_request *req)
{
return NT_STATUS_IS_ERR(req->status);
}
/* Return true if the last packet was OK */
BOOL smb2_request_is_ok(struct smb2_request *req)
{
return NT_STATUS_IS_OK(req->status);
}
/*
check if a range in the reply body is out of bounds
*/
BOOL smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
{
/* be careful with wraparound! */
if (ptr < buf->body ||
ptr >= buf->body + buf->body_size ||
size > buf->body_size ||
ptr + size > buf->body + buf->body_size) {
return True;
}
return False;
}
size_t smb2_padding_size(uint32_t offset, size_t n)
{
if ((offset & (n-1)) == 0) return 0;
return n - (offset & (n-1));
}
static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
{
if (buf->dynamic == (buf->body + buf->body_fixed)) {
return 1;
}
return 0;
}
/*
grow a SMB2 buffer by the specified amount
*/
static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
{
size_t dynamic_ofs;
uint8_t *buffer_ptr;
uint32_t newsize = buf->size + increase;
/* a packet size should be limited a bit */
if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
if (newsize <= buf->allocated) return NT_STATUS_OK;
dynamic_ofs = buf->dynamic - buf->buffer;
buffer_ptr = talloc_realloc_size(buf, buf->buffer, newsize);
NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
buf->buffer = buffer_ptr;
buf->hdr = buf->buffer + NBT_HDR_SIZE;
buf->body = buf->hdr + SMB2_HDR_BODY;
buf->dynamic = buf->buffer + dynamic_ofs;
buf->allocated = newsize;
return NT_STATUS_OK;
}
/*
pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
the ptr points to the start of the offset/length pair
*/
NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
{
uint16_t ofs, size;
if (smb2_oob(buf, ptr, 4)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
ofs = SVAL(ptr, 0);
size = SVAL(ptr, 2);
if (ofs == 0 || size == 0) {
*blob = data_blob(NULL, 0);
return NT_STATUS_OK;
}
if (smb2_oob(buf, buf->hdr + ofs, size)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
*blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
NT_STATUS_HAVE_NO_MEMORY(blob->data);
return NT_STATUS_OK;
}
/*
push a uint16_t ofs/ uint16_t length/blob triple into a data blob
the ofs points to the start of the offset/length pair, and is relative
to the body start
*/
NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf,
uint16_t ofs, DATA_BLOB blob)
{
NTSTATUS status;
size_t offset;
size_t padding_length;
size_t padding_fix;
uint8_t *ptr = buf->body+ofs;
if (buf->dynamic == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
/* we have only 16 bit for the size */
if (blob.length > 0xFFFF) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
/* check if there're enough room for ofs and size */
if (smb2_oob(buf, ptr, 4)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
if (blob.length == 0) {
SSVAL(ptr, 0, 0);
SSVAL(ptr, 2, 0);
return NT_STATUS_OK;
}
offset = buf->dynamic - buf->hdr;
padding_length = smb2_padding_size(offset, 2);
offset += padding_length;
padding_fix = smb2_padding_fix(buf);
SSVAL(ptr, 0, offset);
SSVAL(ptr, 2, blob.length);
status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
NT_STATUS_NOT_OK_RETURN(status);
memset(buf->dynamic, 0, padding_length);
buf->dynamic += padding_length;
memcpy(buf->dynamic, blob.data, blob.length);
buf->dynamic += blob.length;
buf->size += blob.length + padding_length - padding_fix;
buf->body_size += blob.length + padding_length;
return NT_STATUS_OK;
}
/*
push a uint16_t ofs/ uint32_t length/blob triple into a data blob
the ofs points to the start of the offset/length pair, and is relative
to the body start
*/
NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf,
uint16_t ofs, DATA_BLOB blob)
{
NTSTATUS status;
size_t offset;
size_t padding_length;
size_t padding_fix;
uint8_t *ptr = buf->body+ofs;
if (buf->dynamic == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
/* check if there're enough room for ofs and size */
if (smb2_oob(buf, ptr, 6)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
if (blob.length == 0) {
SSVAL(ptr, 0, 0);
SIVAL(ptr, 2, 0);
return NT_STATUS_OK;
}
offset = buf->dynamic - buf->hdr;
padding_length = smb2_padding_size(offset, 2);
offset += padding_length;
padding_fix = smb2_padding_fix(buf);
SSVAL(ptr, 0, offset);
SIVAL(ptr, 2, blob.length);
status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
NT_STATUS_NOT_OK_RETURN(status);
memset(buf->dynamic, 0, padding_length);
buf->dynamic += padding_length;
memcpy(buf->dynamic, blob.data, blob.length);
buf->dynamic += blob.length;
buf->size += blob.length + padding_length - padding_fix;
buf->body_size += blob.length + padding_length;
return NT_STATUS_OK;
}
/*
push a uint32_t ofs/ uint32_t length/blob triple into a data blob
the ofs points to the start of the offset/length pair, and is relative
to the body start
*/
NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf,
uint32_t ofs, DATA_BLOB blob)
{
NTSTATUS status;
size_t offset;
size_t padding_length;
size_t padding_fix;
uint8_t *ptr = buf->body+ofs;
if (buf->dynamic == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
/* check if there're enough room for ofs and size */
if (smb2_oob(buf, ptr, 8)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
if (blob.length == 0) {
SIVAL(ptr, 0, 0);
SIVAL(ptr, 4, 0);
return NT_STATUS_OK;
}
offset = buf->dynamic - buf->hdr;
padding_length = smb2_padding_size(offset, 8);
offset += padding_length;
padding_fix = smb2_padding_fix(buf);
SIVAL(ptr, 0, offset);
SIVAL(ptr, 4, blob.length);
status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
NT_STATUS_NOT_OK_RETURN(status);
memset(buf->dynamic, 0, padding_length);
buf->dynamic += padding_length;
memcpy(buf->dynamic, blob.data, blob.length);
buf->dynamic += blob.length;
buf->size += blob.length + padding_length - padding_fix;
buf->body_size += blob.length + padding_length;
return NT_STATUS_OK;
}
/*
push a uint32_t length/ uint32_t ofs/blob triple into a data blob
the ofs points to the start of the length/offset pair, and is relative
to the body start
*/
NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf,
uint32_t ofs, DATA_BLOB blob)
{
NTSTATUS status;
size_t offset;
size_t padding_length;
size_t padding_fix;
uint8_t *ptr = buf->body+ofs;
if (buf->dynamic == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
/* check if there're enough room for ofs and size */
if (smb2_oob(buf, ptr, 8)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
if (blob.length == 0) {
SIVAL(ptr, 0, 0);
SIVAL(ptr, 4, 0);
return NT_STATUS_OK;
}
offset = buf->dynamic - buf->hdr;
padding_length = smb2_padding_size(offset, 8);
offset += padding_length;
padding_fix = smb2_padding_fix(buf);
SIVAL(ptr, 0, blob.length);
SIVAL(ptr, 4, offset);
status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
NT_STATUS_NOT_OK_RETURN(status);
memset(buf->dynamic, 0, padding_length);
buf->dynamic += padding_length;
memcpy(buf->dynamic, blob.data, blob.length);
buf->dynamic += blob.length;
buf->size += blob.length + padding_length - padding_fix;
buf->body_size += blob.length + padding_length;
return NT_STATUS_OK;
}
/*
pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
the ptr points to the start of the offset/length pair
*/
NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
{
uint16_t ofs;
uint32_t size;
if (smb2_oob(buf, ptr, 6)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
ofs = SVAL(ptr, 0);
size = IVAL(ptr, 2);
if (ofs == 0 || size == 0) {
*blob = data_blob(NULL, 0);
return NT_STATUS_OK;
}
if (smb2_oob(buf, buf->hdr + ofs, size)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
*blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
NT_STATUS_HAVE_NO_MEMORY(blob->data);
return NT_STATUS_OK;
}
/*
pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
the ptr points to the start of the offset/length pair
*/
NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
{
uint32_t ofs, size;
if (smb2_oob(buf, ptr, 8)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
ofs = IVAL(ptr, 0);
size = IVAL(ptr, 4);
if (ofs == 0 || size == 0) {
*blob = data_blob(NULL, 0);
return NT_STATUS_OK;
}
if (smb2_oob(buf, buf->hdr + ofs, size)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
*blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
NT_STATUS_HAVE_NO_MEMORY(blob->data);
return NT_STATUS_OK;
}
/*
pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
the ptr points to the start of the offset/length pair
*/
NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
{
uint32_t ofs, size;
if (smb2_oob(buf, ptr, 8)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
size = IVAL(ptr, 0);
ofs = IVAL(ptr, 4);
if (ofs == 0 || size == 0) {
*blob = data_blob(NULL, 0);
return NT_STATUS_OK;
}
if (smb2_oob(buf, buf->hdr + ofs, size)) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
*blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
NT_STATUS_HAVE_NO_MEMORY(blob->data);
return NT_STATUS_OK;
}
/*
pull a string in a uint16_t ofs/ uint16_t length/blob format
UTF-16 without termination
*/
NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
uint8_t *ptr, const char **str)
{
DATA_BLOB blob;
NTSTATUS status;
ssize_t size;
void *vstr;
status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
NT_STATUS_NOT_OK_RETURN(status);
if (blob.length == 0) {
char *s;
s = talloc_strdup(mem_ctx, "");
NT_STATUS_HAVE_NO_MEMORY(s);
*str = s;
return NT_STATUS_OK;
}
size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
blob.data, blob.length, &vstr);
data_blob_free(&blob);
(*str) = vstr;
if (size == -1) {
return NT_STATUS_ILLEGAL_CHARACTER;
}
return NT_STATUS_OK;
}
/*
push a string in a uint16_t ofs/ uint16_t length/blob format
UTF-16 without termination
*/
NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
uint16_t ofs, const char *str)
{
DATA_BLOB blob;
NTSTATUS status;
ssize_t size;
if (strcmp("", str) == 0) {
return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
}
size = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16,
str, strlen(str), (void **)&blob.data);
if (size == -1) {
return NT_STATUS_ILLEGAL_CHARACTER;
}
blob.length = size;
status = smb2_push_o16s16_blob(buf, ofs, blob);
data_blob_free(&blob);
return status;
}
/*
push a file handle into a buffer
*/
void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
{
SBVAL(data, 0, h->data[0]);
SBVAL(data, 8, h->data[1]);
}
/*
pull a file handle from a buffer
*/
void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
{
h->data[0] = BVAL(ptr, 0);
h->data[1] = BVAL(ptr, 8);
}
+258
View File
@@ -0,0 +1,258 @@
/*
Unix SMB/CIFS implementation.
SMB2 client session handling
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 "libcli/composite/composite.h"
#include "auth/gensec/gensec.h"
/*
initialise a smb2_session structure
*/
struct smb2_session *smb2_session_init(struct smb2_transport *transport,
TALLOC_CTX *parent_ctx, BOOL primary)
{
struct smb2_session *session;
NTSTATUS status;
session = talloc_zero(parent_ctx, struct smb2_session);
if (!session) {
return NULL;
}
if (primary) {
session->transport = talloc_steal(session, transport);
} else {
session->transport = talloc_reference(session, transport);
}
/* prepare a gensec context for later use */
status = gensec_client_start(session, &session->gensec,
session->transport->socket->event.ctx);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(session);
return NULL;
}
gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);
return session;
}
/*
send a session setup request
*/
struct smb2_request *smb2_session_setup_send(struct smb2_session *session,
struct smb2_session_setup *io)
{
struct smb2_request *req;
NTSTATUS status;
req = smb2_request_init(session->transport, SMB2_OP_SESSSETUP,
0x18, True, io->in.secblob.length);
if (req == NULL) return NULL;
SBVAL(req->out.hdr, SMB2_HDR_UID, session->uid);
SSVAL(req->out.body, 0x02, io->in._pad); /* pad */
SIVAL(req->out.body, 0x04, io->in.unknown2);
SIVAL(req->out.body, 0x08, io->in.unknown3);
req->session = session;
status = smb2_push_o16s16_blob(&req->out, 0x0C, io->in.secblob);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(req);
return NULL;
}
SBVAL(req->out.body, 0x10, io->in.unknown4);
smb2_transport_send(req);
return req;
}
/*
recv a session setup reply
*/
NTSTATUS smb2_session_setup_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
struct smb2_session_setup *io)
{
NTSTATUS status;
if (!smb2_request_receive(req) ||
(smb2_request_is_error(req) &&
!NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED))) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x08, True);
io->out._pad = SVAL(req->in.body, 0x02);
io->out.uid = BVAL(req->in.hdr, SMB2_HDR_UID);
status = smb2_pull_o16s16_blob(&req->in, mem_ctx, req->in.body+0x04, &io->out.secblob);
if (!NT_STATUS_IS_OK(status)) {
smb2_request_destroy(req);
return status;
}
return smb2_request_destroy(req);
}
/*
sync session setup request
*/
NTSTATUS smb2_session_setup(struct smb2_session *session,
TALLOC_CTX *mem_ctx, struct smb2_session_setup *io)
{
struct smb2_request *req = smb2_session_setup_send(session, io);
return smb2_session_setup_recv(req, mem_ctx, io);
}
struct smb2_session_state {
struct smb2_session_setup io;
struct smb2_request *req;
NTSTATUS gensec_status;
};
/*
handle continuations of the spnego session setup
*/
static void session_request_handler(struct smb2_request *req)
{
struct composite_context *c = talloc_get_type(req->async.private,
struct composite_context);
struct smb2_session_state *state = talloc_get_type(c->private_data,
struct smb2_session_state);
struct smb2_session *session = req->session;
c->status = smb2_session_setup_recv(req, c, &state->io);
if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
(NT_STATUS_IS_OK(c->status) &&
NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED))) {
NTSTATUS session_key_err;
DATA_BLOB session_key;
c->status = gensec_update(session->gensec, c,
state->io.out.secblob,
&state->io.in.secblob);
state->gensec_status = c->status;
session_key_err = gensec_session_key(session->gensec, &session_key);
if (NT_STATUS_IS_OK(session_key_err)) {
session->session_key = session_key;
}
}
session->uid = state->io.out.uid;
if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
state->req = smb2_session_setup_send(session, &state->io);
if (state->req == NULL) {
composite_error(c, NT_STATUS_NO_MEMORY);
return;
}
state->req->async.fn = session_request_handler;
state->req->async.private = c;
return;
}
if (!NT_STATUS_IS_OK(c->status)) {
composite_error(c, c->status);
return;
}
composite_done(c);
}
/*
a composite function that does a full SPNEGO session setup
*/
struct composite_context *smb2_session_setup_spnego_send(struct smb2_session *session,
struct cli_credentials *credentials)
{
struct composite_context *c;
struct smb2_session_state *state;
c = composite_create(session, session->transport->socket->event.ctx);
if (c == NULL) return NULL;
state = talloc(c, struct smb2_session_state);
if (composite_nomem(state, c)) return c;
c->private_data = state;
ZERO_STRUCT(state->io);
state->io.in._pad = 0x0000;
state->io.in.unknown2 = 0x0000000F;
state->io.in.unknown3 = 0x00000000;
state->io.in.unknown4 = 0; /* uint64_t */
c->status = gensec_set_credentials(session->gensec, credentials);
if (!composite_is_ok(c)) return c;
c->status = gensec_set_target_hostname(session->gensec,
session->transport->socket->hostname);
if (!composite_is_ok(c)) return c;
c->status = gensec_set_target_service(session->gensec, "cifs");
if (!composite_is_ok(c)) return c;
c->status = gensec_start_mech_by_oid(session->gensec, GENSEC_OID_SPNEGO);
if (!composite_is_ok(c)) return c;
c->status = gensec_update(session->gensec, c,
session->transport->negotiate.secblob,
&state->io.in.secblob);
if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
composite_error(c, c->status);
return c;
}
state->gensec_status = c->status;
state->req = smb2_session_setup_send(session, &state->io);
composite_continue_smb2(c, state->req, session_request_handler, c);
return c;
}
/*
receive a composite session setup reply
*/
NTSTATUS smb2_session_setup_spnego_recv(struct composite_context *c)
{
NTSTATUS status;
status = composite_wait(c);
talloc_free(c);
return status;
}
/*
sync version of smb2_session_setup_spnego
*/
NTSTATUS smb2_session_setup_spnego(struct smb2_session *session,
struct cli_credentials *credentials)
{
struct composite_context *c = smb2_session_setup_spnego_send(session, credentials);
return smb2_session_setup_spnego_recv(c);
}
+116
View File
@@ -0,0 +1,116 @@
/*
Unix SMB/CIFS implementation.
SMB2 client setinfo calls
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 setinfo request
*/
struct smb2_request *smb2_setinfo_send(struct smb2_tree *tree, struct smb2_setinfo *io)
{
NTSTATUS status;
struct smb2_request *req;
req = smb2_request_init_tree(tree, SMB2_OP_SETINFO, 0x20, True, io->in.blob.length);
if (req == NULL) return NULL;
SSVAL(req->out.body, 0x02, io->in.level);
status = smb2_push_s32o32_blob(&req->out, 0x04, io->in.blob);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(req);
return NULL;
}
SIVAL(req->out.body, 0x0C, io->in.flags);
smb2_push_handle(req->out.body+0x10, &io->in.file.handle);
smb2_transport_send(req);
return req;
}
/*
recv a setinfo reply
*/
NTSTATUS smb2_setinfo_recv(struct smb2_request *req)
{
if (!smb2_request_receive(req) ||
!smb2_request_is_ok(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x02, False);
return smb2_request_destroy(req);
}
/*
sync setinfo request
*/
NTSTATUS smb2_setinfo(struct smb2_tree *tree, struct smb2_setinfo *io)
{
struct smb2_request *req = smb2_setinfo_send(tree, io);
return smb2_setinfo_recv(req);
}
/*
level specific file setinfo call - async send
*/
struct smb2_request *smb2_setinfo_file_send(struct smb2_tree *tree, union smb_setfileinfo *io)
{
struct smb2_setinfo b;
uint16_t smb2_level = smb2_getinfo_map_level(io->generic.level, SMB2_GETINFO_FILE);
struct smb2_request *req;
if (smb2_level == 0) {
return NULL;
}
ZERO_STRUCT(b);
b.in.level = smb2_level;
b.in.file.handle = io->generic.in.file.handle;
if (!smb_raw_setfileinfo_passthru(tree, io->generic.level, io, &b.in.blob)) {
return NULL;
}
if (io->generic.level == RAW_SFILEINFO_SEC_DESC) {
b.in.flags = io->set_secdesc.in.secinfo_flags;
}
req = smb2_setinfo_send(tree, &b);
data_blob_free(&b.in.blob);
return req;
}
/*
level specific file setinfo call - sync
*/
NTSTATUS smb2_setinfo_file(struct smb2_tree *tree, union smb_setfileinfo *io)
{
struct smb2_request *req = smb2_setinfo_file_send(tree, io);
return smb2_setinfo_recv(req);
}
+215
View File
@@ -0,0 +1,215 @@
/*
Unix SMB/CIFS implementation.
SMB2 client library header
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.
*/
struct smb2_options {
uint32_t timeout;
};
/*
information returned from the negotiate response
*/
struct smb2_negotiate {
DATA_BLOB secblob;
};
/* this is the context for the smb2 transport layer */
struct smb2_transport {
/* socket level info */
struct smbcli_socket *socket;
struct smb2_options options;
struct smb2_negotiate negotiate;
/* next seqnum to allocate */
uint64_t seqnum;
/* a list of requests that are pending for receive on this
connection */
struct smb2_request *pending_recv;
/* context of the stream -> packet parser */
struct packet_context *packet;
/* an idle function - if this is defined then it will be
called once every period microseconds while we are waiting
for a packet */
struct {
void (*func)(struct smb2_transport *, void *);
void *private;
uint_t period;
} idle;
};
/*
SMB2 tree context
*/
struct smb2_tree {
struct smb2_session *session;
uint32_t tid;
};
/*
SMB2 session context
*/
struct smb2_session {
struct smb2_transport *transport;
struct gensec_security *gensec;
uint64_t uid;
DATA_BLOB session_key;
};
struct smb2_request_buffer {
/* the raw SMB2 buffer, including the 4 byte length header */
uint8_t *buffer;
/* the size of the raw buffer, including 4 byte header */
size_t size;
/* how much has been allocated - on reply the buffer is over-allocated to
prevent too many realloc() calls
*/
size_t allocated;
/* the start of the SMB2 header - this is always buffer+4 */
uint8_t *hdr;
/* the packet body */
uint8_t *body;
size_t body_fixed;
size_t body_size;
/* this point to the next dynamic byte that can be used
* this will be moved when some dynamic data is pushed
*/
uint8_t *dynamic;
};
/*
a client request moves between the following 4 states.
*/
enum smb2_request_state {SMB2_REQUEST_INIT, /* we are creating the request */
SMB2_REQUEST_RECV, /* we are waiting for a matching reply */
SMB2_REQUEST_DONE, /* the request is finished */
SMB2_REQUEST_ERROR}; /* a packet or transport level error has occurred */
/* the context for a single SMB2 request */
struct smb2_request {
/* allow a request to be part of a list of requests */
struct smb2_request *next, *prev;
/* each request is in one of 3 possible states */
enum smb2_request_state state;
struct smb2_transport *transport;
struct smb2_session *session;
struct smb2_tree *tree;
uint64_t seqnum;
struct {
BOOL do_cancel;
BOOL can_cancel;
uint32_t pending_id;
} cancel;
/* the NT status for this request. Set by packet receive code
or code detecting error. */
NTSTATUS status;
struct smb2_request_buffer in;
struct smb2_request_buffer out;
/* information on what to do with a reply when it is received
asyncronously. If this is not setup when a reply is received then
the reply is discarded
The private pointer is private to the caller of the client
library (the application), not private to the library
*/
struct {
void (*fn)(struct smb2_request *);
void *private;
} async;
};
#define SMB2_MIN_SIZE 0x42
/* offsets into header elements */
#define SMB2_HDR_LENGTH 0x04
#define SMB2_HDR_PAD1 0x06
#define SMB2_HDR_STATUS 0x08
#define SMB2_HDR_OPCODE 0x0c
#define SMB2_HDR_UNKNOWN1 0x0e
#define SMB2_HDR_FLAGS 0x10
#define SMB2_HDR_UNKNOWN2 0x14
#define SMB2_HDR_SEQNUM 0x18
#define SMB2_HDR_PID 0x20
#define SMB2_HDR_TID 0x24
#define SMB2_HDR_UID 0x28 /* 64 bit */
#define SMB2_HDR_SIG 0x30 /* guess ... */
#define SMB2_HDR_BODY 0x40
/* SMB2 opcodes */
#define SMB2_OP_NEGPROT 0x00
#define SMB2_OP_SESSSETUP 0x01
#define SMB2_OP_LOGOFF 0x02
#define SMB2_OP_TCON 0x03
#define SMB2_OP_TDIS 0x04
#define SMB2_OP_CREATE 0x05
#define SMB2_OP_CLOSE 0x06
#define SMB2_OP_FLUSH 0x07
#define SMB2_OP_READ 0x08
#define SMB2_OP_WRITE 0x09
#define SMB2_OP_LOCK 0x0a
#define SMB2_OP_IOCTL 0x0b
#define SMB2_OP_CANCEL 0x0c
#define SMB2_OP_KEEPALIVE 0x0d
#define SMB2_OP_FIND 0x0e
#define SMB2_OP_NOTIFY 0x0f
#define SMB2_OP_GETINFO 0x10
#define SMB2_OP_SETINFO 0x11
#define SMB2_OP_BREAK 0x12
#define SMB2_MAGIC 0x424D53FE /* 0xFE 'S' 'M' 'B' */
/*
check that a body has the expected size
*/
#define SMB2_CHECK_PACKET_RECV(req, size, dynamic) do { \
size_t is_size = req->in.body_size; \
uint16_t field_size = SVAL(req->in.body, 0); \
uint16_t want_size = ((dynamic)?(size)+1:(size)); \
if (is_size < (size)) { \
DEBUG(0,("%s: buffer too small 0x%x. Expected 0x%x\n", \
__location__, (unsigned)is_size, (unsigned)want_size)); \
return NT_STATUS_BUFFER_TOO_SMALL; \
}\
if (field_size != want_size) { \
DEBUG(0,("%s: unexpected fixed body size 0x%x. Expected 0x%x\n", \
__location__, (unsigned)field_size, (unsigned)want_size)); \
return NT_STATUS_INVALID_PARAMETER; \
} \
} while (0)
+99
View File
@@ -0,0 +1,99 @@
/*
Unix SMB/CIFS implementation.
SMB2 client calls
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 "libcli/raw/interfaces.h"
struct smb2_negprot {
struct {
/* static body buffer 38 (0x26) bytes */
/* uint16_t buffer_code; 0x24 (why?) */
uint16_t unknown1; /* 0x0001 */
uint8_t unknown2[32]; /* all zero */
uint16_t unknown3; /* 0x00000 */
} in;
struct {
/* static body buffer 64 (0x40) bytes */
/* uint16_t buffer_code; 0x41 = 0x40 + 1 */
uint16_t _pad;
uint32_t unknown2; /* 0x06 */
uint8_t sessid[16];
uint32_t unknown3; /* 0x0d */
uint16_t unknown4; /* 0x00 */
uint32_t unknown5; /* 0x01 */
uint32_t unknown6; /* 0x01 */
uint16_t unknown7; /* 0x01 */
NTTIME current_time;
NTTIME boot_time;
/* uint16_t secblob_ofs */
/* uint16_t secblob_size */
uint32_t unknown9; /* 0x204d4c20 */
/* dynamic body buffer */
DATA_BLOB secblob;
} out;
};
/* getinfo classes */
#define SMB2_GETINFO_FILE 0x01
#define SMB2_GETINFO_FS 0x02
#define SMB2_GETINFO_SECURITY 0x03
/* NOTE! the getinfo fs and file levels exactly match up with the
'passthru' SMB levels, which are levels >= 1000. The SMB2 client
lib uses the names from the libcli/raw/ library */
struct smb2_getinfo {
struct {
/* static body buffer 40 (0x28) bytes */
/* uint16_t buffer_code; 0x29 = 0x28 + 1 (why???) */
uint16_t level;
uint32_t max_response_size;
uint32_t unknown1;
uint32_t unknown2;
uint32_t flags; /* level specific */
uint32_t flags2; /* used by all_eas level */
union smb_handle file;
} in;
struct {
/* static body buffer 8 (0x08) bytes */
/* uint16_t buffer_code; 0x09 = 0x08 + 1 */
/* uint16_t blob_ofs; */
/* uint16_t blob_size; */
/* dynamic body */
DATA_BLOB blob;
} out;
};
struct smb2_setinfo {
struct {
uint16_t level;
uint32_t flags;
union smb_handle file;
DATA_BLOB blob;
} in;
};
struct cli_credentials;
struct event_context;
#include "libcli/smb2/smb2_proto.h"
+104
View File
@@ -0,0 +1,104 @@
/*
Unix SMB/CIFS implementation.
SMB2 client tree handling
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"
/*
initialise a smb2_session structure
*/
struct smb2_tree *smb2_tree_init(struct smb2_session *session,
TALLOC_CTX *parent_ctx, BOOL primary)
{
struct smb2_tree *tree;
tree = talloc_zero(parent_ctx, struct smb2_tree);
if (!session) {
return NULL;
}
if (primary) {
tree->session = talloc_steal(tree, session);
} else {
tree->session = talloc_reference(tree, session);
}
return tree;
}
/*
send a tree connect
*/
struct smb2_request *smb2_tree_connect_send(struct smb2_tree *tree,
struct smb2_tree_connect *io)
{
struct smb2_request *req;
NTSTATUS status;
req = smb2_request_init(tree->session->transport, SMB2_OP_TCON,
0x08, True, 0);
if (req == NULL) return NULL;
SBVAL(req->out.hdr, SMB2_HDR_UID, tree->session->uid);
SSVAL(req->out.body, 0x02, io->in.unknown1);
status = smb2_push_o16s16_string(&req->out, 0x04, io->in.path);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(req);
return NULL;
}
smb2_transport_send(req);
return req;
}
/*
recv a tree connect reply
*/
NTSTATUS smb2_tree_connect_recv(struct smb2_request *req, struct smb2_tree_connect *io)
{
if (!smb2_request_receive(req) ||
smb2_request_is_error(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x10, False);
io->out.tid = IVAL(req->in.hdr, SMB2_HDR_TID);
io->out.unknown1 = SVAL(req->in.body, 0x02);
io->out.unknown2 = IVAL(req->in.body, 0x04);
io->out.unknown3 = IVAL(req->in.body, 0x08);
io->out.access_mask = IVAL(req->in.body, 0x0C);
return smb2_request_destroy(req);
}
/*
sync tree connect request
*/
NTSTATUS smb2_tree_connect(struct smb2_tree *tree, struct smb2_tree_connect *io)
{
struct smb2_request *req = smb2_tree_connect_send(tree, io);
return smb2_tree_connect_recv(req, io);
}
+66
View File
@@ -0,0 +1,66 @@
/*
Unix SMB/CIFS implementation.
SMB2 client tdis handling
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"
/*
send a tdis request
*/
struct smb2_request *smb2_tdis_send(struct smb2_tree *tree)
{
struct smb2_request *req;
req = smb2_request_init_tree(tree, SMB2_OP_TDIS, 0x04, False, 0);
if (req == NULL) return NULL;
SSVAL(req->out.body, 0x02, 0);
smb2_transport_send(req);
return req;
}
/*
recv a tdis reply
*/
NTSTATUS smb2_tdis_recv(struct smb2_request *req)
{
if (!smb2_request_receive(req) ||
!smb2_request_is_ok(req)) {
return smb2_request_destroy(req);
}
SMB2_CHECK_PACKET_RECV(req, 0x04, False);
return smb2_request_destroy(req);
}
/*
sync tdis request
*/
NTSTATUS smb2_tdis(struct smb2_tree *tree)
{
struct smb2_request *req = smb2_tdis_send(tree);
return smb2_tdis_recv(req);
}
+353
View File
@@ -0,0 +1,353 @@
/*
Unix SMB/CIFS implementation.
SMB2 client transport context management functions
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/socket/socket.h"
#include "lib/events/events.h"
#include "lib/stream/packet.h"
#include "lib/util/dlinklist.h"
/*
an event has happened on the socket
*/
static void smb2_transport_event_handler(struct event_context *ev,
struct fd_event *fde,
uint16_t flags, void *private)
{
struct smb2_transport *transport = talloc_get_type(private,
struct smb2_transport);
if (flags & EVENT_FD_READ) {
packet_recv(transport->packet);
return;
}
if (flags & EVENT_FD_WRITE) {
packet_queue_run(transport->packet);
}
}
/*
destroy a transport
*/
static int transport_destructor(struct smb2_transport *transport)
{
smb2_transport_dead(transport, NT_STATUS_LOCAL_DISCONNECT);
return 0;
}
/*
handle receive errors
*/
static void smb2_transport_error(void *private, NTSTATUS status)
{
struct smb2_transport *transport = talloc_get_type(private,
struct smb2_transport);
smb2_transport_dead(transport, status);
}
static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob);
/*
create a transport structure based on an established socket
*/
struct smb2_transport *smb2_transport_init(struct smbcli_socket *sock,
TALLOC_CTX *parent_ctx)
{
struct smb2_transport *transport;
transport = talloc_zero(parent_ctx, struct smb2_transport);
if (!transport) return NULL;
transport->socket = talloc_steal(transport, sock);
/* setup the stream -> packet parser */
transport->packet = packet_init(transport);
if (transport->packet == NULL) {
talloc_free(transport);
return NULL;
}
packet_set_private(transport->packet, transport);
packet_set_socket(transport->packet, transport->socket->sock);
packet_set_callback(transport->packet, smb2_transport_finish_recv);
packet_set_full_request(transport->packet, packet_full_request_nbt);
packet_set_error_handler(transport->packet, smb2_transport_error);
packet_set_event_context(transport->packet, transport->socket->event.ctx);
packet_set_nofree(transport->packet);
/* take over event handling from the socket layer - it only
handles events up until we are connected */
talloc_free(transport->socket->event.fde);
transport->socket->event.fde = event_add_fd(transport->socket->event.ctx,
transport->socket,
socket_get_fd(transport->socket->sock),
EVENT_FD_READ,
smb2_transport_event_handler,
transport);
packet_set_fde(transport->packet, transport->socket->event.fde);
packet_set_serialise(transport->packet);
talloc_set_destructor(transport, transport_destructor);
transport->options.timeout = 30;
return transport;
}
/*
mark the transport as dead
*/
void smb2_transport_dead(struct smb2_transport *transport, NTSTATUS status)
{
smbcli_sock_dead(transport->socket);
if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
}
/* kill all pending receives */
while (transport->pending_recv) {
struct smb2_request *req = transport->pending_recv;
req->state = SMB2_REQUEST_ERROR;
req->status = status;
DLIST_REMOVE(transport->pending_recv, req);
if (req->async.fn) {
req->async.fn(req);
}
}
}
/*
we have a full request in our receive buffer - match it to a pending request
and process
*/
static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob)
{
struct smb2_transport *transport = talloc_get_type(private,
struct smb2_transport);
uint8_t *buffer, *hdr;
int len;
struct smb2_request *req = NULL;
uint64_t seqnum;
uint32_t flags;
uint16_t buffer_code;
uint32_t dynamic_size;
uint32_t i;
buffer = blob.data;
len = blob.length;
hdr = buffer+NBT_HDR_SIZE;
if (len < SMB2_MIN_SIZE) {
DEBUG(1,("Discarding smb2 reply of size %d\n", len));
goto error;
}
flags = IVAL(hdr, SMB2_HDR_FLAGS);
seqnum = BVAL(hdr, SMB2_HDR_SEQNUM);
/* match the incoming request against the list of pending requests */
for (req=transport->pending_recv; req; req=req->next) {
if (req->seqnum == seqnum) break;
}
if (!req) {
DEBUG(1,("Discarding unmatched reply with seqnum 0x%llx op %d\n",
(long long)seqnum, SVAL(hdr, SMB2_HDR_OPCODE)));
goto error;
}
/* fill in the 'in' portion of the matching request */
req->in.buffer = buffer;
talloc_steal(req, buffer);
req->in.size = len;
req->in.allocated = req->in.size;
req->in.hdr = hdr;
req->in.body = hdr+SMB2_HDR_BODY;
req->in.body_size = req->in.size - (SMB2_HDR_BODY+NBT_HDR_SIZE);
req->status = NT_STATUS(IVAL(hdr, SMB2_HDR_STATUS));
if (NT_STATUS_EQUAL(req->status, STATUS_PENDING)) {
if (flags & 0x00000002) {
req->cancel.can_cancel = True;
req->cancel.pending_id = IVAL(hdr, SMB2_HDR_PID);
for (i=0; i< req->cancel.do_cancel; i++) {
smb2_cancel(req);
}
}
talloc_free(buffer);
return NT_STATUS_OK;
}
buffer_code = SVAL(req->in.body, 0);
req->in.body_fixed = (buffer_code & ~1);
req->in.dynamic = NULL;
dynamic_size = req->in.body_size - req->in.body_fixed;
if (dynamic_size != 0 && (buffer_code & 1)) {
req->in.dynamic = req->in.body + req->in.body_fixed;
if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
DEBUG(1,("SMB2 request invalid dynamic size 0x%x\n",
dynamic_size));
goto error;
}
}
DEBUG(2, ("SMB2 RECV seqnum=0x%llx\n", (long long)req->seqnum));
dump_data(5, req->in.body, req->in.body_size);
/* if this request has an async handler then call that to
notify that the reply has been received. This might destroy
the request so it must happen last */
DLIST_REMOVE(transport->pending_recv, req);
req->state = SMB2_REQUEST_DONE;
if (req->async.fn) {
req->async.fn(req);
}
return NT_STATUS_OK;
error:
dump_data(5, buffer, len);
if (req) {
DLIST_REMOVE(transport->pending_recv, req);
req->state = SMB2_REQUEST_ERROR;
if (req->async.fn) {
req->async.fn(req);
}
} else {
talloc_free(buffer);
}
return NT_STATUS_UNSUCCESSFUL;
}
/*
handle timeouts of individual smb requests
*/
static void smb2_timeout_handler(struct event_context *ev, struct timed_event *te,
struct timeval t, void *private)
{
struct smb2_request *req = talloc_get_type(private, struct smb2_request);
if (req->state == SMB2_REQUEST_RECV) {
DLIST_REMOVE(req->transport->pending_recv, req);
}
req->status = NT_STATUS_IO_TIMEOUT;
req->state = SMB2_REQUEST_ERROR;
if (req->async.fn) {
req->async.fn(req);
}
}
/*
destroy a request
*/
static int smb2_request_destructor(struct smb2_request *req)
{
if (req->state == SMB2_REQUEST_RECV) {
DLIST_REMOVE(req->transport->pending_recv, req);
}
return 0;
}
/*
put a request into the send queue
*/
void smb2_transport_send(struct smb2_request *req)
{
DATA_BLOB blob;
NTSTATUS status;
_smb2_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
DEBUG(2, ("SMB2 send seqnum=0x%llx\n", (long long)req->seqnum));
dump_data(5, req->out.body, req->out.body_size);
/* check if the transport is dead */
if (req->transport->socket->sock == NULL) {
req->state = SMB2_REQUEST_ERROR;
req->status = NT_STATUS_NET_WRITE_FAULT;
return;
}
blob = data_blob_const(req->out.buffer, req->out.size);
status = packet_send(req->transport->packet, blob);
if (!NT_STATUS_IS_OK(status)) {
req->state = SMB2_REQUEST_ERROR;
req->status = status;
return;
}
req->state = SMB2_REQUEST_RECV;
DLIST_ADD(req->transport->pending_recv, req);
/* add a timeout */
if (req->transport->options.timeout) {
event_add_timed(req->transport->socket->event.ctx, req,
timeval_current_ofs(req->transport->options.timeout, 0),
smb2_timeout_handler, req);
}
talloc_set_destructor(req, smb2_request_destructor);
}
static void idle_handler(struct event_context *ev,
struct timed_event *te, struct timeval t, void *private)
{
struct smb2_transport *transport = talloc_get_type(private,
struct smb2_transport);
struct timeval next = timeval_add(&t, 0, transport->idle.period);
transport->socket->event.te = event_add_timed(transport->socket->event.ctx,
transport,
next,
idle_handler, transport);
transport->idle.func(transport, transport->idle.private);
}
/*
setup the idle handler for a transport
the period is in microseconds
*/
void smb2_transport_idle_handler(struct smb2_transport *transport,
void (*idle_func)(struct smb2_transport *, void *),
uint64_t period,
void *private)
{
transport->idle.func = idle_func;
transport->idle.private = private;
transport->idle.period = period;
if (transport->socket->event.te != NULL) {
talloc_free(transport->socket->event.te);
}
transport->socket->event.te = event_add_timed(transport->socket->event.ctx,
transport,
timeval_current_ofs(0, period),
idle_handler, transport);
}
+82
View File
@@ -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/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)
{
NTSTATUS status;
struct smb2_request *req;
req = smb2_request_init_tree(tree, SMB2_OP_WRITE, 0x30, True, io->in.data.length);
if (req == NULL) return NULL;
status = smb2_push_o16s32_blob(&req->out, 0x02, io->in.data);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(req);
return NULL;
}
SBVAL(req->out.body, 0x08, io->in.offset);
smb2_push_handle(req->out.body+0x10, &io->in.file.handle);
SBVAL(req->out.body, 0x20, io->in.unknown1);
SBVAL(req->out.body, 0x28, io->in.unknown2);
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);
}
SMB2_CHECK_PACKET_RECV(req, 0x10, True);
io->out._pad = SVAL(req->in.body, 0x02);
io->out.nwritten = IVAL(req->in.body, 0x04);
io->out.unknown1 = BVAL(req->in.body, 0x08);
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);
}