summaryrefslogtreecommitdiff
path: root/source3/libsmb/async_smb.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libsmb/async_smb.c')
-rw-r--r--source3/libsmb/async_smb.c219
1 files changed, 31 insertions, 188 deletions
diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c
index 6edfe514b8..f5000e4730 100644
--- a/source3/libsmb/async_smb.c
+++ b/source3/libsmb/async_smb.c
@@ -153,180 +153,6 @@ void cli_set_error(struct cli_state *cli, NTSTATUS status)
}
/**
- * @brief Find the smb_cmd offset of the last command pushed
- * @param[in] buf The buffer we're building up
- * @retval Where can we put our next andx cmd?
- *
- * While chaining requests, the "next" request we're looking at needs to put
- * its SMB_Command before the data the previous request already built up added
- * to the chain. Find the offset to the place where we have to put our cmd.
- */
-
-static bool find_andx_cmd_ofs(uint8_t *buf, size_t *pofs)
-{
- uint8_t cmd;
- size_t ofs;
-
- cmd = CVAL(buf, smb_com);
-
- SMB_ASSERT(is_andx_req(cmd));
-
- ofs = smb_vwv0;
-
- while (CVAL(buf, ofs) != 0xff) {
-
- if (!is_andx_req(CVAL(buf, ofs))) {
- return false;
- }
-
- /*
- * ofs is from start of smb header, so add the 4 length
- * bytes. The next cmd is right after the wct field.
- */
- ofs = SVAL(buf, ofs+2) + 4 + 1;
-
- SMB_ASSERT(ofs+4 < talloc_get_size(buf));
- }
-
- *pofs = ofs;
- return true;
-}
-
-/**
- * @brief Do the smb chaining at a buffer level
- * @param[in] poutbuf Pointer to the talloc'ed buffer to be modified
- * @param[in] smb_command The command that we want to issue
- * @param[in] wct How many words?
- * @param[in] vwv The words, already in network order
- * @param[in] bytes_alignment How shall we align "bytes"?
- * @param[in] num_bytes How many bytes?
- * @param[in] bytes The data the request ships
- *
- * smb_splice_chain() adds the vwv and bytes to the request already present in
- * *poutbuf.
- */
-
-bool smb_splice_chain(uint8_t **poutbuf, uint8_t smb_command,
- uint8_t wct, const uint16_t *vwv,
- size_t bytes_alignment,
- uint32_t num_bytes, const uint8_t *bytes)
-{
- uint8_t *outbuf;
- size_t old_size, new_size;
- size_t ofs;
- size_t chain_padding = 0;
- size_t bytes_padding = 0;
- bool first_request;
-
- old_size = talloc_get_size(*poutbuf);
-
- /*
- * old_size == smb_wct means we're pushing the first request in for
- * libsmb/
- */
-
- first_request = (old_size == smb_wct);
-
- if (!first_request && ((old_size % 4) != 0)) {
- /*
- * Align the wct field of subsequent requests to a 4-byte
- * boundary
- */
- chain_padding = 4 - (old_size % 4);
- }
-
- /*
- * After the old request comes the new wct field (1 byte), the vwv's
- * and the num_bytes field. After at we might need to align the bytes
- * given to us to "bytes_alignment", increasing the num_bytes value.
- */
-
- new_size = old_size + chain_padding + 1 + wct * sizeof(uint16_t) + 2;
-
- if ((bytes_alignment != 0) && ((new_size % bytes_alignment) != 0)) {
- bytes_padding = bytes_alignment - (new_size % bytes_alignment);
- }
-
- new_size += bytes_padding + num_bytes;
-
- if ((smb_command != SMBwriteX) && (new_size > 0xffff)) {
- DEBUG(1, ("splice_chain: %u bytes won't fit\n",
- (unsigned)new_size));
- return false;
- }
-
- outbuf = TALLOC_REALLOC_ARRAY(NULL, *poutbuf, uint8_t, new_size);
- if (outbuf == NULL) {
- DEBUG(0, ("talloc failed\n"));
- return false;
- }
- *poutbuf = outbuf;
-
- if (first_request) {
- SCVAL(outbuf, smb_com, smb_command);
- } else {
- size_t andx_cmd_ofs;
-
- if (!find_andx_cmd_ofs(outbuf, &andx_cmd_ofs)) {
- DEBUG(1, ("invalid command chain\n"));
- *poutbuf = TALLOC_REALLOC_ARRAY(
- NULL, *poutbuf, uint8_t, old_size);
- return false;
- }
-
- if (chain_padding != 0) {
- memset(outbuf + old_size, 0, chain_padding);
- old_size += chain_padding;
- }
-
- SCVAL(outbuf, andx_cmd_ofs, smb_command);
- SSVAL(outbuf, andx_cmd_ofs + 2, old_size - 4);
- }
-
- ofs = old_size;
-
- /*
- * Push the chained request:
- *
- * wct field
- */
-
- SCVAL(outbuf, ofs, wct);
- ofs += 1;
-
- /*
- * vwv array
- */
-
- memcpy(outbuf + ofs, vwv, sizeof(uint16_t) * wct);
- ofs += sizeof(uint16_t) * wct;
-
- /*
- * bcc (byte count)
- */
-
- SSVAL(outbuf, ofs, num_bytes + bytes_padding);
- ofs += sizeof(uint16_t);
-
- /*
- * padding
- */
-
- if (bytes_padding != 0) {
- memset(outbuf + ofs, 0, bytes_padding);
- ofs += bytes_padding;
- }
-
- /*
- * The bytes field
- */
-
- memcpy(outbuf + ofs, bytes, num_bytes);
-
- return true;
-}
-
-/**
* Figure out if there is an andx command behind the current one
* @param[in] buf The smb buffer to look at
* @param[in] ofs The offset to the wct field that is followed by the cmd
@@ -556,6 +382,7 @@ struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx,
{
struct tevent_req *result;
struct cli_smb_state *state;
+ struct timeval endtime;
if (iov_count > MAX_SMB_IOV) {
/*
@@ -596,6 +423,10 @@ struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx,
}
state->iov_count = iov_count + 3;
+ endtime = timeval_current_ofs(0, cli->timeout * 1000);
+ if (!tevent_req_set_endtime(result, ev, endtime)) {
+ tevent_req_nomem(NULL, result);
+ }
return result;
}
@@ -679,12 +510,10 @@ static NTSTATUS cli_smb_req_iov_send(struct tevent_req *req,
}
iov[0].iov_base = (void *)buf;
iov[0].iov_len = talloc_get_size(buf);
- subreq = writev_send(state, state->ev, state->cli->outgoing,
- state->cli->fd, false, iov, 1);
- } else {
- subreq = writev_send(state, state->ev, state->cli->outgoing,
- state->cli->fd, false, iov, iov_count);
+ iov_count = 1;
}
+ subreq = writev_send(state, state->ev, state->cli->outgoing,
+ state->cli->fd, false, iov, iov_count);
if (subreq == NULL) {
return NT_STATUS_NO_MEMORY;
}
@@ -986,16 +815,30 @@ NTSTATUS cli_smb_recv(struct tevent_req *req, uint8_t min_wct,
status = cli_pull_error((char *)state->inbuf);
- if (!have_andx_command((char *)state->inbuf, wct_ofs)
- && NT_STATUS_IS_ERR(status)) {
- /*
- * The last command takes the error code. All further commands
- * down the requested chain will get a
- * NT_STATUS_REQUEST_ABORTED.
- */
- return status;
+ if (!have_andx_command((char *)state->inbuf, wct_ofs)) {
+
+ if ((cmd == SMBsesssetupX)
+ && NT_STATUS_EQUAL(
+ status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ /*
+ * NT_STATUS_MORE_PROCESSING_REQUIRED is a
+ * valid return code for session setup
+ */
+ goto no_err;
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ /*
+ * The last command takes the error code. All
+ * further commands down the requested chain
+ * will get a NT_STATUS_REQUEST_ABORTED.
+ */
+ return status;
+ }
}
+no_err:
+
wct = CVAL(state->inbuf, wct_ofs);
bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t);
num_bytes = SVAL(state->inbuf, bytes_offset);
@@ -1027,7 +870,7 @@ NTSTATUS cli_smb_recv(struct tevent_req *req, uint8_t min_wct,
*pbytes = (uint8_t *)state->inbuf + bytes_offset + 2;
}
- return NT_STATUS_OK;
+ return status;
}
size_t cli_smb_wct_ofs(struct tevent_req **reqs, int num_reqs)