summaryrefslogtreecommitdiff
path: root/source3/libsmb/smb2cli_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libsmb/smb2cli_base.c')
-rw-r--r--source3/libsmb/smb2cli_base.c52
1 files changed, 34 insertions, 18 deletions
diff --git a/source3/libsmb/smb2cli_base.c b/source3/libsmb/smb2cli_base.c
index 37ac44dd07..1b5a8a6798 100644
--- a/source3/libsmb/smb2cli_base.c
+++ b/source3/libsmb/smb2cli_base.c
@@ -37,7 +37,7 @@ struct smb2cli_req_state {
uint8_t hdr[64];
uint8_t pad[7]; /* padding space for compounding */
- uint8_t *inbuf;
+ /* always an array of 3 talloc elements */
struct iovec *recv_iov;
};
@@ -160,6 +160,12 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
state->ev = ev;
state->cli = cli;
+ state->recv_iov = talloc_zero_array(state, struct iovec, 3);
+ if (state->recv_iov == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
state->fixed = fixed;
state->fixed_len = fixed_len;
state->dyn = dyn;
@@ -439,6 +445,7 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
struct cli_state *cli =
tevent_req_callback_data(subreq,
struct cli_state);
+ TALLOC_CTX *frame = talloc_stackframe();
struct tevent_req *req;
struct iovec *iov;
int i, num_iov;
@@ -447,7 +454,7 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
ssize_t received;
int err;
- received = read_smb_recv(subreq, talloc_tos(), &inbuf, &err);
+ received = read_smb_recv(subreq, frame, &inbuf, &err);
TALLOC_FREE(subreq);
if (received == -1) {
if (cli->fd != -1) {
@@ -458,13 +465,14 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
goto fail;
}
- status = smb2cli_inbuf_parse_compound(inbuf, talloc_tos(),
+ status = smb2cli_inbuf_parse_compound(inbuf, frame,
&iov, &num_iov);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
for (i=1; i<num_iov; i+=3) {
+ uint8_t *inbuf_ref = NULL;
struct iovec *cur = &iov[i];
uint8_t *inhdr = (uint8_t *)cur[0].iov_base;
struct smb2cli_req_state *state;
@@ -479,13 +487,25 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
}
smb2cli_req_unset_pending(req);
state = tevent_req_data(req, struct smb2cli_req_state);
- if (i+3 >= num_iov) {
- /* last in chain */
- state->inbuf = inbuf;
+
+ /*
+ * Note: here we use talloc_reference() in a way
+ * that does not expose it to the caller.
+ */
+ inbuf_ref = talloc_reference(state->recv_iov, inbuf);
+ if (tevent_req_nomem(inbuf_ref, req)) {
+ continue;
}
- state->recv_iov = cur;
+
+ /* copy the related buffers */
+ state->recv_iov[0] = cur[0];
+ state->recv_iov[1] = cur[1];
+ state->recv_iov[2] = cur[2];
+
tevent_req_done(req);
}
+
+ TALLOC_FREE(frame);
return;
fail:
/*
@@ -498,6 +518,8 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
smb2cli_req_unset_pending(req);
tevent_req_nterror(req, status);
}
+
+ TALLOC_FREE(frame);
}
NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
@@ -511,23 +533,17 @@ NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
if (tevent_req_is_nterror(req, &status)) {
return status;
}
+
+ status = NT_STATUS(IVAL(state->recv_iov[0].iov_base, SMB2_HDR_STATUS));
+
if (body_size != 0) {
if (body_size != SVAL(state->recv_iov[1].iov_base, 0)) {
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
}
- talloc_steal(req, state->inbuf);
if (piov != NULL) {
- *piov = state->recv_iov;
+ *piov = talloc_move(mem_ctx, &state->recv_iov);
}
- return NT_STATUS(IVAL(state->recv_iov[0].iov_base, SMB2_HDR_STATUS));
-}
-
-uint8_t *smb2cli_req_inbuf(struct tevent_req *req)
-{
- struct smb2cli_req_state *state = tevent_req_data(
- req, struct smb2cli_req_state);
-
- return state->inbuf;
+ return status;
}