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/rpc/dcerpc_gssapi.h"
32 #define DBGC_CLASS DBGC_RPC_PARSE
35 * @brief NDR Encodes a ncacn_packet
37 * @param mem_ctx The memory context the blob will be allocated on
38 * @param ptype The DCERPC packet type
39 * @param pfc_flags The DCERPC PFC Falgs
40 * @param auth_length The length of the trailing auth blob
41 * @param call_id The call ID
42 * @param u The payload of the packet
43 * @param blob [out] The encoded blob if successful
45 * @return an NTSTATUS error code
47 NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx,
48 enum dcerpc_pkt_type ptype,
52 union dcerpc_payload *u,
55 struct ncacn_packet r;
56 enum ndr_err_code ndr_err;
61 r.pfc_flags = pfc_flags;
62 r.drep[0] = DCERPC_DREP_LE;
66 r.auth_length = auth_length;
70 ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
71 (ndr_push_flags_fn_t)ndr_push_ncacn_packet);
72 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
73 return ndr_map_error2ntstatus(ndr_err);
76 dcerpc_set_frag_length(blob, blob->length);
79 if (DEBUGLEVEL >= 10) {
80 /* set frag len for print function */
81 r.frag_length = blob->length;
82 NDR_PRINT_DEBUG(ncacn_packet, &r);
89 * @brief Decodes a ncacn_packet
91 * @param mem_ctx The memory context on which to allocate the packet
93 * @param blob The blob of data to decode
94 * @param r An empty ncacn_packet, must not be NULL
96 * @return a NTSTATUS error code
98 NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
99 const DATA_BLOB *blob,
100 struct ncacn_packet *r,
103 enum ndr_err_code ndr_err;
104 struct ndr_pull *ndr;
106 ndr = ndr_pull_init_blob(blob, mem_ctx);
108 return NT_STATUS_NO_MEMORY;
111 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
114 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, r);
116 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
118 return ndr_map_error2ntstatus(ndr_err);
122 if (DEBUGLEVEL >= 10) {
123 NDR_PRINT_DEBUG(ncacn_packet, r);
130 * @brief NDR Encodes a NL_AUTH_MESSAGE
132 * @param mem_ctx The memory context the blob will be allocated on
133 * @param r The NL_AUTH_MESSAGE to encode
134 * @param blob [out] The encoded blob if successful
136 * @return a NTSTATUS error code
138 NTSTATUS dcerpc_push_schannel_bind(TALLOC_CTX *mem_ctx,
139 struct NL_AUTH_MESSAGE *r,
142 enum ndr_err_code ndr_err;
144 ndr_err = ndr_push_struct_blob(blob, mem_ctx, r,
145 (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
146 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
147 return ndr_map_error2ntstatus(ndr_err);
150 if (DEBUGLEVEL >= 10) {
151 NDR_PRINT_DEBUG(NL_AUTH_MESSAGE, r);
158 * @brief NDR Encodes a dcerpc_auth structure
160 * @param mem_ctx The memory context the blob will be allocated on
161 * @param auth_type The DCERPC Authentication Type
162 * @param auth_level The DCERPC Authentication Level
163 * @param auth_pad_length The padding added to the packet this blob will be
165 * @param auth_context_id The context id
166 * @param credentials The authentication credentials blob (signature)
167 * @param blob [out] The encoded blob if successful
169 * @return a NTSTATUS error code
171 NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx,
172 enum dcerpc_AuthType auth_type,
173 enum dcerpc_AuthLevel auth_level,
174 uint8_t auth_pad_length,
175 uint32_t auth_context_id,
176 const DATA_BLOB *credentials,
179 struct dcerpc_auth r;
180 enum ndr_err_code ndr_err;
182 r.auth_type = auth_type;
183 r.auth_level = auth_level;
184 r.auth_pad_length = auth_pad_length;
186 r.auth_context_id = auth_context_id;
187 r.credentials = *credentials;
189 ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
190 (ndr_push_flags_fn_t)ndr_push_dcerpc_auth);
191 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
192 return ndr_map_error2ntstatus(ndr_err);
195 if (DEBUGLEVEL >= 10) {
196 NDR_PRINT_DEBUG(dcerpc_auth, &r);
203 * @brief Decodes a dcerpc_auth blob
205 * @param mem_ctx The memory context on which to allocate the packet
207 * @param blob The blob of data to decode
208 * @param r An empty dcerpc_auth structure, must not be NULL
210 * @return a NTSTATUS error code
212 NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx,
213 const DATA_BLOB *blob,
214 struct dcerpc_auth *r,
217 enum ndr_err_code ndr_err;
218 struct ndr_pull *ndr;
220 ndr = ndr_pull_init_blob(blob, mem_ctx);
222 return NT_STATUS_NO_MEMORY;
225 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
228 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, r);
230 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
232 return ndr_map_error2ntstatus(ndr_err);
236 if (DEBUGLEVEL >= 10) {
237 NDR_PRINT_DEBUG(dcerpc_auth, r);
243 /*******************************************************************
244 Create and add the NTLMSSP sign/seal auth data.
245 ********************************************************************/
247 static NTSTATUS add_ntlmssp_auth_footer(struct auth_ntlmssp_state *auth_state,
248 enum dcerpc_AuthLevel auth_level,
251 uint16_t data_and_pad_len = rpc_out->length
252 - DCERPC_RESPONSE_LENGTH
253 - DCERPC_AUTH_TRAILER_LENGTH;
258 return NT_STATUS_INVALID_PARAMETER;
261 switch (auth_level) {
262 case DCERPC_AUTH_LEVEL_PRIVACY:
263 /* Data portion is encrypted. */
264 status = auth_ntlmssp_seal_packet(auth_state,
267 + DCERPC_RESPONSE_LENGTH,
272 if (!NT_STATUS_IS_OK(status)) {
277 case DCERPC_AUTH_LEVEL_INTEGRITY:
278 /* Data is signed. */
279 status = auth_ntlmssp_sign_packet(auth_state,
282 + DCERPC_RESPONSE_LENGTH,
287 if (!NT_STATUS_IS_OK(status)) {
294 smb_panic("bad auth level");
296 return NT_STATUS_INVALID_PARAMETER;
299 /* Finally attach the blob. */
300 if (!data_blob_append(NULL, rpc_out,
301 auth_blob.data, auth_blob.length)) {
302 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
303 (unsigned int)auth_blob.length));
304 return NT_STATUS_NO_MEMORY;
306 data_blob_free(&auth_blob);
311 /*******************************************************************
312 Create and add the schannel sign/seal auth data.
313 ********************************************************************/
315 static NTSTATUS add_schannel_auth_footer(struct schannel_state *sas,
316 enum dcerpc_AuthLevel auth_level,
319 uint8_t *data_p = rpc_out->data + DCERPC_RESPONSE_LENGTH;
320 size_t data_and_pad_len = rpc_out->length
321 - DCERPC_RESPONSE_LENGTH
322 - DCERPC_AUTH_TRAILER_LENGTH;
327 return NT_STATUS_INVALID_PARAMETER;
330 DEBUG(10,("add_schannel_auth_footer: SCHANNEL seq_num=%d\n",
333 switch (auth_level) {
334 case DCERPC_AUTH_LEVEL_PRIVACY:
335 status = netsec_outgoing_packet(sas,
342 case DCERPC_AUTH_LEVEL_INTEGRITY:
343 status = netsec_outgoing_packet(sas,
351 status = NT_STATUS_INTERNAL_ERROR;
355 if (!NT_STATUS_IS_OK(status)) {
356 DEBUG(1,("add_schannel_auth_footer: failed to process packet: %s\n",
361 if (DEBUGLEVEL >= 10) {
362 dump_NL_AUTH_SIGNATURE(talloc_tos(), &auth_blob);
365 /* Finally attach the blob. */
366 if (!data_blob_append(NULL, rpc_out,
367 auth_blob.data, auth_blob.length)) {
368 return NT_STATUS_NO_MEMORY;
370 data_blob_free(&auth_blob);
375 /*******************************************************************
376 Create and add the gssapi sign/seal auth data.
377 ********************************************************************/
379 static NTSTATUS add_gssapi_auth_footer(struct gse_context *gse_ctx,
380 enum dcerpc_AuthLevel auth_level,
388 return NT_STATUS_INVALID_PARAMETER;
391 data.data = rpc_out->data + DCERPC_RESPONSE_LENGTH;
392 data.length = rpc_out->length - DCERPC_RESPONSE_LENGTH
393 - DCERPC_AUTH_TRAILER_LENGTH;
395 switch (auth_level) {
396 case DCERPC_AUTH_LEVEL_PRIVACY:
397 status = gse_seal(talloc_tos(), gse_ctx, &data, &auth_blob);
399 case DCERPC_AUTH_LEVEL_INTEGRITY:
400 status = gse_sign(talloc_tos(), gse_ctx, &data, &auth_blob);
403 status = NT_STATUS_INTERNAL_ERROR;
407 if (!NT_STATUS_IS_OK(status)) {
408 DEBUG(1, ("Failed to process packet: %s\n",
413 /* Finally attach the blob. */
414 if (!data_blob_append(NULL, rpc_out,
415 auth_blob.data, auth_blob.length)) {
416 return NT_STATUS_NO_MEMORY;
419 data_blob_free(&auth_blob);
425 * @brief Append an auth footer according to what is the current mechanism
427 * @param auth The pipe_auth_data associated with the connection
428 * @param pad_len The padding used in the packet
429 * @param rpc_out Packet blob up to and including the auth header
431 * @return A NTSTATUS error code.
433 NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
434 size_t pad_len, DATA_BLOB *rpc_out)
436 char pad[CLIENT_NDR_PADDING_SIZE] = { 0, };
441 if (auth->auth_type == DCERPC_AUTH_TYPE_NONE) {
446 /* Copy the sign/seal padding data. */
447 if (!data_blob_append(NULL, rpc_out, pad, pad_len)) {
448 return NT_STATUS_NO_MEMORY;
452 /* marshall the dcerpc_auth with an actually empty auth_blob.
453 * This is needed because the ntmlssp signature includes the
454 * auth header. We will append the actual blob later. */
455 auth_blob = data_blob_null;
456 status = dcerpc_push_dcerpc_auth(rpc_out->data,
463 if (!NT_STATUS_IS_OK(status)) {
467 /* append the header */
468 if (!data_blob_append(NULL, rpc_out,
469 auth_info.data, auth_info.length)) {
470 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
471 (unsigned int)auth_info.length));
472 return NT_STATUS_NO_MEMORY;
474 data_blob_free(&auth_info);
476 /* Generate any auth sign/seal and add the auth footer. */
477 switch (auth->auth_type) {
478 case DCERPC_AUTH_TYPE_NONE:
479 status = NT_STATUS_OK;
481 case DCERPC_AUTH_TYPE_SPNEGO:
482 if (auth->spnego_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
483 return NT_STATUS_INVALID_PARAMETER;
486 case DCERPC_AUTH_TYPE_NTLMSSP:
487 status = add_ntlmssp_auth_footer(auth->a_u.auth_ntlmssp_state,
491 case DCERPC_AUTH_TYPE_SCHANNEL:
492 status = add_schannel_auth_footer(auth->a_u.schannel_auth,
496 case DCERPC_AUTH_TYPE_KRB5:
497 status = add_gssapi_auth_footer(auth->a_u.gssapi_state,
502 status = NT_STATUS_INVALID_PARAMETER;
510 * @brief Check authentication for request/response packets
512 * @param auth The auth data for the connection
513 * @param pkt The actual ncacn_packet
514 * @param pkt_trailer The stub_and_verifier part of the packet
515 * @param header_size The header size
516 * @param raw_pkt The whole raw packet data blob
517 * @param pad_len [out] The padding length used in the packet
519 * @return A NTSTATUS error code
521 NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
522 struct ncacn_packet *pkt,
523 DATA_BLOB *pkt_trailer,
529 struct dcerpc_auth auth_info;
530 uint32_t auth_length;
534 switch (auth->auth_level) {
535 case DCERPC_AUTH_LEVEL_PRIVACY:
536 DEBUG(10, ("Requested Privacy.\n"));
539 case DCERPC_AUTH_LEVEL_INTEGRITY:
540 DEBUG(10, ("Requested Integrity.\n"));
543 case DCERPC_AUTH_LEVEL_CONNECT:
544 if (pkt->auth_length != 0) {
550 case DCERPC_AUTH_LEVEL_NONE:
551 if (pkt->auth_length != 0) {
552 DEBUG(3, ("Got non-zero auth len on non "
553 "authenticated connection!\n"));
554 return NT_STATUS_INVALID_PARAMETER;
560 DEBUG(3, ("Unimplemented Auth Level %d",
562 return NT_STATUS_INVALID_PARAMETER;
565 /* Paranioa checks for auth_length. */
566 if (pkt->auth_length > pkt->frag_length) {
567 return NT_STATUS_INFO_LENGTH_MISMATCH;
569 if ((pkt->auth_length
570 + DCERPC_AUTH_TRAILER_LENGTH < pkt->auth_length) ||
572 + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) {
573 /* Integer wrap attempt. */
574 return NT_STATUS_INFO_LENGTH_MISMATCH;
577 status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
578 &auth_info, &auth_length, false);
579 if (!NT_STATUS_IS_OK(status)) {
583 data = data_blob_const(raw_pkt->data + header_size,
584 pkt_trailer->length - auth_length);
585 full_pkt = data_blob_const(raw_pkt->data,
586 raw_pkt->length - auth_info.credentials.length);
588 switch (auth->auth_type) {
589 case DCERPC_AUTH_TYPE_NONE:
592 case DCERPC_AUTH_TYPE_SPNEGO:
593 if (auth->spnego_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
594 DEBUG(0, ("Currently only NTLMSSP is supported "
596 return NT_STATUS_INVALID_PARAMETER;
599 case DCERPC_AUTH_TYPE_NTLMSSP:
601 DEBUG(10, ("NTLMSSP auth\n"));
603 if (!auth->a_u.auth_ntlmssp_state) {
604 DEBUG(0, ("Invalid auth level, "
605 "failed to process packet auth.\n"));
606 return NT_STATUS_INVALID_PARAMETER;
609 switch (auth->auth_level) {
610 case DCERPC_AUTH_LEVEL_PRIVACY:
611 status = auth_ntlmssp_unseal_packet(
612 auth->a_u.auth_ntlmssp_state,
613 data.data, data.length,
614 full_pkt.data, full_pkt.length,
615 &auth_info.credentials);
616 if (!NT_STATUS_IS_OK(status)) {
619 memcpy(pkt_trailer->data, data.data, data.length);
622 case DCERPC_AUTH_LEVEL_INTEGRITY:
623 status = auth_ntlmssp_check_packet(
624 auth->a_u.auth_ntlmssp_state,
625 data.data, data.length,
626 full_pkt.data, full_pkt.length,
627 &auth_info.credentials);
628 if (!NT_STATUS_IS_OK(status)) {
634 DEBUG(0, ("Invalid auth level, "
635 "failed to process packet auth.\n"));
636 return NT_STATUS_INVALID_PARAMETER;
640 case DCERPC_AUTH_TYPE_SCHANNEL:
642 DEBUG(10, ("SCHANNEL auth\n"));
644 switch (auth->auth_level) {
645 case DCERPC_AUTH_LEVEL_PRIVACY:
646 status = netsec_incoming_packet(
647 auth->a_u.schannel_auth,
649 data.data, data.length,
650 &auth_info.credentials);
651 if (!NT_STATUS_IS_OK(status)) {
654 memcpy(pkt_trailer->data, data.data, data.length);
657 case DCERPC_AUTH_LEVEL_INTEGRITY:
658 status = netsec_incoming_packet(
659 auth->a_u.schannel_auth,
661 data.data, data.length,
662 &auth_info.credentials);
663 if (!NT_STATUS_IS_OK(status)) {
669 DEBUG(0, ("Invalid auth level, "
670 "failed to process packet auth.\n"));
671 return NT_STATUS_INVALID_PARAMETER;
675 case DCERPC_AUTH_TYPE_KRB5:
677 DEBUG(10, ("KRB5 auth\n"));
679 switch (auth->auth_level) {
680 case DCERPC_AUTH_LEVEL_PRIVACY:
681 status = gse_unseal(pkt, auth->a_u.gssapi_state,
682 &data, &auth_info.credentials);
683 if (!NT_STATUS_IS_OK(status)) {
686 memcpy(pkt_trailer->data, data.data, data.length);
689 case DCERPC_AUTH_LEVEL_INTEGRITY:
690 /* TODO: pass in full_pkt when
691 * DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN is set */
692 status = gse_sigcheck(pkt, auth->a_u.gssapi_state,
693 &data, &auth_info.credentials);
694 if (!NT_STATUS_IS_OK(status)) {
700 DEBUG(0, ("Invalid auth level, "
701 "failed to process packet auth.\n"));
702 return NT_STATUS_INVALID_PARAMETER;
707 DEBUG(0, ("process_request_pdu: "
708 "unknown auth type %u set.\n",
709 (unsigned int)auth->auth_type));
710 return NT_STATUS_INVALID_PARAMETER;
713 *pad_len = auth_info.auth_pad_length;
714 data_blob_free(&auth_info.credentials);