From 66ddbc5f246aa6595be1c018900c5ca1c945c4c1 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 24 Oct 2013 14:49:19 -0700
Subject: [PATCH 01/15] Add NT_STATUS_RPC_* codes

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
---
 libcli/util/ntstatus.h      |   16 ++++++++++++++--
 source3/libsmb/nterr.c      |    9 +++++++++
 source4/libcli/util/nterr.c |    8 ++++++++
 3 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/libcli/util/ntstatus.h b/libcli/util/ntstatus.h
index 1608e28..d0fbb2d 100644
--- a/libcli/util/ntstatus.h
+++ b/libcli/util/ntstatus.h
@@ -605,7 +605,16 @@ typedef uint32_t NTSTATUS;
 #define NT_STATUS_NO_SUCH_JOB NT_STATUS(0xC0000000 | 0xEDE) /* scheduler */
 #define NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED NT_STATUS(0xC0000000 | 0x20004)
 #define NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX NT_STATUS(0xC0000000 | 0x20026)
-#define NT_STATUS_RPC_NT_CALL_FAILED NT_STATUS(0xC0000000 | 0x2001B)
+#define NT_STATUS_RPC_UNKNOWN_IF NT_STATUS(0xC0000000 | 0x20012)
+#define NT_STATUS_RPC_CALL_FAILED NT_STATUS(0xC0000000 | 0x2001B)
+#define NT_STATUS_RPC_PROTOCOL_ERROR NT_STATUS(0xC0000000 | 0x2001D)
+#define NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE NT_STATUS(0xC0000000 | 0x2002E)
+#define NT_STATUS_RPC_CANNOT_SUPPORT NT_STATUS(0xC0000000 | 0x20041)
+#define NT_STATUS_RPC_SS_CONTEXT_MISMATCH NT_STATUS(0xC0000000 | 0x30005)
+#define NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE NT_STATUS(0xC000000 | 0x3000A)
+#define NT_STATUS_RPC_BAD_STUB_DATA NT_STATUS(0xC0000000 | 0x3000C)
+#define NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS NT_STATUS(0xC0000000 | 0x2071)
+#define NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION NT_STATUS(0xC0000000 | 0x00002177)
 
 
 /* I use NT_STATUS_FOOBAR when I have no idea what error code to use -
@@ -688,6 +697,9 @@ extern bool ntstatus_check_dos_mapping;
 #define NT_STATUS_IS_LDAP(status) ((NT_STATUS_V(status) & 0xFF000000) == 0xF2000000)
 #define NT_STATUS_LDAP_CODE(status) (NT_STATUS_V(status) & ~0xFF000000)
 
-#define NT_STATUS_RPC_CANNOT_SUPPORT NT_STATUS(0xC0000000 | 0x20041)
+#define NT_STATUS_IS_RPC(status) \
+	(((NT_STATUS_V(status) & 0xFFFF) == 0xC0020000) || \
+	((NT_STATUS_V(status) & 0xFFFF) == 0xC0030000))
+
 
 #endif /* _NTSTATUS_H */
diff --git a/source3/libsmb/nterr.c b/source3/libsmb/nterr.c
index 52e81ac..fd0258c 100644
--- a/source3/libsmb/nterr.c
+++ b/source3/libsmb/nterr.c
@@ -541,6 +541,15 @@ static const nt_err_code_struct nt_errs[] =
 	{ "STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED },
 	{ "STATUS_NO_MORE_FILES", STATUS_NO_MORE_FILES },
 	{ "NT_STATUS_RPC_CANNOT_SUPPORT", NT_STATUS_RPC_CANNOT_SUPPORT },
+	{ "NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED", NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED },
+	{ "NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX", NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX },
+	{ "NT_STATUS_RPC_UNKNOWN_IF", NT_STATUS_RPC_UNKNOWN_IF },
+	{ "NT_STATUS_RPC_CALL_FAILED", NT_STATUS_RPC_CALL_FAILED },
+	{ "NT_STATUS_RPC_PROTOCOL_ERROR", NT_STATUS_RPC_PROTOCOL_ERROR },
+	{ "NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE", NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE },
+	{ "NT_STATUS_RPC_SS_CONTEXT_MISMATCH", NT_STATUS_RPC_SS_CONTEXT_MISMATCH },
+	{ "NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE", NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE },
+	{ "NT_STATUS_RPC_BAD_STUB_DATA", NT_STATUS_RPC_BAD_STUB_DATA },
 	{ NULL, NT_STATUS(0) }
 };
 
diff --git a/source4/libcli/util/nterr.c b/source4/libcli/util/nterr.c
index 4e7cdf5..d179a04 100644
--- a/source4/libcli/util/nterr.c
+++ b/source4/libcli/util/nterr.c
@@ -545,6 +545,14 @@ static const nt_err_code_struct nt_errs[] =
         { "NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES },
 	{ "NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED", NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED },
 	{ "NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX", NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX },
+	{ "NT_STATUS_RPC_UNKNOWN_IF", NT_STATUS_RPC_UNKNOWN_IF },
+	{ "NT_STATUS_RPC_CALL_FAILED", NT_STATUS_RPC_CALL_FAILED },
+	{ "NT_STATUS_RPC_PROTOCOL_ERROR", NT_STATUS_RPC_PROTOCOL_ERROR },
+	{ "NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE", NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE },
+	{ "NT_STATUS_RPC_CANNOT_SUPPORT", NT_STATUS_RPC_CANNOT_SUPPORT },
+	{ "NT_STATUS_RPC_SS_CONTEXT_MISMATCH", NT_STATUS_RPC_SS_CONTEXT_MISMATCH },
+	{ "NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE", NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE },
+	{ "NT_STATUS_RPC_BAD_STUB_DATA", NT_STATUS_RPC_BAD_STUB_DATA },
 	{ "NT_STATUS_CURRENT_DOMAIN_NOT_ALLOWED", NT_STATUS_CURRENT_DOMAIN_NOT_ALLOWED },
 	{ "NT_STATUS_OBJECTID_NOT_FOUND", NT_STATUS_OBJECTID_NOT_FOUND },
 	{ "NT_STATUS_DOWNGRADE_DETECTED", NT_STATUS_DOWNGRADE_DETECTED },
-- 
1.7.9.5


From d1b1e12255ac91636cc7aeac637d1b6c2b54415c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 25 Sep 2013 23:25:12 +0200
Subject: [PATCH 02/15] CVE-2013-4408:s3:rpc_client: verify frag_len at least
 contains the header size

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
---
 source3/rpc_client/cli_pipe.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index b47bef8..bb72d8e 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -378,6 +378,12 @@ static NTSTATUS parse_rpc_header(struct rpc_pipe_client *cli,
 		return NT_STATUS_BUFFER_TOO_SMALL;
 	}
 
+	if (prhdr->frag_len < RPC_HEADER_LEN) {
+		DEBUG(0, ("parse_rpc_header: Server sent fraglen %d,"
+			  " < RPC_HEADER_LEN\n", (int)prhdr->frag_len));
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+
 	if (prhdr->frag_len > cli->max_recv_frag) {
 		DEBUG(0, ("cli_pipe_get_current_pdu: Server sent fraglen %d,"
 			  " we only allow %d\n", (int)prhdr->frag_len,
-- 
1.7.9.5


From 28e3f10e37f32812cc8f9866008200cb49f9a307 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 25 Sep 2013 23:25:12 +0200
Subject: [PATCH 03/15] CVE-2013-4408:s4:dcerpc: check for invalid frag_len in
 ncacn_pull()

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
---
 source4/librpc/rpc/dcerpc.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index 7a568d3..f3b64ca 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -205,6 +205,10 @@ static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_
 		return ndr_map_error2ntstatus(ndr_err);
 	}
 
+	if (pkt->frag_length != blob->length) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+
 	return NT_STATUS_OK;
 }
 
-- 
1.7.9.5


From b2c4cdc6eb237fa449685ce53b7d3a3a1ff32412 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 25 Sep 2013 23:25:12 +0200
Subject: [PATCH 04/15] CVE-2013-4408:s4:dcerpc_smb: check for invalid
 frag_len in send_read_request_continue()

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
---
 source4/librpc/rpc/dcerpc_smb.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c
index 013a857..b10c617 100644
--- a/source4/librpc/rpc/dcerpc_smb.c
+++ b/source4/librpc/rpc/dcerpc_smb.c
@@ -159,6 +159,12 @@ static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLO
 	} else {
 		uint32_t frag_length = blob->length>=16?
 			dcerpc_get_frag_length(blob):0x2000;
+
+		if (frag_length < state->data.length) {
+			talloc_free(state);
+			return NT_STATUS_RPC_PROTOCOL_ERROR;
+		}
+
 		state->received = blob->length;
 		state->data = data_blob_talloc(state, NULL, frag_length);
 		if (!state->data.data) {
-- 
1.7.9.5


From 246aafc6785717df4e369695807f08db550f323f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 25 Sep 2013 23:25:12 +0200
Subject: [PATCH 05/15] CVE-2013-4408:s4:dcerpc_smb2: check for invalid
 frag_len in send_read_request_continue()

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
---
 source4/librpc/rpc/dcerpc_smb2.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/source4/librpc/rpc/dcerpc_smb2.c b/source4/librpc/rpc/dcerpc_smb2.c
index 84ba811..8bdea67 100644
--- a/source4/librpc/rpc/dcerpc_smb2.c
+++ b/source4/librpc/rpc/dcerpc_smb2.c
@@ -169,6 +169,12 @@ static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLO
 
 	if (state->data.length >= 16) {
 		uint16_t frag_length = dcerpc_get_frag_length(&state->data);
+
+		if (frag_length < state->data.length) {
+			talloc_free(state);
+			return NT_STATUS_RPC_PROTOCOL_ERROR;
+		}
+
 		io.in.length = frag_length - state->data.length;
 	} else {
 		io.in.length = 0x2000;
-- 
1.7.9.5


From 7f0103b12ca04785800d248307fed919285e8969 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Tue, 24 Sep 2013 05:03:40 +0200
Subject: [PATCH 06/15] CVE-2013-4408:s4:dcerpc_sock: check for invalid
 frag_len within sock_complete_packet()

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
---
 source4/librpc/rpc/dcerpc_sock.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/source4/librpc/rpc/dcerpc_sock.c b/source4/librpc/rpc/dcerpc_sock.c
index 64a5b92..9259bb7 100644
--- a/source4/librpc/rpc/dcerpc_sock.c
+++ b/source4/librpc/rpc/dcerpc_sock.c
@@ -101,6 +101,12 @@ static NTSTATUS sock_complete_packet(void *private_data, DATA_BLOB blob, size_t
 		return STATUS_MORE_ENTRIES;
 	}
 	*size = dcerpc_get_frag_length(&blob);
+	if (*size < blob.length) {
+		/*
+		 * something is wrong, let the caller deal with it
+		 */
+		*size = blob.length;
+	}
 	if (*size > blob.length) {
 		return STATUS_MORE_ENTRIES;
 	}
-- 
1.7.9.5


From 1d68a036ebd309e9fe216d532d46cf9eec9c014d Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 9 Oct 2013 13:05:03 -0700
Subject: [PATCH 07/15] CVE-2013-4408:s3:rpc_server: ensure frag_len is at
 least as large as RPC_HEADER_LEN.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
---
 source3/rpc_server/srv_pipe_hnd.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c
index 14b137b..a18f7ad 100644
--- a/source3/rpc_server/srv_pipe_hnd.c
+++ b/source3/rpc_server/srv_pipe_hnd.c
@@ -1298,6 +1298,10 @@ static ssize_t rpc_frag_more_fn(uint8_t *buf, size_t buflen, void *priv)
 		return -1;
 	}
 
+	if (hdr.frag_len < RPC_HEADER_LEN) {
+		return -1;
+	}
+
 	return (hdr.frag_len - RPC_HEADER_LEN);
 }
 
-- 
1.7.9.5


From 51ea748a80d53c3e05c634d35705cbcf8c781fcb Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 9 Oct 2013 11:20:53 -0700
Subject: [PATCH 08/15] CVE-2013-4408:s3:rpc_server: check a pipe with
 PIPE_AUTH_TYPE_NONE does not receive auth_len.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
---
 source3/rpc_server/srv_pipe_hnd.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c
index a18f7ad..2b76139 100644
--- a/source3/rpc_server/srv_pipe_hnd.c
+++ b/source3/rpc_server/srv_pipe_hnd.c
@@ -385,6 +385,11 @@ static bool process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
 
 	switch(p->auth.auth_type) {
 		case PIPE_AUTH_TYPE_NONE:
+			if (p->hdr.auth_len != 0) {
+				DEBUG(0,("process_request_pdu: PIPE_AUTH_TYPE_NONE given auth_data.\n"));
+				set_incoming_fault(p);
+				return False;
+			}
 			break;
 
 		case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
-- 
1.7.9.5


From cc886f485b7f5c4bdfdb8841d27ff7320322d1d4 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 16 Oct 2013 12:21:51 -0700
Subject: [PATCH 09/15] CVE-2013-4408:s3:rpc_server: for auth_level
 DCERPC_AUTH_LEVEL_NONE or DCERPC_AUTH_LEVEL_CONNECT
 auth_len must be zero.

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
---
 source3/rpc_server/srv_pipe.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index f3ee18d..d3046d3 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -2003,7 +2003,8 @@ bool api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in,
 	*pstatus = NT_STATUS_OK;
 
 	if (p->auth.auth_level == PIPE_AUTH_LEVEL_NONE || p->auth.auth_level == PIPE_AUTH_LEVEL_CONNECT) {
-		return True;
+		/* For these auth_levels the auth_len must be zero. */
+		return (auth_len == 0);
 	}
 
 	if (!a) {
-- 
1.7.9.5


From c9c986f1d2a1694bf3c7e650e61d96922605dcb9 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 9 Oct 2013 13:13:57 -0700
Subject: [PATCH 10/15] CVE-2013-4408:s3:rpc_server: integer wrap check on
 data_len.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
---
 source3/rpc_server/srv_pipe_hnd.c |   13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c
index 2b76139..52c4747 100644
--- a/source3/rpc_server/srv_pipe_hnd.c
+++ b/source3/rpc_server/srv_pipe_hnd.c
@@ -359,8 +359,7 @@ static void free_pipe_context(pipes_struct *p)
 static bool process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
 {
 	uint32 ss_padding_len = 0;
-	size_t data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
-				(p->hdr.auth_len ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len;
+	size_t data_len = 0;
 
 	if(!p->pipe_bound) {
 		DEBUG(0,("process_request_pdu: rpc request with no bind.\n"));
@@ -419,6 +418,16 @@ static bool process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
 			return False;
 	}
 
+	data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
+			(p->hdr.auth_len ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len;
+
+	if (data_len > p->hdr.frag_len) {
+		DEBUG(0,("process_request_pdu: rpc frag size too small (%u)\n",
+				(unsigned int)p->hdr.frag_len));
+		set_incoming_fault(p);
+		return False;
+	}
+
 	/* Now we've done the sign/seal we can remove any padding data. */
 	if (data_len > ss_padding_len) {
 		data_len -= ss_padding_len;
-- 
1.7.9.5


From 77003090bb4094c3fb79daf21a7243c8cb3ea13c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Oct 2013 14:17:49 +0200
Subject: [PATCH 11/15] CVE-2013-4408:async_sock: add some overflow detection
 to read_packet_handler()

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
---
 lib/async_req/async_sock.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index c428e3c..83432b8 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -595,6 +595,11 @@ static void read_packet_handler(struct tevent_context *ev,
 		return;
 	}
 
+	if (total + more < total) {
+		tevent_req_error(req, EMSGSIZE);
+		return;
+	}
+
 	tmp = TALLOC_REALLOC_ARRAY(state, state->buf, uint8_t, total+more);
 	if (tevent_req_nomem(tmp, req)) {
 		return;
-- 
1.7.9.5


From 93484c7d713f90b6052411c91699293bf8e1f306 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 24 Oct 2013 14:38:23 -0700
Subject: [PATCH 12/15] CVE-2013-4408:s3:Ensure we always check call_id when
 validating an RPC reply.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
---
 source3/rpc_client/cli_pipe.c |   56 +++++++++++++++++++++++++++++++++++------
 1 file changed, 48 insertions(+), 8 deletions(-)

diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index bb72d8e..87c4430 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -366,7 +366,8 @@ static NTSTATUS rpc_write_recv(struct async_req *req)
 
 static NTSTATUS parse_rpc_header(struct rpc_pipe_client *cli,
 				 struct rpc_hdr_info *prhdr,
-				 prs_struct *pdu)
+				 prs_struct *pdu,
+				 uint32_t call_id)
 {
 	/*
 	 * This next call sets the endian bit correctly in current_pdu. We
@@ -391,6 +392,14 @@ static NTSTATUS parse_rpc_header(struct rpc_pipe_client *cli,
 		return NT_STATUS_BUFFER_TOO_SMALL;
 	}
 
+	if (prhdr->call_id != call_id) {
+		DEBUG(0, ("parse_rpc_header: call_id was %u,"
+			  " expected %u\n",
+			(unsigned int)prhdr->call_id,
+			(unsigned int)call_id));
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+
 	return NT_STATUS_OK;
 }
 
@@ -403,6 +412,7 @@ struct get_complete_frag_state {
 	struct event_context *ev;
 	struct rpc_pipe_client *cli;
 	struct rpc_hdr_info *prhdr;
+	uint32_t call_id;
 	prs_struct *pdu;
 };
 
@@ -412,6 +422,7 @@ static void get_complete_frag_got_rest(struct async_req *subreq);
 static struct async_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
 					       struct event_context *ev,
 					       struct rpc_pipe_client *cli,
+					       uint32_t call_id,
 					       struct rpc_hdr_info *prhdr,
 					       prs_struct *pdu)
 {
@@ -427,6 +438,7 @@ static struct async_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
 	state->ev = ev;
 	state->cli = cli;
 	state->prhdr = prhdr;
+	state->call_id = call_id;
 	state->pdu = pdu;
 
 	pdu_len = prs_data_size(pdu);
@@ -449,7 +461,7 @@ static struct async_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
 		return result;
 	}
 
-	status = parse_rpc_header(cli, prhdr, pdu);
+	status = parse_rpc_header(cli, prhdr, pdu, call_id);
 	if (!NT_STATUS_IS_OK(status)) {
 		goto post_status;
 	}
@@ -499,7 +511,8 @@ static void get_complete_frag_got_header(struct async_req *subreq)
 		return;
 	}
 
-	status = parse_rpc_header(state->cli, state->prhdr, state->pdu);
+	status = parse_rpc_header(state->cli, state->prhdr, state->pdu,
+				state->call_id);
 	if (!NT_STATUS_IS_OK(status)) {
 		async_req_nterror(req, status);
 		return;
@@ -1229,6 +1242,7 @@ struct rpc_api_pipe_state {
 	struct event_context *ev;
 	struct rpc_pipe_client *cli;
 	uint8_t expected_pkt_type;
+	uint32_t call_id;
 
 	prs_struct incoming_frag;
 	struct rpc_hdr_info rhdr;
@@ -1251,7 +1265,8 @@ static struct async_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
 					   struct event_context *ev,
 					   struct rpc_pipe_client *cli,
 					   prs_struct *data, /* Outgoing PDU */
-					   uint8_t expected_pkt_type)
+					   uint8_t expected_pkt_type,
+					   uint32_t call_id)
 {
 	struct async_req *result, *subreq;
 	struct rpc_api_pipe_state *state;
@@ -1265,6 +1280,7 @@ static struct async_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
 	state->ev = ev;
 	state->cli = cli;
 	state->expected_pkt_type = expected_pkt_type;
+	state->call_id = call_id;
 	state->incoming_pdu_offset = 0;
 
 	prs_init_empty(&state->incoming_frag, state, UNMARSHALL);
@@ -1350,6 +1366,7 @@ static void rpc_api_pipe_trans_done(struct async_req *subreq)
 
 	/* Ensure we have enough data for a pdu. */
 	subreq = get_complete_frag_send(state, state->ev, state->cli,
+					state->call_id,
 					&state->rhdr, &state->incoming_frag);
 	if (async_req_nomem(subreq, req)) {
 		return;
@@ -1442,6 +1459,7 @@ static void rpc_api_pipe_got_pdu(struct async_req *subreq)
 	}
 
 	subreq = get_complete_frag_send(state, state->ev, state->cli,
+					state->call_id,
 					&state->rhdr, &state->incoming_frag);
 	if (async_req_nomem(subreq, req)) {
 		return;
@@ -2102,7 +2120,8 @@ struct async_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
 	if (is_last_frag) {
 		subreq = rpc_api_pipe_send(state, ev, state->cli,
 					   &state->outgoing_frag,
-					   RPC_RESPONSE);
+					   RPC_RESPONSE,
+					   state->call_id);
 		if (subreq == NULL) {
 			status = NT_STATUS_NO_MEMORY;
 			goto post_status;
@@ -2241,7 +2260,8 @@ static void rpc_api_pipe_req_write_done(struct async_req *subreq)
 	if (is_last_frag) {
 		subreq = rpc_api_pipe_send(state, state->ev, state->cli,
 					   &state->outgoing_frag,
-					   RPC_RESPONSE);
+					   RPC_RESPONSE,
+					   state->call_id);
 		if (async_req_nomem(subreq, req)) {
 			return;
 		}
@@ -2582,7 +2602,7 @@ struct async_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx,
 	}
 
 	subreq = rpc_api_pipe_send(state, ev, cli, &state->rpc_out,
-				   RPC_BINDACK);
+				   RPC_BINDACK, state->rpc_call_id);
 	if (subreq == NULL) {
 		status = NT_STATUS_NO_MEMORY;
 		goto post_status;
@@ -2628,6 +2648,16 @@ static void rpc_pipe_bind_step_one_done(struct async_req *subreq)
 		return;
 	}
 
+	if (hdr.call_id != state->rpc_call_id) {
+		DEBUG(0, ("rpc_pipe_bind: Missmatched call_id "
+			"(was %u, should be %u).\n",
+			(unsigned int)hdr.call_id,
+			(unsigned int)state->rpc_call_id));
+		prs_mem_free(&reply_pdu);
+		async_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+		return;
+	}
+
 	if (!smb_io_rpc_hdr_ba("", &hdr_ba, &reply_pdu, 0)) {
 		DEBUG(0, ("rpc_pipe_bind: Failed to unmarshall "
 			  "RPC_HDR_BA.\n"));
@@ -2853,7 +2883,8 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind_send(struct async_req *req,
 	}
 
 	subreq = rpc_api_pipe_send(state, state->ev, state->cli,
-				   &state->rpc_out, RPC_ALTCONTRESP);
+				   &state->rpc_out, RPC_ALTCONTRESP,
+				   state->rpc_call_id);
 	if (subreq == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
@@ -2890,6 +2921,15 @@ static void rpc_bind_ntlmssp_api_done(struct async_req *subreq)
 		return;
 	}
 
+	if (hdr.call_id != state->rpc_call_id) {
+		DEBUG(0, ("Missmatched call_id "
+			"(was %u, should be %u).\n",
+			(unsigned int)hdr.call_id,
+			(unsigned int)state->rpc_call_id));
+		async_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+		return;
+	}
+
 	if (!prs_set_offset(
 		    &reply_pdu,
 		    hdr.frag_len - hdr.auth_len - RPC_HDR_AUTH_LEN)) {
-- 
1.7.9.5


From abb0f97085a63e8d112ab3c315ff79fb710af91d Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 20 Nov 2013 12:13:47 -0800
Subject: [PATCH 13/15] CVE-2013-4408:s3:Ensure LookupSids replies arrays are
 range checked.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/rpc_client/cli_lsarpc.c    |   13 +++++++++++++
 source4/winbind/wb_async_helpers.c |   13 ++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c
index 74fd082..dc29bd0 100644
--- a/source3/rpc_client/cli_lsarpc.c
+++ b/source3/rpc_client/cli_lsarpc.c
@@ -197,6 +197,11 @@ static NTSTATUS rpccli_lsa_lookup_sids_noalloc(struct rpc_pipe_client *cli,
 		goto done;
 	}
 
+	if (num_sids != lsa_names.count) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+
 	/* Return output parameters */
 
 	if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
@@ -218,6 +223,14 @@ static NTSTATUS rpccli_lsa_lookup_sids_noalloc(struct rpc_pipe_client *cli,
 		/* Translate optimised name through domain index array */
 
 		if (dom_idx != 0xffffffff) {
+			if (ref_domains == NULL) {
+				result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+				goto done;
+			}
+			if (dom_idx >= ref_domains->count) {
+				result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+				goto done;
+			}
 
 			dom_name = ref_domains->domains[dom_idx].name.string;
 			name = lsa_names.names[i].name.string;
diff --git a/source4/winbind/wb_async_helpers.c b/source4/winbind/wb_async_helpers.c
index a50a0fe..266634c 100644
--- a/source4/winbind/wb_async_helpers.c
+++ b/source4/winbind/wb_async_helpers.c
@@ -122,6 +122,12 @@ static void lsa_lookupsids_recv_names(struct rpc_request *req)
 		return;
 	}
 
+	if (state->names.count != state->num_sids) {
+		composite_error(state->ctx,
+				NT_STATUS_INVALID_NETWORK_RESPONSE);
+		return;
+	}
+
 	state->result = talloc_array(state, struct wb_sid_object *,
 				     state->num_sids);
 	if (composite_nomem(state->result, state->ctx)) return;
@@ -142,9 +148,14 @@ static void lsa_lookupsids_recv_names(struct rpc_request *req)
 			continue;
 		}
 
+		if (domains == NULL) {
+			composite_error(state->ctx,
+					NT_STATUS_INVALID_NETWORK_RESPONSE);
+			return;
+		}
 		if (name->sid_index >= domains->count) {
 			composite_error(state->ctx,
-					NT_STATUS_INVALID_PARAMETER);
+					NT_STATUS_INVALID_NETWORK_RESPONSE);
 			return;
 		}
 
-- 
1.7.9.5


From 4a4e0ef9dadbafd21ac9d567ecb04192b1ba467f Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 20 Nov 2013 13:10:04 -0800
Subject: [PATCH 14/15] CVE-2013-4408:s3:Ensure LookupNames replies arrays are
 range checked.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/lib/netapi/group.c         |   84 ++++++++++++++++++++++++++++++++++++
 source3/lib/netapi/localgroup.c    |    9 +++-
 source3/lib/netapi/user.c          |   56 ++++++++++++++++++++++++
 source3/libnet/libnet_join.c       |   16 +++++++
 source3/rpc_client/cli_lsarpc.c    |   18 ++++++++
 source3/rpcclient/cmd_samr.c       |   62 ++++++++++++++++++++++++++
 source3/smbd/lanman.c              |    8 ++++
 source3/utils/net_rpc.c            |   40 ++++++++++++++++-
 source3/utils/net_rpc_join.c       |    9 ++++
 source4/libcli/util/clilsa.c       |    6 ++-
 source4/libnet/groupinfo.c         |   10 +++--
 source4/libnet/groupman.c          |   10 ++---
 source4/libnet/libnet_join.c       |   12 +++++-
 source4/libnet/libnet_lookup.c     |    5 +++
 source4/libnet/libnet_passwd.c     |   10 ++++-
 source4/libnet/userinfo.c          |    9 +++-
 source4/libnet/userman.c           |   24 +++++------
 source4/winbind/wb_async_helpers.c |   13 +++++-
 18 files changed, 370 insertions(+), 31 deletions(-)

diff --git a/source3/lib/netapi/group.c b/source3/lib/netapi/group.c
index 004fd3a..1769095 100644
--- a/source3/lib/netapi/group.c
+++ b/source3/lib/netapi/group.c
@@ -272,6 +272,15 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
 		goto done;
 	}
 
+	if (rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+
 	if (types.ids[0] != SID_NAME_DOM_GRP) {
 		werr = WERR_INVALID_DATATYPE;
 		goto done;
@@ -436,6 +445,14 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	if (types.ids[0] != SID_NAME_DOM_GRP) {
 		werr = WERR_INVALID_DATATYPE;
@@ -671,6 +688,14 @@ WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	if (types.ids[0] != SID_NAME_DOM_GRP) {
 		werr = WERR_INVALID_DATATYPE;
@@ -787,6 +812,14 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
 		werr = WERR_GROUP_NOT_FOUND;
 		goto done;
 	}
+	if (rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	if (types.ids[0] != SID_NAME_DOM_GRP) {
 		werr = WERR_GROUP_NOT_FOUND;
@@ -815,6 +848,14 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
 		werr = WERR_USER_NOT_FOUND;
 		goto done;
 	}
+	if (rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	if (types.ids[0] != SID_NAME_USER) {
 		werr = WERR_USER_NOT_FOUND;
@@ -908,6 +949,14 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
 		werr = WERR_GROUP_NOT_FOUND;
 		goto done;
 	}
+	if (rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	if (types.ids[0] != SID_NAME_DOM_GRP) {
 		werr = WERR_GROUP_NOT_FOUND;
@@ -936,6 +985,14 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
 		werr = WERR_USER_NOT_FOUND;
 		goto done;
 	}
+	if (rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	if (types.ids[0] != SID_NAME_USER) {
 		werr = WERR_USER_NOT_FOUND;
@@ -1318,6 +1375,15 @@ WERROR NetGroupGetUsers_r(struct libnetapi_ctx *ctx,
 		goto done;
 	}
 
+	if (group_rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+
 	status = rpccli_samr_OpenGroup(pipe_cli, ctx,
 				       &domain_handle,
 				       SAMR_GROUP_ACCESS_GET_MEMBERS,
@@ -1470,6 +1536,15 @@ WERROR NetGroupSetUsers_r(struct libnetapi_ctx *ctx,
 		goto done;
 	}
 
+	if (group_rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (group_types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+
 	status = rpccli_samr_OpenGroup(pipe_cli, ctx,
 				       &domain_handle,
 				       SAMR_GROUP_ACCESS_GET_MEMBERS |
@@ -1532,6 +1607,15 @@ WERROR NetGroupSetUsers_r(struct libnetapi_ctx *ctx,
 		goto done;
 	}
 
+	if (r->in.num_entries != user_rids.count) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (r->in.num_entries != name_types.count) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+
 	member_rids = user_rids.ids;
 	num_member_rids = user_rids.count;
 
diff --git a/source3/lib/netapi/localgroup.c b/source3/lib/netapi/localgroup.c
index d389c1f..05ac477 100644
--- a/source3/lib/netapi/localgroup.c
+++ b/source3/lib/netapi/localgroup.c
@@ -48,6 +48,13 @@ static NTSTATUS libnetapi_samr_lookup_and_open_alias(TALLOC_CTX *mem_ctx,
 		return status;
 	}
 
+	if (user_rids.count != 1) {
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+	}
+	if (name_types.count != 1) {
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+	}
+
 	switch (name_types.ids[0]) {
 		case SID_NAME_ALIAS:
 		case SID_NAME_WKN_GRP:
@@ -949,7 +956,7 @@ static NTSTATUS libnetapi_lsa_lookup_names3(TALLOC_CTX *mem_ctx,
 	NT_STATUS_NOT_OK_RETURN(status);
 
 	if (count != 1 || sids.count != 1) {
-		return NT_STATUS_NONE_MAPPED;
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
 	}
 
 	sid_copy(sid, sids.sids[0].sid);
diff --git a/source3/lib/netapi/user.c b/source3/lib/netapi/user.c
index d28c136..815306f 100644
--- a/source3/lib/netapi/user.c
+++ b/source3/lib/netapi/user.c
@@ -545,6 +545,14 @@ WERROR NetUserDel_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (user_rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	status = rpccli_samr_OpenUser(pipe_cli, ctx,
 				      &domain_handle,
@@ -1677,6 +1685,14 @@ WERROR NetUserGetInfo_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (user_rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	status = libnetapi_samr_lookup_user_map_USER_INFO(ctx, pipe_cli,
 							  domain_sid,
@@ -1832,6 +1848,14 @@ WERROR NetUserSetInfo_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (user_rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	status = rpccli_samr_OpenUser(pipe_cli, ctx,
 				      &domain_handle,
@@ -2851,6 +2875,14 @@ WERROR NetUserGetGroups_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (user_rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	status = rpccli_samr_OpenUser(pipe_cli, ctx,
 				      &domain_handle,
@@ -3002,6 +3034,14 @@ WERROR NetUserSetGroups_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (user_rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	status = rpccli_samr_OpenUser(pipe_cli, ctx,
 				      &domain_handle,
@@ -3052,6 +3092,14 @@ WERROR NetUserSetGroups_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (group_rids.count != r->in.num_entries) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (name_types.count != r->in.num_entries) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	member_rids = group_rids.ids;
 	num_member_rids = group_rids.count;
@@ -3296,6 +3344,14 @@ WERROR NetUserGetLocalGroups_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (user_rids.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	status = rpccli_samr_OpenUser(pipe_cli, ctx,
 				      &domain_handle,
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 6489126..b2a9517 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -880,6 +880,14 @@ static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
 	if (!NT_STATUS_IS_OK(status)) {
 		goto done;
 	}
+	if (user_rids.count != 1) {
+		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
 
 	if (name_types.ids[0] != SID_NAME_USER) {
 		DEBUG(0,("%s is not a user account (type=%d)\n",
@@ -1206,6 +1214,14 @@ static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
 	if (!NT_STATUS_IS_OK(status)) {
 		goto done;
 	}
+	if (user_rids.count != 1) {
+		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
 
 	if (name_types.ids[0] != SID_NAME_USER) {
 		DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c
index dc29bd0..dc84b5f 100644
--- a/source3/rpc_client/cli_lsarpc.c
+++ b/source3/rpc_client/cli_lsarpc.c
@@ -515,9 +515,19 @@ static NTSTATUS rpccli_lsa_lookup_names_generic(struct rpc_pipe_client *cli,
 		DOM_SID *sid = &(*sids)[i];
 
 		if (use_lookupnames4) {
+			if (i >= sid_array3.count) {
+				result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+				goto done;
+			}
+
 			dom_idx		= sid_array3.sids[i].sid_index;
 			(*types)[i]	= sid_array3.sids[i].sid_type;
 		} else {
+			if (i >= sid_array.count) {
+				result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+				goto done;
+			}
+
 			dom_idx		= sid_array.sids[i].sid_index;
 			(*types)[i]	= sid_array.sids[i].sid_type;
 		}
@@ -530,6 +540,14 @@ static NTSTATUS rpccli_lsa_lookup_names_generic(struct rpc_pipe_client *cli,
 			(*types)[i] = SID_NAME_UNKNOWN;
 			continue;
 		}
+		if (domains == NULL) {
+			result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+			goto done;
+		}
+		if (dom_idx >= domains->count) {
+			result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+			goto done;
+		}
 
 		if (use_lookupnames4) {
 			sid_copy(sid, sid_array3.sids[i].sid);
diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c
index de21a40..bfe3b44 100644
--- a/source3/rpcclient/cmd_samr.c
+++ b/source3/rpcclient/cmd_samr.c
@@ -358,6 +358,15 @@ static NTSTATUS cmd_samr_query_user(struct rpc_pipe_client *cli,
 						 &types);
 
 		if (NT_STATUS_IS_OK(result)) {
+			if (rids.count != 1) {
+				result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+				goto done;
+			}
+			if (types.count != 1) {
+				result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+				goto done;
+			}
+
 			result = rpccli_samr_OpenUser(cli, mem_ctx,
 						      &domain_pol,
 						      access_mask,
@@ -1291,6 +1300,15 @@ static NTSTATUS cmd_samr_delete_alias(struct rpc_pipe_client *cli,
 						 &types);
 
 		if (NT_STATUS_IS_OK(result)) {
+			if (rids.count != 1) {
+				result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+				goto done;
+			}
+			if (types.count != 1) {
+				result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+				goto done;
+			}
+
 			result = rpccli_samr_OpenAlias(cli, mem_ctx,
 						       &domain_pol,
 						       access_mask,
@@ -1881,6 +1899,15 @@ static NTSTATUS cmd_samr_lookup_names(struct rpc_pipe_client *cli,
 	if (!NT_STATUS_IS_OK(result))
 		goto done;
 
+	if (rids.count != num_names) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+	if (name_types.count != num_names) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+
 	/* Display results */
 
 	for (i = 0; i < num_names; i++)
@@ -2021,6 +2048,15 @@ static NTSTATUS cmd_samr_delete_dom_group(struct rpc_pipe_client *cli,
 		if (!NT_STATUS_IS_OK(result))
 			goto done;
 
+		if (group_rids.count != 1) {
+			result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+			goto done;
+		}
+		if (name_types.count != 1) {
+			result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+			goto done;
+		}
+
 		result = rpccli_samr_OpenGroup(cli, mem_ctx,
 					       &domain_pol,
 					       access_mask,
@@ -2103,6 +2139,15 @@ static NTSTATUS cmd_samr_delete_dom_user(struct rpc_pipe_client *cli,
 		if (!NT_STATUS_IS_OK(result))
 			goto done;
 
+		if (user_rids.count != 1) {
+			result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+			goto done;
+		}
+		if (name_types.count != 1) {
+			result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+			goto done;
+		}
+
 		result = rpccli_samr_OpenUser(cli, mem_ctx,
 					      &domain_pol,
 					      access_mask,
@@ -2418,6 +2463,15 @@ static NTSTATUS cmd_samr_chgpasswd(struct rpc_pipe_client *cli,
 		goto done;
 	}
 
+	if (rids.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+	if (types.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+
 	result = rpccli_samr_OpenUser(cli, mem_ctx,
 				      &domain_pol,
 				      access_mask,
@@ -2786,6 +2840,14 @@ static NTSTATUS cmd_samr_setuserinfo_int(struct rpc_pipe_client *cli,
 		if (!NT_STATUS_IS_OK(status)) {
 			return status;
 		}
+		if (rids.count != 1) {
+			status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+			goto done;
+		}
+		if (types.count != 1) {
+			status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+			goto done;
+		}
 
 		status = rpccli_samr_OpenUser(cli, mem_ctx,
 					      &domain_pol,
diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c
index 40b6aca..3b2c8c6 100644
--- a/source3/smbd/lanman.c
+++ b/source3/smbd/lanman.c
@@ -2492,6 +2492,14 @@ static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
 			  nt_errstr(status)));
 		goto close_domain;
 	}
+	if (rid.count != 1) {
+		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto close_domain;
+	}
+	if (type.count != 1) {
+		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto close_domain;
+	}
 
 	if (type.ids[0] != SID_NAME_USER) {
 		DEBUG(10, ("%s is a %s, not a user\n", UserName,
diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c
index aa04172..589874a 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -1448,6 +1448,15 @@ static NTSTATUS rpc_group_delete_internals(struct net_context *c,
    		goto done;
 	}
 
+	if (group_rids.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+
 	switch (name_types.ids[0])
 	{
 	case SID_NAME_DOM_GRP:
@@ -1768,6 +1777,14 @@ static NTSTATUS rpc_add_groupmem(struct rpc_pipe_client *pipe_hnd,
 		d_fprintf(stderr, "Could not lookup up group member %s\n", member);
 		goto done;
 	}
+	if (rids.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+	if (rid_types.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
 
 	result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx,
 				       &domain_pol,
@@ -1972,6 +1989,14 @@ static NTSTATUS rpc_del_groupmem(struct net_context *c,
 		d_fprintf(stderr, "Could not lookup up group member %s\n", member);
 		goto done;
 	}
+	if (rids.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+	if (rid_types.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
 
 	result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx,
 				       &domain_pol,
@@ -2625,7 +2650,12 @@ static NTSTATUS rpc_group_members_internals(struct net_context *c,
 
 	if (rids.count != 1) {
 		d_fprintf(stderr, "Couldn't find group %s\n", argv[0]);
-		return result;
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+	}
+	if (rid_types.count != 1) {
+		d_fprintf(stderr, "Couldn't find group %s\n",
+			argv[0]);
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
 	}
 
 	if (rid_types.ids[0] == SID_NAME_DOM_GRP) {
@@ -5371,6 +5401,14 @@ static NTSTATUS rpc_trustdom_del_internals(struct net_context *c,
 			acct_name, nt_errstr(result) );
 		goto done;
 	}
+	if (user_rids.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
 
 	result = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
 				      &domain_pol,
diff --git a/source3/utils/net_rpc_join.c b/source3/utils/net_rpc_join.c
index 127b306..9c7b0c4 100644
--- a/source3/utils/net_rpc_join.c
+++ b/source3/utils/net_rpc_join.c
@@ -314,6 +314,15 @@ int net_rpc_join_newstyle(struct net_context *c, int argc, const char **argv)
 			    ("error looking up rid for user %s: %s\n",
 			     acct_name, nt_errstr(result)));
 
+	if (user_rids.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+	if (name_types.count != 1) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+
 	if (name_types.ids[0] != SID_NAME_USER) {
 		DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types.ids[0]));
 		goto done;
diff --git a/source4/libcli/util/clilsa.c b/source4/libcli/util/clilsa.c
index 16967d7..f8bb74c 100644
--- a/source4/libcli/util/clilsa.c
+++ b/source4/libcli/util/clilsa.c
@@ -298,7 +298,11 @@ NTSTATUS smblsa_lookup_name(struct smbcli_state *cli,
 	}
 	if (sids.count != 1) {
 		talloc_free(mem_ctx2);
-		return NT_STATUS_UNSUCCESSFUL;
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+	}
+	if (domains->count != 1) {
+		talloc_free(mem_ctx2);
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
 	}
 
 	sid = domains->domains[0].sid;
diff --git a/source4/libnet/groupinfo.c b/source4/libnet/groupinfo.c
index 1779c28..6020350 100644
--- a/source4/libnet/groupinfo.c
+++ b/source4/libnet/groupinfo.c
@@ -87,12 +87,16 @@ static void continue_groupinfo_lookup(struct rpc_request *req)
 		
 		s->monitor_fn(&msg);
 	}
-	
 
 	/* have we actually got name resolved
 	   - we're looking for only one at the moment */
-	if (s->lookup.out.rids->count == 0) {
-		composite_error(c, NT_STATUS_NO_SUCH_USER);
+	if (s->lookup.out.rids->count != s->lookup.in.num_names) {
+		composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
+		return;
+	}
+	if (s->lookup.out.types->count != s->lookup.in.num_names) {
+		composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
+		return;
 	}
 
 	/* TODO: find proper status code for more than one rid found */
diff --git a/source4/libnet/groupman.c b/source4/libnet/groupman.c
index 0f54db9..2bc318a 100644
--- a/source4/libnet/groupman.c
+++ b/source4/libnet/groupman.c
@@ -207,13 +207,13 @@ static void continue_groupdel_name_found(struct rpc_request *req)
 
 	/* what to do when there's no group account to delete
 	   and what if there's more than one rid resolved */
-	if (!s->lookupname.out.rids->count) {
-		c->status = NT_STATUS_NO_SUCH_GROUP;
+	if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
+		c->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
 		composite_error(c, c->status);
 		return;
-
-	} else if (!s->lookupname.out.rids->count > 1) {
-		c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
+	}
+	if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
+		c->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
 		composite_error(c, c->status);
 		return;
 	}
diff --git a/source4/libnet/libnet_join.c b/source4/libnet/libnet_join.c
index 0a4e357..d5173fd 100644
--- a/source4/libnet/libnet_join.c
+++ b/source4/libnet/libnet_join.c
@@ -642,9 +642,17 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
 							      "samr_LookupNames for [%s] returns %d RIDs",
 							      r->in.account_name, ln.out.rids->count);
 			talloc_free(tmp_ctx);
-			return NT_STATUS_INVALID_PARAMETER;
+			return NT_STATUS_INVALID_NETWORK_RESPONSE;
 		}
-		
+
+		if (ln.out.types->count != 1) {
+			r->out.error_string = talloc_asprintf(mem_ctx,
+								"samr_LookupNames for [%s] returns %d RID TYPEs",
+								r->in.account_name, ln.out.types->count);
+			talloc_free(tmp_ctx);
+			return NT_STATUS_INVALID_NETWORK_RESPONSE;
+		}
+
 		/* prepare samr_OpenUser */
 		ZERO_STRUCTP(u_handle);
 		ou.in.domain_handle = &d_handle;
diff --git a/source4/libnet/libnet_lookup.c b/source4/libnet/libnet_lookup.c
index fc30782..a271d96 100644
--- a/source4/libnet/libnet_lookup.c
+++ b/source4/libnet/libnet_lookup.c
@@ -354,6 +354,11 @@ static void continue_name_found(struct rpc_request *req)
 	c->status = s->lookup.out.result;
 	if (!composite_is_ok(c)) return;
 
+	if (s->lookup.out.sids->count != s->lookup.in.num_names) {
+		composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
+		return;
+	}
+
 	composite_done(c);
 }
 
diff --git a/source4/libnet/libnet_passwd.c b/source4/libnet/libnet_passwd.c
index c2db219..120cf4e 100644
--- a/source4/libnet/libnet_passwd.c
+++ b/source4/libnet/libnet_passwd.c
@@ -626,10 +626,18 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *
 		r->samr.out.error_string = talloc_asprintf(mem_ctx,
 						"samr_LookupNames for [%s] returns %d RIDs",
 						r->samr.in.account_name, ln.out.rids->count);
-		status = NT_STATUS_INVALID_PARAMETER;
+		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
 		goto disconnect;	
 	}
 
+	if (ln.out.types->count != 1) {
+		r->samr.out.error_string = talloc_asprintf(mem_ctx,
+						"samr_LookupNames for [%s] returns %d RID TYPEs",
+						r->samr.in.account_name, ln.out.types->count);
+		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto disconnect;
+	}
+
 	/* prepare samr_OpenUser */
 	ZERO_STRUCT(u_handle);
 	ou.in.domain_handle = &d_handle;
diff --git a/source4/libnet/userinfo.c b/source4/libnet/userinfo.c
index a718ab9..283b126 100644
--- a/source4/libnet/userinfo.c
+++ b/source4/libnet/userinfo.c
@@ -90,8 +90,13 @@ static void continue_userinfo_lookup(struct rpc_request *req)
 
 	/* have we actually got name resolved
 	   - we're looking for only one at the moment */
-	if (s->lookup.out.rids->count == 0) {
-		composite_error(c, NT_STATUS_NO_SUCH_USER);
+	if (s->lookup.out.rids->count != s->lookup.in.num_names) {
+		composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
+		return;
+	}
+	if (s->lookup.out.types->count != s->lookup.in.num_names) {
+		composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
+		return;
 	}
 
 	/* TODO: find proper status code for more than one rid found */
diff --git a/source4/libnet/userman.c b/source4/libnet/userman.c
index 62d4e0e..9e5a30d 100644
--- a/source4/libnet/userman.c
+++ b/source4/libnet/userman.c
@@ -233,14 +233,12 @@ static void continue_userdel_name_found(struct rpc_request *req)
 
 	/* what to do when there's no user account to delete
 	   and what if there's more than one rid resolved */
-	if (!s->lookupname.out.rids->count) {
-		c->status = NT_STATUS_NO_SUCH_USER;
-		composite_error(c, c->status);
+	if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
+		composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
 		return;
-
-	} else if (!s->lookupname.out.rids->count > 1) {
-		c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
-		composite_error(c, c->status);
+	}
+	if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
+		composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
 		return;
 	}
 
@@ -501,14 +499,12 @@ static void continue_usermod_name_found(struct rpc_request *req)
 
 	/* what to do when there's no user account to delete
 	   and what if there's more than one rid resolved */
-	if (!s->lookupname.out.rids->count) {
-		c->status = NT_STATUS_NO_SUCH_USER;
-		composite_error(c, c->status);
+	if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
+		composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
 		return;
-
-	} else if (!s->lookupname.out.rids->count > 1) {
-		c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
-		composite_error(c, c->status);
+	}
+	if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
+		composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
 		return;
 	}
 
diff --git a/source4/winbind/wb_async_helpers.c b/source4/winbind/wb_async_helpers.c
index 266634c..433754b 100644
--- a/source4/winbind/wb_async_helpers.c
+++ b/source4/winbind/wb_async_helpers.c
@@ -282,6 +282,12 @@ static void lsa_lookupnames_recv_sids(struct rpc_request *req)
 		return;
 	}
 
+	if (state->sids.count != state->num_names) {
+		composite_error(state->ctx,
+				NT_STATUS_INVALID_NETWORK_RESPONSE);
+		return;
+	}
+
 	state->result = talloc_array(state, struct wb_sid_object *,
 				     state->num_names);
 	if (composite_nomem(state->result, state->ctx)) return;
@@ -300,9 +306,14 @@ static void lsa_lookupnames_recv_sids(struct rpc_request *req)
 			continue;
 		}
 
+		if (domains == NULL) {
+			composite_error(state->ctx,
+					NT_STATUS_INVALID_NETWORK_RESPONSE);
+			return;
+		}
 		if (sid->sid_index >= domains->count) {
 			composite_error(state->ctx,
-					NT_STATUS_INVALID_PARAMETER);
+					NT_STATUS_INVALID_NETWORK_RESPONSE);
 			return;
 		}
 
-- 
1.7.9.5


From 98edf7444395be7f1dd4b66fac4de20d3948c434 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 20 Nov 2013 13:58:34 -0800
Subject: [PATCH 15/15] CVE-2013-4408:s3:Ensure LookupRids() replies arrays
 are range checked.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Jeremy Allison <jra@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 source3/lib/netapi/group.c      |   16 ++++++++++++++++
 source3/lib/netapi/user.c       |   16 ++++++++++++++++
 source3/rpcclient/cmd_samr.c    |    8 ++++++++
 source3/utils/net_rpc.c         |    7 +++++++
 source3/winbindd/winbindd_rpc.c |    8 +++++---
 5 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/source3/lib/netapi/group.c b/source3/lib/netapi/group.c
index 1769095..2b2c805 100644
--- a/source3/lib/netapi/group.c
+++ b/source3/lib/netapi/group.c
@@ -338,6 +338,14 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (names.count != rid_array->count) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (member_types.count != rid_array->count) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 	}
 
 	for (i=0; i < rid_array->count; i++) {
@@ -1412,6 +1420,14 @@ WERROR NetGroupGetUsers_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (names.count != rid_array->count) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (member_types.count != rid_array->count) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	for (i=0; i < names.count; i++) {
 
diff --git a/source3/lib/netapi/user.c b/source3/lib/netapi/user.c
index 815306f..9457951 100644
--- a/source3/lib/netapi/user.c
+++ b/source3/lib/netapi/user.c
@@ -2923,6 +2923,14 @@ WERROR NetUserGetGroups_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (names.count != rid_array->count) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (types.count != rid_array->count) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	for (i=0; i < names.count; i++) {
 		status = add_GROUP_USERS_INFO_X_buffer(ctx,
@@ -3448,6 +3456,14 @@ WERROR NetUserGetLocalGroups_r(struct libnetapi_ctx *ctx,
 		werr = ntstatus_to_werror(status);
 		goto done;
 	}
+	if (names.count != num_rids) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
+	if (types.count != num_rids) {
+		werr = WERR_BAD_NET_RESP;
+		goto done;
+	}
 
 	for (i=0; i < names.count; i++) {
 		status = add_LOCALGROUP_USERS_INFO_X_buffer(ctx,
diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c
index bfe3b44..3f892c2 100644
--- a/source3/rpcclient/cmd_samr.c
+++ b/source3/rpcclient/cmd_samr.c
@@ -1983,6 +1983,14 @@ static NTSTATUS cmd_samr_lookup_rids(struct rpc_pipe_client *cli,
 		goto done;
 
 	/* Display results */
+	if (num_rids != names.count) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+	if (num_rids != types.count) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
 
 	for (i = 0; i < num_rids; i++) {
 		printf("rid 0x%x: %s (%d)\n",
diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c
index 589874a..1aa7a9b 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -2446,6 +2446,13 @@ static NTSTATUS rpc_list_group_members(struct net_context *c,
 		if (!NT_STATUS_IS_OK(result))
 			return result;
 
+		if (names.count != this_time) {
+			return NT_STATUS_INVALID_NETWORK_RESPONSE;
+		}
+		if (types.count != this_time) {
+			return NT_STATUS_INVALID_NETWORK_RESPONSE;
+		}
+
 		/* We only have users as members, but make the output
 		   the same as the output of alias members */
 
diff --git a/source3/winbindd/winbindd_rpc.c b/source3/winbindd/winbindd_rpc.c
index aa8a5c8..e234dda 100644
--- a/source3/winbindd/winbindd_rpc.c
+++ b/source3/winbindd/winbindd_rpc.c
@@ -839,9 +839,11 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
 
 		/* Copy result into array.  The talloc system will take
 		   care of freeing the temporary arrays later on. */
-
-		if (tmp_names.count != tmp_types.count) {
-			return NT_STATUS_UNSUCCESSFUL;
+		if (tmp_names.count != num_lookup_rids) {
+			return NT_STATUS_INVALID_NETWORK_RESPONSE;
+		}
+		if (tmp_types.count != num_lookup_rids) {
+			return NT_STATUS_INVALID_NETWORK_RESPONSE;
 		}
 
 		for (r=0; r<tmp_names.count; r++) {
-- 
1.7.9.5