From 8716bb5e03cc4f10e2d4edc704d8defe7e8045f1 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Thu, 16 Jul 2015 22:46:05 +0200
Subject: [PATCH 01/40] CVE-2015-5370: dcerpc.idl: add
 DCERPC_{NCACN_PAYLOAD,FRAG}_MAX_SIZE defines
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11344

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Günther Deschner <gd@samba.org>
---
 librpc/idl/dcerpc.idl | 2 ++
 1 file changed, 2 insertions(+)

--- a/librpc/idl/dcerpc.idl
+++ b/librpc/idl/dcerpc.idl
@@ -475,9 +475,11 @@ interface dcerpc
 	const uint8 DCERPC_PFC_OFFSET      =  3;
 	const uint8 DCERPC_DREP_OFFSET     =  4;
 	const uint8 DCERPC_FRAG_LEN_OFFSET =  8;
+	const uint32 DCERPC_FRAG_MAX_SIZE  = 5840;
 	const uint8 DCERPC_AUTH_LEN_OFFSET = 10;
 	const uint8 DCERPC_CALL_ID_OFFSET  = 12;
 	const uint8 DCERPC_NCACN_PAYLOAD_OFFSET = 16;
+	const uint32 DCERPC_NCACN_PAYLOAD_MAX_SIZE = 0x400000; /* 4 MByte */
 
 	/* little-endian flag */
 	const uint8 DCERPC_DREP_LE  = 0x10;
--- a/librpc/rpc/dcerpc_util.c
+++ b/librpc/rpc/dcerpc_util.c
@@ -92,31 +92,49 @@ uint8_t dcerpc_get_endian_flag(DATA_BLOB
 *
 * @return		- A NTSTATUS error code.
 */
-NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
+NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
 				  TALLOC_CTX *mem_ctx,
-				  DATA_BLOB *pkt_trailer,
+				  const DATA_BLOB *pkt_trailer,
 				  struct dcerpc_auth *auth,
-				  uint32_t *auth_length,
+				  uint32_t *_auth_length,
 				  bool auth_data_only)
 {
 	struct ndr_pull *ndr;
 	enum ndr_err_code ndr_err;
-	uint32_t data_and_pad;
+	uint16_t data_and_pad;
+	uint16_t auth_length;
+	uint32_t tmp_length;
 
-	data_and_pad = pkt_trailer->length
-			- (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length);
+	ZERO_STRUCTP(auth);
+	if (_auth_length != NULL) {
+		*_auth_length = 0;
+	}
+
+	/* Paranoia checks for auth_length. The caller should check this... */
+	if (pkt->auth_length == 0) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	/* Paranoia checks for auth_length. The caller should check this... */
+	if (pkt->auth_length > pkt->frag_length) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+	tmp_length = DCERPC_NCACN_PAYLOAD_OFFSET;
+	tmp_length += DCERPC_AUTH_TRAILER_LENGTH;
+	tmp_length += pkt->auth_length;
+	if (tmp_length > pkt->frag_length) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+	if (pkt_trailer->length > UINT16_MAX) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
 
-	/* paranoia check for pad size. This would be caught anyway by
-	   the ndr_pull_advance() a few lines down, but it scared
-	   Jeremy enough for him to call me, so we might as well check
-	   it now, just to prevent someone posting a bogus YouTube
-	   video in the future.
-	*/
-	if (data_and_pad > pkt_trailer->length) {
-		return NT_STATUS_INFO_LENGTH_MISMATCH;
+	auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length;
+	if (pkt_trailer->length < auth_length) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
 	}
 
-	*auth_length = pkt_trailer->length - data_and_pad;
+	data_and_pad = pkt_trailer->length - auth_length;
 
 	ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx);
 	if (!ndr) {
@@ -136,14 +154,28 @@ NTSTATUS dcerpc_pull_auth_trailer(struct
 	ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth);
 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 		talloc_free(ndr);
+		ZERO_STRUCTP(auth);
 		return ndr_map_error2ntstatus(ndr_err);
 	}
 
+	if (data_and_pad < auth->auth_pad_length) {
+		DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
+			  "Calculated %u  got %u\n",
+			  (unsigned)data_and_pad,
+			  (unsigned)auth->auth_pad_length));
+		talloc_free(ndr);
+		ZERO_STRUCTP(auth);
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+
 	if (auth_data_only && data_and_pad != auth->auth_pad_length) {
-		DEBUG(1, (__location__ ": WARNING: pad length mismatch. "
+		DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
 			  "Calculated %u  got %u\n",
 			  (unsigned)data_and_pad,
 			  (unsigned)auth->auth_pad_length));
+		talloc_free(ndr);
+		ZERO_STRUCTP(auth);
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
 	}
 
 	DEBUG(6,(__location__ ": auth_pad_length %u\n",
@@ -152,6 +184,83 @@ NTSTATUS dcerpc_pull_auth_trailer(struct
 	talloc_steal(mem_ctx, auth->credentials.data);
 	talloc_free(ndr);
 
+	if (_auth_length != NULL) {
+		*_auth_length = auth_length;
+	}
+
+	return NT_STATUS_OK;
+}
+
+/**
+* @brief	Verify the fields in ncacn_packet header.
+*
+* @param pkt		- The ncacn_packet strcuture
+* @param ptype		- The expected PDU type
+* @param max_auth_info	- The maximum size of a possible auth trailer
+* @param required_flags	- The required flags for the pdu.
+* @param optional_flags	- The possible optional flags for the pdu.
+*
+* @return		- A NTSTATUS error code.
+*/
+NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
+					   enum dcerpc_pkt_type ptype,
+					   size_t max_auth_info,
+					   uint8_t required_flags,
+					   uint8_t optional_flags)
+{
+	if (pkt->rpc_vers != 5) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+
+	if (pkt->rpc_vers_minor != 0) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+
+	if (pkt->auth_length > pkt->frag_length) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+
+	if (pkt->ptype != ptype) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+
+	if (max_auth_info > UINT16_MAX) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	if (pkt->auth_length > 0) {
+		size_t max_auth_length;
+
+		if (max_auth_info <= DCERPC_AUTH_TRAILER_LENGTH) {
+			return NT_STATUS_RPC_PROTOCOL_ERROR;
+		}
+		max_auth_length = max_auth_info - DCERPC_AUTH_TRAILER_LENGTH;
+
+		if (pkt->auth_length > max_auth_length) {
+			return NT_STATUS_RPC_PROTOCOL_ERROR;
+		}
+	}
+
+	if ((pkt->pfc_flags & required_flags) != required_flags) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+	if (pkt->pfc_flags & ~(optional_flags|required_flags)) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+
+	if (pkt->drep[0] & ~DCERPC_DREP_LE) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+	if (pkt->drep[1] != 0) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+	if (pkt->drep[2] != 0) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+	if (pkt->drep[3] != 0) {
+		return NT_STATUS_RPC_PROTOCOL_ERROR;
+	}
+
 	return NT_STATUS_OK;
 }
 
--- a/librpc/rpc/rpc_common.h
+++ b/librpc/rpc/rpc_common.h
@@ -158,12 +158,17 @@ uint8_t dcerpc_get_endian_flag(DATA_BLOB
 *
 * @return		- A NTSTATUS error code.
 */
-NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
+NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
 				  TALLOC_CTX *mem_ctx,
-				  DATA_BLOB *pkt_trailer,
+				  const DATA_BLOB *pkt_trailer,
 				  struct dcerpc_auth *auth,
 				  uint32_t *auth_length,
 				  bool auth_data_only);
+NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
+					   enum dcerpc_pkt_type ptype,
+					   size_t max_auth_info,
+					   uint8_t required_flags,
+					   uint8_t optional_flags);
 struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
 						 struct tevent_context *ev,
 						 struct tstream_context *stream);
--- a/source3/librpc/rpc/dcerpc_helpers.c
+++ b/source3/librpc/rpc/dcerpc_helpers.c
@@ -210,47 +210,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_
 }
 
 /**
-* @brief Decodes a dcerpc_auth blob
-*
-* @param mem_ctx	The memory context on which to allocate the packet
-*			elements
-* @param blob		The blob of data to decode
-* @param r		An empty dcerpc_auth structure, must not be NULL
-*
-* @return a NTSTATUS error code
-*/
-NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx,
-				 const DATA_BLOB *blob,
-				 struct dcerpc_auth *r,
-				 bool bigendian)
-{
-	enum ndr_err_code ndr_err;
-	struct ndr_pull *ndr;
-
-	ndr = ndr_pull_init_blob(blob, mem_ctx);
-	if (!ndr) {
-		return NT_STATUS_NO_MEMORY;
-	}
-	if (bigendian) {
-		ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
-	}
-
-	ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, r);
-
-	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-		talloc_free(ndr);
-		return ndr_map_error2ntstatus(ndr_err);
-	}
-	talloc_free(ndr);
-
-	if (DEBUGLEVEL >= 10) {
-		NDR_PRINT_DEBUG(dcerpc_auth, r);
-	}
-
-	return NT_STATUS_OK;
-}
-
-/**
 * @brief Calculate how much data we can in a packet, including calculating
 *	 auth token and pad lengths.
 *
@@ -782,7 +741,7 @@ NTSTATUS dcerpc_add_auth_footer(struct p
 					 auth->auth_type,
 					 auth->auth_level,
 					 pad_len,
-					 1 /* context id. */,
+					 auth->auth_context_id,
 					 &auth_blob,
 					 &auth_info);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -844,19 +803,18 @@ NTSTATUS dcerpc_add_auth_footer(struct p
 *
 * @param auth		The auth data for the connection
 * @param pkt		The actual ncacn_packet
-* @param pkt_trailer	The stub_and_verifier part of the packet
+* @param pkt_trailer [in][out]	The stub_and_verifier part of the packet,
+* 			the auth_trailer and padding will be removed.
 * @param header_size	The header size
 * @param raw_pkt	The whole raw packet data blob
-* @param pad_len	[out] The padding length used in the packet
 *
 * @return A NTSTATUS error code
 */
 NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
 			   struct ncacn_packet *pkt,
 			   DATA_BLOB *pkt_trailer,
-			   size_t header_size,
-			   DATA_BLOB *raw_pkt,
-			   size_t *pad_len)
+			   uint8_t header_size,
+			   DATA_BLOB *raw_pkt)
 {
 	struct schannel_state *schannel_auth;
 	struct auth_ntlmssp_state *ntlmssp_ctx;
@@ -868,6 +826,14 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
 	DATA_BLOB full_pkt;
 	DATA_BLOB data;
 
+	/*
+	 * These check should be done in the caller.
+	 */
+	SMB_ASSERT(raw_pkt->length == pkt->frag_length);
+	SMB_ASSERT(header_size <= pkt->frag_length);
+	SMB_ASSERT(pkt_trailer->length < pkt->frag_length);
+	SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length);
+
 	switch (auth->auth_level) {
 	case DCERPC_AUTH_LEVEL_PRIVACY:
 		DEBUG(10, ("Requested Privacy.\n"));
@@ -881,7 +847,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
 		if (pkt->auth_length != 0) {
 			break;
 		}
-		*pad_len = 0;
 		return NT_STATUS_OK;
 
 	case DCERPC_AUTH_LEVEL_NONE:
@@ -890,7 +855,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
 				  "authenticated connection!\n"));
 			return NT_STATUS_INVALID_PARAMETER;
 		}
-		*pad_len = 0;
 		return NT_STATUS_OK;
 
 	default:
@@ -899,16 +863,8 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
-	/* Paranioa checks for auth_length. */
-	if (pkt->auth_length > pkt->frag_length) {
-		return NT_STATUS_INFO_LENGTH_MISMATCH;
-	}
-	if (((unsigned int)pkt->auth_length
-	     + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) ||
-	    ((unsigned int)pkt->auth_length
-	     + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) {
-		/* Integer wrap attempt. */
-		return NT_STATUS_INFO_LENGTH_MISMATCH;
+	if (pkt->auth_length == 0) {
+		return NT_STATUS_INVALID_PARAMETER;
 	}
 
 	status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
@@ -917,10 +873,23 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
 		return status;
 	}
 
+	if (auth_info.auth_type != auth->auth_type) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	if (auth_info.auth_level != auth->auth_level) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	if (auth_info.auth_context_id != auth->auth_context_id) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	pkt_trailer->length -= auth_length;
 	data = data_blob_const(raw_pkt->data + header_size,
-				pkt_trailer->length - auth_length);
-	full_pkt = data_blob_const(raw_pkt->data,
-				raw_pkt->length - auth_info.credentials.length);
+			       pkt_trailer->length);
+	full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length);
+	full_pkt.length -= auth_info.credentials.length;
 
 	switch (auth->auth_type) {
 	case DCERPC_AUTH_TYPE_NONE:
@@ -996,10 +965,13 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
 	 * pkt_trailer actually has a copy of the raw data, and they
 	 * are still both used in later calls */
 	if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+		if (pkt_trailer->length != data.length) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
 		memcpy(pkt_trailer->data, data.data, data.length);
 	}
 
-	*pad_len = auth_info.auth_pad_length;
+	pkt_trailer->length -= auth_info.auth_pad_length;
 	data_blob_free(&auth_info.credentials);
 	return NT_STATUS_OK;
 }
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -404,9 +404,9 @@ static NTSTATUS cli_pipe_validate_curren
 						DATA_BLOB *rdata,
 						DATA_BLOB *reply_pdu)
 {
-	struct dcerpc_response *r;
+	const struct dcerpc_response *r = NULL;
+	DATA_BLOB tmp_stub = data_blob_null;
 	NTSTATUS ret = NT_STATUS_OK;
-	size_t pad_len = 0;
 
 	/*
 	 * Point the return values at the real data including the RPC
@@ -414,50 +414,128 @@ static NTSTATUS cli_pipe_validate_curren
 	 */
 	*rdata = *pdu;
 
+	if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
+	    !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
+		/*
+		 * TODO: do we still need this hack which was introduced
+		 * in commit a42afcdcc7ab9aa9ed193ae36d3dbb10843447f0.
+		 *
+		 * I don't even know what AS/U might be...
+		 */
+		DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
+			  "fragment first/last ON.\n"));
+		pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+	}
+
 	/* Ensure we have the correct type. */
 	switch (pkt->ptype) {
-	case DCERPC_PKT_ALTER_RESP:
+	case DCERPC_PKT_BIND_NAK:
+		DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
+			  rpccli_pipe_txt(talloc_tos(), cli)));
+
+		ret = dcerpc_verify_ncacn_packet_header(pkt,
+						DCERPC_PKT_BIND_NAK,
+						0, /* max_auth_info */
+						DCERPC_PFC_FLAG_FIRST |
+						DCERPC_PFC_FLAG_LAST,
+						0); /* optional flags */
+		if (!NT_STATUS_IS_OK(ret)) {
+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+				  "RPC packet type - %u, expected %u: %s\n",
+				  rpccli_pipe_txt(talloc_tos(), cli),
+				  pkt->ptype, expected_pkt_type,
+				  nt_errstr(ret)));
+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+			return ret;
+		}
+
+		/* Use this for now... */
+		return NT_STATUS_NETWORK_ACCESS_DENIED;
+
 	case DCERPC_PKT_BIND_ACK:
+		ret = dcerpc_verify_ncacn_packet_header(pkt,
+					expected_pkt_type,
+					pkt->u.bind_ack.auth_info.length,
+					DCERPC_PFC_FLAG_FIRST |
+					DCERPC_PFC_FLAG_LAST,
+					DCERPC_PFC_FLAG_CONC_MPX |
+					DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
+		if (!NT_STATUS_IS_OK(ret)) {
+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+				  "RPC packet type - %u, expected %u: %s\n",
+				  rpccli_pipe_txt(talloc_tos(), cli),
+				  pkt->ptype, expected_pkt_type,
+				  nt_errstr(ret)));
+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+			return ret;
+		}
 
-		/* Client code never receives this kind of packets */
 		break;
 
+	case DCERPC_PKT_ALTER_RESP:
+		ret = dcerpc_verify_ncacn_packet_header(pkt,
+					expected_pkt_type,
+					pkt->u.alter_resp.auth_info.length,
+					DCERPC_PFC_FLAG_FIRST |
+					DCERPC_PFC_FLAG_LAST,
+					DCERPC_PFC_FLAG_CONC_MPX |
+					DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
+		if (!NT_STATUS_IS_OK(ret)) {
+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+				  "RPC packet type - %u, expected %u: %s\n",
+				  rpccli_pipe_txt(talloc_tos(), cli),
+				  pkt->ptype, expected_pkt_type,
+				  nt_errstr(ret)));
+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+			return ret;
+		}
+
+		break;
 
 	case DCERPC_PKT_RESPONSE:
 
 		r = &pkt->u.response;
 
+		ret = dcerpc_verify_ncacn_packet_header(pkt,
+						expected_pkt_type,
+						r->stub_and_verifier.length,
+						0, /* required_flags */
+						DCERPC_PFC_FLAG_FIRST |
+						DCERPC_PFC_FLAG_LAST);
+		if (!NT_STATUS_IS_OK(ret)) {
+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+				  "RPC packet type - %u, expected %u: %s\n",
+				  rpccli_pipe_txt(talloc_tos(), cli),
+				  pkt->ptype, expected_pkt_type,
+				  nt_errstr(ret)));
+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+			return ret;
+		}
+
+		tmp_stub.data = r->stub_and_verifier.data;
+		tmp_stub.length = r->stub_and_verifier.length;
+
 		/* Here's where we deal with incoming sign/seal. */
 		ret = dcerpc_check_auth(cli->auth, pkt,
-					&r->stub_and_verifier,
+					&tmp_stub,
 					DCERPC_RESPONSE_LENGTH,
-					pdu, &pad_len);
+					pdu);
 		if (!NT_STATUS_IS_OK(ret)) {
+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+				  "RPC packet type - %u, expected %u: %s\n",
+				  rpccli_pipe_txt(talloc_tos(), cli),
+				  pkt->ptype, expected_pkt_type,
+				  nt_errstr(ret)));
+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
 			return ret;
 		}
 
-		if (pkt->frag_length < DCERPC_RESPONSE_LENGTH + pad_len) {
-			return NT_STATUS_BUFFER_TOO_SMALL;
-		}
-
 		/* Point the return values at the NDR data. */
-		rdata->data = r->stub_and_verifier.data;
+		*rdata = tmp_stub;
 
-		if (pkt->auth_length) {
-			/* We've already done integer wrap tests in
-			 * dcerpc_check_auth(). */
-			rdata->length = r->stub_and_verifier.length
-					 - pad_len
-					 - DCERPC_AUTH_TRAILER_LENGTH
-					 - pkt->auth_length;
-		} else {
-			rdata->length = r->stub_and_verifier.length;
-		}
-
-		DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
+		DEBUG(10, ("Got pdu len %lu, data_len %lu\n",
 			   (long unsigned int)pdu->length,
-			   (long unsigned int)rdata->length,
-			   (unsigned int)pad_len));
+			   (long unsigned int)rdata->length));
 
 		/*
 		 * If this is the first reply, and the allocation hint is
@@ -478,14 +556,24 @@ static NTSTATUS cli_pipe_validate_curren
 
 		break;
 
-	case DCERPC_PKT_BIND_NAK:
-		DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
-			  rpccli_pipe_txt(talloc_tos(), cli)));
-		/* Use this for now... */
-		return NT_STATUS_NETWORK_ACCESS_DENIED;
-
 	case DCERPC_PKT_FAULT:
 
+		ret = dcerpc_verify_ncacn_packet_header(pkt,
+						DCERPC_PKT_FAULT,
+						0, /* max_auth_info */
+						DCERPC_PFC_FLAG_FIRST |
+						DCERPC_PFC_FLAG_LAST,
+						DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
+		if (!NT_STATUS_IS_OK(ret)) {
+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+				  "RPC packet type - %u, expected %u: %s\n",
+				  rpccli_pipe_txt(talloc_tos(), cli),
+				  pkt->ptype, expected_pkt_type,
+				  nt_errstr(ret)));
+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+			return ret;
+		}
+
 		DEBUG(1, (__location__ ": RPC fault code %s received "
 			  "from %s!\n",
 			  dcerpc_errstr(talloc_tos(),
@@ -502,13 +590,6 @@ static NTSTATUS cli_pipe_validate_curren
 		return NT_STATUS_RPC_PROTOCOL_ERROR;
 	}
 
-	if (pkt->ptype != expected_pkt_type) {
-		DEBUG(3, (__location__ ": Connection to %s got an unexpected "
-			  "RPC packet type - %u, not %u\n",
-			  rpccli_pipe_txt(talloc_tos(), cli),
-			  pkt->ptype, expected_pkt_type));
-		return NT_STATUS_RPC_PROTOCOL_ERROR;
-	}
 
 	if (pkt->call_id != call_id) {
 		DEBUG(3, (__location__ ": Connection to %s got an unexpected "
@@ -518,17 +599,6 @@ static NTSTATUS cli_pipe_validate_curren
 		return NT_STATUS_RPC_PROTOCOL_ERROR;
 	}
 
-	/* Do this just before return - we don't want to modify any rpc header
-	   data before now as we may have needed to do cryptographic actions on
-	   it before. */
-
-	if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
-	    !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
-		DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
-			  "fragment first/last ON.\n"));
-		pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
-	}
-
 	return NT_STATUS_OK;
 }
 
@@ -883,6 +953,12 @@ static void rpc_api_pipe_got_pdu(struct
 
 	state->pkt = talloc(state, struct ncacn_packet);
 	if (!state->pkt) {
+		/*
+		 * TODO: do a real async disconnect ...
+		 *
+		 * For now do it sync...
+		 */
+		TALLOC_FREE(state->cli->transport);
 		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
 		return;
 	}
@@ -892,18 +968,16 @@ static void rpc_api_pipe_got_pdu(struct
 					  state->pkt,
 					  !state->endianess);
 	if (!NT_STATUS_IS_OK(status)) {
+		/*
+		 * TODO: do a real async disconnect ...
+		 *
+		 * For now do it sync...
+		 */
+		TALLOC_FREE(state->cli->transport);
 		tevent_req_nterror(req, status);
 		return;
 	}
 
-	if (state->incoming_frag.length != state->pkt->frag_length) {
-		DEBUG(5, ("Incorrect pdu length %u, expected %u\n",
-			  (unsigned int)state->incoming_frag.length,
-			  (unsigned int)state->pkt->frag_length));
-		tevent_req_nterror(req,  NT_STATUS_INVALID_PARAMETER);
-		return;
-	}
-
 	status = cli_pipe_validate_current_pdu(state,
 						state->cli, state->pkt,
 						&state->incoming_frag,
@@ -917,6 +991,28 @@ static void rpc_api_pipe_got_pdu(struct
 		  (unsigned)state->reply_pdu_offset,
 		  nt_errstr(status)));
 
+	if (state->pkt->ptype != DCERPC_PKT_FAULT && !NT_STATUS_IS_OK(status)) {
+		/*
+		 * TODO: do a real async disconnect ...
+		 *
+		 * For now do it sync...
+		 */
+		TALLOC_FREE(state->cli->transport);
+	} else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
+		/*
+		 * TODO: do a real async disconnect ...
+		 *
+		 * For now do it sync...
+		 */
+		TALLOC_FREE(state->cli->transport);
+	} else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+		/*
+		 * TODO: do a real async disconnect ...
+		 *
+		 * For now do it sync...
+		 */
+		TALLOC_FREE(state->cli->transport);
+	}
 	if (!NT_STATUS_IS_OK(status)) {
 		tevent_req_nterror(req, status);
 		return;
@@ -941,7 +1037,24 @@ static void rpc_api_pipe_got_pdu(struct
 			 "%s\n",
 			 state->endianess?"little":"big",
 			 state->pkt->drep[0]?"little":"big"));
-		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+		/*
+		 * TODO: do a real async disconnect ...
+		 *
+		 * For now do it sync...
+		 */
+		TALLOC_FREE(state->cli->transport);
+		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+		return;
+	}
+
+	if (state->reply_pdu_offset + rdata.length > MAX_RPC_DATA_SIZE) {
+		/*
+		 * TODO: do a real async disconnect ...
+		 *
+		 * For now do it sync...
+		 */
+		TALLOC_FREE(state->cli->transport);
+		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
 		return;
 	}
 
@@ -949,6 +1062,12 @@ static void rpc_api_pipe_got_pdu(struct
 	if (state->reply_pdu.length < state->reply_pdu_offset + rdata.length) {
 		if (!data_blob_realloc(NULL, &state->reply_pdu,
 				state->reply_pdu_offset + rdata.length)) {
+			/*
+			 * TODO: do a real async disconnect ...
+			 *
+			 * For now do it sync...
+			 */
+			TALLOC_FREE(state->cli->transport);
 			tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
 			return;
 		}
@@ -978,6 +1097,14 @@ static void rpc_api_pipe_got_pdu(struct
 	subreq = get_complete_frag_send(state, state->ev, state->cli,
 					state->call_id,
 					&state->incoming_frag);
+	if (subreq == NULL) {
+		/*
+		 * TODO: do a real async disconnect ...
+		 *
+		 * For now do it sync...
+		 */
+		TALLOC_FREE(state->cli->transport);
+	}
 	if (tevent_req_nomem(subreq, req)) {
 		return;
 	}
@@ -1247,7 +1374,7 @@ static NTSTATUS create_rpc_bind_req(TALL
 						auth->auth_type,
 						auth->auth_level,
 						0, /* auth_pad_length */
-						1, /* auth_context_id */
+						auth->auth_context_id,
 						&auth_token,
 						&auth_info);
 		if (!NT_STATUS_IS_OK(ret)) {
@@ -1749,9 +1876,8 @@ static bool check_bind_response(const st
 
 static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
 				struct rpc_pipe_client *cli,
-				uint32 rpc_call_id,
-				enum dcerpc_AuthType auth_type,
-				enum dcerpc_AuthLevel auth_level,
+				struct pipe_auth_data *auth,
+				uint32_t rpc_call_id,
 				DATA_BLOB *pauth_blob,
 				DATA_BLOB *rpc_out)
 {
@@ -1761,10 +1887,10 @@ static NTSTATUS create_rpc_bind_auth3(TA
 	u.auth3._pad = 0;
 
 	status = dcerpc_push_dcerpc_auth(mem_ctx,
-					 auth_type,
-					 auth_level,
+					 auth->auth_type,
+					 auth->auth_level,
 					 0, /* auth_pad_length */
-					 1, /* auth_context_id */
+					 auth->auth_context_id,
 					 pauth_blob,
 					 &u.auth3.auth_info);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -1794,9 +1920,8 @@ static NTSTATUS create_rpc_bind_auth3(TA
  ********************************************************************/
 
 static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx,
-					enum dcerpc_AuthType auth_type,
-					enum dcerpc_AuthLevel auth_level,
-					uint32 rpc_call_id,
+					struct pipe_auth_data *auth,
+					uint32_t rpc_call_id,
 					const struct ndr_syntax_id *abstract,
 					const struct ndr_syntax_id *transfer,
 					const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */
@@ -1806,10 +1931,10 @@ static NTSTATUS create_rpc_alter_context
 	NTSTATUS status;
 
 	status = dcerpc_push_dcerpc_auth(mem_ctx,
-					 auth_type,
-					 auth_level,
+					 auth->auth_type,
+					 auth->auth_level,
 					 0, /* auth_pad_length */
-					 1, /* auth_context_id */
+					 auth->auth_context_id,
 					 pauth_blob,
 					 &auth_info);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -1957,30 +2082,45 @@ static void rpc_pipe_bind_step_one_done(
 		rpc_pipe_bind_step_two_trigger(req);
 		return;
 
-	case DCERPC_AUTH_TYPE_NTLMSSP:
-	case DCERPC_AUTH_TYPE_SPNEGO:
-	case DCERPC_AUTH_TYPE_KRB5:
-		/* Paranoid lenght checks */
-		if (pkt->frag_length < DCERPC_AUTH_TRAILER_LENGTH
-						+ pkt->auth_length) {
-			tevent_req_nterror(req,
-					NT_STATUS_INFO_LENGTH_MISMATCH);
+	default:
+		if (pkt->auth_length == 0) {
+			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
 			return;
 		}
 		/* get auth credentials */
-		status = dcerpc_pull_dcerpc_auth(talloc_tos(),
-						 &pkt->u.bind_ack.auth_info,
-						 &auth, false);
+		status = dcerpc_pull_auth_trailer(pkt, talloc_tos(),
+						  &pkt->u.bind_ack.auth_info,
+						  &auth, NULL, true);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(0, ("Failed to pull dcerpc auth: %s.\n",
 				  nt_errstr(status)));
 			tevent_req_nterror(req, status);
 			return;
 		}
-		break;
 
-	default:
-		goto err_out;
+		if (auth.auth_type != pauth->auth_type) {
+			DEBUG(0, (__location__ " Auth type %u mismatch expected %u.\n",
+				  auth.auth_type, pauth->auth_type));
+			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+			return;
+		}
+
+		if (auth.auth_level != pauth->auth_level) {
+			DEBUG(0, (__location__ " Auth level %u mismatch expected %u.\n",
+				  auth.auth_level, pauth->auth_level));
+			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+			return;
+		}
+
+		if (auth.auth_context_id != pauth->auth_context_id) {
+			DEBUG(0, (__location__ " Auth context id %u mismatch expected %u.\n",
+				  (unsigned)auth.auth_context_id,
+				  (unsigned)pauth->auth_context_id));
+			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+			return;
+		}
+
+		break;
 	}
 
 	/*
@@ -2226,9 +2366,7 @@ static NTSTATUS rpc_bind_next_send(struc
 	/* Now prepare the alter context pdu. */
 	data_blob_free(&state->rpc_out);
 
-	status = create_rpc_alter_context(state,
-					  auth->auth_type,
-					  auth->auth_level,
+	status = create_rpc_alter_context(state, auth,
 					  state->rpc_call_id,
 					  &state->cli->abstract_syntax,
 					  &state->cli->transfer_syntax,
@@ -2261,10 +2399,8 @@ static NTSTATUS rpc_bind_finish_send(str
 	/* Now prepare the auth3 context pdu. */
 	data_blob_free(&state->rpc_out);
 
-	status = create_rpc_bind_auth3(state, state->cli,
+	status = create_rpc_bind_auth3(state, state->cli, auth,
 					state->rpc_call_id,
-					auth->auth_type,
-					auth->auth_level,
 					auth_token,
 					&state->rpc_out);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -2498,8 +2634,9 @@ static struct tevent_req *rpccli_bh_disc
 	/*
 	 * TODO: do a real async disconnect ...
 	 *
-	 * For now the caller needs to free rpc_cli
+	 * For now we do it sync...
 	 */
+	TALLOC_FREE(hs->rpc_cli->transport);
 	hs->rpc_cli = NULL;
 
 	tevent_req_done(req);
@@ -2636,6 +2773,7 @@ NTSTATUS rpccli_ncalrpc_bind_data(TALLOC
 
 	result->auth_type = DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM;
 	result->auth_level = DCERPC_AUTH_LEVEL_CONNECT;
+	result->auth_context_id = 1;
 
 	result->user_name = talloc_strdup(result, "");
 	result->domain = talloc_strdup(result, "");
@@ -2660,6 +2798,7 @@ NTSTATUS rpccli_anon_bind_data(TALLOC_CT
 
 	result->auth_type = DCERPC_AUTH_TYPE_NONE;
 	result->auth_level = DCERPC_AUTH_LEVEL_NONE;
+	result->auth_context_id = 0;
 
 	result->user_name = talloc_strdup(result, "");
 	result->domain = talloc_strdup(result, "");
@@ -2697,6 +2836,7 @@ static NTSTATUS rpccli_ntlmssp_bind_data
 
 	result->auth_type = auth_type;
 	result->auth_level = auth_level;
+	result->auth_context_id = 1;
 
 	result->user_name = talloc_strdup(result, username);
 	result->domain = talloc_strdup(result, domain);
@@ -2768,6 +2908,7 @@ NTSTATUS rpccli_schannel_bind_data(TALLO
 
 	result->auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
 	result->auth_level = auth_level;
+	result->auth_context_id = 1;
 
 	result->user_name = talloc_strdup(result, "");
 	result->domain = talloc_strdup(result, domain);
@@ -3432,6 +3573,7 @@ NTSTATUS cli_rpc_pipe_open_krb5(struct c
 	}
 	auth->auth_type = DCERPC_AUTH_TYPE_KRB5;
 	auth->auth_level = auth_level;
+	auth->auth_context_id = 1;
 
 	if (!username) {
 		username = "";
@@ -3502,6 +3644,7 @@ NTSTATUS cli_rpc_pipe_open_spnego_krb5(s
 	}
 	auth->auth_type = DCERPC_AUTH_TYPE_SPNEGO;
 	auth->auth_level = auth_level;
+	auth->auth_context_id = 1;
 
 	if (!username) {
 		username = "";
@@ -3576,6 +3719,7 @@ NTSTATUS cli_rpc_pipe_open_spnego_ntlmss
 	}
 	auth->auth_type = DCERPC_AUTH_TYPE_SPNEGO;
 	auth->auth_level = auth_level;
+	auth->auth_context_id = 1;
 
 	if (!username) {
 		username = "";
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -46,7 +46,7 @@ bool dcesrv_auth_bind(struct dcesrv_call
 	NTSTATUS status;
 	uint32_t auth_length;
 
-	if (pkt->u.bind.auth_info.length == 0) {
+	if (pkt->auth_length == 0) {
 		dce_conn->auth_state.auth_info = NULL;
 		return true;
 	}
@@ -108,7 +108,7 @@ NTSTATUS dcesrv_auth_bind_ack(struct dce
 	struct dcesrv_connection *dce_conn = call->conn;
 	NTSTATUS status;
 
-	if (!call->conn->auth_state.gensec_security) {
+	if (call->pkt.auth_length == 0) {
 		return NT_STATUS_OK;
 	}
 
@@ -155,10 +155,16 @@ bool dcesrv_auth_auth3(struct dcesrv_cal
 	NTSTATUS status;
 	uint32_t auth_length;
 
-	/* We can't work without an existing gensec state, and an new blob to feed it */
-	if (!dce_conn->auth_state.auth_info ||
-	    !dce_conn->auth_state.gensec_security ||
-	    pkt->u.auth3.auth_info.length == 0) {
+	if (pkt->auth_length == 0) {
+		return false;
+	}
+
+	if (!dce_conn->auth_state.auth_info) {
+		return false;
+	}
+
+	/* We can't work without an existing gensec state */
+	if (!dce_conn->auth_state.gensec_security) {
 		return false;
 	}
 
@@ -203,7 +209,7 @@ bool dcesrv_auth_alter(struct dcesrv_cal
 	uint32_t auth_length;
 
 	/* on a pure interface change there is no auth blob */
-	if (pkt->u.alter.auth_info.length == 0) {
+	if (pkt->auth_length == 0) {
 		return true;
 	}
 
@@ -238,8 +244,7 @@ NTSTATUS dcesrv_auth_alter_ack(struct dc
 
 	/* on a pure interface change there is no auth_info structure
 	   setup */
-	if (!call->conn->auth_state.auth_info ||
-	    dce_conn->auth_state.auth_info->credentials.length == 0) {
+	if (call->pkt.auth_length == 0) {
 		return NT_STATUS_OK;
 	}
 
@@ -315,6 +320,11 @@ bool dcesrv_auth_request(struct dcesrv_c
 		return false;
 	}
 
+	if (pkt->auth_length == 0) {
+		DEBUG(1,("dcesrv_auth_request: unexpected auth_length of 0\n"));
+		return false;
+	}
+
 	status = dcerpc_pull_auth_trailer(pkt, call,
 					  &pkt->u.request.stub_and_verifier,
 					  &auth, &auth_length, false);
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -701,6 +701,14 @@ static NTSTATUS ncacn_pull_request_auth(
 		return NT_STATUS_INVALID_LEVEL;
 	}
 
+	if (pkt->auth_length == 0) {
+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
+	}
+
+	if (c->security_state.generic_state == NULL) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
 	status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
 					  &pkt->u.response.stub_and_verifier,
 					  &auth, &auth_length, false);
@@ -1074,7 +1082,7 @@ static void dcerpc_bind_recv_handler(str
 	}
 
 	/* the bind_ack might contain a reply set of credentials */
-	if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
+	if (conn->security_state.auth_info && pkt->auth_length) {
 		NTSTATUS status;
 		uint32_t auth_length;
 		status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
@@ -1847,8 +1855,7 @@ static void dcerpc_alter_recv_handler(st
 	}
 
 	/* the alter_resp might contain a reply set of credentials */
-	if (recv_pipe->conn->security_state.auth_info &&
-	    pkt->u.alter_resp.auth_info.length) {
+	if (recv_pipe->conn->security_state.auth_info && pkt->auth_length) {
 		struct dcecli_connection *conn = recv_pipe->conn;
 		NTSTATUS status;
 		uint32_t auth_length;
--- a/source3/librpc/rpc/dcerpc.h
+++ b/source3/librpc/rpc/dcerpc.h
@@ -42,6 +42,7 @@ struct pipe_auth_data {
 	bool verified_bitmask1;
 
 	void *auth_ctx;
+	uint32_t auth_context_id;
 
 	/* Only the client code uses these 3 for now */
 	char *domain;
@@ -71,10 +72,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_
 				 uint32_t auth_context_id,
 				 const DATA_BLOB *credentials,
 				 DATA_BLOB *blob);
-NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx,
-				 const DATA_BLOB *blob,
-				 struct dcerpc_auth *r,
-				 bool bigendian);
 NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth,
 			    size_t header_len, size_t data_left,
 			    size_t max_xmit_frag, size_t pad_alignment,
@@ -85,9 +82,8 @@ NTSTATUS dcerpc_add_auth_footer(struct p
 NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
 			   struct ncacn_packet *pkt,
 			   DATA_BLOB *pkt_trailer,
-			   size_t header_size,
-			   DATA_BLOB *raw_pkt,
-			   size_t *pad_len);
+			   uint8_t header_size,
+			   DATA_BLOB *raw_pkt);
 
 /* The following definitions come from librpc/rpc/rpc_common.c  */
 
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -42,6 +42,7 @@
 #include "auth.h"
 #include "ntdomain.h"
 #include "rpc_server/srv_pipe.h"
+#include "../librpc/gen_ndr/ndr_dcerpc.h"
 #include "../librpc/ndr/ndr_dcerpc.h"
 
 #undef DBGC_CLASS
@@ -270,10 +271,14 @@ static bool setup_bind_nak(struct pipes_
 	p->out_data.data_sent_length = 0;
 	p->out_data.current_pdu_sent = 0;
 
+	set_incoming_fault(p);
 	TALLOC_FREE(p->auth.auth_ctx);
 	p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE;
 	p->auth.auth_type = DCERPC_AUTH_TYPE_NONE;
 	p->pipe_bound = False;
+	p->allow_bind = false;
+	p->allow_alter = false;
+	p->allow_auth3 = false;
 
 	return True;
 }
@@ -339,16 +344,46 @@ static bool check_bind_req(struct pipes_
 	DEBUG(3,("check_bind_req for %s\n",
 		 get_pipe_name_from_syntax(talloc_tos(), abstract)));
 
+	ok = ndr_syntax_id_equal(transfer, &ndr_transfer_syntax);
+	if (!ok) {
+		DEBUG(1,("check_bind_req unknown transfer syntax for "
+			 "%s context_id=%u\n",
+			 get_pipe_name_from_syntax(talloc_tos(), abstract),
+			 (unsigned)context_id));
+		return false;
+	}
+
+	for (context_fns = p->contexts;
+	     context_fns != NULL;
+	     context_fns = context_fns->next)
+	{
+		if (context_fns->context_id != context_id) {
+			continue;
+		}
+
+		ok = ndr_syntax_id_equal(&context_fns->syntax,
+					 abstract);
+		if (ok) {
+			return true;
+		}
+
+		DEBUG(1,("check_bind_req: changing abstract syntax for "
+			 "%s context_id=%u into %s not supported\n",
+			 get_pipe_name_from_syntax(talloc_tos(), &context_fns->syntax),
+			 (unsigned)context_id,
+			 get_pipe_name_from_syntax(talloc_tos(), abstract)));
+		return false;
+	}
+
 	/* we have to check all now since win2k introduced a new UUID on the lsaprpc pipe */
-	if (rpc_srv_pipe_exists_by_id(abstract) &&
-	   ndr_syntax_id_equal(transfer, &ndr_transfer_syntax)) {
-		DEBUG(3, ("check_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n",
-			rpc_srv_get_pipe_cli_name(abstract),
-			rpc_srv_get_pipe_srv_name(abstract)));
-	} else {
+	if (!rpc_srv_pipe_exists_by_id(abstract)) {
 		return false;
 	}
 
+	DEBUG(3, ("check_bind_req: %s -> %s rpc service\n",
+		  rpc_srv_get_pipe_cli_name(abstract),
+		  rpc_srv_get_pipe_srv_name(abstract)));
+
 	context_fns = SMB_MALLOC_P(struct pipe_rpc_fns);
 	if (context_fns == NULL) {
 		DEBUG(0,("check_bind_req: malloc() failed!\n"));
@@ -447,6 +482,7 @@ static bool pipe_spnego_auth_bind(struct
 
 	p->auth.auth_ctx = spnego_ctx;
 	p->auth.auth_type = DCERPC_AUTH_TYPE_SPNEGO;
+	p->auth.auth_context_id = auth_info->auth_context_id;
 
 	DEBUG(10, ("SPNEGO auth started\n"));
 
@@ -557,6 +593,7 @@ static bool pipe_schannel_auth_bind(stru
 	/* We're finished with this bind - no more packets. */
 	p->auth.auth_ctx = schannel_auth;
 	p->auth.auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
+	p->auth.auth_context_id = auth_info->auth_context_id;
 
 	p->pipe_bound = True;
 
@@ -601,6 +638,7 @@ static bool pipe_ntlmssp_auth_bind(struc
 
 	p->auth.auth_ctx = ntlmssp_state;
 	p->auth.auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
+	p->auth.auth_context_id = auth_info->auth_context_id;
 
 	DEBUG(10, (__location__ ": NTLMSSP auth started\n"));
 
@@ -776,6 +814,11 @@ static NTSTATUS pipe_auth_verify_final(s
 	void *mech_ctx;
 	NTSTATUS status;
 
+	if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) {
+		p->pipe_bound = true;
+		return NT_STATUS_OK;
+	}
+
 	switch (p->auth.auth_type) {
 	case DCERPC_AUTH_TYPE_NTLMSSP:
 		ntlmssp_ctx = talloc_get_type_abort(p->auth.auth_ctx,
@@ -867,16 +910,38 @@ static bool api_pipe_bind_req(struct pip
 	DATA_BLOB auth_resp = data_blob_null;
 	DATA_BLOB auth_blob = data_blob_null;
 
-	/* No rebinds on a bound pipe - use alter context. */
-	if (p->pipe_bound) {
-		DEBUG(2,("api_pipe_bind_req: rejecting bind request on bound "
-			 "pipe %s.\n",
-			 get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
+	if (!p->allow_bind) {
+		DEBUG(2,("Pipe not in allow bind state\n"));
 		return setup_bind_nak(p, pkt);
 	}
+	p->allow_bind = false;
+
+	status = dcerpc_verify_ncacn_packet_header(pkt,
+			DCERPC_PKT_BIND,
+			pkt->u.bind.auth_info.length,
+			0, /* required flags */
+			DCERPC_PFC_FLAG_FIRST |
+			DCERPC_PFC_FLAG_LAST |
+			DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+			0x08 | /* this is not defined, but should be ignored */
+			DCERPC_PFC_FLAG_CONC_MPX |
+			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+			DCERPC_PFC_FLAG_MAYBE |
+			DCERPC_PFC_FLAG_OBJECT_UUID);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("api_pipe_bind_req: invalid pdu: %s\n",
+			  nt_errstr(status)));
+		NDR_PRINT_DEBUG(ncacn_packet, pkt);
+		goto err_exit;
+	}
 
 	if (pkt->u.bind.num_contexts == 0) {
-		DEBUG(0, ("api_pipe_bind_req: no rpc contexts around\n"));
+		DEBUG(1, ("api_pipe_bind_req: no rpc contexts around\n"));
+		goto err_exit;
+	}
+
+	if (pkt->u.bind.ctx_list[0].num_transfer_syntaxes == 0) {
+		DEBUG(1, ("api_pipe_bind_req: no transfer syntaxes around\n"));
 		goto err_exit;
 	}
 
@@ -960,25 +1025,12 @@ static bool api_pipe_bind_req(struct pip
 	 * Check if this is an authenticated bind request.
 	 */
 	if (pkt->auth_length) {
-		/* Quick length check. Won't catch a bad auth footer,
-		 * prevents overrun. */
-
-		if (pkt->frag_length < RPC_HEADER_LEN +
-					DCERPC_AUTH_TRAILER_LENGTH +
-					pkt->auth_length) {
-			DEBUG(0,("api_pipe_bind_req: auth_len (%u) "
-				"too long for fragment %u.\n",
-				(unsigned int)pkt->auth_length,
-				(unsigned int)pkt->frag_length));
-			goto err_exit;
-		}
-
 		/*
 		 * Decode the authentication verifier.
 		 */
-		status = dcerpc_pull_dcerpc_auth(pkt,
-						 &pkt->u.bind.auth_info,
-						 &auth_info, p->endian);
+		status = dcerpc_pull_auth_trailer(pkt, pkt,
+						  &pkt->u.bind.auth_info,
+						  &auth_info, NULL, true);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n"));
 			goto err_exit;
@@ -1072,6 +1124,7 @@ static bool api_pipe_bind_req(struct pip
 		p->pipe_bound = True;
 		/* The session key was initialized from the SMB
 		 * session in make_internal_rpc_pipe_p */
+		p->auth.auth_context_id = 0;
 	}
 
 	ZERO_STRUCT(u.bind_ack);
@@ -1113,15 +1166,15 @@ static bool api_pipe_bind_req(struct pip
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n",
 			  nt_errstr(status)));
+		goto err_exit;
 	}
 
 	if (auth_resp.length) {
-
 		status = dcerpc_push_dcerpc_auth(pkt,
 						 auth_type,
 						 auth_info.auth_level,
-						 0,
-						 1, /* auth_context_id */
+						 0, /* pad_len */
+						 p->auth.auth_context_id,
 						 &auth_resp,
 						 &auth_blob);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -1152,6 +1205,22 @@ static bool api_pipe_bind_req(struct pip
 	p->out_data.current_pdu_sent = 0;
 
 	TALLOC_FREE(auth_blob.data);
+
+	if (bind_ack_ctx.result == 0) {
+		p->allow_alter = true;
+		p->allow_auth3 = true;
+		if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) {
+			status = pipe_auth_verify_final(p);
+			if (!NT_STATUS_IS_OK(status)) {
+				DEBUG(0, ("pipe_auth_verify_final failed: %s\n",
+					  nt_errstr(status)));
+				goto err_exit;
+			}
+		}
+	} else {
+		goto err_exit;
+	}
+
 	return True;
 
   err_exit:
@@ -1176,18 +1245,39 @@ bool api_pipe_bind_auth3(struct pipes_st
 
 	DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__));
 
-	if (pkt->auth_length == 0) {
-		DEBUG(0, ("No auth field sent for bind request!\n"));
+	if (!p->allow_auth3) {
+		DEBUG(1, ("Pipe not in allow auth3 state.\n"));
 		goto err;
 	}
 
-	/* Ensure there's enough data for an authenticated request. */
-	if (pkt->frag_length < RPC_HEADER_LEN
-				+ DCERPC_AUTH_TRAILER_LENGTH
-				+ pkt->auth_length) {
-			DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len "
-				"%u is too large.\n",
-                        (unsigned int)pkt->auth_length));
+	status = dcerpc_verify_ncacn_packet_header(pkt,
+			DCERPC_PKT_AUTH3,
+			pkt->u.auth3.auth_info.length,
+			0, /* required flags */
+			DCERPC_PFC_FLAG_FIRST |
+			DCERPC_PFC_FLAG_LAST |
+			DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+			0x08 | /* this is not defined, but should be ignored */
+			DCERPC_PFC_FLAG_CONC_MPX |
+			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+			DCERPC_PFC_FLAG_MAYBE |
+			DCERPC_PFC_FLAG_OBJECT_UUID);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("api_pipe_bind_auth3: invalid pdu: %s\n",
+			  nt_errstr(status)));
+		NDR_PRINT_DEBUG(ncacn_packet, pkt);
+		goto err;
+	}
+
+	/* We can only finish if the pipe is unbound for now */
+	if (p->pipe_bound) {
+		DEBUG(0, (__location__ ": Pipe already bound, "
+			  "AUTH3 not supported!\n"));
+		goto err;
+	}
+
+	if (pkt->auth_length == 0) {
+		DEBUG(1, ("No auth field sent for auth3 request!\n"));
 		goto err;
 	}
 
@@ -1195,9 +1285,9 @@ bool api_pipe_bind_auth3(struct pipes_st
 	 * Decode the authentication verifier response.
 	 */
 
-	status = dcerpc_pull_dcerpc_auth(pkt,
-					 &pkt->u.auth3.auth_info,
-					 &auth_info, p->endian);
+	status = dcerpc_pull_auth_trailer(pkt, pkt,
+					  &pkt->u.auth3.auth_info,
+					  &auth_info, NULL, true);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("Failed to unmarshall dcerpc_auth.\n"));
 		goto err;
@@ -1215,6 +1305,21 @@ bool api_pipe_bind_auth3(struct pipes_st
 		goto err;
 	}
 
+	if (auth_info.auth_level != p->auth.auth_level) {
+		DEBUG(1, ("Auth level mismatch! Client sent %d, "
+			  "but auth was started as level %d!\n",
+			  auth_info.auth_level, p->auth.auth_level));
+		goto err;
+	}
+
+	if (auth_info.auth_context_id != p->auth.auth_context_id) {
+		DEBUG(0, ("Auth context id mismatch! Client sent %u, "
+			  "but auth was started as level %u!\n",
+			  (unsigned)auth_info.auth_context_id,
+			  (unsigned)p->auth.auth_context_id));
+		goto err;
+	}
+
 	switch (auth_info.auth_type) {
 	case DCERPC_AUTH_TYPE_NTLMSSP:
 		ntlmssp_ctx = talloc_get_type_abort(p->auth.auth_ctx,
@@ -1267,6 +1372,10 @@ bool api_pipe_bind_auth3(struct pipes_st
 	return true;
 
 err:
+	p->pipe_bound = false;
+	p->allow_bind = false;
+	p->allow_alter = false;
+	p->allow_auth3 = false;
 
 	TALLOC_FREE(p->auth.auth_ctx);
 	return false;
@@ -1284,7 +1393,7 @@ static bool api_pipe_alter_context(struc
 	uint16 assoc_gid;
 	NTSTATUS status;
 	union dcerpc_payload u;
-	struct dcerpc_ack_ctx bind_ack_ctx;
+	struct dcerpc_ack_ctx alter_ack_ctx;
 	DATA_BLOB auth_resp = data_blob_null;
 	DATA_BLOB auth_blob = data_blob_null;
 	int pad_len = 0;
@@ -1294,8 +1403,42 @@ static bool api_pipe_alter_context(struc
 
 	DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__));
 
-	if (pkt->u.bind.assoc_group_id != 0) {
-		assoc_gid = pkt->u.bind.assoc_group_id;
+	if (!p->allow_alter) {
+		DEBUG(1, ("Pipe not in allow alter state.\n"));
+		goto err_exit;
+	}
+
+	status = dcerpc_verify_ncacn_packet_header(pkt,
+			DCERPC_PKT_ALTER,
+			pkt->u.alter.auth_info.length,
+			0, /* required flags */
+			DCERPC_PFC_FLAG_FIRST |
+			DCERPC_PFC_FLAG_LAST |
+			DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+			0x08 | /* this is not defined, but should be ignored */
+			DCERPC_PFC_FLAG_CONC_MPX |
+			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+			DCERPC_PFC_FLAG_MAYBE |
+			DCERPC_PFC_FLAG_OBJECT_UUID);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("api_pipe_alter_context: invalid pdu: %s\n",
+			  nt_errstr(status)));
+		NDR_PRINT_DEBUG(ncacn_packet, pkt);
+		goto err_exit;
+	}
+
+	if (pkt->u.alter.num_contexts == 0) {
+		DEBUG(1, ("api_pipe_alter_context: no rpc contexts around\n"));
+		goto err_exit;
+	}
+
+	if (pkt->u.alter.ctx_list[0].num_transfer_syntaxes == 0) {
+		DEBUG(1, ("api_pipe_alter_context: no transfer syntaxes around\n"));
+		goto err_exit;
+	}
+
+	if (pkt->u.alter.assoc_group_id != 0) {
+		assoc_gid = pkt->u.alter.assoc_group_id;
 	} else {
 		assoc_gid = 0x53f0;
 	}
@@ -1305,59 +1448,45 @@ static bool api_pipe_alter_context(struc
 	 */
 
 	/* If the requested abstract synt uuid doesn't match our client pipe,
-		reject the bind_ack & set the transfer interface synt to all 0's,
+		reject the alter_ack & set the transfer interface synt to all 0's,
 		ver 0 (observed when NT5 attempts to bind to abstract interfaces
 		unknown to NT4)
 		Needed when adding entries to a DACL from NT5 - SK */
 
 	if (check_bind_req(p,
-			&pkt->u.bind.ctx_list[0].abstract_syntax,
-			&pkt->u.bind.ctx_list[0].transfer_syntaxes[0],
-			pkt->u.bind.ctx_list[0].context_id)) {
-
-		bind_ack_ctx.result = 0;
-		bind_ack_ctx.reason = 0;
-		bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0];
+			&pkt->u.alter.ctx_list[0].abstract_syntax,
+			&pkt->u.alter.ctx_list[0].transfer_syntaxes[0],
+			pkt->u.alter.ctx_list[0].context_id)) {
+
+		alter_ack_ctx.result = 0;
+		alter_ack_ctx.reason = 0;
+		alter_ack_ctx.syntax = pkt->u.alter.ctx_list[0].transfer_syntaxes[0];
 	} else {
-		p->pipe_bound = False;
 		/* Rejection reason: abstract syntax not supported */
-		bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
-		bind_ack_ctx.reason = DCERPC_BIND_REASON_ASYNTAX;
-		bind_ack_ctx.syntax = null_ndr_syntax_id;
+		alter_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
+		alter_ack_ctx.reason = DCERPC_BIND_REASON_ASYNTAX;
+		alter_ack_ctx.syntax = null_ndr_syntax_id;
 	}
 
 	/*
 	 * Check if this is an authenticated alter context request.
 	 */
 	if (pkt->auth_length) {
-		/* Quick length check. Won't catch a bad auth footer,
-		 * prevents overrun. */
-
-		if (pkt->frag_length < RPC_HEADER_LEN +
-					DCERPC_AUTH_TRAILER_LENGTH +
-					pkt->auth_length) {
-			DEBUG(0,("api_pipe_alter_context: auth_len (%u) "
-				"too long for fragment %u.\n",
-				(unsigned int)pkt->auth_length,
-				(unsigned int)pkt->frag_length ));
+		/* We can only finish if the pipe is unbound for now */
+		if (p->pipe_bound) {
+			DEBUG(0, (__location__ ": Pipe already bound, "
+				  "Altering Context not yet supported!\n"));
 			goto err_exit;
 		}
 
-		status = dcerpc_pull_dcerpc_auth(pkt,
-						 &pkt->u.bind.auth_info,
-						 &auth_info, p->endian);
+		status = dcerpc_pull_auth_trailer(pkt, pkt,
+						  &pkt->u.alter.auth_info,
+						  &auth_info, NULL, true);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n"));
 			goto err_exit;
 		}
 
-		/* We can only finish if the pipe is unbound for now */
-		if (p->pipe_bound) {
-			DEBUG(0, (__location__ ": Pipe already bound, "
-				  "Altering Context not yet supported!\n"));
-			goto err_exit;
-		}
-
 		if (auth_info.auth_type != p->auth.auth_type) {
 			DEBUG(0, ("Auth type mismatch! Client sent %d, "
 				  "but auth was started as type %d!\n",
@@ -1365,6 +1494,20 @@ static bool api_pipe_alter_context(struc
 			goto err_exit;
 		}
 
+		if (auth_info.auth_level != p->auth.auth_level) {
+			DEBUG(0, ("Auth level mismatch! Client sent %d, "
+				  "but auth was started as level %d!\n",
+				  auth_info.auth_level, p->auth.auth_level));
+			goto err_exit;
+		}
+
+		if (auth_info.auth_context_id != p->auth.auth_context_id) {
+			DEBUG(0, ("Auth context id mismatch! Client sent %u, "
+				  "but auth was started as level %u!\n",
+				  (unsigned)auth_info.auth_context_id,
+				  (unsigned)p->auth.auth_context_id));
+			goto err_exit;
+		}
 
 		switch (auth_info.auth_type) {
 		case DCERPC_AUTH_TYPE_SPNEGO:
@@ -1431,7 +1574,7 @@ static bool api_pipe_alter_context(struc
 	u.alter_resp.secondary_address_size = 1;
 
 	u.alter_resp.num_results = 1;
-	u.alter_resp.ctx_list = &bind_ack_ctx;
+	u.alter_resp.ctx_list = &alter_ack_ctx;
 
 	/* NOTE: We leave the auth_info empty so we can calculate the padding
 	 * later and then append the auth_info --simo */
@@ -1451,8 +1594,9 @@ static bool api_pipe_alter_context(struc
 					  &u,
 					  &p->out_data.frag);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n",
+		DEBUG(0, ("Failed to marshall alter_resp packet. (%s)\n",
 			  nt_errstr(status)));
+		goto err_exit;
 	}
 
 	if (auth_resp.length) {
@@ -1469,7 +1613,7 @@ static bool api_pipe_alter_context(struc
 						 auth_info.auth_type,
 						 auth_info.auth_level,
 						 pad_len,
-						 1, /* auth_context_id */
+						 p->auth.auth_context_id,
 						 &auth_resp,
 						 &auth_blob);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -1618,6 +1762,7 @@ static bool api_pipe_request(struct pipe
 
 	if (!srv_pipe_check_verification_trailer(p, pkt, pipe_fns)) {
 		DEBUG(1, ("srv_pipe_check_verification_trailer: failed\n"));
+		set_incoming_fault(p);
 		setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED));
 		data_blob_free(&p->out_data.rdata);
 		TALLOC_FREE(frame);
@@ -1756,7 +1901,11 @@ void set_incoming_fault(struct pipes_str
 	data_blob_free(&p->in_data.data);
 	p->in_data.pdu_needed_len = 0;
 	p->in_data.pdu.length = 0;
-	p->fault_state = DCERPC_FAULT_CANT_PERFORM;
+	p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
+
+	p->allow_alter = false;
+	p->allow_auth3 = false;
+	p->pipe_bound = false;
 
 	DEBUG(10, ("Setting fault state\n"));
 }
@@ -1767,7 +1916,6 @@ static NTSTATUS dcesrv_auth_request(stru
 {
 	NTSTATUS status;
 	size_t hdr_size = DCERPC_REQUEST_LENGTH;
-	size_t pad_len;
 
 	DEBUG(10, ("Checking request auth.\n"));
 
@@ -1778,25 +1926,11 @@ static NTSTATUS dcesrv_auth_request(stru
 	/* in case of sealing this function will unseal the data in place */
 	status = dcerpc_check_auth(auth, pkt,
 				   &pkt->u.request.stub_and_verifier,
-				   hdr_size, raw_pkt,
-				   &pad_len);
+				   hdr_size, raw_pkt);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
 
-
-	/* remove padding and auth trailer,
-	 * this way the caller will get just the data */
-	if (pkt->auth_length) {
-		size_t trail_len = pad_len
-					+ DCERPC_AUTH_TRAILER_LENGTH
-					+ pkt->auth_length;
-		if (pkt->u.request.stub_and_verifier.length < trail_len) {
-			return NT_STATUS_INFO_LENGTH_MISMATCH;
-		}
-		pkt->u.request.stub_and_verifier.length -= trail_len;
-	}
-
 	return NT_STATUS_OK;
 }
 
@@ -1816,6 +1950,29 @@ static bool process_request_pdu(struct p
 		return False;
 	}
 
+	/*
+	 * We don't ignore DCERPC_PFC_FLAG_PENDING_CANCEL.
+	 * TODO: we can reject it with DCERPC_FAULT_NO_CALL_ACTIVE later.
+	 */
+	status = dcerpc_verify_ncacn_packet_header(pkt,
+			DCERPC_PKT_REQUEST,
+			pkt->u.request.stub_and_verifier.length,
+			0, /* required_flags */
+			DCERPC_PFC_FLAG_FIRST |
+			DCERPC_PFC_FLAG_LAST |
+			0x08 | /* this is not defined, but should be ignored */
+			DCERPC_PFC_FLAG_CONC_MPX |
+			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+			DCERPC_PFC_FLAG_MAYBE |
+			DCERPC_PFC_FLAG_OBJECT_UUID);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("process_request_pdu: invalid pdu: %s\n",
+			  nt_errstr(status)));
+		NDR_PRINT_DEBUG(ncacn_packet, pkt);
+		set_incoming_fault(p);
+		return false;
+	}
+
 	/* Store the opnum */
 	p->opnum = pkt->u.request.opnum;
 
@@ -2065,7 +2222,7 @@ done:
 			 "pipe %s\n", get_pipe_name_from_syntax(talloc_tos(),
 								&p->syntax)));
 		set_incoming_fault(p);
-		setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
+		setup_fault_pdu(p, NT_STATUS(DCERPC_NCA_S_PROTO_ERROR));
 		TALLOC_FREE(pkt);
 	} else {
 		/*
--- a/source3/include/ntdomain.h
+++ b/source3/include/ntdomain.h
@@ -135,6 +135,13 @@ struct pipes_struct {
 	bool pipe_bound;
 
 	/*
+	 * States we can be in.
+	 */
+	bool allow_alter;
+	bool allow_bind;
+	bool allow_auth3;
+
+	/*
 	 * Set the DCERPC_FAULT to return.
 	 */
 
--- a/source3/rpc_server/rpc_ncacn_np.c
+++ b/source3/rpc_server/rpc_ncacn_np.c
@@ -171,6 +171,7 @@ struct pipes_struct *make_internal_rpc_p
 
 	p->syntax = *syntax;
 	p->transport = NCALRPC;
+	p->allow_bind = true;
 
 	DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n",
 		 get_pipe_name_from_syntax(talloc_tos(), syntax), pipes_open));
@@ -780,6 +781,7 @@ static NTSTATUS rpc_pipe_open_external(T
 	}
 	result->auth->auth_type = DCERPC_AUTH_TYPE_NONE;
 	result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
+	result->auth->auth_context_id = 0;
 
 	status = rpccli_anon_bind_data(result, &auth);
 	if (!NT_STATUS_IS_OK(status)) {
--- a/source3/rpc_server/rpc_server.c
+++ b/source3/rpc_server/rpc_server.c
@@ -102,6 +102,7 @@ static int make_server_pipes_struct(TALL
 	p->syntax = id;
 	p->transport = transport;
 	p->ncalrpc_as_system = ncalrpc_as_system;
+	p->allow_bind = true;
 
 	p->mem_ctx = talloc_named(p, 0, "pipe %s %p", pipe_name, p);
 	if (!p->mem_ctx) {
@@ -663,6 +664,12 @@ static void named_pipe_packet_done(struc
 		goto fail;
 	}
 
+	if (npc->p->fault_state != 0) {
+		DEBUG(2, ("Disconnect after fault\n"));
+		sys_errno = EINVAL;
+		goto fail;
+	}
+
 	/* clear out any data that may have been left around */
 	npc->count = 0;
 	TALLOC_FREE(npc->iov);
@@ -1391,6 +1398,12 @@ static void dcerpc_ncacn_packet_done(str
 		goto fail;
 	}
 
+	if (ncacn_conn->p->fault_state != 0) {
+		DEBUG(2, ("Disconnect after fault\n"));
+		sys_errno = EINVAL;
+		goto fail;
+	}
+
 	/* clear out any data that may have been left around */
 	ncacn_conn->count = 0;
 	TALLOC_FREE(ncacn_conn->iov);
