mirror of
https://github.com/samba-team/samba.git
synced 2025-02-23 09:57:40 +03:00
s4:libcli/raw: implement on top of smbXcli_conn/req
metze Autobuild-User: Stefan Metzmacher <metze@samba.org> Autobuild-Date: Wed Nov 30 15:13:36 CET 2011 on sn-devel-104
This commit is contained in:
parent
99ef6a4bec
commit
4afbda221c
@ -39,9 +39,10 @@ bool smbcli_socket_connect(struct smbcli_state *cli, const char *server,
|
||||
struct nbt_name *calling,
|
||||
struct nbt_name *called)
|
||||
{
|
||||
struct smbcli_socket *sock = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
cli->options = *options;
|
||||
|
||||
status = smbcli_sock_connect(cli,
|
||||
NULL, /* host_addr */
|
||||
ports,
|
||||
@ -51,22 +52,30 @@ bool smbcli_socket_connect(struct smbcli_state *cli, const char *server,
|
||||
socket_options,
|
||||
calling,
|
||||
called,
|
||||
&sock);
|
||||
&cli->sock);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cli->transport = smbcli_transport_init(sock, cli, true, options);
|
||||
if (!cli->transport) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* wrapper around smb_raw_negotiate() */
|
||||
NTSTATUS smbcli_negprot(struct smbcli_state *cli, bool unicode, int maxprotocol)
|
||||
{
|
||||
if (unicode) {
|
||||
cli->options.unicode = 1;
|
||||
} else {
|
||||
cli->options.unicode = 0;
|
||||
}
|
||||
|
||||
cli->transport = smbcli_transport_init(cli->sock, cli,
|
||||
true, &cli->options);
|
||||
cli->sock = NULL;
|
||||
if (!cli->transport) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
return smb_raw_negotiate(cli->transport, unicode, maxprotocol);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#define __LIBCLI_H__
|
||||
|
||||
#include "librpc/gen_ndr/nbt.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
|
||||
struct substitute_context;
|
||||
|
||||
@ -30,6 +31,8 @@ struct substitute_context;
|
||||
i.e. a single session on a single socket.
|
||||
*/
|
||||
struct smbcli_state {
|
||||
struct smbcli_options options;
|
||||
struct smbcli_socket *sock; /* NULL if connected */
|
||||
struct smbcli_transport *transport;
|
||||
struct smbcli_session *session;
|
||||
struct smbcli_tree *tree;
|
||||
|
@ -40,11 +40,12 @@ _PUBLIC_ bool smbcli_oplock_ack(struct smbcli_tree *tree, uint16_t fnum, uint16_
|
||||
SSVAL(req->out.vwv,VWV(6),0);
|
||||
SSVAL(req->out.vwv,VWV(7),0);
|
||||
|
||||
/* this request does not expect a reply, so tell the signing
|
||||
subsystem not to allocate an id for a reply */
|
||||
req->one_way_request = 1;
|
||||
|
||||
ret = smbcli_request_send(req);
|
||||
/*
|
||||
* The low level code knows it is a
|
||||
* one way request by looking at SMBlockingX,
|
||||
* wct == 8 and LOCKING_ANDX_OPLOCK_RELEASE
|
||||
*/
|
||||
ret = smbcli_request_send(req);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/raw/raw_proto.h"
|
||||
#include "system/filesys.h"
|
||||
#include "../libcli/smb/smbXcli_base.h"
|
||||
|
||||
#define SETUP_REQUEST_SESSION(cmd, wct, buflen) do { \
|
||||
req = smbcli_request_setup_session(session, cmd, wct, buflen); \
|
||||
@ -68,7 +69,7 @@ struct smbcli_session *smbcli_session_init(struct smbcli_transport *transport,
|
||||
if (capabilities & CAP_EXTENDED_SECURITY) {
|
||||
flags2 |= FLAGS2_EXTENDED_SECURITY;
|
||||
}
|
||||
if (session->transport->negotiate.sign_info.doing_signing) {
|
||||
if (smb1cli_conn_signing_is_active(session->transport->conn)) {
|
||||
flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
|
||||
}
|
||||
|
||||
|
@ -432,16 +432,3 @@ NTSTATUS smbcli_sock_connect(TALLOC_CTX *mem_ctx,
|
||||
calling, called);
|
||||
return smbcli_sock_connect_recv(c, mem_ctx, result);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
mark the socket as dead
|
||||
****************************************************************************/
|
||||
_PUBLIC_ void smbcli_sock_dead(struct smbcli_socket *sock)
|
||||
{
|
||||
talloc_free(sock->event.fde);
|
||||
sock->event.fde = NULL;
|
||||
talloc_free(sock->sock);
|
||||
sock->sock = NULL;
|
||||
}
|
||||
|
||||
|
@ -20,33 +20,17 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/network.h"
|
||||
#include "../lib/async_req/async_sock.h"
|
||||
#include "../lib/util/tevent_ntstatus.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/raw/raw_proto.h"
|
||||
#include "lib/socket/socket.h"
|
||||
#include "../lib/util/dlinklist.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "lib/stream/packet.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
#include "../libcli/nbt/libnbt.h"
|
||||
|
||||
|
||||
/*
|
||||
an event has happened on the socket
|
||||
*/
|
||||
static void smbcli_transport_event_handler(struct tevent_context *ev,
|
||||
struct tevent_fd *fde,
|
||||
uint16_t flags, void *private_data)
|
||||
{
|
||||
struct smbcli_transport *transport = talloc_get_type(private_data,
|
||||
struct smbcli_transport);
|
||||
if (flags & TEVENT_FD_READ) {
|
||||
packet_recv(transport->packet);
|
||||
return;
|
||||
}
|
||||
if (flags & TEVENT_FD_WRITE) {
|
||||
packet_queue_run(transport->packet);
|
||||
}
|
||||
}
|
||||
#include "../libcli/smb/smbXcli_base.h"
|
||||
#include "../libcli/smb/read_smb.h"
|
||||
|
||||
/*
|
||||
destroy a transport
|
||||
@ -57,18 +41,6 @@ static int transport_destructor(struct smbcli_transport *transport)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handle receive errors
|
||||
*/
|
||||
static void smbcli_transport_error(void *private_data, NTSTATUS status)
|
||||
{
|
||||
struct smbcli_transport *transport = talloc_get_type(private_data, struct smbcli_transport);
|
||||
smbcli_transport_dead(transport, status);
|
||||
}
|
||||
|
||||
static NTSTATUS smbcli_transport_finish_recv(void *private_data, DATA_BLOB blob);
|
||||
|
||||
/*
|
||||
create a transport structure based on an established socket
|
||||
*/
|
||||
@ -78,51 +50,55 @@ struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock,
|
||||
struct smbcli_options *options)
|
||||
{
|
||||
struct smbcli_transport *transport;
|
||||
uint32_t smb1_capabilities;
|
||||
|
||||
transport = talloc_zero(parent_ctx, struct smbcli_transport);
|
||||
if (!transport) return NULL;
|
||||
|
||||
if (primary) {
|
||||
transport->socket = talloc_steal(transport, sock);
|
||||
} else {
|
||||
transport->socket = talloc_reference(transport, sock);
|
||||
}
|
||||
transport->negotiate.protocol = PROTOCOL_NT1;
|
||||
transport->ev = sock->event.ctx;
|
||||
transport->options = *options;
|
||||
transport->negotiate.max_xmit = transport->options.max_xmit;
|
||||
|
||||
/* setup the stream -> packet parser */
|
||||
transport->packet = packet_init(transport);
|
||||
if (transport->packet == NULL) {
|
||||
talloc_free(transport);
|
||||
TALLOC_FREE(sock->event.fde);
|
||||
TALLOC_FREE(sock->event.te);
|
||||
|
||||
smb1_capabilities = 0;
|
||||
smb1_capabilities |= CAP_LARGE_FILES;
|
||||
smb1_capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS;
|
||||
smb1_capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND;
|
||||
smb1_capabilities |= CAP_DFS | CAP_W2K_SMBS;
|
||||
smb1_capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX;
|
||||
smb1_capabilities |= CAP_LWIO;
|
||||
|
||||
if (options->ntstatus_support) {
|
||||
smb1_capabilities |= CAP_STATUS32;
|
||||
}
|
||||
|
||||
if (options->unicode) {
|
||||
smb1_capabilities |= CAP_UNICODE;
|
||||
}
|
||||
|
||||
if (options->use_spnego) {
|
||||
smb1_capabilities |= CAP_EXTENDED_SECURITY;
|
||||
}
|
||||
|
||||
if (options->use_level2_oplocks) {
|
||||
smb1_capabilities |= CAP_LEVEL_II_OPLOCKS;
|
||||
}
|
||||
|
||||
transport->conn = smbXcli_conn_create(transport,
|
||||
sock->sock->fd,
|
||||
sock->hostname,
|
||||
options->signing,
|
||||
smb1_capabilities,
|
||||
NULL); /* client_guid */
|
||||
if (transport->conn == NULL) {
|
||||
TALLOC_FREE(sock);
|
||||
TALLOC_FREE(transport);
|
||||
return NULL;
|
||||
}
|
||||
packet_set_private(transport->packet, transport);
|
||||
packet_set_socket(transport->packet, transport->socket->sock);
|
||||
packet_set_callback(transport->packet, smbcli_transport_finish_recv);
|
||||
packet_set_full_request(transport->packet, packet_full_request_nbt);
|
||||
packet_set_error_handler(transport->packet, smbcli_transport_error);
|
||||
packet_set_event_context(transport->packet, transport->socket->event.ctx);
|
||||
packet_set_nofree(transport->packet);
|
||||
packet_set_initial_read(transport->packet, 4);
|
||||
sock->sock->fd = -1;
|
||||
TALLOC_FREE(sock);
|
||||
|
||||
smbcli_init_signing(transport);
|
||||
|
||||
ZERO_STRUCT(transport->called);
|
||||
|
||||
/* 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 = tevent_add_fd(transport->socket->event.ctx,
|
||||
transport->socket->sock,
|
||||
socket_get_fd(transport->socket->sock),
|
||||
TEVENT_FD_READ,
|
||||
smbcli_transport_event_handler,
|
||||
transport);
|
||||
|
||||
packet_set_fde(transport->packet, transport->socket->event.fde);
|
||||
packet_set_serialise(transport->packet);
|
||||
talloc_set_destructor(transport, transport_destructor);
|
||||
|
||||
return transport;
|
||||
@ -133,54 +109,14 @@ struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock,
|
||||
*/
|
||||
void smbcli_transport_dead(struct smbcli_transport *transport, NTSTATUS status)
|
||||
{
|
||||
smbcli_sock_dead(transport->socket);
|
||||
|
||||
if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
|
||||
status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
|
||||
}
|
||||
|
||||
/* kill only the first pending receive - this is so that if
|
||||
that async function frees the connection we don't die trying
|
||||
to use old memory. The caller has to cope with only one
|
||||
network error */
|
||||
if (transport->pending_recv) {
|
||||
struct smbcli_request *req = transport->pending_recv;
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
req->status = status;
|
||||
DLIST_REMOVE(transport->pending_recv, req);
|
||||
if (req->async.fn) {
|
||||
req->async.fn(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
get next mid in sequence
|
||||
****************************************************************************/
|
||||
uint16_t smbcli_transport_next_mid(struct smbcli_transport *transport)
|
||||
{
|
||||
uint16_t mid;
|
||||
struct smbcli_request *req;
|
||||
|
||||
mid = transport->next_mid;
|
||||
|
||||
again:
|
||||
/* now check to see if this mid is being used by one of the
|
||||
pending requests. This is quite efficient because the list is
|
||||
usually very short */
|
||||
|
||||
/* the zero mid is reserved for requests that don't have a mid */
|
||||
if (mid == 0) mid = 1;
|
||||
|
||||
for (req=transport->pending_recv; req; req=req->next) {
|
||||
if (req->mid == mid) {
|
||||
mid++;
|
||||
goto again;
|
||||
}
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
status = NT_STATUS_LOCAL_DISCONNECT;
|
||||
}
|
||||
|
||||
transport->next_mid = mid+1;
|
||||
return mid;
|
||||
smbXcli_conn_disconnect(transport->conn, status);
|
||||
}
|
||||
|
||||
static void idle_handler(struct tevent_context *ev,
|
||||
@ -188,12 +124,17 @@ static void idle_handler(struct tevent_context *ev,
|
||||
{
|
||||
struct smbcli_transport *transport = talloc_get_type(private_data,
|
||||
struct smbcli_transport);
|
||||
struct timeval next = timeval_add(&t, 0, transport->idle.period);
|
||||
transport->socket->event.te = tevent_add_timer(transport->socket->event.ctx,
|
||||
transport,
|
||||
next,
|
||||
idle_handler, transport);
|
||||
struct timeval next;
|
||||
|
||||
transport->idle.func(transport, transport->idle.private_data);
|
||||
|
||||
next = timeval_current_ofs_usec(transport->idle.period);
|
||||
|
||||
transport->idle.te = tevent_add_timer(transport->ev,
|
||||
transport,
|
||||
next,
|
||||
idle_handler,
|
||||
transport);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -205,189 +146,17 @@ _PUBLIC_ void smbcli_transport_idle_handler(struct smbcli_transport *transport,
|
||||
uint64_t period,
|
||||
void *private_data)
|
||||
{
|
||||
TALLOC_FREE(transport->idle.te);
|
||||
|
||||
transport->idle.func = idle_func;
|
||||
transport->idle.private_data = private_data;
|
||||
transport->idle.period = period;
|
||||
|
||||
if (transport->socket->event.te != NULL) {
|
||||
talloc_free(transport->socket->event.te);
|
||||
}
|
||||
|
||||
transport->socket->event.te = tevent_add_timer(transport->socket->event.ctx,
|
||||
transport,
|
||||
timeval_current_ofs_usec(period),
|
||||
idle_handler, transport);
|
||||
}
|
||||
|
||||
/*
|
||||
we have a full request in our receive buffer - match it to a pending request
|
||||
and process
|
||||
*/
|
||||
static NTSTATUS smbcli_transport_finish_recv(void *private_data, DATA_BLOB blob)
|
||||
{
|
||||
struct smbcli_transport *transport = talloc_get_type(private_data,
|
||||
struct smbcli_transport);
|
||||
uint8_t *buffer, *hdr, *vwv;
|
||||
int len;
|
||||
uint16_t wct=0, mid = 0, op = 0;
|
||||
struct smbcli_request *req = NULL;
|
||||
|
||||
buffer = blob.data;
|
||||
len = blob.length;
|
||||
|
||||
hdr = buffer+NBT_HDR_SIZE;
|
||||
vwv = hdr + HDR_VWV;
|
||||
|
||||
/* see if it could be an oplock break request */
|
||||
if (smbcli_handle_oplock_break(transport, len, hdr, vwv)) {
|
||||
talloc_free(buffer);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/* at this point we need to check for a readbraw reply, as
|
||||
these can be any length */
|
||||
if (transport->readbraw_pending) {
|
||||
transport->readbraw_pending = 0;
|
||||
|
||||
/* it must match the first entry in the pending queue
|
||||
as the client is not allowed to have outstanding
|
||||
readbraw requests */
|
||||
req = transport->pending_recv;
|
||||
if (!req) goto error;
|
||||
|
||||
req->in.buffer = buffer;
|
||||
talloc_steal(req, buffer);
|
||||
req->in.size = len;
|
||||
req->in.allocated = req->in.size;
|
||||
goto async;
|
||||
}
|
||||
|
||||
if (len >= MIN_SMB_SIZE) {
|
||||
/* extract the mid for matching to pending requests */
|
||||
mid = SVAL(hdr, HDR_MID);
|
||||
wct = CVAL(hdr, HDR_WCT);
|
||||
op = CVAL(hdr, HDR_COM);
|
||||
}
|
||||
|
||||
/* match the incoming request against the list of pending requests */
|
||||
for (req=transport->pending_recv; req; req=req->next) {
|
||||
if (req->mid == mid) break;
|
||||
}
|
||||
|
||||
/* see if it's a ntcancel reply for the current MID */
|
||||
req = smbcli_handle_ntcancel_reply(req, len, hdr);
|
||||
|
||||
if (!req) {
|
||||
DEBUG(1,("Discarding unmatched reply with mid %d op %d\n", mid, op));
|
||||
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;
|
||||
|
||||
/* handle NBT session replies */
|
||||
if (req->in.size >= 4 && req->in.buffer[0] != 0) {
|
||||
req->status = NT_STATUS_OK;
|
||||
goto async;
|
||||
}
|
||||
|
||||
/* handle non-SMB replies */
|
||||
if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE) {
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
|
||||
DEBUG(2,("bad reply size for mid %d\n", mid));
|
||||
req->status = NT_STATUS_UNSUCCESSFUL;
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
req->in.hdr = hdr;
|
||||
req->in.vwv = vwv;
|
||||
req->in.wct = wct;
|
||||
if (req->in.size >= NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
|
||||
req->in.data = req->in.vwv + VWV(wct) + 2;
|
||||
req->in.data_size = SVAL(req->in.vwv, VWV(wct));
|
||||
if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + req->in.data_size) {
|
||||
DEBUG(3,("bad data size for mid %d\n", mid));
|
||||
/* blergh - w2k3 gives a bogus data size values in some
|
||||
openX replies */
|
||||
req->in.data_size = req->in.size - (NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct));
|
||||
}
|
||||
}
|
||||
req->in.ptr = req->in.data;
|
||||
req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
|
||||
|
||||
smb_setup_bufinfo(req);
|
||||
|
||||
if (!(req->flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
|
||||
int eclass = CVAL(req->in.hdr,HDR_RCLS);
|
||||
int code = SVAL(req->in.hdr,HDR_ERR);
|
||||
if (eclass == 0 && code == 0) {
|
||||
transport->error.e.nt_status = NT_STATUS_OK;
|
||||
} else {
|
||||
transport->error.e.nt_status = NT_STATUS_DOS(eclass, code);
|
||||
}
|
||||
} else {
|
||||
transport->error.e.nt_status = NT_STATUS(IVAL(req->in.hdr, HDR_RCLS));
|
||||
}
|
||||
|
||||
req->status = transport->error.e.nt_status;
|
||||
if (NT_STATUS_IS_OK(req->status)) {
|
||||
transport->error.etype = ETYPE_NONE;
|
||||
} else {
|
||||
transport->error.etype = ETYPE_SMB;
|
||||
}
|
||||
|
||||
if (!smbcli_request_check_sign_mac(req)) {
|
||||
transport->error.etype = ETYPE_SOCKET;
|
||||
transport->error.e.socket_error = SOCKET_READ_BAD_SIG;
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
req->status = NT_STATUS_ACCESS_DENIED;
|
||||
goto error;
|
||||
};
|
||||
|
||||
async:
|
||||
/* 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 */
|
||||
|
||||
req->state = SMBCLI_REQUEST_DONE;
|
||||
|
||||
if (req->recv_helper.fn) {
|
||||
/*
|
||||
* let the recv helper decide in
|
||||
* what state the request really is
|
||||
*/
|
||||
req->state = req->recv_helper.fn(req);
|
||||
|
||||
/* if more parts are needed, wait for them */
|
||||
if (req->state <= SMBCLI_REQUEST_RECV) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
}
|
||||
DLIST_REMOVE(transport->pending_recv, req);
|
||||
if (req->async.fn) {
|
||||
req->async.fn(req);
|
||||
}
|
||||
return NT_STATUS_OK;
|
||||
|
||||
error:
|
||||
if (req) {
|
||||
DLIST_REMOVE(transport->pending_recv, req);
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
if (req->async.fn) {
|
||||
req->async.fn(req);
|
||||
}
|
||||
} else {
|
||||
talloc_free(buffer);
|
||||
}
|
||||
return NT_STATUS_OK;
|
||||
transport->idle.te = tevent_add_timer(transport->ev,
|
||||
transport,
|
||||
timeval_current_ofs_usec(period),
|
||||
idle_handler,
|
||||
transport);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -396,102 +165,364 @@ error:
|
||||
*/
|
||||
_PUBLIC_ bool smbcli_transport_process(struct smbcli_transport *transport)
|
||||
{
|
||||
NTSTATUS status;
|
||||
size_t npending;
|
||||
struct tevent_req *subreq = NULL;
|
||||
int ret;
|
||||
|
||||
packet_queue_run(transport->packet);
|
||||
if (transport->socket->sock == NULL) {
|
||||
if (!smbXcli_conn_is_connected(transport->conn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
status = socket_pending(transport->socket->sock, &npending);
|
||||
if (NT_STATUS_IS_OK(status) && npending > 0) {
|
||||
packet_recv(transport->packet);
|
||||
if (!smbXcli_conn_has_async_calls(transport->conn)) {
|
||||
return true;
|
||||
}
|
||||
if (transport->socket->sock == NULL) {
|
||||
|
||||
/*
|
||||
* do not block for more than 500 micro seconds
|
||||
*/
|
||||
subreq = tevent_wakeup_send(transport,
|
||||
transport->ev,
|
||||
timeval_current_ofs_usec(500));
|
||||
if (subreq == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = tevent_loop_once(transport->ev);
|
||||
if (ret != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TALLOC_FREE(subreq);
|
||||
|
||||
if (!smbXcli_conn_is_connected(transport->conn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
handle timeouts of individual smb requests
|
||||
*/
|
||||
static void smbcli_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
|
||||
struct timeval t, void *private_data)
|
||||
static void smbcli_transport_break_handler(struct tevent_req *subreq);
|
||||
static void smbcli_request_done(struct tevent_req *subreq);
|
||||
|
||||
struct tevent_req *smbcli_transport_setup_subreq(struct smbcli_request *req)
|
||||
{
|
||||
struct smbcli_request *req = talloc_get_type(private_data, struct smbcli_request);
|
||||
struct smbcli_transport *transport = req->transport;
|
||||
uint8_t smb_command;
|
||||
uint8_t additional_flags;
|
||||
uint8_t clear_flags;
|
||||
uint16_t additional_flags2;
|
||||
uint16_t clear_flags2;
|
||||
uint32_t pid;
|
||||
uint16_t tid;
|
||||
uint16_t uid;
|
||||
uint32_t timeout_msec = transport->options.request_timeout * 1000;
|
||||
struct iovec *bytes_iov = NULL;
|
||||
struct tevent_req *subreq = NULL;
|
||||
|
||||
if (req->state == SMBCLI_REQUEST_RECV) {
|
||||
DLIST_REMOVE(req->transport->pending_recv, req);
|
||||
smb_command = SVAL(req->out.hdr, HDR_COM);
|
||||
additional_flags = CVAL(req->out.hdr, HDR_FLG);
|
||||
additional_flags2 = SVAL(req->out.hdr, HDR_FLG2);
|
||||
pid = SVAL(req->out.hdr, HDR_PID);
|
||||
pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16;
|
||||
tid = SVAL(req->out.hdr, HDR_TID);
|
||||
uid = SVAL(req->out.hdr, HDR_UID);
|
||||
|
||||
clear_flags = ~additional_flags;
|
||||
clear_flags2 = ~additional_flags2;
|
||||
|
||||
bytes_iov = talloc(req, struct iovec);
|
||||
if (bytes_iov == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
req->status = NT_STATUS_IO_TIMEOUT;
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
if (req->async.fn) {
|
||||
req->async.fn(req);
|
||||
bytes_iov->iov_base = (void *)req->out.data;
|
||||
bytes_iov->iov_len = req->out.data_size;
|
||||
|
||||
subreq = smb1cli_req_create(req,
|
||||
transport->ev,
|
||||
transport->conn,
|
||||
smb_command,
|
||||
additional_flags,
|
||||
clear_flags,
|
||||
additional_flags2,
|
||||
clear_flags2,
|
||||
timeout_msec,
|
||||
pid,
|
||||
tid,
|
||||
uid,
|
||||
req->out.wct,
|
||||
(uint16_t *)req->out.vwv,
|
||||
1, bytes_iov);
|
||||
if (subreq == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZERO_STRUCT(req->out);
|
||||
|
||||
return subreq;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
destroy a request
|
||||
*/
|
||||
static int smbcli_request_destructor(struct smbcli_request *req)
|
||||
{
|
||||
if (req->state == SMBCLI_REQUEST_RECV) {
|
||||
DLIST_REMOVE(req->transport->pending_recv, req);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
put a request into the send queue
|
||||
*/
|
||||
void smbcli_transport_send(struct smbcli_request *req)
|
||||
{
|
||||
DATA_BLOB blob;
|
||||
struct smbcli_transport *transport = req->transport;
|
||||
NTSTATUS status;
|
||||
bool need_pending_break = false;
|
||||
struct tevent_req *subreq = NULL;
|
||||
size_t i;
|
||||
size_t num_subreqs = 0;
|
||||
|
||||
/* check if the transport is dead */
|
||||
if (req->transport->socket->sock == NULL) {
|
||||
if (transport->oplock.handler) {
|
||||
need_pending_break = true;
|
||||
}
|
||||
|
||||
if (transport->break_subreq) {
|
||||
need_pending_break = false;
|
||||
}
|
||||
|
||||
if (need_pending_break) {
|
||||
subreq = smb1cli_req_create(transport,
|
||||
transport->ev,
|
||||
transport->conn,
|
||||
0, /* smb_command */
|
||||
0, /* additional_flags */
|
||||
0, /* clear_flags */
|
||||
0, /* additional_flags2 */
|
||||
0, /* clear_flags2 */
|
||||
0, /* timeout_msec */
|
||||
0, /* pid */
|
||||
0, /* tid */
|
||||
0, /* uid */
|
||||
0, /* wct */
|
||||
NULL, /* vwv */
|
||||
0, /* iov_count */
|
||||
NULL); /* bytes_iov */
|
||||
if (subreq != NULL) {
|
||||
smb1cli_req_set_mid(subreq, 0xFFFF);
|
||||
smbXcli_req_set_pending(subreq);
|
||||
tevent_req_set_callback(subreq,
|
||||
smbcli_transport_break_handler,
|
||||
transport);
|
||||
transport->break_subreq = subreq;
|
||||
subreq = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
subreq = smbcli_transport_setup_subreq(req);
|
||||
if (subreq == NULL) {
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
req->status = NT_STATUS_NET_WRITE_FAULT;
|
||||
req->status = NT_STATUS_NO_MEMORY;
|
||||
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 = SMBCLI_REQUEST_ERROR;
|
||||
req->status = status;
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(req->subreqs); i++) {
|
||||
if (req->subreqs[i] == NULL) {
|
||||
req->subreqs[i] = subreq;
|
||||
subreq = NULL;
|
||||
}
|
||||
if (req->subreqs[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
packet_queue_run(req->transport->packet);
|
||||
if (req->transport->socket->sock == NULL) {
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
req->status = NT_STATUS_NET_WRITE_FAULT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->one_way_request) {
|
||||
req->state = SMBCLI_REQUEST_DONE;
|
||||
smbcli_request_destroy(req);
|
||||
return;
|
||||
if (!tevent_req_is_in_progress(req->subreqs[i])) {
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
req->status = NT_STATUS_INTERNAL_ERROR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
num_subreqs = i;
|
||||
|
||||
req->state = SMBCLI_REQUEST_RECV;
|
||||
DLIST_ADD(req->transport->pending_recv, req);
|
||||
tevent_req_set_callback(req->subreqs[0], smbcli_request_done, req);
|
||||
|
||||
/* add a timeout */
|
||||
if (req->transport->options.request_timeout) {
|
||||
tevent_add_timer(req->transport->socket->event.ctx, req,
|
||||
timeval_current_ofs(req->transport->options.request_timeout, 0),
|
||||
smbcli_timeout_handler, req);
|
||||
status = smb1cli_req_chain_submit(req->subreqs, num_subreqs);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
smbXcli_conn_disconnect(transport->conn, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void smbcli_request_done(struct tevent_req *subreq)
|
||||
{
|
||||
struct smbcli_request *req =
|
||||
tevent_req_callback_data(subreq,
|
||||
struct smbcli_request);
|
||||
struct smbcli_transport *transport = req->transport;
|
||||
ssize_t len;
|
||||
size_t i;
|
||||
uint8_t *hdr = NULL;
|
||||
uint8_t wct = 0;
|
||||
uint16_t *vwv = NULL;
|
||||
uint32_t num_bytes = 0;
|
||||
uint8_t *bytes = NULL;
|
||||
struct iovec *recv_iov = NULL;
|
||||
uint8_t *inbuf = NULL;
|
||||
|
||||
req->status = smb1cli_req_recv(req->subreqs[0], req,
|
||||
&recv_iov,
|
||||
&hdr,
|
||||
&wct,
|
||||
&vwv,
|
||||
NULL, /* pvwv_offset */
|
||||
&num_bytes,
|
||||
&bytes,
|
||||
NULL, /* pbytes_offset */
|
||||
&inbuf,
|
||||
NULL, 0); /* expected */
|
||||
TALLOC_FREE(req->subreqs[0]);
|
||||
if (!NT_STATUS_IS_OK(req->status)) {
|
||||
if (recv_iov == NULL) {
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
transport->error.e.nt_status = req->status;
|
||||
transport->error.etype = ETYPE_SOCKET;
|
||||
if (req->async.fn) {
|
||||
req->async.fn(req);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For SMBreadBraw hdr is NULL
|
||||
*/
|
||||
len = recv_iov[0].iov_len;
|
||||
for (i=1; hdr != NULL && i < 3; i++) {
|
||||
uint8_t *p = recv_iov[i-1].iov_base;
|
||||
uint8_t *c1 = recv_iov[i].iov_base;
|
||||
uint8_t *c2 = p + recv_iov[i-1].iov_len;
|
||||
|
||||
len += recv_iov[i].iov_len;
|
||||
|
||||
c2 += i;
|
||||
len += i;
|
||||
|
||||
if (recv_iov[i].iov_len == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c1 != c2) {
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
req->status = NT_STATUS_INTERNAL_ERROR;
|
||||
transport->error.e.nt_status = req->status;
|
||||
transport->error.etype = ETYPE_SMB;
|
||||
if (req->async.fn) {
|
||||
req->async.fn(req);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill in the 'in' portion of the matching request */
|
||||
req->in.buffer = inbuf;
|
||||
req->in.size = NBT_HDR_SIZE + len;
|
||||
req->in.allocated = req->in.size;
|
||||
|
||||
req->in.hdr = hdr;
|
||||
req->in.vwv = (uint8_t *)vwv;
|
||||
req->in.wct = wct;
|
||||
req->in.data = bytes;
|
||||
req->in.data_size = num_bytes;
|
||||
req->in.ptr = req->in.data;
|
||||
if (hdr != NULL) {
|
||||
req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
|
||||
}
|
||||
|
||||
smb_setup_bufinfo(req);
|
||||
|
||||
transport->error.e.nt_status = req->status;
|
||||
if (NT_STATUS_IS_OK(req->status)) {
|
||||
transport->error.etype = ETYPE_NONE;
|
||||
} else {
|
||||
transport->error.etype = ETYPE_SMB;
|
||||
}
|
||||
|
||||
req->state = SMBCLI_REQUEST_DONE;
|
||||
if (req->async.fn) {
|
||||
req->async.fn(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void smbcli_transport_break_handler(struct tevent_req *subreq)
|
||||
{
|
||||
struct smbcli_transport *transport =
|
||||
tevent_req_callback_data(subreq,
|
||||
struct smbcli_transport);
|
||||
NTSTATUS status;
|
||||
struct iovec *recv_iov = NULL;
|
||||
uint8_t *hdr = NULL;
|
||||
uint16_t *vwv = NULL;
|
||||
const struct smb1cli_req_expected_response expected[] = {
|
||||
{
|
||||
.status = NT_STATUS_OK,
|
||||
.wct = 8,
|
||||
}
|
||||
};
|
||||
uint16_t tid;
|
||||
uint16_t fnum;
|
||||
uint8_t level;
|
||||
|
||||
transport->break_subreq = NULL;
|
||||
|
||||
status = smb1cli_req_recv(subreq, transport,
|
||||
&recv_iov,
|
||||
&hdr,
|
||||
NULL, /* pwct */
|
||||
&vwv,
|
||||
NULL, /* pvwv_offset */
|
||||
NULL, /* pnum_bytes */
|
||||
NULL, /* pbytes */
|
||||
NULL, /* pbytes_offset */
|
||||
NULL, /* pinbuf */
|
||||
expected,
|
||||
ARRAY_SIZE(expected));
|
||||
TALLOC_FREE(subreq);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
TALLOC_FREE(recv_iov);
|
||||
smbcli_transport_dead(transport, status);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the subreq to handle the
|
||||
* next incoming SMB2 Break.
|
||||
*/
|
||||
subreq = smb1cli_req_create(transport,
|
||||
transport->ev,
|
||||
transport->conn,
|
||||
0, /* smb_command */
|
||||
0, /* additional_flags */
|
||||
0, /* clear_flags */
|
||||
0, /* additional_flags2 */
|
||||
0, /* clear_flags2 */
|
||||
0, /* timeout_msec */
|
||||
0, /* pid */
|
||||
0, /* tid */
|
||||
0, /* uid */
|
||||
0, /* wct */
|
||||
NULL, /* vwv */
|
||||
0, /* iov_count */
|
||||
NULL); /* bytes_iov */
|
||||
if (subreq != NULL) {
|
||||
smb1cli_req_set_mid(subreq, 0xFFFF);
|
||||
smbXcli_req_set_pending(subreq);
|
||||
tevent_req_set_callback(subreq,
|
||||
smbcli_transport_break_handler,
|
||||
transport);
|
||||
transport->break_subreq = subreq;
|
||||
}
|
||||
|
||||
tid = SVAL(hdr, HDR_TID);
|
||||
fnum = SVAL(vwv+2, 0);
|
||||
level = CVAL(vwv+3, 1);
|
||||
|
||||
TALLOC_FREE(recv_iov);
|
||||
|
||||
if (transport->oplock.handler) {
|
||||
transport->oplock.handler(transport, tid, fnum, level,
|
||||
transport->oplock.private_data);
|
||||
} else {
|
||||
DEBUG(5,("Got SMB oplock break with no handler\n"));
|
||||
}
|
||||
|
||||
talloc_set_destructor(req, smbcli_request_destructor);
|
||||
}
|
||||
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "../libcli/smb/smb_common.h"
|
||||
#include "libcli/raw/request.h"
|
||||
#include "librpc/gen_ndr/nbt.h"
|
||||
#include "libcli/raw/interfaces.h"
|
||||
|
||||
struct smbcli_tree; /* forward declare */
|
||||
struct smbcli_request; /* forward declare */
|
||||
@ -52,23 +53,18 @@ struct smbcli_negotiate {
|
||||
enum protocol_types protocol;
|
||||
|
||||
uint8_t sec_mode; /* security mode returned by negprot */
|
||||
uint8_t key_len;
|
||||
DATA_BLOB server_guid; /* server_guid */
|
||||
DATA_BLOB secblob; /* cryptkey or negTokenInit blob */
|
||||
uint32_t sesskey;
|
||||
|
||||
struct smb_signing_context sign_info;
|
||||
|
||||
/* capabilities that the server reported */
|
||||
uint32_t capabilities;
|
||||
|
||||
int server_zone;
|
||||
time_t server_time;
|
||||
|
||||
unsigned int readbraw_supported:1;
|
||||
unsigned int writebraw_supported:1;
|
||||
unsigned int lockread_supported:1;
|
||||
|
||||
char *server_domain;
|
||||
};
|
||||
|
||||
/* this is the context for a SMB socket associated with the socket itself */
|
||||
@ -109,24 +105,14 @@ struct smbcli_options {
|
||||
/* this is the context for the client transport layer */
|
||||
struct smbcli_transport {
|
||||
struct tevent_context *ev; /* TODO: remove this !!! */
|
||||
struct smbXcli_conn *conn;
|
||||
|
||||
/* socket level info */
|
||||
struct smbcli_socket *socket;
|
||||
|
||||
/* the next mid to be allocated - needed for signing and
|
||||
request matching */
|
||||
uint16_t next_mid;
|
||||
|
||||
/* negotiated protocol information */
|
||||
struct smbcli_negotiate negotiate;
|
||||
|
||||
/* options to control the behaviour of the client code */
|
||||
struct smbcli_options options;
|
||||
|
||||
/* is a readbraw pending? we need to handle that case
|
||||
specially on receiving packets */
|
||||
unsigned int readbraw_pending:1;
|
||||
|
||||
/* an idle function - if this is defined then it will be
|
||||
called once every period microseconds while we are waiting
|
||||
for a packet */
|
||||
@ -134,6 +120,7 @@ struct smbcli_transport {
|
||||
void (*func)(struct smbcli_transport *, void *);
|
||||
void *private_data;
|
||||
unsigned int period;
|
||||
struct tevent_timer *te;
|
||||
} idle;
|
||||
|
||||
/* the error fields from the last message */
|
||||
@ -157,16 +144,7 @@ struct smbcli_transport {
|
||||
/* private data passed to the oplock handler */
|
||||
void *private_data;
|
||||
} oplock;
|
||||
|
||||
/* a list of async requests that are pending for receive on this connection */
|
||||
struct smbcli_request *pending_recv;
|
||||
|
||||
/* remember the called name - some sub-protocols require us to
|
||||
know the server name */
|
||||
struct nbt_name called;
|
||||
|
||||
/* context of the stream -> packet parser */
|
||||
struct packet_context *packet;
|
||||
struct tevent_req *break_subreq;
|
||||
};
|
||||
|
||||
/* this is the context for the user */
|
||||
@ -227,8 +205,8 @@ enum smbcli_request_state {SMBCLI_REQUEST_INIT, /* we are creating the request *
|
||||
* functions (similar to context.h, the server version).
|
||||
* This will allow requests to be multi-threaded. */
|
||||
struct smbcli_request {
|
||||
/* allow a request to be part of a list of requests */
|
||||
struct smbcli_request *next, *prev;
|
||||
/* smbXcli_req */
|
||||
struct tevent_req *subreqs[2];
|
||||
|
||||
/* each request is in one of 4 possible states */
|
||||
enum smbcli_request_state state;
|
||||
@ -239,14 +217,6 @@ struct smbcli_request {
|
||||
struct smbcli_session *session;
|
||||
struct smbcli_tree *tree;
|
||||
|
||||
/* a receive helper, smbcli_transport_finish_recv will not call
|
||||
req->async.fn callback handler unless the recv_helper returns
|
||||
a value > SMBCLI_REQUEST_RECV. */
|
||||
struct {
|
||||
enum smbcli_request_state (*fn)(struct smbcli_request *);
|
||||
void *private_data;
|
||||
} recv_helper;
|
||||
|
||||
/* the flags2 from the SMB request, in raw form (host byte
|
||||
order). Used to parse strings */
|
||||
uint16_t flags2;
|
||||
@ -254,20 +224,6 @@ struct smbcli_request {
|
||||
/* the NT status for this request. Set by packet receive code
|
||||
or code detecting error. */
|
||||
NTSTATUS status;
|
||||
|
||||
/* the sequence number of this packet - used for signing */
|
||||
unsigned int seq_num;
|
||||
|
||||
/* list of ntcancel request for this requests */
|
||||
struct smbcli_request *ntcancel;
|
||||
|
||||
/* set if this is a one-way request, meaning we are not
|
||||
expecting a reply from the server. */
|
||||
unsigned int one_way_request:1;
|
||||
|
||||
/* set this when the request should only increment the signing
|
||||
counter by one */
|
||||
unsigned int sign_single_increment:1;
|
||||
|
||||
/* the caller wants to do the signing check */
|
||||
bool sign_caller_checks;
|
||||
@ -275,12 +231,12 @@ struct smbcli_request {
|
||||
/* give the caller a chance to prevent the talloc_free() in the _recv() function */
|
||||
bool do_not_free;
|
||||
|
||||
/* the mid of this packet - used to match replies */
|
||||
uint16_t mid;
|
||||
|
||||
struct smb_request_buffer in;
|
||||
struct smb_request_buffer out;
|
||||
|
||||
struct smb_trans2 trans2;
|
||||
struct smb_nttrans nttrans;
|
||||
|
||||
/* 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
|
||||
@ -307,8 +263,6 @@ struct smbcli_request {
|
||||
goto failed; \
|
||||
}
|
||||
|
||||
#include "libcli/raw/interfaces.h"
|
||||
|
||||
NTSTATUS smb_raw_read_recv(struct smbcli_request *req, union smb_read *parms);
|
||||
struct smbcli_request *smb_raw_read_send(struct smbcli_tree *tree, union smb_read *parms);
|
||||
NTSTATUS smb_raw_trans_recv(struct smbcli_request *req,
|
||||
@ -379,6 +333,4 @@ NTSTATUS smb_raw_trans(struct smbcli_tree *tree,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct smb_trans2 *parms);
|
||||
|
||||
void smbcli_sock_dead(struct smbcli_socket *sock);
|
||||
|
||||
#endif /* __LIBCLI_RAW__H__ */
|
||||
|
@ -21,184 +21,106 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <tevent.h>
|
||||
#include "system/time.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/raw/raw_proto.h"
|
||||
#include "system/time.h"
|
||||
#include "../libcli/smb/smbXcli_base.h"
|
||||
#include "../lib/util/tevent_ntstatus.h"
|
||||
|
||||
static const struct {
|
||||
enum protocol_types prot;
|
||||
const char *name;
|
||||
} prots[] = {
|
||||
{PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
|
||||
{PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
|
||||
{PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
|
||||
{PROTOCOL_LANMAN1,"LANMAN1.0"},
|
||||
{PROTOCOL_LANMAN1,"Windows for Workgroups 3.1a"},
|
||||
{PROTOCOL_LANMAN2,"LM1.2X002"},
|
||||
{PROTOCOL_LANMAN2,"DOS LANMAN2.1"},
|
||||
{PROTOCOL_LANMAN2,"LANMAN2.1"},
|
||||
{PROTOCOL_LANMAN2,"Samba"},
|
||||
{PROTOCOL_NT1,"NT LANMAN 1.0"},
|
||||
{PROTOCOL_NT1,"NT LM 0.12"},
|
||||
#if 0
|
||||
/* we don't yet handle chaining a SMB transport onto SMB2 */
|
||||
{PROTOCOL_SMB2_02,"SMB 2.002"},
|
||||
#endif
|
||||
struct smb_raw_negotiate_state {
|
||||
struct smbcli_transport *transport;
|
||||
};
|
||||
|
||||
/*
|
||||
Send a negprot command.
|
||||
*/
|
||||
struct smbcli_request *smb_raw_negotiate_send(struct smbcli_transport *transport,
|
||||
bool unicode,
|
||||
int maxprotocol)
|
||||
static void smb_raw_negotiate_done(struct tevent_req *subreq);
|
||||
|
||||
struct tevent_req *smb_raw_negotiate_send(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
struct smbcli_transport *transport,
|
||||
int maxprotocol)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
int i;
|
||||
uint16_t flags2 = 0;
|
||||
struct tevent_req *req;
|
||||
struct smb_raw_negotiate_state *state;
|
||||
struct tevent_req *subreq;
|
||||
uint32_t timeout_msec = transport->options.request_timeout * 1000;
|
||||
|
||||
req = smbcli_request_setup_transport(transport, SMBnegprot, 0, 0);
|
||||
if (!req) {
|
||||
req = tevent_req_create(mem_ctx, &state,
|
||||
struct smb_raw_negotiate_state);;
|
||||
if (req == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
state->transport = transport;
|
||||
|
||||
if (transport->options.ntstatus_support) {
|
||||
flags2 |= FLAGS2_32_BIT_ERROR_CODES;
|
||||
}
|
||||
|
||||
if (unicode) {
|
||||
flags2 |= FLAGS2_UNICODE_STRINGS;
|
||||
}
|
||||
flags2 |= FLAGS2_EXTENDED_ATTRIBUTES;
|
||||
flags2 |= FLAGS2_LONG_PATH_COMPONENTS;
|
||||
flags2 |= FLAGS2_IS_LONG_NAME;
|
||||
|
||||
if (transport->options.use_spnego) {
|
||||
flags2 |= FLAGS2_EXTENDED_SECURITY;
|
||||
}
|
||||
|
||||
SSVAL(req->out.hdr,HDR_FLG2, flags2);
|
||||
|
||||
/* setup the protocol strings */
|
||||
for (i=0; i < ARRAY_SIZE(prots) && prots[i].prot <= maxprotocol; i++) {
|
||||
smbcli_req_append_bytes(req, (const uint8_t *)"\2", 1);
|
||||
smbcli_req_append_string(req, prots[i].name, STR_TERMINATE | STR_ASCII);
|
||||
}
|
||||
|
||||
if (!smbcli_request_send(req)) {
|
||||
smbcli_request_destroy(req);
|
||||
return NULL;
|
||||
subreq = smbXcli_negprot_send(state, ev,
|
||||
transport->conn,
|
||||
timeout_msec,
|
||||
PROTOCOL_CORE,
|
||||
maxprotocol);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
tevent_req_set_callback(subreq, smb_raw_negotiate_done, req);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static void smb_raw_negotiate_done(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req =
|
||||
tevent_req_callback_data(subreq,
|
||||
struct tevent_req);
|
||||
struct smb_raw_negotiate_state *state =
|
||||
tevent_req_data(req,
|
||||
struct smb_raw_negotiate_state);
|
||||
struct smbcli_negotiate *n = &state->transport->negotiate;
|
||||
struct smbXcli_conn *c = state->transport->conn;
|
||||
NTSTATUS status;
|
||||
NTTIME ntt;
|
||||
|
||||
status = smbXcli_negprot_recv(subreq);
|
||||
TALLOC_FREE(subreq);
|
||||
if (tevent_req_nterror(req, status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
n->protocol = smbXcli_conn_protocol(c);
|
||||
|
||||
n->sec_mode = smb1cli_conn_server_security_mode(c);
|
||||
n->max_mux = smbXcli_conn_max_requests(c);
|
||||
n->max_xmit = smb1cli_conn_max_xmit(c);
|
||||
n->sesskey = smb1cli_conn_server_session_key(c);
|
||||
n->capabilities = smb1cli_conn_capabilities(c);;
|
||||
|
||||
/* this time arrives in real GMT */
|
||||
ntt = smbXcli_conn_server_system_time(c);
|
||||
n->server_time = nt_time_to_unix(ntt);
|
||||
n->server_zone = smb1cli_conn_server_time_zone(c);
|
||||
|
||||
if (n->capabilities & CAP_EXTENDED_SECURITY) {
|
||||
const DATA_BLOB *b = smbXcli_conn_server_gss_blob(c);
|
||||
if (b) {
|
||||
n->secblob = *b;
|
||||
}
|
||||
} else {
|
||||
const uint8_t *p = smb1cli_conn_server_challenge(c);
|
||||
if (p) {
|
||||
n->secblob = data_blob_const(p, 8);
|
||||
}
|
||||
}
|
||||
|
||||
n->readbraw_supported = smb1cli_conn_server_readbraw(c);
|
||||
n->readbraw_supported = smb1cli_conn_server_writebraw(c);
|
||||
n->lockread_supported = smb1cli_conn_server_lockread(c);
|
||||
|
||||
tevent_req_done(req);
|
||||
}
|
||||
|
||||
/*
|
||||
Send a negprot command.
|
||||
*/
|
||||
NTSTATUS smb_raw_negotiate_recv(struct smbcli_request *req)
|
||||
NTSTATUS smb_raw_negotiate_recv(struct tevent_req *req)
|
||||
{
|
||||
struct smbcli_transport *transport = req->transport;
|
||||
int protocol;
|
||||
|
||||
if (!smbcli_request_receive(req) ||
|
||||
smbcli_request_is_error(req)) {
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
SMBCLI_CHECK_MIN_WCT(req, 1);
|
||||
|
||||
protocol = SVALS(req->in.vwv, VWV(0));
|
||||
|
||||
if (protocol >= ARRAY_SIZE(prots) || protocol < 0) {
|
||||
req->status = NT_STATUS_UNSUCCESSFUL;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
transport->negotiate.protocol = prots[protocol].prot;
|
||||
|
||||
if (transport->negotiate.protocol >= PROTOCOL_NT1) {
|
||||
NTTIME ntt;
|
||||
|
||||
/* NT protocol */
|
||||
SMBCLI_CHECK_WCT(req, 17);
|
||||
transport->negotiate.sec_mode = CVAL(req->in.vwv,VWV(1));
|
||||
transport->negotiate.max_mux = SVAL(req->in.vwv,VWV(1)+1);
|
||||
transport->negotiate.max_xmit = IVAL(req->in.vwv,VWV(3)+1);
|
||||
transport->negotiate.sesskey = IVAL(req->in.vwv,VWV(7)+1);
|
||||
transport->negotiate.capabilities = IVAL(req->in.vwv,VWV(9)+1);
|
||||
|
||||
/* this time arrives in real GMT */
|
||||
ntt = smbcli_pull_nttime(req->in.vwv, VWV(11)+1);
|
||||
transport->negotiate.server_time = nt_time_to_unix(ntt);
|
||||
transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(15)+1) * 60;
|
||||
transport->negotiate.key_len = CVAL(req->in.vwv,VWV(16)+1);
|
||||
|
||||
if (transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
|
||||
if (req->in.data_size < 16) {
|
||||
goto failed;
|
||||
}
|
||||
transport->negotiate.server_guid = smbcli_req_pull_blob(&req->in.bufinfo, transport, req->in.data, 16);
|
||||
transport->negotiate.secblob = smbcli_req_pull_blob(&req->in.bufinfo, transport, req->in.data + 16, req->in.data_size - 16);
|
||||
} else {
|
||||
if (req->in.data_size < (transport->negotiate.key_len)) {
|
||||
goto failed;
|
||||
}
|
||||
transport->negotiate.secblob = smbcli_req_pull_blob(&req->in.bufinfo, transport, req->in.data, transport->negotiate.key_len);
|
||||
smbcli_req_pull_string(&req->in.bufinfo, transport, &transport->negotiate.server_domain,
|
||||
req->in.data+transport->negotiate.key_len,
|
||||
req->in.data_size-transport->negotiate.key_len, STR_UNICODE|STR_NOALIGN);
|
||||
/* here comes the server name */
|
||||
}
|
||||
|
||||
if (transport->negotiate.capabilities & CAP_RAW_MODE) {
|
||||
transport->negotiate.readbraw_supported = true;
|
||||
transport->negotiate.writebraw_supported = true;
|
||||
}
|
||||
|
||||
if (transport->negotiate.capabilities & CAP_LOCK_AND_READ)
|
||||
transport->negotiate.lockread_supported = true;
|
||||
} else if (transport->negotiate.protocol >= PROTOCOL_LANMAN1) {
|
||||
SMBCLI_CHECK_WCT(req, 13);
|
||||
transport->negotiate.sec_mode = SVAL(req->in.vwv,VWV(1));
|
||||
transport->negotiate.max_xmit = SVAL(req->in.vwv,VWV(2));
|
||||
transport->negotiate.sesskey = IVAL(req->in.vwv,VWV(6));
|
||||
transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(10)) * 60;
|
||||
|
||||
/* this time is converted to GMT by raw_pull_dos_date */
|
||||
transport->negotiate.server_time = raw_pull_dos_date(transport,
|
||||
req->in.vwv+VWV(8));
|
||||
if ((SVAL(req->in.vwv,VWV(5)) & 0x1)) {
|
||||
transport->negotiate.readbraw_supported = 1;
|
||||
}
|
||||
if ((SVAL(req->in.vwv,VWV(5)) & 0x2)) {
|
||||
transport->negotiate.writebraw_supported = 1;
|
||||
}
|
||||
transport->negotiate.secblob = smbcli_req_pull_blob(&req->in.bufinfo, transport,
|
||||
req->in.data, req->in.data_size);
|
||||
} else {
|
||||
/* the old core protocol */
|
||||
transport->negotiate.sec_mode = 0;
|
||||
transport->negotiate.server_time = time(NULL);
|
||||
transport->negotiate.max_xmit = transport->options.max_xmit;
|
||||
transport->negotiate.server_zone = get_time_zone(transport->negotiate.server_time);
|
||||
}
|
||||
|
||||
/* a way to force ascii SMB */
|
||||
if (!transport->options.unicode) {
|
||||
transport->negotiate.capabilities &= ~CAP_UNICODE;
|
||||
}
|
||||
|
||||
if (!transport->options.ntstatus_support) {
|
||||
transport->negotiate.capabilities &= ~CAP_STATUS32;
|
||||
}
|
||||
|
||||
if (!transport->options.use_level2_oplocks) {
|
||||
transport->negotiate.capabilities &= ~CAP_LEVEL_II_OPLOCKS;
|
||||
}
|
||||
|
||||
failed:
|
||||
return smbcli_request_destroy(req);
|
||||
return tevent_req_simple_recv_ntstatus(req);
|
||||
}
|
||||
|
||||
|
||||
@ -207,6 +129,27 @@ failed:
|
||||
*/
|
||||
NTSTATUS smb_raw_negotiate(struct smbcli_transport *transport, bool unicode, int maxprotocol)
|
||||
{
|
||||
struct smbcli_request *req = smb_raw_negotiate_send(transport, unicode, maxprotocol);
|
||||
return smb_raw_negotiate_recv(req);
|
||||
NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
|
||||
struct tevent_req *subreq = NULL;
|
||||
bool ok;
|
||||
|
||||
subreq = smb_raw_negotiate_send(transport,
|
||||
transport->ev,
|
||||
transport,
|
||||
maxprotocol);
|
||||
if (subreq == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ok = tevent_req_poll(subreq, transport->ev);
|
||||
if (!ok) {
|
||||
status = map_nt_error_from_unix_common(errno);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
status = smb_raw_negotiate_recv(subreq);
|
||||
|
||||
failed:
|
||||
TALLOC_FREE(subreq);
|
||||
return status;
|
||||
}
|
||||
|
@ -18,9 +18,9 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <tevent.h>
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/raw/raw_proto.h"
|
||||
#include "../lib/util/dlinklist.h"
|
||||
|
||||
/****************************************************************************
|
||||
change notify (async send)
|
||||
@ -100,38 +100,6 @@ _PUBLIC_ NTSTATUS smb_raw_changenotify_recv(struct smbcli_request *req,
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
handle ntcancel replies from the server,
|
||||
as the MID of the real reply and the ntcancel reply is the same
|
||||
we need to do find out to what request the reply belongs
|
||||
****************************************************************************/
|
||||
struct smbcli_request *smbcli_handle_ntcancel_reply(struct smbcli_request *req,
|
||||
size_t len, const uint8_t *hdr)
|
||||
{
|
||||
struct smbcli_request *ntcancel;
|
||||
|
||||
if (!req) return req;
|
||||
|
||||
if (!req->ntcancel) return req;
|
||||
|
||||
if (len >= MIN_SMB_SIZE + NBT_HDR_SIZE &&
|
||||
(CVAL(hdr, HDR_FLG) & FLAG_REPLY) &&
|
||||
CVAL(hdr,HDR_COM) == SMBntcancel) {
|
||||
ntcancel = req->ntcancel;
|
||||
DLIST_REMOVE(req->ntcancel, ntcancel);
|
||||
|
||||
/*
|
||||
* TODO: untill we understand how the
|
||||
* smb_signing works for this case we
|
||||
* return NULL, to just ignore the packet
|
||||
*/
|
||||
/*return ntcancel;*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Send a NT Cancel request - used to hurry along a pending request. Usually
|
||||
used to cancel a pending change notify request
|
||||
@ -139,30 +107,16 @@ struct smbcli_request *smbcli_handle_ntcancel_reply(struct smbcli_request *req,
|
||||
****************************************************************************/
|
||||
NTSTATUS smb_raw_ntcancel(struct smbcli_request *oldreq)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
bool ok;
|
||||
|
||||
req = smbcli_request_setup_transport(oldreq->transport, SMBntcancel, 0, 0);
|
||||
if (oldreq->subreqs[0] == NULL) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
SSVAL(req->out.hdr, HDR_MID, SVAL(oldreq->out.hdr, HDR_MID));
|
||||
SSVAL(req->out.hdr, HDR_PID, SVAL(oldreq->out.hdr, HDR_PID));
|
||||
SSVAL(req->out.hdr, HDR_TID, SVAL(oldreq->out.hdr, HDR_TID));
|
||||
SSVAL(req->out.hdr, HDR_UID, SVAL(oldreq->out.hdr, HDR_UID));
|
||||
|
||||
/* this request does not expect a reply, so tell the signing
|
||||
subsystem not to allocate an id for a reply */
|
||||
req->sign_single_increment = 1;
|
||||
req->one_way_request = 1;
|
||||
|
||||
/*
|
||||
* smbcli_request_send() free's oneway requests
|
||||
* but we want to keep it under oldreq->ntcancel
|
||||
*/
|
||||
req->do_not_free = true;
|
||||
talloc_steal(oldreq, req);
|
||||
|
||||
smbcli_request_send(req);
|
||||
|
||||
DLIST_ADD_END(oldreq->ntcancel, req, struct smbcli_request *);
|
||||
ok = tevent_req_cancel(oldreq->subreqs[0]);
|
||||
if (!ok) {
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
@ -104,12 +104,6 @@ _PUBLIC_ struct smbcli_request *smb_raw_read_send(struct smbcli_tree *tree, unio
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* the transport layer needs to know that a readbraw is pending
|
||||
and handle receives a little differently */
|
||||
if (parms->generic.level == RAW_READ_READBRAW) {
|
||||
tree->session->transport->readbraw_pending = 1;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,10 @@
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/raw/raw_proto.h"
|
||||
#include "../lib/util/dlinklist.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "librpc/ndr/libndr.h"
|
||||
#include "librpc/gen_ndr/ndr_misc.h"
|
||||
#include "../libcli/smb/smbXcli_base.h"
|
||||
|
||||
/* we over allocate the data buffer to prevent too many realloc calls */
|
||||
#define REQ_OVER_ALLOCATION 0
|
||||
@ -59,12 +59,6 @@ _PUBLIC_ NTSTATUS smbcli_request_destroy(struct smbcli_request *req)
|
||||
_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 == SMBCLI_REQUEST_ERROR &&
|
||||
NT_STATUS_IS_OK(req->status)) {
|
||||
req->status = NT_STATUS_INTERNAL_ERROR;
|
||||
@ -80,41 +74,6 @@ _PUBLIC_ NTSTATUS smbcli_request_destroy(struct smbcli_request *req)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
low-level function to setup a request buffer for a non-SMB packet
|
||||
at the transport level
|
||||
*/
|
||||
struct smbcli_request *smbcli_request_setup_nonsmb(struct smbcli_transport *transport, size_t size)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
|
||||
req = talloc(transport, struct smbcli_request);
|
||||
if (!req) {
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(req);
|
||||
|
||||
/* setup the request context */
|
||||
req->state = SMBCLI_REQUEST_INIT;
|
||||
req->transport = transport;
|
||||
req->session = NULL;
|
||||
req->tree = NULL;
|
||||
req->out.size = size;
|
||||
|
||||
/* over allocate by a small amount */
|
||||
req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
|
||||
|
||||
req->out.buffer = talloc_array(req, uint8_t, req->out.allocated);
|
||||
if (!req->out.buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SIVAL(req->out.buffer, 0, 0);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
setup a SMB packet at transport level
|
||||
*/
|
||||
@ -122,11 +81,28 @@ struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *t
|
||||
uint8_t command, unsigned int wct, unsigned int buflen)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
size_t size;
|
||||
|
||||
req = smbcli_request_setup_nonsmb(transport, NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen);
|
||||
size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
|
||||
|
||||
req = talloc_zero(transport, struct smbcli_request);
|
||||
if (!req) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* setup the request context */
|
||||
req->state = SMBCLI_REQUEST_INIT;
|
||||
req->transport = transport;
|
||||
req->out.size = size;
|
||||
|
||||
/* over allocate by a small amount */
|
||||
req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
|
||||
|
||||
req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated);
|
||||
if (!req->out.buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!req) return NULL;
|
||||
|
||||
req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
|
||||
req->out.vwv = req->out.hdr + HDR_VWV;
|
||||
req->out.wct = wct;
|
||||
@ -143,15 +119,10 @@ struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *t
|
||||
SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
|
||||
SSVAL(req->out.hdr,HDR_FLG2, 0);
|
||||
|
||||
if (command != SMBtranss && command != SMBtranss2) {
|
||||
/* assign a mid */
|
||||
req->mid = smbcli_transport_next_mid(transport);
|
||||
}
|
||||
|
||||
/* copy the pid, uid and mid to the request */
|
||||
SSVAL(req->out.hdr, HDR_PID, 0);
|
||||
SSVAL(req->out.hdr, HDR_UID, 0);
|
||||
SSVAL(req->out.hdr, HDR_MID, req->mid);
|
||||
SSVAL(req->out.hdr, HDR_MID, 0);
|
||||
SSVAL(req->out.hdr, HDR_TID,0);
|
||||
SSVAL(req->out.hdr, HDR_PIDHIGH,0);
|
||||
SIVAL(req->out.hdr, HDR_RCLS, 0);
|
||||
@ -276,56 +247,143 @@ NTSTATUS smbcli_chained_request_setup(struct smbcli_request *req,
|
||||
uint8_t command,
|
||||
unsigned int wct, size_t buflen)
|
||||
{
|
||||
unsigned int new_size = 1 + (wct*2) + 2 + buflen;
|
||||
size_t wct_ofs;
|
||||
size_t size;
|
||||
|
||||
SSVAL(req->out.vwv, VWV(0), command);
|
||||
SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
|
||||
/*
|
||||
* here we only support one chained command
|
||||
* If someone needs longer chains, the low
|
||||
* level code should be used directly.
|
||||
*/
|
||||
if (req->subreqs[0] != NULL) {
|
||||
return NT_STATUS_INVALID_PARAMETER_MIX;
|
||||
}
|
||||
if (req->subreqs[1] != NULL) {
|
||||
return NT_STATUS_INVALID_PARAMETER_MIX;
|
||||
}
|
||||
|
||||
smbcli_req_grow_allocation(req, req->out.data_size + new_size);
|
||||
req->subreqs[0] = smbcli_transport_setup_subreq(req);
|
||||
if (req->subreqs[0] == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
req->out.vwv = req->out.buffer + req->out.size + 1;
|
||||
SCVAL(req->out.vwv, -1, wct);
|
||||
wct_ofs = smb1cli_req_wct_ofs(req->subreqs, 1);
|
||||
|
||||
size = NBT_HDR_SIZE + wct_ofs + 1 + VWV(wct) + 2 + buflen;
|
||||
|
||||
req->out.size = size;
|
||||
|
||||
/* over allocate by a small amount */
|
||||
req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
|
||||
|
||||
req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated);
|
||||
if (!req->out.buffer) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
|
||||
req->out.vwv = req->out.hdr + wct_ofs;
|
||||
req->out.wct = wct;
|
||||
req->out.data = req->out.vwv + VWV(wct) + 2;
|
||||
req->out.data_size = buflen;
|
||||
req->out.ptr = req->out.data;
|
||||
|
||||
SCVAL(req->out.hdr, HDR_WCT, wct);
|
||||
SSVAL(req->out.vwv, VWV(wct), buflen);
|
||||
|
||||
req->out.size += new_size;
|
||||
req->out.data_size += new_size;
|
||||
memcpy(req->out.hdr, "\377SMB", 4);
|
||||
SCVAL(req->out.hdr,HDR_COM,command);
|
||||
|
||||
SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
|
||||
SSVAL(req->out.hdr,HDR_FLG2, 0);
|
||||
|
||||
/* copy the pid, uid and mid to the request */
|
||||
SSVAL(req->out.hdr, HDR_PID, 0);
|
||||
SSVAL(req->out.hdr, HDR_UID, 0);
|
||||
SSVAL(req->out.hdr, HDR_MID, 0);
|
||||
SSVAL(req->out.hdr, HDR_TID,0);
|
||||
SSVAL(req->out.hdr, HDR_PIDHIGH,0);
|
||||
SIVAL(req->out.hdr, HDR_RCLS, 0);
|
||||
memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
|
||||
|
||||
if (req->session != NULL) {
|
||||
SSVAL(req->out.hdr, HDR_FLG2, req->session->flags2);
|
||||
SSVAL(req->out.hdr, HDR_PID, req->session->pid & 0xFFFF);
|
||||
SSVAL(req->out.hdr, HDR_PIDHIGH, req->session->pid >> 16);
|
||||
SSVAL(req->out.hdr, HDR_UID, req->session->vuid);
|
||||
}
|
||||
|
||||
if (req->tree != NULL) {
|
||||
SSVAL(req->out.hdr, HDR_TID, req->tree->tid);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
aadvance to the next chained reply in a request
|
||||
advance to the next chained reply in a request
|
||||
*/
|
||||
NTSTATUS smbcli_chained_advance(struct smbcli_request *req)
|
||||
{
|
||||
uint8_t *buffer;
|
||||
struct smbcli_transport *transport = req->transport;
|
||||
uint8_t *hdr = NULL;
|
||||
uint8_t wct = 0;
|
||||
uint16_t *vwv = NULL;
|
||||
uint32_t num_bytes = 0;
|
||||
uint8_t *bytes = NULL;
|
||||
struct iovec *recv_iov = NULL;
|
||||
uint8_t *inbuf = NULL;
|
||||
|
||||
if (CVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE) {
|
||||
return NT_STATUS_NOT_FOUND;
|
||||
if (req->subreqs[0] != NULL) {
|
||||
return NT_STATUS_INVALID_PARAMETER_MIX;
|
||||
}
|
||||
if (req->subreqs[1] == NULL) {
|
||||
return NT_STATUS_INVALID_PARAMETER_MIX;
|
||||
}
|
||||
|
||||
buffer = req->in.hdr + SVAL(req->in.vwv, VWV(1));
|
||||
|
||||
if (buffer + 3 > req->in.buffer + req->in.size) {
|
||||
return NT_STATUS_BUFFER_TOO_SMALL;
|
||||
req->status = smb1cli_req_recv(req->subreqs[1], req,
|
||||
&recv_iov,
|
||||
&hdr,
|
||||
&wct,
|
||||
&vwv,
|
||||
NULL, /* pvwv_offset */
|
||||
&num_bytes,
|
||||
&bytes,
|
||||
NULL, /* pbytes_offset */
|
||||
&inbuf,
|
||||
NULL, 0); /* expected */
|
||||
TALLOC_FREE(req->subreqs[1]);
|
||||
if (!NT_STATUS_IS_OK(req->status)) {
|
||||
if (recv_iov == NULL) {
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
return req->status;
|
||||
}
|
||||
}
|
||||
|
||||
req->in.vwv = buffer + 1;
|
||||
req->in.wct = CVAL(buffer, 0);
|
||||
if (buffer + 3 + req->in.wct*2 > req->in.buffer + req->in.size) {
|
||||
return NT_STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
req->in.data = req->in.vwv + 2 + req->in.wct * 2;
|
||||
req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
|
||||
/* fill in the 'in' portion of the matching request */
|
||||
req->in.buffer = inbuf;
|
||||
req->in.size = NBT_HDR_SIZE + PTR_DIFF(bytes, hdr) + num_bytes;
|
||||
req->in.allocated = req->in.size;
|
||||
|
||||
req->in.hdr = hdr;
|
||||
req->in.vwv = (uint8_t *)vwv;
|
||||
req->in.wct = wct;
|
||||
req->in.data = bytes;
|
||||
req->in.data_size = num_bytes;
|
||||
req->in.ptr = req->in.data;
|
||||
req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
|
||||
|
||||
/* fix the bufinfo */
|
||||
smb_setup_bufinfo(req);
|
||||
|
||||
if (buffer + 3 + req->in.wct*2 + req->in.data_size >
|
||||
req->in.buffer + req->in.size) {
|
||||
return NT_STATUS_BUFFER_TOO_SMALL;
|
||||
transport->error.e.nt_status = req->status;
|
||||
if (NT_STATUS_IS_OK(req->status)) {
|
||||
transport->error.etype = ETYPE_NONE;
|
||||
} else {
|
||||
transport->error.etype = ETYPE_SMB;
|
||||
}
|
||||
|
||||
req->state = SMBCLI_REQUEST_DONE;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
@ -335,14 +393,7 @@ NTSTATUS smbcli_chained_advance(struct smbcli_request *req)
|
||||
*/
|
||||
bool smbcli_request_send(struct smbcli_request *req)
|
||||
{
|
||||
if (IVAL(req->out.buffer, 0) == 0) {
|
||||
_smb_setlen_nbt(req->out.buffer, req->out.size - NBT_HDR_SIZE);
|
||||
}
|
||||
|
||||
smbcli_request_calculate_sign_mac(req);
|
||||
|
||||
smbcli_transport_send(req);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -366,34 +417,6 @@ bool smbcli_request_receive(struct smbcli_request *req)
|
||||
return req->state == SMBCLI_REQUEST_DONE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handle oplock break requests from the server - return true if the request was
|
||||
an oplock break
|
||||
*/
|
||||
bool smbcli_handle_oplock_break(struct smbcli_transport *transport, unsigned int len, const uint8_t *hdr, const uint8_t *vwv)
|
||||
{
|
||||
/* we must be very fussy about what we consider an oplock break to avoid
|
||||
matching readbraw replies */
|
||||
if (len != MIN_SMB_SIZE + VWV(8) + NBT_HDR_SIZE ||
|
||||
(CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
|
||||
CVAL(hdr,HDR_COM) != SMBlockingX ||
|
||||
SVAL(hdr, HDR_MID) != 0xFFFF ||
|
||||
SVAL(vwv,VWV(6)) != 0 ||
|
||||
SVAL(vwv,VWV(7)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (transport->oplock.handler) {
|
||||
uint16_t tid = SVAL(hdr, HDR_TID);
|
||||
uint16_t fnum = SVAL(vwv,VWV(2));
|
||||
uint8_t level = CVAL(vwv,VWV(3)+1);
|
||||
transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private_data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
wait for a reply to be received for a packet that just returns an error
|
||||
code and nothing more
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -42,28 +42,6 @@ bool set_smb_signing_common(struct smb_signing_context *sign_info)
|
||||
return true;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Common code before we set a new signing implementation
|
||||
************************************************************/
|
||||
static bool smbcli_set_smb_signing_common(struct smbcli_transport *transport)
|
||||
{
|
||||
if (!set_smb_signing_common(&transport->negotiate.sign_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(transport->negotiate.sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
|
||||
&& !transport->negotiate.sign_info.mandatory_signing) {
|
||||
DEBUG(5, ("SMB Signing is not negotiated by the peer\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* These calls are INCOMPATIBLE with SMB signing */
|
||||
transport->negotiate.readbraw_supported = false;
|
||||
transport->negotiate.writebraw_supported = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mark_packet_signed(struct smb_request_buffer *out)
|
||||
{
|
||||
uint16_t flags2;
|
||||
@ -202,55 +180,6 @@ bool check_signed_incoming_message(struct smb_request_buffer *in, DATA_BLOB *mac
|
||||
return good;
|
||||
}
|
||||
|
||||
static void smbcli_req_allocate_seq_num(struct smbcli_request *req)
|
||||
{
|
||||
req->seq_num = req->transport->negotiate.sign_info.next_seq_num;
|
||||
|
||||
/* some requests (eg. NTcancel) are one way, and the sequence number
|
||||
should be increased by 1 not 2 */
|
||||
if (req->sign_single_increment) {
|
||||
req->transport->negotiate.sign_info.next_seq_num += 1;
|
||||
} else {
|
||||
req->transport->negotiate.sign_info.next_seq_num += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - calculate a MAC to send.
|
||||
************************************************************/
|
||||
void smbcli_request_calculate_sign_mac(struct smbcli_request *req)
|
||||
{
|
||||
#if 0
|
||||
/* enable this when packet signing is preventing you working out why valgrind
|
||||
says that data is uninitialised */
|
||||
file_save("pkt.dat", req->out.buffer, req->out.size);
|
||||
#endif
|
||||
|
||||
switch (req->transport->negotiate.sign_info.signing_state) {
|
||||
case SMB_SIGNING_ENGINE_OFF:
|
||||
break;
|
||||
|
||||
case SMB_SIGNING_ENGINE_BSRSPYL:
|
||||
/* mark the packet as signed - BEFORE we sign it...*/
|
||||
mark_packet_signed(&req->out);
|
||||
|
||||
/* I wonder what BSRSPYL stands for - but this is what MS
|
||||
actually sends! */
|
||||
memcpy((req->out.hdr + HDR_SS_FIELD), "BSRSPYL ", 8);
|
||||
break;
|
||||
|
||||
case SMB_SIGNING_ENGINE_ON:
|
||||
|
||||
smbcli_req_allocate_seq_num(req);
|
||||
sign_outgoing_message(&req->out,
|
||||
&req->transport->negotiate.sign_info.mac_key,
|
||||
req->seq_num);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
SMB signing - NULL implementation
|
||||
|
||||
@ -266,68 +195,6 @@ bool smbcli_set_signing_off(struct smb_signing_context *sign_info)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
SMB signing - TEMP implementation - setup the MAC key.
|
||||
|
||||
*/
|
||||
bool smbcli_temp_set_signing(struct smbcli_transport *transport)
|
||||
{
|
||||
if (!smbcli_set_smb_signing_common(transport)) {
|
||||
return false;
|
||||
}
|
||||
DEBUG(5, ("BSRSPYL SMB signing enabled\n"));
|
||||
smbcli_set_signing_off(&transport->negotiate.sign_info);
|
||||
|
||||
transport->negotiate.sign_info.mac_key = data_blob(NULL, 0);
|
||||
transport->negotiate.sign_info.signing_state = SMB_SIGNING_ENGINE_BSRSPYL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - check a MAC sent by server.
|
||||
************************************************************/
|
||||
/**
|
||||
* Check a packet supplied by the server.
|
||||
* @return false if we had an established signing connection
|
||||
* which had a back checksum, true otherwise
|
||||
*/
|
||||
bool smbcli_request_check_sign_mac(struct smbcli_request *req)
|
||||
{
|
||||
bool good;
|
||||
|
||||
if (!req->transport->negotiate.sign_info.doing_signing &&
|
||||
req->sign_caller_checks) {
|
||||
return true;
|
||||
}
|
||||
|
||||
req->sign_caller_checks = false;
|
||||
|
||||
switch (req->transport->negotiate.sign_info.signing_state)
|
||||
{
|
||||
case SMB_SIGNING_ENGINE_OFF:
|
||||
return true;
|
||||
case SMB_SIGNING_ENGINE_BSRSPYL:
|
||||
return true;
|
||||
|
||||
case SMB_SIGNING_ENGINE_ON:
|
||||
{
|
||||
if (req->in.size < (HDR_SS_FIELD + 8)) {
|
||||
return false;
|
||||
} else {
|
||||
good = check_signed_incoming_message(&req->in,
|
||||
&req->transport->negotiate.sign_info.mac_key,
|
||||
req->seq_num+1);
|
||||
|
||||
return signing_good(&req->transport->negotiate.sign_info,
|
||||
req->seq_num+1, good);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - setup the MAC key.
|
||||
************************************************************/
|
||||
@ -362,45 +229,3 @@ bool smbcli_simple_set_signing(TALLOC_CTX *mem_ctx,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - setup the MAC key.
|
||||
************************************************************/
|
||||
bool smbcli_transport_simple_set_signing(struct smbcli_transport *transport,
|
||||
const DATA_BLOB user_session_key,
|
||||
const DATA_BLOB response)
|
||||
{
|
||||
if (!smbcli_set_smb_signing_common(transport)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return smbcli_simple_set_signing(transport,
|
||||
&transport->negotiate.sign_info,
|
||||
&user_session_key,
|
||||
&response);
|
||||
}
|
||||
|
||||
|
||||
bool smbcli_init_signing(struct smbcli_transport *transport)
|
||||
{
|
||||
transport->negotiate.sign_info.next_seq_num = 0;
|
||||
transport->negotiate.sign_info.mac_key = data_blob(NULL, 0);
|
||||
if (!smbcli_set_signing_off(&transport->negotiate.sign_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (transport->options.signing) {
|
||||
case SMB_SIGNING_OFF:
|
||||
transport->negotiate.sign_info.allow_smb_signing = false;
|
||||
break;
|
||||
case SMB_SIGNING_DEFAULT:
|
||||
case SMB_SIGNING_IF_REQUIRED:
|
||||
transport->negotiate.sign_info.allow_smb_signing = true;
|
||||
break;
|
||||
case SMB_SIGNING_REQUIRED:
|
||||
transport->negotiate.sign_info.allow_smb_signing = true;
|
||||
transport->negotiate.sign_info.mandatory_signing = true;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -232,7 +232,8 @@ static NTSTATUS connect_negprot(struct composite_context *c,
|
||||
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_raw_negotiate_recv(state->req);
|
||||
status = smb_raw_negotiate_recv(state->subreq);
|
||||
TALLOC_FREE(state->subreq);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* next step is a session setup */
|
||||
@ -283,13 +284,19 @@ static NTSTATUS connect_send_negprot(struct composite_context *c,
|
||||
{
|
||||
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
|
||||
|
||||
state->req = smb_raw_negotiate_send(state->transport, io->in.options.unicode, io->in.options.max_protocol);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
/* the socket is up - we can initialise the smbcli transport layer */
|
||||
state->transport = smbcli_transport_init(state->sock, state, true,
|
||||
&io->in.options);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->transport);
|
||||
|
||||
state->req->async.fn = request_handler;
|
||||
state->req->async.private_data = c;
|
||||
state->subreq = smb_raw_negotiate_send(state,
|
||||
state->transport->ev,
|
||||
state->transport,
|
||||
io->in.options.max_protocol);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->subreq);
|
||||
tevent_req_set_callback(state->subreq, subreq_handler, c);
|
||||
state->stage = CONNECT_NEGPROT;
|
||||
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
@ -305,11 +312,6 @@ static NTSTATUS connect_socket(struct composite_context *c,
|
||||
status = smbcli_sock_connect_recv(state->creq, state, &state->sock);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* the socket is up - we can initialise the smbcli transport layer */
|
||||
state->transport = smbcli_transport_init(state->sock, state, true,
|
||||
&io->in.options);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->transport);
|
||||
|
||||
if (is_ipaddress(state->sock->hostname) &&
|
||||
(state->io->in.called_name != NULL)) {
|
||||
/* If connecting to an IP address, we might want the real name
|
||||
@ -320,10 +322,6 @@ static NTSTATUS connect_socket(struct composite_context *c,
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->sock->hostname);
|
||||
}
|
||||
|
||||
status = nbt_name_dup(state->transport, &state->called,
|
||||
&state->transport->called);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* next step is a negprot */
|
||||
return connect_send_negprot(c, io);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "auth/credentials/credentials.h"
|
||||
#include "version.h"
|
||||
#include "param/param.h"
|
||||
#include "libcli/smb/smbXcli_base.h"
|
||||
|
||||
struct sesssetup_state {
|
||||
union smb_sesssetup setup;
|
||||
@ -200,7 +201,9 @@ static void request_handler(struct smbcli_request *req)
|
||||
}
|
||||
session_key_err = gensec_session_key(session->gensec, session, &session->user_session_key);
|
||||
if (NT_STATUS_IS_OK(session_key_err)) {
|
||||
smbcli_transport_simple_set_signing(session->transport, session->user_session_key, null_data_blob);
|
||||
smb1cli_conn_activate_signing(session->transport->conn,
|
||||
session->user_session_key,
|
||||
null_data_blob);
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +216,8 @@ static void request_handler(struct smbcli_request *req)
|
||||
session->vuid = state->io->out.vuid;
|
||||
state->req = smb_raw_sesssetup_send(session, &state->setup);
|
||||
session->vuid = vuid;
|
||||
if (state->req) {
|
||||
if (state->req &&
|
||||
!smb1cli_conn_signing_is_active(state->req->transport->conn)) {
|
||||
state->req->sign_caller_checks = true;
|
||||
}
|
||||
composite_continue_smb(c, state->req, request_handler, c);
|
||||
@ -229,23 +233,19 @@ static void request_handler(struct smbcli_request *req)
|
||||
}
|
||||
|
||||
if (check_req) {
|
||||
bool ok;
|
||||
|
||||
check_req->sign_caller_checks = false;
|
||||
if (!smbcli_request_check_sign_mac(check_req)) {
|
||||
|
||||
ok = smb1cli_conn_check_signing(check_req->transport->conn,
|
||||
check_req->in.buffer, 1);
|
||||
if (!ok) {
|
||||
c->status = NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
talloc_free(check_req);
|
||||
check_req = NULL;
|
||||
}
|
||||
|
||||
/* enforce the local signing required flag */
|
||||
if (NT_STATUS_IS_OK(c->status) && !cli_credentials_is_anonymous(state->io->in.credentials)) {
|
||||
if (!session->transport->negotiate.sign_info.doing_signing
|
||||
&& session->transport->negotiate.sign_info.mandatory_signing) {
|
||||
DEBUG(0, ("SMB signing required, but server does not support it\n"));
|
||||
c->status = NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(c->status)) {
|
||||
composite_error(c, c->status);
|
||||
return;
|
||||
@ -291,8 +291,6 @@ static NTSTATUS session_setup_nt1(struct composite_context *c,
|
||||
DATA_BLOB session_key = data_blob(NULL, 0);
|
||||
int flags = CLI_CRED_NTLM_AUTH;
|
||||
|
||||
smbcli_temp_set_signing(session->transport);
|
||||
|
||||
if (session->options.lanman_auth) {
|
||||
flags |= CLI_CRED_LANMAN_AUTH;
|
||||
}
|
||||
@ -339,10 +337,11 @@ static NTSTATUS session_setup_nt1(struct composite_context *c,
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_OK(nt_status)) {
|
||||
smbcli_transport_simple_set_signing(session->transport, session_key,
|
||||
state->setup.nt1.in.password2);
|
||||
smb1cli_conn_activate_signing(session->transport->conn,
|
||||
session_key,
|
||||
state->setup.nt1.in.password2);
|
||||
set_user_session_key(session, &session_key);
|
||||
|
||||
|
||||
data_blob_free(&session_key);
|
||||
}
|
||||
|
||||
@ -441,8 +440,6 @@ static NTSTATUS session_setup_spnego(struct composite_context *c,
|
||||
state->setup.spnego.in.lanman = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING);
|
||||
state->setup.spnego.in.workgroup = io->in.workgroup;
|
||||
|
||||
smbcli_temp_set_signing(session->transport);
|
||||
|
||||
status = gensec_client_start(session, &session->gensec,
|
||||
io->in.gensec_settings);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
@ -459,7 +456,8 @@ static NTSTATUS session_setup_spnego(struct composite_context *c,
|
||||
return status;
|
||||
}
|
||||
|
||||
status = gensec_set_target_hostname(session->gensec, session->transport->socket->hostname);
|
||||
status = gensec_set_target_hostname(session->gensec,
|
||||
smbXcli_conn_remote_name(session->transport->conn));
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n",
|
||||
nt_errstr(status)));
|
||||
@ -530,7 +528,9 @@ static NTSTATUS session_setup_spnego(struct composite_context *c,
|
||||
* as the session key might be the acceptor subkey
|
||||
* which comes within the response itself
|
||||
*/
|
||||
(*req)->sign_caller_checks = true;
|
||||
if (!smb1cli_conn_signing_is_active((*req)->transport->conn)) {
|
||||
(*req)->sign_caller_checks = true;
|
||||
}
|
||||
|
||||
return (*req)->status;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "librpc/rpc/dcerpc.h"
|
||||
#include "librpc/rpc/dcerpc_proto.h"
|
||||
#include "librpc/rpc/rpc_common.h"
|
||||
#include "../libcli/smb/smbXcli_base.h"
|
||||
|
||||
/* transport private information used by SMB pipe transport */
|
||||
struct smb_private {
|
||||
@ -417,7 +418,7 @@ static const char *smb_target_hostname(struct dcecli_connection *c)
|
||||
{
|
||||
struct smb_private *smb = talloc_get_type(c->transport.private_data, struct smb_private);
|
||||
if (smb == NULL) return "";
|
||||
return smb->tree->session->transport->socket->hostname;
|
||||
return smbXcli_conn_remote_name(smb->tree->session->transport->conn);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -456,9 +457,10 @@ struct composite_context *dcerpc_pipe_open_smb_send(struct dcerpc_pipe *p,
|
||||
/* if we don't have a binding on this pipe yet, then create one */
|
||||
if (p->binding == NULL) {
|
||||
NTSTATUS status;
|
||||
const char *r = smbXcli_conn_remote_name(tree->session->transport->conn);
|
||||
char *s;
|
||||
SMB_ASSERT(tree->session->transport->socket->hostname != NULL);
|
||||
s = talloc_asprintf(p, "ncacn_np:%s", tree->session->transport->socket->hostname);
|
||||
SMB_ASSERT(r != NULL);
|
||||
s = talloc_asprintf(p, "ncacn_np:%s", r);
|
||||
if (s == NULL) return NULL;
|
||||
status = dcerpc_parse_binding(p, s, &p->binding);
|
||||
talloc_free(s);
|
||||
@ -549,7 +551,7 @@ static void pipe_open_recv(struct smbcli_request *req)
|
||||
smb->fnum = state->open->ntcreatex.out.file.fnum;
|
||||
smb->tree = talloc_reference(smb, state->tree);
|
||||
smb->server_name= strupper_talloc(smb,
|
||||
state->tree->session->transport->called.name);
|
||||
smbXcli_conn_remote_name(state->tree->session->transport->conn));
|
||||
if (composite_nomem(smb->server_name, ctx)) return;
|
||||
smb->dead = false;
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "../lib/util/dlinklist.h"
|
||||
#include "param/param.h"
|
||||
#include "libcli/resolve/resolve.h"
|
||||
#include "../libcli/smb/smbXcli_base.h"
|
||||
|
||||
struct cvfs_file {
|
||||
struct cvfs_file *prev, *next;
|
||||
@ -66,7 +67,7 @@ struct async_info {
|
||||
NTSTATUS ntvfs_cifs_init(void);
|
||||
|
||||
#define CHECK_UPSTREAM_OPEN do { \
|
||||
if (! p->transport->socket->sock) { \
|
||||
if (!smbXcli_conn_is_connected(p->transport->conn)) { \
|
||||
req->async_states->state|=NTVFS_ASYNC_STATE_CLOSE; \
|
||||
return NT_STATUS_CONNECTION_DISCONNECTED; \
|
||||
} \
|
||||
|
@ -65,6 +65,14 @@ static struct smbcli_state *open_nbt_connection(struct torture_context *tctx)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
cli->transport = smbcli_transport_init(cli->sock, cli,
|
||||
true, &cli->options);
|
||||
cli->sock = NULL;
|
||||
if (!cli->transport) {
|
||||
torture_comment(tctx, "smbcli_transport_init failed\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return cli;
|
||||
|
||||
failed:
|
||||
@ -360,15 +368,23 @@ static bool run_negprot_nowait(struct torture_context *tctx)
|
||||
torture_comment(tctx, "Filling send buffer\n");
|
||||
|
||||
for (i=0;i<100;i++) {
|
||||
struct smbcli_request *req;
|
||||
req = smb_raw_negotiate_send(cli->transport, lpcfg_unicode(tctx->lp_ctx), PROTOCOL_NT1);
|
||||
struct tevent_req *req;
|
||||
req = smb_raw_negotiate_send(cli, tctx->ev,
|
||||
cli->transport,
|
||||
PROTOCOL_NT1);
|
||||
tevent_loop_once(tctx->ev);
|
||||
if (req->state == SMBCLI_REQUEST_ERROR) {
|
||||
if (!tevent_req_is_in_progress(req)) {
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_raw_negotiate_recv(req);
|
||||
TALLOC_FREE(req);
|
||||
if (i > 0) {
|
||||
torture_comment(tctx, "Failed to fill pipe packet[%d] - %s (ignored)\n", i+1, nt_errstr(req->status));
|
||||
torture_comment(tctx, "Failed to fill pipe packet[%d] - %s (ignored)\n",
|
||||
i+1, nt_errstr(status));
|
||||
break;
|
||||
} else {
|
||||
torture_comment(tctx, "Failed to fill pipe - %s \n", nt_errstr(req->status));
|
||||
torture_comment(tctx, "Failed to fill pipe - %s \n",
|
||||
nt_errstr(status));
|
||||
torture_close_connection(cli);
|
||||
return false;
|
||||
}
|
||||
|
@ -33,6 +33,8 @@
|
||||
#include "libcli/resolve/resolve.h"
|
||||
#include "param/param.h"
|
||||
#include "torture/raw/proto.h"
|
||||
#include "libcli/smb/smbXcli_base.h"
|
||||
#include "../lib/util/util_net.h"
|
||||
|
||||
#define BASEDIR "\\benchlock"
|
||||
#define FNAME BASEDIR "\\lock.dat"
|
||||
@ -336,6 +338,11 @@ bool torture_bench_lock(struct torture_context *torture)
|
||||
|
||||
printf("Opening %d connections\n", nprocs);
|
||||
for (i=0;i<nprocs;i++) {
|
||||
const struct sockaddr_storage *dest_ss;
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
const char *dest_str;
|
||||
uint16_t dest_port;
|
||||
|
||||
state[i].tctx = torture;
|
||||
state[i].mem_ctx = talloc_new(state);
|
||||
state[i].client_num = i;
|
||||
@ -343,20 +350,23 @@ bool torture_bench_lock(struct torture_context *torture)
|
||||
if (!torture_open_connection_ev(&cli, i, torture, torture->ev)) {
|
||||
return false;
|
||||
}
|
||||
talloc_steal(mem_ctx, state);
|
||||
talloc_steal(state[i].mem_ctx, cli);
|
||||
state[i].tree = cli->tree;
|
||||
state[i].dest_host = talloc_strdup(state[i].mem_ctx,
|
||||
cli->tree->session->transport->socket->hostname);
|
||||
|
||||
dest_ss = smbXcli_conn_remote_sockaddr(
|
||||
state[i].tree->session->transport->conn);
|
||||
dest_str = print_sockaddr(addrstr, sizeof(addrstr), dest_ss);
|
||||
dest_port = get_sockaddr_port(dest_ss);
|
||||
|
||||
state[i].dest_host = talloc_strdup(state[i].mem_ctx, dest_str);
|
||||
state[i].dest_ports = talloc_array(state[i].mem_ctx,
|
||||
const char *, 2);
|
||||
state[i].dest_ports[0] = talloc_asprintf(state[i].dest_ports,
|
||||
"%u",
|
||||
cli->tree->session->transport->socket->port);
|
||||
"%u", dest_port);
|
||||
state[i].dest_ports[1] = NULL;
|
||||
state[i].called_name = talloc_strdup(state[i].mem_ctx,
|
||||
cli->tree->session->transport->called.name);
|
||||
state[i].service_type = talloc_strdup(state[i].mem_ctx,
|
||||
cli->tree->device);
|
||||
smbXcli_conn_remote_name(cli->tree->session->transport->conn));
|
||||
state[i].service_type = talloc_strdup(state[i].mem_ctx, "?????");
|
||||
}
|
||||
|
||||
num_connected = i;
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include "libcli/resolve/resolve.h"
|
||||
#include "param/param.h"
|
||||
#include "torture/raw/proto.h"
|
||||
#include "libcli/smb/smbXcli_base.h"
|
||||
#include "../lib/util/util_net.h"
|
||||
|
||||
#define BASEDIR "\\benchopen"
|
||||
|
||||
@ -390,6 +392,11 @@ bool torture_bench_open(struct torture_context *torture)
|
||||
|
||||
printf("Opening %d connections\n", nprocs);
|
||||
for (i=0;i<nprocs;i++) {
|
||||
const struct sockaddr_storage *dest_ss;
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
const char *dest_str;
|
||||
uint16_t dest_port;
|
||||
|
||||
state[i].tctx = torture;
|
||||
state[i].mem_ctx = talloc_new(state);
|
||||
state[i].client_num = i;
|
||||
@ -397,19 +404,23 @@ bool torture_bench_open(struct torture_context *torture)
|
||||
if (!torture_open_connection_ev(&state[i].cli, i, torture, torture->ev)) {
|
||||
return false;
|
||||
}
|
||||
talloc_steal(mem_ctx, state);
|
||||
talloc_steal(state[i].mem_ctx, state[i].cli);
|
||||
state[i].tree = state[i].cli->tree;
|
||||
state[i].dest_host = talloc_strdup(state[i].mem_ctx,
|
||||
state[i].cli->tree->session->transport->socket->hostname);
|
||||
|
||||
dest_ss = smbXcli_conn_remote_sockaddr(
|
||||
state[i].tree->session->transport->conn);
|
||||
dest_str = print_sockaddr(addrstr, sizeof(addrstr), dest_ss);
|
||||
dest_port = get_sockaddr_port(dest_ss);
|
||||
|
||||
state[i].dest_host = talloc_strdup(state[i].mem_ctx, dest_str);
|
||||
state[i].dest_ports = talloc_array(state[i].mem_ctx,
|
||||
const char *, 2);
|
||||
state[i].dest_ports[0] = talloc_asprintf(state[i].dest_ports,
|
||||
"%u", state[i].cli->tree->session->transport->socket->port);
|
||||
"%u", dest_port);
|
||||
state[i].dest_ports[1] = NULL;
|
||||
state[i].called_name = talloc_strdup(state[i].mem_ctx,
|
||||
state[i].cli->tree->session->transport->called.name);
|
||||
state[i].service_type = talloc_strdup(state[i].mem_ctx,
|
||||
state[i].cli->tree->device);
|
||||
smbXcli_conn_remote_name(state[i].tree->session->transport->conn));
|
||||
state[i].service_type = talloc_strdup(state[i].mem_ctx, "?????");
|
||||
}
|
||||
|
||||
num_connected = i;
|
||||
|
Loading…
x
Reference in New Issue
Block a user