samba: fix some security problems
[openwrt.git] / package / network / services / samba36 / patches / 022-CVE-2015-5370-v3-6.patch
1 From 8716bb5e03cc4f10e2d4edc704d8defe7e8045f1 Mon Sep 17 00:00:00 2001
2 From: Stefan Metzmacher <metze@samba.org>
3 Date: Thu, 16 Jul 2015 22:46:05 +0200
4 Subject: [PATCH 01/40] CVE-2015-5370: dcerpc.idl: add
5  DCERPC_{NCACN_PAYLOAD,FRAG}_MAX_SIZE defines
6 MIME-Version: 1.0
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
9
10 BUG: https://bugzilla.samba.org/show_bug.cgi?id=11344
11
12 Signed-off-by: Stefan Metzmacher <metze@samba.org>
13 Reviewed-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);