2 * DCERPC Helper routines
3 * Günther Deschner <gd@samba.org> 2010.
4 * Simo Sorce <idra@samba.org> 2010.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "librpc/rpc/dcerpc.h"
23 #include "librpc/gen_ndr/ndr_dcerpc.h"
24 #include "librpc/gen_ndr/ndr_schannel.h"
25 #include "../libcli/auth/schannel.h"
26 #include "../libcli/auth/spnego.h"
27 #include "../libcli/auth/ntlmssp.h"
28 #include "ntlmssp_wrap.h"
29 #include "librpc/crypto/gse.h"
30 #include "librpc/crypto/spnego.h"
33 #define DBGC_CLASS DBGC_RPC_PARSE
36 * @brief NDR Encodes a ncacn_packet
38 * @param mem_ctx The memory context the blob will be allocated on
39 * @param ptype The DCERPC packet type
40 * @param pfc_flags The DCERPC PFC Falgs
41 * @param auth_length The length of the trailing auth blob
42 * @param call_id The call ID
43 * @param u The payload of the packet
44 * @param blob [out] The encoded blob if successful
46 * @return an NTSTATUS error code
48 NTSTATUS
dcerpc_push_ncacn_packet(TALLOC_CTX
*mem_ctx
,
49 enum dcerpc_pkt_type ptype
,
53 union dcerpc_payload
*u
,
56 struct ncacn_packet r
;
57 enum ndr_err_code ndr_err
;
62 r
.pfc_flags
= pfc_flags
;
63 r
.drep
[0] = DCERPC_DREP_LE
;
67 r
.auth_length
= auth_length
;
71 ndr_err
= ndr_push_struct_blob(blob
, mem_ctx
, &r
,
72 (ndr_push_flags_fn_t
)ndr_push_ncacn_packet
);
73 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
74 return ndr_map_error2ntstatus(ndr_err
);
77 dcerpc_set_frag_length(blob
, blob
->length
);
80 if (DEBUGLEVEL
>= 10) {
81 /* set frag len for print function */
82 r
.frag_length
= blob
->length
;
83 NDR_PRINT_DEBUG(ncacn_packet
, &r
);
90 * @brief Decodes a ncacn_packet
92 * @param mem_ctx The memory context on which to allocate the packet
94 * @param blob The blob of data to decode
95 * @param r An empty ncacn_packet, must not be NULL
96 * @param bigendian Whether the packet is bignedian encoded
98 * @return a NTSTATUS error code
100 NTSTATUS
dcerpc_pull_ncacn_packet(TALLOC_CTX
*mem_ctx
,
101 const DATA_BLOB
*blob
,
102 struct ncacn_packet
*r
,
105 enum ndr_err_code ndr_err
;
106 struct ndr_pull
*ndr
;
108 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
110 return NT_STATUS_NO_MEMORY
;
113 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
116 if (CVAL(blob
->data
, DCERPC_PFC_OFFSET
) & DCERPC_PFC_FLAG_OBJECT_UUID
) {
117 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
120 ndr_err
= ndr_pull_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, r
);
122 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
124 return ndr_map_error2ntstatus(ndr_err
);
128 if (DEBUGLEVEL
>= 10) {
129 NDR_PRINT_DEBUG(ncacn_packet
, r
);
136 * @brief NDR Encodes a NL_AUTH_MESSAGE
138 * @param mem_ctx The memory context the blob will be allocated on
139 * @param r The NL_AUTH_MESSAGE to encode
140 * @param blob [out] The encoded blob if successful
142 * @return a NTSTATUS error code
144 NTSTATUS
dcerpc_push_schannel_bind(TALLOC_CTX
*mem_ctx
,
145 struct NL_AUTH_MESSAGE
*r
,
148 enum ndr_err_code ndr_err
;
150 ndr_err
= ndr_push_struct_blob(blob
, mem_ctx
, r
,
151 (ndr_push_flags_fn_t
)ndr_push_NL_AUTH_MESSAGE
);
152 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
153 return ndr_map_error2ntstatus(ndr_err
);
156 if (DEBUGLEVEL
>= 10) {
157 NDR_PRINT_DEBUG(NL_AUTH_MESSAGE
, r
);
164 * @brief NDR Encodes a dcerpc_auth structure
166 * @param mem_ctx The memory context the blob will be allocated on
167 * @param auth_type The DCERPC Authentication Type
168 * @param auth_level The DCERPC Authentication Level
169 * @param auth_pad_length The padding added to the packet this blob will be
171 * @param auth_context_id The context id
172 * @param credentials The authentication credentials blob (signature)
173 * @param blob [out] The encoded blob if successful
175 * @return a NTSTATUS error code
177 NTSTATUS
dcerpc_push_dcerpc_auth(TALLOC_CTX
*mem_ctx
,
178 enum dcerpc_AuthType auth_type
,
179 enum dcerpc_AuthLevel auth_level
,
180 uint8_t auth_pad_length
,
181 uint32_t auth_context_id
,
182 const DATA_BLOB
*credentials
,
185 struct dcerpc_auth r
;
186 enum ndr_err_code ndr_err
;
188 r
.auth_type
= auth_type
;
189 r
.auth_level
= auth_level
;
190 r
.auth_pad_length
= auth_pad_length
;
192 r
.auth_context_id
= auth_context_id
;
193 r
.credentials
= *credentials
;
195 ndr_err
= ndr_push_struct_blob(blob
, mem_ctx
, &r
,
196 (ndr_push_flags_fn_t
)ndr_push_dcerpc_auth
);
197 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
198 return ndr_map_error2ntstatus(ndr_err
);
201 if (DEBUGLEVEL
>= 10) {
202 NDR_PRINT_DEBUG(dcerpc_auth
, &r
);
209 * @brief Decodes a dcerpc_auth blob
211 * @param mem_ctx The memory context on which to allocate the packet
213 * @param blob The blob of data to decode
214 * @param r An empty dcerpc_auth structure, must not be NULL
216 * @return a NTSTATUS error code
218 NTSTATUS
dcerpc_pull_dcerpc_auth(TALLOC_CTX
*mem_ctx
,
219 const DATA_BLOB
*blob
,
220 struct dcerpc_auth
*r
,
223 enum ndr_err_code ndr_err
;
224 struct ndr_pull
*ndr
;
226 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
228 return NT_STATUS_NO_MEMORY
;
231 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
234 ndr_err
= ndr_pull_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, r
);
236 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
238 return ndr_map_error2ntstatus(ndr_err
);
242 if (DEBUGLEVEL
>= 10) {
243 NDR_PRINT_DEBUG(dcerpc_auth
, r
);
250 * @brief Calculate how much data we can in a packet, including calculating
251 * auth token and pad lengths.
253 * @param auth The pipe_auth_data structure for this pipe.
254 * @param header_len The length of the packet header
255 * @param data_left The data left in the send buffer
256 * @param max_xmit_frag The max fragment size.
257 * @param pad_alignment The NDR padding size.
258 * @param data_to_send [out] The max data we will send in the pdu
259 * @param frag_len [out] The total length of the fragment
260 * @param auth_len [out] The length of the auth trailer
261 * @param pad_len [out] The padding to be applied
263 * @return A NT Error status code.
265 NTSTATUS
dcerpc_guess_sizes(struct pipe_auth_data
*auth
,
266 size_t header_len
, size_t data_left
,
267 size_t max_xmit_frag
, size_t pad_alignment
,
268 size_t *data_to_send
, size_t *frag_len
,
269 size_t *auth_len
, size_t *pad_len
)
273 struct schannel_state
*schannel_auth
;
274 struct spnego_context
*spnego_ctx
;
275 struct gse_context
*gse_ctx
;
276 enum spnego_mech auth_type
;
281 /* no auth token cases first */
282 switch (auth
->auth_level
) {
283 case DCERPC_AUTH_LEVEL_NONE
:
284 case DCERPC_AUTH_LEVEL_CONNECT
:
285 case DCERPC_AUTH_LEVEL_PACKET
:
286 max_len
= max_xmit_frag
- header_len
;
287 *data_to_send
= MIN(max_len
, data_left
);
290 *frag_len
= header_len
+ *data_to_send
;
293 case DCERPC_AUTH_LEVEL_PRIVACY
:
297 case DCERPC_AUTH_LEVEL_INTEGRITY
:
301 return NT_STATUS_INVALID_PARAMETER
;
305 /* Sign/seal case, calculate auth and pad lengths */
307 max_len
= max_xmit_frag
- header_len
- DCERPC_AUTH_TRAILER_LENGTH
;
309 /* Treat the same for all authenticated rpc requests. */
310 switch (auth
->auth_type
) {
311 case DCERPC_AUTH_TYPE_SPNEGO
:
312 spnego_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
313 struct spnego_context
);
314 status
= spnego_get_negotiated_mech(spnego_ctx
,
315 &auth_type
, &auth_ctx
);
316 if (!NT_STATUS_IS_OK(status
)) {
321 *auth_len
= NTLMSSP_SIG_SIZE
;
325 gse_ctx
= talloc_get_type_abort(auth_ctx
,
328 return NT_STATUS_INVALID_PARAMETER
;
330 *auth_len
= gse_get_signature_length(gse_ctx
,
335 return NT_STATUS_INVALID_PARAMETER
;
339 case DCERPC_AUTH_TYPE_NTLMSSP
:
340 *auth_len
= NTLMSSP_SIG_SIZE
;
343 case DCERPC_AUTH_TYPE_SCHANNEL
:
344 schannel_auth
= talloc_get_type_abort(auth
->auth_ctx
,
345 struct schannel_state
);
346 *auth_len
= netsec_outgoing_sig_size(schannel_auth
);
349 case DCERPC_AUTH_TYPE_KRB5
:
350 gse_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
352 *auth_len
= gse_get_signature_length(gse_ctx
,
357 return NT_STATUS_INVALID_PARAMETER
;
360 max_len
-= *auth_len
;
362 *data_to_send
= MIN(max_len
, data_left
);
364 mod_len
= (header_len
+ *data_to_send
) % pad_alignment
;
366 *pad_len
= pad_alignment
- mod_len
;
371 if (*data_to_send
+ *pad_len
> max_len
) {
372 *data_to_send
-= pad_alignment
;
375 *frag_len
= header_len
+ *data_to_send
+ *pad_len
376 + DCERPC_AUTH_TRAILER_LENGTH
+ *auth_len
;
381 /*******************************************************************
382 Create and add the NTLMSSP sign/seal auth data.
383 ********************************************************************/
385 static NTSTATUS
add_ntlmssp_auth_footer(struct auth_ntlmssp_state
*auth_state
,
386 enum dcerpc_AuthLevel auth_level
,
389 uint16_t data_and_pad_len
= rpc_out
->length
390 - DCERPC_RESPONSE_LENGTH
391 - DCERPC_AUTH_TRAILER_LENGTH
;
396 return NT_STATUS_INVALID_PARAMETER
;
399 switch (auth_level
) {
400 case DCERPC_AUTH_LEVEL_PRIVACY
:
401 /* Data portion is encrypted. */
402 status
= auth_ntlmssp_seal_packet(auth_state
,
405 + DCERPC_RESPONSE_LENGTH
,
410 if (!NT_STATUS_IS_OK(status
)) {
415 case DCERPC_AUTH_LEVEL_INTEGRITY
:
416 /* Data is signed. */
417 status
= auth_ntlmssp_sign_packet(auth_state
,
420 + DCERPC_RESPONSE_LENGTH
,
425 if (!NT_STATUS_IS_OK(status
)) {
432 smb_panic("bad auth level");
434 return NT_STATUS_INVALID_PARAMETER
;
437 /* Finally attach the blob. */
438 if (!data_blob_append(NULL
, rpc_out
,
439 auth_blob
.data
, auth_blob
.length
)) {
440 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
441 (unsigned int)auth_blob
.length
));
442 return NT_STATUS_NO_MEMORY
;
444 data_blob_free(&auth_blob
);
449 /*******************************************************************
450 Check/unseal the NTLMSSP auth data. (Unseal in place).
451 ********************************************************************/
453 static NTSTATUS
get_ntlmssp_auth_footer(struct auth_ntlmssp_state
*auth_state
,
454 enum dcerpc_AuthLevel auth_level
,
455 DATA_BLOB
*data
, DATA_BLOB
*full_pkt
,
456 DATA_BLOB
*auth_token
)
458 switch (auth_level
) {
459 case DCERPC_AUTH_LEVEL_PRIVACY
:
460 /* Data portion is encrypted. */
461 return auth_ntlmssp_unseal_packet(auth_state
,
468 case DCERPC_AUTH_LEVEL_INTEGRITY
:
469 /* Data is signed. */
470 return auth_ntlmssp_check_packet(auth_state
,
478 return NT_STATUS_INVALID_PARAMETER
;
482 /*******************************************************************
483 Create and add the schannel sign/seal auth data.
484 ********************************************************************/
486 static NTSTATUS
add_schannel_auth_footer(struct schannel_state
*sas
,
487 enum dcerpc_AuthLevel auth_level
,
490 uint8_t *data_p
= rpc_out
->data
+ DCERPC_RESPONSE_LENGTH
;
491 size_t data_and_pad_len
= rpc_out
->length
492 - DCERPC_RESPONSE_LENGTH
493 - DCERPC_AUTH_TRAILER_LENGTH
;
498 return NT_STATUS_INVALID_PARAMETER
;
501 DEBUG(10,("add_schannel_auth_footer: SCHANNEL seq_num=%d\n",
504 switch (auth_level
) {
505 case DCERPC_AUTH_LEVEL_PRIVACY
:
506 status
= netsec_outgoing_packet(sas
,
513 case DCERPC_AUTH_LEVEL_INTEGRITY
:
514 status
= netsec_outgoing_packet(sas
,
522 status
= NT_STATUS_INTERNAL_ERROR
;
526 if (!NT_STATUS_IS_OK(status
)) {
527 DEBUG(1,("add_schannel_auth_footer: failed to process packet: %s\n",
532 if (DEBUGLEVEL
>= 10) {
533 dump_NL_AUTH_SIGNATURE(talloc_tos(), &auth_blob
);
536 /* Finally attach the blob. */
537 if (!data_blob_append(NULL
, rpc_out
,
538 auth_blob
.data
, auth_blob
.length
)) {
539 return NT_STATUS_NO_MEMORY
;
541 data_blob_free(&auth_blob
);
546 /*******************************************************************
547 Check/unseal the Schannel auth data. (Unseal in place).
548 ********************************************************************/
550 static NTSTATUS
get_schannel_auth_footer(TALLOC_CTX
*mem_ctx
,
551 struct schannel_state
*auth_state
,
552 enum dcerpc_AuthLevel auth_level
,
553 DATA_BLOB
*data
, DATA_BLOB
*full_pkt
,
554 DATA_BLOB
*auth_token
)
556 switch (auth_level
) {
557 case DCERPC_AUTH_LEVEL_PRIVACY
:
558 /* Data portion is encrypted. */
559 return netsec_incoming_packet(auth_state
,
565 case DCERPC_AUTH_LEVEL_INTEGRITY
:
566 /* Data is signed. */
567 return netsec_incoming_packet(auth_state
,
574 return NT_STATUS_INVALID_PARAMETER
;
578 /*******************************************************************
579 Create and add the gssapi sign/seal auth data.
580 ********************************************************************/
582 static NTSTATUS
add_gssapi_auth_footer(struct gse_context
*gse_ctx
,
583 enum dcerpc_AuthLevel auth_level
,
591 return NT_STATUS_INVALID_PARAMETER
;
594 data
.data
= rpc_out
->data
+ DCERPC_RESPONSE_LENGTH
;
595 data
.length
= rpc_out
->length
- DCERPC_RESPONSE_LENGTH
596 - DCERPC_AUTH_TRAILER_LENGTH
;
598 switch (auth_level
) {
599 case DCERPC_AUTH_LEVEL_PRIVACY
:
600 status
= gse_seal(talloc_tos(), gse_ctx
, &data
, &auth_blob
);
602 case DCERPC_AUTH_LEVEL_INTEGRITY
:
603 status
= gse_sign(talloc_tos(), gse_ctx
, &data
, &auth_blob
);
606 status
= NT_STATUS_INTERNAL_ERROR
;
610 if (!NT_STATUS_IS_OK(status
)) {
611 DEBUG(1, ("Failed to process packet: %s\n",
616 /* Finally attach the blob. */
617 if (!data_blob_append(NULL
, rpc_out
,
618 auth_blob
.data
, auth_blob
.length
)) {
619 return NT_STATUS_NO_MEMORY
;
622 data_blob_free(&auth_blob
);
627 /*******************************************************************
628 Check/unseal the gssapi auth data. (Unseal in place).
629 ********************************************************************/
631 static NTSTATUS
get_gssapi_auth_footer(TALLOC_CTX
*mem_ctx
,
632 struct gse_context
*gse_ctx
,
633 enum dcerpc_AuthLevel auth_level
,
634 DATA_BLOB
*data
, DATA_BLOB
*full_pkt
,
635 DATA_BLOB
*auth_token
)
637 /* TODO: pass in full_pkt when
638 * DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN is set */
639 switch (auth_level
) {
640 case DCERPC_AUTH_LEVEL_PRIVACY
:
641 /* Data portion is encrypted. */
642 return gse_unseal(mem_ctx
, gse_ctx
,
645 case DCERPC_AUTH_LEVEL_INTEGRITY
:
646 /* Data is signed. */
647 return gse_sigcheck(mem_ctx
, gse_ctx
,
650 return NT_STATUS_INVALID_PARAMETER
;
654 /*******************************************************************
655 Create and add the spnego-negotiated sign/seal auth data.
656 ********************************************************************/
658 static NTSTATUS
add_spnego_auth_footer(struct spnego_context
*spnego_ctx
,
659 enum dcerpc_AuthLevel auth_level
,
667 return NT_STATUS_INVALID_PARAMETER
;
670 rpc_data
= data_blob_const(rpc_out
->data
671 + DCERPC_RESPONSE_LENGTH
,
673 - DCERPC_RESPONSE_LENGTH
674 - DCERPC_AUTH_TRAILER_LENGTH
);
676 switch (auth_level
) {
677 case DCERPC_AUTH_LEVEL_PRIVACY
:
678 /* Data portion is encrypted. */
679 status
= spnego_seal(rpc_out
->data
, spnego_ctx
,
680 &rpc_data
, rpc_out
, &auth_blob
);
683 if (!NT_STATUS_IS_OK(status
)) {
688 case DCERPC_AUTH_LEVEL_INTEGRITY
:
689 /* Data is signed. */
690 status
= spnego_sign(rpc_out
->data
, spnego_ctx
,
691 &rpc_data
, rpc_out
, &auth_blob
);
694 if (!NT_STATUS_IS_OK(status
)) {
701 smb_panic("bad auth level");
703 return NT_STATUS_INVALID_PARAMETER
;
706 /* Finally attach the blob. */
707 if (!data_blob_append(NULL
, rpc_out
,
708 auth_blob
.data
, auth_blob
.length
)) {
709 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
710 (unsigned int)auth_blob
.length
));
711 return NT_STATUS_NO_MEMORY
;
713 data_blob_free(&auth_blob
);
718 static NTSTATUS
get_spnego_auth_footer(TALLOC_CTX
*mem_ctx
,
719 struct spnego_context
*sp_ctx
,
720 enum dcerpc_AuthLevel auth_level
,
721 DATA_BLOB
*data
, DATA_BLOB
*full_pkt
,
722 DATA_BLOB
*auth_token
)
724 switch (auth_level
) {
725 case DCERPC_AUTH_LEVEL_PRIVACY
:
726 /* Data portion is encrypted. */
727 return spnego_unseal(mem_ctx
, sp_ctx
,
728 data
, full_pkt
, auth_token
);
730 case DCERPC_AUTH_LEVEL_INTEGRITY
:
731 /* Data is signed. */
732 return spnego_sigcheck(mem_ctx
, sp_ctx
,
733 data
, full_pkt
, auth_token
);
736 return NT_STATUS_INVALID_PARAMETER
;
741 * @brief Append an auth footer according to what is the current mechanism
743 * @param auth The pipe_auth_data associated with the connection
744 * @param pad_len The padding used in the packet
745 * @param rpc_out Packet blob up to and including the auth header
747 * @return A NTSTATUS error code.
749 NTSTATUS
dcerpc_add_auth_footer(struct pipe_auth_data
*auth
,
750 size_t pad_len
, DATA_BLOB
*rpc_out
)
752 struct schannel_state
*schannel_auth
;
753 struct auth_ntlmssp_state
*ntlmssp_ctx
;
754 struct spnego_context
*spnego_ctx
;
755 struct gse_context
*gse_ctx
;
756 char pad
[CLIENT_NDR_PADDING_SIZE
] = { 0, };
761 if (auth
->auth_type
== DCERPC_AUTH_TYPE_NONE
||
762 auth
->auth_type
== DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM
) {
767 /* Copy the sign/seal padding data. */
768 if (!data_blob_append(NULL
, rpc_out
, pad
, pad_len
)) {
769 return NT_STATUS_NO_MEMORY
;
773 /* marshall the dcerpc_auth with an actually empty auth_blob.
774 * This is needed because the ntmlssp signature includes the
775 * auth header. We will append the actual blob later. */
776 auth_blob
= data_blob_null
;
777 status
= dcerpc_push_dcerpc_auth(rpc_out
->data
,
784 if (!NT_STATUS_IS_OK(status
)) {
788 /* append the header */
789 if (!data_blob_append(NULL
, rpc_out
,
790 auth_info
.data
, auth_info
.length
)) {
791 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
792 (unsigned int)auth_info
.length
));
793 return NT_STATUS_NO_MEMORY
;
795 data_blob_free(&auth_info
);
797 /* Generate any auth sign/seal and add the auth footer. */
798 switch (auth
->auth_type
) {
799 case DCERPC_AUTH_TYPE_NONE
:
800 case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM
:
801 status
= NT_STATUS_OK
;
803 case DCERPC_AUTH_TYPE_SPNEGO
:
804 spnego_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
805 struct spnego_context
);
806 status
= add_spnego_auth_footer(spnego_ctx
,
807 auth
->auth_level
, rpc_out
);
809 case DCERPC_AUTH_TYPE_NTLMSSP
:
810 ntlmssp_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
811 struct auth_ntlmssp_state
);
812 status
= add_ntlmssp_auth_footer(ntlmssp_ctx
,
816 case DCERPC_AUTH_TYPE_SCHANNEL
:
817 schannel_auth
= talloc_get_type_abort(auth
->auth_ctx
,
818 struct schannel_state
);
819 status
= add_schannel_auth_footer(schannel_auth
,
823 case DCERPC_AUTH_TYPE_KRB5
:
824 gse_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
826 status
= add_gssapi_auth_footer(gse_ctx
,
831 status
= NT_STATUS_INVALID_PARAMETER
;
839 * @brief Check authentication for request/response packets
841 * @param auth The auth data for the connection
842 * @param pkt The actual ncacn_packet
843 * @param pkt_trailer The stub_and_verifier part of the packet
844 * @param header_size The header size
845 * @param raw_pkt The whole raw packet data blob
846 * @param pad_len [out] The padding length used in the packet
848 * @return A NTSTATUS error code
850 NTSTATUS
dcerpc_check_auth(struct pipe_auth_data
*auth
,
851 struct ncacn_packet
*pkt
,
852 DATA_BLOB
*pkt_trailer
,
857 struct schannel_state
*schannel_auth
;
858 struct auth_ntlmssp_state
*ntlmssp_ctx
;
859 struct spnego_context
*spnego_ctx
;
860 struct gse_context
*gse_ctx
;
862 struct dcerpc_auth auth_info
;
863 uint32_t auth_length
;
867 switch (auth
->auth_level
) {
868 case DCERPC_AUTH_LEVEL_PRIVACY
:
869 DEBUG(10, ("Requested Privacy.\n"));
872 case DCERPC_AUTH_LEVEL_INTEGRITY
:
873 DEBUG(10, ("Requested Integrity.\n"));
876 case DCERPC_AUTH_LEVEL_CONNECT
:
877 if (pkt
->auth_length
!= 0) {
883 case DCERPC_AUTH_LEVEL_NONE
:
884 if (pkt
->auth_length
!= 0) {
885 DEBUG(3, ("Got non-zero auth len on non "
886 "authenticated connection!\n"));
887 return NT_STATUS_INVALID_PARAMETER
;
893 DEBUG(3, ("Unimplemented Auth Level %d",
895 return NT_STATUS_INVALID_PARAMETER
;
898 /* Paranioa checks for auth_length. */
899 if (pkt
->auth_length
> pkt
->frag_length
) {
900 return NT_STATUS_INFO_LENGTH_MISMATCH
;
902 if (((unsigned int)pkt
->auth_length
903 + DCERPC_AUTH_TRAILER_LENGTH
< (unsigned int)pkt
->auth_length
) ||
904 ((unsigned int)pkt
->auth_length
905 + DCERPC_AUTH_TRAILER_LENGTH
< DCERPC_AUTH_TRAILER_LENGTH
)) {
906 /* Integer wrap attempt. */
907 return NT_STATUS_INFO_LENGTH_MISMATCH
;
910 status
= dcerpc_pull_auth_trailer(pkt
, pkt
, pkt_trailer
,
911 &auth_info
, &auth_length
, false);
912 if (!NT_STATUS_IS_OK(status
)) {
916 data
= data_blob_const(raw_pkt
->data
+ header_size
,
917 pkt_trailer
->length
- auth_length
);
918 full_pkt
= data_blob_const(raw_pkt
->data
,
919 raw_pkt
->length
- auth_info
.credentials
.length
);
921 switch (auth
->auth_type
) {
922 case DCERPC_AUTH_TYPE_NONE
:
923 case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM
:
926 case DCERPC_AUTH_TYPE_SPNEGO
:
927 spnego_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
928 struct spnego_context
);
929 status
= get_spnego_auth_footer(pkt
, spnego_ctx
,
932 &auth_info
.credentials
);
933 if (!NT_STATUS_IS_OK(status
)) {
938 case DCERPC_AUTH_TYPE_NTLMSSP
:
940 DEBUG(10, ("NTLMSSP auth\n"));
942 ntlmssp_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
943 struct auth_ntlmssp_state
);
944 status
= get_ntlmssp_auth_footer(ntlmssp_ctx
,
947 &auth_info
.credentials
);
948 if (!NT_STATUS_IS_OK(status
)) {
953 case DCERPC_AUTH_TYPE_SCHANNEL
:
955 DEBUG(10, ("SCHANNEL auth\n"));
957 schannel_auth
= talloc_get_type_abort(auth
->auth_ctx
,
958 struct schannel_state
);
959 status
= get_schannel_auth_footer(pkt
, schannel_auth
,
962 &auth_info
.credentials
);
963 if (!NT_STATUS_IS_OK(status
)) {
968 case DCERPC_AUTH_TYPE_KRB5
:
970 DEBUG(10, ("KRB5 auth\n"));
972 gse_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
974 status
= get_gssapi_auth_footer(pkt
, gse_ctx
,
977 &auth_info
.credentials
);
978 if (!NT_STATUS_IS_OK(status
)) {
984 DEBUG(0, ("process_request_pdu: "
985 "unknown auth type %u set.\n",
986 (unsigned int)auth
->auth_type
));
987 return NT_STATUS_INVALID_PARAMETER
;
990 /* TODO: remove later
991 * this is still needed because in the server code the
992 * pkt_trailer actually has a copy of the raw data, and they
993 * are still both used in later calls */
994 if (auth
->auth_level
== DCERPC_AUTH_LEVEL_PRIVACY
) {
995 memcpy(pkt_trailer
->data
, data
.data
, data
.length
);
998 *pad_len
= auth_info
.auth_pad_length
;
999 data_blob_free(&auth_info
.credentials
);
1000 return NT_STATUS_OK
;