summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libcli/cliconnect.c12
-rw-r--r--source4/libcli/raw/clisocket.c280
-rw-r--r--source4/libcli/smb_composite/connect.c40
3 files changed, 240 insertions, 92 deletions
diff --git a/source4/libcli/cliconnect.c b/source4/libcli/cliconnect.c
index d670324c88..e25a400985 100644
--- a/source4/libcli/cliconnect.c
+++ b/source4/libcli/cliconnect.c
@@ -58,7 +58,17 @@ bool smbcli_transport_establish(struct smbcli_state *cli,
struct nbt_name *calling,
struct nbt_name *called)
{
- return smbcli_transport_connect(cli->transport, calling, called);
+ uint32_t timeout_msec = cli->transport->options.request_timeout * 1000;
+ NTSTATUS status;
+
+ status = smbcli_transport_connect(cli->transport->socket,
+ timeout_msec,
+ calling, called);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ return true;
}
/* wrapper around smb_raw_negotiate() */
diff --git a/source4/libcli/raw/clisocket.c b/source4/libcli/raw/clisocket.c
index 70a83a493f..d0867b2023 100644
--- a/source4/libcli/raw/clisocket.c
+++ b/source4/libcli/raw/clisocket.c
@@ -21,6 +21,9 @@
*/
#include "includes.h"
+#include "system/network.h"
+#include "../lib/async_req/async_sock.h"
+#include "../lib/util/tevent_ntstatus.h"
#include "lib/events/events.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/composite/composite.h"
@@ -28,128 +31,251 @@
#include "libcli/resolve/resolve.h"
#include "param/param.h"
#include "libcli/raw/raw_proto.h"
+#include "../libcli/smb/read_smb.h"
+
+struct smbcli_transport_connect_state {
+ struct tevent_context *ev;
+ struct smbcli_socket *sock;
+ uint8_t *request;
+ struct iovec iov;
+ uint8_t *response;
+};
-/*
- send a session request
-*/
-struct smbcli_request *smbcli_transport_connect_send(struct smbcli_transport *transport,
- struct nbt_name *calling,
- struct nbt_name *called)
+static void smbcli_transport_connect_writev_done(struct tevent_req *subreq);
+static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq);
+
+struct tevent_req *smbcli_transport_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbcli_socket *sock,
+ uint32_t timeout_msec,
+ struct nbt_name *calling,
+ struct nbt_name *called)
{
- uint8_t *p;
- struct smbcli_request *req;
+ struct tevent_req *req;
+ struct smbcli_transport_connect_state *state;
+ struct tevent_req *subreq;
DATA_BLOB calling_blob, called_blob;
- TALLOC_CTX *tmp_ctx = talloc_new(transport);
+ uint8_t *p;
NTSTATUS status;
- status = nbt_name_dup(transport, called, &transport->called);
- if (!NT_STATUS_IS_OK(status)) goto failed;
-
- status = nbt_name_to_blob(tmp_ctx, &calling_blob, calling);
- if (!NT_STATUS_IS_OK(status)) goto failed;
+ req = tevent_req_create(mem_ctx, &state,
+ struct smbcli_transport_connect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->sock = sock;
+
+ if (sock->port != 139) {
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
- status = nbt_name_to_blob(tmp_ctx, &called_blob, called);
- if (!NT_STATUS_IS_OK(status)) goto failed;
+ status = nbt_name_to_blob(state, &calling_blob, calling);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
- /* allocate output buffer */
- req = smbcli_request_setup_nonsmb(transport,
- NBT_HDR_SIZE +
- calling_blob.length + called_blob.length);
- if (req == NULL) goto failed;
+ status = nbt_name_to_blob(state, &called_blob, called);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->request = talloc_array(state, uint8_t,
+ NBT_HDR_SIZE +
+ called_blob.length +
+ calling_blob.length);
+ if (tevent_req_nomem(state->request, req)) {
+ return tevent_req_post(req, ev);
+ }
/* put in the destination name */
- p = req->out.buffer + NBT_HDR_SIZE;
+ p = state->request + NBT_HDR_SIZE;
memcpy(p, called_blob.data, called_blob.length);
p += called_blob.length;
memcpy(p, calling_blob.data, calling_blob.length);
p += calling_blob.length;
- _smb_setlen_nbt(req->out.buffer, PTR_DIFF(p, req->out.buffer) - NBT_HDR_SIZE);
- SCVAL(req->out.buffer,0,0x81);
+ _smb_setlen_nbt(state->request,
+ PTR_DIFF(p, state->request) - NBT_HDR_SIZE);
+ SCVAL(state->request, 0, NBSSrequest);
+
+ state->iov.iov_len = talloc_array_length(state->request);
+ state->iov.iov_base = (void *)state->request;
- if (!smbcli_request_send(req)) {
- smbcli_request_destroy(req);
- goto failed;
+ subreq = writev_send(state, ev, NULL,
+ sock->sock->fd,
+ true, /* err_on_readability */
+ &state->iov, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq,
+ smbcli_transport_connect_writev_done,
+ req);
- talloc_free(tmp_ctx);
- return req;
+ if (timeout_msec > 0) {
+ struct timeval endtime;
-failed:
- talloc_free(tmp_ctx);
- return NULL;
+ endtime = timeval_current_ofs_msec(timeout_msec);
+ if (!tevent_req_set_endtime(req, ev, endtime)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ return req;
}
-/*
- map a session request error to a NTSTATUS
- */
-static NTSTATUS map_session_refused_error(uint8_t error)
+static void smbcli_transport_connect_writev_done(struct tevent_req *subreq)
{
- switch (error) {
- case 0x80:
- case 0x81:
- return NT_STATUS_REMOTE_NOT_LISTENING;
- case 0x82:
- return NT_STATUS_RESOURCE_NAME_NOT_FOUND;
- case 0x83:
- return NT_STATUS_REMOTE_RESOURCES;
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smbcli_transport_connect_state *state =
+ tevent_req_data(req,
+ struct smbcli_transport_connect_state);
+ ssize_t ret;
+ int err;
+
+ ret = writev_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ NTSTATUS status = map_nt_error_from_unix_common(err);
+
+ close(state->sock->sock->fd);
+ state->sock->sock->fd = -1;
+
+ tevent_req_nterror(req, status);
+ return;
}
- return NT_STATUS_UNEXPECTED_IO_ERROR;
-}
+ subreq = read_smb_send(state, state->ev,
+ state->sock->sock->fd);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ smbcli_transport_connect_read_smb_done,
+ req);
+}
-/*
- finish a smbcli_transport_connect()
-*/
-NTSTATUS smbcli_transport_connect_recv(struct smbcli_request *req)
+static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq)
{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smbcli_transport_connect_state *state =
+ tevent_req_data(req,
+ struct smbcli_transport_connect_state);
+ ssize_t ret;
+ int err;
NTSTATUS status;
+ uint8_t error;
+
+ ret = read_smb_recv(subreq, state,
+ &state->response, &err);
+ if (ret == -1) {
+ status = map_nt_error_from_unix_common(err);
+
+ close(state->sock->sock->fd);
+ state->sock->sock->fd = -1;
- if (!smbcli_request_receive(req)) {
- smbcli_request_destroy(req);
- return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ tevent_req_nterror(req, status);
+ return;
}
- switch (CVAL(req->in.buffer,0)) {
- case 0x82:
- status = NT_STATUS_OK;
- break;
- case 0x83:
- status = map_session_refused_error(CVAL(req->in.buffer,4));
+ if (ret < 4) {
+ close(state->sock->sock->fd);
+ state->sock->sock->fd = -1;
+
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ switch (CVAL(state->response, 0)) {
+ case NBSSpositive:
+ tevent_req_done(req);
+ return;
+
+ case NBSSnegative:
+ if (ret < 5) {
+ close(state->sock->sock->fd);
+ state->sock->sock->fd = -1;
+
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ error = CVAL(state->response, 4);
+ switch (error) {
+ case 0x80:
+ case 0x81:
+ status = NT_STATUS_REMOTE_NOT_LISTENING;
+ break;
+ case 0x82:
+ status = NT_STATUS_RESOURCE_NAME_NOT_FOUND;
+ break;
+ case 0x83:
+ status = NT_STATUS_REMOTE_RESOURCES;
+ break;
+ default:
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ break;
+ }
break;
- case 0x84:
+
+ case NBSSretarget:
DEBUG(1,("Warning: session retarget not supported\n"));
status = NT_STATUS_NOT_SUPPORTED;
break;
+
default:
- status = NT_STATUS_UNEXPECTED_IO_ERROR;
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
break;
}
- smbcli_request_destroy(req);
- return status;
-}
+ close(state->sock->sock->fd);
+ state->sock->sock->fd = -1;
+ tevent_req_nterror(req, status);
+}
-/*
- send a session request (if needed)
-*/
-bool smbcli_transport_connect(struct smbcli_transport *transport,
- struct nbt_name *calling,
- struct nbt_name *called)
+NTSTATUS smbcli_transport_connect_recv(struct tevent_req *req)
{
- struct smbcli_request *req;
- NTSTATUS status;
+ return tevent_req_simple_recv_ntstatus(req);
+}
- if (transport->socket->port == 445) {
- return true;
+NTSTATUS smbcli_transport_connect(struct smbcli_socket *sock,
+ uint32_t timeout_msec,
+ struct nbt_name *calling,
+ struct nbt_name *called)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ bool ok;
+
+ ev = tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
}
-
- req = smbcli_transport_connect_send(transport,
+ req = smbcli_transport_connect_send(frame, ev, sock,
+ timeout_msec,
calling, called);
+ if (req == NULL) {
+ goto fail;
+ }
+ ok = tevent_req_poll(req, ev);
+ if (!ok) {
+ status = map_nt_error_from_unix_common(errno);
+ goto fail;
+ }
status = smbcli_transport_connect_recv(req);
- return NT_STATUS_IS_OK(status);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
}
struct sock_connect_state {
diff --git a/source4/libcli/smb_composite/connect.c b/source4/libcli/smb_composite/connect.c
index d36bf26914..306b96c167 100644
--- a/source4/libcli/smb_composite/connect.c
+++ b/source4/libcli/smb_composite/connect.c
@@ -52,11 +52,13 @@ struct connect_state {
struct smb_composite_sesssetup *io_setup;
struct smbcli_request *req;
struct composite_context *creq;
+ struct tevent_req *subreq;
};
static void request_handler(struct smbcli_request *);
static void composite_handler(struct composite_context *);
+static void subreq_handler(struct tevent_req *subreq);
/*
a tree connect request has completed
@@ -301,7 +303,8 @@ static NTSTATUS connect_session_request(struct composite_context *c,
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
NTSTATUS status;
- status = smbcli_transport_connect_recv(state->req);
+ status = smbcli_transport_connect_recv(state->subreq);
+ TALLOC_FREE(state->subreq);
NT_STATUS_NOT_OK_RETURN(status);
/* next step is a negprot */
@@ -317,6 +320,7 @@ static NTSTATUS connect_socket(struct composite_context *c,
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
NTSTATUS status;
struct nbt_name calling, called;
+ uint32_t timeout_msec = io->in.options.request_timeout * 1000;
status = smbcli_sock_connect_recv(state->creq, state, &state->sock);
NT_STATUS_NOT_OK_RETURN(status);
@@ -340,21 +344,18 @@ static NTSTATUS connect_socket(struct composite_context *c,
nbt_choose_called_name(state, &called, io->in.called_name, NBT_NAME_SERVER);
- /* we have a connected socket - next step is a session
- request, if needed. Port 445 doesn't need it, so it goes
- straight to the negprot */
- if (state->sock->port == 445) {
- status = nbt_name_dup(state->transport, &called,
- &state->transport->called);
- NT_STATUS_NOT_OK_RETURN(status);
- return connect_send_negprot(c, io);
- }
+ status = nbt_name_dup(state->transport, &called,
+ &state->transport->called);
+ NT_STATUS_NOT_OK_RETURN(status);
- state->req = smbcli_transport_connect_send(state->transport, &calling, &called);
- NT_STATUS_HAVE_NO_MEMORY(state->req);
+ state->subreq = smbcli_transport_connect_send(state,
+ state->transport->ev,
+ state->transport->socket,
+ timeout_msec,
+ &calling, &called);
+ NT_STATUS_HAVE_NO_MEMORY(state->subreq);
- state->req->async.fn = request_handler;
- state->req->async.private_data = c;
+ tevent_req_set_callback(state->subreq, subreq_handler, c);
state->stage = CONNECT_SESSION_REQUEST;
return NT_STATUS_OK;
@@ -421,6 +422,17 @@ static void composite_handler(struct composite_context *creq)
}
/*
+ handler for completion of a tevent_req sub-request
+*/
+static void subreq_handler(struct tevent_req *subreq)
+{
+ struct composite_context *c =
+ tevent_req_callback_data(subreq,
+ struct composite_context);
+ state_handler(c);
+}
+
+/*
a function to establish a smbcli_tree from scratch
*/
struct composite_context *smb_composite_connect_send(struct smb_composite_connect *io,