summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/smbd/globals.h6
-rw-r--r--source3/smbd/smb2_server.c335
2 files changed, 80 insertions, 261 deletions
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 9a8910cdfd..967fe858e8 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -493,10 +493,8 @@ struct smbd_smb2_request {
#define SMBD_SMB2_OUT_DYN_LEN(req) (SMBD_SMB2_OUT_DYN_IOV(req)->iov_len)
struct {
- /* the NBT header is not allocated */
- uint8_t nbt_hdr[4];
/*
- * vector[0] NBT
+ * vector[0] TRANSPORT HEADER
* .
* vector[1] SMB2
* vector[2] fixed body
@@ -518,7 +516,7 @@ struct smbd_smb2_request {
/* the NBT header is not allocated */
uint8_t nbt_hdr[4];
/*
- * vector[0] NBT
+ * vector[0] TRANSPORT HEADER
* .
* vector[1] SMB2
* vector[2] fixed body
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 7002479246..1c19cce442 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -332,8 +332,6 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
talloc_steal(req, inbuf);
- memcpy(req->in.nbt_hdr, inbuf, 4);
-
req->request_time = timeval_current();
now = timeval_to_nttime(&req->request_time);
@@ -740,8 +738,6 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
int count;
int idx;
- req->request_time = timeval_current();
-
count = req->in.vector_count;
vector = talloc_zero_array(req, struct iovec, count);
if (vector == NULL) {
@@ -2491,9 +2487,15 @@ static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
}
struct smbd_smb2_request_read_state {
- size_t missing;
- bool asked_for_header;
+ struct tevent_context *ev;
+ struct smbd_server_connection *sconn;
struct smbd_smb2_request *smb2_req;
+ struct {
+ uint8_t nbt[NBT_HDR_SIZE];
+ bool done;
+ } hdr;
+ size_t pktlen;
+ uint8_t *pktbuf;
};
static int smbd_smb2_request_next_vector(struct tstream_context *stream,
@@ -2516,8 +2518,8 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
if (req == NULL) {
return NULL;
}
- state->missing = 0;
- state->asked_for_header = false;
+ state->ev = ev;
+ state->sconn = sconn;
state->smb2_req = smbd_smb2_request_allocate(state);
if (tevent_req_nomem(state->smb2_req, req)) {
@@ -2525,10 +2527,12 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
}
state->smb2_req->sconn = sconn;
- subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
- sconn->smb2.recv_queue,
- smbd_smb2_request_next_vector,
- state);
+ subreq = tstream_readv_pdu_queue_send(state->smb2_req,
+ state->ev,
+ state->sconn->smb2.stream,
+ state->sconn->smb2.recv_queue,
+ smbd_smb2_request_next_vector,
+ state);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
@@ -2546,273 +2550,58 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
struct smbd_smb2_request_read_state *state =
talloc_get_type_abort(private_data,
struct smbd_smb2_request_read_state);
- struct smbd_smb2_request *req = state->smb2_req;
struct iovec *vector;
- int idx = req->in.vector_count;
- size_t len = 0;
- uint8_t *buf = NULL;
-
- if (req->in.vector_count == 0) {
- /*
- * first we need to get the NBT header
- */
- req->in.vector = talloc_array(req, struct iovec,
- req->in.vector_count + 1);
- if (req->in.vector == NULL) {
- return -1;
- }
- req->in.vector_count += 1;
-
- req->in.vector[idx].iov_base = (void *)req->in.nbt_hdr;
- req->in.vector[idx].iov_len = 4;
-
- vector = talloc_array(mem_ctx, struct iovec, 1);
- if (vector == NULL) {
- return -1;
- }
-
- vector[0] = req->in.vector[idx];
-
- *_vector = vector;
- *_count = 1;
- return 0;
- }
-
- if (req->in.vector_count == 1) {
- /*
- * Now we analyze the NBT header
- */
- state->missing = smb2_len(req->in.vector[0].iov_base);
-
- if (state->missing == 0) {
- /* if there're no remaining bytes, we're done */
- *_vector = NULL;
- *_count = 0;
- return 0;
- }
-
- req->in.vector = talloc_realloc(req, req->in.vector,
- struct iovec,
- req->in.vector_count + 1);
- if (req->in.vector == NULL) {
- return -1;
- }
- req->in.vector_count += 1;
-
- if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
- /*
- * it's a special NBT message,
- * so get all remaining bytes
- */
- len = state->missing;
- } else if (state->missing < (SMB2_HDR_BODY + 2)) {
- /*
- * it's an invalid message, just read what we can get
- * and let the caller handle the error
- */
- len = state->missing;
- } else {
- /*
- * We assume it's a SMB2 request,
- * and we first get the header and the
- * first 2 bytes (the struct size) of the body
- */
- len = SMB2_HDR_BODY + 2;
-
- state->asked_for_header = true;
- }
-
- state->missing -= len;
-
- buf = talloc_array(req->in.vector, uint8_t, len);
- if (buf == NULL) {
- return -1;
- }
-
- req->in.vector[idx].iov_base = (void *)buf;
- req->in.vector[idx].iov_len = len;
-
- vector = talloc_array(mem_ctx, struct iovec, 1);
- if (vector == NULL) {
- return -1;
- }
-
- vector[0] = req->in.vector[idx];
- *_vector = vector;
- *_count = 1;
- return 0;
- }
-
- if (state->missing == 0) {
+ if (state->pktlen > 0) {
/* if there're no remaining bytes, we're done */
*_vector = NULL;
*_count = 0;
return 0;
}
- if (state->asked_for_header) {
- const uint8_t *hdr;
- size_t full_size;
- size_t next_command_ofs;
- size_t body_size;
- uint8_t *body;
- size_t dyn_size;
- uint8_t *dyn;
- bool invalid = false;
-
- state->asked_for_header = false;
-
+ if (!state->hdr.done) {
/*
- * We got the SMB2 header and the first 2 bytes
- * of the body. We fix the size to just the header
- * and manually copy the 2 first bytes to the body section
+ * first we need to get the NBT header
*/
- req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
- hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
-
- /* allocate vectors for body and dynamic areas */
- req->in.vector = talloc_realloc(req, req->in.vector,
- struct iovec,
- req->in.vector_count + 2);
- if (req->in.vector == NULL) {
- return -1;
- }
- req->in.vector_count += 2;
-
- full_size = state->missing + SMB2_HDR_BODY + 2;
- next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
- body_size = SVAL(hdr, SMB2_HDR_BODY);
-
- if (next_command_ofs != 0) {
- if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
- /*
- * this is invalid, just return a zero
- * body and let the caller deal with the error
- */
- invalid = true;
- } else if (next_command_ofs > full_size) {
- /*
- * this is invalid, just return a zero
- * body and let the caller deal with the error
- */
- invalid = true;
- } else {
- full_size = next_command_ofs;
- }
- }
-
- if (!invalid) {
- if (body_size < 2) {
- /*
- * this is invalid, just return a zero
- * body and let the caller deal with the error
- */
- invalid = true;
- }
-
- /*
- * Mask out the lowest bit, the "dynamic" part
- * of body_size.
- */
- body_size &= ~1;
-
- if (body_size > (full_size - SMB2_HDR_BODY)) {
- /*
- * this is invalid, just return a zero
- * body and let the caller deal with the error
- */
- invalid = true;
- }
- }
-
- if (invalid) {
- /* the caller should check this */
- body_size = 2;
- }
-
- dyn_size = full_size - (SMB2_HDR_BODY + body_size);
-
- state->missing -= (body_size - 2) + dyn_size;
-
- body = talloc_array(req->in.vector, uint8_t, body_size);
- if (body == NULL) {
- return -1;
- }
-
- dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
- if (dyn == NULL) {
- return -1;
- }
-
- req->in.vector[idx].iov_base = (void *)body;
- req->in.vector[idx].iov_len = body_size;
- req->in.vector[idx+1].iov_base = (void *)dyn;
- req->in.vector[idx+1].iov_len = dyn_size;
-
- vector = talloc_array(mem_ctx, struct iovec, 2);
+ vector = talloc_array(mem_ctx, struct iovec, 1);
if (vector == NULL) {
return -1;
}
- /*
- * the first 2 bytes of the body were already fetched
- * together with the header
- */
- memcpy(body, hdr + SMB2_HDR_BODY, 2);
- vector[0].iov_base = body + 2;
- vector[0].iov_len = body_size - 2;
-
- vector[1] = req->in.vector[idx+1];
+ vector[0].iov_base = (void *)state->hdr.nbt;
+ vector[0].iov_len = NBT_HDR_SIZE;
*_vector = vector;
- *_count = 2;
- return 0;
- }
-
- /*
- * when we endup here, we're looking for a new SMB2 request
- * next. And we ask for its header and the first 2 bytes of
- * the body (like we did for the first SMB2 request).
- */
+ *_count = 1;
- req->in.vector = talloc_realloc(req, req->in.vector,
- struct iovec,
- req->in.vector_count + 1);
- if (req->in.vector == NULL) {
- return -1;
+ state->hdr.done = true;
+ return 0;
}
- req->in.vector_count += 1;
/*
- * We assume it's a SMB2 request,
- * and we first get the header and the
- * first 2 bytes (the struct size) of the body
+ * Now we analyze the NBT header
*/
- len = SMB2_HDR_BODY + 2;
+ state->pktlen = smb2_len(state->hdr.nbt);
- if (len > state->missing) {
- /* let the caller handle the error */
- len = state->missing;
+ if (state->pktlen == 0) {
+ /* if there're no remaining bytes, we're done */
+ *_vector = NULL;
+ *_count = 0;
+ return 0;
}
- state->missing -= len;
- state->asked_for_header = true;
-
- buf = talloc_array(req->in.vector, uint8_t, len);
- if (buf == NULL) {
+ state->pktbuf = talloc_array(state->smb2_req, uint8_t, state->pktlen);
+ if (state->pktbuf == NULL) {
return -1;
}
- req->in.vector[idx].iov_base = (void *)buf;
- req->in.vector[idx].iov_len = len;
-
vector = talloc_array(mem_ctx, struct iovec, 1);
if (vector == NULL) {
return -1;
}
- vector[0] = req->in.vector[idx];
+ vector[0].iov_base = (void *)state->pktbuf;
+ vector[0].iov_len = state->pktlen;
*_vector = vector;
*_count = 1;
@@ -2824,17 +2613,59 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq)
struct tevent_req *req =
tevent_req_callback_data(subreq,
struct tevent_req);
+ struct smbd_smb2_request_read_state *state =
+ tevent_req_data(req,
+ struct smbd_smb2_request_read_state);
int ret;
int sys_errno;
NTSTATUS status;
+ NTTIME now;
ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
if (ret == -1) {
status = map_nt_error_from_unix(sys_errno);
tevent_req_nterror(req, status);
return;
}
+ if (state->hdr.nbt[0] != 0x00) {
+ DEBUG(1,("smbd_smb2_request_read_done: ignore NBT[0x%02X] msg\n",
+ state->hdr.nbt[0]));
+
+ ZERO_STRUCT(state->hdr);
+ TALLOC_FREE(state->pktbuf);
+ state->pktlen = 0;
+
+ subreq = tstream_readv_pdu_queue_send(state->smb2_req,
+ state->ev,
+ state->sconn->smb2.stream,
+ state->sconn->smb2.recv_queue,
+ smbd_smb2_request_next_vector,
+ state);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
+ return;
+ }
+
+ state->smb2_req->request_time = timeval_current();
+ now = timeval_to_nttime(&state->smb2_req->request_time);
+
+ status = smbd_smb2_inbuf_parse_compound(state->smb2_req->sconn->conn,
+ now,
+ state->pktbuf,
+ state->pktlen,
+ state->smb2_req,
+ &state->smb2_req->in.vector,
+ &state->smb2_req->in.vector_count);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->smb2_req->current_idx = 1;
+
tevent_req_done(req);
}
@@ -2967,15 +2798,6 @@ static void smbd_smb2_request_incoming(struct tevent_req *subreq)
return;
}
- if (req->in.nbt_hdr[0] != 0x00) {
- DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
- req->in.nbt_hdr[0]));
- TALLOC_FREE(req);
- goto next;
- }
-
- req->current_idx = 1;
-
DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
req->current_idx, req->in.vector_count));
@@ -2997,7 +2819,6 @@ static void smbd_smb2_request_incoming(struct tevent_req *subreq)
return;
}
-next:
status = smbd_smb2_request_next_incoming(sconn);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(sconn, nt_errstr(status));