samba: fix some security problems
[openwrt.git] / package / network / services / samba36 / patches / 022-CVE-2015-5370-v3-6.patch
diff --git a/package/network/services/samba36/patches/022-CVE-2015-5370-v3-6.patch b/package/network/services/samba36/patches/022-CVE-2015-5370-v3-6.patch
new file mode 100644 (file)
index 0000000..36656ab
--- /dev/null
@@ -0,0 +1,1791 @@
+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);