Add cli_pull_reply
authorVolker Lendecke <vl@samba.org>
Mon, 25 Aug 2008 11:33:41 +0000 (13:33 +0200)
committerVolker Lendecke <vl@samba.org>
Thu, 28 Aug 2008 15:53:37 +0000 (17:53 +0200)
Along the lines of cli_request_send this abstracts away the smb-level buffer
handling when parsing replies we got from the server.

source/include/async_smb.h
source/libsmb/async_smb.c
source/libsmb/clifile.c
source/libsmb/clireadwrite.c

index 40a8d3476eee1684c82c812deaa201cf26dea90e..93d2273239c1261979272082364d7ace1318e782 100644 (file)
@@ -37,6 +37,10 @@ struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
 
 struct cli_request *cli_request_get(struct async_req *req);
 
+NTSTATUS cli_pull_reply(struct async_req *req,
+                       uint8_t *pwct, uint16_t **pvwv,
+                       uint16_t *pnum_bytes, uint8_t **pbytes);
+
 /*
  * Fetch an error out of a NBT packet
  */
index e58b753da2bff099b68edf36a9cd854fd6cc04a3..32f0e8abd6124f96bfda972fc1ee3668b8d1b004 100644 (file)
@@ -230,6 +230,60 @@ struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
        return result;
 }
 
+/**
+ * @brief Pull reply data out of a request
+ * @param[in] req              The request that we just received a reply for
+ * @param[out] pwct            How many words did the server send?
+ * @param[out] pvwv            The words themselves
+ * @param[out] pnum_bytes      How many bytes did the server send?
+ * @param[out] pbytes          The bytes themselves
+ * @retval Was the reply formally correct?
+ */
+
+NTSTATUS cli_pull_reply(struct async_req *req,
+                       uint8_t *pwct, uint16_t **pvwv,
+                       uint16_t *pnum_bytes, uint8_t **pbytes)
+{
+       struct cli_request *cli_req = cli_request_get(req);
+       uint8_t wct, cmd;
+       uint16_t num_bytes;
+       size_t wct_ofs, bytes_offset;
+       NTSTATUS status;
+
+       status = cli_pull_error(cli_req->inbuf);
+
+       if (NT_STATUS_IS_ERR(status)) {
+               cli_set_error(cli_req->cli, status);
+               return status;
+       }
+
+       cmd = CVAL(cli_req->inbuf, smb_com);
+       wct_ofs = smb_wct;
+
+       wct = CVAL(cli_req->inbuf, wct_ofs);
+
+       bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t);
+       num_bytes = SVAL(cli_req->inbuf, bytes_offset);
+
+       /*
+        * wct_ofs is a 16-bit value plus 4, wct is a 8-bit value, num_bytes
+        * is a 16-bit value. So bytes_offset being size_t should be far from
+        * wrapping.
+        */
+
+       if ((bytes_offset + 2 > talloc_get_size(cli_req->inbuf))
+           || (bytes_offset > 0xffff)) {
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+
+       *pwct = wct;
+       *pvwv = (uint16_t *)(cli_req->inbuf + wct_ofs + 1);
+       *pnum_bytes = num_bytes;
+       *pbytes = (uint8_t *)cli_req->inbuf + bytes_offset + 2;
+
+       return NT_STATUS_OK;
+}
+
 /*
  * Convenience function to get the SMB part out of an async_req
  */
index dfb0ce8c111fc3854e4f7a78db8cd8c646d336fa..b3032a08eb078e0d160f4ab88b45e109a381f389 100644 (file)
@@ -902,7 +902,10 @@ struct async_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
 
 NTSTATUS cli_open_recv(struct async_req *req, int *fnum)
 {
-       struct cli_request *cli_req = cli_request_get(req);
+       uint8_t wct;
+       uint16_t *vwv;
+       uint16_t num_bytes;
+       uint8_t *bytes;
        NTSTATUS status;
 
        SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
@@ -910,12 +913,16 @@ NTSTATUS cli_open_recv(struct async_req *req, int *fnum)
                return req->status;
        }
 
-       status = cli_pull_error(cli_req->inbuf);
+       status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       *fnum = SVAL(cli_req->inbuf, smb_vwv2);
+       if (wct < 3) {
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+
+       *fnum = SVAL(vwv+2, 0);
 
        return NT_STATUS_OK;
 }
@@ -974,14 +981,17 @@ struct async_req *cli_close_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
 
 NTSTATUS cli_close_recv(struct async_req *req)
 {
-       struct cli_request *cli_req = cli_request_get(req);
+       uint8_t wct;
+       uint16_t *vwv;
+       uint16_t num_bytes;
+       uint8_t *bytes;
 
        SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
        if (req->state == ASYNC_REQ_ERROR) {
                return req->status;
        }
 
-       return cli_pull_error(cli_req->inbuf);
+       return cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
 }
 
 bool cli_close(struct cli_state *cli, int fnum)
index d2c8f3c1ba391ed09ff5c48ddae59a47efb6108c..b64a4c68f3304947f732ecf5865cdabc67074cf3 100644 (file)
@@ -104,6 +104,10 @@ NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received,
                            uint8_t **rcvbuf)
 {
        struct cli_request *cli_req = cli_request_get(req);
+       uint8_t wct;
+       uint16_t *vwv;
+       uint16_t num_bytes;
+       uint8_t *bytes;
        NTSTATUS status;
        size_t size;
 
@@ -112,24 +116,27 @@ NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received,
                return req->status;
        }
 
-       status = cli_pull_error(cli_req->inbuf);
+       status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
 
        if (NT_STATUS_IS_ERR(status)) {
                return status;
        }
 
+       if (wct < 12) {
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+
        /* size is the number of bytes the server returned.
         * Might be zero. */
-       size = SVAL(cli_req->inbuf, smb_vwv5);
-       size |= (((unsigned int)(SVAL(cli_req->inbuf, smb_vwv7))) << 16);
+       size = SVAL(vwv + 5, 0);
+       size |= (((unsigned int)SVAL(vwv + 7, 0)) << 16);
 
        if (size > cli_req->data.read.size) {
                DEBUG(5,("server returned more than we wanted!\n"));
                return NT_STATUS_UNEXPECTED_IO_ERROR;
        }
 
-       *rcvbuf = (uint8_t *)
-               (smb_base(cli_req->inbuf) + SVAL(cli_req->inbuf, smb_vwv6));
+       *rcvbuf = (uint8_t *)(smb_base(cli_req->inbuf) + SVAL(vwv + 6, 0));
        *received = size;
        return NT_STATUS_OK;
 }