summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/async_smb.h4
-rw-r--r--source3/libsmb/async_smb.c54
-rw-r--r--source3/libsmb/clifile.c20
-rw-r--r--source3/libsmb/clireadwrite.c17
4 files changed, 85 insertions, 10 deletions
diff --git a/source3/include/async_smb.h b/source3/include/async_smb.h
index 40a8d3476e..93d2273239 100644
--- a/source3/include/async_smb.h
+++ b/source3/include/async_smb.h
@@ -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
*/
diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c
index e58b753da2..32f0e8abd6 100644
--- a/source3/libsmb/async_smb.c
+++ b/source3/libsmb/async_smb.c
@@ -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
*/
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index dfb0ce8c11..b3032a08eb 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -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)
diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c
index d2c8f3c1ba..b64a4c68f3 100644
--- a/source3/libsmb/clireadwrite.c
+++ b/source3/libsmb/clireadwrite.c
@@ -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;
}