[Pkg-samba-maint] [samba] 02/03: add patch for CVE-2013-4408

Ivo De Decker idd-guest at moszumanska.debian.org
Mon Dec 9 09:15:36 UTC 2013


This is an automated email from the git hooks/post-receive script.

idd-guest pushed a commit to branch wheezy
in repository samba.

commit 8ffb5040be2a75869c066ba329a6980ee5699404
Author: Ivo De Decker <ivo.dedecker at ugent.be>
Date:   Sun Dec 1 19:01:06 2013 +0100

    add patch for CVE-2013-4408
    
    DCE-RPC fragment length field is incorrectly checked
---
 debian/changelog                            |    1 +
 debian/patches/security-CVE-2013-4408.patch | 1584 +++++++++++++++++++++++++++
 debian/patches/series                       |    1 +
 3 files changed, 1586 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index bb06420..e378f2d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -3,6 +3,7 @@ samba (2:3.6.6-6+deb7u2) UNRELEASED; urgency=low
   * Security update
   * CVE-2013-4475: ACLs are not checked on opening an alternate data stream on
     a file or directory
+  * CVE-2013-4408: DCE-RPC fragment length field is incorrectly checked
 
  -- Ivo De Decker <ivo.dedecker at ugent.be>  Sun, 01 Dec 2013 18:24:42 +0100
 
diff --git a/debian/patches/security-CVE-2013-4408.patch b/debian/patches/security-CVE-2013-4408.patch
new file mode 100644
index 0000000..482dbda
--- /dev/null
+++ b/debian/patches/security-CVE-2013-4408.patch
@@ -0,0 +1,1584 @@
+===========================================================
+== Subject:     DCE-RPC fragment length field is incorrectly checked.
+==
+== CVE ID#:     CVE-2013-4408
+==
+== Versions:    All versions of Samba later than 3.4.0
+==
+== Summary:     Incorrect length checks on DCE-RPC fragment lengths
+==              cause Samba client utilities including winbindd to
+==              be vulnerable to buffer overrun exploits.
+==
+===========================================================
+
+===========
+Description
+===========
+
+Samba versions 3.4.0 and above (versions 3.4.0 - 3.4.17, 3.5.0 -
+3.5.22, 3.6.0 - 3.6.21, 4.0.0 - 4.0.12 and including 4.1.2) are
+vulnerable to buffer overrun exploits in the client processing of
+DCE-RPC packets. This is due to incorrect checking of the DCE-RPC
+fragment length in the client code.
+
+This is a critical vulnerability as the DCE-RPC client code is part of
+the winbindd authentication and identity mapping daemon, which is
+commonly configured as part of many server installations (when joined
+to an Active Directory Domain). A malicious Active Directory Domain
+Controller or man-in-the-middle attacker impersonating an Active
+Directory Domain Controller could achieve root-level access by
+compromising the winbindd process.
+
+Samba server versions 3.4.0 - 3.4.17 and versions 3.5.0 - 3.5.22 are
+also vulnerable to a denial of service attack (server crash) due to a
+similar error in the server code of those versions.
+
+Samba server versions 3.6.0 and above (including all 3.6.x versions,
+all 4.0.x versions and 4.1.x) are not vulnerable to this problem.
+
+In addition range checks were missing on arguments returned from calls
+to the DCE-RPC functions LookupSids (lsa and samr), LookupNames (lsa and samr)
+and LookupRids (samr) which could also cause similar problems.
+
+As this was found during an internal audit of the Samba code there are
+no currently known exploits for this problem (as of December 9th 2013).
+
+--- a/librpc/rpc/dcerpc_util.c
++++ b/librpc/rpc/dcerpc_util.c
+@@ -48,6 +48,15 @@
+ 	}
+ }
+ 
++uint32_t dcerpc_get_call_id(const DATA_BLOB *blob)
++{
++	if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
++		return IVAL(blob->data, DCERPC_CALL_ID_OFFSET);
++	} else {
++		return RIVAL(blob->data, DCERPC_CALL_ID_OFFSET);
++	}
++}
++
+ void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
+ {
+ 	if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
+@@ -223,6 +232,15 @@
+ 
+ 		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);
+@@ -292,6 +310,11 @@
+ 		return;
+ 	}
+ 
++	if (state->pkt->frag_length != state->buffer.length) {
++		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
++		return;
++	}
++
+ 	tevent_req_done(req);
+ }
+ 
+--- a/source3/librpc/rpc/dcerpc_helpers.c
++++ b/source3/librpc/rpc/dcerpc_helpers.c
+@@ -125,6 +125,10 @@
+ 		NDR_PRINT_DEBUG(ncacn_packet, r);
+ 	}
+ 
++	if (r->frag_length != blob->length) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++
+ 	return NT_STATUS_OK;
+ }
+ 
+--- a/source3/rpc_client/cli_pipe.c
++++ b/source3/rpc_client/cli_pipe.c
+@@ -235,6 +235,7 @@
+ 	struct event_context *ev;
+ 	struct rpc_pipe_client *cli;
+ 	uint16_t frag_len;
++	uint32_t call_id;
+ 	DATA_BLOB *pdu;
+ };
+ 
+@@ -244,6 +245,7 @@
+ 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,
+ 						 DATA_BLOB *pdu)
+ {
+ 	struct tevent_req *req, *subreq;
+@@ -259,6 +261,7 @@
+ 	state->ev = ev;
+ 	state->cli = cli;
+ 	state->frag_len = RPC_HEADER_LEN;
++	state->call_id = call_id;
+ 	state->pdu = pdu;
+ 
+ 	received = pdu->length;
+@@ -281,6 +284,15 @@
+ 	}
+ 
+ 	state->frag_len = dcerpc_get_frag_length(pdu);
++	if (state->frag_len < RPC_HEADER_LEN) {
++		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
++		return tevent_req_post(req, ev);
++	}
++
++	if (state->call_id != dcerpc_get_call_id(pdu)) {
++		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
++		return tevent_req_post(req, ev);
++	}
+ 
+ 	/*
+ 	 * Ensure we have frag_len bytes of data.
+@@ -329,6 +341,15 @@
+ 	}
+ 
+ 	state->frag_len = dcerpc_get_frag_length(state->pdu);
++	if (state->frag_len < RPC_HEADER_LEN) {
++		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
++		return;
++	}
++
++	if (state->call_id != dcerpc_get_call_id(state->pdu)) {
++		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
++		return;
++	}
+ 
+ 	if (!data_blob_realloc(NULL, state->pdu, state->frag_len)) {
+ 		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+@@ -690,6 +711,7 @@
+ 	struct event_context *ev;
+ 	struct rpc_pipe_client *cli;
+ 	uint8_t expected_pkt_type;
++	uint32_t call_id;
+ 
+ 	DATA_BLOB incoming_frag;
+ 	struct ncacn_packet *pkt;
+@@ -708,7 +730,8 @@
+ 					    struct event_context *ev,
+ 					    struct rpc_pipe_client *cli,
+ 					    DATA_BLOB *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;
+@@ -722,6 +745,7 @@
+ 	state->ev = ev;
+ 	state->cli = cli;
+ 	state->expected_pkt_type = expected_pkt_type;
++	state->call_id = call_id;
+ 	state->incoming_frag = data_blob_null;
+ 	state->reply_pdu = data_blob_null;
+ 	state->reply_pdu_offset = 0;
+@@ -821,6 +845,7 @@
+ 
+ 	/* Ensure we have enough data for a pdu. */
+ 	subreq = get_complete_frag_send(state, state->ev, state->cli,
++					state->call_id,
+ 					&state->incoming_frag);
+ 	if (tevent_req_nomem(subreq, req)) {
+ 		return;
+@@ -940,6 +965,7 @@
+ 	}
+ 
+ 	subreq = get_complete_frag_send(state, state->ev, state->cli,
++					state->call_id,
+ 					&state->incoming_frag);
+ 	if (tevent_req_nomem(subreq, req)) {
+ 		return;
+@@ -1292,7 +1318,8 @@
+ 	if (is_last_frag) {
+ 		subreq = rpc_api_pipe_send(state, ev, state->cli,
+ 					   &state->rpc_out,
+-					   DCERPC_PKT_RESPONSE);
++					   DCERPC_PKT_RESPONSE,
++					   state->call_id);
+ 		if (subreq == NULL) {
+ 			goto fail;
+ 		}
+@@ -1428,7 +1455,8 @@
+ 	if (is_last_frag) {
+ 		subreq = rpc_api_pipe_send(state, state->ev, state->cli,
+ 					   &state->rpc_out,
+-					   DCERPC_PKT_RESPONSE);
++					   DCERPC_PKT_RESPONSE,
++					   state->call_id);
+ 		if (tevent_req_nomem(subreq, req)) {
+ 			return;
+ 		}
+@@ -1667,7 +1695,7 @@
+ 	}
+ 
+ 	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;
+ 	}
+@@ -1865,7 +1893,8 @@
+ 	}
+ 
+ 	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;
+ 	}
+@@ -1897,7 +1926,8 @@
+ 	}
+ 
+ 	subreq = rpc_api_pipe_send(state, state->ev, state->cli,
+-				   &state->rpc_out, DCERPC_PKT_AUTH3);
++				   &state->rpc_out, DCERPC_PKT_AUTH3,
++				   state->rpc_call_id);
+ 	if (subreq == NULL) {
+ 		return NT_STATUS_NO_MEMORY;
+ 	}
+--- a/source4/librpc/rpc/dcerpc.c
++++ b/source4/librpc/rpc/dcerpc.c
+@@ -658,6 +658,10 @@
+ 		return ndr_map_error2ntstatus(ndr_err);
+ 	}
+ 
++	if (pkt->frag_length != blob->length) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++
+ 	return NT_STATUS_OK;
+ }
+ 
+--- a/source4/librpc/rpc/dcerpc_smb.c
++++ b/source4/librpc/rpc/dcerpc_smb.c
+@@ -160,6 +160,12 @@
+ 	} 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) {
+--- a/source4/librpc/rpc/dcerpc_smb2.c
++++ b/source4/librpc/rpc/dcerpc_smb2.c
+@@ -170,6 +170,12 @@
+ 
+ 	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;
+--- a/source4/librpc/rpc/dcerpc_sock.c
++++ b/source4/librpc/rpc/dcerpc_sock.c
+@@ -102,6 +102,12 @@
+ 		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;
+ 	}
+--- a/lib/async_req/async_sock.c
++++ b/lib/async_req/async_sock.c
+@@ -635,6 +635,11 @@
+ 		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;
+--- a/source3/lib/util_tsock.c
++++ b/source3/lib/util_tsock.c
+@@ -110,6 +110,11 @@
+ 		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;
+--- a/libcli/util/tstream.c
++++ b/libcli/util/tstream.c
+@@ -129,6 +129,11 @@
+ 		return;
+ 	}
+ 
++	if (new_buf_size <= old_buf_size) {
++		tevent_req_nterror(req, NT_STATUS_INVALID_BUFFER_SIZE);
++		return;
++	}
++
+ 	buf = talloc_realloc(state, state->pdu_blob.data, uint8_t, new_buf_size);
+ 	if (tevent_req_nomem(buf, req)) {
+ 		return;
+--- a/librpc/idl/dcerpc.idl
++++ b/librpc/idl/dcerpc.idl
+@@ -467,6 +467,7 @@
+ 	const uint8 DCERPC_DREP_OFFSET     =  4;
+ 	const uint8 DCERPC_FRAG_LEN_OFFSET =  8;
+ 	const uint8 DCERPC_AUTH_LEN_OFFSET = 10;
++	const uint8 DCERPC_CALL_ID_OFFSET  = 12;
+ 
+ 	/* little-endian flag */
+ 	const uint8 DCERPC_DREP_LE  = 0x10;
+--- a/librpc/rpc/rpc_common.h
++++ b/librpc/rpc/rpc_common.h
+@@ -135,6 +135,7 @@
+ 
+ void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v);
+ uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob);
++uint32_t dcerpc_get_call_id(const DATA_BLOB *blob);
+ void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v);
+ uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob);
+ 
+--- a/nsswitch/libwbclient/wbc_sid.c
++++ b/nsswitch/libwbclient/wbc_sid.c
+@@ -421,6 +421,13 @@
+ 	for (i=0; i<num_names; i++) {
+ 
+ 		names[i].domain_index = strtoul(p, &q, 10);
++		if (names[i].domain_index < 0) {
++			goto wbc_err_invalid;
++		}
++		if (names[i].domain_index >= num_domains) {
++			goto wbc_err_invalid;
++		}
++
+ 		if (*q != ' ') {
+ 			goto wbc_err_invalid;
+ 		}
+--- a/nsswitch/wbinfo.c
++++ b/nsswitch/wbinfo.c
+@@ -1380,11 +1380,28 @@
+ 	}
+ 
+ 	for (i=0; i<num_sids; i++) {
++		const char *domain = NULL;
++
+ 		wbcSidToStringBuf(&sids[i], sidstr, sizeof(sidstr));
+ 
+-		d_printf("%s -> %s\\%s %d\n", sidstr,
+-			 domains[names[i].domain_index].short_name,
+-			 names[i].name, names[i].type);
++		if (names[i].domain_index >= num_domains) {
++			domain = "<none>";
++		} else if (names[i].domain_index < 0) {
++			domain = "<none>";
++		} else {
++			domain = domains[names[i].domain_index].short_name;
++		}
++
++		if (names[i].type == WBC_SID_NAME_DOMAIN) {
++			d_printf("%s -> %s %d\n", sidstr,
++				domain,
++				names[i].type);
++		} else {
++			d_printf("%s -> %s%c%s %d\n", sidstr,
++				domain,
++				winbind_separator(),
++				names[i].name, names[i].type);
++		}
+ 	}
+ 	return true;
+ }
+--- a/source3/rpc_client/cli_lsarpc.c
++++ b/source3/rpc_client/cli_lsarpc.c
+@@ -279,11 +279,26 @@
+ 
+ 	for (i = 0; i < num_sids; i++) {
+ 		const char *name, *dom_name;
+-		uint32_t dom_idx = lsa_names.names[i].sid_index;
++		uint32_t dom_idx;
++
++		if (i >= lsa_names.count) {
++			*presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
++			return status;
++		}
++
++		dom_idx = lsa_names.names[i].sid_index;
+ 
+ 		/* Translate optimised name through domain index array */
+ 
+ 		if (dom_idx != 0xffffffff) {
++			if (ref_domains == NULL) {
++				*presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
++				return status;
++			}
++			if (dom_idx >= ref_domains->count) {
++				*presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
++				return status;
++			}
+ 
+ 			dom_name = ref_domains->domains[dom_idx].name.string;
+ 			name = lsa_names.names[i].name.string;
+@@ -676,9 +691,19 @@
+ 		struct dom_sid *sid = &(*sids)[i];
+ 
+ 		if (use_lookupnames4) {
++			if (i >= sid_array3.count) {
++				*presult = 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) {
++				*presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
++				goto done;
++			}
++
+ 			dom_idx		= sid_array.sids[i].sid_index;
+ 			(*types)[i]	= sid_array.sids[i].sid_type;
+ 		}
+@@ -691,6 +716,14 @@
+ 			(*types)[i] = SID_NAME_UNKNOWN;
+ 			continue;
+ 		}
++		if (domains == NULL) {
++			*presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
++			goto done;
++		}
++		if (dom_idx >= domains->count) {
++			*presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
++			goto done;
++		}
+ 
+ 		if (use_lookupnames4) {
+ 			sid_copy(sid, sid_array3.sids[i].sid);
+--- a/source3/rpcclient/cmd_lsarpc.c
++++ b/source3/rpcclient/cmd_lsarpc.c
+@@ -323,7 +323,7 @@
+ 
+ 	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;
+@@ -361,6 +361,10 @@
+ 		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);
+@@ -450,7 +454,7 @@
+ 	NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
+ 	int i;
+ 	struct lsa_SidArray sids;
+-	struct lsa_RefDomainList *domains;
++	struct lsa_RefDomainList *domains = NULL;
+ 	struct lsa_TransNameArray2 names;
+ 	uint32_t count = 0;
+ 	struct dcerpc_binding_handle *b = cli->binding_handle;
+@@ -506,9 +510,12 @@
+ 
+ 	/* Print results */
+ 
+-	for (i = 0; i < count; i++) {
++	for (i = 0; i < names.count; i++) {
+ 		fstring sid_str;
+ 
++		if (i >= sids.num_sids) {
++			break;
++		}
+ 		sid_to_fstring(sid_str, sids.sids[i].sid);
+ 		printf("%s %s (%d)\n", sid_str,
+ 		       names.names[i].name.string,
+--- a/source3/winbindd/wb_lookupsids.c
++++ b/source3/winbindd/wb_lookupsids.c
+@@ -402,6 +402,9 @@
+ 	uint32_t src_domain_index, dst_domain_index;
+ 
+ 	src_domain_index = src_name->sid_index;
++	if (src_domain_index >= src_domains->count) {
++		return false;
++	}
+ 	src_domain = &src_domains->domains[src_domain_index];
+ 
+ 	if (!wb_lookupsids_find_dom_idx(
+--- a/source3/winbindd/winbindd_rpc.c
++++ b/source3/winbindd/winbindd_rpc.c
+@@ -871,14 +871,20 @@
+ 
+ 	/* 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_names) {
++		return NT_STATUS_INVALID_NETWORK_RESPONSE;
++	}
++	if (tmp_types.count != num_names) {
++		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ 	}
+ 
+ 	for (r = 0; r < tmp_names.count; r++) {
+ 		if (tmp_types.ids[r] == SID_NAME_UNKNOWN) {
+ 			continue;
+ 		}
++		if (total_names >= num_names) {
++			break;
++		}
+ 		names[total_names] = fill_domain_username_talloc(names,
+ 								 domain_name,
+ 								 tmp_names.names[r].string,
+@@ -1038,7 +1044,7 @@
+ 				     struct lsa_TransNameArray **pnames)
+ {
+ 	struct lsa_TransNameArray2 lsa_names2;
+-	struct lsa_TransNameArray *names;
++	struct lsa_TransNameArray *names = *pnames;
+ 	uint32_t i, count;
+ 	struct rpc_pipe_client *cli;
+ 	NTSTATUS status, result;
+@@ -1066,10 +1072,10 @@
+ 	if (NT_STATUS_IS_ERR(result)) {
+ 		return result;
+ 	}
+-	names = TALLOC_ZERO_P(mem_ctx, struct lsa_TransNameArray);
+-	if (names == NULL) {
+-		return NT_STATUS_NO_MEMORY;
++	if (sids->num_sids != lsa_names2.count) {
++		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ 	}
++
+ 	names->count = lsa_names2.count;
+ 	names->names = talloc_array(names, struct lsa_TranslatedName,
+ 				    names->count);
+@@ -1081,8 +1087,17 @@
+ 		names->names[i].name.string = talloc_move(
+ 			names->names, &lsa_names2.names[i].name.string);
+ 		names->names[i].sid_index = lsa_names2.names[i].sid_index;
++
++		if (names->names[i].sid_index == UINT32_MAX) {
++			continue;
++		}
++		if ((*pdomains) == NULL) {
++			return NT_STATUS_INVALID_NETWORK_RESPONSE;
++		}
++		if (names->names[i].sid_index >= (*pdomains)->count) {
++			return NT_STATUS_INVALID_NETWORK_RESPONSE;
++		}
+ 	}
+-	*pnames = names;
+ 	return result;
+ }
+ 
+@@ -1092,10 +1107,11 @@
+ 			 struct lsa_RefDomainList **pdomains,
+ 			 struct lsa_TransNameArray **pnames)
+ {
+-	struct lsa_TransNameArray *names;
++	struct lsa_TransNameArray *names = *pnames;
+ 	struct rpc_pipe_client *cli = NULL;
+ 	struct policy_handle lsa_policy;
+ 	uint32_t count;
++	uint32_t i;
+ 	NTSTATUS status, result;
+ 
+ 	if (domain->can_do_ncacn_ip_tcp) {
+@@ -1111,10 +1127,6 @@
+ 		return status;
+ 	}
+ 
+-	names = TALLOC_ZERO_P(mem_ctx, struct lsa_TransNameArray);
+-	if (names == NULL) {
+-		return NT_STATUS_NO_MEMORY;
+-	}
+ 	status = dcerpc_lsa_LookupSids(cli->binding_handle, mem_ctx,
+ 				       &lsa_policy, sids, pdomains,
+ 				       names, LSA_LOOKUP_NAMES_ALL,
+@@ -1125,6 +1137,22 @@
+ 	if (NT_STATUS_IS_ERR(result)) {
+ 		return result;
+ 	}
+-	*pnames = names;
++
++	if (sids->num_sids != names->count) {
++		return NT_STATUS_INVALID_NETWORK_RESPONSE;
++	}
++
++	for (i=0; i < names->count; i++) {
++		if (names->names[i].sid_index == UINT32_MAX) {
++			continue;
++		}
++		if ((*pdomains) == NULL) {
++			return NT_STATUS_INVALID_NETWORK_RESPONSE;
++		}
++		if (names->names[i].sid_index >= (*pdomains)->count) {
++			return NT_STATUS_INVALID_NETWORK_RESPONSE;
++		}
++	}
++
+ 	return result;
+ }
+--- a/source4/libcli/util/clilsa.c
++++ b/source4/libcli/util/clilsa.c
+@@ -254,7 +254,21 @@
+ 	}
+ 	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", 
+@@ -315,7 +329,11 @@
+ 	}
+ 	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;
+--- a/source4/winbind/wb_async_helpers.c
++++ b/source4/winbind/wb_async_helpers.c
+@@ -120,6 +120,12 @@
+ 		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;
+@@ -140,9 +146,14 @@
+ 			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;
+ 		}
+ 
+@@ -272,6 +283,12 @@
+ 		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;
+@@ -290,9 +307,14 @@
+ 			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;
+ 		}
+ 
+--- a/source3/lib/netapi/group.c
++++ b/source3/lib/netapi/group.c
+@@ -309,6 +309,15 @@
+ 		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;
+@@ -386,6 +395,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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++) {
+@@ -511,6 +528,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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;
+@@ -781,6 +806,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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;
+@@ -921,6 +954,14 @@
+ 		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;
+@@ -959,6 +1000,14 @@
+ 		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;
+@@ -1065,6 +1114,14 @@
+ 		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;
+@@ -1104,6 +1161,14 @@
+ 		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;
+@@ -1514,6 +1579,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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 = dcerpc_samr_OpenGroup(b, talloc_tos(),
+ 				       &domain_handle,
+@@ -1558,6 +1631,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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++) {
+ 
+@@ -1689,6 +1770,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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 = dcerpc_samr_OpenGroup(b, talloc_tos(),
+ 				       &domain_handle,
+@@ -1767,6 +1856,15 @@
+ 		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;
+ 
+ 	status = dcerpc_samr_QueryGroupMember(b, talloc_tos(),
+--- a/source3/lib/netapi/localgroup.c
++++ b/source3/lib/netapi/localgroup.c
+@@ -58,6 +58,12 @@
+ 	if (!NT_STATUS_IS_OK(result)) {
+ 		return result;
+ 	}
++	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:
+@@ -1041,7 +1047,7 @@
+ 	NT_STATUS_NOT_OK_RETURN(result);
+ 
+ 	if (count != 1 || sids.count != 1) {
+-		return NT_STATUS_NONE_MAPPED;
++		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ 	}
+ 
+ 	sid_copy(sid, sids.sids[0].sid);
+--- a/source3/lib/netapi/user.c
++++ b/source3/lib/netapi/user.c
+@@ -604,6 +604,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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 = dcerpc_samr_OpenUser(b, talloc_tos(),
+ 				      &domain_handle,
+@@ -1803,6 +1811,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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,
+@@ -1967,6 +1983,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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 = dcerpc_samr_OpenUser(b, talloc_tos(),
+ 				      &domain_handle,
+@@ -3026,6 +3050,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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 = dcerpc_samr_OpenUser(b, talloc_tos(),
+ 				      &domain_handle,
+@@ -3081,6 +3113,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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,
+@@ -3201,6 +3241,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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 = dcerpc_samr_OpenUser(b, talloc_tos(),
+ 				      &domain_handle,
+@@ -3261,6 +3309,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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;
+@@ -3539,6 +3595,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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 = dcerpc_samr_OpenUser(b, talloc_tos(),
+ 				      &domain_handle,
+@@ -3660,6 +3724,14 @@
+ 		werr = ntstatus_to_werror(result);
+ 		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,
+--- a/source3/libnet/libnet_join.c
++++ b/source3/libnet/libnet_join.c
+@@ -996,6 +996,14 @@
+ 		status = result;
+ 		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",
+@@ -1367,6 +1375,14 @@
+ 		status = result;
+ 		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,
+--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
++++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
+@@ -586,7 +586,7 @@
+ 		status = NT_STATUS_NO_SUCH_USER;
+ 		goto out;
+ 	}
+-	if (rids.count != types.count) {
++	if (types.count != 1) {
+ 		status = NT_STATUS_INVALID_PARAMETER;
+ 		goto out;
+ 	}
+--- a/source3/rpcclient/cmd_samr.c
++++ b/source3/rpcclient/cmd_samr.c
+@@ -385,7 +385,17 @@
+ 		if (!NT_STATUS_IS_OK(status)) {
+ 			goto done;
+ 		}
++
+ 		if (NT_STATUS_IS_OK(result)) {
++			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 = dcerpc_samr_OpenUser(b, mem_ctx,
+ 						      &domain_pol,
+ 						      access_mask,
+@@ -1450,6 +1460,15 @@
+ 			goto done;
+ 		}
+ 		if (NT_STATUS_IS_OK(result)) {
++			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 = dcerpc_samr_OpenAlias(b, mem_ctx,
+ 						       &domain_pol,
+ 						       access_mask,
+@@ -2112,6 +2131,14 @@
+ 		status = result;
+ 		goto done;
+ 	}
++	if (rids.count != num_names) {
++		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++		goto done;
++	}
++	if (name_types.count != num_names) {
++		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++		goto done;
++	}
+ 
+ 	/* Display results */
+ 
+@@ -2193,6 +2220,14 @@
+ 		goto done;
+ 
+ 	/* Display results */
++	if (num_rids != names.count) {
++		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++		goto done;
++	}
++	if (num_rids != types.count) {
++		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++		goto done;
++	}
+ 
+ 	for (i = 0; i < num_rids; i++) {
+ 		printf("rid 0x%x: %s (%d)\n",
+@@ -2269,6 +2304,14 @@
+ 			status = result;
+ 			goto done;
+ 		}
++		if (group_rids.count != 1) {
++			status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++			goto done;
++		}
++		if (name_types.count != 1) {
++			status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++			goto done;
++		}
+ 
+ 		status = dcerpc_samr_OpenGroup(b, mem_ctx,
+ 					       &domain_pol,
+@@ -2372,6 +2415,14 @@
+ 			status = result;
+ 			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;
++		}
+ 
+ 		status = dcerpc_samr_OpenUser(b, mem_ctx,
+ 					      &domain_pol,
+@@ -2758,6 +2809,14 @@
+ 		status = result;
+ 		goto done;
+ 	}
++	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 = dcerpc_samr_OpenUser(b, mem_ctx,
+ 				      &domain_pol,
+@@ -3161,7 +3220,12 @@
+ 		if (!NT_STATUS_IS_OK(result)) {
+ 			return result;
+ 		}
+-
++		if (rids.count != 1) {
++			return NT_STATUS_INVALID_NETWORK_RESPONSE;
++		}
++		if (types.count != 1) {
++			return NT_STATUS_INVALID_NETWORK_RESPONSE;
++		}
+ 
+ 		status = dcerpc_samr_OpenUser(b, mem_ctx,
+ 					      &domain_pol,
+--- a/source3/smbd/lanman.c
++++ b/source3/smbd/lanman.c
+@@ -2628,6 +2628,14 @@
+ 			  nt_errstr(result)));
+ 		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,
+--- a/source3/utils/net_rpc.c
++++ b/source3/utils/net_rpc.c
+@@ -1656,6 +1656,14 @@
+ 		d_fprintf(stderr, _("Lookup of '%s' failed\n"),argv[0]);
+ 		goto done;
+ 	}
++	if (group_rids.count != 1) {
++		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++		goto done;
++	}
++	if (name_types.count != 1) {
++		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++		goto done;
++	}
+ 
+ 	switch (name_types.ids[0])
+ 	{
+@@ -2063,6 +2071,14 @@
+ 			  member);
+ 		goto done;
+ 	}
++	if (rids.count != 1) {
++		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++		goto done;
++	}
++	if (rid_types.count != 1) {
++		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++		goto done;
++	}
+ 
+ 	status = dcerpc_samr_OpenGroup(b, mem_ctx,
+ 				       &domain_pol,
+@@ -2318,6 +2334,14 @@
+ 			  member);
+ 		goto done;
+ 	}
++	if (rids.count != 1) {
++		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++		goto done;
++	}
++	if (rid_types.count != 1) {
++		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
++		goto done;
++	}
+ 
+ 	status = dcerpc_samr_OpenGroup(b, mem_ctx,
+ 				       &domain_pol,
+@@ -2865,7 +2889,12 @@
+ 		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 */
+ 
+@@ -3101,8 +3130,14 @@
+ 	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,
+@@ -6011,6 +6046,14 @@
+ 			acct_name, nt_errstr(result) );
+ 		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;
++	}
+ 
+ 	status = dcerpc_samr_OpenUser(b, mem_ctx,
+ 				      &domain_pol,
+--- a/source3/utils/net_rpc_join.c
++++ b/source3/utils/net_rpc_join.c
+@@ -367,6 +367,15 @@
+ 			    ("error looking up rid for user %s: %s/%s\n",
+ 			     acct_name, nt_errstr(status), nt_errstr(result)));
+ 
++	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, name_types.ids[0]));
+ 		goto done;
+--- a/source4/libnet/groupinfo.c
++++ b/source4/libnet/groupinfo.c
+@@ -87,12 +87,16 @@
+ 		
+ 		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 */
+--- a/source4/libnet/groupman.c
++++ b/source4/libnet/groupman.c
+@@ -212,13 +212,13 @@
+ 
+ 	/* 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;
+ 	}
+--- a/source4/libnet/libnet_join.c
++++ b/source4/libnet/libnet_join.c
+@@ -656,9 +656,17 @@
+ 							      "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;
+--- a/source4/libnet/libnet_lookup.c
++++ b/source4/libnet/libnet_lookup.c
+@@ -363,6 +363,11 @@
+ 	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);
+ }
+ 
+--- a/source4/libnet/libnet_passwd.c
++++ b/source4/libnet/libnet_passwd.c
+@@ -627,10 +627,18 @@
+ 		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;
+--- a/source4/libnet/userinfo.c
++++ b/source4/libnet/userinfo.c
+@@ -90,8 +90,13 @@
+ 
+ 	/* 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 */
+--- a/source4/libnet/userman.c
++++ b/source4/libnet/userman.c
+@@ -236,14 +236,12 @@
+ 
+ 	/* 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;
+ 	}
+ 
+@@ -511,14 +509,12 @@
+ 
+ 	/* 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;
+ 	}
+ 
+--- a/source3/winbindd/winbindd_msrpc.c
++++ b/source3/winbindd/winbindd_msrpc.c
+@@ -737,14 +737,20 @@
+ 		/* 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++) {
+ 			if (tmp_types.ids[r] == SID_NAME_UNKNOWN) {
+ 				continue;
+ 			}
++			if (total_names >= *num_names) {
++				break;
++			}
+ 			(*names)[total_names] = fill_domain_username_talloc(
+ 				mem_ctx, domain->name,
+ 				tmp_names.names[r].string, true);
diff --git a/debian/patches/series b/debian/patches/series
index f4d0e31..6d45860 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -26,3 +26,4 @@ security-CVE-2013-0213.patch
 security-CVE-2013-0214.patch
 security-CVE-2013-4124.patch
 security-CVE-2013-4475.patch
+security-CVE-2013-4408.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-samba/samba.git




More information about the Pkg-samba-maint mailing list