1From 8716bb5e03cc4f10e2d4edc704d8defe7e8045f1 Mon Sep 17 00:00:00 2001
2From: Stefan Metzmacher <metze@samba.org>
3Date: Thu, 16 Jul 2015 22:46:05 +0200
4Subject: [PATCH 01/40] CVE-2015-5370: dcerpc.idl: add
5 DCERPC_{NCACN_PAYLOAD,FRAG}_MAX_SIZE defines
6MIME-Version: 1.0
7Content-Type: text/plain; charset=UTF-8
8Content-Transfer-Encoding: 8bit
9
10BUG: https://bugzilla.samba.org/show_bug.cgi?id=11344
11
12Signed-off-by: Stefan Metzmacher <metze@samba.org>
13Reviewed-by: G��nther Deschner <gd@samba.org>
14---
15 librpc/idl/dcerpc.idl | 2 ++
16 1 file changed, 2 insertions(+)
17
18--- a/librpc/idl/dcerpc.idl
19+++ b/librpc/idl/dcerpc.idl
20@@ -475,9 +475,11 @@ interface dcerpc
21 	const uint8 DCERPC_PFC_OFFSET      =  3;
22 	const uint8 DCERPC_DREP_OFFSET     =  4;
23 	const uint8 DCERPC_FRAG_LEN_OFFSET =  8;
24+	const uint32 DCERPC_FRAG_MAX_SIZE  = 5840;
25 	const uint8 DCERPC_AUTH_LEN_OFFSET = 10;
26 	const uint8 DCERPC_CALL_ID_OFFSET  = 12;
27 	const uint8 DCERPC_NCACN_PAYLOAD_OFFSET = 16;
28+	const uint32 DCERPC_NCACN_PAYLOAD_MAX_SIZE = 0x400000; /* 4 MByte */
29 
30 	/* little-endian flag */
31 	const uint8 DCERPC_DREP_LE  = 0x10;
32--- a/librpc/rpc/dcerpc_util.c
33+++ b/librpc/rpc/dcerpc_util.c
34@@ -92,31 +92,49 @@ uint8_t dcerpc_get_endian_flag(DATA_BLOB
35 *
36 * @return		- A NTSTATUS error code.
37 */
38-NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
39+NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
40 				  TALLOC_CTX *mem_ctx,
41-				  DATA_BLOB *pkt_trailer,
42+				  const DATA_BLOB *pkt_trailer,
43 				  struct dcerpc_auth *auth,
44-				  uint32_t *auth_length,
45+				  uint32_t *_auth_length,
46 				  bool auth_data_only)
47 {
48 	struct ndr_pull *ndr;
49 	enum ndr_err_code ndr_err;
50-	uint32_t data_and_pad;
51+	uint16_t data_and_pad;
52+	uint16_t auth_length;
53+	uint32_t tmp_length;
54 
55-	data_and_pad = pkt_trailer->length
56-			- (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length);
57+	ZERO_STRUCTP(auth);
58+	if (_auth_length != NULL) {
59+		*_auth_length = 0;
60+	}
61+
62+	/* Paranoia checks for auth_length. The caller should check this... */
63+	if (pkt->auth_length == 0) {
64+		return NT_STATUS_INTERNAL_ERROR;
65+	}
66+
67+	/* Paranoia checks for auth_length. The caller should check this... */
68+	if (pkt->auth_length > pkt->frag_length) {
69+		return NT_STATUS_INTERNAL_ERROR;
70+	}
71+	tmp_length = DCERPC_NCACN_PAYLOAD_OFFSET;
72+	tmp_length += DCERPC_AUTH_TRAILER_LENGTH;
73+	tmp_length += pkt->auth_length;
74+	if (tmp_length > pkt->frag_length) {
75+		return NT_STATUS_INTERNAL_ERROR;
76+	}
77+	if (pkt_trailer->length > UINT16_MAX) {
78+		return NT_STATUS_INTERNAL_ERROR;
79+	}
80 
81-	/* paranoia check for pad size. This would be caught anyway by
82-	   the ndr_pull_advance() a few lines down, but it scared
83-	   Jeremy enough for him to call me, so we might as well check
84-	   it now, just to prevent someone posting a bogus YouTube
85-	   video in the future.
86-	*/
87-	if (data_and_pad > pkt_trailer->length) {
88-		return NT_STATUS_INFO_LENGTH_MISMATCH;
89+	auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length;
90+	if (pkt_trailer->length < auth_length) {
91+		return NT_STATUS_RPC_PROTOCOL_ERROR;
92 	}
93 
94-	*auth_length = pkt_trailer->length - data_and_pad;
95+	data_and_pad = pkt_trailer->length - auth_length;
96 
97 	ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx);
98 	if (!ndr) {
99@@ -136,14 +154,28 @@ NTSTATUS dcerpc_pull_auth_trailer(struct
100 	ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth);
101 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
102 		talloc_free(ndr);
103+		ZERO_STRUCTP(auth);
104 		return ndr_map_error2ntstatus(ndr_err);
105 	}
106 
107+	if (data_and_pad < auth->auth_pad_length) {
108+		DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
109+			  "Calculated %u  got %u\n",
110+			  (unsigned)data_and_pad,
111+			  (unsigned)auth->auth_pad_length));
112+		talloc_free(ndr);
113+		ZERO_STRUCTP(auth);
114+		return NT_STATUS_RPC_PROTOCOL_ERROR;
115+	}
116+
117 	if (auth_data_only && data_and_pad != auth->auth_pad_length) {
118-		DEBUG(1, (__location__ ": WARNING: pad length mismatch. "
119+		DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
120 			  "Calculated %u  got %u\n",
121 			  (unsigned)data_and_pad,
122 			  (unsigned)auth->auth_pad_length));
123+		talloc_free(ndr);
124+		ZERO_STRUCTP(auth);
125+		return NT_STATUS_RPC_PROTOCOL_ERROR;
126 	}
127 
128 	DEBUG(6,(__location__ ": auth_pad_length %u\n",
129@@ -152,6 +184,83 @@ NTSTATUS dcerpc_pull_auth_trailer(struct
130 	talloc_steal(mem_ctx, auth->credentials.data);
131 	talloc_free(ndr);
132 
133+	if (_auth_length != NULL) {
134+		*_auth_length = auth_length;
135+	}
136+
137+	return NT_STATUS_OK;
138+}
139+
140+/**
141+* @brief	Verify the fields in ncacn_packet header.
142+*
143+* @param pkt		- The ncacn_packet strcuture
144+* @param ptype		- The expected PDU type
145+* @param max_auth_info	- The maximum size of a possible auth trailer
146+* @param required_flags	- The required flags for the pdu.
147+* @param optional_flags	- The possible optional flags for the pdu.
148+*
149+* @return		- A NTSTATUS error code.
150+*/
151+NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
152+					   enum dcerpc_pkt_type ptype,
153+					   size_t max_auth_info,
154+					   uint8_t required_flags,
155+					   uint8_t optional_flags)
156+{
157+	if (pkt->rpc_vers != 5) {
158+		return NT_STATUS_RPC_PROTOCOL_ERROR;
159+	}
160+
161+	if (pkt->rpc_vers_minor != 0) {
162+		return NT_STATUS_RPC_PROTOCOL_ERROR;
163+	}
164+
165+	if (pkt->auth_length > pkt->frag_length) {
166+		return NT_STATUS_RPC_PROTOCOL_ERROR;
167+	}
168+
169+	if (pkt->ptype != ptype) {
170+		return NT_STATUS_RPC_PROTOCOL_ERROR;
171+	}
172+
173+	if (max_auth_info > UINT16_MAX) {
174+		return NT_STATUS_INTERNAL_ERROR;
175+	}
176+
177+	if (pkt->auth_length > 0) {
178+		size_t max_auth_length;
179+
180+		if (max_auth_info <= DCERPC_AUTH_TRAILER_LENGTH) {
181+			return NT_STATUS_RPC_PROTOCOL_ERROR;
182+		}
183+		max_auth_length = max_auth_info - DCERPC_AUTH_TRAILER_LENGTH;
184+
185+		if (pkt->auth_length > max_auth_length) {
186+			return NT_STATUS_RPC_PROTOCOL_ERROR;
187+		}
188+	}
189+
190+	if ((pkt->pfc_flags & required_flags) != required_flags) {
191+		return NT_STATUS_RPC_PROTOCOL_ERROR;
192+	}
193+	if (pkt->pfc_flags & ~(optional_flags|required_flags)) {
194+		return NT_STATUS_RPC_PROTOCOL_ERROR;
195+	}
196+
197+	if (pkt->drep[0] & ~DCERPC_DREP_LE) {
198+		return NT_STATUS_RPC_PROTOCOL_ERROR;
199+	}
200+	if (pkt->drep[1] != 0) {
201+		return NT_STATUS_RPC_PROTOCOL_ERROR;
202+	}
203+	if (pkt->drep[2] != 0) {
204+		return NT_STATUS_RPC_PROTOCOL_ERROR;
205+	}
206+	if (pkt->drep[3] != 0) {
207+		return NT_STATUS_RPC_PROTOCOL_ERROR;
208+	}
209+
210 	return NT_STATUS_OK;
211 }
212 
213--- a/librpc/rpc/rpc_common.h
214+++ b/librpc/rpc/rpc_common.h
215@@ -158,12 +158,17 @@ uint8_t dcerpc_get_endian_flag(DATA_BLOB
216 *
217 * @return		- A NTSTATUS error code.
218 */
219-NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
220+NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
221 				  TALLOC_CTX *mem_ctx,
222-				  DATA_BLOB *pkt_trailer,
223+				  const DATA_BLOB *pkt_trailer,
224 				  struct dcerpc_auth *auth,
225 				  uint32_t *auth_length,
226 				  bool auth_data_only);
227+NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
228+					   enum dcerpc_pkt_type ptype,
229+					   size_t max_auth_info,
230+					   uint8_t required_flags,
231+					   uint8_t optional_flags);
232 struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
233 						 struct tevent_context *ev,
234 						 struct tstream_context *stream);
235--- a/source3/librpc/rpc/dcerpc_helpers.c
236+++ b/source3/librpc/rpc/dcerpc_helpers.c
237@@ -210,47 +210,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_
238 }
239 
240 /**
241-* @brief Decodes a dcerpc_auth blob
242-*
243-* @param mem_ctx	The memory context on which to allocate the packet
244-*			elements
245-* @param blob		The blob of data to decode
246-* @param r		An empty dcerpc_auth structure, must not be NULL
247-*
248-* @return a NTSTATUS error code
249-*/
250-NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx,
251-				 const DATA_BLOB *blob,
252-				 struct dcerpc_auth *r,
253-				 bool bigendian)
254-{
255-	enum ndr_err_code ndr_err;
256-	struct ndr_pull *ndr;
257-
258-	ndr = ndr_pull_init_blob(blob, mem_ctx);
259-	if (!ndr) {
260-		return NT_STATUS_NO_MEMORY;
261-	}
262-	if (bigendian) {
263-		ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
264-	}
265-
266-	ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, r);
267-
268-	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
269-		talloc_free(ndr);
270-		return ndr_map_error2ntstatus(ndr_err);
271-	}
272-	talloc_free(ndr);
273-
274-	if (DEBUGLEVEL >= 10) {
275-		NDR_PRINT_DEBUG(dcerpc_auth, r);
276-	}
277-
278-	return NT_STATUS_OK;
279-}
280-
281-/**
282 * @brief Calculate how much data we can in a packet, including calculating
283 *	 auth token and pad lengths.
284 *
285@@ -782,7 +741,7 @@ NTSTATUS dcerpc_add_auth_footer(struct p
286 					 auth->auth_type,
287 					 auth->auth_level,
288 					 pad_len,
289-					 1 /* context id. */,
290+					 auth->auth_context_id,
291 					 &auth_blob,
292 					 &auth_info);
293 	if (!NT_STATUS_IS_OK(status)) {
294@@ -844,19 +803,18 @@ NTSTATUS dcerpc_add_auth_footer(struct p
295 *
296 * @param auth		The auth data for the connection
297 * @param pkt		The actual ncacn_packet
298-* @param pkt_trailer	The stub_and_verifier part of the packet
299+* @param pkt_trailer [in][out]	The stub_and_verifier part of the packet,
300+* 			the auth_trailer and padding will be removed.
301 * @param header_size	The header size
302 * @param raw_pkt	The whole raw packet data blob
303-* @param pad_len	[out] The padding length used in the packet
304 *
305 * @return A NTSTATUS error code
306 */
307 NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
308 			   struct ncacn_packet *pkt,
309 			   DATA_BLOB *pkt_trailer,
310-			   size_t header_size,
311-			   DATA_BLOB *raw_pkt,
312-			   size_t *pad_len)
313+			   uint8_t header_size,
314+			   DATA_BLOB *raw_pkt)
315 {
316 	struct schannel_state *schannel_auth;
317 	struct auth_ntlmssp_state *ntlmssp_ctx;
318@@ -868,6 +826,14 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
319 	DATA_BLOB full_pkt;
320 	DATA_BLOB data;
321 
322+	/*
323+	 * These check should be done in the caller.
324+	 */
325+	SMB_ASSERT(raw_pkt->length == pkt->frag_length);
326+	SMB_ASSERT(header_size <= pkt->frag_length);
327+	SMB_ASSERT(pkt_trailer->length < pkt->frag_length);
328+	SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length);
329+
330 	switch (auth->auth_level) {
331 	case DCERPC_AUTH_LEVEL_PRIVACY:
332 		DEBUG(10, ("Requested Privacy.\n"));
333@@ -881,7 +847,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
334 		if (pkt->auth_length != 0) {
335 			break;
336 		}
337-		*pad_len = 0;
338 		return NT_STATUS_OK;
339 
340 	case DCERPC_AUTH_LEVEL_NONE:
341@@ -890,7 +855,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
342 				  "authenticated connection!\n"));
343 			return NT_STATUS_INVALID_PARAMETER;
344 		}
345-		*pad_len = 0;
346 		return NT_STATUS_OK;
347 
348 	default:
349@@ -899,16 +863,8 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
350 		return NT_STATUS_INVALID_PARAMETER;
351 	}
352 
353-	/* Paranioa checks for auth_length. */
354-	if (pkt->auth_length > pkt->frag_length) {
355-		return NT_STATUS_INFO_LENGTH_MISMATCH;
356-	}
357-	if (((unsigned int)pkt->auth_length
358-	     + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) ||
359-	    ((unsigned int)pkt->auth_length
360-	     + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) {
361-		/* Integer wrap attempt. */
362-		return NT_STATUS_INFO_LENGTH_MISMATCH;
363+	if (pkt->auth_length == 0) {
364+		return NT_STATUS_INVALID_PARAMETER;
365 	}
366 
367 	status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
368@@ -917,10 +873,23 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
369 		return status;
370 	}
371 
372+	if (auth_info.auth_type != auth->auth_type) {
373+		return NT_STATUS_INVALID_PARAMETER;
374+	}
375+
376+	if (auth_info.auth_level != auth->auth_level) {
377+		return NT_STATUS_INVALID_PARAMETER;
378+	}
379+
380+	if (auth_info.auth_context_id != auth->auth_context_id) {
381+		return NT_STATUS_INVALID_PARAMETER;
382+	}
383+
384+	pkt_trailer->length -= auth_length;
385 	data = data_blob_const(raw_pkt->data + header_size,
386-				pkt_trailer->length - auth_length);
387-	full_pkt = data_blob_const(raw_pkt->data,
388-				raw_pkt->length - auth_info.credentials.length);
389+			       pkt_trailer->length);
390+	full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length);
391+	full_pkt.length -= auth_info.credentials.length;
392 
393 	switch (auth->auth_type) {
394 	case DCERPC_AUTH_TYPE_NONE:
395@@ -996,10 +965,13 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
396 	 * pkt_trailer actually has a copy of the raw data, and they
397 	 * are still both used in later calls */
398 	if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
399+		if (pkt_trailer->length != data.length) {
400+			return NT_STATUS_INVALID_PARAMETER;
401+		}
402 		memcpy(pkt_trailer->data, data.data, data.length);
403 	}
404 
405-	*pad_len = auth_info.auth_pad_length;
406+	pkt_trailer->length -= auth_info.auth_pad_length;
407 	data_blob_free(&auth_info.credentials);
408 	return NT_STATUS_OK;
409 }
410--- a/source3/rpc_client/cli_pipe.c
411+++ b/source3/rpc_client/cli_pipe.c
412@@ -404,9 +404,9 @@ static NTSTATUS cli_pipe_validate_curren
413 						DATA_BLOB *rdata,
414 						DATA_BLOB *reply_pdu)
415 {
416-	struct dcerpc_response *r;
417+	const struct dcerpc_response *r = NULL;
418+	DATA_BLOB tmp_stub = data_blob_null;
419 	NTSTATUS ret = NT_STATUS_OK;
420-	size_t pad_len = 0;
421 
422 	/*
423 	 * Point the return values at the real data including the RPC
424@@ -414,50 +414,128 @@ static NTSTATUS cli_pipe_validate_curren
425 	 */
426 	*rdata = *pdu;
427 
428+	if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
429+	    !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
430+		/*
431+		 * TODO: do we still need this hack which was introduced
432+		 * in commit a42afcdcc7ab9aa9ed193ae36d3dbb10843447f0.
433+		 *
434+		 * I don't even know what AS/U might be...
435+		 */
436+		DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
437+			  "fragment first/last ON.\n"));
438+		pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
439+	}
440+
441 	/* Ensure we have the correct type. */
442 	switch (pkt->ptype) {
443-	case DCERPC_PKT_ALTER_RESP:
444+	case DCERPC_PKT_BIND_NAK:
445+		DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
446+			  rpccli_pipe_txt(talloc_tos(), cli)));
447+
448+		ret = dcerpc_verify_ncacn_packet_header(pkt,
449+						DCERPC_PKT_BIND_NAK,
450+						0, /* max_auth_info */
451+						DCERPC_PFC_FLAG_FIRST |
452+						DCERPC_PFC_FLAG_LAST,
453+						0); /* optional flags */
454+		if (!NT_STATUS_IS_OK(ret)) {
455+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
456+				  "RPC packet type - %u, expected %u: %s\n",
457+				  rpccli_pipe_txt(talloc_tos(), cli),
458+				  pkt->ptype, expected_pkt_type,
459+				  nt_errstr(ret)));
460+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
461+			return ret;
462+		}
463+
464+		/* Use this for now... */
465+		return NT_STATUS_NETWORK_ACCESS_DENIED;
466+
467 	case DCERPC_PKT_BIND_ACK:
468+		ret = dcerpc_verify_ncacn_packet_header(pkt,
469+					expected_pkt_type,
470+					pkt->u.bind_ack.auth_info.length,
471+					DCERPC_PFC_FLAG_FIRST |
472+					DCERPC_PFC_FLAG_LAST,
473+					DCERPC_PFC_FLAG_CONC_MPX |
474+					DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
475+		if (!NT_STATUS_IS_OK(ret)) {
476+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
477+				  "RPC packet type - %u, expected %u: %s\n",
478+				  rpccli_pipe_txt(talloc_tos(), cli),
479+				  pkt->ptype, expected_pkt_type,
480+				  nt_errstr(ret)));
481+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
482+			return ret;
483+		}
484 
485-		/* Client code never receives this kind of packets */
486 		break;
487 
488+	case DCERPC_PKT_ALTER_RESP:
489+		ret = dcerpc_verify_ncacn_packet_header(pkt,
490+					expected_pkt_type,
491+					pkt->u.alter_resp.auth_info.length,
492+					DCERPC_PFC_FLAG_FIRST |
493+					DCERPC_PFC_FLAG_LAST,
494+					DCERPC_PFC_FLAG_CONC_MPX |
495+					DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
496+		if (!NT_STATUS_IS_OK(ret)) {
497+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
498+				  "RPC packet type - %u, expected %u: %s\n",
499+				  rpccli_pipe_txt(talloc_tos(), cli),
500+				  pkt->ptype, expected_pkt_type,
501+				  nt_errstr(ret)));
502+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
503+			return ret;
504+		}
505+
506+		break;
507 
508 	case DCERPC_PKT_RESPONSE:
509 
510 		r = &pkt->u.response;
511 
512+		ret = dcerpc_verify_ncacn_packet_header(pkt,
513+						expected_pkt_type,
514+						r->stub_and_verifier.length,
515+						0, /* required_flags */
516+						DCERPC_PFC_FLAG_FIRST |
517+						DCERPC_PFC_FLAG_LAST);
518+		if (!NT_STATUS_IS_OK(ret)) {
519+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
520+				  "RPC packet type - %u, expected %u: %s\n",
521+				  rpccli_pipe_txt(talloc_tos(), cli),
522+				  pkt->ptype, expected_pkt_type,
523+				  nt_errstr(ret)));
524+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
525+			return ret;
526+		}
527+
528+		tmp_stub.data = r->stub_and_verifier.data;
529+		tmp_stub.length = r->stub_and_verifier.length;
530+
531 		/* Here's where we deal with incoming sign/seal. */
532 		ret = dcerpc_check_auth(cli->auth, pkt,
533-					&r->stub_and_verifier,
534+					&tmp_stub,
535 					DCERPC_RESPONSE_LENGTH,
536-					pdu, &pad_len);
537+					pdu);
538 		if (!NT_STATUS_IS_OK(ret)) {
539+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
540+				  "RPC packet type - %u, expected %u: %s\n",
541+				  rpccli_pipe_txt(talloc_tos(), cli),
542+				  pkt->ptype, expected_pkt_type,
543+				  nt_errstr(ret)));
544+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
545 			return ret;
546 		}
547 
548-		if (pkt->frag_length < DCERPC_RESPONSE_LENGTH + pad_len) {
549-			return NT_STATUS_BUFFER_TOO_SMALL;
550-		}
551-
552 		/* Point the return values at the NDR data. */
553-		rdata->data = r->stub_and_verifier.data;
554+		*rdata = tmp_stub;
555 
556-		if (pkt->auth_length) {
557-			/* We've already done integer wrap tests in
558-			 * dcerpc_check_auth(). */
559-			rdata->length = r->stub_and_verifier.length
560-					 - pad_len
561-					 - DCERPC_AUTH_TRAILER_LENGTH
562-					 - pkt->auth_length;
563-		} else {
564-			rdata->length = r->stub_and_verifier.length;
565-		}
566-
567-		DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
568+		DEBUG(10, ("Got pdu len %lu, data_len %lu\n",
569 			   (long unsigned int)pdu->length,
570-			   (long unsigned int)rdata->length,
571-			   (unsigned int)pad_len));
572+			   (long unsigned int)rdata->length));
573 
574 		/*
575 		 * If this is the first reply, and the allocation hint is
576@@ -478,14 +556,24 @@ static NTSTATUS cli_pipe_validate_curren
577 
578 		break;
579 
580-	case DCERPC_PKT_BIND_NAK:
581-		DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
582-			  rpccli_pipe_txt(talloc_tos(), cli)));
583-		/* Use this for now... */
584-		return NT_STATUS_NETWORK_ACCESS_DENIED;
585-
586 	case DCERPC_PKT_FAULT:
587 
588+		ret = dcerpc_verify_ncacn_packet_header(pkt,
589+						DCERPC_PKT_FAULT,
590+						0, /* max_auth_info */
591+						DCERPC_PFC_FLAG_FIRST |
592+						DCERPC_PFC_FLAG_LAST,
593+						DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
594+		if (!NT_STATUS_IS_OK(ret)) {
595+			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
596+				  "RPC packet type - %u, expected %u: %s\n",
597+				  rpccli_pipe_txt(talloc_tos(), cli),
598+				  pkt->ptype, expected_pkt_type,
599+				  nt_errstr(ret)));
600+			NDR_PRINT_DEBUG(ncacn_packet, pkt);
601+			return ret;
602+		}
603+
604 		DEBUG(1, (__location__ ": RPC fault code %s received "
605 			  "from %s!\n",
606 			  dcerpc_errstr(talloc_tos(),
607@@ -502,13 +590,6 @@ static NTSTATUS cli_pipe_validate_curren
608 		return NT_STATUS_RPC_PROTOCOL_ERROR;
609 	}
610 
611-	if (pkt->ptype != expected_pkt_type) {
612-		DEBUG(3, (__location__ ": Connection to %s got an unexpected "
613-			  "RPC packet type - %u, not %u\n",
614-			  rpccli_pipe_txt(talloc_tos(), cli),
615-			  pkt->ptype, expected_pkt_type));
616-		return NT_STATUS_RPC_PROTOCOL_ERROR;
617-	}
618 
619 	if (pkt->call_id != call_id) {
620 		DEBUG(3, (__location__ ": Connection to %s got an unexpected "
621@@ -518,17 +599,6 @@ static NTSTATUS cli_pipe_validate_curren
622 		return NT_STATUS_RPC_PROTOCOL_ERROR;
623 	}
624 
625-	/* Do this just before return - we don't want to modify any rpc header
626-	   data before now as we may have needed to do cryptographic actions on
627-	   it before. */
628-
629-	if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
630-	    !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
631-		DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
632-			  "fragment first/last ON.\n"));
633-		pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
634-	}
635-
636 	return NT_STATUS_OK;
637 }
638 
639@@ -883,6 +953,12 @@ static void rpc_api_pipe_got_pdu(struct
640 
641 	state->pkt = talloc(state, struct ncacn_packet);
642 	if (!state->pkt) {
643+		/*
644+		 * TODO: do a real async disconnect ...
645+		 *
646+		 * For now do it sync...
647+		 */
648+		TALLOC_FREE(state->cli->transport);
649 		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
650 		return;
651 	}
652@@ -892,18 +968,16 @@ static void rpc_api_pipe_got_pdu(struct
653 					  state->pkt,
654 					  !state->endianess);
655 	if (!NT_STATUS_IS_OK(status)) {
656+		/*
657+		 * TODO: do a real async disconnect ...
658+		 *
659+		 * For now do it sync...
660+		 */
661+		TALLOC_FREE(state->cli->transport);
662 		tevent_req_nterror(req, status);
663 		return;
664 	}
665 
666-	if (state->incoming_frag.length != state->pkt->frag_length) {
667-		DEBUG(5, ("Incorrect pdu length %u, expected %u\n",
668-			  (unsigned int)state->incoming_frag.length,
669-			  (unsigned int)state->pkt->frag_length));
670-		tevent_req_nterror(req,  NT_STATUS_INVALID_PARAMETER);
671-		return;
672-	}
673-
674 	status = cli_pipe_validate_current_pdu(state,
675 						state->cli, state->pkt,
676 						&state->incoming_frag,
677@@ -917,6 +991,28 @@ static void rpc_api_pipe_got_pdu(struct
678 		  (unsigned)state->reply_pdu_offset,
679 		  nt_errstr(status)));
680 
681+	if (state->pkt->ptype != DCERPC_PKT_FAULT && !NT_STATUS_IS_OK(status)) {
682+		/*
683+		 * TODO: do a real async disconnect ...
684+		 *
685+		 * For now do it sync...
686+		 */
687+		TALLOC_FREE(state->cli->transport);
688+	} else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
689+		/*
690+		 * TODO: do a real async disconnect ...
691+		 *
692+		 * For now do it sync...
693+		 */
694+		TALLOC_FREE(state->cli->transport);
695+	} else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
696+		/*
697+		 * TODO: do a real async disconnect ...
698+		 *
699+		 * For now do it sync...
700+		 */
701+		TALLOC_FREE(state->cli->transport);
702+	}
703 	if (!NT_STATUS_IS_OK(status)) {
704 		tevent_req_nterror(req, status);
705 		return;
706@@ -941,7 +1037,24 @@ static void rpc_api_pipe_got_pdu(struct
707 			 "%s\n",
708 			 state->endianess?"little":"big",
709 			 state->pkt->drep[0]?"little":"big"));
710-		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
711+		/*
712+		 * TODO: do a real async disconnect ...
713+		 *
714+		 * For now do it sync...
715+		 */
716+		TALLOC_FREE(state->cli->transport);
717+		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
718+		return;
719+	}
720+
721+	if (state->reply_pdu_offset + rdata.length > MAX_RPC_DATA_SIZE) {
722+		/*
723+		 * TODO: do a real async disconnect ...
724+		 *
725+		 * For now do it sync...
726+		 */
727+		TALLOC_FREE(state->cli->transport);
728+		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
729 		return;
730 	}
731 
732@@ -949,6 +1062,12 @@ static void rpc_api_pipe_got_pdu(struct
733 	if (state->reply_pdu.length < state->reply_pdu_offset + rdata.length) {
734 		if (!data_blob_realloc(NULL, &state->reply_pdu,
735 				state->reply_pdu_offset + rdata.length)) {
736+			/*
737+			 * TODO: do a real async disconnect ...
738+			 *
739+			 * For now do it sync...
740+			 */
741+			TALLOC_FREE(state->cli->transport);
742 			tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
743 			return;
744 		}
745@@ -978,6 +1097,14 @@ static void rpc_api_pipe_got_pdu(struct
746 	subreq = get_complete_frag_send(state, state->ev, state->cli,
747 					state->call_id,
748 					&state->incoming_frag);
749+	if (subreq == NULL) {
750+		/*
751+		 * TODO: do a real async disconnect ...
752+		 *
753+		 * For now do it sync...
754+		 */
755+		TALLOC_FREE(state->cli->transport);
756+	}
757 	if (tevent_req_nomem(subreq, req)) {
758 		return;
759 	}
760@@ -1247,7 +1374,7 @@ static NTSTATUS create_rpc_bind_req(TALL
761 						auth->auth_type,
762 						auth->auth_level,
763 						0, /* auth_pad_length */
764-						1, /* auth_context_id */
765+						auth->auth_context_id,
766 						&auth_token,
767 						&auth_info);
768 		if (!NT_STATUS_IS_OK(ret)) {
769@@ -1749,9 +1876,8 @@ static bool check_bind_response(const st
770 
771 static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
772 				struct rpc_pipe_client *cli,
773-				uint32 rpc_call_id,
774-				enum dcerpc_AuthType auth_type,
775-				enum dcerpc_AuthLevel auth_level,
776+				struct pipe_auth_data *auth,
777+				uint32_t rpc_call_id,
778 				DATA_BLOB *pauth_blob,
779 				DATA_BLOB *rpc_out)
780 {
781@@ -1761,10 +1887,10 @@ static NTSTATUS create_rpc_bind_auth3(TA
782 	u.auth3._pad = 0;
783 
784 	status = dcerpc_push_dcerpc_auth(mem_ctx,
785-					 auth_type,
786-					 auth_level,
787+					 auth->auth_type,
788+					 auth->auth_level,
789 					 0, /* auth_pad_length */
790-					 1, /* auth_context_id */
791+					 auth->auth_context_id,
792 					 pauth_blob,
793 					 &u.auth3.auth_info);
794 	if (!NT_STATUS_IS_OK(status)) {
795@@ -1794,9 +1920,8 @@ static NTSTATUS create_rpc_bind_auth3(TA
796  ********************************************************************/
797 
798 static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx,
799-					enum dcerpc_AuthType auth_type,
800-					enum dcerpc_AuthLevel auth_level,
801-					uint32 rpc_call_id,
802+					struct pipe_auth_data *auth,
803+					uint32_t rpc_call_id,
804 					const struct ndr_syntax_id *abstract,
805 					const struct ndr_syntax_id *transfer,
806 					const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */
807@@ -1806,10 +1931,10 @@ static NTSTATUS create_rpc_alter_context
808 	NTSTATUS status;
809 
810 	status = dcerpc_push_dcerpc_auth(mem_ctx,
811-					 auth_type,
812-					 auth_level,
813+					 auth->auth_type,
814+					 auth->auth_level,
815 					 0, /* auth_pad_length */
816-					 1, /* auth_context_id */
817+					 auth->auth_context_id,
818 					 pauth_blob,
819 					 &auth_info);
820 	if (!NT_STATUS_IS_OK(status)) {
821@@ -1957,30 +2082,45 @@ static void rpc_pipe_bind_step_one_done(
822 		rpc_pipe_bind_step_two_trigger(req);
823 		return;
824 
825-	case DCERPC_AUTH_TYPE_NTLMSSP:
826-	case DCERPC_AUTH_TYPE_SPNEGO:
827-	case DCERPC_AUTH_TYPE_KRB5:
828-		/* Paranoid lenght checks */
829-		if (pkt->frag_length < DCERPC_AUTH_TRAILER_LENGTH
830-						+ pkt->auth_length) {
831-			tevent_req_nterror(req,
832-					NT_STATUS_INFO_LENGTH_MISMATCH);
833+	default:
834+		if (pkt->auth_length == 0) {
835+			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
836 			return;
837 		}
838 		/* get auth credentials */
839-		status = dcerpc_pull_dcerpc_auth(talloc_tos(),
840-						 &pkt->u.bind_ack.auth_info,
841-						 &auth, false);
842+		status = dcerpc_pull_auth_trailer(pkt, talloc_tos(),
843+						  &pkt->u.bind_ack.auth_info,
844+						  &auth, NULL, true);
845 		if (!NT_STATUS_IS_OK(status)) {
846 			DEBUG(0, ("Failed to pull dcerpc auth: %s.\n",
847 				  nt_errstr(status)));
848 			tevent_req_nterror(req, status);
849 			return;
850 		}
851-		break;
852 
853-	default:
854-		goto err_out;
855+		if (auth.auth_type != pauth->auth_type) {
856+			DEBUG(0, (__location__ " Auth type %u mismatch expected %u.\n",
857+				  auth.auth_type, pauth->auth_type));
858+			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
859+			return;
860+		}
861+
862+		if (auth.auth_level != pauth->auth_level) {
863+			DEBUG(0, (__location__ " Auth level %u mismatch expected %u.\n",
864+				  auth.auth_level, pauth->auth_level));
865+			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
866+			return;
867+		}
868+
869+		if (auth.auth_context_id != pauth->auth_context_id) {
870+			DEBUG(0, (__location__ " Auth context id %u mismatch expected %u.\n",
871+				  (unsigned)auth.auth_context_id,
872+				  (unsigned)pauth->auth_context_id));
873+			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
874+			return;
875+		}
876+
877+		break;
878 	}
879 
880 	/*
881@@ -2226,9 +2366,7 @@ static NTSTATUS rpc_bind_next_send(struc
882 	/* Now prepare the alter context pdu. */
883 	data_blob_free(&state->rpc_out);
884 
885-	status = create_rpc_alter_context(state,
886-					  auth->auth_type,
887-					  auth->auth_level,
888+	status = create_rpc_alter_context(state, auth,
889 					  state->rpc_call_id,
890 					  &state->cli->abstract_syntax,
891 					  &state->cli->transfer_syntax,
892@@ -2261,10 +2399,8 @@ static NTSTATUS rpc_bind_finish_send(str
893 	/* Now prepare the auth3 context pdu. */
894 	data_blob_free(&state->rpc_out);
895 
896-	status = create_rpc_bind_auth3(state, state->cli,
897+	status = create_rpc_bind_auth3(state, state->cli, auth,
898 					state->rpc_call_id,
899-					auth->auth_type,
900-					auth->auth_level,
901 					auth_token,
902 					&state->rpc_out);
903 	if (!NT_STATUS_IS_OK(status)) {
904@@ -2498,8 +2634,9 @@ static struct tevent_req *rpccli_bh_disc
905 	/*
906 	 * TODO: do a real async disconnect ...
907 	 *
908-	 * For now the caller needs to free rpc_cli
909+	 * For now we do it sync...
910 	 */
911+	TALLOC_FREE(hs->rpc_cli->transport);
912 	hs->rpc_cli = NULL;
913 
914 	tevent_req_done(req);
915@@ -2636,6 +2773,7 @@ NTSTATUS rpccli_ncalrpc_bind_data(TALLOC
916 
917 	result->auth_type = DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM;
918 	result->auth_level = DCERPC_AUTH_LEVEL_CONNECT;
919+	result->auth_context_id = 1;
920 
921 	result->user_name = talloc_strdup(result, "");
922 	result->domain = talloc_strdup(result, "");
923@@ -2660,6 +2798,7 @@ NTSTATUS rpccli_anon_bind_data(TALLOC_CT
924 
925 	result->auth_type = DCERPC_AUTH_TYPE_NONE;
926 	result->auth_level = DCERPC_AUTH_LEVEL_NONE;
927+	result->auth_context_id = 0;
928 
929 	result->user_name = talloc_strdup(result, "");
930 	result->domain = talloc_strdup(result, "");
931@@ -2697,6 +2836,7 @@ static NTSTATUS rpccli_ntlmssp_bind_data
932 
933 	result->auth_type = auth_type;
934 	result->auth_level = auth_level;
935+	result->auth_context_id = 1;
936 
937 	result->user_name = talloc_strdup(result, username);
938 	result->domain = talloc_strdup(result, domain);
939@@ -2768,6 +2908,7 @@ NTSTATUS rpccli_schannel_bind_data(TALLO
940 
941 	result->auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
942 	result->auth_level = auth_level;
943+	result->auth_context_id = 1;
944 
945 	result->user_name = talloc_strdup(result, "");
946 	result->domain = talloc_strdup(result, domain);
947@@ -3432,6 +3573,7 @@ NTSTATUS cli_rpc_pipe_open_krb5(struct c
948 	}
949 	auth->auth_type = DCERPC_AUTH_TYPE_KRB5;
950 	auth->auth_level = auth_level;
951+	auth->auth_context_id = 1;
952 
953 	if (!username) {
954 		username = "";
955@@ -3502,6 +3644,7 @@ NTSTATUS cli_rpc_pipe_open_spnego_krb5(s
956 	}
957 	auth->auth_type = DCERPC_AUTH_TYPE_SPNEGO;
958 	auth->auth_level = auth_level;
959+	auth->auth_context_id = 1;
960 
961 	if (!username) {
962 		username = "";
963@@ -3576,6 +3719,7 @@ NTSTATUS cli_rpc_pipe_open_spnego_ntlmss
964 	}
965 	auth->auth_type = DCERPC_AUTH_TYPE_SPNEGO;
966 	auth->auth_level = auth_level;
967+	auth->auth_context_id = 1;
968 
969 	if (!username) {
970 		username = "";
971--- a/source4/rpc_server/dcesrv_auth.c
972+++ b/source4/rpc_server/dcesrv_auth.c
973@@ -46,7 +46,7 @@ bool dcesrv_auth_bind(struct dcesrv_call
974 	NTSTATUS status;
975 	uint32_t auth_length;
976 
977-	if (pkt->u.bind.auth_info.length == 0) {
978+	if (pkt->auth_length == 0) {
979 		dce_conn->auth_state.auth_info = NULL;
980 		return true;
981 	}
982@@ -108,7 +108,7 @@ NTSTATUS dcesrv_auth_bind_ack(struct dce
983 	struct dcesrv_connection *dce_conn = call->conn;
984 	NTSTATUS status;
985 
986-	if (!call->conn->auth_state.gensec_security) {
987+	if (call->pkt.auth_length == 0) {
988 		return NT_STATUS_OK;
989 	}
990 
991@@ -155,10 +155,16 @@ bool dcesrv_auth_auth3(struct dcesrv_cal
992 	NTSTATUS status;
993 	uint32_t auth_length;
994 
995-	/* We can't work without an existing gensec state, and an new blob to feed it */
996-	if (!dce_conn->auth_state.auth_info ||
997-	    !dce_conn->auth_state.gensec_security ||
998-	    pkt->u.auth3.auth_info.length == 0) {
999+	if (pkt->auth_length == 0) {
1000+		return false;
1001+	}
1002+
1003+	if (!dce_conn->auth_state.auth_info) {
1004+		return false;
1005+	}
1006+
1007+	/* We can't work without an existing gensec state */
1008+	if (!dce_conn->auth_state.gensec_security) {
1009 		return false;
1010 	}
1011 
1012@@ -203,7 +209,7 @@ bool dcesrv_auth_alter(struct dcesrv_cal
1013 	uint32_t auth_length;
1014 
1015 	/* on a pure interface change there is no auth blob */
1016-	if (pkt->u.alter.auth_info.length == 0) {
1017+	if (pkt->auth_length == 0) {
1018 		return true;
1019 	}
1020 
1021@@ -238,8 +244,7 @@ NTSTATUS dcesrv_auth_alter_ack(struct dc
1022 
1023 	/* on a pure interface change there is no auth_info structure
1024 	   setup */
1025-	if (!call->conn->auth_state.auth_info ||
1026-	    dce_conn->auth_state.auth_info->credentials.length == 0) {
1027+	if (call->pkt.auth_length == 0) {
1028 		return NT_STATUS_OK;
1029 	}
1030 
1031@@ -315,6 +320,11 @@ bool dcesrv_auth_request(struct dcesrv_c
1032 		return false;
1033 	}
1034 
1035+	if (pkt->auth_length == 0) {
1036+		DEBUG(1,("dcesrv_auth_request: unexpected auth_length of 0\n"));
1037+		return false;
1038+	}
1039+
1040 	status = dcerpc_pull_auth_trailer(pkt, call,
1041 					  &pkt->u.request.stub_and_verifier,
1042 					  &auth, &auth_length, false);
1043--- a/source4/librpc/rpc/dcerpc.c
1044+++ b/source4/librpc/rpc/dcerpc.c
1045@@ -701,6 +701,14 @@ static NTSTATUS ncacn_pull_request_auth(
1046 		return NT_STATUS_INVALID_LEVEL;
1047 	}
1048 
1049+	if (pkt->auth_length == 0) {
1050+		return NT_STATUS_INVALID_NETWORK_RESPONSE;
1051+	}
1052+
1053+	if (c->security_state.generic_state == NULL) {
1054+		return NT_STATUS_INTERNAL_ERROR;
1055+	}
1056+
1057 	status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
1058 					  &pkt->u.response.stub_and_verifier,
1059 					  &auth, &auth_length, false);
1060@@ -1074,7 +1082,7 @@ static void dcerpc_bind_recv_handler(str
1061 	}
1062 
1063 	/* the bind_ack might contain a reply set of credentials */
1064-	if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1065+	if (conn->security_state.auth_info && pkt->auth_length) {
1066 		NTSTATUS status;
1067 		uint32_t auth_length;
1068 		status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1069@@ -1847,8 +1855,7 @@ static void dcerpc_alter_recv_handler(st
1070 	}
1071 
1072 	/* the alter_resp might contain a reply set of credentials */
1073-	if (recv_pipe->conn->security_state.auth_info &&
1074-	    pkt->u.alter_resp.auth_info.length) {
1075+	if (recv_pipe->conn->security_state.auth_info && pkt->auth_length) {
1076 		struct dcecli_connection *conn = recv_pipe->conn;
1077 		NTSTATUS status;
1078 		uint32_t auth_length;
1079--- a/source3/librpc/rpc/dcerpc.h
1080+++ b/source3/librpc/rpc/dcerpc.h
1081@@ -42,6 +42,7 @@ struct pipe_auth_data {
1082 	bool verified_bitmask1;
1083 
1084 	void *auth_ctx;
1085+	uint32_t auth_context_id;
1086 
1087 	/* Only the client code uses these 3 for now */
1088 	char *domain;
1089@@ -71,10 +72,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_
1090 				 uint32_t auth_context_id,
1091 				 const DATA_BLOB *credentials,
1092 				 DATA_BLOB *blob);
1093-NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx,
1094-				 const DATA_BLOB *blob,
1095-				 struct dcerpc_auth *r,
1096-				 bool bigendian);
1097 NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth,
1098 			    size_t header_len, size_t data_left,
1099 			    size_t max_xmit_frag, size_t pad_alignment,
1100@@ -85,9 +82,8 @@ NTSTATUS dcerpc_add_auth_footer(struct p
1101 NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
1102 			   struct ncacn_packet *pkt,
1103 			   DATA_BLOB *pkt_trailer,
1104-			   size_t header_size,
1105-			   DATA_BLOB *raw_pkt,
1106-			   size_t *pad_len);
1107+			   uint8_t header_size,
1108+			   DATA_BLOB *raw_pkt);
1109 
1110 /* The following definitions come from librpc/rpc/rpc_common.c  */
1111 
1112--- a/source3/rpc_server/srv_pipe.c
1113+++ b/source3/rpc_server/srv_pipe.c
1114@@ -42,6 +42,7 @@
1115 #include "auth.h"
1116 #include "ntdomain.h"
1117 #include "rpc_server/srv_pipe.h"
1118+#include "../librpc/gen_ndr/ndr_dcerpc.h"
1119 #include "../librpc/ndr/ndr_dcerpc.h"
1120 
1121 #undef DBGC_CLASS
1122@@ -270,10 +271,14 @@ static bool setup_bind_nak(struct pipes_
1123 	p->out_data.data_sent_length = 0;
1124 	p->out_data.current_pdu_sent = 0;
1125 
1126+	set_incoming_fault(p);
1127 	TALLOC_FREE(p->auth.auth_ctx);
1128 	p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE;
1129 	p->auth.auth_type = DCERPC_AUTH_TYPE_NONE;
1130 	p->pipe_bound = False;
1131+	p->allow_bind = false;
1132+	p->allow_alter = false;
1133+	p->allow_auth3 = false;
1134 
1135 	return True;
1136 }
1137@@ -339,16 +344,46 @@ static bool check_bind_req(struct pipes_
1138 	DEBUG(3,("check_bind_req for %s\n",
1139 		 get_pipe_name_from_syntax(talloc_tos(), abstract)));
1140 
1141+	ok = ndr_syntax_id_equal(transfer, &ndr_transfer_syntax);
1142+	if (!ok) {
1143+		DEBUG(1,("check_bind_req unknown transfer syntax for "
1144+			 "%s context_id=%u\n",
1145+			 get_pipe_name_from_syntax(talloc_tos(), abstract),
1146+			 (unsigned)context_id));
1147+		return false;
1148+	}
1149+
1150+	for (context_fns = p->contexts;
1151+	     context_fns != NULL;
1152+	     context_fns = context_fns->next)
1153+	{
1154+		if (context_fns->context_id != context_id) {
1155+			continue;
1156+		}
1157+
1158+		ok = ndr_syntax_id_equal(&context_fns->syntax,
1159+					 abstract);
1160+		if (ok) {
1161+			return true;
1162+		}
1163+
1164+		DEBUG(1,("check_bind_req: changing abstract syntax for "
1165+			 "%s context_id=%u into %s not supported\n",
1166+			 get_pipe_name_from_syntax(talloc_tos(), &context_fns->syntax),
1167+			 (unsigned)context_id,
1168+			 get_pipe_name_from_syntax(talloc_tos(), abstract)));
1169+		return false;
1170+	}
1171+
1172 	/* we have to check all now since win2k introduced a new UUID on the lsaprpc pipe */
1173-	if (rpc_srv_pipe_exists_by_id(abstract) &&
1174-	   ndr_syntax_id_equal(transfer, &ndr_transfer_syntax)) {
1175-		DEBUG(3, ("check_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n",
1176-			rpc_srv_get_pipe_cli_name(abstract),
1177-			rpc_srv_get_pipe_srv_name(abstract)));
1178-	} else {
1179+	if (!rpc_srv_pipe_exists_by_id(abstract)) {
1180 		return false;
1181 	}
1182 
1183+	DEBUG(3, ("check_bind_req: %s -> %s rpc service\n",
1184+		  rpc_srv_get_pipe_cli_name(abstract),
1185+		  rpc_srv_get_pipe_srv_name(abstract)));
1186+
1187 	context_fns = SMB_MALLOC_P(struct pipe_rpc_fns);
1188 	if (context_fns == NULL) {
1189 		DEBUG(0,("check_bind_req: malloc() failed!\n"));
1190@@ -447,6 +482,7 @@ static bool pipe_spnego_auth_bind(struct
1191 
1192 	p->auth.auth_ctx = spnego_ctx;
1193 	p->auth.auth_type = DCERPC_AUTH_TYPE_SPNEGO;
1194+	p->auth.auth_context_id = auth_info->auth_context_id;
1195 
1196 	DEBUG(10, ("SPNEGO auth started\n"));
1197 
1198@@ -557,6 +593,7 @@ static bool pipe_schannel_auth_bind(stru
1199 	/* We're finished with this bind - no more packets. */
1200 	p->auth.auth_ctx = schannel_auth;
1201 	p->auth.auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
1202+	p->auth.auth_context_id = auth_info->auth_context_id;
1203 
1204 	p->pipe_bound = True;
1205 
1206@@ -601,6 +638,7 @@ static bool pipe_ntlmssp_auth_bind(struc
1207 
1208 	p->auth.auth_ctx = ntlmssp_state;
1209 	p->auth.auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
1210+	p->auth.auth_context_id = auth_info->auth_context_id;
1211 
1212 	DEBUG(10, (__location__ ": NTLMSSP auth started\n"));
1213 
1214@@ -776,6 +814,11 @@ static NTSTATUS pipe_auth_verify_final(s
1215 	void *mech_ctx;
1216 	NTSTATUS status;
1217 
1218+	if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) {
1219+		p->pipe_bound = true;
1220+		return NT_STATUS_OK;
1221+	}
1222+
1223 	switch (p->auth.auth_type) {
1224 	case DCERPC_AUTH_TYPE_NTLMSSP:
1225 		ntlmssp_ctx = talloc_get_type_abort(p->auth.auth_ctx,
1226@@ -867,16 +910,38 @@ static bool api_pipe_bind_req(struct pip
1227 	DATA_BLOB auth_resp = data_blob_null;
1228 	DATA_BLOB auth_blob = data_blob_null;
1229 
1230-	/* No rebinds on a bound pipe - use alter context. */
1231-	if (p->pipe_bound) {
1232-		DEBUG(2,("api_pipe_bind_req: rejecting bind request on bound "
1233-			 "pipe %s.\n",
1234-			 get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
1235+	if (!p->allow_bind) {
1236+		DEBUG(2,("Pipe not in allow bind state\n"));
1237 		return setup_bind_nak(p, pkt);
1238 	}
1239+	p->allow_bind = false;
1240+
1241+	status = dcerpc_verify_ncacn_packet_header(pkt,
1242+			DCERPC_PKT_BIND,
1243+			pkt->u.bind.auth_info.length,
1244+			0, /* required flags */
1245+			DCERPC_PFC_FLAG_FIRST |
1246+			DCERPC_PFC_FLAG_LAST |
1247+			DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
1248+			0x08 | /* this is not defined, but should be ignored */
1249+			DCERPC_PFC_FLAG_CONC_MPX |
1250+			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
1251+			DCERPC_PFC_FLAG_MAYBE |
1252+			DCERPC_PFC_FLAG_OBJECT_UUID);
1253+	if (!NT_STATUS_IS_OK(status)) {
1254+		DEBUG(1, ("api_pipe_bind_req: invalid pdu: %s\n",
1255+			  nt_errstr(status)));
1256+		NDR_PRINT_DEBUG(ncacn_packet, pkt);
1257+		goto err_exit;
1258+	}
1259 
1260 	if (pkt->u.bind.num_contexts == 0) {
1261-		DEBUG(0, ("api_pipe_bind_req: no rpc contexts around\n"));
1262+		DEBUG(1, ("api_pipe_bind_req: no rpc contexts around\n"));
1263+		goto err_exit;
1264+	}
1265+
1266+	if (pkt->u.bind.ctx_list[0].num_transfer_syntaxes == 0) {
1267+		DEBUG(1, ("api_pipe_bind_req: no transfer syntaxes around\n"));
1268 		goto err_exit;
1269 	}
1270 
1271@@ -960,25 +1025,12 @@ static bool api_pipe_bind_req(struct pip
1272 	 * Check if this is an authenticated bind request.
1273 	 */
1274 	if (pkt->auth_length) {
1275-		/* Quick length check. Won't catch a bad auth footer,
1276-		 * prevents overrun. */
1277-
1278-		if (pkt->frag_length < RPC_HEADER_LEN +
1279-					DCERPC_AUTH_TRAILER_LENGTH +
1280-					pkt->auth_length) {
1281-			DEBUG(0,("api_pipe_bind_req: auth_len (%u) "
1282-				"too long for fragment %u.\n",
1283-				(unsigned int)pkt->auth_length,
1284-				(unsigned int)pkt->frag_length));
1285-			goto err_exit;
1286-		}
1287-
1288 		/*
1289 		 * Decode the authentication verifier.
1290 		 */
1291-		status = dcerpc_pull_dcerpc_auth(pkt,
1292-						 &pkt->u.bind.auth_info,
1293-						 &auth_info, p->endian);
1294+		status = dcerpc_pull_auth_trailer(pkt, pkt,
1295+						  &pkt->u.bind.auth_info,
1296+						  &auth_info, NULL, true);
1297 		if (!NT_STATUS_IS_OK(status)) {
1298 			DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n"));
1299 			goto err_exit;
1300@@ -1072,6 +1124,7 @@ static bool api_pipe_bind_req(struct pip
1301 		p->pipe_bound = True;
1302 		/* The session key was initialized from the SMB
1303 		 * session in make_internal_rpc_pipe_p */
1304+		p->auth.auth_context_id = 0;
1305 	}
1306 
1307 	ZERO_STRUCT(u.bind_ack);
1308@@ -1113,15 +1166,15 @@ static bool api_pipe_bind_req(struct pip
1309 	if (!NT_STATUS_IS_OK(status)) {
1310 		DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n",
1311 			  nt_errstr(status)));
1312+		goto err_exit;
1313 	}
1314 
1315 	if (auth_resp.length) {
1316-
1317 		status = dcerpc_push_dcerpc_auth(pkt,
1318 						 auth_type,
1319 						 auth_info.auth_level,
1320-						 0,
1321-						 1, /* auth_context_id */
1322+						 0, /* pad_len */
1323+						 p->auth.auth_context_id,
1324 						 &auth_resp,
1325 						 &auth_blob);
1326 		if (!NT_STATUS_IS_OK(status)) {
1327@@ -1152,6 +1205,22 @@ static bool api_pipe_bind_req(struct pip
1328 	p->out_data.current_pdu_sent = 0;
1329 
1330 	TALLOC_FREE(auth_blob.data);
1331+
1332+	if (bind_ack_ctx.result == 0) {
1333+		p->allow_alter = true;
1334+		p->allow_auth3 = true;
1335+		if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) {
1336+			status = pipe_auth_verify_final(p);
1337+			if (!NT_STATUS_IS_OK(status)) {
1338+				DEBUG(0, ("pipe_auth_verify_final failed: %s\n",
1339+					  nt_errstr(status)));
1340+				goto err_exit;
1341+			}
1342+		}
1343+	} else {
1344+		goto err_exit;
1345+	}
1346+
1347 	return True;
1348 
1349   err_exit:
1350@@ -1176,18 +1245,39 @@ bool api_pipe_bind_auth3(struct pipes_st
1351 
1352 	DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__));
1353 
1354-	if (pkt->auth_length == 0) {
1355-		DEBUG(0, ("No auth field sent for bind request!\n"));
1356+	if (!p->allow_auth3) {
1357+		DEBUG(1, ("Pipe not in allow auth3 state.\n"));
1358 		goto err;
1359 	}
1360 
1361-	/* Ensure there's enough data for an authenticated request. */
1362-	if (pkt->frag_length < RPC_HEADER_LEN
1363-				+ DCERPC_AUTH_TRAILER_LENGTH
1364-				+ pkt->auth_length) {
1365-			DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len "
1366-				"%u is too large.\n",
1367-                        (unsigned int)pkt->auth_length));
1368+	status = dcerpc_verify_ncacn_packet_header(pkt,
1369+			DCERPC_PKT_AUTH3,
1370+			pkt->u.auth3.auth_info.length,
1371+			0, /* required flags */
1372+			DCERPC_PFC_FLAG_FIRST |
1373+			DCERPC_PFC_FLAG_LAST |
1374+			DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
1375+			0x08 | /* this is not defined, but should be ignored */
1376+			DCERPC_PFC_FLAG_CONC_MPX |
1377+			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
1378+			DCERPC_PFC_FLAG_MAYBE |
1379+			DCERPC_PFC_FLAG_OBJECT_UUID);
1380+	if (!NT_STATUS_IS_OK(status)) {
1381+		DEBUG(1, ("api_pipe_bind_auth3: invalid pdu: %s\n",
1382+			  nt_errstr(status)));
1383+		NDR_PRINT_DEBUG(ncacn_packet, pkt);
1384+		goto err;
1385+	}
1386+
1387+	/* We can only finish if the pipe is unbound for now */
1388+	if (p->pipe_bound) {
1389+		DEBUG(0, (__location__ ": Pipe already bound, "
1390+			  "AUTH3 not supported!\n"));
1391+		goto err;
1392+	}
1393+
1394+	if (pkt->auth_length == 0) {
1395+		DEBUG(1, ("No auth field sent for auth3 request!\n"));
1396 		goto err;
1397 	}
1398 
1399@@ -1195,9 +1285,9 @@ bool api_pipe_bind_auth3(struct pipes_st
1400 	 * Decode the authentication verifier response.
1401 	 */
1402 
1403-	status = dcerpc_pull_dcerpc_auth(pkt,
1404-					 &pkt->u.auth3.auth_info,
1405-					 &auth_info, p->endian);
1406+	status = dcerpc_pull_auth_trailer(pkt, pkt,
1407+					  &pkt->u.auth3.auth_info,
1408+					  &auth_info, NULL, true);
1409 	if (!NT_STATUS_IS_OK(status)) {
1410 		DEBUG(0, ("Failed to unmarshall dcerpc_auth.\n"));
1411 		goto err;
1412@@ -1215,6 +1305,21 @@ bool api_pipe_bind_auth3(struct pipes_st
1413 		goto err;
1414 	}
1415 
1416+	if (auth_info.auth_level != p->auth.auth_level) {
1417+		DEBUG(1, ("Auth level mismatch! Client sent %d, "
1418+			  "but auth was started as level %d!\n",
1419+			  auth_info.auth_level, p->auth.auth_level));
1420+		goto err;
1421+	}
1422+
1423+	if (auth_info.auth_context_id != p->auth.auth_context_id) {
1424+		DEBUG(0, ("Auth context id mismatch! Client sent %u, "
1425+			  "but auth was started as level %u!\n",
1426+			  (unsigned)auth_info.auth_context_id,
1427+			  (unsigned)p->auth.auth_context_id));
1428+		goto err;
1429+	}
1430+
1431 	switch (auth_info.auth_type) {
1432 	case DCERPC_AUTH_TYPE_NTLMSSP:
1433 		ntlmssp_ctx = talloc_get_type_abort(p->auth.auth_ctx,
1434@@ -1267,6 +1372,10 @@ bool api_pipe_bind_auth3(struct pipes_st
1435 	return true;
1436 
1437 err:
1438+	p->pipe_bound = false;
1439+	p->allow_bind = false;
1440+	p->allow_alter = false;
1441+	p->allow_auth3 = false;
1442 
1443 	TALLOC_FREE(p->auth.auth_ctx);
1444 	return false;
1445@@ -1284,7 +1393,7 @@ static bool api_pipe_alter_context(struc
1446 	uint16 assoc_gid;
1447 	NTSTATUS status;
1448 	union dcerpc_payload u;
1449-	struct dcerpc_ack_ctx bind_ack_ctx;
1450+	struct dcerpc_ack_ctx alter_ack_ctx;
1451 	DATA_BLOB auth_resp = data_blob_null;
1452 	DATA_BLOB auth_blob = data_blob_null;
1453 	int pad_len = 0;
1454@@ -1294,8 +1403,42 @@ static bool api_pipe_alter_context(struc
1455 
1456 	DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__));
1457 
1458-	if (pkt->u.bind.assoc_group_id != 0) {
1459-		assoc_gid = pkt->u.bind.assoc_group_id;
1460+	if (!p->allow_alter) {
1461+		DEBUG(1, ("Pipe not in allow alter state.\n"));
1462+		goto err_exit;
1463+	}
1464+
1465+	status = dcerpc_verify_ncacn_packet_header(pkt,
1466+			DCERPC_PKT_ALTER,
1467+			pkt->u.alter.auth_info.length,
1468+			0, /* required flags */
1469+			DCERPC_PFC_FLAG_FIRST |
1470+			DCERPC_PFC_FLAG_LAST |
1471+			DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
1472+			0x08 | /* this is not defined, but should be ignored */
1473+			DCERPC_PFC_FLAG_CONC_MPX |
1474+			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
1475+			DCERPC_PFC_FLAG_MAYBE |
1476+			DCERPC_PFC_FLAG_OBJECT_UUID);
1477+	if (!NT_STATUS_IS_OK(status)) {
1478+		DEBUG(1, ("api_pipe_alter_context: invalid pdu: %s\n",
1479+			  nt_errstr(status)));
1480+		NDR_PRINT_DEBUG(ncacn_packet, pkt);
1481+		goto err_exit;
1482+	}
1483+
1484+	if (pkt->u.alter.num_contexts == 0) {
1485+		DEBUG(1, ("api_pipe_alter_context: no rpc contexts around\n"));
1486+		goto err_exit;
1487+	}
1488+
1489+	if (pkt->u.alter.ctx_list[0].num_transfer_syntaxes == 0) {
1490+		DEBUG(1, ("api_pipe_alter_context: no transfer syntaxes around\n"));
1491+		goto err_exit;
1492+	}
1493+
1494+	if (pkt->u.alter.assoc_group_id != 0) {
1495+		assoc_gid = pkt->u.alter.assoc_group_id;
1496 	} else {
1497 		assoc_gid = 0x53f0;
1498 	}
1499@@ -1305,59 +1448,45 @@ static bool api_pipe_alter_context(struc
1500 	 */
1501 
1502 	/* If the requested abstract synt uuid doesn't match our client pipe,
1503-		reject the bind_ack & set the transfer interface synt to all 0's,
1504+		reject the alter_ack & set the transfer interface synt to all 0's,
1505 		ver 0 (observed when NT5 attempts to bind to abstract interfaces
1506 		unknown to NT4)
1507 		Needed when adding entries to a DACL from NT5 - SK */
1508 
1509 	if (check_bind_req(p,
1510-			&pkt->u.bind.ctx_list[0].abstract_syntax,
1511-			&pkt->u.bind.ctx_list[0].transfer_syntaxes[0],
1512-			pkt->u.bind.ctx_list[0].context_id)) {
1513-
1514-		bind_ack_ctx.result = 0;
1515-		bind_ack_ctx.reason = 0;
1516-		bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0];
1517+			&pkt->u.alter.ctx_list[0].abstract_syntax,
1518+			&pkt->u.alter.ctx_list[0].transfer_syntaxes[0],
1519+			pkt->u.alter.ctx_list[0].context_id)) {
1520+
1521+		alter_ack_ctx.result = 0;
1522+		alter_ack_ctx.reason = 0;
1523+		alter_ack_ctx.syntax = pkt->u.alter.ctx_list[0].transfer_syntaxes[0];
1524 	} else {
1525-		p->pipe_bound = False;
1526 		/* Rejection reason: abstract syntax not supported */
1527-		bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
1528-		bind_ack_ctx.reason = DCERPC_BIND_REASON_ASYNTAX;
1529-		bind_ack_ctx.syntax = null_ndr_syntax_id;
1530+		alter_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
1531+		alter_ack_ctx.reason = DCERPC_BIND_REASON_ASYNTAX;
1532+		alter_ack_ctx.syntax = null_ndr_syntax_id;
1533 	}
1534 
1535 	/*
1536 	 * Check if this is an authenticated alter context request.
1537 	 */
1538 	if (pkt->auth_length) {
1539-		/* Quick length check. Won't catch a bad auth footer,
1540-		 * prevents overrun. */
1541-
1542-		if (pkt->frag_length < RPC_HEADER_LEN +
1543-					DCERPC_AUTH_TRAILER_LENGTH +
1544-					pkt->auth_length) {
1545-			DEBUG(0,("api_pipe_alter_context: auth_len (%u) "
1546-				"too long for fragment %u.\n",
1547-				(unsigned int)pkt->auth_length,
1548-				(unsigned int)pkt->frag_length ));
1549+		/* We can only finish if the pipe is unbound for now */
1550+		if (p->pipe_bound) {
1551+			DEBUG(0, (__location__ ": Pipe already bound, "
1552+				  "Altering Context not yet supported!\n"));
1553 			goto err_exit;
1554 		}
1555 
1556-		status = dcerpc_pull_dcerpc_auth(pkt,
1557-						 &pkt->u.bind.auth_info,
1558-						 &auth_info, p->endian);
1559+		status = dcerpc_pull_auth_trailer(pkt, pkt,
1560+						  &pkt->u.alter.auth_info,
1561+						  &auth_info, NULL, true);
1562 		if (!NT_STATUS_IS_OK(status)) {
1563 			DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n"));
1564 			goto err_exit;
1565 		}
1566 
1567-		/* We can only finish if the pipe is unbound for now */
1568-		if (p->pipe_bound) {
1569-			DEBUG(0, (__location__ ": Pipe already bound, "
1570-				  "Altering Context not yet supported!\n"));
1571-			goto err_exit;
1572-		}
1573-
1574 		if (auth_info.auth_type != p->auth.auth_type) {
1575 			DEBUG(0, ("Auth type mismatch! Client sent %d, "
1576 				  "but auth was started as type %d!\n",
1577@@ -1365,6 +1494,20 @@ static bool api_pipe_alter_context(struc
1578 			goto err_exit;
1579 		}
1580 
1581+		if (auth_info.auth_level != p->auth.auth_level) {
1582+			DEBUG(0, ("Auth level mismatch! Client sent %d, "
1583+				  "but auth was started as level %d!\n",
1584+				  auth_info.auth_level, p->auth.auth_level));
1585+			goto err_exit;
1586+		}
1587+
1588+		if (auth_info.auth_context_id != p->auth.auth_context_id) {
1589+			DEBUG(0, ("Auth context id mismatch! Client sent %u, "
1590+				  "but auth was started as level %u!\n",
1591+				  (unsigned)auth_info.auth_context_id,
1592+				  (unsigned)p->auth.auth_context_id));
1593+			goto err_exit;
1594+		}
1595 
1596 		switch (auth_info.auth_type) {
1597 		case DCERPC_AUTH_TYPE_SPNEGO:
1598@@ -1431,7 +1574,7 @@ static bool api_pipe_alter_context(struc
1599 	u.alter_resp.secondary_address_size = 1;
1600 
1601 	u.alter_resp.num_results = 1;
1602-	u.alter_resp.ctx_list = &bind_ack_ctx;
1603+	u.alter_resp.ctx_list = &alter_ack_ctx;
1604 
1605 	/* NOTE: We leave the auth_info empty so we can calculate the padding
1606 	 * later and then append the auth_info --simo */
1607@@ -1451,8 +1594,9 @@ static bool api_pipe_alter_context(struc
1608 					  &u,
1609 					  &p->out_data.frag);
1610 	if (!NT_STATUS_IS_OK(status)) {
1611-		DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n",
1612+		DEBUG(0, ("Failed to marshall alter_resp packet. (%s)\n",
1613 			  nt_errstr(status)));
1614+		goto err_exit;
1615 	}
1616 
1617 	if (auth_resp.length) {
1618@@ -1469,7 +1613,7 @@ static bool api_pipe_alter_context(struc
1619 						 auth_info.auth_type,
1620 						 auth_info.auth_level,
1621 						 pad_len,
1622-						 1, /* auth_context_id */
1623+						 p->auth.auth_context_id,
1624 						 &auth_resp,
1625 						 &auth_blob);
1626 		if (!NT_STATUS_IS_OK(status)) {
1627@@ -1618,6 +1762,7 @@ static bool api_pipe_request(struct pipe
1628 
1629 	if (!srv_pipe_check_verification_trailer(p, pkt, pipe_fns)) {
1630 		DEBUG(1, ("srv_pipe_check_verification_trailer: failed\n"));
1631+		set_incoming_fault(p);
1632 		setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED));
1633 		data_blob_free(&p->out_data.rdata);
1634 		TALLOC_FREE(frame);
1635@@ -1756,7 +1901,11 @@ void set_incoming_fault(struct pipes_str
1636 	data_blob_free(&p->in_data.data);
1637 	p->in_data.pdu_needed_len = 0;
1638 	p->in_data.pdu.length = 0;
1639-	p->fault_state = DCERPC_FAULT_CANT_PERFORM;
1640+	p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
1641+
1642+	p->allow_alter = false;
1643+	p->allow_auth3 = false;
1644+	p->pipe_bound = false;
1645 
1646 	DEBUG(10, ("Setting fault state\n"));
1647 }
1648@@ -1767,7 +1916,6 @@ static NTSTATUS dcesrv_auth_request(stru
1649 {
1650 	NTSTATUS status;
1651 	size_t hdr_size = DCERPC_REQUEST_LENGTH;
1652-	size_t pad_len;
1653 
1654 	DEBUG(10, ("Checking request auth.\n"));
1655 
1656@@ -1778,25 +1926,11 @@ static NTSTATUS dcesrv_auth_request(stru
1657 	/* in case of sealing this function will unseal the data in place */
1658 	status = dcerpc_check_auth(auth, pkt,
1659 				   &pkt->u.request.stub_and_verifier,
1660-				   hdr_size, raw_pkt,
1661-				   &pad_len);
1662+				   hdr_size, raw_pkt);
1663 	if (!NT_STATUS_IS_OK(status)) {
1664 		return status;
1665 	}
1666 
1667-
1668-	/* remove padding and auth trailer,
1669-	 * this way the caller will get just the data */
1670-	if (pkt->auth_length) {
1671-		size_t trail_len = pad_len
1672-					+ DCERPC_AUTH_TRAILER_LENGTH
1673-					+ pkt->auth_length;
1674-		if (pkt->u.request.stub_and_verifier.length < trail_len) {
1675-			return NT_STATUS_INFO_LENGTH_MISMATCH;
1676-		}
1677-		pkt->u.request.stub_and_verifier.length -= trail_len;
1678-	}
1679-
1680 	return NT_STATUS_OK;
1681 }
1682 
1683@@ -1816,6 +1950,29 @@ static bool process_request_pdu(struct p
1684 		return False;
1685 	}
1686 
1687+	/*
1688+	 * We don't ignore DCERPC_PFC_FLAG_PENDING_CANCEL.
1689+	 * TODO: we can reject it with DCERPC_FAULT_NO_CALL_ACTIVE later.
1690+	 */
1691+	status = dcerpc_verify_ncacn_packet_header(pkt,
1692+			DCERPC_PKT_REQUEST,
1693+			pkt->u.request.stub_and_verifier.length,
1694+			0, /* required_flags */
1695+			DCERPC_PFC_FLAG_FIRST |
1696+			DCERPC_PFC_FLAG_LAST |
1697+			0x08 | /* this is not defined, but should be ignored */
1698+			DCERPC_PFC_FLAG_CONC_MPX |
1699+			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
1700+			DCERPC_PFC_FLAG_MAYBE |
1701+			DCERPC_PFC_FLAG_OBJECT_UUID);
1702+	if (!NT_STATUS_IS_OK(status)) {
1703+		DEBUG(1, ("process_request_pdu: invalid pdu: %s\n",
1704+			  nt_errstr(status)));
1705+		NDR_PRINT_DEBUG(ncacn_packet, pkt);
1706+		set_incoming_fault(p);
1707+		return false;
1708+	}
1709+
1710 	/* Store the opnum */
1711 	p->opnum = pkt->u.request.opnum;
1712 
1713@@ -2065,7 +2222,7 @@ done:
1714 			 "pipe %s\n", get_pipe_name_from_syntax(talloc_tos(),
1715 								&p->syntax)));
1716 		set_incoming_fault(p);
1717-		setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
1718+		setup_fault_pdu(p, NT_STATUS(DCERPC_NCA_S_PROTO_ERROR));
1719 		TALLOC_FREE(pkt);
1720 	} else {
1721 		/*
1722--- a/source3/include/ntdomain.h
1723+++ b/source3/include/ntdomain.h
1724@@ -135,6 +135,13 @@ struct pipes_struct {
1725 	bool pipe_bound;
1726 
1727 	/*
1728+	 * States we can be in.
1729+	 */
1730+	bool allow_alter;
1731+	bool allow_bind;
1732+	bool allow_auth3;
1733+
1734+	/*
1735 	 * Set the DCERPC_FAULT to return.
1736 	 */
1737 
1738--- a/source3/rpc_server/rpc_ncacn_np.c
1739+++ b/source3/rpc_server/rpc_ncacn_np.c
1740@@ -171,6 +171,7 @@ struct pipes_struct *make_internal_rpc_p
1741 
1742 	p->syntax = *syntax;
1743 	p->transport = NCALRPC;
1744+	p->allow_bind = true;
1745 
1746 	DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n",
1747 		 get_pipe_name_from_syntax(talloc_tos(), syntax), pipes_open));
1748@@ -780,6 +781,7 @@ static NTSTATUS rpc_pipe_open_external(T
1749 	}
1750 	result->auth->auth_type = DCERPC_AUTH_TYPE_NONE;
1751 	result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
1752+	result->auth->auth_context_id = 0;
1753 
1754 	status = rpccli_anon_bind_data(result, &auth);
1755 	if (!NT_STATUS_IS_OK(status)) {
1756--- a/source3/rpc_server/rpc_server.c
1757+++ b/source3/rpc_server/rpc_server.c
1758@@ -102,6 +102,7 @@ static int make_server_pipes_struct(TALL
1759 	p->syntax = id;
1760 	p->transport = transport;
1761 	p->ncalrpc_as_system = ncalrpc_as_system;
1762+	p->allow_bind = true;
1763 
1764 	p->mem_ctx = talloc_named(p, 0, "pipe %s %p", pipe_name, p);
1765 	if (!p->mem_ctx) {
1766@@ -663,6 +664,12 @@ static void named_pipe_packet_done(struc
1767 		goto fail;
1768 	}
1769 
1770+	if (npc->p->fault_state != 0) {
1771+		DEBUG(2, ("Disconnect after fault\n"));
1772+		sys_errno = EINVAL;
1773+		goto fail;
1774+	}
1775+
1776 	/* clear out any data that may have been left around */
1777 	npc->count = 0;
1778 	TALLOC_FREE(npc->iov);
1779@@ -1391,6 +1398,12 @@ static void dcerpc_ncacn_packet_done(str
1780 		goto fail;
1781 	}
1782 
1783+	if (ncacn_conn->p->fault_state != 0) {
1784+		DEBUG(2, ("Disconnect after fault\n"));
1785+		sys_errno = EINVAL;
1786+		goto fail;
1787+	}
1788+
1789 	/* clear out any data that may have been left around */
1790 	ncacn_conn->count = 0;
1791 	TALLOC_FREE(ncacn_conn->iov);
1792