From a7b7ece7aa3c8288f3373e8101f3d5abca8fac39 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@sernet.private>
Date: Wed, 17 Mar 2010 19:48:56 +0100
Subject: [PATCH 01/20] libcli/util: add more NT_STATUS_RPC_* defines

metze
(cherry picked from commit 6a1f8e67eb6e15bbafca570ac9b3714681025a1f)
---
 libcli/util/ntstatus.h      |   15 +++++++++++----
 source4/libcli/util/nterr.c |    8 ++++++++
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/libcli/util/ntstatus.h b/libcli/util/ntstatus.h
index 1025f47..d6191e4 100644
--- a/libcli/util/ntstatus.h
+++ b/libcli/util/ntstatus.h
@@ -604,9 +604,14 @@ 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_NT_PROTOCOL_ERROR NT_STATUS(0xC0000000 | 0x2001D)
-#define NT_STATUS_RPC_NT_PROCNUM_OUT_OF_RANGE NT_STATUS(0xC0000000 | 0x2002E)
+#define NT_STAUTS_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)
 
@@ -699,6 +704,8 @@ 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/source4/libcli/util/nterr.c b/source4/libcli/util/nterr.c
index 75bbbde..c9466dd 100644
--- a/source4/libcli/util/nterr.c
+++ b/source4/libcli/util/nterr.c
@@ -546,6 +546,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_STAUTS_RPC_UNKNOWN_IF", NT_STAUTS_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 46f1a08ab4348618c973a4ec16eee7e0c0c14fee Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Thu, 18 Mar 2010 15:27:05 +0100
Subject: [PATCH 02/20] s3:libsmb/nterr.c: fix/add NT_STATUS_RPC_* codes

metze
(cherry picked from commit 421a926237f94ebdb90aaf0cf7678a9804bd5cdc)
---
 source3/libsmb/nterr.c |   13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/source3/libsmb/nterr.c b/source3/libsmb/nterr.c
index 197d5bd..52dc5b8 100644
--- a/source3/libsmb/nterr.c
+++ b/source3/libsmb/nterr.c
@@ -539,11 +539,16 @@ static const nt_err_code_struct nt_errs[] =
 	{ "STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES },
 	{ "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_NT_CALL_FAILED", NT_STATUS_RPC_NT_CALL_FAILED },
-	{ "NT_STATUS_RPC_NT_PROTOCOL_ERROR", NT_STATUS_RPC_NT_PROTOCOL_ERROR },
-	{ "NT_STATUS_RPC_NT_PROCNUM_OUT_OF_RANGE", NT_STATUS_RPC_NT_PROCNUM_OUT_OF_RANGE },
 	{ "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_STAUTS_RPC_UNKNOWN_IF", NT_STAUTS_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 },
 	{ NULL, NT_STATUS(0) }
 };
 
-- 
1.7.9.5


From a4749747d364c795cac1284e40e70ed20b58507b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
Date: Fri, 19 Mar 2010 09:30:36 +0100
Subject: [PATCH 03/20] error_codes: fix NT_STATUS_RPC_UNKNOWN_IF typo.

Metze, please check.

Guenther
(cherry picked from commit e7cc45cb140e1df5731619ae09af6c10b8f9fffa)
---
 libcli/util/ntstatus.h      |    2 +-
 source3/libsmb/nterr.c      |    2 +-
 source4/libcli/util/nterr.c |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcli/util/ntstatus.h b/libcli/util/ntstatus.h
index d6191e4..2989764 100644
--- a/libcli/util/ntstatus.h
+++ b/libcli/util/ntstatus.h
@@ -604,7 +604,7 @@ 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_STAUTS_RPC_UNKNOWN_IF NT_STATUS(0xC0000000 | 0x20012)
+#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)
diff --git a/source3/libsmb/nterr.c b/source3/libsmb/nterr.c
index 52dc5b8..ae41a9b 100644
--- a/source3/libsmb/nterr.c
+++ b/source3/libsmb/nterr.c
@@ -541,7 +541,7 @@ static const nt_err_code_struct nt_errs[] =
 	{ "STATUS_NO_MORE_FILES", STATUS_NO_MORE_FILES },
 	{ "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_STAUTS_RPC_UNKNOWN_IF", NT_STAUTS_RPC_UNKNOWN_IF },
+	{ "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 },
diff --git a/source4/libcli/util/nterr.c b/source4/libcli/util/nterr.c
index c9466dd..0764a28 100644
--- a/source4/libcli/util/nterr.c
+++ b/source4/libcli/util/nterr.c
@@ -546,7 +546,7 @@ 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_STAUTS_RPC_UNKNOWN_IF", NT_STAUTS_RPC_UNKNOWN_IF },
+	{ "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 },
-- 
1.7.9.5


From 131d5d789d5ed5550ee6060dd1cc805753a42395 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/20] 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 0298f79..609f209 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -455,6 +455,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 b968b39f4d874b6b7fbc14bd833ebdc33a13ab76 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Tue, 24 Sep 2013 05:03:40 +0200
Subject: [PATCH 05/20] CVE-2013-4408:s4:rpc_server: check for invalid
 frag_len within dcerpc_read_ncacn_packet_done()

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/rpc_server/service_rpc.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/source4/rpc_server/service_rpc.c b/source4/rpc_server/service_rpc.c
index ea41689..ca3b3cb 100644
--- a/source4/rpc_server/service_rpc.c
+++ b/source4/rpc_server/service_rpc.c
@@ -303,6 +303,11 @@ static void dcerpc_read_ncacn_packet_done(struct tevent_req *subreq)
 		return;
 	}
 
+	if (state->pkt->frag_length != state->buffer.length) {
+		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+		return;
+	}
+
 	tevent_req_done(req);
 }
 
-- 
1.7.9.5


From e86230c9175bb4eefbecf0d36dffaf15c8254ce8 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/20] CVE-2013-4408:s4:rpc_server: check for invalid
 frag_len within
 dcerpc_read_ncacn_packet_next_vector()

We should do this explicit instead of relying on
tstream_readv_pdu_ask_for_next_vector() to catch the overflow.

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/rpc_server/service_rpc.c |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/source4/rpc_server/service_rpc.c b/source4/rpc_server/service_rpc.c
index ca3b3cb..1c9c76a 100644
--- a/source4/rpc_server/service_rpc.c
+++ b/source4/rpc_server/service_rpc.c
@@ -232,6 +232,15 @@ static int dcerpc_read_ncacn_packet_next_vector(struct tstream_context *stream,
 
 		ofs = state->buffer.length;
 
+		if (frag_len < ofs) {
+			/*
+			 * something is wrong, let the caller deal with it
+			 */
+			*_vector = NULL;
+			*_count = 0;
+			return 0;
+		}
+
 		state->buffer.data = talloc_realloc(state,
 						    state->buffer.data,
 						    uint8_t, frag_len);
-- 
1.7.9.5


From 0a9482c35325a2d3e3d915274b997dfb6812a4dd Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 25 Sep 2013 23:25:12 +0200
Subject: [PATCH 07/20] 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 87d4438..277c7c6 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -213,6 +213,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 27ad9277415735c6ab3ec174e02826d85f8b8d91 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 25 Sep 2013 23:25:12 +0200
Subject: [PATCH 08/20] 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 f4e6b8c..909e7e4 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 0c87e0818834f9b982ad824a8952803e1ddfdf09 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 25 Sep 2013 23:25:12 +0200
Subject: [PATCH 09/20] 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 fbd8476..d322a0b 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 6b8495ca22252af01fc0a90c67b5950210c50380 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Tue, 24 Sep 2013 05:03:40 +0200
Subject: [PATCH 10/20] 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 d8bd6d2..f70880f 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 1232bf297d6d618cf31b590900c707978571fd1e 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/20] 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 18adb42..ab7f884 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -594,6 +594,11 @@ static void read_packet_handler(struct tevent_context *ev,
 		return;
 	}
 
+	if (total + more < total) {
+		tevent_req_error(req, EMSGSIZE);
+		return;
+	}
+
 	tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
 	if (tevent_req_nomem(tmp, req)) {
 		return;
-- 
1.7.9.5


From 2abfeaeeff334bec2bcfe7db8af3d122847a985e Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 9 Oct 2013 11:16:08 -0700
Subject: [PATCH 12/20] 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 83f27fe..ca14886 100644
--- a/source3/rpc_server/srv_pipe_hnd.c
+++ b/source3/rpc_server/srv_pipe_hnd.c
@@ -1311,6 +1311,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 0c04a663f2683a5e8334400bc775fd81664dc07b Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 9 Oct 2013 11:20:53 -0700
Subject: [PATCH 13/20] 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 ca14886..54f4208 100644
--- a/source3/rpc_server/srv_pipe_hnd.c
+++ b/source3/rpc_server/srv_pipe_hnd.c
@@ -388,6 +388,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 db6ab8b22588b9c483fe9d0bf5f4d52f2c5273c1 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 16 Oct 2013 10:45:02 -0700
Subject: [PATCH 14/20] 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 9c80fa2..893fa1b 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -2089,7 +2089,8 @@ bool api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in,
 	*pstatus = NT_STATUS_OK;
 
 	if (p->auth.auth_level == DCERPC_AUTH_LEVEL_NONE || p->auth.auth_level == DCERPC_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 0f8f75562aeba87c0d5bdca2c710f704dcabb586 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 9 Oct 2013 11:23:38 -0700
Subject: [PATCH 15/20] 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 54f4208..9c0546a 100644
--- a/source3/rpc_server/srv_pipe_hnd.c
+++ b/source3/rpc_server/srv_pipe_hnd.c
@@ -362,8 +362,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"));
@@ -422,6 +421,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 1cfcb587e27c807dd07644b0868f619cf223f5ca Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Oct 2013 14:17:49 +0200
Subject: [PATCH 16/20] CVE-2013-4408:s3:util_tsock: add some overflow
 detection to tstream_read_packet_done()

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/lib/util_tsock.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/source3/lib/util_tsock.c b/source3/lib/util_tsock.c
index 7588857..9b48f69 100644
--- a/source3/lib/util_tsock.c
+++ b/source3/lib/util_tsock.c
@@ -108,6 +108,11 @@ static void tstream_read_packet_done(struct tevent_req *subreq)
 		return;
 	}
 
+	if (total + more < total) {
+		tevent_req_error(req, EMSGSIZE);
+		return;
+	}
+
 	tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
 	if (tevent_req_nomem(tmp, req)) {
 		return;
-- 
1.7.9.5


From d756dae474213d37dac08fe0951872dd5a76b37d Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 24 Oct 2013 11:58:48 -0700
Subject: [PATCH 17/20] 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 609f209..fe1b3fe 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -443,7 +443,8 @@ static NTSTATUS rpc_write_recv(struct tevent_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
@@ -468,6 +469,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;
 }
 
@@ -480,6 +489,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;
 };
 
@@ -489,6 +499,7 @@ static void get_complete_frag_got_rest(struct tevent_req *subreq);
 static struct tevent_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)
 {
@@ -505,6 +516,7 @@ static struct tevent_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);
@@ -527,7 +539,7 @@ static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
 		return req;
 	}
 
-	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;
 	}
@@ -578,7 +590,8 @@ static void get_complete_frag_got_header(struct tevent_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)) {
 		tevent_req_nterror(req, status);
 		return;
@@ -1321,6 +1334,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;
@@ -1343,7 +1357,8 @@ static struct tevent_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 tevent_req *req, *subreq;
 	struct rpc_api_pipe_state *state;
@@ -1357,6 +1372,7 @@ static struct tevent_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);
@@ -1440,6 +1456,7 @@ static void rpc_api_pipe_trans_done(struct tevent_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 (tevent_req_nomem(subreq, req)) {
 		return;
@@ -1531,6 +1548,7 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
 	}
 
 	subreq = get_complete_frag_send(state, state->ev, state->cli,
+					state->call_id,
 					&state->rhdr, &state->incoming_frag);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
@@ -2217,7 +2235,8 @@ struct tevent_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,
-					   DCERPC_PKT_RESPONSE);
+					   DCERPC_PKT_RESPONSE,
+					   state->call_id);
 		if (subreq == NULL) {
 			goto fail;
 		}
@@ -2353,7 +2372,8 @@ static void rpc_api_pipe_req_write_done(struct tevent_req *subreq)
 	if (is_last_frag) {
 		subreq = rpc_api_pipe_send(state, state->ev, state->cli,
 					   &state->outgoing_frag,
-					   DCERPC_PKT_RESPONSE);
+					   DCERPC_PKT_RESPONSE,
+					   state->call_id);
 		if (tevent_req_nomem(subreq, req)) {
 			return;
 		}
@@ -2664,7 +2684,7 @@ struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx,
 	}
 
 	subreq = rpc_api_pipe_send(state, ev, cli, &state->rpc_out,
-				   DCERPC_PKT_BIND_ACK);
+				   DCERPC_PKT_BIND_ACK, state->rpc_call_id);
 	if (subreq == NULL) {
 		goto fail;
 	}
@@ -2708,6 +2728,16 @@ static void rpc_pipe_bind_step_one_done(struct tevent_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);
+		tevent_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"));
@@ -2932,7 +2962,8 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind_send(struct tevent_req *req,
 	}
 
 	subreq = rpc_api_pipe_send(state, state->ev, state->cli,
-				   &state->rpc_out, DCERPC_PKT_ALTER_RESP);
+				   &state->rpc_out, DCERPC_PKT_ALTER_RESP,
+				   state->rpc_call_id);
 	if (subreq == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
@@ -2968,6 +2999,15 @@ static void rpc_bind_ntlmssp_api_done(struct tevent_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));
+		tevent_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 d0b51b31ad37807a27fbbd42557f06673366ae10 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 19 Nov 2013 15:36:11 -0800
Subject: [PATCH 18/20] 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 +++++++++++++
 source3/rpcclient/cmd_lsarpc.c     |    9 +++++++--
 source4/libcli/util/clilsa.c       |   16 +++++++++++++++-
 source4/winbind/wb_async_helpers.c |   13 ++++++++++++-
 4 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c
index caa2583..5f89840 100644
--- a/source3/rpc_client/cli_lsarpc.c
+++ b/source3/rpc_client/cli_lsarpc.c
@@ -198,6 +198,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) ||
@@ -219,6 +224,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/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c
index e0f4ac4..fea1096 100644
--- a/source3/rpcclient/cmd_lsarpc.c
+++ b/source3/rpcclient/cmd_lsarpc.c
@@ -430,7 +430,7 @@ static NTSTATUS cmd_lsa_lookup_sids3(struct rpc_pipe_client *cli,
 	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
 	int i;
 	struct lsa_SidArray sids;
-	struct lsa_RefDomainList *domains;
+	struct lsa_RefDomainList *domains = NULL;
 	struct lsa_TransNameArray2 names;
 	uint32_t count = 0;
 
@@ -472,11 +472,16 @@ static NTSTATUS cmd_lsa_lookup_sids3(struct rpc_pipe_client *cli,
 	    NT_STATUS_V(STATUS_SOME_UNMAPPED))
 		goto done;
 
+	if (sids.num_sids != names.count) {
+		result = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		goto done;
+	}
+
 	result = NT_STATUS_OK;
 
 	/* Print results */
 
-	for (i = 0; i < count; i++) {
+	for (i = 0; i < names.count; i++) {
 		fstring sid_str;
 
 		sid_to_fstring(sid_str, sids.sids[i].sid);
diff --git a/source4/libcli/util/clilsa.c b/source4/libcli/util/clilsa.c
index 16967d7..a7d202d 100644
--- a/source4/libcli/util/clilsa.c
+++ b/source4/libcli/util/clilsa.c
@@ -241,7 +241,21 @@ NTSTATUS smblsa_lookup_sid(struct smbcli_state *cli,
 	}
 	if (names.count != 1) {
 		talloc_free(mem_ctx2);
-		return NT_STATUS_UNSUCCESSFUL;
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+	}
+	if (domains == NULL) {
+		talloc_free(mem_ctx2);
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+	}
+	if (domains->count != 1) {
+		talloc_free(mem_ctx2);
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+	}
+	if (names.names[0].sid_index != UINT32_MAX &&
+	    names.names[0].sid_index >= domains->count)
+	{
+		talloc_free(mem_ctx2);
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
 	}
 
 	(*name) = talloc_asprintf(mem_ctx, "%s\\%s", 
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 26eb2dd21f9e08ab75fbf37bccb3477fc37eca7d Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 19 Nov 2013 16:34:52 -0800
Subject: [PATCH 19/20] 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_lsarpc.c     |    6 ++-
 source3/rpcclient/cmd_samr.c       |   62 ++++++++++++++++++++++++++
 source3/smbd/lanman.c              |    8 ++++
 source3/utils/net_rpc.c            |   41 +++++++++++++++++-
 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 +++++-
 19 files changed, 376 insertions(+), 32 deletions(-)

diff --git a/source3/lib/netapi/group.c b/source3/lib/netapi/group.c
index f5a7e77..c511ecd 100644
--- a/source3/lib/netapi/group.c
+++ b/source3/lib/netapi/group.c
@@ -273,6 +273,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;
@@ -437,6 +446,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;
@@ -672,6 +689,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;
@@ -788,6 +813,14 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
 		werr = WERR_GROUPNOTFOUND;
 		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_GROUPNOTFOUND;
@@ -816,6 +849,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;
@@ -909,6 +950,14 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
 		werr = WERR_GROUPNOTFOUND;
 		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_GROUPNOTFOUND;
@@ -937,6 +986,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;
@@ -1319,6 +1376,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, talloc_tos(),
 				       &domain_handle,
 				       SAMR_GROUP_ACCESS_GET_MEMBERS,
@@ -1471,6 +1537,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, talloc_tos(),
 				       &domain_handle,
 				       SAMR_GROUP_ACCESS_GET_MEMBERS |
@@ -1533,6 +1608,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 03f9da5..6e83d5d 100644
--- a/source3/lib/netapi/localgroup.c
+++ b/source3/lib/netapi/localgroup.c
@@ -50,6 +50,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:
@@ -951,7 +958,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 c5f7b37..e15a8f8 100644
--- a/source3/lib/netapi/user.c
+++ b/source3/lib/netapi/user.c
@@ -546,6 +546,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, talloc_tos(),
 				      &domain_handle,
@@ -1678,6 +1686,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,
@@ -1833,6 +1849,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, talloc_tos(),
 				      &domain_handle,
@@ -2852,6 +2876,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, talloc_tos(),
 				      &domain_handle,
@@ -3003,6 +3035,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, talloc_tos(),
 				      &domain_handle,
@@ -3053,6 +3093,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;
@@ -3297,6 +3345,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, talloc_tos(),
 				      &domain_handle,
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 8522c17..c7dad56 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -948,6 +948,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",
@@ -1274,6 +1282,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 5f89840..90f97c7 100644
--- a/source3/rpc_client/cli_lsarpc.c
+++ b/source3/rpc_client/cli_lsarpc.c
@@ -516,9 +516,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;
 		}
@@ -531,6 +541,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_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c
index fea1096..7b8506c 100644
--- a/source3/rpcclient/cmd_lsarpc.c
+++ b/source3/rpcclient/cmd_lsarpc.c
@@ -309,7 +309,7 @@ static NTSTATUS cmd_lsa_lookup_names4(struct rpc_pipe_client *cli,
 
 	uint32_t num_names;
 	struct lsa_String *names;
-	struct lsa_RefDomainList *domains;
+	struct lsa_RefDomainList *domains = NULL;
 	struct lsa_TransSidArray3 sids;
 	uint32_t count = 0;
 	int i;
@@ -342,6 +342,10 @@ static NTSTATUS cmd_lsa_lookup_names4(struct rpc_pipe_client *cli,
 		return result;
 	}
 
+	if (sids.count != num_names) {
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+	}
+
 	for (i = 0; i < sids.count; i++) {
 		fstring sid_str;
 		sid_to_fstring(sid_str, sids.sids[i].sid);
diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c
index 3964b7d..9b42eef 100644
--- a/source3/rpcclient/cmd_samr.c
+++ b/source3/rpcclient/cmd_samr.c
@@ -360,6 +360,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,
@@ -1309,6 +1318,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,
@@ -1899,6 +1917,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++)
@@ -2039,6 +2066,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,
@@ -2121,6 +2157,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,
@@ -2436,6 +2481,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,
@@ -2804,6 +2858,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 9b173d4..18ab1e3 100644
--- a/source3/smbd/lanman.c
+++ b/source3/smbd/lanman.c
@@ -2494,6 +2494,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 749b0c2..6e155ea 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -1493,6 +1493,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:
@@ -1826,6 +1835,14 @@ static NTSTATUS rpc_add_groupmem(struct rpc_pipe_client *pipe_hnd,
 			  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,
@@ -2034,6 +2051,14 @@ static NTSTATUS rpc_del_groupmem(struct net_context *c,
 			  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,
@@ -2695,9 +2720,15 @@ 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) {
 		return rpc_list_group_members(c, pipe_hnd, mem_ctx, domain_name,
 					      domain_sid, &domain_pol,
@@ -5479,6 +5510,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 bb7d74b..2a4477c 100644
--- a/source3/utils/net_rpc_join.c
+++ b/source3/utils/net_rpc_join.c
@@ -322,6 +322,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 a7d202d..d4e02c0 100644
--- a/source4/libcli/util/clilsa.c
+++ b/source4/libcli/util/clilsa.c
@@ -312,7 +312,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 fc7de10..d5d7ee0 100644
--- a/source4/libnet/libnet_join.c
+++ b/source4/libnet/libnet_join.c
@@ -643,9 +643,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 4548864..24642ba 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 e558c93..bd1110a 100644
--- a/source4/libnet/libnet_passwd.c
+++ b/source4/libnet/libnet_passwd.c
@@ -594,10 +594,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 1c392c7fe7794428a4f02c0e3405fb5194803336 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 19 Nov 2013 17:14:48 -0800
Subject: [PATCH 20/20] 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 c511ecd..1081c86 100644
--- a/source3/lib/netapi/group.c
+++ b/source3/lib/netapi/group.c
@@ -339,6 +339,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++) {
@@ -1413,6 +1421,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 e15a8f8..39c6b66 100644
--- a/source3/lib/netapi/user.c
+++ b/source3/lib/netapi/user.c
@@ -2924,6 +2924,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,
@@ -3449,6 +3457,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 9b42eef..368e845 100644
--- a/source3/rpcclient/cmd_samr.c
+++ b/source3/rpcclient/cmd_samr.c
@@ -2001,6 +2001,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 6e155ea..517ee9c 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -2513,6 +2513,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 59d3457..a379b0b 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