librpc: add dcerpc_get_auth_{type,level,context_id}() helper functions
[Samba.git] / librpc / rpc / dcerpc_util.c
blobe0479c2f36b1aea81a1536937f4f726080dab69e
1 /*
2 Unix SMB/CIFS implementation.
3 raw dcerpc operations
5 Copyright (C) Andrew Tridgell 2003-2005
6 Copyright (C) Jelmer Vernooij 2004-2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "system/network.h"
24 #include <tevent.h>
25 #include "lib/tsocket/tsocket.h"
26 #include "lib/util/tevent_ntstatus.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 #include "rpc_common.h"
30 #include "lib/util/bitmap.h"
31 #include "auth/gensec/gensec.h"
33 /* we need to be able to get/set the fragment length without doing a full
34 decode */
35 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
37 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
38 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
39 } else {
40 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
44 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
46 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
47 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
48 } else {
49 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
53 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
55 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
56 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
57 } else {
58 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
62 uint16_t dcerpc_get_auth_length(const DATA_BLOB *blob)
64 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
65 return SVAL(blob->data, DCERPC_AUTH_LEN_OFFSET);
66 } else {
67 return RSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET);
71 uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob)
73 return blob->data[DCERPC_DREP_OFFSET];
76 static uint16_t dcerpc_get_auth_context_offset(const DATA_BLOB *blob)
78 uint16_t frag_len = dcerpc_get_frag_length(blob);
79 uint16_t auth_len = dcerpc_get_auth_length(blob);
80 uint16_t min_offset;
81 uint16_t offset;
83 if (auth_len == 0) {
84 return 0;
87 if (frag_len > blob->length) {
88 return 0;
91 if (auth_len > frag_len) {
92 return 0;
95 min_offset = DCERPC_NCACN_PAYLOAD_OFFSET + DCERPC_AUTH_TRAILER_LENGTH;
96 offset = frag_len - auth_len;
97 if (offset < min_offset) {
98 return 0;
100 offset -= DCERPC_AUTH_TRAILER_LENGTH;
102 return offset;
105 uint8_t dcerpc_get_auth_type(const DATA_BLOB *blob)
107 uint16_t offset;
109 offset = dcerpc_get_auth_context_offset(blob);
110 if (offset == 0) {
111 return 0;
115 * auth_typw is in the 1st byte
116 * of the auth trailer
118 offset += 0;
120 return blob->data[offset];
123 uint8_t dcerpc_get_auth_level(const DATA_BLOB *blob)
125 uint16_t offset;
127 offset = dcerpc_get_auth_context_offset(blob);
128 if (offset == 0) {
129 return 0;
133 * auth_level is in 2nd byte
134 * of the auth trailer
136 offset += 1;
138 return blob->data[offset];
141 uint32_t dcerpc_get_auth_context_id(const DATA_BLOB *blob)
143 uint16_t offset;
145 offset = dcerpc_get_auth_context_offset(blob);
146 if (offset == 0) {
147 return 0;
151 * auth_context_id is in the last 4 byte
152 * of the auth trailer
154 offset += 4;
156 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
157 return IVAL(blob->data, offset);
158 } else {
159 return RIVAL(blob->data, offset);
164 * @brief Decodes a ncacn_packet
166 * @param mem_ctx The memory context on which to allocate the packet
167 * elements
168 * @param blob The blob of data to decode
169 * @param r An empty ncacn_packet, must not be NULL
171 * @return a NTSTATUS error code
173 NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
174 const DATA_BLOB *blob,
175 struct ncacn_packet *r)
177 enum ndr_err_code ndr_err;
178 struct ndr_pull *ndr;
180 ndr = ndr_pull_init_blob(blob, mem_ctx);
181 if (!ndr) {
182 return NT_STATUS_NO_MEMORY;
185 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, r);
187 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
188 talloc_free(ndr);
189 return ndr_map_error2ntstatus(ndr_err);
191 talloc_free(ndr);
193 if (r->frag_length != blob->length) {
194 return NT_STATUS_RPC_PROTOCOL_ERROR;
197 return NT_STATUS_OK;
201 * @brief Pull a dcerpc_auth structure, taking account of any auth
202 * padding in the blob. For request/response packets we pass
203 * the whole data blob, so auth_data_only must be set to false
204 * as the blob contains data+pad+auth and no just pad+auth.
206 * @param pkt - The ncacn_packet strcuture
207 * @param mem_ctx - The mem_ctx used to allocate dcerpc_auth elements
208 * @param pkt_trailer - The packet trailer data, usually the trailing
209 * auth_info blob, but in the request/response case
210 * this is the stub_and_verifier blob.
211 * @param auth - A preallocated dcerpc_auth *empty* structure
212 * @param auth_length - The length of the auth trail, sum of auth header
213 * lenght and pkt->auth_length
214 * @param auth_data_only - Whether the pkt_trailer includes only the auth_blob
215 * (+ padding) or also other data.
217 * @return - A NTSTATUS error code.
219 NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
220 TALLOC_CTX *mem_ctx,
221 const DATA_BLOB *pkt_trailer,
222 struct dcerpc_auth *auth,
223 uint32_t *_auth_length,
224 bool auth_data_only)
226 struct ndr_pull *ndr;
227 enum ndr_err_code ndr_err;
228 uint16_t data_and_pad;
229 uint16_t auth_length;
230 uint32_t tmp_length;
231 uint32_t max_pad_len = 0;
233 ZERO_STRUCTP(auth);
234 if (_auth_length != NULL) {
235 *_auth_length = 0;
237 if (auth_data_only) {
238 return NT_STATUS_INTERNAL_ERROR;
240 } else {
241 if (!auth_data_only) {
242 return NT_STATUS_INTERNAL_ERROR;
246 /* Paranoia checks for auth_length. The caller should check this... */
247 if (pkt->auth_length == 0) {
248 return NT_STATUS_INTERNAL_ERROR;
251 /* Paranoia checks for auth_length. The caller should check this... */
252 if (pkt->auth_length > pkt->frag_length) {
253 return NT_STATUS_INTERNAL_ERROR;
255 tmp_length = DCERPC_NCACN_PAYLOAD_OFFSET;
256 tmp_length += DCERPC_AUTH_TRAILER_LENGTH;
257 tmp_length += pkt->auth_length;
258 if (tmp_length > pkt->frag_length) {
259 return NT_STATUS_INTERNAL_ERROR;
261 if (pkt_trailer->length > UINT16_MAX) {
262 return NT_STATUS_INTERNAL_ERROR;
265 auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length;
266 if (pkt_trailer->length < auth_length) {
267 return NT_STATUS_RPC_PROTOCOL_ERROR;
270 data_and_pad = pkt_trailer->length - auth_length;
272 ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx);
273 if (!ndr) {
274 return NT_STATUS_NO_MEMORY;
277 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
278 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
281 ndr_err = ndr_pull_advance(ndr, data_and_pad);
282 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
283 talloc_free(ndr);
284 return ndr_map_error2ntstatus(ndr_err);
287 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth);
288 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
289 talloc_free(ndr);
290 ZERO_STRUCTP(auth);
291 return ndr_map_error2ntstatus(ndr_err);
295 * Make sure the padding would not exceed
296 * the frag_length.
298 * Here we assume at least 24 bytes for the
299 * payload specific header the value of
300 * DCERPC_{REQUEST,RESPONSE}_LENGTH.
302 * We use this also for BIND_*, ALTER_* and AUTH3 pdus.
304 * We need this check before we ignore possible
305 * invalid values. See also bug #11982.
307 * This check is mainly used to generate the correct
308 * error for BIND_*, ALTER_* and AUTH3 pdus.
310 * We always have the 'if (data_and_pad < auth->auth_pad_length)'
311 * protection for REQUEST and RESPONSE pdus, where the
312 * auth_pad_length field is actually used by the caller.
314 tmp_length = DCERPC_REQUEST_LENGTH;
315 tmp_length += DCERPC_AUTH_TRAILER_LENGTH;
316 tmp_length += pkt->auth_length;
317 if (tmp_length < pkt->frag_length) {
318 max_pad_len = pkt->frag_length - tmp_length;
320 if (max_pad_len < auth->auth_pad_length) {
321 DEBUG(1, (__location__ ": ERROR: pad length to large. "
322 "max %u got %u\n",
323 (unsigned)max_pad_len,
324 (unsigned)auth->auth_pad_length));
325 talloc_free(ndr);
326 ZERO_STRUCTP(auth);
327 return NT_STATUS_RPC_PROTOCOL_ERROR;
331 * This is a workarround for a bug in old
332 * Samba releases. For BIND_ACK <= 3.5.x
333 * and for ALTER_RESP <= 4.2.x (see bug #11061)
335 * See also bug #11982.
337 if (auth_data_only && data_and_pad == 0 &&
338 auth->auth_pad_length > 0) {
340 * we need to ignore invalid auth_pad_length
341 * values for BIND_*, ALTER_* and AUTH3 pdus.
343 auth->auth_pad_length = 0;
346 if (data_and_pad < auth->auth_pad_length) {
347 DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
348 "Calculated %u got %u\n",
349 (unsigned)data_and_pad,
350 (unsigned)auth->auth_pad_length));
351 talloc_free(ndr);
352 ZERO_STRUCTP(auth);
353 return NT_STATUS_RPC_PROTOCOL_ERROR;
356 if (auth_data_only && data_and_pad != auth->auth_pad_length) {
357 DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
358 "Calculated %u got %u\n",
359 (unsigned)data_and_pad,
360 (unsigned)auth->auth_pad_length));
361 talloc_free(ndr);
362 ZERO_STRUCTP(auth);
363 return NT_STATUS_RPC_PROTOCOL_ERROR;
366 DBG_DEBUG("auth_pad_length %u\n",
367 (unsigned)auth->auth_pad_length);
369 talloc_steal(mem_ctx, auth->credentials.data);
370 talloc_free(ndr);
372 if (_auth_length != NULL) {
373 *_auth_length = auth_length;
376 return NT_STATUS_OK;
380 * @brief Verify the fields in ncacn_packet header.
382 * @param pkt - The ncacn_packet strcuture
383 * @param ptype - The expected PDU type
384 * @param max_auth_info - The maximum size of a possible auth trailer
385 * @param required_flags - The required flags for the pdu.
386 * @param optional_flags - The possible optional flags for the pdu.
388 * @return - A NTSTATUS error code.
390 NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
391 enum dcerpc_pkt_type ptype,
392 size_t max_auth_info,
393 uint8_t required_flags,
394 uint8_t optional_flags)
396 if (pkt->rpc_vers != 5) {
397 return NT_STATUS_RPC_PROTOCOL_ERROR;
400 if (pkt->rpc_vers_minor != 0) {
401 return NT_STATUS_RPC_PROTOCOL_ERROR;
404 if (pkt->auth_length > pkt->frag_length) {
405 return NT_STATUS_RPC_PROTOCOL_ERROR;
408 if (pkt->ptype != ptype) {
409 return NT_STATUS_RPC_PROTOCOL_ERROR;
412 if (max_auth_info > UINT16_MAX) {
413 return NT_STATUS_INTERNAL_ERROR;
416 if (pkt->auth_length > 0) {
417 size_t max_auth_length;
419 if (max_auth_info <= DCERPC_AUTH_TRAILER_LENGTH) {
420 return NT_STATUS_RPC_PROTOCOL_ERROR;
422 max_auth_length = max_auth_info - DCERPC_AUTH_TRAILER_LENGTH;
424 if (pkt->auth_length > max_auth_length) {
425 return NT_STATUS_RPC_PROTOCOL_ERROR;
429 if ((pkt->pfc_flags & required_flags) != required_flags) {
430 return NT_STATUS_RPC_PROTOCOL_ERROR;
432 if (pkt->pfc_flags & ~(optional_flags|required_flags)) {
433 return NT_STATUS_RPC_PROTOCOL_ERROR;
436 if (pkt->drep[0] & ~DCERPC_DREP_LE) {
437 return NT_STATUS_RPC_PROTOCOL_ERROR;
439 if (pkt->drep[1] != 0) {
440 return NT_STATUS_RPC_PROTOCOL_ERROR;
442 if (pkt->drep[2] != 0) {
443 return NT_STATUS_RPC_PROTOCOL_ERROR;
445 if (pkt->drep[3] != 0) {
446 return NT_STATUS_RPC_PROTOCOL_ERROR;
449 return NT_STATUS_OK;
452 NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
453 struct gensec_security *gensec,
454 TALLOC_CTX *mem_ctx,
455 enum dcerpc_pkt_type ptype,
456 uint8_t required_flags,
457 uint8_t optional_flags,
458 uint8_t payload_offset,
459 DATA_BLOB *payload_and_verifier,
460 DATA_BLOB *raw_packet,
461 const struct ncacn_packet *pkt)
463 NTSTATUS status;
464 struct dcerpc_auth auth;
465 uint32_t auth_length;
467 if (auth_state == NULL) {
468 return NT_STATUS_INTERNAL_ERROR;
471 status = dcerpc_verify_ncacn_packet_header(pkt, ptype,
472 payload_and_verifier->length,
473 required_flags, optional_flags);
474 if (!NT_STATUS_IS_OK(status)) {
475 return status;
478 switch (auth_state->auth_level) {
479 case DCERPC_AUTH_LEVEL_PRIVACY:
480 case DCERPC_AUTH_LEVEL_INTEGRITY:
481 case DCERPC_AUTH_LEVEL_PACKET:
482 break;
484 case DCERPC_AUTH_LEVEL_CONNECT:
485 if (pkt->auth_length != 0) {
486 break;
488 return NT_STATUS_OK;
489 case DCERPC_AUTH_LEVEL_NONE:
490 if (pkt->auth_length != 0) {
491 return NT_STATUS_ACCESS_DENIED;
493 return NT_STATUS_OK;
495 default:
496 return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
499 if (pkt->auth_length == 0) {
500 return NT_STATUS_RPC_PROTOCOL_ERROR;
503 if (gensec == NULL) {
504 return NT_STATUS_INTERNAL_ERROR;
507 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
508 payload_and_verifier,
509 &auth, &auth_length, false);
510 if (!NT_STATUS_IS_OK(status)) {
511 return status;
514 if (payload_and_verifier->length < auth_length) {
516 * should be checked in dcerpc_pull_auth_trailer()
518 return NT_STATUS_INTERNAL_ERROR;
521 payload_and_verifier->length -= auth_length;
523 if (payload_and_verifier->length < auth.auth_pad_length) {
525 * should be checked in dcerpc_pull_auth_trailer()
527 return NT_STATUS_INTERNAL_ERROR;
530 if (auth.auth_type != auth_state->auth_type) {
531 return NT_STATUS_ACCESS_DENIED;
534 if (auth.auth_level != auth_state->auth_level) {
535 return NT_STATUS_ACCESS_DENIED;
538 if (auth.auth_context_id != auth_state->auth_context_id) {
539 return NT_STATUS_ACCESS_DENIED;
542 /* check signature or unseal the packet */
543 switch (auth_state->auth_level) {
544 case DCERPC_AUTH_LEVEL_PRIVACY:
545 status = gensec_unseal_packet(gensec,
546 raw_packet->data + payload_offset,
547 payload_and_verifier->length,
548 raw_packet->data,
549 raw_packet->length -
550 auth.credentials.length,
551 &auth.credentials);
552 if (!NT_STATUS_IS_OK(status)) {
553 return NT_STATUS_RPC_SEC_PKG_ERROR;
555 memcpy(payload_and_verifier->data,
556 raw_packet->data + payload_offset,
557 payload_and_verifier->length);
558 break;
560 case DCERPC_AUTH_LEVEL_INTEGRITY:
561 case DCERPC_AUTH_LEVEL_PACKET:
562 status = gensec_check_packet(gensec,
563 payload_and_verifier->data,
564 payload_and_verifier->length,
565 raw_packet->data,
566 raw_packet->length -
567 auth.credentials.length,
568 &auth.credentials);
569 if (!NT_STATUS_IS_OK(status)) {
570 return NT_STATUS_RPC_SEC_PKG_ERROR;
572 break;
574 case DCERPC_AUTH_LEVEL_CONNECT:
575 /* for now we ignore possible signatures here */
576 break;
578 default:
579 return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
583 * remove the indicated amount of padding
585 * A possible overflow is checked above.
587 payload_and_verifier->length -= auth.auth_pad_length;
589 return NT_STATUS_OK;
592 NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
593 struct gensec_security *gensec,
594 TALLOC_CTX *mem_ctx,
595 DATA_BLOB *raw_packet,
596 size_t sig_size,
597 uint8_t payload_offset,
598 const DATA_BLOB *payload,
599 const struct ncacn_packet *pkt)
601 TALLOC_CTX *frame = talloc_stackframe();
602 NTSTATUS status;
603 enum ndr_err_code ndr_err;
604 struct ndr_push *ndr = NULL;
605 uint32_t payload_length;
606 uint32_t whole_length;
607 DATA_BLOB blob = data_blob_null;
608 DATA_BLOB sig = data_blob_null;
609 struct dcerpc_auth _out_auth_info;
610 struct dcerpc_auth *out_auth_info = NULL;
612 *raw_packet = data_blob_null;
614 if (auth_state == NULL) {
615 TALLOC_FREE(frame);
616 return NT_STATUS_INTERNAL_ERROR;
619 switch (auth_state->auth_level) {
620 case DCERPC_AUTH_LEVEL_PRIVACY:
621 case DCERPC_AUTH_LEVEL_INTEGRITY:
622 case DCERPC_AUTH_LEVEL_PACKET:
623 if (sig_size == 0) {
624 TALLOC_FREE(frame);
625 return NT_STATUS_INTERNAL_ERROR;
628 if (gensec == NULL) {
629 TALLOC_FREE(frame);
630 return NT_STATUS_INTERNAL_ERROR;
633 _out_auth_info = (struct dcerpc_auth) {
634 .auth_type = auth_state->auth_type,
635 .auth_level = auth_state->auth_level,
636 .auth_context_id = auth_state->auth_context_id,
638 out_auth_info = &_out_auth_info;
639 break;
641 case DCERPC_AUTH_LEVEL_CONNECT:
643 * TODO: let the gensec mech decide if it wants to generate a
644 * signature that might be needed for schannel...
646 if (sig_size != 0) {
647 TALLOC_FREE(frame);
648 return NT_STATUS_INTERNAL_ERROR;
651 if (gensec == NULL) {
652 TALLOC_FREE(frame);
653 return NT_STATUS_INTERNAL_ERROR;
655 break;
657 case DCERPC_AUTH_LEVEL_NONE:
658 if (sig_size != 0) {
659 TALLOC_FREE(frame);
660 return NT_STATUS_INTERNAL_ERROR;
662 break;
664 default:
665 TALLOC_FREE(frame);
666 return NT_STATUS_INTERNAL_ERROR;
669 ndr = ndr_push_init_ctx(frame);
670 if (ndr == NULL) {
671 TALLOC_FREE(frame);
672 return NT_STATUS_NO_MEMORY;
675 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
676 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
677 TALLOC_FREE(frame);
678 return ndr_map_error2ntstatus(ndr_err);
681 if (out_auth_info != NULL) {
683 * pad to 16 byte multiple in the payload portion of the
684 * packet. This matches what w2k3 does. Note that we can't use
685 * ndr_push_align() as that is relative to the start of the
686 * whole packet, whereas w2k8 wants it relative to the start
687 * of the stub.
689 out_auth_info->auth_pad_length =
690 DCERPC_AUTH_PAD_LENGTH(payload->length);
691 ndr_err = ndr_push_zero(ndr, out_auth_info->auth_pad_length);
692 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
693 TALLOC_FREE(frame);
694 return ndr_map_error2ntstatus(ndr_err);
697 payload_length = payload->length +
698 out_auth_info->auth_pad_length;
700 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
701 out_auth_info);
702 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
703 TALLOC_FREE(frame);
704 return ndr_map_error2ntstatus(ndr_err);
707 whole_length = ndr->offset;
709 ndr_err = ndr_push_zero(ndr, sig_size);
710 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
711 TALLOC_FREE(frame);
712 return ndr_map_error2ntstatus(ndr_err);
714 } else {
715 payload_length = payload->length;
716 whole_length = ndr->offset;
719 /* extract the whole packet as a blob */
720 blob = ndr_push_blob(ndr);
723 * Setup the frag and auth length in the packet buffer.
724 * This is needed if the GENSEC mech does AEAD signing
725 * of the packet headers. The signature itself will be
726 * appended later.
728 dcerpc_set_frag_length(&blob, blob.length);
729 dcerpc_set_auth_length(&blob, sig_size);
731 /* sign or seal the packet */
732 switch (auth_state->auth_level) {
733 case DCERPC_AUTH_LEVEL_PRIVACY:
734 status = gensec_seal_packet(gensec,
735 frame,
736 blob.data + payload_offset,
737 payload_length,
738 blob.data,
739 whole_length,
740 &sig);
741 if (!NT_STATUS_IS_OK(status)) {
742 TALLOC_FREE(frame);
743 return status;
745 break;
747 case DCERPC_AUTH_LEVEL_INTEGRITY:
748 case DCERPC_AUTH_LEVEL_PACKET:
749 status = gensec_sign_packet(gensec,
750 frame,
751 blob.data + payload_offset,
752 payload_length,
753 blob.data,
754 whole_length,
755 &sig);
756 if (!NT_STATUS_IS_OK(status)) {
757 TALLOC_FREE(frame);
758 return status;
760 break;
762 case DCERPC_AUTH_LEVEL_CONNECT:
763 case DCERPC_AUTH_LEVEL_NONE:
764 break;
766 default:
767 TALLOC_FREE(frame);
768 return NT_STATUS_INTERNAL_ERROR;
771 if (sig.length != sig_size) {
772 TALLOC_FREE(frame);
773 return NT_STATUS_RPC_SEC_PKG_ERROR;
776 if (sig_size != 0) {
777 memcpy(blob.data + whole_length, sig.data, sig_size);
780 *raw_packet = blob;
781 talloc_steal(mem_ctx, raw_packet->data);
782 TALLOC_FREE(frame);
783 return NT_STATUS_OK;
786 struct dcerpc_read_ncacn_packet_state {
787 #if 0
788 struct {
789 } caller;
790 #endif
791 DATA_BLOB buffer;
792 struct ncacn_packet *pkt;
795 static int dcerpc_read_ncacn_packet_next_vector(struct tstream_context *stream,
796 void *private_data,
797 TALLOC_CTX *mem_ctx,
798 struct iovec **_vector,
799 size_t *_count);
800 static void dcerpc_read_ncacn_packet_done(struct tevent_req *subreq);
802 struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
803 struct tevent_context *ev,
804 struct tstream_context *stream)
806 struct tevent_req *req;
807 struct dcerpc_read_ncacn_packet_state *state;
808 struct tevent_req *subreq;
810 req = tevent_req_create(mem_ctx, &state,
811 struct dcerpc_read_ncacn_packet_state);
812 if (req == NULL) {
813 return NULL;
816 state->pkt = talloc_zero(state, struct ncacn_packet);
817 if (tevent_req_nomem(state->pkt, req)) {
818 goto post;
821 subreq = tstream_readv_pdu_send(state, ev,
822 stream,
823 dcerpc_read_ncacn_packet_next_vector,
824 state);
825 if (tevent_req_nomem(subreq, req)) {
826 goto post;
828 tevent_req_set_callback(subreq, dcerpc_read_ncacn_packet_done, req);
830 return req;
831 post:
832 tevent_req_post(req, ev);
833 return req;
836 static int dcerpc_read_ncacn_packet_next_vector(struct tstream_context *stream,
837 void *private_data,
838 TALLOC_CTX *mem_ctx,
839 struct iovec **_vector,
840 size_t *_count)
842 struct dcerpc_read_ncacn_packet_state *state =
843 talloc_get_type_abort(private_data,
844 struct dcerpc_read_ncacn_packet_state);
845 struct iovec *vector;
846 off_t ofs = 0;
848 if (state->buffer.length == 0) {
850 * first get enough to read the fragment length
852 * We read the full fixed ncacn_packet header
853 * in order to make wireshark happy with
854 * pcap files from socket_wrapper.
856 ofs = 0;
857 state->buffer.length = DCERPC_NCACN_PAYLOAD_OFFSET;
858 state->buffer.data = talloc_array(state, uint8_t,
859 state->buffer.length);
860 if (!state->buffer.data) {
861 return -1;
863 } else if (state->buffer.length == DCERPC_NCACN_PAYLOAD_OFFSET) {
864 /* now read the fragment length and allocate the full buffer */
865 size_t frag_len = dcerpc_get_frag_length(&state->buffer);
867 ofs = state->buffer.length;
869 if (frag_len < ofs) {
871 * something is wrong, let the caller deal with it
873 *_vector = NULL;
874 *_count = 0;
875 return 0;
878 state->buffer.data = talloc_realloc(state,
879 state->buffer.data,
880 uint8_t, frag_len);
881 if (!state->buffer.data) {
882 return -1;
884 state->buffer.length = frag_len;
885 } else {
886 /* if we reach this we have a full fragment */
887 *_vector = NULL;
888 *_count = 0;
889 return 0;
892 /* now create the vector that we want to be filled */
893 vector = talloc_array(mem_ctx, struct iovec, 1);
894 if (!vector) {
895 return -1;
898 vector[0].iov_base = (void *) (state->buffer.data + ofs);
899 vector[0].iov_len = state->buffer.length - ofs;
901 *_vector = vector;
902 *_count = 1;
903 return 0;
906 static void dcerpc_read_ncacn_packet_done(struct tevent_req *subreq)
908 struct tevent_req *req = tevent_req_callback_data(subreq,
909 struct tevent_req);
910 struct dcerpc_read_ncacn_packet_state *state = tevent_req_data(req,
911 struct dcerpc_read_ncacn_packet_state);
912 int ret;
913 int sys_errno;
914 NTSTATUS status;
916 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
917 TALLOC_FREE(subreq);
918 if (ret == -1) {
919 status = map_nt_error_from_unix_common(sys_errno);
920 tevent_req_nterror(req, status);
921 return;
924 status = dcerpc_pull_ncacn_packet(state->pkt,
925 &state->buffer,
926 state->pkt);
927 if (tevent_req_nterror(req, status)) {
928 return;
931 tevent_req_done(req);
934 NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req,
935 TALLOC_CTX *mem_ctx,
936 struct ncacn_packet **pkt,
937 DATA_BLOB *buffer)
939 struct dcerpc_read_ncacn_packet_state *state = tevent_req_data(req,
940 struct dcerpc_read_ncacn_packet_state);
941 NTSTATUS status;
943 if (tevent_req_is_nterror(req, &status)) {
944 tevent_req_received(req);
945 return status;
948 *pkt = talloc_move(mem_ctx, &state->pkt);
949 if (buffer) {
950 buffer->data = talloc_move(mem_ctx, &state->buffer.data);
951 buffer->length = state->buffer.length;
954 tevent_req_received(req);
955 return NT_STATUS_OK;
958 const char *dcerpc_default_transport_endpoint(TALLOC_CTX *mem_ctx,
959 enum dcerpc_transport_t transport,
960 const struct ndr_interface_table *table)
962 NTSTATUS status;
963 const char *p = NULL;
964 const char *endpoint = NULL;
965 int i;
966 struct dcerpc_binding *default_binding = NULL;
967 TALLOC_CTX *frame = talloc_stackframe();
969 /* Find one of the default pipes for this interface */
971 for (i = 0; i < table->endpoints->count; i++) {
972 enum dcerpc_transport_t dtransport;
973 const char *dendpoint;
975 status = dcerpc_parse_binding(frame, table->endpoints->names[i],
976 &default_binding);
977 if (!NT_STATUS_IS_OK(status)) {
978 continue;
981 dtransport = dcerpc_binding_get_transport(default_binding);
982 dendpoint = dcerpc_binding_get_string_option(default_binding,
983 "endpoint");
984 if (dendpoint == NULL) {
985 TALLOC_FREE(default_binding);
986 continue;
989 if (transport == NCA_UNKNOWN) {
990 transport = dtransport;
993 if (transport != dtransport) {
994 TALLOC_FREE(default_binding);
995 continue;
998 p = dendpoint;
999 break;
1002 if (p == NULL) {
1003 goto done;
1007 * extract the pipe name without \\pipe from for example
1008 * ncacn_np:[\\pipe\\epmapper]
1010 if (transport == NCACN_NP) {
1011 if (strncasecmp(p, "\\pipe\\", 6) == 0) {
1012 p += 6;
1014 if (strncmp(p, "\\", 1) == 0) {
1015 p += 1;
1019 endpoint = talloc_strdup(mem_ctx, p);
1021 done:
1022 talloc_free(frame);
1023 return endpoint;
1026 struct dcerpc_sec_vt_header2 dcerpc_sec_vt_header2_from_ncacn_packet(const struct ncacn_packet *pkt)
1028 struct dcerpc_sec_vt_header2 ret;
1030 ZERO_STRUCT(ret);
1031 ret.ptype = pkt->ptype;
1032 memcpy(&ret.drep, pkt->drep, sizeof(ret.drep));
1033 ret.call_id = pkt->call_id;
1035 switch (pkt->ptype) {
1036 case DCERPC_PKT_REQUEST:
1037 ret.context_id = pkt->u.request.context_id;
1038 ret.opnum = pkt->u.request.opnum;
1039 break;
1041 case DCERPC_PKT_RESPONSE:
1042 ret.context_id = pkt->u.response.context_id;
1043 break;
1045 case DCERPC_PKT_FAULT:
1046 ret.context_id = pkt->u.fault.context_id;
1047 break;
1049 default:
1050 break;
1053 return ret;
1056 bool dcerpc_sec_vt_header2_equal(const struct dcerpc_sec_vt_header2 *v1,
1057 const struct dcerpc_sec_vt_header2 *v2)
1059 if (v1->ptype != v2->ptype) {
1060 return false;
1063 if (memcmp(v1->drep, v2->drep, sizeof(v1->drep)) != 0) {
1064 return false;
1067 if (v1->call_id != v2->call_id) {
1068 return false;
1071 if (v1->context_id != v2->context_id) {
1072 return false;
1075 if (v1->opnum != v2->opnum) {
1076 return false;
1079 return true;
1082 static bool dcerpc_sec_vt_is_valid(const struct dcerpc_sec_verification_trailer *r)
1084 bool ret = false;
1085 TALLOC_CTX *frame = talloc_stackframe();
1086 struct bitmap *commands_seen;
1087 int i;
1089 if (r->count.count == 0) {
1090 ret = true;
1091 goto done;
1094 if (memcmp(r->magic, DCERPC_SEC_VT_MAGIC, sizeof(r->magic)) != 0) {
1095 goto done;
1098 commands_seen = bitmap_talloc(frame, DCERPC_SEC_VT_COMMAND_ENUM + 1);
1099 if (commands_seen == NULL) {
1100 goto done;
1103 for (i=0; i < r->count.count; i++) {
1104 enum dcerpc_sec_vt_command_enum cmd =
1105 r->commands[i].command & DCERPC_SEC_VT_COMMAND_ENUM;
1107 if (bitmap_query(commands_seen, cmd)) {
1108 /* Each command must appear at most once. */
1109 goto done;
1111 bitmap_set(commands_seen, cmd);
1113 switch (cmd) {
1114 case DCERPC_SEC_VT_COMMAND_BITMASK1:
1115 case DCERPC_SEC_VT_COMMAND_PCONTEXT:
1116 case DCERPC_SEC_VT_COMMAND_HEADER2:
1117 break;
1118 default:
1119 if ((r->commands[i].u._unknown.length % 4) != 0) {
1120 goto done;
1122 break;
1125 ret = true;
1126 done:
1127 TALLOC_FREE(frame);
1128 return ret;
1131 static bool dcerpc_sec_vt_bitmask_check(const uint32_t *bitmask1,
1132 struct dcerpc_sec_vt *c)
1134 if (bitmask1 == NULL) {
1135 if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
1136 DEBUG(10, ("SEC_VT check Bitmask1 must_process_command "
1137 "failed\n"));
1138 return false;
1141 return true;
1144 if ((c->u.bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING)
1145 && (!(*bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING))) {
1146 DEBUG(10, ("SEC_VT check Bitmask1 client_header_signing "
1147 "failed\n"));
1148 return false;
1150 return true;
1153 static bool dcerpc_sec_vt_pctx_check(const struct dcerpc_sec_vt_pcontext *pcontext,
1154 struct dcerpc_sec_vt *c)
1156 TALLOC_CTX *mem_ctx;
1157 bool ok;
1159 if (pcontext == NULL) {
1160 if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
1161 DEBUG(10, ("SEC_VT check Pcontext must_process_command "
1162 "failed\n"));
1163 return false;
1166 return true;
1169 mem_ctx = talloc_stackframe();
1170 ok = ndr_syntax_id_equal(&pcontext->abstract_syntax,
1171 &c->u.pcontext.abstract_syntax);
1172 if (!ok) {
1173 DEBUG(10, ("SEC_VT check pcontext abstract_syntax failed: "
1174 "%s vs. %s\n",
1175 ndr_syntax_id_to_string(mem_ctx,
1176 &pcontext->abstract_syntax),
1177 ndr_syntax_id_to_string(mem_ctx,
1178 &c->u.pcontext.abstract_syntax)));
1179 goto err_ctx_free;
1181 ok = ndr_syntax_id_equal(&pcontext->transfer_syntax,
1182 &c->u.pcontext.transfer_syntax);
1183 if (!ok) {
1184 DEBUG(10, ("SEC_VT check pcontext transfer_syntax failed: "
1185 "%s vs. %s\n",
1186 ndr_syntax_id_to_string(mem_ctx,
1187 &pcontext->transfer_syntax),
1188 ndr_syntax_id_to_string(mem_ctx,
1189 &c->u.pcontext.transfer_syntax)));
1190 goto err_ctx_free;
1193 ok = true;
1194 err_ctx_free:
1195 talloc_free(mem_ctx);
1196 return ok;
1199 static bool dcerpc_sec_vt_hdr2_check(const struct dcerpc_sec_vt_header2 *header2,
1200 struct dcerpc_sec_vt *c)
1202 if (header2 == NULL) {
1203 if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
1204 DEBUG(10, ("SEC_VT check Header2 must_process_command failed\n"));
1205 return false;
1208 return true;
1211 if (!dcerpc_sec_vt_header2_equal(header2, &c->u.header2)) {
1212 DEBUG(10, ("SEC_VT check Header2 failed\n"));
1213 return false;
1216 return true;
1219 bool dcerpc_sec_verification_trailer_check(
1220 const struct dcerpc_sec_verification_trailer *vt,
1221 const uint32_t *bitmask1,
1222 const struct dcerpc_sec_vt_pcontext *pcontext,
1223 const struct dcerpc_sec_vt_header2 *header2)
1225 size_t i;
1227 if (!dcerpc_sec_vt_is_valid(vt)) {
1228 return false;
1231 for (i=0; i < vt->count.count; i++) {
1232 bool ok;
1233 struct dcerpc_sec_vt *c = &vt->commands[i];
1235 switch (c->command & DCERPC_SEC_VT_COMMAND_ENUM) {
1236 case DCERPC_SEC_VT_COMMAND_BITMASK1:
1237 ok = dcerpc_sec_vt_bitmask_check(bitmask1, c);
1238 if (!ok) {
1239 return false;
1241 break;
1243 case DCERPC_SEC_VT_COMMAND_PCONTEXT:
1244 ok = dcerpc_sec_vt_pctx_check(pcontext, c);
1245 if (!ok) {
1246 return false;
1248 break;
1250 case DCERPC_SEC_VT_COMMAND_HEADER2: {
1251 ok = dcerpc_sec_vt_hdr2_check(header2, c);
1252 if (!ok) {
1253 return false;
1255 break;
1258 default:
1259 if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
1260 DEBUG(10, ("SEC_VT check Unknown must_process_command failed\n"));
1261 return false;
1264 break;
1268 return true;
1271 static const struct ndr_syntax_id dcerpc_bind_time_features_prefix = {
1272 .uuid = {
1273 .time_low = 0x6cb71c2c,
1274 .time_mid = 0x9812,
1275 .time_hi_and_version = 0x4540,
1276 .clock_seq = {0x00, 0x00},
1277 .node = {0x00,0x00,0x00,0x00,0x00,0x00}
1279 .if_version = 1,
1282 bool dcerpc_extract_bind_time_features(struct ndr_syntax_id s, uint64_t *_features)
1284 uint8_t values[8];
1285 uint64_t features = 0;
1287 values[0] = s.uuid.clock_seq[0];
1288 values[1] = s.uuid.clock_seq[1];
1289 values[2] = s.uuid.node[0];
1290 values[3] = s.uuid.node[1];
1291 values[4] = s.uuid.node[2];
1292 values[5] = s.uuid.node[3];
1293 values[6] = s.uuid.node[4];
1294 values[7] = s.uuid.node[5];
1296 ZERO_STRUCT(s.uuid.clock_seq);
1297 ZERO_STRUCT(s.uuid.node);
1299 if (!ndr_syntax_id_equal(&s, &dcerpc_bind_time_features_prefix)) {
1300 if (_features != NULL) {
1301 *_features = 0;
1303 return false;
1306 features = BVAL(values, 0);
1308 if (_features != NULL) {
1309 *_features = features;
1312 return true;
1315 struct ndr_syntax_id dcerpc_construct_bind_time_features(uint64_t features)
1317 struct ndr_syntax_id s = dcerpc_bind_time_features_prefix;
1318 uint8_t values[8];
1320 SBVAL(values, 0, features);
1322 s.uuid.clock_seq[0] = values[0];
1323 s.uuid.clock_seq[1] = values[1];
1324 s.uuid.node[0] = values[2];
1325 s.uuid.node[1] = values[3];
1326 s.uuid.node[2] = values[4];
1327 s.uuid.node[3] = values[5];
1328 s.uuid.node[4] = values[6];
1329 s.uuid.node[5] = values[7];
1331 return s;