diff options
author | Stefan Metzmacher <metze@samba.org> | 2011-09-23 08:35:17 +0200 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2011-11-30 15:13:36 +0100 |
commit | 4afbda221c20ffa36a1d1e37ef11f86073a49da6 (patch) | |
tree | 8d9cc7d03f5bb4ea4ffa761dfee0ba7e9cdc005c /source4/libcli | |
parent | 99ef6a4bec1058b3649e5e72f8ea85f6df93a154 (diff) | |
download | samba-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')
-rw-r--r-- | source4/libcli/cliconnect.c | 23 | ||||
-rw-r--r-- | source4/libcli/libcli.h | 3 | ||||
-rw-r--r-- | source4/libcli/raw/clioplock.c | 11 | ||||
-rw-r--r-- | source4/libcli/raw/clisession.c | 3 | ||||
-rw-r--r-- | source4/libcli/raw/clisocket.c | 13 | ||||
-rw-r--r-- | source4/libcli/raw/clitransport.c | 713 | ||||
-rw-r--r-- | source4/libcli/raw/libcliraw.h | 68 | ||||
-rw-r--r-- | source4/libcli/raw/rawnegotiate.c | 253 | ||||
-rw-r--r-- | source4/libcli/raw/rawnotify.c | 64 | ||||
-rw-r--r-- | source4/libcli/raw/rawreadwrite.c | 6 | ||||
-rw-r--r-- | source4/libcli/raw/rawrequest.c | 227 | ||||
-rw-r--r-- | source4/libcli/raw/rawtrans.c | 1126 | ||||
-rw-r--r-- | source4/libcli/raw/smb_signing.c | 175 | ||||
-rw-r--r-- | source4/libcli/smb_composite/connect.c | 28 | ||||
-rw-r--r-- | source4/libcli/smb_composite/sesssetup.c | 42 |
15 files changed, 968 insertions, 1787 deletions
diff --git a/source4/libcli/cliconnect.c b/source4/libcli/cliconnect.c index a8e86a0488..45d8d2a776 100644 --- a/source4/libcli/cliconnect.c +++ b/source4/libcli/cliconnect.c @@ -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); } diff --git a/source4/libcli/libcli.h b/source4/libcli/libcli.h index 9f661e3f4d..9e817408de 100644 --- a/source4/libcli/libcli.h +++ b/source4/libcli/libcli.h @@ -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; diff --git a/source4/libcli/raw/clioplock.c b/source4/libcli/raw/clioplock.c index 42ac6b517b..396ab96445 100644 --- a/source4/libcli/raw/clioplock.c +++ b/source4/libcli/raw/clioplock.c @@ -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; } diff --git a/source4/libcli/raw/clisession.c b/source4/libcli/raw/clisession.c index 41765bfb2b..d68f309519 100644 --- a/source4/libcli/raw/clisession.c +++ b/source4/libcli/raw/clisession.c @@ -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; } diff --git a/source4/libcli/raw/clisocket.c b/source4/libcli/raw/clisocket.c index 258fe8b091..dd3ea3971c 100644 --- a/source4/libcli/raw/clisocket.c +++ b/source4/libcli/raw/clisocket.c @@ -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; -} - 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); } diff --git a/source4/libcli/raw/libcliraw.h b/source4/libcli/raw/libcliraw.h index b3d32273b2..81bf715f08 100644 --- a/source4/libcli/raw/libcliraw.h +++ b/source4/libcli/raw/libcliraw.h @@ -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__ */ diff --git a/source4/libcli/raw/rawnegotiate.c b/source4/libcli/raw/rawnegotiate.c index 9d6c9ffaf2..9b0ed38cf0 100644 --- a/source4/libcli/raw/rawnegotiate.c +++ b/source4/libcli/raw/rawnegotiate.c @@ -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) -{ - struct smbcli_request *req; - int i; - uint16_t flags2 = 0; +static void smb_raw_negotiate_done(struct tevent_req *subreq); - req = smbcli_request_setup_transport(transport, SMBnegprot, 0, 0); - if (!req) { +struct tevent_req *smb_raw_negotiate_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbcli_transport *transport, + int maxprotocol) +{ + struct tevent_req *req; + struct smb_raw_negotiate_state *state; + struct tevent_req *subreq; + uint32_t timeout_msec = transport->options.request_timeout * 1000; + + req = tevent_req_create(mem_ctx, &state, + struct smb_raw_negotiate_state);; + if (req == NULL) { return NULL; } - - 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; + state->transport = transport; + + 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; } -/* - Send a negprot command. -*/ -NTSTATUS smb_raw_negotiate_recv(struct smbcli_request *req) +static void smb_raw_negotiate_done(struct tevent_req *subreq) { - struct smbcli_transport *transport = req->transport; - int protocol; - - if (!smbcli_request_receive(req) || - smbcli_request_is_error(req)) { - return smbcli_request_destroy(req); + 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; } - SMBCLI_CHECK_MIN_WCT(req, 1); - - protocol = SVALS(req->in.vwv, VWV(0)); + n->protocol = smbXcli_conn_protocol(c); - 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 */ - } + 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);; - if (transport->negotiate.capabilities & CAP_RAW_MODE) { - transport->negotiate.readbraw_supported = true; - transport->negotiate.writebraw_supported = true; - } + /* 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 (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; + if (n->capabilities & CAP_EXTENDED_SECURITY) { + const DATA_BLOB *b = smbXcli_conn_server_gss_blob(c); + if (b) { + n->secblob = *b; } - 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; + const uint8_t *p = smb1cli_conn_server_challenge(c); + if (p) { + n->secblob = data_blob_const(p, 8); + } } - if (!transport->options.ntstatus_support) { - transport->negotiate.capabilities &= ~CAP_STATUS32; - } + n->readbraw_supported = smb1cli_conn_server_readbraw(c); + n->readbraw_supported = smb1cli_conn_server_writebraw(c); + n->lockread_supported = smb1cli_conn_server_lockread(c); - if (!transport->options.use_level2_oplocks) { - transport->negotiate.capabilities &= ~CAP_LEVEL_II_OPLOCKS; - } + tevent_req_done(req); +} -failed: - return smbcli_request_destroy(req); +/* + Send a negprot command. +*/ +NTSTATUS smb_raw_negotiate_recv(struct tevent_req *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; } diff --git a/source4/libcli/raw/rawnotify.c b/source4/libcli/raw/rawnotify.c index 40256aa405..dcb979b28a 100644 --- a/source4/libcli/raw/rawnotify.c +++ b/source4/libcli/raw/rawnotify.c @@ -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) @@ -101,68 +101,22 @@ _PUBLIC_ NTSTATUS smb_raw_changenotify_recv(struct smbcli_request *req, } /**************************************************************************** - 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 note that this request does not expect a response! ****************************************************************************/ NTSTATUS smb_raw_ntcancel(struct smbcli_request *oldreq) { - struct smbcli_request *req; - - req = smbcli_request_setup_transport(oldreq->transport, SMBntcancel, 0, 0); - - 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)); + bool ok; - /* 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); + if (oldreq->subreqs[0] == NULL) { + return NT_STATUS_OK; + } - 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; } diff --git a/source4/libcli/raw/rawreadwrite.c b/source4/libcli/raw/rawreadwrite.c index 68977ebd3e..d3f5518e01 100644 --- a/source4/libcli/raw/rawreadwrite.c +++ b/source4/libcli/raw/rawreadwrite.c @@ -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; } diff --git a/source4/libcli/raw/rawrequest.c b/source4/libcli/raw/rawrequest.c index ae68fb0cd3..1b4c8c7524 100644 --- a/source4/libcli/raw/rawrequest.c +++ b/source4/libcli/raw/rawrequest.c @@ -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; @@ -81,52 +75,34 @@ _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 + setup a SMB packet at transport level */ -struct smbcli_request *smbcli_request_setup_nonsmb(struct smbcli_transport *transport, size_t size) +struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport, + uint8_t command, unsigned int wct, unsigned int buflen) { struct smbcli_request *req; + size_t size; - req = talloc(transport, struct smbcli_request); + size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen; + + req = talloc_zero(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); + req->out.buffer = talloc_zero_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 -*/ -struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport, - uint8_t command, unsigned int wct, unsigned int buflen) -{ - struct smbcli_request *req; - - req = smbcli_request_setup_nonsmb(transport, NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen); - - 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; + } + + wct_ofs = smb1cli_req_wct_ofs(req->subreqs, 1); + + size = NBT_HDR_SIZE + wct_ofs + 1 + VWV(wct) + 2 + buflen; + + req->out.size = size; - req->out.vwv = req->out.buffer + req->out.size + 1; - SCVAL(req->out.vwv, -1, wct); + /* 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; - - if (CVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE) { - return NT_STATUS_NOT_FOUND; + 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 (req->subreqs[0] != 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; + if (req->subreqs[1] == NULL) { + return NT_STATUS_INVALID_PARAMETER_MIX; } - 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->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.data = req->in.vwv + 2 + req->in.wct * 2; - req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct)); - /* fix the bufinfo */ + /* 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); + 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 diff --git a/source4/libcli/raw/rawtrans.c b/source4/libcli/raw/rawtrans.c index dd017715c7..8e16e5b911 100644 --- a/source4/libcli/raw/rawtrans.c +++ b/source4/libcli/raw/rawtrans.c @@ -19,513 +19,201 @@ */ #include "includes.h" -#include "../lib/util/dlinklist.h" +#include <tevent.h> #include "libcli/raw/libcliraw.h" #include "libcli/raw/raw_proto.h" +#include "../libcli/smb/smbXcli_base.h" -#define TORTURE_TRANS_DATA 0 +static void smb_raw_trans_backend_done(struct tevent_req *subreq); -/* - check out of bounds for incoming data -*/ -static bool raw_trans_oob(struct smbcli_request *req, - unsigned int offset, unsigned int count) -{ - uint8_t *ptr; - - if (count == 0) { - return false; - } - - ptr = req->in.hdr + offset; - - /* be careful with wraparound! */ - if ((uintptr_t)ptr < (uintptr_t)req->in.data || - (uintptr_t)ptr >= (uintptr_t)req->in.data + req->in.data_size || - count > req->in.data_size || - (uintptr_t)ptr + count > (uintptr_t)req->in.data + req->in.data_size) { - return true; - } - return false; -} - -static size_t raw_trans_space_left(struct smbcli_request *req) -{ - if (req->transport->negotiate.max_xmit <= req->out.size) { - return 0; - } - - return req->transport->negotiate.max_xmit - req->out.size; -} - -struct smb_raw_trans2_recv_state { - uint8_t command; - uint32_t params_total; - uint32_t data_total; - uint32_t params_left; - uint32_t data_left; - bool got_first; - uint32_t recvd_data; - uint32_t recvd_param; - struct smb_trans2 io; -}; - -NTSTATUS smb_raw_trans2_recv(struct smbcli_request *req, - TALLOC_CTX *mem_ctx, - struct smb_trans2 *parms) -{ - struct smb_raw_trans2_recv_state *state; - - if (!smbcli_request_receive(req) || - smbcli_request_is_error(req)) { - goto failed; - } - - state = talloc_get_type(req->recv_helper.private_data, - struct smb_raw_trans2_recv_state); - - parms->out = state->io.out; - talloc_steal(mem_ctx, parms->out.setup); - talloc_steal(mem_ctx, parms->out.params.data); - talloc_steal(mem_ctx, parms->out.data.data); - talloc_free(state); - - ZERO_STRUCT(req->recv_helper); - -failed: - return smbcli_request_destroy(req); -} - -static enum smbcli_request_state smb_raw_trans2_ship_rest(struct smbcli_request *req, - struct smb_raw_trans2_recv_state *state); - -/* - * This helper returns SMBCLI_REQUEST_RECV until all data has arrived - */ -static enum smbcli_request_state smb_raw_trans2_recv_helper(struct smbcli_request *req) -{ - struct smb_raw_trans2_recv_state *state = talloc_get_type(req->recv_helper.private_data, - struct smb_raw_trans2_recv_state); - uint16_t param_count, param_ofs, param_disp; - uint16_t data_count, data_ofs, data_disp; - uint16_t total_data, total_param; - uint8_t setup_count; - - /* - * An NT RPC pipe call can return ERRDOS, ERRmoredata - * to a trans call. This is not an error and should not - * be treated as such. - */ - if (smbcli_request_is_error(req)) { - goto failed; - } - - if (state->params_left > 0 || state->data_left > 0) { - return smb_raw_trans2_ship_rest(req, state); - } - - SMBCLI_CHECK_MIN_WCT(req, 10); - - total_data = SVAL(req->in.vwv, VWV(1)); - total_param = SVAL(req->in.vwv, VWV(0)); - setup_count = CVAL(req->in.vwv, VWV(9)); - - param_count = SVAL(req->in.vwv, VWV(3)); - param_ofs = SVAL(req->in.vwv, VWV(4)); - param_disp = SVAL(req->in.vwv, VWV(5)); - - data_count = SVAL(req->in.vwv, VWV(6)); - data_ofs = SVAL(req->in.vwv, VWV(7)); - data_disp = SVAL(req->in.vwv, VWV(8)); - - if (!state->got_first) { - if (total_param > 0) { - state->io.out.params = data_blob_talloc(state, NULL, total_param); - if (!state->io.out.params.data) { - goto nomem; - } - } - - if (total_data > 0) { - state->io.out.data = data_blob_talloc(state, NULL, total_data); - if (!state->io.out.data.data) { - goto nomem; - } - } - - if (setup_count > 0) { - uint16_t i; - - SMBCLI_CHECK_WCT(req, 10 + setup_count); - - state->io.out.setup_count = setup_count; - state->io.out.setup = talloc_array(state, uint16_t, setup_count); - if (!state->io.out.setup) { - goto nomem; - } - for (i=0; i < setup_count; i++) { - state->io.out.setup[i] = SVAL(req->in.vwv, VWV(10+i)); - } - } - - state->got_first = true; - } - - if (total_data > state->io.out.data.length || - total_param > state->io.out.params.length) { - /* they must *only* shrink */ - DEBUG(1,("smb_raw_trans2_recv_helper: data/params expanded!\n")); - req->status = NT_STATUS_BUFFER_TOO_SMALL; - goto failed; - } - - state->io.out.data.length = total_data; - state->io.out.params.length = total_param; - - if (data_count + data_disp > total_data || - param_count + param_disp > total_param) { - DEBUG(1,("smb_raw_trans2_recv_helper: Buffer overflow\n")); - req->status = NT_STATUS_BUFFER_TOO_SMALL; - goto failed; - } - - /* check the server isn't being nasty */ - if (raw_trans_oob(req, param_ofs, param_count) || - raw_trans_oob(req, data_ofs, data_count)) { - DEBUG(1,("smb_raw_trans2_recv_helper: out of bounds parameters!\n")); - req->status = NT_STATUS_BUFFER_TOO_SMALL; - goto failed; - } - - if (data_count) { - memcpy(state->io.out.data.data + data_disp, - req->in.hdr + data_ofs, - data_count); - } - - if (param_count) { - memcpy(state->io.out.params.data + param_disp, - req->in.hdr + param_ofs, - param_count); - } - - state->recvd_param += param_count; - state->recvd_data += data_count; - - if (state->recvd_data < total_data || - state->recvd_param < total_param) { - - /* we don't need the in buffer any more */ - talloc_free(req->in.buffer); - ZERO_STRUCT(req->in); - - /* we still wait for more data */ - DEBUG(10,("smb_raw_trans2_recv_helper: more data needed\n")); - return SMBCLI_REQUEST_RECV; - } - - DEBUG(10,("smb_raw_trans2_recv_helper: done\n")); - return SMBCLI_REQUEST_DONE; - -nomem: - req->status = NT_STATUS_NO_MEMORY; -failed: - return SMBCLI_REQUEST_ERROR; -} - -_PUBLIC_ NTSTATUS smb_raw_trans_recv(struct smbcli_request *req, - TALLOC_CTX *mem_ctx, - struct smb_trans2 *parms) +static struct smbcli_request *smb_raw_trans_backend_send(struct smbcli_tree *tree, + struct smb_trans2 *parms, + uint8_t command) { - return smb_raw_trans2_recv(req, mem_ctx, parms); -} - - -/* - trans/trans2 raw async interface - only BLOBs used in this interface. -*/ -struct smbcli_request *smb_raw_trans_send_backend(struct smbcli_tree *tree, - struct smb_trans2 *parms, - uint8_t command) -{ - struct smb_raw_trans2_recv_state *state; struct smbcli_request *req; - int i; - int padding; - size_t space_left; - size_t namelen = 0; - DATA_BLOB params_chunk; - uint16_t ofs; - uint16_t params_ofs = 0; - DATA_BLOB data_chunk; - uint16_t data_ofs = 0; - - if (parms->in.params.length > UINT16_MAX || - parms->in.data.length > UINT16_MAX) { - DEBUG(3,("Attempt to send invalid trans2 request (params %u, data %u)\n", - (unsigned)parms->in.params.length, (unsigned)parms->in.data.length)); + 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; + const char *pipe_name = NULL; + uint8_t s; + uint32_t timeout_msec; + uint32_t tmp; + + tmp = parms->in.params.length + parms->in.data.length; + + req = smbcli_request_setup(tree, command, parms->in.setup_count, tmp); + if (req == NULL) { return NULL; } - - - if (command == SMBtrans) - padding = 1; - else - padding = 3; - - req = smbcli_request_setup(tree, command, - 14 + parms->in.setup_count, - padding); - if (!req) { - return NULL; - } - - state = talloc_zero(req, struct smb_raw_trans2_recv_state); - if (!state) { - smbcli_request_destroy(req); - return NULL; - } - - state->command = command; - - /* make sure we don't leak data via the padding */ - memset(req->out.data, 0, padding); - - /* Watch out, this changes the req->out.* pointers */ - if (command == SMBtrans && parms->in.trans_name) { - namelen = smbcli_req_append_string(req, parms->in.trans_name, - STR_TERMINATE); - } - - ofs = PTR_DIFF(req->out.data,req->out.hdr)+padding+namelen; - - /* see how much bytes of the params block we can ship in the first request */ - space_left = raw_trans_space_left(req); - - params_chunk.length = MIN(parms->in.params.length, space_left); - params_chunk.data = parms->in.params.data; - params_ofs = ofs; - - state->params_left = parms->in.params.length - params_chunk.length; - - if (state->params_left > 0) { - /* we copy the whole params block, if needed we can optimize that latter */ - state->io.in.params = data_blob_talloc(state, NULL, parms->in.params.length); - if (!state->io.in.params.data) { - smbcli_request_destroy(req); - return NULL; - } - memcpy(state->io.in.params.data, - parms->in.params.data, - parms->in.params.length); - } - /* see how much bytes of the data block we can ship in the first request */ - space_left -= params_chunk.length; + 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); -#if TORTURE_TRANS_DATA - if (space_left > 1) { - space_left /= 2; - } -#endif - - data_chunk.length = MIN(parms->in.data.length, space_left); - data_chunk.data = parms->in.data.data; - data_ofs = params_ofs + params_chunk.length; - - state->data_left = parms->in.data.length - data_chunk.length; + clear_flags = ~additional_flags; + clear_flags2 = ~additional_flags2; - if (state->data_left > 0) { - /* we copy the whole params block, if needed we can optimize that latter */ - state->io.in.data = data_blob_talloc(state, NULL, parms->in.data.length); - if (!state->io.in.data.data) { - smbcli_request_destroy(req); - return NULL; - } - memcpy(state->io.in.data.data, - parms->in.data.data, - parms->in.data.length); - } + timeout_msec = req->transport->options.request_timeout * 1000; - state->params_total = parms->in.params.length; - state->data_total = parms->in.data.length; - - /* primary request */ - SSVAL(req->out.vwv,VWV(0),parms->in.params.length); - SSVAL(req->out.vwv,VWV(1),parms->in.data.length); - SSVAL(req->out.vwv,VWV(2),parms->in.max_param); - SSVAL(req->out.vwv,VWV(3),parms->in.max_data); - SCVAL(req->out.vwv,VWV(4),parms->in.max_setup); - SCVAL(req->out.vwv,VWV(4)+1,0); /* reserved */ - SSVAL(req->out.vwv,VWV(5),parms->in.flags); - SIVAL(req->out.vwv,VWV(6),parms->in.timeout); - SSVAL(req->out.vwv,VWV(8),0); /* reserved */ - SSVAL(req->out.vwv,VWV(9),params_chunk.length); - SSVAL(req->out.vwv,VWV(10),params_ofs); - SSVAL(req->out.vwv,VWV(11),data_chunk.length); - SSVAL(req->out.vwv,VWV(12),data_ofs); - SCVAL(req->out.vwv,VWV(13),parms->in.setup_count); - SCVAL(req->out.vwv,VWV(13)+1,0); /* reserved */ - for (i=0;i<parms->in.setup_count;i++) { - SSVAL(req->out.vwv,VWV(14)+VWV(i),parms->in.setup[i]); + for (s=0; s < parms->in.setup_count; s++) { + SSVAL(req->out.vwv, VWV(s), parms->in.setup[s]); } - smbcli_req_append_blob(req, ¶ms_chunk); - smbcli_req_append_blob(req, &data_chunk); - /* add the helper which will check that all multi-part replies are - in before an async client callack will be issued */ - req->recv_helper.fn = smb_raw_trans2_recv_helper; - req->recv_helper.private_data = state; + memcpy(req->out.data, + parms->in.params.data, + parms->in.params.length); + memcpy(req->out.data + parms->in.params.length, + parms->in.data.data, + parms->in.data.length); - if (!smbcli_request_send(req)) { - smbcli_request_destroy(req); + if (command == SMBtrans && parms->in.trans_name) { + pipe_name = parms->in.trans_name; + } + + req->subreqs[0] = smb1cli_trans_send(req, + req->transport->ev, + req->transport->conn, + command, + additional_flags, + clear_flags, + additional_flags2, + clear_flags2, + timeout_msec, + pid, tid, uid, + pipe_name, + 0xFFFF, /* fid */ + 0, /* function */ + parms->in.flags, + (uint16_t *)req->out.vwv, + parms->in.setup_count, + parms->in.max_setup, + req->out.data, + parms->in.params.length, + parms->in.max_param, + req->out.data+ + parms->in.params.length, + parms->in.data.length, + parms->in.max_data); + if (req->subreqs[0] == NULL) { + talloc_free(req); return NULL; } + tevent_req_set_callback(req->subreqs[0], + smb_raw_trans_backend_done, + req); return req; } -static enum smbcli_request_state smb_raw_trans2_ship_next(struct smbcli_request *req, - struct smb_raw_trans2_recv_state *state) +static void smb_raw_trans_backend_done(struct tevent_req *subreq) { - struct smbcli_request *req2; - size_t space_left; - DATA_BLOB params_chunk; - uint16_t ofs; - uint16_t params_ofs = 0; - uint16_t params_disp = 0; - DATA_BLOB data_chunk; - uint16_t data_ofs = 0; - uint16_t data_disp = 0; - uint8_t wct; - - if (state->command == SMBtrans2) { - wct = 9; - } else { - wct = 8; + struct smbcli_request *req = + tevent_req_callback_data(subreq, + struct smbcli_request); + struct smbcli_transport *transport = req->transport; + uint16_t *setup = NULL; + uint8_t num_setup = 0; + uint8_t s; + uint8_t *param = NULL; + uint32_t num_param = 0; + uint8_t *data = NULL; + uint32_t num_data = 0; + + req->status = smb1cli_trans_recv(req->subreqs[0], req, + &req->flags2, + &setup, + 0, /* min_setup */ + &num_setup, + ¶m, + 0, /* min_param */ + &num_param, + &data, + 0, /* min_data */ + &num_data); + TALLOC_FREE(req->subreqs[0]); + if (NT_STATUS_IS_ERR(req->status)) { + req->state = SMBCLI_REQUEST_ERROR; + transport->error.e.nt_status = req->status; + transport->error.etype = ETYPE_SMB; + if (req->async.fn) { + req->async.fn(req); + } + return; + } + + req->trans2.out.setup_count = num_setup; + req->trans2.out.setup = talloc_array(req, uint16_t, num_setup); + if (req->trans2.out.setup == NULL) { + req->state = SMBCLI_REQUEST_ERROR; + req->status = NT_STATUS_NO_MEMORY; + transport->error.e.nt_status = req->status; + transport->error.etype = ETYPE_SMB; + if (req->async.fn) { + req->async.fn(req); + } + return; } - - req2 = smbcli_request_setup(req->tree, state->command+1, wct, 0); - if (!req2) { - goto nomem; + for (s = 0; s < num_setup; s++) { + req->trans2.out.setup[s] = SVAL(setup, VWV(s)); } - req2->mid = req->mid; - SSVAL(req2->out.hdr, HDR_MID, req2->mid); - - ofs = PTR_DIFF(req2->out.data,req2->out.hdr); - - /* see how much bytes of the params block we can ship in the first request */ - space_left = raw_trans_space_left(req2); - - params_disp = state->io.in.params.length - state->params_left; - params_chunk.length = MIN(state->params_left, space_left); - params_chunk.data = state->io.in.params.data + params_disp; - params_ofs = ofs; - state->params_left -= params_chunk.length; - - /* see how much bytes of the data block we can ship in the first request */ - space_left -= params_chunk.length; - -#if TORTURE_TRANS_DATA - if (space_left > 1) { - space_left /= 2; - } -#endif - - data_disp = state->io.in.data.length - state->data_left; - data_chunk.length = MIN(state->data_left, space_left); - data_chunk.data = state->io.in.data.data + data_disp; - data_ofs = params_ofs+params_chunk.length; - - state->data_left -= data_chunk.length; - - SSVAL(req2->out.vwv,VWV(0), state->params_total); - SSVAL(req2->out.vwv,VWV(1), state->data_total); - SSVAL(req2->out.vwv,VWV(2), params_chunk.length); - SSVAL(req2->out.vwv,VWV(3), params_ofs); - SSVAL(req2->out.vwv,VWV(4), params_disp); - SSVAL(req2->out.vwv,VWV(5), data_chunk.length); - SSVAL(req2->out.vwv,VWV(6), data_ofs); - SSVAL(req2->out.vwv,VWV(7), data_disp); - if (wct == 9) { - SSVAL(req2->out.vwv,VWV(8), 0xFFFF); - } + req->trans2.out.params.data = param; + req->trans2.out.params.length = num_param; - smbcli_req_append_blob(req2, ¶ms_chunk); - smbcli_req_append_blob(req2, &data_chunk); + req->trans2.out.data.data = data; + req->trans2.out.data.length = num_data; - /* - * it's a one way request but we need - * the seq_num, so we destroy req2 by hand - */ - if (!smbcli_request_send(req2)) { - goto failed; + 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->seq_num = req2->seq_num; - smbcli_request_destroy(req2); - - return SMBCLI_REQUEST_RECV; - -nomem: - req->status = NT_STATUS_NO_MEMORY; -failed: - if (req2) { - req->status = smbcli_request_destroy(req2); + req->state = SMBCLI_REQUEST_DONE; + if (req->async.fn) { + req->async.fn(req); } - return SMBCLI_REQUEST_ERROR; } -static enum smbcli_request_state smb_raw_trans2_ship_rest(struct smbcli_request *req, - struct smb_raw_trans2_recv_state *state) +static NTSTATUS smb_raw_trans_backend_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) { - enum smbcli_request_state ret = SMBCLI_REQUEST_ERROR; - - while (state->params_left > 0 || state->data_left > 0) { - ret = smb_raw_trans2_ship_next(req, state); - if (ret != SMBCLI_REQUEST_RECV) { - break; - } + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + goto failed; } - return ret; -} - + parms->out = req->trans2.out; + talloc_steal(mem_ctx, parms->out.setup); + talloc_steal(mem_ctx, parms->out.params.data); + talloc_steal(mem_ctx, parms->out.data.data); -/* - trans/trans2 raw async interface - only BLOBs used in this interface. - note that this doesn't yet support multi-part requests -*/ -_PUBLIC_ struct smbcli_request *smb_raw_trans_send(struct smbcli_tree *tree, - struct smb_trans2 *parms) -{ - return smb_raw_trans_send_backend(tree, parms, SMBtrans); +failed: + return smbcli_request_destroy(req); } -struct smbcli_request *smb_raw_trans2_send(struct smbcli_tree *tree, +_PUBLIC_ struct smbcli_request *smb_raw_trans_send(struct smbcli_tree *tree, struct smb_trans2 *parms) { - return smb_raw_trans_send_backend(tree, parms, SMBtrans2); + return smb_raw_trans_backend_send(tree, parms, SMBtrans); } -/* - trans2 synchronous blob interface -*/ -NTSTATUS smb_raw_trans2(struct smbcli_tree *tree, - TALLOC_CTX *mem_ctx, - struct smb_trans2 *parms) +_PUBLIC_ NTSTATUS smb_raw_trans_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) { - struct smbcli_request *req; - req = smb_raw_trans2_send(tree, parms); - if (!req) return NT_STATUS_UNSUCCESSFUL; - return smb_raw_trans2_recv(req, mem_ctx, parms); + return smb_raw_trans_backend_recv(req, mem_ctx, parms); } - -/* - trans synchronous blob interface -*/ _PUBLIC_ NTSTATUS smb_raw_trans(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, struct smb_trans2 *parms) @@ -536,413 +224,185 @@ _PUBLIC_ NTSTATUS smb_raw_trans(struct smbcli_tree *tree, return smb_raw_trans_recv(req, mem_ctx, parms); } -struct smb_raw_nttrans_recv_state { - uint32_t params_total; - uint32_t data_total; - uint32_t params_left; - uint32_t data_left; - bool got_first; - uint32_t recvd_data; - uint32_t recvd_param; - struct smb_nttrans io; -}; - -NTSTATUS smb_raw_nttrans_recv(struct smbcli_request *req, - TALLOC_CTX *mem_ctx, - struct smb_nttrans *parms) +struct smbcli_request *smb_raw_trans2_send(struct smbcli_tree *tree, + struct smb_trans2 *parms) { - struct smb_raw_nttrans_recv_state *state; - - if (!smbcli_request_receive(req) || - smbcli_request_is_error(req)) { - goto failed; - } - - state = talloc_get_type(req->recv_helper.private_data, - struct smb_raw_nttrans_recv_state); - - parms->out = state->io.out; - talloc_steal(mem_ctx, parms->out.setup); - talloc_steal(mem_ctx, parms->out.params.data); - talloc_steal(mem_ctx, parms->out.data.data); - talloc_free(state); - - ZERO_STRUCT(req->recv_helper); - -failed: - return smbcli_request_destroy(req); + return smb_raw_trans_backend_send(tree, parms, SMBtrans2); } -static enum smbcli_request_state smb_raw_nttrans_ship_rest(struct smbcli_request *req, - struct smb_raw_nttrans_recv_state *state); - -/* - * This helper returns SMBCLI_REQUEST_RECV until all data has arrived - */ -static enum smbcli_request_state smb_raw_nttrans_recv_helper(struct smbcli_request *req) +NTSTATUS smb_raw_trans2_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) { - struct smb_raw_nttrans_recv_state *state = talloc_get_type(req->recv_helper.private_data, - struct smb_raw_nttrans_recv_state); - uint32_t param_count, param_ofs, param_disp; - uint32_t data_count, data_ofs, data_disp; - uint32_t total_data, total_param; - uint8_t setup_count; - - /* - * An NT RPC pipe call can return ERRDOS, ERRmoredata - * to a trans call. This is not an error and should not - * be treated as such. - */ - if (smbcli_request_is_error(req)) { - goto failed; - } - - /* sanity check */ - if (CVAL(req->in.hdr, HDR_COM) != SMBnttrans) { - DEBUG(0,("smb_raw_nttrans_recv_helper: Expected %s response, got command 0x%02x\n", - "SMBnttrans", - CVAL(req->in.hdr,HDR_COM))); - req->status = NT_STATUS_INVALID_NETWORK_RESPONSE; - goto failed; - } - - if (state->params_left > 0 || state->data_left > 0) { - return smb_raw_nttrans_ship_rest(req, state); - } - - /* this is the first packet of the response */ - SMBCLI_CHECK_MIN_WCT(req, 18); - - total_param = IVAL(req->in.vwv, 3); - total_data = IVAL(req->in.vwv, 7); - setup_count = CVAL(req->in.vwv, 35); - - param_count = IVAL(req->in.vwv, 11); - param_ofs = IVAL(req->in.vwv, 15); - param_disp = IVAL(req->in.vwv, 19); - - data_count = IVAL(req->in.vwv, 23); - data_ofs = IVAL(req->in.vwv, 27); - data_disp = IVAL(req->in.vwv, 31); - - if (!state->got_first) { - if (total_param > 0) { - state->io.out.params = data_blob_talloc(state, NULL, total_param); - if (!state->io.out.params.data) { - goto nomem; - } - } - - if (total_data > 0) { - state->io.out.data = data_blob_talloc(state, NULL, total_data); - if (!state->io.out.data.data) { - goto nomem; - } - } - - if (setup_count > 0) { - SMBCLI_CHECK_WCT(req, 18 + setup_count); - - state->io.out.setup_count = setup_count; - state->io.out.setup = talloc_array(state, uint8_t, - setup_count * VWV(1)); - if (!state->io.out.setup) { - goto nomem; - } - memcpy(state->io.out.setup, (uint8_t *)req->out.vwv + VWV(18), - setup_count * VWV(1)); - } - - state->got_first = true; - } - - if (total_data > state->io.out.data.length || - total_param > state->io.out.params.length) { - /* they must *only* shrink */ - DEBUG(1,("smb_raw_nttrans_recv_helper: data/params expanded!\n")); - req->status = NT_STATUS_BUFFER_TOO_SMALL; - goto failed; - } - - state->io.out.data.length = total_data; - state->io.out.params.length = total_param; - - if (data_count + data_disp > total_data || - param_count + param_disp > total_param) { - DEBUG(1,("smb_raw_nttrans_recv_helper: Buffer overflow\n")); - req->status = NT_STATUS_BUFFER_TOO_SMALL; - goto failed; - } - - /* check the server isn't being nasty */ - if (raw_trans_oob(req, param_ofs, param_count) || - raw_trans_oob(req, data_ofs, data_count)) { - DEBUG(1,("smb_raw_nttrans_recv_helper: out of bounds parameters!\n")); - req->status = NT_STATUS_BUFFER_TOO_SMALL; - goto failed; - } - - if (data_count) { - memcpy(state->io.out.data.data + data_disp, - req->in.hdr + data_ofs, - data_count); - } - - if (param_count) { - memcpy(state->io.out.params.data + param_disp, - req->in.hdr + param_ofs, - param_count); - } - - state->recvd_param += param_count; - state->recvd_data += data_count; - - if (state->recvd_data < total_data || - state->recvd_param < total_param) { - - /* we don't need the in buffer any more */ - talloc_free(req->in.buffer); - ZERO_STRUCT(req->in); - - /* we still wait for more data */ - DEBUG(10,("smb_raw_nttrans_recv_helper: more data needed\n")); - return SMBCLI_REQUEST_RECV; - } - - DEBUG(10,("smb_raw_nttrans_recv_helper: done\n")); - return SMBCLI_REQUEST_DONE; + return smb_raw_trans_backend_recv(req, mem_ctx, parms); +} -nomem: - req->status = NT_STATUS_NO_MEMORY; -failed: - return SMBCLI_REQUEST_ERROR; +NTSTATUS smb_raw_trans2(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) +{ + struct smbcli_request *req; + req = smb_raw_trans2_send(tree, parms); + if (!req) return NT_STATUS_UNSUCCESSFUL; + return smb_raw_trans2_recv(req, mem_ctx, parms); } -/**************************************************************************** - nttrans raw - only BLOBs used in this interface. - at the moment we only handle a single primary request -****************************************************************************/ +static void smb_raw_nttrans_done(struct tevent_req *subreq); + struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree, - struct smb_nttrans *parms) + struct smb_nttrans *parms) { - struct smbcli_request *req; - struct smb_raw_nttrans_recv_state *state; - uint32_t ofs; - size_t space_left; - DATA_BLOB params_chunk; - uint32_t params_ofs; - DATA_BLOB data_chunk; - uint32_t data_ofs; - int align = 0; - - /* only align if there are parameters or data */ - if (parms->in.params.length || parms->in.data.length) { - align = 3; - } - - req = smbcli_request_setup(tree, SMBnttrans, - 19 + parms->in.setup_count, align); - if (!req) { + struct smbcli_request *req; + 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; + uint32_t tmp; + + tmp = parms->in.params.length + parms->in.data.length; + + req = smbcli_request_setup(tree, SMBnttrans, parms->in.setup_count, tmp); + if (req == NULL) { return NULL; } - state = talloc_zero(req, struct smb_raw_nttrans_recv_state); - if (!state) { + 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; + + timeout_msec = req->transport->options.request_timeout * 1000; + + memcpy(req->out.vwv, + parms->in.setup, + parms->in.setup_count * 2); + + memcpy(req->out.data, + parms->in.params.data, + parms->in.params.length); + memcpy(req->out.data + parms->in.params.length, + parms->in.data.data, + parms->in.data.length); + + req->subreqs[0] = smb1cli_trans_send(req, + req->transport->ev, + req->transport->conn, + SMBnttrans, + additional_flags, + clear_flags, + additional_flags2, + clear_flags2, + timeout_msec, + pid, tid, uid, + NULL, /* pipe_name */ + 0xFFFF, /* fid */ + parms->in.function, + 0, /* flags */ + (uint16_t *)req->out.vwv, + parms->in.setup_count, + parms->in.max_setup, + req->out.data, + parms->in.params.length, + parms->in.max_param, + req->out.data+ + parms->in.params.length, + parms->in.data.length, + parms->in.max_data); + if (req->subreqs[0] == NULL) { talloc_free(req); return NULL; } + tevent_req_set_callback(req->subreqs[0], + smb_raw_nttrans_done, + req); - /* fill in SMB parameters */ - - if (align != 0) { - memset(req->out.data, 0, align); - } - - ofs = PTR_DIFF(req->out.data,req->out.hdr)+align; - - /* see how much bytes of the params block we can ship in the first request */ - space_left = raw_trans_space_left(req); - - params_chunk.length = MIN(parms->in.params.length, space_left); - params_chunk.data = parms->in.params.data; - params_ofs = ofs; - - state->params_left = parms->in.params.length - params_chunk.length; + return req; +} - if (state->params_left > 0) { - /* we copy the whole params block, if needed we can optimize that latter */ - state->io.in.params = data_blob_talloc(state, NULL, parms->in.params.length); - if (!state->io.in.params.data) { - smbcli_request_destroy(req); - return NULL; +static void smb_raw_nttrans_done(struct tevent_req *subreq) +{ + struct smbcli_request *req = + tevent_req_callback_data(subreq, + struct smbcli_request); + struct smbcli_transport *transport = req->transport; + uint16_t *setup = NULL; + uint8_t num_setup = 0; + uint8_t *param = NULL; + uint32_t num_param = 0; + uint8_t *data = NULL; + uint32_t num_data = 0; + + req->status = smb1cli_trans_recv(req->subreqs[0], req, + &req->flags2, + &setup, + 0, /* min_setup */ + &num_setup, + ¶m, + 0, /* min_param */ + &num_param, + &data, + 0, /* min_data */ + &num_data); + TALLOC_FREE(req->subreqs[0]); + if (NT_STATUS_IS_ERR(req->status)) { + req->state = SMBCLI_REQUEST_ERROR; + transport->error.e.nt_status = req->status; + transport->error.etype = ETYPE_SMB; + if (req->async.fn) { + req->async.fn(req); } - memcpy(state->io.in.params.data, - parms->in.params.data, - parms->in.params.length); + return; } - /* see how much bytes of the data block we can ship in the first request */ - space_left -= params_chunk.length; - -#if TORTURE_TRANS_DATA - if (space_left > 1) { - space_left /= 2; - } -#endif + req->nttrans.out.setup_count = num_setup; + req->nttrans.out.setup = (uint8_t *)setup; - data_chunk.length = MIN(parms->in.data.length, space_left); - data_chunk.data = parms->in.data.data; - data_ofs = params_ofs + params_chunk.length; + req->nttrans.out.params.data = param; + req->nttrans.out.params.length = num_param; - state->data_left = parms->in.data.length - data_chunk.length; + req->nttrans.out.data.data = data; + req->nttrans.out.data.length = num_data; - if (state->data_left > 0) { - /* we copy the whole params block, if needed we can optimize that latter */ - state->io.in.data = data_blob_talloc(state, NULL, parms->in.data.length); - if (!state->io.in.data.data) { - smbcli_request_destroy(req); - return NULL; - } - memcpy(state->io.in.data.data, - parms->in.data.data, - parms->in.data.length); + 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; } - state->params_total = parms->in.params.length; - state->data_total = parms->in.data.length; - - SCVAL(req->out.vwv, 0, parms->in.max_setup); - SSVAL(req->out.vwv, 1, 0); /* reserved */ - SIVAL(req->out.vwv, 3, parms->in.params.length); - SIVAL(req->out.vwv, 7, parms->in.data.length); - SIVAL(req->out.vwv, 11, parms->in.max_param); - SIVAL(req->out.vwv, 15, parms->in.max_data); - SIVAL(req->out.vwv, 19, params_chunk.length); - SIVAL(req->out.vwv, 23, params_ofs); - SIVAL(req->out.vwv, 27, data_chunk.length); - SIVAL(req->out.vwv, 31, data_ofs); - SCVAL(req->out.vwv, 35, parms->in.setup_count); - SSVAL(req->out.vwv, 36, parms->in.function); - memcpy(req->out.vwv + VWV(19), parms->in.setup, - sizeof(uint16_t) * parms->in.setup_count); - - smbcli_req_append_blob(req, ¶ms_chunk); - smbcli_req_append_blob(req, &data_chunk); - - /* add the helper which will check that all multi-part replies are - in before an async client callack will be issued */ - req->recv_helper.fn = smb_raw_nttrans_recv_helper; - req->recv_helper.private_data = state; - - if (!smbcli_request_send(req)) { - smbcli_request_destroy(req); - return NULL; + req->state = SMBCLI_REQUEST_DONE; + if (req->async.fn) { + req->async.fn(req); } - - return req; } -static enum smbcli_request_state smb_raw_nttrans_ship_next(struct smbcli_request *req, - struct smb_raw_nttrans_recv_state *state) +NTSTATUS smb_raw_nttrans_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_nttrans *parms) { - struct smbcli_request *req2; - size_t space_left; - DATA_BLOB params_chunk; - uint32_t ofs; - uint32_t params_ofs = 0; - uint32_t params_disp = 0; - DATA_BLOB data_chunk; - uint32_t data_ofs = 0; - uint32_t data_disp = 0; - - req2 = smbcli_request_setup(req->tree, SMBnttranss, 18, 0); - if (!req2) { - goto nomem; - } - req2->mid = req->mid; - SSVAL(req2->out.hdr, HDR_MID, req2->mid); - - ofs = PTR_DIFF(req2->out.data,req2->out.hdr); - - /* see how much bytes of the params block we can ship in the first request */ - space_left = raw_trans_space_left(req2); - - params_disp = state->io.in.params.length - state->params_left; - params_chunk.length = MIN(state->params_left, space_left); - params_chunk.data = state->io.in.params.data + params_disp; - params_ofs = ofs; - - state->params_left -= params_chunk.length; - - /* see how much bytes of the data block we can ship in the first request */ - space_left -= params_chunk.length; - -#if TORTURE_TRANS_DATA - if (space_left > 1) { - space_left /= 2; - } -#endif - - data_disp = state->io.in.data.length - state->data_left; - data_chunk.length = MIN(state->data_left, space_left); - data_chunk.data = state->io.in.data.data + data_disp; - data_ofs = params_ofs+params_chunk.length; - - state->data_left -= data_chunk.length; - - SSVAL(req2->out.vwv,0, 0); /* reserved */ - SCVAL(req2->out.vwv,2, 0); /* reserved */ - SIVAL(req2->out.vwv,3, state->params_total); - SIVAL(req2->out.vwv,7, state->data_total); - SIVAL(req2->out.vwv,11, params_chunk.length); - SIVAL(req2->out.vwv,15, params_ofs); - SIVAL(req2->out.vwv,19, params_disp); - SIVAL(req2->out.vwv,23, data_chunk.length); - SIVAL(req2->out.vwv,27, data_ofs); - SIVAL(req2->out.vwv,31, data_disp); - SCVAL(req2->out.vwv,35, 0); /* reserved */ - - smbcli_req_append_blob(req2, ¶ms_chunk); - smbcli_req_append_blob(req2, &data_chunk); - - /* - * it's a one way request but we need - * the seq_num, so we destroy req2 by hand - */ - if (!smbcli_request_send(req2)) { + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { goto failed; } - req->seq_num = req2->seq_num; - smbcli_request_destroy(req2); - - return SMBCLI_REQUEST_RECV; + parms->out = req->nttrans.out; + talloc_steal(mem_ctx, parms->out.setup); + talloc_steal(mem_ctx, parms->out.params.data); + talloc_steal(mem_ctx, parms->out.data.data); -nomem: - req->status = NT_STATUS_NO_MEMORY; failed: - if (req2) { - req->status = smbcli_request_destroy(req2); - } - return SMBCLI_REQUEST_ERROR; -} - -static enum smbcli_request_state smb_raw_nttrans_ship_rest(struct smbcli_request *req, - struct smb_raw_nttrans_recv_state *state) -{ - enum smbcli_request_state ret = SMBCLI_REQUEST_ERROR; - - while (state->params_left > 0 || state->data_left > 0) { - ret = smb_raw_nttrans_ship_next(req, state); - if (ret != SMBCLI_REQUEST_RECV) { - break; - } - } - - return ret; + return smbcli_request_destroy(req); } - /**************************************************************************** receive a SMB nttrans response allocating the necessary memory ****************************************************************************/ diff --git a/source4/libcli/raw/smb_signing.c b/source4/libcli/raw/smb_signing.c index e1d7a2d187..5d2f928747 100644 --- a/source4/libcli/raw/smb_signing.c +++ b/source4/libcli/raw/smb_signing.c @@ -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; -} diff --git a/source4/libcli/smb_composite/connect.c b/source4/libcli/smb_composite/connect.c index 0f66f2873d..0688684e95 100644 --- a/source4/libcli/smb_composite/connect.c +++ b/source4/libcli/smb_composite/connect.c @@ -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); } diff --git a/source4/libcli/smb_composite/sesssetup.c b/source4/libcli/smb_composite/sesssetup.c index cafaacd8bb..63f3a8e10d 100644 --- a/source4/libcli/smb_composite/sesssetup.c +++ b/source4/libcli/smb_composite/sesssetup.c @@ -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; } |