summaryrefslogtreecommitdiff
path: root/source4/libcli/raw/clitransport.c
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2011-09-23 08:35:17 +0200
committerStefan Metzmacher <metze@samba.org>2011-11-30 15:13:36 +0100
commit4afbda221c20ffa36a1d1e37ef11f86073a49da6 (patch)
tree8d9cc7d03f5bb4ea4ffa761dfee0ba7e9cdc005c /source4/libcli/raw/clitransport.c
parent99ef6a4bec1058b3649e5e72f8ea85f6df93a154 (diff)
downloadsamba-4afbda221c20ffa36a1d1e37ef11f86073a49da6.tar.gz
samba-4afbda221c20ffa36a1d1e37ef11f86073a49da6.tar.bz2
samba-4afbda221c20ffa36a1d1e37ef11f86073a49da6.zip
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
Diffstat (limited to 'source4/libcli/raw/clitransport.c')
-rw-r--r--source4/libcli/raw/clitransport.c713
1 files changed, 372 insertions, 341 deletions
diff --git a/source4/libcli/raw/clitransport.c b/source4/libcli/raw/clitransport.c
index b83a07063c..f1f41bcb78 100644
--- a/source4/libcli/raw/clitransport.c
+++ b/source4/libcli/raw/clitransport.c
@@ -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);
-
- 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);
+ sock->sock->fd = -1;
+ TALLOC_FREE(sock);
+
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,293 +146,383 @@ _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);
+ transport->idle.te = tevent_add_timer(transport->ev,
+ 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)
+ process some read/write requests that are pending
+ return false if the socket is dead
+*/
+_PUBLIC_ bool smbcli_transport_process(struct smbcli_transport *transport)
{
- 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;
+ struct tevent_req *subreq = NULL;
+ int ret;
- 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;
+ if (!smbXcli_conn_is_connected(transport->conn)) {
+ return false;
}
- /* 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 (!smbXcli_conn_has_async_calls(transport->conn)) {
+ return true;
}
- 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);
+ /*
+ * 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;
}
- /* match the incoming request against the list of pending requests */
- for (req=transport->pending_recv; req; req=req->next) {
- if (req->mid == mid) break;
+ ret = tevent_loop_once(transport->ev);
+ if (ret != 0) {
+ return false;
}
- /* see if it's a ntcancel reply for the current MID */
- req = smbcli_handle_ntcancel_reply(req, len, hdr);
+ TALLOC_FREE(subreq);
- if (!req) {
- DEBUG(1,("Discarding unmatched reply with mid %d op %d\n", mid, op));
- goto error;
+ if (!smbXcli_conn_is_connected(transport->conn)) {
+ return false;
}
- /* 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;
+ return true;
+}
+
+static void smbcli_transport_break_handler(struct tevent_req *subreq);
+static void smbcli_request_done(struct tevent_req *subreq);
- /* handle NBT session replies */
- if (req->in.size >= 4 && req->in.buffer[0] != 0) {
- req->status = NT_STATUS_OK;
- goto async;
+struct tevent_req *smbcli_transport_setup_subreq(struct smbcli_request *req)
+{
+ 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;
+
+ 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;
+ }
+ 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;
}
- /* handle non-SMB replies */
- if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE) {
- req->state = SMBCLI_REQUEST_ERROR;
- goto error;
+ ZERO_STRUCT(req->out);
+
+ return subreq;
+}
+
+/*
+ put a request into the send queue
+*/
+void smbcli_transport_send(struct smbcli_request *req)
+{
+ 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;
+
+ 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;
+ }
}
- 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;
+ subreq = smbcli_transport_setup_subreq(req);
+ if (subreq == NULL) {
req->state = SMBCLI_REQUEST_ERROR;
- goto error;
+ req->status = NT_STATUS_NO_MEMORY;
+ return;
}
- 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));
+ 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;
}
- }
- 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);
+ if (!tevent_req_is_in_progress(req->subreqs[i])) {
+ req->state = SMBCLI_REQUEST_ERROR;
+ req->status = NT_STATUS_INTERNAL_ERROR;
+ return;
}
- } else {
- transport->error.e.nt_status = NT_STATUS(IVAL(req->in.hdr, HDR_RCLS));
}
+ num_subreqs = i;
- 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;
+ req->state = SMBCLI_REQUEST_RECV;
+ tevent_req_set_callback(req->subreqs[0], smbcli_request_done, req);
+
+ status = smb1cli_req_chain_submit(req->subreqs, num_subreqs);
+ if (!NT_STATUS_IS_OK(status)) {
+ smbXcli_conn_disconnect(transport->conn, status);
}
+}
- 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;
- };
+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;
+ }
+ }
-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 */
+ /*
+ * 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;
- req->state = SMBCLI_REQUEST_DONE;
+ len += recv_iov[i].iov_len;
- if (req->recv_helper.fn) {
- /*
- * let the recv helper decide in
- * what state the request really is
- */
- req->state = req->recv_helper.fn(req);
+ c2 += i;
+ len += i;
- /* if more parts are needed, wait for them */
- if (req->state <= SMBCLI_REQUEST_RECV) {
- return NT_STATUS_OK;
+ if (recv_iov[i].iov_len == 0) {
+ continue;
}
- }
- 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);
+ 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;
}
- } else {
- talloc_free(buffer);
}
- return NT_STATUS_OK;
-}
-
-/*
- process some read/write requests that are pending
- return false if the socket is dead
-*/
-_PUBLIC_ bool smbcli_transport_process(struct smbcli_transport *transport)
-{
- NTSTATUS status;
- size_t npending;
- packet_queue_run(transport->packet);
- if (transport->socket->sock == NULL) {
- return false;
- }
+ /* 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;
- status = socket_pending(transport->socket->sock, &npending);
- if (NT_STATUS_IS_OK(status) && npending > 0) {
- packet_recv(transport->packet);
- }
- if (transport->socket->sock == NULL) {
- return false;
+ 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);
}
- 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)
-{
- struct smbcli_request *req = talloc_get_type(private_data, struct smbcli_request);
+ smb_setup_bufinfo(req);
- if (req->state == SMBCLI_REQUEST_RECV) {
- DLIST_REMOVE(req->transport->pending_recv, 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->status = NT_STATUS_IO_TIMEOUT;
- req->state = SMBCLI_REQUEST_ERROR;
+
+ req->state = SMBCLI_REQUEST_DONE;
if (req->async.fn) {
req->async.fn(req);
}
}
-
-/*
- 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)
+static void smbcli_transport_break_handler(struct tevent_req *subreq)
{
- DATA_BLOB blob;
+ struct smbcli_transport *transport =
+ tevent_req_callback_data(subreq,
+ struct smbcli_transport);
NTSTATUS status;
-
- /* check if the transport is dead */
- if (req->transport->socket->sock == NULL) {
- req->state = SMBCLI_REQUEST_ERROR;
- req->status = NT_STATUS_NET_WRITE_FAULT;
- return;
+ 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,
}
-
- blob = data_blob_const(req->out.buffer, req->out.size);
- status = packet_send(req->transport->packet, blob);
+ };
+ 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)) {
- req->state = SMBCLI_REQUEST_ERROR;
- req->status = status;
+ TALLOC_FREE(recv_iov);
+ smbcli_transport_dead(transport, status);
return;
}
- 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;
- }
-
- req->state = SMBCLI_REQUEST_RECV;
- DLIST_ADD(req->transport->pending_recv, 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);
+ /*
+ * 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);
}