diff options
author | Volker Lendecke <vl@samba.org> | 2008-08-25 13:33:41 +0200 |
---|---|---|
committer | Volker Lendecke <vl@samba.org> | 2008-08-28 17:53:37 +0200 |
commit | 128524930d490fb5ea637d99bffb36157c80869b (patch) | |
tree | ac12973877b56e5117ead320c5528a037da48770 | |
parent | 2650207d4adbfd68974fc2b342dd2af079a2552c (diff) | |
download | samba-128524930d490fb5ea637d99bffb36157c80869b.tar.gz samba-128524930d490fb5ea637d99bffb36157c80869b.tar.bz2 samba-128524930d490fb5ea637d99bffb36157c80869b.zip |
Add cli_pull_reply
Along the lines of cli_request_send this abstracts away the smb-level buffer
handling when parsing replies we got from the server.
(This used to be commit 253134d3aaa359fdfb665709dd5686f69af7f8fd)
-rw-r--r-- | source3/include/async_smb.h | 4 | ||||
-rw-r--r-- | source3/libsmb/async_smb.c | 54 | ||||
-rw-r--r-- | source3/libsmb/clifile.c | 20 | ||||
-rw-r--r-- | source3/libsmb/clireadwrite.c | 17 |
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; } |