summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/globals.h2
-rw-r--r--source3/smbd/smb2_server.c98
2 files changed, 96 insertions, 4 deletions
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 581e5b197f..f002a6f51a 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -229,6 +229,8 @@ struct smbd_smb2_request {
struct files_struct *compat_chain_fsp;
+ NTSTATUS next_status;
+
struct {
/* the NBT header is not allocated */
uint8_t nbt_hdr[4];
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index dee06b37af..fa91e29b5e 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -186,6 +186,79 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *conn,
return NT_STATUS_OK;
}
+static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
+{
+ int count;
+ int idx;
+ bool compound_related = false;
+
+ count = req->in.vector_count;
+
+ if (count < 4) {
+ /* It's not a SMB2 request */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ for (idx=1; idx < count; idx += 3) {
+ const uint8_t *inhdr = NULL;
+ uint32_t flags;
+
+ if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (req->in.vector[idx+1].iov_len < 2) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
+
+ /* setup the SMB2 header */
+ if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ flags = IVAL(inhdr, SMB2_HDR_FLAGS);
+ if (idx == 1) {
+ /*
+ * the 1st request should never have the
+ * SMB2_HDR_FLAG_CHAINED flag set
+ */
+ if (flags & SMB2_HDR_FLAG_CHAINED) {
+ req->next_status = NT_STATUS_INVALID_PARAMETER;
+ return NT_STATUS_OK;
+ }
+ } else if (idx == 4) {
+ /*
+ * the 2nd request triggers related vs. unrelated
+ * compounded requests
+ */
+ if (flags & SMB2_HDR_FLAG_CHAINED) {
+ compound_related = true;
+ }
+ } else if (idx > 4) {
+ /*
+ * all other requests should match the 2nd one
+ */
+ if (flags & SMB2_HDR_FLAG_CHAINED) {
+ if (!compound_related) {
+ req->next_status =
+ NT_STATUS_INVALID_PARAMETER;
+ return NT_STATUS_OK;
+ }
+ } else {
+ if (compound_related) {
+ req->next_status =
+ NT_STATUS_INVALID_PARAMETER;
+ return NT_STATUS_OK;
+ }
+ }
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
{
struct iovec *vector;
@@ -323,6 +396,16 @@ static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
}
+ /*
+ * This check is mostly for giving the correct error code
+ * for compounded requests.
+ *
+ * TODO: we may need to move this after the session and tcon checks.
+ */
+ if (!NT_STATUS_IS_OK(req->next_status)) {
+ return smbd_smb2_request_error(req, req->next_status);
+ }
+
switch (opcode) {
case SMB2_OP_NEGPROT:
return smbd_smb2_request_process_negprot(req);
@@ -609,9 +692,11 @@ NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
req->out.vector[i+2].iov_len = 0;
}
- /* the error packet is the last response in the chain */
- SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
- req->out.vector_count = req->current_idx + 3;
+ /*
+ * if a request fails, all other remaining
+ * compounded requests should fail too
+ */
+ req->next_status = NT_STATUS_INVALID_PARAMETER;
return smbd_smb2_request_reply(req);
}
@@ -1115,12 +1200,17 @@ static void smbd_smb2_request_incoming(struct tevent_req *subreq)
goto next;
}
- /* TODO: validate the incoming request */
req->current_idx = 1;
DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
req->current_idx, req->in.vector_count));
+ status = smbd_smb2_request_validate(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ smbd_server_connection_terminate(conn, nt_errstr(status));
+ return;
+ }
+
status = smbd_smb2_request_setup_out(req);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(conn, nt_errstr(status));