1
0
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:
Stefan Metzmacher 2011-09-23 08:35:17 +02:00
parent 99ef6a4bec
commit 4afbda221c
20 changed files with 1090 additions and 1869 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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; \
} \

View File

@ -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;
}

View File

@ -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;

View File

@ -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;