diff options
Diffstat (limited to 'source3/libsmb/async_smb.c')
-rw-r--r-- | source3/libsmb/async_smb.c | 219 |
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) |