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"
34 #define DBGC_CLASS DBGC_RPC_PARSE
37 * @brief NDR Encodes a ncacn_packet
39 * @param mem_ctx The memory context the blob will be allocated on
40 * @param ptype The DCERPC packet type
41 * @param pfc_flags The DCERPC PFC Falgs
42 * @param auth_length The length of the trailing auth blob
43 * @param call_id The call ID
44 * @param u The payload of the packet
45 * @param blob [out] The encoded blob if successful
47 * @return an NTSTATUS error code
49 NTSTATUS
dcerpc_push_ncacn_packet(TALLOC_CTX
*mem_ctx
,
50 enum dcerpc_pkt_type ptype
,
54 union dcerpc_payload
*u
,
57 struct ncacn_packet r
;
58 enum ndr_err_code ndr_err
;
63 r
.pfc_flags
= pfc_flags
;
64 r
.drep
[0] = DCERPC_DREP_LE
;
68 r
.auth_length
= auth_length
;
72 ndr_err
= ndr_push_struct_blob(blob
, mem_ctx
, &r
,
73 (ndr_push_flags_fn_t
)ndr_push_ncacn_packet
);
74 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
75 return ndr_map_error2ntstatus(ndr_err
);
78 dcerpc_set_frag_length(blob
, blob
->length
);
81 if (DEBUGLEVEL
>= 10) {
82 /* set frag len for print function */
83 r
.frag_length
= blob
->length
;
84 NDR_PRINT_DEBUG(ncacn_packet
, &r
);
91 * @brief Decodes a ncacn_packet
93 * @param mem_ctx The memory context on which to allocate the packet
95 * @param blob The blob of data to decode
96 * @param r An empty ncacn_packet, must not be NULL
97 * @param bigendian Whether the packet is bignedian encoded
99 * @return a NTSTATUS error code
101 NTSTATUS
dcerpc_pull_ncacn_packet(TALLOC_CTX
*mem_ctx
,
102 const DATA_BLOB
*blob
,
103 struct ncacn_packet
*r
,
106 enum ndr_err_code ndr_err
;
107 struct ndr_pull
*ndr
;
109 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
111 return NT_STATUS_NO_MEMORY
;
114 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
117 ndr_err
= ndr_pull_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, r
);
119 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
121 return ndr_map_error2ntstatus(ndr_err
);
125 if (DEBUGLEVEL
>= 10) {
126 NDR_PRINT_DEBUG(ncacn_packet
, r
);
133 * @brief NDR Encodes a NL_AUTH_MESSAGE
135 * @param mem_ctx The memory context the blob will be allocated on
136 * @param r The NL_AUTH_MESSAGE to encode
137 * @param blob [out] The encoded blob if successful
139 * @return a NTSTATUS error code
141 NTSTATUS
dcerpc_push_schannel_bind(TALLOC_CTX
*mem_ctx
,
142 struct NL_AUTH_MESSAGE
*r
,
145 enum ndr_err_code ndr_err
;
147 ndr_err
= ndr_push_struct_blob(blob
, mem_ctx
, r
,
148 (ndr_push_flags_fn_t
)ndr_push_NL_AUTH_MESSAGE
);
149 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
150 return ndr_map_error2ntstatus(ndr_err
);
153 if (DEBUGLEVEL
>= 10) {
154 NDR_PRINT_DEBUG(NL_AUTH_MESSAGE
, r
);
161 * @brief NDR Encodes a dcerpc_auth structure
163 * @param mem_ctx The memory context the blob will be allocated on
164 * @param auth_type The DCERPC Authentication Type
165 * @param auth_level The DCERPC Authentication Level
166 * @param auth_pad_length The padding added to the packet this blob will be
168 * @param auth_context_id The context id
169 * @param credentials The authentication credentials blob (signature)
170 * @param blob [out] The encoded blob if successful
172 * @return a NTSTATUS error code
174 NTSTATUS
dcerpc_push_dcerpc_auth(TALLOC_CTX
*mem_ctx
,
175 enum dcerpc_AuthType auth_type
,
176 enum dcerpc_AuthLevel auth_level
,
177 uint8_t auth_pad_length
,
178 uint32_t auth_context_id
,
179 const DATA_BLOB
*credentials
,
182 struct dcerpc_auth r
;
183 enum ndr_err_code ndr_err
;
185 r
.auth_type
= auth_type
;
186 r
.auth_level
= auth_level
;
187 r
.auth_pad_length
= auth_pad_length
;
189 r
.auth_context_id
= auth_context_id
;
190 r
.credentials
= *credentials
;
192 ndr_err
= ndr_push_struct_blob(blob
, mem_ctx
, &r
,
193 (ndr_push_flags_fn_t
)ndr_push_dcerpc_auth
);
194 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
195 return ndr_map_error2ntstatus(ndr_err
);
198 if (DEBUGLEVEL
>= 10) {
199 NDR_PRINT_DEBUG(dcerpc_auth
, &r
);
206 * @brief Decodes a dcerpc_auth blob
208 * @param mem_ctx The memory context on which to allocate the packet
210 * @param blob The blob of data to decode
211 * @param r An empty dcerpc_auth structure, must not be NULL
213 * @return a NTSTATUS error code
215 NTSTATUS
dcerpc_pull_dcerpc_auth(TALLOC_CTX
*mem_ctx
,
216 const DATA_BLOB
*blob
,
217 struct dcerpc_auth
*r
,
220 enum ndr_err_code ndr_err
;
221 struct ndr_pull
*ndr
;
223 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
225 return NT_STATUS_NO_MEMORY
;
228 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
231 ndr_err
= ndr_pull_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, r
);
233 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
235 return ndr_map_error2ntstatus(ndr_err
);
239 if (DEBUGLEVEL
>= 10) {
240 NDR_PRINT_DEBUG(dcerpc_auth
, r
);
247 * @brief Calculate how much data we can in a packet, including calculating
248 * auth token and pad lengths.
250 * @param auth The pipe_auth_data structure for this pipe.
251 * @param header_len The length of the packet header
252 * @param data_left The data left in the send buffer
253 * @param max_xmit_frag The max fragment size.
254 * @param pad_alignment The NDR padding size.
255 * @param data_to_send [out] The max data we will send in the pdu
256 * @param frag_len [out] The total length of the fragment
257 * @param auth_len [out] The length of the auth trailer
258 * @param pad_len [out] The padding to be applied
260 * @return A NT Error status code.
262 NTSTATUS
dcerpc_guess_sizes(struct pipe_auth_data
*auth
,
263 size_t header_len
, size_t data_left
,
264 size_t max_xmit_frag
, size_t pad_alignment
,
265 size_t *data_to_send
, size_t *frag_len
,
266 size_t *auth_len
, size_t *pad_len
)
270 struct schannel_state
*schannel_auth
;
271 struct spnego_context
*spnego_ctx
;
272 struct gse_context
*gse_ctx
;
273 enum spnego_mech auth_type
;
278 /* no auth token cases first */
279 switch (auth
->auth_level
) {
280 case DCERPC_AUTH_LEVEL_NONE
:
281 case DCERPC_AUTH_LEVEL_CONNECT
:
282 case DCERPC_AUTH_LEVEL_PACKET
:
283 max_len
= max_xmit_frag
- header_len
;
284 *data_to_send
= MIN(max_len
, data_left
);
287 *frag_len
= header_len
+ *data_to_send
;
290 case DCERPC_AUTH_LEVEL_PRIVACY
:
294 case DCERPC_AUTH_LEVEL_INTEGRITY
:
298 return NT_STATUS_INVALID_PARAMETER
;
302 /* Sign/seal case, calculate auth and pad lengths */
304 max_len
= max_xmit_frag
- header_len
- DCERPC_AUTH_TRAILER_LENGTH
;
306 /* Treat the same for all authenticated rpc requests. */
307 switch (auth
->auth_type
) {
308 case DCERPC_AUTH_TYPE_SPNEGO
:
309 spnego_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
310 struct spnego_context
);
311 status
= spnego_get_negotiated_mech(spnego_ctx
,
312 &auth_type
, &auth_ctx
);
313 if (!NT_STATUS_IS_OK(status
)) {
318 *auth_len
= NTLMSSP_SIG_SIZE
;
322 gse_ctx
= talloc_get_type_abort(auth_ctx
,
325 return NT_STATUS_INVALID_PARAMETER
;
327 *auth_len
= gse_get_signature_length(gse_ctx
,
332 return NT_STATUS_INVALID_PARAMETER
;
336 case DCERPC_AUTH_TYPE_NTLMSSP
:
337 *auth_len
= NTLMSSP_SIG_SIZE
;
340 case DCERPC_AUTH_TYPE_SCHANNEL
:
341 schannel_auth
= talloc_get_type_abort(auth
->auth_ctx
,
342 struct schannel_state
);
343 *auth_len
= netsec_outgoing_sig_size(schannel_auth
);
346 case DCERPC_AUTH_TYPE_KRB5
:
347 gse_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
349 *auth_len
= gse_get_signature_length(gse_ctx
,
354 return NT_STATUS_INVALID_PARAMETER
;
357 max_len
-= *auth_len
;
359 *data_to_send
= MIN(max_len
, data_left
);
361 mod_len
= (header_len
+ *data_to_send
) % pad_alignment
;
363 *pad_len
= pad_alignment
- mod_len
;
368 if (*data_to_send
+ *pad_len
> max_len
) {
369 *data_to_send
-= pad_alignment
;
372 *frag_len
= header_len
+ *data_to_send
+ *pad_len
373 + DCERPC_AUTH_TRAILER_LENGTH
+ *auth_len
;
378 /*******************************************************************
379 Create and add the NTLMSSP sign/seal auth data.
380 ********************************************************************/
382 static NTSTATUS
add_ntlmssp_auth_footer(struct auth_ntlmssp_state
*auth_state
,
383 enum dcerpc_AuthLevel auth_level
,
386 uint16_t data_and_pad_len
= rpc_out
->length
387 - DCERPC_RESPONSE_LENGTH
388 - DCERPC_AUTH_TRAILER_LENGTH
;
393 return NT_STATUS_INVALID_PARAMETER
;
396 switch (auth_level
) {
397 case DCERPC_AUTH_LEVEL_PRIVACY
:
398 /* Data portion is encrypted. */
399 status
= auth_ntlmssp_seal_packet(auth_state
,
402 + DCERPC_RESPONSE_LENGTH
,
407 if (!NT_STATUS_IS_OK(status
)) {
412 case DCERPC_AUTH_LEVEL_INTEGRITY
:
413 /* Data is signed. */
414 status
= auth_ntlmssp_sign_packet(auth_state
,
417 + DCERPC_RESPONSE_LENGTH
,
422 if (!NT_STATUS_IS_OK(status
)) {
429 smb_panic("bad auth level");
431 return NT_STATUS_INVALID_PARAMETER
;
434 /* Finally attach the blob. */
435 if (!data_blob_append(NULL
, rpc_out
,
436 auth_blob
.data
, auth_blob
.length
)) {
437 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
438 (unsigned int)auth_blob
.length
));
439 return NT_STATUS_NO_MEMORY
;
441 data_blob_free(&auth_blob
);
446 /*******************************************************************
447 Check/unseal the NTLMSSP auth data. (Unseal in place).
448 ********************************************************************/
450 static NTSTATUS
get_ntlmssp_auth_footer(struct auth_ntlmssp_state
*auth_state
,
451 enum dcerpc_AuthLevel auth_level
,
452 DATA_BLOB
*data
, DATA_BLOB
*full_pkt
,
453 DATA_BLOB
*auth_token
)
455 switch (auth_level
) {
456 case DCERPC_AUTH_LEVEL_PRIVACY
:
457 /* Data portion is encrypted. */
458 return auth_ntlmssp_unseal_packet(auth_state
,
465 case DCERPC_AUTH_LEVEL_INTEGRITY
:
466 /* Data is signed. */
467 return auth_ntlmssp_check_packet(auth_state
,
475 return NT_STATUS_INVALID_PARAMETER
;
479 /*******************************************************************
480 Create and add the schannel sign/seal auth data.
481 ********************************************************************/
483 static NTSTATUS
add_schannel_auth_footer(struct schannel_state
*sas
,
484 enum dcerpc_AuthLevel auth_level
,
487 uint8_t *data_p
= rpc_out
->data
+ DCERPC_RESPONSE_LENGTH
;
488 size_t data_and_pad_len
= rpc_out
->length
489 - DCERPC_RESPONSE_LENGTH
490 - DCERPC_AUTH_TRAILER_LENGTH
;
495 return NT_STATUS_INVALID_PARAMETER
;
498 DEBUG(10,("add_schannel_auth_footer: SCHANNEL seq_num=%d\n",
501 switch (auth_level
) {
502 case DCERPC_AUTH_LEVEL_PRIVACY
:
503 status
= netsec_outgoing_packet(sas
,
510 case DCERPC_AUTH_LEVEL_INTEGRITY
:
511 status
= netsec_outgoing_packet(sas
,
519 status
= NT_STATUS_INTERNAL_ERROR
;
523 if (!NT_STATUS_IS_OK(status
)) {
524 DEBUG(1,("add_schannel_auth_footer: failed to process packet: %s\n",
529 if (DEBUGLEVEL
>= 10) {
530 dump_NL_AUTH_SIGNATURE(talloc_tos(), &auth_blob
);
533 /* Finally attach the blob. */
534 if (!data_blob_append(NULL
, rpc_out
,
535 auth_blob
.data
, auth_blob
.length
)) {
536 return NT_STATUS_NO_MEMORY
;
538 data_blob_free(&auth_blob
);
543 /*******************************************************************
544 Check/unseal the Schannel auth data. (Unseal in place).
545 ********************************************************************/
547 static NTSTATUS
get_schannel_auth_footer(TALLOC_CTX
*mem_ctx
,
548 struct schannel_state
*auth_state
,
549 enum dcerpc_AuthLevel auth_level
,
550 DATA_BLOB
*data
, DATA_BLOB
*full_pkt
,
551 DATA_BLOB
*auth_token
)
553 switch (auth_level
) {
554 case DCERPC_AUTH_LEVEL_PRIVACY
:
555 /* Data portion is encrypted. */
556 return netsec_incoming_packet(auth_state
,
562 case DCERPC_AUTH_LEVEL_INTEGRITY
:
563 /* Data is signed. */
564 return netsec_incoming_packet(auth_state
,
571 return NT_STATUS_INVALID_PARAMETER
;
575 /*******************************************************************
576 Create and add the gssapi sign/seal auth data.
577 ********************************************************************/
579 static NTSTATUS
add_gssapi_auth_footer(struct gse_context
*gse_ctx
,
580 enum dcerpc_AuthLevel auth_level
,
588 return NT_STATUS_INVALID_PARAMETER
;
591 data
.data
= rpc_out
->data
+ DCERPC_RESPONSE_LENGTH
;
592 data
.length
= rpc_out
->length
- DCERPC_RESPONSE_LENGTH
593 - DCERPC_AUTH_TRAILER_LENGTH
;
595 switch (auth_level
) {
596 case DCERPC_AUTH_LEVEL_PRIVACY
:
597 status
= gse_seal(talloc_tos(), gse_ctx
, &data
, &auth_blob
);
599 case DCERPC_AUTH_LEVEL_INTEGRITY
:
600 status
= gse_sign(talloc_tos(), gse_ctx
, &data
, &auth_blob
);
603 status
= NT_STATUS_INTERNAL_ERROR
;
607 if (!NT_STATUS_IS_OK(status
)) {
608 DEBUG(1, ("Failed to process packet: %s\n",
613 /* Finally attach the blob. */
614 if (!data_blob_append(NULL
, rpc_out
,
615 auth_blob
.data
, auth_blob
.length
)) {
616 return NT_STATUS_NO_MEMORY
;
619 data_blob_free(&auth_blob
);
624 /*******************************************************************
625 Check/unseal the gssapi auth data. (Unseal in place).
626 ********************************************************************/
628 static NTSTATUS
get_gssapi_auth_footer(TALLOC_CTX
*mem_ctx
,
629 struct gse_context
*gse_ctx
,
630 enum dcerpc_AuthLevel auth_level
,
631 DATA_BLOB
*data
, DATA_BLOB
*full_pkt
,
632 DATA_BLOB
*auth_token
)
634 /* TODO: pass in full_pkt when
635 * DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN is set */
636 switch (auth_level
) {
637 case DCERPC_AUTH_LEVEL_PRIVACY
:
638 /* Data portion is encrypted. */
639 return gse_unseal(mem_ctx
, gse_ctx
,
642 case DCERPC_AUTH_LEVEL_INTEGRITY
:
643 /* Data is signed. */
644 return gse_sigcheck(mem_ctx
, gse_ctx
,
647 return NT_STATUS_INVALID_PARAMETER
;
651 /*******************************************************************
652 Create and add the spnego-negotiated sign/seal auth data.
653 ********************************************************************/
655 static NTSTATUS
add_spnego_auth_footer(struct spnego_context
*spnego_ctx
,
656 enum dcerpc_AuthLevel auth_level
,
664 return NT_STATUS_INVALID_PARAMETER
;
667 rpc_data
= data_blob_const(rpc_out
->data
668 + DCERPC_RESPONSE_LENGTH
,
670 - DCERPC_RESPONSE_LENGTH
671 - DCERPC_AUTH_TRAILER_LENGTH
);
673 switch (auth_level
) {
674 case DCERPC_AUTH_LEVEL_PRIVACY
:
675 /* Data portion is encrypted. */
676 status
= spnego_seal(rpc_out
->data
, spnego_ctx
,
677 &rpc_data
, rpc_out
, &auth_blob
);
680 if (!NT_STATUS_IS_OK(status
)) {
685 case DCERPC_AUTH_LEVEL_INTEGRITY
:
686 /* Data is signed. */
687 status
= spnego_sign(rpc_out
->data
, spnego_ctx
,
688 &rpc_data
, rpc_out
, &auth_blob
);
691 if (!NT_STATUS_IS_OK(status
)) {
698 smb_panic("bad auth level");
700 return NT_STATUS_INVALID_PARAMETER
;
703 /* Finally attach the blob. */
704 if (!data_blob_append(NULL
, rpc_out
,
705 auth_blob
.data
, auth_blob
.length
)) {
706 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
707 (unsigned int)auth_blob
.length
));
708 return NT_STATUS_NO_MEMORY
;
710 data_blob_free(&auth_blob
);
715 static NTSTATUS
get_spnego_auth_footer(TALLOC_CTX
*mem_ctx
,
716 struct spnego_context
*sp_ctx
,
717 enum dcerpc_AuthLevel auth_level
,
718 DATA_BLOB
*data
, DATA_BLOB
*full_pkt
,
719 DATA_BLOB
*auth_token
)
721 switch (auth_level
) {
722 case DCERPC_AUTH_LEVEL_PRIVACY
:
723 /* Data portion is encrypted. */
724 return spnego_unseal(mem_ctx
, sp_ctx
,
725 data
, full_pkt
, auth_token
);
727 case DCERPC_AUTH_LEVEL_INTEGRITY
:
728 /* Data is signed. */
729 return spnego_sigcheck(mem_ctx
, sp_ctx
,
730 data
, full_pkt
, auth_token
);
733 return NT_STATUS_INVALID_PARAMETER
;
738 * @brief Append an auth footer according to what is the current mechanism
740 * @param auth The pipe_auth_data associated with the connection
741 * @param pad_len The padding used in the packet
742 * @param rpc_out Packet blob up to and including the auth header
744 * @return A NTSTATUS error code.
746 NTSTATUS
dcerpc_add_auth_footer(struct pipe_auth_data
*auth
,
747 size_t pad_len
, DATA_BLOB
*rpc_out
)
749 struct schannel_state
*schannel_auth
;
750 struct auth_ntlmssp_state
*ntlmssp_ctx
;
751 struct spnego_context
*spnego_ctx
;
752 struct gse_context
*gse_ctx
;
753 char pad
[CLIENT_NDR_PADDING_SIZE
] = { 0, };
758 if (auth
->auth_type
== DCERPC_AUTH_TYPE_NONE
||
759 auth
->auth_type
== DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM
) {
764 /* Copy the sign/seal padding data. */
765 if (!data_blob_append(NULL
, rpc_out
, pad
, pad_len
)) {
766 return NT_STATUS_NO_MEMORY
;
770 /* marshall the dcerpc_auth with an actually empty auth_blob.
771 * This is needed because the ntmlssp signature includes the
772 * auth header. We will append the actual blob later. */
773 auth_blob
= data_blob_null
;
774 status
= dcerpc_push_dcerpc_auth(rpc_out
->data
,
781 if (!NT_STATUS_IS_OK(status
)) {
785 /* append the header */
786 if (!data_blob_append(NULL
, rpc_out
,
787 auth_info
.data
, auth_info
.length
)) {
788 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
789 (unsigned int)auth_info
.length
));
790 return NT_STATUS_NO_MEMORY
;
792 data_blob_free(&auth_info
);
794 /* Generate any auth sign/seal and add the auth footer. */
795 switch (auth
->auth_type
) {
796 case DCERPC_AUTH_TYPE_NONE
:
797 case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM
:
798 status
= NT_STATUS_OK
;
800 case DCERPC_AUTH_TYPE_SPNEGO
:
801 spnego_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
802 struct spnego_context
);
803 status
= add_spnego_auth_footer(spnego_ctx
,
804 auth
->auth_level
, rpc_out
);
806 case DCERPC_AUTH_TYPE_NTLMSSP
:
807 ntlmssp_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
808 struct auth_ntlmssp_state
);
809 status
= add_ntlmssp_auth_footer(ntlmssp_ctx
,
813 case DCERPC_AUTH_TYPE_SCHANNEL
:
814 schannel_auth
= talloc_get_type_abort(auth
->auth_ctx
,
815 struct schannel_state
);
816 status
= add_schannel_auth_footer(schannel_auth
,
820 case DCERPC_AUTH_TYPE_KRB5
:
821 gse_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
823 status
= add_gssapi_auth_footer(gse_ctx
,
828 status
= NT_STATUS_INVALID_PARAMETER
;
836 * @brief Check authentication for request/response packets
838 * @param auth The auth data for the connection
839 * @param pkt The actual ncacn_packet
840 * @param pkt_trailer The stub_and_verifier part of the packet
841 * @param header_size The header size
842 * @param raw_pkt The whole raw packet data blob
843 * @param pad_len [out] The padding length used in the packet
845 * @return A NTSTATUS error code
847 NTSTATUS
dcerpc_check_auth(struct pipe_auth_data
*auth
,
848 struct ncacn_packet
*pkt
,
849 DATA_BLOB
*pkt_trailer
,
854 struct schannel_state
*schannel_auth
;
855 struct auth_ntlmssp_state
*ntlmssp_ctx
;
856 struct spnego_context
*spnego_ctx
;
857 struct gse_context
*gse_ctx
;
859 struct dcerpc_auth auth_info
;
860 uint32_t auth_length
;
864 switch (auth
->auth_level
) {
865 case DCERPC_AUTH_LEVEL_PRIVACY
:
866 DEBUG(10, ("Requested Privacy.\n"));
869 case DCERPC_AUTH_LEVEL_INTEGRITY
:
870 DEBUG(10, ("Requested Integrity.\n"));
873 case DCERPC_AUTH_LEVEL_CONNECT
:
874 if (pkt
->auth_length
!= 0) {
880 case DCERPC_AUTH_LEVEL_NONE
:
881 if (pkt
->auth_length
!= 0) {
882 DEBUG(3, ("Got non-zero auth len on non "
883 "authenticated connection!\n"));
884 return NT_STATUS_INVALID_PARAMETER
;
890 DEBUG(3, ("Unimplemented Auth Level %d",
892 return NT_STATUS_INVALID_PARAMETER
;
895 /* Paranioa checks for auth_length. */
896 if (pkt
->auth_length
> pkt
->frag_length
) {
897 return NT_STATUS_INFO_LENGTH_MISMATCH
;
899 if (((unsigned int)pkt
->auth_length
900 + DCERPC_AUTH_TRAILER_LENGTH
< (unsigned int)pkt
->auth_length
) ||
901 ((unsigned int)pkt
->auth_length
902 + DCERPC_AUTH_TRAILER_LENGTH
< DCERPC_AUTH_TRAILER_LENGTH
)) {
903 /* Integer wrap attempt. */
904 return NT_STATUS_INFO_LENGTH_MISMATCH
;
907 status
= dcerpc_pull_auth_trailer(pkt
, pkt
, pkt_trailer
,
908 &auth_info
, &auth_length
, false);
909 if (!NT_STATUS_IS_OK(status
)) {
913 data
= data_blob_const(raw_pkt
->data
+ header_size
,
914 pkt_trailer
->length
- auth_length
);
915 full_pkt
= data_blob_const(raw_pkt
->data
,
916 raw_pkt
->length
- auth_info
.credentials
.length
);
918 switch (auth
->auth_type
) {
919 case DCERPC_AUTH_TYPE_NONE
:
920 case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM
:
923 case DCERPC_AUTH_TYPE_SPNEGO
:
924 spnego_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
925 struct spnego_context
);
926 status
= get_spnego_auth_footer(pkt
, spnego_ctx
,
929 &auth_info
.credentials
);
930 if (!NT_STATUS_IS_OK(status
)) {
935 case DCERPC_AUTH_TYPE_NTLMSSP
:
937 DEBUG(10, ("NTLMSSP auth\n"));
939 ntlmssp_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
940 struct auth_ntlmssp_state
);
941 status
= get_ntlmssp_auth_footer(ntlmssp_ctx
,
944 &auth_info
.credentials
);
945 if (!NT_STATUS_IS_OK(status
)) {
950 case DCERPC_AUTH_TYPE_SCHANNEL
:
952 DEBUG(10, ("SCHANNEL auth\n"));
954 schannel_auth
= talloc_get_type_abort(auth
->auth_ctx
,
955 struct schannel_state
);
956 status
= get_schannel_auth_footer(pkt
, schannel_auth
,
959 &auth_info
.credentials
);
960 if (!NT_STATUS_IS_OK(status
)) {
965 case DCERPC_AUTH_TYPE_KRB5
:
967 DEBUG(10, ("KRB5 auth\n"));
969 gse_ctx
= talloc_get_type_abort(auth
->auth_ctx
,
971 status
= get_gssapi_auth_footer(pkt
, gse_ctx
,
974 &auth_info
.credentials
);
975 if (!NT_STATUS_IS_OK(status
)) {
981 DEBUG(0, ("process_request_pdu: "
982 "unknown auth type %u set.\n",
983 (unsigned int)auth
->auth_type
));
984 return NT_STATUS_INVALID_PARAMETER
;
987 /* TODO: remove later
988 * this is still needed because in the server code the
989 * pkt_trailer actually has a copy of the raw data, and they
990 * are still both used in later calls */
991 if (auth
->auth_level
== DCERPC_AUTH_LEVEL_PRIVACY
) {
992 memcpy(pkt_trailer
->data
, data
.data
, data
.length
);
995 *pad_len
= auth_info
.auth_pad_length
;
996 data_blob_free(&auth_info
.credentials
);