OpenWrt – Blame information for rev 4

Subversion Repositories:
Rev:
Rev Author Line No. Line
4 office 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);