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.c177
1 files changed, 125 insertions, 52 deletions
diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c
index fd2fe930f8..82a919455a 100644
--- a/source3/libsmb/async_smb.c
+++ b/source3/libsmb/async_smb.c
@@ -127,7 +127,7 @@ static char *cli_request_print(TALLOC_CTX *mem_ctx, struct async_req *req)
static int cli_request_destructor(struct cli_request *req)
{
if (req->enc_state != NULL) {
- common_free_enc_buffer(req->enc_state, req->outbuf);
+ common_free_enc_buffer(req->enc_state, (char *)req->outbuf);
}
DLIST_REMOVE(req->cli->outstanding_requests, req);
if (req->cli->outstanding_requests == NULL) {
@@ -187,7 +187,7 @@ static bool is_andx_req(uint8_t cmd)
* to the chain. Find the offset to the place where we have to put our cmd.
*/
-static bool find_andx_cmd_ofs(char *buf, size_t *pofs)
+static bool find_andx_cmd_ofs(uint8_t *buf, size_t *pofs)
{
uint8_t cmd;
size_t ofs;
@@ -231,12 +231,12 @@ static bool find_andx_cmd_ofs(char *buf, size_t *pofs)
* *poutbuf.
*/
-bool smb_splice_chain(char **poutbuf, uint8_t smb_command,
+bool smb_splice_chain(uint8_t **poutbuf, uint8_t smb_command,
uint8_t wct, const uint16_t *vwv,
size_t bytes_alignment,
- uint16_t num_bytes, const uint8_t *bytes)
+ uint32_t num_bytes, const uint8_t *bytes)
{
- char *outbuf;
+ uint8_t *outbuf;
size_t old_size, new_size;
size_t ofs;
size_t chain_padding = 0;
@@ -269,18 +269,18 @@ bool smb_splice_chain(char **poutbuf, uint8_t smb_command,
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);
+ bytes_padding = bytes_alignment - (new_size % bytes_alignment);
}
new_size += bytes_padding + num_bytes;
- if (new_size > 0xffff) {
+ 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, char, new_size);
+ outbuf = TALLOC_REALLOC_ARRAY(NULL, *poutbuf, uint8_t, new_size);
if (outbuf == NULL) {
DEBUG(0, ("talloc failed\n"));
return false;
@@ -295,7 +295,7 @@ bool smb_splice_chain(char **poutbuf, uint8_t smb_command,
if (!find_andx_cmd_ofs(outbuf, &andx_cmd_ofs)) {
DEBUG(1, ("invalid command chain\n"));
*poutbuf = TALLOC_REALLOC_ARRAY(
- NULL, *poutbuf, char, old_size);
+ NULL, *poutbuf, uint8_t, old_size);
return false;
}
@@ -310,20 +310,42 @@ bool smb_splice_chain(char **poutbuf, uint8_t smb_command,
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;
@@ -379,6 +401,7 @@ static int cli_async_req_destructor(struct async_req *req)
* @param[in] additional_flags open_and_x wants to add oplock header flags
* @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
*
@@ -394,7 +417,8 @@ static struct async_req *cli_request_chain(TALLOC_CTX *mem_ctx,
uint8_t smb_command,
uint8_t additional_flags,
uint8_t wct, const uint16_t *vwv,
- uint16_t num_bytes,
+ size_t bytes_alignment,
+ uint32_t num_bytes,
const uint8_t *bytes)
{
struct async_req **tmp_reqs;
@@ -423,7 +447,7 @@ static struct async_req *cli_request_chain(TALLOC_CTX *mem_ctx,
cli_async_req_destructor);
if (!smb_splice_chain(&req->outbuf, smb_command, wct, vwv,
- 0, num_bytes, bytes)) {
+ bytes_alignment, num_bytes, bytes)) {
goto fail;
}
@@ -489,11 +513,12 @@ bool cli_chain_cork(struct cli_state *cli, struct event_context *ev,
if (size_hint == 0) {
size_hint = 100;
}
- req->outbuf = talloc_array(req, char, smb_wct + size_hint);
+ req->outbuf = talloc_array(req, uint8_t, smb_wct + size_hint);
if (req->outbuf == NULL) {
goto fail;
}
- req->outbuf = TALLOC_REALLOC_ARRAY(NULL, req->outbuf, char, smb_wct);
+ req->outbuf = TALLOC_REALLOC_ARRAY(NULL, req->outbuf, uint8_t,
+ smb_wct);
req->num_async = 0;
req->async = NULL;
@@ -502,7 +527,7 @@ bool cli_chain_cork(struct cli_state *cli, struct event_context *ev,
req->recv_helper.fn = NULL;
SSVAL(req->outbuf, smb_tid, cli->cnum);
- cli_setup_packet_buf(cli, req->outbuf);
+ cli_setup_packet_buf(cli, (char *)req->outbuf);
req->mid = cli_new_mid(cli);
@@ -527,6 +552,7 @@ bool cli_chain_cork(struct cli_state *cli, struct event_context *ev,
void cli_chain_uncork(struct cli_state *cli)
{
struct cli_request *req = cli->chain_accumulator;
+ size_t smblen;
SMB_ASSERT(req != NULL);
@@ -536,22 +562,35 @@ void cli_chain_uncork(struct cli_state *cli)
cli->chain_accumulator = NULL;
SSVAL(req->outbuf, smb_mid, req->mid);
- smb_setlen(req->outbuf, talloc_get_size(req->outbuf) - 4);
- cli_calculate_sign_mac(cli, req->outbuf);
+ smblen = talloc_get_size(req->outbuf) - 4;
+
+ smb_setlen((char *)req->outbuf, smblen);
+
+ if (smblen > 0x1ffff) {
+ /*
+ * This is a POSIX 14 word large write. Overwrite just the
+ * size field, the '0xFFSMB' has been set by smb_setlen which
+ * _smb_setlen_large does not do.
+ */
+ _smb_setlen_large(((char *)req->outbuf), smblen);
+ }
+
+ cli_calculate_sign_mac(cli, (char *)req->outbuf);
if (cli_encryption_on(cli)) {
NTSTATUS status;
char *enc_buf;
- status = cli_encrypt_message(cli, req->outbuf, &enc_buf);
+ status = cli_encrypt_message(cli, (char *)req->outbuf,
+ &enc_buf);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("Error in encrypting client message. "
"Error %s\n", nt_errstr(status)));
TALLOC_FREE(req);
return;
}
- req->outbuf = enc_buf;
+ req->outbuf = (uint8_t *)enc_buf;
req->enc_state = cli->trans_enc_state;
}
@@ -569,6 +608,7 @@ void cli_chain_uncork(struct cli_state *cli)
* @param[in] additional_flags open_and_x wants to add oplock header flags
* @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
*
@@ -581,7 +621,8 @@ struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
uint8_t smb_command,
uint8_t additional_flags,
uint8_t wct, const uint16_t *vwv,
- uint16_t num_bytes, const uint8_t *bytes)
+ size_t bytes_alignment,
+ uint32_t num_bytes, const uint8_t *bytes)
{
struct async_req *result;
bool uncork = false;
@@ -596,7 +637,7 @@ struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
}
result = cli_request_chain(mem_ctx, ev, cli, smb_command,
- additional_flags, wct, vwv,
+ additional_flags, wct, vwv, bytes_alignment,
num_bytes, bytes);
if (result == NULL) {
@@ -611,6 +652,37 @@ struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
}
/**
+ * Calculate the current ofs to wct for requests like write&x
+ * @param[in] req The smb request we're currently building
+ * @retval how many bytes offset have we accumulated?
+ */
+
+uint16_t cli_wct_ofs(const struct cli_state *cli)
+{
+ size_t buf_size;
+
+ if (cli->chain_accumulator == NULL) {
+ return smb_wct - 4;
+ }
+
+ buf_size = talloc_get_size(cli->chain_accumulator->outbuf);
+
+ if (buf_size == smb_wct) {
+ return smb_wct - 4;
+ }
+
+ /*
+ * Add alignment for subsequent requests
+ */
+
+ if ((buf_size % 4) != 0) {
+ buf_size += (4 - (buf_size % 4));
+ }
+
+ return buf_size - 4;
+}
+
+/**
* 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
@@ -955,6 +1027,39 @@ static void cli_state_handler(struct event_context *event_ctx,
DEBUG(11, ("cli_state_handler called with flags %d\n", flags));
+ if (flags & EVENT_FD_WRITE) {
+ size_t to_send;
+ ssize_t sent;
+
+ for (req = cli->outstanding_requests; req; req = req->next) {
+ to_send = smb_len(req->outbuf)+4;
+ if (to_send > req->sent) {
+ break;
+ }
+ }
+
+ if (req == NULL) {
+ if (cli->fd_event != NULL) {
+ event_fd_set_not_writeable(cli->fd_event);
+ }
+ return;
+ }
+
+ sent = sys_send(cli->fd, req->outbuf + req->sent,
+ to_send - req->sent, 0);
+
+ if (sent < 0) {
+ status = map_nt_error_from_unix(errno);
+ goto sock_error;
+ }
+
+ req->sent += sent;
+
+ if (req->sent == to_send) {
+ return;
+ }
+ }
+
if (flags & EVENT_FD_READ) {
int res, available;
size_t old_size, new_size;
@@ -1020,38 +1125,6 @@ static void cli_state_handler(struct event_context *event_ctx,
}
}
- if (flags & EVENT_FD_WRITE) {
- size_t to_send;
- ssize_t sent;
-
- for (req = cli->outstanding_requests; req; req = req->next) {
- to_send = smb_len(req->outbuf)+4;
- if (to_send > req->sent) {
- break;
- }
- }
-
- if (req == NULL) {
- if (cli->fd_event != NULL) {
- event_fd_set_not_writeable(cli->fd_event);
- }
- return;
- }
-
- sent = sys_send(cli->fd, req->outbuf + req->sent,
- to_send - req->sent, 0);
-
- if (sent < 0) {
- status = map_nt_error_from_unix(errno);
- goto sock_error;
- }
-
- req->sent += sent;
-
- if (req->sent == to_send) {
- return;
- }
- }
return;
sock_error: