1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

Factor out smb_splice_chain(), to be used by chain_reply() in smbd

This commit is contained in:
Volker Lendecke 2008-11-12 18:43:34 +01:00
parent 53c41661bd
commit f0bb53dd0f
2 changed files with 101 additions and 46 deletions

View File

@ -125,6 +125,9 @@ bool cli_chain_cork(struct cli_state *cli, struct event_context *ev,
size_t size_hint);
void cli_chain_uncork(struct cli_state *cli);
bool cli_in_chain(struct cli_state *cli);
bool smb_splice_chain(char **poutbuf, uint8_t smb_command,
uint8_t wct, const uint16_t *vwv,
uint16_t num_bytes, const uint8_t *bytes);
NTSTATUS cli_pull_reply(struct async_req *req,
uint8_t *pwct, uint16_t **pvwv,

View File

@ -217,6 +217,102 @@ static bool find_andx_cmd_ofs(char *buf, size_t *pofs)
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] 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,
uint16_t num_bytes, const uint8_t *bytes)
{
char *outbuf;
size_t old_size, new_size;
size_t ofs;
size_t 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 subsequent requests to a 4-byte boundary
*/
padding = 4 - (old_size % 4);
}
/*
* We need space for the wct field, the words, the byte count field
* and the bytes themselves.
*/
new_size = old_size + padding
+ 1 + wct * sizeof(uint16_t) + 2 + 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 (padding != 0) {
memset(outbuf + old_size, 0, padding);
old_size += 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);
ofs += sizeof(uint16_t);
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
@ -286,10 +382,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 +406,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,
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: