Split up async_req into a generic and a NTSTATUS specific part
[tprouty/samba.git] / source3 / libsmb / async_smb.c
index 3b7442a6803c9d2ea6b8054a5bc44ba748e8507a..e579d1c9f0bcc32b7cdfda27ae2fbe6390f721ea 100644 (file)
@@ -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) {
@@ -151,32 +151,6 @@ bool cli_in_chain(struct cli_state *cli)
        return (cli->chain_accumulator->num_async != 0);
 }
 
-/**
- * Is the SMB command able to hold an AND_X successor
- * @param[in] cmd      The SMB command in question
- * @retval Can we add a chained request after "cmd"?
- */
-
-static bool is_andx_req(uint8_t cmd)
-{
-       switch (cmd) {
-       case SMBtconX:
-       case SMBlockingX:
-       case SMBopenX:
-       case SMBreadX:
-       case SMBwriteX:
-       case SMBsesssetupX:
-       case SMBulogoffX:
-       case SMBntcreateX:
-               return true;
-               break;
-       default:
-               break;
-       }
-
-       return false;
-}
-
 /**
  * @brief Find the smb_cmd offset of the last command pushed
  * @param[in] buf      The buffer we're building up
@@ -187,7 +161,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 +205,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;
@@ -274,13 +248,13 @@ bool smb_splice_chain(char **poutbuf, uint8_t smb_command,
 
        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 +269,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;
                }
 
@@ -401,6 +375,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
  *
@@ -417,7 +392,7 @@ static struct async_req *cli_request_chain(TALLOC_CTX *mem_ctx,
                                           uint8_t additional_flags,
                                           uint8_t wct, const uint16_t *vwv,
                                           size_t bytes_alignment,
-                                          uint16_t num_bytes,
+                                          uint32_t num_bytes,
                                           const uint8_t *bytes)
 {
        struct async_req **tmp_reqs;
@@ -434,7 +409,7 @@ static struct async_req *cli_request_chain(TALLOC_CTX *mem_ctx,
        req->async = tmp_reqs;
        req->num_async += 1;
 
-       req->async[req->num_async-1] = async_req_new(mem_ctx, ev);
+       req->async[req->num_async-1] = async_req_new(mem_ctx);
        if (req->async[req->num_async-1] == NULL) {
                DEBUG(0, ("async_req_new failed\n"));
                req->num_async -= 1;
@@ -512,11 +487,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;
@@ -525,7 +501,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);
 
@@ -550,6 +526,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);
 
@@ -559,22 +536,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;
        }
 
@@ -606,7 +596,7 @@ struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
                                   uint8_t additional_flags,
                                   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)
 {
        struct async_req *result;
        bool uncork = false;
@@ -635,6 +625,37 @@ struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
        return result;
 }
 
+/**
+ * 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
@@ -958,7 +979,7 @@ static void handle_incoming_pdu(struct cli_state *cli)
                   nt_errstr(status)));
 
        for (req = cli->outstanding_requests; req; req = req->next) {
-               async_req_error(req->async[0], status);
+               async_req_nterror(req->async[0], status);
        }
        return;
 }
@@ -975,7 +996,7 @@ static void cli_state_handler(struct event_context *event_ctx,
                              struct fd_event *event, uint16 flags, void *p)
 {
        struct cli_state *cli = (struct cli_state *)p;
-       struct cli_request *req;
+       struct cli_request *req, *next;
        NTSTATUS status;
 
        DEBUG(11, ("cli_state_handler called with flags %d\n", flags));
@@ -1081,10 +1102,15 @@ static void cli_state_handler(struct event_context *event_ctx,
        return;
 
  sock_error:
-       for (req = cli->outstanding_requests; req; req = req->next) {
-               int i;
-               for (i=0; i<req->num_async; i++) {
-                       async_req_error(req->async[i], status);
+
+       for (req = cli->outstanding_requests; req; req = next) {
+               int i, num_async;
+
+               next = req->next;
+               num_async = req->num_async;
+
+               for (i=0; i<num_async; i++) {
+                       async_req_nterror(req->async[i], status);
                }
        }
        TALLOC_FREE(cli->fd_event);