summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libcli/smb/smbXcli_base.c209
-rw-r--r--libcli/smb/smbXcli_base.h20
2 files changed, 118 insertions, 111 deletions
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index 2a996be04b..36bbedc3ae 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -143,8 +143,6 @@ struct smbXcli_req_state {
int iov_count;
uint32_t seqnum;
- int chain_num;
- int chain_length;
struct tevent_req **chained_requests;
uint8_t recv_cmd;
@@ -1488,8 +1486,6 @@ static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
}
state->inbuf = inbuf;
- state->smb1.chain_num = i;
- state->smb1.chain_length = num_chained;
/*
* Note: here we use talloc_reference() in a way
@@ -1519,8 +1515,6 @@ static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
state->smb1.recv_cmd = cmd;
state->smb1.recv_status = status;
state->inbuf = talloc_move(state->smb1.recv_iov, &inbuf);
- state->smb1.chain_num = 0;
- state->smb1.chain_length = 1;
state->smb1.recv_iov[0] = iov[0];
state->smb1.recv_iov[1] = iov[1];
@@ -1537,149 +1531,148 @@ static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
}
NTSTATUS smb1cli_req_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx, uint8_t **pinbuf,
- uint8_t min_wct, uint8_t *pwct, uint16_t **pvwv,
- uint32_t *pnum_bytes, uint8_t **pbytes)
+ TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ uint8_t **phdr,
+ uint8_t *pwct,
+ uint16_t **pvwv,
+ uint32_t *pvwv_offset,
+ uint32_t *pnum_bytes,
+ uint8_t **pbytes,
+ uint32_t *pbytes_offset,
+ uint8_t **pinbuf,
+ const struct smb1cli_req_expected_response *expected,
+ size_t num_expected)
{
struct smbXcli_req_state *state =
tevent_req_data(req,
struct smbXcli_req_state);
NTSTATUS status = NT_STATUS_OK;
- uint8_t cmd, wct;
- uint16_t num_bytes;
- size_t wct_ofs, bytes_offset;
- int i;
+ struct iovec *recv_iov = NULL;
+ uint8_t *hdr = NULL;
+ uint8_t wct = 0;
+ uint32_t vwv_offset = 0;
+ uint16_t *vwv = NULL;
+ uint32_t num_bytes = 0;
+ uint32_t bytes_offset = 0;
+ uint8_t *bytes = NULL;
+ size_t i;
+ bool found_status = false;
+ bool found_size = false;
- if (tevent_req_is_nterror(req, &status)) {
- return status;
+ if (piov != NULL) {
+ *piov = NULL;
}
-
- if (state->inbuf == NULL) {
- if (min_wct != 0) {
- return NT_STATUS_INVALID_NETWORK_RESPONSE;
- }
- if (pinbuf) {
- *pinbuf = NULL;
- }
- if (pwct) {
- *pwct = 0;
- }
- if (pvwv) {
- *pvwv = NULL;
- }
- if (pnum_bytes) {
- *pnum_bytes = 0;
- }
- if (pbytes) {
- *pbytes = NULL;
- }
- /* This was a request without a reply */
- return NT_STATUS_OK;
+ if (phdr != NULL) {
+ *phdr = 0;
+ }
+ if (pwct != NULL) {
+ *pwct = 0;
+ }
+ if (pvwv != NULL) {
+ *pvwv = NULL;
+ }
+ if (pvwv_offset != NULL) {
+ *pvwv_offset = 0;
+ }
+ if (pnum_bytes != NULL) {
+ *pnum_bytes = 0;
+ }
+ if (pbytes != NULL) {
+ *pbytes = NULL;
+ }
+ if (pbytes_offset != NULL) {
+ *pbytes_offset = 0;
+ }
+ if (pinbuf != NULL) {
+ *pinbuf = NULL;
}
- wct_ofs = NBT_HDR_SIZE + HDR_WCT;
- cmd = CVAL(state->inbuf, NBT_HDR_SIZE + HDR_COM);
+ if (state->inbuf != NULL) {
+ recv_iov = state->smb1.recv_iov;
+ hdr = (uint8_t *)recv_iov[0].iov_base;
+ wct = recv_iov[1].iov_len/2;
+ vwv = (uint16_t *)recv_iov[1].iov_base;
+ vwv_offset = PTR_DIFF(vwv, hdr);
+ num_bytes = recv_iov[2].iov_len;
+ bytes = (uint8_t *)recv_iov[2].iov_base;
+ bytes_offset = PTR_DIFF(bytes, hdr);
+ }
- for (i=0; i<state->smb1.chain_num; i++) {
- if (i < state->smb1.chain_num-1) {
- if (cmd == 0xff) {
- return NT_STATUS_REQUEST_ABORTED;
- }
- if (!smb1cli_is_andx_req(cmd)) {
- return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ if (tevent_req_is_nterror(req, &status)) {
+ for (i=0; i < num_expected; i++) {
+ if (NT_STATUS_EQUAL(status, expected[i].status)) {
+ found_status = true;
+ break;
}
}
- if (!smb1cli_have_andx_command(state->inbuf, wct_ofs, cmd)) {
- /*
- * This request was not completed because a previous
- * request in the chain had received an error.
- */
- return NT_STATUS_REQUEST_ABORTED;
+ if (found_status) {
+ return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
}
- cmd = CVAL(state->inbuf, wct_ofs + 1);
- wct_ofs = SVAL(state->inbuf, wct_ofs + 3);
-
- /*
- * Skip the all-present length field. No overflow, we've just
- * put a 16-bit value into a size_t.
- */
- wct_ofs += 4;
+ return status;
+ }
- if (wct_ofs+2 > talloc_get_size(state->inbuf)) {
- return NT_STATUS_INVALID_NETWORK_RESPONSE;
- }
+ if (num_expected == 0) {
+ found_status = true;
+ found_size = true;
}
- status = smb1cli_pull_raw_error(state->inbuf+NBT_HDR_SIZE);
+ status = state->smb1.recv_status;
- if (!smb1cli_have_andx_command(state->inbuf, wct_ofs, cmd)) {
+ for (i=0; i < num_expected; i++) {
+ if (!NT_STATUS_EQUAL(status, expected[i].status)) {
+ continue;
+ }
- if ((cmd == SMBsesssetupX)
- && NT_STATUS_EQUAL(
- status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- /*
- * NT_STATUS_MORE_PROCESSING_REQUIRED is a
- * valid return code for session setup
- */
- goto no_err;
+ found_status = true;
+ if (expected[i].wct == 0) {
+ found_size = true;
+ break;
}
- if (NT_STATUS_IS_ERR(status)) {
- /*
- * The last command takes the error code. All
- * further commands down the requested chain
- * will get a NT_STATUS_REQUEST_ABORTED.
- */
- return status;
+ if (expected[i].wct == wct) {
+ found_size = true;
+ break;
}
- } else {
- /*
- * Only the last request in the chain get the returned
- * status.
- */
- status = NT_STATUS_OK;
}
-no_err:
-
- wct = CVAL(state->inbuf, wct_ofs);
- bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t);
- num_bytes = SVAL(state->inbuf, bytes_offset);
+ if (!found_status) {
+ return status;
+ }
- if (wct < min_wct) {
+ if (!found_size) {
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
- /*
- * 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(state->inbuf))
- || (bytes_offset > 0xffff)) {
- return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ if (piov != NULL) {
+ *piov = talloc_move(mem_ctx, &recv_iov);
}
+ if (phdr != NULL) {
+ *phdr = hdr;
+ }
if (pwct != NULL) {
*pwct = wct;
}
if (pvwv != NULL) {
- *pvwv = (uint16_t *)(state->inbuf + wct_ofs + 1);
+ *pvwv = vwv;
+ }
+ if (pvwv_offset != NULL) {
+ *pvwv_offset = vwv_offset;
}
if (pnum_bytes != NULL) {
*pnum_bytes = num_bytes;
}
if (pbytes != NULL) {
- *pbytes = (uint8_t *)state->inbuf + bytes_offset + 2;
+ *pbytes = bytes;
}
- if ((mem_ctx != NULL) && (pinbuf != NULL)) {
- if (state->smb1.chain_num == state->smb1.chain_length-1) {
- *pinbuf = talloc_move(mem_ctx, &state->inbuf);
- } else {
- *pinbuf = state->inbuf;
- }
+ if (pbytes_offset != NULL) {
+ *pbytes_offset = bytes_offset;
+ }
+ if (pinbuf != NULL) {
+ *pinbuf = state->inbuf;
}
return status;
diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
index fdcd3aadf2..17c889c4e5 100644
--- a/libcli/smb/smbXcli_base.h
+++ b/libcli/smb/smbXcli_base.h
@@ -66,6 +66,11 @@ void smb1cli_req_set_mid(struct tevent_req *req, uint16_t mid);
uint32_t smb1cli_req_seqnum(struct tevent_req *req);
void smb1cli_req_set_seqnum(struct tevent_req *req, uint32_t seqnum);
+struct smb1cli_req_expected_response {
+ NTSTATUS status;
+ uint8_t wct;
+};
+
struct tevent_req *smb1cli_req_create(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct smbXcli_conn *conn,
@@ -99,9 +104,18 @@ struct tevent_req *smb1cli_req_send(TALLOC_CTX *mem_ctx,
uint32_t num_bytes,
const uint8_t *bytes);
NTSTATUS smb1cli_req_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx, uint8_t **pinbuf,
- uint8_t min_wct, uint8_t *pwct, uint16_t **pvwv,
- uint32_t *pnum_bytes, uint8_t **pbytes);
+ TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ uint8_t **phdr,
+ uint8_t *pwct,
+ uint16_t **pvwv,
+ uint32_t *pvwv_offset,
+ uint32_t *pnum_bytes,
+ uint8_t **pbytes,
+ uint32_t *pbytes_offset,
+ uint8_t **pinbuf,
+ const struct smb1cli_req_expected_response *expected,
+ size_t num_expected);
struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,