diff options
Diffstat (limited to 'source4/libcli/raw/clisocket.c')
-rw-r--r-- | source4/libcli/raw/clisocket.c | 280 |
1 files changed, 203 insertions, 77 deletions
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 { |