summaryrefslogtreecommitdiff
path: root/libcli
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2021-01-14 17:27:21 +0100
committerVolker Lendecke <vl@samba.org>2021-01-15 07:26:29 +0000
commit508ed5b42c23f8b3d9730d838bd921cb73c61358 (patch)
tree3219efe601224919c2f60e1a34e36f939b1e4ed1 /libcli
parent0abb5ca6b96c843909dea56d5594e334547ae90f (diff)
downloadsamba-508ed5b42c23f8b3d9730d838bd921cb73c61358.tar.gz
libcli/smb: split out smb2cli_ioctl_parse_buffer()
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14607 Pair-Programmed-With: Volker Lendecke <vl@samba.org> Signed-off-by: Stefan Metzmacher <metze@samba.org> Signed-off-by: Volker Lendecke <vl@samba.org>
Diffstat (limited to 'libcli')
-rw-r--r--libcli/smb/smb2cli_ioctl.c190
1 files changed, 110 insertions, 80 deletions
diff --git a/libcli/smb/smb2cli_ioctl.c b/libcli/smb/smb2cli_ioctl.c
index 2b572baeb23..6368bd31bc2 100644
--- a/libcli/smb/smb2cli_ioctl.c
+++ b/libcli/smb/smb2cli_ioctl.c
@@ -160,6 +160,80 @@ struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx,
return req;
}
+static NTSTATUS smb2cli_ioctl_parse_buffer(uint32_t dyn_offset,
+ const DATA_BLOB dyn_buffer,
+ uint32_t min_offset,
+ uint32_t buffer_offset,
+ uint32_t buffer_length,
+ uint32_t max_length,
+ uint32_t *next_offset,
+ DATA_BLOB *buffer)
+{
+ uint32_t offset;
+ bool oob;
+
+ *buffer = data_blob_null;
+ *next_offset = dyn_offset;
+
+ if (buffer_offset == 0) {
+ /*
+ * If the offset is 0, we better ignore
+ * the buffer_length field.
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (buffer_length == 0) {
+ /*
+ * If the length is 0, we better ignore
+ * the buffer_offset field.
+ */
+ return NT_STATUS_OK;
+ }
+
+ SMB_ASSERT(min_offset >= dyn_offset);
+ if (buffer_offset != min_offset) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * Make [input|output]_buffer_offset relative to "dyn_buffer"
+ */
+ offset = buffer_offset - dyn_offset;
+ oob = smb_buffer_oob(dyn_buffer.length, offset, buffer_length);
+ if (oob) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * Give the caller a hint what we consumed,
+ * the caller may need to add possible padding.
+ */
+ *next_offset = buffer_offset + buffer_length;
+
+ if (max_length == 0) {
+ /*
+ * If max_input_length is 0 we ignore the
+ * input_buffer_length, because Windows 2008 echos the
+ * DCERPC request from the requested input_buffer to
+ * the response input_buffer.
+ *
+ * We just use the same logic also for max_output_length...
+ */
+ buffer_length = 0;
+ }
+
+ if (buffer_length > max_length) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *buffer = (DATA_BLOB) {
+ .data = dyn_buffer.data + offset,
+ .length = buffer_length,
+ };
+ return NT_STATUS_OK;
+}
+
static void smb2cli_ioctl_done(struct tevent_req *subreq)
{
struct tevent_req *req =
@@ -169,15 +243,19 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq)
tevent_req_data(req,
struct smb2cli_ioctl_state);
NTSTATUS status;
+ NTSTATUS error;
struct iovec *iov;
uint8_t *fixed;
- uint8_t *dyn;
- size_t dyn_len;
+ DATA_BLOB dyn_buffer = data_blob_null;
uint32_t dyn_ofs = SMB2_HDR_BODY + 0x30;
+ uint32_t input_min_offset;
uint32_t input_buffer_offset;
uint32_t input_buffer_length;
+ uint32_t input_next_offset;
+ uint32_t output_min_offset;
uint32_t output_buffer_offset;
uint32_t output_buffer_length;
+ uint32_t output_next_offset;
static const struct smb2cli_req_expected_response expected[] = {
{
.status = NT_STATUS_OK,
@@ -247,92 +325,44 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq)
state->recv_iov = iov;
fixed = (uint8_t *)iov[1].iov_base;
- dyn = (uint8_t *)iov[2].iov_base;
- dyn_len = iov[2].iov_len;
+ dyn_buffer = data_blob_const((uint8_t *)iov[2].iov_base,
+ iov[2].iov_len);
input_buffer_offset = IVAL(fixed, 0x18);
input_buffer_length = IVAL(fixed, 0x1C);
output_buffer_offset = IVAL(fixed, 0x20);
output_buffer_length = IVAL(fixed, 0x24);
- if ((input_buffer_offset > 0) && (input_buffer_length > 0)) {
- uint32_t ofs;
-
- if (input_buffer_offset != dyn_ofs) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- ofs = input_buffer_length;
- ofs = NDR_ROUND(ofs, 8);
-
- if (state->max_input_length == 0) {
- /*
- * If max_input_length is 0 we ignore
- * the input_buffer_length, because
- * Windows 2008 echos the DCERPC request
- * from the requested input_buffer
- * to the response input_buffer.
- */
- input_buffer_length = 0;
- }
-
- if (input_buffer_length > dyn_len) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- if (input_buffer_length > state->max_input_length) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- state->out_input_buffer.data = dyn;
- state->out_input_buffer.length = input_buffer_length;
-
- if (ofs > dyn_len) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- dyn_ofs += ofs;
- dyn += ofs;
- dyn_len -= ofs;
+ input_min_offset = dyn_ofs;
+ input_next_offset = dyn_ofs;
+ error = smb2cli_ioctl_parse_buffer(dyn_ofs,
+ dyn_buffer,
+ input_min_offset,
+ input_buffer_offset,
+ input_buffer_length,
+ state->max_input_length,
+ &input_next_offset,
+ &state->out_input_buffer);
+ if (tevent_req_nterror(req, error)) {
+ return;
}
- if ((output_buffer_offset > 0) && (output_buffer_length > 0)) {
- if (output_buffer_offset != dyn_ofs) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- if (state->max_output_length == 0) {
- /*
- * We do the same logic as for
- * max_input_length.
- */
- output_buffer_length = 0;
- }
-
- if (output_buffer_length > dyn_len) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- if (output_buffer_length > state->max_output_length) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- state->out_output_buffer.data = dyn;
- state->out_output_buffer.length = output_buffer_length;
+ /*
+ * If output data is returned, the output offset MUST be set to
+ * InputOffset + InputCount rounded up to a multiple of 8.
+ */
+ output_min_offset = NDR_ROUND(input_next_offset, 8);
+ output_next_offset = 0; /* this variable is completely ignored */
+ error = smb2cli_ioctl_parse_buffer(dyn_ofs,
+ dyn_buffer,
+ output_min_offset,
+ output_buffer_offset,
+ output_buffer_length,
+ state->max_output_length,
+ &output_next_offset,
+ &state->out_output_buffer);
+ if (tevent_req_nterror(req, error)) {
+ return;
}
state->out_valid = true;