diff options
author | Andrew Tridgell <tridge@samba.org> | 2008-12-16 11:41:20 +1100 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2008-12-16 11:41:20 +1100 |
commit | f448fde4e35e56508ad93be8de9f60d88e8b8dcd (patch) | |
tree | 597b58ba1af03f5250af918ec15300c385281706 /source3/libsmb/async_smb.c | |
parent | a226d86dcec393b2cd657d5441c3041dfdf5cd8f (diff) | |
parent | 530758dc2a6dd6dce083789b328e16e51ba6573d (diff) | |
download | samba-f448fde4e35e56508ad93be8de9f60d88e8b8dcd.tar.gz samba-f448fde4e35e56508ad93be8de9f60d88e8b8dcd.tar.bz2 samba-f448fde4e35e56508ad93be8de9f60d88e8b8dcd.zip |
Merge branch 'master' of ssh://git.samba.org/data/git/samba
Diffstat (limited to 'source3/libsmb/async_smb.c')
-rw-r--r-- | source3/libsmb/async_smb.c | 160 |
1 files changed, 114 insertions, 46 deletions
diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c index d371e057e3..fd2fe930f8 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -218,6 +218,118 @@ static bool find_andx_cmd_ofs(char *buf, size_t *pofs) } /** + * @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(char **poutbuf, uint8_t smb_command, + uint8_t wct, const uint16_t *vwv, + size_t bytes_alignment, + uint16_t num_bytes, const uint8_t *bytes) +{ + char *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 (new_size > 0xffff) { + DEBUG(1, ("splice_chain: %u bytes won't fit\n", + (unsigned)new_size)); + return false; + } + + outbuf = TALLOC_REALLOC_ARRAY(NULL, *poutbuf, char, 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, char, 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; + + SCVAL(outbuf, ofs, wct); + ofs += 1; + + memcpy(outbuf + ofs, vwv, sizeof(uint16_t) * wct); + ofs += sizeof(uint16_t) * wct; + + SSVAL(outbuf, ofs, num_bytes + bytes_padding); + ofs += sizeof(uint16_t); + + if (bytes_padding != 0) { + memset(outbuf + ofs, 0, bytes_padding); + ofs += bytes_padding; + } + + memcpy(outbuf + ofs, bytes, num_bytes); + + return true; +} + +/** * @brief Destroy an async_req that is the visible part of a cli_request * @param[in] req The request to kill * @retval Return 0 to make talloc happy @@ -286,10 +398,7 @@ static struct async_req *cli_request_chain(TALLOC_CTX *mem_ctx, const uint8_t *bytes) { struct async_req **tmp_reqs; - char *tmp_buf; struct cli_request *req; - size_t old_size, new_size; - size_t ofs; req = cli->chain_accumulator; @@ -313,52 +422,11 @@ static struct async_req *cli_request_chain(TALLOC_CTX *mem_ctx, talloc_set_destructor(req->async[req->num_async-1], cli_async_req_destructor); - old_size = talloc_get_size(req->outbuf); - - /* - * We need space for the wct field, the words, the byte count field - * and the bytes themselves. - */ - new_size = old_size + 1 + wct * sizeof(uint16_t) + 2 + num_bytes; - - if (new_size > 0xffff) { - DEBUG(1, ("cli_request_chain: %u bytes won't fit\n", - (unsigned)new_size)); + if (!smb_splice_chain(&req->outbuf, smb_command, wct, vwv, + 0, num_bytes, bytes)) { goto fail; } - tmp_buf = TALLOC_REALLOC_ARRAY(NULL, req->outbuf, char, new_size); - if (tmp_buf == NULL) { - DEBUG(0, ("talloc failed\n")); - goto fail; - } - req->outbuf = tmp_buf; - - if (old_size == smb_wct) { - SCVAL(req->outbuf, smb_com, smb_command); - } else { - size_t andx_cmd_ofs; - if (!find_andx_cmd_ofs(req->outbuf, &andx_cmd_ofs)) { - DEBUG(1, ("invalid command chain\n")); - goto fail; - } - SCVAL(req->outbuf, andx_cmd_ofs, smb_command); - SSVAL(req->outbuf, andx_cmd_ofs + 2, old_size - 4); - } - - ofs = old_size; - - SCVAL(req->outbuf, ofs, wct); - ofs += 1; - - memcpy(req->outbuf + ofs, vwv, sizeof(uint16_t) * wct); - ofs += sizeof(uint16_t) * wct; - - SSVAL(req->outbuf, ofs, num_bytes); - ofs += sizeof(uint16_t); - - memcpy(req->outbuf + ofs, bytes, num_bytes); - return req->async[req->num_async-1]; fail: |